Переведенные поля больше не используют модель `ir.translation`. Теперь они хранят все свои значения как `JSON` и сохраняют их в столбцах `JSONB` в
таблице соответствующей модели. Значение столбца поля либо `NULL`, либо `JSON dict`, где ключом является код языка, а его значение и есть термин. Ключ
`en_US` всегда ставится по умолчанию, в тех случаях когда нет других ключей Пустой текст допускается в значениях перевода, но не `NULL`.

Вот пример поля с параметром `translate=True`:

```json
    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`:

```json
    NULL
    {"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}
```

Изменение для полей `callable(translate)`: теперь в таком поле можно записать любое значение на любом языке. Новое значение будет адаптировано для
всех языков на основе сопоставления терминов между языками в старых значениях. В основном структура значения должна оставаться одинаковой для всех
языков, как и раньше.

Чтение переведенного поля теперь проще и быстрее, чем в предыдущей реализации. Мы извлекаем значение поля на текущем языке, объединяя его значение со
значением поля `en_US`:

```sql
    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

Резюме по исследованию формирования переводов для представлений: Переводы для имен полей формируются следующим образом:

1. Необходимо иметь перевод в PO файле, тогда при обновлении перевода как такового, применится новый перевод
2. Для перевода имени поля создается в модели `ir.model.fields` создано поле `field_description` которое и хранит его перевод
3. Тем не менее данный перевод будет применен только после перезагрузке системы
4. Это связано с тем, что при обновлении страницы вызывается метод `get_views` из модели `ir.ui.view` в ответе которого есть ключ `models`, и в нем
   содержатся переводы для имен полей. Но происходит это не через переводы, а через сбор атрибутов поля Есть предположение что для конкретного языка в
   памяти создается единожды класс для каждого поля с переведенными атрибутами и именно по этому помогает только перезагрузка.

Дополнительные сведения полученные экспериментальным путем

1. Если в каталоге i18n есть pot файл, то если в нем не указаны какие либо термины для перевода, то эти термины будут игнорироваться во всех po файлах
   этих переводов. Т.е для того, чтобы переводы из po файла применились нужно указать термины в pot файле, либо удалить pot файл из каталог
2. Часть терминов берется напрямую из po файлов при обновлении страницы и на фронт загружаются все термины, которые помечены комментарием
   `#. odoo-javascript`
3.

В системе есть как минимум 3 больших блока для которых необходимо сформировать инструменты для перевода:

1. Атрибуты полей
2. Термины для перводов во вьюхах в том числе и Search View
3. Термины для переводов в js коде
4. Меню?
