这个方法我很早就在用了,最近偶然看到 i18n 插件,所以又想了起来。由于 i18n 插件不支持移动端,所以只能迂回使用该方法。同时该方法需要安装 pydroid3 或其它可以执行 python 代码的 app。
i18n 插件
该方法会使用到 i18n 插件的部分文件。桌面端可直接使用该插件,有关 i18n 插件的内容详见站内介绍:
Obsidian插件翻译工具i18n:汉化插件、翻译词典编辑器、云端共享词典、内置沉浸式翻译
方法来源
该方法来源于站内:
经过改良,适配移动端与 i18n 插件文件。
使用步骤
- 下载 i18n 插件,该插件中 zh-cn 文件夹中有一个 plugins 文件夹。复制该文件夹路径,替换代码中 i18n_dir 单引号中的内容。
- 复制自己的 obsidian 的插件路径,替换代码中 plugins_dir 单引号中的内容。
- 执行代码。
- 插件更新后汉化会失效,需要重新执行一次代码。
已实现
- 翻译所有插件 main.js (若有翻译文件)
- 翻译所有插件 manifest.json (仅 description)(若有翻译文件)
- 多个翻译版本中选择最新版本进行翻译
- 自动备份一次原 main.js 和 原 manifest.json
总结
只能勉强用用,大家还是期待 i18n 插件支持移动端吧。
代码如下
import os
import json
class I18n:
plugins_dir = r'/storage/emulated/0/notes/.obsidian/plugins/'
i18n_dir = r'/storage/emulated/0/notes/.obsidian/zh-cn/plugins'
def translate_plugins(self):
"""翻译所有插件"""
plugins_names = os.listdir(f'{self.plugins_dir}')
for plugin_name in plugins_names:
self._translate_plugin(plugin_name)
def _translate_plugin(self, plugin_name:str):
"""翻译指定插件
:plugin_name: 插件名称
"""
i18n_plugin_dir = f'{self.i18n_dir}{plugin_name}/'
if not os.path.exists(i18n_plugin_dir):
print(f'{plugin_name} 的翻译目录不存在')
return
i18n_name = self._get_latest_file(i18n_plugin_dir)
i18n_path = f'{i18n_plugin_dir}{i18n_name}'
if not os.path.exists(i18n_path):
print(f'{plugin_name} 的翻译文件不存在')
return
with open(i18n_path,'r',encoding='utf-8') as i18n_file:
i18n:dict = json.load(i18n_file)
self._translate_main(plugin_name, i18n)
self._translate_manifest(plugin_name, i18n)
print(f'已翻译 {plugin_name}')
def _translate_main(self, plugin_name:str, i18n:dict):
"""翻译插件 main 文件
:plugin_name: 插件名称
:i18n: 翻译字典
"""
main_path = f'{self.plugins_dir}{plugin_name}/main.js'
with open(main_path,'r',encoding='utf-8') as plugin_file:
main:str = plugin_file.read()
if not os.path.exists(f'{main_path}.bak'):
os.rename(main_path,f'{main_path}.bak')
for line in i18n["dict"].items():
main = main.replace(*line)
with open(main_path,'w',encoding='utf-8') as plugin_file:
plugin_file.write(main)
def _translate_manifest(self, plugin_name:str, i18n:dict):
"""翻译插件 manifest 文件
:plugin_name: 插件名称
:i18n: 翻译字典
"""
manifest_path = f'{self.plugins_dir}{plugin_name}/manifest.json'
with open(manifest_path,'r',encoding='utf-8') as manifest_file:
manifest:dict = json.load(manifest_file)
if not os.path.exists(f'{manifest_path}.bak'):
os.rename(manifest_path,f'{manifest_path}.bak')
manifest["description"] = i18n["description"]["translation"]
with open(manifest_path,'w',encoding='utf-8') as manifest_file:
json.dump(manifest, manifest_file, indent=4, ensure_ascii=False)
def _get_latest_file(self, dir_:str)->str:
"""获取指定目录下版本最新文件名
:dir_: 目录路径
:return: 版本最新文件名
"""
# 获取目录下所有.json文件
files = [f for f in os.listdir(dir_) if f.endswith('.json')]
if len(files) == 1: return files[0]
version_files = []
for file in files:
# 去除.json后缀并分割版本号
version_str = file.rsplit('.', 1)[0]
parts = version_str.split('.')
# 验证是否为三段式版本号
if len(parts) != 3: continue
try:
# 将版本号转换为整数元组
version_tuple = tuple(map(int, parts))
version_files.append((version_tuple, file))
except ValueError: continue
# 如果没有有效文件返回None
if not version_files: return None
# 按版本号降序排序并返回最新文件名
version_files.sort(reverse=True)
return version_files[0][1]
if __name__=='__main__':
I18n().translate_plugins()