😀

多言語対応がめんどくさいからChatGPTにやらせてみた(1日クッキング)

2023/12/22に公開

はじめに

Next.js で構築しているサービスを多言語対応させたくなった。

でも、めんどくさい事はやりたくないし、翻訳精度も高精度がいい。

CSR にも SSG にも対応させたい。

そうだ、ChatGPT に任せてみよう。

目標

こんな感じで、決められたコンポーネントでテキストを包むだけで、自動的にChatGPTに翻訳してほしい

const Test = () => {
  return <GlobalText>快適にご利用いただくために</GlobalText>
}

多言語対応辞書生成モジュール を作成する感じになりそう
辞書さえ生成できればあとはどうとでもなるからね

JSX(TSX)の探索

glob で対象ファイルを検索

const paths = await glob(`${translateTargetDir}/**/*.+(tsx|jsx)`);

@babel/parser と @babel/traverse で、JSXを解析しつつ
"GlobalText" コンポーネントを探し、その中のテキストだけ取ってくる

  const targetTexts: string[] = [];
  
  paths.forEach(file => {
    const content = fs.readFileSync(file, 'utf-8');
    const ast = parser.parse(content, {
      sourceType: 'module',
      plugins: ['jsx', 'typescript']
    });

    traverse(ast, {
      JSXElement(path) {
        if (
          'name' in path.node.openingElement.name &&
          path.node.openingElement.name.name === 'GlobalText'
        ) {
          path.node.children.forEach(child => {
            if (child.type === 'JSXText') {
              const text = normalizeString(child.value);
              targetTexts.push(text);
              console.info('found text: ', text, text.length);
            }
          });
        }
      }
    });
  });

翻訳

取得した文字列の配列を、自前で構築した ChatGPT サーバーに投げ、返却された翻訳結果でjsonファイルを作成する

ちなみに、ChatGPT のモデルは 'gpt-3.5-turbo' を使うと、こちらが希望する形式で返却してくれないことが多々あったので、gpt-4 turbo(gpt-4-1106-preview) を使用した。

req

{
    "text": "[テストです, こんにちは]"
}

res

{
    "content": "{\"en\": [\"It's a test\", \"Hello\"], \"ko\": [\"테스트입니다\", \"안녕하세요\"]}",
    "usage": {
        "prompt_tokens": 319,
        "completion_tokens": 28,
        "total_tokens": 347
    }
}

作成するjson ファイルの形式はこんな感じ

export interface Output {
  [hash: string]: {[lang: string]: string};
}

ポイントは、"GlobalText" コンポーネントで括った、「翻訳元の日本語」を sha-256 でハッシュ化して、json のキーにすること。

辞書ファイルとして書き込み

const writeOutputs = (globalTextMap: Output, outputTargetDir: string) => {
  const globalTextMapCacheOutput = `${JSON.stringify(globalTextMap)}`;

  fs.writeFileSync(
    `${outputTargetDir}/${CACHE_FILENAME}`,
    globalTextMapCacheOutput,
    'utf8'
  );
};

こんな感じの出力になる

{
  "f1b04f77514c350cc6d69ff2847e1c211790e470ff91f34bf0a3226ad5e7e464": {
    "en": "For your comfortable use",
    "ko": "편안한 이용을 위하여"
  },
  "f68d602db234c10114afd38158e3e16ae2c276887abbdac716096b39ce0c110e": {
    "en": "There is a possibility that Bluetooth earphones may not work properly",
    "ko": "블루투스 이어폰은 제대로 들리지 않을 수 있습니다"
  },
  "40e1fe4392655a130f715a52fd8a66f738db8d6007aa9ca93f483a2cfd85e359": {
    "en": "We recommend closing other tabs and background apps",
    "ko": "다른 탭이나 백그라운드 앱을 종료하는 것이 좋습니다"
  }
  etc .......
}

基本的に必要な事はこれだけ
あとはモジュール化して 別プロジェクトで yarn add でインポートができる様にして、shell で コマンド実行すれば、辞書ファイルの生成ができる様にした

npm-scripts

{
  "scripts": {
    "gtb": "create-global-txt 'https://xxxxxx' './src/constants/globalTxtBuilder/outputs' './src'",
    "build:gtb": "npm run gtb && NEXT_PUBLIC_ENV=prd NEXT_PUBLIC_BUILD_LANG=en next build"
  }
}

自社サービスで確かめてみる

このモーダルのテキスト達を "GlobalText" コンポーネントで囲ってみる

おお、ちゃんと翻訳された

あとがき

ChatGPT すげえ

1日でこんなのができる時代になったんだね

今回作った多言語対応辞書生成モジュールはこちら
https://github.com/m-lab-inc/global-txt-builder

Discussion