forked from azukaar/Cosmos-Server
-
Notifications
You must be signed in to change notification settings - Fork 1
/
translate.js
146 lines (122 loc) · 4.36 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
const fs = require('fs').promises;
const path = require('path');
const { execSync } = require('child_process');
const axios = require('axios');
const API_KEY = process.env.API_KEY;
const BATCH_SIZE = 50;
async function readJsonFile(filePath) {
const data = await fs.readFile(filePath, 'utf8');
return JSON.parse(data);
}
async function writeJsonFile(filePath, data) {
await fs.writeFile(filePath, JSON.stringify(data, null, 2));
}
async function translateBatch(batch, targetLang) {
const prompt = `Translate the following JSON key-value pairs from English to ${targetLang}. Maintain the JSON structure and only translate the values. Always return valid JSON:
${JSON.stringify(batch, null, 2)}`;
try {
const res = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4o",
max_tokens: 3000,
messages: [
{
role: "system",
content: "You are a translator for technical products.",
},
{
role: "user",
content: prompt,
},
],
})
});
let rawText = await res.json();
// console.log(rawText);
rawText = rawText.choices[0].message.content;
let json = rawText.split('{').slice(1).join('{');
json = json.split('}').slice(0, -1).join('}');
console.log(json);
json = JSON.parse(`{${json}}`);
return json;
} catch (error) {
console.error('Error calling API:', error.message);
return null;
}
}
async function getModifiedKeys(filePath, since) {
try {
const output = execSync(`git diff ${since} -- ${filePath}`, { encoding: 'utf-8' });
const addedLines = output.split('\n').filter(line => line.startsWith('+') && line.includes(':'));
return addedLines.map(line => line.split(':')[0].replace(/["+]/g, '').trim());
} catch (error) {
console.error('Error getting modified keys:', error.message);
return [];
}
}
async function translateFile(sourcePath, targetPath, targetLang, all, since) {
const sourceData = await readJsonFile(sourcePath);
let targetData = {};
if (!all) {
try {
targetData = await readJsonFile(targetPath);
} catch (error) {
console.log('Target file not found. Creating a new one.');
// Create the target directory if it doesn't exist
const targetDir = path.dirname(targetPath);
await fs.mkdir(targetDir, { recursive: true });
}
}
let keysToTranslate;
if (all) {
keysToTranslate = Object.keys(sourceData);
} else if (since) {
keysToTranslate = await getModifiedKeys(sourcePath, since);
} else {
keysToTranslate = Object.keys(sourceData).filter(key => !(key in targetData));
}
for (let i = 0; i < keysToTranslate.length; i += BATCH_SIZE) {
const batch = Object.fromEntries(
keysToTranslate.slice(i, i + BATCH_SIZE).map(key => [key, sourceData[key]])
);
console.log(`Translating keys ${i + 1} to ${i + BATCH_SIZE} out of ${keysToTranslate.length}`);
const translatedBatch = await translateBatch(batch, targetLang);
if (translatedBatch) {
Object.assign(targetData, translatedBatch);
}
}
if (!all) {
// Remove keys that are not in the source file
Object.keys(targetData).forEach(key => {
if (!(key in sourceData)) {
delete targetData[key];
}
});
}
await writeJsonFile(targetPath, targetData);
console.log(`Translation completed. Output saved to ${targetPath}`);
}
async function main() {
const args = process.argv.slice(2);
const targetLang = args[0];
const all = args.includes('--all');
const sinceIndex = args.indexOf('--since');
const since = sinceIndex !== -1 ? args[sinceIndex + 1] : null;
if (!targetLang) {
console.error('Please provide a target language.');
process.exit(1);
}
if (all && since) {
console.error('--all and --since options are incompatible.');
process.exit(1);
}
const sourcePath = path.join('client/src/utils/locales', 'en', 'translation.json');
const targetPath = path.join('client/src/utils/locales', targetLang, 'translation.json');
await translateFile(sourcePath, targetPath, targetLang, all, since);
}
main().catch(console.error);