背景

多言語対応(i18n)を実装する際、「どの文字列を翻訳し、どの文字列を英語のまま残すか」の判断に迷うことがある。特にエクスポート機能(HTML/Markdown/PlainText)のように、画面表示とファイル出力の両方にテキストが含まれる場合、基準が曖昧になりやすい。

実際のプロジェクト(差分ビューアツール)での判断過程を記録する。

一般的な切り分け基準

翻訳すべきもの

ユーザーが読む・操作するすべてのテキストが原則。

  • ボタンラベル(「Copy All」→「差分をコピー」)
  • 見出し・セクションタイトル
  • 説明文・ヘルプテキスト
  • エラーメッセージ・ステータス表示
  • ツールチップ
  • 動的テンプレート(「N lines hidden」等の補間テキスト)

翻訳不要なもの

  • ブランド名・プロダクト名: 「BDiff」「GitHub」等はそのまま
  • 技術用語・業界標準: 「diff」「HTML」「Markdown」「API」
  • URL・ファイルパス
  • コード内の識別子: 変数名、関数名、翻訳キー自体
  • バージョン番号・ビルドID

エクスポートファイルでの判断

ここが最も迷いやすいポイント。画面表示とエクスポートファイルでは、ユーザーのコンテキストが異なる。

エクスポートでも翻訳するもの

文字列 理由
"Original" / "Modified" 画面表示と一致させるべき主要ラベル
"No differences to display" ユーザーが読むメッセージ
"N lines hidden" 省略ブロックのテキスト

エクスポートで翻訳不要なもの

文字列 理由
"BDiff Comparison Report" ブランド名を含むレポートタイトル
"Generated by BDiff" ブランドクレジット
"Name:" / "Size:" / "Lines:" 構造ラベル。英語でも意味が通じ、技術レポートとして国際的に通用する
"Generated:" 同上
"Statistics" / "Added" / "Removed" Markdown/PlainTextの構造。英語が国際標準

判断の考え方

エクスポートファイルの構造ラベル(Name:, Size: 等)は翻訳コストに対して効果が低い。理由:

  1. 技術レポートは英語が共通語: 開発者向けツールのエクスポートは英語でも違和感がない
  2. 翻訳すると逆に混乱: 構造ラベルまで翻訳すると、エクスポートファイルの国際的な可読性が下がる
  3. コスト対効果: 8言語 × 多数のラベル = 大量の翻訳エントリ。ユーザー体験の向上は限定的

Reactプロジェクトでの実装パターン

コンポーネント内(React hook使用可)

const { t } = useTranslation();
<button>{t('diff.copyDiff')}</button>

サービスクラス(hook使用不可)

サービスクラスやレンダラーは React hook を使えないため、翻訳方式を選ぶ必要がある。

方式A: i18nextを直接使用

import i18next from 'i18next';
const label = i18next.t('export.original');

方式B: 翻訳済み文字列をオプション経由で渡す

// コンポーネント側
const labels = {
  original: t('diff.original'),
  modified: t('diff.modified'),
};
ExportService.export(lines, { labels });

// サービス側
render(lines: DiffLine[], options: { labels: ExportLabels }) {
  // options.labels.original を使用
}

方式C: locale を渡してサービス内で翻訳JSONを直接参照

方式Bが最もシンプルで、サービスをi18nextに依存させない点で推奨。

まとめ

  • 原則: ユーザーが見る・操作するテキストは翻訳する
  • 例外: ブランド名、技術用語、エクスポートの構造ラベル
  • 判断基準: 翻訳することでユーザー体験が改善するか?翻訳コストに見合うか?
  • エクスポート: 画面と共通のラベル(Original/Modified等)は翻訳、構造ラベルは英語のまま

参考