Comment gérer le repli de locale lorsque la locale préférée n'est pas disponible
Sélectionner automatiquement les langues prises en charge lorsque les utilisateurs préfèrent des locales non prises en charge
Introduction
Toutes les applications web ne prennent pas en charge toutes les langues du monde. Lorsqu'un utilisateur préfère une langue que votre application ne prend pas en charge, vous avez besoin d'un mécanisme de repli pour afficher le contenu dans la meilleure langue alternative au lieu d'afficher des erreurs ou du texte non traduit.
Le repli de locale est le processus de sélection d'une locale alternative lorsque la locale préférée n'est pas disponible. L'API Intl de JavaScript gère cela automatiquement en acceptant plusieurs options de locale et en sélectionnant la première qu'elle prend en charge. Cela garantit que votre application affiche toujours du contenu correctement formaté, même lorsque la locale préférée exacte n'est pas disponible.
Cette leçon explique comment fonctionne le repli de locale en JavaScript, comment l'implémenter efficacement et comment créer une logique de repli personnalisée pour les applications ayant des exigences spécifiques de prise en charge des locales.
Le problème des locales non prises en charge
Lorsque vous transmettez un identifiant de locale à une API Intl, le runtime JavaScript doit prendre en charge cette locale pour formater correctement le contenu. Si vous demandez le formatage pour le norvégien nynorsk mais que le runtime ne prend en charge que le norvégien bokmål, le formateur a besoin d'un moyen de gérer cela de manière appropriée.
Sans repli, les applications ne parviendraient pas à afficher le contenu ou afficheraient du texte non traduit lors de la rencontre de locales non prises en charge. Les utilisateurs de régions avec des variantes linguistiques moins courantes rencontreraient des interfaces défaillantes.
Prenons l'exemple d'un utilisateur qui parle français canadien. Si votre application ne prend en charge que le français européen, vous souhaitez que le formateur utilise les conventions du français européen plutôt que d'échouer complètement. Bien que ce ne soit pas parfait, cela offre une meilleure expérience que l'absence totale de localisation.
Comment l'API Intl gère automatiquement le repli
Chaque constructeur Intl accepte soit une chaîne de locale unique, soit un tableau de chaînes de locales. Lorsque vous passez un tableau, le runtime évalue chaque locale dans l'ordre et utilise la première qu'il prend en charge.
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
Le runtime examine le tableau de gauche à droite. S'il prend en charge le français canadien, il l'utilise. Sinon, il essaie le français européen. Si aucune variante française n'est disponible, il se replie sur l'anglais américain.
Ce repli automatique signifie que vous n'avez pas besoin de vérifier manuellement la prise en charge ou de gérer les erreurs lors de la demande de locales spécifiques. L'API Intl garantit qu'elle sélectionnera une locale prise en charge ou se repliera sur la locale système par défaut.
Fournir plusieurs options de locale
La façon la plus simple d'implémenter le repli est de passer un tableau de locales par ordre de préférence. Cela fonctionne avec tous les constructeurs Intl, y compris DateTimeFormat, NumberFormat, Collator et d'autres.
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
Ce modèle fournit un chemin de dégradation progressive. Les utilisateurs obtiennent du contenu dans leur dialecte préféré s'il est disponible, puis une variante plus large de leur langue, puis une langue de repli commune.
L'ordre est important. Le runtime sélectionne la première locale qu'il prend en charge, donc placez les locales les plus spécifiques et préférées en premier.
Comprendre le fonctionnement de la correspondance de locale
Lorsque vous fournissez plusieurs locales, le runtime JavaScript utilise un algorithme de correspondance de locale pour sélectionner la meilleure option disponible. Cet algorithme compare vos locales demandées à l'ensemble des locales que le runtime prend en charge.
Si une locale demandée correspond exactement à une locale prise en charge, le runtime l'utilise immédiatement. Si aucune correspondance exacte n'existe, le runtime peut sélectionner une locale apparentée en fonction des codes de langue et de région.
Par exemple, si vous demandez en-AU (anglais australien) mais que le runtime ne prend en charge que en-US et en-GB, il sélectionnera l'une de ces variantes anglaises plutôt que de basculer vers une langue complètement différente.
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
La méthode resolvedOptions() renvoie la locale réelle utilisée par le formateur. Cela vous permet de vérifier quelle locale a été sélectionnée après le mécanisme de repli.
Vérifier quelles locales sont prises en charge
La méthode statique supportedLocalesOf() vérifie quelles locales d'une liste sont prises en charge par un constructeur Intl spécifique. Cette méthode renvoie un tableau contenant uniquement les locales prises en charge.
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
Cette méthode filtre les locales demandées pour afficher celles que le runtime peut utiliser sans basculer vers les valeurs par défaut. Les locales non prises en charge sont supprimées du tableau renvoyé.
Vous pouvez utiliser cette méthode pour vérifier la prise en charge avant de créer des formateurs, ou pour afficher les options de langue disponibles aux utilisateurs.
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
Chaque constructeur Intl possède sa propre méthode supportedLocalesOf() car la prise en charge des locales peut varier entre les différentes fonctionnalités d'internationalisation. Un runtime peut prendre en charge le français pour le formatage des nombres mais pas pour la segmentation de texte.
Construire des chaînes de repli à partir d'identifiants de locale
Lorsque vous savez que votre application prend en charge des locales spécifiques, vous pouvez construire une chaîne de repli qui devient progressivement moins spécifique. Ce modèle commence par un identifiant de locale complet et supprime des composants jusqu'à trouver une correspondance.
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
Cette fonction crée une chaîne de repli en extrayant le code de langue d'un identifiant de locale et en ajoutant un repli final vers l'anglais. Vous pouvez étendre cette logique pour inclure des règles de repli plus sophistiquées basées sur les locales prises en charge par votre application.
Pour les applications qui prennent en charge plusieurs variantes d'une langue, vous pouvez souhaiter revenir aux dialectes apparentés avant de passer à l'anglais.
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
Cette approche garantit que les utilisateurs voient le contenu dans un dialecte apparenté de leur langue avant de revenir à l'anglais.
Sélection d'un algorithme de correspondance de locale
L'API Intl prend en charge deux algorithmes de correspondance de locale : lookup et best fit. Vous pouvez spécifier l'algorithme à utiliser via l'option localeMatcher lors de la création de formateurs.
L'algorithme lookup suit la spécification BCP 47 Lookup. Il effectue une correspondance stricte en comparant systématiquement les identifiants de locale et en sélectionnant la première correspondance exacte.
const locales = ["de-DE", "en-US"];
const formatter = new Intl.NumberFormat(locales, {
localeMatcher: "lookup"
});
console.log(formatter.resolvedOptions().locale);
// Uses strict lookup matching rules
L'algorithme best fit permet au runtime de sélectionner une locale en utilisant sa propre logique de correspondance. Cet algorithme peut prendre des décisions intelligentes sur la locale qui répond le mieux aux besoins de l'utilisateur, même s'il ne s'agit pas d'une correspondance exacte.
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
L'algorithme par défaut est best fit. La plupart des applications devraient utiliser la valeur par défaut car elle fournit de meilleurs résultats sur différents runtimes JavaScript. Utilisez lookup uniquement lorsque vous avez besoin d'un comportement de correspondance strict et prévisible.
Utilisation des préférences linguistiques du navigateur pour le fallback automatique
La propriété navigator.languages renvoie un tableau des langues préférées de l'utilisateur par ordre de préférence. Vous pouvez transmettre ce tableau directement aux constructeurs Intl pour implémenter un fallback automatique basé sur les paramètres du navigateur.
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
Cette approche permet au navigateur de gérer toute la logique de fallback. Si la première préférence de l'utilisateur n'est pas prise en charge, l'API Intl essaie automatiquement sa deuxième préférence, puis la troisième, et ainsi de suite.
Ce modèle fonctionne bien lorsque vous souhaitez respecter toutes les préférences linguistiques de l'utilisateur sans construire manuellement des chaînes de repli.
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
L'API Intl évalue chaque langue du tableau et sélectionne la première qu'elle prend en charge, ce qui en fait une solution robuste pour gérer des préférences utilisateur diverses.
Combiner la prise en charge de l'application avec les préférences utilisateur
Pour les applications avec une prise en charge limitée des locales, vous pouvez filtrer les préférences utilisateur pour qu'elles correspondent à vos locales prises en charge avant de créer des formateurs. Cela garantit que vous n'essayez d'utiliser que des locales que votre application peut gérer.
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
Cette fonction trouve la première correspondance entre les préférences utilisateur et les locales prises en charge, y compris en essayant les codes de langue sans codes de région pour une correspondance plus large.
Pour une correspondance plus sophistiquée, vous pouvez vérifier lesquelles des préférences de l'utilisateur sont prises en charge par l'API Intl dans cet environnement d'exécution.
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);
Cette approche garantit que la locale sélectionnée est prise en charge à la fois par votre application et par l'environnement d'exécution JavaScript.
Gérer les cas où aucune locale ne correspond
Si aucune des locales demandées n'est prise en charge, l'API Intl se replie sur la locale par défaut du système. Cette valeur par défaut varie selon l'environnement et est déterminée par le système d'exploitation, le navigateur ou la configuration Node.js.
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
La valeur par défaut du système garantit que les formateurs fonctionnent toujours, même avec des listes de locales complètement invalides ou non prises en charge. Votre application ne générera pas d'erreurs dues à des problèmes de locale.
Pour garantir un repli spécifique au lieu de vous fier à la valeur par défaut du système, incluez toujours une locale largement prise en charge comme en ou en-US à la fin de votre tableau de locales.
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
Ce modèle rend le comportement de votre application plus prévisible dans différents environnements.
Modèles pratiques pour les applications de production
Lors de la création d'applications de production, combinez plusieurs stratégies de repli pour garantir une gestion robuste des paramètres régionaux dans des bases d'utilisateurs diverses.
Un modèle courant crée des formateurs avec une chaîne de repli complète qui inclut les préférences utilisateur, les paramètres régionaux pris en charge par l'application et un repli final garanti.
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
Cette classe encapsule la logique de repli des paramètres régionaux et garantit un comportement cohérent dans toute votre application.
Pour les applications qui doivent répondre aux changements de paramètres régionaux de l'utilisateur à l'exécution, combinez le gestionnaire de paramètres régionaux avec des écouteurs d'événements.
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
Ce modèle crée des formateurs qui restent synchronisés avec les changements de langue du navigateur, garantissant que votre application affiche toujours le contenu selon les préférences actuelles.
Résumé
Le repli des paramètres régionaux garantit que votre application affiche un contenu correctement formaté même lorsque les utilisateurs préfèrent des paramètres régionaux que vous ne prenez pas explicitement en charge. L'API Intl gère le repli automatiquement en acceptant des tableaux de préférences de paramètres régionaux et en sélectionnant la première option prise en charge.
Concepts clés :
- Passez des tableaux de paramètres régionaux aux constructeurs Intl pour un repli automatique
- Le runtime sélectionne le premier paramètre régional qu'il prend en charge dans le tableau
- Utilisez
supportedLocalesOf()pour vérifier quels paramètres régionaux sont disponibles - Construisez des chaînes de repli qui progressent des paramètres régionaux spécifiques aux généraux
- L'option
localeMatchercontrôle l'algorithme de correspondance - Passez
navigator.languagesdirectement pour une gestion automatique des préférences utilisateur - Incluez toujours un repli final largement pris en charge comme l'anglais
- Le runtime revient aux valeurs par défaut du système lorsqu'aucun paramètre régional ne correspond
Utilisez le repli automatique avec des tableaux de paramètres régionaux pour la plupart des applications. Implémentez une logique de repli personnalisée lorsque vous avez besoin d'un contrôle spécifique sur les paramètres régionaux tentés et dans quel ordre.