Cómo normalizar identificadores de localización a forma estándar
Convertir identificadores de localización a formato canónico con el uso correcto de mayúsculas y ordenamiento de componentes
Introducción
Los identificadores de configuración regional pueden escribirse de muchas formas diferentes mientras se refieren al mismo idioma y región. Un usuario podría escribir EN-us, en-US, o en-us, y los tres representan el inglés estadounidense. Al almacenar, comparar o mostrar identificadores de configuración regional, estas variaciones crean inconsistencias.
La normalización convierte los identificadores de configuración regional a una forma canónica estándar. Este proceso ajusta el uso de mayúsculas y minúsculas de los componentes, ordena alfabéticamente las palabras clave de extensión y produce una representación consistente en la que puede confiar en toda su aplicación.
JavaScript proporciona métodos integrados para normalizar automáticamente los identificadores de configuración regional. Esta guía explica qué significa la normalización, cómo aplicarla en su código y cuándo los identificadores normalizados mejoran su lógica de internacionalización.
Qué significa la normalización para los identificadores de configuración regional
La normalización transforma un identificador de configuración regional en su forma canónica según el estándar BCP 47 y las especificaciones de Unicode. La forma canónica tiene reglas específicas para el uso de mayúsculas y minúsculas, ordenamiento y estructura.
Un identificador de configuración regional normalizado sigue estas convenciones:
- Los códigos de idioma están en minúsculas
- Los códigos de escritura están en formato título con la primera letra en mayúscula
- Los códigos de región están en mayúsculas
- Los códigos de variante están en minúsculas
- Las palabras clave de extensión se ordenan alfabéticamente
- Los atributos de extensión se ordenan alfabéticamente
Estas reglas crean una representación estándar única para cada configuración regional. No importa cómo un usuario escriba un identificador de configuración regional, la forma normalizada siempre es la misma.
Comprendiendo las reglas de normalización
Cada componente de un identificador de configuración regional tiene una convención específica de uso de mayúsculas y minúsculas en la forma canónica.
Uso de mayúsculas y minúsculas en el idioma
Los códigos de idioma siempre utilizan letras minúsculas:
en (correcto)
EN (incorrecto, pero se normaliza a en)
eN (incorrecto, pero se normaliza a en)
Esto se aplica tanto a los códigos de idioma de dos letras como a los de tres letras.
Uso de mayúsculas en códigos de escritura
Los códigos de escritura utilizan mayúscula inicial, donde la primera letra está en mayúscula y las tres letras restantes en minúscula:
Hans (correcto)
hans (incorrecto, pero se normaliza a Hans)
HANS (incorrecto, pero se normaliza a Hans)
Los códigos de escritura comunes incluyen Latn para Latino, Cyrl para Cirílico, Hans para caracteres Han Simplificados, y Hant para caracteres Han Tradicionales.
Uso de mayúsculas en códigos de región
Los códigos de región siempre utilizan letras mayúsculas:
US (correcto)
us (incorrecto, pero se normaliza a US)
Us (incorrecto, pero se normaliza a US)
Esto se aplica a los códigos de país de dos letras utilizados en la mayoría de los identificadores de localización.
Ordenamiento de extensiones
Las etiquetas de extensión Unicode contienen palabras clave que especifican preferencias de formato. En la forma canónica, estas palabras clave aparecen en orden alfabético según su clave:
en-US-u-ca-gregory-nu-latn (correcto)
en-US-u-nu-latn-ca-gregory (incorrecto, pero se normaliza a la primera forma)
La clave de calendario ca viene antes que la clave de sistema de numeración nu alfabéticamente, por lo que ca-gregory aparece primero en la forma normalizada.
Uso de Intl.getCanonicalLocales para normalizar
El método Intl.getCanonicalLocales() normaliza los identificadores de localización y los devuelve en forma canónica. Este es el método principal para la normalización en JavaScript.
const normalized = Intl.getCanonicalLocales("EN-us");
console.log(normalized);
// ["en-US"]
El método acepta un identificador de localización con cualquier uso de mayúsculas y devuelve la forma canónica con las mayúsculas correctas.
Normalización de códigos de idioma
El método convierte los códigos de idioma a minúsculas:
const result = Intl.getCanonicalLocales("FR-fr");
console.log(result);
// ["fr-FR"]
El código de idioma FR se convierte en fr en la salida.
Normalización de códigos de escritura
El método convierte los códigos de escritura a mayúscula inicial:
const result = Intl.getCanonicalLocales("zh-HANS-cn");
console.log(result);
// ["zh-Hans-CN"]
El código de escritura HANS se convierte en Hans, y el código de región cn se convierte en CN.
Normalización de códigos de región
El método convierte los códigos de región a mayúsculas:
const result = Intl.getCanonicalLocales("en-gb");
console.log(result);
// ["en-GB"]
El código de región gb se convierte en GB en la salida.
Normalización de palabras clave de extensión
El método ordena las palabras clave de extensión alfabéticamente:
const result = Intl.getCanonicalLocales("en-US-u-nu-latn-hc-h12-ca-gregory");
console.log(result);
// ["en-US-u-ca-gregory-hc-h12-nu-latn"]
Las palabras clave se reordenan de nu-latn-hc-h12-ca-gregory a ca-gregory-hc-h12-nu-latn porque ca viene antes que hc y hc viene antes que nu alfabéticamente.
Normalización de múltiples identificadores de localización
El método Intl.getCanonicalLocales() acepta un array de identificadores de localización y los normaliza todos:
const locales = ["EN-us", "fr-FR", "ZH-hans-cn"];
const normalized = Intl.getCanonicalLocales(locales);
console.log(normalized);
// ["en-US", "fr-FR", "zh-Hans-CN"]
Cada localización en el array se convierte a su forma canónica.
Eliminación de duplicados
El método elimina los identificadores de localización duplicados después de la normalización. Si múltiples valores de entrada se normalizan a la misma forma canónica, el resultado contiene solo una copia:
const locales = ["en-US", "EN-us", "en-us"];
const normalized = Intl.getCanonicalLocales(locales);
console.log(normalized);
// ["en-US"]
Las tres entradas representan la misma localización, por lo que la salida contiene un solo identificador normalizado.
Esta deduplicación es útil cuando se procesa la entrada del usuario o se fusionan listas de localizaciones de múltiples fuentes.
Manejo de identificadores inválidos
Si algún identificador de localización en el array es inválido, el método lanza un RangeError:
try {
Intl.getCanonicalLocales(["en-US", "invalid", "fr-FR"]);
} catch (error) {
console.error(error.message);
// "invalid is not a structurally valid language tag"
}
Cuando se normalizan listas proporcionadas por el usuario, valide o capture errores para cada localización individualmente para identificar qué identificadores específicos son inválidos.
Uso de Intl.Locale para normalización
El constructor Intl.Locale también normaliza los identificadores de localización al crear objetos de localización. Puede acceder a la forma normalizada a través del método toString().
const locale = new Intl.Locale("EN-us");
console.log(locale.toString());
// "en-US"
El constructor acepta cualquier uso válido de mayúsculas y minúsculas y produce un objeto de localización normalizado.
Accediendo a componentes normalizados
Cada propiedad del objeto locale devuelve la forma normalizada de ese componente:
const locale = new Intl.Locale("ZH-hans-CN");
console.log(locale.language);
// "zh"
console.log(locale.script);
// "Hans"
console.log(locale.region);
// "CN"
console.log(locale.baseName);
// "zh-Hans-CN"
Las propiedades language, script y region utilizan el formato de mayúsculas y minúsculas correcto para la forma canónica.
Normalización con opciones
Cuando creas un objeto locale con opciones, el constructor normaliza tanto el identificador base como las opciones:
const locale = new Intl.Locale("EN-us", {
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString());
// "en-US-u-ca-gregory-hc-h12-nu-latn"
Las palabras clave de extensión aparecen en orden alfabético en la salida, aunque el objeto de opciones no especifique ningún orden particular.
Por qué importa la normalización
La normalización proporciona consistencia en toda tu aplicación. Cuando almacenas, muestras o comparas identificadores de locale, usar la forma canónica previene errores sutiles y mejora la fiabilidad.
Almacenamiento consistente
Al almacenar identificadores de locale en bases de datos, archivos de configuración o almacenamiento local, las formas normalizadas previenen la duplicación:
const userPreferences = new Set();
function saveUserLocale(identifier) {
const normalized = Intl.getCanonicalLocales(identifier)[0];
userPreferences.add(normalized);
}
saveUserLocale("en-US");
saveUserLocale("EN-us");
saveUserLocale("en-us");
console.log(userPreferences);
// Set { "en-US" }
Sin normalización, el conjunto contendría tres entradas para el mismo locale. Con normalización, correctamente contiene una.
Comparación fiable
Comparar identificadores de locale requiere normalización. Dos identificadores que difieren solo en mayúsculas y minúsculas representan el mismo locale:
function isSameLocale(locale1, locale2) {
const normalized1 = Intl.getCanonicalLocales(locale1)[0];
const normalized2 = Intl.getCanonicalLocales(locale2)[0];
return normalized1 === normalized2;
}
console.log(isSameLocale("en-US", "EN-us"));
// true
console.log(isSameLocale("en-US", "en-GB"));
// false
La comparación directa de cadenas de identificadores no normalizados produce resultados incorrectos.
Visualización consistente
Al mostrar identificadores de configuración regional a los usuarios o en la salida de depuración, las formas normalizadas proporcionan un formato consistente:
function displayLocale(identifier) {
try {
const normalized = Intl.getCanonicalLocales(identifier)[0];
return `Current locale: ${normalized}`;
} catch (error) {
return "Invalid locale identifier";
}
}
console.log(displayLocale("EN-us"));
// "Current locale: en-US"
console.log(displayLocale("zh-HANS-cn"));
// "Current locale: zh-Hans-CN"
Los usuarios ven identificadores de configuración regional correctamente formateados independientemente del formato de entrada.
Aplicaciones prácticas
La normalización resuelve problemas comunes al trabajar con identificadores de configuración regional en aplicaciones reales.
Normalización de entrada del usuario
Cuando los usuarios ingresan identificadores de configuración regional en formularios o ajustes, normaliza la entrada antes de almacenarla:
function processLocaleInput(input) {
try {
const normalized = Intl.getCanonicalLocales(input)[0];
return {
success: true,
locale: normalized
};
} catch (error) {
return {
success: false,
error: "Please enter a valid locale identifier"
};
}
}
const result = processLocaleInput("fr-ca");
console.log(result);
// { success: true, locale: "fr-CA" }
Esto asegura un formato consistente en tu base de datos o configuración.
Creación de tablas de búsqueda de configuración regional
Al crear tablas de búsqueda para traducciones o datos específicos de configuración regional, utiliza claves normalizadas:
const translations = new Map();
function addTranslation(locale, key, value) {
const normalized = Intl.getCanonicalLocales(locale)[0];
if (!translations.has(normalized)) {
translations.set(normalized, {});
}
translations.get(normalized)[key] = value;
}
addTranslation("en-us", "hello", "Hello");
addTranslation("EN-US", "goodbye", "Goodbye");
console.log(translations.get("en-US"));
// { hello: "Hello", goodbye: "Goodbye" }
Ambas llamadas a addTranslation utilizan la misma clave normalizada, por lo que las traducciones se almacenan en el mismo objeto.
Fusión de listas de configuración regional
Al combinar identificadores de configuración regional de múltiples fuentes, normalízalos y elimina duplicados:
function mergeLocales(...sources) {
const allLocales = sources.flat();
const normalized = Intl.getCanonicalLocales(allLocales);
return normalized;
}
const userLocales = ["en-us", "fr-FR"];
const appLocales = ["EN-US", "de-de"];
const systemLocales = ["en-US", "es-mx"];
const merged = mergeLocales(userLocales, appLocales, systemLocales);
console.log(merged);
// ["en-US", "fr-FR", "de-DE", "es-MX"]
El método elimina duplicados y normaliza el uso de mayúsculas y minúsculas en todas las fuentes.
Creación de interfaces de selección de idioma
Al construir menús desplegables o interfaces de selección, normaliza los identificadores de idioma para su visualización:
function buildLocaleOptions(locales) {
const normalized = Intl.getCanonicalLocales(locales);
return normalized.map(locale => {
const localeObj = new Intl.Locale(locale);
const displayNames = new Intl.DisplayNames([locale], {
type: "language"
});
return {
value: locale,
label: displayNames.of(localeObj.language)
};
});
}
const options = buildLocaleOptions(["EN-us", "fr-FR", "DE-de"]);
console.log(options);
// [
// { value: "en-US", label: "English" },
// { value: "fr-FR", label: "French" },
// { value: "de-DE", label: "German" }
// ]
Los valores normalizados proporcionan identificadores consistentes para el envío de formularios.
Validación de archivos de configuración
Al cargar identificadores de idioma desde archivos de configuración, normalízalos durante la inicialización:
function loadLocaleConfig(config) {
const validatedConfig = {
defaultLocale: null,
supportedLocales: []
};
try {
validatedConfig.defaultLocale = Intl.getCanonicalLocales(
config.defaultLocale
)[0];
} catch (error) {
console.error("Invalid default locale:", config.defaultLocale);
validatedConfig.defaultLocale = "en-US";
}
config.supportedLocales.forEach(locale => {
try {
const normalized = Intl.getCanonicalLocales(locale)[0];
validatedConfig.supportedLocales.push(normalized);
} catch (error) {
console.warn("Skipping invalid locale:", locale);
}
});
return validatedConfig;
}
const config = {
defaultLocale: "en-us",
supportedLocales: ["EN-us", "fr-FR", "invalid", "de-DE"]
};
const validated = loadLocaleConfig(config);
console.log(validated);
// {
// defaultLocale: "en-US",
// supportedLocales: ["en-US", "fr-FR", "de-DE"]
// }
Esto detecta errores de configuración tempranamente y asegura que tu aplicación utilice identificadores normalizados válidos.
Normalización y coincidencia de idiomas
La normalización es importante para los algoritmos de coincidencia de idiomas. Al buscar la mejor coincidencia para la preferencia de un usuario, compara las formas normalizadas:
function findBestMatch(userPreference, availableLocales) {
const normalizedPreference = Intl.getCanonicalLocales(userPreference)[0];
const normalizedAvailable = Intl.getCanonicalLocales(availableLocales);
if (normalizedAvailable.includes(normalizedPreference)) {
return normalizedPreference;
}
const preferenceLocale = new Intl.Locale(normalizedPreference);
const languageMatch = normalizedAvailable.find(available => {
const availableLocale = new Intl.Locale(available);
return availableLocale.language === preferenceLocale.language;
});
if (languageMatch) {
return languageMatch;
}
return normalizedAvailable[0];
}
const available = ["en-us", "fr-FR", "DE-de"];
console.log(findBestMatch("EN-GB", available));
// "en-US"
La normalización asegura que la lógica de coincidencia funcione correctamente independientemente del uso de mayúsculas y minúsculas en la entrada.
La normalización no cambia el significado
La normalización solo afecta a la representación de un identificador de configuración regional. No cambia el idioma, la escritura o la región que representa el identificador.
const locale1 = new Intl.Locale("en-us");
const locale2 = new Intl.Locale("EN-US");
console.log(locale1.language === locale2.language);
// true
console.log(locale1.region === locale2.region);
// true
console.log(locale1.toString() === locale2.toString());
// true
Ambos identificadores se refieren al inglés estadounidense. La normalización simplemente asegura que se escriban de la misma manera.
Esto es diferente de operaciones como maximize() y minimize(), que añaden o eliminan componentes y pueden cambiar la especificidad del identificador.
Compatibilidad con navegadores
El método Intl.getCanonicalLocales() funciona en todos los navegadores modernos. Chrome, Firefox, Safari y Edge proporcionan soporte completo.
Node.js admite Intl.getCanonicalLocales() a partir de la versión 9, con soporte completo en la versión 10 y posteriores.
El constructor Intl.Locale y su comportamiento de normalización funcionan en todos los navegadores que admiten la API Intl.Locale. Esto incluye versiones modernas de Chrome, Firefox, Safari y Edge.
Resumen
La normalización convierte los identificadores de configuración regional a su forma canónica aplicando reglas estándar de mayúsculas y minúsculas y ordenando las palabras clave de extensión. Esto crea representaciones consistentes que puedes almacenar, comparar y mostrar de manera fiable.
Conceptos clave:
- La forma canónica utiliza minúsculas para idiomas, mayúscula inicial para escrituras y mayúsculas para regiones
- Las palabras clave de extensión se ordenan alfabéticamente en la forma canónica
- El método
Intl.getCanonicalLocales()normaliza los identificadores y elimina duplicados - El constructor
Intl.Localetambién produce una salida normalizada - La normalización no cambia el significado de un identificador de configuración regional
- Utiliza identificadores normalizados para almacenamiento, comparación y visualización
La normalización es una operación fundamental para cualquier aplicación que trabaje con identificadores de configuración regional. Previene errores causados por inconsistencias en el uso de mayúsculas y minúsculas y asegura que tu lógica de internacionalización maneje los identificadores de configuración regional de manera fiable.