vasilgerginski / filamentphp-text-extractor
Extract and manage translatable text from Filament models with an intuitive admin interface
Requires
- php: ^8.1
- filament/filament: ^3.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- laravel/framework: ^10.0|^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
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.
๐ Features
๐ Automatic Text Extraction
- 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
โจ Translation Casts (NEW!)
- 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!
๐จ Filament Integration
- 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
๐๏ธ Advanced Content Support
- 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
๐ Multi-Language Ready
- 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
โก Performance & Developer Experience
- 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
๐ Requirements
- PHP 8.1 or higher
- Laravel 10.0 or higher
- Filament 3.0 or higher
๐ง Installation
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"
๐ฏ Quick Start
1. Add the Trait to Your Model
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', ]; }
2. Extract Text
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);
3. Use the Artisan Command
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
โจ Translation Casts (NEW!)
๐ฏ Translatable Cast for Simple Fields
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! --}}
๐๏ธ JsonTranslatable Cast for UI Components
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!)
๐ง Smart Field Detection
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)
๐ญ Live Demos & Examples
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
๐ Advanced Features
Filament Builder Block Extraction
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!)
Rich Text Extraction
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.'
๐จ Filament Admin Interface
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
Dashboard Features
The extraction dashboard provides:
- Total number of extracted texts
- Breakdown by model type
- Language distribution
- Recent extractions
- Quick actions for bulk operations
โ๏ธ Configuration
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 ], ];
๐ Field Handlers
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
Creating Custom Field Handlers
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); } }
๐ Auto-Generated Translation Files
The package can automatically generate Laravel translation files in your lang
directory, enabling seamless localization:
Automatic Translation File Generation
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 ];
Using Translations in Your Models
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
Automatic Model Casting
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
Translation Workflow
- 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)
๐งช Testing
The package includes a comprehensive test suite. Run the tests with:
composer test
For code coverage:
composer test-coverage
๐ค Contributing
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
๐ Bug Reports
If you discover any issues, please create an issue on GitHub: https://github.com/vasilGerginski/filamentphp-text-extractor/issues
๐ Changelog
Please see CHANGELOG for more information on what has changed recently.
๐ Security
If you discover any security-related issues, please email vasil.gerginsky@gmail.com instead of using the issue tracker.
๐ Credits
๐ License
The MIT License (MIT). Please see License File for more information.
๐ Show Your Support
If you find this package helpful, please consider giving it a star on GitHub! โญ
Built with โค๏ธ by Vasil Gerginski