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

Detecta y valida sistemas de calendario y formatos de numeración para cualquier localización 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 los 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 localizaciones específicas.

La API Intl.Locale incluye propiedades y métodos que revelan qué calendario y sistemas de numeración utiliza una localización. 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 localizaciones, comprender qué significan los diferentes sistemas y utilizar esta información para formatear contenido apropiadamente.

Comprender 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 con fines religiosos, históricos 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 eras imperiales
  • 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 los cristianos coptos

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

Comprender 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 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.

Verificar 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 te indica que al formatear fechas para usuarios tailandeses, se prefiere el calendario budista.

Diferentes configuraciones regionales 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 americano utiliza únicamente el calendario gregoriano. El árabe de Arabia Saudita utiliza comúnmente tanto el calendario gregoriano como el islámico. Las configuraciones regionales japonesas utilizan tanto el calendario gregoriano como el calendario imperial japonés.

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

Comprobar el sistema de numeración predeterminado para una configuración regional

El método getNumberingSystems() devuelve un array de sistemas de numeración comúnmente utilizados para una configuración regional. 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 configuraciones regionales 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 configuraciones regionales modernas utilizan dígitos latinos por defecto incluso cuando existen sistemas de numeración tradicionales, reflejando los patrones de uso actuales.

Leer el calendario activo de una configuración regional

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

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

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

Puedes crear configuraciones regionales con preferencias de calendario explícitas 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 configuración regional:

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 configuración regional.

Leer el sistema de numeración activo de una localización

La propiedad numberingSystem devuelve el sistema de numeración explícitamente establecido para una localización. 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 localización básica sin extensiones de sistema de numeración devuelve undefined. La localización utilizará su sistema de numeración predeterminado al formatear números.

Puedes crear localizaciones 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 localización:

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

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

Detectar cuándo una localización tiene un calendario explícito

Para comprobar si una localización tiene un calendario explícitamente establecido en lugar de usar su 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 predeterminado de la localización.

Detectar cuándo una localización tiene un sistema de numeración explícito

De manera similar, verifica si la propiedad numberingSystem está definida para detectar preferencias explícitas de 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 localización utilizará el sistema de numeración predeterminado para árabe egipcio. La segunda localización 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 adelante 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.

Crear un selector de calendario

Utiliza la información del calendario para crear 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 de árabe de Arabia Saudita, quienes comúnmente utilizan múltiples calendarios.

Crear un selector de sistema de numeración

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

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

  const labels = {
    latn: "Western (0-9)",
    arab: "Arabic-Indic (٠-٩)",
    arabext: "Eastern Arabic (۰-۹)",
    deva: "Devanagari (०-९)",
    beng: "Bengali (০-৯)"
  };

  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 opción.

Validar compatibilidad del calendario

Antes de aplicar un calendario a una configuración regional, verifica que la configuración regional 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 configuraciones regionales tailandesas admiten el calendario budista, pero las configuraciones regionales de inglés americano no lo utilizan comúnmente.

Validar compatibilidad del sistema de numeración

Verifica si una configuración regional 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 arábigo-í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 establecido explícitamente si existe uno, de lo contrario devuelve el calendario predeterminado para la configuración regional.

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 establecido explícitamente si está presente, de lo contrario el predeterminado para el locale.

Almacenar preferencias de calendario del usuario

Cuando los usuarios seleccionan una preferencia de calendario, almacénala como una cadena de locale 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 locale 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 de 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 locale incluye la preferencia de sistema de numeración y puede utilizarse directamente con las API de formateo.

Gestionar 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 única cadena de locale.

Comprobar 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 admite a partir de la versión 18.

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

Comprueba la compatibilidad 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 garantiza que tu código funcione en entornos que admiten Intl.Locale pero carecen de los métodos más recientes.

Resumen

JavaScript proporciona herramientas para detectar qué calendario y sistemas de numeración utiliza un locale 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 un locale
  • Usa getNumberingSystems() para obtener un array de sistemas de numeración comúnmente utilizados para un locale
  • La propiedad calendar devuelve el calendario establecido explícitamente o undefined
  • La propiedad numberingSystem devuelve el sistema de numeración establecido explícitamente o undefined
  • Diferentes locales tienen por defecto diferentes calendarios y sistemas de numeración
  • Aplica la información del calendario y sistema de numeración al crear formateadores
  • Almacena las preferencias del usuario como cadenas de locale con extensiones Unicode
  • Valida que los locales soporten calendarios y sistemas de numeración específicos antes de aplicarlos

Utiliza estos métodos al construir selectores de locale, almacenar preferencias de usuario, validar opciones de formato o crear aplicaciones internacionalizadas que respeten las convenciones culturales para fechas y números.