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 : Prise en main
2
+
3
+ `ai-i18n-tools` fournit deux flux de travail indépendants et composables :
4
+
5
+ - **Flux de travail 1 - Traduction de l'UI** : extraire les appels `t("…")` de toute source JS/TS, les traduire via OpenRouter, et écrire des fichiers JSON plats par locale prêts pour i18next.
6
+ - **Flux de travail 2 - Traduction de documents** : traduire des fichiers markdown (MDX) et des fichiers de labels JSON Docusaurus vers n'importe quel nombre de locales, avec un cache intelligent. Les actifs **SVG** utilisent `features.translateSVG`, le bloc `svg` de niveau supérieur, et `translate-svg` (voir [référence CLI](#cli-reference)).
7
+
8
+ Les deux flux de travail utilisent OpenRouter (tout LLM compatible) et partagent un seul fichier de configuration.
9
+
10
+ <small>**Lire dans d'autres langues :** </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
+ **Table des matières**
19
+
20
+ - [Installation](#installation)
21
+ - [Démarrage rapide](#quick-start)
22
+ - [Flux de travail 1 - Traduction de l'interface utilisateur](#workflow-1---ui-translation)
23
+ - [Étape 1 : Initialiser](#step-1-initialise)
24
+ - [Étape 2 : Extraire les chaînes](#step-2-extract-strings)
25
+ - [Étape 3 : Traduire les chaînes d'interface](#step-3-translate-ui-strings)
26
+ - [Exporter vers XLIFF 2.0 (facultatif)](#exporting-to-xliff-20-optional)
27
+ - [Étape 4 : Connecter i18next au moment de l'exécution](#step-4-wire-i18next-at-runtime)
28
+ - [Utilisation de `t()` dans le code source](#using-t-in-source-code)
29
+ - [Interpolation](#interpolation)
30
+ - [Interface de commutateur de langue](#language-switcher-ui)
31
+ - [Langues RTL](#rtl-languages)
32
+ - [Flux de travail 2 - Traduction de documents](#workflow-2---document-translation)
33
+ - [Étape 1 : Initialiser](#step-1-initialise-1)
34
+ - [Étape 2 : Traduire les documents](#step-2-translate-documents)
35
+ - [Comportement du cache et indicateurs `translate-docs`](#cache-behaviour-and-translate-docs-flags)
36
+ - [Dispositions de sortie](#output-layouts)
37
+ - [Flux de travail combiné (UI + Docs)](#combined-workflow-ui--docs)
38
+ - [Référence de configuration](#configuration-reference)
39
+ - [`sourceLocale`](#sourcelocale)
40
+ - [`targetLocales`](#targetlocales)
41
+ - [`uiLanguagesPath` (facultatif)](#uilanguagespath-optional)
42
+ - [`concurrency` (facultatif)](#concurrency-optional)
43
+ - [`batchConcurrency` (facultatif)](#batchconcurrency-optional)
44
+ - [`batchSize` / `maxBatchChars` (facultatif)](#batchsize--maxbatchchars-optional)
45
+ - [`openrouter`](#openrouter)
46
+ - [`features`](#features)
47
+ - [`ui`](#ui)
48
+ - [`cacheDir`](#cachedir)
49
+ - [`documentations`](#documentations)
50
+ - [`svg` (facultatif)](#svg-optional)
51
+ - [`glossary`](#glossary)
52
+ - [Référence CLI](#cli-reference)
53
+ - [Variables d'environnement](#environment-variables)
54
+
55
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
56
+
57
+ ## Installation
58
+
59
+ Le package publié est **uniquement ESM**. Utilisez `import`/`import()` dans Node.js ou votre bundler ; **ne pas utiliser `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
+ Définissez votre clé API OpenRouter :
70
+
71
+ ```bash
72
+ export OPENROUTER_API_KEY=sk-or-v1-your-key-here
73
+ ```
74
+
75
+ Ou créez un fichier `.env` à la racine du projet :
76
+
77
+ ```env
78
+ OPENROUTER_API_KEY=sk-or-v1-your-key-here
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Prise en main rapide
84
+
85
+ Le modèle `init` par défaut (`ui-markdown`) permet uniquement l'extraction et la traduction **UI**. Le modèle `ui-docusaurus` permet la traduction **de documents** (`translate-docs`). Utilisez `sync` lorsque vous souhaitez une commande qui exécute l'extraction, la traduction UI, la traduction SVG autonome optionnelle et la traduction de documentation selon votre configuration.
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
+ ## Flux de travail 1 - Traduction UI
107
+
108
+ Conçu pour tout projet JS/TS qui utilise i18next : applications React, Next.js (composants client et serveur), services Node.js, outils CLI.
109
+
110
+ ### Étape 1 : Initialiser
111
+
112
+ ```bash
113
+ npx ai-i18n-tools init
114
+ ```
115
+
116
+ Cela écrit `ai-i18n-tools.config.json` avec le modèle `ui-markdown`. Modifiez-le pour définir :
117
+
118
+ - `sourceLocale` - votre code de langue source BCP-47 (par exemple, `"en-GB"`). **Doit correspondre** à `SOURCE_LOCALE` exporté de votre fichier de configuration i18n (`src/i18n.ts` / `src/i18n.js`).
119
+ - `targetLocales` - chemin vers votre manifeste `ui-languages.json` OU un tableau de codes BCP-47.
120
+ - `ui.sourceRoots` - répertoires à scanner pour les appels `t("…")` (par exemple, `["src/"]`).
121
+ - `ui.stringsJson` - où écrire le catalogue principal (par exemple, `"src/locales/strings.json"`).
122
+ - `ui.flatOutputDir` - où écrire `de.json`, `pt-BR.json`, etc. (par exemple, `"src/locales/"`).
123
+ - `ui.preferredModel` (facultatif) - identifiant du modèle OpenRouter à essayer **en premier** uniquement pour `translate-ui` ; en cas d'échec, la CLI continue avec `openrouter.translationModels` (ou les anciens `defaultModel` / `fallbackModel`) dans l'ordre, en sautant les doublons.
124
+
125
+ ### Étape 2 : Extraire les chaînes
126
+
127
+ ```bash
128
+ npx ai-i18n-tools extract
129
+ ```
130
+
131
+ Scanne tous les fichiers JS/TS sous `ui.sourceRoots` pour les appels `t("literal")` et `i18n.t("literal")`. Écrit (ou fusionne dans) `ui.stringsJson`.
132
+
133
+ Le scanner est configurable : ajoutez des noms de fonctions personnalisées via `ui.reactExtractor.funcNames`.
134
+
135
+ ### Étape 3 : Traduire les chaînes de l'interface utilisateur
136
+
137
+ ```bash
138
+ npx ai-i18n-tools translate-ui
139
+ ```
140
+
141
+ Lit `strings.json`, envoie des lots à OpenRouter pour chaque locale cible, écrit des fichiers JSON plats (`de.json`, `fr.json`, etc.) dans `ui.flatOutputDir`. Lorsque `ui.preferredModel` est défini, ce modèle est tenté avant la liste ordonnée dans `openrouter.translationModels` (la traduction de documents et d'autres commandes utilisent toujours uniquement `openrouter`).
142
+
143
+ Pour chaque entrée, `translate-ui` stocke l'**identifiant de modèle OpenRouter** qui a correctement traduit chaque locale dans un objet facultatif `models` (avec les mêmes clés de locale que dans `translated`). Les chaînes modifiées dans la commande locale `editor` sont marquées avec la valeur sentinelle `user-edited` dans `models` pour cette locale. Les fichiers plats par locale situés sous `ui.flatOutputDir` restent au format **chaîne source → traduction** uniquement ; ils n'incluent pas `models` (ainsi les bundles au moment de l'exécution restent inchangés).
144
+
145
+ > **Remarque sur l'utilisation de l'éditeur de cache :** Si vous modifiez une entrée dans l'éditeur de cache, vous devez exécuter un `sync --force-update` (ou la commande `translate` équivalente avec `--force-update`) pour réécrire les fichiers de sortie avec l'entrée de cache mise à jour. De plus, gardez à l'esprit que si le texte source change plus tard, votre modification manuelle sera perdue car une nouvelle clé de cache (hash) sera générée pour la nouvelle chaîne source.
146
+
147
+ ### Exporter vers XLIFF 2.0 (facultatif)
148
+
149
+ Pour transmettre les chaînes d'interface à un prestataire de traduction, un système de gestion de la traduction (TMS) ou un outil de traduction assistée par ordinateur (CAT), exportez le catalogue au format **XLIFF 2.0** (un fichier par langue cible). Cette commande est **en lecture seule** : elle ne modifie pas `strings.json` ni n'appelle aucune API.
150
+
151
+ ```bash
152
+ npx ai-i18n-tools export-ui-xliff
153
+ ```
154
+
155
+ Par défaut, les fichiers sont écrits à côté de `ui.stringsJson`, nommés comme `strings.de.xliff`, `strings.pt-BR.xliff` (nom de base de votre catalogue + langue + `.xliff`). Utilisez `-o` / `--output-dir` pour écrire ailleurs. Les traductions existantes provenant de `strings.json` apparaissent dans `<target>` ; les langues manquantes utilisent `state="initial"` sans `<target>`, afin que les outils puissent les compléter. Utilisez `--untranslated-only` pour exporter uniquement les unités qui nécessitent encore une traduction pour chaque langue (utile pour les lots envoyés aux prestataires). `--dry-run` affiche les chemins sans écrire les fichiers.
156
+
157
+ ### Étape 4 : Connecter i18next à l'exécution
158
+
159
+ Créez votre fichier de configuration i18n en utilisant les helpers exportés par `'ai-i18n-tools/runtime'` :
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
+ Importez `i18n.js` avant que React ne rende (par exemple, en haut de votre point d'entrée). Lorsque l'utilisateur change de langue, appelez `await loadLocale(code)` puis `i18n.changeLanguage(code)`.
192
+
193
+ `SOURCE_LOCALE` est exporté afin que tout autre fichier qui en a besoin (par exemple, un sélecteur de langue) puisse l'importer directement depuis `'./i18n'`.
194
+
195
+ `defaultI18nInitOptions(sourceLocale)` renvoie les options standard pour les configurations où la clé sert de valeur par défaut :
196
+
197
+ - `parseMissingKeyHandler` retourne la clé elle-même, de sorte que les chaînes non traduites affichent le texte source.
198
+ - `nsSeparator: false` permet des clés contenant des deux-points.
199
+ - `interpolation.escapeValue: false` - sûr à désactiver : React échappe les valeurs lui-même, et la sortie Node.js/CLI n'a pas de HTML à échapper.
200
+
201
+ `wrapI18nWithKeyTrim(i18n)` enveloppe `i18n.t` de sorte que : (1) les clés soient tronquées avant la recherche, ce qui correspond à la manière dont le script d'extraction les stocke ; (2) l'interpolation <code>{"{{var}}"}</code> soit appliquée lorsque la locale source renvoie la clé brute - ainsi <code>{"t('Hello {{name}}', { name })"}</code> fonctionne correctement même pour la langue source.
202
+
203
+ `makeLoadLocale(i18n, loaders, sourceLocale)` renvoie une fonction asynchrone `loadLocale(lang)` qui importe dynamiquement le bundle JSON pour une locale et l'enregistre auprès d'i18next.
204
+
205
+ ### Utiliser `t()` dans le code source
206
+
207
+ Appelez `t()` avec une **chaîne littérale** afin que le script d'extraction puisse la trouver :
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
+ Le même modèle fonctionne en dehors de React (Node.js, composants serveur, CLI) :
219
+
220
+ ```js
221
+ import i18n from './i18n.js';
222
+ console.log(i18n.t('Processing complete'));
223
+ ```
224
+
225
+ **Règles :**
226
+
227
+ - Seules ces formes sont extraites : `t("…")`, `t('…')`, `t(`…`)`, `i18n.t("…")`.
228
+ - La clé doit être une **chaîne littérale** - pas de variables ou d'expressions comme clé.
229
+ - N'utilisez pas de littéraux de modèle pour la clé : <code>{'t(`Hello ${name}`)'}</code> n'est pas extractible.
230
+
231
+ ### Interpolation
232
+
233
+ Utilisez l'interpolation native du deuxième argument d'i18next pour les espaces réservés <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
+ Le script d'extraction ignore le deuxième argument - seule la chaîne clé littérale <code>{"\"Hello {{name}}, vous avez {{count}} messages\""}</code> est extraite et envoyée pour traduction. Les traducteurs sont instruits de préserver les jetons <code>{"{{...}}"}</code>.
242
+
243
+ ### Interface de sélection de langue
244
+
245
+ Utilisez le manifeste `ui-languages.json` pour construire un sélecteur de langue. `ai-i18n-tools` exporte deux helpers d'affichage :
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)` - affiche `t(englishName)` lorsque traduit, ou `englishName / t(englishName)` lorsque les deux diffèrent. Convient pour les écrans de paramètres.
298
+
299
+ `getUILanguageLabelNative(lang)` - affiche `englishName / label` (pas d'appel à `t()` sur chaque ligne). Convient pour les menus d'en-tête où vous souhaitez que le nom natif soit visible.
300
+
301
+ Le manifeste `ui-languages.json` est un tableau JSON d'entrées <code>{"{ code, label, englishName }"}</code>. Exemple :
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
+ Définissez `targetLocales` dans la configuration sur le chemin de ce fichier afin que la commande de traduction utilise la même liste.
314
+
315
+ ### Langues RTL
316
+
317
+ `ai-i18n-tools` exporte `getTextDirection(lng)` et `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` définit `document.documentElement.dir` (navigateur) ou est une opération sans effet (Node.js). Passez un argument `element` optionnel pour cibler un élément spécifique.
329
+
330
+ Pour les chaînes qui peuvent contenir des flèches `→`, inversez-les pour les mises en page 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
+ ## Flux de travail 2 - Traduction de documents
342
+
343
+ Conçu pour la documentation markdown, les sites Docusaurus, et les fichiers de labels JSON. Les actifs SVG autonomes sont traduits via [`translate-svg`](#cli-reference) lorsque `features.translateSVG` est activé et que le bloc `svg` de niveau supérieur est défini — pas via `documentations[].contentPaths`.
344
+
345
+ ### Étape 1 : Initialiser
346
+
347
+ ```bash
348
+ npx ai-i18n-tools init -t ui-docusaurus
349
+ ```
350
+
351
+ Modifiez le fichier généré `ai-i18n-tools.config.json` :
352
+
353
+ - `sourceLocale` - langue source (doit correspondre à `defaultLocale` dans `docusaurus.config.js`).
354
+ - `targetLocales` - tableau de codes de langue ou chemin vers un manifeste.
355
+ - `cacheDir` - répertoire de cache SQLite partagé pour tous les pipelines de documentation (et répertoire de journal par défaut pour `--write-logs`).
356
+ - `documentations` - tableau de blocs de documentation. Chaque bloc possède un `description` facultatif, `contentPaths`, `outputDir`, un `jsonSource` facultatif, `markdownOutput`, `targetLocales`, `addFrontmatter`, etc.
357
+ - `documentations[].description` - note courte facultative destinée aux mainteneurs (indiquant la portée de ce bloc). Lorsqu'elle est définie, elle apparaît dans l'en-tête de `translate-docs` (`🌐 … : traduction de …`) et dans les en-têtes des sections `status`.
358
+ - `documentations[].contentPaths` - répertoires ou fichiers sources en markdown/MDX (voir aussi `documentations[].jsonSource` pour les libellés JSON).
359
+ - `documentations[].outputDir` - répertoire racine de sortie traduit pour ce bloc.
360
+ - `documentations[].markdownOutput.style` - `"nested"` (par défaut), `"docusaurus"` ou `"flat"` (voir [Dispositions de sortie](#output-layouts)).
361
+
362
+ ### Étape 2 : Traduire des documents
363
+
364
+ ```bash
365
+ npx ai-i18n-tools translate-docs
366
+ ```
367
+
368
+ Cela traduit tous les fichiers dans chaque bloc `documentations` dans les `contentPaths` vers toutes les locales de documentation effectives (union de chaque bloc `targetLocales` lorsqu'il est défini, sinon les `targetLocales` racine). Les segments déjà traduits sont servis depuis le cache SQLite - seuls les segments nouveaux ou modifiés sont envoyés au LLM.
369
+
370
+ Pour traduire une seule locale :
371
+
372
+ ```bash
373
+ npx ai-i18n-tools translate-docs --locale de
374
+ ```
375
+
376
+ Pour vérifier ce qui doit être traduit :
377
+
378
+ ```bash
379
+ npx ai-i18n-tools status
380
+ ```
381
+
382
+ #### Comportement du cache et drapeaux `translate-docs`
383
+
384
+ La CLI garde une **suivi des fichiers** dans SQLite (hash source par fichier × locale) et des lignes de **segment** (hash × locale par morceau traduisible). Un fonctionnement normal ignore complètement un fichier lorsque le hash suivi correspond à la source actuelle **et** que le fichier de sortie existe déjà ; sinon, il traite le fichier et utilise le cache de segments afin que le texte inchangé n'appelle pas l'API.
385
+
386
+ | Drapeau | Effet |
387
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
388
+ | *(par défaut)* | Ignore les fichiers inchangés lorsque le suivi et la sortie sur disque correspondent ; utilise le cache de segments pour le reste. |
389
+ | `--force-update` | Re-traite chaque fichier correspondant (extraction, réassemblage, écriture des sorties) même si le suivi de fichiers aurait dû l'ignorer. **Le cache de segments s'applique toujours** - les segments inchangés ne sont pas envoyés au LLM. |
390
+ | `--force` | Efface le suivi des fichiers pour chaque fichier traité et **ne lit pas** le cache de segments pour la traduction via API (re-traduction complète). Les nouveaux résultats sont tout de même **écrits** dans le cache de segments. |
391
+ | `--stats` | Affiche les nombres de segments, les nombres de fichiers suivis et les totaux de segments par locale, puis quitte. |
392
+ | `--clear-cache [locale]` | Supprime les traductions mises en cache (et le suivi des fichiers) : toutes les locales, ou une seule locale, puis quitte. |
393
+ | `--prompt-format <mode>` | Détermine la manière dont chaque **lot** de segments est envoyé au modèle et analysé (`xml`, `json-array` ou `json-object`). Valeur par défaut : **`xml`**. Ne modifie pas l'extraction, les espaces réservés, la validation, le cache ou le comportement de secours — voir [Format du prompt par lot](#batch-prompt-format).
394
+
395
+ Vous ne pouvez pas combiner `--force` avec `--force-update` (ils sont mutuellement exclusifs).
396
+
397
+ #### Format du prompt par lot
398
+
399
+ `translate-docs` envoie les segments traduisibles à OpenRouter par **lots** (groupés par `batchSize` / `maxBatchChars`). Le drapeau **`--prompt-format`** modifie uniquement le **format de transmission** de ce lot ; la segmentation, les jetons `PlaceholderHandler`, les vérifications AST Markdown, les clés de cache SQLite et le secours par segment en cas d'échec d'analyse du lot restent inchangés.
400
+
401
+ | Mode | Message utilisateur | Réponse du modèle |
402
+ | ---- | ------------ | ----------- |
403
+ | **`xml`** (par défaut) | Pseudo-XML : un `<seg id="N">…</seg>` par segment (avec échappement XML). | Uniquement des blocs `<t id="N">…</t>`, un par index de segment. |
404
+ | **`json-array`** | Un tableau JSON de chaînes, une entrée par segment, dans l'ordre. | Un tableau JSON de **même longueur** (même ordre). |
405
+ | **`json-object`** | Un objet JSON `{"0":"…","1":"…",…}` indexé par numéro de segment. | Un objet JSON avec les **mêmes clés** et des valeurs traduites. |
406
+
407
+ L'en-tête d'exécution affiche également `Batch prompt format: …` afin que vous puissiez confirmer le mode actif. Les fichiers d'étiquettes JSON (`jsonSource`) et les lots SVG autonomes utilisent le même paramètre lorsque ces étapes s'exécutent dans le cadre de `translate-docs` (ou de la phase docs de `sync` — `sync` n'expose pas ce drapeau ; il utilise par défaut **`xml`**).
408
+
409
+ **Dédoublonnage des segments et chemins dans SQLite**
410
+
411
+ - Les lignes de segment sont indexées globalement par `(source_hash, locale)` (hash = contenu normalisé). Un texte identique dans deux fichiers partage une même ligne ; `translations.filepath` est une métadonnée (dernier rédacteur), pas une entrée de cache supplémentaire par fichier.
412
+ - `file_tracking.filepath` utilise des clés avec espace de noms : `doc-block:{index}:{relPath}` par bloc `documentations` (`relPath` est un chemin posix relatif à la racine du projet : les chemins markdown tels que collectés ; **les fichiers d'étiquettes JSON utilisent le chemin relatif au répertoire courant du fichier source**, par exemple `docs-site/i18n/en/code.json`, afin que le nettoyage puisse résoudre le fichier réel), et `svg-assets:{relPath}` pour les ressources SVG autonomes situées sous `translate-svg`.
413
+ - `translations.filepath` stocke les chemins posix relatifs au répertoire courant pour les segments markdown, JSON et SVG (SVG utilise la même forme de chemin que les autres ressources ; le préfixe `svg-assets:…` est **uniquement** présent dans `file_tracking`).
414
+ - Après une exécution, `last_hit_at` est effacé uniquement pour les lignes de segment **dans la même portée de traduction** (respectant `--path` et les types activés) qui n'ont pas été touchées, ainsi une exécution filtrée ou uniquement docs ne marque pas comme obsolètes les fichiers non concernés.
415
+
416
+ ### Dispositions de sortie
417
+
418
+ `"nested"` (par défaut lorsqu'omis) — reflète l'arborescence source sous `{outputDir}/{locale}/` (par exemple `docs/guide.md` → `i18n/de/docs/guide.md`).
419
+
420
+ `"docusaurus"` — place les fichiers situés sous `docsRoot` dans `i18n/<locale>/docusaurus-plugin-content-docs/current/<relativeToDocsRoot>`, conformément à la structure i18n Docusaurus habituelle. Définissez `documentations[].markdownOutput.docsRoot` sur la racine source de votre documentation (par exemple `"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"` - place les fichiers traduits à côté du fichier source avec un suffixe de langue, ou dans un sous-répertoire. Les liens relatifs entre pages sont réécrits automatiquement.
428
+
429
+ ```
430
+ docs/guide.md → i18n/guide.de.md
431
+ ```
432
+
433
+ Vous pouvez remplacer complètement les chemins avec `documentations[].markdownOutput.pathTemplate`. Espaces réservés : <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
+ ## Flux de travail combiné (UI + Docs)
438
+
439
+ Activez toutes les fonctionnalités dans une seule configuration pour exécuter les deux flux de travail ensemble :
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` pointe la traduction des documents vers le même catalogue `strings.json` que l'UI afin que la terminologie reste cohérente ; `glossary.userGlossary` ajoute des remplacements CSV pour les termes produits.
473
+
474
+ Exécutez `npx ai-i18n-tools sync` pour exécuter un pipeline : **extraire** les chaînes UI (si `features.extractUIStrings`), **traduire les chaînes UI** (si `features.translateUIStrings`), **traduire les actifs SVG autonomes** (si `features.translateSVG` et un bloc `svg` sont définis), puis **traduire la documentation** (chaque bloc `documentations` : markdown/JSON comme configuré). Ignorez les parties avec `--no-ui`, `--no-svg`, ou `--no-docs`. L'étape de documentation accepte `--dry-run`, `-p` / `--path`, `--force`, et `--force-update` (les deux dernières ne s'appliquent que lorsque la traduction de la documentation est exécutée ; elles sont ignorées si vous passez `--no-docs`).
475
+
476
+ Utilisez `documentations[].targetLocales` sur un bloc pour traduire les fichiers de ce bloc vers un **sous-ensemble plus petit** que l'UI (les locales de documentation effectives sont l'**union** des blocs) :
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
+ ## Référence de configuration
494
+
495
+ ### `sourceLocale`
496
+
497
+ Code BCP-47 pour la langue source (par exemple `"en-GB"`, `"en"`, `"pt-BR"`). Aucun fichier de traduction n'est généré pour cette locale - la chaîne clé elle-même est le texte source.
498
+
499
+ **Doit correspondre** à `SOURCE_LOCALE` exporté de votre fichier de configuration i18n d'exécution (`src/i18n.ts` / `src/i18n.js`).
500
+
501
+ ### `targetLocales`
502
+
503
+ Quelles locales traduire. Accepte :
504
+
505
+ - **Chemin de chaîne** vers un manifeste `ui-languages.json` (`"src/locales/ui-languages.json"`). Le fichier est chargé et les codes de locale sont extraits.
506
+ - **Tableau de codes BCP-47** (`["de", "fr", "es"]`).
507
+ - **Tableau à un élément avec un chemin** (`["src/locales/ui-languages.json"]`) - même comportement que la forme chaîne.
508
+
509
+ `targetLocales` est la liste principale des locales pour la traduction de l'UI et la liste de locales par défaut pour les blocs de documentation. Si vous préférez garder un tableau explicite ici mais souhaitez toujours des étiquettes et un filtrage de locale basés sur le manifeste, définissez également `uiLanguagesPath`.
510
+
511
+ ### `uiLanguagesPath` (optionnel)
512
+
513
+ Chemin vers un manifeste `ui-languages.json` utilisé pour les noms d'affichage, le filtrage de locale et le post-traitement de la liste des langues.
514
+
515
+ Utilisez ceci lorsque :
516
+
517
+ - `targetLocales` est un tableau explicite, mais vous souhaitez toujours des étiquettes en anglais/natives du manifeste.
518
+ - Vous souhaitez que `markdownOutput.postProcessing.languageListBlock` construise des étiquettes de locale à partir du même manifeste.
519
+ - Seule la traduction de l'UI est activée et vous souhaitez que le manifeste fournisse la liste effective des locales de l'UI.
520
+
521
+ ### `concurrency` (optionnel)
522
+
523
+ Nombre maximum de **locales cibles** traduites en même temps (`translate-ui`, `translate-docs`, `translate-svg`, et les étapes correspondantes à l'intérieur de `sync`). Si omis, le CLI utilise **4** pour la traduction de l'UI et **3** pour la traduction de la documentation (valeurs par défaut intégrées). Remplacez par exécution avec `-j` / `--concurrency`.
524
+
525
+ ### `batchConcurrency` (optionnel)
526
+
527
+ **translate-docs** et **translate-svg** (et l'étape de documentation de `sync`) : nombre maximum de requêtes **batch** OpenRouter en parallèle par fichier (chaque batch peut contenir plusieurs segments). Par défaut **4** si omis. Ignoré par `translate-ui`. Remplacez avec `-b` / `--batch-concurrency`. Sur `sync`, `-b` s'applique uniquement à l'étape de traduction de la documentation.
528
+
529
+ ### `batchSize` / `maxBatchChars` (optionnel)
530
+
531
+ Regroupement de segments pour la traduction de documents : combien de segments par requête API, et un plafond de caractères. Valeurs par défaut : **20** segments, **4096** caractères (si omis).
532
+
533
+ ### `openrouter`
534
+
535
+ | Champ | Description |
536
+ | ------------------- | ---------------------------------------------------------------------------------------- |
537
+ | `baseUrl` | URL de base de l'API OpenRouter. Par défaut : `https://openrouter.ai/api/v1`. |
538
+ | `translationModels` | Liste ordonnée préférée d'identifiants de modèles. Le premier est essayé en priorité ; les entrées suivantes servent de secours en cas d'erreur. Pour `translate-ui` uniquement**, vous pouvez également définir `ui.preferredModel` pour essayer un modèle avant cette liste (voir `ui`). |
539
+ | `defaultModel` | Modèle principal unique hérité. Utilisé uniquement lorsque `translationModels` n'est pas défini ou vide. |
540
+ | `fallbackModel` | Modèle de secours unique hérité. Utilisé après `defaultModel` lorsque `translationModels` n'est pas défini ou vide. |
541
+ | `maxTokens` | Nombre maximal de jetons de complétion par requête. Par défaut : `8192`. |
542
+ | `temperature` | Température d'échantillonnage. Par défaut : `0.2`. |
543
+
544
+ Définissez `OPENROUTER_API_KEY` dans votre environnement ou fichier `.env`.
545
+
546
+ ### `features`
547
+
548
+ | Champ | Flux de travail | Description |
549
+ | -------------------- | -------- | ----------------------------------------------------------------- |
550
+ | `extractUIStrings` | 1 | Scanner la source pour `t("…")` et écrire/fusionner `strings.json`. |
551
+ | `translateUIStrings` | 1 | Traduire les entrées de `strings.json` et écrire des fichiers JSON par locale. |
552
+ | `translateMarkdown` | 2 | Traduire des fichiers `.md` / `.mdx`. |
553
+ | `translateJSON` | 2 | Traduire des fichiers de labels JSON Docusaurus. |
554
+ | `translateSVG` | 2 | Traduire des actifs `.svg` autonomes (nécessite le bloc `svg` de niveau supérieur). |
555
+
556
+ Traduisez les actifs **SVG** autonomes avec `translate-svg` lorsque `features.translateSVG` est vrai et qu'un bloc `svg` de niveau supérieur est configuré. La commande `sync` exécute cette étape lorsque les deux sont définis (à moins que `--no-svg`).
557
+
558
+ ### `ui`
559
+
560
+ | Champ | Description |
561
+ | --------------------------- | ----------------------------------------------------------------------- |
562
+ | `sourceRoots` | Répertoires (relatifs au répertoire de travail courant) analysés pour les appels `t("…")`. |
563
+ | `stringsJson` | Chemin vers le fichier catalogue principal. Mis à jour par `extract`. |
564
+ | `flatOutputDir` | Répertoire où sont écrits les fichiers JSON par langue (`de.json`, etc.). |
565
+ | `preferredModel` | Facultatif. Identifiant du modèle OpenRouter essayé en premier pour `translate-ui` uniquement ; puis `openrouter.translationModels` (ou les modèles hérités) dans l'ordre, sans dupliquer cet identifiant. |
566
+ | `reactExtractor.funcNames` | Noms de fonctions supplémentaires à analyser (par défaut : `["t", "i18n.t"]`). |
567
+ | `reactExtractor.extensions` | Extensions de fichiers à inclure (par défaut : `[".js", ".jsx", ".ts", ".tsx"]`). |
568
+ | `reactExtractor.includePackageDescription` | Lorsque `true` (par défaut), `extract` inclut également la `description` du `package.json` comme chaîne d'interface utilisateur si elle est présente. |
569
+ | `reactExtractor.packageJsonPath` | Chemin personnalisé vers le fichier `package.json` utilisé pour cette extraction facultative de description.
570
+
571
+ ### `cacheDir`
572
+
573
+ | Champ | Description |
574
+ | ---------- | ----------------------------------------------------------------------------- |
575
+ | `cacheDir` | Répertoire de cache SQLite (partagé par tous les blocs `documentations`). Réutiliser entre les exécutions. |
576
+
577
+ ### `documentations`
578
+
579
+ Tableau des blocs de pipeline de documentation. `translate-docs` et la phase de documentation du processus `sync` **chaque** bloc dans l'ordre.
580
+
581
+ | Champ | Description |
582
+ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
583
+ | `description` | Note facultative lisible par l'humain pour ce bloc (non utilisée pour la traduction). Préfixée dans le titre `translate-docs` avec l'icône `🌐` lorsqu'elle est définie ; également affichée dans les en-têtes de section `status`. |
584
+ | `contentPaths` | Sources Markdown/MDX à traduire (`translate-docs` analyse ces fichiers pour les extensions `.md` / `.mdx`). Les libellés JSON proviennent de `jsonSource` sur le même bloc. |
585
+ | `outputDir` | Répertoire racine pour la sortie traduite de ce bloc. |
586
+ | `sourceFiles` | Alias facultatif fusionné à `contentPaths` au chargement. |
587
+ | `targetLocales` | Sous-ensemble facultatif de paramètres régionaux pour ce bloc uniquement (sinon, utilise les `targetLocales` racines). Les paramètres régionaux effectifs pour la documentation sont l'union entre tous les blocs. |
588
+ | `jsonSource` | Répertoire source pour les fichiers de libellés JSON Docusaurus de ce bloc (par exemple, `"i18n/en"`). |
589
+ | `markdownOutput.style` | `"nested"` (par défaut), `"docusaurus"` ou `"flat"`. |
590
+ | `markdownOutput.docsRoot` | Répertoire source docs pour la structure Docusaurus (par exemple, `"docs"`). |
591
+ | `markdownOutput.pathTemplate` | Chemin personnalisé de sortie Markdown. Espaces réservés : <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` | Chemin personnalisé de sortie JSON pour les fichiers de libellés. Prend en charge les mêmes espaces réservés que `pathTemplate`. |
593
+ | `markdownOutput.flatPreserveRelativeDir` | Pour le style `flat`, conserve les sous-répertoires sources afin d'éviter les conflits entre fichiers ayant le même nom de base. |
594
+ | `markdownOutput.rewriteRelativeLinks` | Réécrit les liens relatifs après la traduction (activé automatiquement pour le style `flat`). |
595
+ | `markdownOutput.linkRewriteDocsRoot` | Racine du dépôt utilisée lors du calcul des préfixes de réécriture des liens plats. Laissez généralement à `"."` sauf si vos documents traduits se trouvent sous une racine de projet différente. |
596
+ | `markdownOutput.postProcessing` | Transformations facultatives appliquées au **corps** Markdown traduit (le front matter YAML est préservé). S'exécute après le réassemblage des segments et la réécriture des liens plats, et avant `addFrontmatter`. |
597
+ | `markdownOutput.postProcessing.regexAdjustments` | Liste ordonnée de `{ "description"?, "search", "replace" }`. `search` est un motif regex (une chaîne simple utilise le drapeau `g`, ou `/pattern/flags`). `replace` prend en charge des espaces réservés tels que `${translatedLocale}`, `${sourceLocale}`, `${sourceFullPath}`, `${translatedFullPath}`, `${sourceFilename}`, `${translatedFilename}`, `${sourceBasedir}`, `${translatedBasedir}` (même principe que la référence `additional-adjustments`). |
598
+ | `markdownOutput.postProcessing.languageListBlock` | `{ "start", "end", "separator" }` — le traducteur recherche la première ligne contenant `start` et la ligne `end` correspondante, puis remplace cet extrait par un sélecteur de langue canonique. Les liens sont construits avec des chemins relatifs au fichier traduit ; les libellés proviennent de `uiLanguagesPath` / `ui-languages.json` si configuré, sinon de `localeDisplayNames` et des codes de paramètres régionaux. |
599
+ | `addFrontmatter` | Lorsque `true` (par défaut si omis), les fichiers Markdown traduits incluent les clés YAML : `translation_last_updated`, `source_file_mtime`, `source_file_hash`, `translation_language`, `source_file_path`, et lorsqu'au moins un segment possède des métadonnées de modèle, `translation_models` (liste triée des identifiants de modèles OpenRouter utilisés). Définir à `false` pour ignorer. |
600
+
601
+ Exemple (pipeline README plat — chemins des captures d'écran + wrapper de liste de langues optionnel) :
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` (optionnel)
624
+
625
+ Chemins de niveau supérieur et mise en page pour les actifs SVG autonomes. La traduction s'exécute uniquement lorsque **`features.translateSVG`** est vrai (via `translate-svg` ou l'étape SVG de `sync`).
626
+
627
+ | Champ | Description |
628
+ | --------------------------- | ----------- |
629
+ | `sourcePath` | Un répertoire ou un tableau de répertoires scannés récursivement pour les fichiers `.svg`. |
630
+ | `outputDir` | Répertoire racine pour la sortie SVG traduite. |
631
+ | `style` | `"plat"` ou `"imbriqué"` lorsque `pathTemplate` n'est pas défini. |
632
+ | `pathTemplate` | Chemin de sortie SVG personnalisé. Espaces réservés : <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` | Texte traduit en minuscules lors du réassemblage SVG. Utile pour les designs qui dépendent d'étiquettes entièrement en minuscules. |
634
+
635
+ ### `glossary`
636
+
637
+ | Champ | Description |
638
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
639
+ | `uiGlossary` | Chemin vers `strings.json` - construit automatiquement un glossaire à partir des traductions existantes. |
640
+ | `userGlossary` | Chemin vers un fichier CSV avec les colonnes `Original language string` (ou `en`), `locale`, `Translation` - une ligne par terme source et langue cible (`locale` peut être `*` pour toutes les cibles).
641
+
642
+ La clé héritée `uiGlossaryFromStringsJson` est toujours acceptée et mappée à `uiGlossary` lors du chargement de la configuration.
643
+
644
+ Générer un CSV de glossaire vide :
645
+
646
+ ```bash
647
+ npx ai-i18n-tools glossary-generate
648
+ ```
649
+
650
+ ---
651
+
652
+ ## Référence CLI
653
+
654
+ | Commande | Description |
655
+ | --- | --- |
656
+ | `init [-t ui-markdown|ui-docusaurus] [-o path] [--with-translate-ignore]` | Écrit un fichier de configuration de démarrage (inclut `concurrency`, `batchConcurrency`, `batchSize`, `maxBatchChars` et `documentations[].addFrontmatter`). `--with-translate-ignore` crée un `.translate-ignore` de démarrage. |
657
+ | `extract` | Analyse la source à la recherche d'appels `t("…")` et met à jour `strings.json`. Nécessite `features.extractUIStrings`. |
658
+ | `translate-docs …` | Traduit le markdown/MDX et le JSON pour chaque bloc `documentations` (`contentPaths`, `jsonSource` facultatif). `-j` : nombre maximal de langues en parallèle ; `-b` : nombre maximal d'appels d'API par lot en parallèle par fichier. `--prompt-format` : format de transmission par lot (`xml` \| `json-array` \| `json-object`). Voir [Comportement du cache et indicateurs `translate-docs`](#cache-behaviour-and-translate-docs-flags) et [Format de prompt par lot](#batch-prompt-format). |
659
+ | `translate-svg …` | Traduit les ressources SVG autonomes configurées dans `config.svg` (distinctes de la documentation). Nécessite `features.translateSVG`. Mêmes principes de cache que pour la documentation ; prend en charge `--no-cache` pour ignorer les lectures/écritures SQLite lors de cette exécution. `-j`, `-b`, `--force`, `--force-update`, `-p` / `--path`, `--dry-run`. |
660
+ | `translate-ui [--locale <code>] [--force] [--dry-run] [-j <n>]` | Traduit uniquement les chaînes d'interface utilisateur. `--force` : traduit à nouveau toutes les entrées par langue (ignore les traductions existantes). `--dry-run` : aucune écriture, aucun appel API. `-j` : nombre maximal de langues en parallèle. Nécessite `features.translateUIStrings`. |
661
+ | `export-ui-xliff [-l <codes>] [-o <dir>] [--untranslated-only] [--dry-run]` | Exporte `strings.json` vers XLIFF 2.0 (un `.xliff` par langue cible). `-o` / `--output-dir` : répertoire de sortie (par défaut : même dossier que le catalogue). `--untranslated-only` : uniquement les unités manquantes d'une traduction pour cette langue. Lecture seule ; pas d'API. |
662
+ | `sync …` | Extraction (si activée), puis traduction de l'interface utilisateur, puis `translate-svg` lorsque `features.translateSVG` et `config.svg` sont définis, puis traduction de la documentation – sauf si ignorée avec `--no-ui`, `--no-svg` ou `--no-docs`. Indicateurs partagés : `-l`, `-p`, `--dry-run`, `-j`, `-b` (uniquement pour le traitement par lots de la documentation), `--force` / `--force-update` (uniquement pour la documentation ; mutuellement exclusifs lorsque la documentation est exécutée). |
663
+ | `status` | Affiche l'état de traduction du markdown par fichier × langue (pas de filtre `--locale` ; les langues proviennent de la configuration). |
664
+ | `cleanup [--dry-run] [--no-backup] [--backup <path>]` | Exécute d'abord `sync --force-update` (extraction, interface utilisateur, SVG, documentation), puis supprime les lignes de segments obsolètes (`last_hit_at` nul / chemin de fichier vide) ; supprime les lignes `file_tracking` dont le chemin source résolu est manquant sur le disque ; supprime les lignes de traduction dont les métadonnées `filepath` pointent vers un fichier manquant. Affiche trois compteurs (obsolètes, `file_tracking` orphelins, traductions orphelines). Crée une sauvegarde SQLite horodatée dans le répertoire de cache, sauf si `--no-backup` est utilisé. |
665
+ | `editor [-p <port>] [--no-open]` | Lance un éditeur web local pour le cache, `strings.json` et le fichier CSV du glossaire. `--no-open` : n'ouvre pas automatiquement le navigateur par défaut.<br><br>**Remarque :** Si vous modifiez une entrée dans l'éditeur de cache, vous devez exécuter un `sync --force-update` pour réécrire les fichiers de sortie avec l'entrée de cache mise à jour. De plus, si le texte source change ultérieurement, la modification manuelle sera perdue car une nouvelle clé de cache est générée. |
666
+ | `glossary-generate [-o <path>]` | Écrit un modèle `glossary-user.csv` vide. `-o` : remplace le chemin de sortie (par défaut : `glossary.userGlossary` depuis la configuration, ou `glossary-user.csv`). |
667
+
668
+ Toutes les commandes acceptent `-c <path>` pour spécifier un fichier de configuration non par défaut, `-v` pour une sortie détaillée, et `-w` / `--write-logs [path]` pour rediriger la sortie de la console vers un fichier journal (chemin par défaut : sous `cacheDir` racine).
669
+
670
+ ---
671
+
672
+ ## Variables d'environnement
673
+
674
+ | Variable | Description |
675
+ | ---------------------- | ---------------------------------------------------------- |
676
+ | `OPENROUTER_API_KEY` | **Requis.** Votre clé API OpenRouter. |
677
+ | `OPENROUTER_BASE_URL` | Remplacer l'URL de base de l'API. |
678
+ | `I18N_SOURCE_LOCALE` | Remplacer `sourceLocale` à l'exécution. |
679
+ | `I18N_TARGET_LOCALES` | Codes de locale séparés par des virgules pour remplacer `targetLocales`. |
680
+ | `I18N_LOG_LEVEL` | Niveau du journal (`debug`, `info`, `warn`, `error`, `silent`). |
681
+ | `NO_COLOR` | Lorsque `1`, désactiver les couleurs ANSI dans la sortie du journal. |
682
+ | `I18N_LOG_SESSION_MAX` | Nombre maximum de lignes conservées par session de journal (par défaut `5000`). |