Locale — это язык, на котором могут выводиться экраны входа, сообщения с одноразовым кодом и экран согласия. Карточка Locales на странице System settings хранит список языков, помечает один из них языком по умолчанию и включает или отключает остальные. Активировать язык можно, только когда есть все нужные ему тексты.
Прежде чем начать
Карточка Locales находится на странице System settings в боковом меню в группе GLOBAL и действует для всех тенантов. Чтобы увидеть карточку, нужно разрешение locales:read, чтобы менять — locales:manage. Прежде чем активировать новый язык, добавьте его тексты в записи из раздела Активация языка.
Список

| Колонка | Значение |
|---|---|
| Code | Код из фиксированного списка, например en или ru. |
| Language | Название языка, подставляется по коду. Экраны входа показывают его в переключателе языка. |
| Status | Active или Inactive. Предлагает ли auth этот язык. Используются только активные языки. |
| Default | Язык, который применяется, когда ничего другого не подошло. Ровно один. Он должен быть активным. |
В новой установке есть en (по умолчанию) и ru, оба активны.
Правка списка
Каждое изменение на карточке сохраняется сразу, формы для отправки нет. Меню ⋯ в строке предлагает:

| Действие | Результат |
|---|---|
| Set as default | Делает активный язык, который еще не стоит по умолчанию, языком по умолчанию. |
| Activate / Deactivate | Включает или отключает язык. Активация проверяется, см. ниже. Deactivate просит подтверждение: страницы входа перестают предлагать язык, а выбравшие его пользователи переходят на язык по умолчанию. Для языка по умолчанию действие неактивно с причиной Pick another default first. |
| Remove locale | Удаляет язык после подтверждения: страницы входа перестают его предлагать, а выбравшие его пользователи переходят на язык по умолчанию. Заодно стираются тексты этого языка во всех формах и в шаблонах сообщений OTP и пароля. Описания scope и названия клиентов на этом языке сохраняются. Если добавить язык снова, тексты форм и шаблонов не вернутся. Для языка по умолчанию тоже неактивно. |
+ Add locale открывает небольшую форму.

- Выберите язык в списке Language. Код и название подставятся по нему.
- Отметьте Activate now, чтобы сразу проверить и активировать язык. Без флажка язык добавляется как Inactive.
- Нажмите Add locale.
Активация языка
Активация еще не активного языка завершится ошибкой, пока во всех этих записях нет непустого текста на нем:
| Запись | Что проверяется |
|---|---|
| Клиенты | Название каждого клиента. |
| Scope | Описание каждого scope и описание каждого claim в нем. См. Scope. |
| Формы | Каждая строка активной версии каждой формы. См. Forms. |
| Шаблоны | Каждый шаблон OTP и временного пароля. См. OTP templates. |
Если проверка не прошла, карточка показывает баннер Cannot activate ru: content is missing for N keys и список недостающего, например scope 'payments_read' description или form 'otp' v1. Заполните тексты и активируйте снова. Проверка выполняется только при активации. Уже активный язык при других изменениях заново не проверяется.

Как выбирается язык
ui_locales — параметр запроса OIDC: список кодов языков через пробел, самый предпочтительный первым. Это подсказка. Клиент может передать ее в /authorize, и непригодное значение запрос не отклоняет.
В /authorize auth оставляет из ui_locales те коды, которые активны на этом экране, в том порядке, в каком их прислал клиент. Сравнение идет по точному коду: en-US не совпадает с en. Если ничего не осталось, auth берет язык по умолчанию. Затем каждый текст выбирается по одному правилу:
- Форма берет первый язык из списка, который есть в переводах этой формы. Строки, которых нет на этом языке, берутся из языка по умолчанию. В собственном меню языков форма показывает свои языки, которые активны.
- Сообщения с одноразовым кодом и временным паролем берут первый язык из списка, для которого есть текст шаблона, затем язык по умолчанию.
- На экране согласия описания scope и claim берут первый язык из списка, для которого есть текст, затем язык по умолчанию. Если у scope нет описания, экран показывает сам ID scope.
Заголовок Accept-Language /authorize игнорирует. Экраны после него его учитывают (см. ниже).
На каком языке показывается экран
Каждый раз, когда auth показывает экран, он собирает список языков, самый предпочтительный первым. Экраны — это шаги входа, страницы «сессия истекла» и «сервис недоступен», страницы подтверждения выхода и «вы вышли», а также страница аккаунта.
| Порядок | Источник | Откуда берется |
|---|---|---|
| 1 | Язык, который выбрал пользователь | ui_locale, его отправляет только что отправленная форма. |
| 2 | Подсказки ui_locales | Коды, сохраненные в /authorize вместе со входом, либо параметр ui_locales в /logout и на странице аккаунта. |
| 3 | Accept-Language | Теги браузера в порядке их весов q. Тег с q=0 отбрасывается. |
| 4 | Язык по умолчанию | Берется, когда ни один источник выше не дал активного языка. |
Используется первый язык из списка, который активен на этом экране. Форма ищет свой перевод без учета регистра: pt-br находит pt-BR. Значение ui_locale или ui_locales, которое не тег языка, игнорируется.
Выбранный пользователем язык передается дальше в адресе. После отправки формы редирект на следующий шаг ведет на /challenge?ui_locale=ru, а если за это время вход истек, пользователя перенаправляют так же, и страница «сессия истекла» остается на его языке. Форма подтверждения выхода отправляет ui_locale вместе с запросом, поэтому страница «вы вышли» тоже сохраняет язык.
Выбор не сохраняется. Cookie нет, а страница, открытая напрямую без ui_locale и без входа (например, старая вкладка с истекшим входом), использует подсказки ui_locales и Accept-Language. По той же причине форма, которую тенант изменил и которая не отправляет ui_locale, не сохраняет язык между шагами.