@verbaly/compiler 0.23.0 → 0.24.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 +1 -1
- package/dist/claude-C-ETlqsW.js.map +1 -1
- package/dist/cli.js +6 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
The compiler behind [Verbaly](https://github.com/AronSoto/verbaly): AST extraction of `t\`...\``**and JSX`<Trans>` children** into stable hashed keys (or **readable keys** via `` t.id('inbox.title')`…` `` and `<Trans id="inbox.title">…</Trans>`), flat JSON catalog sync, and typed codegen. It also ships the **`verbaly`
|
|
14
|
+
The compiler behind [Verbaly](https://github.com/AronSoto/verbaly): AST extraction of `t\`...\``**and JSX`<Trans>` children** into stable hashed keys (or **readable keys** via `` t.id('inbox.title')`…` `` and `<Trans id="inbox.title">…</Trans>`), flat JSON catalog sync, and typed codegen. It also ships the **`verbaly`CLI**. Extraction covers`.js/.ts/.jsx/.tsx`**and`.svelte`/`.vue`single-file components** (script blocks and markup, including Svelte's`$t` store form).
|
|
15
15
|
|
|
16
16
|
> Most projects don't install this directly: [`@verbaly/vite`](https://www.npmjs.com/package/@verbaly/vite) wraps it with zero config. Reach for it when scripting extraction/checks yourself.
|
|
17
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-C-ETlqsW.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 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 );\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
|
|
1
|
+
{"version":3,"file":"claude-C-ETlqsW.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 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 );\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,OACE,8BAA8B,QAAQ,aAAa,QAAQ,QAAQ,aAAa,yEAEhF,KAAK,UAAU,QAAQ,UAAU,MAAM,CAAC;AAE5C;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"}
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, watch, writeFileSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
5
|
-
import { RICH_TAGS, createVerbaly, parse, parseTags,
|
|
5
|
+
import { RICH_TAGS, createVerbaly, normalizeLink, parse, parseTags, safeAttribute } from "verbaly";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
import { glob } from "tinyglobby";
|
|
8
8
|
import { parse as parse$1 } from "@babel/parser";
|
|
@@ -1407,12 +1407,13 @@ function renderHtml(html, options) {
|
|
|
1407
1407
|
if (attrMapRaw !== void 0) {
|
|
1408
1408
|
const map = parseArgs$1(attrMapRaw);
|
|
1409
1409
|
if (map) for (const [name, attrKey] of Object.entries(map)) {
|
|
1410
|
-
if (typeof attrKey !== "string"
|
|
1410
|
+
if (typeof attrKey !== "string") continue;
|
|
1411
1411
|
if (!v.has(attrKey)) {
|
|
1412
1412
|
missing.add(attrKey);
|
|
1413
1413
|
continue;
|
|
1414
1414
|
}
|
|
1415
|
-
|
|
1415
|
+
const value = safeAttribute(name, t(attrKey, args));
|
|
1416
|
+
if (value !== void 0) setAttribute(ms, html, chunkStart, openEnd, attrChunk, name, value);
|
|
1416
1417
|
}
|
|
1417
1418
|
}
|
|
1418
1419
|
}
|
|
@@ -1574,10 +1575,8 @@ function richToHtml(nodes, allowed, links) {
|
|
|
1574
1575
|
let out = "";
|
|
1575
1576
|
for (const node of nodes) if (typeof node === "string") out += escapeHtml(node);
|
|
1576
1577
|
else if (links?.[node.name] !== void 0) {
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
const safe = safeHref(href);
|
|
1580
|
-
let attrs = safe !== void 0 ? ` href="${escapeAttr(safe)}"` : "";
|
|
1578
|
+
const { href, target, rel } = normalizeLink(links[node.name]);
|
|
1579
|
+
let attrs = href !== void 0 ? ` href="${escapeAttr(href)}"` : "";
|
|
1581
1580
|
if (target) attrs += ` target="${escapeAttr(target)}"`;
|
|
1582
1581
|
if (rel) attrs += ` rel="${escapeAttr(rel)}"`;
|
|
1583
1582
|
out += `<a${attrs}>${richToHtml(node.children, allowed, links)}</a>`;
|