DEV Community

Cover image for Automate Multilingual Translations in Frontends with OpenAI
Daniel Klug Gareis for Cloud(x);

Posted on

4

Automate Multilingual Translations in Frontends with OpenAI

Implementing multilingual support in frontend applications usually involves repetitive tasks, especially when manually translating multiple JSON files. In this article, we'll show you how to simplify and automate this process using the OpenAI API and its Structured Output capability.

📌 Step by Step Guide

Below you'll find each step clearly explained with practical JavaScript examples.

🔑 OpenAI Configuration and Initialization

First, configure the OpenAI API:

import OpenAI from "openai";

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});
Enter fullscreen mode Exit fullscreen mode

📖 Reading the Base English File

Load the base file containing the English translations (en.json):

import fs from 'fs/promises';
import path from 'path';

const localesDir = "src/locales";
const englishLocalesPath = path.join(localesDir, "en.json");
const englishLocales = JSON.parse(await fs.readFile(englishLocalesPath, "utf-8"));
Enter fullscreen mode Exit fullscreen mode

🔍 Generate a Checksum to Detect Changes

Use a checksum to identify changes in the translations file:

const checksum = Crypto.generateChecksum({ obj: englishLocales });
Enter fullscreen mode Exit fullscreen mode

⚠️ Check for Changes in Existing Translations

Compare the current checksum with a previously saved one:

const checksumPath = path.join(localesDir, "checksum.txt");
let savedChecksum;

try {
  savedChecksum = await fs.readFile(checksumPath, "utf-8");
} catch {
  savedChecksum = null;
}

if (savedChecksum !== checksum) {
  // Proceed with translations.
}
Enter fullscreen mode Exit fullscreen mode

🌐 Automatic Translation using OpenAI Structured Output

Use the OpenAI API to automatically translate locales, ensuring they adhere to a precise structure via JSON Schema:

const translateLocale = async ({ language, obj }) => {
  const jsonSchema = {
    type: "json_schema",
    json_schema: {
      name: "locales_response",
      schema: {
        type: "object",
        properties: Object.keys(obj).reduce((acc, key) => {
          acc[key] = { type: "string" };
          return acc;
        }, {}),
        required: Object.keys(obj),
        additionalProperties: false,
      },
      strict: true,
    },
  };

  const response = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    temperature: 0,
    messages: [
      { role: "system", content: `Translate the values of the object using the language code: ${language}` },
      { role: "user", content: JSON.stringify(obj) },
    ],
    response_format: jsonSchema,
  });

  return JSON.parse(response.choices[0].message.content);
};
Enter fullscreen mode Exit fullscreen mode

📁 Automatic Saving to JSON Files

Finally, save the generated translations into separate JSON files for each language:

translations.unshift(englishLocales); // Include English

await Promise.all(
  languages.map((lang, index) =>
    fs.writeFile(path.join(localesDir, `${lang}.json`), JSON.stringify(translations[index], null, 2), "utf-8")
  )
);

await fs.writeFile(checksumPath, checksum, "utf-8");
Enter fullscreen mode Exit fullscreen mode

✅ Complete Ready-to-Use Code

Below is the complete integrated code ready to use in your project:

import OpenAI from "openai";
import fs from 'fs/promises';
import path from 'path';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const autoTranslateLocales = async () => {
  const languages = ["en", "es", "fr", "de"];
  const localesDir = "src/locales";
  const englishLocalesPath = path.join(localesDir, "en.json");

  const englishLocales = JSON.parse(await fs.readFile(englishLocalesPath, "utf-8"));
  const checksum = Crypto.generateChecksum({ obj: englishLocales });
  const checksumPath = path.join(localesDir, "checksum.txt");

  let savedChecksum;
  try {
    savedChecksum = await fs.readFile(checksumPath, "utf-8");
  } catch {
    savedChecksum = null;
  }

  if (savedChecksum !== checksum) {
    const translations = await Promise.all(
      languages.filter(lang => lang !== "en").map(lang =>
        translateLocale({ language: lang, obj: englishLocales })
      )
    );

    translations.unshift(englishLocales);

    await Promise.all(
      languages.map((lang, index) =>
        fs.writeFile(path.join(localesDir, `${lang}.json`), JSON.stringify(translations[index], null, 2), "utf-8")
      )
    );

    await fs.writeFile(checksumPath, checksum, "utf-8");
  }
};

const translateLocale = async ({ language, obj }) => {
  const jsonSchema = {
    type: "json_schema",
    json_schema: {
      name: "locales_response",
      schema: {
        type: "object",
        properties: Object.keys(obj).reduce((acc, key) => {
          acc[key] = { type: "string" };
          return acc;
        }, {}),
        required: Object.keys(obj),
        additionalProperties: false,
      },
      strict: true,
    },
  };

  const response = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    temperature: 0,
    messages: [
      { role: "system", content: `Translate the values of the object using the language code: ${language}` },
      { role: "user", content: JSON.stringify(obj) },
    ],
    response_format: jsonSchema,
  });

  return JSON.parse(response.choices[0].message.content);
};
Enter fullscreen mode Exit fullscreen mode

🎯 Benefits of Automating Your Translations

  • Automation: Avoid manual translation each time you change or add text.
  • Consistency: Ensure updated and uniform translations.
  • Efficiency: Speed up the development and deployment of your application.

Heroku

Deploy with ease. Manage efficiently. Scale faster.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)