Symfony po krůčkách – Translation – překlady jednoduše

V tomto díle si ukážeme, jak použít pro překlady textů Symfony komponentu Translation. Ta umožňuje pracovat s překlady uloženými v různých formátech. To může usnadnit výměnu textů s překladatelem nebo externím API. Hodí se ale i k zobrazení různých textů v závislosti na počtu (1 jablko, 5 jablek).

Seriál: Symfony po krůčkách (18 dílů)

  1. Symfony po krůčkách – Event Dispatcher 30.11.2015
  2. Symfony Console jako první rande se Symfony 7.12.2015
  3. Symfony po krůčkách – Filesystem a Finder 14.12.2015
  4. Symfony po krůčkách – Paralýza možností? OptionsResolver tě zachrání 21.12.2015
  5. Symfony po krůčkách – spouštíme procesy 4.1.2016
  6. Symfony po krůčkách – Translation – překlady jednoduše 11.1.2016
  7. Symfony po krůčkách – Validator (1) 18.1.2016
  8. Symfony po krůčkách – Validator (2) 25.1.2016
  9. Symfony po krůčkách – Routing 1.2.2016
  10. Symfony po krůčkách – MicroKernel 9.2.2016
  11. Konfigurujeme Symfony pomocí YAMLu 16.2.2016
  12. Symfony po krůčkách – oblékáme MicroKernel 23.2.2016
  13. Symfony po krůčkách – ClassLoader 29.2.2016
  14. Symfony po krůčkách – Twig 8.3.2016
  15. Symfony po krůčkách – Twig II. 15.3.2016
  16. Symfony po krůčkách – DomCrawler a CssSelector 23.3.2016
  17. Symfony po krůčkách – HTTP fundamentalista 12.4.2016
  18. Symfony po krůčkách – ušli jsme pořádný kus 19.4.2016

Příklad na začátek

Celý princip práce s překladačem je velmi jednoduchý. Pro každý jazyk, se kterým chceme pracovat, naplníme Translator našimi překlady – to je jen seznam klíčů a jejich hodnot. Klíč určuje řetězec, ke kterému hledáme překlad, hodnota jeho překlad. Odpovídající překlady pro různé jazyky jsou uloženy pod stejným klíčem. Pak už se jen Translatoru ptáme na překlady pro konkrétní klíč a jazyk.

Komponentu nainstalujeme jednoduše přes Composer:

composer require symfony/translation

A použijeme v jednoduchém skriptu:

<?php

use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Translator;

require_once __DIR__. '/vendor/autoload.php';

$translator = new Translator('cs_CZ');

$translator->addLoader('array', new ArrayLoader());

$translator->addResource('array', [
 'Hello world!' => 'Ahoj světe!',
], 'cs_CZ');

echo $translator->trans('Hello world!');

Po spuštění se vypíše Ahoj světe!. Rozebereme si, co se v ukázce děje:

Translatoru určíme jazyk

Nejdříve vytváříme objekt třídy Translator. Tomu musíme předat v parametru locale určující výchozí jazyk, do kterého chceme překládat.

Doporučený formát locale je dvoupísmený kod jazyka podle ISO 639-1 následovaný podtržítkem a dvoupísmenným kódem státu podle ISO 3166-1.

Nastavíme loader

V dalším kroku se přidává instance třídy Loaderu. Loader umí načítat zdroje překladů v určitém formátu, tady pro "array".

Přidáme zdroje

Metoda addResource() přidává zdroj překladů. V tomto případě je to pole s jedním prvkem. Posledním argumentem říkáme, že texty jsou v češtině – v jednom zdroji jsou překlady vždy jen pro jeden jazyk.

Překládáme

Teď už můžeme na překladači zavolat metodu trans(), které předáme překládaný řetězec a dostaneme zpět jeho překlad. Pokud by se stalo, že by překlad neexistoval, vrátí se řetězec předávaný v argumentu.

Locale můžeme předat i metodě trans() jako čtvrtý argument a vynutit si tak překlad do jiného jazyka:

$translator->trans('Hello world!', [], null, 'en_EN');

Překládat původní text nebo zástupné klíče?

V úvodním příkladu vytváříme překladový slovník, kde klíčem překladu je přímo původní text v angličtině ('Hello world!') a ten se pak předává i metodě trans().

Druhá možnost je místo původního textu použít zástupný klíč, který by měl vyjadřovat obsah překladu. Zdrojový jazyk, v tomto případě angličtinu, je potřeba pak přidat jako další jazyk.

$translator->addResource('array', [
   'hello.world' => 'Ahoj světe!',
], 'cs_CZ');

$translator->addResource('array', [
   'hello.world' => 'Hello world!',
], 'en_EN');

echo $translator->trans('hello.world');

// “Ahoj světe!”

Použití klíčů má několik výhod:

  • Když se mírně změní překládaný zdrojový text, jeho klíč zůstane stejný i ve všech dalších překladech.
  • U dlouhých textů může být klíč také kratší.
  • Pokud budou překlady uložené v YAMLu, je možné je zanořovat. (Ukážeme si dále.)

Častěji bývá doporučován a používán právě způsob se zástupnými klíči. Volba je ale jen na vás.

Proměnné v překladech

Někdy je do překládaných textů potřeba vložit hodnotu dynamicky. K tomu účelu se do překládaného řetězce vkládají placeholdery a metodě trans() se předává pole náhrad:

$name = 'Zdroják';

echo $translator->trans(
   'Hello %name%',
   ['%name%' => $name]
);

// "Hello Zdroják"

Doporučuje se placeholder ohraničit znaky procenta, může mít ale libovolný formát.

Další způsoby načítání překladů

V příkladu jsme předali texty přímo v poli a k jejich zpracování použili ArrayLoader. Často jsou ale překlady připravovány profesionálními překladateli, kterým chceme dát seznam překladů v jiném formátu. Přímo s komponentou máte na výběr z dalších loaderů – CSV, Xliff, Php, Yaml, Po… Celý seznam naleznete v dokumentaci.

Oblíbeným formátem pro uchovávání překladů bývá YAML. Ten aktivujeme pomocí:

composer require symfony/yaml

YAML umožňuje zanořovat klíče:

#messages.cs.yml
greetings:
  hello: 'Ahoj'
  good:
    morning: 'Dobré ráno'
    afternoon: 'Dobré odpoledne'
    evening: 'Dobrý večer'

Použít překlady z YAML souboru pak můžeme takto:

use \Symfony\Component\Translation\Loader\YamlFileLoader;

$translator->addLoader('yaml', new YamlFileLoader());
$translator->addResource('yaml', 'messages.cs.yml', 'cs_CZ')

echo $translator->trans('greetings.good.morning')

// "Dobré ráno"

Domény – dělení do skupin

Překladové soubory jsou organizovány podle jednotlivých locales, které překládají. Další členění může být na “domény”. Můžeme tak oddělit překlady validačních hlášek, chyb nebo třeba administračního rozhraní do samostatných souborů.

Doména se předává jako 4. argument metodě addResource(). Výchozí hodnota je 'messages'.

$translator->addResource('yaml', 'messages.cs.yml', 'cs_CZ')
$translator->addResource('yaml', 'admin.cs.yml', 'cs_CZ', 'admin')

Překlad s použitím domény pak vypadá takto:

$translator->trans('Přidat nový záznam', [], 'admin');

Fallback překlady

Pokud není klíč překladu nalezen v seznamu překladů pro daný jazyk, lze určit pořadí dalších jazyků, které se mají brát jako náhrada.

Pokud chceme překlad pro 'cs_CZ' locale, hledá se v tomto pořadí:

  1. Překlad pro 'cs_CZ' locale
  2. Pokud není nalezen, hledá se v 'cs' locale
  3. Pokud není stále nalezen, hledá se ve fallback locale, které musí být explicitně nastaveno a může jich být více:
$translator->setFallbackLocales(['en']);

1 jablko, 5 jablek

V češtině jsou různé tvary podstatného jména pro “jeden”, “dva až čtyři” a “žádný nebo pět a více”. V angličtině jsou různé tvary jen dva – pro “jeden” a “žádný nebo více než jeden”. V jiných jazycích mohou být pravidla i složitější. Translation komponenta má podporu pro výběr vhodného tvaru ze zadaných možností.

V překladech je možné zadat více tvarů, oddělených znakem |:

‘You have 1 mail|You have %count% mails’

Místo metody trans() se pak používá metoda transChoice():

echo $translator->transChoice(
   ‘You have 1 mail|You have %count% mails’,
   10,
   ['%count%' => 10]
);

// “You have 10 mails”

Druhý argument v příkladu výše je počet, podle kterého se zvolí vhodný překlad. Počet se v překladu nahrazuje přes placeholder "%count%".

Každé locale má vlastní pravidla, podle kterých se vybírá vhodná forma. Pro češtinu může překladový řetězec vypadat takto:

echo $translator->transChoice(
   'Máte 1 zprávu|Máte %count% zprávy|Máte %count% zpráv',
   10,
   ['%count%' => 10],
   null,
   'cs'
);

// “Máte 10 zpráv”

Profi intervaly

Někdy můžeme chtít vybrat různý text pro konkrétní počet, například pro “0”. Pro takové případy je možné uvést přímo intervaly čísel, pro které se má zvolit která zpráva:

'{0} Nemáte žádnou zprávu|{1} Máte jednu zprávu|]1,19] Máte několik zpráv|[20,Inf[ Máte moc zpráv'

Přístupy lze i kombinovat. V případě, že pro počet nelze vybrat konkrétní interval, berou se standardní pravidla po odstranění intervalových:

'{0} Nemáte žádnou zprávu|[1000,Inf[ Máte hodně moc zpráv|Máte 1 zprávu|Máte %count% zprávy|Máte %count% zpráv'

Interval může být konečný seznam čísel:

{1,2,3,4}

Nebo interval mezi dvěma čísly:

[1, +Inf[
]-1,2[

Jako v matematice může být interval zleva uzavřený [ nebo otevřený ], a zprava uzavřený ] nebo otevřený [. Kromě čísel jde použít i -Inf a +Inf pro nekonečno.

Zase o krok dále

Dnes jsme si ukázali komponetu, která nám pomůže:

  • překládát pro různé jazyky
  • načítat různé typy překladových souborů
  • počítá s množnými čísly
  • jak využít intervaly pro hlášku na míru

Kam jít dál?

Víc si o Translation komponentě můžete přečist v oficiální dokumentaci.

Do Nette existuje integrace komponenty v Kdyby/Translation od Filipa Procházky. Ve full-stack Symfony frameworku jsou překlady integrované a rozšířené ještě o další nástroje. To si ukážeme v některém z dalších dílů.

Už v Symfony děláš léta a chceš posdílet zkušenosti?

Nebo tě Symfony zatím jen láká a rád by se o něm dozvěděl více? Přijd si pokecat na pravidelné měsíční srazy v Praze, Brně a Ostravě.

Komentáře: 2

Přehled komentářů

Luděk Benedík
Milan Krupa
Zdroj: https://www.zdrojak.cz/?p=17071