(开发者)为blender插件制作翻译(i18n/international) make translations for blender addon
不直观的教程/文档
https://developer.blender.org/docs/handbook/translating/translator_guide/?utm_source=blender-4.3.2#manage-ui-translations-add-on
https://developer.blender.org/docs/handbook/translating/developer_guide/#python-translation-api
https://docs.blender.org/api/current/bpy.app.translations.html
demo: https://github.com/blender/blender-addons/tree/main/render_copy_settings
BLT/user translate
这些插件使用自己的csv,需要依赖这些插件才能加载翻译。不考虑。
利用官方的可翻译词汇
https://translate.blender.org/search/blender-ui/?offset=&q=关键词&sort_by=num_words
然后开启禅模式即可。
方案1:部分用python自带的gettext
一部分blender translate插件检测不出来的,得手动用gettext
详见:https://github.com/AClon314/mocap_importer_blender/tree/a01887c098ad1308d81aaf5bf5dbaae2b93d5a4a/i18n/zh_HANS/LC_MESSAGES
pot.py,调用xgettext快速创建.pot/.po/.mo
#!/bin/env python
import os
import re
import time
import difflib
import subprocess
from lib import get_toml, ID
LANGS: list[str] = ['zh_HANS']
DIR_LOCALE = 'i18n'
POT = 'msg.pot'
DIR_SELF = os.path.dirname(__file__).removesuffix('.')
METAINFO = {
'Project-Id-Version': get_toml()['version'],
'PO-Revision-Date': time.strftime('%Y-%m-%d %H:%M%z'),
'Last-Translator': 'nolca <nolca@qq.com>',
# 'Language-Team': 'mocap_importer contributors <github.com/aclon314/mocap_importer>',
}
def path_lc(lang: str, suffix='.po') -> str:
folder = os.path.join(DIR_SELF, DIR_LOCALE, lang, 'LC_MESSAGES')
os.makedirs(folder, exist_ok=True)
return os.path.join(folder, ID + suffix)
def merge_diff(old: str, new: str, rule=[r'-msgstr "', r'\+msgstr ""']):
with open(old, 'r') as o, open(new, 'r') as n:
old_lines = o.readlines()
new_lines = n.readlines()
diff = difflib.unified_diff(old_lines, new_lines, fromfile=old, tofile=new)
prev = ''
begin = end = offset = 0
skip = 2
for l in diff:
if skip > 0:
skip -= 1
continue
print(l, end='')
match = re.search(r'@@ -(\d*),(\d*) \+(\d*),(\d*) @@', l)
if match:
skip = 3 # skip no change 3 lines
begin_end = match.groups()
a_begin, a_count, b_begin, b_count = map(int, begin_end)
offset = min(a_begin, b_begin) + 1
if l.startswith(' ') or l.startswith('+'):
offset += 1
if re.search(rule[0], prev) and re.search(rule[1], l):
print(f'\t{new_lines[offset][:-1]} -> {prev[1:]}')
new_lines[offset] = prev[1:]
prev = l
return ''.join(new_lines)
def pot():
pys = [f for f in os.listdir('.') if f.endswith('.py')]
subprocess.run([
'xgettext', '--language=Python', '--keyword=_', f'--output={POT}', *pys
])
def pot_to_po(lang):
PATH_NEW = PATH_OLD = path_lc(lang)
need_diff = False
if os.path.exists(PATH_OLD):
PATH_NEW += '.bak'
subprocess.run([
'msginit', f'--input={POT}', '--no-translator', '--locale', lang, '--output', PATH_NEW
])
subprocess.run([
'msgconv', '--to-code=UTF-8', PATH_NEW, '-o', PATH_NEW
])
text = ''
with open(PATH_NEW, 'r') as f:
text: str = f.read()
with open(PATH_NEW, 'w') as f:
for k, v in METAINFO.items():
text = re.sub(f'"({k}: ).*?"', f'"\\1 {v}"', text)
f.seek(0)
f.write(text)
if PATH_OLD != PATH_NEW:
text = merge_diff(PATH_OLD, PATH_NEW)
with open(PATH_OLD, 'w') as f:
f.write(text)
os.remove(PATH_NEW)
def po_to_mo(lang):
subprocess.run([
'msgfmt', path_lc(lang), '--output-file',
path_lc(lang, '.mo')
])
def main():
pot()
for lang in LANGS:
pot_to_po(lang)
os.remove(POT)
for lang in LANGS:
po_to_mo(lang)
if __name__ == "__main__":
main()
方案2:blender工作流
更新:终于弄懂了,官方文档写的不直白。
git clone
git clone --depth 1 https://github.com/blender/blender
# git clone --depth 1 https://projects.blender.org/blender/blender-ui-translations #如果你要带翻译来编译blender……
为何--depth 1
很有趣,项目源码本身不大,git commit history却很庞大,如translations仓库,8MB,但其git history有1.5GB!这就是年长的开源项目啊!
启用/配置Manage UI translations插件
把blender的git库的地址填到:源文件根目录。这是linux下成功示例(Windows需自行编译fribidi.dll):

注意,不是blender/blender(可执行文件),而是blender文件夹
在渲染选项卡内的面板
In the I18n Update Translation panel (bottom of Render buttons)...
在渲染选项卡(有设置修改器/骨骼/物理约束的侧边栏)里。
这个太坑爹了,到处找都找不到。
- 在列表内选择要翻译的语言(对于插件开发者,只选英文与中文就够。不要强行上机翻,放到开源仓库,让其母语者做pr/issue)
- 然后点击
Refresh i18n data/刷新i18n数据,选择你的插件。 - 再点击
Export PO/导出PO文件,选择要导出的文件夹,如addon/i18n。之后会得到一堆.po文件与一个translate.py


浙公网安备 33010602011771号