- How do I install spatie/laravel-translatable in a Laravel project?
- Run `composer require spatie/laravel-translatable` in your project root. No additional configuration is needed beyond using the `HasTranslations` trait in your Eloquent models. The package auto-discovers itself via Laravel’s service provider system.
- Can I use this package with Laravel 10+ and PHP 8.1+?
- Yes, the package officially supports Laravel 9.x, 10.x, and 11.x, as well as PHP 8.1+. Check the [GitHub releases](https://github.com/spatie/laravel-translatable/releases) for the latest compatibility matrix. PHP 8.0 is also supported but lacks PHP 8 attribute syntax.
- What’s the difference between using #[Translatable] attributes vs. $translatable property?
- Both methods define translatable fields, but attributes (PHP 8+) are preferred for modern Laravel projects. If both are defined, their values are merged and deduplicated. Attributes are type-safe and IDE-friendly, while the property works in older PHP versions.
- How do I query models by translation content (e.g., find posts with 'title' containing 'Laravel')?
- Use `whereJsonContainsLocale('title', 'Laravel', 'en')` or `whereJsonContains('translations->title->en', 'Laravel')` for direct JSON queries. For complex queries, cast the `translations` attribute to an array and use Laravel’s query builder. Indexing the JSON column may improve performance.
- Does this package support nested translations (e.g., meta.description) or only flat keys?
- Yes, it supports nested JSON structures like `meta->description` or `author->name`. Define nested keys in the translatable list (e.g., `#[Translatable('meta.description')]`), and access them via `getTranslation('meta.description', 'en')`. The JSON column stores the entire hierarchy.
- How do I handle missing translations (fallback locales)?
- Enable fallbacks via `$translatable = ['name' => ['fallback' => 'nl']]` or globally in the config. When a translation is missing, it falls back to the specified locale. Disable fallbacks per attribute by setting `fallback: false` or globally via `config(['translatable.fallback_locale' => null])`.
- Will this package work with SQLite or only MySQL/PostgreSQL?
- SQLite has limited JSON query support, so some features (like `whereJsonContainsLocale`) may not work. For SQLite, use raw accessors or cast the `translations` attribute to an array. MySQL 5.7+ and PostgreSQL are fully supported with JSON/JSONB columns.
- How do I migrate existing data into the JSON column format?
- Use Laravel migrations to add a JSON column, then write a custom script to backfill translations. For example, loop through existing records, extract translations from separate tables, and update the JSON column. The package doesn’t provide a built-in importer, but the `setTranslation()` method can be used programmatically.
- Can I use this with Laravel Scout for full-text search on translations?
- Yes, but you’ll need to index the JSON column or extract translations into a searchable format. Use `toSearchableArray()` in your model to include translations, or create a custom Scout engine. Note that JSON queries in Scout may require database-specific optimizations.
- Are there performance concerns with storing translations in a single JSON column?
- JSON columns can slow down queries on large datasets, especially with `whereJsonContains`. For performance-critical apps, consider indexing the JSON column (e.g., MySQL generated columns or PostgreSQL JSON operators) or using a separate translations table. Write performance is also impacted by full-column rewrites on updates.