Kansainvälistäminen @angular/localize

Suuri edistysaskel on tapahtunut i18n-rintamalla!Uusi paketti nimeltä @angular/localize on otettu käyttöön Angular 9.0.

Sitä käytetään konepellin alla, jotta saamme samat ominaisuudet, jotka meillä oli aiemmin:käännökset malleissa käännöksen kääntämisen aikana.

Mutta se antaa meille toivoa enemmän tulevaisuudessa,dokumentoimattomia ominaisuuksia jo saatavilla,kuten käännöksiä koodissa,tai ajoaikaisia käännöksiä pelkkien käännöskäännösten sijaan 😎.

Aloitetaan katsomalla mitä voimme tehdä @angular/localizeja CLI:n avulla v9:ssä.

i18n malleissa

Uusi @angular/localize-paketti tarjoaa toiminnon nimeltä $localize.

Olemassa oleva i18n-tuki Angularissa käyttää nyt $localize,mikä tarkoittaa, että sellaiset mallit kuin:

<h1 i18n>Hello</h1>

käännetään $localize-kutsuiksi.

Jos suoritat ng serve tällaisen mallin kanssa,törmäät ajovirheeseen:

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.)

Virhe on itsestään selvä:koska i18n-attribuutit muunnetaan nyt $localize-kutsuiksi generoidussa koodissa,meidän täytyy ladata $localize-funktio.Se voitaisiin tehdä oletusarvoisesti,mutta koska sitä tarvitaan vain jos käytät kansainvälistämistä,siinä ei olisi oikeastaan mitään järkeä.

Jos sovelluksesi tai jokin sen riippuvuuksista käyttää i18n-attribuutteja malleissaan,sinun on lisättävä import '@angular/localize/init' polyfilleihisi!

CLI:ssä on kaavio,jolla tämä voidaan tehdä puolestasi.Suorita yksinkertaisesti:

ng add @angular/localize

ja CLI lisää paketin riippuvuuksiisi ja tarvittavan tuonnin polyfilleihisi.

Silloin kun suoritat sovelluksesi yksinkertaisella ng serve:llä,$localize näyttää yksinkertaisesti alkuperäisen viestin.

Miten nämä viestit käännetään?

Prosessi on hyvin samankaltainen kuin aiemmin.Ensin ajetaan ng xi18n poimimaan viestit messages.xlf-tiedostoon.Sitten tiedosto käännetään paikallisille kielille, esimerkiksi messages.fr.xlfja messages.es.xlf.

Sitten sinun täytyy konfiguroida CLI, kohdassa 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" } } } // ...}

Nyt es tai fr konfiguraatiot mahdollistavat ajamisen:

ng serve --configuration=fr

Ja sovellus tarjoillaan nyt ranskaksi!

Sovelluksen voi myös rakentaa tietyllä paikallisella:

ng build --configuration=production,es

tai kaikilla paikallisilla kerralla:

ng build --prod --localize

Tämä on suuri edistysaskel aiempiin Angular-versioihin nähden.Ennen jouduimme rakentamaan saman sovelluksen jokaiselle paikalliselle,sillä käännös oli osa kääntämistä.Nyt, kun Angular kääntää sovelluksen, se luo $localize-kutsuja.Sitten, kun tämä on tehty, työkalu ottaa käännetyn sovelluksen ja korvaa kaikki $localize-kutsut oikeilla käännöksillä.Tämä on supernopeaa.Sinulla on sitten paketti, joka ei sisällä lainkaan $localize-kutsuja, ja kaikki i18n-merkkijonot on käännetty.

Vaan nyt, sinun piti rakentaa sovelluksesi kerran jokaista paikallisuutta kohden, ja tämä oli täysi build. Joten sanotaan, että se on 30s build,ja halusit 4 locales, niin olit 2 minuuttia.

Uuden lähestymistavan myötä kääntäminen tehdään kerran,ja sitten eri i18n-versiot generoidaan muutamassa sekunnissa(se generoidaan jopa rinnakkain jos mahdollista).Joten menet 2 minuutista ~40 sekuntiin! 🌈

Tällöin sinulla on useita paketteja, yksi per lokaliteetti,ja voit tarjota käyttäjillesi sopivaa riippuen heidän mieltymyksistään, kuten ennenkin.

Tätä strategiaa kutsutaan kääntämisen aikaiseksi inlineeraukseksi,koska käännöksiä inlineerataan suoraan,ja sen jälkeen ei jää mitään tekemistä ajonaikana.

Puhutaan nyt jostain vielä dokumentoimattomasta asiasta,joka saattaa muuttua tulevaisuudessa,mutta on silti mielenkiintoista tietää:voimme nyt myös kääntää viestejä TypeScript-koodissamme!

Funktiota $localize,josta olen puhunut,voi käyttää suoraan. Se on erikoinen funktio,jolla voit merkitä mallimerkkijonon lokalisointia varten.

Mutta ehkä meidän pitäisi aloittaa selittämällä, mikä on merkitty mallimerkkijono?

Mallimerkkijonot ja tag-funktiot

Mallimerkkijonoja käytettäessä voidaan määritellä tag-funktio,ja soveltaa sitä mallimerkkijonoon.tässä askQuestion lisää merkkijonon loppuun kyselypisteen:

const askQuestion = strings => strings + '?';const template = askQuestion`Is anyone here`;

Mitä eroa on siis yksinkertaiseen funktioon?Tag-funktio vastaanottaa itse asiassa useita argumentteja:

  • merkkijonon staattisten osien matriisi
  • lausekkeiden evaluoinnin tuloksena saadut arvot

Jos meillä on esimerkiksi mallimerkkijono, joka sisältää lausekkeita:

const person1 = 'Cedric';const person2 = 'Agnes';const template = `Hello ${person1}! Where is ${person2}?`;

ton tag-funktio vastaanottaa merkkijonon eri staattiset ja dynaamiset osat.Tässä meillä on tag-funktio, jolla päähenkilöiden nimet kirjoitetaan suuraakkosin:

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 kanssa $localize TypeScript-koodissa

$localize käyttää tätä mekaniikkaa, jotta voimme kirjoittaa:

@Component({ template: '{{ title }}'})export class HomeComponent { title = $localize`You have 10 users`;}

Huomaa, että funktiota ei tarvitse tuoda.Kunhan lisäät import '@angular/localize/init' kerran sovellukseesi,$localize lisätään globaaliin objektiin.

Voit sitten kääntää viestin samalla tavalla kuin mallin kohdalla.Mutta juuri nyt (v9.0.0) CLI ei poimi näitä viestejä xi18n-komennolla, kuten se tekee malleille.

Jos palvelet sovellusta eikä käännöstä löydy,$localize näyttää vain alkuperäisen merkkijonon,ja kirjaa varoituksen konsoliin:

No translation found for "6480943972743237078" ("You have 10 users").

Se on siis lisättävä manuaalisesti messages.fr.xlfnimellä annetulla ID:lläjos haluat kokeilla:

<trans-unit> <source>You have 10 users</source> <target>Vous avez 10 utilisateurs</target></trans-unit>

Minun HomeComponent:n malli näyttää silloin Vous avez 10 utilisateurs!

Mitä tapahtuu, jos mallimerkkijonossa on jokin dynaaminen lauseke?

title = $localize`Hi ${this.name}! You have ${this.users.length} users.`;

Lausekkeet nimetään automaattisesti PH ja PH_1 (PH on paikkaaja).Sitten voit käyttää näitä paikanhaltijoita missä tahansa käännöksissä:

<trans-unit> <source>Hi <x/>! You have <x/> users.</source> <target>Bonjour <x/>&nbsp;! Vous avez <x/> utilisateurs.</target></trans-unit>

Mutta paras käytäntö on antaa itse mielekäs paikanhaltijanimi lausekkeelle,ja voit tehdä sen käyttämällä ${expression}:placeholder:-syntaksia.

title = $localize`Hi ${this.name}:name:! You have ${this.users.length}:userCount: users.`;

Sitten voit käyttää tätä placeholderiä missä tahansa käännöksissä:

<trans-unit> <source>Hi <x/>! You have <x/> users.</source> <target>Bonjour <x/>&nbsp;! Vous avez <x/> utilisateurs.</target></trans-unit>

Kustomoidut tunnukset

Huomaa, että jos sinulla on käännöksiä, joilla on mukautetut tunnukset,niitä käytetään $localize:llä (kuten aiemmin):

<h1 i18n="@@home.greetings">Hello</h1>

Tällöin käännöksesi näyttää seuraavalta:

<trans-unit> <source>Hello</source> <target>Bonjour</target></trans-unit>

mikä on selvästi mukavampi käyttää.

Miten olisi käännösten kanssa koodissa?$localize ymmärtää myös syntaksin, joka mahdollistaa ID:n määrittämisen:

title = $localize`:@@home.users:You have 10 users`;

Kustomoidun ID:n syntaksi on sama kuin malleissa,ja ID:tä ympäröi kaksoispisteet erottamaan sen käännöksen sisällöstä.

Mallien syntaksin tapaan voit myös määritellä kuvauksen ja merkityksen,jotta kääntäjät saisivat hieman kontekstia: :meaning|description@@id:message.

Esimerkiksi:

title = $localize`:greeting message with the number of users currently logged in@@home.users:You have 10 users`;

Pitäkää mielessä, että tämä on matalan tason, dokumentoimaton API.Angular-tiimi tai -yhteisö tulee luultavasti tarjoamaan korkeamman tason toimintoja paremmalla kehittäjäkokemuksella (no, toivon niin!).Locl:lta Olivier Combe,ngx-translate:n kirjoittajaltaon luultavasti silmälläpidettävä 🧐.

Laajuusaikaiset käännökset

Kuten olin mainitsemassa,jos käytät edellä mainittuja CLI-komentoja (ng serve --configuration=fr tai ng build --localize),niin sovellus käännetään ja käännetään ennen kuin se osuu selaimeen,joten ajoaikaisia $localize-kutsuja ei ole.

Mutta $localize:n on suunniteltu tarjoavan toisenkin vaihtoehdon:aajuusaikaiset käännökset.Mitä se tarkoittaa? No, voisimme toimittaa vain yhden sovelluksen,joka sisältäisi $localize-kutsuja,ja ennen kuin sovellus käynnistyy, voisimme ladata haluamamme käännökset.Ei enää N buildia ja N bundlea N:lle localesille \o/

Taivuttelematta liikaa yksityiskohtiin,tämä on mahdollista jo v9:ssä,käyttämällä @angular/localize:n tarjoamaa loadTranslations-funktiota.Mutta tämä on tehtävä ennen sovelluksen käynnistämistä.

Voit ladata käännöksesi polyfills.ts:

import '@angular/localize/init';import { loadTranslations } from '@angular/localize';loadTranslations({ '1815172606781074132': 'Bonjour {$name}\xa0! Vous avez {$userCount} utilisateurs.'});

Kuten huomaat, ei ole mitään locale-harkintaa:lataat vain käännöksesi objektina,jonka avaimet ovat käännettävät merkkijonot ja arvot niiden käännökset.

Nyt jos suoritat yksinkertaisen ng serve,otsikko näytetään ranskaksi!Eikä enää tarvita ng xi18n,tai messages.fr.xlftai erityistä konfigurointia jokaista localea varten angular.json.Pitkällä tähtäimellä,kun tätä tuetaan ja dokumentoidaan kunnolla,meidän pitäisi pystyä lataamaan JSON-tiedostoja ajonaikana,kuten useimmat i18n-kirjastot tekevät.Se onnistuu jopa v9:ssä, se on vain hieman manuaalista työtä, mutta se on toteutettavissa.

Mitä sitten on, kun vaihdetaan localea lennossa?Voimmeko ladata toisen joukon käännöksiä, kun sovellus käynnistetään?No, ei. Nykyinen tapa, jolla $localize-kutsut luodaan, tekee niiden muuttamisen jälkikäteen mahdottomaksi: sinun on käynnistettävä sovellus uudelleen.Mutta jos sinua ei haittaa selaimen päivittäminen, se on mahdollista.Testasin yksinkertaista strategiaa, joka toimii:

  • käyttäjä valitsee uuden kielen (esimerkiksi espanjan).
  • tallennamme kielen selaimeen (esimerkiksi localStorageen)
  • lataamme sivun uudelleen, jolloin sovellus käynnistyy uudelleen
  • kohdassa polyfills.ts aloitamme lukemalla tallennetun kielen
  • lataamme oikeat käännökset espanjankielelle loadTranslations.

Tämä on tietysti sujuvampaa tulevaisuudessa,joko Angularin tulevassa versiossa,tai ekosysteemin kirjaston kautta.Joka tapauksessa,olemme yhä lähempänä sitä,että toimitamme vain yhden version sovelluksestamme,ja lataamme vain käännökset ajonaikana \o/

Kaikki materiaalimme (ebook,verkkokoulutus ja koulutus) ovat ajan tasalla näiden muutosten kanssa,jos haluat oppia lisää!

Leave a Reply