Skip to content

架構 ​

架構總覽 ​

程式碼庫分為四層。本節用於建立心智模型;需要檔案級別的詳細資訊時,請開啟原始碼樹。

sync 執行如何協同運作 ​

sync(以及個別的翻譯指令)依序執行已啟用的功能:

步驟指令功能
1extract → translate-ui掃描 UI 原始碼 → 更新 strings.json → 填寫平面語言環境 JSON (de.json,…)
2translate-svg (選用)翻譯 config.svg 下的 SVG 文字
3translate-docs翻譯 markdown、MDX、.astro 頁面;Docusaurus 目錄 JSON;Nextra _meta / 字典 .ts;VitePress 主題目錄
4translate-json (選用)翻譯 json[] 下的巢狀 JSON 葉節點

每個管線都遵循相同的核心迴圈:提取區段 → 保護語法 → 批次處理 → 快取查詢或 LLM 呼叫 → 寫入輸出。中間的共用服務 — 設定、預留位置、快取、詞彙表、LlmClient — 在共用基礎設施下描述。

模組對應 ​

層資料夾角色
入口src/cli/CLI 指令:init、extract、mark-html、translate-ui、translate-docs、translate-json、translate-svg、sync、status、dashboard,…
管線src/extractors/從 JS/TS、HTML 標記、Markdown、JSON、SVG、.astro 提取區段
src/processors/預留位置保護、批次處理、驗證、連結重寫
共用src/core/設定、類型、SQLite 快取、提示、輸出路徑、語言環境工具
src/api/LlmClient — 與供應商無關的聊天用戶端 (Vercel AI SDK),具有模型備援
src/glossary/詞彙表載入、術語提示,以及用於提示詞的選用專案情境檔案
src/utils/記錄器、雜湊、忽略解析器、顯示寬度表格、.env 載入器
您的應用程式執行階段src/runtime/i18next 輔助程式和顯示工具 — 匯出為 'ai-i18n-tools/runtime' (執行階段輔助程式)
工具 UI (內部測試)src/i18n/、src/dashboard-app/、src/server/本地化此套件自己的 CLI 和翻譯儀表板 — 與您的專案內容分開 (自我本地化)

所有用於程式化用途的內容都從 src/index.ts 重新匯出 (程式化 API)。

管線摘要 ​

管道區段輸入 → 輸出
UI 字串UI 字串內部原始檔案 → strings.json → 平面 {locale}.json
文件文件內部Markdown / MDX / .astro / Docusaurus JSON → docs[].outputDir 下的每個地區設定檔案
JSON 捆綁包JSON 內部json[] 下的巢狀 JSON → 每個地區設定的 JSON 檔案
SVG文件內部 — 擷取器config.svg 下的 SVG 檔案 → 翻譯的 SVG 副本

UI 字串內部結構 ​

步驟元件結果
1原始檔案 (JS/TS;選用 .astro / .html)磁碟上的檔案
2UIStringExtractor (i18next-scanner;透過 ui-string-babel.ts 的 .astro)以 MD5 雜湊為鍵的區段
3strings.json主要目錄:{ hash: { source, translated, models?, locations? } }
4LlmClient.translateUIBatch()原始字串的 JSON 陣列 → 翻譯 (+ 每批次的模型 ID)
5de.json、pt-BR.json、…平面對應:原始字串 → 翻譯 (無模型中繼資料)

UIStringExtractor ​

使用 i18next-scanner 的 Parser.parseFuncFromString 來尋找 JS/TS 檔案中的 t("literal") 與 i18n.t("literal") 呼叫。對於 .astro 原始碼(當列於 ui.uiExtractor.extensions 時),ui-string-babel.ts 會剖析 frontmatter 與範本 {expression} 區塊(使用 @babel/parser),並套用相同的 funcNames 規則。函式名稱與副檔名可透過 ui.uiExtractor 設定(ui.reactExtractor 為支援的別名)。extract 也會將非掃描器的輸入合併至同一目錄: 當啟用 includePackageDescription 時(預設)的專案 package.json description,以及當 includeUiLanguageEnglishNames 為 true 時,來自內建 ui-languages 主目錄(由 sourceLocale + targetLocales 建置)的每個 englishName(已在原始碼中找到的字串優先保留;不會讀取 languagesManifestPath)。extract 亦會在 languagesManifestPath 重新產生 ui-languages.json。區段雜湊為已修剪原始字串之 MD5 前 8 個十六進位字元 — 這些會成為 strings.json 中的索引鍵。

對於 .html / .htm 來源(當列於 ui.uiExtractor.extensions 時),extract 會改為透過 html-i18n-marks.ts 來路由檔案,該檔案會掃描 data-i18n / data-i18n-title / data-i18n-placeholder 標記屬性(可透過 ui.uiExtractor.htmlI18nAttributes 設定)。純標記會從元素的自身 textContent / title / placeholder 獲取來源文字;有值的標記(data-i18n="Key")則使用該值。相同的模組也支援 mark-html 命令,該命令會自動插入純標記。HTML 檔案永遠不會到達 Babel / i18next-scanner 的處理階段。

純 Astro SSG 網站可以略過 i18next:在建置時載入扁平 {locale}.json,並按源文字鍵解析 t('English')(參見 examples/astro-website/src/i18n/t.ts 與 UI 字串 — Astro 網站)。

純 HTML 應用程式遵循相同的目錄模型,使用標記屬性而非 t() 呼叫 — 參見標記 HTML 以供翻譯。

strings.json ​

主目錄的結構如下:

json
{
  "a1b2c3d4": {
    "source": "The English string",
    "translated": {
      "de": "Der deutsche Text",
      "pt-BR": "O texto em português"
    },
    "models": {
      "de": "anthropic/claude-3.5-haiku",
      "pt-BR": "openai/gpt-4o"
    },
    "locations": [{ "file": "src/app/page.tsx", "line": 51 }]
  }
}

models(選用)— 每個語系中,該語系上次成功執行 translate-ui 後產生該翻譯的模型(若文字是從翻譯儀表板儲存的則為 user-edited)。locations(選用)— extract 找到該字串的位置(掃描器 + 套件描述行;內建主目錄 englishName 字串可省略 locations)。

extract 會新增索引鍵,並為掃描中仍存在的索引鍵(掃描器字面值、選用描述、選用內建主目錄 englishName)保留既有的 translated / models 資料。translate-ui 會填入缺失的 translated 項目、更新其翻譯之語系的 models,並寫入扁平的語系檔案。

ui-languages.json manifest — { code, label, englishName, direction } 的 JSON 陣列(BCP-47 code、UI label、參考 englishName、"ltr" 或 "rtl")。使用 generate-ui-languages 或 extract 從 sourceLocale + targetLocales 與內建主目錄 data/ui-languages-complete.json 建置專案檔。

扁平化地區設定檔案 ​

每個目標地區設定都會獲得一個扁平化的 JSON 檔案 (de.json) 將來源字串對應到翻譯 (沒有 models 欄位):

json
{
  "The English string": "Der deutsche Text",
  "Save": "Speichern"
}

i18next 會將這些載入為資源套件,並透過來源字串 (預設值即金鑰模型) 來查找翻譯。

UI 翻譯提示 ​

buildUIPromptMessages 建置系統 + 使用者訊息,這些訊息會:

  • 識別來源與目標語言(透過 localeDisplayNames 或 ui-languages.json 的顯示名稱)。
  • 當目標地區具有預期的書寫系統時(明確的 BCP-47 腳本,或語言預設值,例如 hi → 天城文,ar → 阿拉伯文,ja → 日文假名/漢字),請在前面加上腳本指令。
  • 傳送字串的 JSON 陣列,並要求傳回翻譯的 JSON 陣列。
  • 可用時包含詞彙表提示。

LlmClient.translateUIBatch 會依序嘗試每個模型,在發生解析、網路或腳本錯誤時進行後援(包含原生腳本地區的羅馬化/拉丁字母後援)。CLI 會根據 localeModels、選用的 uiModels 和 translationModels 為每個目標地區建立該清單(請參閱 供應商與模型)。


文件內部結構 ​

步驟元件結果
1Markdown / MDX / JSON / .astro 檔案 (translate-docs)原始檔案
2MarkdownExtractor / JsonExtractor / AstroTemplateExtractorsegments[] — 帶有雜湊 + 內容的類型化區段
3PlaceholderHandler受保護的文字 — HTML、提示、錨點、MDX、URL、行內程式碼、以標記遮罩的強調
4splitTranslatableIntoBatchesbatches[] — 按計數 + 字元限制分組
5TranslationCache 查詢快取命中 → 跳過;未命中 → LlmClient.translateDocumentBatch
6PlaceholderHandler.restoreAfterTranslation最終文字 — 預留位置已還原
7resolveDocumentationOutputPath輸出檔案 — Docusaurus 版面配置或平面版面配置

提取器 ​

所有提取器都會擴充 BaseExtractor 並實作 extract(content, filepath): Segment[]。

  • MarkdownExtractor - 將 markdown 分割為具型別的段落:frontmatter、heading、paragraph、code、admonition。YAML frontmatter 被歸類為 不可翻譯(slug、id 及其他路由鍵保持穩定)。頂層 export ... 區塊(例如 React 元件定義)與既有的 import ... 處理一同被歸類為不可翻譯的 other 段落。以大寫 JSX 標籤起始的多行區塊(例如 <Tabs> 區塊)被歸類為可翻譯段落。不可翻譯的段落(程式碼區塊、原始 HTML)會原樣保留。
  • AstroTemplateExtractor - 針對 .astro 行銷頁面的解析與替換(透過 doc-translate.ts 中的 translateAstroFile 使用 translate-docs)。提取面向使用者的 HTML 文字節點與可翻譯屬性(alt、title、aria-label、placeholder),以及範本 {expression} 區塊內面向使用者時的字串字面量。略過 frontmatter TypeScript、<script>、<style>、受保護的屬性/鍵值,以及 t('…') 內的字面量。重組時會在輸出路徑較深時調整相對匯入(例如 src/pages/de/index.astro)。參見 Astro 網站頁面。
  • JsonExtractor - 從 Docusaurus JSON 標籤檔案提取字串值(Docusaurus UI 目錄,非 MDX 本文)。
  • SvgExtractor - 從 SVG 提取 <text>、<title> 及 <desc> 內容(由 translate-svg 用於 config.svg 下的檔案,而非由 translate-docs 使用)。
  • html-i18n-marks.ts - 一個專注的 HTML 標記掃描器,由 extract 用於 .html / .htm 來源,並由 mark-html 命令使用。collectHtmlI18nStrings / collectHtmlI18nLocations 讀取 data-i18n* 標記屬性(純標記 → 元素 textContent / title / placeholder;有值標記 → 該值),而 markHtmlContent 會將純標記插入到葉面文字 / 標題 / 預留位置元素中(結果相同,尊重 data-i18n-ignore,並略過類似程式碼和混合內容的元素)。共用的 normalizeI18nText 輔助工具可確保建置時的索引鍵與瀏覽器執行階段的索引鍵相同。

Astro 混合網站 (UI + 頁面 HTML) ​

純 Astro 應用程式通常在一個設定中同時啟用 UI 字串和文件(參考:examples/astro-website/):

層機制輸出
範本 HTMLAstroTemplateExtractor + translate-docsdocs[].outputDir 下的每個地區設定 .astro
前導資訊 / t('…')ui-string-babel.ts + extract + translate-ui扁平化 public/locales/{locale}.json (以英文來源作為金鑰)

sync 命令會依序執行已啟用的步驟:提取,然後是 翻譯 UI(當 features.translateUIStrings 時)→ 可選的 翻譯 SVG → 翻譯文件 → 可選的 翻譯 JSON(除非使用 --no-ui、--no-svg、--no-docs 或 --no-json 跳過)。初始化模板 ui-astro-website 僅搭建 UI 字串;新增 docs[] 和 features.translateDocs 以用於頁面 HTML。

標題錨點插入 (write-heading-ids CLI) ​

write-heading-ids 命令是一個 本機、非 LLM 的文件 Markdown 預處理器。實作方式:src/cli/write-heading-ids.ts 負責協調檔案發現;src/markdown/write-heading-ids-core.ts 解析行內容並插入錨點。

它需要一個有效的設定,內含至少一個 at least one docs[] block。對於每個區塊,它會收集 contentPaths 下的 .md / .mdx 檔案,套用專案的 .translate-ignore 規則(概念與文件翻譯相同),並可選擇使用 --path / --file 限制於子樹狀結構。每個檔案都會透過 applyHeadingAnchorsToMarkdown 進行轉換:對於每個位於圍欄程式碼區塊外的 flat ATX heading(# … 至 ###### …),任何形式的現有標題 ID 都會被替換為所選樣式。HTML 樣式會在無後綴標題的上一行寫入 <a id="slug"></a>;--slug-style mdx-comment 會在標題行寫入 {/* #slug */}(並移除前面的 HTML 錨點)。Slug 一律取自目前的標題文字。--remove 會移除 HTML 錨點、傳統的 {#id} 後綴,以及 MDX 註解 ID,而不寫入新的。Slug 演算法符合常見的生態系統 — github(預設)、bitbucket、gitlab、pymdown(可選的 Unicode 正規化 / 百分比編碼旗標)、azure-devops,以及 mdx-comment(github slug + MDX 註解輸出)— 這樣錨點 ID 就能與現有工具保持一致(doctoc、PyMdown、Docusaurus 等)。--dry-run 會報告將進行的編輯而不實際寫入。

在來源遍歷之後,同一指令會將這些英文 id 重新定位到各語系現有的翻譯 markdown(resolveTranslatedOutputPath)上。翻譯後的標題絕不會重新產生 slug;標題中間的 {#id} / {/* #id */} 會被移回至所選樣式預期的後綴(或 HTML 錨點)位置。缺少的語系檔案會被略過。

此命令不會在 translate-docs 或 sync 中執行;當您希望在翻譯或發佈前,原始檔案中有穩定的片段 ID 時,請明確執行此命令。

佔位符保護 ​

在翻譯之前,敏感語法會被替換為不透明的 token,以防止 LLM 損壞,按此順序套用(還原是反向的):

  1. 標題 id 後綴(位於 ATX 標題結尾的傳統 {#id} / MDX {/* #id */})— 會從該行完全剝離,且不會傳送給模型。還原後會重新釘回至對應標題的結尾,讓 Docusaurus 仍能看見有效的 id。標題中間的註解會保留在文字中,由後續的 MDX / {#…} 層處理。
  2. HTML 標籤與註解(<strong>、<!-- ... --> 等)— 來自已知允許清單的小寫 HTML 標籤會被替換為 權杖。首字母大寫的 JSX 標籤(<Highlight>、<Tabs>、</Tab>)由 MDX 層(步驟 5)另行處理。
  3. 提示標記(:::note、:::)— 僅將開頭行的指令前綴替換為 ;同一行上的任何標題則保留給模型翻譯。還原時使用完全相同的原始文字。
  4. 文件錨點(HTML <a id="…">、標題中間殘留的 Docusaurus {#…})— 原樣保留。
  5. MDX 專用結構(src/processors/mdx-placeholders.ts):
    • MDX 註解({/* … */},包含非行尾後綴的標題中間 {/* #my-id */})替換為 。
    • 首字母大寫的 JSX 標籤(<Highlight>、<Tabs>、<TabItem>、<TOCInline />、</Highlight>)— 保留為 ,可翻譯的字串屬性(label、tooltip、aria-label)會在標籤內改寫為 ,除非該屬性名稱出現在 docs[].protectAttributes 中;<Tabs values={[ { label: '…' } ]}> 物件字面量中的 label:(可透過 docs[].protectKeys 跳過)以及 <TabItem value="…">(當不存在 label 屬性時,跳過類似 slug 的小寫值)也會被擷取。以 ||JXA_N: …|| 行的形式附加至段落中,並由 restoreMdx 合併回來。
    • MDX 大括號運算式({frontMatter.title}、style={{…}})— 具備深度感知的比對,替換為 。
  6. Markdown URL(](url)、src="…")— 翻譯後從對照表還原。
  7. 行內程式碼區段(`code`)與粗體包裹的行內程式碼(**code**)— 保留。
  8. Markdown 強調(可選,CJK/RTL 語系自動啟用)— 強調分隔符號會被遮罩。

在模型回傳後,translate-docs 會還原映射並驗證區段:必須存在相同的雙大括號權杖多重集,結構權杖({{HTM_N}}、警告標記)必須保持其有序子序列(內容權杖如 {{ILC_N}} / {{URL_N}} / ** 可隨語序移動),還原的 HTML 標籤類型必須與未受保護的來源相符,且任何剩餘的雙大括號識別碼必須已存在於來源中(因此虛構的權杖將會失敗)。文件提示也要求模型複製每個權杖一次,保持結構權杖順序,且不得發明新的雙大括號包裝器;機械式檢查仍然具有權威性。

Astro 模板和 MDX JSX 的共享屬性/鍵保護在 src/processors/expression-attribute-protection.ts 中實現,並由 docs[].protectAttributes 和 docs[].protectKeys 按區塊驅動(請參閱 protectAttributes / protectKeys)。

快取(TranslationCache) ​

SQLite 資料庫(透過 node:sqlite)儲存列,其金鑰為 (source_hash, locale),包含 translated_text、model、filepath、last_hit_at 和相關欄位。雜湊是正規化內容(空白字元折疊)的前 16 個十六進位字元的 SHA-256。

在每次執行時,區段會透過雜湊 × 語系進行查詢。只有快取未命中才會傳送至 LLM。翻譯後,目前翻譯範圍中未命中的區段列會重設 last_hit_at。文件翻譯期間成功的快取命中會清除該區段過時的 translation_failures 列。cleanup 會先執行 sync --force-update,接著移除過時的區段列(null last_hit_at / 空白檔案路徑),當解析後的來源路徑在磁碟上不存在時修剪 file_tracking 鍵(doc-block:…、json-block:…、svg-files:… 等),移除元資料檔案路徑指向不存在檔案的翻譯列,修剪孤立的 translation_failures 列,修剪解析後來源路徑在磁碟上不存在的孤立 markdown_source_issues 列,並捨棄設定中缺少語系的快取列(sourceLocale、根 targetLocales,以及任何每個區塊的 docs[] / json[] targetLocales;僅限 SQLite — 使用 purge-locale 來刪除產生的檔案);除非傳遞了 --backup <path>,否則它不會備份 cache.db,傳遞時會先將備份寫入該路徑。

計費的模型呼叫(已接受的翻譯與已捨棄的重試)會儲存在 api_calls 中。在執行記錄呼叫的命令後,超過七個 UTC 曆日的詳細資料列會彙總至月度 api_totals。usage 與儀表板的「使用量與成本」檢視會合併這兩個資料表。請參閱使用量與成本。

術語表 Context 備註與 glossary.contextFiles 會產生指紋 (prompt_context_hash),並注入至 UI、文件、JSON、SVG 及校對提示詞中。變更該指引會使下次執行時相符的快取區段與檔案追蹤列失效。儀表板 user-edited 快取列會予以保留。僅變更偏好的術語表翻譯會維持現有快取不變,直到 --force / --force-update。

translate-docs 指令也使用 檔案追蹤,因此對於未更改且已有最新輸出的來源,可以完全跳過工作。--check-cache 會以預期的書寫系統重新開啟語言環境,以便重新驗證快取的段落;--force-update 會對每個語言環境重新執行檔案處理,同時仍使用段落快取;--force 會清除檔案追蹤並繞過段落快取讀取以進行 API 翻譯。當每個已設定的模型在 Markdown 段落上未能通過 AST 驗證時,translate-docs 可以逐步分割段落並重試較小的部分(docs[].segmentSplitting.qualityRetrySplit,預設開啟)。請參閱文件 — 快取行為與旗標以取得完整的旗標表格。

批次提示格式: translate-docs --prompt-format 僅為 LlmClient.translateDocumentBatch 選擇 XML (<seg> / <t>) 或 JSON 陣列/物件形狀;提取、佔位符和驗證保持不變。請參閱 批次提示格式。

輸出路徑解析 ​

resolveDocumentationOutputPath(config, cwd, locale, relPath, kind) 將相對於來源的路徑對應至輸出路徑:

  • nested 樣式(預設):用於 Markdown 的 {outputDir}/{locale}/{relPath}。
  • doc-system 樣式:在 docsRoot 下,輸出使用 {outputDir}/{locale}/[localeSubpath/]{relativeToDocsRoot};docsRoot 以外的路徑會回溯到巢狀佈局。別名:docusaurus(預設 localeSubpath = Docusaurus 外掛程式路徑)、astro-starlight(預設為空 localeSubpath)、vitepress(與 doc-system 相同,但 localeSubpath 為空;保留 BCP-47 資料夾大小寫)。
  • flat 樣式:{outputDir}/{stem}.{locale}{extension}。當 flatPreserveRelativeDir 為 true 時,來源子目錄會保留在 outputDir 下。
  • 自訂 pathTemplate:任何使用 {outputDir}、{locale}、{LOCALE}、{relPath}、{stem}、{basename}、{extension}、{docsRoot}、{relativeToDocsRoot} 的 Markdown 佈局。
  • 自訂 jsonPathTemplate:為 JSON 標籤檔案提供獨立的自訂佈局,使用相同的佔位符。
  • linkRewriteDocsRoot 協助平面連結重寫器在翻譯輸出位於預設專案根目錄以外的位置時計算正確的前置詞。

平面連結重寫 ​

當 docsOutput.style === "flat" 時,翻譯後的 markdown 檔案會與源檔案並排放置,並帶有語系後綴。頁面之間的相對連結會被改寫,使 readme.de.md 中的 [Guide](./guide.md) 指向 guide.de.md。由 rewriteRelativeLinks 控制(扁平樣式且無自訂 pathTemplate 時自動啟用)。同一遍次會在 postProcessing.regexAdjustments 執行前,為非 markdown 資源 URL 加上按檔案深度的前綴 — 參見扁平連結改寫器。


JSON 內部結構 ​

步驟元件結果
1json[].contentPaths檔案已解析(檔案、目錄或 glob)
2NestedJsonExtractor字串葉子由 keyPolicy 選取(點路徑 + minimatch)
3PlaceholderHandler + 批次 + TranslationCache快取命中 → 跳過;未命中 → LlmClient.translateDocumentBatch (共享 SQLite)
4NestedJsonExtractor.reassemble透過 expandJsonBlockOutputPath(outputPathTemplate) 輸出檔案
  • NestedJsonExtractor (src/extractors/nested-json-extractor.ts) 遍歷任意巢狀 JSON,並為每個可翻譯的字串葉節點發出一個區段。keyPolicy.mode (allowlist、denylist 或 both) 使用點符號上的 minimatch 過濾路徑(像 slug 這樣的裸名稱匹配最終的鍵區段)。
  • 快取檔案追蹤使用 json-block:{blockIndex}:{projectRelPath} 在 file_tracking 中(與文件和 SVG 相同的 cacheDir)。
  • 不適用於 Docusaurus write-translations 目錄 ({ message, description } 形狀) — 這些使用文件 (docs[].docusaurusCatalogDir + JsonExtractor 在 translate-docs 內部)。
  • 不適用於 t() UI 字串 — UI 字串 (strings.json + 扁平套件)。
  • CLI:translate-json;協調在 src/cli/translate-json-run.ts。初始化範本:ui-json-bundles。

共用基礎結構 ​

LlmClient ​

基於 Vercel AI SDK(ai + @ai-sdk/openai-compatible)建置的提供者無關的聊天用戶端。它會從 provider / providers 解析作用中的提供者,為該提供者的 baseUrl + API 金鑰建置一個 OpenAI 相容的用戶端(createOpenAICompatible),並透過 generateText 路由所有呼叫。OpenRouterClient 保留為已淘汰的別名。主要行為:

  • 模型後備:依序嘗試已解析清單中的每個模型;在請求或解析失敗時回退。每個目標語言區都有各自的已解析鏈:已設定時優先使用 localeModels(locale),接著是 uiModels(僅限 UI 管線),然後是 translationModels。文件、JSON 及 SVG 翻譯會使用非 UI 鏈為每個語言區建立客戶端。bench-models 指令則改為每個已設定的 id 建立一個單一模型客戶端(translationModels、uiModels 與 localeModels 的聯集;translationModels: [id],無後備),以便獨立計時和計價每個模型。
  • 請求逾時:requestTimeout(秒)或作用中供應商上的 requestTimeoutMs,否則使用設定檔頂端的相同鍵值(預設 45 秒),透過 AbortSignal.timeout 中止每個請求。當 CLI 載入供應商的模型清單以供 check-models(任何供應商)使用時,相同的值也適用於 GET /models。捨棄未知模型 id 的選用預檢篩選器僅在作用中供應商為 OpenRouter 時執行。
  • OpenRouter 額外功能(僅當 openrouter 為作用中時):透過 provider 請求欄位進行吞吐量路由,HTTP-Referer / X-Title 標頭,以及從 usage.cost 讀取的精確 USD 成本。每個供應商都會回報 Token 使用量。當供應商省略 usage.cost 時,USD 成本會從 providers.<name>.modelPricing 或供應商全域的 pricing 預設值計算,並儲存在 api_calls 列上。供應商回報的成本永遠不會被取代。
  • 除錯流量記錄:若已設定 debugTrafficFilePath,會將請求與回應 JSON 附加至檔案(程式化方式)。CLI --debug-failed 會在 cacheDir 下寫入 FAILED-TRANSLATION 個檔案,包含系統/使用者提示詞、原始助理回覆,以及失敗的 UI、文件、JSON 及 SVG 翻譯檢查嘗試的驗證錯誤。供應商 API / 空回應體失敗會在主控台印出,而非傾印僅含提示詞的檔案。

設定載入 ​

loadI18nConfigFromFile(configPath, cwd) 管道:

  1. 讀取並剖析 ai-i18n-tools.config.json(JSON)。
  2. mergeWithDefaults — 與 defaultI18nConfigPartial 深度合併,並將任何 docs[].sourceFiles 項目合併至 contentPaths。
  3. expandTargetLocalesFileReferenceInRawInput — 將 targetLocales 強制轉換為陣列,並拒絕路徑狀項目(必須為 BCP-47 代碼,而非通往 ui-languages.json 的路徑);在 mergeWithDefaults 期間,languagesManifestPath 預設為 {ui.flatOutputDir}/ui-languages.json。
  4. expandDocumentationTargetLocalesInRawInput — 對每個 docs[].targetLocales 項目執行相同操作。
  5. expandJsonTargetLocalesInRawInput - 每個 json[].targetLocales 條目都相同。
  6. parseI18nConfig - Zod 驗證 + validateI18nBusinessRules。
  7. applyProviderOverrideToRawInput - 當 -P / --provider 在 CLI 上傳遞時。
  8. applyEnvOverrides - 設定時應用 OPENROUTER_BASE_URL、OLLAMA_BASE_URL、I18N_SOURCE_LOCALE 和 I18N_TARGET_LOCALES(API 金鑰在 LlmClient 內部為每個提供者單獨解析)。
  9. augmentConfigWithUiLanguagesMaster - 從捆綁的主目錄中附加清單顯示名稱。
  10. assertEffectiveLocalesInUiLanguagesMaster - 在適用時根據主目錄驗證地區設定代碼。

init 會從 initConfigTemplates 寫入入門設定:ui-markdown(UI + 可選的應用程式 markdown)、ui-docusaurus、ui-starlight、ui-vitepress(VitePress 文件 + vitepressThemeCatalog)、ui-nextra(Nextra 文件 + nextraDictionaryPath)、ui-astro-website(純 Astro UI;加入 docs[] 以進行 .astro 頁面翻譯)、ui-json-bundles(僅限 JSON json[])。請參閱快速入門 — 初始化。

記錄器 ​

Logger 支援 debug、info、warn、error 層級,並帶有 ANSI 顏色輸出。詳細模式(-v)啟用 debug。當設定了 logFilePath 時,記錄行也會寫入該檔案。

工具使用者介面自行本地化 ​

此工具會將其自身的使用者介面(命令列說明、高流量記錄/摘要/錯誤訊息,以及翻譯儀表板)與您需要翻譯的內容分開進行本地化。

  • 地區解析(resolveUiLocale 在 src/core/ui-locale.ts 中):從 -L / --ui-lang > AI_I18N_LANG > 設定 uiLanguage > 主機作業系統地區設定(Intl.DateTimeFormat().resolvedOptions().locale)中選擇 UI 地區設定。候選者會被正規化並與已發布的捆綁包集精確匹配或透過最接近的變體匹配(例如 pt-PT → pt-BR,en-US → en-GB),回退到原始地區設定(en-GB)。CLI 在建立說明之前解析一次(預解析 argv 掃描),並在設定載入後再次解析,以便 uiLanguage 適用(該旗標和環境變數仍然優先)。
  • 執行時(src/i18n/index.ts):一個最小的 t(source, vars),帶有 插值,透過英文原始字串作為鍵,對應 src/i18n/locales/<code>.json 中的扁平化每個地區設定捆綁包(在建置時複製到 dist/i18n/locales)。缺少鍵或捆綁包會返回原始文字。這與 UI 字串的鍵作為預設模型相同 — 沒有雜湊查找。
  • 儀表板:伺服器公開 GET /api/ui-i18n,返回已解析 UI 地區設定的 { locale, dir, bundle };前端設定 <html lang> / dir 並透過 data-i18n* 屬性本地化靜態標記。
  • 內部測試:捆綁包是透過對 ai-i18n-self.config.json(pnpm i18n:self)執行套件自己的提取 → translate-ui 管道生成的。目錄鍵來自 t() 在 src/cli/ 和 src/i18n/ 中的呼叫,以及儀表板在 src/dashboard-app/index.html 中的 data-i18n* 標記。

擴充點 ​

自訂函式名稱(UI 提取) ​

透過設定新增非標準翻譯函式名稱:

json
{
  "ui": {
    "uiExtractor": {
      "funcNames": ["t", "i18n.t", "translate", "i18n.translate"],
      "extensions": [".js", ".jsx", ".ts", ".tsx", ".astro", ".html"],
      "htmlI18nAttributes": ["data-i18n", "data-i18n-title", "data-i18n-placeholder"]
    }
  }
}

(ui.reactExtractor 是 ui.uiExtractor 的完全支援別名。)

將 .html / .htm 加入 extensions 中,以便在 extract 期間掃描 HTML 標記屬性。ui.uiExtractor.htmlI18nAttributes 是選用的,預設為 ["data-i18n", "data-i18n-title", "data-i18n-placeholder"];data-i18n 對應到元素的 textContent,而 data-i18n-<attr> 對應到該屬性的值(例如 data-i18n-aria-label)。

自訂提取器 ​

實作套件中的 ContentExtractor:

ts
import { BaseExtractor, type Segment } from 'ai-i18n-tools';

class MyExtractor extends BaseExtractor {
  readonly name = 'my-format';
  canHandle(filepath: string) { return filepath.endsWith('.myext'); }
  extract(content: string, filepath: string): Segment[] { /* … */ }
  reassemble(segments: Segment[], translations: Map<string, string>): string { /* … */ }
}

透過擴展從 'ai-i18n-tools' 匯出的公共提取器類別來註冊自訂提取器(例如子類別 MarkdownExtractor)。CLI 在內部連接內建提取器;不支援深度匯入 doc-translate.ts。

自訂輸出路徑 ​

對任何檔案配置使用 docsOutput.pathTemplate:

json
{
  "docs": [
    {
      "docsOutput": {
        "pathTemplate": "{outputDir}/{locale}/{relativeToDocsRoot}"
      }
    }
  ]
}

原始碼樹 ​

完整的 src/ 版面配置(檔案級參考)
text
src/
├── index.ts                        Public API re-exports
│
├── cli/
│   ├── index.ts                    CLI entry point (commander)
│   ├── extract-strings.ts          `extract` command implementation
│   ├── mark-html.ts                `mark-html` command (insert bare `data-i18n*` markers into HTML)
│   ├── translate-ui-strings.ts     `translate-ui` command implementation
│   ├── doc-translate.ts            `translate-docs` command (documentation files only)
│   ├── translate-json-run.ts       `translate-json` command (`json[]` nested locale bundles)
│   ├── translate-svg.ts            `translate-svg` command (SVG files from `config.svg`)
│   ├── write-heading-ids.ts        `write-heading-ids` command (markdown heading anchors)
│   ├── bench-models.ts             `bench-models` command (per-model translate latency/token/cost benchmark)
│   ├── helpers.ts                  Shared CLI utilities
│   └── file-utils.ts               File collection helpers
│
├── markdown/
│   └── write-heading-ids-core.ts   Slug styles + `<a id="…">` insertion for `write-heading-ids`
│
├── core/
│   ├── types.ts                    Zod schemas + TypeScript types for all config shapes
│   ├── config.ts                   Config loading, merging, validation, init templates
│   ├── cache.ts                    SQLite translation cache (node:sqlite)
│   ├── prompt-builder.ts           LLM prompt construction for docs and UI strings
│   ├── output-paths.ts             Docusaurus / flat output path resolution
│   ├── ui-languages.ts             ui-languages.json loading and locale resolution
│   ├── ui-locale.ts                Resolve the tool's own UI locale (flag/env/config/OS → shipped bundle)
│   ├── locale-utils.ts             BCP-47 normalisation, locale list parsing, script/Han-variant validation
│   └── errors.ts                   Typed error classes
│
├── extractors/
│   ├── base-extractor.ts           Abstract base class for all extractors
│   ├── ui-string-extractor.ts      JS/TS source scanner (i18next-scanner + Babel for `.astro`)
│   ├── ui-string-babel.ts          Babel-based `t()` discovery in `.astro` frontmatter and `{expression}` blocks
│   ├── ui-string-locations.ts      Source locations for extracted UI strings
│   ├── html-i18n-marks.ts          HTML `data-i18n*` marker scanner + `mark-html` annotator
│   ├── classify-segment.ts         Heuristic segment type classification
│   ├── markdown-extractor.ts       Markdown / MDX segment extraction
│   ├── markdown-segment-split.ts   Optional segment splitting for long markdown blocks
│   ├── frontmatter-fields.ts       Selective YAML front matter field translation
│   ├── astro-template-extractor.ts `.astro` parse-and-replace (HTML + template expressions; used by `translate-docs`)
│   ├── json-extractor.ts           Docusaurus catalog JSON extraction (`translate-docs`)
│   ├── nested-json-extractor.ts    Arbitrary nested JSON leaves (`translate-json`, `json[]`)
│   └── svg-extractor.ts            SVG text extraction
│
├── processors/
│   ├── placeholder-handler.ts      Chain: HTML → admonitions → anchors → MDX → URLs → emphasis
│   ├── expression-attribute-protection.ts  Shared protected attribute/key lists (Astro + MDX JSX)
│   ├── url-placeholders.ts         Markdown URL protection/restore
│   ├── admonition-placeholders.ts  Docusaurus admonition protection/restore
│   ├── anchor-placeholders.ts      HTML anchor / heading ID protection/restore
│   ├── html-tag-placeholders.ts    Lowercase HTML tag / comment protection ({{HTM_N}})
│   ├── placeholder-integrity.ts    Pre/post-restore token sequence + tag-kind + invented {{IDENT}} checks
│   ├── mdx-placeholders.ts         MDX comments, JSX tags, brace expressions, JSX attribute extraction
│   ├── batch-processor.ts          Segment → batch grouping (count + char limits)
│   ├── validator.ts                Post-translation structural checks
│   └── flat-link-rewrite.ts        Relative link rewriting for flat output
│
├── api/
│   ├── llm-client.ts               LlmClient: provider-agnostic chat client (AI SDK) with model fallback chain
│   └── provider-models-catalog.ts  Fetch/parse any provider's OpenAI-compatible GET /models catalog
│
├── glossary/
│   ├── glossary.ts                 Glossary loading (CSV + auto-build from strings.json)
│   ├── matcher.ts                  Term hint extraction for prompts
│   └── translation-context.ts      contextFiles loader and guidance fingerprints
│
├── runtime/
│   ├── index.ts                    Runtime re-exports
│   ├── template.ts                 interpolateTemplate, flipUiArrowsForRtl
│   ├── ui-language-display.ts      getUILanguageLabel, getUILanguageLabelNative
│   └── i18next-helpers.ts          RTL detection, i18next setup factories
│
├── i18n/                           Self-localization runtime for the tool's own UI
│   ├── index.ts                    t(source, vars) + bundle/manifest loaders (keyed by English source string)
│   └── locales/                    Shipped UI bundles (de.json, es.json, …; generated by `pnpm i18n:self`)
│
├── dashboard-app/
│   ├── index.html                  Translation Dashboard static UI (HTML/CSS/JS)
│   ├── app.js
│   └── styles.css
│
├── server/
│   └── translation-dashboard.ts    Express app for Translation Dashboard (cache / strings.json / glossary)
│
└── utils/
    ├── logger.ts                   Leveled logger with ANSI support
    ├── hash.ts                     Segment hash (SHA-256 first 16 hex)
    ├── table.ts                    Display-width aware table rendering (CJK/emoji column alignment)
    ├── load-dotenv.ts              Auto-load `.env` from the cwd at CLI startup (never overrides existing env)
    └── ignore-parser.ts            .translate-ignore file parser

採用 MIT 授權條款釋出。