Как проверить, какую календарную или числовую систему использует локаль
Определяйте и проверяйте календарные системы и числовые форматы для любой локали с помощью 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));
// "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 Адара 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: "Западная (0-9)",
arab: "Арабская-Индийская (٠-٩)",
arabext: "Восточная арабская (۰-۹)",
deva: "Деванагари (०-९)",
beng: "Бенгальская (০-৯)"
};
return systems.map(system => ({
value: system,
label: labels[system] || system
}));
}
const options = getNumberingSystemOptions("ar-EG");
console.log(options);
// [{ value: "arab", label: "Арабская-Индийская (٠-٩)" }]
Это обеспечивает понятные метки для вариантов системы нумерации, показывая пользователям, как выглядит каждый выбор.
Проверка совместимости календаря
Перед применением календаря к локали убедитесь, что локаль поддерживает этот календарь:
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() показывает, какой календарь и система нумерации фактически используются форматтером после разрешения значений по умолчанию и пользовательских предпочтений.
Поддержка браузеров
Intl.Locale API поддерживается всеми современными браузерами. Методы 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
- Убедитесь, что локали поддерживают определенные календари и системы счисления перед их применением
Используйте эти методы при создании селекторов локалей, сохранении пользовательских предпочтений, проверке параметров форматирования или создании интернационализированных приложений, которые учитывают культурные особенности форматирования дат и чисел.