Как узнать, какой календарь или систему чисел использует локаль
Определяйте и проверяйте системы календарей и форматы чисел для любой локали с помощью JavaScript
Введение
Когда кто-то из Таиланда смотрит на дату в вашем веб-приложении, они ожидают увидеть даты по буддийскому календарю, а не по григорианскому, принятому в западных странах. Точно так же носители арабского языка ожидают увидеть цифры, отображённые как ١٢٣, а не 123. Разные культуры используют разные системы календарей и чисел, и в JavaScript есть инструменты, которые позволяют определить, какие из них применяются для конкретной локали.
API Intl.Locale содержит свойства и методы, которые показывают, какие системы календарей и чисел используются в локали. Эта информация помогает правильно форматировать даты и числа без жёстких предположений о предпочтениях разных культур.
В этом гайде рассказывается, как проверить системы календарей и чисел для локалей, что означают разные системы и как использовать эту информацию для корректного форматирования контента.
Понимание систем календарей
Система календаря — это способ организации времени по годам, месяцам и дням. Хотя григорианский календарь широко распространён, многие культуры используют другие системы календарей по религиозным, историческим или культурным причинам.
Самые распространённые системы календарей включают:
gregory— григорианский календарь, используется в большинстве западных странbuddhist— буддийский календарь, используется в Таиланде, Камбодже и Мьянмеislamic— исламский лунный календарь, используется для религиозных целей в мусульманских странахhebrew— еврейский календарь, используется в Израиле и для иудейских религиозных обрядовjapanese— японский календарь, использует императорские эрыchinese— китайский лунно-солнечный календарь, используется для традиционных праздниковpersian— персидский солнечный календарь, используется в Иране и Афганистанеindian— индийский национальный календарьcoptic— коптский календарь, используется в Египте коптскими христианами
В разных регионах по умолчанию используются разные календари, а в некоторых регионах часто применяются сразу несколько календарных систем.
Понимание систем счисления
Система счисления — это набор символов для обозначения цифр. В западных странах используются латинские цифры (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), а в других культурах для тех же числовых значений применяются другие символы.
К распространённым системам счисления относятся:
latnдля латинских цифр: 0 1 2 3 4 5 6 7 8 9arabдля арабских цифр: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩arabextдля восточно-арабских цифр: ۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹devaдля деванагари: ० १ २ ३ ४ ५ ६ ७ ८ ९bengдля бенгальских цифр: ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯thaiдля тайских цифр: ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙hanidecдля китайских десятичных чиселfullwideдля полноширинных цифр, используемых в восточноазиатской типографике
Все системы счисления обозначают одни и те же числовые значения, но используют разные визуальные символы в зависимости от письменности языка.
Как узнать календарь по умолчанию для локали
Метод getCalendars() возвращает массив календарных систем, которые обычно используются для данной локали, в порядке предпочтения. Первый элемент — это календарь по умолчанию.
const locale = new Intl.Locale("th-TH");
const calendars = locale.getCalendars();
console.log(calendars);
// ["buddhist", "gregory"]
В тайских локалях по умолчанию используется буддийский календарь, но также часто применяется григорианский. Это значит, что при форматировании дат для тайских пользователей предпочтительнее использовать буддийский календарь.
В разных локалях используются разные календари по умолчанию:
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"]
В американском английском используется только григорианский календарь. В арабском языке Саудовской Аравии обычно применяются и григорианский, и исламский календари. В японских локалях используются григорианский и японский императорский календари.
Массив содержит все календари, которые обычно используются в данной локали, чтобы вы могли предложить пользователю несколько вариантов, если это уместно.
Как узнать систему счисления по умолчанию для локали
Метод getNumberingSystems() возвращает массив систем счисления, которые обычно используются в локали. Первый элемент — это система счисления по умолчанию.
const locale = new Intl.Locale("ar-EG");
const numberingSystems = locale.getNumberingSystems();
console.log(numberingSystems);
// ["arab"]
В египетском арабском по умолчанию используются арабско-индийские цифры. При форматировании чисел для пользователей из Египта используйте арабско-индийскую систему, если пользователь не указал другую.
В разных локалях используются разные системы счисления по умолчанию:
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"]
В американском английском используются латинские цифры. В хинди в Индии по умолчанию также используются латинские цифры в современных контекстах, хотя существуют и деванагарские цифры. В тайском языке по умолчанию в большинстве современных случаев тоже используются латинские цифры.
Во многих современных локалях по умолчанию используются латинские цифры, даже если существуют традиционные системы счисления — это отражает современные тенденции.
Как узнать активный календарь локали
Свойство calendar возвращает календарную систему, явно установленную для локали. Если календарь не указан, возвращается undefined.
const locale = new Intl.Locale("en-US");
console.log(locale.calendar);
// undefined
Базовая локаль без расширения календаря возвращает undefined. В этом случае локаль будет использовать календарь по умолчанию при форматировании дат.
Вы можете создавать локали с явными предпочтениями календаря с помощью расширений Unicode:
const locale = new Intl.Locale("en-US-u-ca-buddhist");
console.log(locale.calendar);
// "buddhist"
Расширение -u-ca-buddhist указывает на буддийский календарь. Свойство calendar возвращает "buddhist".
Вы также можете задать календарь при создании локали:
const locale = new Intl.Locale("en-US", { calendar: "islamic" });
console.log(locale.calendar);
// "islamic"
Объект options имеет приоритет над любым календарём, указанным в строке локали.
Получение активной системы счисления из локали
Свойство numberingSystem возвращает явно установленную для локали систему счисления. Если система счисления не указана, возвращается undefined.
const locale = new Intl.Locale("en-US");
console.log(locale.numberingSystem);
// undefined
Базовая локаль без расширения системы счисления возвращает undefined. Такая локаль будет использовать свою систему счисления по умолчанию при форматировании чисел.
Вы можете создавать локали с явным указанием предпочтительной системы счисления:
const locale = new Intl.Locale("en-US-u-nu-arab");
console.log(locale.numberingSystem);
// "arab"
Расширение -u-nu-arab указывает на арабско-индийские цифры. Свойство numberingSystem возвращает "arab".
Вы также можете задать систему счисления при создании локали:
const locale = new Intl.Locale("ar-SA", { numberingSystem: "latn" });
console.log(locale.numberingSystem);
// "latn"
Это создаёт арабскую локаль, использующую латинские цифры вместо стандартных арабско-индийских.
Определение, задан ли в локали явный календарь
Чтобы проверить, установлен ли в локали явный календарь или используется календарь по умолчанию, проверьте, определено ли свойство calendar:
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
Это различие важно, если нужно понять, выбрал ли пользователь конкретный календарь или стоит использовать календарь по умолчанию для локали.
Определение, задана ли явная система счисления в локали
Аналогично, проверьте, определено ли свойство numberingSystem, чтобы узнать, задана ли явная система счисления:
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
Первая локаль будет использовать систему счисления по умолчанию для египетского арабского. Вторая локаль явно использует латинские цифры.
Используйте информацию о календаре для форматирования дат
Когда вы знаете, какой календарь используется в локали, применяйте его при форматировании дат с помощью 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"
В тайском буддийском календаре та же дата отображается как 2568 год, что на 543 года больше григорианского календаря.
Вы также можете явно переопределить календарь:
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"
Это форматирует дату по еврейскому календарю, отображая соответствующий еврейский год и месяц.
Используйте информацию о системе счисления для форматирования чисел
Применяйте информацию о системе счисления при форматировании чисел с помощью 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));
// "١٢٣٬٤٥٦"
Одно и то же число отображается разными символами цифр в зависимости от системы счисления.
Создайте селектор календаря
Используйте информацию о календаре для создания интерфейса, позволяющего пользователям выбирать предпочитаемый календарь:
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" }
// ]
Это создаёт список вариантов календарей, подходящих для пользователей из Саудовской Аравии, которые часто используют несколько календарей.
Создайте селектор системы счисления
Создайте интерфейс для выбора предпочтительной системы счисления:
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 (٠-٩)" }]
Это даёт понятные подписи к вариантам системы счисления, чтобы пользователи видели, как выглядит каждый вариант.
Проверьте совместимость календаря
Перед применением календаря к локали убедитесь, что локаль поддерживает этот календарь:
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
В тайских локалях поддерживается буддийский календарь, а в американском английском он обычно не используется.
Проверьте совместимость системы счисления
Проверьте, поддерживает ли локаль определённую систему счисления:
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
В египетском арабском используются арабо-индийские цифры, а в американском английском они не применяются.
Определение используемого календаря для форматирования
При форматировании дат определите, какой календарь будет фактически использоваться:
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"
Эта функция возвращает явно установленный календарь, если он задан, иначе — календарь по умолчанию для локали.
Определение используемой системы счисления для форматирования
Определите, какая система счисления будет использоваться при форматировании чисел:
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"
Возвращается явно установленная система счисления, если она есть, иначе — система по умолчанию для локали.
Сохранение пользовательских настроек календаря
Когда пользователь выбирает предпочтительный календарь, сохраняйте его как строку локали с расширениями:
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"
Это создаёт полную строку локали, в которой сохраняется выбранный календарь. Сохраняйте эту строку в настройках пользователя или в cookies.
Сохранение пользовательских настроек системы счисления
Сохраняйте предпочтения системы счисления аналогичным образом:
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"
Строка локали включает выбранную систему счисления и может использоваться напрямую с API форматирования.
Одновременная работа с несколькими предпочтениями
Пользователь может выбрать и календарь, и систему счисления одновременно:
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"
Это объединяет несколько предпочтений форматирования в одну строку локали.
Проверка итоговых параметров форматирования
После создания форматтера проверьте, какой календарь и систему счисления он использует:
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"
Метод resolvedOptions() показывает, какой календарь и систему счисления на самом деле использует форматтер после применения значений по умолчанию и пользовательских настроек.
Поддержка браузеров
API Intl.Locale поддерживается во всех современных браузерах. Методы getCalendars() и getNumberingSystems() требуют более новых версий браузеров. Chrome 99, Firefox 99, Safari 15.4 и Edge 99 поддерживают эти методы. Node.js поддерживает их начиная с версии 18.
Свойства calendar и numberingSystem имеют более широкую поддержку и доступны с момента появления Intl.Locale в Chrome 74, Firefox 75, Safari 14 и Node.js 12.
Проверьте поддержку метода перед использованием:
const locale = new Intl.Locale("th-TH");
if (typeof locale.getCalendars === "function") {
const calendars = locale.getCalendars();
console.log(calendars);
}
Это гарантирует, что ваш код будет работать в средах, где поддерживается Intl.Locale, но отсутствуют новые методы.
Итоги
JavaScript предоставляет инструменты для определения, какие календарь и система счисления используются в локали, с помощью API Intl.Locale. Эти инструменты помогают правильно форматировать даты и числа для разных культур без жёстко заданных предположений.
Ключевые моменты:
- Используйте
getCalendars(), чтобы получить массив часто используемых календарей для локали - Используйте
getNumberingSystems(), чтобы получить массив часто используемых систем счисления для локали - Свойство
calendarвозвращает явно установленный календарь илиundefined - Свойство
numberingSystemвозвращает явно установленную систему счисления илиundefined - В разных локалях по умолчанию используются разные календари и системы счисления
- Учитывайте информацию о календаре и системе счисления при создании форматтеров
- Сохраняйте пользовательские настройки в виде строк локали с Unicode-расширениями
- Проверяйте, поддерживает ли локаль определённые календари и системы счисления перед их применением
Используйте эти методы при создании селекторов локалей, хранении пользовательских настроек, проверке параметров форматирования или разработке интернационализированных приложений, которые учитывают культурные особенности отображения дат и чисел.