Lokalizace - Jet\Locale

Možnost vytvářet projekty v různých lokalizacích (tedy určené pro více jazyků a také regionů/zemí/států) je jeden z důležitých rysů a základních vlastností platformy Jet. Vychází to z faktu, že takových projektů jsem na své pracovní cestě "potkal" celou řadu. A získal jsem tak poznatky díky úspěchům, ale i neúspěchům a chybám, či slepým uličkám. Proto je tento rys tak důležitý a prolíná se celým systémem. Je to jeden ze základních kamenů MVC, ale lokalizace je dokonce samostatný datový typ v ORM DataModel. Proto toto téma zařazuji jako jednu z prvních kapitol. Ale dost řečí ... Jde se na věc.

Lokalizace? Proč ne jazyk, nebo jazyková mutace?

Proč nepoužívám jednoduše termín jazyková mutace, jazyk, či tak podobně? V úvodu jsem zmínil nezdary a to ne náhodou. Jeden z těch nezdarů byl právě o tom, že jsem si myslel, že rozlišení podle jazyka bude stačit a postavil tak CMS. Má naivita byla potrestána a vyléčena velice záhy. Přišel projekt, který v sobě zahrnoval spoustu zemí a spoustu jazykových mutací. Obsah měl být do značné míry propojen a sdílen. Radoval jsem se jak jsme na takový projekt připraveni. Až jsme narazili na takovou "drobnost". Že ani ta němčina v Rakousku není úplně stejná němčina jako v Německu ... O americké a britské angličtině ani nemluvím. A pak tu máme běžně země, kde nepoužívá jeden jazyk, ale dva a více. Švýcarsko, Belgie, Kanada ... A ostatně i naše bývalé Československo ... 
Vázat něco čistě jen na nějaký jazyk prostě nestačí. Jazyk není jeden a nejde jen o jazyk. Jde i o zobrazování čísel, cen, datumů a časů ... Prostě je to téma samo o sobě. Takto už je to zřejmé, že? Mě to ale před lety prostě nedošlo ... Ale teď už to vím. Proto Jet používá striktně pojem lokalizace a pracuje s entitou Locale.

Jak vypadá Locale v Jet?

Nic zvláštního ... Jde o identifikátor používaný ICU. Jedná se o řetězec složený ze dvou kódů oddělených znakem "_". 

Například naše: cs_CZ

První kód je ISO 639 kód pro jazyk (cs - čeština)

Druhý kód je ISO 3166 kód pro zemi (CZ - Česká republika / Česko)

Pozor! Ve skutečnosti v rámci tohoto kódu může být ještě víc informací. Týká se např. čínštiny a podobně. Po pravdě jsem tento aspekt v praxi ještě nepoužil, ale je to jeden z důvodů, proč se v systému nepoužívá kód v podobě textového řetězce, ale instance třídy Jet\Locale. To je velice důležité! Jakmile někam předáváte Locale, nepracujete s textem, ale instancí této třídy. Do budoucna předpokládám, že se Jet\Locale ještě rozšíří na základě praktických poznatků - třeba právě poznatků od vás - kolegyň a kolegů. Ale základem je mít v aplikaci pevně daný řád a systém a ten systém říká, že se používá kód lokalizace dle ISO norem, ale vždy ve formě instance Jet\Locale. 

Třída Jet\Locale

Jak už víte, tak v systému se nepoužívá kód lokalizace ve formě textového řetězce, ale vše co s lokalizací pracuje očekává instanci této třídy. Je to tedy sice relativně malá, osamocená, ale o to důležitější třída. Pojďme se na ní kouknout. Co je jejím určením?

  • Její instance představuje informaci o konkrétní lokalizaci. Tedy instance této třídy se všude používá jako primární identifikátor lokalizace.
  • Jedná se také o fasádu nad řadou funkcí již integrovaných v samotném PHP.
  • Umožňuje pohodlně formátovat čísla, časové údaje a ceny.
  • Umožňuje pracovat s lokalizací jako takovou. Například získat přesný název dané lokalizace a to třeba i v jiné lokalizaci (viz dále)

A nyní se již podívejme na třídu samotnou. Metody si rozdělíme podle toho zda jsou určené pro všeobecné použití (to budou metody statické) a metody vztahující se ke konkrétní lokalizaci - nestatické.

Nestatické metody - práce s konkrétní lokalizací

Metoda Význam
public __construct(
string|null $locale = null
)
Jako parametr konstruktoru může být (a v praxi většinou je) předán textový kód lokalizace dle ISO norem. Tedy např. "cs_CZ", ale samozřejmě jakýkoliv jiný. Pokud je tomu tak, pak je tento kód automaticky rozparsován a objekt je nastaven.

K parsování je využita metoda public static \Locale::parseLocale(string $locale): ?array samotného PHP.

Jak již bylo uvedeno, tak třída Jet\Locale představuje fasádu nad věcmi, které PHP již standardně obsahuje. Konkrétně jde o modul Intl. Ten je již od dávných dob PHP5.3 brán jako standardní a tedy se s ním prostě počítá. 
public getRegion(
): string
Vrátí dvoumístný kód regionu (nebo chcete-li země) dle ISO 3166.
public getLanguage(
): string
Vrátí kód jazyka dle ISO 639
public getName(
Locale|null $in_locale = null
): string
Vrátí pro koncového uživatele čitelný celý název lokalizace. 

Tedy například "čeština (Česko)" pro lokalizaci cs_CZ.

Parametr $in_locale určuje v jaké lokalizaci má být název vrácen. 
Tedy je možné získat název lokalizace cs_CZ ovšem čitelný pro USA, tedy pro lokalizaci en_US. Pak metoda vrátí: "Czech (Czechia)"

Pokud parametr není zadán, pak je použita aktuální lokalizace.
public getLanguageName(
Locale|null $in_locale = null
): string
Vrátí pro koncového uživatele čitelný celý název jazyka. 

Tedy například "čeština" pro cs_CZ.

Parametr $in_locale určuje v jaké lokalizaci má být název vrácen. 
Tedy je možné získat název jazyka cs_CZ ovšem čitelný pro USA, tedy pro lokalizaci en_US. Pak metoda vrátí: "Czech"

Pokud parametr není zadán, pak je použita aktuální lokalizace.
public getRegionName(
Locale|null $in_locale = null
): string
Vrátí pro koncového uživatele čitelný celý název země - regionu. 

Tedy například "Česko" pro cs_CZ.

Parametr $in_locale určuje v jaké lokalizaci má být název vrácen. 
Tedy je možné získat název jazyka cs_CZ ovšem čitelný pro USA, tedy pro lokalizaci en_US. Pak metoda vrátí: "Czechia"

Pokud parametr není zadán, pak je použita aktuální lokalizace.
public getTimeZone(
): string
Vrací kód časové zóny.

Pozor! Hodnota není nastavena například konstruktorem. Jaká bude použita časová zóna pro danou lokalizaci záleží na vás a na situaci. Nemusí totiž vždy platit, že použitá lokalizace = časová zóna. Navíc velké země jsou v několika časových zónách. Tedy časová zóna není žádná jednoznačná věc.

Jako výchozí je vzata ta časová zóna, kterou má jako výchozí nastaveno PHP, potažmo server. Ovšem například v inicializeru při použití MVC můžete aktuální lokalizaci nastavit časovou zónu dle vašich potřeb.
public setTimeZone(
string $time_zone
): void
Nastavuje lokalizaci časovou zónu. Více viz předchozí metoda getTimeZone.
public getCalendar(
): int
Vrací číslo použitého kalendáře. Výchozí je gregoriánský kalendář.

Ale situace je analogická s časovou zónou. Tedy jaký bude použit kalendář záleží na mnoha faktorech, konkrétním projektu, konkrétní situaci a konkrétní aplikaci. 
Tedy stejně jako u časové zóny je možné si kalendář nastavit (viz metoda getTimeZone )

Typy kalendářů jsou Jet\Locale::CALENDAR_GREGORIAN a Jet\Locale::CALENDAR_TRADITIONAL, ale jedná se opět o fasádu nad PHP.
public setCalendar(
int $calendar
): void
Nastavuje použitý kalendář. Více viz předchozí metoda getCalendar.
public getLocale(): string S lokalizací je pochopitelně někde nutné pracovat opět jako s řetězcem. Například při ukládání tohoto údaje - ať už do databáze, nebo do souboru. 
Za tímto účelem tyto metody vrací textový kód lokalizace. Instanci Jet\Locale tedy lze přetypovat na string.
public __toString(): string
public toString(): string
public formatDate(
?Data_DateTime $date_and_time,
int $format = self::DATE_TIME_FORMAT_MEDIUM
): string
Vrátí datum naformátované dle zvyklostí platných pro danou lokalizaci.

Možné formáty viz konstanty.
public formatDateAndTime(
?Data_DateTime $date_and_time,
int $date_format = self::DATE_TIME_FORMAT_MEDIUM,
int $time_format = self::DATE_TIME_FORMAT_SHORT
): string
Vrátí datum a čas naformátovaný dle zvyklostí platných pro danou lokalizaci.

Možné formáty viz konstanty.
public formatTime(
?Data_DateTime $date_and_time,
int $time_format = self::DATE_TIME_FORMAT_SHORT
): string
Vrátí čas naformátovaný dle zvyklostí platných pro danou lokalizaci.

Možné formáty viz konstanty.
public formatInt(
int $number
): string
Vrátí celé číslo naformátované dle zvyklostí platných pro danou lokalizaci.
public formatFloat(
float $number,
int $min_fraction_digits = 0,
int $max_fraction_digits = 2
): string
Vrátí desetinné číslo naformátované dle zvyklostí platných pro danou lokalizaci.

Je možné určit minimální a maximální počet desetinných míst.
public formatSize(
int $bytes,
string $unit = 'iB',
int $max_places = 2,
string $glue = ' '
): string
Vrátí údaj o datovém objemu (např. velikosti souboru) naformátovaný dle zvyklostí platných pro danou lokalizaci.
public formatCurrency(
float|int $value,
string $currency
) : string
Vrátí částku naformátovanou dle zvyklostí platných pro danou lokalizaci a v dané měně. 

Měna je určena kóden dle ISO 4217.

(Měna také není pevně navázána na lokalizaci)
public getCurrencyFormatter(
string $currency
): \NumberFormatter
Vrátí instanci PHP třídy \NumberFormatter inicializovanou tak, aby byla připravena naformátovat čísla v dané lokalizaci a měně.

Měna je určena kóden dle ISO 4217.

Statické metody - obecné

Metoda Význam
public static getCurrentLocale(
): Locale
Vrátí instanci aktuálně platné (momentálně nastavené) lokalizace.
public static setCurrentLocale(
Locale $current_locale
): void
Nastaví aktuálně platnou lokalizaci.

Pokud budete používat Jet MVC, tak toto router udělá za vás.

V opačném případě (pokud nepoužijete Jet MVC) je pochopitelně potřeba si aktuální Locale nastavit.
public static date(
?Data_DateTime $date_and_time,
int $format = self::DATE_TIME_FORMAT_MEDIUM
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatDate$date_and_time$format );
Stačí tedy: Locale::date$date_and_time$format );
public static dateAndTime(
?Data_DateTime $date_and_time,
int $date_format = self::DATE_TIME_FORMAT_MEDIUM,
int $time_format = self::DATE_TIME_FORMAT_SHORT
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatDateAndTime$date_and_time$date_format$time_format );
Stačí tedy: Locale::dateAndTime$date_and_time$date_format$time_format );
public static time(
?Data_DateTime $date_and_time,
int $time_format = self::DATE_TIME_FORMAT_SHORT
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatTime$date_and_time$time_format );
Stačí tedy: Locale::dateAndTime$date_and_time$time_format );
public static int(
int $number
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatInt$number );
Stačí tedy: Locale::int$number );
public static float(
float $number,
int $min_fraction_digits = 0,
int $max_fraction_digits = 2
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatFloat$number$min_fraction_digits$max_fraction_digits );
Stačí tedy: Locale::float $number$min_fraction_digits$max_fraction_digits  );
public static size(
int $bytes, string $unit = 'iB',
int $max_places = 2,
string $glue = ' '
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatSize$bytes$unit$max_places$glue );
Stačí tedy: Locale::size( $bytes$unit$max_places$glue );
public static currency(
float|int $value,
string $currency
): string
Jedná se o zkratku pro: Locale::getCurrentLocale()->formatCurrency$value$currency );
Stačí tedy: Locale::currency( $value$currency );
public static getAllLocalesList
null|Locale $in_locale = null 
) : array
Vrátí všechny známé lokalizace, respektive jejich názvy.

Výstupem je pole, kde klíč je kód lokalizace a hodnota je název lokalizace.

Parametrem $in_locale lze určit v jaké lokalizaci budou názvy lokalizací. Výchozí je aktuální lokalizace.

Konstanty

Konstanta Význam
Jet\Locale::CALENDAR_GREGORIAN Odpovídá PHP konstaně \IntlDateFormatter::GREGORIAN
Jet\Locale::CALENDAR_TRADITIONAL Odpovídá PHP konstaně \IntlDateFormatter::TRADITIONAL
Jet\Locale::DATE_TIME_FORMAT_SHORT Odpovídá PHP konstaně \IntlDateFormatter::SHORT
Jet\Locale::DATE_TIME_FORMAT_MEDIUM Odpovídá PHP konstaně \IntlDateFormatter::MEDIUM
Jet\Locale::DATE_TIME_FORMAT_LONG Odpovídá PHP konstaně \IntlDateFormatter::LONG
Jet\Locale::DATE_TIME_FORMAT_FULL Odpovídá PHP konstaně \IntlDateFormatter::FULL
Předchozí kapitola
Jet\Debug_Profiler_Run_BacktraceItem
Další kapitola
MVC - obecně