Closed Lyoko-Jeremie closed 1 year ago
我们直接修改 .twee 和 .js 原文件中的文本后使用源仓库自带的编译脚本编译为 html 文件。
出现这种情况十分正常,因为游戏基于 Twine/Twee3 引擎,使用的编码格式是 Sugarcube2,因此在游戏源代码中常常会出现普通的文本字符串与变量、逻辑语句混杂交织的情况,对于任何形式的 i18n 均不友好。
例如挑一句源代码中的文本如下:
a hidden pocket on the inside of <<nnpc_his "Kylar">> <<if $NPCName[$NPCNameList.indexOf("Kylar")].pronoun is "m">>pant leg<<else>>skirt<</if>>
其对应的汉化文本为:
<<nnpc_his "Kylar">>的<<if $NPCName[$NPCNameList.indexOf("Kylar")].pronoun is "m">>裤子<<else>>裙子<</if>>内的隐藏口袋里掏了出来。
其中的变量 <<nnpc_his "Kylar">>
的定义在此处不得而知,需要在其他地方独立翻译。包括这一种情况在内的有各种复杂情况,包括但不限于:
截止目前形如此的需汉化文本有超过 111,719 条,因此在汉化过程中会出现大量的语义混杂、中英交织,或是非字符串被错误地汉化进而导致的报错问题,直至现在仍在完善过程中。因此需要大量玩家反馈游玩过程中可能出现的各种问题,进而修复完善汉化。
感觉,既然已经在做大手术了,或许可以直接给解析引擎SugarCube2打补丁,在Parser上加个i18n扩展
简单研究了一下代码
sugarcube 2 是在 markup/parserlib.js
的 L113 把用来解析<<xxxxx>> <</xxxxx>>
标签的解析器注入到Wikifier这个解析和生成器里面的
https://gitgud.io/Vrelnir/sugarcube-2/-/blob/master/src/markup/parserlib.js?ref_type=heads#L113
Wikifier.Parser.add({
name : 'macro',
profiles : ['core'],
match : '<<',
lookahead : new RegExp(`<<(/?${Patterns.macroName})(?:\\s*)((?:(?:/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*/)|(?://.*\\n)|(?:\`(?:\\\\.|[^\`\\\\])*\`)|(?:"(?:\\\\.|[^"\\\\])*")|(?:'(?:\\\\.|[^'\\\\])*')|(?:\\[(?:[<>]?[Ii][Mm][Gg])?\\[[^\\r\\n]*?\\]\\]+)|[^>]|(?:>(?!>)))*)>>`, 'gm'),
working : { source : '', name : '', arguments : '', index : 0 }, // the working parse object
context : null, // last execution context object (top-level macros, hierarchically, have a null context)
这个地方做了括号匹配和标签提取,以及标签内内容的提取。
所以应该可以在这里做 获取标签的原始文本内容 或 把汉化之后的文本替换/注入到输出结果 的工作。
大概想了一下,有两个在这个地方实现汉化注入的方法,
学习Angular的 @angular/localize ,在原始项目的 <<>> 标签上面添加i18n注解,这个是为了给标签生成固定id,然后导出angular那样格式的.xlf翻译文件,翻译之后生成angular式的节点到翻译的json字典,然后在运行时加载回去替换。
优点是翻译效果好,结果固定。
缺点就是需要给原始游戏添加i18n注解,但这个注解加完以后可以PR给原始游戏,相信作者会很开心。对付游戏JS脚本生成的动态内容以及变量,可以组合用翻译工厂 (类似Angular这种或者这种 ) 来解决
代码跑起来,在这里挂一个记录器,记录所有跑过这里的文本语句,然后生成原文字典cvs,翻译之后生成语句和翻译的查找表类似于KinkiestDungeon这种,然后在运行时加载回这个地方做替换。
这个思路就有点像GalGame啃生肉用的VNR,只不过VNR的思路是给游戏输出字符串的win api函数挂钩来提取原始文本输出到翻译机再以外挂字幕的方式显示,这里的方法要再进一步,把翻译的结果字典又输回游戏的渲染引擎(Wikifier)。
优点就是完全不需要触碰游戏原始剧本文件,跟踪上游更方便。
缺点就是匹配准确的要求高,上游即使改动一个空格这里也会出现匹配不上的情况,并且要跑过的地方才能抓到内容,要全覆盖比较麻烦。
sugarcube2 编译结果放在游戏项目的这个地方,所以打了补丁之后替换它就好
devTools/tweego/storyFormats/sugarcube-2/format.js
游戏应该用的是作者的这个打了补丁的版本的sugarcube2
刚才想测一下,发现这个 https://gitgud.io/Vrelnir/sugarcube-2 不是最新版的代码,得问问作者请他push最新的sugarcube-2更改上来
@Lyoko-Jeremie 可以考虑看这个https://github.com/tmedwards/sugarcube-2 的develop分支
没接触过相关,不确定对不对
@LittleNightmare 研究了一下git log,不像是
把两个project放在一起可以看到 Vrelnir 这个版本有个DoL特定的patch,但没看到 tmedwards 这个版本上有这个patch , 所以感觉这应该 ~是为另一个游戏做的特化版本,或者就~ 是sugarcube-2的后续开发。 (EDIT:看了下作者,tmedwards这边好像是sugarcube-2的官方,Vrelnir这边是在DoL开发过程中为了方便给sugarcube-2打了补丁)
把tmedwards这个版本放进去跑起来也是:
另外我可以确定正确版本应该是 Vrelnir 的版本,因为之前我放进去之后的第一个报错是有关 maxSessionStates 缺失的,刚好就是这个还没合并的 PR#3 里面添加进来的。 ~但是我在我本地手动Patch这个PR之后报错提示还缺少其他东西,所以我可以肯定是作者本地已经合并了这个PR,然后在其上还做了其他开发加了点最新版游戏必须的功能,但是没有把最新修改推上来。~
我的错,刚才研究了一下,打了这个 PR#3 之后得清理掉本地所有数据才能用,不然读取旧数据会报JSON解析失败,可能是IndexBD里面的数据格式变了。现在可以打开进入游戏了,但不确定其他地方会不会有问题,后边我研究一下这个sugarcube-2怎么运行的。
打过 PR#3 能跑的版本 https://github.com/Lyoko-Jeremie/sugarcube-2_Vrelnir
打过 PR#3 能跑的版本 https://github.com/Lyoko-Jeremie/sugarcube-2_Vrelnir
@Pi1viayarn 3Q~~
@Eltirosto 测试了一下,这个框架好像挺复杂的,先给我点时间找到能用的注入点弄个demo出来
初步分析写在 这里了 , 上面的 汉化方法2 应该是可以实现了。
未来汉化发布方式将独立于原版游戏,采取 I18N 模组的方式发布
想问一下,这类翻译的使用方式,之前没有接触过,能不能补贴一下使用方式之类的?
想问一下,这类翻译的使用方式,之前没有接触过,能不能补贴一下使用方式之类的?
截至 0.4.2.7-chs-alpha4.0.0 的汉化方式(下称“旧版汉化方式”)仍然是修改硬编码,直接下载发布版中的 zip 压缩文件解压即玩。
未来的新版汉化方式将基于 ModLoader,(基本用法请查看 ReadMe,基本原理是向原游戏的 HTML 文件中注入 js 实现加载模组的功能)仅放出含汉化词典的 I18N 模组,在不修改游戏本地英文原文的情况下在运行过程中动态汉化,类比 Minecraft 的 I18N 模组。
未来可能的发布汉化版方式可能会是:
- 玩家自行在官方英文版发布地址下载英文版
- 本仓库以安装包的形式发布 ModLoader 和内置汉化词典的 I18N 模组
- 玩家自行安装 ModLoader 和汉化模组
说说你遇到的问题?
在游玩过程中有发现存在同一句子同一单词,前一对话翻译成了中文后一对话就变成英文,或者反过来,这样的翻译闪烁问题。
在家里的sex玩具箱页面特别容易触发这个现象。
我想请问一下,汉化是使用内存注入并替换输出字符串形式的动态汉化,还是直接修改原始剧本脚本(.twee脚本)的静态汉化,还是官方原版游戏框架中提供了原生的i18n系统呢?