Î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:
Codul sursă este disponibil în replica GitHub tutorial.
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).
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 admin
, cart
, 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.
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.
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ă.
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 '
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 Li
s:
inițializați () // ... this.element.innerHTML = languages.map ((lang) => return '
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 '
În cele din urmă, nu uitați să eliminați setTimeout
de la loadUsers ()
metodă:
jsr => this.renderUsers (json) this.localize ())
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()
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ă.Î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ă.