Machine Translation Integration
Machine Translation (MT) bisa mempercepat proses terjemahan secara drastis. Tapi MT bukan pengganti human translator — workflow terbaik adalah MT + Post-editing.
Provider Populer
| Provider | Kelebihan | Pricing |
|---|---|---|
| DeepL | Kualitas terbaik untuk bahasa Eropa | $25/1M chars |
| Google Translate | 500+ bahasa, termasuk bahasa langka | $20/1M chars |
| Azure Translator | Custom training, enterprise features | $10/1M chars |
| Amazon Translate | AWS ecosystem integration | $15/1M chars |
| Claude/GPT | Context-aware, bisa terima instruksi gaya bahasa | Varies |
DeepL API Integration
// Node.js: translate file terjemahan
import * as deepl from "deepl-node";
const translator = new deepl.Translator(process.env.DEEPL_API_KEY);
async function translateFile(sourceFile, targetLang) {
const source = JSON.parse(fs.readFileSync(sourceFile, "utf-8"));
const result = {};
for (const [key, value] of Object.entries(source)) {
if (typeof value === "string") {
// Skip interpolation variables
const cleaned = value.replace(/\{\{(\w+)\}\}/g, "<x id=\"$1\"></x>");
const { text } = await translator.translateText(
cleaned, "en", targetLang
);
result[key] = text.replace(/<x id="(\w+)"><\/x>/g, "{{$1}}");
} else if (typeof value === "object") {
result[key] = await translateNested(value, targetLang);
}
}
return result;
}
// Usage
const translated = await translateFile(
"locales/en/common.json", "id"
);
fs.writeFileSync("locales/id/common.json", JSON.stringify(translated, null, 2));
Post-editing Workflow
// Workflow: MT → Review → Approve
//
// 1. Developer menambah string baru (en)
// 2. CI trigger MT untuk semua target locale
// 3. MT result masuk ke TMS dengan status "machine_translated"
// 4. Human translator review & post-edit
// 5. Status berubah ke "reviewed"
// 6. PR dibuat otomatis
// Crowdin: enable MT pre-translation
// Project Settings → Machine Translation → Enable → DeepL
// Pre-translation: "Translate untranslated strings via MT"
LLM-based Translation
// Menggunakan Claude/GPT untuk terjemahan context-aware
async function translateWithLLM(strings, targetLang, context) {
const prompt = `Translate the following UI strings from English to ${targetLang}.
Context: This is a web development learning platform.
Rules:
- Keep technical terms in English (API, HTML, CSS, etc.)
- Maintain interpolation variables like {{name}} as-is
- Use formal but friendly tone
- Keep translations concise (UI space is limited)
Strings to translate:
${JSON.stringify(strings, null, 2)}
Return as JSON with the same keys.`;
const response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
messages: [{ role: "user", content: prompt }],
});
return JSON.parse(response.content[0].text);
}
Quality Assurance
// Automated QA checks setelah MT
function validateTranslation(source, translated) {
const issues = [];
// Cek interpolation variables masih ada
const sourceVars = source.match(/\{\{(\w+)\}\}/g) || [];
const transVars = translated.match(/\{\{(\w+)\}\}/g) || [];
if (sourceVars.join(",") !== transVars.join(",")) {
issues.push("Missing/extra interpolation variables");
}
// Cek panjang (terjemahan biasanya 20-40% lebih panjang)
const ratio = translated.length / source.length;
if (ratio > 3 || ratio < 0.3) {
issues.push(`Suspicious length ratio: ${ratio.toFixed(1)}x`);
}
// Cek HTML tags masih valid
const sourceTags = source.match(/<[^>]+>/g) || [];
const transTags = translated.match(/<[^>]+>/g) || [];
if (sourceTags.length !== transTags.length) {
issues.push("HTML tag mismatch");
}
return issues;
}