Traducerea aplicațiilor de stimulare cu I18Dext

În articolul meu precedent am abordat Stimulul - un cadru JavaScript modest creat de Basecamp. Astăzi, voi vorbi despre internaționalizarea unei aplicații Stimulus, deoarece cadrul nu furnizează nici un fel de instrumente I18n. Internaționalizarea este un pas important, mai ales când aplicația dvs. este folosită de oameni din întreaga lume, astfel încât o înțelegere de bază a modului de a face acest lucru poate fi cu adevărat utilă.

Desigur, depinde de tine să hotărâți soluția de implementare a internaționalizării, fie ea jQuery.I18n, Polyglot sau alta. În acest tutorial aș dori să vă arăt un cadru popular I18n numit I18next care are o mulțime de caracteristici interesante și oferă multe pluginuri terțe părți pentru a simplifica procesul de dezvoltare chiar mai departe. Chiar și cu toate aceste caracteristici, I18next nu este un instrument complex și nu trebuie să studiezi o mulțime de documente pentru a începe.

În acest articol, veți învăța cum să activați suportul I18n în aplicațiile Stimul cu ajutorul bibliotecii I18next. Mai precis, vom vorbi despre:

  • Configurația următoare
  • traduceți fișierele și încărcați-le asincron
  • efectuarea de traduceri și traducerea întregii pagini într-un singur pas
  • lucrul cu pluraluri și informații de gen
  • comutarea între localuri și persistența localizării alese în parametrul GET
  • setarea localizării pe baza preferințelor utilizatorului

Codul sursă este disponibil în replica GitHub tutorial.

Bootstrapping un App Stimul

Pentru a începe, hai să clonăm proiectul Stimulus Starter și să instalăm toate dependențele folosind managerul de pachete de fire:

git clone https://github.com/stimulusjs/stimulus-starter.git cd stimul-starter fire instalare

Vom construi o aplicație web simplă care va încărca informații despre utilizatorii înregistrați. Pentru fiecare utilizator, vom afișa datele de conectare și numărul de fotografii pe care le-a încărcat până acum (nu contează ce sunt aceste fotografii). 

De asemenea, vom prezenta un switch de limbă în partea de sus a paginii. Când este aleasă o limbă, interfața trebuie tradusă imediat fără reîncărcarea paginilor. Mai mult, URL-ul ar trebui să fie atașat cu un ?locale Parametrul GET care specifică ce locație este în prezent utilizată. Desigur, dacă pagina este încărcată cu acest parametru deja furnizat, limbajul corespunzător trebuie setat automat.

Bine, să mergem la redarea utilizatorilor noștri. Adăugați următoarea linie de cod la publice / index.html fişier:

Aici, folosim utilizatori controler și furnizarea unei adrese URL de la care să se încarce utilizatorii noștri. Într-o aplicație din lumea reală, probabil că vom avea un script de pe server, care va atrage utilizatorii din baza de date și va răspunde cu JSON. Pentru acest tutorial, totuși, să plasăm pur și simplu toate datele necesare în publice / api / utilizatori / index.json fişier:

"login": "johndoe", "photos_count": "15", "gender": "masculin", "login": "annsmith", "photos_count" "] 

Acum creați un nou src / controlere / users_controller.js fişier:

import Controller din clasa implicită de export "stimul" extinde Controller connect () this.loadUsers ()

De îndată ce controlerul este conectat la DOM, încărcăm asincron utilizatorii noștri cu ajutorul lui loadUsers () metodă:

 () .then (answer => response.text ()) .then (json => this.renderUsers (json)

Această metodă trimite o solicitare de preluare către adresa URL dată, captează răspunsul și, în final, redă utilizatorii:

 renderUsers (utilizatori) let content = "JSON.parse (users) .forEach ((utilizator) => content + = '
Conectare: $ user.login
A încărcat fotografii $ user.photos_count

') this.element.innerHTML = content

renderUsers (), la rândul său, analizează JSON, construiește un nou șir cu tot conținutul și, în cele din urmă, afișează acest conținut pe pagină (this.element va reveni la actualul nod DOM la care este conectat controlerul, care este div în cazul nostru).

I18next

Acum vom continua integrarea aplicației I18next în aplicația noastră. Adăugați două biblioteci la proiectul nostru: I18next în sine și un plugin pentru a permite încărcarea asincronă a fișierelor de traducere din spate:

fire adaugă i18next i18next-xhr-backend

Vom stoca toate lucrurile legate de I18next într-un altul src / i18n / config.js fișier, creați-l acum:

import i18next de la 'i18next' import I18nXHR de la 'i18next-xhr-backend' const i18n = i18next.use (I18nXHR) .init (fallbackLng: 'en', whitelist: 'en', 'ru'], ns: "utilizatori", defaultNS: "utilizatori", fallbackNS: false, debug: true, backend: loadPath: '/ i18n / lng / ns. json ',, funcția (err, t) if (err) returnează console.error (err)); export i18n ca i18n

Să mergem de sus în jos pentru a înțelege ce se întâmplă aici:

  • utilizarea (I18nXHR) permite pluginul i18next-xhr-backend.
  • fallbackLng îi spune să folosească limba engleză ca limbă de rezervă.
  • Listă albă permite setarea limbii engleze și rusești. Desigur, puteți alege alte limbi.
  • preîncărcare instruiește ca fișierele de traducere să fie preîncărcate de pe server, mai degrabă decât să le încarce când este selectată limba corespunzătoare.
  • ns înseamnă "spațiu de nume" și acceptă fie un șir sau un matrice. În acest exemplu, avem doar un spațiu de nume, dar pentru aplicații mai mari puteți introduce și alte spații de nume, cum ar fi admincart, profil, etc. Pentru fiecare spațiu de nume, trebuie creat un fișier de traducere separat.
  • defaultns seturi utilizatori a fi spațiul de nume implicit.
  • fallbackNS dezactivează schimbarea spațiului de nume.
  • depanare permite ca informațiile de depanare să fie afișate în consola browserului. În mod specific, se afișează care fișiere de traducere sunt încărcate, limba selectată, etc. Probabil doriți să dezactivați această setare înainte de a lansa aplicația în producție.
  • backend asigură configurarea pluginului I18nXHR și specifică unde să se încarce traducerile. Rețineți că calea trebuie să conțină titlul localului, în timp ce fișierul ar trebui să fie denumit după spațiul de nume și să aibă .JSON extensie
  • (err, t) este apelul pentru a rula atunci când I18next este gata (sau când a apărut o eroare).

Apoi, să realizăm fișiere de traducere. Traducerile pentru limba rusă ar trebui plasate în publice / i18n / ru / users.json fişier:

"login": "Login"

Logare aici este cheia de traducere, în timp ce Логин este valoarea care trebuie afișată.

Traduceri engleze, la rândul lor, ar trebui să meargă la publice / i18n / ro / users.json fişier:

"login": "Conectare"

Pentru a vă asigura că funcționează I18next, puteți adăuga următoarea linie de cod la apelul invers în interiorul lui i18n / config.js fişier:

// config merge aici ... funcția (err, t) if (err) returna console.error (err) console.log (i18n.t ('login')

Aici, folosim o metodă numită T înseamnă "traduce". Această metodă acceptă o cheie de traducere și returnează valoarea corespunzătoare.

Cu toate acestea, s-ar putea să avem multe părți ale UI care trebuie traduse și să facă acest lucru utilizând T metoda ar fi destul de obositoare. În schimb, vă sugerăm să utilizați un alt plugin numit loc-i18next care vă permite să traduceți mai multe elemente simultan.

Traducere în One Go

Instalați pluginul loc-i18next:

fire adăugați loc-i18next

Importați-o în partea de sus a paginii src / i18n / config.js fişier:

import locI18next de la 'loc-i18next'

Acum asigurați configurația pentru plugin-ul însuși:

/ / alte config const loc lo1818 = locI18next.init (i18n, selectorAttr: 'data-i18n', optionsAttr: 'data-i18n-options', useOptionsAttr: true); export loci18n ca loci18n, i18n ca i18n

Există câteva lucruri de reținut aici:

  • locI18next.init (i18n) creează o nouă instanță a pluginului pe baza instanței definite anterior a I18next.
  • selectorAttr specifică ce atribut să utilizeze pentru a detecta elementele care necesită localizare. Practic, loc-i18next va căuta astfel de elemente și va folosi valoarea lui Date-i18n atribut ca cheie de traducere.
  • optionsAttr specifică care atribut conține opțiuni de traducere suplimentare.
  • useOptionsAttr instruiește pluginul să utilizeze opțiunile suplimentare.

Utilizatorii noștri sunt încărcați în mod asincron, așa că trebuie să așteptăm până când această operațiune este terminată și numai după aceea să efectueze localizarea. Pentru moment, hai să stabilim un cronometru care ar trebui să aștepte două secunde înainte de a apela localiza() metoda - asta este un hack temporar, desigur.

 import loci18n de la "... / i18n / config" // alt cod ... loadUsers () fetch (this.data.get ("url")) .then (response => response.text => this.renderUsers (json) setTimeout (() => // <--- this.localize() , '2000') ) 

Codul localiza() metoda în sine:

 localize () loci18n ("utilizatori")

După cum vedeți, trebuie să trecem doar un selector la pluginul loc-i18next. Toate elementele din interiorul (care au Date-i18n set de atribute) vor fi localizate automat.

Acum tweak renderUsers metodă. Pentru moment, să traducem doar cuvântul "Conectare":

 renderUsers (utilizatori) let content = "JSON.parse (users) .forEach ((utilizator) => content + = '
ID: $ user.id
: $ user.login
A încărcat fotografii $ user.photos_count

') this.element.innerHTML = content

Frumos! Reîncărcați pagina, așteptați două secunde și asigurați-vă că apare cuvântul "Conectare" pentru fiecare utilizator.

Plurala și genul

Avem localizată o parte a interfeței, care este foarte cool. Totuși, fiecare utilizator are încă două câmpuri: numărul de fotografii încărcate și genul. Deoarece nu putem anticipa numărul de fotografii pe care fiecare utilizator le va avea, cuvântul "fotografie" ar trebui să fie pluralizat în mod corespunzător în funcție de numărul dat. Pentru a face acest lucru, vom avea nevoie de a data-i18n-opțiuni atribut configurat anterior. Pentru a oferi numărătoarea, data-i18n-opțiuni ar trebui să fie atribuit cu următorul obiect: "conta": YOUR_COUNT.

De asemenea, ar trebui luate în considerare și informațiile privind genul. Cuvântul "încărcat" în limba engleză poate fi aplicat atît bărbaților, cît și femeilor, dar în limba rusă devine "загрузил" sau "загрузила", deci avem nevoie de data-i18n-opțiuni din nou, care a fost "context": "GENDER" ca valoare. Rețineți, apropo, că puteți utiliza acest context pentru a realiza alte sarcini, nu numai pentru a oferi informații despre gen.

 renderUsers (utilizatori) let content = "JSON.parse (users) .forEach ((utilizator) => content + = '
: $ user.login

') this.element.innerHTML = content

Acum actualizați traducerile în limba engleză:

"login": "Conectare", "încărcat": "A încărcat", "fotografii": "o fotografie", "photos_plural": "count fotografii"

Nimic complex aici. Deoarece pentru engleza nu ne interesează informațiile de gen (care este contextul), cheia de traducere ar trebui să fie pur și simplu încărcat. Pentru a oferi traducerile pluralizate în mod corespunzător, folosim fotografii și photos_plural chei. numara parte este interpolare și va fi înlocuit cu numărul real.

În ceea ce privește limba rusă, lucrurile sunt mai complexe:

"login": "Logins", "uploaded_male": "Загрузил уже", "uploaded_female": "Загрузила уже", "photos_0": "одну фотографию" photos_2 ":" count fotografiile " 

Mai întâi de toate, rețineți că avem amândouă uploaded_male și uploaded_female chei pentru două contexte posibile. Apoi, regulile de pluralizare sunt și mai complexe în limba rusă decât în ​​limba engleză, deci nu trebuie să furnizăm două, ci trei fraze posibile. I18next acceptă multe limbi din cutie și acest mic instrument vă poate ajuta să înțelegeți ce chei de pluralizare trebuie specificate pentru o anumită limbă.

Comutarea locală

Am terminat cu traducerea aplicației noastre, dar utilizatorii ar trebui să poată schimba locațiile. Prin urmare, adăugați o nouă componentă "switch language" la publice / index.html fişier:

    Plasați controlerul corespunzător în interiorul src / controlere / languages_controller.js fişier:

    import Controller de la "stimul" import i18n, loci18n din clasa implicită pentru exportul "... / i18n / config" extinde Controller inialize  title: 'Русский', cod: 'ru'] this.element.innerHTML = languages.map ((lang) => return '
  • $ lang.title
  • ' ).a adera(")

    Aici folosim inițializa () apel invers pentru a afișa o listă de limbi acceptate. Fiecare Li are o date de acțiune care specifică ce metodă (switchLanguage, în acest caz) trebuie să fie declanșat atunci când elementul este apăsat.

    Acum adaugati switchLanguage () metodă:

     comutaLanguage (e) this.currentLang = e.target.getAttribute ("date-lang")

    Pur și simplu ia ținta evenimentului și apreciază valoarea date-lang atribut.

    Aș dori, de asemenea, să adaug un getter și setter pentru currentLang atribut:

     (lang) dacă (this.currentLang! == lang) if18n.language! == lang) i18n.changeLanguage (lang) ) this.data.set ("currentLang", lang) loci18n ('body') this.highlightCurrentLang ()

    Getter-ul este foarte simplu - extragem valoarea limbajului folosit în prezent și îl returnează.

    Setterul este mai complex. Mai întâi, folosim changeLanguage dacă limba curentă nu este egală cu cea selectată. De asemenea, stocăm noul locale selectat sub Date-curent-lang (care este accesat în getter), localizarea corpului paginii HTML folosind pluginul loc-i18next și în cele din urmă evidențierea localizării locale utilizate.

    Să codificăm highlightCurrentLang ():

     () () () () () () () () () ()

    Aici, iterăm peste o serie de switch-uri locale și comparăm valorile lor date-lang atributele la valoarea localizării utilizate în prezent. Dacă valorile se potrivesc, comutatorul este asociat cu a actual CSS, altfel această clasă este eliminată.

    Pentru a face this.switcherTargets să construim o muncă, trebuie să definim obiectivele Stimulului în felul următor:

    obiective statice = ["switch"]

    De asemenea, adăugați date-țintă atributele cu valori ale switcher pentru Lis:

     inițializați () // ... this.element.innerHTML = languages.map ((lang) => return '
  • $ lang.title
  • ' ).a adera(") //…

    Un alt lucru important care trebuie luat în considerare este faptul că fișierele de traducere pot dura ceva timp pentru încărcare și trebuie să așteptăm ca această operație să se finalizeze înainte de a permite schimbarea locale. Prin urmare, să profităm de încărcat suna inapoi:

     initialize () i18n.on ('încărcat', (încărcat) => // <--- let languages = [ title: 'English', code: 'en', title: 'Русский', code: 'ru' ] this.element.innerHTML = languages.map((lang) =>  întoarcere '
  • $ lang.title
  • ') se alăture (") this.currentLang = i18n.language)

    În cele din urmă, nu uitați să eliminați setTimeout de la loadUsers () metodă:

     jsr => this.renderUsers (json) this.localize ())

    Persistență locală în URL

    După ce localul este schimbat, aș dori să adaug un ?lang Parametru GET la adresa URL care conține codul pentru limba aleasă. Adăugarea unei paranteze GET fără reîncărcarea paginii poate fi făcută cu ușurință cu ajutorul API-ului History:

     setul curentLang (lang) if (i18n.language! == lang) i18n.changeLanguage (lang) window.history.pushState (null, null, '? lang = $ lang') <---  if(this.currentLang !== lang)  this.data.set("currentLang", lang) loci18n('body') this.highlightCurrentLang()  

    Detectarea localizării

    Ultimul lucru pe care îl vom implementa astăzi este capacitatea de a seta locația în funcție de preferințele utilizatorului. Un plugin numit LanguageDetector ne poate ajuta să rezolvăm această problemă. Adăugați un nou pachet de Fire:

    fire adaugă i18next-browser-languagedetector

    Import LanguageDetector în interiorul i18n / config.js fişier:

    import LngDetector de la "i18next-browser-languagedetector"

    Acum ajustați configurația:

    const i18n = i18next.use (I18nXHR) .use (LngDetector) .init (// <--- // other options go here… detection:  order: ['querystring', 'navigator', 'htmlTag'], lookupQuerystring: 'lang',  , function(err, t)  if (err) return console.error(err) );

    Ordin opțiunea include toate tehnicile (sortate după importanța lor) pe care pluginul ar trebui să le încerce pentru a "ghici" localul preferat:

    • șir de interogare înseamnă verificarea unei paranteze GET care conține codul locale.
    • lookupQuerystring stabilește numele paramului GET de utilizat, care este lang în cazul nostru.
    • navigator înseamnă obținerea datelor locale din solicitarea utilizatorului.
    • htmlTag implică preluarea localității preferate din lang atributul html etichetă.

    Concluzie

    În acest articol am aruncat o privire la I18next - o soluție populară de traducere ușoară a aplicațiilor JavaScript. Ați învățat cum să integrați I18next cu cadrul de stimulare, să îl configurați și să încărcați fișierele de traducere într-un mod asincron. De asemenea, ați văzut cum să comutați între localizări și să setați limba prestabilită pe baza preferințelor utilizatorului.

    I18next are câteva opțiuni de configurare suplimentare și multe pluginuri, deci asigurați-vă că navigați în documentația oficială pentru a afla mai multe. De asemenea, rețineți că Stimulul nu vă obligă să utilizați o soluție de localizare specifică, astfel încât să încercați, de asemenea, să utilizați ceva de genul jQuery.I18n sau Polyglot. 

    Asta e tot pentru ziua de azi! Vă mulțumim pentru că ați citit și până la următoarea dată.

    Cod