ai-localize-locale-engine 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # ai-localize-locale-engine
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **`copyDefaultValues` option in `LocaleExtractor`** — Added `copyDefaultValues?: boolean` to `ExtractOptions`. When `true`, target language locale files are pre-populated with the default language's source text values instead of empty strings. Defaults to `false` for backward compatibility.
8
+ - **`copyDefaultValues` option in `LocaleSynchronizer`** — Added `SyncOptions` interface with `copyDefaultValues?: boolean`. When `true`, newly added keys in target language files are seeded from the default language file instead of using empty strings.
9
+
10
+ ## 3.0.0
11
+
12
+ ### Major Changes
13
+
14
+ - bug fixes
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+ - ai-localize-shared@3.0.0
20
+
3
21
  ## 2.0.7
4
22
 
5
23
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -24,6 +24,18 @@ interface ExtractOptions {
24
24
  * }
25
25
  */
26
26
  staticKeys?: Record<string, string>;
27
+ /**
28
+ * When `true`, target language locale files are pre-populated with the same
29
+ * source text values as the default language instead of empty strings.
30
+ *
31
+ * This ensures the app always has a visible fallback value while translators
32
+ * work on proper translations. Empty-string values cause the UI to show
33
+ * nothing at all for untranslated keys.
34
+ *
35
+ * Defaults to `false` to preserve backward-compatible behaviour (empty
36
+ * strings for target languages).
37
+ */
38
+ copyDefaultValues?: boolean;
27
39
  }
28
40
  interface ExtractionResult {
29
41
  localeFiles: LocaleFile[];
@@ -88,14 +100,29 @@ declare function deduplicateTexts(texts: DetectedText[]): DetectedText[];
88
100
  declare function filterAlreadyTranslated(texts: DetectedText[], existingKeys: Set<string>): DetectedText[];
89
101
  declare function findUnusedKeys(localeKeys: string[], sourceKeys: string[]): string[];
90
102
 
103
+ interface SyncOptions {
104
+ /**
105
+ * When `true`, newly added keys in target language files are pre-populated
106
+ * with the same source text value from the default language file instead of
107
+ * an empty string.
108
+ *
109
+ * This ensures the app always has a visible fallback value while translators
110
+ * work on proper translations. Empty-string values cause the UI to show
111
+ * nothing at all for untranslated keys.
112
+ *
113
+ * Defaults to `false` to preserve backward-compatible behaviour.
114
+ */
115
+ copyDefaultValues?: boolean;
116
+ }
91
117
  declare class LocaleSynchronizer {
92
118
  private localesDir;
93
119
  private defaultLanguage;
94
- constructor(localesDir: string, defaultLanguage?: string);
120
+ private options;
121
+ constructor(localesDir: string, defaultLanguage?: string, options?: SyncOptions);
95
122
  sync(): {
96
123
  updated: string[];
97
124
  addedKeys: number;
98
125
  };
99
126
  }
100
127
 
101
- export { type ExtractOptions, type ExtractionResult, LocaleExtractor, LocaleSynchronizer, LocaleWriter, type WriteOptions, deduplicateTexts, filterAlreadyTranslated, findUnusedKeys };
128
+ export { type ExtractOptions, type ExtractionResult, LocaleExtractor, LocaleSynchronizer, LocaleWriter, type SyncOptions, type WriteOptions, deduplicateTexts, filterAlreadyTranslated, findUnusedKeys };
package/dist/index.d.ts CHANGED
@@ -24,6 +24,18 @@ interface ExtractOptions {
24
24
  * }
25
25
  */
26
26
  staticKeys?: Record<string, string>;
27
+ /**
28
+ * When `true`, target language locale files are pre-populated with the same
29
+ * source text values as the default language instead of empty strings.
30
+ *
31
+ * This ensures the app always has a visible fallback value while translators
32
+ * work on proper translations. Empty-string values cause the UI to show
33
+ * nothing at all for untranslated keys.
34
+ *
35
+ * Defaults to `false` to preserve backward-compatible behaviour (empty
36
+ * strings for target languages).
37
+ */
38
+ copyDefaultValues?: boolean;
27
39
  }
28
40
  interface ExtractionResult {
29
41
  localeFiles: LocaleFile[];
@@ -88,14 +100,29 @@ declare function deduplicateTexts(texts: DetectedText[]): DetectedText[];
88
100
  declare function filterAlreadyTranslated(texts: DetectedText[], existingKeys: Set<string>): DetectedText[];
89
101
  declare function findUnusedKeys(localeKeys: string[], sourceKeys: string[]): string[];
90
102
 
103
+ interface SyncOptions {
104
+ /**
105
+ * When `true`, newly added keys in target language files are pre-populated
106
+ * with the same source text value from the default language file instead of
107
+ * an empty string.
108
+ *
109
+ * This ensures the app always has a visible fallback value while translators
110
+ * work on proper translations. Empty-string values cause the UI to show
111
+ * nothing at all for untranslated keys.
112
+ *
113
+ * Defaults to `false` to preserve backward-compatible behaviour.
114
+ */
115
+ copyDefaultValues?: boolean;
116
+ }
91
117
  declare class LocaleSynchronizer {
92
118
  private localesDir;
93
119
  private defaultLanguage;
94
- constructor(localesDir: string, defaultLanguage?: string);
120
+ private options;
121
+ constructor(localesDir: string, defaultLanguage?: string, options?: SyncOptions);
95
122
  sync(): {
96
123
  updated: string[];
97
124
  addedKeys: number;
98
125
  };
99
126
  }
100
127
 
101
- export { type ExtractOptions, type ExtractionResult, LocaleExtractor, LocaleSynchronizer, LocaleWriter, type WriteOptions, deduplicateTexts, filterAlreadyTranslated, findUnusedKeys };
128
+ export { type ExtractOptions, type ExtractionResult, LocaleExtractor, LocaleSynchronizer, LocaleWriter, type SyncOptions, type WriteOptions, deduplicateTexts, filterAlreadyTranslated, findUnusedKeys };
package/dist/index.js CHANGED
@@ -48,7 +48,8 @@ var LocaleExtractor = class {
48
48
  defaultLanguage: options.defaultLanguage || "en",
49
49
  targetLanguages: options.targetLanguages || [],
50
50
  namespaceSplitting: options.namespaceSplitting ?? true,
51
- staticKeys: options.staticKeys ?? {}
51
+ staticKeys: options.staticKeys ?? {},
52
+ copyDefaultValues: options.copyDefaultValues ?? false
52
53
  };
53
54
  }
54
55
  extract(detectedTexts) {
@@ -91,7 +92,7 @@ var LocaleExtractor = class {
91
92
  for (const lang of allLanguages) {
92
93
  for (const [namespace, entries] of namespaceMap) {
93
94
  const isDefault = lang === this.options.defaultLanguage;
94
- const langEntries = isDefault ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k) => [k, ""]));
95
+ const langEntries = isDefault || this.options.copyDefaultValues ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k) => [k, ""]));
95
96
  localeFiles.push({ language: lang, namespace, entries: langEntries, filePath: "" });
96
97
  }
97
98
  }
@@ -235,15 +236,18 @@ var fs = __toESM(require("fs"));
235
236
  var path2 = __toESM(require("path"));
236
237
  var import_ai_localize_shared3 = require("ai-localize-shared");
237
238
  var LocaleSynchronizer = class {
238
- constructor(localesDir, defaultLanguage = "en") {
239
+ constructor(localesDir, defaultLanguage = "en", options = {}) {
239
240
  this.localesDir = localesDir;
240
241
  this.defaultLanguage = defaultLanguage;
242
+ this.options = options;
241
243
  }
242
244
  localesDir;
243
245
  defaultLanguage;
246
+ options;
244
247
  sync() {
245
248
  const updated = [];
246
249
  let addedKeys = 0;
250
+ const copyDefaultValues = this.options.copyDefaultValues ?? false;
247
251
  const defaultDir = path2.join(this.localesDir, this.defaultLanguage);
248
252
  if (!fs.existsSync(defaultDir)) return { updated, addedKeys };
249
253
  const defaultFiles = fs.readdirSync(defaultDir).filter((f) => f.endsWith(".json"));
@@ -258,7 +262,7 @@ var LocaleSynchronizer = class {
258
262
  let changed = false;
259
263
  for (const key of Object.keys(defaultEntries)) {
260
264
  if (!(key in existing)) {
261
- existing[key] = "";
265
+ existing[key] = copyDefaultValues ? defaultEntries[key] ?? "" : "";
262
266
  addedKeys++;
263
267
  changed = true;
264
268
  }
package/dist/index.mjs CHANGED
@@ -11,7 +11,8 @@ var LocaleExtractor = class {
11
11
  defaultLanguage: options.defaultLanguage || "en",
12
12
  targetLanguages: options.targetLanguages || [],
13
13
  namespaceSplitting: options.namespaceSplitting ?? true,
14
- staticKeys: options.staticKeys ?? {}
14
+ staticKeys: options.staticKeys ?? {},
15
+ copyDefaultValues: options.copyDefaultValues ?? false
15
16
  };
16
17
  }
17
18
  extract(detectedTexts) {
@@ -54,7 +55,7 @@ var LocaleExtractor = class {
54
55
  for (const lang of allLanguages) {
55
56
  for (const [namespace, entries] of namespaceMap) {
56
57
  const isDefault = lang === this.options.defaultLanguage;
57
- const langEntries = isDefault ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k) => [k, ""]));
58
+ const langEntries = isDefault || this.options.copyDefaultValues ? { ...entries } : Object.fromEntries(Object.keys(entries).map((k) => [k, ""]));
58
59
  localeFiles.push({ language: lang, namespace, entries: langEntries, filePath: "" });
59
60
  }
60
61
  }
@@ -198,15 +199,18 @@ import * as fs from "fs";
198
199
  import * as path2 from "path";
199
200
  import { readJsonSafe as readJsonSafe2, writeJson as writeJson2, ensureDir as ensureDir2 } from "ai-localize-shared";
200
201
  var LocaleSynchronizer = class {
201
- constructor(localesDir, defaultLanguage = "en") {
202
+ constructor(localesDir, defaultLanguage = "en", options = {}) {
202
203
  this.localesDir = localesDir;
203
204
  this.defaultLanguage = defaultLanguage;
205
+ this.options = options;
204
206
  }
205
207
  localesDir;
206
208
  defaultLanguage;
209
+ options;
207
210
  sync() {
208
211
  const updated = [];
209
212
  let addedKeys = 0;
213
+ const copyDefaultValues = this.options.copyDefaultValues ?? false;
210
214
  const defaultDir = path2.join(this.localesDir, this.defaultLanguage);
211
215
  if (!fs.existsSync(defaultDir)) return { updated, addedKeys };
212
216
  const defaultFiles = fs.readdirSync(defaultDir).filter((f) => f.endsWith(".json"));
@@ -221,7 +225,7 @@ var LocaleSynchronizer = class {
221
225
  let changed = false;
222
226
  for (const key of Object.keys(defaultEntries)) {
223
227
  if (!(key in existing)) {
224
- existing[key] = "";
228
+ existing[key] = copyDefaultValues ? defaultEntries[key] ?? "" : "";
225
229
  addedKeys++;
226
230
  changed = true;
227
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-localize-locale-engine",
3
- "version": "2.0.7",
3
+ "version": "3.1.0",
4
4
  "description": "Locale file generation, merging, deduplication and synchronization",
5
5
  "author": "ai-localize-core contributors",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "node": ">=18.0.0"
46
46
  },
47
47
  "dependencies": {
48
- "ai-localize-shared": "2.0.7"
48
+ "ai-localize-shared": "3.0.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "tsup": "^8.0.1",