@dune2/cli 0.0.3 → 0.0.5
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/{chunk-Q6SDTDV5.js → chunk-BEIVJU3S.js} +18 -27
- package/dist/chunk-BEIVJU3S.js.map +1 -0
- package/dist/cli.js +38 -28
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +21 -3
- package/dist/index.js +1 -6
- package/package.json +2 -2
- package/dist/chunk-Q6SDTDV5.js.map +0 -1
|
@@ -17,44 +17,35 @@ function resolveSheetId(str) {
|
|
|
17
17
|
|
|
18
18
|
// src/shared/config.ts
|
|
19
19
|
var joycon = new JoyCon();
|
|
20
|
-
function defineConfig(config) {
|
|
21
|
-
return config;
|
|
22
|
-
}
|
|
23
20
|
var configName = "dune.config.js";
|
|
24
21
|
async function getConfig() {
|
|
22
|
+
var _a;
|
|
25
23
|
const res = await joycon.load([configName]);
|
|
26
|
-
const
|
|
27
|
-
i18nDir: "./i18n",
|
|
24
|
+
const defaultI18nConfig = {
|
|
25
|
+
i18nDir: "./src/i18n",
|
|
28
26
|
i18nFileName: "{locale}.i18n.json",
|
|
29
27
|
cwd: process.cwd(),
|
|
30
|
-
position: {
|
|
31
|
-
key: "B",
|
|
32
|
-
zh: "C",
|
|
33
|
-
en: "D",
|
|
34
|
-
in: "E"
|
|
35
|
-
},
|
|
28
|
+
position: { key: "B", zh: "C", en: "D", in: "E" },
|
|
36
29
|
parseStartIndex: 2
|
|
37
30
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
item = Object.assign({}, defaultConfig, item);
|
|
42
|
-
item.locales = Object.keys(item.position).filter(
|
|
43
|
-
(item2) => item2 !== "key"
|
|
44
|
-
);
|
|
45
|
-
item.sheetId = resolveSheetId(item.sheetId);
|
|
46
|
-
item.keySorter = (a, b) => {
|
|
47
|
-
return a.localeCompare(b);
|
|
48
|
-
};
|
|
49
|
-
return item;
|
|
50
|
-
});
|
|
31
|
+
let config = res.data ?? {};
|
|
32
|
+
if (!config.i18n || !((_a = config.i18n) == null ? void 0 : _a.length)) {
|
|
33
|
+
config.i18n = [defaultI18nConfig];
|
|
51
34
|
}
|
|
52
|
-
|
|
35
|
+
config.i18n = config.i18n.map((item) => {
|
|
36
|
+
item = Object.assign({}, defaultI18nConfig, item);
|
|
37
|
+
item.locales = Object.keys(item.position).filter((item2) => item2 !== "key");
|
|
38
|
+
item.sheetId = resolveSheetId(item.sheetId);
|
|
39
|
+
item.keySorter = (a, b) => {
|
|
40
|
+
return a.localeCompare(b);
|
|
41
|
+
};
|
|
42
|
+
return item;
|
|
43
|
+
});
|
|
44
|
+
return config;
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
export {
|
|
56
|
-
defineConfig,
|
|
57
48
|
configName,
|
|
58
49
|
getConfig
|
|
59
50
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
51
|
+
//# sourceMappingURL=chunk-BEIVJU3S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/config.ts","../src/shared/resolveSheetId.ts"],"sourcesContent":["import JoyCon from \"joycon\";\nimport { resolveSheetId } from \"./resolveSheetId\";\n\nconst joycon = new JoyCon();\n\nexport interface I18nConfig {\n // 语言文件存放目录,默认为项目根目录的 \"./src/i18n\"\n i18nDir?: string;\n // 语言文件名,默认为 \"{locale}.i18n.json\",其中 {locale} 会被替换为 locales 中的语言\n i18nFileName?: string;\n // 默认语言,默认为 \"zh\",影响到提出出来的文案的默认值\n defaultLocale?: string;\n /**\n * 可以是 id 或者 url,如果是 url 则会自动解析出 id\n * id: 1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\n * url: https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\n */\n sheetId?: string;\n // google sheets 工作表名称\n sheetRange?: string;\n /**\n * 对应 语言、i18nKey 所在的列标识符 如(A,B,C...)\n * 传入时将忽略默认的配置\n * @default {key: \"B\", zh: \"C\", en: \"D\", in: \"E\",}\n */\n position?: {\n key: string;\n [key: string]: string;\n };\n\n /**\n * 从 Google Sheets 哪一行开始解析\n * 默认从第2行开始,模板文件第一行是表头\n * @default 2\n */\n parseStartIndex?: number;\n\n /**\n * 默认是 命令运行的目录,一般是项目根目录\n * @internal\n */\n cwd?: string;\n /**\n * 支持的语言列表,从 position 中解析出来\n * @internal\n */\n locales?: string[];\n\n /**\n * 翻译key的排序\n * @internal\n */\n keySorter?: (a: string, b: string) => number;\n}\n\nexport interface Config {\n i18n?: I18nConfig[];\n}\nexport const configName = \"dune.config.js\";\n\nexport async function getConfig(): Promise<Config> {\n const res = await joycon.load([configName]);\n\n const defaultI18nConfig: I18nConfig = {\n i18nDir: \"./src/i18n\",\n i18nFileName: \"{locale}.i18n.json\",\n cwd: process.cwd(),\n position: { key: \"B\", zh: \"C\", en: \"D\", in: \"E\" },\n parseStartIndex: 2,\n };\n\n let config = (res.data ?? {}) as Config;\n if (!config.i18n || !config.i18n?.length) {\n config.i18n = [defaultI18nConfig];\n }\n\n // 格式化 i18n 配置\n config.i18n = config.i18n.map((item) => {\n item = Object.assign({}, defaultI18nConfig, item);\n item.locales = Object.keys(item.position!).filter((item) => item !== \"key\");\n item.sheetId = resolveSheetId(item.sheetId);\n item.keySorter = (a, b) => {\n return a.localeCompare(b);\n };\n return item;\n });\n\n return config;\n}\n","/**\n * input:\n * \"https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\"\n * output:\n * \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * --\n * input: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * output: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n */\nimport { match } from \"path-to-regexp\";\n\nexport function resolveSheetId(str?: string) {\n if (!str || !str?.startsWith(\"http\")) {\n return str;\n }\n const url = new URL(str);\n const matched = match<{ id: string[] }>(\"/spreadsheets/d/:id*\", {\n decode: decodeURIComponent,\n })(url.pathname);\n return matched ? matched.params.id?.[0] : str;\n}\n"],"mappings":";AAAA,OAAO,YAAY;;;ACSnB,SAAS,aAAa;AAEf,SAAS,eAAe,KAAc;AAX7C;AAYE,MAAI,CAAC,OAAO,EAAC,2BAAK,WAAW,UAAS;AACpC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,IAAI,IAAI,GAAG;AACvB,QAAM,UAAU,MAAwB,wBAAwB;AAAA,IAC9D,QAAQ;AAAA,EACV,CAAC,EAAE,IAAI,QAAQ;AACf,SAAO,WAAU,aAAQ,OAAO,OAAf,mBAAoB,KAAK;AAC5C;;;ADjBA,IAAM,SAAS,IAAI,OAAO;AAuDnB,IAAM,aAAa;AAE1B,eAAsB,YAA6B;AA5DnD;AA6DE,QAAM,MAAM,MAAM,OAAO,KAAK,CAAC,UAAU,CAAC;AAE1C,QAAM,oBAAgC;AAAA,IACpC,SAAS;AAAA,IACT,cAAc;AAAA,IACd,KAAK,QAAQ,IAAI;AAAA,IACjB,UAAU,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI;AAAA,IAChD,iBAAiB;AAAA,EACnB;AAEA,MAAI,SAAU,IAAI,QAAQ,CAAC;AAC3B,MAAI,CAAC,OAAO,QAAQ,GAAC,YAAO,SAAP,mBAAa,SAAQ;AACxC,WAAO,OAAO,CAAC,iBAAiB;AAAA,EAClC;AAGA,SAAO,OAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AACtC,WAAO,OAAO,OAAO,CAAC,GAAG,mBAAmB,IAAI;AAChD,SAAK,UAAU,OAAO,KAAK,KAAK,QAAS,EAAE,OAAO,CAACA,UAASA,UAAS,KAAK;AAC1E,SAAK,UAAU,eAAe,KAAK,OAAO;AAC1C,SAAK,YAAY,CAAC,GAAG,MAAM;AACzB,aAAO,EAAE,cAAc,CAAC;AAAA,IAC1B;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AACT;","names":["item"]}
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
configName,
|
|
4
4
|
getConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BEIVJU3S.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/extract.ts
|
|
8
8
|
import fs3 from "fs-extra";
|
|
@@ -78,7 +78,7 @@ var I18nData = class {
|
|
|
78
78
|
async updateByExtractedData(extractedData, shouldUseDefault = false) {
|
|
79
79
|
await this.loadData();
|
|
80
80
|
extractedData.forEach((value, key) => {
|
|
81
|
-
this.data[key] = shouldUseDefault ? value.
|
|
81
|
+
this.data[key] = shouldUseDefault ? value.messages || key : this.data[key] || "";
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
async updateFromSheetData(sheetData) {
|
|
@@ -128,8 +128,9 @@ var I18nData = class {
|
|
|
128
128
|
}
|
|
129
129
|
async trySaveToGoogle(sheetData) {
|
|
130
130
|
await pMap(Object.entries(this.data), async ([key, value]) => {
|
|
131
|
+
var _a;
|
|
131
132
|
if (sheetData.hasI18nItem(this.locale, key)) {
|
|
132
|
-
await sheetData.getI18nItem(this.locale, key).tryUpdate(value);
|
|
133
|
+
await ((_a = sheetData.getI18nItem(this.locale, key)) == null ? void 0 : _a.tryUpdate(value));
|
|
133
134
|
} else {
|
|
134
135
|
log.error(
|
|
135
136
|
"%s range %s not found key %s",
|
|
@@ -168,7 +169,7 @@ var log2 = createLogger("extract");
|
|
|
168
169
|
async function extract() {
|
|
169
170
|
const config = await getConfig();
|
|
170
171
|
const { extract: extract2 } = await import("@dune2/wasm");
|
|
171
|
-
for (const configItem of config) {
|
|
172
|
+
for (const configItem of config.i18n ?? []) {
|
|
172
173
|
const files = await globby(
|
|
173
174
|
[`**/**.{js,jsx,ts,tsx}`, "!**/node_modules/**", "!**.d.ts"],
|
|
174
175
|
{
|
|
@@ -189,7 +190,7 @@ async function extract() {
|
|
|
189
190
|
);
|
|
190
191
|
res.forEach((value, key) => {
|
|
191
192
|
const cur = extractedI18nDataMap.get(key);
|
|
192
|
-
if (!(cur == null ? void 0 : cur.
|
|
193
|
+
if (!(cur == null ? void 0 : cur.messages)) {
|
|
193
194
|
extractedI18nDataMap.set(key, value);
|
|
194
195
|
}
|
|
195
196
|
});
|
|
@@ -201,12 +202,15 @@ async function extract() {
|
|
|
201
202
|
pc2.green(extractedI18nDataMap.size),
|
|
202
203
|
extractedI18nDataMap
|
|
203
204
|
);
|
|
204
|
-
const statistics = await pMap2(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
const statistics = await pMap2(
|
|
206
|
+
configItem.locales ?? [],
|
|
207
|
+
async (locale, index) => {
|
|
208
|
+
const i18nData = new I18nData(locale, configItem);
|
|
209
|
+
await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);
|
|
210
|
+
await i18nData.saveToDisk();
|
|
211
|
+
return await i18nData.statistic();
|
|
212
|
+
}
|
|
213
|
+
);
|
|
210
214
|
I18nData.printStatistic("\u63D0\u53D6\u7ED3\u679C: ", statistics);
|
|
211
215
|
}
|
|
212
216
|
}
|
|
@@ -447,7 +451,7 @@ async function resolveSheetData(config) {
|
|
|
447
451
|
}
|
|
448
452
|
const sheetData = new SheetData(config, res.data.values.length + 1);
|
|
449
453
|
res.data.values.forEach((row, rowIndex) => {
|
|
450
|
-
var _a;
|
|
454
|
+
var _a, _b;
|
|
451
455
|
const trulyRowIndex = rowIndex + 1;
|
|
452
456
|
if (parseStartIndex > trulyRowIndex) {
|
|
453
457
|
return;
|
|
@@ -461,7 +465,7 @@ async function resolveSheetData(config) {
|
|
|
461
465
|
} else {
|
|
462
466
|
sheetData.keySet.add(i18nKey);
|
|
463
467
|
}
|
|
464
|
-
config.locales.forEach((lang) => {
|
|
468
|
+
(_b = config.locales) == null ? void 0 : _b.forEach((lang) => {
|
|
465
469
|
sheetData.setI18nItem(
|
|
466
470
|
lang,
|
|
467
471
|
new SheetI18nItem(
|
|
@@ -512,19 +516,22 @@ var log7 = createLogger("generate");
|
|
|
512
516
|
async function generate() {
|
|
513
517
|
const config = await getConfig();
|
|
514
518
|
let i = 0;
|
|
515
|
-
for (const configItem of config) {
|
|
519
|
+
for (const configItem of config.i18n ?? []) {
|
|
516
520
|
i++;
|
|
517
521
|
if (!configItem.sheetId || !configItem.sheetRange) {
|
|
518
522
|
log7.error(`config.${i} sheetId \u6216 sheetRange \u4E3A\u7A7A\uFF0C\u8BF7\u68C0\u67E5`);
|
|
519
523
|
continue;
|
|
520
524
|
}
|
|
521
525
|
const sheetData = await resolveSheetData(configItem);
|
|
522
|
-
const statistics = await pMap3(
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
526
|
+
const statistics = await pMap3(
|
|
527
|
+
configItem.locales ?? [],
|
|
528
|
+
async (locale, index) => {
|
|
529
|
+
const i18nData = new I18nData(locale, configItem);
|
|
530
|
+
await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));
|
|
531
|
+
await i18nData.saveToDisk();
|
|
532
|
+
return await i18nData.statistic();
|
|
533
|
+
}
|
|
534
|
+
);
|
|
528
535
|
I18nData.printStatistic(`${configItem.sheetRange} \u751F\u6210\u7ED3\u679C: `, statistics);
|
|
529
536
|
}
|
|
530
537
|
}
|
|
@@ -536,13 +543,13 @@ var log8 = createLogger("initConfig");
|
|
|
536
543
|
var tpl = `
|
|
537
544
|
/**
|
|
538
545
|
* @template {import('@dune2/cli').Config} T
|
|
539
|
-
* @param {T
|
|
546
|
+
* @param {T} config - A generic parameter that flows through to the return type
|
|
540
547
|
* @constraint {{import('@dune2/cli').Config}}
|
|
541
548
|
*/
|
|
542
549
|
function defineConfig(config) {
|
|
543
550
|
return config;
|
|
544
551
|
}
|
|
545
|
-
module.exports = defineConfig([]);
|
|
552
|
+
module.exports = defineConfig({ i18n: [] });
|
|
546
553
|
`;
|
|
547
554
|
var initConfig = async () => {
|
|
548
555
|
const config = await getConfig();
|
|
@@ -563,7 +570,7 @@ async function batchUpdateKeys(config) {
|
|
|
563
570
|
let sheetData = await resolveSheetData(config);
|
|
564
571
|
const allKeys = [];
|
|
565
572
|
const i18nDataMap = /* @__PURE__ */ new Map();
|
|
566
|
-
await pMap4(config.locales, async (locale) => {
|
|
573
|
+
await pMap4(config.locales ?? [], async (locale) => {
|
|
567
574
|
const i18nData = new I18nData(locale, config);
|
|
568
575
|
i18nDataMap.set(locale, i18nData);
|
|
569
576
|
const data = await i18nData.loadData();
|
|
@@ -587,7 +594,9 @@ async function batchUpdateKeys(config) {
|
|
|
587
594
|
const langFile = i18nDataMap.get(lang);
|
|
588
595
|
const needSyncValues = [];
|
|
589
596
|
needSyncKeys.forEach((k) => {
|
|
590
|
-
|
|
597
|
+
if (langFile) {
|
|
598
|
+
needSyncValues.push(langFile.data[k]);
|
|
599
|
+
}
|
|
591
600
|
});
|
|
592
601
|
log9.info(
|
|
593
602
|
`\u5373\u5C06\u540C\u6B65\u672C\u5730 ${lang} \u65B0\u589E\u52A0 ${needSyncValues.length} \u4E2A\u503C\u5230\u4E91\u7AEF`
|
|
@@ -613,9 +622,9 @@ function sleep(ms) {
|
|
|
613
622
|
}
|
|
614
623
|
async function upload() {
|
|
615
624
|
const config = await getConfig();
|
|
616
|
-
for (const configItem of config) {
|
|
625
|
+
for (const configItem of config.i18n ?? []) {
|
|
617
626
|
const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);
|
|
618
|
-
await pMap4(configItem.locales, async (locale) => {
|
|
627
|
+
await pMap4(configItem.locales ?? [], async (locale) => {
|
|
619
628
|
const i18nData = i18nDataMap.get(locale);
|
|
620
629
|
await i18nData.trySaveToGoogle(sheetData);
|
|
621
630
|
});
|
|
@@ -624,12 +633,13 @@ async function upload() {
|
|
|
624
633
|
}
|
|
625
634
|
|
|
626
635
|
// package.json
|
|
627
|
-
var version = "0.0.
|
|
636
|
+
var version = "0.0.4";
|
|
628
637
|
|
|
629
638
|
// src/commands/interactive.ts
|
|
630
639
|
import prompts from "prompts";
|
|
631
640
|
var log10 = createLogger("interactive");
|
|
632
641
|
var interactive = async (args) => {
|
|
642
|
+
var _a;
|
|
633
643
|
const commands = cli.commands.filter((command2) => {
|
|
634
644
|
if (command2.name) {
|
|
635
645
|
return !command2.name.startsWith("@@") && command2.name !== "interactive";
|
|
@@ -655,7 +665,7 @@ var interactive = async (args) => {
|
|
|
655
665
|
log10.error("\u672A\u627E\u5230\u547D\u4EE4 %s", res.command);
|
|
656
666
|
return;
|
|
657
667
|
}
|
|
658
|
-
command.commandAction.apply(cli, args);
|
|
668
|
+
(_a = command.commandAction) == null ? void 0 : _a.apply(cli, args);
|
|
659
669
|
};
|
|
660
670
|
|
|
661
671
|
// src/cli.ts
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/extract.ts","../src/shared/index.ts","../src/shared/i18nData.ts","../src/commands/generate.ts","../src/shared/google/sheet.ts","../src/shared/letters.ts","../src/shared/google/auth.ts","../src/shared/google/shared.ts","../src/shared/resolveSheetData.ts","../src/commands/initConfig.ts","../src/commands/upload.ts","../src/commands/interactive.ts","../src/cli.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport { globby } from \"globby\";\nimport pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData, ExtractedMap } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\n\nconst log = createLogger(\"extract\");\n\nexport async function extract() {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n // 这是使得任务串行,方便看日志\n for (const configItem of config) {\n const files = await globby(\n [`**/**.{js,jsx,ts,tsx}`, \"!**/node_modules/**\", \"!**.d.ts\"],\n {\n cwd: configItem.cwd,\n }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n const extractedI18nDataMap: ExtractedMap = new Map();\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res: ExtractedMap = await extract(content);\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n res.size ? pc.green(res.size) : res.size\n );\n res.forEach((value, key) => {\n const cur = extractedI18nDataMap.get(key);\n if (!cur?.defaults) {\n extractedI18nDataMap.set(key, value);\n }\n });\n },\n { concurrency: 20 }\n );\n log.info(\n \"总统提取到 %s 条文案 %O\",\n pc.green(extractedI18nDataMap.size),\n extractedI18nDataMap\n );\n\n const statistics = await pMap(configItem.locales, async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n });\n I18nData.printStatistic(\"提取结果: \", statistics);\n }\n}\n","import cac from \"cac\";\nimport debug from \"debug\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\n\nexport const cli = cac(\"dune\");\n\nexport const createLogger = (name: string) => {\n const info = debug(`${cli.name}:${name}`);\n return {\n ...info,\n info,\n error: info.extend(\"error\"),\n };\n};\n\ndebug.enable(`${cli.name}:*`);\n\n/**\n * same with chacheDir\n * homeDir();\n * //=> '~/name'\n *\n * homeDir('bar.js')\n * //=> '~/name/bar.js'\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport const homeConfigDir = (() => {\n const isWin = process.platform === \"win32\";\n const USER_HOME_DIR = isWin ? process.env.USERPROFILE : process.env.HOME;\n const configDir = path.join(USER_HOME_DIR, \".config\", cli.name);\n\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir);\n }\n return homeConfigDir;\n\n function homeConfigDir(p?: string): string {\n if (!p) {\n return configDir;\n }\n return path.join(configDir, p);\n }\n})();\n","import pMap from \"p-map\";\nimport { InternalConfig } from \"./config\";\nimport { createLogger } from \"./index\";\nimport fs from \"fs-extra\";\nimport pc from \"picocolors\";\nimport path from \"path\";\nimport Table from \"cli-table3\";\nimport { SheetData } from \"./resolveSheetData\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<string, { id: string; defaults: string }>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n constructor(public locale: string, public config: InternalConfig) {\n this.filePath = path.join(\n config.cwd,\n config.i18nDir,\n config.i18nFileName.replace(\"{locale}\", locale)\n );\n }\n\n async loadData() {\n try {\n if (await fs.pathExists(this.filePath)) {\n this.data = await fs.readJSON(this.filePath);\n } else {\n log.info(\"File '%s' does not exist\", pc.dim(this.filePath));\n }\n } catch (e) {\n log.error(\n \"Error loading i18n data for locale '%s' from file '%s'\",\n pc.yellow(this.locale),\n pc.yellow(this.filePath)\n );\n log.error(\"Error: %s\", e.message);\n }\n return this.data;\n }\n\n async updateByExtractedData(\n extractedData: ExtractedMap,\n shouldUseDefault = false\n ) {\n await this.loadData();\n extractedData.forEach((value, key) => {\n this.data[key] = shouldUseDefault\n ? value.defaults || key\n : this.data[key] || \"\";\n });\n }\n\n async updateFromSheetData(sheetData: Record<string, string>) {\n await this.loadData();\n this.data = { ...this.data, ...sheetData };\n }\n\n private sortData() {\n //region 语言key按一定规则排序\n const keys = Object.keys(this.data).sort(this.config.keySorter);\n const newData = {};\n keys.forEach((key) => {\n newData[key] = this.data[key];\n });\n this.data = newData;\n //endregion\n }\n\n async saveToDisk() {\n this.sortData();\n log.info(\n \"Saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n try {\n await fs.ensureFile(this.filePath);\n await fs.writeJson(this.filePath, this.data, { spaces: 2 });\n log.info(\n \"Saved i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n } catch (e) {\n log.error(\n \"Error saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n log.error(\"Error: %s\", pc.red(e.message));\n }\n }\n\n async statistic() {\n const total = Object.keys(this.data).length;\n const missing = Object.values(this.data).filter((v) => !v).length;\n\n return {\n locale: this.locale,\n total,\n missing,\n };\n }\n\n async trySaveToGoogle(sheetData: SheetData) {\n await pMap(Object.entries(this.data), async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key).tryUpdate(value);\n } else {\n log.error(\n \"%s range %s not found key %s\",\n pc.bold(this.config.sheetRange),\n pc.bold(this.locale),\n pc.bold(key)\n );\n }\n });\n }\n\n static printStatistic(\n label: string,\n statistics: { locale: string; total: number; missing: number }[]\n ) {\n const table = new Table({\n head: [\"Language\", \"Total count\", \"Missing\"],\n colAligns: [\"left\", \"center\", \"center\"],\n style: {\n head: [\"green\"],\n border: [],\n compact: true,\n },\n });\n statistics.forEach((statistic) => {\n table.push([\n statistic.locale,\n statistic.total,\n statistic.missing > 0 ? pc.red(statistic.missing) : statistic.missing,\n ]);\n });\n console.log(pc.bold(label));\n console.log(table.toString());\n }\n}\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"generate\");\n\nexport async function generate() {\n const config = await getConfig();\n let i = 0;\n for (const configItem of config) {\n i++;\n if (!configItem.sheetId || !configItem.sheetRange) {\n log.error(`config.${i} sheetId 或 sheetRange 为空,请检查`);\n continue;\n }\n const sheetData = await resolveSheetData(configItem);\n\n const statistics = await pMap(configItem.locales, async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n });\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\n }\n}\n","import { GaxiosResponse } from \"gaxios\";\nimport type { sheets_v4 } from \"googleapis\";\nimport { google } from \"googleapis\";\nimport { createLogger } from \"../index\";\nimport { numberToLetter } from \"../letters\";\nimport { googleAuth } from \"./auth\";\n\nconst log = createLogger(\"google:sheets\");\n\nclass GoogleSheet {\n private sheets: sheets_v4.Sheets;\n\n private initPromise: Promise<void> | null = null;\n private async initImpl() {\n if (!this.sheets) {\n await googleAuth.initCredentials();\n this.sheets = google.sheets({\n version: \"v4\",\n auth: googleAuth.oauth2Client,\n });\n }\n }\n /**\n * 调用sheets其他方法的时候需要先初始化\n */\n async init() {\n if (!this.initPromise) {\n this.initPromise = this.initImpl();\n }\n await this.initPromise;\n }\n\n get = async (options: sheets_v4.Params$Resource$Spreadsheets$Values$Get) => {\n await this.init();\n return this.sheets.spreadsheets.values.get(options);\n };\n\n private async update(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[][]\n ): Promise<GaxiosResponse<sheets_v4.Schema$UpdateValuesResponse>> {\n await this.init();\n\n const colLetter = numberToLetter(colIndex);\n const sheetNeedRange = `${range}!${colLetter}${rowIndex}`;\n\n const res = await this.sheets.spreadsheets.values.update({\n spreadsheetId,\n range: sheetNeedRange,\n valueInputOption: \"USER_ENTERED\",\n requestBody: { values },\n });\n\n if (res.status === 200) {\n log.info(`更新 ${sheetNeedRange} 的值成功`);\n } else {\n log.error(\"some thing wrong\", res);\n }\n return res;\n }\n\n /**\n * 更新某一个单元格\n */\n async updateCell(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [[values]]);\n }\n\n /**\n * 更新某一列\n */\n async updateColumn(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[]\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [\n ...values.map((v) => [v]),\n ]);\n }\n}\n\nexport const googleSheet = new GoogleSheet();\n","/**\n *\n * - input : A\n * output : 0\n * - input : Z\n * output : 25\n * - input : AA\n * output : 26\n * - input : a\n * output : 0\n */\nexport function letterToNumber(letters: string | number) {\n if (typeof letters === \"number\" || !Number.isNaN(+letters)) {\n return +letters;\n }\n\n let n = 0;\n letters = letters.toUpperCase();\n for (let p = 0; p < letters.length; p++) {\n n = letters[p].charCodeAt(0) - 64 + n * 26;\n }\n\n return Math.max(0, n - 1);\n}\n\n/**\n * fork from https://github.com/matthewmueller/number-to-letter\n */\nconst alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst base = alphabet.length;\n/**\n * numberToLetter(0) // A\n * numberToLetter(25) // Z\n * numberToLetter(26) // AA\n * numberToLetter(51) // AZ\n * numberToLetter(52) // BA\n * numberToLetter(676) // ZA\n * numberToLetter(701) // ZZ\n * numberToLetter(702) // AAA\n */\nexport function numberToLetter(n: number) {\n const digits = [];\n\n do {\n const v = n % base;\n digits.push(v);\n n = Math.floor(n / base);\n } while (n-- > 0);\n\n const chars = [];\n while (digits.length) {\n chars.push(alphabet[digits.pop()]);\n }\n\n return chars.join(\"\");\n}\n","import fs from \"fs-extra\";\nimport { OAuth2Client } from \"google-auth-library\";\nimport { google } from \"googleapis\";\nimport { homeConfigDir, createLogger } from \"../index\";\nimport { openAndWaitReturnQuery } from \"./shared\";\n\ninterface AuthOptions {\n client_id: string;\n client_secret: string;\n /**\n * @default ['spreadsheets']\n */\n scope?: string[];\n}\n\nconst log = createLogger(\"google:auth\");\n\nclass GoogleAuth {\n private tokens: any = null;\n\n private tokensCachePath = homeConfigDir(\"chromeAuthToken.json\");\n\n private readonly scope: string[];\n\n oauth2Client: OAuth2Client = new google.auth.OAuth2(\n this.options.client_id,\n this.options.client_secret,\n \"http://localhost:12345\"\n );\n\n constructor(private options: AuthOptions) {\n this.options.scope = this.options.scope ?? [\"spreadsheets\"];\n const scopePrefix = `https://www.googleapis.com/auth/`;\n this.scope = this.options.scope.map((item) => {\n if (item.startsWith(scopePrefix)) {\n return item;\n }\n return `${scopePrefix}${item}`;\n });\n\n try {\n this.tokens = fs.readJsonSync(this.tokensCachePath);\n } catch (e) {\n log.info(\"未获取到缓存的token\");\n this.tokens = null;\n }\n }\n\n private async saveTokens(tokens: any): Promise<void> {\n this.tokens = tokens;\n await fs.writeJSON(this.tokensCachePath, tokens);\n log.info(\"保存token成功\");\n }\n\n async getCode(): Promise<string> {\n log.info(\"将打开chrome浏览器进行授权\");\n const authUrl = this.oauth2Client.generateAuthUrl({\n access_type: \"offline\",\n scope: this.scope,\n });\n return await openAndWaitReturnQuery(authUrl, 12345, \"code\");\n }\n\n private async initCredentialsImpl(): Promise<void> {\n if (!this.tokens) {\n const code = await this.getCode();\n const { tokens } = await this.oauth2Client.getToken(code);\n await this.saveTokens(tokens);\n }\n this.oauth2Client.setCredentials(this.tokens);\n }\n private initCredentialsPromise: Promise<void> | null = null;\n async initCredentials() {\n if (!this.initCredentialsPromise) {\n this.initCredentialsPromise = this.initCredentialsImpl();\n }\n return await this.initCredentialsPromise;\n }\n}\n\n// see in https://console.cloud.google.com/apis/credentials?organizationId=286245507762&orgonly=true&project=dune-cli&supportedpurview=organizationId\nconst clientSecret = {\n client_id:\n \"728508473485-fgl11a3op1ucd0lef9hs49mkliuaipqa.apps.googleusercontent.com\",\n project_id: \"dune-cli\",\n auth_uri: \"https://accounts.google.com/o/oauth2/auth\",\n token_uri: \"https://oauth2.googleapis.com/token\",\n auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\",\n client_secret: \"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\",\n redirect_uris: [\"http://localhost\"],\n};\nexport const googleAuth = new GoogleAuth(clientSecret);\n","import connect from \"connect\";\nimport open from \"open\";\nimport { URL } from \"url\";\nimport { createLogger } from \"../index\";\n\nconst log = createLogger(\"google:shared\");\n\nfunction openBrowser(url: string) {\n log.info(`如未自动打开浏览器,可访问以下地址:${url}`);\n open(url, { app: { name: open.apps.chrome } });\n}\n\nexport function openAndWaitReturnQuery(\n toOpenUrl: string,\n port: number,\n queryKey: string\n) {\n return new Promise<string>((resolve) => {\n openBrowser(toOpenUrl);\n\n const app = connect();\n app.use((req, res, next) => {\n const parsedUrl = new URL(req.url, `http://localhost:${port}`);\n const target = parsedUrl.searchParams.get(queryKey);\n if (target) {\n res.writeHead(200, {\n \"content-type\": \"text/html;charset=utf8\",\n });\n res.end(\n `<div>当前窗口可直接关闭</div>\n <script>\n window.open(\"\", \"_self\", \"\");\n window.close();\n </script>`\n );\n server.close();\n server.unref();\n resolve(target);\n }\n next();\n });\n\n const server = app.listen(port);\n });\n}\n","import { InternalConfig } from \"./config\";\nimport { googleSheet } from \"./google/sheet\";\nimport { createLogger } from \"./index\";\nimport { letterToNumber } from \"./letters\";\n\nconst log = createLogger(\"shared:resolveSheetData\");\n\nclass SheetI18nItem {\n value: string;\n\n colIndex: number;\n\n constructor(\n private spreadsheetId: string,\n private range: string,\n public key: string,\n colIndex: number | string,\n public row: string[],\n private rowIndex: number\n ) {\n this.colIndex = letterToNumber(colIndex);\n // TODO: 待确定 无值的key是否要生成\n // value = undefined 即不会生成\n this.value = this.row[this.colIndex] || \"\";\n }\n\n /**\n * 尝试更新 单元格的值\n * 如果一样则不更新\n */\n async tryUpdate(newValue: string) {\n if (newValue === this.value) {\n // 云端的值跟本地一样 不需要同步\n return;\n }\n\n await googleSheet.updateCell(\n this.spreadsheetId,\n this.range,\n this.colIndex,\n this.rowIndex,\n newValue\n );\n }\n}\n\nexport async function resolveSheetData(\n config: InternalConfig\n): Promise<SheetData> {\n const { position } = config;\n const parseStartIndex = config.parseStartIndex ?? 2;\n\n log.info(`读取 ${config.sheetRange} sheet数据`);\n\n const res = await googleSheet.get({\n spreadsheetId: config.sheetId,\n range: config.sheetRange,\n });\n if (!res.data.values) {\n log.error(\n `${config.sheetRange} sheet数据为空,请检查,应该最少有一行头部数据`\n );\n return new SheetData(config, 2);\n }\n\n const sheetData = new SheetData(config, res.data.values.length + 1);\n\n res.data.values.forEach((row: string[], rowIndex) => {\n // excel 的开始索引是1,所以要 +1\n const trulyRowIndex = rowIndex + 1;\n if (parseStartIndex > trulyRowIndex) {\n // 还未到可以开始解析的行数\n return;\n }\n\n const i18nKey = row[letterToNumber(position.key)]?.trim();\n\n if (i18nKey) {\n if (sheetData.keySet.has(i18nKey)) {\n log.error(\n `表格 ${config.sheetRange} 发现重复的i18nKey: ${i18nKey}, 将覆盖前面的值`\n );\n } else {\n sheetData.keySet.add(i18nKey);\n }\n\n config.locales.forEach((lang) => {\n sheetData.setI18nItem(\n lang,\n new SheetI18nItem(\n config.sheetId,\n config.sheetRange,\n i18nKey,\n position[lang],\n row,\n trulyRowIndex\n )\n );\n });\n }\n });\n\n return sheetData;\n}\n\nexport class SheetData {\n keySet = new Set<string>();\n\n constructor(\n private config: InternalConfig,\n // 当前有多少行 新增的时候往后面添加\n public nextAppendRowIndex: number\n ) {}\n\n private value = new Map(\n this.config.locales.map((lang) => {\n return [lang, new Map<string, SheetI18nItem>()];\n })\n );\n\n getI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang).get(i18nKey);\n }\n\n setI18nItem(lang: string, i18nItem: SheetI18nItem) {\n this.value.get(lang).set(i18nItem.key, i18nItem);\n }\n\n hasI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang).has(i18nKey);\n }\n\n getLangDataJSON(lang: string) {\n const res = {} as Record<string, string>;\n this.value.get(lang).forEach((i18nItem) => {\n res[i18nItem.key] = i18nItem.value;\n });\n return res;\n }\n}\n","import { createLogger } from \"../shared\";\nimport { getConfig, configName } from \"../shared/config\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\n\nconst log = createLogger(\"initConfig\");\n\nconst tpl = `\n/**\n * @template {import('@dune2/cli').Config} T\n * @param {T | T[]} config - A generic parameter that flows through to the return type\n * @constraint {{import('@dune2/cli').Config}}\n */\nfunction defineConfig(config) {\n return config;\n}\nmodule.exports = defineConfig([]);\n`;\n\nexport const initConfig = async () => {\n const config = await getConfig();\n const configPath = path.join(config[0].cwd, configName);\n log.info(`config file path: ${configPath}`);\n if (await fs.pathExists(configPath)) {\n log.info(`config file already exists, skip`);\n return;\n }\n await fs.writeFile(configPath, tpl);\n log.info(`config file created`);\n};\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig, InternalConfig } from \"../shared/config\";\nimport { googleSheet } from \"../shared/google/sheet\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { letterToNumber } from \"../shared/letters\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"upload\");\n\n/**\n * 检测有本地有新增的key 则将新增的key更新到云端\n * 无则跳过\n */\nasync function batchUpdateKeys(config: InternalConfig) {\n let sheetData = await resolveSheetData(config);\n\n const allKeys = [];\n const i18nDataMap = new Map<string, I18nData>();\n await pMap(config.locales, async (locale) => {\n const i18nData = new I18nData(locale, config);\n i18nDataMap.set(locale, i18nData);\n const data = await i18nData.loadData();\n allKeys.push(...Object.keys(data));\n });\n\n let needSyncKeys = Array.from(new Set(allKeys)).filter((key) => {\n // 本地有新的key 服务器没有\n return !sheetData.keySet.has(key);\n });\n needSyncKeys = needSyncKeys.sort(config.keySorter);\n\n if (needSyncKeys.length) {\n log.info(`即将同步本地新增加 ${needSyncKeys.length} 个 i18nKey 到云端`);\n await googleSheet.updateColumn(\n config.sheetId,\n config.sheetRange,\n letterToNumber(config.position.key),\n sheetData.nextAppendRowIndex,\n needSyncKeys\n );\n log.info(\"同步新增加i18nKey成功\");\n\n // 批量同步新增的key的values到云端\n for (const lang of config.locales) {\n const langFile = i18nDataMap.get(lang);\n const needSyncValues = [];\n needSyncKeys.forEach((k) => {\n needSyncValues.push(langFile.data[k]);\n });\n log.info(\n `即将同步本地 ${lang} 新增加 ${needSyncValues.length} 个值到云端`\n );\n await googleSheet.updateColumn(\n config.sheetId,\n config.sheetRange,\n letterToNumber(config.position[lang]),\n sheetData.nextAppendRowIndex,\n needSyncValues\n );\n }\n\n await sleep(1000);\n sheetData = await resolveSheetData(config);\n log.info(`已重新获取 ${config.sheetRange} 的数据`);\n }\n\n return { sheetData, i18nDataMap };\n}\nfunction sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport async function upload() {\n const config = await getConfig();\n\n for (const configItem of config) {\n const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);\n await pMap(configItem.locales, async (locale) => {\n const i18nData = i18nDataMap.get(locale);\n await i18nData.trySaveToGoogle(sheetData);\n });\n }\n\n log.info(\"上传成功\");\n}\n","import { cli, createLogger } from \"../shared\";\nimport prompts from \"prompts\";\n\nconst log = createLogger(\"interactive\");\n\nexport const interactive = async (args: any) => {\n const commands = cli.commands.filter((command) => {\n if (command.name) {\n return !command.name.startsWith(\"@@\") && command.name !== \"interactive\";\n }\n return false;\n });\n\n const commandMap = new Map<string, typeof commands[number]>();\n const res = await prompts({\n type: \"select\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n title: command.name,\n value: command.name,\n description: command.description,\n };\n }),\n });\n\n const command = commandMap.get(res.command);\n if (!command) {\n log.error(\"未找到命令 %s\", res.command);\n return;\n }\n command.commandAction.apply(cli, args);\n};\n","#!/usr/bin/env node\nimport { extract } from \"./commands/extract\";\nimport { generate } from \"./commands/generate\";\nimport { initConfig } from \"./commands/initConfig\";\nimport { upload } from \"./commands/upload\";\nimport { cli } from \"./shared\";\nimport { version } from \"../package.json\";\nimport { interactive } from \"./commands/interactive\";\n\ncli\n .command(\"generate\", \"生成翻译文件\")\n .alias(\"gen\")\n .example(\"dune generate\")\n .example(\"dune gen\")\n .action(generate);\n\ncli.command(\"upload\", \"上传翻译文件\").example(\"dune upload\").action(upload);\n\ncli\n .command(\"extract\", \"提取代码中的文案\")\n .example(\"dune extract\")\n .action(extract);\n\ncli.command(\"init\", \"初始化配置文件\").example(\"dune init\").action(initConfig);\n\ncli\n .command(\"interactive\", \"交互式操作\")\n .example(\"dune interactive\")\n .alias(\"i\")\n .action(interactive);\n// make default command run interactive\ncli.command(\"\").action(interactive);\n\ncli.version(version);\ncli.help();\n\n(async () => {\n try {\n // Parse CLI args without running the command\n cli.parse(process.argv, { run: false });\n // Run the command yourself\n // You only need `await` when your command action returns a Promise\n await cli.runMatchedCommand();\n } catch (error) {\n // Handle error here..\n // e.g.\n // console.error(error.stack)\n // process.exit(1)\n }\n})();\n"],"mappings":"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","names":["fs","pMap","homeConfigDir","fs","path","pc","log","extract","pMap","fs","pMap","google","fs","log","log","fs","log","google","log","log","pMap","fs","path","log","pMap","log","pMap","log","command"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/extract.ts","../src/shared/index.ts","../src/shared/i18nData.ts","../src/commands/generate.ts","../src/shared/google/sheet.ts","../src/shared/letters.ts","../src/shared/google/auth.ts","../src/shared/google/shared.ts","../src/shared/resolveSheetData.ts","../src/commands/initConfig.ts","../src/commands/upload.ts","../src/commands/interactive.ts","../src/cli.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport { globby } from \"globby\";\nimport pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData, ExtractedMap } from \"../shared/i18nData\";\nimport pc from \"picocolors\";\n\nconst log = createLogger(\"extract\");\n\nexport async function extract() {\n const config = await getConfig();\n const { extract } = await import(\"@dune2/wasm\");\n\n // 这是使得任务串行,方便看日志\n for (const configItem of config.i18n ?? []) {\n const files = await globby(\n [`**/**.{js,jsx,ts,tsx}`, \"!**/node_modules/**\", \"!**.d.ts\"],\n {\n cwd: configItem.cwd,\n }\n );\n log.info(\"预计共解析 %s 个文件\", pc.green(files.length));\n const extractedI18nDataMap: ExtractedMap = new Map();\n await pMap(\n files,\n async (file) => {\n const content = await fs.readFile(file, \"utf-8\");\n const res: ExtractedMap = await extract(content);\n log.info(\n \"从 %s 中提取到 %s 条文案\",\n pc.dim(file),\n res.size ? pc.green(res.size) : res.size\n );\n res.forEach((value, key) => {\n const cur = extractedI18nDataMap.get(key);\n // 优先保留有 messages 的\n if (!cur?.messages) {\n extractedI18nDataMap.set(key, value);\n }\n });\n },\n { concurrency: 20 }\n );\n log.info(\n \"总统提取到 %s 条文案 %O\",\n pc.green(extractedI18nDataMap.size),\n extractedI18nDataMap\n );\n\n const statistics = await pMap(\n configItem.locales ?? [],\n async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateByExtractedData(extractedI18nDataMap, index === 0);\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n }\n );\n I18nData.printStatistic(\"提取结果: \", statistics);\n }\n}\n","import cac from \"cac\";\nimport debug from \"debug\";\nimport path from \"path\";\nimport fs from \"fs-extra\";\n\nexport const cli = cac(\"dune\");\n\nexport const createLogger = (name: string) => {\n const info = debug(`${cli.name}:${name}`);\n return {\n ...info,\n info,\n error: info.extend(\"error\"),\n };\n};\n\ndebug.enable(`${cli.name}:*`);\n\n/**\n * same with chacheDir\n * homeDir();\n * //=> '~/name'\n *\n * homeDir('bar.js')\n * //=> '~/name/bar.js'\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport const homeConfigDir = (() => {\n const isWin = process.platform === \"win32\";\n const USER_HOME_DIR = isWin ? process.env.USERPROFILE : process.env.HOME;\n const configDir = path.join(USER_HOME_DIR!, \".config\", cli.name);\n\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir);\n }\n return homeConfigDir;\n\n function homeConfigDir(p?: string): string {\n if (!p) {\n return configDir;\n }\n return path.join(configDir, p);\n }\n})();\n","import pMap from \"p-map\";\nimport { I18nConfig } from \"./config\";\nimport { createLogger } from \"./index\";\nimport fs from \"fs-extra\";\nimport pc from \"picocolors\";\nimport path from \"path\";\nimport Table from \"cli-table3\";\nimport { SheetData } from \"./resolveSheetData\";\n\nconst log = createLogger(\"i18nData\");\nexport type ExtractedMap = Map<string, { id: string; messages: string }>;\n\nexport class I18nData {\n data: Record<string, string> = {};\n\n filePath: string;\n\n constructor(public locale: string, public config: I18nConfig) {\n this.filePath = path.join(\n config.cwd!,\n config.i18nDir!,\n config.i18nFileName!.replace(\"{locale}\", locale)\n );\n }\n\n async loadData() {\n try {\n if (await fs.pathExists(this.filePath)) {\n this.data = await fs.readJSON(this.filePath);\n } else {\n log.info(\"File '%s' does not exist\", pc.dim(this.filePath));\n }\n } catch (e) {\n log.error(\n \"Error loading i18n data for locale '%s' from file '%s'\",\n pc.yellow(this.locale),\n pc.yellow(this.filePath)\n );\n log.error(\"Error: %s\", e.message);\n }\n return this.data;\n }\n\n async updateByExtractedData(\n extractedData: ExtractedMap,\n shouldUseDefault = false\n ) {\n await this.loadData();\n extractedData.forEach((value, key) => {\n this.data[key] = shouldUseDefault\n ? value.messages || key\n : this.data[key] || \"\";\n });\n }\n\n async updateFromSheetData(sheetData: Record<string, string>) {\n await this.loadData();\n this.data = { ...this.data, ...sheetData };\n }\n\n private sortData() {\n //region 语言key按一定规则排序\n const keys = Object.keys(this.data).sort(this.config.keySorter);\n const newData = {};\n keys.forEach((key) => {\n newData[key] = this.data[key];\n });\n this.data = newData;\n //endregion\n }\n\n async saveToDisk() {\n this.sortData();\n log.info(\n \"Saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n try {\n await fs.ensureFile(this.filePath);\n await fs.writeJson(this.filePath, this.data, { spaces: 2 });\n log.info(\n \"Saved i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n } catch (e) {\n log.error(\n \"Error saving i18n data for locale '%s' to file '%s'\",\n pc.green(this.locale),\n pc.dim(this.filePath)\n );\n log.error(\"Error: %s\", pc.red(e.message));\n }\n }\n\n async statistic() {\n const total = Object.keys(this.data).length;\n const missing = Object.values(this.data).filter((v) => !v).length;\n\n return {\n locale: this.locale,\n total,\n missing,\n };\n }\n\n async trySaveToGoogle(sheetData: SheetData) {\n await pMap(Object.entries(this.data), async ([key, value]) => {\n if (sheetData.hasI18nItem(this.locale, key)) {\n // 更新已有的\n await sheetData.getI18nItem(this.locale, key)?.tryUpdate(value);\n } else {\n log.error(\n \"%s range %s not found key %s\",\n pc.bold(this.config.sheetRange),\n pc.bold(this.locale),\n pc.bold(key)\n );\n }\n });\n }\n\n static printStatistic(\n label: string,\n statistics: { locale: string; total: number; missing: number }[]\n ) {\n const table = new Table({\n head: [\"Language\", \"Total count\", \"Missing\"],\n colAligns: [\"left\", \"center\", \"center\"],\n style: {\n head: [\"green\"],\n border: [],\n compact: true,\n },\n });\n statistics.forEach((statistic) => {\n table.push([\n statistic.locale,\n statistic.total,\n statistic.missing > 0 ? pc.red(statistic.missing) : statistic.missing,\n ]);\n });\n console.log(pc.bold(label));\n console.log(table.toString());\n }\n}\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig } from \"../shared/config\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"generate\");\n\nexport async function generate() {\n const config = await getConfig();\n let i = 0;\n for (const configItem of config.i18n ?? []) {\n i++;\n if (!configItem.sheetId || !configItem.sheetRange) {\n log.error(`config.${i} sheetId 或 sheetRange 为空,请检查`);\n continue;\n }\n const sheetData = await resolveSheetData(configItem);\n\n const statistics = await pMap(\n configItem.locales ?? [],\n async (locale, index) => {\n const i18nData = new I18nData(locale, configItem);\n await i18nData.updateFromSheetData(sheetData.getLangDataJSON(locale));\n await i18nData.saveToDisk();\n return await i18nData.statistic();\n }\n );\n I18nData.printStatistic(`${configItem.sheetRange} 生成结果: `, statistics);\n }\n}\n","import { GaxiosResponse } from \"gaxios\";\nimport type { sheets_v4 } from \"googleapis\";\nimport { google } from \"googleapis\";\nimport { createLogger } from \"../index\";\nimport { numberToLetter } from \"../letters\";\nimport { googleAuth } from \"./auth\";\n\nconst log = createLogger(\"google:sheets\");\n\nclass GoogleSheet {\n private sheets: sheets_v4.Sheets;\n\n private initPromise: Promise<void> | null = null;\n private async initImpl() {\n if (!this.sheets) {\n await googleAuth.initCredentials();\n this.sheets = google.sheets({\n version: \"v4\",\n auth: googleAuth.oauth2Client,\n });\n }\n }\n /**\n * 调用sheets其他方法的时候需要先初始化\n */\n async init() {\n if (!this.initPromise) {\n this.initPromise = this.initImpl();\n }\n await this.initPromise;\n }\n\n get = async (options: sheets_v4.Params$Resource$Spreadsheets$Values$Get) => {\n await this.init();\n return this.sheets.spreadsheets.values.get(options);\n };\n\n private async update(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[][]\n ): Promise<GaxiosResponse<sheets_v4.Schema$UpdateValuesResponse>> {\n await this.init();\n\n const colLetter = numberToLetter(colIndex);\n const sheetNeedRange = `${range}!${colLetter}${rowIndex}`;\n\n const res = await this.sheets.spreadsheets.values.update({\n spreadsheetId,\n range: sheetNeedRange,\n valueInputOption: \"USER_ENTERED\",\n requestBody: { values },\n });\n\n if (res.status === 200) {\n log.info(`更新 ${sheetNeedRange} 的值成功`);\n } else {\n log.error(\"some thing wrong\", res);\n }\n return res;\n }\n\n /**\n * 更新某一个单元格\n */\n async updateCell(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [[values]]);\n }\n\n /**\n * 更新某一列\n */\n async updateColumn(\n spreadsheetId: string,\n range: string,\n colIndex: number,\n rowIndex: number,\n values: string[]\n ) {\n return this.update(spreadsheetId, range, colIndex, rowIndex, [\n ...values.map((v) => [v]),\n ]);\n }\n}\n\nexport const googleSheet = new GoogleSheet();\n","/**\n *\n * - input : A\n * output : 0\n * - input : Z\n * output : 25\n * - input : AA\n * output : 26\n * - input : a\n * output : 0\n */\nexport function letterToNumber(letters: string | number) {\n if (typeof letters === \"number\" || !Number.isNaN(+letters)) {\n return +letters;\n }\n\n let n = 0;\n letters = letters.toUpperCase();\n for (let p = 0; p < letters.length; p++) {\n n = letters[p].charCodeAt(0) - 64 + n * 26;\n }\n\n return Math.max(0, n - 1);\n}\n\n/**\n * fork from https://github.com/matthewmueller/number-to-letter\n */\nconst alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst base = alphabet.length;\n/**\n * numberToLetter(0) // A\n * numberToLetter(25) // Z\n * numberToLetter(26) // AA\n * numberToLetter(51) // AZ\n * numberToLetter(52) // BA\n * numberToLetter(676) // ZA\n * numberToLetter(701) // ZZ\n * numberToLetter(702) // AAA\n */\nexport function numberToLetter(n: number) {\n const digits: number[] = [];\n\n do {\n const v = n % base;\n digits.push(v);\n n = Math.floor(n / base);\n } while (n-- > 0);\n\n const chars: string[] = [];\n while (digits.length) {\n chars.push(alphabet[digits.pop()!]);\n }\n\n return chars.join(\"\");\n}\n","import fs from \"fs-extra\";\nimport { OAuth2Client } from \"google-auth-library\";\nimport { google } from \"googleapis\";\nimport { homeConfigDir, createLogger } from \"../index\";\nimport { openAndWaitReturnQuery } from \"./shared\";\n\ninterface AuthOptions {\n client_id: string;\n client_secret: string;\n /**\n * @default ['spreadsheets']\n */\n scope?: string[];\n}\n\nconst log = createLogger(\"google:auth\");\n\nclass GoogleAuth {\n private tokens: any = null;\n\n private tokensCachePath = homeConfigDir(\"chromeAuthToken.json\");\n\n private readonly scope: string[];\n\n oauth2Client: OAuth2Client = new google.auth.OAuth2(\n this.options.client_id,\n this.options.client_secret,\n \"http://localhost:12345\"\n );\n\n constructor(private options: AuthOptions) {\n this.options.scope = this.options.scope ?? [\"spreadsheets\"];\n const scopePrefix = `https://www.googleapis.com/auth/`;\n this.scope = this.options.scope.map((item) => {\n if (item.startsWith(scopePrefix)) {\n return item;\n }\n return `${scopePrefix}${item}`;\n });\n\n try {\n this.tokens = fs.readJsonSync(this.tokensCachePath);\n } catch (e) {\n log.info(\"未获取到缓存的token\");\n this.tokens = null;\n }\n }\n\n private async saveTokens(tokens: any): Promise<void> {\n this.tokens = tokens;\n await fs.writeJSON(this.tokensCachePath, tokens);\n log.info(\"保存token成功\");\n }\n\n async getCode(): Promise<string> {\n log.info(\"将打开chrome浏览器进行授权\");\n const authUrl = this.oauth2Client.generateAuthUrl({\n access_type: \"offline\",\n scope: this.scope,\n });\n return await openAndWaitReturnQuery(authUrl, 12345, \"code\");\n }\n\n private async initCredentialsImpl(): Promise<void> {\n if (!this.tokens) {\n const code = await this.getCode();\n const { tokens } = await this.oauth2Client.getToken(code);\n await this.saveTokens(tokens);\n }\n this.oauth2Client.setCredentials(this.tokens);\n }\n private initCredentialsPromise: Promise<void> | null = null;\n async initCredentials() {\n if (!this.initCredentialsPromise) {\n this.initCredentialsPromise = this.initCredentialsImpl();\n }\n return await this.initCredentialsPromise;\n }\n}\n\n// see in https://console.cloud.google.com/apis/credentials?organizationId=286245507762&orgonly=true&project=dune-cli&supportedpurview=organizationId\nconst clientSecret = {\n client_id:\n \"728508473485-fgl11a3op1ucd0lef9hs49mkliuaipqa.apps.googleusercontent.com\",\n project_id: \"dune-cli\",\n auth_uri: \"https://accounts.google.com/o/oauth2/auth\",\n token_uri: \"https://oauth2.googleapis.com/token\",\n auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\",\n client_secret: \"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\",\n redirect_uris: [\"http://localhost\"],\n};\nexport const googleAuth = new GoogleAuth(clientSecret);\n","import connect from \"connect\";\nimport open from \"open\";\nimport { URL } from \"url\";\nimport { createLogger } from \"../index\";\n\nconst log = createLogger(\"google:shared\");\n\nfunction openBrowser(url: string) {\n log.info(`如未自动打开浏览器,可访问以下地址:${url}`);\n open(url, { app: { name: open.apps.chrome } });\n}\n\nexport function openAndWaitReturnQuery(\n toOpenUrl: string,\n port: number,\n queryKey: string\n) {\n return new Promise<string>((resolve) => {\n openBrowser(toOpenUrl);\n\n const app = connect();\n app.use((req, res, next) => {\n const parsedUrl = new URL(req.url, `http://localhost:${port}`);\n const target = parsedUrl.searchParams.get(queryKey);\n if (target) {\n res.writeHead(200, {\n \"content-type\": \"text/html;charset=utf8\",\n });\n res.end(\n `<div>当前窗口可直接关闭</div>\n <script>\n window.open(\"\", \"_self\", \"\");\n window.close();\n </script>`\n );\n server.close();\n server.unref();\n resolve(target);\n }\n next();\n });\n\n const server = app.listen(port);\n });\n}\n","import { I18nConfig } from \"./config\";\nimport { googleSheet } from \"./google/sheet\";\nimport { createLogger } from \"./index\";\nimport { letterToNumber } from \"./letters\";\n\nconst log = createLogger(\"shared:resolveSheetData\");\n\nclass SheetI18nItem {\n value: string;\n\n colIndex: number;\n\n constructor(\n private spreadsheetId: string,\n private range: string,\n public key: string,\n colIndex: number | string,\n public row: string[],\n private rowIndex: number\n ) {\n this.colIndex = letterToNumber(colIndex);\n // TODO: 待确定 无值的key是否要生成\n // value = undefined 即不会生成\n this.value = this.row[this.colIndex] || \"\";\n }\n\n /**\n * 尝试更新 单元格的值\n * 如果一样则不更新\n */\n async tryUpdate(newValue: string) {\n if (newValue === this.value) {\n // 云端的值跟本地一样 不需要同步\n return;\n }\n\n await googleSheet.updateCell(\n this.spreadsheetId,\n this.range,\n this.colIndex,\n this.rowIndex,\n newValue\n );\n }\n}\n\nexport async function resolveSheetData(config: I18nConfig): Promise<SheetData> {\n const { position } = config;\n const parseStartIndex = config.parseStartIndex ?? 2;\n\n log.info(`读取 ${config.sheetRange} sheet数据`);\n\n const res = await googleSheet.get({\n spreadsheetId: config.sheetId,\n range: config.sheetRange,\n });\n if (!res.data.values) {\n log.error(\n `${config.sheetRange} sheet数据为空,请检查,应该最少有一行头部数据`\n );\n return new SheetData(config, 2);\n }\n\n const sheetData = new SheetData(config, res.data.values.length + 1);\n\n res.data.values.forEach((row: string[], rowIndex) => {\n // excel 的开始索引是1,所以要 +1\n const trulyRowIndex = rowIndex + 1;\n if (parseStartIndex > trulyRowIndex) {\n // 还未到可以开始解析的行数\n return;\n }\n\n const i18nKey = row[letterToNumber(position!.key)]?.trim();\n\n if (i18nKey) {\n if (sheetData.keySet.has(i18nKey)) {\n log.error(\n `表格 ${config.sheetRange} 发现重复的i18nKey: ${i18nKey}, 将覆盖前面的值`\n );\n } else {\n sheetData.keySet.add(i18nKey);\n }\n\n config.locales?.forEach((lang) => {\n sheetData.setI18nItem(\n lang,\n new SheetI18nItem(\n config.sheetId!,\n config.sheetRange!,\n i18nKey,\n position![lang],\n row,\n trulyRowIndex\n )\n );\n });\n }\n });\n\n return sheetData;\n}\n\nexport class SheetData {\n keySet = new Set<string>();\n\n constructor(\n private config: I18nConfig,\n // 当前有多少行 新增的时候往后面添加\n public nextAppendRowIndex: number\n ) {}\n\n private value = new Map(\n this.config.locales!.map((lang) => {\n return [lang, new Map<string, SheetI18nItem>()];\n })\n );\n\n getI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang)!.get(i18nKey);\n }\n\n setI18nItem(lang: string, i18nItem: SheetI18nItem) {\n this.value.get(lang)!.set(i18nItem.key, i18nItem);\n }\n\n hasI18nItem(lang: string, i18nKey: string) {\n return this.value.get(lang)!.has(i18nKey);\n }\n\n getLangDataJSON(lang: string) {\n const res = {} as Record<string, string>;\n this.value.get(lang)!.forEach((i18nItem) => {\n res[i18nItem.key] = i18nItem.value;\n });\n return res;\n }\n}\n","import { createLogger } from \"../shared\";\nimport { getConfig, configName } from \"../shared/config\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\n\nconst log = createLogger(\"initConfig\");\n\nconst tpl = `\n/**\n * @template {import('@dune2/cli').Config} T\n * @param {T} config - A generic parameter that flows through to the return type\n * @constraint {{import('@dune2/cli').Config}}\n */\nfunction defineConfig(config) {\n return config;\n}\nmodule.exports = defineConfig({ i18n: [] });\n`;\n\nexport const initConfig = async () => {\n const config = await getConfig();\n const configPath = path.join(config[0].cwd, configName);\n log.info(`config file path: ${configPath}`);\n if (await fs.pathExists(configPath)) {\n log.info(`config file already exists, skip`);\n return;\n }\n await fs.writeFile(configPath, tpl);\n log.info(`config file created`);\n};\n","import pMap from \"p-map\";\nimport { createLogger } from \"../shared\";\nimport { getConfig, I18nConfig } from \"../shared/config\";\nimport { googleSheet } from \"../shared/google/sheet\";\nimport { I18nData } from \"../shared/i18nData\";\nimport { letterToNumber } from \"../shared/letters\";\nimport { resolveSheetData } from \"../shared/resolveSheetData\";\n\nconst log = createLogger(\"upload\");\n\n/**\n * 检测有本地有新增的key 则将新增的key更新到云端\n * 无则跳过\n */\nasync function batchUpdateKeys(config: I18nConfig) {\n let sheetData = await resolveSheetData(config);\n\n const allKeys: string[] = [];\n const i18nDataMap = new Map<string, I18nData>();\n await pMap(config.locales ?? [], async (locale) => {\n const i18nData = new I18nData(locale, config);\n i18nDataMap.set(locale, i18nData);\n const data = await i18nData.loadData();\n allKeys.push(...Object.keys(data));\n });\n\n let needSyncKeys = Array.from(new Set(allKeys)).filter((key) => {\n // 本地有新的key 服务器没有\n return !sheetData.keySet.has(key);\n });\n needSyncKeys = needSyncKeys.sort(config.keySorter);\n\n if (needSyncKeys.length) {\n log.info(`即将同步本地新增加 ${needSyncKeys.length} 个 i18nKey 到云端`);\n await googleSheet.updateColumn(\n config.sheetId!,\n config.sheetRange!,\n letterToNumber(config.position!.key),\n sheetData.nextAppendRowIndex,\n needSyncKeys\n );\n log.info(\"同步新增加i18nKey成功\");\n\n // 批量同步新增的key的values到云端\n for (const lang of config.locales!) {\n const langFile = i18nDataMap.get(lang);\n const needSyncValues: string[] = [];\n needSyncKeys.forEach((k) => {\n if (langFile) {\n needSyncValues.push(langFile.data[k]);\n }\n });\n log.info(\n `即将同步本地 ${lang} 新增加 ${needSyncValues.length} 个值到云端`\n );\n await googleSheet.updateColumn(\n config.sheetId!,\n config.sheetRange!,\n letterToNumber(config.position![lang]),\n sheetData.nextAppendRowIndex,\n needSyncValues\n );\n }\n\n await sleep(1000);\n sheetData = await resolveSheetData(config);\n log.info(`已重新获取 ${config.sheetRange} 的数据`);\n }\n\n return { sheetData, i18nDataMap };\n}\nfunction sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport async function upload() {\n const config = await getConfig();\n\n for (const configItem of config.i18n ?? []) {\n const { sheetData, i18nDataMap } = await batchUpdateKeys(configItem);\n await pMap(configItem.locales ?? [], async (locale) => {\n const i18nData = i18nDataMap.get(locale)!;\n await i18nData.trySaveToGoogle(sheetData);\n });\n }\n\n log.info(\"上传成功\");\n}\n","import { cli, createLogger } from \"../shared\";\nimport prompts from \"prompts\";\n\nconst log = createLogger(\"interactive\");\n\nexport const interactive = async (args: any) => {\n const commands = cli.commands.filter((command) => {\n if (command.name) {\n return !command.name.startsWith(\"@@\") && command.name !== \"interactive\";\n }\n return false;\n });\n\n const commandMap = new Map<string, typeof commands[number]>();\n const res = await prompts({\n type: \"select\",\n name: \"command\",\n message: \"选择要执行的命令:\",\n choices: commands.map((command) => {\n commandMap.set(command.name, command);\n return {\n title: command.name,\n value: command.name,\n description: command.description,\n };\n }),\n });\n\n const command = commandMap.get(res.command);\n if (!command) {\n log.error(\"未找到命令 %s\", res.command);\n return;\n }\n command.commandAction?.apply(cli, args);\n};\n","#!/usr/bin/env node\nimport { extract } from \"./commands/extract\";\nimport { generate } from \"./commands/generate\";\nimport { initConfig } from \"./commands/initConfig\";\nimport { upload } from \"./commands/upload\";\nimport { cli } from \"./shared\";\nimport { version } from \"../package.json\";\nimport { interactive } from \"./commands/interactive\";\n\ncli\n .command(\"generate\", \"生成翻译文件\")\n .alias(\"gen\")\n .example(\"dune generate\")\n .example(\"dune gen\")\n .action(generate);\n\ncli.command(\"upload\", \"上传翻译文件\").example(\"dune upload\").action(upload);\n\ncli\n .command(\"extract\", \"提取代码中的文案\")\n .example(\"dune extract\")\n .action(extract);\n\ncli.command(\"init\", \"初始化配置文件\").example(\"dune init\").action(initConfig);\n\ncli\n .command(\"interactive\", \"交互式操作\")\n .example(\"dune interactive\")\n .alias(\"i\")\n .action(interactive);\n// make default command run interactive\ncli.command(\"\").action(interactive);\n\ncli.version(version);\ncli.help();\n\n(async () => {\n try {\n // Parse CLI args without running the command\n cli.parse(process.argv, { run: false });\n // Run the command yourself\n // You only need `await` when your command action returns a Promise\n await cli.runMatchedCommand();\n } catch (error) {\n // Handle error here..\n // e.g.\n // console.error(error.stack)\n // process.exit(1)\n }\n})();\n"],"mappings":"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","names":["fs","pMap","homeConfigDir","fs","path","pc","log","extract","pMap","fs","pMap","google","fs","log","log","fs","log","google","log","log","pMap","fs","path","log","pMap","log","pMap","log","command"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface I18nConfig {
|
|
2
2
|
i18nDir?: string;
|
|
3
3
|
i18nFileName?: string;
|
|
4
4
|
defaultLocale?: string;
|
|
@@ -12,6 +12,7 @@ interface Config {
|
|
|
12
12
|
/**
|
|
13
13
|
* 对应 语言、i18nKey 所在的列标识符 如(A,B,C...)
|
|
14
14
|
* 传入时将忽略默认的配置
|
|
15
|
+
* @default {key: "B", zh: "C", en: "D", in: "E",}
|
|
15
16
|
*/
|
|
16
17
|
position?: {
|
|
17
18
|
key: string;
|
|
@@ -23,7 +24,24 @@ interface Config {
|
|
|
23
24
|
* @default 2
|
|
24
25
|
*/
|
|
25
26
|
parseStartIndex?: number;
|
|
27
|
+
/**
|
|
28
|
+
* 默认是 命令运行的目录,一般是项目根目录
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
cwd?: string;
|
|
32
|
+
/**
|
|
33
|
+
* 支持的语言列表,从 position 中解析出来
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
locales?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* 翻译key的排序
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
keySorter?: (a: string, b: string) => number;
|
|
42
|
+
}
|
|
43
|
+
interface Config {
|
|
44
|
+
i18n?: I18nConfig[];
|
|
26
45
|
}
|
|
27
|
-
declare function defineConfig(config: Config | Config[]): Config | Config[];
|
|
28
46
|
|
|
29
|
-
export { Config
|
|
47
|
+
export { Config };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dune2/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@dune2/wasm": "0.0.
|
|
22
|
+
"@dune2/wasm": "0.0.5",
|
|
23
23
|
"cac": "^6.7.14",
|
|
24
24
|
"cli-table3": "^0.6.3",
|
|
25
25
|
"connect": "^3.7.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/config.ts","../src/shared/resolveSheetId.ts"],"sourcesContent":["import JoyCon from \"joycon\";\nimport { resolveSheetId } from \"./resolveSheetId\";\n\nconst joycon = new JoyCon();\n\nexport interface Config {\n // 语言文件存放目录,默认为项目根目录的 \"./i18n\"\n i18nDir?: string;\n // 语言文件名,默认为 \"{locale}.i18n.json\",其中 {locale} 会被替换为 locales 中的语言\n i18nFileName?: string;\n // 默认语言,默认为 \"zh\",影响到提出出来的文案的默认值\n defaultLocale?: string;\n /**\n * 可以是 id 或者 url,如果是 url 则会自动解析出 id\n * id: 1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\n * url: https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\n */\n sheetId?: string;\n // google sheets 工作表名称\n sheetRange?: string;\n /**\n * 对应 语言、i18nKey 所在的列标识符 如(A,B,C...)\n * 传入时将忽略默认的配置\n */\n position?: {\n key: string;\n [key: string]: string;\n };\n\n /**\n * 从 Google Sheets 哪一行开始解析\n * 默认从第2行开始,模板文件第一行是表头\n * @default 2\n */\n parseStartIndex?: number;\n}\nexport interface InternalConfig extends Config {\n // 默认是 命令运行的目录,一般是项目根目录\n cwd?: string;\n // 支持的语言列表,从 position 中解析出来\n locales?: string[];\n\n keySorter?: (a: string, b: string) => number;\n}\n\nexport function defineConfig(config: Config | Config[]) {\n return config;\n}\n\nexport const configName = \"dune.config.js\";\n\nexport async function getConfig(): Promise<InternalConfig[]> {\n const res = await joycon.load([configName]);\n\n const defaultConfig = {\n i18nDir: \"./i18n\",\n i18nFileName: \"{locale}.i18n.json\",\n cwd: process.cwd(),\n position: {\n key: \"B\",\n zh: \"C\",\n en: \"D\",\n in: \"E\",\n },\n parseStartIndex: 2,\n };\n\n if (res.data) {\n const config: InternalConfig[] = Array.isArray(res.data)\n ? res.data\n : [res.data];\n return config.map((item) => {\n item = Object.assign({}, defaultConfig, item);\n item.locales = Object.keys(item.position).filter(\n (item) => item !== \"key\"\n );\n\n item.sheetId = resolveSheetId(item.sheetId);\n\n item.keySorter = (a, b) => {\n return a.localeCompare(b);\n };\n\n return item;\n });\n }\n\n return [defaultConfig];\n}\n","/**\n * input:\n * \"https://docs.google.com/spreadsheets/d/1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk/edit#gid=1740568548\"\n * output:\n * \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * --\n * input: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n * output: \"1C9-Dol3oO20W9_FhiVlxNsDhOaaejJIgAZYRkonGmfk\"\n */\nimport { match } from \"path-to-regexp\";\n\nexport function resolveSheetId(str?: string) {\n if (!str || !str?.startsWith(\"http\")) {\n return str;\n }\n const url = new URL(str);\n const matched = match<{ id: string[] }>(\"/spreadsheets/d/:id*\", {\n decode: decodeURIComponent,\n })(url.pathname);\n return matched ? matched.params.id?.[0] : str;\n}\n"],"mappings":";AAAA,OAAO,YAAY;;;ACSnB,SAAS,aAAa;AAEf,SAAS,eAAe,KAAc;AAX7C;AAYE,MAAI,CAAC,OAAO,EAAC,2BAAK,WAAW,UAAS;AACpC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,IAAI,IAAI,GAAG;AACvB,QAAM,UAAU,MAAwB,wBAAwB;AAAA,IAC9D,QAAQ;AAAA,EACV,CAAC,EAAE,IAAI,QAAQ;AACf,SAAO,WAAU,aAAQ,OAAO,OAAf,mBAAoB,KAAK;AAC5C;;;ADjBA,IAAM,SAAS,IAAI,OAAO;AA0CnB,SAAS,aAAa,QAA2B;AACtD,SAAO;AACT;AAEO,IAAM,aAAa;AAE1B,eAAsB,YAAuC;AAC3D,QAAM,MAAM,MAAM,OAAO,KAAK,CAAC,UAAU,CAAC;AAE1C,QAAM,gBAAgB;AAAA,IACpB,SAAS;AAAA,IACT,cAAc;AAAA,IACd,KAAK,QAAQ,IAAI;AAAA,IACjB,UAAU;AAAA,MACR,KAAK;AAAA,MACL,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AAAA,IACA,iBAAiB;AAAA,EACnB;AAEA,MAAI,IAAI,MAAM;AACZ,UAAM,SAA2B,MAAM,QAAQ,IAAI,IAAI,IACnD,IAAI,OACJ,CAAC,IAAI,IAAI;AACb,WAAO,OAAO,IAAI,CAAC,SAAS;AAC1B,aAAO,OAAO,OAAO,CAAC,GAAG,eAAe,IAAI;AAC5C,WAAK,UAAU,OAAO,KAAK,KAAK,QAAQ,EAAE;AAAA,QACxC,CAACA,UAASA,UAAS;AAAA,MACrB;AAEA,WAAK,UAAU,eAAe,KAAK,OAAO;AAE1C,WAAK,YAAY,CAAC,GAAG,MAAM;AACzB,eAAO,EAAE,cAAc,CAAC;AAAA,MAC1B;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,CAAC,aAAa;AACvB;","names":["item"]}
|