API Intl.Locale

Analiza, manipula y consulta identificadores de locale con objetos JavaScript estructurados

Introducción

Al crear aplicaciones para múltiples idiomas y regiones, te encuentras con identificadores de locale como en-US, fr-FR o zh-Hans-CN. Estas cadenas aparecen en APIs del navegador, encabezados HTTP y preferencias de usuario. Codifican información sobre idioma, región, sistema de escritura y preferencias de formato.

La API Intl.Locale transforma estas cadenas opacas en objetos estructurados que puedes inspeccionar y manipular. En lugar de analizar cadenas manualmente o adivinar qué significa zh-Hans-CN, creas un objeto locale y lees sus propiedades directamente.

Esta guía explica cómo funcionan los identificadores de locale, cómo usar la API Intl.Locale para trabajar con ellos y cuándo los objetos locale estructurados ayudan a resolver problemas reales.

Comprender los identificadores de locale

Un identificador de locale es una cadena que especifica preferencias culturales para formatear fechas, números, monedas y texto. El identificador contiene múltiples componentes separados por guiones.

La estructura más común sigue el estándar BCP 47:

language-script-region-variant-extensions

Cada componente es opcional excepto el código de idioma.

Códigos de idioma

Los códigos de idioma utilizan dos o tres letras de ISO 639. Ejemplos comunes:

  • en para inglés
  • es para español
  • fr para francés
  • de para alemán
  • ja para japonés
  • zh para chino
  • ar para árabe

El código de idioma siempre está en minúsculas y aparece primero en el identificador.

Códigos de región

Los códigos de región especifican áreas geográficas utilizando dos letras mayúsculas de ISO 3166-1. Indican qué variante de un idioma usar:

  • en-US para inglés americano
  • en-GB para inglés británico
  • es-ES para español europeo
  • es-MX para español mexicano
  • fr-FR para francés hablado en Francia
  • fr-CA para francés canadiense

Los códigos de región cambian las convenciones de formato. El inglés americano usa fechas MM/DD/YYYY, mientras que el inglés británico usa DD/MM/YYYY.

Códigos de script

Los códigos de script especifican el sistema de escritura usando cuatro letras con la primera letra en mayúscula. Son importantes para idiomas escritos en múltiples scripts:

  • zh-Hans para caracteres chinos simplificados
  • zh-Hant para caracteres chinos tradicionales
  • sr-Cyrl para serbio en script cirílico
  • sr-Latn para serbio en script latino

La mayoría de los locales omiten el código de script porque el idioma implica un script predeterminado. El inglés usa el script latino por defecto, por lo que escribes en en lugar de en-Latn.

Etiquetas de extensión

Las etiquetas de extensión agregan preferencias de formato a los identificadores de locale. Comienzan con -u- seguido de pares clave-valor:

en-US-u-ca-gregory-nu-latn-hc-h12

Claves de extensión comunes:

  • ca para sistema de calendario (gregory, buddhist, islamic)
  • nu para sistema de numeración (latn, arab, hanidec)
  • hc para ciclo horario (h12, h23, h11, h24)

Las extensiones personalizan cómo los formateadores muestran los datos sin cambiar el idioma o la región.

Crear objetos locale

El constructor Intl.Locale acepta una cadena identificadora de locale y devuelve un objeto estructurado:

const locale = new Intl.Locale("en-US");

console.log(locale.language); // "en"
console.log(locale.region); // "US"

También puedes pasar un objeto de opciones para sobrescribir o agregar propiedades:

const locale = new Intl.Locale("en", {
  region: "GB",
  hourCycle: "h23"
});

console.log(locale.baseName); // "en-GB"
console.log(locale.hourCycle); // "h23"

El constructor lanza un RangeError si el identificador no es válido:

try {
  const invalid = new Intl.Locale("invalid-locale-code");
} catch (error) {
  console.error(error.message); // "invalid language subtag: invalid"
}

Esta validación garantiza que detectes identificadores de locale mal formados antes de pasarlos a los formateadores.

Leer propiedades de locale

Los objetos locale exponen propiedades que corresponden a componentes de la cadena identificadora. Todas las propiedades son de solo lectura.

Propiedades principales

La propiedad language devuelve el código de idioma:

const locale = new Intl.Locale("fr-CA");
console.log(locale.language); // "fr"

La propiedad region devuelve el código de región:

const locale = new Intl.Locale("fr-CA");
console.log(locale.region); // "CA"

La propiedad script devuelve el código de escritura si está presente:

const locale = new Intl.Locale("zh-Hans-CN");
console.log(locale.script); // "Hans"

La propiedad baseName devuelve el identificador principal completo sin extensiones:

const locale = new Intl.Locale("en-US-u-ca-gregory-nu-latn");
console.log(locale.baseName); // "en-US"

Utiliza baseName cuando necesites el idioma y la región pero quieras ignorar las preferencias de formato.

Propiedades de extensión

Las propiedades de extensión devuelven valores de la etiqueta de extensión -u- o undefined si no se especifica.

La propiedad calendar devuelve el sistema de calendario:

const locale = new Intl.Locale("ar-SA-u-ca-islamic");
console.log(locale.calendar); // "islamic"

La propiedad numberingSystem devuelve el sistema de numeración:

const locale = new Intl.Locale("ar-EG-u-nu-arab");
console.log(locale.numberingSystem); // "arab"

La propiedad hourCycle devuelve la preferencia de ciclo horario:

const locale = new Intl.Locale("en-US-u-hc-h23");
console.log(locale.hourCycle); // "h23"

La propiedad caseFirst devuelve la preferencia de mayúsculas y minúsculas para la intercalación:

const locale = new Intl.Locale("en-US-u-kf-upper");
console.log(locale.caseFirst); // "upper"

La propiedad numeric indica si la intercalación numérica está habilitada:

const locale = new Intl.Locale("en-US-u-kn-true");
console.log(locale.numeric); // true

Estas propiedades te permiten inspeccionar las preferencias de formato sin analizar manualmente la cadena de extensión.

Consulta de información de configuración regional

La API Intl.Locale proporciona métodos que devuelven arrays de opciones disponibles para una configuración regional. Estos métodos ayudan a construir interfaces de usuario y validar opciones de formato.

Calendarios disponibles

El método getCalendars() devuelve los sistemas de calendario comúnmente utilizados para la configuración regional:

const locale = new Intl.Locale("th-TH");
const calendars = locale.getCalendars();
console.log(calendars); // ["buddhist", "gregory"]

El primer elemento es el calendario predeterminado. Las configuraciones regionales tailandesas utilizan por defecto el calendario budista, pero también usan el calendario gregoriano.

Colaciones disponibles

El método getCollations() devuelve tipos de colación para ordenar cadenas:

const locale = new Intl.Locale("de-DE");
const collations = locale.getCollations();
console.log(collations); // ["phonebk", "emoji", "eor"]

El alemán tiene una colación de guía telefónica que ordena las cadenas de manera diferente a la colación Unicode estándar.

Ciclos horarios disponibles

El método getHourCycles() devuelve formatos de ciclo horario:

const locale = new Intl.Locale("en-US");
const hourCycles = locale.getHourCycles();
console.log(hourCycles); // ["h12"]

El inglés americano utiliza el formato de 12 horas por defecto. Muchas otras configuraciones regionales devuelven ["h23"] para el formato de 24 horas.

Sistemas de numeración disponibles

El método getNumberingSystems() devuelve los sistemas de numeración comúnmente utilizados para la configuración regional:

const locale = new Intl.Locale("ar-EG");
const numberingSystems = locale.getNumberingSystems();
console.log(numberingSystems); // ["arab", "latn"]

Las configuraciones regionales árabes a menudo admiten tanto los numerales arábigo-índicos como los numerales latinos.

Dirección del texto

El método getTextInfo() devuelve información sobre el orden del texto:

const locale = new Intl.Locale("ar-SA");
const textInfo = locale.getTextInfo();
console.log(textInfo.direction); // "rtl"

Los idiomas de derecha a izquierda como el árabe y el hebreo devuelven "rtl". Los idiomas de izquierda a derecha devuelven "ltr".

Convenciones de semana

El método getWeekInfo() devuelve la estructura de la semana para la configuración regional:

const locale = new Intl.Locale("en-US");
const weekInfo = locale.getWeekInfo();
console.log(weekInfo.firstDay); // 7 (Sunday)
console.log(weekInfo.weekend); // [6, 7] (Saturday, Sunday)
console.log(weekInfo.minimalDays); // 1

Las convenciones de semana varían según la región. Las semanas americanas comienzan el domingo, mientras que la mayoría de las semanas europeas comienzan el lunes.

Zonas horarias

El método getTimeZones() devuelve las zonas horarias para la región de la configuración regional:

const locale = new Intl.Locale("en-US");
const timeZones = locale.getTimeZones();
console.log(timeZones); // ["America/New_York", "America/Chicago", ...]

Este método devuelve identificadores de zona horaria IANA para el código de región.

Maximizando identificadores de locale

El método maximize() añade subetiquetas probables para crear un identificador completo. Infiere los códigos de escritura y región faltantes basándose en datos lingüísticos.

Cuando especificas solo un código de idioma, maximize() añade el sistema de escritura y la región más comunes:

const locale = new Intl.Locale("en");
const maximized = locale.maximize();
console.log(maximized.baseName); // "en-Latn-US"

El inglés utiliza por defecto el alfabeto latino y la región de Estados Unidos porque son las asociaciones más comunes.

La maximización del chino depende del sistema de escritura:

const simplified = new Intl.Locale("zh-Hans");
const maximized = simplified.maximize();
console.log(maximized.baseName); // "zh-Hans-CN"

const traditional = new Intl.Locale("zh-Hant");
const maximizedTrad = traditional.maximize();
console.log(maximizedTrad.baseName); // "zh-Hant-TW"

El chino simplificado se asocia con China, mientras que el chino tradicional se asocia con Taiwán.

Utiliza maximize() al normalizar entradas de usuario o comparar identificadores de configuración regional. Hace explícita la información implícita.

Minimizando identificadores de configuración regional

El método minimize() elimina subetiquetas redundantes para crear el identificador equivalente más corto. Elimina los códigos de escritura y región cuando coinciden con los valores predeterminados probables.

Cuando una configuración regional utiliza el sistema de escritura y la región predeterminados, minimize() los elimina:

const locale = new Intl.Locale("en-Latn-US");
const minimized = locale.minimize();
console.log(minimized.baseName); // "en"

El alfabeto latino y la región de Estados Unidos son valores predeterminados para el inglés, por lo que pueden eliminarse sin perder información.

Para configuraciones regionales con regiones no predeterminadas, minimize() mantiene la región:

const locale = new Intl.Locale("en-Latn-GB");
const minimized = locale.minimize();
console.log(minimized.baseName); // "en-GB"

El inglés británico necesita el código de región porque difiere del predeterminado.

Utiliza minimize() para crear identificadores compactos para almacenamiento o URLs mientras preservas el significado.

Convirtiendo a cadenas

El método toString() devuelve el identificador de configuración regional completo incluyendo extensiones:

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"

La representación en cadena es válida para pasarla a otras APIs de Intl o almacenarla como datos de configuración.

También puedes convertir objetos locale a cadenas implícitamente:

const locale = new Intl.Locale("fr-FR");
const formatter = new Intl.DateTimeFormat(locale);

El constructor DateTimeFormat acepta objetos locale directamente y llama a toString() internamente.

Casos de uso prácticos

La API Intl.Locale resuelve varios problemas comunes al construir aplicaciones internacionalizadas.

Construcción de selectores de locale

Los selectores de locale permiten a los usuarios elegir su idioma y región. La API Intl.Locale ayuda a analizar y validar las selecciones de usuario:

function createLocaleSelector(locales) {
  const options = locales.map(identifier => {
    const locale = new Intl.Locale(identifier);
    const displayName = new Intl.DisplayNames([identifier], { type: "language" });

    return {
      value: locale.toString(),
      label: displayName.of(locale.language),
      region: locale.region
    };
  });

  return options;
}

const options = createLocaleSelector(["en-US", "en-GB", "fr-FR", "es-MX"]);
console.log(options);
// [
//   { value: "en-US", label: "English", region: "US" },
//   { value: "en-GB", label: "English", region: "GB" },
//   { value: "fr-FR", label: "French", region: "FR" },
//   { value: "es-MX", label: "Spanish", region: "MX" }
// ]

Validación de entrada de locale

Al aceptar identificadores de locale desde entrada de usuario o archivos de configuración, valídalos antes de usarlos:

function validateLocale(identifier) {
  try {
    const locale = new Intl.Locale(identifier);
    return {
      valid: true,
      locale: locale.toString(),
      language: locale.language,
      region: locale.region
    };
  } catch (error) {
    return {
      valid: false,
      error: error.message
    };
  }
}

console.log(validateLocale("en-US")); // { valid: true, locale: "en-US", ... }
console.log(validateLocale("invalid")); // { valid: false, error: "..." }

Extracción de idioma para respaldos

Al implementar cadenas de respaldo de idioma, extrae el código de idioma sin la región:

function getLanguageFallback(identifier) {
  const locale = new Intl.Locale(identifier);
  const fallbacks = [locale.toString()];

  if (locale.region) {
    const languageOnly = new Intl.Locale(locale.language);
    fallbacks.push(languageOnly.toString());
  }

  fallbacks.push("en");

  return fallbacks;
}

console.log(getLanguageFallback("fr-CA"));
// ["fr-CA", "fr", "en"]

Esto crea una cadena de respaldo que intenta el locale específico, luego el idioma sin región y finalmente el idioma predeterminado.

Configuración de formateadores

Utiliza objetos locale para configurar formateadores Intl con preferencias específicas:

function createFormatter(baseLocale, options = {}) {
  const locale = new Intl.Locale(baseLocale, {
    calendar: options.calendar || "gregory",
    numberingSystem: options.numberingSystem || "latn",
    hourCycle: options.hourCycle || "h23"
  });

  return {
    date: new Intl.DateTimeFormat(locale),
    number: new Intl.NumberFormat(locale),
    locale: locale.toString()
  };
}

const formatter = createFormatter("ar-SA", {
  calendar: "islamic",
  numberingSystem: "arab"
});

console.log(formatter.locale); // "ar-SA-u-ca-islamic-nu-arab"

Detección de preferencias de usuario

Las API del navegador proporcionan cadenas de locale que puedes analizar para comprender las preferencias del usuario:

function getUserPreferences() {
  const userLocale = new Intl.Locale(navigator.language);
  const hourCycles = userLocale.getHourCycles();
  const calendars = userLocale.getCalendars();
  const textInfo = userLocale.getTextInfo();

  return {
    language: userLocale.language,
    region: userLocale.region,
    preferredHourCycle: hourCycles[0],
    preferredCalendar: calendars[0],
    textDirection: textInfo.direction
  };
}

const preferences = getUserPreferences();
console.log(preferences);
// { language: "en", region: "US", preferredHourCycle: "h12", ... }

Esto crea un perfil de preferencias de usuario basado en la configuración de su navegador.

Compatibilidad con navegadores

La API Intl.Locale funciona en todos los navegadores modernos. Chrome, Firefox, Safari y Edge proporcionan compatibilidad completa para el constructor, propiedades y métodos descritos en esta guía.

Los métodos más recientes como getCalendars(), getCollations(), getHourCycles(), getNumberingSystems(), getTextInfo(), getTimeZones() y getWeekInfo() requieren versiones recientes del navegador. Consulta las tablas de compatibilidad del navegador antes de usar estos métodos si das soporte a navegadores más antiguos.

Node.js admite la API Intl.Locale a partir de la versión 12, con compatibilidad completa de métodos en la versión 18 y posteriores.

Resumen

La API Intl.Locale transforma cadenas identificadoras de locale en objetos estructurados que puedes inspeccionar y manipular. En lugar de analizar cadenas manualmente, creas objetos locale y lees sus propiedades.

Conceptos principales:

  • Los identificadores de configuración regional contienen componentes de idioma, escritura, región y extensión
  • El constructor Intl.Locale valida identificadores y crea objetos
  • Las propiedades como language, region y calendar proporcionan acceso estructurado
  • Los métodos como getCalendars() y getHourCycles() devuelven las opciones disponibles
  • Los métodos maximize() y minimize() normalizan identificadores
  • Los objetos locale funcionan directamente con otras API de Intl

Usa la API Intl.Locale al construir selectores de configuración regional, validar entrada de usuario, implementar cadenas de respaldo o configurar formateadores. Proporciona una forma estándar de trabajar con identificadores de configuración regional en aplicaciones JavaScript.