9.4 KiB
Переведенные поля больше не используют модель ir.translation. Теперь они хранят все свои значения как JSON и сохраняют их в столбцах JSONB в
таблице соответствующей модели. Значение столбца поля либо NULL, либо JSON dict, где ключом является код языка, а его значение и есть термин. Ключ
en_US всегда ставится по умолчанию, в тех случаях когда нет других ключей Пустой текст допускается в значениях перевода, но не NULL.
Вот пример поля с параметром translate=True:
NULL
{"en_US": "Foo"}
{"en_US": "Foo", "fr_FR": "Bar", "nl_NL": "Baz"}
{"en_US": "Foo", "fr_FR": "", "nl_NL": "Baz"}
Как и ранее, если полю установить значение False , то на уровне БД оно будет NULL, т. е. False для всех языков. Однако если установить значение
"" (пустая строка) система делает его значение пустым на текущем языке, но не отменяет значения на других языках.
Вот пример поля с параметром translate=xml_translate:
NULL
{"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}
Изменение для полей callable(translate): теперь в таком поле можно записать любое значение на любом языке. Новое значение будет адаптировано для
всех языков на основе сопоставления терминов между языками в старых значениях. В основном структура значения должна оставаться одинаковой для всех
языков, как и раньше.
Чтение переведенного поля теперь проще и быстрее, чем в предыдущей реализации. Мы извлекаем значение поля на текущем языке, объединяя его значение со
значением поля en_US:
SELECT id, COALESCE(name->>'fr_FR', name->>'en_US') AS name ...
Необработанный кэш поля содержит в базе данных (за исключением отсутствующих языков) либо None, либо dict, который концептуально является
подмножеством значения JSON . Для простоты большинство операций кэширования работают с dict и возвращают текстовое значение на текущем языке.
Индексы триграмм адаптированы к новой стратегии хранения и должны позволять поиск на любом языке. До этого изменения индексировалось только исходное
значение поля en_US.
Хранимые вычисляемые переведенные поля не поддерживаются фреймворком из-за сложности самого вычисления: поле должно быть вычислено на всех активных языках. Мы решили не предоставлять никаких хуков для вычисления поля на всех языках одновременно, и фреймворк всегда вызывает метод вычисления один раз, чтобы пересчитать его.
Переводы кода больше не хранятся в базе данных. Они становятся статическими и извлекаются из файлов PO по мере необходимости. Worker просто использует
кэш с извлеченными переводами кода для производительности. Это разумно, так как переводы кода fr_FR для всех модулей занимают около 2 МБ памяти, и
кэш может быть общим для всех реестров в Worker. Изменение переводов кода требует обновления соответствующего файла PO и перезагрузки Worker.
Сводка по производительности: (+) чтение переведенных полей model происходит быстрее (+) чтение переведенных полей model_terms происходит намного
быстрее (нет необходимости вводить переводы в исходное значение) (+) поиск переведенных полей с оператором ilike происходит намного быстрее, если
поле индексировано с помощью trigram (+) обновление переведенных полей требует меньше очистки ORM (-) импорт переводов из файлов PO происходит в
2 раза медленнее
Несколько экстра исправлений: сделать поле name модели ir.actions.actions переведенным; из-за наследования PG это необходимо для того, чтобы
сделать определение столбца согласованным во всех моделях, которые наследуются от ir.actions.actions. добавить внутренний API для
веб-клиента/клиента веб-сайта для редактирования переводов переместить методы get_field_string() в модель ir.model.fields переместить
_load_module_terms в модель ir.module.module адаптировать тесты в test_impex, test_new_api поскольку env.lang внедряется в запросы SQL,
его возвращаемое значение теперь гарантированно соответствует допустимому активному языку или None удалить мастер для вставки отсутствующих
переводов (больше не имеет смысла)
task-id: 2081307
Резюме по исследованию формирования переводов для представлений: Переводы для имен полей формируются следующим образом:
- Необходимо иметь перевод в PO файле, тогда при обновлении перевода как такового, применится новый перевод
- Для перевода имени поля создается в модели
ir.model.fieldsсоздано полеfield_descriptionкоторое и хранит его перевод - Тем не менее данный перевод будет применен только после перезагрузке системы
- Это связано с тем, что при обновлении страницы вызывается метод
get_viewsиз моделиir.ui.viewв ответе которого есть ключmodels, и в нем содержатся переводы для имен полей. Но происходит это не через переводы, а через сбор атрибутов поля Есть предположение что для конкретного языка в памяти создается единожды класс для каждого поля с переведенными атрибутами и именно по этому помогает только перезагрузка.
Дополнительные сведения полученные экспериментальным путем
- Если в каталоге i18n есть pot файл, то если в нем не указаны какие либо термины для перевода, то эти термины будут игнорироваться во всех po файлах этих переводов. Т.е для того, чтобы переводы из po файла применились нужно указать термины в pot файле, либо удалить pot файл из каталог
- Часть терминов берется напрямую из po файлов при обновлении страницы и на фронт загружаются все термины, которые помечены комментарием
#. odoo-javascript
В системе есть как минимум 3 больших блока для которых необходимо сформировать инструменты для перевода:
- Атрибуты полей
- Термины для перводов во вьюхах в том числе и Search View
- Термины для переводов в js коде
- Меню?