must-cli 1.9.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/LICENSE +22 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +192 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +16 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +142 -0
- package/dist/config/index.js.map +1 -0
- package/dist/extractors/base.d.ts +59 -0
- package/dist/extractors/base.d.ts.map +1 -0
- package/dist/extractors/base.js +204 -0
- package/dist/extractors/base.js.map +1 -0
- package/dist/extractors/html.d.ts +8 -0
- package/dist/extractors/html.d.ts.map +1 -0
- package/dist/extractors/html.js +70 -0
- package/dist/extractors/html.js.map +1 -0
- package/dist/extractors/index.d.ts +33 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +86 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/javascript.d.ts +17 -0
- package/dist/extractors/javascript.d.ts.map +1 -0
- package/dist/extractors/javascript.js +249 -0
- package/dist/extractors/javascript.js.map +1 -0
- package/dist/extractors/vue.d.ts +9 -0
- package/dist/extractors/vue.d.ts.map +1 -0
- package/dist/extractors/vue.js +99 -0
- package/dist/extractors/vue.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +414 -0
- package/dist/index.js.map +1 -0
- package/dist/transformer/index.d.ts +102 -0
- package/dist/transformer/index.d.ts.map +1 -0
- package/dist/transformer/index.js +844 -0
- package/dist/transformer/index.js.map +1 -0
- package/dist/translators/azure.d.ts +7 -0
- package/dist/translators/azure.d.ts.map +1 -0
- package/dist/translators/azure.js +43 -0
- package/dist/translators/azure.js.map +1 -0
- package/dist/translators/baidu.d.ts +8 -0
- package/dist/translators/baidu.d.ts.map +1 -0
- package/dist/translators/baidu.js +67 -0
- package/dist/translators/baidu.js.map +1 -0
- package/dist/translators/base.d.ts +15 -0
- package/dist/translators/base.d.ts.map +1 -0
- package/dist/translators/base.js +50 -0
- package/dist/translators/base.js.map +1 -0
- package/dist/translators/custom.d.ts +19 -0
- package/dist/translators/custom.d.ts.map +1 -0
- package/dist/translators/custom.js +82 -0
- package/dist/translators/custom.js.map +1 -0
- package/dist/translators/google.d.ts +6 -0
- package/dist/translators/google.d.ts.map +1 -0
- package/dist/translators/google.js +25 -0
- package/dist/translators/google.js.map +1 -0
- package/dist/translators/index.d.ts +16 -0
- package/dist/translators/index.d.ts.map +1 -0
- package/dist/translators/index.js +57 -0
- package/dist/translators/index.js.map +1 -0
- package/dist/types/index.d.ts +385 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/file.d.ts +5 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +41 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/interpolation.d.ts +68 -0
- package/dist/utils/interpolation.d.ts.map +1 -0
- package/dist/utils/interpolation.js +174 -0
- package/dist/utils/interpolation.js.map +1 -0
- package/dist/utils/text.d.ts +42 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +234 -0
- package/dist/utils/text.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义包裹函数生成器
|
|
3
|
+
* @param key - 翻译 key
|
|
4
|
+
* @param originalText - 原文
|
|
5
|
+
* @param interpolations - 插值表达式数组(用于模板字符串)
|
|
6
|
+
* @returns 生成的代码字符串
|
|
7
|
+
*/
|
|
8
|
+
export type WrapperGenerator = (key: string, originalText: string, interpolations?: string[]) => string;
|
|
9
|
+
/**
|
|
10
|
+
* 导入配置 - 支持全局导入和上下文注入
|
|
11
|
+
*/
|
|
12
|
+
export interface ImportConfig {
|
|
13
|
+
/**
|
|
14
|
+
* 统一模式:所有文件(React 组件和静态文件)使用相同的导入和包裹方式
|
|
15
|
+
* 如果为 true,将只使用 global 和 wrapper 配置,忽略其他配置
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
unified?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 统一包裹函数(当 unified 为 true 时使用)
|
|
21
|
+
* 支持三种格式:
|
|
22
|
+
* 1. 简单函数名: "trans" -> trans("key")
|
|
23
|
+
* 2. 模板字符串: "trans('{{key}}', '{{text}}')" -> trans('key', '原文')
|
|
24
|
+
* 3. 函数生成器: (key, text) => `trans('${key}', '${text}')`
|
|
25
|
+
*
|
|
26
|
+
* 模板变量:
|
|
27
|
+
* - {{key}}: 翻译 key
|
|
28
|
+
* - {{text}}: 原文(会自动转义引号)
|
|
29
|
+
* - {{0}}, {{1}}, ...: 插值表达式(用于模板字符串)
|
|
30
|
+
*/
|
|
31
|
+
wrapper?: string | WrapperGenerator;
|
|
32
|
+
/**
|
|
33
|
+
* 全局导入语句,会添加到文件顶部的 import 区域
|
|
34
|
+
* 例如: "import { useTranslation } from 'react-i18next';"
|
|
35
|
+
* 或统一模式: "import { trans } from 'i18n-utils';"
|
|
36
|
+
*/
|
|
37
|
+
global?: string;
|
|
38
|
+
/**
|
|
39
|
+
* 上下文注入语句,会添加到 React 组件/Hook 函数体的开头
|
|
40
|
+
* 例如: "const { t } = useTranslation();"
|
|
41
|
+
* 注意:统一模式下此配置被忽略
|
|
42
|
+
*/
|
|
43
|
+
contextInjection?: string;
|
|
44
|
+
/**
|
|
45
|
+
* 静态文件的导入语句(用于非 React 组件的纯 JS/TS 文件)
|
|
46
|
+
* 例如: "import i18n from '@/i18n';"
|
|
47
|
+
* 或: "import { getLocal } from '@/utils/local';"
|
|
48
|
+
* 注意:统一模式下此配置被忽略,使用 global
|
|
49
|
+
*/
|
|
50
|
+
staticFileImport?: string;
|
|
51
|
+
/**
|
|
52
|
+
* 静态文件中使用的翻译函数
|
|
53
|
+
* 支持三种格式:
|
|
54
|
+
* 1. 简单函数名: "i18n.t" -> i18n.t("key")
|
|
55
|
+
* 2. 模板字符串: "getLocal('{{key}}', '{{text}}')" -> getLocal('key', '原文')
|
|
56
|
+
* 3. 函数生成器: (key, text) => `getLocal('${key}', '${text}')`
|
|
57
|
+
*
|
|
58
|
+
* 模板变量:
|
|
59
|
+
* - {{key}}: 翻译 key
|
|
60
|
+
* - {{text}}: 原文
|
|
61
|
+
* - {{0}}, {{1}}, ...: 插值表达式(用于模板字符串)
|
|
62
|
+
* 注意:统一模式下此配置被忽略,使用 wrapper
|
|
63
|
+
*/
|
|
64
|
+
staticFileWrapper?: string | WrapperGenerator;
|
|
65
|
+
/**
|
|
66
|
+
* React 组件中使用的翻译函数(可选,默认使用 wrapperFunction)
|
|
67
|
+
* 支持与 staticFileWrapper 相同的格式
|
|
68
|
+
* 注意:统一模式下此配置被忽略,使用 wrapper
|
|
69
|
+
*/
|
|
70
|
+
componentWrapper?: string | WrapperGenerator;
|
|
71
|
+
}
|
|
72
|
+
export interface TransformConfig {
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* 导入配置,支持两种格式:
|
|
76
|
+
* 1. 字符串格式(向后兼容): "import { useTranslation } from 'react-i18next';"
|
|
77
|
+
* 2. 对象格式(推荐): { global: "import ...", contextInjection: "const { t } = ..." }
|
|
78
|
+
*/
|
|
79
|
+
importStatement?: string | ImportConfig;
|
|
80
|
+
wrapperFunction?: string;
|
|
81
|
+
formatCode?: boolean;
|
|
82
|
+
customTransform?: (params: {
|
|
83
|
+
text: string;
|
|
84
|
+
key: string;
|
|
85
|
+
sourceCode: string;
|
|
86
|
+
filePath: string;
|
|
87
|
+
}) => string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Key 生成器参数
|
|
91
|
+
*/
|
|
92
|
+
export interface KeyGeneratorParams {
|
|
93
|
+
/** 路径部分,如 'app.components.UserProfile' */
|
|
94
|
+
base: string;
|
|
95
|
+
/** 文案简写部分,如 'welcomeBack' */
|
|
96
|
+
text: string;
|
|
97
|
+
/** 计数器,从 0 开始,用于处理重复 key */
|
|
98
|
+
num: number;
|
|
99
|
+
/** 命名参数列表(当启用 namedParams 时) */
|
|
100
|
+
params?: string[];
|
|
101
|
+
/** 完整文件路径 */
|
|
102
|
+
filePath: string;
|
|
103
|
+
/** 原始源语言文案 */
|
|
104
|
+
originalText: string;
|
|
105
|
+
/** 翻译后的文案(用于生成 key) */
|
|
106
|
+
translatedText: string;
|
|
107
|
+
/** 应用名称 */
|
|
108
|
+
appName?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Key 生成配置
|
|
112
|
+
*/
|
|
113
|
+
export interface KeyConfig {
|
|
114
|
+
/**
|
|
115
|
+
* 自定义前缀
|
|
116
|
+
* 例如: 'CB_IBG_APPROLL_'
|
|
117
|
+
* 生成的 key: 'CB_IBG_APPROLL_00001'
|
|
118
|
+
*/
|
|
119
|
+
prefix?: string;
|
|
120
|
+
/**
|
|
121
|
+
* 计数器样式
|
|
122
|
+
* - 'none': 不添加计数器
|
|
123
|
+
* - 'auto': 仅在重复时添加计数器(默认)
|
|
124
|
+
* - 'always': 始终添加计数器
|
|
125
|
+
*/
|
|
126
|
+
counterStyle?: 'none' | 'auto' | 'always';
|
|
127
|
+
/**
|
|
128
|
+
* 计数器填充位数
|
|
129
|
+
* 例如: 5 表示 00001, 00002, ...
|
|
130
|
+
* 默认: 0(不填充)
|
|
131
|
+
*/
|
|
132
|
+
counterPadding?: number;
|
|
133
|
+
/**
|
|
134
|
+
* 计数器起始值
|
|
135
|
+
* 默认: 0
|
|
136
|
+
*/
|
|
137
|
+
counterStart?: number;
|
|
138
|
+
/**
|
|
139
|
+
* 是否只使用前缀+计数器模式
|
|
140
|
+
* 如果为 true,key 格式为: {prefix}{counter}[_{params}]
|
|
141
|
+
* 如果为 false(默认),key 格式为: {prefix}{base}.{text}[_{params}][.counter]
|
|
142
|
+
*/
|
|
143
|
+
prefixOnly?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* 是否在 key 中包含命名参数
|
|
146
|
+
* 当 interpolation.namedParams 为 true 时,可以选择将参数名添加到 key 中
|
|
147
|
+
* 例如: 'CB_IBG_APPROLL_00001_{username}_{count}'
|
|
148
|
+
* @default false
|
|
149
|
+
*/
|
|
150
|
+
includeParams?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* 自定义 key 生成函数
|
|
153
|
+
* 提供最大灵活性,可以完全自定义 key 格式
|
|
154
|
+
* 如果提供此函数,将忽略其他配置(prefix, counterStyle 等)
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* // 简单前缀+计数器格式
|
|
158
|
+
* generator: ({ num }) => `CB_IBG_${String(num).padStart(5, '0')}`
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // 自定义格式
|
|
162
|
+
* generator: ({ base, text, num, params }) => {
|
|
163
|
+
* let key = `${base}.${text}`;
|
|
164
|
+
* if (params?.length) key += `_{${params.join('}_{')}}`;
|
|
165
|
+
* if (num > 0) key += `.${num}`;
|
|
166
|
+
* return key;
|
|
167
|
+
* }
|
|
168
|
+
*/
|
|
169
|
+
generator?: (params: KeyGeneratorParams) => string;
|
|
170
|
+
}
|
|
171
|
+
export interface I18nConfig {
|
|
172
|
+
appName?: string;
|
|
173
|
+
sourceLanguage: string;
|
|
174
|
+
targetLanguages: string[];
|
|
175
|
+
/**
|
|
176
|
+
* 翻译服务商
|
|
177
|
+
* 当使用 customTranslate 时可以设为 'custom'
|
|
178
|
+
*/
|
|
179
|
+
translationProvider: 'google' | 'baidu' | 'youdao' | 'azure' | 'custom';
|
|
180
|
+
apiKey?: string;
|
|
181
|
+
apiSecret?: string;
|
|
182
|
+
region?: string;
|
|
183
|
+
outputDir: string;
|
|
184
|
+
inputPatterns: string[];
|
|
185
|
+
excludePatterns: string[];
|
|
186
|
+
/** @deprecated 使用 customTranslate 代替 */
|
|
187
|
+
customTranslator?: string;
|
|
188
|
+
/**
|
|
189
|
+
* 自定义翻译函数配置
|
|
190
|
+
* 当 translationProvider 为 'custom' 时必须提供
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* // 单文本翻译
|
|
194
|
+
* customTranslate: {
|
|
195
|
+
* translate: async ({ text, sourceLanguage, targetLanguage }) => {
|
|
196
|
+
* const result = await myTranslationAPI(text, sourceLanguage, targetLanguage);
|
|
197
|
+
* return result.translatedText;
|
|
198
|
+
* }
|
|
199
|
+
* }
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* // 批量翻译(更高效)
|
|
203
|
+
* customTranslate: {
|
|
204
|
+
* batch: true,
|
|
205
|
+
* translate: async ({ texts, sourceLanguage, targetLanguage }) => {
|
|
206
|
+
* const results = await myBatchTranslationAPI(texts, sourceLanguage, targetLanguage);
|
|
207
|
+
* return results.map(r => r.translatedText);
|
|
208
|
+
* }
|
|
209
|
+
* }
|
|
210
|
+
*/
|
|
211
|
+
customTranslate?: CustomTranslatorConfig;
|
|
212
|
+
patchDir?: string;
|
|
213
|
+
keyStyle?: 'dot' | 'underscore';
|
|
214
|
+
keyMaxLength?: number;
|
|
215
|
+
keyConfig?: KeyConfig;
|
|
216
|
+
transform?: TransformConfig;
|
|
217
|
+
interpolation?: InterpolationConfig;
|
|
218
|
+
}
|
|
219
|
+
export interface ExtractedText {
|
|
220
|
+
text: string;
|
|
221
|
+
file: string;
|
|
222
|
+
line: number;
|
|
223
|
+
column: number;
|
|
224
|
+
context?: string;
|
|
225
|
+
type: 'string' | 'template' | 'jsx' | 'vue' | 'html';
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* 提取警告的严重程度
|
|
229
|
+
*/
|
|
230
|
+
export type ExtractionWarningSeverity = 'warning' | 'error' | 'info';
|
|
231
|
+
/**
|
|
232
|
+
* 提取警告
|
|
233
|
+
*/
|
|
234
|
+
export interface ExtractionWarning {
|
|
235
|
+
/** 警告类型 */
|
|
236
|
+
type: 'complex-expression' | 'nested-template' | 'conditional-expression' | 'function-call' | 'too-many-interpolations' | 'dynamic-text' | 'binary-expression' | 'parse-error';
|
|
237
|
+
/** 严重程度 */
|
|
238
|
+
severity: ExtractionWarningSeverity;
|
|
239
|
+
/** 警告消息 */
|
|
240
|
+
message: string;
|
|
241
|
+
/** 文件路径 */
|
|
242
|
+
file: string;
|
|
243
|
+
/** 行号 */
|
|
244
|
+
line: number;
|
|
245
|
+
/** 列号 */
|
|
246
|
+
column: number;
|
|
247
|
+
/** 原始代码片段 */
|
|
248
|
+
code?: string;
|
|
249
|
+
/** 建议的处理方式 */
|
|
250
|
+
suggestion?: string;
|
|
251
|
+
}
|
|
252
|
+
export interface TranslationResult {
|
|
253
|
+
sourceText: string;
|
|
254
|
+
translatedText: string;
|
|
255
|
+
sourceLanguage: string;
|
|
256
|
+
targetLanguage: string;
|
|
257
|
+
provider: string;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 自定义翻译函数的参数
|
|
261
|
+
*/
|
|
262
|
+
export interface CustomTranslateParams {
|
|
263
|
+
/** 要翻译的文本 */
|
|
264
|
+
text: string;
|
|
265
|
+
/** 源语言代码 */
|
|
266
|
+
sourceLanguage: string;
|
|
267
|
+
/** 目标语言代码 */
|
|
268
|
+
targetLanguage: string;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* 批量翻译函数的参数
|
|
272
|
+
*/
|
|
273
|
+
export interface CustomBatchTranslateParams {
|
|
274
|
+
/** 要翻译的文本数组 */
|
|
275
|
+
texts: string[];
|
|
276
|
+
/** 源语言代码 */
|
|
277
|
+
sourceLanguage: string;
|
|
278
|
+
/** 目标语言代码 */
|
|
279
|
+
targetLanguage: string;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* 自定义翻译函数类型
|
|
283
|
+
* 可以是单个文本翻译函数或批量翻译函数
|
|
284
|
+
*/
|
|
285
|
+
export type CustomTranslateFunction = ((params: CustomTranslateParams) => Promise<string>) | ((params: CustomBatchTranslateParams) => Promise<string[]>);
|
|
286
|
+
/**
|
|
287
|
+
* 自定义翻译器配置
|
|
288
|
+
*/
|
|
289
|
+
export interface CustomTranslatorConfig {
|
|
290
|
+
/**
|
|
291
|
+
* 翻译函数
|
|
292
|
+
* 支持两种签名:
|
|
293
|
+
* 1. 单文本翻译: ({ text, sourceLanguage, targetLanguage }) => Promise<string>
|
|
294
|
+
* 2. 批量翻译: ({ texts, sourceLanguage, targetLanguage }) => Promise<string[]>
|
|
295
|
+
*/
|
|
296
|
+
translate: CustomTranslateFunction;
|
|
297
|
+
/**
|
|
298
|
+
* 翻译器名称(用于日志和报告)
|
|
299
|
+
* @default 'custom'
|
|
300
|
+
*/
|
|
301
|
+
name?: string;
|
|
302
|
+
/**
|
|
303
|
+
* 是否为批量翻译函数
|
|
304
|
+
* 如果为 true,translate 函数应接收 texts 数组并返回翻译结果数组
|
|
305
|
+
* @default false
|
|
306
|
+
*/
|
|
307
|
+
batch?: boolean;
|
|
308
|
+
}
|
|
309
|
+
export interface I18nFile {
|
|
310
|
+
[key: string]: string | I18nFile;
|
|
311
|
+
}
|
|
312
|
+
export interface ExtractorOptions {
|
|
313
|
+
includeComments?: boolean;
|
|
314
|
+
includeTemplateLiterals?: boolean;
|
|
315
|
+
includeJSX?: boolean;
|
|
316
|
+
includeVue?: boolean;
|
|
317
|
+
includeHTML?: boolean;
|
|
318
|
+
}
|
|
319
|
+
export interface TranslatorOptions {
|
|
320
|
+
apiKey?: string;
|
|
321
|
+
apiSecret?: string;
|
|
322
|
+
region?: string;
|
|
323
|
+
customEndpoint?: string;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* 插值配置 - 定义如何处理模板字符串中的动态表达式
|
|
327
|
+
*/
|
|
328
|
+
export interface InterpolationConfig {
|
|
329
|
+
/**
|
|
330
|
+
* 占位符前缀
|
|
331
|
+
* @default '{{'
|
|
332
|
+
*/
|
|
333
|
+
prefix?: string;
|
|
334
|
+
/**
|
|
335
|
+
* 占位符后缀
|
|
336
|
+
* @default '}}'
|
|
337
|
+
*/
|
|
338
|
+
suffix?: string;
|
|
339
|
+
/**
|
|
340
|
+
* 使用命名参数而非索引参数
|
|
341
|
+
* 如果为 true,会从模板字符串的变量名提取参数名
|
|
342
|
+
* 例如: `欢迎${username}` -> '欢迎{username}'
|
|
343
|
+
*
|
|
344
|
+
* @default false
|
|
345
|
+
*/
|
|
346
|
+
namedParams?: boolean;
|
|
347
|
+
/**
|
|
348
|
+
* 在 key 中包含参数名
|
|
349
|
+
* 例如: 'app.welcome_{username}_{location}'
|
|
350
|
+
*
|
|
351
|
+
* @default false
|
|
352
|
+
*/
|
|
353
|
+
includeParamsInKey?: boolean;
|
|
354
|
+
/**
|
|
355
|
+
* 自定义占位符生成函数
|
|
356
|
+
* 如果提供,将忽略 prefix/suffix,完全由函数控制格式
|
|
357
|
+
* @param index 占位符索引 (0, 1, 2, ...)
|
|
358
|
+
* @param name 变量名(如果 namedParams 为 true)
|
|
359
|
+
* @returns 占位符字符串,如 '{{0}}', '{username}', '<ph id="0"/>'
|
|
360
|
+
*/
|
|
361
|
+
format?: (index: number, name?: string) => string;
|
|
362
|
+
/**
|
|
363
|
+
* 翻译时使用的占位符格式
|
|
364
|
+
* 某些翻译 API 会修改特定格式的文本,可以指定一个"安全"的格式
|
|
365
|
+
* 翻译完成后会自动转换回标准格式
|
|
366
|
+
*
|
|
367
|
+
* 支持的格式:
|
|
368
|
+
* - 'xml': 使用 <ph id="N"/> 格式(大多数翻译 API 会保留 XML 标签)
|
|
369
|
+
* - 'bracket': 使用 [N] 格式
|
|
370
|
+
* - 'custom': 使用 translationPrefix/translationSuffix 自定义格式
|
|
371
|
+
* - null: 不转换,直接使用原格式
|
|
372
|
+
*
|
|
373
|
+
* @default null (不转换)
|
|
374
|
+
*/
|
|
375
|
+
translationFormat?: 'xml' | 'bracket' | 'custom' | null;
|
|
376
|
+
/**
|
|
377
|
+
* 翻译时使用的自定义前缀(当 translationFormat 为 'custom' 时生效)
|
|
378
|
+
*/
|
|
379
|
+
translationPrefix?: string;
|
|
380
|
+
/**
|
|
381
|
+
* 翻译时使用的自定义后缀(当 translationFormat 为 'custom' 时生效)
|
|
382
|
+
*/
|
|
383
|
+
translationSuffix?: string;
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function findFiles(patterns: string[], excludePatterns?: string[]): Promise<string[]>;
|
|
2
|
+
export declare function ensureOutputDirectory(outputDir: string): void;
|
|
3
|
+
export declare function writeI18nFile(outputDir: string, language: string, data: Record<string, string>): void;
|
|
4
|
+
export declare function groupTextsByFile(extractedTexts: any[]): Map<string, any[]>;
|
|
5
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"AAIA,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,eAAe,GAAE,MAAM,EAAO,GAC7B,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,IAAI,CAGN;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAY1E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findFiles = findFiles;
|
|
4
|
+
exports.ensureOutputDirectory = ensureOutputDirectory;
|
|
5
|
+
exports.writeI18nFile = writeI18nFile;
|
|
6
|
+
exports.groupTextsByFile = groupTextsByFile;
|
|
7
|
+
const glob_1 = require("glob");
|
|
8
|
+
const fs_extra_1 = require("fs-extra");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
async function findFiles(patterns, excludePatterns = []) {
|
|
11
|
+
const allFiles = [];
|
|
12
|
+
for (const pattern of patterns) {
|
|
13
|
+
const files = await (0, glob_1.glob)(pattern, {
|
|
14
|
+
ignore: excludePatterns,
|
|
15
|
+
nodir: true
|
|
16
|
+
});
|
|
17
|
+
allFiles.push(...files);
|
|
18
|
+
}
|
|
19
|
+
return [...new Set(allFiles)]; // Remove duplicates
|
|
20
|
+
}
|
|
21
|
+
function ensureOutputDirectory(outputDir) {
|
|
22
|
+
if (!(0, fs_extra_1.existsSync)(outputDir)) {
|
|
23
|
+
(0, fs_extra_1.ensureDirSync)(outputDir);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function writeI18nFile(outputDir, language, data) {
|
|
27
|
+
const filePath = (0, path_1.join)(outputDir, `${language}.json`);
|
|
28
|
+
(0, fs_extra_1.writeFileSync)(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
function groupTextsByFile(extractedTexts) {
|
|
31
|
+
const grouped = new Map();
|
|
32
|
+
for (const text of extractedTexts) {
|
|
33
|
+
const file = text.file;
|
|
34
|
+
if (!grouped.has(file)) {
|
|
35
|
+
grouped.set(file, []);
|
|
36
|
+
}
|
|
37
|
+
grouped.get(file).push(text);
|
|
38
|
+
}
|
|
39
|
+
return grouped;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":";;AAIA,8BAeC;AAED,sDAIC;AAED,sCAOC;AAED,4CAYC;AAhDD,+BAA4B;AAC5B,uCAAoE;AACpE,+BAA4B;AAErB,KAAK,UAAU,SAAS,CAC7B,QAAkB,EAClB,kBAA4B,EAAE;IAE9B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC,OAAO,EAAE;YAChC,MAAM,EAAE,eAAe;YACvB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,oBAAoB;AACrD,CAAC;AAED,SAAgB,qBAAqB,CAAC,SAAiB;IACrD,IAAI,CAAC,IAAA,qBAAU,EAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAgB,aAAa,CAC3B,SAAiB,EACjB,QAAgB,EAChB,IAA4B;IAE5B,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;IACrD,IAAA,wBAAa,EAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAClE,CAAC;AAED,SAAgB,gBAAgB,CAAC,cAAqB;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { InterpolationConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 插值处理器 - 处理模板字符串中的动态表达式占位符
|
|
4
|
+
*/
|
|
5
|
+
export declare class InterpolationHandler {
|
|
6
|
+
private config;
|
|
7
|
+
constructor(config?: InterpolationConfig);
|
|
8
|
+
/**
|
|
9
|
+
* 是否使用命名参数
|
|
10
|
+
*/
|
|
11
|
+
get useNamedParams(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 是否在 key 中包含参数名
|
|
14
|
+
*/
|
|
15
|
+
get includeParamsInKey(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 生成标准占位符(用于提取和最终输出)
|
|
18
|
+
* @param index 占位符索引
|
|
19
|
+
* @param name 变量名(用于命名参数模式)
|
|
20
|
+
*/
|
|
21
|
+
formatPlaceholder(index: number, name?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* 生成用于 key 的参数后缀
|
|
24
|
+
* 例如: ['username', 'count'] -> '_{username}_{count}'
|
|
25
|
+
*/
|
|
26
|
+
formatKeyParamsSuffix(paramNames: string[]): string;
|
|
27
|
+
/**
|
|
28
|
+
* 生成翻译时使用的占位符
|
|
29
|
+
* 根据 translationFormat 配置决定使用什么格式
|
|
30
|
+
* @param indexOrName 索引或参数名
|
|
31
|
+
*/
|
|
32
|
+
formatForTranslation(indexOrName: number | string): string;
|
|
33
|
+
/**
|
|
34
|
+
* 获取匹配标准占位符的正则表达式
|
|
35
|
+
* 支持索引格式 {{0}} 和命名格式 {{name}}
|
|
36
|
+
*/
|
|
37
|
+
getPlaceholderRegex(): RegExp;
|
|
38
|
+
/**
|
|
39
|
+
* 获取匹配翻译格式占位符的正则表达式
|
|
40
|
+
* 支持索引和命名参数
|
|
41
|
+
*/
|
|
42
|
+
getTranslationFormatRegex(): RegExp;
|
|
43
|
+
/**
|
|
44
|
+
* 将文本中的标准占位符转换为翻译格式
|
|
45
|
+
*/
|
|
46
|
+
convertToTranslationFormat(text: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* 将翻译后的文本中的翻译格式占位符转换回标准格式
|
|
49
|
+
*/
|
|
50
|
+
convertFromTranslationFormat(text: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* 检查文本是否包含占位符
|
|
53
|
+
*/
|
|
54
|
+
hasPlaceholders(text: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 提取文本中的所有占位符索引
|
|
57
|
+
*/
|
|
58
|
+
extractPlaceholderIndices(text: string): number[];
|
|
59
|
+
/**
|
|
60
|
+
* 转义正则表达式特殊字符
|
|
61
|
+
*/
|
|
62
|
+
private escapeRegex;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 创建默认的插值处理器
|
|
66
|
+
*/
|
|
67
|
+
export declare function createInterpolationHandler(config?: InterpolationConfig): InterpolationHandler;
|
|
68
|
+
//# sourceMappingURL=interpolation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpolation.d.ts","sourceRoot":"","sources":["../../src/utils/interpolation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAiF;gBAEnF,MAAM,GAAE,mBAAwB;IAQ5C;;OAEG;IACH,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED;;OAEG;IACH,IAAI,kBAAkB,IAAI,OAAO,CAEhC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAavD;;;OAGG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM;IAOnD;;;;OAIG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;IAwB1D;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAO7B;;;OAGG;IACH,yBAAyB,IAAI,MAAM;IAoBnC;;OAEG;IACH,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAahD;;OAEG;IACH,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAelD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACH,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAUjD;;OAEG;IACH,OAAO,CAAC,WAAW;CAGpB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,oBAAoB,CAE7F"}
|