本篇教程由作者设定使用 CC BY-NC-SA 协议。

动态翻译教程-第1张图片

 

 

在进行mod国际化 的时候,有时会遇到部分文本的硬编码无法简单国际化的问题,导致国际化工作比较困难,通常需要进行对源文件的注入进行修改,一方面对源文件造成了破坏性的改动,而且进行更新后又需要重复工作。

 

这个mod的对象是mod汉化人员,和对应的使用玩家,主要针对部分国际化不完善的mod,同时如果你觉得有用并且有精力去配置我不觉得有什么用可以配置聊天栏的文本翻译。

 

同时在一些娱乐向方面,我们需要替换游戏内文本来达到一些特殊效果,这时候也需要对游戏内文本进行修改。

 


DynTranslation替换的时间节点


DynTranslation通过映射表文件进行运行时文本替换来达到以上效果。

 

通过介绍时间节点来避免不必要的问题产生,动态翻译在进行替换时,需要在Forge完成初始化时才能锁定配置文件位置,所以在初始化完成前无法加载配置文件,同时这样做也是减少CPU空转时间,因为在加载时间点会产生大量动态数字,造成翻译队列阻塞,过高的消耗CPU资源。


所以在初始化完成前,动态翻译本身不能替换加载界面的文本。

 

替换方法

通过简单的文本替换,这里采用了json文件作为载体,对映射文件进行读取;

 

关于映射文件命名如下:

父文件夹:位于mod的config文件夹下,并且会创建子文件夹名为dyntranslation

子文件命名:所有子文件,必须以形如 dyntranslation_{name}.json 的规范命名,其中{name}为所有系统文件可用字符。

动态翻译教程-第2张图片 

 

替换内容:替换内容以 json 的标准格式为准的Map嵌套形式。

{
    //容器(GUI)包名,“*”表示没有在任何容器(GUI)中,大部分在Tooltip中
  "*": { 
    "§f腐肉§r": "§d腐肉§r",
    "  盔甲": "",
    "§7穿在腿上时:": "§8穿在腿上时"
  },
    //这里表示字符显示在GuiEnchantment中
  "net.minecraft.client.gui.GuiEnchantment": {
    "附魔": "附魔"
  }
}

 

性能影响


由于是每帧替换,所以其性能影响和帧数也是成正比的,最后的影响结果是线性的。其中的IO操作和分词耗时操作放在其他线程中,最终的性能影响来自于:

map的存取性能

map的大小

线程的创建销毁时间

新词汇的产生速度过快导致的队列阻塞

后两者无法通过人工进行控制, 在实测中新增加的内容打开分词后的平均影响如下图:动态翻译教程-第3张图片

平均值为3099.375,量纲为纳秒,小于毫秒的数量级,可以认为在稀疏操作下的影响可以忽略不记。

 

gui(mc1.15.2)

动态翻译教程-第4张图片GUI设置

顾名思义~

控制中可以自己修改键位默认打开设置Z, 开始和停止记录屏幕字符V,

开启和关闭聊天栏翻译Y。


命令(mc1.12.2)


/translation loadMap 重新载入文件;
/translation startRecord 开始捕捉字符,这个命令会在你指令被接受后再游戏中记录所有出现的字符,并存入缓存,上限为1000;
/translation endRecord <-n> 停止记录并保存,这个命令会停止捕捉并存入之前提过的config文件的dyntranslation中,文件名形如record_{mill_time}.json。<可选项-n>用来进行简化输出,删除格式化字符。
/translation enable 启用动态翻译
/translation disable 关闭动态翻译
/translation spilt 启用分词
/translation notSpilt 关闭分词


其中record产生的输出文件如下所示:

{
  "*": {
    "§f腐肉§r": "§f§r",
    "  盔甲": "",
    "§7穿在腿上时:": "§7",
    "穿在腿上时": ""
  },
  "net.minecraft.client.gui.GuiEnchantment": {
    "附魔": "",
    "物品栏": ""
  }
}

其中§{char}为格式字符,默认情况下生成两行(如果不产生冲突),上一行为包含格式字符的记录对,下方为清除格式字符的记录对。

因为在minecraft中的Tooltip中会包含格式字符而当其在Highlight显示在游戏界面下方时是不包含格式字符的,同样的在F3+H开启高级调试时会在其后方添加#{id}这里不再记录。对于这些情况都已经做过部分处理可以自动替换,如果你想修改原来的格式显示也可以在此处修改来达到不同的展示效果。

 

分词


我自己不是做自然语言处理的,这里针对English和中文进行了分词处理,分词和语言检测来自于com.github.houbb:segment和com.optimaize.languagedetector,分词的平均速度采用了最快(准确率最低)的贪心算法,语言检测使用了3种语言的检测:中文,英文和日文,但是对于日文迫于字典太大(其实不加也很大了),就没有添加。

 

分词主要用于拓展映射表节省搜索耗时,例如:

{
  "*" : {
          "金矿石" : "金闪闪",
          "草" : "艹",
          "Grass": "艹"
        },
    
  ... ...
    
}

对草进行了翻译替换,这样也会默认对所有含“草”的词组以及句子进行替换(前提是通过一般匹配)。

举个栗子:

如果在你的映射表中没有对“草方块”单独做映射,那么,你的“草方块”文本将会被替换为“艹方块”,如下图所示


动态翻译教程-第5张图片 

 

动态翻译教程-第6张图片 

 

如何避免这种情况?

你可以在你的映射文件中添加全匹配标记符@

... ...

{
"Iron Ore" : "铁矿",
"@草" : "cao",
"@@草" : "@cao"
},

... ...

如果你需要@这个字符可以通过@再进行转义,如上图所示。

 

或者你也可以关闭分词功能,详见章节命令

 

渲染位置微调


有时候面临的Gui中出现的居中字符,我们经过翻译/替换后的文本长度和原来的文本长度不同,导致原来mod中的居中计算会造成错位。如下图:

动态翻译教程-第7张图片 

 

动态翻译教程-第8张图片 

 

图中的tile在英文表示中较短,而中文表示可能会比较长,导致mod本身计算时讲起始点保持在了英文起始点导致居中失效。

为了解决这个问题,在每个配对右侧翻译部分增加了控制字段来微调渲染位置[x(整数),y(整数),scale(小数)]:

{
  "*":{
    "金矿石" : "金闪闪"
  },

  "net.minecraft.client.gui.GuiEnchantment": {
    "附魔": "{x=1,y=2,scale=auto}附魔测试"//现在共有3个可用属性,x,y,scale;
  }
}

这里对附魔进行了位置微调,首先进行一次自动的缩放,这次缩放会按照替换文本“附魔测试”和被替换文本“附魔”的文本长度进行缩放比例调整,这里我们很清楚的可以计算,被替换后长度变成了原来的2倍,所以会对替换文本进行x,y方向位移后的位置进行0.5倍的缩放来保持和原来文本的对齐:

动态翻译教程-第9张图片 

 

同样的控制字符中的x,y除了可以填写相对位置的具体值外,也可以使用值“auto”进行自动位置调整:

• 对于x,自动调整会将替换后文本和替换前文本进行居中对齐,即两份文本的中线对齐。

• 对于y,因为字体高度不变,仅仅通过缩放比来做到竖直方向上的垂直居中,同上。

当你不填写控制字段(一个或多个)的时候x的默认值位0,y的默认值为0,scale的默认值为1;

当你的文本中本身就以"{","}"开头和闭合时,如

“公式“ : “{[(1-x) * y]} * z”

你可以在右边的开头插入空的控制字段来防止渲染出错:

“公式“ : “{}{[(1-x) * y]} * z”

当然,所有的控制字段必须在替换文本的开头,并以规范形式结束,否则可能会造成不可预料的后果。

对于控制字段,仅仅对非,并且不会作为子单词嵌套。


数字内容匹配替换


这个是游戏F3按下时右上角的内存提示的记录文件,使用record捕获:

"Mem:  8% 319/3605MB": ""

现在要将其替换成中文:

"Mem:  {0}% {1}/{2}MB": "内存:  占用百分之{0} {1}/{2}兆字节"

游戏中由于每帧都在搜索替换,为了减小开销,防止游戏性能受到影响,没有使用基于自动机的匹配算法,因为当你有很多通配符时会带来很大的性能压力,退而求其次,我们以线性复杂度拆分检查的字符对于上述例子,我们将原文使用数字和小数点符号(0-9,.)拆分字符串为:{"Mem: ","8","%"," ","319","/","3605","MB"},记录所有可能的数字(这里会合并所有数字和英文半角句号——".",也就是说即使是形如"0.1.1.3"或"."或"..."也会被当成一个数字来对待):{0:"8", 1:"319",2:"3605"},重新在运行时格式化你的翻译,在{0},{1},{2},按照捕获顺序进行填充,注意前文中的必须按照从左到右的顺序从0开始记录字符串:

"Mem:  {1}% {0}/{2}MB": "内存:  占用百分之{0} {1}/{2}兆字节"

如上记录的key值不按顺序,这样是不行的!


联网物品翻译 (vmc1.16.x-1.3.5-beta以及之后的版本)

使用领域数据训练的神经网络提供在线翻译服务,悬浮指针在背包或工具栏的物品上,默认按住Alt获得翻译结果,仅翻译物品名,暂时有次数限制。


联网翻译聊天栏 (v1.3添加)

没什么好说的,默认键位Home键,可以在控制选项里调整,切换是否对聊天栏进行联网翻译,翻译结果根据你所选的当前语言种类确定,baidu翻译接口,接口访问有访问速度限制,所有会有点慢。

指令 /translation retainOrg true 开启翻译时保留原句。


由于经费不足😂,没钱架设翻译服务器,免费的翻译接口又可能随时gg,所以这个功能的接口申请要靠使用者自己处理了,这里只写了一个baidu翻译的接口,有空的话可以去baidu翻译申请接口,有免费的,然后将id和key填入到以下的配置文件中(这个文件会在游戏初始化后自动生成)。

游戏内用命令 /translation loadConfig 主动加载配置(为了以后平滑升级到其他版本,没有使用用minecraft自带的配置文件系统,所以修改后请主动加载下配置文件)。


config.json(位于config/dyntranslation/中,同映射文件,请按以下示例填写name,id和key)

{
"ChatTranslate": true,
"Enable": true,
"SpiltWords": true,
"RetainOrg": false,
"TranslateApis": [
{
  "name": "baidu",//现在只支持baidu的翻译Api
  "id": "****************",//对于baidu翻译,这里填入你的AppId
  "key": "*****************"//这里填入你的SecretKey
}
]
}

如果是覆盖原文不保留原句,大部分时候不会缩放结果,但是如果开启了保留原句,句子太长会进行缩放,可能非满屏下会看不清字,暂时没什么办法,我还没测试过mod更好的字体,那个做过字体平滑抗锯齿(但可能会不兼容)。


动态翻译教程-第10张图片image-20200413131525429


不足和缺陷

动态翻译无法完成的事情:

  • 非FontRenderer渲染的文字,如材质中的文字,图片中的文字和非Opengl环境下的文本。

  • 渲染时的背景框,或者文本编辑时候的背景长度适配,具体见下图。

  • Minecraft自带的一些组件以及Mod中的编辑组件会被错误渲染(比如编辑栏,搜索栏等你自己就需要输入字符的组件),你输入了你定义过的字符,那么在渲染时会被错误映射为你的翻译/替换结果。

  • 只支持中英文的分词。

  • ... ...

动态翻译教程-第11张图片wrong render result show


注意事项


在windows平台,所有的json文件请使用ANSI编码,否则会出现加载失败或者是乱码等。如下图:

动态翻译教程-第12张图片image-20200409194226293