Stimulus-Apps mit I18Next übersetzen

In meinem vorherigen Artikel habe ich Stimulus behandelt - ein bescheidenes JavaScript-Framework, das von Basecamp erstellt wurde. Heute spreche ich über die Internationalisierung einer Stimulus-Anwendung, da das Framework keine I18n-Werkzeuge aus der Box enthält. Die Internationalisierung ist ein wichtiger Schritt, vor allem wenn Ihre App von Menschen auf der ganzen Welt verwendet wird. Daher ist ein grundlegendes Verständnis der Vorgehensweise möglicherweise von Nutzen.

Natürlich müssen Sie entscheiden, welche Internationalisierungslösung implementiert werden soll, sei es jQuery.I18n, Polyglot oder eine andere. In diesem Tutorial möchte ich Ihnen ein beliebtes I18n-Framework namens I18next zeigen, das viele coole Funktionen bietet und viele zusätzliche Plugins von Drittanbietern enthält, um den Entwicklungsprozess noch weiter zu vereinfachen. Trotz all dieser Funktionen ist I18next kein komplexes Werkzeug, und Sie müssen nicht viel Dokumentation studieren, um zu beginnen.

In diesem Artikel erfahren Sie, wie Sie die Unterstützung von I18n in Stimulus-Anwendungen mithilfe der I18next-Bibliothek aktivieren. Konkret sprechen wir über:

  • I18nächste Konfiguration
  • Übersetzungsdateien und laden sie asynchron
  • Durchführen von Übersetzungen und Übersetzen der gesamten Seite in einem Arbeitsgang
  • Arbeit mit Pluralformen und Gender-Informationen
  • zwischen Gebietsschemas wechseln und das ausgewählte Gebietsschema im Parameter GET beibehalten
  • Festlegen des Gebietsschemas basierend auf den Benutzereinstellungen

Der Quellcode ist im GitHub-Repo des Tutorials verfügbar.

Bootstrapping einer Stimulus-App

Um zu beginnen, klonen wir das Stimulus Starter-Projekt und installieren alle Abhängigkeiten mit dem Yarn-Paketmanager:

Git Klon https://github.com/stimulusjs/stimulus-starter.git cd Stimulus-Starter-Garn installieren

Wir werden eine einfache Webanwendung erstellen, die Informationen über die registrierten Benutzer lädt. Für jeden Benutzer zeigen wir sein Login und die Anzahl der Fotos an, die er bisher hochgeladen hat (es ist nicht wichtig, was diese Fotos sind).. 

Außerdem werden wir oben auf der Seite einen Sprachumschalter präsentieren. Wenn eine Sprache ausgewählt wird, sollte die Benutzeroberfläche sofort übersetzt werden, ohne dass Seiten neu geladen werden müssen. Außerdem sollte die URL mit einem ?Gebietsschema GET-Parameter, der angibt, welches Gebietsschema derzeit verwendet wird. Wenn die Seite bereits mit diesem Parameter geladen wurde, sollte die richtige Sprache automatisch eingestellt werden.

Okay, lass uns unsere Benutzer rendern. Fügen Sie dem folgenden Code hinzu public / index.html Datei:

Hier benutzen wir die Benutzer Controller und Bereitstellung einer URL, von der aus unsere Benutzer geladen werden können. In einer realen Anwendung hätten wir wahrscheinlich ein serverseitiges Skript, das Benutzer aus der Datenbank abruft und mit JSON antwortet. Lassen Sie uns für dieses Tutorial jedoch einfach alle erforderlichen Daten in die public / api / users / index.json Datei:

["login": "johndoe", "photos_count": "15", "gender": "male", "login": "annsmith", "photos_count": "20", "gender": "female "] 

Erstellen Sie jetzt ein neues src / controller / users_controller.js Datei:

Import Controller aus "stimulus" Export-Standardklasse erweitert Controller connect () this.loadUsers ()

Sobald der Controller mit dem DOM verbunden ist, laden wir unsere Benutzer asynchron mit Hilfe von loadUsers () Methode:

 loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json))

Diese Methode sendet eine Abrufanforderung an die angegebene URL, erfasst die Antwort und rendert schließlich die Benutzer:

 renderUsers (Benutzer) let content = "JSON.parse (Benutzer) .forEach ((Benutzer) => content + = '
Login: $ user.login
Hat $ user.photos_count Foto (s) hochgeladen

') this.element.innerHTML = Inhalt

Renderbenutzer (), wiederum analysiert JSON, erstellt einen neuen String mit dem gesamten Inhalt und zeigt diesen Inhalt schließlich auf der Seite an (this.element wird den tatsächlichen DOM-Knoten zurückgeben, mit dem der Controller verbunden ist div in unserem Fall).

I18weiter

Jetzt werden wir I18next in unsere App integrieren. Fügen Sie unserem Projekt zwei Bibliotheken hinzu: I18next selbst und ein Plugin, um das asynchrone Laden von Übersetzungsdateien vom Backend aus zu ermöglichen:

garne hinzufügen i18next i18next-xhr-backend

Wir werden alles, was mit I18next zu tun hat, separat speichern src / i18n / config.js Datei, so erstellen Sie es jetzt:

i18next aus 'i18next' importieren I18nXHR aus 'i18next-xhr-backend' importieren const i18n = i18next.use (I18nXHR). '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)); i18n als i18n exportieren

Gehen wir von oben nach unten durch, um zu verstehen, was hier vor sich geht:

  • verwenden (I18nXHR) Aktiviert das Plugin i18next-xhr-backend.
  • fallbackLng sagt ihm, Englisch als Ausweichsprache zu verwenden.
  • Whitelist Es können nur Englisch und Russisch eingestellt werden. Natürlich können Sie auch andere Sprachen wählen.
  • Vorspannung weist Übersetzungsdateien an, von dem Server vorgeladen zu werden, anstatt sie zu laden, wenn die entsprechende Sprache ausgewählt ist.
  • ns bedeutet "Namespace" und akzeptiert entweder eine Zeichenfolge oder ein Array. In diesem Beispiel haben wir nur einen Namespace, aber für größere Anwendungen können Sie andere Namespaces wie AdministratorWagen, Profil, usw. Für jeden Namespace sollte eine separate Übersetzungsdatei erstellt werden.
  • defaultNS setzt Benutzer um den Standard-Namespace zu sein.
  • FallbackNS Deaktiviert den Namespace-Fallback.
  • debuggen ermöglicht die Anzeige von Debugging-Informationen in der Browserkonsole. Insbesondere wird angegeben, welche Übersetzungsdateien geladen werden, welche Sprache ausgewählt ist usw. Sie werden diese Einstellung wahrscheinlich deaktivieren, bevor Sie die Anwendung für die Produktion bereitstellen.
  • Backend enthält die Konfiguration für das I18nXHR-Plugin und gibt an, woher die Übersetzungen geladen werden. Beachten Sie, dass der Pfad den Titel des Gebietsschemas enthalten sollte, während die Datei nach dem Namespace benannt werden muss und das .Json Erweiterung
  • Funktion (Err, T) ist der Callback, der ausgeführt werden soll, wenn I18next bereit ist (oder wenn ein Fehler ausgelöst wurde).

Lassen Sie uns als Nächstes Übersetzungsdateien erstellen. Übersetzungen für die russische Sprache sollten in die public / i18n / ru / users.json Datei:

"login": "Логин"

Anmeldung Hier ist der Übersetzungsschlüssel, während Логин ist der anzuzeigende Wert.

Englische Übersetzungen wiederum sollten in die public / i18n / de / users.json Datei:

 "Einloggen Einloggen" 

Um sicherzustellen, dass I18next funktioniert, können Sie dem Callback in der folgenden Zeile Code hinzufügen i18n / config.js Datei:

// config geht hier hin… function (err, t) if (err) return console.error (err) console.log (i18n.t ('login'))

Hier verwenden wir eine Methode namens t das heißt "übersetzen". Diese Methode akzeptiert einen Übersetzungsschlüssel und gibt den entsprechenden Wert zurück.

Es kann jedoch viele Teile der Benutzeroberfläche geben, die übersetzt werden müssen, und zwar durch Verwendung der t Methode wäre ziemlich langweilig. Stattdessen schlage ich vor, dass Sie ein anderes Plugin namens loc-i18next verwenden, mit dem Sie mehrere Elemente gleichzeitig übersetzen können.

Übersetzen in einem Rutsch

Installieren Sie das loc-i18next-Plugin:

Garn hinzufügen loc-i18next

Importiere es oben in der src / i18n / config.js Datei:

locI18next von 'loc-i18next' importieren

Geben Sie nun die Konfiguration für das Plugin selbst an:

// other config const loci18n = locI18next.init (i18n, selectorAttr: 'data-i18n', optionsAttr: 'data-i18n-options', useOptionsAttr: true); loci18n als loci18n exportieren, i18n als i18n

Hier sind einige Dinge zu beachten:

  • locI18next.init (i18n) erstellt eine neue Instanz des Plugins basierend auf der zuvor definierten Instanz von I18next.
  • SelectorAttr Gibt an, welches Attribut zum Erkennen von Elementen verwendet werden soll, für die eine Lokalisierung erforderlich ist. Grundsätzlich sucht loc-i18next nach solchen Elementen und verwendet den Wert von data-i18n Attribut als Übersetzungsschlüssel.
  • OptionenAttr gibt an, welches Attribut zusätzliche Übersetzungsoptionen enthält.
  • useOptionsAttr weist das Plugin an, die zusätzlichen Optionen zu verwenden.

Unsere Benutzer werden asynchron geladen. Daher müssen wir warten, bis diese Operation abgeschlossen ist, und erst dann eine Lokalisierung durchführen. Lassen Sie uns jetzt einfach einen Timer einstellen, der zwei Sekunden warten soll, bevor Sie die lokalisieren() Methode - das ist natürlich ein temporärer Hack.

 loci18n aus '… / i18n / config' importieren // anderer Code… loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json) setTimeout (()) => // <--- this.localize() , '2000') ) 

Code der lokalisieren() Methode selbst:

 localize () loci18n ('. Benutzer')

Wie Sie sehen, müssen wir nur einen Selektor an das loc-i18next-Plugin übergeben. Alle Elemente im Inneren (die die data-i18n Attributsatz) wird automatisch lokalisiert.

Jetzt optimieren Sie die Renderbenutzer Methode. Im Moment übersetzen wir nur das "Login" -Wort:

 renderUsers (Benutzer) let content = "JSON.parse (Benutzer) .forEach ((Benutzer) => content + = '
ID: $ user.id
: $ user.login
Hat $ user.photos_count Foto (s) hochgeladen

') this.element.innerHTML = Inhalt

Nett! Laden Sie die Seite neu, warten Sie zwei Sekunden und stellen Sie sicher, dass das Wort "Login" für jeden Benutzer angezeigt wird.

Vielfalt und Geschlecht

Wir haben einen Teil der Schnittstelle lokalisiert, was wirklich cool ist. Jeder Benutzer hat jedoch zwei weitere Felder: die Anzahl der hochgeladenen Fotos und das Geschlecht. Da wir nicht vorhersagen können, wie viele Fotos jeder Benutzer haben wird, sollte das Wort "Foto" auf der Grundlage der angegebenen Anzahl ordnungsgemäß pluriert werden. Dazu benötigen wir eine Daten-I18N-Optionen zuvor konfiguriertes Attribut Um die Zählung anzugeben, Daten-I18N-Optionen sollte mit dem folgenden Objekt zugewiesen werden: "count": YOUR_COUNT.

Die geschlechtsspezifische Information sollte ebenfalls berücksichtigt werden. Das Wort "hochgeladen" in Englisch kann sowohl für Männer als auch für Frauen verwendet werden, aber in Russisch wird es entweder "загрузил" oder "загрузила", also brauchen wir Daten-I18N-Optionen wieder was hat "context": "GENDER" als Wert. Beachten Sie übrigens, dass Sie diesen Kontext verwenden können, um andere Aufgaben zu erledigen, nicht nur, um Genderinformationen bereitzustellen.

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

') this.element.innerHTML = Inhalt

Aktualisieren Sie nun die englischen Übersetzungen:

"login": "Login", "uploaded": "Hat hochgeladen", "photos": "ein Foto", "photos_plural": "count photos"

Nichts hier komplex. Da uns für Englisch die Gender-Informationen (also der Kontext) nicht wichtig sind, sollte der Übersetzungsschlüssel einfach sein hochgeladen. Um korrekt pluralisierte Übersetzungen bereitzustellen, verwenden wir die Fotos und photos_plural Schlüssel. Das Anzahl Teil ist Interpolation und wird durch die tatsächliche Zahl ersetzt.

In Bezug auf die russische Sprache sind die Dinge komplexer:

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

Beachten Sie zunächst, dass wir beides haben uploaded_male und uploaded_female Schlüssel für zwei mögliche Kontexte. Pluralisierungsregeln sind im Russischen auch komplexer als im Englischen, daher müssen nicht zwei, sondern drei mögliche Ausdrücke angegeben werden. I18next unterstützt viele Standardsprachen, und dieses kleine Tool kann Ihnen helfen zu verstehen, welche Pluralisierungsschlüssel für eine bestimmte Sprache angegeben werden sollten.

Gebietsschema wechseln

Wir sind mit der Übersetzung unserer Anwendung fertig, aber die Benutzer sollten zwischen den Ländereinstellungen wechseln können. Fügen Sie daher eine neue "Sprachumschalter" -Komponente hinzu public / index.html Datei:

    Fertige den entsprechenden Controller in der src / controller / languages_controller.js Datei:

    Controller aus "stimulus" importieren i18n, loci18n aus '… / i18n / config' importieren Standardklasse erweitert Controller initialize () let languages ​​= [title: 'English', Code: 'en', title: 'Русский', code: 'ru'] this.element.innerHTML = languages.map ((lang) => return '
  • $ lang.title
  • ' ).Beitreten(")

    Hier benutzen wir die initialisieren() Rückruf, um eine Liste der unterstützten Sprachen anzuzeigen. Jeder li hat ein Datenaktion Attribut, das die Methode angibt (switchSprache, sollte in diesem Fall ausgelöst werden, wenn das Element angeklickt wird.

    Nun füge das hinzu switchLanguage () Methode:

     switchLanguage (e) this.currentLang = e.target.getAttribute ("data-lang")

    Es nimmt einfach das Ziel des Ereignisses und erfasst den Wert der data-lang Attribut.

    Ich möchte auch einen Getter und Setter für die hinzufügen currentLang Attribut:

     get currentLang () return this.data.get ("currentLang") set currentLang (lang) if (i18n.language! == lang) i18n.changeLanguage (lang) if (this.currentLang! == lang ) this.data.set ("currentLang", lang) loci18n ('body') this.highlightCurrentLang ()

    Der Getter ist sehr einfach - wir holen den Wert der aktuell verwendeten Sprache ab und geben ihn zurück.

    Der Setter ist komplexer. Als erstes benutzen wir die Sprache ändern Methode, wenn die aktuell eingestellte Sprache nicht der ausgewählten entspricht. Außerdem speichern wir das neu ausgewählte Gebietsschema unter data-current-lang Attribut (auf das im Getter zugegriffen wird), Lokalisierung des Hauptteils der HTML-Seite mithilfe des loc-i18next-Plugins und Hervorhebung des aktuell verwendeten Gebietsschemas.

    Lass uns die codieren highlightCurrentLang ():

     highlightCurrentLang () this.switcherTargets.forEach ((el, i) => el.classList.toggle ("current", this.currentLang === el.getAttribute ("data-lang")))

    Hier durchlaufen wir eine Reihe von Locale-Switchern und vergleichen deren Werte data-lang Attribute für den Wert des aktuell verwendeten Gebietsschemas. Stimmen die Werte überein, wird dem Switcher ein zugewiesen aktuell CSS-Klasse, sonst wird diese Klasse entfernt.

    Um das zu machen this.switcherTargets Um Arbeit zu konstruieren, müssen wir Stimulus-Ziele folgendermaßen definieren:

    statische Ziele = ["Switcher"]

    Auch hinzufügen Datenziel Attribute mit Werten von Umschalter für die lis:

     initialize () //… this.element.innerHTML = languages.map ((lang) => return '
  • $ lang.title
  • ' ).Beitreten(") //…

    Zu beachten ist auch, dass das Laden von Übersetzungsdateien einige Zeit dauern kann. Wir müssen warten, bis dieser Vorgang abgeschlossen ist, bevor das Gebietsschema gewechselt werden kann. Nutzen wir also die geladen Ruf zurück:

     initialize () i18n.on ('geladen', (geladen) => // <--- let languages = [ title: 'English', code: 'en', title: 'Русский', code: 'ru' ] this.element.innerHTML = languages.map((lang) =>  Rückkehr '
  • $ lang.title
  • '). join (") this.currentLang = i18n.language)

    Vergessen Sie nicht zu entfernen setTimeout von dem loadUsers () Methode:

     loadUsers () fetch (this.data.get ("url")) .then (response => response.text ()) .then (json => this.renderUsers (json) this.localize ())

    Dauerhaftes Gebietsschema in der URL

    Nachdem das Gebietsschema gewechselt wurde, möchte ich eine hinzufügen ?lang GET-Parameter an die URL, die den Code der ausgewählten Sprache enthält. Das Anfügen eines GET-Parameters ohne erneutes Laden der Seite kann mit Hilfe der History-API problemlos durchgeführt werden:

     set 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()  

    Gebietsschema ermitteln

    Das letzte, was wir heute implementieren werden, ist die Möglichkeit, das Gebietsschema basierend auf den Präferenzen des Benutzers festzulegen. Ein Plugin namens LanguageDetector kann uns dabei helfen, diese Aufgabe zu lösen. Fügen Sie ein neues Garnpaket hinzu:

    garne addiere i18next-browser-languagedetector

    Einführen SprachDetektor in der i18n / config.js Datei:

    LngDetector aus 'i18next-browser-languagedetector' importieren

    Jetzt die Konfiguration anpassen:

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

    Das Auftrag Option listet alle Techniken (sortiert nach ihrer Wichtigkeit) auf, die das Plugin ausprobieren soll, um das bevorzugte Gebietsschema zu erraten:

    • Querzeichenfolge bedeutet das Überprüfen eines GET-Parameters, der den Code des Gebietsschemas enthält.
    • LookupQuerystring Legt den Namen des zu verwendenden GET-Parameters fest lang in unserem Fall.
    • Navigator bedeutet, aus der Benutzeranfrage Länderdaten abzurufen.
    • htmlTag beinhaltet das Abrufen des bevorzugten Gebietsschemas aus der lang Attribut des html Etikett.

    Fazit

    In diesem Artikel haben wir einen Blick auf I18next - eine beliebte Lösung zum einfachen Übersetzen von JavaScript-Anwendungen - geworfen. Sie haben gelernt, I18next in das Stimulus-Framework zu integrieren, zu konfigurieren und Übersetzungsdateien asynchron zu laden. Außerdem haben Sie gesehen, wie Sie zwischen den Gebietsschemas wechseln und die Standardsprache basierend auf den Benutzereinstellungen festlegen.

    I18next bietet einige zusätzliche Konfigurationsoptionen und viele Plugins. Sehen Sie sich daher die offizielle Dokumentation an, um mehr zu erfahren. Beachten Sie auch, dass Stimulus Sie nicht zwingt, eine bestimmte Lokalisierungslösung zu verwenden. Sie können also auch etwas wie jQuery.I18n oder Polyglot verwenden. 

    Das ist alles für heute! Vielen Dank fürs Mitlesen und bis zum nächsten Mal.