Cómo verificar qué calendario o sistema de numeración utiliza una configuración regional

Detecta y valida sistemas de calendario y formatos de numeración para cualquier configuración regional con JavaScript

Introducción

Cuando alguien en Tailandia visualiza una fecha en tu aplicación web, espera ver fechas en el calendario budista, no en el calendario gregoriano utilizado en países occidentales. De manera similar, los hablantes de árabe esperan ver dígitos representados como ١٢٣ en lugar de 123. Diferentes culturas utilizan diferentes sistemas de calendario y sistemas de numeración, y JavaScript proporciona herramientas para detectar cuáles se aplican a locales específicos.

La API Intl.Locale incluye propiedades y métodos que revelan qué calendario y sistemas de numeración utiliza un locale. Esta información te ayuda a formatear fechas y números correctamente sin codificar suposiciones sobre qué sistemas prefieren las diferentes culturas.

Esta guía explica cómo verificar los sistemas de calendario y numeración para locales, entender qué significan los diferentes sistemas y utilizar esta información para formatear el contenido de manera apropiada.

Entendiendo los sistemas de calendario

Un sistema de calendario es una forma de organizar el tiempo en años, meses y días. Aunque el calendario gregoriano está muy extendido, muchas culturas utilizan diferentes sistemas de calendario por razones religiosas, históricas o culturales.

Los sistemas de calendario más comunes incluyen:

  • gregory para el calendario gregoriano, utilizado en la mayoría de los países occidentales
  • buddhist para el calendario budista, utilizado en Tailandia, Camboya y Myanmar
  • islamic para el calendario lunar islámico, utilizado con fines religiosos en países musulmanes
  • hebrew para el calendario hebreo, utilizado en Israel y para observancias religiosas judías
  • japanese para el calendario japonés, que utiliza nombres de era imperial
  • chinese para el calendario lunisolar chino, utilizado para festividades tradicionales
  • persian para el calendario solar persa, utilizado en Irán y Afganistán
  • indian para el calendario nacional indio
  • coptic para el calendario copto, utilizado en Egipto por cristianos coptos

Diferentes regiones utilizan diferentes calendarios como predeterminados, y algunas regiones comúnmente utilizan múltiples sistemas de calendario.

Comprendiendo los sistemas de numeración

Un sistema de numeración es un conjunto de símbolos utilizados para representar dígitos. Mientras que los países occidentales utilizan dígitos latinos (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), otras culturas utilizan diferentes símbolos para representar los mismos valores numéricos.

Los sistemas de numeración comunes incluyen:

  • latn para dígitos latinos: 0 1 2 3 4 5 6 7 8 9
  • arab para dígitos arábigo-índicos: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩
  • arabext para dígitos arábigo-índicos orientales: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹
  • deva para dígitos devanagari: ० १ २ ३ ४ ५ ६ ७ ८ ९
  • beng para dígitos bengalíes: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯
  • thai para dígitos tailandeses: ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙
  • hanidec para números decimales chinos
  • fullwide para dígitos de ancho completo utilizados en la tipografía de Asia Oriental

Todos los sistemas de numeración representan los mismos valores numéricos pero utilizan diferentes símbolos visuales basados en el sistema de escritura del idioma.

Comprobar el calendario predeterminado para una localización

El método getCalendars() devuelve un array de sistemas de calendario comúnmente utilizados para una localización, ordenados por preferencia. El primer elemento es el calendario predeterminado.

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

Las localizaciones tailandesas utilizan por defecto el calendario budista, pero también utilizan comúnmente el calendario gregoriano. Esto indica que al formatear fechas para usuarios tailandeses, se prefiere el calendario budista.

Diferentes localizaciones devuelven diferentes preferencias de calendario:

const usLocale = new Intl.Locale("en-US");
console.log(usLocale.getCalendars());
// ["gregory"]

const saLocale = new Intl.Locale("ar-SA");
console.log(saLocale.getCalendars());
// ["gregory", "islamic", "islamic-civil"]

const jpLocale = new Intl.Locale("ja-JP");
console.log(jpLocale.getCalendars());
// ["gregory", "japanese"]

El inglés estadounidense utiliza únicamente el calendario gregoriano. El árabe de Arabia Saudita comúnmente utiliza tanto el calendario gregoriano como el islámico. Las localizaciones japonesas utilizan tanto el calendario gregoriano como el calendario imperial japonés.

El array contiene todos los calendarios comúnmente utilizados en esa localización, lo que permite ofrecer múltiples opciones de calendario cuando sea apropiado.

Comprobar el sistema de numeración predeterminado para una localización

El método getNumberingSystems() devuelve un array de sistemas de numeración comúnmente utilizados para una localización. El primer elemento es el sistema de numeración predeterminado.

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

El árabe egipcio utiliza por defecto dígitos arábigo-índicos. Al formatear números para usuarios de árabe egipcio, utiliza el sistema de numeración arábigo-índico a menos que el usuario haya especificado lo contrario.

Diferentes localizaciones utilizan diferentes sistemas de numeración predeterminados:

const usLocale = new Intl.Locale("en-US");
console.log(usLocale.getNumberingSystems());
// ["latn"]

const inLocale = new Intl.Locale("hi-IN");
console.log(inLocale.getNumberingSystems());
// ["latn"]

const thLocale = new Intl.Locale("th-TH");
console.log(thLocale.getNumberingSystems());
// ["latn"]

El inglés americano utiliza dígitos latinos. El hindi en India también utiliza dígitos latinos por defecto en contextos modernos, aunque existen dígitos devanagari. El tailandés utiliza dígitos latinos por defecto en la mayoría de los contextos modernos.

Muchas localizaciones modernas utilizan por defecto dígitos latinos incluso cuando existen sistemas de numeración tradicionales, reflejando los patrones de uso actuales.

Leer el calendario activo de una localización

La propiedad calendar devuelve el sistema de calendario explícitamente establecido para una localización. Si no se especifica ningún calendario, devuelve undefined.

const locale = new Intl.Locale("en-US");
console.log(locale.calendar);
// undefined

Una localización básica sin extensiones de calendario devuelve undefined. La localización utilizará su calendario predeterminado al formatear fechas.

Puedes crear localizaciones con preferencias explícitas de calendario utilizando extensiones Unicode:

const locale = new Intl.Locale("en-US-u-ca-buddhist");
console.log(locale.calendar);
// "buddhist"

La extensión -u-ca-buddhist especifica el calendario budista. La propiedad calendar devuelve "buddhist".

También puedes establecer el calendario al crear la localización:

const locale = new Intl.Locale("en-US", { calendar: "islamic" });
console.log(locale.calendar);
// "islamic"

El objeto de opciones tiene prioridad sobre cualquier calendario especificado en la cadena de localización.

Leer el sistema de numeración activo desde una configuración regional

La propiedad numberingSystem devuelve el sistema de numeración explícitamente establecido para una configuración regional. Si no se especifica ningún sistema de numeración, devuelve undefined.

const locale = new Intl.Locale("en-US");
console.log(locale.numberingSystem);
// undefined

Una configuración regional básica sin extensiones de sistema de numeración devuelve undefined. La configuración regional utilizará su sistema de numeración predeterminado al formatear números.

Puedes crear configuraciones regionales con preferencias explícitas de sistema de numeración:

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

La extensión -u-nu-arab especifica dígitos arábigo-índicos. La propiedad numberingSystem devuelve "arab".

También puedes establecer el sistema de numeración al crear la configuración regional:

const locale = new Intl.Locale("ar-SA", { numberingSystem: "latn" });
console.log(locale.numberingSystem);
// "latn"

Esto crea una configuración regional árabe que utiliza dígitos latinos en lugar de los dígitos arábigo-índicos predeterminados.

Detectar cuando una configuración regional tiene un calendario explícito

Para comprobar si una configuración regional tiene un calendario explícitamente establecido en lugar de usar su valor predeterminado, verifica si la propiedad calendar está definida:

function hasExplicitCalendar(localeString) {
  const locale = new Intl.Locale(localeString);
  return locale.calendar !== undefined;
}

console.log(hasExplicitCalendar("en-US"));
// false

console.log(hasExplicitCalendar("en-US-u-ca-buddhist"));
// true

Esta distinción es importante cuando necesitas determinar si el usuario ha elegido explícitamente una preferencia de calendario o si debes usar el calendario predeterminado de la configuración regional.

Detectar cuando una configuración regional tiene un sistema de numeración explícito

De manera similar, verifica si la propiedad numberingSystem está definida para detectar preferencias explícitas del sistema de numeración:

function hasExplicitNumberingSystem(localeString) {
  const locale = new Intl.Locale(localeString);
  return locale.numberingSystem !== undefined;
}

console.log(hasExplicitNumberingSystem("ar-EG"));
// false

console.log(hasExplicitNumberingSystem("ar-EG-u-nu-latn"));
// true

La primera configuración regional utilizará el sistema de numeración predeterminado para el árabe egipcio. La segunda configuración regional solicita explícitamente dígitos latinos.

Usar información del calendario para formatear fechas

Una vez que sepas qué calendario utiliza una localización, aplícalo al formatear fechas con Intl.DateTimeFormat:

const date = new Date("2025-03-15");

const gregorianLocale = new Intl.Locale("en-US");
const gregorianFormatter = new Intl.DateTimeFormat(gregorianLocale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(gregorianFormatter.format(date));
// "March 15, 2025"

const buddhistLocale = new Intl.Locale("th-TH");
const buddhistFormatter = new Intl.DateTimeFormat(buddhistLocale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(buddhistFormatter.format(date));
// "15 มีนาคม 2568"

El calendario budista tailandés muestra la misma fecha como año 2568, que está 543 años por delante del calendario gregoriano.

También puedes anular explícitamente el calendario:

const date = new Date("2025-03-15");

const locale = new Intl.Locale("en-US", { calendar: "hebrew" });
const formatter = new Intl.DateTimeFormat(locale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});
console.log(formatter.format(date));
// "15 Adar II 5785"

Esto formatea la fecha en el calendario hebreo, mostrando el año y mes hebreo correspondiente.

Usar información del sistema de numeración para formatear números

Aplica la información del sistema de numeración al formatear números con Intl.NumberFormat:

const number = 123456;

const latinLocale = new Intl.Locale("ar-EG", { numberingSystem: "latn" });
const latinFormatter = new Intl.NumberFormat(latinLocale);
console.log(latinFormatter.format(number));
// "123,456"

const arabicLocale = new Intl.Locale("ar-EG", { numberingSystem: "arab" });
const arabicFormatter = new Intl.NumberFormat(arabicLocale);
console.log(arabicFormatter.format(number));
// "١٢٣٬٤٥٦"

El mismo número se representa con diferentes símbolos de dígitos según el sistema de numeración.

Construir un selector de calendario

Utiliza la información del calendario para construir interfaces de usuario que permitan a los usuarios elegir su calendario preferido:

function getCalendarOptions(localeString) {
  const locale = new Intl.Locale(localeString);
  const calendars = locale.getCalendars();

  return calendars.map(calendar => ({
    value: calendar,
    label: calendar.charAt(0).toUpperCase() + calendar.slice(1)
  }));
}

const options = getCalendarOptions("ar-SA");
console.log(options);
// [
//   { value: "gregory", label: "Gregory" },
//   { value: "islamic", label: "Islamic" },
//   { value: "islamic-civil", label: "Islamic-civil" }
// ]

Esto crea una lista de opciones de calendario apropiadas para usuarios árabes de Arabia Saudita, quienes comúnmente utilizan múltiples calendarios.

Construir un selector de sistema de numeración

Crea interfaces de usuario para preferencias de sistema de numeración:

function getNumberingSystemOptions(localeString) {
  const locale = new Intl.Locale(localeString);
  const systems = locale.getNumberingSystems();

  const labels = {
    latn: "Occidental (0-9)",
    arab: "Árabe-Índico (٠-٩)",
    arabext: "Árabe Oriental (۰-۹)",
    deva: "Devanagari (०-९)",
    beng: "Bengalí (০-৯)"
  };

  return systems.map(system => ({
    value: system,
    label: labels[system] || system
  }));
}

const options = getNumberingSystemOptions("ar-EG");
console.log(options);
// [{ value: "arab", label: "Arabic-Indic (٠-٩)" }]

Esto proporciona etiquetas claras para las opciones de sistema de numeración, mostrando a los usuarios cómo se ve cada elección.

Validar compatibilidad de calendario

Antes de aplicar un calendario a una localización, verifica que la localización admita ese calendario:

function supportsCalendar(localeString, calendar) {
  const locale = new Intl.Locale(localeString);
  const supportedCalendars = locale.getCalendars();
  return supportedCalendars.includes(calendar);
}

console.log(supportsCalendar("th-TH", "buddhist"));
// true

console.log(supportsCalendar("en-US", "buddhist"));
// false

Las localizaciones tailandesas admiten el calendario budista, pero las localizaciones de inglés americano no lo utilizan comúnmente.

Validar compatibilidad de sistema de numeración

Comprueba si una localización admite un sistema de numeración específico:

function supportsNumberingSystem(localeString, numberingSystem) {
  const locale = new Intl.Locale(localeString);
  const supportedSystems = locale.getNumberingSystems();
  return supportedSystems.includes(numberingSystem);
}

console.log(supportsNumberingSystem("ar-EG", "arab"));
// true

console.log(supportsNumberingSystem("en-US", "arab"));
// false

El árabe egipcio admite dígitos árabe-índicos, pero el inglés americano no los utiliza.

Determinar el calendario efectivo para el formateo

Al formatear fechas, determina qué calendario se utilizará realmente:

function getEffectiveCalendar(localeString) {
  const locale = new Intl.Locale(localeString);

  if (locale.calendar) {
    return locale.calendar;
  }

  const defaultCalendars = locale.getCalendars();
  return defaultCalendars[0];
}

console.log(getEffectiveCalendar("th-TH"));
// "buddhist"

console.log(getEffectiveCalendar("en-US-u-ca-islamic"));
// "islamic"

Esta función devuelve el calendario explícitamente establecido si existe uno, de lo contrario devuelve el calendario predeterminado para la localización.

Determinar el sistema de numeración efectivo para el formateo

Determina qué sistema de numeración se utilizará al formatear números:

function getEffectiveNumberingSystem(localeString) {
  const locale = new Intl.Locale(localeString);

  if (locale.numberingSystem) {
    return locale.numberingSystem;
  }

  const defaultSystems = locale.getNumberingSystems();
  return defaultSystems[0];
}

console.log(getEffectiveNumberingSystem("ar-EG"));
// "arab"

console.log(getEffectiveNumberingSystem("ar-EG-u-nu-latn"));
// "latn"

Esto devuelve el sistema de numeración explícitamente establecido si está presente, de lo contrario, el predeterminado para la configuración regional.

Almacenar preferencias de calendario del usuario

Cuando los usuarios seleccionan una preferencia de calendario, almacénala como una cadena de configuración regional con extensiones:

function setUserCalendarPreference(baseLocale, calendar) {
  const locale = new Intl.Locale(baseLocale, { calendar });
  return locale.toString();
}

const preference = setUserCalendarPreference("en-US", "buddhist");
console.log(preference);
// "en-US-u-ca-buddhist"

Esto crea una cadena de configuración regional completa que preserva la preferencia de calendario. Almacena esta cadena en la configuración del usuario o en cookies.

Almacenar preferencias de sistema de numeración del usuario

Almacena las preferencias del sistema de numeración de la misma manera:

function setUserNumberingPreference(baseLocale, numberingSystem) {
  const locale = new Intl.Locale(baseLocale, { numberingSystem });
  return locale.toString();
}

const preference = setUserNumberingPreference("ar-SA", "latn");
console.log(preference);
// "ar-SA-u-nu-latn"

La cadena de configuración regional incluye la preferencia del sistema de numeración y puede usarse directamente con las APIs de formateo.

Manejar múltiples preferencias simultáneamente

Los usuarios pueden tener preferencias tanto de calendario como de sistema de numeración:

function createLocaleWithPreferences(baseLocale, options) {
  const locale = new Intl.Locale(baseLocale, {
    calendar: options.calendar,
    numberingSystem: options.numberingSystem
  });
  return locale.toString();
}

const preference = createLocaleWithPreferences("ar-SA", {
  calendar: "islamic",
  numberingSystem: "latn"
});
console.log(preference);
// "ar-SA-u-ca-islamic-nu-latn"

Esto combina múltiples preferencias de formateo en una sola cadena de configuración regional.

Verificar opciones de formateo resueltas

Después de crear un formateador, verifica qué calendario y sistema de numeración utiliza:

const locale = new Intl.Locale("th-TH");
const formatter = new Intl.DateTimeFormat(locale, {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const options = formatter.resolvedOptions();
console.log(options.calendar);
// "buddhist"
console.log(options.numberingSystem);
// "latn"

El método resolvedOptions() muestra qué calendario y sistema de numeración utiliza realmente el formateador después de resolver los valores predeterminados y las preferencias del usuario.

Compatibilidad con navegadores

La API Intl.Locale es compatible con todos los navegadores modernos. Los métodos getCalendars() y getNumberingSystems() requieren versiones recientes de navegadores. Chrome 99, Firefox 99, Safari 15.4 y Edge 99 son compatibles con estos métodos. Node.js los soporta a partir de la versión 18.

Las propiedades calendar y numberingSystem tienen un soporte más amplio, disponibles desde la introducción de Intl.Locale en Chrome 74, Firefox 75, Safari 14 y Node.js 12.

Verifica el soporte del método antes de usarlo:

const locale = new Intl.Locale("th-TH");

if (typeof locale.getCalendars === "function") {
  const calendars = locale.getCalendars();
  console.log(calendars);
}

Esto asegura que tu código funcione en entornos que soportan Intl.Locale pero carecen de los métodos más nuevos.

Resumen

JavaScript proporciona herramientas para detectar qué calendario y sistemas de numeración utiliza una localización a través de la API Intl.Locale. Estas herramientas te ayudan a formatear fechas y números correctamente para diferentes culturas sin codificar suposiciones.

Conceptos clave:

  • Usa getCalendars() para obtener un array de calendarios comúnmente utilizados para una localización
  • Usa getNumberingSystems() para obtener un array de sistemas de numeración comúnmente utilizados para una localización
  • La propiedad calendar devuelve el calendario explícitamente establecido o undefined
  • La propiedad numberingSystem devuelve el sistema de numeración explícitamente establecido o undefined
  • Diferentes localizaciones utilizan por defecto diferentes calendarios y sistemas de numeración
  • Aplica la información de calendario y sistema de numeración al crear formateadores
  • Almacena las preferencias del usuario como cadenas de localización con extensiones Unicode
  • Valida que las localizaciones soporten calendarios específicos y sistemas de numeración antes de aplicarlos

Utiliza estos métodos cuando construyas selectores de localización, almacenes preferencias de usuario, valides opciones de formato o crees aplicaciones internacionalizadas que respeten las convenciones culturales para fechas y números.