@vite-plugin-i18n-auto/core 0.1.0 → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 malinli-88
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -17,8 +17,13 @@ interface ExtractCodeOptions {
17
17
  moduleName: string;
18
18
  /** 默认语言代码 */
19
19
  defaultLocale: string;
20
- /** 是否改写 AST t('key') */
20
+ /** 是否改写 AST 为翻译函数调用 */
21
21
  replaceInSource: boolean;
22
+ /**
23
+ * replaceInSource 为真时:`t('key')`(key 为稳定 hash)或 `__tr('原文')`(默认语言文案,切换语言时按反向表解析;仅插件生成)
24
+ */
25
+ /** inline 时用 `__tr('原文')`(仅插件生成,非对外 API);`t` 为按 key */
26
+ translateCallee?: 't' | '__tr';
22
27
  /** 静态通道 callee:处于这些调用内的字面量不提取 */
23
28
  skipCallNames?: string[];
24
29
  }
@@ -32,7 +37,7 @@ interface ExtractCodeResult {
32
37
  }
33
38
 
34
39
  /**
35
- * 从单文件源码提取中文并按选项替换为 t('key')
40
+ * 从单文件源码提取中文并按选项替换为 t('key') 或 __tr('原文')
36
41
  */
37
42
  declare function extractFromSource(code: string, options: ExtractCodeOptions): ExtractCodeResult;
38
43
 
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ function generateCode(ast, code) {
42
42
  return generateFn(ast, { retainLines: false, compact: false }, code).code;
43
43
  }
44
44
 
45
- const DEFAULT_SKIP_CALLS = ["t", "$t"];
45
+ const DEFAULT_SKIP_CALLS = ["t", "__tr", "$t", "$$t"];
46
46
  function buildSkipSet(extra) {
47
47
  const s = new Set(DEFAULT_SKIP_CALLS);
48
48
  if (extra) for (const n of extra) s.add(n);
@@ -65,18 +65,23 @@ function isInsideSkippedCall(path, skipSet) {
65
65
  }
66
66
  return false;
67
67
  }
68
+ function normalizeExtractText(raw) {
69
+ return raw.trim();
70
+ }
68
71
  function isModuleSpecifierLiteral(path) {
69
72
  const p = path.parentPath;
70
73
  return !!(p?.isImportDeclaration() || p?.isExportAllDeclaration() || p?.isExportNamedDeclaration() || p?.isImportExpression());
71
74
  }
72
- function replaceStringLiteral(path, key, messages, value) {
75
+ function replaceStringLiteral(path, key, messages, value, callee) {
73
76
  messages[key] = value;
74
- path.replaceWith(t.callExpression(t.identifier("t"), [t.stringLiteral(key)]));
77
+ const arg = callee === "__tr" ? t.stringLiteral(value) : t.stringLiteral(key);
78
+ path.replaceWith(t.callExpression(t.identifier(callee), [arg]));
75
79
  }
76
- function replaceJsxText(path, key, messages, value) {
80
+ function replaceJsxText(path, key, messages, value, callee) {
77
81
  messages[key] = value;
82
+ const arg = callee === "__tr" ? t.stringLiteral(value) : t.stringLiteral(key);
78
83
  path.replaceWith(
79
- t.jsxExpressionContainer(t.callExpression(t.identifier("t"), [t.stringLiteral(key)]))
84
+ t.jsxExpressionContainer(t.callExpression(t.identifier(callee), [arg]))
80
85
  );
81
86
  }
82
87
  function extractFromSource(code, options) {
@@ -92,28 +97,30 @@ function extractFromSource(code, options) {
92
97
  return { messages: {}, code, modified: false };
93
98
  }
94
99
  const { keyRegistry, filePath, replaceInSource } = options;
100
+ const callee = options.translateCallee ?? "t";
95
101
  const skipSet = buildSkipSet(options.skipCallNames);
96
102
  traverseAst(ast, {
97
103
  StringLiteral(path) {
98
- const v = path.node.value;
104
+ const v = normalizeExtractText(path.node.value);
105
+ if (!v) return;
99
106
  if (!hasChinese(v)) return;
100
107
  if (isModuleSpecifierLiteral(path)) return;
101
108
  if (isInsideSkippedCall(path, skipSet)) return;
102
109
  const key = makeStableKey(keyRegistry, filePath, v);
103
110
  if (replaceInSource) {
104
- replaceStringLiteral(path, key, messages, v);
111
+ replaceStringLiteral(path, key, messages, v, callee);
105
112
  } else {
106
113
  messages[key] = v;
107
114
  }
108
115
  },
109
116
  JSXText(path) {
110
- const v = path.node.value;
117
+ const v = normalizeExtractText(path.node.value);
118
+ if (!v) return;
111
119
  if (!hasChinese(v)) return;
112
120
  if (isInsideSkippedCall(path, skipSet)) return;
113
- if (!v.trim()) return;
114
121
  const key = makeStableKey(keyRegistry, filePath, v);
115
122
  if (replaceInSource) {
116
- replaceJsxText(path, key, messages, v);
123
+ replaceJsxText(path, key, messages, v, callee);
117
124
  } else {
118
125
  messages[key] = v;
119
126
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/chinese.ts","../src/stable-key.ts","../src/babel-traverse.ts","../src/babel-generate.ts","../src/babel-extract.ts","../src/locale-writer.ts","../src/parse-index.ts"],"sourcesContent":["/** 是否包含需提取的中文(含常见 CJK 标点范围) */\nconst CHINESE_RE = /[\\u4e00-\\u9fff\\u3000-\\u303f\\uff00-\\uffef]/;\n\nexport function hasChinese(text: string): boolean {\n return CHINESE_RE.test(text);\n}\n","import { createHash } from 'node:crypto';\n\nconst usedKeys = new WeakMap<object, Set<string>>();\n\n/**\n * 基于文件路径与原文生成稳定 key,并在一次处理周期内按 registry 去重碰撞。\n */\nexport function makeStableKey(\n registry: object,\n filePath: string,\n literalText: string\n): string {\n const h = createHash('sha256')\n .update(`${filePath}\\0${literalText}`, 'utf8')\n .digest('hex')\n .slice(0, 12);\n let base = `i18n_${h}`;\n let set = usedKeys.get(registry);\n if (!set) {\n set = new Set();\n usedKeys.set(registry, set);\n }\n let key = base;\n let n = 0;\n while (set.has(key)) {\n key = `${base}_${++n}`;\n }\n set.add(key);\n return key;\n}\n\n/** 新一轮构建开始前清空某 registry(用聚合根对象作为 registry) */\nexport function clearKeyRegistry(registry: object): void {\n usedKeys.delete(registry);\n}\n","import traverseImport from '@babel/traverse';\nimport type { NodePath } from '@babel/traverse';\nimport type * as t from '@babel/types';\n\n/* CJS 打包进 ESM 后 default 可能落在 .default 上 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst traverseFn = ((traverseImport as any).default ?? traverseImport) as (\n ast: t.File,\n visitor: object\n) => void;\n\nexport function traverseAst(ast: t.File, visitor: object): void {\n traverseFn(ast, visitor);\n}\n\nexport type { NodePath };\n","import genImport from '@babel/generator';\nimport type * as t from '@babel/types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst generateFn = ((genImport as any).default ?? genImport) as (\n ast: t.Node,\n opts?: object,\n code?: string\n) => { code: string };\n\nexport function generateCode(ast: t.File, code: string): string {\n return generateFn(ast, { retainLines: false, compact: false }, code).code;\n}\n","import { parse } from '@babel/parser';\nimport type { NodePath } from '@babel/traverse';\nimport { traverseAst } from './babel-traverse.js';\nimport { generateCode } from './babel-generate.js';\nimport * as t from '@babel/types';\nimport type { ExtractCodeOptions, ExtractCodeResult } from './types.js';\nimport { hasChinese } from './chinese.js';\nimport { makeStableKey } from './stable-key.js';\n\nconst DEFAULT_SKIP_CALLS = ['t', '$t'];\n\nfunction buildSkipSet(extra?: string[]): Set<string> {\n const s = new Set<string>(DEFAULT_SKIP_CALLS);\n if (extra) for (const n of extra) s.add(n);\n return s;\n}\n\nfunction calleeMatchesSkip(\n callee: t.CallExpression['callee'],\n skipNames: Set<string>\n): boolean {\n if (t.isIdentifier(callee) && skipNames.has(callee.name)) return true;\n if (\n t.isMemberExpression(callee) &&\n !callee.computed &&\n t.isIdentifier(callee.object, { name: 'i18n' }) &&\n t.isIdentifier(callee.property, { name: 't' })\n ) {\n return true;\n }\n return false;\n}\n\n/** 字面量是否位于应跳过的 CallExpression 参数树内(t / $t / i18n.t) */\nfunction isInsideSkippedCall(\n path: NodePath<t.StringLiteral | t.JSXText>,\n skipSet: Set<string>\n): boolean {\n let p: NodePath<t.Node> | null = path.parentPath;\n while (p) {\n if (p.isCallExpression() && calleeMatchesSkip(p.node.callee, skipSet)) {\n return true;\n }\n p = p.parentPath;\n }\n return false;\n}\n\n/** import / export / dynamic import 的源字符串不提取 */\nfunction isModuleSpecifierLiteral(path: NodePath<t.StringLiteral>): boolean {\n const p = path.parentPath;\n return !!(\n p?.isImportDeclaration() ||\n p?.isExportAllDeclaration() ||\n p?.isExportNamedDeclaration() ||\n p?.isImportExpression()\n );\n}\n\nfunction replaceStringLiteral(\n path: NodePath<t.StringLiteral>,\n key: string,\n messages: Record<string, string>,\n value: string\n): void {\n messages[key] = value;\n path.replaceWith(t.callExpression(t.identifier('t'), [t.stringLiteral(key)]));\n}\n\nfunction replaceJsxText(\n path: NodePath<t.JSXText>,\n key: string,\n messages: Record<string, string>,\n value: string\n): void {\n messages[key] = value;\n path.replaceWith(\n t.jsxExpressionContainer(t.callExpression(t.identifier('t'), [t.stringLiteral(key)]))\n );\n}\n\n/**\n * 从单文件源码提取中文并按选项替换为 t('key')\n */\nexport function extractFromSource(code: string, options: ExtractCodeOptions): ExtractCodeResult {\n const messages: Record<string, string> = {};\n\n let ast: t.File;\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n errorRecovery: false,\n });\n } catch {\n return { messages: {}, code, modified: false };\n }\n\n const { keyRegistry, filePath, replaceInSource } = options;\n const skipSet = buildSkipSet(options.skipCallNames);\n\n traverseAst(ast, {\n StringLiteral(path) {\n const v = path.node.value;\n if (!hasChinese(v)) return;\n if (isModuleSpecifierLiteral(path)) return;\n if (isInsideSkippedCall(path, skipSet)) return;\n\n const key = makeStableKey(keyRegistry, filePath, v);\n if (replaceInSource) {\n replaceStringLiteral(path, key, messages, v);\n } else {\n messages[key] = v;\n }\n },\n JSXText(path) {\n const v = path.node.value;\n if (!hasChinese(v)) return;\n if (isInsideSkippedCall(path, skipSet)) return;\n if (!v.trim()) return;\n\n const key = makeStableKey(keyRegistry, filePath, v);\n if (replaceInSource) {\n replaceJsxText(path, key, messages, v);\n } else {\n messages[key] = v;\n }\n },\n });\n\n const hasMsgs = Object.keys(messages).length > 0;\n if (!hasMsgs) {\n return { messages: {}, code, modified: false };\n }\n\n if (!replaceInSource) {\n return { messages, code, modified: false };\n }\n\n const out = generateCode(ast, code);\n return {\n messages,\n code: out,\n modified: true,\n };\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { TranslateMode } from './types.js';\n\nexport interface WriteLocalesParams {\n cwd: string;\n outputDir: string;\n /** moduleName -> locale -> messages */\n aggregate: Map<string, Map<string, Record<string, string>>>;\n defaultLocale: string;\n targetLocales: string[];\n translate: TranslateMode;\n}\n\n/** 生成可供 runtime 安全解析的 index.ts(JSON 数组单行,便于正则 + JSON.parse) */\nexport function generateIndexTsContent(\n moduleNames: string[],\n locales: string[]\n): string {\n const modSorted = [...moduleNames].sort();\n const locSorted = [...locales].sort();\n const localeUnion = locSorted.map((l) => JSON.stringify(l)).join(' | ');\n const moduleUnion = modSorted.map((m) => JSON.stringify(m)).join(' | ');\n const modulesJson = JSON.stringify(modSorted);\n const localesJson = JSON.stringify(locSorted);\n\n return `/* 由 vite-plugin-i18n-auto extract 生成,请勿手改模块/语言列表结构 */\nexport type Locale = ${localeUnion};\nexport type ModuleName = ${moduleUnion};\n\nexport const modules = ${modulesJson} as const;\nexport const locales = ${localesJson} as const;\n\nexport async function loadModule(\n locale: Locale,\n module: ModuleName\n): Promise<Record<string, string>> {\n const mod = await import(/* @vite-ignore */ \\`./\\${module}/\\${locale}.json\\`);\n return (mod as { default: Record<string, string> }).default;\n}\n`;\n}\n\n/**\n * 填充目标语言 key(占位空串),便于 manual / ai 写入\n */\nfunction ensureTargetPlaceholders(\n aggregate: Map<string, Map<string, Record<string, string>>>,\n defaultLocale: string,\n targetLocales: string[]\n): void {\n for (const [, byLoc] of aggregate) {\n const def = byLoc.get(defaultLocale) ?? {};\n for (const tl of targetLocales) {\n if (!byLoc.has(tl)) byLoc.set(tl, {});\n const tgt = byLoc.get(tl)!;\n for (const key of Object.keys(def)) {\n if (!(key in tgt)) tgt[key] = '';\n }\n }\n }\n}\n\nasync function readJsonFile(file: string): Promise<Record<string, string>> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as Record<string, string>;\n } catch {\n return {};\n }\n}\n\nfunction mergeDefaultLocale(\n existing: Record<string, string>,\n incoming: Record<string, string>\n): Record<string, string> {\n return { ...existing, ...incoming };\n}\n\n/** 目标语言:已有非空译文不被空字符串覆盖 */\nfunction mergeTargetLocale(\n existing: Record<string, string>,\n incoming: Record<string, string>\n): Record<string, string> {\n const out = { ...incoming };\n for (const [k, v] of Object.entries(existing)) {\n if (v && String(v).trim() !== '' && (!out[k] || String(out[k]).trim() === '')) {\n out[k] = v;\n }\n }\n return out;\n}\n\n/**\n * 将聚合结果写入磁盘并生成 index.ts\n */\nexport async function writeLocaleArtifacts(params: WriteLocalesParams): Promise<void> {\n const root = path.resolve(params.cwd, params.outputDir);\n await mkdir(root, { recursive: true });\n\n const { aggregate, defaultLocale, targetLocales, translate } = params;\n\n if (translate !== false) {\n ensureTargetPlaceholders(aggregate, defaultLocale, targetLocales);\n }\n\n const localesToWrite =\n translate === false ? [defaultLocale] : [defaultLocale, ...targetLocales];\n\n const moduleNames = [...aggregate.keys()].sort();\n\n for (const mod of moduleNames) {\n const byLoc = aggregate.get(mod)!;\n const modDir = path.join(root, mod);\n await mkdir(modDir, { recursive: true });\n\n for (const loc of localesToWrite) {\n const file = path.join(modDir, `${loc}.json`);\n const incoming = { ...(byLoc.get(loc) ?? {}) };\n const existing = await readJsonFile(file);\n const merged =\n loc === defaultLocale\n ? mergeDefaultLocale(existing, incoming)\n : mergeTargetLocale(existing, incoming);\n await writeFile(file, `${JSON.stringify(merged, null, 2)}\\n`, 'utf8');\n }\n }\n\n const indexLocales =\n translate === false ? [defaultLocale] : [defaultLocale, ...targetLocales];\n const indexContent = generateIndexTsContent(moduleNames, [...new Set(indexLocales)]);\n await writeFile(path.join(root, 'index.ts'), indexContent, 'utf8');\n}\n","/**\n * 从 extract 生成的 index.ts 源码中解析 modules、locales(禁止 eval)\n */\nexport function parseModulesAndLocalesFromIndexTs(source: string): {\n modules: string[];\n locales: string[];\n} {\n const modMatch = source.match(/export const modules = (\\[[^\\]]*\\])\\s+as\\s+const/);\n const locMatch = source.match(/export const locales = (\\[[^\\]]*\\])\\s+as\\s+const/);\n let modules: string[] = [];\n let locales: string[] = [];\n try {\n if (modMatch) modules = JSON.parse(modMatch[1]) as string[];\n } catch {\n modules = [];\n }\n try {\n if (locMatch) locales = JSON.parse(locMatch[1]) as string[];\n } catch {\n locales = [];\n }\n return { modules, locales };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/chinese.ts","../src/stable-key.ts","../src/babel-traverse.ts","../src/babel-generate.ts","../src/babel-extract.ts","../src/locale-writer.ts","../src/parse-index.ts"],"sourcesContent":["/** 是否包含需提取的中文(含常见 CJK 标点范围) */\nconst CHINESE_RE = /[\\u4e00-\\u9fff\\u3000-\\u303f\\uff00-\\uffef]/;\n\nexport function hasChinese(text: string): boolean {\n return CHINESE_RE.test(text);\n}\n","import { createHash } from 'node:crypto';\n\nconst usedKeys = new WeakMap<object, Set<string>>();\n\n/**\n * 基于文件路径与原文生成稳定 key,并在一次处理周期内按 registry 去重碰撞。\n */\nexport function makeStableKey(\n registry: object,\n filePath: string,\n literalText: string\n): string {\n const h = createHash('sha256')\n .update(`${filePath}\\0${literalText}`, 'utf8')\n .digest('hex')\n .slice(0, 12);\n let base = `i18n_${h}`;\n let set = usedKeys.get(registry);\n if (!set) {\n set = new Set();\n usedKeys.set(registry, set);\n }\n let key = base;\n let n = 0;\n while (set.has(key)) {\n key = `${base}_${++n}`;\n }\n set.add(key);\n return key;\n}\n\n/** 新一轮构建开始前清空某 registry(用聚合根对象作为 registry) */\nexport function clearKeyRegistry(registry: object): void {\n usedKeys.delete(registry);\n}\n","import traverseImport from '@babel/traverse';\nimport type { NodePath } from '@babel/traverse';\nimport type * as t from '@babel/types';\n\n/* CJS 打包进 ESM 后 default 可能落在 .default 上 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst traverseFn = ((traverseImport as any).default ?? traverseImport) as (\n ast: t.File,\n visitor: object\n) => void;\n\nexport function traverseAst(ast: t.File, visitor: object): void {\n traverseFn(ast, visitor);\n}\n\nexport type { NodePath };\n","import genImport from '@babel/generator';\nimport type * as t from '@babel/types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst generateFn = ((genImport as any).default ?? genImport) as (\n ast: t.Node,\n opts?: object,\n code?: string\n) => { code: string };\n\nexport function generateCode(ast: t.File, code: string): string {\n return generateFn(ast, { retainLines: false, compact: false }, code).code;\n}\n","import { parse } from '@babel/parser';\nimport type { NodePath } from '@babel/traverse';\nimport { traverseAst } from './babel-traverse.js';\nimport { generateCode } from './babel-generate.js';\nimport * as t from '@babel/types';\nimport type { ExtractCodeOptions, ExtractCodeResult } from './types.js';\nimport { hasChinese } from './chinese.js';\nimport { makeStableKey } from './stable-key.js';\n\n/** t / __tr / $t:已接入 i18n;$$t:显式不参与提取与翻译(__tr 仅插件注入,不对手写 tr 兼容) */\nconst DEFAULT_SKIP_CALLS = ['t', '__tr', '$t', '$$t'];\n\nfunction buildSkipSet(extra?: string[]): Set<string> {\n const s = new Set<string>(DEFAULT_SKIP_CALLS);\n if (extra) for (const n of extra) s.add(n);\n return s;\n}\n\nfunction calleeMatchesSkip(\n callee: t.CallExpression['callee'],\n skipNames: Set<string>\n): boolean {\n if (t.isIdentifier(callee) && skipNames.has(callee.name)) return true;\n if (\n t.isMemberExpression(callee) &&\n !callee.computed &&\n t.isIdentifier(callee.object, { name: 'i18n' }) &&\n t.isIdentifier(callee.property, { name: 't' })\n ) {\n return true;\n }\n return false;\n}\n\n/** 字面量是否位于应跳过的 CallExpression 参数树内(t / __tr / $t / $$t / i18n.t) */\nfunction isInsideSkippedCall(\n path: NodePath<t.StringLiteral | t.JSXText>,\n skipSet: Set<string>\n): boolean {\n let p: NodePath<t.Node> | null = path.parentPath;\n while (p) {\n if (p.isCallExpression() && calleeMatchesSkip(p.node.callee, skipSet)) {\n return true;\n }\n p = p.parentPath;\n }\n return false;\n}\n\n/**\n * 提取与 key 生成使用:去掉前后空格、换行等,避免 JSX 缩进导致语言包原文与 __tr(…) 不一致\n */\nfunction normalizeExtractText(raw: string): string {\n return raw.trim();\n}\n\n/** import / export / dynamic import 的源字符串不提取 */\nfunction isModuleSpecifierLiteral(path: NodePath<t.StringLiteral>): boolean {\n const p = path.parentPath;\n return !!(\n p?.isImportDeclaration() ||\n p?.isExportAllDeclaration() ||\n p?.isExportNamedDeclaration() ||\n p?.isImportExpression()\n );\n}\n\nfunction replaceStringLiteral(\n path: NodePath<t.StringLiteral>,\n key: string,\n messages: Record<string, string>,\n value: string,\n callee: 't' | '__tr'\n): void {\n messages[key] = value;\n const arg = callee === '__tr' ? t.stringLiteral(value) : t.stringLiteral(key);\n path.replaceWith(t.callExpression(t.identifier(callee), [arg]));\n}\n\nfunction replaceJsxText(\n path: NodePath<t.JSXText>,\n key: string,\n messages: Record<string, string>,\n value: string,\n callee: 't' | '__tr'\n): void {\n messages[key] = value;\n const arg = callee === '__tr' ? t.stringLiteral(value) : t.stringLiteral(key);\n path.replaceWith(\n t.jsxExpressionContainer(t.callExpression(t.identifier(callee), [arg]))\n );\n}\n\n/**\n * 从单文件源码提取中文并按选项替换为 t('key') 或 __tr('原文')\n */\nexport function extractFromSource(code: string, options: ExtractCodeOptions): ExtractCodeResult {\n const messages: Record<string, string> = {};\n\n let ast: t.File;\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n errorRecovery: false,\n });\n } catch {\n return { messages: {}, code, modified: false };\n }\n\n const { keyRegistry, filePath, replaceInSource } = options;\n const callee: 't' | '__tr' = options.translateCallee ?? 't';\n const skipSet = buildSkipSet(options.skipCallNames);\n\n traverseAst(ast, {\n StringLiteral(path: NodePath<t.StringLiteral>) {\n const v = normalizeExtractText(path.node.value);\n if (!v) return;\n if (!hasChinese(v)) return;\n if (isModuleSpecifierLiteral(path)) return;\n if (isInsideSkippedCall(path, skipSet)) return;\n\n const key = makeStableKey(keyRegistry, filePath, v);\n if (replaceInSource) {\n replaceStringLiteral(path, key, messages, v, callee);\n } else {\n messages[key] = v;\n }\n },\n JSXText(path: NodePath<t.JSXText>) {\n const v = normalizeExtractText(path.node.value);\n if (!v) return;\n if (!hasChinese(v)) return;\n if (isInsideSkippedCall(path, skipSet)) return;\n\n const key = makeStableKey(keyRegistry, filePath, v);\n if (replaceInSource) {\n replaceJsxText(path, key, messages, v, callee);\n } else {\n messages[key] = v;\n }\n },\n });\n\n const hasMsgs = Object.keys(messages).length > 0;\n if (!hasMsgs) {\n return { messages: {}, code, modified: false };\n }\n\n if (!replaceInSource) {\n return { messages, code, modified: false };\n }\n\n const out = generateCode(ast, code);\n return {\n messages,\n code: out,\n modified: true,\n };\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { TranslateMode } from './types.js';\n\nexport interface WriteLocalesParams {\n cwd: string;\n outputDir: string;\n /** moduleName -> locale -> messages */\n aggregate: Map<string, Map<string, Record<string, string>>>;\n defaultLocale: string;\n targetLocales: string[];\n translate: TranslateMode;\n}\n\n/** 生成可供 runtime 安全解析的 index.ts(JSON 数组单行,便于正则 + JSON.parse) */\nexport function generateIndexTsContent(\n moduleNames: string[],\n locales: string[]\n): string {\n const modSorted = [...moduleNames].sort();\n const locSorted = [...locales].sort();\n const localeUnion = locSorted.map((l) => JSON.stringify(l)).join(' | ');\n const moduleUnion = modSorted.map((m) => JSON.stringify(m)).join(' | ');\n const modulesJson = JSON.stringify(modSorted);\n const localesJson = JSON.stringify(locSorted);\n\n return `/* 由 vite-plugin-i18n-auto extract 生成,请勿手改模块/语言列表结构 */\nexport type Locale = ${localeUnion};\nexport type ModuleName = ${moduleUnion};\n\nexport const modules = ${modulesJson} as const;\nexport const locales = ${localesJson} as const;\n\nexport async function loadModule(\n locale: Locale,\n module: ModuleName\n): Promise<Record<string, string>> {\n const mod = await import(/* @vite-ignore */ \\`./\\${module}/\\${locale}.json\\`);\n return (mod as { default: Record<string, string> }).default;\n}\n`;\n}\n\n/**\n * 填充目标语言 key(占位空串),便于 manual / ai 写入\n */\nfunction ensureTargetPlaceholders(\n aggregate: Map<string, Map<string, Record<string, string>>>,\n defaultLocale: string,\n targetLocales: string[]\n): void {\n for (const [, byLoc] of aggregate) {\n const def = byLoc.get(defaultLocale) ?? {};\n for (const tl of targetLocales) {\n if (!byLoc.has(tl)) byLoc.set(tl, {});\n const tgt = byLoc.get(tl)!;\n for (const key of Object.keys(def)) {\n if (!(key in tgt)) tgt[key] = '';\n }\n }\n }\n}\n\nasync function readJsonFile(file: string): Promise<Record<string, string>> {\n try {\n const raw = await readFile(file, 'utf8');\n return JSON.parse(raw) as Record<string, string>;\n } catch {\n return {};\n }\n}\n\nfunction mergeDefaultLocale(\n existing: Record<string, string>,\n incoming: Record<string, string>\n): Record<string, string> {\n return { ...existing, ...incoming };\n}\n\n/** 目标语言:已有非空译文不被空字符串覆盖 */\nfunction mergeTargetLocale(\n existing: Record<string, string>,\n incoming: Record<string, string>\n): Record<string, string> {\n const out = { ...incoming };\n for (const [k, v] of Object.entries(existing)) {\n if (v && String(v).trim() !== '' && (!out[k] || String(out[k]).trim() === '')) {\n out[k] = v;\n }\n }\n return out;\n}\n\n/**\n * 将聚合结果写入磁盘并生成 index.ts\n */\nexport async function writeLocaleArtifacts(params: WriteLocalesParams): Promise<void> {\n const root = path.resolve(params.cwd, params.outputDir);\n await mkdir(root, { recursive: true });\n\n const { aggregate, defaultLocale, targetLocales, translate } = params;\n\n if (translate !== false) {\n ensureTargetPlaceholders(aggregate, defaultLocale, targetLocales);\n }\n\n const localesToWrite =\n translate === false ? [defaultLocale] : [defaultLocale, ...targetLocales];\n\n const moduleNames = [...aggregate.keys()].sort();\n\n for (const mod of moduleNames) {\n const byLoc = aggregate.get(mod)!;\n const modDir = path.join(root, mod);\n await mkdir(modDir, { recursive: true });\n\n for (const loc of localesToWrite) {\n const file = path.join(modDir, `${loc}.json`);\n const incoming = { ...(byLoc.get(loc) ?? {}) };\n const existing = await readJsonFile(file);\n const merged =\n loc === defaultLocale\n ? mergeDefaultLocale(existing, incoming)\n : mergeTargetLocale(existing, incoming);\n await writeFile(file, `${JSON.stringify(merged, null, 2)}\\n`, 'utf8');\n }\n }\n\n const indexLocales =\n translate === false ? [defaultLocale] : [defaultLocale, ...targetLocales];\n const indexContent = generateIndexTsContent(moduleNames, [...new Set(indexLocales)]);\n await writeFile(path.join(root, 'index.ts'), indexContent, 'utf8');\n}\n","/**\n * 从 extract 生成的 index.ts 源码中解析 modules、locales(禁止 eval)\n */\nexport function parseModulesAndLocalesFromIndexTs(source: string): {\n modules: string[];\n locales: string[];\n} {\n const modMatch = source.match(/export const modules = (\\[[^\\]]*\\])\\s+as\\s+const/);\n const locMatch = source.match(/export const locales = (\\[[^\\]]*\\])\\s+as\\s+const/);\n let modules: string[] = [];\n let locales: string[] = [];\n try {\n if (modMatch) modules = JSON.parse(modMatch[1]) as string[];\n } catch {\n modules = [];\n }\n try {\n if (locMatch) locales = JSON.parse(locMatch[1]) as string[];\n } catch {\n locales = [];\n }\n return { modules, locales };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "name": "@vite-plugin-i18n-auto/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/malinli-88/vite-plugin-i18n-auto.git",
8
+ "directory": "packages/core"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/malinli-88/vite-plugin-i18n-auto/issues"
12
+ },
13
+ "homepage": "https://github.com/malinli-88/vite-plugin-i18n-auto/tree/main/packages/core#readme",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
4
17
  "type": "module",
5
18
  "main": "./dist/index.js",
6
19
  "module": "./dist/index.js",