- Added new translation files for product dialogs to support additional languages. - Refactored various components to utilize translation functions for error messages, labels, and placeholders, enhancing localization support.
713 lines
24 KiB
JavaScript
Executable File
713 lines
24 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import OpenAI from 'openai';
|
|
|
|
// Configuration
|
|
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
|
const LOCALES_DIR = './src/i18n/locales';
|
|
const GERMAN_DIR = path.join(LOCALES_DIR, 'de');
|
|
const ENGLISH_DIR = path.join(LOCALES_DIR, 'en');
|
|
|
|
// Translation file groups
|
|
const TRANSLATION_FILES = [
|
|
'locale.js',
|
|
'navigation.js',
|
|
'auth.js',
|
|
'cart.js',
|
|
'product.js',
|
|
'productDialogs.js',
|
|
'search.js',
|
|
'sorting.js',
|
|
'chat.js',
|
|
'delivery.js',
|
|
'checkout.js',
|
|
'payment.js',
|
|
'filters.js',
|
|
'tax.js',
|
|
'footer.js',
|
|
'titles.js',
|
|
'sections.js',
|
|
'pages.js',
|
|
'orders.js',
|
|
'settings.js',
|
|
'common.js'
|
|
];
|
|
|
|
// Legal document files that need special translation handling
|
|
const LEGAL_FILES = [
|
|
'legal-agb-delivery.js',
|
|
'legal-agb-payment.js',
|
|
'legal-agb-consumer.js',
|
|
'legal-datenschutz-basic.js',
|
|
'legal-datenschutz-customer.js',
|
|
'legal-datenschutz-google-orders.js',
|
|
'legal-datenschutz-newsletter.js',
|
|
'legal-datenschutz-chatbot.js',
|
|
'legal-datenschutz-cookies-payment.js',
|
|
'legal-datenschutz-rights.js',
|
|
'legal-impressum.js',
|
|
'legal-widerruf.js',
|
|
'legal-batterie.js'
|
|
];
|
|
|
|
// Model configuration
|
|
const GERMAN_TO_ENGLISH_MODEL = 'gpt-5.1'; // High-quality model for German -> English (critical step)
|
|
const ENGLISH_TO_OTHER_MODEL = 'gpt-4.1-mini'; // Faster/cheaper model for English -> Other languages
|
|
|
|
// Supported languages for translation
|
|
const TARGET_LANGUAGES = {
|
|
'bg': 'Bulgarian',
|
|
'cs': 'Czech',
|
|
'es': 'Spanish',
|
|
'fr': 'French',
|
|
'el': 'Greek',
|
|
'hr': 'Croatian',
|
|
'hu': 'Hungarian',
|
|
'it': 'Italian',
|
|
'pl': 'Polish',
|
|
'ro': 'Romanian',
|
|
'ru': 'Russian',
|
|
'sk': 'Slovak',
|
|
'sl': 'Slovenian',
|
|
'sq': 'Albanian',
|
|
'sr': 'Serbian',
|
|
'sv': 'Swedish',
|
|
'tr': 'Turkish',
|
|
'uk': 'Ukrainian',
|
|
'ar': 'Arabic (Egyptian)',
|
|
'zh': 'Chinese (Simplified)'
|
|
};
|
|
|
|
|
|
/* JTL mapping
|
|
bg (Bulgarian) -> kSprache: 37
|
|
cs (Czech) -> kSprache: 21
|
|
es (Spanish) -> kSprache: 20
|
|
fr (French) -> kSprache: 5
|
|
el (Greek) -> kSprache: 7
|
|
hr (Croatian) -> kSprache: 11
|
|
hu (Hungarian) -> kSprache: 24
|
|
it (Italian) -> kSprache: 10
|
|
pl (Polish) -> kSprache: 14
|
|
ro (Romanian) -> kSprache: 26
|
|
ru (Russian) -> kSprache: 16
|
|
sk (Slovak) -> kSprache: 18
|
|
sl (Slovenian) -> kSprache: 19
|
|
sq (Albanian) -> kSprache: 190
|
|
sr (Serbian) -> kSprache: 93
|
|
sv (Swedish) -> kSprache: 17
|
|
tr (Turkish) -> kSprache: 22
|
|
uk (Ukrainian) -> kSprache: 23
|
|
ar (Arabic) -> kSprache: 30
|
|
zh (Chinese) -> kSprache: 43
|
|
*/
|
|
|
|
// Initialize OpenAI client
|
|
const openai = new OpenAI({
|
|
apiKey: OPENAI_API_KEY,
|
|
});
|
|
|
|
// System prompt for German to English translation
|
|
const GERMAN_TO_ENGLISH_SYSTEM_PROMPT = `
|
|
You MUST translate German strings to English AND add the original German text as a comment after EVERY translated string.
|
|
|
|
CRITICAL REQUIREMENT: Every translated string must have the original German text as a comment.
|
|
|
|
Rules:
|
|
1. Translate all German strings to English
|
|
2. MANDATORY: Add the original German text as a comment after EVERY translated string using // format
|
|
3. Preserve all existing comments from the German version
|
|
4. Maintain the exact JavaScript object structure and formatting
|
|
5. Keep all interpolation variables like {{count}}, {{vat}}, etc. unchanged
|
|
6. Keep locale codes appropriate for English
|
|
7. For the locale section, use "en-US" as code
|
|
8. Do not translate technical terms that are already in English
|
|
9. Preserve any special formatting or HTML entities
|
|
10. Return a valid JavaScript object (not JSON) that can be exported
|
|
|
|
MANDATORY FORMAT for every string:
|
|
"englishTranslation": "English Translation", // Original German Text
|
|
|
|
Examples:
|
|
"login": "Login", // Anmelden
|
|
"email": "Email", // E-Mail
|
|
"password": "Password", // Passwort
|
|
"home": "Home", // Startseite
|
|
|
|
DO NOT output any string without its German comment. Every single translated string needs the German original as a comment.
|
|
`;
|
|
|
|
// Special system prompt for legal documents (German to English)
|
|
const LEGAL_GERMAN_TO_ENGLISH_SYSTEM_PROMPT = `
|
|
You MUST translate German legal document strings to English AND add the original German text as a comment after EVERY translated string.
|
|
|
|
CRITICAL LEGAL DOCUMENT REQUIREMENTS:
|
|
- This is a legal document for a GERMAN COMPANY (Growheads) operating under GERMAN LAW
|
|
- All legal terms, regulations, and jurisdictions remain GERMAN even when translated
|
|
- Company name "Growheads" and German address must remain unchanged
|
|
- All references to German laws (DSGVO, BGB, etc.) must remain as German legal references
|
|
- German court jurisdiction and German legal framework must be preserved
|
|
- The translation is for INFORMATIONAL PURPOSES to help international customers understand the German legal terms
|
|
|
|
Rules:
|
|
1. Translate all German strings to English for comprehension
|
|
2. MANDATORY: Add the original German text as a comment after EVERY translated string using // format
|
|
3. Preserve all existing comments from the German version
|
|
4. Maintain the exact JavaScript object structure and formatting
|
|
5. Keep all interpolation variables unchanged
|
|
6. Keep company name "Growheads" unchanged
|
|
7. Keep German address unchanged
|
|
8. Keep German law references (DSGVO, BGB, etc.) unchanged
|
|
9. Keep German court jurisdiction references unchanged
|
|
10. Preserve any special formatting or HTML entities
|
|
11. Return a valid JavaScript object (not JSON) that can be exported
|
|
|
|
MANDATORY FORMAT for every string:
|
|
"englishTranslation": "English Translation", // Original German Text
|
|
|
|
IMPORTANT: The English translation should help international customers understand the German legal terms, but the legal validity remains under German law.
|
|
`;
|
|
|
|
// System prompt template for English to other languages (file content will be inserted)
|
|
const ENGLISH_TO_OTHER_SYSTEM_PROMPT_TEMPLATE = `
|
|
Translate the English strings in the following file to {{targetLanguage}}, preserving the German comments.
|
|
|
|
Rules:
|
|
1. Translate only the English strings to {{targetLanguage}}
|
|
2. Drop the comments in output
|
|
3. Maintain the exact JavaScript object structure and formatting
|
|
4. Keep all interpolation variables like {{count}}, {{vat}}, etc. unchanged
|
|
5. Update locale code appropriately for the target language
|
|
6. Do not translate technical terms, API keys, or code-related strings
|
|
7. Preserve any special formatting or HTML entities
|
|
8. Return a valid JavaScript object (not JSON) that can be exported
|
|
|
|
Here is the English translation file to translate:
|
|
|
|
{{englishFileContent}}
|
|
`;
|
|
|
|
// Special system prompt for legal documents (English to other languages)
|
|
const LEGAL_ENGLISH_TO_OTHER_SYSTEM_PROMPT_TEMPLATE = `
|
|
Translate the English legal document strings to {{targetLanguage}} while preserving the German legal framework.
|
|
|
|
CRITICAL LEGAL DOCUMENT REQUIREMENTS:
|
|
- This is a legal document for a GERMAN COMPANY (Growheads) operating under GERMAN LAW
|
|
- All legal terms, regulations, and jurisdictions remain GERMAN even when translated to {{targetLanguage}}
|
|
- Company name "Growheads" and German address must remain unchanged
|
|
- All references to German laws (DSGVO, BGB, etc.) must remain as German legal references
|
|
- German court jurisdiction and German legal framework must be preserved
|
|
- The translation is for INFORMATIONAL PURPOSES to help {{targetLanguage}} speakers understand the German legal terms
|
|
|
|
Rules:
|
|
1. Translate only the English strings to {{targetLanguage}}
|
|
2. Drop the comments in output
|
|
3. Maintain the exact JavaScript object structure and formatting
|
|
4. Keep all interpolation variables unchanged
|
|
5. Keep company name "Growheads" unchanged
|
|
6. Keep German address unchanged
|
|
7. Keep German law references (DSGVO, BGB, etc.) unchanged
|
|
8. Keep German court jurisdiction references unchanged
|
|
9. Preserve any special formatting or HTML entities
|
|
10. Return a valid JavaScript object (not JSON) that can be exported
|
|
|
|
IMPORTANT: The {{targetLanguage}} translation should help speakers understand the German legal terms, but the legal validity remains under German law.
|
|
|
|
Here is the English legal document translation file to translate:
|
|
|
|
{{englishFileContent}}
|
|
`;
|
|
|
|
// Function to check if source file is newer than target file
|
|
function isSourceNewer(sourcePath, targetPath) {
|
|
try {
|
|
// If target doesn't exist, source is considered newer
|
|
if (!fs.existsSync(targetPath)) {
|
|
return true;
|
|
}
|
|
|
|
const sourceStats = fs.statSync(sourcePath);
|
|
const targetStats = fs.statSync(targetPath);
|
|
|
|
return sourceStats.mtime > targetStats.mtime;
|
|
} catch (error) {
|
|
console.error(`Error checking file timestamps for ${sourcePath} -> ${targetPath}:`, error.message);
|
|
return true; // Default to translating if we can't check
|
|
}
|
|
}
|
|
|
|
// Function to get files that need translation from German to English
|
|
function getFilesNeedingEnglishTranslation() {
|
|
const filesToTranslate = [];
|
|
|
|
// Check regular translation files
|
|
for (const fileName of TRANSLATION_FILES) {
|
|
const germanFile = path.join(GERMAN_DIR, fileName);
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
|
|
if (!fs.existsSync(germanFile)) {
|
|
console.log(`⚠️ German file not found: ${fileName}`);
|
|
continue;
|
|
}
|
|
|
|
if (isSourceNewer(germanFile, englishFile)) {
|
|
filesToTranslate.push(fileName);
|
|
console.log(`📝 ${fileName} needs German → English translation`);
|
|
}
|
|
}
|
|
|
|
// Check legal files
|
|
for (const fileName of LEGAL_FILES) {
|
|
const germanFile = path.join(GERMAN_DIR, fileName);
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
|
|
if (!fs.existsSync(germanFile)) {
|
|
console.log(`⚠️ German legal file not found: ${fileName}`);
|
|
continue;
|
|
}
|
|
|
|
if (isSourceNewer(germanFile, englishFile)) {
|
|
filesToTranslate.push(fileName);
|
|
console.log(`📋 ${fileName} needs German → English legal translation`);
|
|
}
|
|
}
|
|
|
|
return filesToTranslate;
|
|
}
|
|
|
|
// Function to get files that need translation from English to target language
|
|
function getFilesNeedingTargetTranslation(langCode) {
|
|
const filesToTranslate = [];
|
|
const targetDir = path.join(LOCALES_DIR, langCode);
|
|
|
|
// Check regular translation files
|
|
for (const fileName of TRANSLATION_FILES) {
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
const targetFile = path.join(targetDir, fileName);
|
|
|
|
if (!fs.existsSync(englishFile)) {
|
|
console.log(`⚠️ English file not found: ${fileName}`);
|
|
continue;
|
|
}
|
|
|
|
if (isSourceNewer(englishFile, targetFile)) {
|
|
filesToTranslate.push(fileName);
|
|
console.log(`📝 ${fileName} needs English → ${langCode} translation`);
|
|
}
|
|
}
|
|
|
|
// Check legal files
|
|
for (const fileName of LEGAL_FILES) {
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
const targetFile = path.join(targetDir, fileName);
|
|
|
|
if (!fs.existsSync(englishFile)) {
|
|
console.log(`⚠️ English legal file not found: ${fileName}`);
|
|
continue;
|
|
}
|
|
|
|
if (isSourceNewer(englishFile, targetFile)) {
|
|
filesToTranslate.push(fileName);
|
|
console.log(`📋 ${fileName} needs English → ${langCode} legal translation`);
|
|
}
|
|
}
|
|
|
|
return filesToTranslate;
|
|
}
|
|
|
|
// Function to read and parse JavaScript export file
|
|
function readTranslationFile(filePath) {
|
|
try {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
// Remove the export default and evaluate the object
|
|
const objectContent = content.replace(/^export default\s*/, '').replace(/;\s*$/, '');
|
|
return eval(`(${objectContent})`);
|
|
} catch (error) {
|
|
console.error(`Error reading ${filePath}:`, error.message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Function to write translation file (preserving comments as string)
|
|
function writeTranslationFile(filePath, translationString) {
|
|
try {
|
|
// Ensure directory exists
|
|
const dir = path.dirname(filePath);
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
// Ensure the string has proper export format
|
|
const content = translationString.startsWith('export default')
|
|
? translationString
|
|
: `export default ${translationString}`;
|
|
|
|
// Ensure it ends with semicolon and newline
|
|
const finalContent = content.endsWith(';\n') ? content : content.replace(/;?\s*$/, ';\n');
|
|
|
|
fs.writeFileSync(filePath, finalContent, 'utf8');
|
|
console.log(`✅ Successfully wrote ${filePath}`);
|
|
} catch (error) {
|
|
console.error(`Error writing ${filePath}:`, error.message);
|
|
}
|
|
}
|
|
|
|
// Function to translate content using OpenAI (for German to English)
|
|
async function translateContent(content, systemPrompt, targetLanguage = null, model = 'gpt-5.1') {
|
|
try {
|
|
const prompt = targetLanguage
|
|
? systemPrompt.replace(/{{targetLanguage}}/g, targetLanguage)
|
|
: systemPrompt;
|
|
|
|
const response = await openai.chat.completions.create({
|
|
model: model,
|
|
messages: [
|
|
{ role: 'system', content: prompt },
|
|
{ role: 'user', content: `Please translate this translation file content:\n\n${content}` }
|
|
],
|
|
reasoning_effort: "none",
|
|
});
|
|
|
|
return response.choices[0].message.content;
|
|
} catch (error) {
|
|
console.error('OpenAI API error:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Function to translate English to other languages (optimized for caching)
|
|
async function translateToTargetLanguage(englishContent, targetLanguage, model = 'gpt-4o-mini', isLegalFile = false) {
|
|
try {
|
|
// Choose appropriate system prompt based on file type
|
|
const promptTemplate = isLegalFile
|
|
? LEGAL_ENGLISH_TO_OTHER_SYSTEM_PROMPT_TEMPLATE
|
|
: ENGLISH_TO_OTHER_SYSTEM_PROMPT_TEMPLATE;
|
|
|
|
// Create system prompt with file content (cacheable)
|
|
const systemPrompt = promptTemplate
|
|
.replace(/{{targetLanguage}}/g, targetLanguage)
|
|
.replace(/{{englishFileContent}}/g, englishContent);
|
|
|
|
const response = await openai.chat.completions.create({
|
|
model: model,
|
|
messages: [
|
|
{ role: 'system', content: systemPrompt },
|
|
{ role: 'user', content: `Please translate to ${targetLanguage}` }
|
|
],
|
|
temperature: 0.1,
|
|
max_tokens: 4000
|
|
});
|
|
|
|
return response.choices[0].message.content;
|
|
} catch (error) {
|
|
console.error('OpenAI API error:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Function to extract JavaScript object string from OpenAI response (preserving comments)
|
|
function extractJSObjectString(response) {
|
|
try {
|
|
// Remove code block markers if present
|
|
let cleaned = response.replace(/```javascript|```json|```/g, '').trim();
|
|
|
|
// Try to find the object in the response
|
|
const objectMatch = cleaned.match(/\{[\s\S]*\}/);
|
|
if (objectMatch) {
|
|
return objectMatch[0];
|
|
}
|
|
|
|
// If no object found, return the cleaned response
|
|
return cleaned;
|
|
} catch (error) {
|
|
console.error('Error parsing OpenAI response:', error.message);
|
|
console.log('Response was:', response);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Main translation function for multiple files
|
|
async function translateToEnglish() {
|
|
console.log(`🔄 Step 1: Checking which files need German → English translation...`);
|
|
|
|
const filesToTranslate = getFilesNeedingEnglishTranslation();
|
|
|
|
if (filesToTranslate.length === 0) {
|
|
console.log('✅ All German → English translations are up to date');
|
|
return TRANSLATION_FILES.filter(fileName => fs.existsSync(path.join(ENGLISH_DIR, fileName)));
|
|
}
|
|
|
|
console.log(`🔄 Translating ${filesToTranslate.length} files from German to English using ${GERMAN_TO_ENGLISH_MODEL}...`);
|
|
|
|
// Ensure English directory exists
|
|
if (!fs.existsSync(ENGLISH_DIR)) {
|
|
fs.mkdirSync(ENGLISH_DIR, { recursive: true });
|
|
}
|
|
|
|
// Copy structural files (index.js and translation.js) from German directory
|
|
copyStructuralFiles(ENGLISH_DIR, 'en');
|
|
|
|
const translatedFiles = [];
|
|
|
|
for (const fileName of filesToTranslate) {
|
|
const germanFile = path.join(GERMAN_DIR, fileName);
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
|
|
console.log(`🔄 Translating ${fileName}...`);
|
|
|
|
try {
|
|
// Read German translation file
|
|
const germanContent = fs.readFileSync(germanFile, 'utf8');
|
|
|
|
// Use special legal prompt for legal documents
|
|
const isLegalFile = LEGAL_FILES.includes(fileName);
|
|
const systemPrompt = isLegalFile ? LEGAL_GERMAN_TO_ENGLISH_SYSTEM_PROMPT : GERMAN_TO_ENGLISH_SYSTEM_PROMPT;
|
|
|
|
if (isLegalFile) {
|
|
console.log(`📋 Using special legal document translation prompt for ${fileName}`);
|
|
}
|
|
|
|
const translatedContent = await translateContent(germanContent, systemPrompt, null, GERMAN_TO_ENGLISH_MODEL);
|
|
const englishObjectString = extractJSObjectString(translatedContent);
|
|
|
|
if (englishObjectString) {
|
|
writeTranslationFile(englishFile, englishObjectString);
|
|
translatedFiles.push(fileName);
|
|
console.log(`✅ ${fileName} translated successfully`);
|
|
} else {
|
|
throw new Error(`Failed to parse English translation for ${fileName}`);
|
|
}
|
|
} catch (error) {
|
|
console.error(`❌ Error translating ${fileName}:`, error.message);
|
|
}
|
|
|
|
// Add delay to avoid rate limiting
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
console.log(`✅ German to English translation completed for ${translatedFiles.length} files`);
|
|
|
|
// Return all English files that exist (both newly translated and existing)
|
|
const allFiles = [...TRANSLATION_FILES, ...LEGAL_FILES];
|
|
return allFiles.filter(fileName => fs.existsSync(path.join(ENGLISH_DIR, fileName)));
|
|
}
|
|
|
|
// Function to translate English to other languages (multiple files)
|
|
async function translateToOtherLanguages(availableEnglishFiles) {
|
|
console.log(`🔄 Step 2: Translating English to other languages using ${ENGLISH_TO_OTHER_MODEL}...`);
|
|
|
|
for (const [langCode, langName] of Object.entries(TARGET_LANGUAGES)) {
|
|
console.log(`🔄 Checking ${langName} (${langCode}) translations...`);
|
|
|
|
// Create target language directory if it doesn't exist
|
|
const targetDir = path.join(LOCALES_DIR, langCode);
|
|
if (!fs.existsSync(targetDir)) {
|
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
}
|
|
|
|
// Copy structural files (index.js and translation.js) from German directory
|
|
copyStructuralFiles(targetDir, langCode);
|
|
|
|
const filesToTranslate = getFilesNeedingTargetTranslation(langCode);
|
|
|
|
if (filesToTranslate.length === 0) {
|
|
console.log(`✅ All English → ${langName} translations are up to date`);
|
|
continue;
|
|
}
|
|
|
|
console.log(`🔄 Translating ${filesToTranslate.length} files to ${langName}...`);
|
|
|
|
for (const fileName of filesToTranslate) {
|
|
try {
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
const targetFile = path.join(targetDir, fileName);
|
|
|
|
console.log(`🔄 Translating ${fileName} to ${langName}...`);
|
|
|
|
// Read English file
|
|
const englishContent = fs.readFileSync(englishFile, 'utf8');
|
|
|
|
// Check if this is a legal file
|
|
const isLegalFile = LEGAL_FILES.includes(fileName);
|
|
|
|
if (isLegalFile) {
|
|
console.log(`📋 Using special legal document translation prompt for ${fileName} → ${langName}`);
|
|
}
|
|
|
|
const translatedContent = await translateToTargetLanguage(
|
|
englishContent,
|
|
langName,
|
|
ENGLISH_TO_OTHER_MODEL,
|
|
isLegalFile
|
|
);
|
|
|
|
const translatedObjectString = extractJSObjectString(translatedContent);
|
|
|
|
if (translatedObjectString) {
|
|
// Special handling for locale.js file
|
|
let updatedString = translatedObjectString;
|
|
if (fileName === 'locale.js') {
|
|
updatedString = translatedObjectString.replace(
|
|
/"code":\s*"[^"]*"/,
|
|
`"code": "${getLocaleCode(langCode)}"`
|
|
);
|
|
}
|
|
|
|
writeTranslationFile(targetFile, updatedString);
|
|
console.log(`✅ ${fileName} translated to ${langName}`);
|
|
} else {
|
|
console.error(`❌ Failed to parse ${fileName} translation for ${langName}`);
|
|
}
|
|
|
|
// Add delay to avoid rate limiting
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
} catch (error) {
|
|
console.error(`❌ Error translating ${fileName} to ${langName}:`, error.message);
|
|
}
|
|
}
|
|
|
|
// Add longer delay between languages
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
}
|
|
}
|
|
|
|
// Function to copy index.js and translation.js files from German to target language
|
|
function copyStructuralFiles(targetDir, langCode) {
|
|
const filesToCopy = ['index.js', 'translation.js'];
|
|
|
|
for (const fileName of filesToCopy) {
|
|
const sourceFile = path.join(GERMAN_DIR, fileName);
|
|
const targetFile = path.join(targetDir, fileName);
|
|
|
|
// Only copy if source exists and target doesn't exist or is older
|
|
if (fs.existsSync(sourceFile)) {
|
|
if (!fs.existsSync(targetFile) || isSourceNewer(sourceFile, targetFile)) {
|
|
try {
|
|
fs.copyFileSync(sourceFile, targetFile);
|
|
console.log(`📋 Copied ${fileName} to ${langCode} directory`);
|
|
} catch (error) {
|
|
console.error(`❌ Error copying ${fileName} to ${langCode}:`, error.message);
|
|
}
|
|
}
|
|
} else {
|
|
console.warn(`⚠️ Source file not found: ${sourceFile}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function to get locale codes
|
|
function getLocaleCode(langCode) {
|
|
const localeCodes = {
|
|
'bg': 'bg-BG',
|
|
'cs': 'cs-CZ',
|
|
'es': 'es-ES',
|
|
'fr': 'fr-FR',
|
|
'el': 'el-GR',
|
|
'hr': 'hr-HR',
|
|
'hu': 'hu-HU',
|
|
'it': 'it-IT',
|
|
'pl': 'pl-PL',
|
|
'ro': 'ro-RO',
|
|
'ru': 'ru-RU',
|
|
'sk': 'sk-SK',
|
|
'sl': 'sl-SI',
|
|
'sr': 'sr-RS',
|
|
'sv': 'sv-SE',
|
|
'tr': 'tr-TR',
|
|
'uk': 'uk-UA',
|
|
'ar': 'ar-EG',
|
|
'zh': 'zh-CN'
|
|
};
|
|
return localeCodes[langCode] || `${langCode}-${langCode.toUpperCase()}`;
|
|
}
|
|
|
|
|
|
|
|
// Main execution
|
|
async function main() {
|
|
// Parse command line arguments
|
|
const args = process.argv.slice(2);
|
|
const skipEnglish = args.includes('--skip-english') || args.includes('-s');
|
|
const onlyEnglish = args.includes('--only-english') || args.includes('-e');
|
|
|
|
if (skipEnglish && onlyEnglish) {
|
|
console.error('❌ Cannot use both --skip-english and --only-english flags');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('🚀 Starting translation process...');
|
|
|
|
if (skipEnglish) {
|
|
console.log('⏭️ Skipping German → English translation (using existing English file)');
|
|
} else if (onlyEnglish) {
|
|
console.log('🎯 Only translating German → English (skipping other languages)');
|
|
}
|
|
|
|
// Check if OpenAI API key is set (only if we're doing actual translation)
|
|
if (!skipEnglish && !OPENAI_API_KEY) {
|
|
console.error('❌ OPENAI_API_KEY environment variable is not set');
|
|
console.log('Hint: export `cat ../shopApi/.env |grep OPENAI` ; node translate-i18n.js');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Check if German directory exists (only if we're translating from German)
|
|
if (!skipEnglish && !fs.existsSync(GERMAN_DIR)) {
|
|
console.error(`❌ German translation directory not found: ${GERMAN_DIR}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
let translatedFiles;
|
|
|
|
if (skipEnglish) {
|
|
// Skip German → English, read existing English files
|
|
if (!fs.existsSync(ENGLISH_DIR)) {
|
|
console.error(`❌ English translation directory not found: ${ENGLISH_DIR}`);
|
|
console.log('💡 Run without --skip-english first to generate the English files');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('📖 Reading existing English translation files...');
|
|
translatedFiles = TRANSLATION_FILES.filter(fileName => {
|
|
const englishFile = path.join(ENGLISH_DIR, fileName);
|
|
return fs.existsSync(englishFile);
|
|
});
|
|
console.log(`✅ Found ${translatedFiles.length} English files`);
|
|
} else {
|
|
// Step 1: Translate German to English
|
|
translatedFiles = await translateToEnglish();
|
|
|
|
if (!translatedFiles || translatedFiles.length === 0) {
|
|
console.error('❌ Failed to create English translations, stopping process');
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (onlyEnglish) {
|
|
console.log('🎉 English translation completed! Skipping other languages.');
|
|
} else {
|
|
// Step 2: Translate English to other languages
|
|
await translateToOtherLanguages(translatedFiles);
|
|
console.log('🎉 All translations completed successfully!');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Translation process failed:', error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run the script
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
main();
|
|
}
|
|
|
|
export {
|
|
translateToEnglish,
|
|
translateToOtherLanguages,
|
|
readTranslationFile,
|
|
writeTranslationFile
|
|
};
|