291 lines
16 KiB
ReStructuredText
291 lines
16 KiB
ReStructuredText
=====================
|
||
Помощник по переводам
|
||
=====================
|
||
|
||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||
:target: https://odoo-community.org/page/development-status
|
||
:alt: Beta
|
||
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
|
||
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
|
||
:alt: License: LGPL-3
|
||
|
||
|badge1| |badge2|
|
||
|
||
.. warning::
|
||
|
||
Модуль находится на стадии бета-тестирования. Использование в промышленной
|
||
эксплуатации требует осторожности.
|
||
|
||
Модуль для Odoo 19 Community Edition. Помогает переводчику работать прямо в
|
||
интерфейсе Odoo: переводить поля, представления и меню «на лету», накапливать
|
||
переводы в локальных PO-файлах и переносить переводы между базами данных.
|
||
|
||
**Содержание**
|
||
|
||
.. contents::
|
||
:local:
|
||
|
||
Назначение
|
||
==========
|
||
|
||
Модуль решает две задачи:
|
||
|
||
#. **Ручной перевод** полей, представлений и меню прямо из интерфейса Odoo —
|
||
без ручного редактирования PO-файлов и без перезапуска сервера для
|
||
большинства случаев.
|
||
#. **Перенос переводов** из внешних источников: из Weblate (старая интеграция)
|
||
и — что нового — напрямую с удалённой базы Odoo по XML-RPC.
|
||
|
||
Ключевая архитектурная предпосылка: в Odoo 16+/19 модели ``ir.translation``
|
||
больше нет. Переводы хранятся в JSONB-колонках самих моделей. Поэтому перенос
|
||
переводов между базами выполняется только через штатный PO-pipeline
|
||
(export → PO → import), а не через чтение/запись ``ir.translation``. Подробности —
|
||
в разделе «Техническая архитектура».
|
||
|
||
Возможности
|
||
===========
|
||
|
||
* Ручной перевод полей через контекстное меню в UI («Режим переводчика»).
|
||
* Перевод нескольких полей одновременно.
|
||
* Поддержка переводимых полей типа ``char``, ``text`` и ``html``.
|
||
* Перевод меню и элементов представлений (метки полей, подсказки,
|
||
текст-заполнитель, метки кнопок, заголовки групп).
|
||
* Сохранение переводов в локальные PO-файлы модулей
|
||
(``translations/<lang>/<module>.po``).
|
||
* Локальные PO-оверрайды: модуль подменяет штатные PO-файлы Odoo своими файлами
|
||
из каталога ``translations/`` через монкипатчи ``odoo.tools.translate``.
|
||
* Интеграция с Weblate (старая интеграция; на момент ревью известно нерабочая,
|
||
см. соответствующий раздел).
|
||
* **Новое:** «Загрузка перевода из удалённой базы» — тянет переводы выбранных
|
||
модулей с удалённого Odoo-сервера по XML-RPC и применяет их локально.
|
||
|
||
Активация и ручной перевод из UI
|
||
=================================
|
||
|
||
#. Установите модуль.
|
||
#. Перейдите в настройки и активируйте **«Режим переводчика»** — он работает
|
||
аналогично режиму разработчика.
|
||
#. В правом верхнем углу появится дополнительная иконка. Нажмите на неё, чтобы
|
||
открыть меню доступных действий перевода.
|
||
#. У каждого пункта меню появится иконка перевода. При изменении перевода он
|
||
применяется, и страница автоматически перезагружается.
|
||
#. У каждого поля появится кнопка перевода. Можно перевести:
|
||
|
||
* название поля;
|
||
* подсказку (tooltip), которая показывается при наведении на знак вопроса.
|
||
|
||
Перевод применяется немедленно.
|
||
#. Все переводы сохраняются:
|
||
|
||
* в базу данных (в JSONB-колонки моделей);
|
||
* в ``.po``-файлы выбранного языка, с именем модуля, в котором объявлен
|
||
термин.
|
||
|
||
Например, перевод термина из модуля ``crm`` попадёт в файл::
|
||
|
||
translation_helper/translations/<код_языка>/crm.po
|
||
|
||
Локальные PO-оверрайды
|
||
======================
|
||
|
||
Модуль переопределяет внутренние точки ``odoo.tools.translate`` в ``__init__.py``
|
||
(монкипатчи ``get_po_paths`` и ``TranslationReader._push_translation``), а также
|
||
``_load_module_terms`` в ``ir.module.module``. Благодаря этому при загрузке
|
||
переводов Odoo обращается не к штатному файлу модуля, а к локальному оверрайду
|
||
модуля ``translation_helper``.
|
||
|
||
Например, при выборе русского языка система «на лету» подменяет обращение к файлу
|
||
``odoo/addons/crm/i18n/ru.po`` на ваш собственный файл
|
||
``translation_helper/translations/ru/crm.po``.
|
||
|
||
Это позволяет накапливать собственные переводы, независимые от апстрима, и
|
||
переносить их между инстансами простым копированием модуля.
|
||
|
||
.. important::
|
||
|
||
**Хрупкая точка:** монкипатчи повторяют приватную логику Odoo. При обновлении
|
||
Odoo сигнатуры этих внутренних функций могут измениться, что молча сломает
|
||
подмену переводов. Проверяйте совместимость после обновлений.
|
||
|
||
Интеграция с Weblate
|
||
====================
|
||
|
||
Модуль содержит старую интеграцию с Weblate (``models/translation_service.py``,
|
||
``wizards/translation_helper_wizard.py``, настройки Weblate в
|
||
``res.config.settings``). Она формирует ссылки на проект Weblate для выбранных
|
||
модулей и языка.
|
||
|
||
.. note::
|
||
|
||
**Статус:** на момент ревью Weblate-путь известно нерабочий (вероятные
|
||
причины — ошибка области видимости переменной при сборке ссылки, жёсткая
|
||
привязка к внешнему серверу, пустая запись ``res.lang``). Используйте с
|
||
осторожностью; основные рабочие сценарии — ручной перевод и загрузка из
|
||
удалённой базы.
|
||
|
||
Загрузка перевода из удалённой базы
|
||
===================================
|
||
|
||
Позволяет вытянуть переводы выбранных модулей с удалённого сервера Odoo и
|
||
применить их в текущей базе — без ручного экспорта/импорта PO-файлов.
|
||
|
||
Где находится
|
||
-------------
|
||
|
||
Меню: **Настройки → Переводы → «Загрузка перевода из удаленной базы»**
|
||
(пункт меню доступен только пользователям группы «Администратор настроек»,
|
||
``base.group_system``).
|
||
|
||
Поля визарда
|
||
------------
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 25 75
|
||
|
||
* - Поле
|
||
- Назначение
|
||
* - ``remote_url``
|
||
- URL удалённого сервера Odoo (например, ``http://192.168.1.10:8069``).
|
||
* - ``remote_db``
|
||
- Имя базы данных на удалённом сервере.
|
||
* - ``remote_user``
|
||
- Логин на удалённом сервере (по умолчанию ``admin``).
|
||
* - ``remote_password``
|
||
- Пароль (или API-ключ) удалённого пользователя.
|
||
* - ``modules``
|
||
- Список модулей, переводы которых нужно загрузить (только установленные
|
||
на удалённой стороне).
|
||
* - ``language``
|
||
- Язык (``res.lang``), по умолчанию ``ru_RU``.
|
||
* - ``overwrite``
|
||
- Перезаписывать существующие переводы значениями из удалённой базы.
|
||
* - ``save_credentials``
|
||
- Запомнить URL, базу, логин и пароль для повторного использования.
|
||
|
||
Как пользоваться (по шагам)
|
||
---------------------------
|
||
|
||
#. Откройте **Настройки → Переводы → «Загрузка перевода из удаленной базы»**.
|
||
#. Заполните параметры подключения: ``remote_url``, ``remote_db``,
|
||
``remote_user``, ``remote_password``.
|
||
#. Выберите модули (``modules``) и язык (``language``).
|
||
#. При необходимости включите ``overwrite`` и/или ``save_credentials``.
|
||
#. Нажмите **«Просмотр»** (режим ``preview``). Модуль подключится к удалённому
|
||
серверу, выполнит экспорт PO и покажет сводку: сколько всего записей, сколько
|
||
переведено, и первые строки «оригинал → перевод». Скачанный PO кэшируется в
|
||
визарде.
|
||
#. Нажмите **«Загрузить»** (режим ``sync``). Переводы импортируются в текущую
|
||
базу через штатный ``TranslationImporter``. По завершении визард показывает
|
||
итоговое сообщение (модули, язык, число записей, режим перезаписи).
|
||
|
||
Режимы
|
||
------
|
||
|
||
* **preview** — только читает переводы с удалённой базы и показывает сводку,
|
||
ничего не меняя локально. Скачанный PO кэшируется для последующего применения.
|
||
* **sync** — применяет переводы к текущей базе. Если PO уже скачан на шаге
|
||
preview, используется кэш; иначе экспорт выполняется заново.
|
||
|
||
Что делает ``overwrite``
|
||
------------------------
|
||
|
||
* ``overwrite = True`` (по умолчанию) — существующие локальные переводы
|
||
заменяются значениями из удалённой базы.
|
||
* ``overwrite = False`` — заполняются только отсутствующие переводы, уже
|
||
имеющиеся локальные значения сохраняются.
|
||
|
||
Сохранение учётных данных
|
||
-------------------------
|
||
|
||
При включённом ``save_credentials`` параметры подключения (``remote_url``,
|
||
``remote_db``, ``remote_user``, ``remote_password``) сохраняются в
|
||
``ir.config_parameter`` и подставляются при следующем открытии визарда.
|
||
|
||
.. warning::
|
||
|
||
**Безопасность:** пароль сохраняется в ``ir.config_parameter`` в открытом
|
||
виде — он читается администраторами и попадает в дампы/бэкапы БД.
|
||
Рекомендуется использовать для удалённого доступа отдельный API-ключ (который
|
||
можно отозвать) и отключать ``save_credentials`` на боевых серверах.
|
||
Соединение идёт по указанному URL; для защиты учётных данных используйте
|
||
``https://``.
|
||
|
||
Требования
|
||
==========
|
||
|
||
* Odoo 19 Community Edition.
|
||
* Внешние Python-зависимости: ``siphashc``, ``polib``.
|
||
* Для новой фичи: сетевой доступ к XML-RPC-эндпоинтам удалённого сервера Odoo
|
||
(``/xmlrpc/2/common``, ``/xmlrpc/2/object``) и учётные данные с правами на
|
||
экспорт переводов на удалённой стороне.
|
||
|
||
Техническая архитектура
|
||
========================
|
||
|
||
Хранение переводов в Odoo 19
|
||
----------------------------
|
||
|
||
В Odoo 16+/19 модели ``ir.translation`` **не существует**. Переводы хранятся
|
||
прямо в JSONB-колонках самих моделей: значение колонки — это ``JSON``-словарь
|
||
вида ``{"en_US": "Foo", "ru_RU": "Фу"}``, где ключ — код языка. Ключ ``en_US``
|
||
используется по умолчанию. Поэтому единственный надёжный, кросс-версионный путь
|
||
переноса переводов между базами — штатный PO-pipeline, а не прямое
|
||
чтение/запись ``ir.translation``.
|
||
|
||
Поток новой фичи
|
||
----------------
|
||
|
||
Передача переводов между базами идёт только через PO:
|
||
|
||
#. **Экспорт на удалённой базе** — через штатный визард ``base.language.export``
|
||
(режим ``module``, формат ``po``).
|
||
#. **Передача** PO по XML-RPC в виде base64.
|
||
#. **Локальный импорт** — через ``TranslationImporter``, который пишет значения
|
||
в JSONB-колонки.
|
||
|
||
XML-RPC-поток
|
||
-------------
|
||
|
||
* Аутентификация: ``POST /xmlrpc/2/common`` → ``authenticate(db, user,
|
||
password)`` возвращает ``uid``.
|
||
* Вызовы моделей: ``/xmlrpc/2/object`` → ``execute_kw(db, uid, password, model,
|
||
method, args)``.
|
||
|
||
Последовательность вызовов при экспорте с удалённой стороны:
|
||
|
||
#. ``ir.module.module.search`` — найти установленные модули по именам.
|
||
#. ``base.language.export.create`` — создать визард экспорта (``lang``,
|
||
``format=po``, ``export_type=module``, список модулей).
|
||
#. ``base.language.export.act_getfile`` — сгенерировать PO и записать его в поле
|
||
``data``.
|
||
#. ``base.language.export.read(['data', 'name'])`` — прочитать base64-содержимое
|
||
PO.
|
||
|
||
Полученный PO декодируется из base64 и импортируется локально через
|
||
``TranslationImporter.load()`` + ``save(overwrite=...)`` с последующим
|
||
``cr.precommit.run()``.
|
||
|
||
Разделение по слоям
|
||
-------------------
|
||
|
||
* ``models/remote_translation_service.py`` — ``AbstractModel``
|
||
``translation.remote.service``: XML-RPC-транспорт и PO-pipeline
|
||
(``fetch_po_from_remote``, ``apply_po``, ``preview_po``).
|
||
* ``wizards/remote_translation_sync_wizard.py`` — ``TransientModel``
|
||
``translation.remote.sync.wizard``: форма, предпросмотр, применение,
|
||
сохранение учётных данных.
|
||
* ``views/remote_translation_sync_wizard_views.xml`` — форма визарда (состояния
|
||
``form → preview → done``), action и пункт меню в
|
||
``base.menu_translation_export``.
|
||
* ``security/ir.model.access.csv`` — ACL визарда для ``base.group_system``.
|
||
|
||
Авторы
|
||
======
|
||
|
||
* MK.Lab, RuOdoo
|
||
|
||
.. image:: https://ruodoo.ru/logo.png
|
||
:alt: MK.Lab, RuOdoo
|
||
:target: https://ruodoo.ru
|