技術文書を生成AIで翻訳するときは、「用語集を渡す」「訳さないものを明示する」「Markdownの構造を保たせる」「文体を指定する」の4点をプロンプトに入れると、訳が安定します。 「日本語に翻訳して」だけで頼むと、同じ語が段落ごとに別の訳になったり、コマンドやプレースホルダーまで日本語になったりして、そのままでは使えない訳文になることがあります。

この記事では、4点を入れたREADME用・APIリファレンス用・エラーメッセージ用・コードコメント用のプロンプト全文を載せます。あわせて、用語集CSVのひな形、長文を見出し単位で分けて用語を引き継ぐ手順、逆翻訳と差分で訳抜けを見つけるプロンプト、そして訳文のコード・URL・プレースホルダー・数値が原文と一致するかを照合するPythonコードを実行結果つきでまとめました。例は英語から日本語への翻訳ですが、言語名を入れ替えれば逆方向にも使えます。

確認環境:Ubuntu 24.04.4、Python 3.11.15(確認日 2026-10-05)。文書を分けるコードと照合用のコード5本は、架空のツール「roomkit」のREADMEなどを使ってこの環境で実行した出力を載せています。プロンプトの組み立ては、同日に開いた Anthropic・OpenAI・Google の公式ドキュメントの記載に沿っています。この記事はテンプレート集で、照合に使った訳文は確認用に手で書いたものです(AIの回答例は載せていません)。

この記事の結論

  • プロンプトに入れるのは用語集・訳さないもの・構造の保持・文体の4点
  • 用語集は原語・訳語・訳さない・備考の4列のCSVで持ち、毎回貼る
  • 長い文書は見出し単位で分け、用語集と直前までに決まった訳語を引き継ぐ
  • 訳文はコード・URL・プレースホルダー・数値をコードで照合してから、逆翻訳と差分で意味のずれを見る
  • 用語や文体を細かく指示したい文書は生成AI、決まった形の文を大量に一括で訳すなら翻訳専用の機械翻訳、と使い分ける

翻訳プロンプトに入れる4点の早見表

入れるもの プロンプトに書くこと 入れないときに起きやすいこと 確かめ方
用語集 原語と訳語の対、訳さない語の一覧 同じ語が段落ごとに違う訳になる 用語集の語が訳文に同じ回数だけ出るかを数える
訳さないもの コードブロック、インラインコード、コマンド、識別子、プレースホルダー、URL、ファイル名 コマンドの引数や {item_id} のような部分が日本語になる 原文と訳文で文字列が一致するかを照合する
構造の保持 見出しの数と階層、表の行と列、箇条書き、リンクをそのまま保つ 見出しが統合される、表が文章になる 見出しの階層と表の行数を数える
文体 です・ます/だ・である、文の長さ、主語の扱い、全角と半角 段落ごとに文体が混ざる 文末を目で見る、または決めた文末以外を検索する

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「生成AIの翻訳プロンプト集 技術文書・README・エラー文の訳し方」

4点を入れた基本テンプレート

まず、文書の種類によらない土台です。種類別のテンプレートは、この土台の rules を差し替えたものです。

<role>
あなたは技術文書の翻訳者です。英語の技術文書を、日本のソフトウェア開発者向けの日本語に翻訳します。
</role>

<glossary>
(ここに用語集のCSVを貼る)
</glossary>

<source>
(ここに原文を貼る)
</source>

<rules>
1. 用語:glossary の「原語」は必ず「訳語」で訳す。「訳さない」が yes の語は原文の表記のまま残す。
   glossary に無い専門用語は、訳したうえで、最後に「用語集に無かった語」として原語と訳語の対を一覧にする。
2. 訳さないもの:コードブロック、インラインコード(バッククォートで囲まれた部分)、コマンド、
   関数名や変数名などの識別子、プレースホルダー、URL、ファイル名とパスは、1文字も変えない。
3. 構造:見出しの数と階層、箇条書きの項目数、表の行数と列数、リンクの数を原文と同じにする。
   文を足したり、まとめたり、省いたりしない。
4. 文体:です・ます体。1文は短く。英数字は半角。日本語と英数字の間に半角スペースを入れる。
5. 意味が2通りに取れる文は、どちらかに決めて訳し、最後に「確認したい箇所」として原文と理由を書く。
</rules>

<output_format>
訳文だけを Markdown で出力する。前置きや説明は書かない。
訳文の後に、次の2つの見出しを付ける(該当が無ければ「なし」と書く)。
## 用語集に無かった語
## 確認したい箇所
</output_format>

組み立ての根拠は、各社の公式ドキュメントの記載です。

テンプレートの部分 公式ドキュメントの記載
role で役割を1文書く Anthropic:役割を設定すると振る舞いと口調がその用途に絞られる
glossary source rules をタグで分ける Anthropic:指示・文脈・入力をそれぞれタグで囲むと読み違いが減る。OpenAI:Markdown の見出しと XML タグで区切りと階層を伝える
原文を上、指示を下に置く Anthropic:長い文書はプロンプトの上のほうに置き、指示や問いは後ろに置く
必要な情報(用語集)をプロンプトに入れる Google:モデルが必要な情報を持っていると仮定せず、プロンプトに含める
出力の形を指定する Google:応答の形式を指示できる。OpenAI:出力の形を明示する
「〜しない」より「〜する」で書く Anthropic:してほしくないことではなく、してほしいことを伝える

用語集のひな形(CSV)

用語集は4列で持ちます。

列 書く内容
原語 原文に出てくる語。大文字と小文字は原文に合わせる
訳語 統一したい訳。訳さない語は空欄
訳さない 原文の表記のまま残す語に yes
備考 避けたい訳、品詞、使い分け

記入例(glossary.csv)です。

原語,訳語,訳さない,備考
booking,予約,,名詞。動詞 book は「予約する」
item,備品,,「アイテム」「項目」にしない
shared equipment,共有備品,,
pick up,受け取る,,「ピックアップ」にしない
picked up,受け取,,pick up の変化形。語幹の「受け取」で照合する
timeout,タイムアウト,,設定キーの timeout はコードなので訳さない
endpoint,エンドポイント,,設定キーの endpoint はコードなので訳さない
roomkit,,yes,製品名。カタカナにしない
ITEM_ID,,yes,プレースホルダー
item_id,,yes,プレースホルダー
config.toml,,yes,ファイル名

用語集の候補をAIに抜き出させるプロンプト

用語集がまだ無いときは、翻訳の前に候補を出させます。訳語を決めるのは人です。

<source>
(ここに原文を貼る)
</source>

<task>
この文書を日本語に翻訳する前の準備として、用語集の候補を作ってください。
1. 2回以上出てくる名詞と名詞句、および製品名・機能名・設定項目名を拾う。
2. それぞれについて、訳語の案を1〜2個出す。訳さずに残すほうがよい語(製品名、コマンド名、識別子)は「訳さない」を yes にする。
3. 変化形(複数形、過去形)がある語は、備考に書く。
</task>

<output_format>
次の4列のCSVを、コードブロックの中に出力する。
原語,訳語,訳さない,備考
</output_format>

文書の種類別プロンプトテンプレート

種類ごとの違いを先に表にします。

種類 訳すもの 訳さないもの 文体
README 説明文、見出し、表の説明列 コードブロック、コマンド、設定キー、URL、バッジ です・ます体
APIリファレンス 説明、注意書き パス、メソッド、パラメーター名、型、ステータスコード、JSONのキーと値 表の説明は名詞止め、本文はです・ます体
エラーメッセージ メッセージの値 キー、プレースホルダー、書式指定子 です・ます体。何が起きたか+次にすること
コードコメント コメント、docstring コード、識別子、文字列リテラル だ・である体または名詞止め(既存のコメントに合わせる)

README用

<role>
あなたは技術文書の翻訳者です。英語の README を、日本のソフトウェア開発者向けの日本語に翻訳します。
</role>

<glossary>
(用語集のCSV)
</glossary>

<source>
(README の原文)
</source>

<rules>
1. glossary の「原語」は必ず「訳語」で訳す。「訳さない」が yes の語は原文のまま残す。
2. コードブロックの中は、コメントも含めて1文字も変えない。
3. インラインコード、コマンド、オプション名、設定キー、ファイル名、パス、URL、
   山かっこや波かっこで囲まれたプレースホルダーは、原文のまま残す。
4. 見出しは訳す。見出しの数と階層(# の個数)は変えない。
5. 表は行数と列数を保ち、見出し行と説明の列だけを訳す。キーや既定値の列は変えない。
6. リンクは、表示する文字だけを訳し、リンク先は変えない。画像とバッジの行はそのまま残す。
7. です・ます体。1文に1つのことを書く。英数字は半角で、日本語との間に半角スペースを入れる。
8. 数値と単位(日数、時間、バージョン)は原文と同じ値にする。
</rules>

<output_format>
訳した README だけを Markdown で出力する。
その後に「## 用語集に無かった語」「## 確認したい箇所」を付ける(無ければ「なし」)。
</output_format>

コードブロックの中のコメントも訳したいときは、2 を「コードブロックの中は、# や // で始まるコメントだけを訳し、それ以外は1文字も変えない」に差し替えます。どちらにするかを先に決めて書いておくことが大切です。

APIリファレンス用

<role>
あなたは API ドキュメントの翻訳者です。英語の API リファレンスを、API を呼び出す開発者向けの日本語に翻訳します。
</role>

<glossary>
(用語集のCSV)
</glossary>

<source>
(API リファレンスの原文)
</source>

<rules>
1. glossary に従う。
2. 次のものは原文のまま残す:HTTP メソッド、パス、クエリやボディのパラメーター名、ヘッダー名、
   型の名前(string、integer、boolean、array、object など)、ステータスコード、エラーコード、
   JSON のキーと値、列挙値、コードブロックの中身。
3. 訳すのは、説明文、注意書き、表の「説明」の列、見出しだけ。
4. 表の「説明」の列は名詞止めまたは短い文にする(例:「予約の開始日」)。本文はです・ます体。
5. required は「必須」、optional は「任意」、default は「既定値」、deprecated は「非推奨」と訳す。
6. 「must」「should」「may」の強さの違いを保つ(〜する必要があります/〜することを推奨します/〜できます)。
7. 見出しの階層、表の行数と列数、パラメーターの並び順を変えない。
8. 数値、単位、上限値は原文と同じ値にする。
</rules>

<output_format>
訳した文書だけを Markdown で出力する。
その後に「## 用語集に無かった語」「## 確認したい箇所」を付ける(無ければ「なし」)。
</output_format>

エラーメッセージ用

メッセージの一覧(キーと文の組)を訳す場面を想定しています。原文の例(messages.en.json)です。

{
  "item.not_found": "Item {item_id} was not found.",
  "booking.too_long": "You can book an item for up to {max_days} days.",
  "booking.conflict": "{item_name} is already booked from {start} to {end}.",
  "auth.required": "Please sign in to continue.",
  "upload.failed": "Could not upload %s (%d bytes). Try again later."
}
<role>
あなたはソフトウェアの画面に表示する文言の翻訳者です。英語のエラーメッセージを日本語に翻訳します。
</role>

<glossary>
(用語集のCSV)
</glossary>

<context>
(どの画面で、誰に向けて表示されるか。例:社員が使う備品予約の画面。利用者は開発者ではない)
</context>

<source>
(キーとメッセージの JSON)
</source>

<rules>
1. JSON のキーは変えない。値だけを訳す。キーの数と並び順も変えない。
2. 波かっこで囲まれたプレースホルダーと、%s や %d などの書式指定子は、名前も個数もそのまま残す。
   日本語の語順に合わせて位置を動かすのはよい。名前付きでない書式指定子(%s、%d)は順番を変えない。
3. プレースホルダーの前後には半角スペースを入れる。
4. です・ます体。「何が起きたか」を先に、「次にすること」を後に書く。
5. 利用者を責める言い方を避ける(「不正な入力」ではなく「入力内容を確認してください」のように書く)。
6. glossary に従い、画面のほかの文言と用語をそろえる。
7. 1つのメッセージは2文まで。原文に無い情報を足さない。
</rules>

<output_format>
原文と同じ形の JSON だけを、コードブロックの中に出力する。
</output_format>

コードコメント用

<role>
あなたはソースコードのコメントの翻訳者です。英語のコメントを日本語に翻訳します。
</role>

<glossary>
(用語集のCSV)
</glossary>

<source>
(ソースコード)
</source>

<rules>
1. 訳すのはコメントと docstring だけ。それ以外のコードは、空白と改行も含めて1文字も変えない。
2. 文字列リテラル(引用符で囲まれた値)は、docstring を除いて訳さない。
3. コメントの中に出てくる識別子(関数名、変数名、クラス名)は原文のまま残す。
4. TODO、FIXME、NOTE などの目印と、その後ろの担当者名やチケット番号はそのまま残す。
5. コメントの位置(行の上か、行末か)と行数を変えない。
6. 文体は、短い名詞止めまたは「〜する。」の形にする。
7. コードの誤りに気づいても直さない。訳の後に「気づいた点」として別に書く。
</rules>

<output_format>
コメントを訳したソースコードだけを、コードブロックの中に出力する。
その後に「## 気づいた点」を付ける(無ければ「なし」)。
</output_format>

長文は見出し単位で分けて用語を引き継ぐ

長い文書を1回で訳させると、後半で用語がぶれたり、段落が抜けたりしても気づきにくくなります。見出し単位で分け、1回ずつ確かめながら進めます。

手順

順 すること 引き継ぐもの
1 文書を見出し(H2)ごとのファイルに分ける ―
2 全体を渡して用語集の候補を出させ、人が訳語を決める 用語集
3 1つ目のかたまりを訳す 用語集
4 返ってきた「用語集に無かった語」を見て、採用する訳を用語集に足す 更新した用語集
5 次のかたまりを、更新した用語集といっしょに渡して訳す 用語集、直前の見出しの訳
6 すべて訳したらつなげて、照合用のコードを通す ―

見出し単位で分けるコード

import sys

path = sys.argv[1]
parts, current, in_code = [], [], False
for line in open(path, encoding="utf-8").read().split("\n"):
    if line.startswith("```"):
        in_code = not in_code
    if line.startswith("## ") and not in_code and current:
        parts.append(current)
        current = []
    current.append(line)
parts.append(current)

for no, lines in enumerate(parts, start=1):
    name = f"part{no:02d}.md"
    with open(name, "w", encoding="utf-8") as f:
        f.write("\n".join(lines).rstrip("\n") + "\n")
    print(f"{name}\t{len(lines)}行\t{lines[0]}")
python3 split_by_heading.py README.en.md

実行結果です。

part01.md   4行  # roomkit
part02.md   9行  ## Installation
part03.md   10行 ## Usage
part04.md   9行  ## Configuration
part05.md   4行  ## Troubleshooting

in_code で、コードブロックの中かどうかを見ています。題材の README にはコードブロックの中に # Install from the package index というコメントがあり、行頭が # の行を単純に数えると見出しが1つ多くなるためです。

grep -c '^# ' README.en.md
2

H1 は1つだけですが、2 と数えられました。

2回目以降に貼る引き継ぎ用プロンプト

<glossary>
(更新した用語集のCSV)
</glossary>

<previous>
(直前のかたまりの原文の見出しと、その訳。本文は貼らなくてよい)
</previous>

<source>
(今回訳すかたまり)
</source>

<rules>
(文書の種類に合わせたルール。1回目と同じものを貼る)
追加:previous は文体と用語をそろえるための参考で、訳し直さない。source だけを訳す。
</rules>

<output_format>
source の訳だけを Markdown で出力する。
その後に「## 用語集に無かった語」「## 確認したい箇所」を付ける(無ければ「なし」)。
</output_format>

訳文を確かめる:コードで照合する

訳文の確認は、機械的に照合できるものから先に済ませます。題材の README(README.en.md)です。

# roomkit

roomkit is a command-line tool for booking shared equipment.

## Installation

Requires Python 3.11 or later.

```bash
# Install from the package index
pip install roomkit
```

## Usage

Run `roomkit list` to see available items. To book an item, pass its ID:

```bash
roomkit book --item <ITEM_ID> --days 3
```

You can book an item for up to 7 days. A booking is canceled automatically if it is not picked up within 2 hours.

## Configuration

Settings are read from `~/.roomkit/config.toml`.

| Key | Default | Description |
|---|---|---|
| `endpoint` | `https://example.com/api` | Base URL of the API |
| `timeout` | `30` | Request timeout in seconds |

## Troubleshooting

If you see `Error: item {item_id} is not available`, the item is already booked. See https://example.com/docs/errors for details.

確認用に手で書いた訳文(README.ja.md)です。照合の動きを見るために、わざと4か所を崩してあります。

# roomkit

roomkit は、共有備品を予約するためのコマンドラインツールです。

## インストール

Python 3.11 以降が必要です。

```bash
# パッケージインデックスからインストールする
pip install roomkit
```

## 使い方

`roomkit list` を実行すると、利用できる備品を確認できます。備品を予約するには、その ID を渡します。

```bash
roomkit book --item <備品ID> --days 3
```

備品は最長7日間予約できます。

## 設定

設定は `~/.roomkit/config.toml` から読み込まれます。

| キー | 既定値 | 説明 |
|---|---|---|
| `endpoint` | `https://example.com/api` | API のベース URL |
| `timeout` | `30` | リクエストのタイムアウト(秒) |

## トラブルシューティング

`Error: item {備品ID} is not available` と表示された場合、その備品はすでに予約されています。詳しくは https://example.com/docs/errors を参照してください。

コード・URL・プレースホルダー・数値を照合する

import re
import sys
from collections import Counter


def parse(path):
    """Markdown を、コードブロック・見出し・本文に分けて数える。"""
    info = {"headings": [], "code_blocks": [], "inline": Counter(),
            "urls": Counter(), "placeholders": Counter(), "numbers": Counter(),
            "table_rows": 0, "sentences": []}
    in_code, buf, section = False, [], "(先頭)"
    count = 0
    for line in open(path, encoding="utf-8").read().split("\n"):
        if line.startswith("```"):
            if in_code:
                info["code_blocks"].append("\n".join(buf))
                buf = []
            in_code = not in_code
            continue
        if in_code:
            buf.append(line)
            continue
        m = re.match(r"(#{1,6}) ", line)
        if m:
            info["sentences"].append((section, count))
            section, count = line, 0
            info["headings"].append(len(m.group(1)))
            continue
        if line.startswith("|"):
            info["table_rows"] += 1
        else:
            plain = re.sub(r"`[^`]+`", "", line)
            count += len(re.findall(r"。|[.:](?=\s|$)", plain))
        info["inline"].update(re.findall(r"`[^`]+`", line))
        info["urls"].update(re.findall(r"https?://[\w./~%#?=&-]+", line))
        info["placeholders"].update(re.findall(r"\{[^{}]+\}|<[^<>\s]+>|%[sd]", line))
        info["numbers"].update(re.findall(r"\d+(?:\.\d+)?", line))
    info["sentences"].append((section, count))
    return info


def diff(name, a, b):
    lost, added = a - b, b - a
    if not lost and not added:
        print(f"OK   {name}")
        return
    print(f"要確認 {name}")
    for k, v in lost.items():
        print(f"       原文だけにある: {k} x{v}")
    for k, v in added.items():
        print(f"       訳文だけにある: {k} x{v}")


src, dst = parse(sys.argv[1]), parse(sys.argv[2])

print("OK   見出しの数と階層" if src["headings"] == dst["headings"]
      else f'要確認 見出し: 原文 {src["headings"]} / 訳文 {dst["headings"]}')
print("OK   表の行数" if src["table_rows"] == dst["table_rows"]
      else f'要確認 表の行数: 原文 {src["table_rows"]} / 訳文 {dst["table_rows"]}')

if len(src["code_blocks"]) != len(dst["code_blocks"]):
    print(f'要確認 コードブロックの数: 原文 {len(src["code_blocks"])} / 訳文 {len(dst["code_blocks"])}')
for i, (a, b) in enumerate(zip(src["code_blocks"], dst["code_blocks"]), start=1):
    if a == b:
        print(f"OK   コードブロック{i}")
        continue
    print(f"要確認 コードブロック{i}")
    for x, y in zip(a.split("\n"), b.split("\n")):
        if x != y:
            print(f"       原文: {x}")
            print(f"       訳文: {y}")

diff("インラインコード", src["inline"], dst["inline"])
diff("URL", src["urls"], dst["urls"])
diff("プレースホルダー", src["placeholders"], dst["placeholders"])
diff("数値", src["numbers"], dst["numbers"])

for (s_head, s_n), (d_head, d_n) in zip(src["sentences"], dst["sentences"]):
    if s_n != d_n:
        print(f"要確認 文の数: {s_head} 原文 {s_n} / {d_head} 訳文 {d_n}")
python3 check_translation.py README.en.md README.ja.md

実行結果です。

OK   見出しの数と階層
OK   表の行数
要確認 コードブロック1
       原文: # Install from the package index
       訳文: # パッケージインデックスからインストールする
要確認 コードブロック2
       原文: roomkit book --item <ITEM_ID> --days 3
       訳文: roomkit book --item <備品ID> --days 3
要確認 インラインコード
       原文だけにある: `Error: item {item_id} is not available` x1
       訳文だけにある: `Error: item {備品ID} is not available` x1
OK   URL
要確認 プレースホルダー
       原文だけにある: {item_id} x1
       訳文だけにある: {備品ID} x1
要確認 数値
       原文だけにある: 2 x1
要確認 文の数: ## Usage 原文 4 / ## 使い方 訳文 3

崩した4か所がすべて見つかりました。

見つかった行 何が起きていたか
コードブロック1 コードブロックの中のコメントが訳されている(ルールでどちらにするか決めておく箇所)
コードブロック2、インラインコード、プレースホルダー <ITEM_ID> と {item_id} が日本語になっている
数値、文の数 「2時間以内に受け取らないと取り消される」という1文が抜けている

用語集どおりに訳されているかを数える

import csv
import re
import sys

glossary, src_path, dst_path = sys.argv[1:4]


def prose(path):
    """コードブロックとインラインコードを除いた本文を返す。"""
    text = open(path, encoding="utf-8").read()
    text = re.sub(r"```.*?```", "", text, flags=re.S)
    return re.sub(r"`[^`]+`", "", text)


src, dst = prose(src_path), prose(dst_path)

with open(glossary, encoding="utf-8", newline="") as f:
    for row in csv.DictReader(f):
        term = row["原語"]
        n_src = len(re.findall(r"\b" + re.escape(term), src, flags=re.I))
        if n_src == 0:
            continue
        if row["訳さない"] == "yes":
            n_dst = dst.count(term)
            label = f"{term}(訳さない)"
        else:
            n_dst = dst.count(row["訳語"])
            label = f'{term} → {row["訳語"]}'
        mark = "OK  " if n_dst >= n_src else "要確認"
        print(f"{mark} {label}: 原文 {n_src} 回 / 訳文 {n_dst} 回")
python3 check_glossary.py glossary.csv README.en.md README.ja.md
OK   booking → 予約: 原文 2 回 / 訳文 4 回
OK   item → 備品: 原文 4 回 / 訳文 5 回
OK   shared equipment → 共有備品: 原文 1 回 / 訳文 1 回
要確認 picked up → 受け取: 原文 1 回 / 訳文 0 回
OK   timeout → タイムアウト: 原文 1 回 / 訳文 1 回
OK   roomkit(訳さない): 原文 2 回 / 訳文 2 回

抜けた1文に含まれていた picked up が「要確認」になりました。訳文のほうが回数の多い語(予約、備品)は、代名詞の it を名詞で訳したり、動詞の book を「予約する」と訳したりした分で、問題はありません。原文より少ないときだけ確かめます。

エラーメッセージのプレースホルダーを照合する

確認用に手で書いた訳(messages.ja.json)です。2か所を崩してあります。

{
  "item.not_found": "備品 {item_id} が見つかりません。",
  "booking.too_long": "備品を予約できるのは最長 {最大日数} 日間です。",
  "booking.conflict": "{item_name} は {start} からすでに予約されています。",
  "auth.required": "続けるにはサインインしてください。",
  "upload.failed": "%s(%d バイト)をアップロードできませんでした。しばらくしてからもう一度お試しください。"
}
import json
import re
import sys

src = json.load(open(sys.argv[1], encoding="utf-8"))
dst = json.load(open(sys.argv[2], encoding="utf-8"))
PH = re.compile(r"\{[^{}]*\}|%[sd]")

for key in src:
    if key not in dst:
        print(f"要確認 {key}: 訳文にキーが無い")
        continue
    a, b = sorted(PH.findall(src[key])), sorted(PH.findall(dst[key]))
    if a == b:
        print(f"OK   {key}")
    else:
        print(f"要確認 {key}: 原文 {a} / 訳文 {b}")
for key in dst.keys() - src.keys():
    print(f"要確認 {key}: 原文に無いキー")
python3 check_messages.py messages.en.json messages.ja.json
OK   item.not_found
要確認 booking.too_long: 原文 ['{max_days}'] / 訳文 ['{最大日数}']
要確認 booking.conflict: 原文 ['{end}', '{item_name}', '{start}'] / 訳文 ['{item_name}', '{start}']
OK   auth.required
OK   upload.failed

プレースホルダーの名前が訳された行と、{end} が落ちた行が見つかりました。

コメント以外が変わっていないかを照合する(Python)

コードコメントの翻訳では、コードが1文字でも変わると動きが変わります。Python の標準ライブラリ tokenize で、コメントと docstring を除いた並びを比べます。原文(sample.en.py)です。

# Maximum number of days for one booking.
MAX_DAYS = 7


def can_book(days: int) -> bool:
    """Return True if the booking length is allowed."""
    # A booking must be at least one day.
    if days < 1:
        return False
    return days <= MAX_DAYS  # inclusive


print(can_book(7), can_book(8))

確認用に手で書いた訳(sample.ja.py)です。10行目の比較演算子を1か所だけ変えてあります。

# 1回の予約の最大日数。
MAX_DAYS = 7


def can_book(days: int) -> bool:
    """予約の日数が許される範囲なら True を返す。"""
    # 予約は1日以上であること。
    if days < 1:
        return False
    return days < MAX_DAYS  # 上限を含む


print(can_book(7), can_book(8))
import io
import sys
import tokenize


def code_tokens(path):
    """コメントと docstring を除いたトークンの並びを返す。"""
    out, prev = [], None
    text = open(path, encoding="utf-8").read()
    for tok in tokenize.generate_tokens(io.StringIO(text).readline):
        if tok.type in (tokenize.COMMENT, tokenize.NL):
            continue
        is_docstring = tok.type == tokenize.STRING and prev in (None, tokenize.INDENT, tokenize.NEWLINE)
        if not is_docstring:
            out.append((tok.type, tok.string, tok.start[0]))
        prev = tok.type
    return out


a, b = code_tokens(sys.argv[1]), code_tokens(sys.argv[2])
diffs = [(x, y) for x, y in zip(a, b) if x[:2] != y[:2]]
if len(a) == len(b) and not diffs:
    print("OK   コメント以外は同じです")
else:
    print(f"要確認 コメント以外に違いがあります(トークン数 原文 {len(a)} / 訳文 {len(b)})")
    for x, y in diffs[:5]:
        print(f"       {x[2]}行目: 原文 {x[1]!r} / 訳文 {y[1]!r}")
python3 check_comments.py sample.en.py sample.ja.py
要確認 コメント以外に違いがあります(トークン数 原文 48 / 訳文 48)
       10行目: 原文 '<=' / 訳文 '<'

2つのファイルを実行すると、出力も変わっていることが分かります。

$ python3 sample.en.py
True False
$ python3 sample.ja.py
False False

訳文を確かめる:逆翻訳と差分のプロンプト

コードで照合できるのは文字列の一致までです。意味のずれは、訳文を原文の言語に訳し戻し、原文と比べて見つけます。逆翻訳は、訳したときとは別の会話で頼みます。原文を見せずに訳し戻させるためです。

逆翻訳のプロンプト(新しい会話で)

<translated>
(ここに日本語の訳文を貼る)
</translated>

<task>
この日本語の文書を、英語に直訳してください。
- 自然な英語に整えず、日本語に書かれている内容をそのまま英語にする。
- 日本語に書かれていないことを補わない。
- コードブロック、インラインコード、URL はそのまま残す。
- 見出しと段落の区切りを保つ。
</task>

<output_format>
英語の訳だけを Markdown で出力する。
</output_format>

原文と逆翻訳を比べるプロンプト

<original>
(英語の原文)
</original>

<back_translation>
(逆翻訳で得た英語)
</back_translation>

<task>
original と back_translation を、見出しごと・文ごとに対応づけて比べてください。
言い回しの違いは無視し、次の4種類だけを拾います。
- 抜け:original にあって back_translation に無い文や句
- 追加:back_translation にあって original に無い文や句
- 意味のずれ:数値、条件、否定、主語と目的語、必須か任意か、が変わっている
- 強さのずれ:must・should・may の強さが変わっている
見つけた箇所は、両方の文をそのまま引用してください。
</task>

<output_format>
次の列の表で出力する。見つからなければ「差分なし」とだけ書く。
| No | 見出し | 種類(抜け・追加・意味のずれ・強さのずれ) | original の引用 | back_translation の引用 | 説明 |
|---|---|---|---|---|---|
</output_format>

原文と訳文を直接比べるプロンプト

逆翻訳をはさまず、原文と訳文を並べて点検させる方法もあります。両方の言語を読めるモデルなら、手順が1つ減ります。

<original>
(英語の原文)
</original>

<translated>
(日本語の訳文)
</translated>

<glossary>
(用語集のCSV)
</glossary>

<task>
original の文を1つずつ取り上げ、translated に対応する文があるかを確かめてください。
拾うのは、抜け・追加・意味のずれ・強さのずれ・用語集と違う訳、の5種類です。
言い回しの好みは指摘しません。
</task>

<output_format>
| No | 種類 | original の引用 | translated の引用(無ければ「なし」) | 直した訳 |
|---|---|---|---|---|
</output_format>
確かめ方 見つけやすいもの 向いている場面
コードで照合 コード・URL・プレースホルダー・数値の変化、文の抜け、用語の回数 すべての翻訳で最初に通す
逆翻訳と差分 意味のずれ、否定や条件の取り違え 訳先の言語を自分で読めないとき
原文と訳文を直接比べる 抜け、用語集と違う訳 両方の言語を読めて、指摘をすぐ直したいとき

文体の指定に使える書き方

「自然な日本語で」より、形で指定するほうが伝わります。

指定したいこと プロンプトに書く文
文末 です・ます体にする。「〜だ」「〜である」を使わない
文の長さ 1文に1つのことを書く。長い文は2つに分ける
主語 英語の you は訳さず、主語を省く(「あなたは」を使わない)
受け身 英語の受け身は、できるだけ「〜します」「〜できます」の形にする
カタカナ語の長音 「サーバー」「ユーザー」のように語尾の長音を付ける
英数字と記号 英数字は半角。かっこは全角。日本語と英数字の間に半角スペース
見出し 名詞止めにする(「インストール」「使い方」)
箇条書き 文末をそろえる。項目が名詞なら句点を付けない

翻訳専用の機械翻訳と生成AIの使い分け

どちらにも向いた場面があります。次の3つの基準で選びます。

基準 生成AIが向く場面 翻訳専用の機械翻訳が向く場面
用語や文体を指示したいか 文書ごとに用語集・文体・読者をプロンプトで細かく変えたい 決まった用語の登録機能があり、それで足りる
書式を保ちたいか Markdown、JSON、コード中のコメントなど、訳す場所と残す場所を言葉で指定したい ファイルをそのまま渡して、レイアウトごと訳したい
大量に一括処理したいか 1件ずつ確かめながら訳す量である 同じ形の文が大量にあり、速さと一定の結果がほしい
条件 選ぶもの
README やAPIリファレンスで、コードと説明が混ざっている 生成AI(この記事のテンプレート)
エラーメッセージで、読む人に合わせた言い回しにしたい 生成AI
訳す理由や別の案も聞きたい 生成AI
決まった形の文を大量に、一定の品質で訳したい 翻訳専用の機械翻訳
大意をすぐ知りたいだけ どちらでもよい
どちらを使った場合でも コード・URL・プレースホルダー・数値の照合は同じコードで行う

機械翻訳の用語登録や書式の保持は製品ごとに違うので、使う製品の公式の説明で確かめてください。入力した文書の扱いも、サービスの契約と自社の規程で決まります。

似た作業との違い

作業 目的 原文の内容を変えるか
翻訳 同じ内容を別の言語で書く 変えない(足さない・省かない)
要約 短くする 省く
ローカライズ 読む人の地域や習慣に合わせる(日付の書式、単位、例) 一部を置き換える
英文の添削 自分で書いた文を直す 言い回しを変える

翻訳のプロンプトに「分かりやすくまとめて」と書くと、要約が混ざって文が省かれます。翻訳では「足さない・省かない」を明記し、読みやすさは文体の指定で整えます。

確かめて分かったこと

  • 行頭が # の行を数えると、コードブロックの中のコメントも見出しに数えられる:題材の README は H1 が1つですが、grep では 2 になりました。分けるコードも照合するコードも、コードブロックの中かどうかを見る必要があります。
  • 文の数だけでは抜けに気づけないことがある:英語は「pass its ID:」のようにコロンで終わる文があり、日本語は句点で終わります。照合用のコードを最初はピリオドと句点だけで数えていたところ、1文抜けた訳文でも数が一致しました。行末のコロンを数に入れ、数値の照合も並べて行うようにしています。
  • 用語集の照合は変化形で外れる:pick up だけを登録しても、原文の picked up には一致しません。変化形は別の行として登録しておくと、数えられます。
  • 訳文のほうが用語の回数が多いのは普通:英語の it を日本語で名詞に直すため、「備品」は原文の item より1回多くなりました。原文より少ないときだけ確かめれば足ります。
  • インラインコードの中のプレースホルダーも訳されうる:Error: item {item_id} is not available はバッククォートの中にありますが、確認用の訳文で波かっこの中だけを日本語にすると、インラインコードとプレースホルダーの両方で検出できました。
  • コメントの翻訳では、演算子1つの違いで出力が変わる:<= が < になっただけで、can_book(7) の結果が True から False になりました。コメント以外の照合は省かないほうが安心です。

よくある質問

Q. 生成AIの翻訳で用語がばらつくときは? A. 用語集をCSVで作り、毎回プロンプトに貼ります。長い文書を分けて訳すときは、途中で決まった訳語を用語集に足してから次のかたまりを頼みます。AIは前の会話で決めた訳を次の会話では知らないので、毎回渡すのが確実です。

Q. コードブロックやコマンドまで翻訳されてしまうときは? A. 訳さないものを種類ごとに並べて書きます。「コードは訳さない」だけでなく、コードブロック、インラインコード、コマンド、識別子、プレースホルダー、URL、ファイル名と書くと伝わります。訳文は照合用のコードに通して、変わっていないことを確かめます。

Q. 翻訳と意訳の違いは? 技術文書ではどちらがよいですか? A. 技術文書では、内容を足したり省いたりしない翻訳が基本です。手順・数値・条件が1つでも変わると、読んだ人の操作が変わるからです。読みやすさは、文を短く分ける、主語を省く、といった文体の指定で整えます。

Q. エラーメッセージを翻訳するときに気をつけることは? A. プレースホルダーと書式指定子を名前も個数も変えないことです。あわせて、どの画面で誰が読むかを伝え、「何が起きたか」と「次にすること」の順で書かせると、読んだ人が動きやすい文になります。

Q. 日本語から英語に訳すときも同じテンプレートを使えますか? A. 使えます。role の言語名を入れ替え、文体のルールを英語向け(能動態にする、主語を補う、1文を短くする、など)に差し替えます。用語集の列は「原語」に日本語、「訳語」に英語を入れます。照合用のコードは、コード・URL・プレースホルダー・数値についてはそのまま使えます。

まとめ

  • 翻訳プロンプトには用語集・訳さないもの・構造の保持・文体の4点を入れる
  • 用語集は原語・訳語・訳さない・備考のCSVで持ち、変化形も登録する
  • README・APIリファレンス・エラーメッセージ・コードコメントで、訳す場所と残す場所が違う
  • 長文は見出し単位で分け、更新した用語集を次のかたまりに引き継ぐ
  • 訳文はコード・URL・プレースホルダー・数値・用語の回数をコードで照合する
  • 意味のずれは逆翻訳と差分、または原文と訳文を直接比べるプロンプトで拾う
  • 翻訳では足さない・省かないを明記し、読みやすさは文体の指定で整える

参考・出典

  • Anthropic「Prompting best practices」(Claude Platform Docs、2026-10-05 閲覧):役割の設定、XMLタグによる区切り、長い文書の置き場所、してほしいことを伝える書き方
  • OpenAI「Prompt engineering」(OpenAI API ドキュメント、2026-10-05 閲覧):Markdown の見出しと XML タグによる区切り、出力の形の指定
  • Google「Prompt design strategies」(Gemini API ドキュメント、2026-10-05 閲覧):必要な情報をプロンプトに含めること、応答の形式の指定、プロンプトを要素に分けること

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「生成AIの翻訳プロンプト集 技術文書・README・エラー文の訳し方」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?