Warum ein Blogbeitrag über die ehrwürdige, aber veraltete JavaScript-Bibliothek, welche Dinge wie das Durchlaufen und Manipulieren von HTML-Dokumenten usw. einfacher gemacht hat?
Weil mit einer Kombination aus Vielseitigkeit und Erweiterbarkeit jQuery die Art und Weise verändert hat, wie Millionen von Menschen JavaScript schreiben!
Und Sie können dies an der enormen Verwendung von jQuery sehen:
Basierend auf Umfragen zur Webtechnologie von w3Techs wird jQuery von 95.4 % aller Webseiten benutzt, deren JavaScript-Bibliothek sie kennen. Und von 78,3 % aller Webseiten genutzt.
Wenn es um die jQuery-Lokalisierung geht, ist eines der beliebtesten Frameworks i18next mit seiner jQuery-Erweiterung jquery-i18next, und das aus guten Gründen:
i18next wurde Ende 2011 erstellt. Es ist älter als die meisten Bibliotheken, die Sie heutzutage verwenden, einschliesslich Ihrer wichtigsten Frontend-Technologie (React, Angular, Vue, ...). Nur jQuery ist älter 😉 ➡️ nachhaltig
Basierend darauf, wie lange i18next bereits Open Source verfügbar ist, gibt es keinen echten i18n-Fall, der nicht mit i18next gelöst werden könnte. ➡️ reif
i18next kann in jeder Umgebung mit Javascript (und einigen Nicht-Javascript - .net, elm, iOS, Android, Ruby, ...) verwendet werden, mit jedem UI-Framework, mit jedem i18n-Format, ... die Möglichkeiten sind endlos. ➡️ erweiterbar
Es gibt viele Funktionen und Möglichkeiten, die Sie mit i18next im Vergleich zu anderen regulären 18n-Frameworks erhalten. ➡️ reich
Hier finden Sie weitere Informationen darüber, warum i18next so besonders ist und wie es funktioniert.
Fangen wir an...
Voraussetzungen
Stellen Sie sicher, dass Sie eine jQuery-basierte Website oder Webanwendung haben. Wenn Sie etwas Erfahrung mit einfachem HTML, JavaScript und grundlegendem jQuery haben, ist es am besten, bevor Sie zu jquery-i18next springen. Dieses jQuery i18n-Beispiel ist nicht als jQuery-Anfänger-Tutorial gedacht.
Einstieg
Nehmen Sie Ihr eigenes jQuery-Projekt oder erstellen Sie ein neues.
Ich habe hier eine tolle Landingpage 😉
Wir werden die Website anpassen, um die Sprache gemäss den Vorlieben des Benutzers zu erkennen.
Und wir werden einen Sprachumschalter erstellen, um den Inhalt zwischen verschiedenen Sprachen zu ändern.
Lassen Sie uns einige i18next-Abhängigkeiten installieren:
$(function () { // use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', resources: { en: { translation: { // here we will place our translations... } } } }, (err, t) => { if (err) returnconsole.error(err);
// for options see // https://github.com/i18next/jquery-i18next#initialize-the-plugin jqueryI18next.init(i18next, $, { useOptionsAttr: true });
$(function () { // use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', resources: { en: { translation: { intro: { title: 'Landing Page', subTitle: 'Some subtitle' } } }, de: { translation: { intro: { title: 'Webseite', subTitle: 'Ein Untertitel' } } } } }, (err, t) => { if (err) returnconsole.error(err);
// for options see // https://github.com/i18next/jquery-i18next#initialize-the-plugin jqueryI18next.init(i18next, $, { useOptionsAttr: true });
// fill language switcher Object.keys(lngs).map((lng) => { const opt = new Option(lngs[lng].nativeName, lng); if (lng === i18next.resolvedLanguage) { opt.setAttribute("selected", "selected"); } $('#languageSwitcher').append(opt); }); $('#languageSwitcher').change((a, b, c) => { const chosenLng = $(this).find("option:selected").attr('value'); i18next.changeLanguage(chosenLng, () => { rerender(); }); });
rerender(); }); });
🥳 Grossartig, Sie haben gerade Ihren ersten Sprachumschalter erstellt!
Dank i18next-browser-languageDetector versucht es jetzt, die Browsersprache zu erkennen und diese Sprache automatisch zu verwenden, wenn Sie die Übersetzungen dafür bereitgestellt haben. Die manuell ausgewählte Sprache im Sprachumschalter wird im localStorage beibehalten, beim nächsten Besuch der Seite wird diese Sprache als bevorzugte Sprache verwendet.
Head informationen übersetzen
Lassen Sie uns auch den Titel und die Beschreibung der Website übersetzen.
Wir tun dies, indem wir unsere render-Funktion erweitern und die zusätzlichen Übersetzungsressourcen hinzufügen:
Sie sehen also, das geht auch mit der Hilfsfunktion $.t().
Lassen Sie uns das DOM überprüfen:
Sehr gut 👍
Interpolation und Pluralisierung
i18next geht über die Bereitstellung der standardmässigen i18n-Funktionen hinaus.
Aber sicher ist es in der Lage, Plurale und Interpolation zu verarbeiten.
Zählen wir jedes Mal, wenn die Sprache geändert wird:
Erinnern wir uns an den Zähler in der Variable languageChangedCounter und erhöhen ihn bei jedem Sprachwechsel.
...und erweitern die Übersetzungsressourcen:
$(function () { // use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', resources: { en: { translation: { head: { title: 'My Awesome Landing-Page', description: 'The description of this awesome landing page.' }, intro: { title: 'Landing Page', subTitle: 'Some subtitle' }, footer: { counter_one: 'Changed language just once', counter_other: 'Changed language already {{count}} times', date: 'It\'s {{date, LLLL}}' } } }, de: { translation: { head: { title: 'Meine grossartige Webseite', description: 'Die Beschreibung dieser grossartigen Webseite.' }, intro: { title: 'Webseite', subTitle: 'Ein Untertitel' }, footer: { counter_one: 'Die Sprache wurde erst ein mal gewechselt', counter_other: 'Die Sprache wurde {{count}} mal gewechselt', date: 'Es ist {{date, LLLL}}' } } } } }, (err, t) => { if (err) returnconsole.error(err);
// define the formatter function i18next.services.formatter.add('LLLL', (value, lng, options) => { return moment(value).locale(lng).format('LLLL'); });
// for options see // https://github.com/i18next/jquery-i18next#initialize-the-plugin jqueryI18next.init(i18next, $, { useOptionsAttr: true });
// fill language switcher Object.keys(lngs).map((lng) => { const opt = new Option(lngs[lng].nativeName, lng); if (lng === i18next.resolvedLanguage) { opt.setAttribute("selected", "selected"); } $('#languageSwitcher').append(opt); }); let languageChangedCounter = 0; $('#languageSwitcher').change((a, b, c) => { const chosenLng = $(this).find("option:selected").attr('value'); i18next.changeLanguage(chosenLng, () => { rerender(); // language changed message languageChangedCounter++; $('#languageChangedNotification').localize({ count: languageChangedCounter }) if (languageChangedCounter === 1) { $('#languageChangedNotification').show(); } }); });
rerender(); }); });
😎 Cool, jetzt haben wir eine sprachspezifische Datumsformatierung!
Englisch:
Deutsch:
Kontext
Was ist mit einer bestimmten Begrüssungsnachricht basierend auf der aktuellen Tageszeit? also morgens, abends usw.
Dies ist dank der context-Funktion von i18next möglich.
Lassen Sie uns eine getGreetingTime-Funktion erstellen und das Ergebnis als Kontextinformationen für unsere Fusszeilenübersetzung verwenden.
Und fügen Sie einige kontextspezifische Übersetzungsschlüssel hinzu:
resources: { en: { translation: { // ... footer: { counter_one: 'Changed language just once', counter_other: 'Changed language already {{count}} times', date: 'It\'s {{date, LLLL}}', date_afternoon: 'Good afternoon! It\'s {{date, LLLL}}', date_evening: 'Good evening! Today was the {{date, LLLL}}', date_morning: 'Good morning! Today is {{date, LLLL}} | Have a nice day!' } } }, de: { translation: { // ... footer: { counter_one: 'Die Sprache wurde erst ein mal gewechselt', counter_other: 'Die Sprache wurde {{count}} mal gewechselt', date: 'Es ist {{date, LLLL}}', date_afternoon: 'Guten Tag! Es ist {{date, LLLL}}', date_evening: 'Guten Abend! Heute war {{date, LLLL}}', date_morning: 'Guten Morgen! Heute ist {{date, LLLL}} | Wünsche einen schönen Tag!' } } } }
😁 Ja, es funktioniert!
Übersetzungen vom Code trennen
Die Übersetzungen in unserer i18n.js-Datei zu haben, funktioniert, ist aber für Übersetzer nicht so angenehm.
Lassen Sie uns die Übersetzungen vom Code trennen und sie in dedizierte JSON-Dateien verschieben.
$(function () { // use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // i18next-http-backend // loads translations from your server // https://github.com/i18next/i18next-http-backend .use(i18nextHttpBackend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en' // i.e. if you want to customize a different translation path, // use the loadPath option: // backend: { // loadPath: '/assets/locales/{{lng}}/{{ns}}.json' // } }, (err, t) => { if (err) returnconsole.error(err);
// ... }); });
Jetzt werden die Übersetzungen asynchron geladen, daher kann es sein, dass die Benutzeroberfläche etwas später aktualisiert wird, sobald die Übersetzungen geladen sind.
Um dieses Verhalten zu optimieren, können Sie eine Art Ladeanzeige anzeigen, bis i18next initialisiert ist.
So etwas wie:
1 2 3 4
<divid="loader">Loading...</div> <divid="content"style="display: none;"> <!-- your real content --> </div>
1 2
$('#loader').hide(); $('#content').show();
Jetzt sieht Ihre App immer noch gleich aus, aber Ihre Übersetzungen sind getrennt.
Wenn Sie eine neue Sprache unterstützen möchten, erstellen Sie einfach einen neuen Ordner und eine neue JSON-Übersetzungsdatei.
Dies gibt Ihnen die Möglichkeit, die Übersetzungen an die Übersetzer zu senden.
Oder wenn Sie mit einem Übersetzungsmanagementsystem arbeiten, können Sie einfach die Dateien mit einer CLI synchronisieren.
Besseres Übersetzungsmanagement
Indem Sie die Übersetzungen an einige Übersetzer oder Übersetzungsagenturen senden, haben Sie mehr Kontrolle und einen direkten Kontakt mit ihnen. Das bedeutet aber auch mehr Arbeit für Sie.
Dies ist ein traditioneller Weg. Beachten Sie jedoch, dass das Versenden von Dateien immer einen Overhead verursacht.
Gibt es eine bessere Option?
Auf jeden Fall!
i18next hilft dabei, die Anwendung zu übersetzen, und das ist grossartig – aber es steckt noch mehr dahinter.
Wie integrieren Sie eventuelle Übersetzungsdienste/-agenturen?
Wie behalten Sie den Überblick über neue oder entfernte Inhalte?
Wie gehen Sie mit der richtigen Versionierung um?
Wie stellen Sie Übersetzungsänderungen bereit, ohne Ihre vollständige Anwendung bereitzustellen?
Nachdem Sie die zu lokalisierenden Übersetzungen importiert haben, löschen Sie den Ordner locales und passen Sie die Datei i18n.js an, um das i18next-locize-Backend zu verwenden, und stellen Sie sicher, dass Sie die Projekt-ID und den API-Schlüssel aus Ihrem locize-Projekt kopieren:
const locizeOptions = { projectId: '8d751621-323e-4bda-94c8-7d2368102e62', apiKey: '302aca54-2ea8-4b9f-b5f0-df1369c59427'// YOU should not expose your apps API key to production!!! };
$(function () { // use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(i18nextLocizeBackend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', backend: locizeOptions }, (err, t) => { if (err) returnconsole.error(err);
// ... }); });
i18next-locize-backend bietet eine Funktion zum Abrufen der verfügbaren Sprachen direkt von locize an, verwenden wir sie:
const locizeOptions = { projectId: '8d751621-323e-4bda-94c8-7d2368102e62', apiKey: '302aca54-2ea8-4b9f-b5f0-df1369c59427'// YOU should not expose your apps API key to production!!! };
$(function () { const locizeBackend = new i18nextLocizeBackend(locizeOptions, (err, opts, lngs) => { if (err) returnconsole.error(err);
// use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(locizeBackend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', backend: locizeOptions }, (err, t) => { if (err) returnconsole.error(err);
Zusätzlich mit Hilfe des Auto-MachineTranslation-Workflows und der Verwendung der saveMissing-Funktionalität werden während der Entwicklung der App nicht nur neue Schlüssel zur automatischen Lokalisierung hinzugefügt, sondern auch automatisch per maschineller Übersetzung in die Zielsprachen übersetzt.
Sehen Sie sich dieses Video an, um zu sehen, wie der Arbeitsablauf der automatischen maschinellen Übersetzung aussieht!
const locizeOptions = { projectId: '8d751621-323e-4bda-94c8-7d2368102e62', apiKey: '302aca54-2ea8-4b9f-b5f0-df1369c59427'// YOU should not expose your apps API key to production!!! };
i18next.on('editorSaved', rerender); // used for the inContext editor
$(function () { const locizeBackend = new i18nextLocizeBackend(locizeOptions, (err, opts, lngs) => { if (err) returnconsole.error(err);
// use plugins and options as needed, for options, detail see // https://www.i18next.com i18next // locize-editor // InContext Editor of locize .use(locize.locizePlugin) // locize-lastused (do not use this in production) // sets a timestamp of last access on every translation segment on locize // -> safely remove the ones not being touched for weeks/months // https://github.com/locize/locize-lastused .use(locizeLastUsed) // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(locizeBackend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(i18nextBrowserLanguageDetector) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ ...opts, debug: true, fallbackLng: 'en', backend: locizeOptions, locizeLastUsed: locizeOptions, saveMissing: true // interpolation: { // // legacy usage // format: (value, format, lng) => { // if (value instanceof Date) { // return moment(value).locale(lng).format(format); // } // return value; // } // } }, (err, t) => { if (err) returnconsole.error(err);
Während der Entwicklung werden Sie nun weiterhin fehlende Schlüssel speichern und die lastUsed Funktion nutzen.
Und in der Produktionsumgebung sollten Sie die Funktionen saveMissing und lastused deaktivieren oder entfernen, und auch der API-Schlüssel sollte nicht angezeigt werden.