Internacionalizace pomocí @angular/localize
Na poli i18n došlo k velkému pokroku!V Angularu 9.0 byl zaveden nový balíček @angular/localize
.
Pod kapotou nám poskytuje stejné funkce jako dříve:překlady v šablonách při kompilaci.
Dovoluje nám však doufat, že v budoucnu budeme mít k dispozici více nedokumentovaných funkcí,jako jsou překlady v kódu nebo překlady za běhu namísto překladů pouze při kompilaci 😎.
Začněme tím, že se podíváme, co můžeme dělat s pomocí @angular/localize
a CLI ve verzi v9.
i18n v šablonách
Nový balíček @angular/localize
nabízí funkci s názvem $localize
.
Stávající podpora i18n v Angularu nyní používá $localize
,což znamená, že šablony jako:
<h1 i18n>Hello</h1>
budou zkompilovány na volání $localize
.
Pokud spustíte ng serve
s takovou šablonou,narazíte na chybu při spuštění:
Error: It looks like your application or one of its dependencies is using i18n.Angular 9 introduced a global `$localize()` function that needs to be loaded.Please run `ng add @angular/localize` from the Angular CLI.(For non-CLI projects, add `import '@angular/localize/init';` to your `polyfills.ts` file.For server-side rendering applications add the import to your `main.server.ts` file.)
Chybu lze vysvětlit:protože atributy i18n
jsou nyní ve vygenerovaném kódu převedeny na volání $localize
,musíme načíst funkci $localize
.Mohlo by to být provedeno ve výchozím nastavení,ale protože je to vyžadováno pouze v případě, že používáte internacionalizaci,nemělo by to skutečný smysl.
Proto pokud vaše aplikace nebo některá z jejích závislostí používá ve svých šablonách atributy i18n
, pak budete muset do svých polyfillů přidat import '@angular/localize/init'
!
CLI nabízí schéma, které to udělá za vás.Stačí spustit:
ng add @angular/localize
a CLI přidá balíček do vašich závislostí a potřebný import do vašich polyfillů.
Poté, když spustíte svou aplikaci s jednoduchým ng serve
,$localize
jednoduše zobrazí původní zprávu.
Teď jak tyto zprávy přeložíte?
Postup je velmi podobný tomu, který jsme měli dříve.Nejprve spustíte ng xi18n
, abyste zprávy vyextrahovali do souboru messages.xlf
. poté soubor přeložíte pro své lokality, například messages.fr.xlf
a messages.es.xlf
.
Poté musíte nakonfigurovat CLI, v angular.json
{ "projects": { "ponyracer": { "projectType": "application", // ... "i18n": { "locales": { "fr": "src/locale/messages.fr.xlf", "es": "src/locale/messages.es.xlf", } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", // ... "configurations": { "production": { // ... }, "fr": { "localize": }, "es": { "localize": } } }, "serve": { // ... "configurations": { "production": { // ... }, "fr": { "browserTarget": "ponyracer:build:fr" }, "es": { "browserTarget": "ponyracer:build:es" } } } // ...}
Nyní konfigurace es
nebo fr
umožní spustit:
ng serve --configuration=fr
A obsluhovaná aplikace je nyní ve francouzštině!
Můžete také sestavit aplikaci s konkrétním locale:
ng build --configuration=production,es
nebo se všemi locales najednou:
ng build --prod --localize
To je velký pokrok oproti předchozím verzím Angularu. dříve jsme museli sestavovat stejnou aplikaci pro každé locale, protože překlad byl součástí kompilace.Nyní Angular při kompilaci aplikace generuje volání $localize
. když je to hotovo, nástroj vezme zkompilovanou aplikacia nahradí všechna volání $localize
správnými překlady. to je superrychlé. pak máte balíček, který neobsahuje žádná volání $localize
a všechny řetězce i18n byly přeloženy.
Dosud jste museli sestavit aplikaci jednou pro každé locale, a to bylo úplné sestavení. Takže řekněme, že to bylo 30s sestavení,a chtěli jste 4 lokality, pak jste byli na 2 minuty.
S novým přístupem se kompilace provede jednou,a pak se různé verze i18n vygenerují během několika sekund(dokonce se generují paralelně, pokud je to možné).takže se dostanete ze 2 minut na ~40 sekund! 🌈
Máte pak několik balíčků, jeden pro každou lokalizaci, a můžete uživatelům servírovat příslušný podle jejich preferencí, jak jste byli zvyklí.
Této strategii se říká compile-time inliningas, kdy překlady inlinujete přímo, a za běhu už pak není co řešit.
Teď si povíme o něčem zatím nedokumentovaném,co se možná v budoucnu změní,ale přesto je zajímavé to vědět:zprávy nyní můžeme překládat i v našem kódu TypeScriptu!
Funkci $localize
, o které jsem mluvil, můžeme použít přímo. Je to zvláštní funkce, kterou můžete použít k označení šablonového řetězce pro lokalizaci.
Ale možná bychom měli začít tím, že si vysvětlíme, co je to označený šablonový řetězec?
Šablonové řetězce a značkovací funkce
Při použití šablonových řetězců můžete definovat značkovací funkci,a použít ji na šablonový řetězec.zde askQuestion
přidá na konec řetězce dotazovací bod:
const askQuestion = strings => strings + '?';const template = askQuestion`Is anyone here`;
Takže jaký je rozdíl oproti jednoduché funkci?Funkce značky ve skutečnosti přijímá několik argumentů:
- pole statických částí řetězce
- hodnoty vyplývající z vyhodnocení výrazů
Pokud máme například šablonu řetězceobsahující výrazy:
const person1 = 'Cedric';const person2 = 'Agnes';const template = `Hello ${person1}! Where is ${person2}?`;
tak funkce značky obdrží různé statické a dynamické části.Zde máme funkci tagu pro psaní velkých písmen ve jménech protagonistů:
const uppercaseNames = (strings, ...values) => { // `strings` is an array with the static parts // `values` is an array with the evaluated expressions const names = values.map(name => name.toUpperCase()); // `names` now has // let's merge the `strings` and `names` arrays return strings.map((string, i) => `${string}${names ? names : ''}`).join('');};const result = uppercaseNames`Hello ${person1}! Where is ${person2}?`;// returns 'Hello CEDRIC! Where is AGNES?'
i18n s $localize v kódu TypeScript
$localize
používá tuto mechaniku, abychom mohli napsat:
@Component({ template: '{{ title }}'})export class HomeComponent { title = $localize`You have 10 users`;}
Všimněte si, že funkci nemusíte importovat.Pokud jednou přidáte import '@angular/localize/init'
do své aplikace,$localize
se přidá do globálního objektu.
Zprávu pak můžete přeložit stejným způsobem jako v případě šablony. v současné době (v9.0.0) však CLI tyto zprávy nevytahuje příkazem xi18n
, jako je tomu u šablon.
Pokud aplikaci obsluhujete a nenajdete žádný překlad, $localize
jednoduše zobrazí původní řetězec a do konzoly zaznamená varování:
No translation found for "6480943972743237078" ("You have 10 users").
Takže ho musíte ručně přidat do svého messages.fr.xlf
s daným IDpokud to chcete zkusit:
<trans-unit> <source>You have 10 users</source> <target>Vous avez 10 utilisateurs</target></trans-unit>
Šablona mého HomeComponent
pak zobrazí Vous avez 10 utilisateurs
!
Co se stane, když máte v řetězci šablony nějaký dynamický výraz?
title = $localize`Hi ${this.name}! You have ${this.users.length} users.`;
Výrazy se automaticky pojmenují PH
a PH_1
(PH
je pro zástupný symbol).Tyto zástupné znaky pak můžete použít kdekoli v překladech:
<trans-unit> <source>Hi <x/>! You have <x/> users.</source> <target>Bonjour <x/> ! Vous avez <x/> utilisateurs.</target></trans-unit>
Nejlepší je však dát výrazu smysluplné jméno zástupného znaku sám,a to můžete udělat pomocí syntaxe ${expression}:placeholder:
.
title = $localize`Hi ${this.name}:name:! You have ${this.users.length}:userCount: users.`;
Tento zástupný název pak můžete použít kdekoli v překladech:
<trans-unit> <source>Hi <x/>! You have <x/> users.</source> <target>Bonjour <x/> ! Vous avez <x/> utilisateurs.</target></trans-unit>
Vlastní ID
Všimněte si, že pokud máte překlady s vlastními ID,použijí se pomocí $localize
(jako tomu bylo dříve):
<h1 i18n="@@home.greetings">Hello</h1>
Pak váš překlad vypadá takto:
<trans-unit> <source>Hello</source> <target>Bonjour</target></trans-unit>
což je samozřejmě příjemnější k použití.
A co pro překlady v kódu?“$localize
rozumí také syntaxi umožňující zadat ID:
title = $localize`:@@home.users:You have 10 users`;
Syntaxe pro vlastní ID je stejná jako v šablonách,a ID je obklopeno dvojtečkami, aby bylo odděleno od obsahu překladu.
Stejně jako u syntaxe šablony můžete také zadat popis a význam,abyste překladateli pomohli s trochou kontextu: :meaning|description@@id:message
.
Například:
title = $localize`:greeting message with the number of users currently logged in@@home.users:You have 10 users`;
Mějte na paměti, že se jedná o nízkoúrovňové, nedokumentované API. tým nebo komunita Angularu pravděpodobně nabídne funkce vyšší úrovněs lepšími zkušenostmi pro vývojáře (no, doufám v to!). locl od Oliviera Combeho, autora ngx-translate, asi stojí za to sledovat 🧐.
Překlady za běhu
Jak už jsem se zmínil,pokud používáte výše uvedené příkazy CLI (ng serve --configuration=fr
nebo ng build --localize
), pak je aplikace zkompilována a poté přeloženapředtím, než se dostane do prohlížeče, takže za běhu nedochází k žádnému volání $localize
.
Ale $localize
byl navržen tak, aby nabízel další možnost:překlady za běhu. co to znamená? No, mohli bychom dodat pouze jednu aplikaci, která by obsahovala volání $localize
, a před spuštěním aplikace bychom mohli načíst požadované překlady. už žádné N sestavení a N balíčků pro N lokalit \o/
Aniž bychom zabíhali do detailů, je to možné už ve v9, a to pomocí funkce loadTranslations
, kterou nabízí @angular/localize
.To je však třeba provést před spuštěním aplikace.
Překlady můžete načíst v polyfills.ts
pomocí:
import '@angular/localize/init';import { loadTranslations } from '@angular/localize';loadTranslations({ '1815172606781074132': 'Bonjour {$name}\xa0! Vous avez {$userCount} utilisateurs.'});
Jak vidíte, není třeba brát ohled na locale:prostě načtete překlad jako objekt,jehož klíče jsou řetězce k překladu a hodnoty jejich překlady.
Nyní, když spustíte jednoduchý ng serve
,nadpis se zobrazí ve francouzštině! a už není potřeba ng xi18n
, ani messages.fr.xlf
nebo specifická konfigurace pro každé locale v angular.json
. v dlouhodobém horizontu, až to bude řádně podporováno a zdokumentováno,bychom měli být schopni načítat JSON soubory za běhu,jako to dělá většina i18n knihoven.Toho by se dalo dosáhnout i ve v9, jen je to trochu ruční práce,ale je to proveditelné.
A co potom změna locale za běhu?Můžeme načíst další sadu překladů při spuštění aplikace?No, ne. Současný způsob generování volání $localize
znemožňuje jejich následnou změnu: musíte aplikaci restartovat. ale pokud vám nevadí obnovení prohlížeče, je to možné. vyzkoušel jsem jednoduchou strategii, která funguje:
- uživatel vybere nový jazyk (například španělštinu).
- jazyk uložíme do prohlížeče (například do localStorage)
- znovu načteme stránku, čímž se aplikace restartuje
- v
polyfills.ts
začneme načítáním uloženého jazyka - načteme správnou sadu překladů pro španělštinu pomocí
loadTranslations
.
To bude samozřejmě v budoucnu plynulejší, buď v některé z příštích verzí Angularu,nebo prostřednictvím knihovny z ekosystému. každopádně se blížíme k tomu, abychom dodávali jen jednu verzi naší aplikace a překlady načítali jen za běhu \o/
Všechny naše materiály (ebook, online školení a trénink) jsou s těmito změnami aktuální, pokud se chcete dozvědět víc!
Leave a Reply