-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtranslate.js
150 lines (114 loc) · 4.53 KB
/
translate.js
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const { translations, exclusionRegex } = require('./translations.js');
const fs = require('fs');
const path = require('path');
const targetDir = path.join(__dirname, 'docs');
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function isDirectory(filePath) {
return fs.statSync(filePath).isDirectory();
}
function enumerateMdFiles(dir) {
const files = fs.readdirSync(dir);
let mdFiles = [];
for (const file of files) {
const filePath = path.join(dir, file);
if (isDirectory(filePath)) {
mdFiles = mdFiles.concat(enumerateMdFiles(filePath));
} else if (file.endsWith('.md') || file.endsWith('.yml')) {
if (!exclusionRegex.test(filePath))
mdFiles.push(filePath);
}
}
return mdFiles;
}
async function runInference(text) {
const apiKey = process.env.GROQ_API_KEY;
if (!apiKey) {
console.error("GROQ_API_KEY environment variable is not set.");
process.exit(1);
}
const response = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'llama-3.3-70b-specdec',
messages: [{
role: 'user',
content: text
}],
temperature: 0.1,
top_p: 0.75,
max_tokens: 8192
})
});
if (!response.ok) {
const resJson = await response.json();
if (resJson.error?.code == "rate_limit_exceeded") {
const retryAfter = response.headers.get("Retry-After") * 3;
console.error("Rate limit exceeded! Retrying in " + retryAfter + " seconds.");
await sleep(retryAfter * 1000);
return await runInference(text, prompt);
} else {
console.error("Failed to translate the markdown file.");
console.error(await response.text());
process.exit(1);
}
}
const data = await response.json();
return data.choices[0].message.content;
}
const mdFiles = enumerateMdFiles(targetDir);
function getPrompt(toLanguage, fileName, text) {
const baseText = `
You're translating a piece of documentation of the Sisk Framework, an .NET web-server written in C#. Translate the translation input text to ${toLanguage}.
Rules:
- You SHOULD translate texts, code comments, but not code symbols, variables or constants names.
- You MUST NOT translate script-header file names or language names.
- You MUST keep the same file structure, maintaining links targets, headers, codes and page title.
- You SHOULD NOT translate HTML tag names inside Markdown.
- You SHOULD NOT translate markdown warning boxes tags, such as [!TIP] or [!WARNING].
- You MUST keep absolute link targets (eg. links which points to "/spec" or starts with "https://...").
- You SHOULD ONLY translate YAML values, NOT the keys.
- You MUST NOT translate YAML keys.
- You MUST NOT alter the YAML file structure.
- You MUST reply ONLY with the translated text, no greetings, advices or comments.
- The translated text must follow the original input structure.
File name: ${fileName}
<translation-input>
${text}
</translation-input>
`;
return baseText;
}
(async () => {
var translatedCount = 0;
for (const mdFile of mdFiles) {
const fileContents = fs.readFileSync(mdFile, 'utf8');
const fileName = mdFile.replace(targetDir, '');
for (const [langName, langCode] of Object.entries(translations)) {
const prompt = getPrompt(langName, fileName, fileContents);
const translationPath = path.join(targetDir, langCode, fileName);
const translationDir = path.dirname(translationPath);
if (fs.existsSync(translationPath)) {
continue;
}
const translated = (await runInference(prompt))
.replaceAll("/docs/", `/docs/${langCode}/`);
fs.mkdirSync(translationDir, { recursive: true });
fs.writeFileSync(translationPath, translated);
console.log("- Translated: ", translationPath);
// wait 10s (rate-limit)
await sleep(500);
translatedCount++;
}
}
if (translatedCount == 0) {
console.log("No files to translate.");
} else {
console.log(`${translatedCount} files translated.`);
}
})().then(() => console.log("Finished!"));