Документация

Дизайн для любого рынка

Чего ожидает каждый рынок от текста, чисел, дат, валюты, сортировки, имён, адресов, единиц измерения, полей ввода и верстки, как писать код, чтобы всё работало корректно, и какие пометки проверки Глобализации указывают на неверные подходы.

Функционал готов к использованию во всём мире, когда он работает на любом языке и соответствует нормам каждого читателя без изменений в коде. Эта страница следует рекомендациям Microsoft. Контрольный список интернационализации: в каждом разделе описаны различия между рынками, правила написания корректного кода и Проверка Глобализации код, который отмечает неверный подход.

В основном всё сводится к одному правилу: пусть локаль читателя определяет параметры. Браузерная Intl API, средства форматирования вашего фреймворка и используемые данные Культура учитывает нормы каждого рынка; код с жёстко заданными параметрами для одного рынка такого не делает.

Текст и предложения

Любой текст, который видит пользователь, должен быть добавлен в каталог источников под соответствующим ключом и отображаться через функцию перевода проекта. Сюда относятся метки, заголовки, кнопки, сообщения, ошибки, плейсхолдеры alt текст и метки ARIA. Коды: hardcoded_text.

Одно предложение — это одно сообщение. Порядок слов различается в разных языках, поэтому предложение, собранное из частей, перевести нельзя. Передавайте значения через плейсхолдеры, а счётчики — через формы множественного числа. Коды: concatenated_text.

// Not world-ready: English word order and English plurals
'You have ' + count + ' new ' + (count === 1 ? 'message' : 'messages');

// World-ready: one ICU message
t('inbox.new', { count });
// "inbox.new": "{count, plural, one {You have # new message} other {You have # new messages}}"

Для разных языков нужны разные формы множественного числа: в английском их два, в арабском — шесть, в японском — одна. Записывайте исходное сообщение с использованием ICU-плагинов, а движок сам добавит нужные формы для каждого языка.

Числа

На разных рынках одно и то же число записывается по-разному: в США — 1,234.5, в Германии — 1.234,5, в Швеции и Франции — 1 234,5, а в некоторых арабских странах — иначе. Форматируйте числа с учётом локали читателя. Коды: locale_number.

new Intl.NumberFormat(locale).format(1234.5);
new Intl.NumberFormat(locale, { style: 'percent' }).format(0.25);

Считывайте число, введённое пользователем, с учётом той же локали, или используйте поле ввода чисел, значение которого нормализует браузер. parseFloat('1,5') равно 1, а не «одна с половиной». Коды: locale_parsing.

Даты, время и часовые пояса

Порядок дат, разделители, названия месяцев, 12- или 24-часовой формат и календарь — всё это различается. Форматируйте данные с учётом локали читателя и никогда не используйте фиксированный шаблон вроде MM/dd/yyyy. Коды: locale_date.

new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short', timeZone }).format(when);
  • Храните моменты времени в формате UTC, в виде строки ISO 8601 с указанием смещения, и форматируйте их в часовом поясе читателя. Рассчитывайте «сегодня» и границы дней именно в этом часовом поясе, а не в часовом поясе сервера.
  • Неделя начинается в разные дни: в США — в воскресенье, в большинстве стран Европы — в понедельник, в некоторых странах Ближнего Востока — в субботу. Выходные тоже различаются. Учитывайте эти параметры из локали (new Intl.Locale(locale).getWeekInfo() при наличии или из данных локали вашей библиотеки для работы с датами), а не используйте постоянные значения. Коды: calendar_names.
  • Названия дней недели и месяцев берутся из локалиIntl.DateTimeFormat(locale, { weekday: 'long' })), а не из списка в коде. Коды: calendar_names.
  • Календари. В Саудовской Аравии, Израиле и Японии григорианский календарь используется наряду с календарями Умм аль-Кура, еврейским и японским; в Таиланде и Иране по умолчанию применяются буддийский и персидский календари. Культура указывает, какой календарь используется на конкретном рынке.

Валюта

Форматируйте суммы с учётом валюты и локали читателя, никогда не ставьте символ рядом с числом. Одна и та же сумма будет выглядеть $1,234.50, 1.234,50 $ или US$1,234.50 в зависимости от читателя, причём во многих странах используется один и тот же символ. Коды: hardcoded_currency.

new Intl.NumberFormat(locale, { style: 'currency', currency }).format(1234.5);

Выбор валюты — это коммерческое решение, а не вопрос форматирования: изменение локали читателя не должно приводить к пересчёту цен. Культура указывает валюту, принятую на каждом рынке.

Сортировка, сравнение и регистр

Каждый язык имеет свои правила сортировки: в шведском языке буквы å, ä и ö идут после z, в немецком ä сортируется как a, а в китайском — по пиньиню или количеству черт. Сортируйте текст для пользователей с учётом локали читателя. Коды: ordinal_sort.

names.sort(new Intl.Collator(locale).compare);

Сопоставление регистра также зависит от языка: в турецком языке заглавная буква i — это İ. Используйте toLocaleUpperCase(locale) для текста, который видит пользователь. Коды: case_mapping.

Списки

«Анна, Бен и Чен» пишется по-разному в разных языках. Объединяйте элементы списка с учётом локали. Коды: joined_list.

new Intl.ListFormat(locale, { style: 'long', type: 'conjunction' }).format(names);

Имена, адреса, почтовые индексы и номера телефонов

  • Имена. Во многих странах фамилия стоит первой, а у многих людей одно имя или более двух. Вводите имя человека в одно поле, если для конкретного рынка не требуется разделять его части. Принимайте любые алфавиты: Åsa, José, 王 и Мария — все это имена. Коды: latin_only_input.
  • Адреса. Поля, их порядок и названия различаются: в США это штат и почтовый индекс, в Японии — префектура, в некоторых странах почтового индекса вообще нет. Культура показывает, как оформляется адрес в каждой стране. Не требуйте заполнения полей, которые не используются на конкретном рынке.
  • Почтовые индексы. Оставляйте их как текст и проверяйте по правилам конкретной страны или вообще не проверяйте. Шаблон из пяти цифр не подойдёт для большинства стран мира. Коды: postal_code_format.
  • Номера телефонов. Храните их в формате E.164 (+46 8 123 456 78), форматируйте и проверяйте с помощью библиотеки, знающей планы нумерации каждой страны, например libphonenumber. Шаблон вроде (555) 555-1234 Отклоняет любые числа, не относящиеся к Северной Америке. Коды: phone_number_format.

Единицы измерения и бумага

В большинстве стран используются километры, килограммы и градусы Цельсия; в США — мили, фунты и градусы Фаренгейта; в Великобритании применяются оба варианта. Берите единицу измерения из региона читателя и форматируйте её с учётом локали. Коды: fixed_unit.

new Intl.NumberFormat(locale, { style: 'unit', unit: 'kilometer' }).format(12);

Печатный и PDF-формат вывода соответствует стандартам бумаги на рынке: в Северной Америке — формат Letter, почти повсюду — формат A4. Коды: paper_size.

Методы ввода и шрифты

Для ввода текста на китайском, японском и корейском языках используется редактор методов ввода: для выбора слова нажимают Enter, а не для отправки данных. Обработчик, отправляющий данные по нажатию Enter, должен игнорировать этот сигнал во время формирования слова. Коды: ime_composition.

onKeyDown={event => {
  if (event.key === 'Enter' && !event.nativeEvent.isComposing) submit();
}}

Выбирайте шрифты, охватывающие все используемые скрипты, или используйте системные шрифты, которые это обеспечивают; для арабского, китайского, иврита, японского, корейского и тайского языков требуются отдельные шрифты. Оставляйте в межстрочном интервале место для скриптов с высокими символами, не полагайтесь на курсив (для китайского и японского языков он отсутствует), и никогда не размещайте текст в изображениях — их невозможно перевести.

Направление справа налево

Арабский и иврит пишутся справа налево, при этом вся верстка также отражается: навигация, выравнивание, значки, указывающие направление, и порядок колонок.

  • Установите dir="rtl" на корневой элемент для этих языков, а также lang для каждого языка.
  • Используйте логические свойства: margin-inline-start вместо margin-left, padding-inline-end, inset-inline-start, text-align: start, float: inline-start, а также логические вспомогательные классы вашей CSS-системы (ms-4, pe-2, text-start). Коды: physical_direction, unmirrored_layout.
  • Зеркально отображайте значки, указывающие направление, такие как стрелки и шевроны, но не другие, например часы или кнопку воспроизведения.
  • Числа, код, URL и имена латинского алфавита остаются слева направо внутри текста, написанного справа налево. Изолируйте такой текст от людей или данных в <bdi> , чтобы он не нарушал порядок окружающих элементов.

Пространство для расширения

Тексты переводов часто длиннее английских версий, причём самые короткие метки увеличиваются больше всего: немецкое слово «OK» может превратиться в целое слово, а метка из десяти символов — удвоиться. Оставляйте тексту пространство: позволяйте ему переноситься, давайте кнопкам и вкладкам увеличиваться вслед за метками, избегайте фиксированных ширины и высоты для текста. Не сокращайте метки, необходимые пользователям для выполнения действий. Коды: clipped_text.

Режим псевдоперевод удлиняет каждую строку на указанные значения, чтобы вы могли увидеть проблему до того, как её заметит переводчик:

Исходная длинаДобавлено
До 10 символов100%
От 11 до 2080%
От 21 до 3060%
От 31 до 5040%
От 51 до 7031%
Более 7030%

Китайский, японский и корейский текст обычно короче, но требует более высоких строк.

Чек-лист для каждого изменения.

  • Текст, который читают пользователи, берётся из каталога, а каждое предложение — это одно сообщение.
  • Числа, даты, время, валюта, единицы измерения и списки адаптируются под локаль читателя.
  • Сортировка и сопоставление регистра букв осуществляются с учётом локали читателя.
  • Имена, адреса, почтовые индексы и номера телефонов поддерживают все рынки.
  • Нажатие клавиши Enter не отправляет данные, пока идет набор слова.
  • Макет использует логические свойства и предусматривает место для более длинных текстов.