PythonとChatGPT APIでExcelを翻訳する方法【2026年版・動くコード付き】

Translate Excel ChatGPT

最終更新: 2026年6月 — OpenAI Python SDK v1.x と Chat Completions API で動作確認済み。

本記事ではシンプルで広く使われている Chat Completions API を使います。新規アプリケーションでは、OpenAI の Responses API や structured outputs(構造化出力)も検討するとよいでしょう。

Excelを翻訳する2つの方法

コードを書き始める前に、自分にどちらが向いているかを正直に整理しておきましょう。

  • Pythonでスクリプトを書く(本記事)。 大量のファイルをまとめて翻訳したい、定期実行したい、既存のパイプラインに組み込みたい場合に最適です。OpenAIのAPIキーと基本的なPythonの知識が必要です。
  • できあいのツールを使う。 今すぐ1ファイルを翻訳したいだけなら、グラフ・数式・書式を自動で保持してくれるDoc2LangのExcel翻訳ツールにアップロードするほうが速く、コードも一切要りません。

本記事はPythonでの方法に絞り、そのままコピーして動く完全なコードを示します。あわせて、自作した場合にどこでつまずきやすいかも具体的に指摘するので、納得して選べます。記事の終盤に比較表も用意しました。

準備するもの

始める前に、次のものを用意してください。

  • Pythonの基礎知識。 コードが出てきます。基礎が分かっていると有利ですが、各ステップは解説します。
  • Pythonのインストール。 未インストールなら公式サイトからダウンロードしてください。
  • pip。 Pythonライブラリを導入するツールです。Python 3が入っていれば、ほぼ確実にpipも使えます。
  • OpenAIのAPIキー。 OpenAIアカウントのダッシュボードで発行します。同じキーで現行の全モデル(gpt-4ogpt-4o-miniなど)を利用できます。
  • 翻訳したいExcelファイル。 対象の.xlsxファイルを準備しておきます。

APIキーは環境変数に設定し、コード内に直接書かないようにしましょう。

macOS / Linux:

export OPENAI_API_KEY="your_api_key_here"

Windows PowerShell:

$env:OPENAI_API_KEY="your_api_key_here"

.xlsxファイルの中身(読み飛ばし可)

Excelで.xlsxとして保存したファイルは、実際には複数のファイルを1つにまとめたアーカイブです。この形式はOpenXMLと呼ばれます。気になる方は拡張子を.zipに変えて展開すると、中身を覗けます。

  • xl/worksheets/ — シートごとのXMLファイル(sheet1.xmlsheet2.xml…)。行・列・セルの実データはここにあります。
  • xl/styles.xml — ワークブックで使われるすべてのスタイル。どのセルが太字か、青いか、通貨書式か、といった情報が定義されています。
  • xl/sharedStrings.xml — 容量節約のため、Excelは重複する文字列を1度だけ保存し、使う場所から参照します。「合計」が1,000回出てきても、本体は1つだけです。
  • xl/workbook.xml — いわば目次。どのシートがあるか、その順序、シート保護などの属性が記されています。

openpyxlのようなライブラリは、こうした詳細をほとんど隠してくれます。ただ構造を知っておくと、高度な操作やトラブル対応のときに役立ちます。

解凍したreport.xlsxの中身を表示したWindowsエクスプローラー

report.xlsx を解凍したところ。ワークシート・共有文字列・スタイル・ワークブック構造は、zip内のXMLファイルにすぎません。

openpyxlでExcelを読み書きする

openpyxlは、Excelファイル(.xlsx.xlsm.xltx.xltm)の読み書きに特化したPythonライブラリです。シートやセルを直接操作できます。

最初にはっきりさせておきます。openpyxlはセル単位の操作には優れていますが、Excelのレイアウトを完全再現するエンジンではありません。図形、一部の画像、グラフ、マクロ、1つのセル内のリッチテキストなどは、ファイルを開いて再保存すると保持されないことがあります。マクロ有効の.xlsmファイルは load_workbook(..., keep_vba=True) で読み込み、.xlsmとして保存し直してください。そうしないとマクロが失われることがあります。これらの限界については最後にあらためて触れます。

1. openpyxlのインストール

pip install openpyxl

2. 基本となる概念

いくつかの概念がそのままopenpyxlの操作に対応します。

Workbook(ワークブック) — Excelファイル全体のこと。

from openpyxl import load_workbook
 
workbook = load_workbook(filename="sample.xlsx")

Sheet(シート) — ワークブックには1つ以上のシートが含まれます。

sheet = workbook.active            # アクティブなシート
another_sheet = workbook["Sheet2"]  # 名前で指定したシート

Cell(セル) — 行と列が交わる場所。データが入るところです。

cell_value = sheet["A1"].value   # 読み取り
sheet["B1"] = "Hello, Excel!"    # 書き込み

行と列 — 簡単に反復処理できます。

for row in sheet.iter_rows(values_only=True):
    for value in row:
        print(value)

OpenAI APIで翻訳する

openpyxlでデータを読み込んだら、次はOpenAI APIで翻訳します。

1. OpenAI Pythonライブラリのインストール

pip install openai

2. 最新の翻訳関数(2026年版)

import os
from openai import OpenAI
 
# キーは環境変数から読み込む——スクリプトに直接書かないこと。
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
 
def translate_text(text, target_lang="Japanese"):
    response = client.chat.completions.create(
        model="gpt-4o-mini",  # 高速・低コスト。品質重視なら "gpt-4o" を使う
        messages=[
            {
                "role": "system",
                "content": (
                    f"You are a professional translator. Translate the user's text "
                    f"into {target_lang}. Return only the translation, with no extra commentary."
                ),
            },
            {"role": "user", "content": text},
        ],
    )
    return response.choices[0].message.content.strip()

注意: 古いチュートリアルの多くは openai.ChatCompletion.create()model="gpt-4" を使っています。これは1.0より前のSDKの書き方で、openai>=1.0 では動きません。上のコードは現行の client.chat.completions.create() を使っています。コストと速度を重視するなら gpt-4o-mini、翻訳品質を最優先するなら gpt-4o を選びましょう。

3. まずは素朴な実装

最もよくあるチュートリアルの書き方は、全セルをループして1つずつ上書きするものです。

from openpyxl import load_workbook
 
workbook = load_workbook(filename="your_file.xlsx")
 
for sheet in workbook.worksheets:
    for row in sheet.iter_rows():
        for cell in row:
            if isinstance(cell.value, str):
                cell.value = translate_text(cell.value)
 
workbook.save("your_translated_file.xlsx")

デモでは動きますが、実際のシートでは問題が起きます。セルごとにAPIを呼ぶので遅くて高コスト、数式まで翻訳して壊してしまう、レート制限への対策もない——以下で順に解決します。

実務で使えるように改善する

1. 数式は翻訳しない

=SUM(A1:A10) のような数式を翻訳すると、シートが壊れます。数式・空セル・テキスト以外の値はスキップしましょう。

def is_translatable(cell):
    # 空セル・数値・数式セルはスキップ
    value = cell.value
    return (
        isinstance(value, str)
        and value.strip() != ""
        and cell.data_type != "f"   # "f" = 数式
    )

openpyxlは cell.value しか書き換えないため、テキスト以外のセルに触れなければ、数値書式・フォント・塗りつぶしなどのスタイルはほぼそのまま保たれます。

2. 重複文字列をキャッシュしてコストを下げる

シートには同じラベル(「合計」「日付」、部署名など)が何度も出てきます。同じ文字列は1回だけ翻訳しましょう。

cache = {}
 
def translate_cached(text, target_lang="Japanese"):
    if text not in cache:
        cache[text] = translate_text(text, target_lang)
    return cache[text]

これだけで、一般的なレポートならAPIコール数——そして料金——を大きく削減できます。

3. 複数セルをまとめて1回のリクエストに

遅さの最大の原因は「1セル=1API呼び出し」です。複数の文字列を1回のリクエストで送り、結果を確実に対応づけられるようJSONで返させましょう。

import json
 
def translate_batch(texts, target_lang="Japanese"):
    numbered = {str(i): t for i, t in enumerate(texts)}
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": (
                    f"You are a professional translator. Translate each value in the "
                    f"JSON object into {target_lang}. Keep the same keys. "
                    f"Return only a JSON object."
                ),
            },
            {"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
        ],
        response_format={"type": "json_object"},
    )
    result = json.loads(response.choices[0].message.content)
    return [result[str(i)] for i in range(len(texts))]

4. レート制限時はリトライ(指数バックオフ)

レート制限に当たっても落とさず、待ち時間を倍にしながら再試行します。

import time
 
def with_retry(func, *args, retries=5, **kwargs):
    for attempt in range(retries):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            wait = 2 ** attempt
            print(f"Error: {e}. Retrying in {wait}s...")
            time.sleep(wait)
    raise RuntimeError("Translation failed after several retries.")

5. 信頼できないファイルを安全に扱う

他人がアップロードしたExcelファイルを処理する場合は、悪意あるXMLへの対策をしましょう。defusedxmlをインストールしておくと、openpyxlが存在を検知して自動的に利用します。読み込む前にファイルのサイズと種類も検証してください。

pip install defusedxml

自分で作ったファイルなら任意ですが、自分で作成していないファイルを扱うなら強く推奨します。

完成版スクリプト

ここまでを1つにまとめた、そのまま動くスクリプトです。ユニークな文字列を集め、リトライ付きでバッチ翻訳し、結果をキャッシュし、数式をスキップして、新しいファイルに保存します(元ファイルは安全なまま)。

import json
import os
import time
from openai import OpenAI
from openpyxl import load_workbook
 
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
 
TARGET_LANG = "Japanese"
MODEL = "gpt-4o-mini"   # 品質重視なら "gpt-4o"
BATCH_SIZE = 40
 
 
def is_translatable(cell):
    value = cell.value
    return (
        isinstance(value, str)
        and value.strip() != ""
        and cell.data_type != "f"   # "f" = 数式
    )
 
 
def translate_batch(texts, target_lang=TARGET_LANG, retries=5):
    numbered = {str(i): t for i, t in enumerate(texts)}
    system = (
        f"You are a professional translator. Translate each value in the JSON object "
        f"into {target_lang}. Keep the same keys. Return only a JSON object."
    )
    for attempt in range(retries):
        try:
            response = client.chat.completions.create(
                model=MODEL,
                messages=[
                    {"role": "system", "content": system},
                    {"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
                ],
                response_format={"type": "json_object"},
            )
            result = json.loads(response.choices[0].message.content)
            return [result[str(i)] for i in range(len(texts))]
        except Exception as e:
            wait = 2 ** attempt
            print(f"Error: {e}. Retrying in {wait}s...")
            time.sleep(wait)
    raise RuntimeError("Translation failed after several retries.")
 
 
# 1. ワークブックを読み込む
workbook = load_workbook(filename="your_file.xlsx")
 
# 2. 翻訳対象のユニークな文字列を集める
unique_texts = set()
for sheet in workbook.worksheets:
    for row in sheet.iter_rows():
        for cell in row:
            if is_translatable(cell):
                unique_texts.add(cell.value)
unique_texts = list(unique_texts)
 
# 3. バッチで翻訳し、{原文: 訳文} のキャッシュを作る
cache = {}
for start in range(0, len(unique_texts), BATCH_SIZE):
    chunk = unique_texts[start:start + BATCH_SIZE]
    cache.update(dict(zip(chunk, translate_batch(chunk))))
 
# 4. 数式やスタイルに触れず、訳文だけ書き戻す
for sheet in workbook.worksheets:
    for row in sheet.iter_rows():
        for cell in row:
            if is_translatable(cell):
                cell.value = cache[cell.value]
 
# 5. 新しいファイルに保存
workbook.save("your_translated_file.xlsx")
print("Done!")

100行足らずで、速く・数式に安全で・セルごとに呼ぶ版よりずっと安い、実用的な翻訳ツールができました。

任意:実運用向けの堅牢化

上のスクリプトでも十分実用的です。さらに大規模・定期的な処理では、次の3つの安全策が役立ちます。

すべての例外を握りつぶさない。 あらゆる例外で再試行すると、APIキーの誤りやモデル名の間違いまで5回リトライしてしまいます。再試行はレート制限のときだけにして、それ以外は即座に失敗させましょう。

from openai import RateLimitError
 
def translate_batch(texts, target_lang=TARGET_LANG, retries=5):
    numbered = {str(i): t for i, t in enumerate(texts)}
    system = (
        f"You are a professional translator. Translate each value in the JSON object "
        f"into {target_lang}. Keep the same keys. Return only a JSON object."
    )
    for attempt in range(retries):
        try:
            response = client.chat.completions.create(
                model=MODEL,
                messages=[
                    {"role": "system", "content": system},
                    {"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
                ],
                response_format={"type": "json_object"},
            )
            result = json.loads(response.choices[0].message.content)
            missing = [str(i) for i in range(len(texts)) if str(i) not in result]
            if missing:
                raise ValueError(f"Missing translations for keys: {missing}")
            return [result[str(i)] for i in range(len(texts))]
        except RateLimitError:
            wait = 2 ** attempt
            print(f"Rate limited. Retrying in {wait}s...")
            time.sleep(wait)
    raise RuntimeError("Translation failed after several retries.")

このバージョンは、渡したキーがすべて返ってきたかも検証します。応答が途中で切れたり壊れたりした場合に、セルを黙って取りこぼさず、はっきりエラーで止まります。

重複除去では順序を保つ。 set ではなく順序を保った重複除去を使うと、ログやエラーメッセージが予測しやすくなります。

# 旧: unique_texts = list(unique_texts)  (set を使用)
unique_texts = list(dict.fromkeys(collected_texts))

Python自作 vs Doc2Lang:どちらを選ぶ?

自作は強力ですが、限界もあります。正直に比較します。

Python自作Doc2Lang
書式・グラフの保持自前で対処が必要・壊れやすい自動で保持
数式の扱いスキップ条件を自分で書く自動でスキップ
必要なものOpenAI APIキー+コーディングアップロードのみ
向いている人大量・定期処理を自動化したい開発者すぐ1ファイル翻訳したい人
Doc2Langで書式を保ったまま翻訳された製品仕様シート

Doc2Langで翻訳した製品仕様シート——表・列・色・シートタブまで、原本どおりに保持されています。

Excel翻訳ツールを試す — APIキー不要、コード不要。

目安はこうです。定期的に自動化したいなら上のスクリプトを作る。今すぐコードなしで1ファイル訳したいならExcel翻訳ツールを使う——アップロードして翻訳、ダウンロード、書式はそのまま。

関連ガイド

よくある質問(FAQ)

レート制限のエラーが出たら?
OpenAIはアカウントの利用枠に応じてレート制限を設けています。上で示した指数バックオフのリトライを使う、バッチサイズを小さくする、大量に処理するなら利用枠を上げる、のいずれかで対処します。

複数の言語へ同時に翻訳するには?
対象言語のリストをループし、言語ごとに処理を1回ずつ実行して、それぞれ別ファイル(例:report_ja.xlsxreport_de.xlsx)に保存します。

OpenAI APIの利用には費用がかかりますか?
はい。使用トークン量に応じた従量課金です。上で紹介した重複文字列のキャッシュとバッチ送信で費用を抑えられます。日常的な翻訳なら、gpt-4o-miniは大きいモデルより大幅に安価です。

書式や数式は保持されますか?
このスクリプトはテキストセルの値しか変更しないため、基本的なセルのスタイル(フォント・塗りつぶし・罫線・配置・数値書式)はおおむね保持され、数式はスキップされます。ただし、openpyxlはExcelのレイアウトを完全再現するエンジンではありません。マクロ・図形・グラフ・画像・1つのセル内のリッチテキスト・複雑なワークブック機能は、完全には保持されないことがあります。.xlsmファイルは keep_vba=True で読み込み、.xlsmとして保存し直してください。自動化よりもピクセル単位のレイアウト維持が重要なら、専用ツールがこうしたケースを自動で処理します。

まとめ

openpyxlとOpenAI APIを使えば、100行足らずで、速く・数式に安全なExcel翻訳ツールを作れます。大量処理を自動化したいときにうってつけです。

自動化よりもレイアウトの保持を優先したいなら、専用のExcel翻訳ツールのほうが向いているかもしれません。openpyxlでは扱いきれないグラフ・図形・スタイルも自動で処理してくれます。

コードを書かずにExcelファイルを翻訳する