lingo.dev 0.84.0 → 0.85.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/build/cli.cjs +440 -95
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +440 -95
- package/build/cli.mjs.map +1 -1
- package/package.json +2 -1
package/build/cli.mjs
CHANGED
|
@@ -3088,10 +3088,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3088
3088
|
createAndroidLoader(),
|
|
3089
3089
|
createFlatLoader(),
|
|
3090
3090
|
createSyncLoader(),
|
|
3091
|
-
createUnlocalizableLoader(
|
|
3092
|
-
options.isCacheRestore,
|
|
3093
|
-
options.returnUnlocalizedKeys
|
|
3094
|
-
)
|
|
3091
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3095
3092
|
);
|
|
3096
3093
|
case "csv":
|
|
3097
3094
|
return composeLoaders(
|
|
@@ -3099,10 +3096,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3099
3096
|
createCsvLoader(),
|
|
3100
3097
|
createFlatLoader(),
|
|
3101
3098
|
createSyncLoader(),
|
|
3102
|
-
createUnlocalizableLoader(
|
|
3103
|
-
options.isCacheRestore,
|
|
3104
|
-
options.returnUnlocalizedKeys
|
|
3105
|
-
)
|
|
3099
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3106
3100
|
);
|
|
3107
3101
|
case "html":
|
|
3108
3102
|
return composeLoaders(
|
|
@@ -3110,10 +3104,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3110
3104
|
createPrettierLoader({ parser: "html", bucketPathPattern }),
|
|
3111
3105
|
createHtmlLoader(),
|
|
3112
3106
|
createSyncLoader(),
|
|
3113
|
-
createUnlocalizableLoader(
|
|
3114
|
-
options.isCacheRestore,
|
|
3115
|
-
options.returnUnlocalizedKeys
|
|
3116
|
-
)
|
|
3107
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3117
3108
|
);
|
|
3118
3109
|
case "json":
|
|
3119
3110
|
return composeLoaders(
|
|
@@ -3124,10 +3115,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3124
3115
|
createFlatLoader(),
|
|
3125
3116
|
createLockedKeysLoader(lockedKeys || [], options.isCacheRestore),
|
|
3126
3117
|
createSyncLoader(),
|
|
3127
|
-
createUnlocalizableLoader(
|
|
3128
|
-
options.isCacheRestore,
|
|
3129
|
-
options.returnUnlocalizedKeys
|
|
3130
|
-
)
|
|
3118
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3131
3119
|
);
|
|
3132
3120
|
case "markdown":
|
|
3133
3121
|
return composeLoaders(
|
|
@@ -3135,10 +3123,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3135
3123
|
createPrettierLoader({ parser: "markdown", bucketPathPattern }),
|
|
3136
3124
|
createMarkdownLoader(),
|
|
3137
3125
|
createSyncLoader(),
|
|
3138
|
-
createUnlocalizableLoader(
|
|
3139
|
-
options.isCacheRestore,
|
|
3140
|
-
options.returnUnlocalizedKeys
|
|
3141
|
-
)
|
|
3126
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3142
3127
|
);
|
|
3143
3128
|
case "mdx":
|
|
3144
3129
|
return composeLoaders(
|
|
@@ -3149,19 +3134,6 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3149
3134
|
createFlatLoader(),
|
|
3150
3135
|
createMdxStructureLoader(),
|
|
3151
3136
|
createSyncLoader(),
|
|
3152
|
-
createUnlocalizableLoader(
|
|
3153
|
-
options.isCacheRestore,
|
|
3154
|
-
options.returnUnlocalizedKeys
|
|
3155
|
-
)
|
|
3156
|
-
);
|
|
3157
|
-
case "mdx":
|
|
3158
|
-
return composeLoaders(
|
|
3159
|
-
createTextFileLoader(bucketPathPattern),
|
|
3160
|
-
createPrettierLoader({ parser: "mdx", bucketPathPattern }),
|
|
3161
|
-
createMdxFormatLoader(),
|
|
3162
|
-
createFlatLoader(),
|
|
3163
|
-
createMdxStructureLoader(),
|
|
3164
|
-
createSyncLoader(),
|
|
3165
3137
|
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3166
3138
|
);
|
|
3167
3139
|
case "po":
|
|
@@ -3171,30 +3143,21 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3171
3143
|
createFlatLoader(),
|
|
3172
3144
|
createSyncLoader(),
|
|
3173
3145
|
createVariableLoader({ type: "python" }),
|
|
3174
|
-
createUnlocalizableLoader(
|
|
3175
|
-
options.isCacheRestore,
|
|
3176
|
-
options.returnUnlocalizedKeys
|
|
3177
|
-
)
|
|
3146
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3178
3147
|
);
|
|
3179
3148
|
case "properties":
|
|
3180
3149
|
return composeLoaders(
|
|
3181
3150
|
createTextFileLoader(bucketPathPattern),
|
|
3182
3151
|
createPropertiesLoader(),
|
|
3183
3152
|
createSyncLoader(),
|
|
3184
|
-
createUnlocalizableLoader(
|
|
3185
|
-
options.isCacheRestore,
|
|
3186
|
-
options.returnUnlocalizedKeys
|
|
3187
|
-
)
|
|
3153
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3188
3154
|
);
|
|
3189
3155
|
case "xcode-strings":
|
|
3190
3156
|
return composeLoaders(
|
|
3191
3157
|
createTextFileLoader(bucketPathPattern),
|
|
3192
3158
|
createXcodeStringsLoader(),
|
|
3193
3159
|
createSyncLoader(),
|
|
3194
|
-
createUnlocalizableLoader(
|
|
3195
|
-
options.isCacheRestore,
|
|
3196
|
-
options.returnUnlocalizedKeys
|
|
3197
|
-
)
|
|
3160
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3198
3161
|
);
|
|
3199
3162
|
case "xcode-stringsdict":
|
|
3200
3163
|
return composeLoaders(
|
|
@@ -3202,10 +3165,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3202
3165
|
createXcodeStringsdictLoader(),
|
|
3203
3166
|
createFlatLoader(),
|
|
3204
3167
|
createSyncLoader(),
|
|
3205
|
-
createUnlocalizableLoader(
|
|
3206
|
-
options.isCacheRestore,
|
|
3207
|
-
options.returnUnlocalizedKeys
|
|
3208
|
-
)
|
|
3168
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3209
3169
|
);
|
|
3210
3170
|
case "xcode-xcstrings":
|
|
3211
3171
|
return composeLoaders(
|
|
@@ -3216,10 +3176,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3216
3176
|
createFlatLoader(),
|
|
3217
3177
|
createSyncLoader(),
|
|
3218
3178
|
createVariableLoader({ type: "ieee" }),
|
|
3219
|
-
createUnlocalizableLoader(
|
|
3220
|
-
options.isCacheRestore,
|
|
3221
|
-
options.returnUnlocalizedKeys
|
|
3222
|
-
)
|
|
3179
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3223
3180
|
);
|
|
3224
3181
|
case "yaml":
|
|
3225
3182
|
return composeLoaders(
|
|
@@ -3229,10 +3186,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3229
3186
|
createFlatLoader(),
|
|
3230
3187
|
createLockedKeysLoader(lockedKeys || [], options.isCacheRestore),
|
|
3231
3188
|
createSyncLoader(),
|
|
3232
|
-
createUnlocalizableLoader(
|
|
3233
|
-
options.isCacheRestore,
|
|
3234
|
-
options.returnUnlocalizedKeys
|
|
3235
|
-
)
|
|
3189
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3236
3190
|
);
|
|
3237
3191
|
case "yaml-root-key":
|
|
3238
3192
|
return composeLoaders(
|
|
@@ -3242,10 +3196,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3242
3196
|
createRootKeyLoader(true),
|
|
3243
3197
|
createFlatLoader(),
|
|
3244
3198
|
createSyncLoader(),
|
|
3245
|
-
createUnlocalizableLoader(
|
|
3246
|
-
options.isCacheRestore,
|
|
3247
|
-
options.returnUnlocalizedKeys
|
|
3248
|
-
)
|
|
3199
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3249
3200
|
);
|
|
3250
3201
|
case "flutter":
|
|
3251
3202
|
return composeLoaders(
|
|
@@ -3255,10 +3206,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3255
3206
|
createFlutterLoader(),
|
|
3256
3207
|
createFlatLoader(),
|
|
3257
3208
|
createSyncLoader(),
|
|
3258
|
-
createUnlocalizableLoader(
|
|
3259
|
-
options.isCacheRestore,
|
|
3260
|
-
options.returnUnlocalizedKeys
|
|
3261
|
-
)
|
|
3209
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3262
3210
|
);
|
|
3263
3211
|
case "xliff":
|
|
3264
3212
|
return composeLoaders(
|
|
@@ -3266,10 +3214,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3266
3214
|
createXliffLoader(),
|
|
3267
3215
|
createFlatLoader(),
|
|
3268
3216
|
createSyncLoader(),
|
|
3269
|
-
createUnlocalizableLoader(
|
|
3270
|
-
options.isCacheRestore,
|
|
3271
|
-
options.returnUnlocalizedKeys
|
|
3272
|
-
)
|
|
3217
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3273
3218
|
);
|
|
3274
3219
|
case "xml":
|
|
3275
3220
|
return composeLoaders(
|
|
@@ -3277,40 +3222,28 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3277
3222
|
createXmlLoader(),
|
|
3278
3223
|
createFlatLoader(),
|
|
3279
3224
|
createSyncLoader(),
|
|
3280
|
-
createUnlocalizableLoader(
|
|
3281
|
-
options.isCacheRestore,
|
|
3282
|
-
options.returnUnlocalizedKeys
|
|
3283
|
-
)
|
|
3225
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3284
3226
|
);
|
|
3285
3227
|
case "srt":
|
|
3286
3228
|
return composeLoaders(
|
|
3287
3229
|
createTextFileLoader(bucketPathPattern),
|
|
3288
3230
|
createSrtLoader(),
|
|
3289
3231
|
createSyncLoader(),
|
|
3290
|
-
createUnlocalizableLoader(
|
|
3291
|
-
options.isCacheRestore,
|
|
3292
|
-
options.returnUnlocalizedKeys
|
|
3293
|
-
)
|
|
3232
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3294
3233
|
);
|
|
3295
3234
|
case "dato":
|
|
3296
3235
|
return composeLoaders(
|
|
3297
3236
|
createDatoLoader(bucketPathPattern),
|
|
3298
3237
|
createSyncLoader(),
|
|
3299
3238
|
createFlatLoader(),
|
|
3300
|
-
createUnlocalizableLoader(
|
|
3301
|
-
options.isCacheRestore,
|
|
3302
|
-
options.returnUnlocalizedKeys
|
|
3303
|
-
)
|
|
3239
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3304
3240
|
);
|
|
3305
3241
|
case "vtt":
|
|
3306
3242
|
return composeLoaders(
|
|
3307
3243
|
createTextFileLoader(bucketPathPattern),
|
|
3308
3244
|
createVttLoader(),
|
|
3309
3245
|
createSyncLoader(),
|
|
3310
|
-
createUnlocalizableLoader(
|
|
3311
|
-
options.isCacheRestore,
|
|
3312
|
-
options.returnUnlocalizedKeys
|
|
3313
|
-
)
|
|
3246
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3314
3247
|
);
|
|
3315
3248
|
case "php":
|
|
3316
3249
|
return composeLoaders(
|
|
@@ -3318,10 +3251,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3318
3251
|
createPhpLoader(),
|
|
3319
3252
|
createSyncLoader(),
|
|
3320
3253
|
createFlatLoader(),
|
|
3321
|
-
createUnlocalizableLoader(
|
|
3322
|
-
options.isCacheRestore,
|
|
3323
|
-
options.returnUnlocalizedKeys
|
|
3324
|
-
)
|
|
3254
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3325
3255
|
);
|
|
3326
3256
|
case "vue-json":
|
|
3327
3257
|
return composeLoaders(
|
|
@@ -3329,10 +3259,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys)
|
|
|
3329
3259
|
createVueJsonLoader(),
|
|
3330
3260
|
createSyncLoader(),
|
|
3331
3261
|
createFlatLoader(),
|
|
3332
|
-
createUnlocalizableLoader(
|
|
3333
|
-
options.isCacheRestore,
|
|
3334
|
-
options.returnUnlocalizedKeys
|
|
3335
|
-
)
|
|
3262
|
+
createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
|
|
3336
3263
|
);
|
|
3337
3264
|
}
|
|
3338
3265
|
}
|
|
@@ -5111,10 +5038,427 @@ var ci_default = new Command10().command("ci").description("Run Lingo.dev CI/CD
|
|
|
5111
5038
|
main();
|
|
5112
5039
|
});
|
|
5113
5040
|
|
|
5041
|
+
// src/cli/cmd/status.ts
|
|
5042
|
+
import { bucketTypeSchema as bucketTypeSchema3, localeCodeSchema as localeCodeSchema2, resolveOverriddenLocale as resolveOverriddenLocale6 } from "@lingo.dev/_spec";
|
|
5043
|
+
import { Command as Command11 } from "interactive-commander";
|
|
5044
|
+
import Z11 from "zod";
|
|
5045
|
+
import Ora8 from "ora";
|
|
5046
|
+
import chalk2 from "chalk";
|
|
5047
|
+
import Table from "cli-table3";
|
|
5048
|
+
var status_default = new Command11().command("status").description("Show the status of the localization process").helpOption("-h, --help", "Show help").option("--locale <locale>", "Locale to process", (val, prev) => prev ? [...prev, val] : [val]).option("--bucket <bucket>", "Bucket to process", (val, prev) => prev ? [...prev, val] : [val]).option(
|
|
5049
|
+
"--file [files...]",
|
|
5050
|
+
"File to process. Process only a specific path, may contain asterisk * to match multiple files."
|
|
5051
|
+
).option("--force", "Ignore lockfile and process all keys, useful for estimating full re-translation").option("--verbose", "Show detailed output including key-level word counts").option("--api-key <api-key>", "Explicitly set the API key to use, override the default API key from settings").action(async function(options) {
|
|
5052
|
+
const ora = Ora8();
|
|
5053
|
+
const flags = parseFlags2(options);
|
|
5054
|
+
let authId = null;
|
|
5055
|
+
try {
|
|
5056
|
+
ora.start("Loading configuration...");
|
|
5057
|
+
const i18nConfig = getConfig();
|
|
5058
|
+
const settings = getSettings(flags.apiKey);
|
|
5059
|
+
ora.succeed("Configuration loaded");
|
|
5060
|
+
try {
|
|
5061
|
+
ora.start("Checking authentication status...");
|
|
5062
|
+
const auth = await tryAuthenticate(settings);
|
|
5063
|
+
if (auth) {
|
|
5064
|
+
authId = auth.id;
|
|
5065
|
+
ora.succeed(`Authenticated as ${auth.email}`);
|
|
5066
|
+
} else {
|
|
5067
|
+
ora.info(
|
|
5068
|
+
"Not authenticated. Continuing without authentication. (Run `lingo.dev auth --login` to authenticate)"
|
|
5069
|
+
);
|
|
5070
|
+
}
|
|
5071
|
+
} catch (error) {
|
|
5072
|
+
ora.info("Authentication failed. Continuing without authentication.");
|
|
5073
|
+
}
|
|
5074
|
+
ora.start("Validating localization configuration...");
|
|
5075
|
+
validateParams2(i18nConfig, flags);
|
|
5076
|
+
ora.succeed("Localization configuration is valid");
|
|
5077
|
+
trackEvent(authId || "status", "cmd.status.start", {
|
|
5078
|
+
i18nConfig,
|
|
5079
|
+
flags
|
|
5080
|
+
});
|
|
5081
|
+
let buckets = getBuckets(i18nConfig);
|
|
5082
|
+
if (flags.bucket?.length) {
|
|
5083
|
+
buckets = buckets.filter((bucket) => flags.bucket.includes(bucket.type));
|
|
5084
|
+
}
|
|
5085
|
+
ora.succeed("Buckets retrieved");
|
|
5086
|
+
if (flags.file?.length) {
|
|
5087
|
+
buckets = buckets.map((bucket) => {
|
|
5088
|
+
const paths = bucket.paths.filter((path18) => flags.file.find((file) => path18.pathPattern?.match(file)));
|
|
5089
|
+
return { ...bucket, paths };
|
|
5090
|
+
}).filter((bucket) => bucket.paths.length > 0);
|
|
5091
|
+
if (buckets.length === 0) {
|
|
5092
|
+
ora.fail("No buckets found. All buckets were filtered out by --file option.");
|
|
5093
|
+
process.exit(1);
|
|
5094
|
+
} else {
|
|
5095
|
+
ora.info(`\x1B[36mProcessing only filtered buckets:\x1B[0m`);
|
|
5096
|
+
buckets.map((bucket) => {
|
|
5097
|
+
ora.info(` ${bucket.type}:`);
|
|
5098
|
+
bucket.paths.forEach((path18) => {
|
|
5099
|
+
ora.info(` - ${path18.pathPattern}`);
|
|
5100
|
+
});
|
|
5101
|
+
});
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
const targetLocales = flags.locale?.length ? flags.locale : i18nConfig.locale.targets;
|
|
5105
|
+
let totalSourceKeyCount = 0;
|
|
5106
|
+
let uniqueKeysToTranslate = 0;
|
|
5107
|
+
let totalExistingTranslations = 0;
|
|
5108
|
+
const totalWordCount = /* @__PURE__ */ new Map();
|
|
5109
|
+
const languageStats = {};
|
|
5110
|
+
for (const locale of targetLocales) {
|
|
5111
|
+
languageStats[locale] = {
|
|
5112
|
+
complete: 0,
|
|
5113
|
+
missing: 0,
|
|
5114
|
+
updated: 0,
|
|
5115
|
+
words: 0
|
|
5116
|
+
};
|
|
5117
|
+
totalWordCount.set(locale, 0);
|
|
5118
|
+
}
|
|
5119
|
+
const fileStats = {};
|
|
5120
|
+
for (const bucket of buckets) {
|
|
5121
|
+
try {
|
|
5122
|
+
console.log();
|
|
5123
|
+
ora.info(`Analyzing bucket: ${bucket.type}`);
|
|
5124
|
+
for (const bucketPath of bucket.paths) {
|
|
5125
|
+
const bucketOra = Ora8({ indent: 2 }).info(`Analyzing path: ${bucketPath.pathPattern}`);
|
|
5126
|
+
const sourceLocale = resolveOverriddenLocale6(i18nConfig.locale.source, bucketPath.delimiter);
|
|
5127
|
+
const bucketLoader = createBucketLoader(
|
|
5128
|
+
bucket.type,
|
|
5129
|
+
bucketPath.pathPattern,
|
|
5130
|
+
{
|
|
5131
|
+
isCacheRestore: false,
|
|
5132
|
+
defaultLocale: sourceLocale,
|
|
5133
|
+
injectLocale: bucket.injectLocale
|
|
5134
|
+
},
|
|
5135
|
+
bucket.lockedKeys
|
|
5136
|
+
);
|
|
5137
|
+
bucketLoader.setDefaultLocale(sourceLocale);
|
|
5138
|
+
await bucketLoader.init();
|
|
5139
|
+
const filePath = bucketPath.pathPattern;
|
|
5140
|
+
if (!fileStats[filePath]) {
|
|
5141
|
+
fileStats[filePath] = {
|
|
5142
|
+
path: filePath,
|
|
5143
|
+
sourceKeys: 0,
|
|
5144
|
+
wordCount: 0,
|
|
5145
|
+
languageStats: {}
|
|
5146
|
+
};
|
|
5147
|
+
for (const locale of targetLocales) {
|
|
5148
|
+
fileStats[filePath].languageStats[locale] = {
|
|
5149
|
+
complete: 0,
|
|
5150
|
+
missing: 0,
|
|
5151
|
+
updated: 0,
|
|
5152
|
+
words: 0
|
|
5153
|
+
};
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
5157
|
+
const sourceKeys = Object.keys(sourceData);
|
|
5158
|
+
fileStats[filePath].sourceKeys = sourceKeys.length;
|
|
5159
|
+
totalSourceKeyCount += sourceKeys.length;
|
|
5160
|
+
let sourceWordCount = 0;
|
|
5161
|
+
for (const key of sourceKeys) {
|
|
5162
|
+
const value = sourceData[key];
|
|
5163
|
+
if (typeof value === "string") {
|
|
5164
|
+
const words = value.trim().split(/\s+/).length;
|
|
5165
|
+
sourceWordCount += words;
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
fileStats[filePath].wordCount = sourceWordCount;
|
|
5169
|
+
for (const _targetLocale of targetLocales) {
|
|
5170
|
+
const targetLocale = resolveOverriddenLocale6(_targetLocale, bucketPath.delimiter);
|
|
5171
|
+
bucketOra.start(`[${sourceLocale} -> ${targetLocale}] Analyzing translation status...`);
|
|
5172
|
+
let targetData = {};
|
|
5173
|
+
let fileExists = true;
|
|
5174
|
+
try {
|
|
5175
|
+
targetData = await bucketLoader.pull(targetLocale);
|
|
5176
|
+
} catch (error) {
|
|
5177
|
+
fileExists = false;
|
|
5178
|
+
bucketOra.info(
|
|
5179
|
+
`[${sourceLocale} -> ${targetLocale}] Target file not found, assuming all keys need translation.`
|
|
5180
|
+
);
|
|
5181
|
+
}
|
|
5182
|
+
if (!fileExists) {
|
|
5183
|
+
fileStats[filePath].languageStats[targetLocale].missing = sourceKeys.length;
|
|
5184
|
+
fileStats[filePath].languageStats[targetLocale].words = sourceWordCount;
|
|
5185
|
+
languageStats[targetLocale].missing += sourceKeys.length;
|
|
5186
|
+
languageStats[targetLocale].words += sourceWordCount;
|
|
5187
|
+
totalWordCount.set(targetLocale, (totalWordCount.get(targetLocale) || 0) + sourceWordCount);
|
|
5188
|
+
bucketOra.succeed(
|
|
5189
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk2.red(`0% complete`)} (0/${sourceKeys.length} keys) - file not found`
|
|
5190
|
+
);
|
|
5191
|
+
continue;
|
|
5192
|
+
}
|
|
5193
|
+
const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
|
|
5194
|
+
const checksums = await deltaProcessor.loadChecksums();
|
|
5195
|
+
const delta = await deltaProcessor.calculateDelta({
|
|
5196
|
+
sourceData,
|
|
5197
|
+
targetData,
|
|
5198
|
+
checksums
|
|
5199
|
+
});
|
|
5200
|
+
const missingKeys = delta.added;
|
|
5201
|
+
const updatedKeys = delta.updated;
|
|
5202
|
+
const completeKeys = sourceKeys.filter((key) => !missingKeys.includes(key) && !updatedKeys.includes(key));
|
|
5203
|
+
let wordsToTranslate = 0;
|
|
5204
|
+
const keysToProcess = flags.force ? sourceKeys : [...missingKeys, ...updatedKeys];
|
|
5205
|
+
for (const key of keysToProcess) {
|
|
5206
|
+
const value = sourceData[String(key)];
|
|
5207
|
+
if (typeof value === "string") {
|
|
5208
|
+
const words = value.trim().split(/\s+/).length;
|
|
5209
|
+
wordsToTranslate += words;
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
fileStats[filePath].languageStats[targetLocale].missing = missingKeys.length;
|
|
5213
|
+
fileStats[filePath].languageStats[targetLocale].updated = updatedKeys.length;
|
|
5214
|
+
fileStats[filePath].languageStats[targetLocale].complete = completeKeys.length;
|
|
5215
|
+
fileStats[filePath].languageStats[targetLocale].words = wordsToTranslate;
|
|
5216
|
+
languageStats[targetLocale].missing += missingKeys.length;
|
|
5217
|
+
languageStats[targetLocale].updated += updatedKeys.length;
|
|
5218
|
+
languageStats[targetLocale].complete += completeKeys.length;
|
|
5219
|
+
languageStats[targetLocale].words += wordsToTranslate;
|
|
5220
|
+
totalWordCount.set(targetLocale, (totalWordCount.get(targetLocale) || 0) + wordsToTranslate);
|
|
5221
|
+
const totalKeysInFile = sourceKeys.length;
|
|
5222
|
+
const completionPercent = (completeKeys.length / totalKeysInFile * 100).toFixed(1);
|
|
5223
|
+
if (missingKeys.length === 0 && updatedKeys.length === 0) {
|
|
5224
|
+
bucketOra.succeed(
|
|
5225
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk2.green(`100% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`
|
|
5226
|
+
);
|
|
5227
|
+
} else {
|
|
5228
|
+
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ? chalk2.yellow(`${completionPercent}% complete`) : chalk2.red(`${completionPercent}% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`;
|
|
5229
|
+
bucketOra.succeed(message);
|
|
5230
|
+
if (flags.verbose) {
|
|
5231
|
+
if (missingKeys.length > 0) {
|
|
5232
|
+
console.log(` ${chalk2.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`);
|
|
5233
|
+
console.log(
|
|
5234
|
+
` ${chalk2.dim(`Example missing: ${missingKeys.slice(0, 2).join(", ")}${missingKeys.length > 2 ? "..." : ""}`)}`
|
|
5235
|
+
);
|
|
5236
|
+
}
|
|
5237
|
+
if (updatedKeys.length > 0) {
|
|
5238
|
+
console.log(` ${chalk2.yellow(`Updated:`)} ${updatedKeys.length} keys that changed in source`);
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
5244
|
+
} catch (error) {
|
|
5245
|
+
ora.fail(`Failed to analyze bucket ${bucket.type}: ${error.message}`);
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
const totalKeysNeedingTranslation = Object.values(languageStats).reduce((sum, stats) => {
|
|
5249
|
+
return sum + stats.missing + stats.updated;
|
|
5250
|
+
}, 0);
|
|
5251
|
+
const totalCompletedKeys = totalSourceKeyCount - totalKeysNeedingTranslation / targetLocales.length;
|
|
5252
|
+
console.log();
|
|
5253
|
+
ora.succeed(chalk2.green(`Localization status completed.`));
|
|
5254
|
+
console.log(chalk2.bold.cyan(`
|
|
5255
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`));
|
|
5256
|
+
console.log(chalk2.bold.cyan(`\u2551 LOCALIZATION STATUS REPORT \u2551`));
|
|
5257
|
+
console.log(chalk2.bold.cyan(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`));
|
|
5258
|
+
console.log(chalk2.bold(`
|
|
5259
|
+
\u{1F4DD} SOURCE CONTENT:`));
|
|
5260
|
+
console.log(`\u2022 Source language: ${chalk2.green(i18nConfig.locale.source)}`);
|
|
5261
|
+
console.log(`\u2022 Source keys: ${chalk2.yellow(totalSourceKeyCount.toString())} keys across all files`);
|
|
5262
|
+
console.log(chalk2.bold(`
|
|
5263
|
+
\u{1F310} LANGUAGE BY LANGUAGE BREAKDOWN:`));
|
|
5264
|
+
const table = new Table({
|
|
5265
|
+
head: ["Language", "Status", "Complete", "Missing", "Updated", "Total Keys", "Words to Translate"],
|
|
5266
|
+
style: {
|
|
5267
|
+
head: ["white"],
|
|
5268
|
+
// White color for headers
|
|
5269
|
+
border: []
|
|
5270
|
+
// No color for borders
|
|
5271
|
+
},
|
|
5272
|
+
colWidths: [12, 20, 18, 12, 12, 12, 15]
|
|
5273
|
+
// Explicit column widths, making Status column wider
|
|
5274
|
+
});
|
|
5275
|
+
let totalWordsToTranslate = 0;
|
|
5276
|
+
for (const locale of targetLocales) {
|
|
5277
|
+
const stats = languageStats[locale];
|
|
5278
|
+
const percentComplete = (stats.complete / totalSourceKeyCount * 100).toFixed(1);
|
|
5279
|
+
const totalNeeded = stats.missing + stats.updated;
|
|
5280
|
+
let statusText;
|
|
5281
|
+
let statusColor;
|
|
5282
|
+
if (stats.missing === totalSourceKeyCount) {
|
|
5283
|
+
statusText = "\u{1F534} Not started";
|
|
5284
|
+
statusColor = chalk2.red;
|
|
5285
|
+
} else if (stats.missing === 0 && stats.updated === 0) {
|
|
5286
|
+
statusText = "\u2705 Complete";
|
|
5287
|
+
statusColor = chalk2.green;
|
|
5288
|
+
} else if (parseFloat(percentComplete) > 80) {
|
|
5289
|
+
statusText = "\u{1F7E1} Almost done";
|
|
5290
|
+
statusColor = chalk2.yellow;
|
|
5291
|
+
} else if (parseFloat(percentComplete) > 0) {
|
|
5292
|
+
statusText = "\u{1F7E0} In progress";
|
|
5293
|
+
statusColor = chalk2.yellow;
|
|
5294
|
+
} else {
|
|
5295
|
+
statusText = "\u{1F534} Not started";
|
|
5296
|
+
statusColor = chalk2.red;
|
|
5297
|
+
}
|
|
5298
|
+
const words = totalWordCount.get(locale) || 0;
|
|
5299
|
+
totalWordsToTranslate += words;
|
|
5300
|
+
table.push([
|
|
5301
|
+
locale,
|
|
5302
|
+
statusColor(statusText),
|
|
5303
|
+
`${stats.complete}/${totalSourceKeyCount} (${percentComplete}%)`,
|
|
5304
|
+
stats.missing > 0 ? chalk2.red(stats.missing.toString()) : "0",
|
|
5305
|
+
stats.updated > 0 ? chalk2.yellow(stats.updated.toString()) : "0",
|
|
5306
|
+
totalNeeded > 0 ? chalk2.magenta(totalNeeded.toString()) : "0",
|
|
5307
|
+
words > 0 ? `~${words.toLocaleString()}` : "0"
|
|
5308
|
+
]);
|
|
5309
|
+
}
|
|
5310
|
+
console.log(table.toString());
|
|
5311
|
+
console.log(chalk2.bold(`
|
|
5312
|
+
\u{1F4CA} USAGE ESTIMATE:`));
|
|
5313
|
+
console.log(
|
|
5314
|
+
`\u2022 WORDS TO BE CONSUMED: ~${chalk2.yellow.bold(totalWordsToTranslate.toLocaleString())} words across all languages`
|
|
5315
|
+
);
|
|
5316
|
+
console.log(` (Words are counted from source language for keys that need translation in target languages)`);
|
|
5317
|
+
if (targetLocales.length > 1) {
|
|
5318
|
+
console.log(`\u2022 Per-language breakdown:`);
|
|
5319
|
+
for (const locale of targetLocales) {
|
|
5320
|
+
const words = totalWordCount.get(locale) || 0;
|
|
5321
|
+
const percent = (words / totalWordsToTranslate * 100).toFixed(1);
|
|
5322
|
+
console.log(` - ${locale}: ~${words.toLocaleString()} words (${percent}% of total)`);
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
if (flags.confirm && Object.keys(fileStats).length > 0) {
|
|
5326
|
+
console.log(chalk2.bold(`
|
|
5327
|
+
\u{1F4D1} BREAKDOWN BY FILE:`));
|
|
5328
|
+
Object.entries(fileStats).sort((a, b) => b[1].wordCount - a[1].wordCount).forEach(([path18, stats]) => {
|
|
5329
|
+
if (stats.sourceKeys === 0) return;
|
|
5330
|
+
console.log(chalk2.bold(`
|
|
5331
|
+
\u2022 ${path18}:`));
|
|
5332
|
+
console.log(` ${stats.sourceKeys} source keys, ~${stats.wordCount.toLocaleString()} source words`);
|
|
5333
|
+
const fileTable = new Table({
|
|
5334
|
+
head: ["Language", "Status", "Details"],
|
|
5335
|
+
style: {
|
|
5336
|
+
head: ["white"],
|
|
5337
|
+
border: []
|
|
5338
|
+
},
|
|
5339
|
+
colWidths: [12, 20, 50]
|
|
5340
|
+
// Explicit column widths for file detail table
|
|
5341
|
+
});
|
|
5342
|
+
for (const locale of targetLocales) {
|
|
5343
|
+
const langStats = stats.languageStats[locale];
|
|
5344
|
+
const complete = langStats.complete;
|
|
5345
|
+
const total = stats.sourceKeys;
|
|
5346
|
+
const completion = (complete / total * 100).toFixed(1);
|
|
5347
|
+
let status = "\u2705 Complete";
|
|
5348
|
+
let statusColor = chalk2.green;
|
|
5349
|
+
if (langStats.missing === total) {
|
|
5350
|
+
status = "\u274C Not started";
|
|
5351
|
+
statusColor = chalk2.red;
|
|
5352
|
+
} else if (langStats.missing > 0 || langStats.updated > 0) {
|
|
5353
|
+
status = `\u26A0\uFE0F ${completion}% complete`;
|
|
5354
|
+
statusColor = chalk2.yellow;
|
|
5355
|
+
}
|
|
5356
|
+
let details = "";
|
|
5357
|
+
if (langStats.missing > 0 || langStats.updated > 0) {
|
|
5358
|
+
const parts = [];
|
|
5359
|
+
if (langStats.missing > 0) parts.push(`${langStats.missing} missing`);
|
|
5360
|
+
if (langStats.updated > 0) parts.push(`${langStats.updated} changed`);
|
|
5361
|
+
details = `${parts.join(", ")}, ~${langStats.words} words`;
|
|
5362
|
+
} else {
|
|
5363
|
+
details = "All keys translated";
|
|
5364
|
+
}
|
|
5365
|
+
fileTable.push([locale, statusColor(status), details]);
|
|
5366
|
+
}
|
|
5367
|
+
console.log(fileTable.toString());
|
|
5368
|
+
});
|
|
5369
|
+
}
|
|
5370
|
+
const completeLanguages = targetLocales.filter(
|
|
5371
|
+
(locale) => languageStats[locale].missing === 0 && languageStats[locale].updated === 0
|
|
5372
|
+
);
|
|
5373
|
+
const missingLanguages = targetLocales.filter((locale) => languageStats[locale].complete === 0);
|
|
5374
|
+
console.log(chalk2.bold.green(`
|
|
5375
|
+
\u{1F4A1} OPTIMIZATION TIPS:`));
|
|
5376
|
+
if (missingLanguages.length > 0) {
|
|
5377
|
+
console.log(
|
|
5378
|
+
`\u2022 ${chalk2.yellow(missingLanguages.join(", "))} ${missingLanguages.length === 1 ? "has" : "have"} no translations yet`
|
|
5379
|
+
);
|
|
5380
|
+
}
|
|
5381
|
+
if (completeLanguages.length > 0) {
|
|
5382
|
+
console.log(
|
|
5383
|
+
`\u2022 ${chalk2.green(completeLanguages.join(", "))} ${completeLanguages.length === 1 ? "is" : "are"} completely translated`
|
|
5384
|
+
);
|
|
5385
|
+
}
|
|
5386
|
+
if (targetLocales.length > 1) {
|
|
5387
|
+
console.log(`\u2022 Translating one language at a time reduces complexity`);
|
|
5388
|
+
console.log(`\u2022 Try 'lingo.dev@latest i18n --locale ${targetLocales[0]}' to process just one language`);
|
|
5389
|
+
}
|
|
5390
|
+
trackEvent(authId || "status", "cmd.status.success", {
|
|
5391
|
+
i18nConfig,
|
|
5392
|
+
flags,
|
|
5393
|
+
totalSourceKeyCount,
|
|
5394
|
+
languageStats,
|
|
5395
|
+
totalWordsToTranslate,
|
|
5396
|
+
authenticated: !!authId
|
|
5397
|
+
});
|
|
5398
|
+
} catch (error) {
|
|
5399
|
+
ora.fail(error.message);
|
|
5400
|
+
trackEvent(authId || "status", "cmd.status.error", {
|
|
5401
|
+
flags,
|
|
5402
|
+
error: error.message,
|
|
5403
|
+
authenticated: !!authId
|
|
5404
|
+
});
|
|
5405
|
+
process.exit(1);
|
|
5406
|
+
}
|
|
5407
|
+
});
|
|
5408
|
+
function parseFlags2(options) {
|
|
5409
|
+
return Z11.object({
|
|
5410
|
+
locale: Z11.array(localeCodeSchema2).optional(),
|
|
5411
|
+
bucket: Z11.array(bucketTypeSchema3).optional(),
|
|
5412
|
+
force: Z11.boolean().optional(),
|
|
5413
|
+
confirm: Z11.boolean().optional(),
|
|
5414
|
+
verbose: Z11.boolean().optional(),
|
|
5415
|
+
file: Z11.array(Z11.string()).optional(),
|
|
5416
|
+
apiKey: Z11.string().optional()
|
|
5417
|
+
}).parse(options);
|
|
5418
|
+
}
|
|
5419
|
+
async function tryAuthenticate(settings) {
|
|
5420
|
+
if (!settings.auth.apiKey) {
|
|
5421
|
+
return null;
|
|
5422
|
+
}
|
|
5423
|
+
try {
|
|
5424
|
+
const authenticator = createAuthenticator({
|
|
5425
|
+
apiKey: settings.auth.apiKey,
|
|
5426
|
+
apiUrl: settings.auth.apiUrl
|
|
5427
|
+
});
|
|
5428
|
+
const user = await authenticator.whoami();
|
|
5429
|
+
return user;
|
|
5430
|
+
} catch (error) {
|
|
5431
|
+
return null;
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
function validateParams2(i18nConfig, flags) {
|
|
5435
|
+
if (!i18nConfig) {
|
|
5436
|
+
throw new CLIError({
|
|
5437
|
+
message: "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
|
|
5438
|
+
docUrl: "i18nNotFound"
|
|
5439
|
+
});
|
|
5440
|
+
} else if (!i18nConfig.buckets || !Object.keys(i18nConfig.buckets).length) {
|
|
5441
|
+
throw new CLIError({
|
|
5442
|
+
message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
|
|
5443
|
+
docUrl: "bucketNotFound"
|
|
5444
|
+
});
|
|
5445
|
+
} else if (flags.locale?.some((locale) => !i18nConfig.locale.targets.includes(locale))) {
|
|
5446
|
+
throw new CLIError({
|
|
5447
|
+
message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
|
|
5448
|
+
docUrl: "localeTargetNotFound"
|
|
5449
|
+
});
|
|
5450
|
+
} else if (flags.bucket?.some((bucket) => !i18nConfig.buckets[bucket])) {
|
|
5451
|
+
throw new CLIError({
|
|
5452
|
+
message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
|
|
5453
|
+
docUrl: "bucketNotFound"
|
|
5454
|
+
});
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
|
|
5114
5458
|
// package.json
|
|
5115
5459
|
var package_default = {
|
|
5116
5460
|
name: "lingo.dev",
|
|
5117
|
-
version: "0.
|
|
5461
|
+
version: "0.85.1",
|
|
5118
5462
|
description: "Lingo.dev CLI",
|
|
5119
5463
|
private: false,
|
|
5120
5464
|
publishConfig: {
|
|
@@ -5184,6 +5528,7 @@ var package_default = {
|
|
|
5184
5528
|
ai: "^4.3.2",
|
|
5185
5529
|
bitbucket: "^2.12.0",
|
|
5186
5530
|
chalk: "^5.4.1",
|
|
5531
|
+
"cli-table3": "^0.6.5",
|
|
5187
5532
|
cors: "^2.8.5",
|
|
5188
5533
|
"csv-parse": "^5.6.0",
|
|
5189
5534
|
"csv-stringify": "^6.5.2",
|
|
@@ -5289,7 +5634,7 @@ ${vice(
|
|
|
5289
5634
|
|
|
5290
5635
|
Star the the repo :) https://github.com/LingoDotDev/lingo.dev
|
|
5291
5636
|
`
|
|
5292
|
-
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default).addCommand(mcp_default).addCommand(ci_default).exitOverride((err) => {
|
|
5637
|
+
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default).addCommand(mcp_default).addCommand(ci_default).addCommand(status_default).exitOverride((err) => {
|
|
5293
5638
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
5294
5639
|
process.exit(0);
|
|
5295
5640
|
}
|