Umgang mit Locale-Fallback, wenn die bevorzugte Locale nicht verfügbar ist

Automatische Auswahl unterstützter Sprachen, wenn Benutzer nicht unterstützte Locales bevorzugen

Einführung

Nicht jede Webanwendung unterstützt jede Sprache der Welt. Wenn ein Benutzer eine Sprache bevorzugt, die Ihre Anwendung nicht unterstützt, benötigen Sie einen Fallback-Mechanismus, um Inhalte in der nächstbesten Sprache anzuzeigen, anstatt Fehler oder unübersetzte Texte zu zeigen.

Locale-Fallback ist der Prozess der Auswahl einer alternativen Locale, wenn die bevorzugte Locale nicht verfügbar ist. Die Intl-API von JavaScript handhabt dies automatisch, indem sie mehrere Locale-Optionen akzeptiert und die erste auswählt, die sie unterstützt. Dies stellt sicher, dass Ihre Anwendung immer korrekt formatierte Inhalte anzeigt, auch wenn die exakt bevorzugte Locale nicht verfügbar ist.

Diese Lektion erklärt, wie Locale-Fallback in JavaScript funktioniert, wie Sie es effektiv implementieren und wie Sie benutzerdefinierte Fallback-Logik für Anwendungen mit spezifischen Locale-Unterstützungsanforderungen erstellen.

Das Problem mit nicht unterstützten Locales

Wenn Sie einen Locale-Identifier an eine Intl-API übergeben, muss die JavaScript-Runtime diese Locale unterstützen, um Inhalte korrekt zu formatieren. Wenn Sie eine Formatierung für Norwegisch Nynorsk anfordern, die Runtime jedoch nur Norwegisch Bokmål unterstützt, benötigt der Formatter eine Möglichkeit, dies elegant zu handhaben.

Ohne Fallback würden Anwendungen beim Auftreten nicht unterstützter Locales keine Inhalte anzeigen oder unübersetzte Texte zeigen. Benutzer aus Regionen mit weniger verbreiteten Sprachvarianten würden fehlerhafte Benutzeroberflächen erleben.

Betrachten Sie einen Benutzer, der kanadisches Französisch spricht. Wenn Ihre Anwendung nur europäisches Französisch unterstützt, möchten Sie, dass der Formatter europäische französische Konventionen verwendet, anstatt vollständig zu versagen. Obwohl nicht perfekt, bietet dies eine bessere Erfahrung als überhaupt keine Lokalisierung.

Wie die Intl-API automatisch Fallbacks handhabt

Jeder Intl-Konstruktor akzeptiert entweder einen einzelnen Locale-String oder ein Array von Locale-Strings. Wenn Sie ein Array übergeben, wertet die Runtime jede Locale in der Reihenfolge aus und verwendet die erste, die sie unterstützt.

const locales = ["fr-CA", "fr-FR", "en-US"];
const formatter = new Intl.DateTimeFormat(locales);

const date = new Date("2025-03-15");
console.log(formatter.format(date));
// Uses fr-CA if available
// Falls back to fr-FR if fr-CA is not available
// Falls back to en-US if neither French variant is available

Die Runtime untersucht das Array von links nach rechts. Wenn sie kanadisches Französisch unterstützt, verwendet sie dieses. Falls nicht, versucht sie europäisches Französisch. Wenn keine der französischen Varianten verfügbar ist, fällt sie auf amerikanisches Englisch zurück.

Dieser automatische Fallback bedeutet, dass Sie die Unterstützung nicht manuell prüfen oder Fehler behandeln müssen, wenn Sie bestimmte Locales anfordern. Die Intl-API garantiert, dass sie eine unterstützte Locale auswählt oder auf die Systemvorgabe zurückfällt.

Mehrere Locale-Optionen bereitstellen

Der einfachste Weg, Fallback zu implementieren, besteht darin, ein Array von Locales in der Reihenfolge der Präferenz zu übergeben. Dies funktioniert mit allen Intl-Konstruktoren, einschließlich DateTimeFormat, NumberFormat, Collator und anderen.

const locales = ["es-MX", "es-ES", "es", "en"];
const numberFormatter = new Intl.NumberFormat(locales, {
  style: "currency",
  currency: "USD"
});

console.log(numberFormatter.format(1234.56));
// Uses Mexican Spanish if available
// Falls back to European Spanish
// Falls back to generic Spanish
// Falls back to English as final option

Dieses Muster bietet einen Pfad für graceful degradation. Benutzer erhalten Inhalte in ihrem bevorzugten Dialekt, falls verfügbar, dann eine breitere Variante ihrer Sprache, dann eine gemeinsame Fallback-Sprache.

Die Reihenfolge ist wichtig. Die Runtime wählt die erste Locale aus, die sie unterstützt, platzieren Sie daher die spezifischsten und bevorzugten Locales zuerst.

Verstehen, wie Locale-Matching funktioniert

Wenn Sie mehrere Locales bereitstellen, verwendet die JavaScript-Runtime einen Locale-Matching-Algorithmus, um die beste verfügbare Option auszuwählen. Dieser Algorithmus vergleicht Ihre angeforderten Locales mit dem Satz von Locales, die die Runtime unterstützt.

Wenn eine angeforderte Locale exakt mit einer unterstützten Locale übereinstimmt, verwendet die Runtime sie sofort. Wenn keine exakte Übereinstimmung existiert, kann die Runtime eine verwandte Locale basierend auf Sprach- und Regionscodes auswählen.

Wenn Sie beispielsweise en-AU (australisches Englisch) anfordern, die Laufzeitumgebung jedoch nur en-US und en-GB unterstützt, wird eine dieser englischen Varianten ausgewählt, anstatt auf eine völlig andere Sprache zurückzugreifen.

const locales = ["en-AU", "en"];
const formatter = new Intl.DateTimeFormat(locales);

const resolvedLocale = formatter.resolvedOptions().locale;
console.log(resolvedLocale);
// Might show "en-US" or "en-GB" depending on the runtime
// The runtime selected a supported English variant

Die Methode resolvedOptions() gibt das tatsächliche Gebietsschema zurück, das der Formatierer verwendet. Damit können Sie überprüfen, welches Gebietsschema nach dem Fallback ausgewählt wurde.

Überprüfen, welche Gebietsschemata unterstützt werden

Die statische Methode supportedLocalesOf() prüft, welche Gebietsschemata aus einer Liste von einem bestimmten Intl-Konstruktor unterstützt werden. Diese Methode gibt ein Array zurück, das nur die unterstützten Gebietsschemata enthält.

const requestedLocales = ["fr-CA", "fr-FR", "de-DE", "ja-JP"];
const supportedLocales = Intl.DateTimeFormat.supportedLocalesOf(requestedLocales);

console.log(supportedLocales);
// Output depends on runtime support
// Example: ["fr-FR", "de-DE", "ja-JP"]
// Canadian French was not supported, others were

Diese Methode filtert die angeforderten Gebietsschemata, um anzuzeigen, welche die Laufzeitumgebung ohne Rückgriff auf Standardwerte verwenden kann. Nicht unterstützte Gebietsschemata werden aus dem zurückgegebenen Array entfernt.

Sie können diese Methode verwenden, um die Unterstützung vor dem Erstellen von Formatierern zu überprüfen oder um anzuzeigen, welche Sprachoptionen den Benutzern zur Verfügung stehen.

const availableLocales = ["en-US", "es-MX", "fr-FR", "de-DE", "ja-JP"];
const supported = Intl.NumberFormat.supportedLocalesOf(availableLocales);

console.log("This runtime supports:", supported);
// Shows which of your application locales work in this environment

Jeder Intl-Konstruktor verfügt über eine eigene Methode supportedLocalesOf(), da die Unterstützung von Gebietsschemata zwischen verschiedenen Internationalisierungsfunktionen variieren kann. Eine Laufzeitumgebung unterstützt möglicherweise Französisch für die Zahlenformatierung, aber nicht für die Textsegmentierung.

Erstellen von Fallback-Ketten aus Gebietsschema-Identifikatoren

Wenn Sie wissen, dass Ihre Anwendung bestimmte Gebietsschemata unterstützt, können Sie eine Fallback-Kette erstellen, die progressiv weniger spezifisch wird. Dieses Muster beginnt mit einem vollständigen Gebietsschema-Identifikator und entfernt Komponenten, bis eine Übereinstimmung gefunden wird.

function buildFallbackChain(locale) {
  const chain = [locale];

  const parts = locale.split("-");
  if (parts.length > 1) {
    chain.push(parts[0]);
  }

  chain.push("en");

  return chain;
}

const fallbacks = buildFallbackChain("zh-Hans-CN");
console.log(fallbacks);
// ["zh-Hans-CN", "zh", "en"]

const formatter = new Intl.DateTimeFormat(fallbacks);
// Tries Simplified Chinese for China
// Falls back to generic Chinese
// Falls back to English

Diese Funktion erstellt eine Fallback-Kette, indem sie den Sprachcode aus einem Gebietsschema-Identifikator extrahiert und einen finalen englischen Fallback hinzufügt. Sie können diese Logik erweitern, um ausgefeiltere Fallback-Regeln basierend auf den unterstützten Gebietsschemata Ihrer Anwendung einzubeziehen.

Für Anwendungen, die mehrere Varianten einer Sprache unterstützen, möchten Sie möglicherweise auf verwandte Dialekte zurückgreifen, bevor Sie zu Englisch wechseln.

function buildSmartFallbackChain(locale) {
  const chain = [locale];

  if (locale.startsWith("es-")) {
    chain.push("es-MX", "es-ES", "es");
  } else if (locale.startsWith("fr-")) {
    chain.push("fr-FR", "fr-CA", "fr");
  } else if (locale.startsWith("zh-")) {
    chain.push("zh-Hans-CN", "zh-Hant-TW", "zh");
  }

  const parts = locale.split("-");
  if (parts.length > 1 && !chain.includes(parts[0])) {
    chain.push(parts[0]);
  }

  if (!chain.includes("en")) {
    chain.push("en");
  }

  return chain;
}

const fallbacks = buildSmartFallbackChain("es-AR");
console.log(fallbacks);
// ["es-AR", "es-MX", "es-ES", "es", "en"]
// Tries Argentinian Spanish
// Falls back to Mexican Spanish
// Falls back to European Spanish
// Falls back to generic Spanish
// Falls back to English

Dieser Ansatz stellt sicher, dass Benutzer Inhalte in einem verwandten Dialekt ihrer Sprache sehen, bevor auf Englisch zurückgegriffen wird.

Auswahl eines Locale-Matching-Algorithmus

Die Intl-API unterstützt zwei Locale-Matching-Algorithmen: Lookup und Best Fit. Sie können über die Option localeMatcher beim Erstellen von Formatierern angeben, welcher Algorithmus verwendet werden soll.

Der Lookup-Algorithmus folgt der BCP 47 Lookup-Spezifikation. Er führt ein striktes Matching durch, indem er Locale-Identifikatoren systematisch vergleicht und die erste exakte Übereinstimmung auswählt.

const locales = ["de-DE", "en-US"];
const formatter = new Intl.NumberFormat(locales, {
  localeMatcher: "lookup"
});

console.log(formatter.resolvedOptions().locale);
// Uses strict lookup matching rules

Der Best-Fit-Algorithmus ermöglicht es der Runtime, eine Locale mithilfe ihrer eigenen Matching-Logik auszuwählen. Dieser Algorithmus kann intelligente Entscheidungen darüber treffen, welche Locale die Bedürfnisse des Benutzers am besten erfüllt, auch wenn es keine exakte Übereinstimmung gibt.

const locales = ["de-DE", "en-US"];
const formatter = new Intl.NumberFormat(locales, {
  localeMatcher: "best fit"
});

console.log(formatter.resolvedOptions().locale);
// Uses runtime's best fit algorithm
// Might select a related locale more intelligently

Der Standard-Algorithmus ist Best Fit. Die meisten Anwendungen sollten den Standard verwenden, da er bessere Ergebnisse über verschiedene JavaScript-Runtimes hinweg liefert. Verwenden Sie Lookup nur, wenn Sie vorhersehbares, striktes Matching-Verhalten benötigen.

Verwendung von Browser-Spracheinstellungen für automatisches Fallback

Die Eigenschaft navigator.languages gibt ein Array der bevorzugten Sprachen des Benutzers in der Reihenfolge ihrer Präferenz zurück. Sie können dieses Array direkt an Intl-Konstruktoren übergeben, um ein automatisches Fallback basierend auf den Browser-Einstellungen zu implementieren.

const formatter = new Intl.DateTimeFormat(navigator.languages);

const date = new Date("2025-03-15");
console.log(formatter.format(date));
// Automatically uses user's preferred supported language

Dieser Ansatz lässt den Browser die gesamte Fallback-Logik handhaben. Wenn die erste Präferenz des Benutzers nicht unterstützt wird, versucht die Intl-API automatisch seine zweite Präferenz, dann die dritte und so weiter.

Dieses Muster funktioniert gut, wenn Sie alle Sprachpräferenzen der Benutzer respektieren möchten, ohne manuell Fallback-Ketten zu erstellen.

console.log(navigator.languages);
// ["fr-CA", "fr", "en-US", "en"]

const numberFormatter = new Intl.NumberFormat(navigator.languages, {
  style: "currency",
  currency: "USD"
});

console.log(numberFormatter.format(1234.56));
// Tries Canadian French first
// Falls back through the user's complete preference list

Die Intl-API wertet jede Sprache im Array aus und wählt die erste aus, die sie unterstützt, was dies zu einer robusten Lösung für die Handhabung vielfältiger Benutzerpräferenzen macht.

Kombination von Anwendungsunterstützung mit Benutzerpräferenzen

Für Anwendungen mit begrenzter Locale-Unterstützung können Sie Benutzerpräferenzen filtern, um sie mit Ihren unterstützten Locales abzugleichen, bevor Sie Formatter erstellen. Dies stellt sicher, dass Sie nur Locales verwenden, die Ihre Anwendung verarbeiten kann.

const supportedLocales = ["en-US", "es-MX", "fr-FR", "de-DE"];

function findBestLocale(userPreferences, appSupported) {
  const preferences = userPreferences.map(pref => {
    const parts = pref.split("-");
    return [pref, parts[0]];
  }).flat();

  for (const pref of preferences) {
    if (appSupported.includes(pref)) {
      return pref;
    }
  }

  return appSupported[0];
}

const userLocale = findBestLocale(navigator.languages, supportedLocales);
const formatter = new Intl.DateTimeFormat(userLocale);

console.log(formatter.resolvedOptions().locale);
// Selected locale matches both user preference and app support

Diese Funktion findet die erste Übereinstimmung zwischen Benutzerpräferenzen und unterstützten Locales, einschließlich des Versuchs, Sprachcodes ohne Regionscodes für eine breitere Übereinstimmung zu verwenden.

Für ein ausgefeilteres Matching können Sie prüfen, welche der Benutzerpräferenzen von der Intl-API in dieser Laufzeitumgebung unterstützt werden.

const supportedLocales = ["en-US", "es-MX", "fr-FR", "de-DE"];

function findBestSupportedLocale(userPreferences, appSupported) {
  const runtimeSupported = Intl.DateTimeFormat.supportedLocalesOf(appSupported);

  for (const pref of userPreferences) {
    if (runtimeSupported.includes(pref)) {
      return pref;
    }

    const lang = pref.split("-")[0];
    const match = runtimeSupported.find(s => s.startsWith(lang));
    if (match) {
      return match;
    }
  }

  return runtimeSupported[0] || "en";
}

const userLocale = findBestSupportedLocale(navigator.languages, supportedLocales);
const formatter = new Intl.DateTimeFormat(userLocale);

Dieser Ansatz stellt sicher, dass die ausgewählte Locale sowohl von Ihrer Anwendung als auch von der JavaScript-Laufzeitumgebung unterstützt wird.

Handhabung von Fällen, in denen keine Locale übereinstimmt

Wenn keine der angeforderten Locales unterstützt wird, greift die Intl-API auf die Standard-Locale des Systems zurück. Diese Standardeinstellung variiert je nach Umgebung und wird durch das Betriebssystem, den Browser oder die Node.js-Konfiguration bestimmt.

const unsupportedLocales = ["non-existent-locale"];
const formatter = new Intl.DateTimeFormat(unsupportedLocales);

console.log(formatter.resolvedOptions().locale);
// Shows the system default locale
// Might be "en-US" or another locale depending on the system

Die Systemstandardeinstellung stellt sicher, dass Formatter immer funktionieren, selbst bei vollständig ungültigen oder nicht unterstützten Locale-Listen. Ihre Anwendung wird aufgrund von Locale-Problemen keine Fehler auslösen.

Um einen bestimmten Fallback sicherzustellen, anstatt sich auf die Systemstandardeinstellung zu verlassen, fügen Sie immer eine weit verbreitete Locale wie en oder en-US am Ende Ihres Locale-Arrays hinzu.

const locales = ["xyz-INVALID", "en"];
const formatter = new Intl.DateTimeFormat(locales);

console.log(formatter.resolvedOptions().locale);
// Will use "en" since the first locale is invalid
// Guaranteed fallback to English instead of system default

Dieses Muster macht das Verhalten Ihrer Anwendung über verschiedene Umgebungen hinweg vorhersehbarer.

Praktische Muster für Produktionsanwendungen

Beim Erstellen von Produktionsanwendungen kombinieren Sie mehrere Fallback-Strategien, um eine robuste Locale-Behandlung über verschiedene Benutzerbasen hinweg sicherzustellen.

Ein gängiges Muster erstellt Formatter mit einer vollständigen Fallback-Kette, die Benutzerpräferenzen, von der Anwendung unterstützte Locales und einen garantierten finalen Fallback umfasst.

class LocaleManager {
  constructor(supportedLocales) {
    this.supportedLocales = supportedLocales;
    this.defaultLocale = "en-US";
  }

  buildLocaleChain(userPreference) {
    const chain = [];

    if (userPreference) {
      chain.push(userPreference);

      const lang = userPreference.split("-")[0];
      if (lang !== userPreference) {
        chain.push(lang);
      }
    }

    chain.push(...navigator.languages);
    chain.push(...this.supportedLocales);
    chain.push(this.defaultLocale);

    const unique = [...new Set(chain)];
    return unique;
  }

  createDateFormatter(userPreference, options = {}) {
    const locales = this.buildLocaleChain(userPreference);
    return new Intl.DateTimeFormat(locales, options);
  }

  createNumberFormatter(userPreference, options = {}) {
    const locales = this.buildLocaleChain(userPreference);
    return new Intl.NumberFormat(locales, options);
  }
}

const manager = new LocaleManager(["en-US", "es-MX", "fr-FR", "de-DE"]);
const dateFormatter = manager.createDateFormatter("pt-BR");

console.log(dateFormatter.resolvedOptions().locale);
// Uses comprehensive fallback chain
// Tries Portuguese for Brazil
// Falls back to Portuguese
// Falls back through navigator.languages
// Falls back through supported locales
// Guaranteed to use en-US if nothing else matches

Diese Klasse kapselt die Locale-Fallback-Logik und stellt ein konsistentes Verhalten in Ihrer gesamten Anwendung sicher.

Für Anwendungen, die zur Laufzeit auf Änderungen der Benutzer-Locale reagieren müssen, kombinieren Sie den Locale-Manager mit Event-Listenern.

class LocaleAwareFormatter {
  constructor(supportedLocales) {
    this.supportedLocales = supportedLocales;
    this.updateFormatters();

    window.addEventListener("languagechange", () => {
      this.updateFormatters();
    });
  }

  updateFormatters() {
    const locales = [...navigator.languages, ...this.supportedLocales, "en"];

    this.dateFormatter = new Intl.DateTimeFormat(locales);
    this.numberFormatter = new Intl.NumberFormat(locales);
  }

  formatDate(date) {
    return this.dateFormatter.format(date);
  }

  formatNumber(number) {
    return this.numberFormatter.format(number);
  }
}

const formatter = new LocaleAwareFormatter(["en-US", "es-MX", "fr-FR"]);
console.log(formatter.formatDate(new Date()));
// Automatically updates when user changes language preferences

Dieses Muster erstellt Formatter, die mit Änderungen der Browsersprache synchronisiert bleiben und sicherstellen, dass Ihre Anwendung Inhalte immer entsprechend den aktuellen Präferenzen anzeigt.

Zusammenfassung

Locale-Fallback stellt sicher, dass Ihre Anwendung korrekt formatierte Inhalte anzeigt, auch wenn Benutzer Locales bevorzugen, die Sie nicht explizit unterstützen. Die Intl-API behandelt Fallback automatisch, indem sie Arrays von Locale-Präferenzen akzeptiert und die erste unterstützte Option auswählt.

Wichtige Konzepte:

  • Übergeben Sie Arrays von Locales an Intl-Konstruktoren für automatischen Fallback
  • Die Runtime wählt die erste Locale aus dem Array aus, die sie unterstützt
  • Verwenden Sie supportedLocalesOf(), um zu prüfen, welche Locales verfügbar sind
  • Erstellen Sie Fallback-Ketten, die von spezifischen zu allgemeinen Locales fortschreiten
  • Die Option localeMatcher steuert den Matching-Algorithmus
  • Übergeben Sie navigator.languages direkt für automatische Behandlung von Benutzerpräferenzen
  • Fügen Sie immer einen weit unterstützten finalen Fallback wie Englisch hinzu
  • Die Runtime fällt auf Systemstandards zurück, wenn keine Locales übereinstimmen

Verwenden Sie automatischen Fallback mit Locale-Arrays für die meisten Anwendungen. Implementieren Sie benutzerdefinierte Fallback-Logik, wenn Sie spezifische Kontrolle darüber benötigen, welche Locales in welcher Reihenfolge versucht werden.