Jazykové soubory

Překlady jsou ve složce storage/lang/ ve formátu INI. Název souboru odpovídá ISO kódu jazyka.

storage/lang/
├── en.ini    // angličtina
├── cs.ini    // čeština
└── ...
Každý překlad musí existovat ve všech jazykových souborech. Pokud přidáte nový klíč do en.ini, musíte ho přidat i do cs.ini a všech ostatních.

Struktura INI souboru

Klíče se seskupují do sekcí (kategorií) pomocí [NázevSekce]. Konvence názvů: PascalCase pro sekce i klíče.

[System]
InputNotValid = "Input data not valid"
FormMissingItems = "Some submitted fields are missing"

[Global]
Email = "Email"
Password = "Password"
LinkConfirmButton = "Yes, continue"
LinkCancelButton = "No, cancel"
TryAgain = "Try again"

[Login]
EmailNotValid = "Entered email seems to be incorrect."
PasswordEmpty = "Please fill your password."

[Buttons]
OK = "OK"
Cancel = "Cancel"
Create = "Create"
Delete = "Delete"
Sekce [System] obsahuje frameworkové hlášky (validace, CSRF, chyby). Ostatní sekce jsou aplikační.

Použití v PHP

Globální funkce lang() je dostupná kdekoli v PHP i v Twig šablonách.

// Klíč bez sekce (hledá v kořeni)
lang('ItemLabel');

// Klíč se sekcí (Group.Key)
lang('Global.Email');          // "Email"
lang('Login.EmailNotValid');   // "Entered email seems to be incorrect."

// Jednorázově jiný jazyk
lang(['cs', 'Global.Email']);  // "Email" (z cs.ini)

V Twig šablonách

{# Překlad #}
{{ lang('Global.Email') }}

{# V atributech #}
<input placeholder="{{ lang('Global.Email') }}">

{# Podmíněný překlad #}
{% if currentLanguage() == 'cs' %}
    <span>Česky</span>
{% endif %}

Proměnné a skloňování

Proměnné

Pro dosazení proměnných se používá sprintf() a zástupné znaky %s, %d atd.

[Register]
PasswordLength = "Password needs to have at least %d characters."
sprintf(lang('Register.PasswordLength'), 8);
// "Password needs to have at least 8 characters."

Skloňování a plural

Speciální zápis {{hodnota:text||hodnota:text}}. Druhý parametr funkce lang() určuje, který variant se použije. Symbol %% se nahradí hodnotou.

Item1 = "Váš košík obsahuje %% {{1:položku||2,4:položky||5,:položek}}"
Item2 = "Číslo %% je {{,0:menší, nebo rovno 0||1,:větší, než 0}}"
Item3 = "Překlad slova %% je {{car:auto||house:dům}}"
lang('Item1', 10);       // "Váš košík obsahuje 10 položek"
lang('Item1', 1);        // "Váš košík obsahuje 1 položku"
lang('Item1', 3);        // "Váš košík obsahuje 3 položky"
lang('Item2', 2);        // "Číslo 2 je větší, než 0"
lang('Item3', 'car');    // "Překlad slova car je auto"

Překlady v JavaScriptu

JavaScript/TypeScript kód potřebuje přístup k překladům pro hlášky v UI komponentách (modaly, toasty, potvrzovací dialogy). Překlady se předávají přes globální objekt window['lang'] v head layoutu.

Registrace v head.twig

<script>
    window['lang'] = {
        {% for langName in ['Global.LinkConfirmButton', 'Global.LinkCancelButton', 'Global.TryAgain'] %}
            '{{ langName }}': "{{ lang(langName) }}",
        {% endfor %}
    };
</script>

Použití v TypeScript

// Čtení překladu
const text = window['lang']?.['Global.TryAgain'] || 'Try again';

// Příklad v komponentě
const confirmText = window['lang']?.['Global.LinkConfirmButton'] || 'OK';
Tento přístup (server-side rendering překladů do JS objektu) je standardní a používají ho i velké frameworky (Laravel, Next.js). Překlady jsou okamžitě dostupné bez dalšího AJAX volání a jsou vždy v aktuálním jazyce uživatele.
Při přidání nové hlášky do TypeScript komponenty je třeba přidat odpovídající klíč do: 1. jazykového souboru (en.ini, cs.ini), 2. pole v head.twig pro registraci do window['lang'].

Konvence

Názvy sekcíPascalCase — [Login], [Admin-Roles]
Názvy klíčůPascalCase — EmailNotValid, LinkConfirmButton
HodnotyV uvozovkách — "Text překladu"
JS přístupFormát Sekce.Klíčwindow['lang']['Global.TryAgain']