UI интерфейс · 0.8.1

Content / Languages: языки и переводы

Настройте языки сущности и переводимые поля, заполните переводы в админке и выберите язык ответа API.

На этой странице

Один товар может иметь название и описание на нескольких языках, а цену, категорию и изображения — общие для всех переводов. Для этого не нужно создавать отдельную запись товара на каждом языке.

Языки задаются у каждой сущности отдельно. Например, у Product можно включить английский, русский и китайский, а у внутренней OwnerBonus оставить только русский. Язык данных не выдаёт права доступа: кто видит сущность и её записи, по-прежнему определяет Access. Интерфейс генератора и готовой админки остаётся английским.

Настройте языки сущности

  1. В Content выберите persistent-сущность, например Product, и откройте Entity settings.
  2. Перейдите во вкладку Languages после Basic settings и включите Content languages.
  3. В Languages выберите нужные языки. Например, en — английский, ru — русский, zh-Hans — упрощённый китайский, zh-Hant — традиционный китайский. Можно выбрать и один язык.
  4. В Default language задайте основной язык. Он используется при чтении без параметра locale и показывается первым в языковых вкладках и селектах админки.
  5. В Localized fields отметьте поля, для которых нужны переводы.
  6. Выберите обязательность заполнения и поведение при отсутствии перевода по таблице ниже.
  7. Нажмите Finish, затем выполните Generate. Примените созданную миграцию и пересоберите приложение.

Настройка Что она меняет
Require all languages выключено Обязательные переводимые поля нужно заполнить только на основном языке.
Require all languages включено Обязательные переводимые поля нужно заполнить на каждом выбранном языке. Необязательные поля остаются необязательными. Проверка выполняется при сохранении, а не только при публикации.
Missing translation → Return empty value Если нужного перевода нет, API возвращает null. Это исходное поведение: другой язык автоматически не подставляется.
Missing translation → Use default language Вместо отсутствующего значения API возвращает значение этого поля на основном языке сущности. Если и его нет, результат — null.

Подстановка работает для каждого поля отдельно. Если русское название заполнено, а русское описание отсутствует, при включённой подстановке API сохранит русское название и возьмёт только описание с основного языка. Эта настройка чтения не заменяет обязательность заполнения и не создаёт перевод в БД.

Выберите, какие поля переводить

В примере Product есть поля name, description, price и categoryId:

Поле Настройка Результат
name: string Localized, Required У товара свои названия по языкам; обязательность проверяется по настройке Require all languages.
description: text Localized Описание можно заполнить отдельно на каждом языке, в том числе через Markdown-редактор.
price: int64 Общее поле Одна цена для всех языков.
categoryId: relation Общее поле Одна связь с категорией для всех переводов товара.

Переводить можно обычные поля string и text, включая текст с Markdown. Идентификаторы, связи, автогенерируемые поля, enum, числа, даты, JSON, изображения, скрытые и password-поля остаются общими. Чтобы переводить подпись категории, настройте Languages у самой Category.

Переключатель Localized есть и в редакторе отдельного поля. Если он недоступен, сначала настройте языки сущности. Подсказка рядом с ним напоминает, где настроить языки: Entity settings → Languages. В Content языки сущности и переводимые поля отмечаются бейджами.

Заполните переводы в админке

Откройте запись Product. Над полями формы появятся языковые вкладки; основной язык идёт первым. При единственном языке вместо вкладок может отображаться его подпись.

Переключайтесь между вкладками и вводите переводы. Поля остаются в выбранном вами порядке: меняются только переводимые значения. Цена, категория и другие общие поля не получают отдельных копий. Например, подпись name-ru означает русское значение поля name; поле с именем name-ru в модели или API не создаётся.

Нажмите Save, чтобы сохранить запись. Сервер проверяет обязательные переводы; если их не хватает, форму нужно дополнить. Переключение вкладки само по себе данные не сохраняет. Readonly продолжает запрещать изменение переводов уже созданной записи; такие значения заполняйте при создании.

В списке Content language выбирает язык отображения, поиска, фильтров и сортировки. Админка запоминает выбранный язык. Поэтому основной язык будет первым в списке, но после возвращения может остаться выбранным другой язык, с которым вы работали.

Как языки работают в virtual

Virtual читает переводы исходных persistent-сущностей. Отдельные языки или копии переводов у неё создавать не нужно; редактируют данные в исходных сущностях.

Например, CatalogVirtual построена на Category и выбирает связанные products.name и products.description. Даже если у Category языки не включены, а у Product настроены en, ru и zh-Hans, у virtual появится переключатель этих языков.

В него входят языки всех сущностей, чьи переводимые поля выбраны в virtual: основного источника, belongsTo и hasMany. Если переводимые поля не выбраны, переключатель не нужен и не показывается. Начальный основной язык берётся у основного источника, если его переводимые поля участвуют в выборке; иначе — у первой выбранной связанной сущности с такими полями.

Выбранный язык применяется и к вложенным коллекциям: их поиск, фильтры и сортировка работают с соответствующими переводами. Если у связанной сущности нужного языка или значения нет, её переводимые поля возвращаются как null либо используют её собственную настройку подстановки. Общие поля остаются доступными; само отсутствие перевода не удаляет родительскую запись из ответа. Подробнее — виртуальные сущности.

Получите нужный язык через API

Добавьте ?locale=ru к list/get-запросу, чтобы получить русские значения. Без locale каждая исходная сущность использует свой основной язык. Параметр не обходит Access и правила чтения. Если у persistent-сущности с включёнными языками запрошенный язык не настроен, API вернёт HTTP 400; virtual принимает языки выбранных переводимых полей всех своих источников.

External API возвращает обычные имена полей — например, name и description, уже на выбранном языке. В нём нет карты всех переводов. Admin API дополнительно использует _translations: карту языков и значений. Примеры запросов и сохранения есть в документации API.

Если в БД уже есть данные

При первом включении локализации существующие значения становятся значениями основного языка. Остальные переводы можно заполнить позже — Admingen не переводит тексты автоматически.

Добавление локализации, новых языков и включение Require all languages не требует заранее заполнять старые записи. Сохраните нужные настройки, выполните Generate, примените новую миграцию и пересоберите приложение. Миграция не останавливается только из-за того, что в старых записях ещё нет обязательных переводов; такие значения могут оставаться null.

При создании или сохранении записи уже действуют текущие требования: обязательные поля нужно заполнить на основном языке либо на всех выбранных языках. Это относится и к редактированию старой записи, даже если вы меняете другое поле. Статус draft не отменяет проверку. Поэтому старые записи можно читать сразу после обновления, а перед их сохранением — дополнить недостающие значения.

При необходимости заполните старые данные вручную в админке или своей SQL-миграцией. Генератор не придумывает переводы, пустые строки или нулевые значения для выполнения новых требований. Если у вас уже есть ранее созданная блокирующая SQL-миграция, новое Generate не переписывает её автоматически — её применение и историю нужно разобрать отдельно.

Удаление языка из настройки сохраняет его переводы в БД, но убирает язык из доступных вариантов. При смене основного языка отсутствующие переводы также не блокируют новую миграцию; перед сохранением записи их проверят по актуальным правилам. Переименование уже сгенерированного переводимого поля пока блокируется и требует отдельной миграции данных — см. ограничения Rename.

Хранение и собственный код

У записи один ID. Общие поля остаются в основной таблице, переводы — в соседней таблице <table>_translations, например products_translations. Значения основного языка также сохраняются в исходных колонках основной таблицы. Уникальность переводимого поля проверяется отдельно в каждом языке.

Отсутствующий перевод в API может быть null, даже если поле обязательно на основном языке. В Go переводимое поле имеет тип *string: custom-коду нужно учитывать nil. Генератор не переписывает ваши custom-файлы. Для собственного контрола формы доступны текущая locale и inputName — имя ввода для конкретного перевода; обычное имя поля остаётся прежним. Подробнее — расширения приложения.

Дополнительно: манифест и CLI

Настройки сохраняются в .admingen/project.yaml: у сущности — localization, у выбранных полей — localized: true. Обычно удобнее менять их через Languages. Отдельных CLI-флагов для настройки языков сейчас нет; после сохранения модели через UI можно использовать обычные команды генерации.