В текущем мире очень многие сайты имеют поддержку многих языков, в большинстве случаев это происходит с помощью i18n npm пакета. Чаще всего переводы хранятся в .js, .json файлах и очень часто есть языки для которых в компании нет переводчика, либо же он не предполагался в целом, и в таком случае приходит на помощь разработчик с Google Translate. И вот однажды я столкнулся с тем, что на проекте оказалось очень много текстов и все их нужно было переводить вручную, что занимало достаточно много времени и я задумался о том, как это можно автоматизировать.

Моя идея была в том, чтобы написать функцию, в которую можно было бы передать языковой код и json объект с текстом на исходном языке, а на выходе получить переведенный json/js file. С помощью этой функции я мог бы в ci/cd Pipeline переводить все текста на проекте, в исходных текстах которых были изменения, либо же следить за текстами в рантайме и на лету переводить их.

И я нашел два относительно простых метода, для того чтобы это сделать, один из них платный, другой бесплатный.

Способ №1

Я думаю у многих в компании сейчас активно используются всякие ИИ чат-боты в духе chatgpt и тд, и у многих из них есть api, в которых вы можете получить api key и с помощью него отправлять ему запросы. В моем случае я использовал chatgpt от OpenAI и у них есть специальный npm пакет для node js - тык, с помощью которого можно взаимодействовать с chat ботом, вот и тут я подключаю эту библиотеку и отправляю запрос со следующим prompt - translate object values to ${language} ${JSON.stringify(text)}, где language - языковой код нужного вам языка(языковые коды - тык), text - наш объект с переводами.

translate.js

const { Configuration, OpenAIApi } = require('openai');
const fs = require('fs');
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});

const openai = new OpenAIApi(configuration);
async function getTranslation(languageCode, text) {
  try {
    const result = await openai.createChatCompletion({
      model: 'gpt-3.5-turbo',
      messages: [{ role: 'user', content: `translate object values to ${languageCode} ${JSON.stringify(text)}` }],
    });

    return result.data.choices[0].message.content;
  } catch (error) {
    console.error(error);

    return null;
  }
};

getTranslation('zh', {
  label: 'Article about translation',
  title: 'Easy way to implement i18n',
  description: 'Try to translate this description',
}).then((result) => {
  fs.writeFileSync('cn.json', result);
});

module.exports = getTranslation;

Как итог мы получаем переведенный json и можем записать его в нужный нам файл.

Способ №2

Абсолютно бесплатный метод, в котором я использую другую библиотеку - тык, совершенно случайно наткнулся на эту библиотеку на GitHub и решил попробовать ее, по мне работает неплохо - она использует Google Translate. Здесь я реализую аналогичную функцию, за исключением того, что тут я не могу передать весь объект для перевода, поэтому здесь перебирается все значения в объекте и по очереди переводятся.

translate.js

const translate = require('node-google-translate-skidz');
const fs = require('fs');

async function getTranslation(languageCode, text) {
  const getTranslate = async (value) => {
    const t = await translate({
      text: value,
      source: 'en',
      target: languageCode,
    });
    return t.translation;
  };

  const processObject = async (obj) => {
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        const value = obj[key];
        if (typeof value === 'object') {
          await processObject(value);
        } else {
          try {
            const processedValue = value ? await getTranslate(value) : value;
            obj[key] = processedValue;
          } catch (error) {
            console.error(error);
            obj[key] = value;
          }
        }
      }
    }
  };

  const copy = JSON.parse(JSON.stringify(text));
  await processObject(copy);

  return JSON.stringify(copy, null, 2);
};

getTranslation('zh', {
  label: 'Article about translation',
  title: 'Easy way to implement i18n',
  description: 'Try to translate this description',
}).then((result) => {
  fs.writeFileSync('cn.json', result);
});

module.exports = getTranslation;

На выходе также получаем переведенный json файл.

Итого

У меня получился вот такой скрипт, в который я могу прокинуть файл откуда прочитать перевод и куда его записать, также здесь я сделал проверку на то, .json файл это или .js и написал парсер для этого:

const fs = require('fs');
const getTranslation = require('./translate.js');

// .js file имеет вид export const ${languageCode} = { ... }, соответственно для того, чтобы получить контент можно взять все в {} и с помощью eval(я знаю что eval это плохо) преобразовать это в js объект
const parseScriptFile = (filePath) => {
  const fileData = fs.readFileSync(filePath, 'utf-8');
  const jsonStartIndex = fileData.indexOf('{');
  const jsonEndIndex = fileData.lastIndexOf('}');
  const jsonObjectString = fileData.slice(jsonStartIndex, jsonEndIndex + 1);
  const obj = eval(`(${jsonObjectString})`);
  return obj;
};

const languageCode = 'zh';
const filePath = './en.js';
const destinationFilePath = './zh.js';
// Проверяю .js это файл или .json и по разному их обрабатываю
const text = filePath.includes('.json') ? require(filePath) : parseScriptFile(filePath);

getTranslation(languageCode, text).then((res) => {
  if (filePath.includes('.json')) {
    fs.writeFileSync(destinationFilePath, JSON.stringify(res, null, 2));
  } else {
    fs.writeFileSync(destinationFilePath, `export const ${languageCode} = ${JSON.stringify(res, null, 2)}`);
  }
});

Далее вы можете пропатчить эти скрипты в зависимости от ваших потребностей и получить автоматизированные и удобные переводы во Frontend.

Наслаждайтесь :)

Если статья показалась вам интересной, то у меня есть Тг-канал, где я пишу про новые технологии во фронте, делюсь хорошими книжками и интересными статьями других авторов.

Комментарии (6)


  1. Vorchun
    31.07.2023 09:46

    Автоматизировали - это хорошо, способов много разных. А как с качеством? Оцениили / сравнили результат "на адекватность" в первом (ИИ) и втором (онлайн переводчик) случаях?


    1. Dragonek Автор
      31.07.2023 09:46
      -1

      Я сравнивал все это с Google Translate и при переводе в обратную сторону он выдает то, что и должно быть + примерно в 60% случаев текст переводился точно также как в Google Translate в браузере, применимо для обоих случаев.


  1. ingumsky
    31.07.2023 09:46
    +1

    Такой способ подойдёт для домашней странички, но всерьёз рассчитывать на то, что с его помощью вы сможете локализовать свой фронтенд/сервис на разные языки, — очень наивно. Это я вам как человек, который десять лет работает в локализации, скажу.

    Ну и, разумеется, проверка в духе — «я перевёл это с помощью того же сервиса обратно и получилось то же самое» — это отсутствие проверки. Не говоря уж о том, что в вашем случае даже такая «проверка» даёт результат в «±60% случаев».


    1. Dragonek Автор
      31.07.2023 09:46

      Мне кажется этот способ неплох для MVP или стартапов поначалу, потому что не всегда есть возможность нанять переводчика, а иногда очень хочется начать выходить на какой-то рынок и индексироваться, пусть и не с идеально переведенным продуктом.

      Согласен, что проверка не является объективной, но к сожалению, оценить как-либо по-другому довольно трудно и не уверен, что возможно)


  1. interhin
    31.07.2023 09:46

    Тогда уж легче не морочиться с этим и просто автоматический перевод в браузере использовать)


  1. saifutdinov_a
    31.07.2023 09:46

    В некоторых случаях важно переводить фразы в контексте, потому что, например с русского языка *загрузить" на английский перевести и как "Upload" и как "Download". Интересно, как оба способа справляются с "двойными смыслами"?