mcpField
O
odoo-i18n

odoo-i18n

github.com/ahmed-lakosha开发76111 次安装31 周前更新
代码仓库

关于 odoo-i18n

odoo-i18n 是面向开发者的技能,用于管理 Odoo 14–19 的翻译与本地化。它提供提取字符串、校验和报告 .po 文件,以及通过 Odoo CLI 导入或导出翻译的工作流。

主要功能

  1. 01提取可翻译字符串
  2. 02校验 .po 语法与内容
  3. 03报告翻译缺漏
  4. 04合并和转换 .po 文件
  5. 05通过 Odoo CLI 导入导出
  6. 06检查语言特定规则

适用场景

  1. 01为 Odoo 模块生成翻译文件
  2. 02发布前校验 .po 文件
  3. 03跟踪翻译覆盖缺口
  4. 04将翻译载入 Odoo 数据库

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ahmed-lakosha/odoo-plugins --skill odoo-i18n

安装后在 Claude Code 中输入/odoo-i18n确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

scripts/
__init__.py
_common.py
i18n_converter.py
i18n_extractor.py
i18n_reporter.py
i18n_validator.py

详细介绍

Odoo i18n 技能

全面掌握 Odoo 14-19 的国际化(i18n)和本地化(l10n)。

关键翻译规则

  1. 绝对不要在 _() 中使用 f-string——请使用 % 格式化:_('Record %s') % name
  2. 绝对不要在 _() 中拼接字符串——请将完整句子交给译者
  3. 类级别的字符串(selection 值、类属性)请使用 _lt()
  4. 绝对不要将字段属性中的 string= 包装在 _() 中——Odoo 会自动翻译
  5. 将 .po 文件保存为 UTF-8 编码,不带 BOM
  6. 阿拉伯语 .po 文件的 Plural-Forms 标头中必须包含 nplurals=6
  7. 编辑 .po 文件后务必更新模块:-u module --stop-after-init

工作流 1:提取可翻译字符串

扫描 Odoo 模块中的所有可翻译字符串,并生成 .pot(模板)和 .po(语言)文件。

用法
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_extractor.py --module <path> --lang <code> [--output <dir>] [--no-pot] [--verbose]
参数必填说明
--module是Odoo 模块目录的路径
--lang是目标语言代码(例如,ar、fr、tr)
--output否自定义输出目录(默认:module/i18n/)
--no-pot否跳过生成 .pot 模板
--verbose否显示所有提取的字符串
提取内容

Python (*.py) -- _('...') 和 _lt('...'):

# Extracted:
raise UserError(_('Record %s not found') % name)
state = fields.Selection([('draft', _lt('Draft'))])
# NOT extracted: _(variable), _(f'Hello {name}')

XML (*.xml) -- string=、help=、placeholder= 属性;菜单/操作中的 name=;HTML 文本:

<field name="state" string="Status"/>      
<h1>Welcome to our website</h1>            
<record id="view_my_form" model="ir.ui.view">  

JavaScript (*.js) -- _t('...') 和 _lt('...'):

const msg = _t("Save Changes");   // extracted
const msg = _t(someVariable);     // NOT extracted
生成的文件结构
# Translation template for my_module
msgid ""
msgstr ""
"Project-Id-Version: Odoo Module my_module\n"
"Content-Type: text/plain; charset=UTF-8\n"

#: models/my_model.py:45
#, python-format
msgid "Record %s not found"
msgstr ""
替代方案:Odoo 内置提取器
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-export --modules=my_module --language=ar \
    --output=my_module/i18n/ar.po --stop-after-init

Odoo CLI 提取器包含数据库字符串(模型名称、操作名称),而插件提取器不会提取这些内容。对于生产环境,内置提取器更为完整。

提取后
  1. 在翻译编辑器(Poedit、Virtaal 或文本编辑器)中打开 .po 文件
  2. 填写所有 msgstr 条目
  3. 验证:运行 i18n_validator.py --po-file path/to/ar.po
  4. 检查覆盖率:运行 i18n_reporter.py --module path/ --lang ar
  5. 加载到 Odoo 中:更新模块或使用导出/导入工作流

工作流 2:验证 .po 文件

验证 .po 文件中是否存在语法错误、编码问题、空翻译、模糊条目、格式说明符不匹配,以及阿拉伯语/RTL 特定问题。

用法
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_validator.py --po-file <path> [--lang <code>] [--strict] [--output <file>]
参数必填说明
--po-file是要验证的 .po 文件路径
--lang否用于语言特定检查的语言代码(从文件名自动检测)
--strict否将未翻译字符串视为错误,而非警告
--output否将报告写入文件,而非标准输出
验证内容

语法: UTF-8 编码(无 BOM/Latin-1)、包含 Content-Type/charset/Language/MIME-Version 的标头、字符串引号格式正确、无解析错误。

翻译: 空 msgstr(未翻译)、需要审核的 fuzzy 标记、重复的 msgid、过时的(#~)条目。

格式说明符: %s/%d/%f 的数量必须匹配;必须包含所有 %(name)s 命名说明符:

# WRONG - missing second %s:
msgid "Invoice %s due on %s"
msgstr "fatura %s"
# CORRECT:
msgid "Invoice %s due on %s"
msgstr "fatura %s vadesi %s"

阿拉伯语特定检查(--lang ar): 是否包含阿拉伯字符、是否存在 Latin-1 导致的编码异常、方向控制字符、是否要求 nplurals=6、标记 BIDI 覆盖字符。

常见错误及修复方法

“Charset must be UTF-8”:

python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py --action convert --po ar.po --output ar_fixed.po

“Fuzzy translation (needs review)” -- 确认后移除 fuzzy 标记:

# Before:                          # After:
#, fuzzy, python-format            #, python-format
msgid "Record %s not found"        msgid "Record %s not found"
msgstr "record not found"          msgstr "record not found"

“Arabic should have nplurals=6”:

"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
CI/CD 集成
- name: Validate Arabic translations
  run: python odoo-i18n/scripts/i18n_validator.py --po-file my_module/i18n/ar.po --lang ar --strict

退出代码 0 = 通过(可能有警告),1 = 失败(发现错误)。


工作流 3:查找缺失的翻译

将模块源文件中的可翻译字符串与现有 .po 文件进行比较,并报告缺失或不完整的内容。

用法
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_reporter.py --module <path> --lang <code> [--format text|json|csv] [--output <file>] [--min-pct <N>]
参数必需描述
--module是Odoo 模块目录的路径
--lang是要检查的语言代码(例如:ar、fr)
--format否输出格式:text(默认)、json、csv
--output否将报告写入文件,而不是写入标准输出
--min-pct否如果完成率低于阈值,则退出代码为 1
了解报告
  • 缺失:源代码中有此字符串,但 .po 中没有条目
  • .po 中为空:条目存在,但 msgstr 为 ""(尚未翻译)
  • 模糊:自动匹配,需要人工审核;不会向用户显示(Odoo 会回退到源文本)
  • 完成率 % = 已翻译 / 活跃字符串总数 * 100(非空、非模糊、非过期)
工作流:修复缺失的翻译
  1. 运行 i18n_reporter.py,找出缺漏
  2. 使用 Poedit、Virtaal 或文本编辑器打开 .po
  3. 填写缺失的 msgstr 条目
  4. 如果字符串在 .po 中完全不存在,先运行 i18n_extractor.py
  5. 使用 i18n_validator.py 验证
  6. 重新运行 i18n_reporter.py,确认覆盖情况
源代码变更后更新 .po
# 1. Re-extract new strings
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_extractor.py --module /path/ --lang ar --no-pot
# 2. Merge (preserves existing translations)
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py \
    --action merge --base /path/i18n/ar.po --new /path/i18n/ar.po --output /path/i18n/ar_merged.po
# 3. Check remaining gaps
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_reporter.py --module /path/ --lang ar

工作流 4:通过 Odoo CLI 导出/导入

需要 PostgreSQL 和有效的数据库。

导出翻译
# Single module
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-export --modules=my_module --language=ar \
    --output=my_module/i18n/ar.po --stop-after-init

# Export .pot template (no --language = empty msgstr)
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-export --modules=my_module \
    --output=my_module/i18n/my_module.pot --stop-after-init

# Multiple modules / all installed
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-export --modules=mod1,mod2 --language=ar --output=combined_ar.po --stop-after-init
导入翻译
# Import .po
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-import=my_module/i18n/ar.po --language=ar --modules=my_module --stop-after-init

# Import and overwrite existing
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-import=my_module/i18n/ar.po --language=ar \
    --modules=my_module --i18n-overwrite --stop-after-init

# Multiple languages
for lang in ar fr tr; do
    python odoo-bin -c conf/myproject.conf -d mydb \
        --i18n-import=my_module/i18n/${lang}.po --language=${lang} \
        --modules=my_module --stop-after-init
done
加载语言
python odoo-bin -c conf/myproject.conf -d mydb --load-language=ar --stop-after-init
python odoo-bin -c conf/myproject.conf -d mydb --load-language=ar,fr,tr --stop-after-init

通过 shell 检查/激活:

# python odoo-bin shell -d mydb
langs = self.env['res.lang'].with_context(active_test=False).search([])
for lang in langs:
    print(f"[{'ACTIVE' if lang.active else 'inactive'}] {lang.code}: {lang.name}")

# Activate
lang = self.env['res.lang'].with_context(active_test=False).search([('code', '=', 'ar')])
lang.active = True
self.env.cr.commit()
更新模块(最简单的重新加载方式)
python -m odoo -c conf/myproject.conf -d mydb -u my_module --stop-after-init
Odoo 17+ 特有事项

翻译在内部以 JSON 术语形式存储;导出格式仍为 .po。清除缓存:

# python odoo-bin shell -d mydb
self.env['ir.translation'].clear_caches()
self.env.cr.commit()
网站翻译
python odoo-bin -c conf/myproject.conf -d mydb \
    --i18n-export --modules=website,my_theme_module --language=ar \
    --output=website_ar.po --stop-after-init
翻译文件位置
module/i18n/
  module.pot    <- Template (not loaded by Odoo)
  ar.po         <- Arabic
  ar_SA.po      <- Saudi variant (overrides ar.po entries)
  fr.po         <- French
  tr.po         <- Turkish

工具:合并和清理 .po 文件

python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py --action merge --base ar.po --new ar_new.po --output ar_merged.po
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py --action clean --po ar.po
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py --action stats --po ar.po
python ${CLAUDE_PLUGIN_ROOT}/odoo-i18n/scripts/i18n_converter.py --action convert --po ar.po --output ar_fixed.po

支持的语言速查表

代码语言是否为 RTL?复数形式
ar / ar_SA / ar_AE阿拉伯语(变体)是6
en / en_US英语否2
fr / fr_FR法语否2
tr土耳其语否2
de德语否2
es西班牙语否2

Odoo 版本差异

功能Odoo 14-15Odoo 16-17Odoo 18-19
JS 翻译导入import { _t } from "web.core"import { _t } from "@web/core/l10n/translation"与 16 相同
Bootstrap 版本4.x5.1.3(内置 RTL)5.1.3+
翻译存储ir.translation 表JSON 术语(内部)JSON 术语
列表视图类型<tree><tree><list>(仅限 19)
控制器类型type='json'type='json'type='jsonrpc'(仅限 19)
可见性属性attrs={'invisible': ...}attrs={'invisible': ...}内联 invisible="expr"(仅限 19)

常见问题

翻译未显示:使用 -u module --stop-after-init 更新模块,然后清除浏览器缓存。

阿拉伯语文本乱码(mojibake):文件以 Latin-1 格式保存。运行 i18n_converter.py --action convert 修复编码。

格式说明符错误:确保 msgid 和 msgstr 中的 %s/%d/%(name)s 数量一致。

阿拉伯语用户在网站上看到英语:检查 (1) 是否已安装阿拉伯语,(2) 是否已设置用户语言,(3) 添加翻译后是否已更新模块。

模糊条目:打开 .po,核对翻译,并从已批准的条目中移除 #, fuzzy 标记。


可配置的品牌信息

生成的 .pot/.po 文件使用可配置的作者/邮箱。设置环境变量:

export ODOO_I18N_COPYRIGHT="Your Company"
export ODOO_I18N_BUGS_EMAIL="[email protected]"

详细参考(记忆文件)

如需了解本技能摘要之外的完整模式,插件还包含以下记忆文件:

  • memories/translation_patterns.md —— Python _() / _lt() 模式、XML 属性翻译、JS _t() 模式、.po 文件结构、电子邮件模板翻译
  • memories/rtl_patterns.md —— RTL 激活、Bootstrap RTL、CSS 逻辑属性、SCSS 覆盖、RTL 中的 Flexbox、JS RTL 检测、QWeb 报告 RTL、常见 RTL 修复
  • memories/language_codes.md —— 语言代码、日期/时间格式、数字格式、货币显示、伊斯兰历说明、时区参考

评论

支持 Markdown