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

📖 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"));

🔍 Generate a Checksum to Detect Changes

Use a checksum to identify changes in the translations file:

const checksum = Crypto.generateChecksum({ obj: englishLocales });

⚠️ 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.
}

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

📁 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");

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

🎯 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.