@verbaly/compiler 0.26.0 → 0.28.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.
- package/README.md +4 -3
- package/dist/{claude-C-ETlqsW.js → claude-h9WA0ppg.js} +4 -2
- package/dist/claude-h9WA0ppg.js.map +1 -0
- package/dist/cli.js +461 -42
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.js +400 -32
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/claude-C-ETlqsW.js.map +0 -1
package/README.md
CHANGED
|
@@ -26,8 +26,8 @@ npx verbaly extract --prune # drop orphaned keys
|
|
|
26
26
|
npx verbaly status # translation coverage per locale, at a glance
|
|
27
27
|
npx verbaly check # exit 1 if anything is missing (CI)
|
|
28
28
|
npx verbaly translate # fill missing translations via Claude (or your provider)
|
|
29
|
-
npx verbaly export # translator files (XLIFF 2.0, CSV) or mobile resources (Android, iOS)
|
|
30
|
-
npx verbaly import <files> # fill catalogs back from translated XLIFF/CSV files
|
|
29
|
+
npx verbaly export # translator files (XLIFF 2.0, CSV, gettext PO) or mobile resources (Android, iOS)
|
|
30
|
+
npx verbaly import <files> # fill catalogs back from translated XLIFF/CSV/PO files
|
|
31
31
|
npx verbaly pseudo # generate a pseudo-locale catalog for i18n QA (en-XA)
|
|
32
32
|
npx verbaly render # pre-fill data-verbaly HTML per locale (SSG, kills the FOUC)
|
|
33
33
|
```
|
|
@@ -51,10 +51,11 @@ Catalogs are **flat JSON**: most TMS platforms (Crowdin, Lokalise, Phrase, …)
|
|
|
51
51
|
```bash
|
|
52
52
|
npx verbaly export # verbaly-export/<locale>.xlf (XLIFF 2.0, source + target per unit)
|
|
53
53
|
npx verbaly export --format csv # spreadsheet-friendly: key,source,target,location
|
|
54
|
+
npx verbaly export --format po # gettext PO (msgctxt = key, works with any PO editor)
|
|
54
55
|
npx verbaly import verbaly-export/es.xlf # fill the catalog back
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
`export` writes one file per target locale with the source text alongside the current translation (`--missing` exports only the untranslated entries). Every entry carries **where the text lives in your source** (XLIFF `location` notes, a `location` column in CSV), so translators and TMS tools see the context instead of guessing it. `import` reads XLIFF 2.0/1.2 or
|
|
58
|
+
`export` writes one file per target locale with the source text alongside the current translation (`--missing` exports only the untranslated entries). Every entry carries **where the text lives in your source** (XLIFF `location` notes, a `location` column in CSV, `#:` comments in PO), so translators and TMS tools see the context instead of guessing it. In XLIFF, `{params}` and rich tags travel as **protected inline codes with semantic ids** (`<ph id="name"/>`, `<pc id="em">`), so TMS editors show them as untouchable chips instead of editable raw syntax. `import` reads XLIFF 2.0/1.2, CSV or PO back (PO entries flagged `fuzzy` count as untranslated) and **validates every entry like `translate` does**: a translation that drops a `{param}`, a variant block or an `<em>` tag is rejected and reported, so a translator's typo can't break your UI. Existing translations are kept unless `--overwrite`; `--dry-run` previews everything.
|
|
58
59
|
|
|
59
60
|
## 📱 Mobile resources
|
|
60
61
|
|
|
@@ -23,7 +23,9 @@ function claudeProvider(options = {}) {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
function buildPrompt(request) {
|
|
26
|
-
|
|
26
|
+
const origins = request.origins;
|
|
27
|
+
const context = origins && Object.keys(origins).length ? `\n\nWhere each string appears (context for tone and length, do not translate these paths):\n` + Object.entries(origins).map(([key, files]) => ` ${key}: ${files.join(", ")}`).join("\n") : "";
|
|
28
|
+
return `Translate each value from "${request.sourceLocale}" to "${request.targetLocale}". Return a JSON object with the same keys and translated values.\n\n` + JSON.stringify(request.messages, null, 2) + context;
|
|
27
29
|
}
|
|
28
30
|
function batchFormat(request) {
|
|
29
31
|
const keys = Object.keys(request.messages);
|
|
@@ -48,4 +50,4 @@ async function loadSdk(load = () => import("@anthropic-ai/sdk")) {
|
|
|
48
50
|
//#endregion
|
|
49
51
|
export { claudeProvider };
|
|
50
52
|
|
|
51
|
-
//# sourceMappingURL=claude-
|
|
53
|
+
//# sourceMappingURL=claude-h9WA0ppg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-h9WA0ppg.js","names":[],"sources":["../src/providers/claude.ts"],"sourcesContent":["import { isModuleNotFound } from '../config';\nimport type { TranslateProvider, TranslateRequest } from '../translate';\n\nexport interface ClaudeProviderOptions {\n model?: string;\n apiKey?: string;\n maxTokens?: number;\n}\n\n// balanced default for translation\nconst DEFAULT_MODEL = 'claude-sonnet-5';\n\nconst SYSTEM = `You translate UI strings for the Verbaly i18n library.\nRules:\n- Translate only the human-readable text, naturally for the target locale.\n- Preserve verbatim: placeholders like {name}, format specs like {price:currency/EUR}, variant blocks like {count | one: ... | other: # ...} (translate only the text inside each variant, keep keys and # as-is), ICU syntax, named tags like <em>...</em> and escapes {{ }} || ##.\n- Keys are opaque identifiers: return exactly the same keys, never translate or rename them.`;\n\nexport function claudeProvider(options: ClaudeProviderOptions = {}): TranslateProvider {\n return async (request: TranslateRequest) => {\n const Anthropic = await loadSdk();\n const client = new Anthropic(options.apiKey ? { apiKey: options.apiKey } : {});\n const response = await client.messages.create({\n model: options.model ?? DEFAULT_MODEL,\n max_tokens: options.maxTokens ?? 16000,\n thinking: { type: 'disabled' },\n system: SYSTEM,\n messages: [{ role: 'user', content: buildPrompt(request) }],\n output_config: { format: batchFormat(request) },\n });\n const text = response.content.find((block) => block.type === 'text')?.text ?? '{}';\n return JSON.parse(text) as Record<string, string>;\n };\n}\n\nexport function buildPrompt(request: TranslateRequest): string {\n const origins = request.origins;\n const context =\n origins && Object.keys(origins).length\n ? `\\n\\nWhere each string appears (context for tone and length, do not translate these paths):\\n` +\n Object.entries(origins)\n .map(([key, files]) => ` ${key}: ${files.join(', ')}`)\n .join('\\n')\n : '';\n return (\n `Translate each value from \"${request.sourceLocale}\" to \"${request.targetLocale}\". ` +\n `Return a JSON object with the same keys and translated values.\\n\\n` +\n JSON.stringify(request.messages, null, 2) +\n context\n );\n}\n\nexport function batchFormat(request: TranslateRequest) {\n const keys = Object.keys(request.messages);\n return {\n type: 'json_schema' as const,\n schema: {\n type: 'object',\n properties: Object.fromEntries(keys.map((key) => [key, { type: 'string' }])),\n required: keys,\n additionalProperties: false,\n },\n };\n}\n\ntype SdkModule = { default: typeof import('@anthropic-ai/sdk').default };\n\n// injectable for tests\nexport async function loadSdk(\n load: () => Promise<SdkModule> = () => import('@anthropic-ai/sdk'),\n): Promise<SdkModule['default']> {\n try {\n const mod = await load();\n return mod.default;\n } catch (error) {\n if (isModuleNotFound(error, '@anthropic-ai/sdk')) {\n throw new Error(\n '[verbaly] the claude translate provider needs @anthropic-ai/sdk: install it as a dev dependency (e.g. `pnpm add -D @anthropic-ai/sdk` / `npm i -D @anthropic-ai/sdk`) and set ANTHROPIC_API_KEY',\n { cause: error },\n );\n }\n throw error;\n }\n}\n"],"mappings":";;AAUA,MAAM,gBAAgB;AAEtB,MAAM,SAAS;;;;;AAMf,SAAgB,eAAe,UAAiC,CAAC,GAAsB;CACrF,OAAO,OAAO,YAA8B;EAW1C,MAAM,QAAO,MARU,KADJ,OADK,QAAQ,IACH,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC,CAChD,CAAC,CAAC,SAAS,OAAO;GAC5C,OAAO,QAAQ,SAAS;GACxB,YAAY,QAAQ,aAAa;GACjC,UAAU,EAAE,MAAM,WAAW;GAC7B,QAAQ;GACR,UAAU,CAAC;IAAE,MAAM;IAAQ,SAAS,YAAY,OAAO;GAAE,CAAC;GAC1D,eAAe,EAAE,QAAQ,YAAY,OAAO,EAAE;EAChD,CAAC,EAAA,CACqB,QAAQ,MAAM,UAAU,MAAM,SAAS,MAAM,CAAC,EAAE,QAAQ;EAC9E,OAAO,KAAK,MAAM,IAAI;CACxB;AACF;AAEA,SAAgB,YAAY,SAAmC;CAC7D,MAAM,UAAU,QAAQ;CACxB,MAAM,UACJ,WAAW,OAAO,KAAK,OAAO,CAAC,CAAC,SAC5B,iGACA,OAAO,QAAQ,OAAO,CAAC,CACpB,KAAK,CAAC,KAAK,WAAW,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,GAAG,CAAC,CACtD,KAAK,IAAI,IACZ;CACN,OACE,8BAA8B,QAAQ,aAAa,QAAQ,QAAQ,aAAa,yEAEhF,KAAK,UAAU,QAAQ,UAAU,MAAM,CAAC,IACxC;AAEJ;AAEA,SAAgB,YAAY,SAA2B;CACrD,MAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ;CACzC,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM;GACN,YAAY,OAAO,YAAY,KAAK,KAAK,QAAQ,CAAC,KAAK,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC;GAC3E,UAAU;GACV,sBAAsB;EACxB;CACF;AACF;AAKA,eAAsB,QACpB,aAAuC,OAAO,sBACf;CAC/B,IAAI;EAEF,QAAO,MADW,KAAK,EAAA,CACZ;CACb,SAAS,OAAO;EACd,IAAI,iBAAiB,OAAO,mBAAmB,GAC7C,MAAM,IAAI,MACR,mMACA,EAAE,OAAO,MAAM,CACjB;EAEF,MAAM;CACR;AACF"}
|