快轉到主要內容

翻譯 renpy 專案的 skill

·3048 字·7 分鐘
Denny Cheng / 月月冬瓜
作者
Denny Cheng / 月月冬瓜
獸控兼工程師兼鍵盤武術家

背景
#

目前市面上的 renpy 翻譯軟體有一個問題,可能是為了平行化,送去翻譯的時候是一句一句送。這會讓翻譯軟體失去上下文,沒辦法精準知道要如何連貫翻譯會比較好。
剛好生成式 AI 最擅長的就是理解 context,renpy 的翻譯字串又非常結構化,於是就想說是不是能夠弄一個 skill 直接把整份文件一起翻譯。

使用前聲明

  1. 絕對會很慢,因為整段讀入,會需要理解 context,取代回來的時候也需要精準替代,不能像翻譯機無腦翻出就好。
  2. 絕對很燒 token,請盡量用最便宜的 (eg: gpt5.4-mini 思考程度 low) 來執行。

BTW: 這是練習,探索一下 AI 能力的邊界,以及 skill 可以做到什麼事。整篇會比較像流水帳。

事前準備
#

翻譯字串需要先自行抽取,我是使用 Renpy Translator,裡面有中文說明。
大致上會用到

  1. 高級選項=>官方提取:把字串檔全部抓出來
  2. 高級選項=>替換字體:沒換字體中文有時候會變亂碼
  3. 高級選項=>添加更改語言入口:切換語言用

再來就是把 tl/語言 的內容單獨複製出來當作 codex 的專案文件夾。

初版
#

最開始我的 skill 寫得很簡單

---
name: renpy-tl
description: 翻譯 Renpy。
---

.rpy 檔為 Renpy 腳本檔。請按照下列規則

1. 不要修改到註解或是字串編號。
2. 專有名詞 (如人名) 請保留,不要進行翻譯。
3. 翻譯成繁體中文。
4. 不要調用外部翻譯工具,直接翻譯文本即可。

對於短文本也蠻夠用的,AI 本身已經有足夠的背景知識了解什麼叫做 renpy script,所以不一定要給範例或是教他什麼是 renpy 特殊停頓字元,他會自行理解。

問題出在長文本,AI 不會記得上次翻到哪裡。所以就必須不斷下 $renpy-tl 翻譯 @ooo.rpy 等指令,且如果剛好 rpy 檔很長,還需要告訴他從哪行開始。
雖然可以只下 $renpy-tl @ooo.rpy 仍有文字未翻譯,請幫我處理。,但有時 AI 也笨笨的,抓不到正確的行數。

另外,當單一檔案過長的時候,有時候 AI 會試圖讀入所有 context 並重新回寫文件,但過長的 context 會導致 AI 抓錯位置回寫。
雖然沒有出現 A 句接到 B 句的狀況,但文件格式會跑掉,然後 AI 就會發現他搞亂了,又再次試圖修復。
這之間的毫無生產力過程也是會持續耗損 token 的。

二版
#

想看完整可參考 github

用法
#

從用法講起,使用時先初始化進度檔,batch 數量可按照個人財力自行調整,影響的是平行處理要素。

$renpy-tl 初始化為 2 個 batch

$字號是使用 skill 的意思。過後會出現 progress/batch-001.md 之類的檔案,這是進度表。接下來

$renpy-tl 翻譯 @batch-001.md 

在 codex 中加上 @ 可以引用文件。codex 就會開始讀取 batch-001.md 找到翻譯到一半的內容並接續。如果要平行化處理記得開不同 thread 來做事。

如果檔案很少的話也可以直接使用

$renpy-tl 翻譯 @script.rpy

直接指定要翻譯的檔案,不過這樣人工介入的程度就會高一點。

codex 執行一次大約會用 3~10 分鐘不等 (視模型和他的心情)。如果不想要頻頻檢視是否需要繼續的話,codex 本身有排程指令的功能,只要在對話框疊三五個「繼續」,應該就能工作十到二十分鐘。至於要疊多少就看個人喜好。
不建議說太多次「繼續」,開新 session 重新請他翻譯會比較乾淨,context 疊太長有時會影響他的判斷力。下面為繼續示意圖

繼續繼續

初版問題改進
#

初版有兩個比較需要改進的問題點

  1. 當翻譯文本較為大量時,需要讓 AI 知道從哪邊接續。
  2. 要限制 AI 一次能做的量,我目前是抓最多一次處理 50 句翻譯。

進度紀錄
#

要讓 ai 知道要從哪邊繼續下去,最好的方法就是請他做完一個批次就紀錄一次進度。
且這個進度紀錄不能只是「幫我紀錄在 ooxx」,需要給 AI 精準的格式。
我第一次沒給格式的時候,他紀錄未完成內容,有時用行號,有時用 translation label,這會讓不精確性提高。
最好在 skill 內寫死格式。

| Status | File | Resume Point |
| --- | --- | --- |
| not started | `game/day1.rpy` | line 1 |
| in progress | `game/day2.rpy` | line 240 |
| completed | `game/day3.rpy` | completed |

然後在下面補充 not started / in progress / completed 的意義。

限制 AI 一次翻譯量
#

這點比較特殊,但 AI 一次想讀入大量 context 反而會一直出問題。要嘛回寫失敗,要嘛會告訴你說「我要讀完全部才開始翻」,但這個 rpy 檔有一萬行,根本不可能完全理解。所以盡可能的加上限制要他一段一段翻會是比較理想的。
只是 prompt 的遣詞用字也需要考慮一下。如果只寫「一次最多翻譯五十句」很容易被 ai 理解為翻 50 句就停下來問一次是否要繼續。這樣會導致 30 秒就要打一次「繼續」,很煩。

所以需要在 agent 中明確提示這只是 chunk size,請翻到文件結束再中止。目前是這樣寫:

首先明確提示這只是一個內部處理單位

Translation Chunk Size
1. For dialogue or scene translation, process one coherent scene or up to 50 target strings per translation chunk, whichever comes first.
2. For short UI or system-text entries in translate ... strings: blocks, process up to 100 new values per translation chunk.
3. A translation chunk is an internal progress unit, not a stopping point that requires user confirmation.

再來在翻譯過程的地方說明,請他不要中途停下來

5. Do not pause to ask whether to continue after completing a chunk or a file.

雖然這樣還是會中斷,但是中斷頻率會低一點點。

成果
#

仍然需要人工介入。也許是我 prompt 下的還不夠精準,在處理大塊文本時,仍然會遇到下列狀況

  1. 不小心把註解(原文)也進行翻譯
  2. 不小心翻譯人名
  3. 把翻譯文字放到文本最底下。
  4. 漏掉一整段沒翻譯 (但 batch 檔已經顯示 completed)

人工稍微瞄過有沒有問題還是必要的。

也許是機械化的流程應該考慮更自動化的作法,而不是靠生成式 AI 來硬幹。
改進市面上的翻譯軟體效果可能會更好(也更省 token)。

三版
#

二版問題改進
#

二版雖然有紀錄進度,但有時候 AI 翻譯時有時候會搞錯行,導致有一大段沒翻到。
我覺得最大的問題在於 AI 是 non-deterministic,你無法指望他以什麼方式判斷「這邊已經翻過了」。
但這又是流水線最重要的部份:找出未翻譯段落 => 翻譯 => 下一段未翻譯 => 翻譯
消除這類不確定性的方法,最好就是用一個 deterministic 的 script 來告訴 AI 下一次要翻譯什麼、此檔案翻譯完了沒。
這就好像叫 AI 寫 code 的時候,如果有 linter(compiler) / testing,當 AI 產 code 完畢,compiler 一編發現沒編過、或測試一跑發現沒跑過,他就很容易能做自我修正。

自我工具設計
#

既然是在練習 Vibe coding 當然是把規格寫一寫叫 AI 幫忙產產看啦,以下是我當時希望 AI 做出來的規格

## Skill 內部工具

### `scripts/extract.py` — 提取未翻譯文本

用法如下
`python3 <skill-dir>/scripts/extract.py <current-file> --limit 100`

重點提要:
- <skill-dir> 是包含此 `SKILL.md` 的目錄
- `<current-file>` 是當前正在翻譯的 `.rpy` 文件的路徑。
- `--limit` 參數指定要提取的未翻譯文本行的最大數量。

輸出格式為 `行號: 文本`,其中行號為原始 `.rpy` 文件中的行號,文本為該行的內容。範例如下:

===
7: MC "I think I'll go ahead and read some of the book I got from Coach."
13: MC "Let's see here. Chapter one..."
28: new "Harry"
===

AI 當然是瞬間 code 就劈哩啪啦的產好了,不過 review 時還是覺得有點小問題,來回(用嘴)請 AI 修正幾次。

提示詞修正
#

詳細提示詞

覺得二版寫太長了,把所有提示詞用中文重寫。以下節錄關於使用 extract.py 的部份。

## 使用者指定翻譯 .rpy 檔
1. 執行本 skill 內部工具 `scripts/extract.py` 以獲取未翻譯的文本,limit 請不要低於 100 行,以確保翻譯效率。
2. 翻譯後直接取代該行。
3. 若該行不需要翻譯(如僅出現人名、或僅有控制碼等),請在該行行尾添加註解 `# i18n: skip`。範例如下
    `new "Harry" # i18n: skip`
4. 重複上述步驟直到整個檔案翻譯完成。

同時由於 extract.py 已經可以精確分析出哪邊還沒有翻譯,因此進度表不需要再紀錄行號,只要是一個 checklist,完成後直接打勾即可。新進度表範例如下

# Translation Progress: batch-001

- [x] game/day1.rpy
- [ ] game/day2.rpy

成果
#

只要 AI 持續使用 scripts/extract.py 來抽取未翻譯字串,就一定不會漏掉翻譯,所以人工介入的部份又更少一點。
但有遇過「繼續」過多次之後 AI 竟然失憶忘記怎麼用 script 的狀況… 也是蠻好笑的。

如同二版時的感想,機械化流程應當考慮機械化作法。請 AI 產一個可以讀取未翻譯字串 => 送第三方翻譯 => 寫回原擋的 script才是正道。
精確、省錢、無須人工介入。不過這是 codex 練習專案所以還是會繼續折騰無 API 方案。

下一步
#

接下來可以研究的是開 subagent 來輔助流水線。
不需要在 skill 裡面把 progrss 切成多個 batch,而是只要一份 progress file,然後請一個大 agent 把不同 file 丟給小 agent 去處理即可。
這可能會有一些好處

  1. 避免過長上下文 AI 失憶 (像是忘記 extract.py 怎麼用)
  2. 讓 ai 幫你喊「繼續」,我想起碼可以翻完幾個 file 才會停。
  3. 平行化大小可以不需要在初始化決定。