ai-i18n-tools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/api/openrouter.d.ts +115 -0
  4. package/dist/api/openrouter.d.ts.map +1 -0
  5. package/dist/api/openrouter.js +399 -0
  6. package/dist/api/openrouter.js.map +1 -0
  7. package/dist/cli/doc-translate.d.ts +90 -0
  8. package/dist/cli/doc-translate.d.ts.map +1 -0
  9. package/dist/cli/doc-translate.js +1153 -0
  10. package/dist/cli/doc-translate.js.map +1 -0
  11. package/dist/cli/export-ui-xliff.d.ts +32 -0
  12. package/dist/cli/export-ui-xliff.d.ts.map +1 -0
  13. package/dist/cli/export-ui-xliff.js +153 -0
  14. package/dist/cli/export-ui-xliff.js.map +1 -0
  15. package/dist/cli/extract-strings.d.ts +12 -0
  16. package/dist/cli/extract-strings.d.ts.map +1 -0
  17. package/dist/cli/extract-strings.js +80 -0
  18. package/dist/cli/extract-strings.js.map +1 -0
  19. package/dist/cli/file-utils.d.ts +10 -0
  20. package/dist/cli/file-utils.d.ts.map +1 -0
  21. package/dist/cli/file-utils.js +77 -0
  22. package/dist/cli/file-utils.js.map +1 -0
  23. package/dist/cli/format.d.ts +21 -0
  24. package/dist/cli/format.d.ts.map +1 -0
  25. package/dist/cli/format.js +75 -0
  26. package/dist/cli/format.js.map +1 -0
  27. package/dist/cli/helpers.d.ts +27 -0
  28. package/dist/cli/helpers.d.ts.map +1 -0
  29. package/dist/cli/helpers.js +84 -0
  30. package/dist/cli/helpers.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +772 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/log-output.d.ts +13 -0
  36. package/dist/cli/log-output.d.ts.map +1 -0
  37. package/dist/cli/log-output.js +75 -0
  38. package/dist/cli/log-output.js.map +1 -0
  39. package/dist/cli/translate-svg.d.ts +7 -0
  40. package/dist/cli/translate-svg.d.ts.map +1 -0
  41. package/dist/cli/translate-svg.js +167 -0
  42. package/dist/cli/translate-svg.js.map +1 -0
  43. package/dist/cli/translate-ui-strings.d.ts +27 -0
  44. package/dist/cli/translate-ui-strings.d.ts.map +1 -0
  45. package/dist/cli/translate-ui-strings.js +357 -0
  46. package/dist/cli/translate-ui-strings.js.map +1 -0
  47. package/dist/core/cache-tracking-keys.d.ts +12 -0
  48. package/dist/core/cache-tracking-keys.d.ts.map +1 -0
  49. package/dist/core/cache-tracking-keys.js +20 -0
  50. package/dist/core/cache-tracking-keys.js.map +1 -0
  51. package/dist/core/cache.d.ts +153 -0
  52. package/dist/core/cache.d.ts.map +1 -0
  53. package/dist/core/cache.js +546 -0
  54. package/dist/core/cache.js.map +1 -0
  55. package/dist/core/config.d.ts +58 -0
  56. package/dist/core/config.d.ts.map +1 -0
  57. package/dist/core/config.js +392 -0
  58. package/dist/core/config.js.map +1 -0
  59. package/dist/core/doc-file-tracking.d.ts +8 -0
  60. package/dist/core/doc-file-tracking.d.ts.map +1 -0
  61. package/dist/core/doc-file-tracking.js +27 -0
  62. package/dist/core/doc-file-tracking.js.map +1 -0
  63. package/dist/core/errors.d.ts +19 -0
  64. package/dist/core/errors.d.ts.map +1 -0
  65. package/dist/core/errors.js +23 -0
  66. package/dist/core/errors.js.map +1 -0
  67. package/dist/core/locale-utils.d.ts +20 -0
  68. package/dist/core/locale-utils.d.ts.map +1 -0
  69. package/dist/core/locale-utils.js +75 -0
  70. package/dist/core/locale-utils.js.map +1 -0
  71. package/dist/core/output-paths.d.ts +22 -0
  72. package/dist/core/output-paths.d.ts.map +1 -0
  73. package/dist/core/output-paths.js +130 -0
  74. package/dist/core/output-paths.js.map +1 -0
  75. package/dist/core/prompt-builder.d.ts +62 -0
  76. package/dist/core/prompt-builder.d.ts.map +1 -0
  77. package/dist/core/prompt-builder.js +232 -0
  78. package/dist/core/prompt-builder.js.map +1 -0
  79. package/dist/core/prompts.d.ts +27 -0
  80. package/dist/core/prompts.d.ts.map +1 -0
  81. package/dist/core/prompts.js +57 -0
  82. package/dist/core/prompts.js.map +1 -0
  83. package/dist/core/svg-asset-paths.d.ts +40 -0
  84. package/dist/core/svg-asset-paths.d.ts.map +1 -0
  85. package/dist/core/svg-asset-paths.js +107 -0
  86. package/dist/core/svg-asset-paths.js.map +1 -0
  87. package/dist/core/types.d.ts +388 -0
  88. package/dist/core/types.d.ts.map +1 -0
  89. package/dist/core/types.js +265 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/core/ui-languages.d.ts +66 -0
  92. package/dist/core/ui-languages.d.ts.map +1 -0
  93. package/dist/core/ui-languages.js +277 -0
  94. package/dist/core/ui-languages.js.map +1 -0
  95. package/dist/core/user-edited-model.d.ts +3 -0
  96. package/dist/core/user-edited-model.d.ts.map +1 -0
  97. package/dist/core/user-edited-model.js +3 -0
  98. package/dist/core/user-edited-model.js.map +1 -0
  99. package/dist/edit-cache-app/app.js +1326 -0
  100. package/dist/edit-cache-app/index.html +287 -0
  101. package/dist/edit-cache-app/styles.css +664 -0
  102. package/dist/extractors/base-extractor.d.ts +15 -0
  103. package/dist/extractors/base-extractor.d.ts.map +1 -0
  104. package/dist/extractors/base-extractor.js +23 -0
  105. package/dist/extractors/base-extractor.js.map +1 -0
  106. package/dist/extractors/classify-segment.d.ts +6 -0
  107. package/dist/extractors/classify-segment.d.ts.map +1 -0
  108. package/dist/extractors/classify-segment.js +20 -0
  109. package/dist/extractors/classify-segment.js.map +1 -0
  110. package/dist/extractors/json-extractor.d.ts +16 -0
  111. package/dist/extractors/json-extractor.d.ts.map +1 -0
  112. package/dist/extractors/json-extractor.js +128 -0
  113. package/dist/extractors/json-extractor.js.map +1 -0
  114. package/dist/extractors/markdown-extractor.d.ts +15 -0
  115. package/dist/extractors/markdown-extractor.d.ts.map +1 -0
  116. package/dist/extractors/markdown-extractor.js +205 -0
  117. package/dist/extractors/markdown-extractor.js.map +1 -0
  118. package/dist/extractors/svg-extractor.d.ts +19 -0
  119. package/dist/extractors/svg-extractor.d.ts.map +1 -0
  120. package/dist/extractors/svg-extractor.js +132 -0
  121. package/dist/extractors/svg-extractor.js.map +1 -0
  122. package/dist/extractors/ui-string-extractor.d.ts +40 -0
  123. package/dist/extractors/ui-string-extractor.d.ts.map +1 -0
  124. package/dist/extractors/ui-string-extractor.js +146 -0
  125. package/dist/extractors/ui-string-extractor.js.map +1 -0
  126. package/dist/extractors/ui-string-locations.d.ts +23 -0
  127. package/dist/extractors/ui-string-locations.d.ts.map +1 -0
  128. package/dist/extractors/ui-string-locations.js +138 -0
  129. package/dist/extractors/ui-string-locations.js.map +1 -0
  130. package/dist/glossary/glossary.d.ts +34 -0
  131. package/dist/glossary/glossary.d.ts.map +1 -0
  132. package/dist/glossary/glossary.js +260 -0
  133. package/dist/glossary/glossary.js.map +1 -0
  134. package/dist/glossary/matcher.d.ts +10 -0
  135. package/dist/glossary/matcher.d.ts.map +1 -0
  136. package/dist/glossary/matcher.js +12 -0
  137. package/dist/glossary/matcher.js.map +1 -0
  138. package/dist/index.d.ts +44 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +44 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/processors/admonition-placeholders.d.ts +8 -0
  143. package/dist/processors/admonition-placeholders.d.ts.map +1 -0
  144. package/dist/processors/admonition-placeholders.js +59 -0
  145. package/dist/processors/admonition-placeholders.js.map +1 -0
  146. package/dist/processors/anchor-placeholders.d.ts +8 -0
  147. package/dist/processors/anchor-placeholders.d.ts.map +1 -0
  148. package/dist/processors/anchor-placeholders.js +37 -0
  149. package/dist/processors/anchor-placeholders.js.map +1 -0
  150. package/dist/processors/batch-processor.d.ts +10 -0
  151. package/dist/processors/batch-processor.d.ts.map +1 -0
  152. package/dist/processors/batch-processor.js +33 -0
  153. package/dist/processors/batch-processor.js.map +1 -0
  154. package/dist/processors/bold-code-placeholders.d.ts +14 -0
  155. package/dist/processors/bold-code-placeholders.d.ts.map +1 -0
  156. package/dist/processors/bold-code-placeholders.js +116 -0
  157. package/dist/processors/bold-code-placeholders.js.map +1 -0
  158. package/dist/processors/doc-postprocess.d.ts +51 -0
  159. package/dist/processors/doc-postprocess.d.ts.map +1 -0
  160. package/dist/processors/doc-postprocess.js +215 -0
  161. package/dist/processors/doc-postprocess.js.map +1 -0
  162. package/dist/processors/emphasis-placeholders.d.ts +6 -0
  163. package/dist/processors/emphasis-placeholders.d.ts.map +1 -0
  164. package/dist/processors/emphasis-placeholders.js +262 -0
  165. package/dist/processors/emphasis-placeholders.js.map +1 -0
  166. package/dist/processors/flat-link-rewrite.d.ts +32 -0
  167. package/dist/processors/flat-link-rewrite.d.ts.map +1 -0
  168. package/dist/processors/flat-link-rewrite.js +90 -0
  169. package/dist/processors/flat-link-rewrite.js.map +1 -0
  170. package/dist/processors/glossary-force-placeholders.d.ts +12 -0
  171. package/dist/processors/glossary-force-placeholders.d.ts.map +1 -0
  172. package/dist/processors/glossary-force-placeholders.js +58 -0
  173. package/dist/processors/glossary-force-placeholders.js.map +1 -0
  174. package/dist/processors/inline-code-placeholders.d.ts +11 -0
  175. package/dist/processors/inline-code-placeholders.d.ts.map +1 -0
  176. package/dist/processors/inline-code-placeholders.js +87 -0
  177. package/dist/processors/inline-code-placeholders.js.map +1 -0
  178. package/dist/processors/placeholder-handler.d.ts +38 -0
  179. package/dist/processors/placeholder-handler.d.ts.map +1 -0
  180. package/dist/processors/placeholder-handler.js +55 -0
  181. package/dist/processors/placeholder-handler.js.map +1 -0
  182. package/dist/processors/translation-placeholder-leaks.d.ts +2 -0
  183. package/dist/processors/translation-placeholder-leaks.d.ts.map +1 -0
  184. package/dist/processors/translation-placeholder-leaks.js +9 -0
  185. package/dist/processors/translation-placeholder-leaks.js.map +1 -0
  186. package/dist/processors/url-placeholders.d.ts +10 -0
  187. package/dist/processors/url-placeholders.d.ts.map +1 -0
  188. package/dist/processors/url-placeholders.js +29 -0
  189. package/dist/processors/url-placeholders.js.map +1 -0
  190. package/dist/processors/validator.d.ts +23 -0
  191. package/dist/processors/validator.d.ts.map +1 -0
  192. package/dist/processors/validator.js +186 -0
  193. package/dist/processors/validator.js.map +1 -0
  194. package/dist/runtime/i18next-helpers.d.ts +146 -0
  195. package/dist/runtime/i18next-helpers.d.ts.map +1 -0
  196. package/dist/runtime/i18next-helpers.js +192 -0
  197. package/dist/runtime/i18next-helpers.js.map +1 -0
  198. package/dist/runtime/index.d.ts +4 -0
  199. package/dist/runtime/index.d.ts.map +1 -0
  200. package/dist/runtime/index.js +4 -0
  201. package/dist/runtime/index.js.map +1 -0
  202. package/dist/runtime/template.d.ts +21 -0
  203. package/dist/runtime/template.d.ts.map +1 -0
  204. package/dist/runtime/template.js +28 -0
  205. package/dist/runtime/template.js.map +1 -0
  206. package/dist/runtime/ui-language-display.d.ts +16 -0
  207. package/dist/runtime/ui-language-display.d.ts.map +1 -0
  208. package/dist/runtime/ui-language-display.js +26 -0
  209. package/dist/runtime/ui-language-display.js.map +1 -0
  210. package/dist/server/translation-editor.d.ts +25 -0
  211. package/dist/server/translation-editor.d.ts.map +1 -0
  212. package/dist/server/translation-editor.js +583 -0
  213. package/dist/server/translation-editor.js.map +1 -0
  214. package/dist/utils/concurrency.d.ts +31 -0
  215. package/dist/utils/concurrency.d.ts.map +1 -0
  216. package/dist/utils/concurrency.js +103 -0
  217. package/dist/utils/concurrency.js.map +1 -0
  218. package/dist/utils/hash.d.ts +5 -0
  219. package/dist/utils/hash.d.ts.map +1 -0
  220. package/dist/utils/hash.js +9 -0
  221. package/dist/utils/hash.js.map +1 -0
  222. package/dist/utils/ignore-parser.d.ts +7 -0
  223. package/dist/utils/ignore-parser.d.ts.map +1 -0
  224. package/dist/utils/ignore-parser.js +26 -0
  225. package/dist/utils/ignore-parser.js.map +1 -0
  226. package/dist/utils/logger.d.ts +45 -0
  227. package/dist/utils/logger.d.ts.map +1 -0
  228. package/dist/utils/logger.js +158 -0
  229. package/dist/utils/logger.js.map +1 -0
  230. package/docs/GETTING_STARTED.md +697 -0
  231. package/docs/PACKAGE_OVERVIEW.md +427 -0
  232. package/docs/ai-i18n-tools-context.md +481 -0
  233. package/package.json +117 -0
  234. package/translated-docs/README.de.md +157 -0
  235. package/translated-docs/README.es.md +157 -0
  236. package/translated-docs/README.fr.md +157 -0
  237. package/translated-docs/README.hi.md +157 -0
  238. package/translated-docs/README.ja.md +157 -0
  239. package/translated-docs/README.ko.md +157 -0
  240. package/translated-docs/README.pt-BR.md +157 -0
  241. package/translated-docs/README.zh-CN.md +157 -0
  242. package/translated-docs/README.zh-TW.md +157 -0
  243. package/translated-docs/docs/GETTING_STARTED.de.md +682 -0
  244. package/translated-docs/docs/GETTING_STARTED.es.md +682 -0
  245. package/translated-docs/docs/GETTING_STARTED.fr.md +682 -0
  246. package/translated-docs/docs/GETTING_STARTED.hi.md +682 -0
  247. package/translated-docs/docs/GETTING_STARTED.ja.md +682 -0
  248. package/translated-docs/docs/GETTING_STARTED.ko.md +682 -0
  249. package/translated-docs/docs/GETTING_STARTED.pt-BR.md +682 -0
  250. package/translated-docs/docs/GETTING_STARTED.zh-CN.md +682 -0
  251. package/translated-docs/docs/GETTING_STARTED.zh-TW.md +682 -0
  252. package/translated-docs/docs/PACKAGE_OVERVIEW.de.md +428 -0
  253. package/translated-docs/docs/PACKAGE_OVERVIEW.es.md +428 -0
  254. package/translated-docs/docs/PACKAGE_OVERVIEW.fr.md +428 -0
  255. package/translated-docs/docs/PACKAGE_OVERVIEW.hi.md +428 -0
  256. package/translated-docs/docs/PACKAGE_OVERVIEW.ja.md +428 -0
  257. package/translated-docs/docs/PACKAGE_OVERVIEW.ko.md +428 -0
  258. package/translated-docs/docs/PACKAGE_OVERVIEW.pt-BR.md +428 -0
  259. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-CN.md +428 -0
  260. package/translated-docs/docs/PACKAGE_OVERVIEW.zh-TW.md +428 -0
@@ -0,0 +1,682 @@
1
+ # ai-i18n-tools: 入門指南
2
+
3
+ `ai-i18n-tools` 提供兩個獨立的可組合工作流程:
4
+
5
+ - **Workflow 1 - UI 翻譯**:從任何 JS/TS 原始碼中提取 `t("…")` 呼叫,透過 OpenRouter 進行翻譯,並寫入扁平的每種語言 JSON 檔案,以供 i18next 使用。
6
+ - **Workflow 2 - 文件翻譯**:將 markdown(MDX)和 Docusaurus JSON 標籤檔案翻譯成任意數量的語系,並具備智慧快取功能。**SVG** 資產使用 `features.translateSVG`、頂層的 `svg` 區塊,以及 `translate-svg`(參見 [CLI 參考](#cli-reference))。
7
+
8
+ 這兩個工作流程都使用 OpenRouter(任何兼容的 LLM)並共享一個配置文件。
9
+
10
+ <small>**以其他語言閱讀:**</small>
11
+
12
+ <small id="lang-list">[en-GB](../../docs/GETTING_STARTED.md) · [de](./GETTING_STARTED.de.md) · [es](./GETTING_STARTED.es.md) · [fr](./GETTING_STARTED.fr.md) · [hi](./GETTING_STARTED.hi.md) · [ja](./GETTING_STARTED.ja.md) · [ko](./GETTING_STARTED.ko.md) · [pt-BR](./GETTING_STARTED.pt-BR.md) · [zh-CN](./GETTING_STARTED.zh-CN.md) · [zh-TW](./GETTING_STARTED.zh-TW.md)</small>
13
+
14
+ ---
15
+
16
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
17
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
18
+ **目錄**
19
+
20
+ - [安裝](#installation)
21
+ - [快速開始](#quick-start)
22
+ - [工作流程 1 - UI 翻譯](#workflow-1---ui-translation)
23
+ - [步驟 1:初始化](#step-1-initialise)
24
+ - [步驟 2:提取字串](#step-2-extract-strings)
25
+ - [步驟 3:翻譯 UI 字串](#step-3-translate-ui-strings)
26
+ - [匯出為 XLIFF 2.0(可選)](#exporting-to-xliff-20-optional)
27
+ - [步驟 4:在執行階段連結 i18next](#step-4-wire-i18next-at-runtime)
28
+ - [在原始碼中使用 `t()`](#using-t-in-source-code)
29
+ - [插值](#interpolation)
30
+ - [語言切換 UI](#language-switcher-ui)
31
+ - [RTL 語言](#rtl-languages)
32
+ - [工作流程 2 - 文件翻譯](#workflow-2---document-translation)
33
+ - [步驟 1:初始化](#step-1-initialise-1)
34
+ - [步驟 2:翻譯文件](#step-2-translate-documents)
35
+ - [快取行為與 `translate-docs` 標記](#cache-behaviour-and-translate-docs-flags)
36
+ - [輸出佈局](#output-layouts)
37
+ - [合併工作流程(UI + 文件)](#combined-workflow-ui--docs)
38
+ - [設定參考](#configuration-reference)
39
+ - [`sourceLocale`](#sourcelocale)
40
+ - [`targetLocales`](#targetlocales)
41
+ - [`uiLanguagesPath`(可選)](#uilanguagespath-optional)
42
+ - [`concurrency`(可選)](#concurrency-optional)
43
+ - [`batchConcurrency`(可選)](#batchconcurrency-optional)
44
+ - [`batchSize` / `maxBatchChars`(可選)](#batchsize--maxbatchchars-optional)
45
+ - [`openrouter`](#openrouter)
46
+ - [`features`](#features)
47
+ - [`ui`](#ui)
48
+ - [`cacheDir`](#cachedir)
49
+ - [`documentations`](#documentations)
50
+ - [`svg`(可選)](#svg-optional)
51
+ - [`glossary`](#glossary)
52
+ - [CLI 參考](#cli-reference)
53
+ - [環境變數](#environment-variables)
54
+
55
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
56
+
57
+ ## 安裝
58
+
59
+ 發布的包是 **僅限 ESM**。在 Node.js 或您的打包工具中使用 `import`/`import()`;**請勿使用 `require('ai-i18n-tools')`。**
60
+
61
+ ```bash
62
+ npm install ai-i18n-tools
63
+ # or
64
+ pnpm add ai-i18n-tools
65
+ # or
66
+ yarn add ai-i18n-tools
67
+ ```
68
+
69
+ 設定您的 OpenRouter API 金鑰:
70
+
71
+ ```bash
72
+ export OPENROUTER_API_KEY=sk-or-v1-your-key-here
73
+ ```
74
+
75
+ 或者在項目根目錄中創建一個 `.env` 文件:
76
+
77
+ ```env
78
+ OPENROUTER_API_KEY=sk-or-v1-your-key-here
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 快速開始
84
+
85
+ 默認的 `init` 模板(`ui-markdown`)僅啟用 **UI** 提取和翻譯。`ui-docusaurus` 模板啟用 **文檔** 翻譯(`translate-docs`)。當您希望使用一個命令運行提取、UI 翻譯、可選的獨立 SVG 翻譯和根據您的配置進行文檔翻譯時,請使用 `sync`。
86
+
87
+ ```bash
88
+ # Workflow 1 - UI strings (default template enables extract + translate-ui)
89
+ npx ai-i18n-tools init
90
+ npx ai-i18n-tools extract
91
+ npx ai-i18n-tools translate-ui
92
+
93
+ # Workflow 2 - docs (Docusaurus-oriented template)
94
+ npx ai-i18n-tools init -t ui-docusaurus
95
+ npx ai-i18n-tools translate-docs
96
+
97
+ # Combined: extract UI strings, then translate UI + SVG + docs (per config features)
98
+ npx ai-i18n-tools sync
99
+
100
+ # Markdown translation status (per file × locale)
101
+ npx ai-i18n-tools status
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 工作流程 1 - UI 翻譯
107
+
108
+ 設計用於任何使用 i18next 的 JS/TS 項目:React 應用、Next.js(客戶端和服務器組件)、Node.js 服務、CLI 工具。
109
+
110
+ ### 步驟 1:初始化
111
+
112
+ ```bash
113
+ npx ai-i18n-tools init
114
+ ```
115
+
116
+ 這將使用 `ui-markdown` 模板寫入 `ai-i18n-tools.config.json`。編輯它以設置:
117
+
118
+ - `sourceLocale` - 您的來源語言 BCP-47 代碼(例如 `"en-GB"`)。**必須符合**從執行階段 i18n 設定檔(`src/i18n.ts` / `src/i18n.js`)匯出的 `SOURCE_LOCALE`。
119
+ - `targetLocales` - 您的 `ui-languages.json` 資訊清單路徑,或 BCP-47 代碼陣列。
120
+ - `ui.sourceRoots` - 要掃描 `t("…")` 呼叫的目錄(例如 `["src/"]`)。
121
+ - `ui.stringsJson` - 寫入主目錄的位置(例如 `"src/locales/strings.json"`)。
122
+ - `ui.flatOutputDir` - 寫入 `de.json`、`pt-BR.json` 等檔案的位置(例如 `"src/locales/"`)。
123
+ - `ui.preferredModel`(選用)- 僅供 `translate-ui` **優先**嘗試的 OpenRouter 模型 ID;若失敗,CLI 會依序繼續使用 `openrouter.translationModels`(或舊版的 `defaultModel` / `fallbackModel`),並跳過重複項目。
124
+
125
+ ### 步驟 2:擷取字串
126
+
127
+ ```bash
128
+ npx ai-i18n-tools extract
129
+ ```
130
+
131
+ 掃描 `ui.sourceRoots` 下的所有 JS/TS 檔案,尋找 `t("literal")` 和 `i18n.t("literal")` 呼叫。將結果寫入(或合併至)`ui.stringsJson`。
132
+
133
+ 掃描器可進行設定:可透過 `ui.reactExtractor.funcNames` 新增自訂函式名稱。
134
+
135
+ ### 步驟 3:翻譯 UI 字串
136
+
137
+ ```bash
138
+ npx ai-i18n-tools translate-ui
139
+ ```
140
+
141
+ 讀取 `strings.json`,針對每個目標語言批次傳送至 OpenRouter,並將扁平 JSON 檔案(`de.json`、`fr.json` 等)寫入 `ui.flatOutputDir`。當設定 `ui.preferredModel` 時,會優先嘗試該模型,然後才依序使用 `openrouter.translationModels` 中的清單(文件翻譯與其他指令仍僅使用 `openrouter`)。
142
+
143
+ 對於每個條目,`translate-ui` 在可選的 `models` 對象中存儲成功翻譯每個語言的 **OpenRouter 模型 ID**(與 `translated` 相同的語言鍵)。在本地 `editor` 命令中編輯的字符串在該語言的 `models` 中標記為哨兵值 `user-edited`。位於 `ui.flatOutputDir` 下的每個語言的平面文件僅保留 **源字符串 → 翻譯**;它們不包括 `models`(因此運行時包保持不變)。
144
+
145
+ > **使用快取編輯器的注意事項:** 若在快取編輯器中編輯項目,您必須執行 `sync --force-update`(或等效的 `translate` 指令加上 `--force-update`),才能以更新後的快取項目覆寫輸出檔案。此外請注意,若日後來源文字發生變更,您的手動編輯將會遺失,因為系統會為新的來源字串產生新的快取金鑰(雜湊值)。
146
+
147
+ ### 匯出為 XLIFF 2.0(可選)
148
+
149
+ 若要將 UI 字串交給翻譯供應商、TMS 或 CAT 工具,可將目錄匯出為 **XLIFF 2.0** 格式(每個目標語系一個檔案)。此指令為 **唯讀**:不會修改 `strings.json` 或呼叫任何 API。
150
+
151
+ ```bash
152
+ npx ai-i18n-tools export-ui-xliff
153
+ ```
154
+
155
+ 預設情況下,檔案會寫入 `ui.stringsJson` 旁邊,命名方式如 `strings.de.xliff`、`strings.pt-BR.xliff`(您的目錄檔名 + 語系 + `.xliff`)。使用 `-o` / `--output-dir` 可指定其他輸出位置。來自 `strings.json` 的現有翻譯會出現在 `<target>` 中;缺少的語系則使用 `state="initial"` 且不含 `<target>`,以便工具填入內容。使用 `--untranslated-only` 可僅匯出每個語系尚待翻譯的項目(適用於供應商批次作業)。`--dry-run` 則僅列印路徑而不寫入檔案。
156
+
157
+ ### 步驟 4:在執行階段串接 i18next
158
+
159
+ 使用 `'ai-i18n-tools/runtime'` 匯出的輔助工具建立您的 i18n 設定檔:
160
+
161
+ ```js
162
+ // src/i18n.js (or src/i18n.ts)
163
+ import i18n from 'i18next';
164
+ import { initReactI18next } from 'react-i18next';
165
+ import uiLanguages from './locales/ui-languages.json';
166
+ import {
167
+ defaultI18nInitOptions,
168
+ wrapI18nWithKeyTrim,
169
+ makeLoadLocale,
170
+ applyDirection,
171
+ } from 'ai-i18n-tools/runtime';
172
+
173
+ // Must match sourceLocale in ai-i18n-tools.config.json
174
+ export const SOURCE_LOCALE = 'en-GB';
175
+
176
+ void i18n.use(initReactI18next).init(defaultI18nInitOptions(SOURCE_LOCALE));
177
+ wrapI18nWithKeyTrim(i18n);
178
+ i18n.on('languageChanged', applyDirection);
179
+ applyDirection(i18n.language);
180
+
181
+ const localeLoaders = Object.fromEntries(
182
+ uiLanguages
183
+ .filter(({ code }) => code !== SOURCE_LOCALE)
184
+ .map(({ code }) => [code, () => import(`./locales/${code}.json`)])
185
+ );
186
+
187
+ export const loadLocale = makeLoadLocale(i18n, localeLoaders, SOURCE_LOCALE);
188
+ export default i18n;
189
+ ```
190
+
191
+ 在 React 渲染前匯入 `i18n.js`(例如在進入點檔案的最上方)。當使用者變更語言時,呼叫 `await loadLocale(code)`,接著呼叫 `i18n.changeLanguage(code)`。
192
+
193
+ `SOURCE_LOCALE` 已匯出,因此任何其他需要它的檔案(例如語言切換器)都可以直接從 `'./i18n'` 匯入。
194
+
195
+ `defaultI18nInitOptions(sourceLocale)` 返回鍵作為默認設置的標準選項:
196
+
197
+ - `parseMissingKeyHandler` 會回傳金鑰本身,因此未翻譯的字串會顯示來源文字。
198
+ - `nsSeparator: false` 允許金鑰包含冒號。
199
+ - `interpolation.escapeValue: false` - 可安全停用:React 會自行跳脫值,且 Node.js/CLI 輸出沒有需要跳脫的 HTML。
200
+
201
+ `wrapI18nWithKeyTrim(i18n)` 將 `i18n.t` 包裝為: (1) 在查找之前修剪鍵,與提取腳本存儲它們的方式相匹配; (2) 當源語言返回原始鍵時,應用 <code>{"{{var}}"}</code> 插值 - 因此 <code>{"t('Hello {{name}}', { name })"}</code> 即使對於源語言也能正確工作。
202
+
203
+ `makeLoadLocale(i18n, loaders, sourceLocale)` 返回一個異步的 `loadLocale(lang)` 函數,該函數動態導入某個語言的 JSON 包並將其註冊到 i18next。
204
+
205
+ ### 在原始碼中使用 `t()`
206
+
207
+ 使用**字面字串**呼叫 `t()`,以便擷取指令碼能夠找到它:
208
+
209
+ ```jsx
210
+ import { useTranslation } from 'react-i18next';
211
+
212
+ function MyComponent() {
213
+ const { t } = useTranslation();
214
+ return <button>{t('Save')}</button>;
215
+ }
216
+ ```
217
+
218
+ 相同的模式也適用於 React 之外(Node.js、伺服器元件、CLI):
219
+
220
+ ```js
221
+ import i18n from './i18n.js';
222
+ console.log(i18n.t('Processing complete'));
223
+ ```
224
+
225
+ **規則:**
226
+
227
+ - 只有這些形式會被提取:`t("…")`、`t('…')`、`t(`…`)`、`i18n.t("…")`。
228
+ - 鍵必須是**字面字符串** - 鍵不能是變量或表達式。
229
+ - 不要使用模板字面量作為鍵:<code>{'t(`Hello ${name}`)'}</code> 無法提取。
230
+
231
+ ### 插值
232
+
233
+ 使用 i18next 的原生第二個參數插值來處理 <code>{"{{var}}"}</code> 佔位符:
234
+
235
+ ```js
236
+ // i18next handles substitution natively, even in key-as-default mode
237
+ t('Hello {{name}}, you have {{count}} messages', { name, count })
238
+ // → "Hello Alice, you have 3 messages"
239
+ ```
240
+
241
+ 提取腳本會忽略第二個參數 - 只有字面鍵字符串 <code>{"\"Hello {{name}}, you have {{count}} messages\""}</code> 會被提取並發送進行翻譯。翻譯者被指示保留 <code>{"{{...}}"}</code> 令牌。
242
+
243
+ ### 語言切換器 UI
244
+
245
+ 使用 `ui-languages.json` 清單來構建語言選擇器。`ai-i18n-tools` 導出兩個顯示幫助器:
246
+
247
+ ```tsx
248
+ import { useMemo } from 'react';
249
+ import { useTranslation } from 'react-i18next';
250
+ import {
251
+ getUILanguageLabel,
252
+ getUILanguageLabelNative,
253
+ type UiLanguageEntry,
254
+ } from 'ai-i18n-tools/runtime';
255
+ import uiLanguages from './locales/ui-languages.json';
256
+ import { loadLocale } from './i18n';
257
+
258
+ function LanguageSelect({
259
+ value,
260
+ onChange,
261
+ }: {
262
+ value: string;
263
+ onChange: (code: string) => void;
264
+ }) {
265
+ const { t, i18n } = useTranslation();
266
+
267
+ const options = useMemo(
268
+ () =>
269
+ (uiLanguages as UiLanguageEntry[]).map((lang) => ({
270
+ code: lang.code,
271
+ // Settings/content dropdowns: shows translated name when available
272
+ label: getUILanguageLabel(lang, t),
273
+ // Header globe menu: shows "English / Deutsch"-style label, no t() call
274
+ nativeLabel: getUILanguageLabelNative(lang),
275
+ })),
276
+ [t]
277
+ );
278
+
279
+ const handleChange = async (code: string) => {
280
+ await loadLocale(code);
281
+ i18n.changeLanguage(code);
282
+ onChange(code);
283
+ };
284
+
285
+ return (
286
+ <select value={value} onChange={(e) => handleChange(e.target.value)}>
287
+ {options.map((row) => (
288
+ <option key={row.code} value={row.code}>
289
+ {row.label}
290
+ </option>
291
+ ))}
292
+ </select>
293
+ );
294
+ }
295
+ ```
296
+
297
+ `getUILanguageLabel(lang, t)` - 當翻譯時顯示 `t(englishName)`,或者當兩者不同時顯示 `englishName / t(englishName)`。適合設置屏幕。
298
+
299
+ `getUILanguageLabelNative(lang)` - 顯示 `englishName / label`(每行不調用 `t()`)。適合標題菜單,您希望顯示本地名稱。
300
+
301
+ `ui-languages.json` 清單是一個 JSON 陣列,包含 <code>{"{ code, label, englishName }"}</code> 條目。示例:
302
+
303
+ ```json
304
+ [
305
+ { "code": "en-GB", "label": "English (UK)", "englishName": "English (UK)" },
306
+ { "code": "pt-BR", "label": "Português (BR)", "englishName": "Portuguese (BR)" },
307
+ { "code": "de", "label": "Deutsch", "englishName": "German" },
308
+ { "code": "fr", "label": "Français", "englishName": "French" },
309
+ { "code": "ar", "label": "العربية", "englishName": "Arabic" }
310
+ ]
311
+ ```
312
+
313
+ 在配置中設置 `targetLocales` 為此文件的路徑,以便翻譯命令使用相同的列表。
314
+
315
+ ### RTL 語言
316
+
317
+ `ai-i18n-tools` 導出 `getTextDirection(lng)` 和 `applyDirection(lng)`:
318
+
319
+ ```js
320
+ import { getTextDirection, applyDirection } from 'ai-i18n-tools/runtime';
321
+
322
+ getTextDirection('ar') // 'rtl'
323
+ getTextDirection('en-GB') // 'ltr'
324
+
325
+ // Applied automatically via i18n.on('languageChanged', applyDirection) - see Step 4
326
+ ```
327
+
328
+ `applyDirection` 設置 `document.documentElement.dir`(瀏覽器)或在 Node.js 中為無操作。傳遞可選的 `element` 參數以針對特定元素。
329
+
330
+ 對於可能包含 `→` 箭頭的字符串,將其翻轉以適應 RTL 佈局:
331
+
332
+ ```js
333
+ import { flipUiArrowsForRtl } from 'ai-i18n-tools/runtime';
334
+ const { i18n } = useTranslation();
335
+ const isRtl = getTextDirection(i18n.language) === 'rtl';
336
+ const label = flipUiArrowsForRtl(t('Next → Step'), isRtl);
337
+ ```
338
+
339
+ ---
340
+
341
+ ## 工作流程 2 - 文檔翻譯
342
+
343
+ 專為 markdown 文件、Docusaurus 網站和 JSON 標籤檔案設計。當啟用 `features.translateSVG` 且設定頂層 `svg` 區塊時,獨立的 SVG 資產會透過 [`translate-svg`](#cli-reference) 進行翻譯——而不是透過 `documentations[].contentPaths`。
344
+
345
+ ### 步驟 1:初始化
346
+
347
+ ```bash
348
+ npx ai-i18n-tools init -t ui-docusaurus
349
+ ```
350
+
351
+ 編輯生成的 `ai-i18n-tools.config.json`:
352
+
353
+ - `sourceLocale` - 原始語言(必須與 `docusaurus.config.js` 中的 `defaultLocale` 相符)。
354
+ - `targetLocales` - 目標語系代碼陣列,或指向清單的路徑。
355
+ - `cacheDir` - 所有文件管道共用的 SQLite 快取目錄(也是 `--write-logs` 的預設記錄目錄)。
356
+ - `documentations` - 文件區塊的陣列。每個區塊包含可選的 `description`、`contentPaths`、`outputDir`、可選的 `jsonSource`、`markdownOutput`、`targetLocales`、`addFrontmatter` 等。
357
+ - `documentations[].description` - 維護人員的可選簡短註解(說明此區塊涵蓋的內容)。設定時,會出現在 `translate-docs` 的標題(`🌐 …: translating …`)以及 `status` 區段的標題中。
358
+ - `documentations[].contentPaths` - Markdown/MDX 原始檔案目錄或檔案(另請參閱 `documentations[].jsonSource` 以取得 JSON 標籤)。
359
+ - `documentations[].outputDir` - 該區塊的翻譯輸出根目錄。
360
+ - `documentations[].markdownOutput.style` - `"nested"`(預設)、`"docusaurus"` 或 `"flat"`(參見 [輸出佈局](#output-layouts))。
361
+
362
+ ### 步驟 2:翻譯文檔
363
+
364
+ ```bash
365
+ npx ai-i18n-tools translate-docs
366
+ ```
367
+
368
+ 這會將每個 `documentations` 區塊的 `contentPaths` 中的所有文件翻譯成所有有效的文檔語言(當設置時,每個區塊的 `targetLocales` 的聯合,否則為根 `targetLocales`)。已翻譯的段落將從 SQLite 緩存中提供 - 只有新的或更改過的段落會發送到 LLM。
369
+
370
+ 要翻譯單一語言:
371
+
372
+ ```bash
373
+ npx ai-i18n-tools translate-docs --locale de
374
+ ```
375
+
376
+ 要檢查需要翻譯的內容:
377
+
378
+ ```bash
379
+ npx ai-i18n-tools status
380
+ ```
381
+
382
+ #### 緩存行為和 `translate-docs` 標誌
383
+
384
+ CLI 在 SQLite 中保持 **文件跟踪**(每個文件 × 語言的源哈希)和 **段落** 行(可翻譯塊的哈希 × 語言)。正常運行時,當跟踪的哈希與當前源 **匹配** 且輸出文件已存在時,會完全跳過該文件;否則,它會處理該文件並使用段落緩存,以便未更改的文本不會調用 API。
385
+
386
+ | 標誌 | 效果 |
387
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
388
+ | *(默認)* | 在跟蹤 + 磁碟輸出匹配時跳過未更改的文件;對其餘部分使用段緩存。 |
389
+ | `--force-update` | 重新處理每個匹配的文件(提取、重新組裝、寫入輸出),即使文件跟蹤會跳過。 **段緩存仍然適用** - 未更改的段不會發送到 LLM。 |
390
+ | `--force` | 清除每個處理文件的文件跟蹤,並且 **不讀取** API 翻譯的段緩存(完全重新翻譯)。新結果仍然 **寫入** 段緩存。 |
391
+ | `--stats` | 打印段計數、跟蹤的文件計數和每個語言的段總數,然後退出。 |
392
+ | `--clear-cache [locale]` | 刪除緩存的翻譯(和文件跟蹤):所有語言或單一語言,然後退出。 |
393
+ | `--prompt-format <mode>` | 每個 **批次** 的段如何發送到模型並解析(`xml`、`json-array` 或 `json-object`)。默認為 **`xml`**。不改變提取、佔位符、驗證、緩存或回退行為 — 請參見 [批次提示格式](#batch-prompt-format)。 |
394
+
395
+ 您不能將 `--force` 與 `--force-update` 結合使用(它們是互斥的)。
396
+
397
+ #### 批次提示格式
398
+
399
+ `translate-docs` 將可翻譯的段發送到 OpenRouter 中的 **批次**(按 `batchSize` / `maxBatchChars` 分組)。 **`--prompt-format`** 標誌僅改變該批次的 **傳輸格式**;段拆分、`PlaceholderHandler` 令牌、markdown AST 檢查、SQLite 緩存鍵和當批次解析失敗時的每段回退保持不變。
400
+
401
+ | 模式 | 用戶消息 | 模型回覆 |
402
+ | ---- | ------------ | ----------- |
403
+ | **`xml`** (預設) | 偽 XML:每個段落一個 `<seg id="N">…</seg>`(帶有 XML 轉義)。 | 只有 `<t id="N">…</t>` 區塊,每個段落索引一個。 |
404
+ | **`json-array`** | 一個字符串的 JSON 陣列,按順序每個段落一個條目。 | 一個相同長度的 JSON 陣列 **(相同順序)**。 |
405
+ | **`json-object`** | 一個 JSON 對象 `{"0":"…","1":"…",…}`,以段落索引為鍵。 | 一個具有 **相同鍵** 和翻譯值的 JSON 對象。 |
406
+
407
+ 運行標頭還會打印 `Batch prompt format: …`,以便您確認當前模式。JSON 標籤文件(`jsonSource`)和獨立的 SVG 批次在這些步驟作為 `translate-docs`(或 `sync` 的文檔階段 — `sync` 不會暴露此標誌;默認為 **`xml`**)運行時使用相同的設置。
408
+
409
+ **段落去重和 SQLite 中的路徑**
410
+
411
+ - 段落行按 `(source_hash, locale)` 全局鍵入(hash = 正規化內容)。兩個文件中的相同文本共享一行;`translations.filepath` 是元數據(最後寫入者),而不是每個文件的第二個緩存條目。
412
+ - `file_tracking.filepath` 使用命名空間鍵:每個 `documentations` 區塊的 `doc-block:{index}:{relPath}`(`relPath` 是相對於項目根目錄的 posix:收集的 markdown 路徑;**JSON 標籤文件使用相對於當前工作目錄的源文件路徑**,例如 `docs-site/i18n/en/code.json`,因此清理可以解析實際文件),以及 `svg-assets:{relPath}` 用於 `translate-svg` 下的獨立 SVG 資產。
413
+ - `translations.filepath` 存儲 markdown、JSON 和 SVG 段的相對於當前工作目錄的 posix 路徑(SVG 使用與其他資產相同的路徑形狀;`svg-assets:…` 前綴 **僅** 在 `file_tracking` 上)。
414
+ - 運行後,`last_hit_at` 只會清除在相同翻譯範圍內的段落行 **(遵循 `--path` 和啟用的類型)**,這些行未被命中,因此過濾或僅文檔的運行不會將不相關的文件標記為過期。
415
+
416
+ ### 輸出佈局
417
+
418
+ `"nested"`(省略時的預設) — 在 `{outputDir}/{locale}/` 下鏡像源樹(例如 `docs/guide.md` → `i18n/de/docs/guide.md`)。
419
+
420
+ `"docusaurus"` — 將位於 `docsRoot` 下的文件放置在 `i18n/<locale>/docusaurus-plugin-content-docs/current/<relativeToDocsRoot>`,匹配通常的 Docusaurus i18n 佈局。將 `documentations[].markdownOutput.docsRoot` 設置為您的文檔源根目錄(例如 `"docs"`)。
421
+
422
+ ```
423
+ docs/guide.md → i18n/de/docusaurus-plugin-content-docs/current/guide.md
424
+ i18n/en/sidebar.json → i18n/de/sidebar.json (JSON label files)
425
+ ```
426
+
427
+ `"flat"` - 將翻譯文件放置在源旁邊,並帶有語言後綴,或在子目錄中。頁面之間的相對鏈接會自動重寫。
428
+
429
+ ```
430
+ docs/guide.md → i18n/guide.de.md
431
+ ```
432
+
433
+ 您可以完全覆蓋路徑,使用 `documentations[].markdownOutput.pathTemplate`。佔位符:<code>{"{outputDir}"}</code>,<code>{"{locale}"}</code>,<code>{"{LOCALE}"}</code>,<code>{"{relPath}"}</code>,<code>{"{stem}"}</code>,<code>{"{basename}"}</code>,<code>{"{extension}"}</code>,<code>{"{docsRoot}"}</code>,<code>{"{relativeToDocsRoot}"}</code>。
434
+
435
+ ---
436
+
437
+ ## 結合工作流程 (UI + 文檔)
438
+
439
+ 在單一配置中啟用所有功能,以便同時運行兩個工作流程:
440
+
441
+ ```json
442
+ {
443
+ "sourceLocale": "en-GB",
444
+ "targetLocales": "src/locales/ui-languages.json",
445
+ "features": {
446
+ "extractUIStrings": true,
447
+ "translateUIStrings": true,
448
+ "translateMarkdown": true,
449
+ "translateJSON": false,
450
+ "translateSVG": false
451
+ },
452
+ "glossary": {
453
+ "uiGlossary": "src/locales/strings.json",
454
+ "userGlossary": "glossary-user.csv"
455
+ },
456
+ "ui": {
457
+ "sourceRoots": ["src/"],
458
+ "stringsJson": "src/locales/strings.json",
459
+ "flatOutputDir": "src/locales/"
460
+ },
461
+ "cacheDir": ".translation-cache",
462
+ "documentations": [
463
+ {
464
+ "contentPaths": ["docs/"],
465
+ "outputDir": "i18n/",
466
+ "markdownOutput": { "style": "flat" }
467
+ }
468
+ ]
469
+ }
470
+ ```
471
+
472
+ `glossary.uiGlossary` 將文檔翻譯指向與 UI 相同的 `strings.json` 目錄,以保持術語的一致性;`glossary.userGlossary` 為產品術語添加 CSV 覆蓋。
473
+
474
+ 執行 `npx ai-i18n-tools sync` 來運行一個管線:**提取** UI 字串(若設定 `features.extractUIStrings`),**翻譯 UI** 字串(若設定 `features.translateUIStrings`),**翻譯獨立 SVG 資產**(若設定 `features.translateSVG` 且有 `svg` 區塊),然後 **翻譯文件**(每個 `documentations` 區塊:依設定處理 markdown/JSON)。可使用 `--no-ui`、`--no-svg` 或 `--no-docs` 跳過部分步驟。文件步驟接受 `--dry-run`、`-p` / `--path`、`--force` 和 `--force-update`(後兩個僅在執行文件翻譯時有效;若傳入 `--no-docs` 則會被忽略)。
475
+
476
+ 在區塊上使用 `documentations[].targetLocales` 將該區塊的文件翻譯為比 UI 更**小的子集**(有效的文檔地區是區塊之間的**聯集**):
477
+
478
+ ```json
479
+ {
480
+ "targetLocales": "src/locales/ui-languages.json",
481
+ "documentations": [
482
+ {
483
+ "contentPaths": ["docs/"],
484
+ "outputDir": "i18n/",
485
+ "targetLocales": ["de", "fr", "es"]
486
+ }
487
+ ]
488
+ }
489
+ ```
490
+
491
+ ---
492
+
493
+ ## 配置參考
494
+
495
+ ### `sourceLocale`
496
+
497
+ 源語言的 BCP-47 代碼(例如 `"en-GB"`,`"en"`,`"pt-BR"`)。不會為此地區生成翻譯文件 - 鍵字符串本身就是源文本。
498
+
499
+ **必須匹配** 從您的運行時 i18n 設置文件(`src/i18n.ts` / `src/i18n.js`)導出的 `SOURCE_LOCALE`。
500
+
501
+ ### `targetLocales`
502
+
503
+ 要翻譯的地區。接受:
504
+
505
+ - **字符串路徑** 到 `ui-languages.json` 清單(`"src/locales/ui-languages.json"`)。該文件被加載並提取地區代碼。
506
+ - **BCP-47 代碼的數組**(`["de", "fr", "es"]`)。
507
+ - **帶路徑的單元素數組**(`["src/locales/ui-languages.json"]`) - 與字符串形式的行為相同。
508
+
509
+ `targetLocales` 是 UI 翻譯的主要地區列表,也是文檔區塊的默認地區列表。如果您希望在這裡保留明確的數組,但仍希望基於清單的標籤和地區過濾,還需設置 `uiLanguagesPath`。
510
+
511
+ ### `uiLanguagesPath`(可選)
512
+
513
+ 指向用於顯示名稱、地區過濾和語言列表後處理的 `ui-languages.json` 清單的路徑。
514
+
515
+ 當您需要這樣做時:
516
+
517
+ - `targetLocales` 是明確的數組,但您仍希望從清單中獲取英文/本地標籤。
518
+ - 您希望 `markdownOutput.postProcessing.languageListBlock` 從相同的清單中構建地區標籤。
519
+ - 只啟用 UI 翻譯,並希望清單提供有效的 UI 地區列表。
520
+
521
+ ### `concurrency`(可選)
522
+
523
+ 同時翻譯的最大**目標地區**(`translate-ui`,`translate-docs`,`translate-svg`,以及 `sync` 內部的匹配步驟)。如果省略,CLI 對於 UI 翻譯使用**4**,對於文檔翻譯使用**3**(內建默認值)。每次運行時可使用 `-j` / `--concurrency` 覆蓋。
524
+
525
+ ### `batchConcurrency`(可選)
526
+
527
+ **translate-docs** 與 **translate-svg**(以及 `sync` 的文件翻譯步驟):每個檔案的最大平行 OpenRouter **批次**請求數(每個批次可包含多個段落)。省略時預設為 **4**。`translate-ui` 會忽略此設定。可使用 `-b` / `--batch-concurrency` 覆寫。在 `sync` 上,`-b` 僅適用於文件翻譯步驟。
528
+
529
+ ### `batchSize` / `maxBatchChars`(可選)
530
+
531
+ 文件翻譯的段落批次處理:每個 API 請求包含多少段落,以及字元上限。預設值:**20** 個段落,**4096** 個字元(省略時)。
532
+
533
+ ### `openrouter`
534
+
535
+ | 字段 | 描述 |
536
+ | ------------------- | ---------------------------------------------------------------------------------------- |
537
+ | `baseUrl` | OpenRouter API 基本 URL。默認:`https://openrouter.ai/api/v1`。 |
538
+ | `translationModels` | 首選有序模型 ID 列表。第一個優先嘗試;後面的條目在出錯時作為後備。僅對 `translate-ui`**,您還可以設置 `ui.preferredModel` 在此列表之前嘗試一個模型(見 `ui`)。 |
539
+ | `defaultModel` | 遺留的單一主要模型。僅在 `translationModels` 未設置或為空時使用。 |
540
+ | `fallbackModel` | 遺留的單一後備模型。在 `translationModels` 未設置或為空時,在 `defaultModel` 之後使用。 |
541
+ | `maxTokens` | 每個請求的最大完成標記。默認:`8192`。 |
542
+ | `temperature` | 取樣溫度。默認:`0.2`。 |
543
+
544
+ 在您的環境或 `.env` 檔案中設定 `OPENROUTER_API_KEY`。
545
+
546
+ ### `features`
547
+
548
+ | 欄位 | 工作流程 | 說明 |
549
+ | -------------------- | -------- | ----------------------------------------------------------------- |
550
+ | `extractUIStrings` | 1 | 掃描原始碼中的 `t("…")` 並寫入/合併 `strings.json`。 |
551
+ | `translateUIStrings` | 1 | 翻譯 `strings.json` 條目並寫入每種語言的 JSON 檔案。 |
552
+ | `translateMarkdown` | 2 | 翻譯 `.md` / `.mdx` 檔案。 |
553
+ | `translateJSON` | 2 | 翻譯 Docusaurus JSON 標籤檔案。 |
554
+ | `translateSVG` | 2 | 翻譯獨立的 `.svg` 資產(需要頂層 `svg` 區塊)。 |
555
+
556
+ 當 `features.translateSVG` 為 true 且已設定頂層 `svg` 區塊時,使用 `translate-svg` 來翻譯 **獨立** 的 SVG 資產。`sync` 命令會在兩者皆設定時執行該步驟(除非使用 `--no-svg`)。
557
+
558
+ ### `ui`
559
+
560
+ | 欄位 | 說明 |
561
+ | --------------------------- | ----------------------------------------------------------------------- |
562
+ | `sourceRoots` | 搜尋 `t("…")` 呼叫的目錄(相對於目前工作目錄)。 |
563
+ | `stringsJson` | 主要目錄檔案的路徑。由 `extract` 更新。 |
564
+ | `flatOutputDir` | 每個語系的 JSON 檔案輸出目錄(例如 `de.json` 等)。 |
565
+ | `preferredModel` | 選填。僅針對 `translate-ui` 優先嘗試的 OpenRouter 模型 ID;若未成功,則依序嘗試 `openrouter.translationModels`(或舊版模型),且不重複此 ID。 |
566
+ | `reactExtractor.funcNames` | 額外要掃描的函式名稱(預設值:`["t", "i18n.t"]`)。 |
567
+ | `reactExtractor.extensions` | 要包含的檔案副檔名(預設值:`[".js", ".jsx", ".ts", ".tsx"]`)。 |
568
+ | `reactExtractor.includePackageDescription` | 當值為 `true`(預設值)時,若存在 `package.json`,`extract` 也會將其 `description` 包含為 UI 字串。 |
569
+ | `reactExtractor.packageJsonPath` | 用於提取該選用描述的自訂 `package.json` 檔案路徑。 |
570
+
571
+ ### `cacheDir`
572
+
573
+ | 欄位 | 描述 |
574
+ | ---------- | ----------------------------------------------------------------------------- |
575
+ | `cacheDir` | SQLite 快取目錄(由所有 `documentations` 區塊共用)。跨執行重複使用。 |
576
+
577
+ ### `documentations`
578
+
579
+ 文檔管道區塊的數組。`translate-docs` 和 `sync` 過程的文檔階段 **逐一** 處理每個區塊。
580
+
581
+ | 欄位 | 說明 |
582
+ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
583
+ | `description` | 此區塊的可選人類可讀備註(不供翻譯使用)。設定時會出現在 `translate-docs` 的 `🌐` 標題前;也會顯示在 `status` 區段的標頭中。 |
584
+ | `contentPaths` | 要翻譯的 Markdown/MDX 來源(`translate-docs` 會掃描這些路徑中的 `.md` / `.mdx` 檔案)。JSON 標籤來自此區塊上的 `jsonSource`。 |
585
+ | `outputDir` | 此區塊翻譯輸出的根目錄。 |
586
+ | `sourceFiles` | 可選的別名,載入時會合併至 `contentPaths`。 |
587
+ | `targetLocales` | 僅針對此區塊的可選語言子集(否則使用根層級的 `targetLocales`)。實際生效的文件語言是所有區塊的聯集。 |
588
+ | `jsonSource` | 此區塊的 Docusaurus JSON 標籤檔案來源目錄(例如 `"i18n/en"`)。 |
589
+ | `markdownOutput.style` | `"nested"`(預設)、`"docusaurus"` 或 `"flat"`。 |
590
+ | `markdownOutput.docsRoot` | Docusaurus 版面配置的原始文件根目錄(例如 `"docs"`)。 |
591
+ | `markdownOutput.pathTemplate` | 自訂 Markdown 輸出路徑。可用的佔位符: <code>{"{outputDir}"}</code>、<code>{"{locale}"}</code>、<code>{"{LOCALE}"}</code>、<code>{"{relPath}"}</code>、<code>{"{stem}"}</code>、<code>{"{basename}"}</code>、<code>{"{extension}"}</code>、<code>{"{docsRoot}"}</code>、<code>{"{relativeToDocsRoot}"}</code>。 |
592
+ | `markdownOutput.jsonPathTemplate` | 自訂 JSON 輸出路徑用於標籤檔案。支援與 `pathTemplate` 相同的佔位符。 |
593
+ | `markdownOutput.flatPreserveRelativeDir` | 對於 `flat` 風格,保留來源子目錄以避免同檔名檔案衝突。 |
594
+ | `markdownOutput.rewriteRelativeLinks` | 翻譯後重寫相對連結(`flat` 風格將自動啟用)。 |
595
+ | `markdownOutput.linkRewriteDocsRoot` | 計算扁平化連結重寫前綴時使用的儲存庫根目錄。除非你的翻譯文件位於不同的專案根目錄下,否則通常保留為 `"."`。 |
596
+ | `markdownOutput.postProcessing` | 對翻譯後的 Markdown **body** 進行可選的轉換(YAML front matter 會保留)。在片段重新組合與扁平化連結重寫之後、`addFrontmatter` 之前執行。 |
597
+ | `markdownOutput.postProcessing.regexAdjustments` | 有序的 `{ "description"?, "search", "replace" }` 清單。`search` 是正規表示式模式(純字串使用 `g` 標誌,或 `/pattern/flags`)。`replace` 支援諸如 `${translatedLocale}`、`${sourceLocale}`、`${sourceFullPath}`、`${translatedFullPath}`、`${sourceFilename}`、`${translatedFilename}`、`${sourceBasedir}`、`${translatedBasedir}` 等佔位符(概念與參考文檔中的 `additional-adjustments` 相同)。 |
598
+ | `markdownOutput.postProcessing.languageListBlock` | `{ "start", "end", "separator" }` — 翻譯器會尋找包含 `start` 的第一行與對應的 `end` 行,然後將該段落替換為標準的語言切換器。連結根據翻譯後檔案的相對路徑建立;標籤來自 `uiLanguagesPath` / `ui-languages.json`(若已設定),否則來自 `localeDisplayNames` 與 locale 代碼。 |
599
+ | `addFrontmatter` | 當為 `true` 時(省略時預設為 true),翻譯後的 Markdown 檔案會包含 YAML 欄位:`translation_last_updated`、`source_file_mtime`、`source_file_hash`、`translation_language`、`source_file_path`,以及當至少一個片段具有模型中繼資料時,包含 `translation_models`(使用的 OpenRouter 模型 ID 排序清單)。設為 `false` 可跳過。 |
600
+
601
+ 範例(平面 README 管道 — 截圖路徑 + 可選語言列表包裝):
602
+
603
+ ```json
604
+ "markdownOutput": {
605
+ "style": "flat",
606
+ "postProcessing": {
607
+ "regexAdjustments": [
608
+ {
609
+ "description": "Per-locale screenshot folders",
610
+ "search": "images/screenshots/[^/]+/",
611
+ "replace": "images/screenshots/${translatedLocale}/"
612
+ }
613
+ ],
614
+ "languageListBlock": {
615
+ "start": "<small id=\"lang-list\">",
616
+ "end": "</small>",
617
+ "separator": " · "
618
+ }
619
+ }
620
+ }
621
+ ```
622
+
623
+ ### `svg`(可選)
624
+
625
+ 獨立 SVG 資產的頂層路徑與佈局。僅當 **`features.translateSVG`** 為 true 時才會執行翻譯(透過 `translate-svg` 或 `sync` 的 SVG 階段)。
626
+
627
+ | 欄位 | 描述 |
628
+ | --------------------------- | ----------- |
629
+ | `sourcePath` | 一個目錄或一組目錄,遞歸掃描 `.svg` 文件。 |
630
+ | `outputDir` | 翻譯後 SVG 輸出的根目錄。 |
631
+ | `style` | 當 `pathTemplate` 未設置時,為 `"flat"` 或 `"nested"`。 |
632
+ | `pathTemplate` | 自定義 SVG 輸出路徑。佔位符:<code>{"{outputDir}"}</code>, <code>{"{locale}"}</code>, <code>{"{LOCALE}"}</code>, <code>{"{relPath}"}</code>, <code>{"{stem}"}</code>, <code>{"{basename}"}</code>, <code>{"{extension}"}</code>, <code>{"{relativeToSourceRoot}"}</code>。 |
633
+ | `svgExtractor.forceLowercase` | 在 SVG 重新組裝時轉換為小寫的翻譯文本。對於依賴全小寫標籤的設計非常有用。 |
634
+
635
+ ### `glossary`
636
+
637
+ | 欄位 | 說明 |
638
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
639
+ | `uiGlossary` | 指向 `strings.json` 的路徑 - 自動從現有翻譯建立詞彙表。 |
640
+ | `userGlossary` | 指向 CSV 檔案的路徑,其欄位為 `Original language string`(或 `en`)、`locale`、`Translation` - 每個原始術語與目標語系各佔一列(`locale` 可為 `*` 代表所有目標)。 |
641
+
642
+ 舊的鍵 `uiGlossaryFromStringsJson` 仍然被接受並在加載配置時映射到 `uiGlossary`。
643
+
644
+ 生成一個空的詞彙表 CSV:
645
+
646
+ ```bash
647
+ npx ai-i18n-tools glossary-generate
648
+ ```
649
+
650
+ ---
651
+
652
+ ## CLI 參考
653
+
654
+ | 命令 | 說明 |
655
+ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
656
+ | `init [-t ui-markdown|ui-docusaurus] [-o path] [--with-translate-ignore]` | 寫入一個起始設定檔(包含 `concurrency`、`batchConcurrency`、`batchSize`、`maxBatchChars` 和 `documentations[].addFrontmatter`)。`--with-translate-ignore` 會建立一個起始的 `.translate-ignore`。 |
657
+ | `extract` | 掃描原始碼中的 `t("…")` 呼叫並更新 `strings.json`。需要 `features.extractUIStrings`。 |
658
+ | `translate-docs …` | 為每個 `documentations` 區塊(`contentPaths`,可選的 `jsonSource`)翻譯 Markdown/MDX 和 JSON。`-j`:最大並行語系數量;`-b`:每檔案最大並行批次 API 呼叫數。`--prompt-format`:批次傳輸格式(`xml` \| `json-array` \| `json-object`)。請參閱 [快取行為與 `translate-docs` 標記](#cache-behaviour-and-translate-docs-flags) 和 [批次提示格式](#batch-prompt-format)。 |
659
+ | `translate-svg …` | 翻譯在 `config.svg` 中設定的獨立 SVG 資產(與文件分開)。需要 `features.translateSVG`。與文件共享相同的快取機制;支援 `--no-cache` 以跳過該次執行的 SQLite 讀寫操作。`-j`、`-b`、`--force`、`--force-update`、`-p` / `--path`、`--dry-run`。 |
660
+ | `translate-ui [--locale <code>] [--force] [--dry-run] [-j <n>]` | 僅翻譯 UI 字串。`--force`:重新翻譯每個語系的所有項目(忽略現有翻譯)。`--dry-run`:不寫入、不呼叫 API。`-j`:最大並行語系數量。需要 `features.translateUIStrings`。 |
661
+ | `export-ui-xliff [-l <codes>] [-o <dir>] [--untranslated-only] [--dry-run]` | 將 `strings.json` 匯出為 XLIFF 2.0 格式(每個目標語系產生一個 `.xliff`)。`-o` / `--output-dir`:輸出目錄(預設:與目錄檔相同資料夾)。`--untranslated-only`:僅包含該語系中缺少翻譯的單元。唯讀模式;不呼叫 API。 |
662
+ | `sync …` | 啟用時先進行提取,接著進行 UI 翻譯,然後在設定 `features.translateSVG` 和 `config.svg` 時執行 `translate-svg`,最後進行文件翻譯——除非使用 `--no-ui`、`--no-svg` 或 `--no-docs` 跳過。共用旗標:`-l`、`-p`、`--dry-run`、`-j`、`-b`(僅限文件批次處理)、`--force` / `--force-update`(僅限文件;文件執行時互斥)。 |
663
+ | `status` | 顯示每檔案 × 語系的 Markdown 翻譯狀態(無 `--locale` 過濾;語系來自設定)。 |
664
+ | `cleanup [--dry-run] [--no-backup] [--backup <path>]` | 首先執行 `sync --force-update`(提取、UI、SVG、文件),然後移除過時的片段資料列(null `last_hit_at` / 空檔案路徑);刪除其解析後來源路徑在磁碟上不存在的 `file_tracking` 資料列;移除其 `filepath` 中中繼資料指向遺失檔案的翻譯資料列。記錄三項計數(過時、孤立的 `file_tracking`、孤立的翻譯)。除非指定 `--no-backup`,否則會在快取目錄下建立帶有時間戳記的 SQLite 備份。 |
665
+ | `editor [-p <port>] [--no-open]` | 啟動本地網頁編輯器以編輯快取、`strings.json` 和詞彙表 CSV。`--no-open`:不要自動開啟預設瀏覽器。<br><br>**注意:** 如果您在快取編輯器中編輯了某個項目,您必須執行 `sync --force-update` 才能將更新後的快取項目寫回輸出檔案。此外,如果稍後原始文字變更,手動編輯將會遺失,因為會產生新的快取金鑰。 |
666
+ | `glossary-generate [-o <path>]` | 寫入一個空的 `glossary-user.csv` 範本。`-o`:覆寫輸出路徑(預設:來自設定的 `glossary.userGlossary`,或 `glossary-user.csv`)。 |
667
+
668
+ 所有命令都接受 `-c <path>` 來指定非預設的配置文件,`-v` 用於詳細輸出,以及 `-w` / `--write-logs [path]` 將控制台輸出記錄到日誌文件(預設路徑:在根目錄 `cacheDir` 下)。
669
+
670
+ ---
671
+
672
+ ## 環境變數
673
+
674
+ | 變數 | 描述 |
675
+ | ---------------------- | ---------------------------------------------------------- |
676
+ | `OPENROUTER_API_KEY` | **必填。** 您的 OpenRouter API 金鑰。 |
677
+ | `OPENROUTER_BASE_URL` | 覆蓋 API 基本 URL。 |
678
+ | `I18N_SOURCE_LOCALE` | 在運行時覆蓋 `sourceLocale`。 |
679
+ | `I18N_TARGET_LOCALES` | 以逗號分隔的區域代碼,用於覆蓋 `targetLocales`。 |
680
+ | `I18N_LOG_LEVEL` | 日誌級別(`debug`、`info`、`warn`、`error`、`silent`)。 |
681
+ | `NO_COLOR` | 當 `1` 時,禁用日誌輸出的 ANSI 顏色。 |
682
+ | `I18N_LOG_SESSION_MAX` | 每個日誌會話保留的最大行數(預設 `5000`)。 |