Dịch module

Phần này giải thích cách cung cấp khả năng dịch cho module của bạn.

Ghi chú

Nếu bạn muốn đóng góp vào việc dịch chính Odoo, vui lòng tham khảo trang Wiki của Odoo.

Xuất thuật ngữ có thể dịch

Một số thuật ngữ trong module của bạn có thể dịch được một cách ngầm định. Do đó, ngay cả khi bạn chưa thực hiện công việc cụ thể nào cho việc dịch, bạn vẫn có thể xuất các thuật ngữ có thể dịch của module và có thể tìm thấy nội dung để làm việc.

Việc xuất bản dịch được thực hiện thông qua giao diện quản trị bằng cách đăng nhập vào giao diện backend và mở Settings ‣ Translations ‣ Import / Export ‣ Export Translations

  • để ngôn ngữ ở giá trị mặc định (ngôn ngữ mới/mẫu trống)

  • chọn định dạng PO File

  • chọn module của bạn

  • nhấp vào Export và tải file xuống

../../_images/po-export.png

Thao tác này cho bạn một file có tên yourmodule.pot, cần được chuyển vào thư mục yourmodule/i18n/. File này là một PO Template, đơn giản chỉ liệt kê các chuỗi có thể dịch, từ đó có thể tạo ra các bản dịch thực tế (file PO). File PO có thể được tạo bằng msginit, bằng một công cụ dịch chuyên dụng như POEdit, hoặc đơn giản bằng cách sao chép template thành một file mới có tên language.po. Các file dịch nên được đặt trong yourmodule/i18n/, cạnh yourmodule.pot, và sẽ được Odoo tự động tải khi ngôn ngữ tương ứng được cài đặt (thông qua Settings ‣ Translations ‣ Languages)

Ghi chú

bản dịch cho tất cả các ngôn ngữ đã tải cũng sẽ được cài đặt hoặc cập nhật khi cài đặt hoặc cập nhật một module

Xuất ngầm định

Odoo tự động xuất các chuỗi có thể dịch từ nội dung kiểu "data":

  • trong các view không phải QWeb, tất cả các text node đều được xuất, cũng như nội dung của các thuộc tính string, help, sum, confirm và placeholder

  • trong các template QWeb (cả phía server và phía client), tất cả các text node đều được xuất, ngoại trừ bên trong các khối t-translation="off"; nội dung của các thuộc tính title, alt, label và placeholder cũng được xuất

  • đối với Field, trừ khi model của nó được đánh dấu với _translate = False:

    • các thuộc tính string và help của chúng được xuất

    • nếu selection tồn tại và là một list (hoặc tuple), nó sẽ được xuất

    • nếu thuộc tính translate của chúng được đặt là True, tất cả các giá trị hiện có của chúng (trên toàn bộ các bản ghi) đều được xuất

  • các thông báo help/error của _constraints và _sql_constraints được xuất

Xuất tường minh

Đối với các trường hợp mang tính "mệnh lệnh" hơn trong code Python hoặc code Javascript, Odoo không thể tự động xuất các thuật ngữ có thể dịch, vì vậy chúng phải được đánh dấu tường minh để xuất. Việc này được thực hiện bằng cách bọc một chuỗi ký tự (literal string) trong một lời gọi hàm.

Trong Python, hàm bọc là odoo._():

title = _("Bank Accounts")

Trong JavaScript, hàm bọc thường là odoo.web._t():

title = _t("Bank Accounts");

Cảnh báo

Chỉ có các chuỗi ký tự (literal string) mới có thể được đánh dấu để xuất, không phải các biểu thức hay biến. Đối với các trường hợp chuỗi được định dạng, điều này có nghĩa là chuỗi định dạng (format string) phải được đánh dấu, chứ không phải chuỗi đã được định dạng

Phiên bản lazy của _ và _t là odoo._lt() trong python và odoo.web._lt() trong javascript. Việc tra cứu bản dịch chỉ được thực hiện tại thời điểm render và có thể được sử dụng để khai báo các thuộc tính có thể dịch trong các phương thức lớp của biến toàn cục.

Ghi chú

Theo mặc định, bản dịch của một module không được đưa ra front end, và do đó không thể truy cập được từ JavaScript. Để đạt được điều đó, tên module phải được thêm tiền tố website (giống như website_sale, website_event, v.v.) hoặc đăng ký tường minh bằng cách triển khai _get_translation_frontend_modules_name() cho model ir.http.

Nó có thể trông như sau:

from odoo import models

class IrHttp(models.AbstractModel):
    _inherit = 'ir.http'

    @classmethod
    def _get_translation_frontend_modules_name(cls):
        modules = super()._get_translation_frontend_modules_name()
        return modules + ['your_module']

Biến

Không nên việc trích xuất có thể hoạt động nhưng sẽ không dịch văn bản đúng cách:

_("Scheduled meeting with %s" % invitee.name)

Nên đặt các biến động làm tham số của việc tra cứu bản dịch (điều này sẽ dùng lại nguồn gốc nếu thiếu placeholder trong bản dịch):

_("Scheduled meeting with %s", invitee.name)

Khối

Không nên tách bản dịch của bạn thành nhiều khối hoặc nhiều dòng:

# bad, trailing spaces, blocks out of context
_("You have ") + len(invoices) + _(" invoices waiting")
_t("You have ") + invoices.length + _t(" invoices waiting");

# bad, multiple small translations
_("Reference of the document that generated ") + \
_("this sales order request.")

Nên giữ trong một khối duy nhất, cung cấp đầy đủ ngữ cảnh cho người dịch:

# good, allow to change position of the number in the translation
_("You have %s invoices waiting") % len(invoices)
_.str.sprintf(_t("You have %s invoices waiting"), invoices.length);

# good, full sentence is understandable
_("Reference of the document that generated " + \
  "this sales order request.")

Số nhiều

Không nên chia số nhiều theo kiểu tiếng Anh:

msg = _("You have %(count)s invoice", count=invoice_count)
if invoice_count > 1:
  msg += _("s")

Nên ghi nhớ rằng mỗi ngôn ngữ có các hình thức số nhiều khác nhau:

if invoice_count > 1:
  msg = _("You have %(count)s invoices", count=invoice_count)
else:
  msg = _("You have one invoice")

Thời điểm đọc so với thời điểm chạy

Không nên gọi tra cứu bản dịch khi server khởi động:

ERROR_MESSAGE = {
  # bad, evaluated at server launch with no user language
  'access_error': _('Access Error'),
  'missing_error': _('Missing Record'),
}

class Record(models.Model):

  def _raise_error(self, code):
    raise UserError(ERROR_MESSAGE[code])

Không nên gọi tra cứu bản dịch khi file javascript được đọc:

# bad, js _t is evaluated too early
var core = require('web.core');
var _t = core._t;
var map_title = {
    access_error: _t('Access Error'),
    missing_error: _t('Missing Record'),
};

Nên sử dụng phương thức tra cứu bản dịch dạng lazy:

ERROR_MESSAGE = {
  'access_error': _lt('Access Error'),
  'missing_error': _lt('Missing Record'),
}

class Record(models.Model):

  def _raise_error(self, code):
    # translation lookup executed at error rendering
    raise UserError(ERROR_MESSAGE[code])

hoặc nên đánh giá nội dung có thể dịch một cách động:

# good, evaluated at run time
def _get_error_message(self):
  return {
    access_error: _('Access Error'),
    missing_error: _('Missing Record'),
  }

Nên trong trường hợp việc tra cứu bản dịch được thực hiện khi file JS được đọc, sử dụng _lt thay vì _t để dịch thuật ngữ khi nó được sử dụng:

# good, js _lt is evaluated lazily
var core = require('web.core');
var _lt = core._lt;
var map_title = {
    access_error: _lt('Access Error'),
    missing_error: _lt('Missing Record'),
};