當版本即將定版時,翻譯供應商通常會交回數個 .xcloc 或 .xliff 檔案。若直接在開發者日常使用的工作區中按兩下匯入,短期看似快速,實際上卻很容易將過期的翻譯鍵、錯誤的目標語言,以及損壞的預留位置一併寫入專案。更穩妥的做法,是在雲端 Mac 上建立一次性的驗收目錄:先從目前的提交匯出基準,再預檢交付內容,最後執行匯入、審查差異並建置專案。
固定驗收環境
驗收節點應從乾淨的提交開始。不要重複使用已執行過在地化匯入的工作區,也不要在含有未提交變更的目錄中測試。每次收到交付內容時,都可以建立暫存分支或獨立的 worktree:
git fetch origin
git worktree add ../localization-review origin/main
cd ../localization-review
git switch -c review/localization-batch
xcodebuild -version
git status --short
將 xcodebuild -version、提交 SHA、目標 Scheme 與交付批次寫入日誌。若團隊同時使用多個 Xcode 版本,還應明確設定 DEVELOPER_DIR,避免互動式終端機與自動化工作呼叫不同的工具鏈。
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
xcode-select -p
git rev-parse HEAD
在地化驗收的基準並不是「檔案可以開啟」,而是相同提交、相同 Xcode 工具鏈與相同匯出參數能產生可解釋的結果。
在 GPUMini 的雲端 Mac 上執行時,先於控制台確認目前可選的配置,再選擇用於驗收的節點。這項工作通常不依賴高度平行處理,但若匯入後需要完整編譯大型專案,仍應將記憶體與磁碟剩餘空間納入規劃。
從目前專案匯出基準
對於 .xcodeproj,可以使用專案參數匯出;若專案使用 Workspace,則改用 -workspace,並提供可共享的 Scheme。以下範例會匯出簡體中文、日文與法文;重複指定 -exportLanguage 即可增加語言:
mkdir -p Artifacts/Baseline
xcodebuild \
-project ExampleApp.xcodeproj \
-scheme ExampleApp \
-exportLocalizations \
-localizationPath Artifacts/Baseline \
-exportLanguage zh-Hans \
-exportLanguage ja \
-exportLanguage fr
匯出完成後,應先保存檔案清單,而不是立刻覆寫收到的翻譯:
find Artifacts/Baseline -type f -print0 \
| sort -z \
| xargs -0 shasum -a 256 > Artifacts/baseline.sha256
基準可以回答三個問題:目前專案有哪些可翻譯單元、來源語言內容是什麼,以及 Xcode 認可哪些目標語言。若交付檔案含有基準中不存在的鍵,常見原因是翻譯依據舊提交製作;若基準新增大量尚未翻譯的單元,則表示交付範圍可能遺漏了近期功能。
匯入前檢查結構與預留位置
XLIFF 本質上是 XML。首先使用系統工具檢查格式,再擷取語言屬性與翻譯單元數量。不要使用規則運算式改寫 XML;預檢可以讀取內容,但修復工作應回到在地化工具中進行,或使用經過審查的指令碼。
find Incoming -name "*.xliff" -print0 |
while IFS= read -r -d '' file; do
echo "Checking $file"
xmllint --noout "$file"
xmllint --xpath \
'string(/*[local-name()="xliff"]/*[local-name()="file"][1]/@target-language)' \
"$file"
echo
done
預留位置是最值得設為阻斷條件的問題。%@、%d、位置參數,以及 String Catalog 產生的變數,都必須在來源文字與譯文中維持語意對應。只統計百分比符號並不足夠,因為 %%、格式寬度與位置參數各有不同含義。建議使用 XML 解析器,分別讀取每個 trans-unit 的 source 與 target,將預留位置正規化後再比較多重集合。
| 檢查項目 | 阻斷條件 | 處理方式 |
|---|---|---|
| XML 結構 | xmllint 傳回非零值 |
退回交付檔案 |
| 目標語言 | 與檔案批次不一致 | 修正語言對應後重新匯出 |
| 翻譯單元 | 出現未知 ID | 核對基準提交 |
| 預留位置 | 類型或數量不一致 | 修訂譯文後重新檢查 |
| 空白譯文 | 關鍵介面的目標文字為空 | 確認是否允許回退 |
對於使用者可見的格式字串,還應抽查換行符號、逸出字元與複數分支。預留位置的順序可以因語言而調整,但使用位置參數時,必須確保索引仍然有效。
在隔離目錄中匯入並審查差異
通過預檢後,再逐一匯入 .xcloc 套件。每次匯入後都應立即記錄狀態,以便確認是哪一份交付內容引入了異常:
mkdir -p Artifacts/Logs
for package in Incoming/*.xcloc; do
name="$(basename "$package" .xcloc)"
xcodebuild \
-project ExampleApp.xcodeproj \
-importLocalizations \
-localizationPath "$package" \
2>&1 | tee "Artifacts/Logs/import-${name}.log"
test "${PIPESTATUS[0]}" -eq 0 || exit 1
git status --short
done
匯入成功不代表驗收已完成。先使用 git diff --stat 判斷影響範圍,再逐一檢閱各檔案的差異。正常變更應集中在 String Catalog、字串資源或對應的語言目錄;若出現 Scheme、建置設定、簽署設定或不相關的專案檔案變更,應立即暫停並查明來源。
git diff --stat
git diff --check
git diff -- '*.xcstrings' '*.strings' '*.stringsdict' 'project.pbxproj'
git diff --check 可以找出部分行尾空白與衝突痕跡,但無法判斷翻譯語意。建議產生一份「新增、刪除、修改翻譯單元」的摘要,並與匯入日誌一同保存為管線產出物。
透過建置與重新匯出完成閉環
最後,對目標 Scheme 執行乾淨建置。若專案包含多個應用程式目標或擴充功能,應涵蓋實際發布路徑,而不是只建置最小的程式庫目標。
set -o pipefail
xcodebuild \
-project ExampleApp.xcodeproj \
-scheme ExampleApp \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
clean build |
tee Artifacts/Logs/localization-build.log
建置通過後,再從匯入完成的專案匯出一次 XLIFF,並與基準比較。重新匯出可以發現部分譯文未真正寫入專案、語言代碼對應錯誤,或匯入後仍存在未翻譯單元等問題。比較時應忽略純粹的排序差異與工具產生的中繼資料,只關注翻譯單元的來源文字、目標文字、狀態與備註。
一套可維護的驗收管線應明確保存四類證據:工具鏈與提交資訊、預檢報告、匯入差異摘要,以及建置日誌。失敗時不要自動清理工作目錄,應先保留現場;成功後則刪除暫存 worktree,避免下一批交付內容沿用舊狀態。
最終門檻可歸納為:XML 可解析、目標語言正確、預留位置集合一致、未知翻譯單元為零、差異範圍符合預期,以及目標 Scheme 建置成功。如此一來,雲端 Mac 承擔的是可重複執行的在地化驗收節點,而不是另一個只能依靠人工記憶維護的匯入環境。
常見問題
為什麼驗收譯文前要先匯出新的 XLIFF 基準?
基準會固定現行專案可辨識的翻譯單元、原文與目標語言,便於在匯入前找出過期鍵、未知鍵及錯誤語言。
XLIFF 匯入成功是否代表可以發佈?
不是。匯入成功只代表 Xcode 能處理檔案,仍須核對佔位符、複數規則、資源差異,並執行目標 Scheme 的乾淨建置。
可以直接在主要工作目錄匯入譯文嗎?
不建議。應在暫存分支或獨立 worktree 執行,保留匯入記錄與差異摘要,再合併已確認的資源變更。
為開發與建置任務選擇一台雲端 Mac
比較兩種 M4 設定、四種租用週期與四個在售節點,再依任務需求完成部署。