@i18nprune/core 0.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/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/adapters-gp1lXp0T.d.ts +12 -0
- package/dist/capabilities-x74cD2Hu.d.ts +48 -0
- package/dist/cleanup.d.ts +64 -0
- package/dist/cleanup.js +3999 -0
- package/dist/config.d.ts +201 -0
- package/dist/config.js +2865 -0
- package/dist/coreContext-DMaWLvmB.d.ts +388 -0
- package/dist/fs-BUYD8ZhA.d.ts +20 -0
- package/dist/generate.d.ts +487 -0
- package/dist/generate.js +9389 -0
- package/dist/humanEmit-ygNlYX-S.d.ts +79 -0
- package/dist/index-BQuLEQ9b.d.ts +7 -0
- package/dist/index-B_ow_Xvr.d.ts +97 -0
- package/dist/index-BgG01AKL.d.ts +287 -0
- package/dist/index-CIzZl4W8.d.ts +124 -0
- package/dist/index-Csm1w7XD.d.ts +58 -0
- package/dist/index-DLwTogCo.d.ts +43 -0
- package/dist/index-DVT26v11.d.ts +61 -0
- package/dist/index-DdjljwMj.d.ts +39 -0
- package/dist/index-DeIw-cZd.d.ts +52 -0
- package/dist/index-X50E1FIX.d.ts +50 -0
- package/dist/index.d.ts +9180 -0
- package/dist/index.js +21888 -0
- package/dist/init.d.ts +86 -0
- package/dist/init.js +848 -0
- package/dist/listWindow-XEFxQZi1.d.ts +30 -0
- package/dist/localeTargetCodes-BBIQjauw.d.ts +11 -0
- package/dist/locales.d.ts +39 -0
- package/dist/locales.js +2288 -0
- package/dist/missing-BVCvgUC8.d.ts +10 -0
- package/dist/missing.d.ts +85 -0
- package/dist/missing.js +5892 -0
- package/dist/modeResolve-cGVaY5Hh.d.ts +25 -0
- package/dist/path-Bfn3SAts.d.ts +11 -0
- package/dist/profile-BwOP9WKh.d.ts +9 -0
- package/dist/providers-0uMEfT6q.d.ts +82 -0
- package/dist/prune-c6hKZCv_.d.ts +33 -0
- package/dist/quality.d.ts +36 -0
- package/dist/quality.js +3868 -0
- package/dist/report-D5-6bVFj.d.ts +8 -0
- package/dist/report-schema.d.ts +102 -0
- package/dist/report-schema.js +42 -0
- package/dist/resumeCandidates-xR13eEwt.d.ts +200 -0
- package/dist/root-2-kCaBvQ.d.ts +1110 -0
- package/dist/runtime/edge.d.ts +21 -0
- package/dist/runtime/edge.js +87 -0
- package/dist/runtime/helpers/sync.d.ts +16 -0
- package/dist/runtime/helpers/sync.js +117 -0
- package/dist/runtime/node.d.ts +24 -0
- package/dist/runtime/node.js +204 -0
- package/dist/runtime/web.d.ts +21 -0
- package/dist/runtime/web.js +84 -0
- package/dist/shared.d.ts +1177 -0
- package/dist/shared.js +4897 -0
- package/dist/sourceContext-1LQg3HiQ.d.ts +36 -0
- package/dist/sourceSurface-mDtwGo1E.d.ts +122 -0
- package/dist/sync.d.ts +86 -0
- package/dist/sync.js +4971 -0
- package/dist/syncSegment-Bx6He2Mu.d.ts +149 -0
- package/dist/targets-EmtKyr6F.d.ts +23 -0
- package/dist/template-CGM-_WLT.d.ts +139 -0
- package/dist/translate-CIHYp7wi.d.ts +77 -0
- package/dist/types/shared.d.ts +21 -0
- package/dist/types/shared.js +1 -0
- package/dist/types.d.ts +1345 -0
- package/dist/types.js +1 -0
- package/dist/validate.d.ts +126 -0
- package/dist/validate.js +3717 -0
- package/package.json +128 -0
package/dist/locales.js
ADDED
|
@@ -0,0 +1,2288 @@
|
|
|
1
|
+
// src/shared/errors/internal.ts
|
|
2
|
+
var I18nPruneError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
issueCode;
|
|
5
|
+
constructor(message, code, options) {
|
|
6
|
+
super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
7
|
+
this.name = "I18nPruneError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.issueCode = options?.issueCode;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/shared/languages/normalize.ts
|
|
14
|
+
function normalizeLanguageCode(code) {
|
|
15
|
+
return code.trim().toLowerCase().replace(/_/g, "-");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/locales/source.ts
|
|
19
|
+
function getSourceLocaleSlug(path, sourceLocalePath) {
|
|
20
|
+
return normalizeLanguageCode(path.basename(sourceLocalePath, ".json"));
|
|
21
|
+
}
|
|
22
|
+
function getDisplaySourceLocaleCode(ctx) {
|
|
23
|
+
return getSourceLocaleSlug(ctx.path, ctx.paths.sourceLocale);
|
|
24
|
+
}
|
|
25
|
+
function buildSourceLocaleTruthLabel(displaySlug) {
|
|
26
|
+
return `(${displaySlug} - source of truth)`;
|
|
27
|
+
}
|
|
28
|
+
function isSourceLocaleSlug(path, candidate, sourceLocalePath) {
|
|
29
|
+
return normalizeLanguageCode(candidate) === getSourceLocaleSlug(path, sourceLocalePath);
|
|
30
|
+
}
|
|
31
|
+
function excludeSourceLocaleSlugs(path, slugs, sourceLocalePath) {
|
|
32
|
+
const n = getSourceLocaleSlug(path, sourceLocalePath);
|
|
33
|
+
return slugs.filter((s) => normalizeLanguageCode(s) !== n);
|
|
34
|
+
}
|
|
35
|
+
function assertNotSourceTargetLocale(command, lang, sourceLocalePath, ctx) {
|
|
36
|
+
if (!isSourceLocaleSlug(ctx.path, lang, sourceLocalePath)) return;
|
|
37
|
+
const display = getDisplaySourceLocaleCode(ctx);
|
|
38
|
+
throw new I18nPruneError(
|
|
39
|
+
`${command} does not apply to the source locale ${buildSourceLocaleTruthLabel(display)}. Pass a target language code.`,
|
|
40
|
+
"USAGE"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/runtime/helpers/sync/assert.ts
|
|
45
|
+
function isThenable(value) {
|
|
46
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
47
|
+
}
|
|
48
|
+
function assertSyncPortResult(value, label, at) {
|
|
49
|
+
if (isThenable(value)) {
|
|
50
|
+
throw new I18nPruneError(
|
|
51
|
+
`Synchronous ${label} requires a plain value (got a Promise at ${at})`,
|
|
52
|
+
"USAGE"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/runtime/helpers/sync/fs.ts
|
|
59
|
+
function readRuntimeFsTextSync(filePath, fs) {
|
|
60
|
+
return assertSyncPortResult(fs.readText(filePath), "fs.readText", filePath);
|
|
61
|
+
}
|
|
62
|
+
function existsRuntimeFsSync(filePath, fs) {
|
|
63
|
+
return assertSyncPortResult(fs.exists(filePath), "fs.exists", filePath);
|
|
64
|
+
}
|
|
65
|
+
function listRuntimeFsDirSync(dirPath, fs) {
|
|
66
|
+
return assertSyncPortResult(fs.listDir(dirPath), "fs.listDir", dirPath);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/shared/constants/issueCodes.ts
|
|
70
|
+
var ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE = "i18nprune.languages.unsupported_language_code";
|
|
71
|
+
var ISSUE_IO_READ_FAILED = "i18nprune.io.read_failed";
|
|
72
|
+
|
|
73
|
+
// src/shared/json/parse.ts
|
|
74
|
+
var I18nPruneJsonParseError = class extends I18nPruneError {
|
|
75
|
+
filePath;
|
|
76
|
+
line;
|
|
77
|
+
column;
|
|
78
|
+
offset;
|
|
79
|
+
constructor(input) {
|
|
80
|
+
const options = input.issueCode !== void 0 ? { cause: input.cause, issueCode: input.issueCode } : { cause: input.cause };
|
|
81
|
+
super(input.message, input.code, options);
|
|
82
|
+
this.name = "I18nPruneJsonParseError";
|
|
83
|
+
this.filePath = input.filePath;
|
|
84
|
+
this.line = input.location.line;
|
|
85
|
+
this.column = input.location.column;
|
|
86
|
+
this.offset = input.location.offset;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function locationFromOffset(text, offset) {
|
|
90
|
+
let line = 1;
|
|
91
|
+
let column = 1;
|
|
92
|
+
const capped = Math.max(0, Math.min(offset, text.length));
|
|
93
|
+
for (let i = 0; i < capped; i += 1) {
|
|
94
|
+
if (text.charCodeAt(i) === 10) {
|
|
95
|
+
line += 1;
|
|
96
|
+
column = 1;
|
|
97
|
+
} else {
|
|
98
|
+
column += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { line, column, offset };
|
|
102
|
+
}
|
|
103
|
+
function getJsonParseLocation(error, text) {
|
|
104
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
105
|
+
const positionMatch = /\bposition\s+(\d+)\b/i.exec(message);
|
|
106
|
+
if (positionMatch?.[1]) {
|
|
107
|
+
return locationFromOffset(text, Number.parseInt(positionMatch[1], 10));
|
|
108
|
+
}
|
|
109
|
+
const lineColumnMatch = /\bline\s+(\d+)\s+column\s+(\d+)\b/i.exec(message);
|
|
110
|
+
if (lineColumnMatch?.[1] && lineColumnMatch[2]) {
|
|
111
|
+
return {
|
|
112
|
+
line: Number.parseInt(lineColumnMatch[1], 10),
|
|
113
|
+
column: Number.parseInt(lineColumnMatch[2], 10)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
118
|
+
function formatJsonParseMessage(filePath, location, cause) {
|
|
119
|
+
const subject = filePath ? `Invalid JSON in ${filePath}` : "Invalid JSON";
|
|
120
|
+
const at = location.line !== void 0 && location.column !== void 0 ? ` at line ${String(location.line)}, column ${String(location.column)}` : location.offset !== void 0 ? ` at offset ${String(location.offset)}` : "";
|
|
121
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
122
|
+
return `${subject}${at}: ${detail}`;
|
|
123
|
+
}
|
|
124
|
+
function parseJsonText(text, options = {}) {
|
|
125
|
+
try {
|
|
126
|
+
return JSON.parse(text);
|
|
127
|
+
} catch (cause) {
|
|
128
|
+
const location = getJsonParseLocation(cause, text);
|
|
129
|
+
throw new I18nPruneJsonParseError({
|
|
130
|
+
message: formatJsonParseMessage(options.filePath, location, cause),
|
|
131
|
+
code: options.code ?? "IO",
|
|
132
|
+
cause,
|
|
133
|
+
location,
|
|
134
|
+
...options.issueCode !== void 0 ? { issueCode: options.issueCode } : {},
|
|
135
|
+
...options.filePath !== void 0 ? { filePath: options.filePath } : {}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/locales/otherLocales.ts
|
|
141
|
+
function listOtherLocaleCodes(runtime, localesDir, sourceBase) {
|
|
142
|
+
const { fs, path } = runtime;
|
|
143
|
+
if (!existsRuntimeFsSync(localesDir, fs)) return [];
|
|
144
|
+
return listRuntimeFsDirSync(localesDir, fs).filter((e) => e.kind === "file" && e.name.endsWith(".json")).map((e) => path.basename(e.name, ".json")).filter((c) => c !== sourceBase);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/shared/locales/layout/requireStructure.ts
|
|
148
|
+
function localesMode(config) {
|
|
149
|
+
return config.mode ?? "flat_file";
|
|
150
|
+
}
|
|
151
|
+
function resolveLocalesStructure(config) {
|
|
152
|
+
if (config.structure !== void 0) {
|
|
153
|
+
return config.structure;
|
|
154
|
+
}
|
|
155
|
+
if (localesMode(config) === "flat_file") {
|
|
156
|
+
return "locale_file";
|
|
157
|
+
}
|
|
158
|
+
throw new Error("locales.structure is required when locales.mode is locale_directory");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/shared/locales/layout/resolveLayout.ts
|
|
162
|
+
function resolveLocalesLayout(config, directoryAbsolute) {
|
|
163
|
+
const mode = localesMode(config);
|
|
164
|
+
const structure = resolveLocalesStructure(config);
|
|
165
|
+
return { mode, structure, directoryAbsolute, config };
|
|
166
|
+
}
|
|
167
|
+
function resolveLocalesLayoutFromContext(ctx) {
|
|
168
|
+
return resolveLocalesLayout(ctx.config.locales, ctx.paths.localesDir);
|
|
169
|
+
}
|
|
170
|
+
function isLocalesLayoutReadSupported(layout) {
|
|
171
|
+
return layout.mode === "flat_file" && layout.structure === "locale_file" || layout.mode === "locale_directory" && (layout.structure === "locale_per_dir" || layout.structure === "feature_bundle");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/shared/locales/enumerate/parseSegmentLocale.ts
|
|
175
|
+
function localeCodeForSegment(structure, path, segment) {
|
|
176
|
+
if (structure === "locale_file") {
|
|
177
|
+
if (segment.relativePath.includes("/")) return null;
|
|
178
|
+
return path.basename(segment.absolutePath, ".json");
|
|
179
|
+
}
|
|
180
|
+
if (structure === "locale_per_dir") {
|
|
181
|
+
const slash = segment.relativePath.indexOf("/");
|
|
182
|
+
if (slash < 0) return null;
|
|
183
|
+
const locale = segment.relativePath.slice(0, slash);
|
|
184
|
+
return locale.length > 0 ? locale : null;
|
|
185
|
+
}
|
|
186
|
+
if (structure === "feature_bundle") {
|
|
187
|
+
return path.basename(segment.absolutePath, ".json");
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// src/shared/locales/leaves/segmentSource/localeSegmentSourceForFile.ts
|
|
193
|
+
function localeSegmentSourceForFile(input) {
|
|
194
|
+
const { path, absoluteFile, localesDir, structure } = input;
|
|
195
|
+
let relativePath = path.relative(localesDir, absoluteFile);
|
|
196
|
+
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
|
|
197
|
+
relativePath = path.basename(absoluteFile);
|
|
198
|
+
}
|
|
199
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
200
|
+
const locale = localeCodeForSegment(structure, path, { absolutePath: absoluteFile, relativePath });
|
|
201
|
+
if (locale === null) return null;
|
|
202
|
+
return { file: absoluteFile, locale, relativePath };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/shared/locales/leaves/walk/translationSurfaceWalk.ts
|
|
206
|
+
function isPlainObject(x) {
|
|
207
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
208
|
+
}
|
|
209
|
+
function isStructuredLocaleLeafNode(x) {
|
|
210
|
+
return isPlainObject(x) && typeof x.value === "string";
|
|
211
|
+
}
|
|
212
|
+
function readOptionalStatus(o) {
|
|
213
|
+
const s = o.status;
|
|
214
|
+
if (typeof s !== "string" || !s.trim()) return void 0;
|
|
215
|
+
return s;
|
|
216
|
+
}
|
|
217
|
+
function readOptionalLeafSource(o) {
|
|
218
|
+
const s = o.source;
|
|
219
|
+
if (typeof s !== "string" || !s.trim()) return void 0;
|
|
220
|
+
return s;
|
|
221
|
+
}
|
|
222
|
+
function readConfidence(o) {
|
|
223
|
+
const c = o.confidence;
|
|
224
|
+
if (c === null || c === void 0) return null;
|
|
225
|
+
if (typeof c !== "number" || !Number.isFinite(c)) return null;
|
|
226
|
+
const clamped = Math.max(0, Math.min(1, c));
|
|
227
|
+
return Math.round(clamped * 100) / 100;
|
|
228
|
+
}
|
|
229
|
+
function readNeedsReview(o) {
|
|
230
|
+
if (!("needsReview" in o)) return null;
|
|
231
|
+
return typeof o.needsReview === "boolean" ? o.needsReview : null;
|
|
232
|
+
}
|
|
233
|
+
function readNeedsTranslationAgain(o) {
|
|
234
|
+
if (!("needsTranslationAgain" in o)) return null;
|
|
235
|
+
return typeof o.needsTranslationAgain === "boolean" ? o.needsTranslationAgain : null;
|
|
236
|
+
}
|
|
237
|
+
function isCompleteStructuredLocaleLeafMeta(node) {
|
|
238
|
+
if (!isStructuredLocaleLeafNode(node)) return false;
|
|
239
|
+
const o = node;
|
|
240
|
+
if (typeof o.status !== "string" || !o.status.trim()) return false;
|
|
241
|
+
if (!(o.confidence === null || typeof o.confidence === "number" && Number.isFinite(o.confidence))) return false;
|
|
242
|
+
if (typeof o.needsReview !== "boolean") return false;
|
|
243
|
+
if (typeof o.needsTranslationAgain !== "boolean") return false;
|
|
244
|
+
if (typeof o.source !== "string" || !o.source.trim()) return false;
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
function pushStructuredRow(out, prefix, root, fileOrigin) {
|
|
248
|
+
out.push({
|
|
249
|
+
path: prefix,
|
|
250
|
+
value: root.value,
|
|
251
|
+
shape: "structured",
|
|
252
|
+
status: readOptionalStatus(root),
|
|
253
|
+
confidence: readConfidence(root),
|
|
254
|
+
needsReview: readNeedsReview(root),
|
|
255
|
+
needsTranslationAgain: readNeedsTranslationAgain(root),
|
|
256
|
+
source: readOptionalLeafSource(root),
|
|
257
|
+
structuredMetaComplete: isCompleteStructuredLocaleLeafMeta(root),
|
|
258
|
+
...fileOrigin ? { fileOrigin } : {}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function collectTranslationSurfaceLeaves(root, prefix = "", out = [], fileOrigin) {
|
|
262
|
+
if (typeof root === "string") {
|
|
263
|
+
if (prefix) {
|
|
264
|
+
out.push({
|
|
265
|
+
path: prefix,
|
|
266
|
+
value: root,
|
|
267
|
+
shape: "legacy_string",
|
|
268
|
+
confidence: null,
|
|
269
|
+
needsReview: null,
|
|
270
|
+
...fileOrigin ? { fileOrigin } : {}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
if (isStructuredLocaleLeafNode(root)) {
|
|
276
|
+
if (prefix) pushStructuredRow(out, prefix, root, fileOrigin);
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
if (Array.isArray(root)) {
|
|
280
|
+
root.forEach((item, i) => {
|
|
281
|
+
const p = prefix ? `${prefix}[${i}]` : `[${i}]`;
|
|
282
|
+
collectTranslationSurfaceLeaves(item, p, out, fileOrigin);
|
|
283
|
+
});
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
if (isPlainObject(root)) {
|
|
287
|
+
for (const k of Object.keys(root)) {
|
|
288
|
+
const p = prefix ? `${prefix}.${k}` : k;
|
|
289
|
+
collectTranslationSurfaceLeaves(root[k], p, out, fileOrigin);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/shared/locales/read/flatFileSurface.ts
|
|
296
|
+
function readFlatLocaleJsonSurface(input) {
|
|
297
|
+
const diagnostics = [];
|
|
298
|
+
const emit = (d) => {
|
|
299
|
+
diagnostics.push(d);
|
|
300
|
+
};
|
|
301
|
+
try {
|
|
302
|
+
const text = readRuntimeFsTextSync(input.absoluteFile, input.fs);
|
|
303
|
+
let json;
|
|
304
|
+
try {
|
|
305
|
+
json = parseJsonText(text, {
|
|
306
|
+
filePath: input.absoluteFile,
|
|
307
|
+
code: "IO",
|
|
308
|
+
issueCode: ISSUE_IO_READ_FAILED
|
|
309
|
+
});
|
|
310
|
+
} catch (e) {
|
|
311
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
312
|
+
emit({ level: "error", code: "locale_json_parse_failed", message, path: input.absoluteFile });
|
|
313
|
+
return { ok: false, leaves: [], diagnostics };
|
|
314
|
+
}
|
|
315
|
+
const fileOrigin = localeSegmentSourceForFile({
|
|
316
|
+
path: input.path,
|
|
317
|
+
absoluteFile: input.absoluteFile,
|
|
318
|
+
localesDir: input.localesDir,
|
|
319
|
+
structure: input.structure
|
|
320
|
+
});
|
|
321
|
+
const leaves = collectTranslationSurfaceLeaves(json, "", [], fileOrigin ?? void 0);
|
|
322
|
+
return { ok: true, document: json, leaves, text, diagnostics };
|
|
323
|
+
} catch (e) {
|
|
324
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
325
|
+
emit({ level: "error", code: "locale_fs_read_failed", message, path: input.absoluteFile });
|
|
326
|
+
return { ok: false, leaves: [], diagnostics };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/shared/path/posix.ts
|
|
331
|
+
function toPosixPath(value) {
|
|
332
|
+
return value.replace(/\\/g, "/");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/shared/locales/enumerate/resolveSegmentPath.ts
|
|
336
|
+
function localeSegmentRefFromAbsolute(input) {
|
|
337
|
+
const { layout, path, absolutePath } = input;
|
|
338
|
+
let relativePath = path.relative(layout.directoryAbsolute, absolutePath);
|
|
339
|
+
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
343
|
+
if (!relativePath.endsWith(".json")) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const locale = localeCodeForSegment(layout.structure, path, { absolutePath, relativePath });
|
|
347
|
+
if (locale === null) return null;
|
|
348
|
+
return { locale, relativePath, absolutePath: toPosixPath(absolutePath) };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/shared/locales/read/bundle.ts
|
|
352
|
+
function readLocaleBundle(input) {
|
|
353
|
+
const diagnostics = [];
|
|
354
|
+
const emit = (d) => {
|
|
355
|
+
diagnostics.push(d);
|
|
356
|
+
};
|
|
357
|
+
if (!isLocalesLayoutReadSupported(input.layout)) {
|
|
358
|
+
emit({
|
|
359
|
+
level: "error",
|
|
360
|
+
code: "locale_layout_unsupported",
|
|
361
|
+
message: `locale read is not implemented for mode=${input.layout.mode} structure=${input.layout.structure}`,
|
|
362
|
+
path: input.absoluteFile
|
|
363
|
+
});
|
|
364
|
+
return { ok: false, leaves: [], diagnostics };
|
|
365
|
+
}
|
|
366
|
+
const segmentRef = localeSegmentRefFromAbsolute({
|
|
367
|
+
layout: input.layout,
|
|
368
|
+
path: input.path,
|
|
369
|
+
absolutePath: input.absoluteFile
|
|
370
|
+
});
|
|
371
|
+
if (segmentRef === null) {
|
|
372
|
+
emit({
|
|
373
|
+
level: "warn",
|
|
374
|
+
code: "locale_read_path_layout_mismatch",
|
|
375
|
+
message: `path does not match configured layout mode=${input.layout.mode} structure=${input.layout.structure}`,
|
|
376
|
+
path: input.absoluteFile
|
|
377
|
+
});
|
|
378
|
+
return { ok: false, leaves: [], diagnostics };
|
|
379
|
+
}
|
|
380
|
+
return readFlatLocaleJsonSurface({
|
|
381
|
+
fs: input.fs,
|
|
382
|
+
path: input.path,
|
|
383
|
+
absoluteFile: input.absoluteFile,
|
|
384
|
+
localesDir: input.layout.directoryAbsolute,
|
|
385
|
+
structure: input.layout.structure,
|
|
386
|
+
onDiagnostic: input.onDiagnostic
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/shared/locales/diagnostics/structuralParity.ts
|
|
391
|
+
function localeStructuralSlot(structure, relativePath) {
|
|
392
|
+
if (structure === "locale_per_dir") {
|
|
393
|
+
const slash = relativePath.indexOf("/");
|
|
394
|
+
if (slash < 0) return null;
|
|
395
|
+
const slot = relativePath.slice(slash + 1);
|
|
396
|
+
return slot.length > 0 ? slot : null;
|
|
397
|
+
}
|
|
398
|
+
if (structure === "feature_bundle") {
|
|
399
|
+
const slash = relativePath.lastIndexOf("/");
|
|
400
|
+
if (slash < 0) return null;
|
|
401
|
+
const slot = relativePath.slice(0, slash);
|
|
402
|
+
return slot.length > 0 ? slot : null;
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
function slotsByLocale(structure, segments) {
|
|
407
|
+
const byLocale = /* @__PURE__ */ new Map();
|
|
408
|
+
for (const segment of segments) {
|
|
409
|
+
const slot = localeStructuralSlot(structure, segment.relativePath);
|
|
410
|
+
if (slot === null) continue;
|
|
411
|
+
let set = byLocale.get(segment.locale);
|
|
412
|
+
if (!set) {
|
|
413
|
+
set = /* @__PURE__ */ new Set();
|
|
414
|
+
byLocale.set(segment.locale, set);
|
|
415
|
+
}
|
|
416
|
+
set.add(slot);
|
|
417
|
+
}
|
|
418
|
+
return byLocale;
|
|
419
|
+
}
|
|
420
|
+
function pickReferenceLocale(byLocale, preferred) {
|
|
421
|
+
if (preferred !== void 0 && byLocale.has(preferred)) return preferred;
|
|
422
|
+
let best = null;
|
|
423
|
+
let bestSize = -1;
|
|
424
|
+
for (const [locale, slots] of byLocale) {
|
|
425
|
+
if (slots.size > bestSize) {
|
|
426
|
+
best = locale;
|
|
427
|
+
bestSize = slots.size;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return best;
|
|
431
|
+
}
|
|
432
|
+
function collectLocaleStructuralParityDiagnostics(input) {
|
|
433
|
+
const { structure, segments } = input;
|
|
434
|
+
if (structure !== "locale_per_dir" && structure !== "feature_bundle") {
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
const byLocale = slotsByLocale(structure, segments);
|
|
438
|
+
if (byLocale.size < 2) return [];
|
|
439
|
+
const reference = pickReferenceLocale(byLocale, input.referenceLocale);
|
|
440
|
+
if (reference === null) return [];
|
|
441
|
+
const referenceSlots = byLocale.get(reference);
|
|
442
|
+
if (!referenceSlots || referenceSlots.size === 0) return [];
|
|
443
|
+
const diagnostics = [];
|
|
444
|
+
for (const [locale, slots] of byLocale) {
|
|
445
|
+
if (locale === reference) continue;
|
|
446
|
+
for (const slot of referenceSlots) {
|
|
447
|
+
if (!slots.has(slot)) {
|
|
448
|
+
diagnostics.push({
|
|
449
|
+
level: "warn",
|
|
450
|
+
code: "locale_structure_slot_missing",
|
|
451
|
+
message: `locale ${locale} is missing segment slot ${slot} (present for reference locale ${reference})`
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
for (const slot of slots) {
|
|
456
|
+
if (!referenceSlots.has(slot)) {
|
|
457
|
+
diagnostics.push({
|
|
458
|
+
level: "warn",
|
|
459
|
+
code: "locale_structure_slot_extra",
|
|
460
|
+
message: `locale ${locale} has extra segment slot ${slot} (not present for reference locale ${reference})`
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
diagnostics.sort((a, b) => a.message.localeCompare(b.message));
|
|
466
|
+
return diagnostics;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/shared/constants/locales.ts
|
|
470
|
+
var MAX_LOCALE_SEGMENT_TREE_DEPTH = 16;
|
|
471
|
+
|
|
472
|
+
// src/shared/locales/enumerate/walkJsonTree.ts
|
|
473
|
+
function posixRelative(pathApi, root, absolute) {
|
|
474
|
+
let rel = pathApi.relative(root, absolute);
|
|
475
|
+
if (rel.startsWith("..") || pathApi.isAbsolute(rel)) {
|
|
476
|
+
rel = pathApi.basename(absolute);
|
|
477
|
+
}
|
|
478
|
+
return rel.replace(/\\/g, "/");
|
|
479
|
+
}
|
|
480
|
+
function walkLocaleJsonSegments(input) {
|
|
481
|
+
const { fs, path, rootAbsolute, recursive } = input;
|
|
482
|
+
const maxDepth = input.maxDepth ?? MAX_LOCALE_SEGMENT_TREE_DEPTH;
|
|
483
|
+
const out = [];
|
|
484
|
+
function visit(dirAbsolute, depth) {
|
|
485
|
+
if (!existsRuntimeFsSync(dirAbsolute, fs)) return;
|
|
486
|
+
const entries = listRuntimeFsDirSync(dirAbsolute, fs);
|
|
487
|
+
for (const entry of entries) {
|
|
488
|
+
const childAbsolute = path.join(dirAbsolute, entry.name);
|
|
489
|
+
if (entry.kind === "file" && entry.name.endsWith(".json")) {
|
|
490
|
+
out.push({
|
|
491
|
+
absolutePath: childAbsolute,
|
|
492
|
+
relativePath: posixRelative(path, rootAbsolute, childAbsolute)
|
|
493
|
+
});
|
|
494
|
+
} else if (recursive && entry.kind === "directory" && depth < maxDepth) {
|
|
495
|
+
visit(childAbsolute, depth + 1);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
visit(rootAbsolute, 0);
|
|
500
|
+
return out;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/shared/locales/enumerate/listLocaleSegments.ts
|
|
504
|
+
function listLocaleSegments(input) {
|
|
505
|
+
const diagnostics = [];
|
|
506
|
+
const { layout, fs, path } = input;
|
|
507
|
+
const recursive = layout.structure !== "locale_file";
|
|
508
|
+
const walked = walkLocaleJsonSegments({
|
|
509
|
+
fs,
|
|
510
|
+
path,
|
|
511
|
+
rootAbsolute: layout.directoryAbsolute,
|
|
512
|
+
recursive
|
|
513
|
+
});
|
|
514
|
+
const segments = [];
|
|
515
|
+
for (const segment of walked) {
|
|
516
|
+
const locale = localeCodeForSegment(layout.structure, path, segment);
|
|
517
|
+
if (locale === null) continue;
|
|
518
|
+
segments.push({
|
|
519
|
+
locale,
|
|
520
|
+
relativePath: segment.relativePath,
|
|
521
|
+
absolutePath: segment.absolutePath
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
segments.sort((a, b) => {
|
|
525
|
+
const byLocale = a.locale.localeCompare(b.locale);
|
|
526
|
+
if (byLocale !== 0) return byLocale;
|
|
527
|
+
return a.relativePath.localeCompare(b.relativePath);
|
|
528
|
+
});
|
|
529
|
+
diagnostics.push(
|
|
530
|
+
...collectLocaleStructuralParityDiagnostics({
|
|
531
|
+
structure: layout.structure,
|
|
532
|
+
segments
|
|
533
|
+
})
|
|
534
|
+
);
|
|
535
|
+
return { segments, diagnostics };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/shared/locales/enumerate/listLocaleCodes.ts
|
|
539
|
+
function listLocaleCodes(input) {
|
|
540
|
+
const { segments, diagnostics } = listLocaleSegments(input);
|
|
541
|
+
const codes = [...new Set(segments.map((s) => s.locale))].sort((a, b) => a.localeCompare(b));
|
|
542
|
+
return { codes, diagnostics };
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// src/shared/locales/enumerate/fromContext.ts
|
|
546
|
+
function listLocaleSegmentsFromContext(ctx) {
|
|
547
|
+
return listLocaleSegments({
|
|
548
|
+
layout: resolveLocalesLayoutFromContext(ctx),
|
|
549
|
+
fs: ctx.adapters.fs,
|
|
550
|
+
path: ctx.adapters.path
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
function listLocaleCodesFromContext(ctx) {
|
|
554
|
+
return listLocaleCodes({
|
|
555
|
+
layout: resolveLocalesLayoutFromContext(ctx),
|
|
556
|
+
fs: ctx.adapters.fs,
|
|
557
|
+
path: ctx.adapters.path
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/shared/locales/targets/context.ts
|
|
562
|
+
function normalizeCode(code) {
|
|
563
|
+
return normalizeLanguageCode(code);
|
|
564
|
+
}
|
|
565
|
+
function listLocaleSegmentTargets(ctx) {
|
|
566
|
+
const { segments } = listLocaleSegmentsFromContext(ctx);
|
|
567
|
+
return segments.map((segment) => ({
|
|
568
|
+
...segment,
|
|
569
|
+
reportKey: segment.relativePath
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
572
|
+
function sourceLocaleCodeFromContext(ctx) {
|
|
573
|
+
const layout = resolveLocalesLayoutFromContext(ctx);
|
|
574
|
+
const ref = localeSegmentRefFromAbsolute({
|
|
575
|
+
layout,
|
|
576
|
+
path: ctx.adapters.path,
|
|
577
|
+
absolutePath: ctx.paths.sourceLocale
|
|
578
|
+
});
|
|
579
|
+
if (ref !== null) {
|
|
580
|
+
return normalizeCode(ref.locale);
|
|
581
|
+
}
|
|
582
|
+
return normalizeCode(ctx.adapters.path.basename(ctx.paths.sourceLocale, ".json"));
|
|
583
|
+
}
|
|
584
|
+
function localeCodesFromContext(ctx) {
|
|
585
|
+
return listLocaleCodesFromContext(ctx).codes.map((c) => normalizeCode(c));
|
|
586
|
+
}
|
|
587
|
+
function targetLocaleCodesFromContext(ctx) {
|
|
588
|
+
const source = sourceLocaleCodeFromContext(ctx);
|
|
589
|
+
return localeCodesFromContext(ctx).filter((c) => c !== source);
|
|
590
|
+
}
|
|
591
|
+
function segmentsForLocaleCode(ctx, localeCode) {
|
|
592
|
+
const want = normalizeCode(localeCode);
|
|
593
|
+
return listLocaleSegmentTargets(ctx).filter((s) => normalizeCode(s.locale) === want);
|
|
594
|
+
}
|
|
595
|
+
function primarySegmentForLocale(ctx, localeCode) {
|
|
596
|
+
const segments = segmentsForLocaleCode(ctx, localeCode);
|
|
597
|
+
if (segments.length === 0) return void 0;
|
|
598
|
+
const sourceResolved = ctx.adapters.path.resolve(ctx.paths.sourceLocale);
|
|
599
|
+
const sourceMatch = segments.find((s) => ctx.adapters.path.resolve(s.absolutePath) === sourceResolved);
|
|
600
|
+
if (sourceMatch) return sourceMatch;
|
|
601
|
+
return segments.slice().sort((a, b) => a.relativePath.localeCompare(b.relativePath))[0];
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/shared/locales/read/cache.ts
|
|
605
|
+
function dropLocaleCodeReadCache(ctx, localeCode) {
|
|
606
|
+
ctx.localeRead.localeCodes.delete(normalizeLanguageCode(localeCode));
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// src/shared/locales/read/fromContext.ts
|
|
610
|
+
function storeSegmentSnapshot(ctx, absoluteFile, snapshot) {
|
|
611
|
+
ctx.localeRead.segments.set(absoluteFile, snapshot);
|
|
612
|
+
if (snapshot.ok) {
|
|
613
|
+
const layout = resolveLocalesLayoutFromContext(ctx);
|
|
614
|
+
const ref = localeSegmentRefFromAbsolute({
|
|
615
|
+
layout,
|
|
616
|
+
path: ctx.adapters.path,
|
|
617
|
+
absolutePath: absoluteFile
|
|
618
|
+
});
|
|
619
|
+
if (ref !== null) {
|
|
620
|
+
dropLocaleCodeReadCache(ctx, ref.locale);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function segmentSnapshotToResult(snapshot) {
|
|
625
|
+
if (snapshot.ok) {
|
|
626
|
+
return {
|
|
627
|
+
ok: true,
|
|
628
|
+
document: snapshot.document,
|
|
629
|
+
leaves: snapshot.leaves,
|
|
630
|
+
text: snapshot.text,
|
|
631
|
+
diagnostics: []
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return { ok: false, leaves: [], diagnostics: snapshot.diagnostics };
|
|
635
|
+
}
|
|
636
|
+
function readLocaleSegmentFromContext(ctx, absoluteFile, onDiagnostic) {
|
|
637
|
+
const cached = ctx.localeRead.segments.get(absoluteFile);
|
|
638
|
+
if (cached !== void 0) {
|
|
639
|
+
return segmentSnapshotToResult(cached);
|
|
640
|
+
}
|
|
641
|
+
const result = readLocaleBundle({
|
|
642
|
+
layout: resolveLocalesLayoutFromContext(ctx),
|
|
643
|
+
fs: ctx.adapters.fs,
|
|
644
|
+
path: ctx.adapters.path,
|
|
645
|
+
absoluteFile,
|
|
646
|
+
onDiagnostic
|
|
647
|
+
});
|
|
648
|
+
if (result.ok) {
|
|
649
|
+
storeSegmentSnapshot(ctx, absoluteFile, {
|
|
650
|
+
ok: true,
|
|
651
|
+
absolutePath: absoluteFile,
|
|
652
|
+
document: result.document,
|
|
653
|
+
leaves: result.leaves,
|
|
654
|
+
text: result.text
|
|
655
|
+
});
|
|
656
|
+
} else {
|
|
657
|
+
storeSegmentSnapshot(ctx, absoluteFile, {
|
|
658
|
+
ok: false,
|
|
659
|
+
absolutePath: absoluteFile,
|
|
660
|
+
diagnostics: result.diagnostics
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/shared/projects/localeSurfaceMap.ts
|
|
667
|
+
function translationSurfacePathValueMapFromLeaves(leaves) {
|
|
668
|
+
return new Map(leaves.map((row) => [row.path, row.value]));
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// src/locales/summary.ts
|
|
672
|
+
function toLeafMap(ctx, absoluteFile) {
|
|
673
|
+
if (!isLocalesLayoutReadSupported(resolveLocalesLayoutFromContext(ctx))) {
|
|
674
|
+
return /* @__PURE__ */ new Map();
|
|
675
|
+
}
|
|
676
|
+
const read = readLocaleSegmentFromContext(ctx, absoluteFile);
|
|
677
|
+
if (!read.ok) return /* @__PURE__ */ new Map();
|
|
678
|
+
return translationSurfacePathValueMapFromLeaves(read.leaves);
|
|
679
|
+
}
|
|
680
|
+
function buildLocaleListRows(ctx, localeCodes) {
|
|
681
|
+
const { sourceLocale } = ctx.paths;
|
|
682
|
+
const pathApi = ctx.adapters.path;
|
|
683
|
+
const sourceMap = toLeafMap(ctx, sourceLocale);
|
|
684
|
+
const sourceCode = sourceLocaleCodeFromContext(ctx);
|
|
685
|
+
return localeCodes.slice().sort((a, b) => a.localeCompare(b)).map((code) => {
|
|
686
|
+
const normalized = normalizeLanguageCode(code);
|
|
687
|
+
const segments = segmentsForLocaleCode(ctx, normalized);
|
|
688
|
+
const primary = primarySegmentForLocale(ctx, normalized);
|
|
689
|
+
const localePath = toPosixPath(
|
|
690
|
+
primary?.absolutePath ?? pathApi.join(ctx.paths.localesDir, `${normalized}.json`)
|
|
691
|
+
);
|
|
692
|
+
const isSourceLocale = normalized === sourceCode;
|
|
693
|
+
const leafMaps = segments.map((s) => toLeafMap(ctx, s.absolutePath));
|
|
694
|
+
const leafCount = leafMaps.reduce((sum, m) => sum + m.size, 0);
|
|
695
|
+
let englishIdenticalLeafCount = null;
|
|
696
|
+
if (!isSourceLocale) {
|
|
697
|
+
let identical = 0;
|
|
698
|
+
for (const localeMap of leafMaps) {
|
|
699
|
+
for (const [leafPath, value] of localeMap) {
|
|
700
|
+
if (sourceMap.get(leafPath) === value) identical += 1;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
englishIdenticalLeafCount = identical;
|
|
704
|
+
}
|
|
705
|
+
const segmentRelativePaths = segments.map((s) => s.relativePath).sort((a, b) => a.localeCompare(b));
|
|
706
|
+
return {
|
|
707
|
+
code: normalized,
|
|
708
|
+
localePath,
|
|
709
|
+
segmentCount: segments.length,
|
|
710
|
+
segmentRelativePaths,
|
|
711
|
+
leafCount,
|
|
712
|
+
englishIdenticalLeafCount,
|
|
713
|
+
isSourceLocale
|
|
714
|
+
};
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// src/shared/languages/catalog/languages.json
|
|
719
|
+
var languages_default = [
|
|
720
|
+
{
|
|
721
|
+
code: "ab",
|
|
722
|
+
english: "Abkhazian",
|
|
723
|
+
native: "Abkhazian",
|
|
724
|
+
direction: "ltr"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
code: "ace",
|
|
728
|
+
english: "Acehnese",
|
|
729
|
+
native: "Acehnese",
|
|
730
|
+
direction: "ltr"
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
code: "ach",
|
|
734
|
+
english: "Acoli",
|
|
735
|
+
native: "Acoli",
|
|
736
|
+
direction: "ltr"
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
code: "af",
|
|
740
|
+
english: "Afrikaans",
|
|
741
|
+
native: "Afrikaans",
|
|
742
|
+
direction: "ltr"
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
code: "ak",
|
|
746
|
+
english: "Akan",
|
|
747
|
+
native: "Akan",
|
|
748
|
+
direction: "ltr"
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
code: "alz",
|
|
752
|
+
english: "alz",
|
|
753
|
+
native: "alz",
|
|
754
|
+
direction: "ltr"
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
code: "am",
|
|
758
|
+
english: "Amharic",
|
|
759
|
+
native: "\u12A0\u121B\u122D\u129B",
|
|
760
|
+
direction: "ltr"
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
code: "ar",
|
|
764
|
+
english: "Arabic",
|
|
765
|
+
native: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
|
|
766
|
+
direction: "rtl"
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
code: "ar-sa",
|
|
770
|
+
english: "Arabic (Saudi Arabia)",
|
|
771
|
+
native: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629 (\u0627\u0644\u0645\u0645\u0644\u0643\u0629 \u0627\u0644\u0639\u0631\u0628\u064A\u0629 \u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0629)",
|
|
772
|
+
direction: "rtl"
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
code: "as",
|
|
776
|
+
english: "Assamese",
|
|
777
|
+
native: "\u0985\u09B8\u09AE\u09C0\u09AF\u09BC\u09BE",
|
|
778
|
+
direction: "ltr"
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
code: "awa",
|
|
782
|
+
english: "Awadhi",
|
|
783
|
+
native: "Awadhi",
|
|
784
|
+
direction: "ltr"
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
code: "ay",
|
|
788
|
+
english: "Aymara",
|
|
789
|
+
native: "Aymara",
|
|
790
|
+
direction: "ltr"
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
code: "az",
|
|
794
|
+
english: "Azerbaijani",
|
|
795
|
+
native: "az\u0259rbaycan",
|
|
796
|
+
direction: "ltr"
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
code: "ba",
|
|
800
|
+
english: "Bashkir",
|
|
801
|
+
native: "Bashkir",
|
|
802
|
+
direction: "ltr"
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
code: "ban",
|
|
806
|
+
english: "Balinese",
|
|
807
|
+
native: "Balinese",
|
|
808
|
+
direction: "ltr"
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
code: "bbc",
|
|
812
|
+
english: "Batak Toba",
|
|
813
|
+
native: "Batak Toba",
|
|
814
|
+
direction: "ltr"
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
code: "be",
|
|
818
|
+
english: "Belarusian",
|
|
819
|
+
native: "\u0431\u0435\u043B\u0430\u0440\u0443\u0441\u043A\u0430\u044F",
|
|
820
|
+
direction: "ltr"
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
code: "bem",
|
|
824
|
+
english: "Bemba",
|
|
825
|
+
native: "Ichibemba",
|
|
826
|
+
direction: "ltr"
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
code: "bew",
|
|
830
|
+
english: "Betawi",
|
|
831
|
+
native: "Betawi",
|
|
832
|
+
direction: "ltr"
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
code: "bg",
|
|
836
|
+
english: "Bulgarian",
|
|
837
|
+
native: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438",
|
|
838
|
+
direction: "ltr"
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
code: "bho",
|
|
842
|
+
english: "Bhojpuri",
|
|
843
|
+
native: "\u092D\u094B\u091C\u092A\u0941\u0930\u0940",
|
|
844
|
+
direction: "ltr"
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
code: "bik",
|
|
848
|
+
english: "Bikol",
|
|
849
|
+
native: "Bikol",
|
|
850
|
+
direction: "ltr"
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
code: "bm",
|
|
854
|
+
english: "Bambara",
|
|
855
|
+
native: "bamanakan",
|
|
856
|
+
direction: "ltr"
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
code: "bn",
|
|
860
|
+
english: "Bangla",
|
|
861
|
+
native: "\u09AC\u09BE\u0982\u09B2\u09BE",
|
|
862
|
+
direction: "ltr"
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
code: "bn-in",
|
|
866
|
+
english: "Bangla (India)",
|
|
867
|
+
native: "\u09AC\u09BE\u0982\u09B2\u09BE (\u09AD\u09BE\u09B0\u09A4)",
|
|
868
|
+
direction: "ltr"
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
code: "br",
|
|
872
|
+
english: "Breton",
|
|
873
|
+
native: "brezhoneg",
|
|
874
|
+
direction: "ltr"
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
code: "bs",
|
|
878
|
+
english: "Bosnian",
|
|
879
|
+
native: "bosanski",
|
|
880
|
+
direction: "ltr"
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
code: "bs-cyrl",
|
|
884
|
+
english: "Bosnian (Cyrillic)",
|
|
885
|
+
native: "\u0431\u043E\u0441\u0430\u043D\u0441\u043A\u0438 (\u045B\u0438\u0440\u0438\u043B\u0438\u0446\u0430)",
|
|
886
|
+
direction: "ltr"
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
code: "bts",
|
|
890
|
+
english: "bts",
|
|
891
|
+
native: "bts",
|
|
892
|
+
direction: "ltr"
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
code: "btx",
|
|
896
|
+
english: "btx",
|
|
897
|
+
native: "btx",
|
|
898
|
+
direction: "ltr"
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
code: "bua",
|
|
902
|
+
english: "Buriat",
|
|
903
|
+
native: "Buriat",
|
|
904
|
+
direction: "ltr"
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
code: "ca",
|
|
908
|
+
english: "Catalan",
|
|
909
|
+
native: "catal\xE0",
|
|
910
|
+
direction: "ltr"
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
code: "ceb",
|
|
914
|
+
english: "Cebuano",
|
|
915
|
+
native: "Cebuano",
|
|
916
|
+
direction: "ltr"
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
code: "cgg",
|
|
920
|
+
english: "Chiga",
|
|
921
|
+
native: "Rukiga",
|
|
922
|
+
direction: "ltr"
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
code: "chm",
|
|
926
|
+
english: "Mari",
|
|
927
|
+
native: "Mari",
|
|
928
|
+
direction: "ltr"
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
code: "ckb",
|
|
932
|
+
english: "Central Kurdish",
|
|
933
|
+
native: "\u06A9\u0648\u0631\u062F\u06CC\u06CC \u0646\u0627\u0648\u06D5\u0646\u062F\u06CC",
|
|
934
|
+
direction: "rtl"
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
code: "cnh",
|
|
938
|
+
english: "cnh",
|
|
939
|
+
native: "cnh",
|
|
940
|
+
direction: "ltr"
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
code: "co",
|
|
944
|
+
english: "Corsican",
|
|
945
|
+
native: "Corsican",
|
|
946
|
+
direction: "ltr"
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
code: "crh",
|
|
950
|
+
english: "Crimean Tatar",
|
|
951
|
+
native: "Crimean Tatar",
|
|
952
|
+
direction: "ltr"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
code: "crs",
|
|
956
|
+
english: "Seselwa Creole French",
|
|
957
|
+
native: "Seselwa Creole French",
|
|
958
|
+
direction: "ltr"
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
code: "cs",
|
|
962
|
+
english: "Czech",
|
|
963
|
+
native: "\u010De\u0161tina",
|
|
964
|
+
direction: "ltr"
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
code: "cv",
|
|
968
|
+
english: "Chuvash",
|
|
969
|
+
native: "\u0447\u04D1\u0432\u0430\u0448",
|
|
970
|
+
direction: "ltr"
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
code: "cy",
|
|
974
|
+
english: "Welsh",
|
|
975
|
+
native: "Cymraeg",
|
|
976
|
+
direction: "ltr"
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
code: "da",
|
|
980
|
+
english: "Danish",
|
|
981
|
+
native: "dansk",
|
|
982
|
+
direction: "ltr"
|
|
983
|
+
},
|
|
984
|
+
{
|
|
985
|
+
code: "de",
|
|
986
|
+
english: "German",
|
|
987
|
+
native: "Deutsch",
|
|
988
|
+
direction: "ltr"
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
code: "din",
|
|
992
|
+
english: "Dinka",
|
|
993
|
+
native: "Dinka",
|
|
994
|
+
direction: "ltr"
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
code: "doi",
|
|
998
|
+
english: "Dogri",
|
|
999
|
+
native: "\u0921\u094B\u0917\u0930\u0940",
|
|
1000
|
+
direction: "ltr"
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
code: "dov",
|
|
1004
|
+
english: "dov",
|
|
1005
|
+
native: "dov",
|
|
1006
|
+
direction: "ltr"
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
code: "dv",
|
|
1010
|
+
english: "Divehi",
|
|
1011
|
+
native: "Divehi",
|
|
1012
|
+
direction: "rtl"
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
code: "dz",
|
|
1016
|
+
english: "Dzongkha",
|
|
1017
|
+
native: "\u0F62\u0FAB\u0F7C\u0F44\u0F0B\u0F41",
|
|
1018
|
+
direction: "ltr"
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
code: "ee",
|
|
1022
|
+
english: "Ewe",
|
|
1023
|
+
native: "E\u028Begbe",
|
|
1024
|
+
direction: "ltr"
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
code: "el",
|
|
1028
|
+
english: "Greek",
|
|
1029
|
+
native: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC",
|
|
1030
|
+
direction: "ltr"
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
code: "en",
|
|
1034
|
+
english: "English",
|
|
1035
|
+
native: "English",
|
|
1036
|
+
direction: "ltr"
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
code: "en-au",
|
|
1040
|
+
english: "Australian English",
|
|
1041
|
+
native: "Australian English",
|
|
1042
|
+
direction: "ltr"
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
code: "en-ca",
|
|
1046
|
+
english: "Canadian English",
|
|
1047
|
+
native: "Canadian English",
|
|
1048
|
+
direction: "ltr"
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
code: "en-gb",
|
|
1052
|
+
english: "British English",
|
|
1053
|
+
native: "British English",
|
|
1054
|
+
direction: "ltr"
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
code: "en-nz",
|
|
1058
|
+
english: "English (New Zealand)",
|
|
1059
|
+
native: "English (New Zealand)",
|
|
1060
|
+
direction: "ltr"
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
code: "en-ph",
|
|
1064
|
+
english: "English (Philippines)",
|
|
1065
|
+
native: "English (Philippines)",
|
|
1066
|
+
direction: "ltr"
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
code: "en-us",
|
|
1070
|
+
english: "American English",
|
|
1071
|
+
native: "American English",
|
|
1072
|
+
direction: "ltr"
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
code: "en-za",
|
|
1076
|
+
english: "English (South Africa)",
|
|
1077
|
+
native: "English (South Africa)",
|
|
1078
|
+
direction: "ltr"
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
code: "eo",
|
|
1082
|
+
english: "Esperanto",
|
|
1083
|
+
native: "Esperanto",
|
|
1084
|
+
direction: "ltr"
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
code: "es",
|
|
1088
|
+
english: "Spanish",
|
|
1089
|
+
native: "espa\xF1ol",
|
|
1090
|
+
direction: "ltr"
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
code: "es-419",
|
|
1094
|
+
english: "Latin American Spanish",
|
|
1095
|
+
native: "espa\xF1ol latinoamericano",
|
|
1096
|
+
direction: "ltr"
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
code: "es-ar",
|
|
1100
|
+
english: "Spanish (Argentina)",
|
|
1101
|
+
native: "espa\xF1ol (Argentina)",
|
|
1102
|
+
direction: "ltr"
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
code: "es-cl",
|
|
1106
|
+
english: "Spanish (Chile)",
|
|
1107
|
+
native: "espa\xF1ol (Chile)",
|
|
1108
|
+
direction: "ltr"
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
code: "es-co",
|
|
1112
|
+
english: "Spanish (Colombia)",
|
|
1113
|
+
native: "espa\xF1ol (Colombia)",
|
|
1114
|
+
direction: "ltr"
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
code: "es-cr",
|
|
1118
|
+
english: "Spanish (Costa Rica)",
|
|
1119
|
+
native: "espa\xF1ol (Costa Rica)",
|
|
1120
|
+
direction: "ltr"
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
code: "es-ec",
|
|
1124
|
+
english: "Spanish (Ecuador)",
|
|
1125
|
+
native: "espa\xF1ol (Ecuador)",
|
|
1126
|
+
direction: "ltr"
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
code: "es-es",
|
|
1130
|
+
english: "European Spanish",
|
|
1131
|
+
native: "espa\xF1ol de Espa\xF1a",
|
|
1132
|
+
direction: "ltr"
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
code: "es-gt",
|
|
1136
|
+
english: "Spanish (Guatemala)",
|
|
1137
|
+
native: "espa\xF1ol (Guatemala)",
|
|
1138
|
+
direction: "ltr"
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
code: "es-hn",
|
|
1142
|
+
english: "Spanish (Honduras)",
|
|
1143
|
+
native: "espa\xF1ol (Honduras)",
|
|
1144
|
+
direction: "ltr"
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
code: "es-ht",
|
|
1148
|
+
english: "Spanish (Haiti)",
|
|
1149
|
+
native: "espa\xF1ol (Hait\xED)",
|
|
1150
|
+
direction: "ltr"
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
code: "es-mx",
|
|
1154
|
+
english: "Mexican Spanish",
|
|
1155
|
+
native: "espa\xF1ol de M\xE9xico",
|
|
1156
|
+
direction: "ltr"
|
|
1157
|
+
},
|
|
1158
|
+
{
|
|
1159
|
+
code: "es-ni",
|
|
1160
|
+
english: "Spanish (Nicaragua)",
|
|
1161
|
+
native: "espa\xF1ol (Nicaragua)",
|
|
1162
|
+
direction: "ltr"
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
code: "es-pa",
|
|
1166
|
+
english: "Spanish (Panama)",
|
|
1167
|
+
native: "espa\xF1ol (Panam\xE1)",
|
|
1168
|
+
direction: "ltr"
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
code: "es-pe",
|
|
1172
|
+
english: "Spanish (Peru)",
|
|
1173
|
+
native: "espa\xF1ol (Per\xFA)",
|
|
1174
|
+
direction: "ltr"
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
code: "es-pr",
|
|
1178
|
+
english: "Spanish (Puerto Rico)",
|
|
1179
|
+
native: "espa\xF1ol (Puerto Rico)",
|
|
1180
|
+
direction: "ltr"
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
code: "es-py",
|
|
1184
|
+
english: "Spanish (Paraguay)",
|
|
1185
|
+
native: "espa\xF1ol (Paraguay)",
|
|
1186
|
+
direction: "ltr"
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
code: "es-sv",
|
|
1190
|
+
english: "Spanish (El Salvador)",
|
|
1191
|
+
native: "espa\xF1ol (El Salvador)",
|
|
1192
|
+
direction: "ltr"
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
code: "es-us",
|
|
1196
|
+
english: "Spanish (United States)",
|
|
1197
|
+
native: "espa\xF1ol (Estados Unidos)",
|
|
1198
|
+
direction: "ltr"
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
code: "es-uy",
|
|
1202
|
+
english: "Spanish (Uruguay)",
|
|
1203
|
+
native: "espa\xF1ol (Uruguay)",
|
|
1204
|
+
direction: "ltr"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
code: "es-ve",
|
|
1208
|
+
english: "Spanish (Venezuela)",
|
|
1209
|
+
native: "espa\xF1ol (Venezuela)",
|
|
1210
|
+
direction: "ltr"
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
code: "et",
|
|
1214
|
+
english: "Estonian",
|
|
1215
|
+
native: "eesti",
|
|
1216
|
+
direction: "ltr"
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
code: "eu",
|
|
1220
|
+
english: "Basque",
|
|
1221
|
+
native: "euskara",
|
|
1222
|
+
direction: "ltr"
|
|
1223
|
+
},
|
|
1224
|
+
{
|
|
1225
|
+
code: "fa",
|
|
1226
|
+
english: "Persian",
|
|
1227
|
+
native: "\u0641\u0627\u0631\u0633\u06CC",
|
|
1228
|
+
direction: "rtl"
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
code: "ff",
|
|
1232
|
+
english: "Fula",
|
|
1233
|
+
native: "Pulaar",
|
|
1234
|
+
direction: "rtl"
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
code: "fi",
|
|
1238
|
+
english: "Finnish",
|
|
1239
|
+
native: "suomi",
|
|
1240
|
+
direction: "ltr"
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
code: "fil",
|
|
1244
|
+
english: "Filipino",
|
|
1245
|
+
native: "Filipino",
|
|
1246
|
+
direction: "ltr"
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
code: "fj",
|
|
1250
|
+
english: "Fijian",
|
|
1251
|
+
native: "Fijian",
|
|
1252
|
+
direction: "ltr"
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
code: "fr",
|
|
1256
|
+
english: "French",
|
|
1257
|
+
native: "fran\xE7ais",
|
|
1258
|
+
direction: "ltr"
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
code: "fr-ca",
|
|
1262
|
+
english: "Canadian French",
|
|
1263
|
+
native: "fran\xE7ais canadien",
|
|
1264
|
+
direction: "ltr"
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
code: "fr-ch",
|
|
1268
|
+
english: "Swiss French",
|
|
1269
|
+
native: "fran\xE7ais suisse",
|
|
1270
|
+
direction: "ltr"
|
|
1271
|
+
},
|
|
1272
|
+
{
|
|
1273
|
+
code: "fr-fr",
|
|
1274
|
+
english: "French (France)",
|
|
1275
|
+
native: "fran\xE7ais (France)",
|
|
1276
|
+
direction: "ltr"
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
code: "fy",
|
|
1280
|
+
english: "Western Frisian",
|
|
1281
|
+
native: "Frysk",
|
|
1282
|
+
direction: "ltr"
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
code: "ga",
|
|
1286
|
+
english: "Irish",
|
|
1287
|
+
native: "Gaeilge",
|
|
1288
|
+
direction: "ltr"
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
code: "gaa",
|
|
1292
|
+
english: "Ga",
|
|
1293
|
+
native: "Ga",
|
|
1294
|
+
direction: "ltr"
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
code: "gd",
|
|
1298
|
+
english: "Scottish Gaelic",
|
|
1299
|
+
native: "G\xE0idhlig",
|
|
1300
|
+
direction: "ltr"
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
code: "gl",
|
|
1304
|
+
english: "Galician",
|
|
1305
|
+
native: "galego",
|
|
1306
|
+
direction: "ltr"
|
|
1307
|
+
},
|
|
1308
|
+
{
|
|
1309
|
+
code: "gn",
|
|
1310
|
+
english: "Guarani",
|
|
1311
|
+
native: "Guarani",
|
|
1312
|
+
direction: "ltr"
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
code: "gom",
|
|
1316
|
+
english: "Goan Konkani",
|
|
1317
|
+
native: "Goan Konkani",
|
|
1318
|
+
direction: "ltr"
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
code: "gu",
|
|
1322
|
+
english: "Gujarati",
|
|
1323
|
+
native: "\u0A97\u0AC1\u0A9C\u0AB0\u0ABE\u0AA4\u0AC0",
|
|
1324
|
+
direction: "ltr"
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
code: "ha",
|
|
1328
|
+
english: "Hausa",
|
|
1329
|
+
native: "Hausa",
|
|
1330
|
+
direction: "rtl"
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
code: "haw",
|
|
1334
|
+
english: "Hawaiian",
|
|
1335
|
+
native: "\u02BB\u014Clelo Hawai\u02BBi",
|
|
1336
|
+
direction: "ltr"
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
code: "he",
|
|
1340
|
+
english: "Hebrew",
|
|
1341
|
+
native: "\u05E2\u05D1\u05E8\u05D9\u05EA",
|
|
1342
|
+
direction: "rtl"
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
code: "hi",
|
|
1346
|
+
english: "Hindi",
|
|
1347
|
+
native: "\u0939\u093F\u0928\u094D\u0926\u0940",
|
|
1348
|
+
direction: "ltr"
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
code: "hil",
|
|
1352
|
+
english: "Hiligaynon",
|
|
1353
|
+
native: "Hiligaynon",
|
|
1354
|
+
direction: "ltr"
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
code: "hmn",
|
|
1358
|
+
english: "Hmong",
|
|
1359
|
+
native: "Hmong",
|
|
1360
|
+
direction: "ltr"
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
code: "hr",
|
|
1364
|
+
english: "Croatian",
|
|
1365
|
+
native: "hrvatski",
|
|
1366
|
+
direction: "ltr"
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
code: "hrx",
|
|
1370
|
+
english: "hrx",
|
|
1371
|
+
native: "hrx",
|
|
1372
|
+
direction: "ltr"
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
code: "ht",
|
|
1376
|
+
english: "Haitian Creole",
|
|
1377
|
+
native: "Haitian Creole",
|
|
1378
|
+
direction: "ltr"
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
code: "hu",
|
|
1382
|
+
english: "Hungarian",
|
|
1383
|
+
native: "magyar",
|
|
1384
|
+
direction: "ltr"
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
code: "hy",
|
|
1388
|
+
english: "Armenian",
|
|
1389
|
+
native: "\u0570\u0561\u0575\u0565\u0580\u0565\u0576",
|
|
1390
|
+
direction: "ltr"
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
code: "id",
|
|
1394
|
+
english: "Indonesian",
|
|
1395
|
+
native: "Indonesia",
|
|
1396
|
+
direction: "ltr"
|
|
1397
|
+
},
|
|
1398
|
+
{
|
|
1399
|
+
code: "ig",
|
|
1400
|
+
english: "Igbo",
|
|
1401
|
+
native: "Igbo",
|
|
1402
|
+
direction: "ltr"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
code: "ilo",
|
|
1406
|
+
english: "Iloko",
|
|
1407
|
+
native: "Iloko",
|
|
1408
|
+
direction: "ltr"
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
code: "is",
|
|
1412
|
+
english: "Icelandic",
|
|
1413
|
+
native: "\xEDslenska",
|
|
1414
|
+
direction: "ltr"
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
code: "it",
|
|
1418
|
+
english: "Italian",
|
|
1419
|
+
native: "italiano",
|
|
1420
|
+
direction: "ltr"
|
|
1421
|
+
},
|
|
1422
|
+
{
|
|
1423
|
+
code: "iw",
|
|
1424
|
+
english: "Hebrew",
|
|
1425
|
+
native: "\u05E2\u05D1\u05E8\u05D9\u05EA",
|
|
1426
|
+
direction: "rtl"
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
code: "ja",
|
|
1430
|
+
english: "Japanese",
|
|
1431
|
+
native: "\u65E5\u672C\u8A9E",
|
|
1432
|
+
direction: "ltr"
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
code: "jv",
|
|
1436
|
+
english: "Javanese",
|
|
1437
|
+
native: "Jawa",
|
|
1438
|
+
direction: "ltr"
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
code: "jw",
|
|
1442
|
+
english: "Javanese",
|
|
1443
|
+
native: "Jawa",
|
|
1444
|
+
direction: "ltr"
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
code: "ka",
|
|
1448
|
+
english: "Georgian",
|
|
1449
|
+
native: "\u10E5\u10D0\u10E0\u10D7\u10E3\u10DA\u10D8",
|
|
1450
|
+
direction: "ltr"
|
|
1451
|
+
},
|
|
1452
|
+
{
|
|
1453
|
+
code: "kk",
|
|
1454
|
+
english: "Kazakh",
|
|
1455
|
+
native: "\u049B\u0430\u0437\u0430\u049B \u0442\u0456\u043B\u0456",
|
|
1456
|
+
direction: "ltr"
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
code: "km",
|
|
1460
|
+
english: "Khmer",
|
|
1461
|
+
native: "\u1781\u17D2\u1798\u17C2\u179A",
|
|
1462
|
+
direction: "ltr"
|
|
1463
|
+
},
|
|
1464
|
+
{
|
|
1465
|
+
code: "kn",
|
|
1466
|
+
english: "Kannada",
|
|
1467
|
+
native: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1",
|
|
1468
|
+
direction: "ltr"
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
code: "ko",
|
|
1472
|
+
english: "Korean",
|
|
1473
|
+
native: "\uD55C\uAD6D\uC5B4",
|
|
1474
|
+
direction: "ltr"
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
code: "kri",
|
|
1478
|
+
english: "Krio",
|
|
1479
|
+
native: "Krio",
|
|
1480
|
+
direction: "ltr"
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
code: "ktu",
|
|
1484
|
+
english: "ktu",
|
|
1485
|
+
native: "ktu",
|
|
1486
|
+
direction: "ltr"
|
|
1487
|
+
},
|
|
1488
|
+
{
|
|
1489
|
+
code: "ku",
|
|
1490
|
+
english: "Kurdish",
|
|
1491
|
+
native: "kurd\xEE (kurmanc\xEE)",
|
|
1492
|
+
direction: "ltr"
|
|
1493
|
+
},
|
|
1494
|
+
{
|
|
1495
|
+
code: "ky",
|
|
1496
|
+
english: "Kyrgyz",
|
|
1497
|
+
native: "\u043A\u044B\u0440\u0433\u044B\u0437\u0447\u0430",
|
|
1498
|
+
direction: "ltr"
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
code: "la",
|
|
1502
|
+
english: "Latin",
|
|
1503
|
+
native: "Latin",
|
|
1504
|
+
direction: "ltr"
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
code: "lb",
|
|
1508
|
+
english: "Luxembourgish",
|
|
1509
|
+
native: "L\xEBtzebuergesch",
|
|
1510
|
+
direction: "ltr"
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
code: "lg",
|
|
1514
|
+
english: "Ganda",
|
|
1515
|
+
native: "Luganda",
|
|
1516
|
+
direction: "ltr"
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
code: "li",
|
|
1520
|
+
english: "Limburgish",
|
|
1521
|
+
native: "Limburgish",
|
|
1522
|
+
direction: "ltr"
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
code: "lij",
|
|
1526
|
+
english: "Ligurian",
|
|
1527
|
+
native: "ligure",
|
|
1528
|
+
direction: "ltr"
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
code: "lmo",
|
|
1532
|
+
english: "Lombard",
|
|
1533
|
+
native: "Lombard",
|
|
1534
|
+
direction: "ltr"
|
|
1535
|
+
},
|
|
1536
|
+
{
|
|
1537
|
+
code: "ln",
|
|
1538
|
+
english: "Lingala",
|
|
1539
|
+
native: "ling\xE1la",
|
|
1540
|
+
direction: "ltr"
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
code: "lo",
|
|
1544
|
+
english: "Lao",
|
|
1545
|
+
native: "\u0EA5\u0EB2\u0EA7",
|
|
1546
|
+
direction: "ltr"
|
|
1547
|
+
},
|
|
1548
|
+
{
|
|
1549
|
+
code: "lt",
|
|
1550
|
+
english: "Lithuanian",
|
|
1551
|
+
native: "lietuvi\u0173",
|
|
1552
|
+
direction: "ltr"
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
code: "ltg",
|
|
1556
|
+
english: "Latgalian",
|
|
1557
|
+
native: "Latgalian",
|
|
1558
|
+
direction: "ltr"
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
code: "luo",
|
|
1562
|
+
english: "Luo",
|
|
1563
|
+
native: "Dholuo",
|
|
1564
|
+
direction: "ltr"
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
code: "lus",
|
|
1568
|
+
english: "Mizo",
|
|
1569
|
+
native: "Mizo",
|
|
1570
|
+
direction: "ltr"
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
code: "lv",
|
|
1574
|
+
english: "Latvian",
|
|
1575
|
+
native: "latvie\u0161u",
|
|
1576
|
+
direction: "ltr"
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
code: "mai",
|
|
1580
|
+
english: "Maithili",
|
|
1581
|
+
native: "\u092E\u0948\u0925\u093F\u0932\u0940",
|
|
1582
|
+
direction: "ltr"
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
code: "mak",
|
|
1586
|
+
english: "Makasar",
|
|
1587
|
+
native: "Makasar",
|
|
1588
|
+
direction: "ltr"
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
code: "mg",
|
|
1592
|
+
english: "Malagasy",
|
|
1593
|
+
native: "Malagasy",
|
|
1594
|
+
direction: "ltr"
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
code: "mi",
|
|
1598
|
+
english: "M\u0101ori",
|
|
1599
|
+
native: "M\u0101ori",
|
|
1600
|
+
direction: "ltr"
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
code: "min",
|
|
1604
|
+
english: "Minangkabau",
|
|
1605
|
+
native: "Minangkabau",
|
|
1606
|
+
direction: "ltr"
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
code: "mk",
|
|
1610
|
+
english: "Macedonian",
|
|
1611
|
+
native: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438",
|
|
1612
|
+
direction: "ltr"
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
code: "ml",
|
|
1616
|
+
english: "Malayalam",
|
|
1617
|
+
native: "\u0D2E\u0D32\u0D2F\u0D3E\u0D33\u0D02",
|
|
1618
|
+
direction: "ltr"
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
code: "mn",
|
|
1622
|
+
english: "Mongolian",
|
|
1623
|
+
native: "\u043C\u043E\u043D\u0433\u043E\u043B",
|
|
1624
|
+
direction: "ltr"
|
|
1625
|
+
},
|
|
1626
|
+
{
|
|
1627
|
+
code: "mni-mtei",
|
|
1628
|
+
english: "Manipuri (Meitei Mayek)",
|
|
1629
|
+
native: "\u09AE\u09C8\u09A4\u09C8\u09B2\u09CB\u09A8\u09CD (\u09AE\u09C0\u09A4\u09C8 \u09AE\u09AF\u09BC\u09C7\u0995)",
|
|
1630
|
+
direction: "ltr"
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
code: "mr",
|
|
1634
|
+
english: "Marathi",
|
|
1635
|
+
native: "\u092E\u0930\u093E\u0920\u0940",
|
|
1636
|
+
direction: "ltr"
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
code: "ms",
|
|
1640
|
+
english: "Malay",
|
|
1641
|
+
native: "Melayu",
|
|
1642
|
+
direction: "ltr"
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
code: "ms-arab",
|
|
1646
|
+
english: "Malay (Arabic)",
|
|
1647
|
+
native: "Melayu (Arab)",
|
|
1648
|
+
direction: "ltr"
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
code: "mt",
|
|
1652
|
+
english: "Maltese",
|
|
1653
|
+
native: "Malti",
|
|
1654
|
+
direction: "ltr"
|
|
1655
|
+
},
|
|
1656
|
+
{
|
|
1657
|
+
code: "my",
|
|
1658
|
+
english: "Burmese",
|
|
1659
|
+
native: "\u1019\u103C\u1014\u103A\u1019\u102C",
|
|
1660
|
+
direction: "ltr"
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
code: "nb",
|
|
1664
|
+
english: "Norwegian Bokm\xE5l",
|
|
1665
|
+
native: "norsk bokm\xE5l",
|
|
1666
|
+
direction: "ltr"
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
code: "ne",
|
|
1670
|
+
english: "Nepali",
|
|
1671
|
+
native: "\u0928\u0947\u092A\u093E\u0932\u0940",
|
|
1672
|
+
direction: "ltr"
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
code: "new",
|
|
1676
|
+
english: "Newari",
|
|
1677
|
+
native: "Newari",
|
|
1678
|
+
direction: "ltr"
|
|
1679
|
+
},
|
|
1680
|
+
{
|
|
1681
|
+
code: "nl",
|
|
1682
|
+
english: "Dutch",
|
|
1683
|
+
native: "Nederlands",
|
|
1684
|
+
direction: "ltr"
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
code: "nl-be",
|
|
1688
|
+
english: "Flemish",
|
|
1689
|
+
native: "Vlaams",
|
|
1690
|
+
direction: "ltr"
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
code: "no",
|
|
1694
|
+
english: "Norwegian",
|
|
1695
|
+
native: "norsk",
|
|
1696
|
+
direction: "ltr"
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
code: "nr",
|
|
1700
|
+
english: "South Ndebele",
|
|
1701
|
+
native: "South Ndebele",
|
|
1702
|
+
direction: "ltr"
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
code: "nso",
|
|
1706
|
+
english: "Northern Sotho",
|
|
1707
|
+
native: "Northern Sotho",
|
|
1708
|
+
direction: "ltr"
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
code: "nus",
|
|
1712
|
+
english: "Nuer",
|
|
1713
|
+
native: "Thok Nath",
|
|
1714
|
+
direction: "ltr"
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
code: "ny",
|
|
1718
|
+
english: "Nyanja",
|
|
1719
|
+
native: "Nyanja",
|
|
1720
|
+
direction: "ltr"
|
|
1721
|
+
},
|
|
1722
|
+
{
|
|
1723
|
+
code: "oc",
|
|
1724
|
+
english: "Occitan",
|
|
1725
|
+
native: "occitan",
|
|
1726
|
+
direction: "ltr"
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
code: "om",
|
|
1730
|
+
english: "Oromo",
|
|
1731
|
+
native: "Oromoo",
|
|
1732
|
+
direction: "ltr"
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
code: "or",
|
|
1736
|
+
english: "Odia",
|
|
1737
|
+
native: "\u0B13\u0B21\u0B3C\u0B3F\u0B06",
|
|
1738
|
+
direction: "ltr"
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
code: "pa",
|
|
1742
|
+
english: "Punjabi",
|
|
1743
|
+
native: "\u0A2A\u0A70\u0A1C\u0A3E\u0A2C\u0A40",
|
|
1744
|
+
direction: "ltr"
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
code: "pa-arab",
|
|
1748
|
+
english: "Punjabi (Arabic)",
|
|
1749
|
+
native: "\u067E\u0646\u062C\u0627\u0628\u06CC (\u0639\u0631\u0628\u06CC)",
|
|
1750
|
+
direction: "ltr"
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
code: "pa-pk",
|
|
1754
|
+
english: "Punjabi (Pakistan)",
|
|
1755
|
+
native: "\u067E\u0646\u062C\u0627\u0628\u06CC (\u067E\u0627\u06A9\u0633\u062A\u0627\u0646)",
|
|
1756
|
+
direction: "ltr"
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
code: "pag",
|
|
1760
|
+
english: "Pangasinan",
|
|
1761
|
+
native: "Pangasinan",
|
|
1762
|
+
direction: "ltr"
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
code: "pam",
|
|
1766
|
+
english: "Pampanga",
|
|
1767
|
+
native: "Pampanga",
|
|
1768
|
+
direction: "ltr"
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
code: "pap",
|
|
1772
|
+
english: "Papiamento",
|
|
1773
|
+
native: "Papiamento",
|
|
1774
|
+
direction: "ltr"
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
code: "pl",
|
|
1778
|
+
english: "Polish",
|
|
1779
|
+
native: "polski",
|
|
1780
|
+
direction: "ltr"
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
code: "ps",
|
|
1784
|
+
english: "Pashto",
|
|
1785
|
+
native: "\u067E\u069A\u062A\u0648",
|
|
1786
|
+
direction: "rtl"
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
code: "pt",
|
|
1790
|
+
english: "Portuguese",
|
|
1791
|
+
native: "portugu\xEAs",
|
|
1792
|
+
direction: "ltr"
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
code: "pt-br",
|
|
1796
|
+
english: "Brazilian Portuguese",
|
|
1797
|
+
native: "portugu\xEAs (Brasil)",
|
|
1798
|
+
direction: "ltr"
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
code: "pt-pt",
|
|
1802
|
+
english: "European Portuguese",
|
|
1803
|
+
native: "portugu\xEAs europeu",
|
|
1804
|
+
direction: "ltr"
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
code: "qu",
|
|
1808
|
+
english: "Quechua",
|
|
1809
|
+
native: "Runasimi",
|
|
1810
|
+
direction: "ltr"
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
code: "rn",
|
|
1814
|
+
english: "Rundi",
|
|
1815
|
+
native: "Ikirundi",
|
|
1816
|
+
direction: "ltr"
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
code: "ro",
|
|
1820
|
+
english: "Romanian",
|
|
1821
|
+
native: "rom\xE2n\u0103",
|
|
1822
|
+
direction: "ltr"
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
code: "rom",
|
|
1826
|
+
english: "Romany",
|
|
1827
|
+
native: "Romany",
|
|
1828
|
+
direction: "ltr"
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
code: "ru",
|
|
1832
|
+
english: "Russian",
|
|
1833
|
+
native: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439",
|
|
1834
|
+
direction: "ltr"
|
|
1835
|
+
},
|
|
1836
|
+
{
|
|
1837
|
+
code: "rw",
|
|
1838
|
+
english: "Kinyarwanda",
|
|
1839
|
+
native: "Kinyarwanda",
|
|
1840
|
+
direction: "ltr"
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
code: "sa",
|
|
1844
|
+
english: "Sanskrit",
|
|
1845
|
+
native: "\u0938\u0902\u0938\u094D\u0915\u0943\u0924 \u092D\u093E\u0937\u093E",
|
|
1846
|
+
direction: "ltr"
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
code: "scn",
|
|
1850
|
+
english: "Sicilian",
|
|
1851
|
+
native: "Sicilian",
|
|
1852
|
+
direction: "ltr"
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
code: "sd",
|
|
1856
|
+
english: "Sindhi",
|
|
1857
|
+
native: "\u0633\u0646\u068C\u064A",
|
|
1858
|
+
direction: "rtl"
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
code: "sg",
|
|
1862
|
+
english: "Sango",
|
|
1863
|
+
native: "S\xE4ng\xF6",
|
|
1864
|
+
direction: "ltr"
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
code: "shn",
|
|
1868
|
+
english: "Shan",
|
|
1869
|
+
native: "Shan",
|
|
1870
|
+
direction: "ltr"
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
code: "si",
|
|
1874
|
+
english: "Sinhala",
|
|
1875
|
+
native: "\u0DC3\u0DD2\u0D82\u0DC4\u0DBD",
|
|
1876
|
+
direction: "ltr"
|
|
1877
|
+
},
|
|
1878
|
+
{
|
|
1879
|
+
code: "sk",
|
|
1880
|
+
english: "Slovak",
|
|
1881
|
+
native: "sloven\u010Dina",
|
|
1882
|
+
direction: "ltr"
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
code: "sl",
|
|
1886
|
+
english: "Slovenian",
|
|
1887
|
+
native: "sloven\u0161\u010Dina",
|
|
1888
|
+
direction: "ltr"
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
code: "sm",
|
|
1892
|
+
english: "Samoan",
|
|
1893
|
+
native: "Samoan",
|
|
1894
|
+
direction: "ltr"
|
|
1895
|
+
},
|
|
1896
|
+
{
|
|
1897
|
+
code: "sn",
|
|
1898
|
+
english: "Shona",
|
|
1899
|
+
native: "chiShona",
|
|
1900
|
+
direction: "ltr"
|
|
1901
|
+
},
|
|
1902
|
+
{
|
|
1903
|
+
code: "so",
|
|
1904
|
+
english: "Somali",
|
|
1905
|
+
native: "Soomaali",
|
|
1906
|
+
direction: "ltr"
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
code: "sq",
|
|
1910
|
+
english: "Albanian",
|
|
1911
|
+
native: "shqip",
|
|
1912
|
+
direction: "ltr"
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
code: "sr",
|
|
1916
|
+
english: "Serbian",
|
|
1917
|
+
native: "\u0441\u0440\u043F\u0441\u043A\u0438",
|
|
1918
|
+
direction: "ltr"
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
code: "ss",
|
|
1922
|
+
english: "Swati",
|
|
1923
|
+
native: "Swati",
|
|
1924
|
+
direction: "ltr"
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
code: "st",
|
|
1928
|
+
english: "Southern Sotho",
|
|
1929
|
+
native: "Southern Sotho",
|
|
1930
|
+
direction: "ltr"
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
code: "su",
|
|
1934
|
+
english: "Sundanese",
|
|
1935
|
+
native: "Basa Sunda",
|
|
1936
|
+
direction: "ltr"
|
|
1937
|
+
},
|
|
1938
|
+
{
|
|
1939
|
+
code: "sv",
|
|
1940
|
+
english: "Swedish",
|
|
1941
|
+
native: "svenska",
|
|
1942
|
+
direction: "ltr"
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
code: "sw",
|
|
1946
|
+
english: "Swahili",
|
|
1947
|
+
native: "Kiswahili",
|
|
1948
|
+
direction: "ltr"
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
code: "szl",
|
|
1952
|
+
english: "Silesian",
|
|
1953
|
+
native: "\u015Bl\u014Dnski",
|
|
1954
|
+
direction: "ltr"
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
code: "ta",
|
|
1958
|
+
english: "Tamil",
|
|
1959
|
+
native: "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
|
|
1960
|
+
direction: "ltr"
|
|
1961
|
+
},
|
|
1962
|
+
{
|
|
1963
|
+
code: "te",
|
|
1964
|
+
english: "Telugu",
|
|
1965
|
+
native: "\u0C24\u0C46\u0C32\u0C41\u0C17\u0C41",
|
|
1966
|
+
direction: "ltr"
|
|
1967
|
+
},
|
|
1968
|
+
{
|
|
1969
|
+
code: "tet",
|
|
1970
|
+
english: "Tetum",
|
|
1971
|
+
native: "Tetum",
|
|
1972
|
+
direction: "ltr"
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
code: "tg",
|
|
1976
|
+
english: "Tajik",
|
|
1977
|
+
native: "\u0442\u043E\u04B7\u0438\u043A\u04E3",
|
|
1978
|
+
direction: "ltr"
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
code: "th",
|
|
1982
|
+
english: "Thai",
|
|
1983
|
+
native: "\u0E44\u0E17\u0E22",
|
|
1984
|
+
direction: "ltr"
|
|
1985
|
+
},
|
|
1986
|
+
{
|
|
1987
|
+
code: "ti",
|
|
1988
|
+
english: "Tigrinya",
|
|
1989
|
+
native: "\u1275\u130D\u122D\u129B",
|
|
1990
|
+
direction: "ltr"
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
code: "tk",
|
|
1994
|
+
english: "Turkmen",
|
|
1995
|
+
native: "t\xFCrkmen dili",
|
|
1996
|
+
direction: "ltr"
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
code: "tl",
|
|
2000
|
+
english: "Filipino",
|
|
2001
|
+
native: "Filipino",
|
|
2002
|
+
direction: "ltr"
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
code: "tn",
|
|
2006
|
+
english: "Tswana",
|
|
2007
|
+
native: "Tswana",
|
|
2008
|
+
direction: "ltr"
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
code: "tr",
|
|
2012
|
+
english: "Turkish",
|
|
2013
|
+
native: "T\xFCrk\xE7e",
|
|
2014
|
+
direction: "ltr"
|
|
2015
|
+
},
|
|
2016
|
+
{
|
|
2017
|
+
code: "ts",
|
|
2018
|
+
english: "Tsonga",
|
|
2019
|
+
native: "Tsonga",
|
|
2020
|
+
direction: "ltr"
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
code: "tt",
|
|
2024
|
+
english: "Tatar",
|
|
2025
|
+
native: "\u0442\u0430\u0442\u0430\u0440",
|
|
2026
|
+
direction: "ltr"
|
|
2027
|
+
},
|
|
2028
|
+
{
|
|
2029
|
+
code: "ug",
|
|
2030
|
+
english: "Uyghur",
|
|
2031
|
+
native: "\u0626\u06C7\u064A\u063A\u06C7\u0631\u0686\u06D5",
|
|
2032
|
+
direction: "rtl"
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
code: "uk",
|
|
2036
|
+
english: "Ukrainian",
|
|
2037
|
+
native: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",
|
|
2038
|
+
direction: "ltr"
|
|
2039
|
+
},
|
|
2040
|
+
{
|
|
2041
|
+
code: "ur",
|
|
2042
|
+
english: "Urdu",
|
|
2043
|
+
native: "\u0627\u0631\u062F\u0648",
|
|
2044
|
+
direction: "rtl"
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
code: "uz",
|
|
2048
|
+
english: "Uzbek",
|
|
2049
|
+
native: "o\u2018zbek",
|
|
2050
|
+
direction: "ltr"
|
|
2051
|
+
},
|
|
2052
|
+
{
|
|
2053
|
+
code: "vi",
|
|
2054
|
+
english: "Vietnamese",
|
|
2055
|
+
native: "Ti\u1EBFng Vi\u1EC7t",
|
|
2056
|
+
direction: "ltr"
|
|
2057
|
+
},
|
|
2058
|
+
{
|
|
2059
|
+
code: "xh",
|
|
2060
|
+
english: "Xhosa",
|
|
2061
|
+
native: "IsiXhosa",
|
|
2062
|
+
direction: "ltr"
|
|
2063
|
+
},
|
|
2064
|
+
{
|
|
2065
|
+
code: "yi",
|
|
2066
|
+
english: "Yiddish",
|
|
2067
|
+
native: "\u05D9\u05D9\u05B4\u05D3\u05D9\u05E9",
|
|
2068
|
+
direction: "rtl"
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
code: "yo",
|
|
2072
|
+
english: "Yoruba",
|
|
2073
|
+
native: "\xC8d\xE8 Yor\xF9b\xE1",
|
|
2074
|
+
direction: "ltr"
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
code: "yua",
|
|
2078
|
+
english: "yua",
|
|
2079
|
+
native: "yua",
|
|
2080
|
+
direction: "ltr"
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
code: "yue",
|
|
2084
|
+
english: "Cantonese",
|
|
2085
|
+
native: "\u7CB5\u8A9E",
|
|
2086
|
+
direction: "ltr"
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
code: "zh",
|
|
2090
|
+
english: "Chinese",
|
|
2091
|
+
native: "\u4E2D\u6587",
|
|
2092
|
+
direction: "ltr"
|
|
2093
|
+
},
|
|
2094
|
+
{
|
|
2095
|
+
code: "zh-cn",
|
|
2096
|
+
english: "Chinese (China)",
|
|
2097
|
+
native: "\u4E2D\u6587\uFF08\u4E2D\u56FD\uFF09",
|
|
2098
|
+
direction: "ltr"
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
code: "zh-hans",
|
|
2102
|
+
english: "Simplified Chinese",
|
|
2103
|
+
native: "\u7B80\u4F53\u4E2D\u6587",
|
|
2104
|
+
direction: "ltr"
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
code: "zh-hant",
|
|
2108
|
+
english: "Traditional Chinese",
|
|
2109
|
+
native: "\u7E41\u9AD4\u4E2D\u6587",
|
|
2110
|
+
direction: "ltr"
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
code: "zh-hk",
|
|
2114
|
+
english: "Chinese (Hong Kong SAR China)",
|
|
2115
|
+
native: "\u4E2D\u6587\uFF08\u4E2D\u570B\u9999\u6E2F\u7279\u5225\u884C\u653F\u5340\uFF09",
|
|
2116
|
+
direction: "ltr"
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
code: "zh-tw",
|
|
2120
|
+
english: "Chinese (Taiwan)",
|
|
2121
|
+
native: "\u4E2D\u6587\uFF08\u53F0\u7063\uFF09",
|
|
2122
|
+
direction: "ltr"
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
code: "zu",
|
|
2126
|
+
english: "Zulu",
|
|
2127
|
+
native: "isiZulu",
|
|
2128
|
+
direction: "ltr"
|
|
2129
|
+
}
|
|
2130
|
+
];
|
|
2131
|
+
|
|
2132
|
+
// src/shared/languages/catalog/index.ts
|
|
2133
|
+
var generatedLanguageCatalog = languages_default;
|
|
2134
|
+
function buildLanguageCatalog(raw) {
|
|
2135
|
+
return Object.freeze(raw.map((r) => ({ ...r, code: normalizeLanguageCode(r.code) })));
|
|
2136
|
+
}
|
|
2137
|
+
function filterLanguageCatalog(catalog2, filter) {
|
|
2138
|
+
const all = [...catalog2];
|
|
2139
|
+
const q = filter?.trim().toLowerCase();
|
|
2140
|
+
if (!q) return all.sort((a, b) => a.code.localeCompare(b.code));
|
|
2141
|
+
return all.filter(
|
|
2142
|
+
(r) => r.code.includes(q) || r.english.toLowerCase().includes(q) || r.native.toLowerCase().includes(q)
|
|
2143
|
+
).sort((a, b) => a.code.localeCompare(b.code));
|
|
2144
|
+
}
|
|
2145
|
+
function getLanguageByCodeFromCatalog(catalog2, code) {
|
|
2146
|
+
const n = normalizeLanguageCode(code);
|
|
2147
|
+
return catalog2.find((r) => r.code === n);
|
|
2148
|
+
}
|
|
2149
|
+
function suggestCatalogCodesForInvalidInputFromCatalog(catalog2, code, maxCodesInCatalogHint = 5) {
|
|
2150
|
+
const n = normalizeLanguageCode(code);
|
|
2151
|
+
const all = [...catalog2].sort((a, b) => a.code.localeCompare(b.code));
|
|
2152
|
+
const out = [];
|
|
2153
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2154
|
+
const push = (c) => {
|
|
2155
|
+
if (!seen.has(c)) {
|
|
2156
|
+
seen.add(c);
|
|
2157
|
+
out.push(c);
|
|
2158
|
+
}
|
|
2159
|
+
};
|
|
2160
|
+
for (const r of filterLanguageCatalog(catalog2, n)) {
|
|
2161
|
+
push(r.code);
|
|
2162
|
+
if (out.length >= maxCodesInCatalogHint) return out;
|
|
2163
|
+
}
|
|
2164
|
+
if (n.length >= 2) {
|
|
2165
|
+
const prefix = n.slice(0, 2);
|
|
2166
|
+
for (const r of all) {
|
|
2167
|
+
if (r.code.startsWith(prefix)) push(r.code);
|
|
2168
|
+
if (out.length >= maxCodesInCatalogHint) return out;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
for (const r of all) {
|
|
2172
|
+
push(r.code);
|
|
2173
|
+
if (out.length >= maxCodesInCatalogHint) return out;
|
|
2174
|
+
}
|
|
2175
|
+
return out;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
// src/shared/languages/validateTargetCode.ts
|
|
2179
|
+
var MAX_HINT = 5;
|
|
2180
|
+
function catalog() {
|
|
2181
|
+
return buildLanguageCatalog(generatedLanguageCatalog);
|
|
2182
|
+
}
|
|
2183
|
+
function assertSupportedTargetLanguageCode(code) {
|
|
2184
|
+
const cat = catalog();
|
|
2185
|
+
if (getLanguageByCodeFromCatalog(cat, code)) return;
|
|
2186
|
+
const hints = suggestCatalogCodesForInvalidInputFromCatalog(cat, code, MAX_HINT);
|
|
2187
|
+
const hintStr = hints.length > 0 ? hints.join(", ") : "run i18nprune languages for supported codes";
|
|
2188
|
+
throw new I18nPruneError(`Unsupported language code "${code}" \u2014 try: ${hintStr}`, "USAGE", {
|
|
2189
|
+
issueCode: ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
// src/locales/targets.ts
|
|
2194
|
+
var ALL_LOCALES_TOKEN = "all";
|
|
2195
|
+
function parseLocaleCodesList(raw) {
|
|
2196
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean).map((c) => normalizeLanguageCode(c));
|
|
2197
|
+
}
|
|
2198
|
+
function isAllLocaleToken(raw) {
|
|
2199
|
+
return raw.trim().toLowerCase() === ALL_LOCALES_TOKEN;
|
|
2200
|
+
}
|
|
2201
|
+
function pickTargetSelector(target) {
|
|
2202
|
+
const t = target?.trim();
|
|
2203
|
+
if (t) return t;
|
|
2204
|
+
return void 0;
|
|
2205
|
+
}
|
|
2206
|
+
function parseSyncLangSelection(lang) {
|
|
2207
|
+
const primary = lang?.trim();
|
|
2208
|
+
if (primary) {
|
|
2209
|
+
if (isAllLocaleToken(primary)) return { mode: "all" };
|
|
2210
|
+
return { mode: "codes", codes: parseLocaleCodesList(primary) };
|
|
2211
|
+
}
|
|
2212
|
+
return { mode: "all" };
|
|
2213
|
+
}
|
|
2214
|
+
function resolveTargetLocaleSlugs(path, localeSlugs, sourceLocalePath) {
|
|
2215
|
+
return excludeSourceLocaleSlugs(path, localeSlugs, sourceLocalePath);
|
|
2216
|
+
}
|
|
2217
|
+
function resolveLocaleTargetCodes(input) {
|
|
2218
|
+
const { commandName, rawTarget, localeSlugs, sourceLocalePath, path } = input;
|
|
2219
|
+
const targetSlugs = resolveTargetLocaleSlugs(path, localeSlugs, sourceLocalePath);
|
|
2220
|
+
if (targetSlugs.length === 0) {
|
|
2221
|
+
throw new I18nPruneError(`${commandName}: no target locale files found in localesDir`, "USAGE");
|
|
2222
|
+
}
|
|
2223
|
+
const selected = pickTargetSelector(rawTarget);
|
|
2224
|
+
if (!selected) {
|
|
2225
|
+
throw new I18nPruneError(`${commandName} requires --target <code[,code]|all>`, "USAGE");
|
|
2226
|
+
}
|
|
2227
|
+
if (isAllLocaleToken(selected)) {
|
|
2228
|
+
return targetSlugs.map((x) => normalizeLanguageCode(x));
|
|
2229
|
+
}
|
|
2230
|
+
const parsed = parseLocaleCodesList(selected);
|
|
2231
|
+
for (const code of parsed) {
|
|
2232
|
+
assertNotSourceTargetLocale(commandName, code, sourceLocalePath, {
|
|
2233
|
+
paths: { sourceLocale: sourceLocalePath },
|
|
2234
|
+
path
|
|
2235
|
+
});
|
|
2236
|
+
if (!targetSlugs.some((x) => normalizeLanguageCode(x) === code)) {
|
|
2237
|
+
throw new I18nPruneError(`${commandName}: locale file not found for target "${code}"`, "USAGE");
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
return parsed;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
// src/locales/resumeTargets.ts
|
|
2244
|
+
function resolveResumeAllTargetCodes(ctx, commandName) {
|
|
2245
|
+
const codes = targetLocaleCodesFromContext(ctx);
|
|
2246
|
+
if (codes.length === 0) {
|
|
2247
|
+
throw new I18nPruneError(`${commandName}: no target locale files found in localesDir`, "USAGE");
|
|
2248
|
+
}
|
|
2249
|
+
return codes.map((c) => normalizeLanguageCode(c));
|
|
2250
|
+
}
|
|
2251
|
+
function resolveResumeTargetCodesFromRaw(input) {
|
|
2252
|
+
const { commandName, raw, ctx } = input;
|
|
2253
|
+
const sourceLocalePath = ctx.paths.sourceLocale;
|
|
2254
|
+
const assertCtx = {
|
|
2255
|
+
paths: { sourceLocale: sourceLocalePath },
|
|
2256
|
+
path: ctx.adapters.path
|
|
2257
|
+
};
|
|
2258
|
+
if (isAllLocaleToken(raw)) {
|
|
2259
|
+
return resolveResumeAllTargetCodes(ctx, commandName);
|
|
2260
|
+
}
|
|
2261
|
+
if (raw.includes(",")) {
|
|
2262
|
+
const codes = parseLocaleCodesList(raw);
|
|
2263
|
+
for (const c of codes) {
|
|
2264
|
+
assertNotSourceTargetLocale(commandName, c, sourceLocalePath, assertCtx);
|
|
2265
|
+
assertSupportedTargetLanguageCode(c);
|
|
2266
|
+
}
|
|
2267
|
+
return codes;
|
|
2268
|
+
}
|
|
2269
|
+
const code = normalizeLanguageCode(raw);
|
|
2270
|
+
assertNotSourceTargetLocale(commandName, code, sourceLocalePath, assertCtx);
|
|
2271
|
+
assertSupportedTargetLanguageCode(code);
|
|
2272
|
+
return [code];
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
// src/locales/generateTargets.ts
|
|
2276
|
+
function assertGenerateTargetCodes(input) {
|
|
2277
|
+
const { commandName, codes, sourceLocalePath, path } = input;
|
|
2278
|
+
const ctx = {
|
|
2279
|
+
paths: { sourceLocale: sourceLocalePath },
|
|
2280
|
+
path
|
|
2281
|
+
};
|
|
2282
|
+
for (const target of codes) {
|
|
2283
|
+
assertNotSourceTargetLocale(commandName, target, sourceLocalePath, ctx);
|
|
2284
|
+
assertSupportedTargetLanguageCode(target);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
export { ALL_LOCALES_TOKEN, assertGenerateTargetCodes, assertNotSourceTargetLocale, buildLocaleListRows, buildSourceLocaleTruthLabel, excludeSourceLocaleSlugs, getDisplaySourceLocaleCode, getSourceLocaleSlug, isAllLocaleToken, isSourceLocaleSlug, listOtherLocaleCodes, parseLocaleCodesList, parseSyncLangSelection, pickTargetSelector, resolveLocaleTargetCodes, resolveResumeAllTargetCodes, resolveResumeTargetCodesFromRaw, resolveTargetLocaleSlugs };
|