poly-lexis 0.5.3 → 0.8.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/dist/cli/translations.js +162 -11
- package/dist/cli/translations.js.map +1 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +60 -1
- package/dist/index.js.map +1 -1
- package/dist/scripts/verify-translations.js +21 -1
- package/dist/scripts/verify-translations.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -225,6 +225,16 @@ interface UnusedKeysResult {
|
|
|
225
225
|
totalKeys: number;
|
|
226
226
|
searchedFiles: number;
|
|
227
227
|
}
|
|
228
|
+
interface DuplicateTranslation {
|
|
229
|
+
namespace: string;
|
|
230
|
+
key: string;
|
|
231
|
+
commonKey: string;
|
|
232
|
+
value: string;
|
|
233
|
+
}
|
|
234
|
+
interface DuplicateKeysResult {
|
|
235
|
+
duplicates: DuplicateTranslation[];
|
|
236
|
+
totalKeysChecked: number;
|
|
237
|
+
}
|
|
228
238
|
declare const DEFAULT_CONFIG: Required<TranslationConfig>;
|
|
229
239
|
declare const DEFAULT_LANGUAGES: readonly ["en", "fr", "it", "pl", "es", "pt", "de", "nl", "sv", "hu", "cs", "ja"];
|
|
230
240
|
|
|
@@ -282,6 +292,11 @@ declare function findUnusedKeys(projectRoot?: string): UnusedKeysResult;
|
|
|
282
292
|
*/
|
|
283
293
|
declare function printUnusedKeysResult(result: UnusedKeysResult): void;
|
|
284
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Extract base keys from plural-suffixed keys (e.g., "items_one" -> "items")
|
|
297
|
+
* Follows CLDR plural categories used by i18next and similar libraries.
|
|
298
|
+
*/
|
|
299
|
+
declare function extractPluralBaseKeys(keys: string[]): string[];
|
|
285
300
|
/**
|
|
286
301
|
* Generate TypeScript types from translation files
|
|
287
302
|
*/
|
|
@@ -462,8 +477,29 @@ declare function translateText(text: string, targetLang: string, sourceLang?: st
|
|
|
462
477
|
*/
|
|
463
478
|
declare function translateBatch(texts: string[], targetLang: string, sourceLang?: string, apiKey?: string, delayMs?: number): Promise<string[]>;
|
|
464
479
|
|
|
480
|
+
/**
|
|
481
|
+
* Nested translation structure (allows nested objects)
|
|
482
|
+
*/
|
|
483
|
+
type NestedTranslationFile = {
|
|
484
|
+
[key: string]: string | NestedTranslationFile;
|
|
485
|
+
};
|
|
486
|
+
/**
|
|
487
|
+
* Flatten a nested object into a flat key-value structure using dot notation
|
|
488
|
+
* Example: { home: { title: "Hello" } } -> { "home.title": "Hello" }
|
|
489
|
+
*/
|
|
490
|
+
declare function flattenObject(obj: NestedTranslationFile, prefix?: string): TranslationFile;
|
|
491
|
+
/**
|
|
492
|
+
* Unflatten a flat object with dot notation keys into a nested structure
|
|
493
|
+
* Example: { "home.title": "Hello" } -> { home: { title: "Hello" } }
|
|
494
|
+
*/
|
|
495
|
+
declare function unflattenObject(obj: TranslationFile): NestedTranslationFile;
|
|
496
|
+
/**
|
|
497
|
+
* Check if an object is flat (all values are strings) or nested
|
|
498
|
+
*/
|
|
499
|
+
declare function isNestedObject(obj: Record<string, unknown>): boolean;
|
|
465
500
|
/**
|
|
466
501
|
* Read all translation files for a specific language
|
|
502
|
+
* Automatically flattens nested structures into dot notation
|
|
467
503
|
*/
|
|
468
504
|
declare function readTranslations(translationsPath: string, language: string): TranslationFiles;
|
|
469
505
|
/**
|
|
@@ -536,4 +572,4 @@ interface SyncResult {
|
|
|
536
572
|
*/
|
|
537
573
|
declare function syncTranslationStructure(translationsPath: string, languages: string[], sourceLanguage: string): SyncResult;
|
|
538
574
|
|
|
539
|
-
export { DEEPL_LANGUAGES, DEFAULT_CONFIG, DEFAULT_LANGUAGES, type DeepLLanguage, GOOGLE_LANGUAGES, type GoogleLanguage, GoogleTranslateProvider, type LanguageFallbackResult, type ManageTranslationsOptions, type MissingTranslation, type OrphanedTranslation, SUPPORTED_LANGUAGES, type SupportedLanguage, type SyncResult, TRANSLATION_CONFIG_SCHEMA, TRANSLATION_PROVIDERS, type TranslateOptions, type TranslationConfig, type TranslationEntry, type TranslationFile, type TranslationFiles, type TranslationProvider, type TranslationProviderFactory, type TranslationProviderType, type TranslationResult, type UnusedKeysResult, type UnusedTranslation, type ValidationResult, addTranslationKey, addTranslationKeys, autoFillTranslations, createEmptyTranslationStructure, detectExistingTranslations, ensureTranslationsStructure, extractVariables, fillNamespace, findUnusedKeys, generateTranslationTypes, getAvailableLanguages, getFallbackMappings, getMissingForLanguage, getNamespaces, getSupportedLanguages, getTranslationProvider, hasInterpolation, initTranslations, initTranslationsInteractive, isValidDeepLLanguage, isValidGoogleLanguage, isValidLanguage, isValidLanguageForProvider, loadConfig, logLanguageFallback, manageTranslations, printUnusedKeysResult, readTranslations, resetTranslationProvider, resolveLanguageWithFallback, setTranslationProvider, sortKeys, syncTranslationStructure, translateBatch, translateText, validateLanguages, validateLanguagesForProvider, validateTranslations, validateVariables, writeTranslation };
|
|
575
|
+
export { DEEPL_LANGUAGES, DEFAULT_CONFIG, DEFAULT_LANGUAGES, type DeepLLanguage, type DuplicateKeysResult, type DuplicateTranslation, GOOGLE_LANGUAGES, type GoogleLanguage, GoogleTranslateProvider, type LanguageFallbackResult, type ManageTranslationsOptions, type MissingTranslation, type NestedTranslationFile, type OrphanedTranslation, SUPPORTED_LANGUAGES, type SupportedLanguage, type SyncResult, TRANSLATION_CONFIG_SCHEMA, TRANSLATION_PROVIDERS, type TranslateOptions, type TranslationConfig, type TranslationEntry, type TranslationFile, type TranslationFiles, type TranslationProvider, type TranslationProviderFactory, type TranslationProviderType, type TranslationResult, type UnusedKeysResult, type UnusedTranslation, type ValidationResult, addTranslationKey, addTranslationKeys, autoFillTranslations, createEmptyTranslationStructure, detectExistingTranslations, ensureTranslationsStructure, extractPluralBaseKeys, extractVariables, fillNamespace, findUnusedKeys, flattenObject, generateTranslationTypes, getAvailableLanguages, getFallbackMappings, getMissingForLanguage, getNamespaces, getSupportedLanguages, getTranslationProvider, hasInterpolation, initTranslations, initTranslationsInteractive, isNestedObject, isValidDeepLLanguage, isValidGoogleLanguage, isValidLanguage, isValidLanguageForProvider, loadConfig, logLanguageFallback, manageTranslations, printUnusedKeysResult, readTranslations, resetTranslationProvider, resolveLanguageWithFallback, setTranslationProvider, sortKeys, syncTranslationStructure, translateBatch, translateText, unflattenObject, validateLanguages, validateLanguagesForProvider, validateTranslations, validateVariables, writeTranslation };
|
package/dist/index.js
CHANGED
|
@@ -626,6 +626,37 @@ var init_language_fallback = __esm({
|
|
|
626
626
|
// src/translations/utils/utils.ts
|
|
627
627
|
import * as fs from "fs";
|
|
628
628
|
import * as path from "path";
|
|
629
|
+
function flattenObject(obj, prefix = "") {
|
|
630
|
+
const result = {};
|
|
631
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
632
|
+
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
633
|
+
if (typeof value === "string") {
|
|
634
|
+
result[newKey] = value;
|
|
635
|
+
} else if (typeof value === "object" && value !== null) {
|
|
636
|
+
Object.assign(result, flattenObject(value, newKey));
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return result;
|
|
640
|
+
}
|
|
641
|
+
function unflattenObject(obj) {
|
|
642
|
+
const result = {};
|
|
643
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
644
|
+
const parts = key.split(".");
|
|
645
|
+
let current = result;
|
|
646
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
647
|
+
const part = parts[i];
|
|
648
|
+
if (!(part in current) || typeof current[part] === "string") {
|
|
649
|
+
current[part] = {};
|
|
650
|
+
}
|
|
651
|
+
current = current[part];
|
|
652
|
+
}
|
|
653
|
+
current[parts[parts.length - 1]] = value;
|
|
654
|
+
}
|
|
655
|
+
return result;
|
|
656
|
+
}
|
|
657
|
+
function isNestedObject(obj) {
|
|
658
|
+
return Object.values(obj).some((value) => typeof value === "object" && value !== null);
|
|
659
|
+
}
|
|
629
660
|
function readTranslations(translationsPath, language) {
|
|
630
661
|
const langPath = path.join(translationsPath, language);
|
|
631
662
|
if (!fs.existsSync(langPath)) {
|
|
@@ -637,7 +668,12 @@ function readTranslations(translationsPath, language) {
|
|
|
637
668
|
const namespace = path.basename(file, ".json");
|
|
638
669
|
const filePath = path.join(langPath, file);
|
|
639
670
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
640
|
-
|
|
671
|
+
const parsed = JSON.parse(content);
|
|
672
|
+
if (isNestedObject(parsed)) {
|
|
673
|
+
translations[namespace] = flattenObject(parsed);
|
|
674
|
+
} else {
|
|
675
|
+
translations[namespace] = parsed;
|
|
676
|
+
}
|
|
641
677
|
}
|
|
642
678
|
return translations;
|
|
643
679
|
}
|
|
@@ -1159,6 +1195,23 @@ init_init();
|
|
|
1159
1195
|
import { execSync } from "child_process";
|
|
1160
1196
|
import * as fs3 from "fs";
|
|
1161
1197
|
import * as path3 from "path";
|
|
1198
|
+
var PLURAL_SUFFIXES = ["_zero", "_one", "_two", "_few", "_many", "_other"];
|
|
1199
|
+
function extractPluralBaseKeys(keys) {
|
|
1200
|
+
const keySet = new Set(keys);
|
|
1201
|
+
const baseKeys = /* @__PURE__ */ new Set();
|
|
1202
|
+
for (const key of keys) {
|
|
1203
|
+
for (const suffix of PLURAL_SUFFIXES) {
|
|
1204
|
+
if (key.endsWith(suffix)) {
|
|
1205
|
+
const baseKey = key.slice(0, -suffix.length);
|
|
1206
|
+
if (baseKey && !keySet.has(baseKey)) {
|
|
1207
|
+
baseKeys.add(baseKey);
|
|
1208
|
+
}
|
|
1209
|
+
break;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
return Array.from(baseKeys);
|
|
1214
|
+
}
|
|
1162
1215
|
var typeTemplate = (translationKeys, namespaceKeys) => `
|
|
1163
1216
|
export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
|
|
1164
1217
|
export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
|
|
@@ -1189,6 +1242,8 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
|
|
|
1189
1242
|
const keys = Object.keys(translations[namespace] || {});
|
|
1190
1243
|
allKeys = allKeys.concat(keys);
|
|
1191
1244
|
}
|
|
1245
|
+
const pluralBaseKeys = extractPluralBaseKeys(allKeys);
|
|
1246
|
+
allKeys = allKeys.concat(pluralBaseKeys);
|
|
1192
1247
|
const outputDir = path3.dirname(outputFilePath);
|
|
1193
1248
|
if (!fs3.existsSync(outputDir)) {
|
|
1194
1249
|
fs3.mkdirSync(outputDir, { recursive: true });
|
|
@@ -2178,9 +2233,11 @@ export {
|
|
|
2178
2233
|
createEmptyTranslationStructure,
|
|
2179
2234
|
detectExistingTranslations,
|
|
2180
2235
|
ensureTranslationsStructure,
|
|
2236
|
+
extractPluralBaseKeys,
|
|
2181
2237
|
extractVariables,
|
|
2182
2238
|
fillNamespace,
|
|
2183
2239
|
findUnusedKeys,
|
|
2240
|
+
flattenObject,
|
|
2184
2241
|
generateTranslationTypes,
|
|
2185
2242
|
getAvailableLanguages,
|
|
2186
2243
|
getFallbackMappings,
|
|
@@ -2191,6 +2248,7 @@ export {
|
|
|
2191
2248
|
hasInterpolation,
|
|
2192
2249
|
initTranslations,
|
|
2193
2250
|
initTranslationsInteractive,
|
|
2251
|
+
isNestedObject,
|
|
2194
2252
|
isValidDeepLLanguage,
|
|
2195
2253
|
isValidGoogleLanguage,
|
|
2196
2254
|
isValidLanguage,
|
|
@@ -2207,6 +2265,7 @@ export {
|
|
|
2207
2265
|
syncTranslationStructure,
|
|
2208
2266
|
translateBatch,
|
|
2209
2267
|
translateText,
|
|
2268
|
+
unflattenObject,
|
|
2210
2269
|
validateLanguages,
|
|
2211
2270
|
validateLanguagesForProvider,
|
|
2212
2271
|
validateTranslations,
|