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 |
| Hodnoty | V uvozovkách — "Text překladu" |
| JS přístup | Formát Sekce.Klíč — window['lang']['Global.TryAgain'] |
