Cómo construir identificadores de configuración regional a partir de componentes

Construye identificadores de configuración regional combinando códigos de idioma, script y región en JavaScript

Introducción

Los identificadores de configuración regional como en-US o zh-Hans-CN codifican información sobre idioma, sistema de escritura y región. A veces necesitas construir estos identificadores de forma programática en lugar de usar una cadena fija. Por ejemplo, podrías permitir que los usuarios seleccionen su idioma y región por separado, y luego combinarlos en un identificador de configuración regional válido.

El constructor Intl.Locale de JavaScript te permite construir identificadores de configuración regional a partir de componentes individuales. Puedes especificar idioma, script y región como parámetros separados, y el constructor los ensambla en un identificador con el formato adecuado.

Esta guía explica cómo construir identificadores de configuración regional a partir de componentes, cuándo usar este enfoque y cómo manejar casos especiales.

Comprender los componentes del identificador de configuración regional

Los identificadores de configuración regional constan de componentes separados por guiones. Cada componente representa un aspecto diferente de las preferencias culturales.

El código de idioma especifica qué idioma usar. Utiliza dos o tres letras minúsculas de ISO 639:

  • en para inglés
  • es para español
  • fr para francés
  • zh para chino
  • ar para árabe

El código de script especifica el sistema de escritura. Utiliza cuatro letras con la primera letra en mayúscula, de ISO 15924:

  • Hans para caracteres chinos simplificados
  • Hant para caracteres chinos tradicionales
  • Cyrl para escritura cirílica
  • Latn para escritura latina

El código de región especifica el área geográfica. Utiliza dos letras mayúsculas de ISO 3166-1 o tres dígitos de UN M.49:

  • US para Estados Unidos
  • GB para Reino Unido
  • CN para China
  • MX para México

Estos componentes se combinan en un orden específico: idioma, luego escritura, luego región. Por ejemplo, zh-Hans-CN significa idioma chino, escritura simplificada, región China.

Creación de locales con solo idioma y región

El escenario más común es combinar códigos de idioma y región. La mayoría de las aplicaciones no necesitan especificar la escritura porque cada idioma tiene una escritura predeterminada.

Puedes construir un locale pasando el código de idioma como primer argumento y un objeto de opciones con la región:

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

console.log(locale.toString());
// Output: "en-US"

Esto crea un identificador de locale para inglés americano.

Puedes crear diferentes variantes regionales del mismo idioma:

const usEnglish = new Intl.Locale("en", { region: "US" });
const britishEnglish = new Intl.Locale("en", { region: "GB" });
const canadianEnglish = new Intl.Locale("en", { region: "CA" });

console.log(usEnglish.toString()); // "en-US"
console.log(britishEnglish.toString()); // "en-GB"
console.log(canadianEnglish.toString()); // "en-CA"

Cada variante usa el mismo idioma pero diferentes convenciones de formato regional.

Creación de locales con idioma, escritura y región

Algunos idiomas requieren códigos de escritura explícitos. El chino, el serbio y algunos otros idiomas usan múltiples sistemas de escritura. Debes especificar la escritura para evitar ambigüedades.

Puedes agregar el componente de escritura al objeto de opciones:

const simplifiedChinese = new Intl.Locale("zh", {
  script: "Hans",
  region: "CN"
});

console.log(simplifiedChinese.toString());
// Output: "zh-Hans-CN"

Esto crea un locale para chino simplificado tal como se usa en China.

El chino tradicional usa una escritura y región diferentes:

const traditionalChinese = new Intl.Locale("zh", {
  script: "Hant",
  region: "TW"
});

console.log(traditionalChinese.toString());
// Output: "zh-Hant-TW"

El código de escritura distingue entre los dos sistemas de escritura.

El serbio usa tanto escritura cirílica como latina. Necesitas especificar qué escritura usar:

const serbianCyrillic = new Intl.Locale("sr", {
  script: "Cyrl",
  region: "RS"
});

const serbianLatin = new Intl.Locale("sr", {
  script: "Latn",
  region: "RS"
});

console.log(serbianCyrillic.toString()); // "sr-Cyrl-RS"
console.log(serbianLatin.toString()); // "sr-Latn-RS"

Ambos locales usan el idioma serbio en Serbia, pero con diferentes sistemas de escritura.

Creación de locales a partir de selecciones del usuario

Las interfaces de usuario a menudo permiten a los usuarios seleccionar idioma y región por separado. Puedes combinar estas selecciones en un identificador de locale.

Considera un formulario de configuración con dos menús desplegables:

function buildLocaleFromSelections(languageCode, regionCode) {
  const locale = new Intl.Locale(languageCode, {
    region: regionCode
  });

  return locale.toString();
}

const userLocale = buildLocaleFromSelections("es", "MX");
console.log(userLocale);
// Output: "es-MX"

Esto crea un identificador de locale a partir de selecciones independientes.

Puede validar las selecciones capturando errores del constructor:

function buildLocaleFromSelections(languageCode, regionCode) {
  try {
    const locale = new Intl.Locale(languageCode, {
      region: regionCode
    });
    return {
      success: true,
      locale: locale.toString()
    };
  } catch (error) {
    return {
      success: false,
      error: error.message
    };
  }
}

const valid = buildLocaleFromSelections("fr", "CA");
console.log(valid);
// Output: { success: true, locale: "fr-CA" }

const invalid = buildLocaleFromSelections("invalid", "XX");
console.log(invalid);
// Output: { success: false, error: "..." }

El constructor lanza un RangeError si algún componente no es válido.

Construcción de locales con componentes opcionales

No todos los locales necesitan todos los componentes. Puede omitir los componentes que no sean necesarios.

Un locale solo de idioma omite región y script:

const locale = new Intl.Locale("fr");
console.log(locale.toString());
// Output: "fr"

Esto representa francés sin especificar una región o script en particular.

Puede incluir componentes condicionalmente según la entrada del usuario:

function buildLocale(language, options = {}) {
  const localeOptions = {};

  if (options.region) {
    localeOptions.region = options.region;
  }

  if (options.script) {
    localeOptions.script = options.script;
  }

  const locale = new Intl.Locale(language, localeOptions);
  return locale.toString();
}

console.log(buildLocale("en"));
// Output: "en"

console.log(buildLocale("en", { region: "US" }));
// Output: "en-US"

console.log(buildLocale("zh", { script: "Hans", region: "CN" }));
// Output: "zh-Hans-CN"

La función construye el identificador de locale válido más simple según la información disponible.

Sobrescritura de componentes en locales existentes

Puede tomar un identificador de locale existente y sobrescribir componentes específicos. Esto es útil cuando necesita cambiar una parte mientras mantiene las demás intactas.

El segundo argumento del constructor sobrescribe componentes del primer argumento:

const baseLocale = new Intl.Locale("en-US");
const withDifferentRegion = new Intl.Locale(baseLocale, {
  region: "GB"
});

console.log(withDifferentRegion.toString());
// Output: "en-GB"

El nuevo locale mantiene el idioma pero cambia la región.

Puede sobrescribir múltiples componentes:

const original = new Intl.Locale("zh-Hans-CN");
const modified = new Intl.Locale(original, {
  script: "Hant",
  region: "TW"
});

console.log(modified.toString());
// Output: "zh-Hant-TW"

Esto cambia tanto el script como la región mientras preserva el idioma.

Adición de preferencias de formato a locales construidos

Más allá del idioma, script y región, los locales pueden incluir preferencias de formato. Estas preferencias controlan cómo aparecen las fechas, números y otros valores.

Puede agregar preferencias de calendario al construir un locale:

const locale = new Intl.Locale("ar", {
  region: "SA",
  calendar: "islamic"
});

console.log(locale.toString());
// Output: "ar-SA-u-ca-islamic"

console.log(locale.calendar);
// Output: "islamic"

La preferencia de calendario aparece como una extensión Unicode en la cadena del identificador.

Puede especificar múltiples preferencias de formato:

const locale = new Intl.Locale("en", {
  region: "US",
  calendar: "gregory",
  numberingSystem: "latn",
  hourCycle: "h12"
});

console.log(locale.toString());
// Output: "en-US-u-ca-gregory-hc-h12-nu-latn"

El constructor ordena las claves de extensión alfabéticamente.

Estas preferencias afectan cómo los formateadores muestran los datos:

const locale = new Intl.Locale("ar", {
  region: "EG",
  numberingSystem: "arab"
});

const formatter = new Intl.NumberFormat(locale);
console.log(formatter.format(12345));
// Output: "١٢٬٣٤٥" (Arabic-Indic numerals)

La preferencia del sistema de numeración controla qué dígitos aparecen.

Validación de combinaciones de componentes

No todas las combinaciones de idioma, escritura y región son significativas. El constructor acepta cualquier componente sintácticamente válido, pero algunas combinaciones pueden no representar locales reales.

El constructor valida la sintaxis pero no la corrección semántica:

// Syntactically valid but semantically questionable
const locale = new Intl.Locale("en", {
  script: "Arab",
  region: "JP"
});

console.log(locale.toString());
// Output: "en-Arab-JP"

Esto construye un locale para inglés en escritura árabe en Japón. El identificador es válido según BCP 47, pero no representa un locale del mundo real.

Puedes usar el método maximize() para verificar si un locale coincide con patrones comunes:

const locale = new Intl.Locale("en", { region: "JP" });
const maximized = locale.maximize();

console.log(maximized.toString());
// Output: "en-Latn-JP"

El método añade la escritura más probable para el idioma. Si el resultado coincide con los patrones esperados, la combinación es razonable.

Lectura de componentes desde locales construidos

Después de construir un locale, puedes leer sus componentes como propiedades.

La propiedad language devuelve el código de idioma:

const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.language);
// Output: "fr"

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

const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.region);
// Output: "CA"

La propiedad script devuelve el código de escritura si se especifica:

const locale = new Intl.Locale("zh", {
  script: "Hans",
  region: "CN"
});

console.log(locale.script);
// Output: "Hans"

Si la escritura no se especifica, la propiedad devuelve undefined:

const locale = new Intl.Locale("en", { region: "US" });
console.log(locale.script);
// Output: undefined

La propiedad baseName devuelve el identificador completo sin extensiones:

const locale = new Intl.Locale("ar", {
  region: "SA",
  calendar: "islamic",
  numberingSystem: "arab"
});

console.log(locale.baseName);
// Output: "ar-SA"

Esto te proporciona la porción idioma-escritura-región sin preferencias de formato.

Convertir identificadores de locale a cadenas

El método toString() devuelve el identificador de locale completo como una cadena:

const locale = new Intl.Locale("es", { region: "MX" });
const identifier = locale.toString();

console.log(identifier);
// Output: "es-MX"

Puedes usar la cadena con otras APIs de Intl:

const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale.toString());

const price = 1234.56;
console.log(formatter.format(price));
// Output: "1.234,56"

El formateador acepta la representación en cadena.

La mayoría de las APIs de Intl también aceptan objetos de locale directamente:

const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale);

La API llama a toString() internamente cuando es necesario.

Casos de uso prácticos

Construir identificadores de locale a partir de componentes resuelve varios problemas comunes en aplicaciones internacionalizadas.

Crear selectores de locale

Las interfaces de usuario a menudo permiten a los usuarios elegir el idioma y la región por separado. Combinas las selecciones:

function createLocaleFromPicker(languageSelect, regionSelect) {
  const language = languageSelect.value;
  const region = regionSelect.value;

  const locale = new Intl.Locale(language, { region });
  return locale.toString();
}

// User selects "Spanish" and "Mexico"
const selectedLocale = createLocaleFromPicker(
  { value: "es" },
  { value: "MX" }
);

console.log(selectedLocale);
// Output: "es-MX"

Generar variantes de locale

Puedes generar múltiples variantes regionales a partir de un único código de idioma:

function generateRegionalVariants(languageCode, regionCodes) {
  return regionCodes.map(regionCode => {
    const locale = new Intl.Locale(languageCode, {
      region: regionCode
    });
    return locale.toString();
  });
}

const englishVariants = generateRegionalVariants("en", [
  "US",
  "GB",
  "CA",
  "AU",
  "NZ"
]);

console.log(englishVariants);
// Output: ["en-US", "en-GB", "en-CA", "en-AU", "en-NZ"]

Esto crea una lista de identificadores de locale para diferentes regiones de habla inglesa.

Construir locales a partir de parámetros de URL

Las URLs a menudo codifican las preferencias de locale como parámetros separados. Puedes construir un locale a partir de estos parámetros:

function getLocaleFromURL(url) {
  const params = new URL(url).searchParams;
  const language = params.get("lang");
  const region = params.get("region");

  if (!language) {
    return null;
  }

  const options = {};
  if (region) {
    options.region = region;
  }

  try {
    const locale = new Intl.Locale(language, options);
    return locale.toString();
  } catch (error) {
    return null;
  }
}

const locale1 = getLocaleFromURL("https://example.com?lang=fr&region=CA");
console.log(locale1);
// Output: "fr-CA"

const locale2 = getLocaleFromURL("https://example.com?lang=ja");
console.log(locale2);
// Output: "ja"

Normalizar identificadores de locale

Puedes normalizar identificadores de locale analizándolos y reconstruyéndolos:

function normalizeLocale(identifier) {
  try {
    const locale = new Intl.Locale(identifier);
    return locale.toString();
  } catch (error) {
    return null;
  }
}

console.log(normalizeLocale("EN-us"));
// Output: "en-US"

console.log(normalizeLocale("zh_Hans_CN"));
// Output: null (invalid separator)

El constructor normaliza las mayúsculas y valida la estructura.

Configuración de formateadores con preferencias de usuario

Puedes construir identificadores de configuración regional con preferencias de formato basadas en la configuración del usuario:

function buildFormatterLocale(language, region, preferences) {
  const locale = new Intl.Locale(language, {
    region,
    hourCycle: preferences.use24Hour ? "h23" : "h12",
    numberingSystem: preferences.numberingSystem
  });

  return locale;
}

const userPreferences = {
  use24Hour: true,
  numberingSystem: "latn"
};

const locale = buildFormatterLocale("fr", "FR", userPreferences);

const timeFormatter = new Intl.DateTimeFormat(locale, {
  hour: "numeric",
  minute: "numeric"
});

const now = new Date("2025-10-15T14:30:00");
console.log(timeFormatter.format(now));
// Output: "14:30" (24-hour format)

La configuración regional incluye preferencias de formato de la configuración del usuario.

Cuándo construir locales a partir de componentes

Construir locales a partir de componentes es útil en escenarios específicos. Utiliza este enfoque cuando tengas datos de idioma y región separados, al procesar entrada del usuario o al generar variantes de configuración regional de forma programática.

Utiliza una cadena literal para locales fijos:

// Good for fixed locales
const locale = new Intl.Locale("en-US");

Construye a partir de componentes cuando los valores provengan de variables:

// Good for dynamic locales
const locale = new Intl.Locale(userLanguage, {
  region: userRegion
});

El constructor valida los componentes y crea un identificador con formato adecuado.

Compatibilidad con navegadores

El constructor Intl.Locale funciona en todos los navegadores modernos. Chrome, Firefox, Safari y Edge admiten el constructor y el objeto de opciones para construir locales a partir de componentes.

Node.js admite Intl.Locale a partir de la versión 12, con compatibilidad completa para todas las opciones del constructor en la versión 14 y posteriores.

Resumen

El constructor Intl.Locale construye identificadores de configuración regional a partir de componentes individuales. Pasas el código de idioma como primer argumento y proporcionas script, región y preferencias de formato en un objeto de opciones.

Conceptos clave:

  • Los identificadores de configuración regional constan de componentes de idioma, script y región
  • El constructor acepta un objeto de opciones con propiedades language, script y region
  • Puedes sobrescribir componentes de una configuración regional existente pasándola como primer argumento
  • Las preferencias de formato como calendar y hourCycle aparecen como extensiones Unicode
  • El método toString() devuelve la cadena de identificador completa
  • Las propiedades como language, region y script te permiten leer componentes
  • El constructor valida la sintaxis pero no la corrección semántica

Utiliza este enfoque al construir configuraciones regionales a partir de la entrada del usuario, generar variantes regionales o combinar selecciones separadas de idioma y región. Para configuraciones regionales fijas, utiliza literales de cadena en su lugar.