ai-localize-cli 2.0.7 → 3.1.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/cli.js +41 -19
  3. package/package.json +10 -10
package/CHANGELOG.md CHANGED
@@ -1,7 +1,42 @@
1
1
  # ai-localize-cli
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **`copyDefaultValues` config option** — `extract` command now passes `copyDefaultValues` from `ai-localize.config.json` to `LocaleExtractor`. When `true`, target language locale files are pre-populated with the default language's source text values instead of empty strings, ensuring the app always has a visible fallback while translators fill in proper translations.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - ai-localize-config@3.1.0
13
+ - ai-localize-locale-engine@3.1.0
14
+
15
+ ## 3.0.0
16
+
17
+ ### Major Changes
18
+
19
+ - bug fixes
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies
24
+ - ai-localize-aws-cloudfront@3.0.0
25
+ - ai-localize-codemods@3.0.0
26
+ - ai-localize-config@3.0.0
27
+ - ai-localize-framework-detectors@3.0.0
28
+ - ai-localize-locale-engine@3.0.0
29
+ - ai-localize-reporting@3.0.0
30
+ - ai-localize-scanner@3.0.0
31
+ - ai-localize-shared@3.0.0
32
+ - ai-localize-validators@3.0.0
33
+
3
34
  ## 2.0.7
4
35
 
36
+ ### Fixed
37
+
38
+ - **`ai-localize scan` no longer crashes with `(0 , import_traverse.default) is not a function`** — Fixed `@babel/traverse` and `@babel/generator` CJS/ESM interop in the bundled CLI. The scanner and React codemod now work correctly when installed from npm.
39
+
5
40
  ### Minor Changes
6
41
 
7
42
  - **Scanner now correctly skips CSS class names, font-family values, camelCase identifiers,
@@ -39,7 +74,7 @@
39
74
  - **Bug fix — `full-migrate` pipeline appeared to do nothing**: Three issues fixed:
40
75
  1. `staticKeys` from `ai-localize.config.json` are now correctly passed to `LocaleExtractor`
41
76
  in the `full-migrate` command (the standalone `extract` command already did this).
42
- 2. `--dry-run` mode now prints a clear yellow banner, lists every locale file that *would*
77
+ 2. `--dry-run` mode now prints a clear yellow banner, lists every locale file that _would_
43
78
  be written, and skips validation/report with an explanatory message — previously it
44
79
  produced no output for the write step, making the pipeline look inactive.
45
80
  3. Validation and report phases now run only in non-dry-run mode; error/warning details
package/dist/cli.js CHANGED
@@ -247274,7 +247274,7 @@ var require_lib5 = __commonJS({
247274
247274
  Object.defineProperty(exports2, "traverse", {
247275
247275
  enumerable: true,
247276
247276
  get: function() {
247277
- return _traverse.default;
247277
+ return _traverse3.default;
247278
247278
  }
247279
247279
  });
247280
247280
  Object.defineProperty(exports2, "traverseFast", {
@@ -247405,15 +247405,15 @@ var require_lib5 = __commonJS({
247405
247405
  var _getBindingIdentifiers = require_getBindingIdentifiers();
247406
247406
  var _getOuterBindingIdentifiers = require_getOuterBindingIdentifiers();
247407
247407
  var _getFunctionName = require_getFunctionName();
247408
- var _traverse = require_traverse();
247409
- Object.keys(_traverse).forEach(function(key) {
247408
+ var _traverse3 = require_traverse();
247409
+ Object.keys(_traverse3).forEach(function(key) {
247410
247410
  if (key === "default" || key === "__esModule") return;
247411
247411
  if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
247412
- if (key in exports2 && exports2[key] === _traverse[key]) return;
247412
+ if (key in exports2 && exports2[key] === _traverse3[key]) return;
247413
247413
  Object.defineProperty(exports2, key, {
247414
247414
  enumerable: true,
247415
247415
  get: function() {
247416
- return _traverse[key];
247416
+ return _traverse3[key];
247417
247417
  }
247418
247418
  });
247419
247419
  });
@@ -248038,8 +248038,8 @@ var require_traverseForScope = __commonJS({
248038
248038
  if (exploded.enter || exploded.exit) {
248039
248039
  throw new Error("Should not be used with enter/exit visitors.");
248040
248040
  }
248041
- _traverse(path19.parentPath, path19.parent, path19.node, path19.container, path19.key, path19.listKey, path19.hub, path19);
248042
- function _traverse(parentPath, parent, node, container, key, listKey, hub, inPath) {
248041
+ _traverse3(path19.parentPath, path19.parent, path19.node, path19.container, path19.key, path19.listKey, path19.hub, path19);
248042
+ function _traverse3(parentPath, parent, node, container, key, listKey, hub, inPath) {
248043
248043
  if (!node) {
248044
248044
  return;
248045
248045
  }
@@ -248071,10 +248071,10 @@ var require_traverseForScope = __commonJS({
248071
248071
  if (Array.isArray(prop)) {
248072
248072
  for (let i7 = 0; i7 < prop.length; i7++) {
248073
248073
  const value = prop[i7];
248074
- _traverse(path20, node, value, prop, i7, key2);
248074
+ _traverse3(path20, node, value, prop, i7, key2);
248075
248075
  }
248076
248076
  } else {
248077
- _traverse(path20, node, prop, node, key2, null);
248077
+ _traverse3(path20, node, prop, node, key2, null);
248078
248078
  }
248079
248079
  }
248080
248080
  if (visitor != null && visitor.exit) {
@@ -294057,7 +294057,7 @@ async function batchReplaceCdnUrls(fileUrlMap, assets, dryRun = false) {
294057
294057
  }
294058
294058
  return results;
294059
294059
  }
294060
- var fs10, nodePath2, parser3, import_traverse2, import_generator, t9, fs24, fs33, fs43, path11, path24, DEFAULT_IMPORT_PACKAGE, DEFAULT_HOOK_NAME, DEFAULT_TRANSLATION_FN, DEFAULT_ACCESSOR_STYLE, ReactCodemod, DEFAULT_TRANSLATION_FN2, VueCodemod, DEFAULT_TS_SERVICE, DEFAULT_TEMPLATE_PIPE, AngularCodemod, CdnReplacer, CodemodRunner;
294060
+ var fs10, nodePath2, parser3, import_traverse2, import_generator, t9, fs24, fs33, fs43, path11, path24, traverse2, generate, DEFAULT_IMPORT_PACKAGE, DEFAULT_HOOK_NAME, DEFAULT_TRANSLATION_FN, DEFAULT_ACCESSOR_STYLE, ReactCodemod, DEFAULT_TRANSLATION_FN2, VueCodemod, DEFAULT_TS_SERVICE, DEFAULT_TEMPLATE_PIPE, AngularCodemod, CdnReplacer, CodemodRunner;
294061
294061
  var init_dist = __esm({
294062
294062
  "../../packages/codemods/dist/index.mjs"() {
294063
294063
  "use strict";
@@ -294072,6 +294072,8 @@ var init_dist = __esm({
294072
294072
  fs43 = __toESM(require("fs"), 1);
294073
294073
  path11 = __toESM(require("path"), 1);
294074
294074
  path24 = __toESM(require("path"), 1);
294075
+ traverse2 = import_traverse2.default.default ?? import_traverse2.default;
294076
+ generate = import_generator.default.default ?? import_generator.default;
294075
294077
  DEFAULT_IMPORT_PACKAGE = "react-i18next";
294076
294078
  DEFAULT_HOOK_NAME = "useTranslation";
294077
294079
  DEFAULT_TRANSLATION_FN = "t";
@@ -294158,7 +294160,7 @@ var init_dist = __esm({
294158
294160
  }
294159
294161
  return t9.callExpression(t9.identifier(translationFn), [t9.stringLiteral(key)]);
294160
294162
  };
294161
- (0, import_traverse2.default)(ast, {
294163
+ traverse2(ast, {
294162
294164
  ImportDeclaration(nodePath22) {
294163
294165
  if (nodePath22.node.source.value === importSpecifier2) {
294164
294166
  hasImport = true;
@@ -294173,7 +294175,7 @@ var init_dist = __esm({
294173
294175
  }
294174
294176
  }
294175
294177
  });
294176
- (0, import_traverse2.default)(ast, {
294178
+ traverse2(ast, {
294177
294179
  JSXText(nodePath22) {
294178
294180
  const text = nodePath22.node.value.trim();
294179
294181
  if (!text) return;
@@ -294225,7 +294227,7 @@ var init_dist = __esm({
294225
294227
  this.injectHook(ast);
294226
294228
  injectedHook = true;
294227
294229
  }
294228
- const output = (0, import_generator.default)(
294230
+ const output = generate(
294229
294231
  ast,
294230
294232
  { retainLines: false, comments: true, compact: false },
294231
294233
  this.content
@@ -294244,7 +294246,7 @@ var init_dist = __esm({
294244
294246
  const hookName = this.hookName;
294245
294247
  const translationFn = this.translationFn;
294246
294248
  const namespace = this.namespace;
294247
- (0, import_traverse2.default)(ast, {
294249
+ traverse2(ast, {
294248
294250
  FunctionDeclaration(nodePath22) {
294249
294251
  if (!isReactComponent(nodePath22.node.id?.name)) return;
294250
294252
  injectHookIntoBody(nodePath22.node.body, hookName, translationFn, namespace);
@@ -298929,7 +298931,24 @@ var LocalizationConfigSchema = external_exports.object({
298929
298931
  * Example:
298930
298932
  * "ignoreTextPatterns": ["^MyBrand", "^theme-", "^data-"]
298931
298933
  */
298932
- ignoreTextPatterns: external_exports.array(external_exports.string()).default([])
298934
+ ignoreTextPatterns: external_exports.array(external_exports.string()).default([]),
298935
+ /**
298936
+ * When `true`, target language locale files are pre-populated with the same
298937
+ * source text values as the default language instead of empty strings.
298938
+ *
298939
+ * This ensures the app always has a visible fallback value while translators
298940
+ * work on proper translations. Empty-string values cause the UI to show
298941
+ * nothing at all for untranslated keys.
298942
+ *
298943
+ * Applies to both `extract` (new files) and `sync` (adding missing keys to
298944
+ * existing files).
298945
+ *
298946
+ * Defaults to `false`.
298947
+ *
298948
+ * Example:
298949
+ * "copyDefaultValues": true
298950
+ */
298951
+ copyDefaultValues: external_exports.boolean().default(false)
298933
298952
  });
298934
298953
  async function loadConfig(cwd = process.cwd(), overrides = {}) {
298935
298954
  dotenv.config({ path: path2.join(cwd, ".env") });
@@ -299339,6 +299358,7 @@ var os = __toESM(require("os"), 1);
299339
299358
  var crypto22 = __toESM(require("crypto"), 1);
299340
299359
  var import_child_process = require("child_process");
299341
299360
  var path42 = __toESM(require("path"), 1);
299361
+ var traverse = import_traverse.default.default ?? import_traverse.default;
299342
299362
  var BUILTIN_TRANSLATION_IMPORT_SOURCES = /* @__PURE__ */ new Set([
299343
299363
  "react-i18next",
299344
299364
  "i18next",
@@ -299634,7 +299654,7 @@ var AstScanner = class {
299634
299654
  return this.regexFallbackScan();
299635
299655
  }
299636
299656
  this.collectTranslationImports(ast);
299637
- (0, import_traverse.default)(ast, {
299657
+ traverse(ast, {
299638
299658
  // ── JSX text nodes: <h1>Welcome</h1> ───────────────────────────────────
299639
299659
  JSXText: (nodePath3) => {
299640
299660
  const text = normalizeText(nodePath3.node.value);
@@ -300271,7 +300291,8 @@ var LocaleExtractor = class {
300271
300291
  defaultLanguage: options.defaultLanguage || "en",
300272
300292
  targetLanguages: options.targetLanguages || [],
300273
300293
  namespaceSplitting: options.namespaceSplitting ?? true,
300274
- staticKeys: options.staticKeys ?? {}
300294
+ staticKeys: options.staticKeys ?? {},
300295
+ copyDefaultValues: options.copyDefaultValues ?? false
300275
300296
  };
300276
300297
  }
300277
300298
  extract(detectedTexts) {
@@ -300314,7 +300335,7 @@ var LocaleExtractor = class {
300314
300335
  for (const lang of allLanguages) {
300315
300336
  for (const [namespace, entries] of namespaceMap) {
300316
300337
  const isDefault = lang === this.options.defaultLanguage;
300317
- const langEntries = isDefault ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k7) => [k7, ""]));
300338
+ const langEntries = isDefault || this.options.copyDefaultValues ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k7) => [k7, ""]));
300318
300339
  localeFiles.push({ language: lang, namespace, entries: langEntries, filePath: "" });
300319
300340
  }
300320
300341
  }
@@ -300469,7 +300490,8 @@ function extractCommand() {
300469
300490
  targetLanguages: config2.targetLanguages,
300470
300491
  namespaceSplitting: structure === "nested",
300471
300492
  // flat mode does not need namespace splitting
300472
- staticKeys
300493
+ staticKeys,
300494
+ copyDefaultValues: config2.copyDefaultValues
300473
300495
  });
300474
300496
  const { localeFiles, keyCount, namespaces } = extractor.extract(uniqueTexts);
300475
300497
  logger.info(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-localize-cli",
3
- "version": "2.0.7",
3
+ "version": "3.1.0",
4
4
  "description": "CLI for ai-localize-core: scan, extract, validate, codemod and migrate CDN",
5
5
  "author": "ai-localize-core contributors",
6
6
  "license": "MIT",
@@ -46,15 +46,15 @@
46
46
  "chalk": "^5.3.0",
47
47
  "ora": "^8.0.1",
48
48
  "inquirer": "^9.2.12",
49
- "ai-localize-config": "2.0.7",
50
- "ai-localize-framework-detectors": "2.0.7",
51
- "ai-localize-scanner": "2.0.7",
52
- "ai-localize-shared": "2.0.7",
53
- "ai-localize-codemods": "2.0.7",
54
- "ai-localize-locale-engine": "2.0.7",
55
- "ai-localize-validators": "2.0.7",
56
- "ai-localize-aws-cloudfront": "2.0.7",
57
- "ai-localize-reporting": "2.0.7"
49
+ "ai-localize-shared": "3.0.0",
50
+ "ai-localize-config": "3.1.0",
51
+ "ai-localize-codemods": "3.0.0",
52
+ "ai-localize-scanner": "3.0.0",
53
+ "ai-localize-framework-detectors": "3.0.0",
54
+ "ai-localize-validators": "3.0.0",
55
+ "ai-localize-locale-engine": "3.1.0",
56
+ "ai-localize-aws-cloudfront": "3.0.0",
57
+ "ai-localize-reporting": "3.0.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/inquirer": "^9.0.7",