vasilgerginski/filamentphp-text-extractor

Extract and manage translatable text from Filament models with an intuitive admin interface

v1.3.0 2025-05-28 00:26 UTC

This package is auto-updated.

Last update: 2025-05-28 10:42:29 UTC


README

Latest Version on Packagist Total Downloads License

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

  1. Extract: Run extraction to populate the database and generate translation files
  2. Translate: Edit the generated files in lang/[locale]/ or use the Filament admin
  3. 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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