Machine Translation Integration — i18n

Machine Translation Integration Machine Translation (MT) bisa mempercepat proses terjemahan secara drastis. Tapi MT bukan pengganti human translator — workflow

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

ProviderKelebihanPricing
DeepLKualitas terbaik untuk bahasa Eropa$25/1M chars
Google Translate500+ bahasa, termasuk bahasa langka$20/1M chars
Azure TranslatorCustom training, enterprise features$10/1M chars
Amazon TranslateAWS ecosystem integration$15/1M chars
Claude/GPTContext-aware, bisa terima instruksi gaya bahasaVaries

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;
}

Yang akan kamu pelajari