-
-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathtranslate-tutorial-templates.mjs
120 lines (98 loc) · 3.3 KB
/
translate-tutorial-templates.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import fs from 'node:fs/promises';
import path from 'node:path';
import arg from 'arg';
import dotenv from 'dotenv';
import { Listr } from 'listr2';
import picocolors from 'picocolors';
import { log, OpenAiTranslate } from './translate.openai.mjs';
import { sampleTranslations } from './translate.samples.mjs';
import { walk, exit, i18nBaseDir, filterFiles } from './translate.shared.mjs';
dotenv.config();
const args = arg({
'--all': Boolean,
'--locale': String,
});
const tutorialBaseDir = 'tutorial';
const translateDir = 'docusaurus-plugin-content-blog-tutorial';
/**
* Whether to translate all tutorial fragments and templates.
* Use this option when you want to translate all templates for a new locale.
*
* @type {boolean}
*/
const all = args['--all'];
/**
* The target locale to translate the files to. Note that the locale must exist in the `i18n`
* directory. It's recommended to run the Docusaurus write translation command before running this
* script.
*
* @type {string}
*/
const locale = args['--locale'];
if (!locale) {
exit('No locale specified. Use --locale to specify the target locale.');
}
await fs.readdir(path.join(i18nBaseDir, locale)).catch(() => {
exit(
`Locale ${locale} does not exist. Did you forget to run the Docusaurus write translation command?`
);
});
const getFiles = async () => {
const filePaths = await walk(tutorialBaseDir);
return filePaths.filter((file) => !file.startsWith('tutorial/build-with-logto/generated-'));
};
const files = await filterFiles(await getFiles(), locale, !all);
if (files.length === 0) {
exit('No generated tutorial found to translate.');
}
const sortedFiles = files.slice().sort();
log(`The following files will be translated:`);
for (const slug of sortedFiles) {
log(` - ${picocolors.blue(slug)}`);
}
const confirm = async () =>
new Promise((resolve) => {
process.stdin.once('data', (data) => resolve(data.toString().trim()));
});
if (files.length > 1) {
log(`${files.length} files will be translated. Enter "y" to confirm.`);
const confirmation = await confirm();
if (confirmation.toLowerCase() !== 'y') {
exit('Translation cancelled.');
}
}
if (!sampleTranslations[locale]) {
log(
picocolors.yellow(
`No sample translation found for locale "${locale}", the translation quality may vary. Enter "y" to confirm.`
)
);
const confirmation = await confirm();
if (confirmation.toLowerCase() !== 'y') {
exit('Translation cancelled.');
}
}
const openAiTranslate = new OpenAiTranslate(locale);
const listr = new Listr([], { concurrent: 2 });
for (const file of files) {
listr.add({
async task(_, task) {
// eslint-disable-next-line @silverhand/fp/no-mutation
task.title = `Translating ${file}...`;
const content = await fs.readFile(file, 'utf8');
const translated = await openAiTranslate.translate(content, locale, task);
const targetFile = file.replace(
tutorialBaseDir,
path.join(i18nBaseDir, locale, translateDir)
);
await fs.mkdir(path.dirname(targetFile), { recursive: true });
await fs.writeFile(targetFile, translated, 'utf8');
// eslint-disable-next-line @silverhand/fp/no-mutation
task.title = `Done: ${targetFile}`;
},
retry: 1,
});
}
await listr.run();
log(picocolors.green('✓ Completed translation.'));
exit();