mirror of
https://github.com/zoo-apps/vote.git
synced 2026-10-30 14:56:32 +00:00
- Full app extraction from zoo monorepo (source only) - Configured for GitHub Pages deployment - Static export enabled - Custom domain: vote.zoo.ngo - Excludes node_modules and build artifacts
172 lines
5.6 KiB
JavaScript
172 lines
5.6 KiB
JavaScript
require('dotenv').config(); // Load environment variables from .env
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const axios = require('axios');
|
|
|
|
const dotenv = require('dotenv');
|
|
// Check if .env.local exists and load it
|
|
const envLocalPath = path.join(__dirname, '../.env.local');
|
|
if (fs.existsSync(envLocalPath)) {
|
|
dotenv.config({ path: envLocalPath });
|
|
}
|
|
|
|
// Adjust paths to be relative to the /scripts folder
|
|
const sourceDir = path.join(__dirname, '../public/locales/en');
|
|
const targetBaseDir = path.join(__dirname, '../public/locales');
|
|
|
|
// List of target languages and their directory names
|
|
const languages = {
|
|
es: 'ES', // Spanish
|
|
de: 'DE', // German
|
|
fr: 'FR', // French
|
|
it: 'IT', // Italian
|
|
ja: 'JA', // Japanese
|
|
ko: 'KO', // Korean
|
|
pt: 'PT', // Portuguese
|
|
ru: 'RU', // Russian
|
|
uk: 'UK', // Ukrainian
|
|
zh: 'ZH', // Simplified Chinese
|
|
zh_hant: 'ZH-HANT', // Traditional Chinese
|
|
};
|
|
|
|
// Helper function to add a delay
|
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
// Your DeepL API key
|
|
const DEEPL_API_KEY = process.env.VITE_APP_DEEPL_API_KEY;
|
|
|
|
if (!DEEPL_API_KEY) {
|
|
console.error('Please set the DEEPL_API_KEY environment variable.');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Function to translate text while preserving placeholders inside {}
|
|
async function translateWithPlaceholders(text, langCode) {
|
|
const singleQuoteRegex = /{[^}]+}/g;
|
|
const singleQuoteRegexPlaceholders = text.match(singleQuoteRegex) || [];
|
|
|
|
const doubleQuoteRegex = /{{[^}]+}}/g;
|
|
const doubleQuoteRegexRegexPlaceholders = text.match(doubleQuoteRegex) || [];
|
|
|
|
let translatedText = text;
|
|
|
|
// Replace placeholders with temporary markers
|
|
singleQuoteRegexPlaceholders.forEach((placeholder, index) => {
|
|
translatedText = translatedText.replace(placeholder, `<xx>${placeholder}</xx>`);
|
|
});
|
|
|
|
// Replace placeholders with double {{}} with temporary markers
|
|
doubleQuoteRegexRegexPlaceholders.forEach((placeholder, index) => {
|
|
translatedText = translatedText.replace(placeholder, `<xx>${placeholder}</xx>`);
|
|
});
|
|
|
|
// Replace "DAO Labs" with temporary markers
|
|
translatedText = translatedText.replace('DAO Labs', '<xx>DAO Labs</xx>');
|
|
|
|
// Translate the text without placeholders
|
|
try {
|
|
const response = await axios.post(
|
|
'https://api-free.deepl.com/v2/translate',
|
|
new URLSearchParams({
|
|
auth_key: DEEPL_API_KEY,
|
|
text: translatedText,
|
|
source_lang: 'EN',
|
|
target_lang: langCode,
|
|
tag_handling: 'xml',
|
|
ignore_tags: 'xx',
|
|
}),
|
|
{
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
},
|
|
);
|
|
|
|
translatedText = response.data.translations[0].text;
|
|
} catch (error) {
|
|
console.error(
|
|
`Error translating text "${text}" to "${langCode}":`,
|
|
error.response?.data || error.message,
|
|
);
|
|
return text; // Fallback to original text
|
|
}
|
|
|
|
// Restore placeholders in the translated text
|
|
translatedText = translatedText.replaceAll('<xx>', '').replaceAll('</xx>', '');
|
|
return translatedText;
|
|
}
|
|
|
|
// Recursive function to translate all string values in a JSON object
|
|
async function translateObject(obj, langCode, existingTranslations = {}) {
|
|
const translatedObj = {};
|
|
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
if (typeof value === 'string') {
|
|
// Check if the key already has a translation
|
|
if (existingTranslations[key]) {
|
|
translatedObj[key] = existingTranslations[key];
|
|
} else {
|
|
try {
|
|
translatedObj[key] = await translateWithPlaceholders(value, langCode);
|
|
await delay(200); // Add a delay of 200ms between requests to avoid rate limiting
|
|
} catch (error) {
|
|
console.error(`Error translating key "${key}" to "${langCode}":`, error);
|
|
translatedObj[key] = value; // Fallback to original
|
|
}
|
|
}
|
|
} else if (typeof value === 'object' && value !== null) {
|
|
// Recursively translate nested objects
|
|
translatedObj[key] = await translateObject(value, langCode, existingTranslations[key] || {});
|
|
} else {
|
|
// Preserve non-string values as-is
|
|
translatedObj[key] = value;
|
|
}
|
|
}
|
|
|
|
return translatedObj;
|
|
}
|
|
|
|
async function translateFiles() {
|
|
try {
|
|
// Read all files in the source directory
|
|
const files = fs.readdirSync(sourceDir);
|
|
|
|
for (const file of files) {
|
|
const sourceFile = path.join(sourceDir, file);
|
|
|
|
// Process only JSON files
|
|
if (path.extname(file) === '.json') {
|
|
console.log(`Translating file: ${file}`);
|
|
|
|
const content = JSON.parse(fs.readFileSync(sourceFile, 'utf8'));
|
|
|
|
// Translate for each target language
|
|
for (const [langDir, langCode] of Object.entries(languages)) {
|
|
const targetDir = path.join(targetBaseDir, langDir);
|
|
const targetFile = path.join(targetDir, file);
|
|
|
|
// Ensure the target directory exists
|
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
|
|
// Load existing translations if the target file exists
|
|
let existingTranslations = {};
|
|
if (fs.existsSync(targetFile)) {
|
|
existingTranslations = JSON.parse(fs.readFileSync(targetFile, 'utf8'));
|
|
}
|
|
|
|
// Translate the entire JSON object
|
|
const translatedContent = await translateObject(content, langCode, existingTranslations);
|
|
|
|
// Write the translated content to the target file
|
|
fs.writeFileSync(targetFile, JSON.stringify(translatedContent, null, 2), 'utf8');
|
|
console.log(`Translated file saved: ${targetFile}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('All files translated successfully!');
|
|
} catch (error) {
|
|
console.error('Error processing files:', error);
|
|
}
|
|
}
|
|
|
|
translateFiles();
|