Nel mio precedente articolo ho trattato Stimulus, un modesto framework JavaScript creato da Basecamp. Oggi parlerò dell'internazionalizzazione di un'applicazione Stimulus, dal momento che il framework non fornisce alcun strumento I18n immediato. L'internazionalizzazione è un passo importante, soprattutto quando la tua app viene utilizzata da persone di tutto il mondo, quindi una comprensione di base su come farlo potrebbe essere davvero utile.
Naturalmente, spetta a te decidere quale soluzione di internazionalizzazione implementare, sia jQuery.I18n, Polyglot, o qualche altro. In questo tutorial vorrei mostrarti un famoso framework I18n chiamato I18next che ha molte funzioni interessanti e fornisce molti plugin aggiuntivi di terze parti per semplificare ulteriormente il processo di sviluppo. Anche con tutte queste funzionalità, I18next non è uno strumento complesso e non è necessario studiare molta documentazione per iniziare.
In questo articolo, imparerai come abilitare il supporto I18n nelle applicazioni Stimulus con l'aiuto della libreria I18next. Nello specifico, parleremo di:
Il codice sorgente è disponibile nel tutorial repo GitHub.
Per iniziare, cloniamo il progetto Stimulus Starter e installiamo tutte le dipendenze usando il gestore di pacchetti Yarn:
git clone https://github.com/stimulusjs/stimulus-starter.git cd stimulus-starter filato installa
Creeremo una semplice applicazione web che carica informazioni sugli utenti registrati. Per ciascun utente, mostreremo il suo login e il numero di foto che ha caricato fino a quel momento (non importa cosa siano queste foto).
Inoltre, presenteremo un selettore di lingua nella parte superiore della pagina. Quando viene scelta una lingua, l'interfaccia deve essere tradotta immediatamente senza ricaricare la pagina. Inoltre, l'URL dovrebbe essere aggiunto con a ?località
GET parametro che specifica quale locale è attualmente utilizzata. Naturalmente, se la pagina viene caricata con questo parametro già fornito, la lingua corretta deve essere impostata automaticamente.
Ok, procediamo a rendere i nostri utenti. Aggiungi la seguente riga di codice al pubblico / index.html file:
Qui, stiamo usando il utenti
controller e fornendo un URL da cui caricare i nostri utenti. In un'applicazione reale, probabilmente avremmo uno script sul lato server che recupera gli utenti dal database e risponde con JSON. Per questo tutorial, tuttavia, inseriamo semplicemente tutti i dati necessari nel / Api / utenti / index.json pubblico file:
["login": "johndoe", "photos_count": "15", "gender": "male", "login": "annsmith", "photos_count": "20", "gender": "female "]
Ora crea un nuovo src / controller / users_controller.js file:
import Controller dalla classe predefinita di esportazione "stimulus" estende Controller connect () this.loadUsers ()
Non appena il controller è collegato al DOM, stiamo caricando in modo asincrono i nostri utenti con l'aiuto di loadUsers ()
metodo:
loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json))
Questo metodo invia una richiesta di recupero all'URL specificato, acquisisce la risposta e infine esegue il rendering degli utenti:
renderUsers (users) let content = "JSON.parse (users) .forEach ((user) => content + = 'Accesso: $ user.login
Ha caricato $ user.photos_count foto
') this.element.innerHTML = contenuto
renderUsers ()
, a sua volta, analizza JSON, crea una nuova stringa con tutto il contenuto e infine visualizza questo contenuto nella pagina (this.element
restituirà l'attuale nodo DOM a cui è connesso il controller, che è div
nel nostro caso).
Ora procederemo all'integrazione di I18next nella nostra app. Aggiungi due librerie al nostro progetto: I18next stesso e un plugin per abilitare il caricamento asincrono dei file di traduzione dal back-end:
filato aggiungere i18next i18next-xhr-backend
Stiamo andando a memorizzare tutte le cose relative a I18next in un separato src / i18n / config.js file, quindi crealo ora:
importare i18next da 'i18next' import I18nXHR da 'i18next-xhr-backend' const i18n = i18next.use (I18nXHR) .init (fallbackLng: 'en', whitelist: ['en', 'ru'], precarico: [ 'en', 'ru'], ns: 'users', defaultNS: 'users', fallbackNS: false, debug: true, backend: loadPath: '/ i18n / lng / ns. json ',, function (err, t) if (err) return console.error (err)); esporta i18n come i18n
Andiamo dall'alto verso il basso per capire cosa sta succedendo qui:
utilizzare (I18nXHR)
abilita il plugin i18next-xhr-backend.fallbackLng
dice di usare l'inglese come lingua di riserva.lista bianca
consente di impostare solo le lingue inglese e russa. Certo, puoi scegliere qualsiasi altra lingua.precarico
ordina che i file di traduzione vengano precaricati dal server, anziché caricarli quando viene selezionata la lingua corrispondente.ns
significa "spazio dei nomi" e accetta una stringa o un array. In questo esempio abbiamo un solo spazio dei nomi, ma per le applicazioni più grandi è possibile introdurre altri spazi dei nomi, come Admin
, carrello
, profilo
, ecc. Per ogni spazio dei nomi, dovrebbe essere creato un file di traduzione separato.defaultNS
imposta utenti
essere lo spazio dei nomi predefinito.fallbackNS
disabilita il fallback del namespace.mettere a punto
consente di visualizzare le informazioni di debug nella console del browser. In particolare, indica quali file di traduzione sono caricati, quale lingua è selezionata, ecc. Probabilmente vorrai disabilitare questa impostazione prima di distribuire l'applicazione in produzione.backend
fornisce la configurazione per il plugin I18nXHR e specifica dove caricare le traduzioni. Si noti che il percorso deve contenere il titolo delle impostazioni internazionali, mentre il nome del file deve essere il seguente al namespace e avere il .jSON estensionefunzione (err, t)
è il callback da eseguire quando I18next è pronto (o quando è stato sollevato un errore).Quindi, costruiamo i file di traduzione. Le traduzioni per la lingua russa dovrebbero essere inserite nel / I18n / RU / users.json pubblico file:
"login": "Логин"
accesso
ecco la chiave di traduzione, mentre Логин
è il valore da visualizzare.
Le traduzioni in inglese, a loro volta, dovrebbero andare al pubblico / i18n / it / users.json file:
"Entra Entra"
Per assicurarsi che I18next funzioni, è possibile aggiungere la seguente riga di codice al callback all'interno di i18n / config.js file:
// config goes here ... function (err, t) if (err) return console.error (err) console.log (i18n.t ('login'))
Qui, stiamo usando un metodo chiamato t
ciò significa "tradurre". Questo metodo accetta una chiave di traduzione e restituisce il valore corrispondente.
Tuttavia, potremmo avere molte parti dell'interfaccia utente che devono essere tradotte, e facendo ciò utilizzando il t
il metodo sarebbe abbastanza noioso Invece, ti suggerisco di usare un altro plugin chiamato loc-i18next che ti permette di tradurre più elementi contemporaneamente.
Installa il plugin loc-i18next:
filato aggiungere loc-i18next
Importalo nella parte superiore del src / i18n / config.js file:
importare locI18next da 'loc-i18next'
Ora fornisci la configurazione per il plugin stesso:
// other config const loci18n = locI18next.init (i18n, selectorAttr: 'data-i18n', optionsAttr: 'data-i18n-options', useOptionsAttr: true); export loci18n as loci18n, i18n as i18n
Ci sono un paio di cose da notare qui:
locI18next.init (i18n)
crea una nuova istanza del plugin in base all'istanza precedentemente definita di I18next.selectorAttr
specifica quale attributo utilizzare per rilevare elementi che richiedono la localizzazione. Fondamentalmente, loc-i18next sta cercando questi elementi e usa il valore di Dati-i18n
attributo come chiave di traduzione.optionsAttr
specifica quale attributo contiene opzioni di traduzione aggiuntive.useOptionsAttr
indica al plug-in di utilizzare le opzioni aggiuntive.I nostri utenti vengono caricati in modo asincrono, quindi dobbiamo aspettare fino a quando questa operazione non viene completata e solo dopo eseguire la localizzazione. Per ora, impostiamo semplicemente un timer che dovrebbe aspettare per due secondi prima di chiamare il localizzare()
metodo: è un trucco temporaneo, ovviamente.
import loci18n da '... / i18n / config' // altro codice ... loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json) setTimeout (() => // <--- this.localize() , '2000') )
Codice il localizzare()
metodo stesso:
localize () loci18n ('. users')
Come vedi, abbiamo solo bisogno di passare un selettore al plug-in i18next di loc. Tutti gli elementi all'interno (che hanno il Dati-i18n
set di attributi) verrà localizzato automaticamente.
Ora modificare il renderUsers
metodo. Per ora, traduciamo solo la parola "Login":
renderUsers (users) let content = "JSON.parse (users) .forEach ((user) => content + = 'ID: $ user.id
: $ user.login
Ha caricato $ user.photos_count foto
') this.element.innerHTML = contenuto
Bello! Ricarica la pagina, attendi due secondi e assicurati che la parola "Login" appaia per ogni utente.
Abbiamo localizzato parte dell'interfaccia, che è davvero interessante. Tuttavia, ogni utente ha altri due campi: il numero di foto e il sesso caricati. Dal momento che non possiamo prevedere quante foto ogni utente avrà, la parola "foto" dovrebbe essere pluralizzata correttamente in base al conteggio dato. Per fare questo, abbiamo bisogno di un -i18n-opzioni dati
attributo configurato in precedenza. Per fornire il conteggio, -i18n-opzioni dati
dovrebbe essere assegnato con il seguente oggetto: "count": YOUR_COUNT
.
Anche le informazioni di genere dovrebbero essere prese in considerazione. La parola "caricato" in inglese può essere applicata sia a uomini che a donne, ma in russo diventa "загрузил" o "загрузила", quindi abbiamo bisogno -i18n-opzioni dati
di nuovo, che ha "context": "GENDER"
come valore Nota, a proposito, che puoi utilizzare questo contesto per raggiungere altri compiti, non solo per fornire informazioni di genere.
renderUsers (users) let content = "JSON.parse (users) .forEach ((user) => content + = ': $ user.login
') this.element.innerHTML = contenuto
Ora aggiorna le traduzioni in inglese:
"login": "Login", "caricato": "Ha caricato", "foto": "una foto", "foto_plural": "count foto"
Niente di complesso qui. Dal momento che per l'inglese non ci interessa l'informazione di genere (che è il contesto), la chiave di traduzione dovrebbe essere semplicemente caricato
. Per fornire traduzioni correttamente pluralizzate, stiamo usando il fotografie
e photos_plural
chiavi. Il contare
parte è l'interpolazione e sarà sostituita con il numero effettivo.
Per quanto riguarda la lingua russa, le cose sono più complesse:
"login": "Логин", "loaded_male": "Загрузил уже", "uploaded_female": "Загрузила уже", "photos_0": "одну фотографию", "photos_1": "count фотографии", " photos_2 ":" count фотографий "
Prima di tutto, nota che abbiamo entrambi uploaded_male
e uploaded_female
chiavi per due possibili contesti. Inoltre, le regole di pluralizzazione sono anche più complesse in russo che in inglese, quindi non dobbiamo fornire due, ma tre possibili frasi. I18next supporta molte lingue fuori dalla scatola e questo piccolo strumento può aiutarti a capire quali tasti di pluralizzazione dovrebbero essere specificati per una determinata lingua.
Abbiamo finito con la traduzione della nostra applicazione, ma gli utenti dovrebbero essere in grado di passare da un locale all'altro. Pertanto, aggiungere un nuovo componente "selettore di lingua" al pubblico / index.html file:
Crea il controller corrispondente all'interno del src / controller / languages_controller.js file:
import Controller da "stimulus" import i18n, loci18n da '... / i18n / config' la classe di default di esportazione estende Controller initialize () let languages = [title: 'English', code: 'en', title: 'Русский', codice: 'ru'] this.element.innerHTML = languages.map ((lang) => return '
Qui stiamo usando il inizializzare()
callback per visualizzare un elenco di lingue supportate. Ogni Li
ha un Dati-action
attributo che specifica quale metodo (switchLanguage
, in questo caso) deve essere attivato quando si fa clic sull'elemento.
Ora aggiungi il switchLanguage ()
metodo:
switchLanguage (e) this.currentLang = e.target.getAttribute ("data-lang")
Prende semplicemente il bersaglio dell'evento e prende il valore del Dati-lang
attributo.
Vorrei anche aggiungere un getter e setter per il currentLang
attributo:
get currentLang () return this.data.get ("currentLang") imposta currentLang (lang) if (i18n.language! == lang) i18n.changeLanguage (lang) if (this.currentLang! == lang ) this.data.set ("currentLang", lang) loci18n ('body') this.highlightCurrentLang ()
Il getter è molto semplice: recuperiamo il valore del linguaggio correntemente usato e lo restituiamo.
Il setter è più complesso. Prima di tutto, usiamo il Cambia lingua
metodo se la lingua attualmente impostata non è uguale a quella selezionata. Inoltre, stiamo memorizzando la nuova localizzazione selezionata sotto Dati-corrente-lang
attributo (a cui si accede nel getter), localizzando il corpo della pagina HTML utilizzando il plug-in loc-i18next e infine evidenziando le impostazioni locali attualmente utilizzate.
Cerchiamo di codificare il highlightCurrentLang ()
:
highlightCurrentLang () this.switcherTargets.forEach ((el, i) => el.classList.toggle ("current", this.currentLang === el.getAttribute ("data-lang")))
Qui stiamo iterando su un array di switcher locali e confrontando i loro valori Dati-lang
attribuisce al valore della locale attualmente utilizzata. Se i valori corrispondono, il commutatore viene assegnato con a attuale
Classe CSS, altrimenti questa classe viene rimossa.
Per rendere il this.switcherTargets
costruire il lavoro, dobbiamo definire gli obiettivi dello stimolo nel seguente modo:
target statici = ["switcher"]
Inoltre, aggiungere data-obiettivo
attributi con valori di interruttore
per il Li
S:
initialize () // ... this.element.innerHTML = languages.map ((lang) => return '
Un'altra cosa importante da considerare è che i file di traduzione potrebbero richiedere del tempo per essere caricati, e dobbiamo attendere il completamento di questa operazione prima di consentire il cambio delle impostazioni internazionali. Pertanto, approfittiamo del caricato
richiama:
initialize () i18n.on ('loaded', (loaded) => // <--- let languages = [ title: 'English', code: 'en', title: 'Русский', code: 'ru' ] this.element.innerHTML = languages.map((lang) => ritorno '
Infine, non dimenticare di rimuovere setTimeout
dal loadUsers ()
metodo:
loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json) this.localize ())
Dopo aver cambiato la lingua, vorrei aggiungere un ?Lang
Ottieni parametro per l'URL contenente il codice della lingua scelta. L'aggiunta di un parametro GET senza ricaricare la pagina può essere facilmente eseguita con l'aiuto dell'API Cronologia:
imposta currentLang (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()
L'ultima cosa che implementeremo oggi è la possibilità di impostare le impostazioni internazionali in base alle preferenze dell'utente. Un plugin chiamato LanguageDetector può aiutarci a risolvere questo compito. Aggiungi un nuovo pacchetto di filati:
filato aggiungere i18next-browser-languagedetector
Importare LanguageDetector
dentro il i18n / config.js file:
importare LngDetector da 'i18next-browser-languagedetector'
Ora modificare la configurazione:
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) );
Il ordine
opzione elenca tutte le tecniche (ordinate in base alla loro importanza) che il plugin dovrebbe provare per "indovinare" le impostazioni locali preferite:
stringa della domanda
significa controllare un parametro GET contenente il codice locale.lookupQuerystring
imposta il nome del parametro GET da usare, che è Lang
nel nostro caso.navigatore
significa ottenere dati locali dalla richiesta dell'utente.htmlTag
implica il recupero delle impostazioni internazionali preferite dal Lang
attributo del html
etichetta.In questo articolo abbiamo dato un'occhiata a I18next, una soluzione popolare per tradurre le applicazioni JavaScript con facilità. Hai imparato come integrare I18next con il framework Stimulus, configurarlo e caricare i file di traduzione in modo asincrono. Inoltre, hai visto come passare da un locale all'altro e impostare la lingua predefinita in base alle preferenze dell'utente.
I18next ha alcune opzioni di configurazione aggiuntive e molti plugin, quindi assicurati di consultare la documentazione ufficiale per saperne di più. Nota inoltre che Stimulus non ti obbliga a utilizzare una soluzione di localizzazione specifica, quindi potresti provare a utilizzare qualcosa come jQuery.I18n o Polyglot.
È tutto per oggi! Grazie per la lettura, e fino alla prossima volta.