Search Documentation

Search across all documentation pages

Extending

Localization

Translate the panel into another language, load your own translations, and set the locale per user.

Every string the panel shows can be translated: buttons, messages, menu entries and the labels you give your Resources. Lathe uses the English text as the translation key and reads translations from JSON files. Without a translation, the English text shows.

How translation works

Strings pass through Lathe::__(). It looks the key up in the catalogue of the current locale and returns it, or returns the key when there is no translation:

use Lathe\Lathe;

Lathe::__('Name');                              // 'Name', or its translation
Lathe::__('Welcome, :name!', ['name' => 'Ada']); // fills the placeholder

The third argument is a default to use when the key is missing: Lathe::__('Name', [], 'Title').

Create a translation file

lathe:translate copies Lathe's English catalogue, which holds every key the panel uses, to your app:

php artisan lathe:translate es

This writes lang/vendor/lathe/es.json. Translate the values and leave the keys. Lathe finds the file on the next request. There is nothing to register. Pass --force to replace a file that exists.

To publish only the English file, run php artisan vendor:publish --tag=lathe-translations. It writes lang/vendor/lathe/en.json.

A locale can be a language (es) or a language with a region (fr-CA; fr_CA reads the same). Lathe builds the catalogue in layers: English first, then the language, then the full locale. For fr-CA it reads en, then fr, then fr-CA, and in each step the app's lang/vendor/lathe/ file overrides the package's file. A region file only needs the strings that differ from its language.

{
    "Name": "Nombre",
    "Create :resource": "Crear :resource",
    "Welcome, :name!": "¡Bienvenido, :name!",
    "Action was executed successfully.": "La acción se ejecutó correctamente."
}

Load translations from code

To read a file that Lathe does not look for, call Lathe::loadTranslations() in boot() of app/Providers/LatheServiceProvider.php. It takes a file path or an array and merges it over the catalogue:

use Lathe\Lathe;

public function boot(): void
{
    parent::boot();

    Lathe::loadTranslations(lang_path('panel/es.json'));

    Lathe::loadTranslations([
        'Name' => 'Nombre',
        'Email' => 'Correo electrónico',
    ]);
}

Translations loaded at boot apply to every request and every locale. Loaded while a panel request is served, for example in a plugin's serving(), they apply to that request only.

To work with the catalogue directly, call Lathe::translations(). It returns the Lathe\Support\TranslationManager, whose set($key, $value), has($key), get($key) and all() methods read and change the catalogue:

use Lathe\Lathe;

Lathe::translations()->set('Custom label', 'Etiqueta personalizada');

Lathe::translations()->has('Custom label'); // true

Placeholders

A :placeholder in a string is replaced by the value you pass. The casing of the token sets the casing of the value:

Token Result for john
:name john
:Name John
:NAME JOHN
Lathe::__('Welcome, :Name!', ['name' => 'john']); // Welcome, John!

When two placeholders share a prefix, such as :resource and :resources, Lathe fills the longer name first.

Set the locale of a user

By default the panel uses app()->getLocale(). To follow each user's own setting, call Lathe::userLocale() in boot() with a closure that takes the request and returns a locale:

use Illuminate\Http\Request;
use Lathe\Lathe;

public function boot(): void
{
    parent::boot();

    Lathe::userLocale(fn (Request $request) => $request->user()?->locale);
}

A null or empty answer falls back to the app locale. Lathe sets the app locale to the answer for the panel request, uses it to pick the catalogue, and sends it to the browser, where dates and numbers use it for their format. Return a tag the browser knows, such as en-US or de-DE, when the format matters.

For languages written right to left, see Lathe::enableRTL() in Layout.

Translate your Resources

Strings you write in PHP are not translated until you pass them through Lathe::__().

Resource labels. Override label() and singularLabel() on the Resource:

use Lathe\Lathe;

public static function label(): string
{
    return Lathe::__('Posts');
}

public static function singularLabel(): string
{
    return Lathe::__('Post');
}

Button labels. createButtonLabel() and updateButtonLabel() return "Create :resource" and "Update :resource" through the catalogue already. Translate those two keys in the JSON file, or override the methods:

public static function createButtonLabel(): string
{
    return Lathe::__('Publish Post');
}

Fields and relations. Pass a translated label as the first argument:

Field::text(Lathe::__('Email Address'), 'email_address')
Field::hasMany(Lathe::__('Posts'), 'posts')

Filters, lenses and actions. Override name():

public function name(): string
{
    return Lathe::__('User Type');
}

Then add the English text and its translation to the JSON file:

{
    "Post": "Publicación",
    "Posts": "Publicaciones",
    "User Type": "Tipo de usuario"
}

Translations in the browser

The panel sends the catalogue of the current locale to the browser with the page. A component reads it with useTranslation() from @lathephp/core, so a string you translate in PHP is also translated in your React code:

import { useTranslation } from '@lathephp/core';

const { __ } = useTranslation();

__('Order #:id is on hold.', { id: 12 });

Pass the English text as the key. See Extension API.

Translations in plugins

A plugin loads its translations in boot(), which runs once:

use Lathe\Lathe;

public function boot(): void
{
    parent::boot();

    Lathe::loadTranslations([
        'Heartbeat OK' => 'Heartbeat correcto',
        'Heartbeat failed' => 'Heartbeat fallido',
    ]);
}

Load a whole file the same way, with Lathe::loadTranslations(__DIR__.'/../lang/es.json'). Keep serving() for state that depends on the request.

What you see

After php artisan lathe:translate es and a user whose locale is es, the panel shows the Spanish text for each key you translated, and the English text for each key you left out. A Resource with label() wrapped in Lathe::__() shows its translated name in the sidebar and headings.