@babelize/engine 0.1.3 → 0.2.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/dist/analysis/analyze.js +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/detection/stack.d.ts +3 -1
- package/dist/detection/stack.js +13 -6
- package/dist/injection/StrategyFactory.d.ts +5 -1
- package/dist/injection/StrategyFactory.js +7 -2
- package/dist/injection/html/html-injector.d.ts +2 -0
- package/dist/injection/html/html-injector.js +55 -6
- package/dist/injection/strategies/VanillaStrategy.d.ts +8 -0
- package/dist/injection/strategies/VanillaStrategy.js +10 -3
- package/dist/local/translate-core.d.ts +2 -2
- package/dist/local/translate-core.js +2 -2
- package/dist/modules/extractor/extract.js +67 -10
- package/dist/modules/finalization/dependencies.d.ts +10 -0
- package/dist/modules/finalization/dependencies.js +23 -0
- package/dist/modules/finalization/finalize.js +47 -43
- package/dist/modules/finalization/nextjs-finalize.js +2 -1
- package/dist/modules/finalization/react-native-finalize.d.ts +45 -0
- package/dist/modules/finalization/react-native-finalize.js +324 -0
- package/dist/modules/finalization/static-runtime.d.ts +2 -2
- package/dist/modules/finalization/static-runtime.js +10 -5
- package/dist/modules/format-injection/index.js +38 -9
- package/dist/modules/format-injection/inject-formats.d.ts +3 -2
- package/dist/modules/format-injection/inject-formats.js +4 -3
- package/dist/modules/injection/inject.d.ts +14 -1
- package/dist/modules/injection/inject.js +307 -154
- package/dist/modules/sync-detector/sync-detector.js +11 -4
- package/dist/modules/translator/line-breaks.d.ts +8 -0
- package/dist/modules/translator/line-breaks.js +63 -0
- package/dist/modules/translator/translate.js +5 -2
- package/dist/modules/workspace/validate.d.ts +13 -1
- package/dist/modules/workspace/validate.js +95 -58
- package/dist/runtime/types.d.ts +22 -0
- package/dist/runtime/types.js +33 -0
- package/dist/utils/ast-helpers.d.ts +30 -2
- package/dist/utils/ast-helpers.js +355 -42
- package/dist/utils/extraction-options.js +1 -1
- package/dist/utils/file-utils.js +4 -1
- package/dist/utils/i18n-config-path.d.ts +18 -0
- package/dist/utils/i18n-config-path.js +64 -0
- package/dist/utils/i18next-icu.js +1 -1
- package/dist/utils/jsx-message.d.ts +16 -1
- package/dist/utils/jsx-message.js +89 -9
- package/dist/utils/key-usage.js +1 -1
- package/dist/utils/metadata.d.ts +5 -1
- package/dist/utils/metadata.js +19 -1
- package/dist/utils/module-constants.d.ts +21 -3
- package/dist/utils/module-constants.js +123 -25
- package/dist/utils/react-native.d.ts +17 -0
- package/dist/utils/react-native.js +108 -0
- package/dist/utils/string-utils.d.ts +8 -0
- package/dist/utils/string-utils.js +29 -1
- package/dist/utils/ui-copy.d.ts +5 -4
- package/dist/utils/ui-copy.js +10 -5
- package/package.json +3 -2
|
@@ -41,7 +41,19 @@ const inject_formats_1 = require("./inject-formats");
|
|
|
41
41
|
const ast_helpers_1 = require("../../utils/ast-helpers");
|
|
42
42
|
const file_utils_1 = require("../../utils/file-utils");
|
|
43
43
|
const types_1 = require("../../runtime/types");
|
|
44
|
+
const StrategyFactory_1 = require("../../injection/StrategyFactory");
|
|
44
45
|
const generator_1 = require("@babel/generator");
|
|
46
|
+
/** The local name of `import X from 'i18next'` in a file, if it has one. */
|
|
47
|
+
function i18nextDefaultImport(ast) {
|
|
48
|
+
for (const node of ast.program.body) {
|
|
49
|
+
if (!t.isImportDeclaration(node) || node.source.value !== 'i18next')
|
|
50
|
+
continue;
|
|
51
|
+
const def = node.specifiers.find((s) => t.isImportDefaultSpecifier(s));
|
|
52
|
+
if (def)
|
|
53
|
+
return def.local.name;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
45
57
|
/**
|
|
46
58
|
* Run format injection for all format strings.
|
|
47
59
|
*
|
|
@@ -66,13 +78,20 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
66
78
|
}
|
|
67
79
|
stringsByFile.get(fileKey).push(s);
|
|
68
80
|
}
|
|
69
|
-
//
|
|
70
|
-
|
|
81
|
+
// The locale the formatted values follow. react-i18next (React, React
|
|
82
|
+
// Native, Next.js with react-i18next): the app's current language,
|
|
83
|
+
// `i18next.language` — React Native has no navigator.language, and on the
|
|
84
|
+
// web it ignored the language the user picked. Before init it is undefined,
|
|
85
|
+
// which Intl reads as the device default. Elsewhere the browser's language:
|
|
86
|
+
// next-intl's useLocale() and vue-i18n's composable only work in components.
|
|
87
|
+
const deps = { ...workspace.packageJson?.dependencies, ...workspace.packageJson?.devDependencies };
|
|
88
|
+
const followsI18next = StrategyFactory_1.StrategyFactory.getStrategy(workspace.framework || 'unknown', deps).id === 'react-i18next';
|
|
89
|
+
const browserLocaleExpr = (0, inject_formats_1.buildLocaleExpression)('browser');
|
|
71
90
|
// Find all source files
|
|
72
91
|
const sourceFiles = [];
|
|
73
92
|
for (const sourceDir of workspace.sourceDirs) {
|
|
74
93
|
const dirPath = path.join(workspace.path, sourceDir);
|
|
75
|
-
const files = await (0, file_utils_1.findFiles)(dirPath, types_1.SUPPORTED_EXTENSIONS, types_1.
|
|
94
|
+
const files = await (0, file_utils_1.findFiles)(dirPath, types_1.SUPPORTED_EXTENSIONS, (0, types_1.workspaceExcludes)(workspace));
|
|
76
95
|
sourceFiles.push(...files);
|
|
77
96
|
}
|
|
78
97
|
// Build a lookup of format strings by (relative file path, line)
|
|
@@ -93,11 +112,17 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
93
112
|
try {
|
|
94
113
|
const originalContent = await (0, file_utils_1.readFile)(filePath);
|
|
95
114
|
const isTypeScript = filePath.endsWith('.ts') || filePath.endsWith('.tsx');
|
|
96
|
-
const ast = (0, ast_helpers_1.parseCode)(originalContent, { isTypeScript });
|
|
115
|
+
const ast = (0, ast_helpers_1.parseCode)(originalContent, { isTypeScript, preserveFormat: true });
|
|
97
116
|
const injections = [];
|
|
98
117
|
const lineLookup = formatStringLookup.get(relativePath);
|
|
99
118
|
if (!lineLookup)
|
|
100
119
|
continue;
|
|
120
|
+
const existingI18next = followsI18next ? i18nextDefaultImport(ast) : null;
|
|
121
|
+
// A name nothing else in the file binds (`import * as i18next from 'i18next'`, a local `i18next`).
|
|
122
|
+
const i18nextName = existingI18next ?? ((0, ast_helpers_1.bindsTopLevel)(ast, 'i18next') ? 'i18nextInstance' : 'i18next');
|
|
123
|
+
const fileLocaleExpr = followsI18next
|
|
124
|
+
? t.memberExpression(t.identifier(i18nextName), t.identifier('language'))
|
|
125
|
+
: browserLocaleExpr;
|
|
101
126
|
// Walk AST and replace matching string literals with Intl.* expressions
|
|
102
127
|
(0, ast_helpers_1.traverse)(ast, {
|
|
103
128
|
StringLiteral(strPath) {
|
|
@@ -111,7 +136,7 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
111
136
|
// Verify the text matches exactly (avoid false positives from partial matches)
|
|
112
137
|
if (node.value !== formatStr.text)
|
|
113
138
|
return;
|
|
114
|
-
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig,
|
|
139
|
+
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig, t.cloneNode(fileLocaleExpr));
|
|
115
140
|
if (!astExpr) {
|
|
116
141
|
skippedFiles.push({
|
|
117
142
|
file: relativePath,
|
|
@@ -144,7 +169,7 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
144
169
|
const text = node.value.trim();
|
|
145
170
|
if (!text)
|
|
146
171
|
return;
|
|
147
|
-
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig,
|
|
172
|
+
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig, t.cloneNode(fileLocaleExpr));
|
|
148
173
|
if (!astExpr) {
|
|
149
174
|
skippedFiles.push({
|
|
150
175
|
file: relativePath,
|
|
@@ -170,6 +195,10 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
170
195
|
});
|
|
171
196
|
if (injections.length === 0)
|
|
172
197
|
continue;
|
|
198
|
+
const importAdded = followsI18next && !existingI18next;
|
|
199
|
+
if (importAdded) {
|
|
200
|
+
ast.program.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier(i18nextName))], t.stringLiteral('i18next')));
|
|
201
|
+
}
|
|
173
202
|
const modifiedContent = (0, ast_helpers_1.generateCode)(ast, originalContent);
|
|
174
203
|
if (!dryRun) {
|
|
175
204
|
await (0, file_utils_1.writeFile)(filePath, modifiedContent);
|
|
@@ -179,7 +208,7 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
179
208
|
originalContent,
|
|
180
209
|
modifiedContent,
|
|
181
210
|
injections,
|
|
182
|
-
importAdded
|
|
211
|
+
importAdded,
|
|
183
212
|
hookAdded: false,
|
|
184
213
|
});
|
|
185
214
|
totalInjections += injections.length;
|
|
@@ -196,7 +225,7 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
196
225
|
const htmlExtensions = ['.html', '.htm'];
|
|
197
226
|
for (const sourceDir of workspace.sourceDirs) {
|
|
198
227
|
const dirPath = path.join(workspace.path, sourceDir);
|
|
199
|
-
const files = await (0, file_utils_1.findFiles)(dirPath, htmlExtensions, types_1.
|
|
228
|
+
const files = await (0, file_utils_1.findFiles)(dirPath, htmlExtensions, (0, types_1.workspaceExcludes)(workspace));
|
|
200
229
|
for (const filePath of files) {
|
|
201
230
|
const relativePath = (0, file_utils_1.getRelativePath)(workspace.path, filePath);
|
|
202
231
|
const fileStrings = stringsByFile.get(relativePath);
|
|
@@ -213,7 +242,7 @@ async function injectFormats(workspace, formatStrings, formatConfig, dryRun = fa
|
|
|
213
242
|
const regex = new RegExp(escaped, 'g');
|
|
214
243
|
if (!regex.test(content))
|
|
215
244
|
continue;
|
|
216
|
-
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig,
|
|
245
|
+
const astExpr = (0, inject_formats_1.buildFormatAstExpression)(formatStr.detectedFormat, formatConfig, browserLocaleExpr);
|
|
217
246
|
if (!astExpr)
|
|
218
247
|
continue;
|
|
219
248
|
const replacementCode = (0, generator_1.generate)(astExpr).code;
|
|
@@ -26,6 +26,7 @@ export declare function buildFormatInjection(extracted: ExtractedString, formatC
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function buildFormatAstExpression(format: DetectedFormat, formatConfig: FormatLocaleConfig, localeExpr: t.Expression): t.Expression | null;
|
|
28
28
|
/**
|
|
29
|
-
* Build a locale expression
|
|
29
|
+
* Build a locale expression for an i18n library (an injection strategy id:
|
|
30
|
+
* 'react-i18next', 'next-intl'); anything else gets the browser's language.
|
|
30
31
|
*/
|
|
31
|
-
export declare function buildLocaleExpression(
|
|
32
|
+
export declare function buildLocaleExpression(library: string): t.Expression;
|
|
@@ -194,10 +194,11 @@ function buildNumberAstExpression(format, localeExpr) {
|
|
|
194
194
|
return t.callExpression(t.memberExpression(nfNew, t.identifier('format')), [t.numericLiteral(numericValue)]);
|
|
195
195
|
}
|
|
196
196
|
/**
|
|
197
|
-
* Build a locale expression
|
|
197
|
+
* Build a locale expression for an i18n library (an injection strategy id:
|
|
198
|
+
* 'react-i18next', 'next-intl'); anything else gets the browser's language.
|
|
198
199
|
*/
|
|
199
|
-
function buildLocaleExpression(
|
|
200
|
-
switch (
|
|
200
|
+
function buildLocaleExpression(library) {
|
|
201
|
+
switch (library) {
|
|
201
202
|
case 'react-i18next':
|
|
202
203
|
return t.memberExpression(t.identifier('i18n'), t.identifier('language'));
|
|
203
204
|
case 'next-intl':
|
|
@@ -14,7 +14,20 @@ positions?: Map<string, Set<number>>): Promise<InjectionResult>;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function injectIntoFile(content: string, filePath: string, keyMapping: Map<string, string>, confidenceThreshold: number, framework: string, existingDeps?: Record<string, string>, forceTypeScript?: boolean,
|
|
16
16
|
/** extractionId → source offsets of the nodes extraction selected (see ExtractedString.offsets). */
|
|
17
|
-
positions?: Map<string, Set<number
|
|
17
|
+
positions?: Map<string, Set<number>>, options?: {
|
|
18
|
+
/**
|
|
19
|
+
* Import path (relative to this file) of the i18n config's module-level `t`.
|
|
20
|
+
* Set when Babelize owns the react-i18next config: strings outside any
|
|
21
|
+
* component the hook can go in use it. Unset, they are left as they are.
|
|
22
|
+
*/
|
|
23
|
+
moduleTranslator?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Messages with placeholders are formatted at runtime (ICU): template
|
|
26
|
+
* literals and `+` concatenations become `t(key, { name })`. Off, they
|
|
27
|
+
* are left as they are.
|
|
28
|
+
*/
|
|
29
|
+
placeholders?: boolean;
|
|
30
|
+
}): FileInjection;
|
|
18
31
|
/**
|
|
19
32
|
* Inject translations into a Vue SFC file.
|
|
20
33
|
* Uses @vue/compiler-sfc to parse, vue/template-scan to find translatable
|