Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Translatable Laravel Package

astrotomic/laravel-translatable

Laravel package for translatable Eloquent models. Store model translations in the database and automatically fetch/save the correct locale with minimal code. Simplifies retrieving and persisting multilingual attributes across your app.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Multilingual Model Support: Perfect fit for Laravel applications requiring multilingual content (e.g., blogs, e-commerce, CMS). The package abstracts translation logic into a reusable trait, reducing boilerplate.
  • Database-Centric: Stores translations in a separate table (e.g., post_translations), adhering to Laravel’s Eloquent conventions. Avoids JSON serialization pitfalls (e.g., querying, indexing).
  • Locale-Agnostic: Supports custom locale formats (e.g., es_MX) and fallback chains (e.g., deen), aligning with i18n best practices.
  • Trait-Based: Leverages PHP traits for minimal model pollution, though this may limit IDE autocompletion for translated attributes.

Integration Feasibility

  • Laravel Compatibility: Officially supports Laravel 9–13 (PHP 8.0+), with backward compatibility for older versions. Minimal risk for modern stacks.
  • Migration Path:
    • New Projects: Zero migration effort—install, configure, and use.
    • Existing Projects: Requires schema changes (add translation tables) and model updates (add trait). Downtime minimal if done incrementally.
  • ORM Alignment: Works seamlessly with Eloquent relationships, scopes, and accessors. Example:
    $post->translations()->where('locale', 'en')->get();
    
  • Query Builder: Supports translating results post-hoc (e.g., Post::all()->each->translate('en')), though eager loading translations via withTranslations() is recommended.

Technical Risk

  • Performance:
    • N+1 Queries: Translations are lazy-loaded by default. Mitigate with withTranslations() or loadTranslations().
    • Join Overhead: Complex queries (e.g., whereHas('translations')) may require raw SQL or custom scopes.
  • Schema Rigidity: Translation tables must mirror the main model’s structure. Refactoring translated attributes requires migrations.
  • Caching: No built-in caching for translations. Requires manual integration (e.g., Cache::remember).
  • Edge Cases:
    • Fallback Logic: Fallback locales may introduce inconsistencies if not managed carefully.
    • Concurrency: Race conditions possible when updating translations (e.g., two users editing the same locale simultaneously).

Key Questions

  1. Locale Strategy:
    • How will locales be determined (user preference, URL, header)?
    • Is dynamic locale switching (e.g., App::setLocale) acceptable, or should it be request-scoped?
  2. Translation Scope:
    • Should all models be translatable, or only specific ones (e.g., Post, Product)?
    • How will non-translatable attributes be handled in mixed models?
  3. Fallback Behavior:
    • What’s the fallback chain (e.g., fr_CAfren)?
    • Should missing translations return null or a default value?
  4. Performance:
    • Will translations be preloaded for all requests, or lazily loaded?
    • Are there plans to optimize queries (e.g., bulk translation loading)?
  5. Testing:
    • How will translation-specific tests be structured (e.g., data factories, seeders)?
    • Are there plans to test fallback and edge cases (e.g., unsupported locales)?

Integration Approach

Stack Fit

  • Laravel Ecosystem: Native support for Eloquent, migrations, and service providers. Integrates with:
    • Laravel Scout: Translatable models can be indexed per locale.
    • Laravel Nova/Vue: Custom fields for translation management.
    • API Resources: Translate responses dynamically (e.g., PostResource::make($post->translate('en'))).
  • PHP Extensions: No external dependencies beyond Laravel core.
  • Frontend: Works with any frontend (Blade, Inertia, React) since translations are model-level.

Migration Path

  1. Schema Changes:
    • Add translation tables for each translatable model (e.g., posts, products).
    • Example migration:
      Schema::create('posts', function (Blueprint $table) {
          $table->id();
          $table->string('author');
          $table->timestamps();
      });
      
      Schema::create('post_translations', function (Blueprint $table) {
          $table->id();
          $table->foreignId('post_id')->constrained()->cascadeOnDelete();
          $table->string('locale')->index();
          $table->string('title');
          $table->text('content');
          $table->unique(['post_id', 'locale']);
      });
      
  2. Model Updates:
    • Add use Translatable trait to models.
    • Define $translatedAttributes and $translationModel (if custom).
    • Example:
      class Post extends Model {
          use \Astrotomic\Translatable\Translatable;
          public $translatedAttributes = ['title', 'content'];
          protected $translationModel = PostTranslation::class;
      }
      
  3. Configuration:
    • Publish and configure config/translatable.php:
      'locales' => ['en', 'fr', 'es'],
      'fallback_locale' => 'en',
      'translations_wrapper' => null, // or 'translations' for nested data
      
  4. Data Migration:
    • Backfill existing data using getTranslationsArray() or manual scripts.
    • Example:
      $post->fill([
          'author' => 'John',
          'translations' => [
              'en' => ['title' => 'Hello'],
              'fr' => ['title' => 'Bonjour'],
          ],
      ]);
      

Compatibility

  • Laravel Versions: Tested on 9–13. Downgrade risks for older versions (e.g., <8.0).
  • Database: MySQL, PostgreSQL, SQLite (no vendor-specific SQL).
  • Caching: No built-in caching; integrate with Laravel Cache or Redis.
  • Testing: Works with PHPUnit, Pest, and Laravel’s testing helpers.

Sequencing

  1. Phase 1: Core Integration
    • Install package and configure locales.
    • Add translation tables for 1–2 critical models (e.g., Post, Product).
    • Test CRUD operations with translations.
  2. Phase 2: API/Backend
    • Implement translation-aware API responses (e.g., Accept-Language headers).
    • Add translation loading to existing queries (e.g., withTranslations).
  3. Phase 3: Frontend
    • Update UI to handle dynamic locales (e.g., dropdowns, URL params).
    • Cache translations client-side (e.g., Vuex, Redux).
  4. Phase 4: Optimization
    • Add database indexes for locale and foreign keys.
    • Implement bulk translation loading for performance-critical pages.

Operational Impact

Maintenance

  • Package Updates: Low effort—composer updates and testing. Follow changelog for breaking changes.
  • Schema Changes: Additive only (new translation tables/columns). Downtime required for migrations.
  • Deprecations: Monitor Laravel version support (e.g., drop PHP 7.4 in v12+).
  • Community: Active maintainer (Tom Witkowski) and GitHub issues for support.

Support

  • Debugging:
    • Use dd($post->getTranslationsArray()) to inspect translation data.
    • Check hasTranslation() for missing locales.
    • Enable query logging (DB::enableQueryLog()) to diagnose N+1 issues.
  • Common Issues:
    • Missing Translations: Verify $translatedAttributes and locale configuration.
    • Save Failures: Ensure locale is unique per model (database constraint).
    • Fallback Misbehavior: Confirm fallback_locale is set in config.
  • Documentation: Comprehensive GitBook and README examples.

Scaling

  • Database:
    • Reads: Optimize with indexes on (model_id, locale).
    • Writes: Batch inserts for bulk translations (e.g., CSV imports).
    • Sharding: Partition translation tables by locale if needed.
  • Caching:
    • Cache entire models with translations (e.g., Cache::remember('post:1:en', ...)).
    • Use Redis for session-based locale preferences.
  • Horizontal Scaling: Stateless design; translations are data-layer concerns.

Failure Modes

Failure Scenario Impact Mitigation
Missing translation table hasTranslation() returns false Pre-migrate all models; use translateOrNew.
Locale not in config Fallback fails Validate locales on startup; use try-catch.
Database constraint violation Save fails Add unique(['post_id', 'locale']) checks.
N+1 queries on list pages
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4