A powerful Laravel package that seamlessly integrates with Filament Admin Panel to extract and manage translatable text from your Eloquent models. Perfect for multi-language applications, content management systems, and any project requiring dynamic text extraction and translation management.
- Extract translatable fields from any Eloquent model with a simple trait
- Auto-generate Laravel translation files in standard format (
lang/en/model_name.php
) - Support for simple text fields, JSON structures, and rich content
- Translatable Cast: Use
{{ $post->title }}
instead of{{ __('blog_post.' . $post->title) }}
- JsonTranslatable Cast: Automatic translation for JSON UI components (hero sections, feature grids, etc.)
- Zero code changes required in your templates!
- Beautiful admin interface built with Filament for managing extracted texts
- Filament Plugin Architecture: Automatically registers with your admin panel
- Built-in resource for managing translations
- Rich Text Support: Extracts text from HTML, Markdown, and rich text editor content
- JSON Field Translation: Perfect for page builders, CMS blocks, and UI components
- Nested Structure Support: Works recursively through complex JSON data
- Built-in support for multiple languages and locales
- Laravel Standard: Uses Laravel's translation system (
__()
helper) - Smart Fallbacks: Returns original text if no translation found
- Queue Support: Handle bulk text extraction asynchronously
- Live Demos: Comprehensive examples showing all features
- Well Tested: Comprehensive test suite included
- Easy Installation: Simple setup with minimal configuration
- PHP 8.1 or higher
- Laravel 10.0 or higher
- Filament 3.0 or higher
Install the package via Composer:
composer require vasilgerginski/filamentphp-text-extractor
Register the plugin in your Panel provider (e.g., app/Providers/Filament/AdminPanelProvider.php
):
use VasilGerginski\FilamentTextExtractor\FilamentTextExtractorPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ... other configuration
->plugin(FilamentTextExtractorPlugin::make());
}
Publish and run the migrations:
php artisan vendor:publish --provider="VasilGerginski\FilamentTextExtractor\FilamentTextExtractorServiceProvider"
php artisan migrate
Optionally, publish the config file:
php artisan vendor:publish --tag="filament-text-extractor-config"
Add the ExtractsTranslatableText
trait to any model you want to extract text from:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use VasilGerginski\FilamentTextExtractor\Traits\ExtractsTranslatableText;
class BlogPost extends Model
{
use ExtractsTranslatableText;
// Define which fields should be extracted
protected array $translatableFields = [
'title',
'content',
'excerpt',
'meta_description',
];
}
You can extract text from a single model instance:
$blogPost = BlogPost::find(1);
$blogPost->extractTranslatableText();
Or extract from all instances of a model:
use VasilGerginski\FilamentTextExtractor\Jobs\ExtractTextJob;
// Extract synchronously
ExtractTextJob::dispatchSync(BlogPost::class);
// Or dispatch to queue
ExtractTextJob::dispatch(BlogPost::class);
Extract text for any model using the provided Artisan command:
# Extract from all blog posts
php artisan text-extractor:extract "App\Models\BlogPost"
# Extract with specific options
php artisan text-extractor:extract "App\Models\BlogPost" --queue
Instead of manual translation calls, use the Translatable
cast for automatic translation:
use VasilGerginski\FilamentTextExtractor\Casts\Translatable;
class BlogPost extends Model
{
use ExtractsTranslatableText;
protected $casts = [
'title' => Translatable::class,
'excerpt' => Translatable::class,
'meta_description' => Translatable::class,
];
}
Usage in templates:
{{-- OLD WAY (manual) --}}
{{ __('blog_post.' . $post->title) }}
{{-- NEW WAY (automatic!) --}}
{{ $post->title }} {{-- Automatically translated! --}}
{{ $post->excerpt }} {{-- Automatically translated! --}}
Perfect for page builders, CMS content blocks, and JSON-based UI components:
use VasilGerginski\FilamentTextExtractor\Casts\JsonTranslatable;
class BlogPost extends Model
{
protected $casts = [
'content' => JsonTranslatable::class, // For page builder blocks
'metadata' => JsonTranslatable::class, // For component data
];
}
JSON Structure (stored in database):
{
"type": "hero",
"title": "Welcome to Our Platform",
"subtitle": "Build amazing applications with our tools",
"button_text": "Get Started Now",
"background_image": "/images/hero-bg.jpg"
}
Template Usage (no translation calls needed!):
<div class="hero">
<h1>{{ $post->content[0]['title'] }}</h1> {{-- Auto-translated! --}}
<p>{{ $post->content[0]['subtitle'] }}</p> {{-- Auto-translated! --}}
<button>{{ $post->content[0]['button_text'] }}</button> {{-- Auto-translated! --}}
</div>
Translation Results:
- English: "Welcome to Our Platform"
- Spanish: "Bienvenido a Nuestra Plataforma" (automatic!)
The JsonTranslatable
cast automatically detects and translates:
- β
UI Text:
title
,subtitle
,heading
,description
,label
,button_text
- β Technical Data:
type
,icon
,url
,id
,background_image
(ignored)
Check out the examples/
directory for comprehensive demos:
- π Translation Demo: Classic
__()
approach - β¨ Cast Demo: Automatic
{{ $property }}
translation - ποΈ JSON Demo: UI component translation with JsonTranslatable cast
- π CLI Demo: Command-line testing and statistics
Quick demo setup:
# Copy demo files to your Laravel project
cp -r vendor/vasilgerginski/filamentphp-text-extractor/examples/* resources/views/
# Add routes (see examples/routes.php)
# Create sample data (see examples/sample-data.php)
# Visit your demos:
# /translation-demo
# /cast-demo
# /json-demo
The package automatically detects and extracts text from Filament Builder JSON blocks. When you have a Builder field with blocks like:
Builder::make('content')
->blocks([
Builder\Block::make('heading')
->schema([
TextInput::make('content')
->label('Heading text')
]),
Builder\Block::make('paragraph')
->schema([
Textarea::make('content')
->label('Paragraph text')
]),
Builder\Block::make('image')
->schema([
FileUpload::make('image'),
TextInput::make('alt_text')
]),
])
The extractor will automatically:
- Parse the JSON structure
- Extract text from all text-based fields within blocks
- Maintain context with keys like
model.field.block_type.field_name
- Skip non-text fields like images (but extract alt text!)
For rich text fields (TinyMCE, Trix, etc.), the package:
- Strips HTML tags to extract clean text
- Preserves meaningful content structure
- Handles nested HTML elements
- Extracts alt text from images
- Processes both plain HTML and encoded content
Example:
// Original rich text content
$content = '<h1>Welcome</h1><p>This is <strong>important</strong> text.</p>';
// Extracted as
'Welcome This is important text.'
The package automatically registers a Filament resource for managing extracted texts. After installation, you'll find a new "Extracted Texts" section in your Filament admin panel with:
- List View: Browse all extracted texts with search and filters
- Edit View: Update extracted text content and metadata
- Create View: Manually add new text entries
- Dashboard: Overview of extraction statistics and recent activity
The extraction dashboard provides:
- Total number of extracted texts
- Breakdown by model type
- Language distribution
- Recent extractions
- Quick actions for bulk operations
The configuration file (config/filament-text-extractor.php
) allows you to customize:
return [
// Default locale for extracted texts
'default_locale' => 'en',
// Available locales
'locales' => ['en', 'es', 'fr', 'de'],
// Auto-generate Laravel translation files
'auto_generate_lang_files' => true,
// Translation file naming pattern
'lang_file_pattern' => '{model_name}.php', // e.g., blog_posts.php
// Queue name for extraction jobs
'queue' => 'default',
// Fields to exclude from extraction
'excluded_fields' => ['id', 'password', 'remember_token'],
// Custom field handlers
'field_handlers' => [
'email' => \VasilGerginski\FilamentTextExtractor\FieldHandlers\EmailHandler::class,
'url' => \VasilGerginski\FilamentTextExtractor\FieldHandlers\UrlHandler::class,
// Add your custom handlers here
],
];
The package includes specialized handlers for different field types:
- EmailHandler: Validates and formats email fields
- UrlHandler: Handles URL validation and formatting
- RichTextHandler: Processes HTML/rich text content, strips tags and extracts clean text
- SlugHandler: Manages URL slugs
- LongTextHandler: Optimized for large text fields
- Built-in JSON Support: Automatically detects and extracts text from Filament Builder blocks and other JSON structures
You can create custom field handlers by extending the AbstractFieldHandler
:
<?php
namespace App\FieldHandlers;
use VasilGerginski\FilamentTextExtractor\FieldHandlers\AbstractFieldHandler;
class PhoneNumberHandler extends AbstractFieldHandler
{
public function handle(mixed $value): ?string
{
// Your custom logic here
return $this->formatPhoneNumber($value);
}
public function shouldExtract(mixed $value): bool
{
return !empty($value) && $this->isValidPhoneNumber($value);
}
}
The package can automatically generate Laravel translation files in your lang
directory, enabling seamless localization:
When texts are extracted, the package automatically creates/updates translation files:
// After extraction, files are created in:
// lang/en/blog_posts.php
// lang/es/blog_posts.php
// etc.
// Example generated file content:
return [
'post_1_title' => 'Welcome to our Blog',
'post_1_content' => 'This is the first blog post content...',
'post_1_excerpt' => 'A brief introduction to our blog',
// ... more extracted texts
];
With the generated translation files, you can easily access localized content:
// In your Blade views
{{ __('blog_posts.post_1_title') }}
// Or create a model accessor
class BlogPost extends Model
{
use ExtractsTranslatableText;
public function getLocalizedTitleAttribute()
{
return __("blog_posts.post_{$this->id}_title");
}
public function getLocalizedContentAttribute()
{
return __("blog_posts.post_{$this->id}_content");
}
}
// Usage
$post = BlogPost::find(1);
echo $post->localized_title; // Automatically uses current locale
You can even create a custom cast for automatic translation:
use VasilGerginski\FilamentTextExtractor\Casts\Translatable;
class BlogPost extends Model
{
protected $casts = [
'title' => Translatable::class,
'content' => Translatable::class,
'excerpt' => Translatable::class,
];
}
// Now these fields automatically return translated values
$post = BlogPost::find(1);
echo $post->title; // Returns translated title based on current locale
- Extract: Run extraction to populate the database and generate translation files
- Translate: Edit the generated files in
lang/[locale]/
or use the Filament admin - Deploy: Your application automatically uses the translated values
# Extract and generate translation files
php artisan text-extractor:extract "App\Models\BlogPost" --generate-lang-files
# Files created:
# - lang/en/blog_posts.php
# - lang/es/blog_posts.php (if Spanish is configured)
# - lang/fr/blog_posts.php (if French is configured)
The package includes a comprehensive test suite. Run the tests with:
composer test
For code coverage:
composer test-coverage
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
If you discover any issues, please create an issue on GitHub: https://github.com/vasilGerginski/filamentphp-text-extractor/issues
Please see CHANGELOG for more information on what has changed recently.
If you discover any security-related issues, please email vasil.gerginsky@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
If you find this package helpful, please consider giving it a star on GitHub! β
Built with β€οΈ by Vasil Gerginski