Localisation

Added v0.2.0

Limitations

Not all fields can be translated. The following fields are currently translatable:

  • Text
  • WYSIWYG
  • Checkbox (e.g. for enabling a language on a item)
  • File Uploads (including images etc)
  • FlexibleContent (as a single whole)

Flexible fields can currently only be translated as a single block - i.e. the client will have to add different rows for each language.

Making Fields Translatable

  1. Each field should have it's own JSON column (instead of whatever type it would normally be). All translations (and the original data) will be stored in there. E.g. your title column might contain something like this: {"en": "Hello!", "fr": "Bonjour!"}
  2. In config/app.php add a provider...

    Spatie\Translatable\TranslatableServiceProvider::class,
    Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider::class,
    
  3. ...and an alias

    'LaravelLocalization' => Mcamara\LaravelLocalization\Facades\LaravelLocalization::class,
    
  4. Add trait to the models that you want to have translatable fields. E.g.:

    use Spatie\Translatable\HasTranslations;
    
    class Thing extends Model
    {
       use HasTranslations;
    
       // ...
    }
    
  5. Set the list of translatable fields on your model. E.g.:

    public $translatable = ['title'];
    
  6. In your CRUD config configure() method, set the CRUD to be translatable

    $this->setUseTranslations()
    
  7. ...and set each field as translatable, as needed.

    (new TextField('name'))
       ->setTranslatable(),
    
  8. Publish the config file.

    php artisan vendor:publish --provider="Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider"
    
  9. Fill in config/laravellocalization.php and enable the locales you need.

Setting Up Locale Routes

This is done using Mcamara/LaravelLocalization so look there if you need more information.

The following will allow you to prepend a locale to a URL (e.g. /fr/some-route-here) and have it automatically set the locale. This will then be cached on the user's session so if they were to then go to /some-route-here they would get redirect to /fr/some-route-here.

There is a lot more functionality and flexibility within the LaravelLocalization.

  1. Add some route middleware in app/Http/Kernel.php

    'localize' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class,
    'localizationRedirect' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class,
    'localeSessionRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class,
    'localeViewPath' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class
    
  2. Add a route group around any routes that should be translatable

    Route::group(
    [
       'prefix' => LaravelLocalization::setLocale(),
       'middleware' => [ 'localeSessionRedirect', 'localizationRedirect', 'localeViewPath' ]
    ],
    function()
    {
       // Your routes go here...
    
       Route::get('/', 'SomeController@someAction');
    });
    

Migrating Data

If you're making existing data translatable you will need to convert your columns to JSON columns. You cannot do this directly, so you will have to a create JSON column, migrate the data, remove the old column and rename the new column. E.g.

```php
public function up()
{
    Schema::table('pages', function (Blueprint $table) {
        $table->json('title_json');
    });

    DB::statement('UPDATE `pages` SET title_json = JSON_OBJECT("en", title)');

    Schema::table('pages', function (Blueprint $table) {
        $table->dropColumn('title');
    });

    DB::statement('ALTER TABLE `pages` CHANGE COLUMN `title_json` `title` JSON');
}

public function down()
{
    Schema::table('pages', function (Blueprint $table) {
        $table->string('title_non_json');
    });

    DB::statement('UPDATE `pages` SET title_non_json = title->>"$.en"');

    Schema::table('pages', function (Blueprint $table) {
        $table->dropColumn('title');
    });

    DB::statement('ALTER TABLE `pages` CHANGE COLUMN `title_non_json` `title` JSON');
}
```

Troubleshooting

Type error: Return value of App\Event::getTranslations() must be of the type array, null returned

A translatable column isn't a JSON column.