@x18n/node 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +112 -10
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -9,12 +9,13 @@ import { glob } from "tinyglobby";
|
|
|
9
9
|
import { parse, stringify } from "yaml";
|
|
10
10
|
import { placeholderFromShape } from "@x18n/builtins/placeholders";
|
|
11
11
|
import regexScopes from "@x18n/builtins/scanners/regex-scopes";
|
|
12
|
+
import { execFile, spawn } from "node:child_process";
|
|
12
13
|
import process from "node:process";
|
|
13
14
|
import { watch } from "chokidar";
|
|
14
15
|
import ignore from "ignore";
|
|
15
16
|
import { createBuiltins } from "@x18n/builtins";
|
|
16
17
|
import { Buffer } from "node:buffer";
|
|
17
|
-
import {
|
|
18
|
+
import { yamlReviewStore } from "@x18n/builtins/reviews";
|
|
18
19
|
import { applyEdits, modify, parse as parse$1 } from "jsonc-parser";
|
|
19
20
|
//#region src/yaml-plugin.ts
|
|
20
21
|
/**
|
|
@@ -287,6 +288,24 @@ async function loadGitignore(root) {
|
|
|
287
288
|
});
|
|
288
289
|
};
|
|
289
290
|
}
|
|
291
|
+
function gitConfig(cwd, key) {
|
|
292
|
+
return new Promise((resolve) => {
|
|
293
|
+
execFile("git", ["config", key], {
|
|
294
|
+
cwd,
|
|
295
|
+
encoding: "utf8"
|
|
296
|
+
}, (error, stdout) => {
|
|
297
|
+
resolve(error ? void 0 : stdout.trim() || void 0);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/** The git `user.name` and `user.email`, or undefined without git or a configured user. */
|
|
302
|
+
async function gitIdentity(cwd) {
|
|
303
|
+
const [name, email] = await Promise.all([gitConfig(cwd, "user.name"), gitConfig(cwd, "user.email")]);
|
|
304
|
+
return name === void 0 && email === void 0 ? void 0 : {
|
|
305
|
+
...name !== void 0 && { name },
|
|
306
|
+
...email !== void 0 && { email }
|
|
307
|
+
};
|
|
308
|
+
}
|
|
290
309
|
/** A persistent cache in one JSON file. Only entries used in this session are written back, so it stays bounded. */
|
|
291
310
|
function createFileCache(dir) {
|
|
292
311
|
const file = join(dir, "cache.json");
|
|
@@ -324,6 +343,7 @@ function createNodeHost(root, options = {}) {
|
|
|
324
343
|
const cacheDir = options.cacheDir === false ? void 0 : options.cacheDir ?? join(absoluteRoot, "node_modules/.cache/x18n");
|
|
325
344
|
const cache = cacheDir ? createFileCache(join(cacheDir, hashText(absoluteRoot))) : void 0;
|
|
326
345
|
const full = (path) => resolve(absoluteRoot, path);
|
|
346
|
+
let identity;
|
|
327
347
|
return {
|
|
328
348
|
root: absoluteRoot,
|
|
329
349
|
logger: options.logger,
|
|
@@ -383,6 +403,7 @@ function createNodeHost(root, options = {}) {
|
|
|
383
403
|
watcher.close();
|
|
384
404
|
} };
|
|
385
405
|
},
|
|
406
|
+
identity: () => identity ??= gitIdentity(absoluteRoot),
|
|
386
407
|
flush: async () => cache?.flush()
|
|
387
408
|
};
|
|
388
409
|
}
|
|
@@ -768,7 +789,7 @@ const frameworkPresets = {
|
|
|
768
789
|
"ui5": "ui5",
|
|
769
790
|
"lingui": "lingui",
|
|
770
791
|
"jekyll": "jekyll",
|
|
771
|
-
"i18n-js": "i18n-js"
|
|
792
|
+
"i18n-js": "ruby-i18n-js"
|
|
772
793
|
};
|
|
773
794
|
const languageExtensions = {
|
|
774
795
|
javascript: [
|
|
@@ -1012,7 +1033,7 @@ function presetsOf(r, notes) {
|
|
|
1012
1033
|
}
|
|
1013
1034
|
function notesOf(settings, notes) {
|
|
1014
1035
|
if ([...settings.keys()].some((key) => key.startsWith("translate."))) notes.push("`translate.*` settings were dropped: x18n writes translate prompts instead (`x18n prompt translate --to <locale>`).");
|
|
1015
|
-
if (
|
|
1036
|
+
if (settings.has("review.removeCommentOnResolved")) notes.push("`i18n-ally.review.removeCommentOnResolved` was dropped: x18n keeps resolved reviews and hides them with `x18n review list --open`.");
|
|
1016
1037
|
for (const key of handledByDefaults) if (settings.has(key)) notes.push(`\`i18n-ally.${key}\` is handled by defaults or dropped.`);
|
|
1017
1038
|
}
|
|
1018
1039
|
function mapConfig(settings, parts, notes) {
|
|
@@ -1059,8 +1080,85 @@ function mapConfig(settings, parts, notes) {
|
|
|
1059
1080
|
...r.str("defaultNamespace") ? { namespace: { default: r.str("defaultNamespace") } } : {},
|
|
1060
1081
|
...Object.keys(usage).length ? { usage } : {},
|
|
1061
1082
|
...write ? { write } : {},
|
|
1062
|
-
...Object.keys(extract).length ? { extract } : {}
|
|
1083
|
+
...Object.keys(extract).length ? { extract } : {},
|
|
1084
|
+
...reviewOf(r)
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
function reviewOf(r) {
|
|
1088
|
+
const enabled = r.get("review.enabled");
|
|
1089
|
+
const author = {
|
|
1090
|
+
...r.str("review.user.name") && { name: r.str("review.user.name") },
|
|
1091
|
+
...r.str("review.user.email") && { email: r.str("review.user.email") }
|
|
1092
|
+
};
|
|
1093
|
+
const review = {
|
|
1094
|
+
...typeof enabled === "boolean" && { enabled },
|
|
1095
|
+
...Object.keys(author).length > 0 && { author }
|
|
1063
1096
|
};
|
|
1097
|
+
return Object.keys(review).length > 0 ? { review } : {};
|
|
1098
|
+
}
|
|
1099
|
+
const reviewTypes = {
|
|
1100
|
+
comment: "comment",
|
|
1101
|
+
approve: "approve",
|
|
1102
|
+
request_change: "request-change"
|
|
1103
|
+
};
|
|
1104
|
+
function str(value) {
|
|
1105
|
+
return typeof value === "string" ? value : void 0;
|
|
1106
|
+
}
|
|
1107
|
+
function recordOf(value) {
|
|
1108
|
+
return isRecord(value) ? value : {};
|
|
1109
|
+
}
|
|
1110
|
+
/** One i18n-ally comment; one with a `suggestion` becomes a suggestion. */
|
|
1111
|
+
function convertComment(comment) {
|
|
1112
|
+
const user = recordOf(comment.user);
|
|
1113
|
+
const name = str(user.name);
|
|
1114
|
+
const email = str(user.email);
|
|
1115
|
+
const text = str(comment.comment);
|
|
1116
|
+
const suggestion = str(comment.suggestion);
|
|
1117
|
+
return {
|
|
1118
|
+
id: str(comment.id) ?? hashText(JSON.stringify(comment)).slice(0, 6),
|
|
1119
|
+
type: suggestion === void 0 ? reviewTypes[str(comment.type) ?? "comment"] ?? "comment" : "suggestion",
|
|
1120
|
+
...(name !== void 0 || email !== void 0) && { author: {
|
|
1121
|
+
...name !== void 0 && { name },
|
|
1122
|
+
...email !== void 0 && { email }
|
|
1123
|
+
} },
|
|
1124
|
+
time: str(comment.time) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
1125
|
+
...text !== void 0 && { text },
|
|
1126
|
+
...suggestion !== void 0 && { suggestion },
|
|
1127
|
+
...comment.resolved === true && { resolved: true }
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
/** The comments of one key and locale, with the translation candidate as a last suggestion. */
|
|
1131
|
+
function convertLocale(key, locale, item) {
|
|
1132
|
+
const comments = (Array.isArray(item.comments) ? item.comments : []).filter(isRecord).map(convertComment);
|
|
1133
|
+
const candidate = recordOf(item.translation_candidate);
|
|
1134
|
+
const text = str(candidate.text);
|
|
1135
|
+
if (text !== void 0) comments.push({
|
|
1136
|
+
id: hashText(`${key}:${locale}:${text}`).slice(0, 6),
|
|
1137
|
+
type: "suggestion",
|
|
1138
|
+
time: str(candidate.time) ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
1139
|
+
text: "Translation candidate from i18n-ally",
|
|
1140
|
+
suggestion: text
|
|
1141
|
+
});
|
|
1142
|
+
return comments;
|
|
1143
|
+
}
|
|
1144
|
+
/** i18n-ally's `reviews.<key>.locales.<locale>.comments` as x18n threads; translation candidates become suggestions. */
|
|
1145
|
+
function convertI18nAllyReviews(text, notes) {
|
|
1146
|
+
const reviews = recordOf(recordOf(parse(text)).reviews);
|
|
1147
|
+
const threads = {};
|
|
1148
|
+
let descriptions = 0;
|
|
1149
|
+
for (const [key, entry] of Object.entries(reviews)) {
|
|
1150
|
+
const { description, locales } = recordOf(entry);
|
|
1151
|
+
if (description !== void 0) descriptions++;
|
|
1152
|
+
for (const [locale, item] of Object.entries(recordOf(locales))) {
|
|
1153
|
+
const comments = convertLocale(key, locale, recordOf(item));
|
|
1154
|
+
if (comments.length > 0) (threads[key] ??= {})[locale] = comments;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
if (descriptions > 0) notes.push(`${descriptions} key description${descriptions === 1 ? " was" : "s were"} dropped: x18n reviews have no key descriptions.`);
|
|
1158
|
+
return yamlReviewStore.serialize({
|
|
1159
|
+
threads,
|
|
1160
|
+
sources: {}
|
|
1161
|
+
});
|
|
1064
1162
|
}
|
|
1065
1163
|
/** The x18n config that a project's i18n-ally settings and custom framework mean, or undefined without any. */
|
|
1066
1164
|
async function readI18nAllyConfig(root) {
|
|
@@ -1107,15 +1205,15 @@ async function migrateI18nAlly(root, options = {}) {
|
|
|
1107
1205
|
};
|
|
1108
1206
|
const { config, plugin } = found;
|
|
1109
1207
|
const notes = [...found.notes];
|
|
1110
|
-
const reviews =
|
|
1208
|
+
const reviews = await readFirst(root, [".vscode/i18n-ally-next-reviews.yml", ".vscode/i18n-ally-reviews.yml"]);
|
|
1111
1209
|
const files = [];
|
|
1112
1210
|
const finalConfig = plugin !== void 0 ? {
|
|
1113
1211
|
...config,
|
|
1114
|
-
plugins: ["
|
|
1212
|
+
plugins: ["./.x18n/custom.x18n-plugin.yml"]
|
|
1115
1213
|
} : config;
|
|
1116
1214
|
files.push(configFile(finalConfig, options.format ?? "ts"));
|
|
1117
1215
|
if (plugin) files.push({
|
|
1118
|
-
path: "x18n/custom.x18n-plugin.yml",
|
|
1216
|
+
path: ".x18n/custom.x18n-plugin.yml",
|
|
1119
1217
|
content: `# yaml-language-server: $schema=../node_modules/@x18n/core/schema/plugin.json\n${stringify(plugin)}`
|
|
1120
1218
|
});
|
|
1121
1219
|
let vscodeText = await readText(join(root, ".vscode/settings.json"));
|
|
@@ -1136,14 +1234,18 @@ async function migrateI18nAlly(root, options = {}) {
|
|
|
1136
1234
|
if (reviews !== void 0 && !existsSync(join(root, ".x18n/reviews.yml"))) {
|
|
1137
1235
|
files.push({
|
|
1138
1236
|
path: ".x18n/reviews.yml",
|
|
1139
|
-
content: reviews
|
|
1237
|
+
content: convertI18nAllyReviews(reviews.text, notes)
|
|
1140
1238
|
});
|
|
1141
|
-
notes.push("Reviews were
|
|
1239
|
+
notes.push("Reviews were converted to `.x18n/reviews.yml`.");
|
|
1142
1240
|
}
|
|
1143
1241
|
return {
|
|
1144
1242
|
files,
|
|
1145
1243
|
notes,
|
|
1146
|
-
removable: [
|
|
1244
|
+
removable: [
|
|
1245
|
+
...keys,
|
|
1246
|
+
...found.customFramework ? [found.customFramework] : [],
|
|
1247
|
+
...reviews ? [reviews.path] : []
|
|
1248
|
+
]
|
|
1147
1249
|
};
|
|
1148
1250
|
}
|
|
1149
1251
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x18n/node",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.15",
|
|
5
5
|
"description": "Node.js host for x18n: file system access, config and plugin loading",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"node": ">=22"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@x18n/builtins": "0.0.
|
|
29
|
-
"@x18n/core": "0.0.
|
|
28
|
+
"@x18n/builtins": "0.0.15",
|
|
29
|
+
"@x18n/core": "0.0.15",
|
|
30
30
|
"chokidar": "^6.0.0",
|
|
31
31
|
"ignore": "^7.0.13",
|
|
32
32
|
"jiti": "^2.7.0",
|