Internationalization¶
Giới thiệu chung¶
Odoo hỗ trợ đa ngôn ngữ và cho phép các người dùng khác nhau trên cùng một instance sử dụng các ngôn ngữ khác nhau. Điều này được thực hiện bởi tính năng i18n của Odoo.
Trong bài viết này, chúng ta sẽ tìm hiểu cách kích hoạt đa ngôn ngữ trong Odoo và cách thêm các file dịch cho một module mới.
Cài đặt ngôn ngữ mới và cấu hình ngôn ngữ của người dùng¶
Khi được cài đặt lần đầu, chỉ có một ngôn ngữ tiếng Anh mặc định. Để có các ngôn ngữ các, chúng ta cần cài đặt chúng. Ví dụ dưới đây sẽ cài đặt và chuyển ngôn ngữ của người dùng sang Tiếng Việt.
Đầu tiên, chúng ta đăng nhập với tài khoản admin và kích hoạt chế độ developer mode, Để kích hoạt bạn vào Setting ‣ General Settings ‣ Developer Tools ‣ Activate the developer mode hoặc thêm
?debug=1
vào trên url của trình duyệt như trong hình.Tiếp theo chúng ta cài đặt một ngôn ngữ mới bằng cách vào Setting ‣ General Settings ‣ Translations ‣ Languages. Sau đó tìm một ngôn ngữ (Tiếng Việt) và nhấn Activate/Update ‣ Add để cài đặt.
Note
Bạn có thể cài đặt một ngôn ngữ mới bằng cách thêm
--load-language=<language>
vào cấu hình chạy của odoo. Ví dụ:$ ./odoo-bin -d mydb --load-language=vi_VN
. Nếu checkbox Overwrite Existing Terms không được tích, sẽ chỉ có những thuật ngữ mới sẽ được dịch. Tích vào nó nếu bạn muốn cập nhật lại các thuật ngữ đã được dịch trước đó, việc này cũng có thể làm mất các bản dịch mà bạn đã sửa thủ công trên giao diện.Lúc này bạn có thể chuyển ngôn ngữ của user sang Tiếng Việt luôn bằng cách nhấn Switch to Vietnamese/Tiếng Việt & Close. Để thay đổi lại ngôn ngữ của user, chúng ta click vào Ảnh đại diện của user ‣ Tùy chỉnh cá nhân, chọn một ngôn ngữ khác và bấm Lưu. Các user khác cũng làm tương tự như vậy.
Chỉnh sửa thông tin bản địa của ngôn ngữ¶
Khi chuyển sang một ngôn ngữ mới, các thông tin về định dạng ngày giờ, dấu phân cách thập phân,… cũng thay đổi để phù hợp với ngôn ngữ/quốc gia đó. Nếu bạn thích tiếng Việt nhưng vẫn muốn giữ định dạng ngày giờ của tiếng Anh thì có thể vào ngôn ngữ đó để chỉnh sửa lại.
Thêm bản dịch cho một module mới¶
Khi tạo một module mới, thông thường chúng ta sẽ viết các đoạn code và thông điệp bằng tiếng Anh. Để quốc tế hóa module,
chúng ta cần phải xuất các file dịch từ module cho các ngôn ngữ khác nhau. Ví dụ với module viin_education
:
viin_education
├── i18n
├── models
│ ├── education_student.py
│ └── __init__.py
├── security
└── views
├── __init__.py
├── __manifest__.py
File education_student.py
:
from odoo import models, fields, _
from odoo.exceptions import UserError
class EducationStudent(models.Model):
_name = 'education.student'
_description = 'Education Student'
name = fields.Char(string='Name')
student_code = fields.Char(string='Student Code')
note = fields.Text(string='Note', help="Brief notes about students")
_sql_constraints = [
('student_code_unique',
'UNIQUE(student_code)',
"Student Code must be unique!"),
]
def copy(self, default=None):
self.ensure_one()
raise UserError(_("Student %s cannot be copied, please create it manually.") % self.name)
Để xuất file dịch tiếng Việt cho module, chúng ta làm theo những bước sau:
Warning
Cần bỏ cấu hình --dev xml
, --dev all
khi chạy odoo trong quá trình thêm bản dịch cho module, nó có thể khiến một số chỗ không
dịch được.
- Cài đặt module, Vào Thiết Lập ‣ Dịch thuật ‣ Xuất bản dịch.Phần Phân hệ cần xuất là
name
của module trong file__manifest__.py
. Chúng ta sẽ xuất 2 fileviin_education.pot
vàvi_VN.po
như trong hình: Tải về và copy 2 file đó vào thư mục
i18n
của module, nếu chưa có thư mục bạn cần phải tạo thủ công. Trong đó fileviin_education.pot
cung cấp một mẫu cho tất cả các bản dịch và chứa tất cả các từ ngữ/câu văn có thể dịch được. Còn filevi_VN.po
chứa bản dịch cho tiếng Việt, chúng ta cần dịch những từ ngữ trong file đấy, ví dụ như sau:file
vi_VN.po
# Translation of Odoo Server. # This file contains the translation of the following modules: # * viin_education # msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-01-22 01:17+0000\n" "PO-Revision-Date: 2022-01-22 01:17+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" #. module: viin_education #: model:ir.model.fields,help:viin_education.field_education_student__note msgid "Brief notes about students" msgstr "Ghi chú ngắn gọn về học sinh" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__create_uid msgid "Created by" msgstr "Được tạo bởi" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__create_date msgid "Created on" msgstr "Được tạo vào" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__display_name msgid "Display Name" msgstr "Tên hiển thị" #. module: viin_education #: model:ir.model,name:viin_education.model_education_student msgid "Education Student" msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__id msgid "ID" msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student____last_update msgid "Last Modified on" msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__write_uid msgid "Last Updated by" msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__write_date msgid "Last Updated on" msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__name msgid "Name" msgstr "Tên" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__note msgid "Note" msgstr "Ghi chú" #. module: viin_education #: code:addons/viin_education/models/education_student.py:0 #, python-format msgid "Student %s cannot be copied, please create it manually." msgstr "" #. module: viin_education #: model:ir.model.fields,field_description:viin_education.field_education_student__student_code msgid "Student Code" msgstr "Mã học sinh" #. module: viin_education #: model:ir.model.constraint,message:viin_education.constraint_education_student_student_code_unique msgid "Student Code must be unique!" msgstr "Mã học sinh phải là duy nhất"
Chạy lại odoo, nâng cấp module và chuyển sang ngôn ngữ của user sang tiếng Việt để xem thành quả:
Với những từ ngữ trong file
vi_VN.po
chưa được dịch, chúng sẽ vẫn giữ nguyên như trạng thái ban đầu:
Giải thích¶
Các bản dịch sẽ được lưu trong model ir.translation
và sẽ được cập nhật khi chúng ta cài đặt hoặc nâng cấp module.
Khi xuất file dịch, một số string trong view và model sẽ tự động được trích xuất để dịch. Ví dụ như thuộc tính _description
,
thuộc tính string
, help
của field… Text trong code Python hoặc JavaScript sẽ không tự động được trích xuất để dịch.
Để thêm các thuật ngữ có thể dịch được, chúng ta cần bao bọc chúng trong hàm odoo._(), odoo._lt()
với python và
odoo.web._t(), odoo.web._lt()
với JavaScript.
from odoo import _
_("Hello")
Một số lưu ý¶
Để thêm biến vào đoạn dịch:
Cách làm đúng.
_("Hello %s") % name _("Hello %s", name)
Cách làm sai.
_("Hello %s" % name)
Không chia bản dịch thành nhiều khối hoặc nhiều dòng:
_("Class: ") + student.class_name + _(", Student: ") + student.name _t("Class: ") + student.class_name + _t(", Student: ") + student.name # bad, chia thành nhiều bản dịch nhỏ, lúc xuất file dịch sẽ bị chia thành từng câu đơn lẻ và không thể dịch sát nghĩa _("A student cannot belong to ") + \ _("more than one class.")
Thay vào đó.
# good, câu đầy đủ sẽ dễ hiểu khi dịch _("A student cannot belong to" + \ "more than one class.")
Runtime
Không gọi hàm dịch
_()
lúc khởi chạy server, (lúc này chưa có ngữ cảnh ngôn ngữ người dùng).#bad ERROR_MESSAGE = { 'error_copy': _('Error when copying') } class EducationStudent(models.Model): _name = 'education.student' def copy(self, default=None): self.ensure_one() raise UserError(ERROR_MESSAGE['error_copy'])
Thay vào đó, sử dụng hàm
_lt()
(Lazy Translate).ERROR_MESSAGE = { 'error_copy': _lt('Error when copying'), } class EducationStudent(models.Model): _name = 'education.student' def copy(self, default=None): self.ensure_one() raise UserError(ERROR_MESSAGE['error_copy'])
Hoặc tách thành hàm nhỏ, gọi khi đã có ngữ cảnh ngôn ngữ người dùng.
def _get_error_message(self): return { error_copy: _('Error when copying') }
Với JavaScript cũng tương tự:
# bad, js _t() được gọi quá sớm var core = require('web.core'); var _t = core._t; var error_message = { error_copy: _t('Error when copying') };
Thay vào đó sử dụng hàm _lt().
# good var core = require('web.core'); var _t = core._t; var error_message = { error_copy: _lt('Error when copying') };
Dịch một câu văn dài: xuống dòng khi cần thiết,
msgstr
đủ số dòng nhưmsgid
.#. module: viin_education #: model:ir.model.fields,help:viin_education.field_education_student__phone_sanitized msgid "" "Field used to store sanitized phone number. Helps speeding up searches and " "comparisons." msgstr "" "Trường được sử dụng để lưu trữ số điện thoại đã qua xử lý. Giúp tăng tốc tìm" " kiếm và so sách."