言語ごとの文言はすべてテーブル(JSON)に一元化し、コード変更なしで追加・上書き できる。レイヤは 5 つで、それぞれ役割と機構が違う。 All translations live in JSON tables; five layers with distinct mechanisms.
ja en zh(简体) tw(繁體/台湾) ko de の 6 言語。半導体サプライチェーンの
主要国を見て選んだ —— 日本・米英・中国・台湾・韓国・ドイツ。
★ 台湾向け繁体字のコードは、ファイル名を 2 文字にそろえるため tw としている。
標準タグ(BCP 47)では zh-TW / zh-Hant であり、tw は本来 ISO 639-1 で Twi 語の
記号なので、OS・ブラウザから来るロケールは必ず tools/opdocs.py の
normalize_lang()(対応表 LANG_ALIASES)を通してから使うこと。
| レイヤ | ベース言語 | テーブル | 切替 |
|---|---|---|---|
| ① Studio UI(メニュー/ボタン/ツールチップ/ガイド) | 英語 | studio_assets/i18n.json(strings / tooltips / guide) |
Tools ▸ Language(記憶される) |
| ② ライブラリのメッセージ(例外/CLI) | 英語(traceback・ログ・検索の通貨) | fullseye/i18n/<lang>.json + ユーザーの FULLSEYE_I18N_DIR(後者優先) |
env FULLSEYE_LANG / fsi18n.set_language() |
| ③ op ヘルプの枠(見出し・ラベル・入力契約) | 日本語(生成器の原文) | docs/i18n/opdocs.json + docs/i18n/op_summary.json |
ヘルプ冒頭の言語リンク / UI 言語に追従 |
| ④ コメント・docstring・op 本文 | 日本語 | 併記は ja+en まで(zh 以降は ⑤ の方式) | — |
| ⑤ 散文ドキュメント(記事・ガイド・カタログ) | 日本語 | 兄弟ファイル <name>.<lang>.md |
ファイルを開く |
studio_assets/i18n.json の一箇所。strings(ラベル対訳、英語原文が
キー)・tooltips・guide。言語追加は languages に 1 行 — コード変更なし。strings 44 件は ja しか入っておらず、
中文を選んでもメニューは英語のままだった。(b) apply_language に
("en","ja","zh") という固定の許可リストがあり、languages に足した言語は
メニューに出るのに選ぶと英語へ戻った(「表に足せば増える」という約束をコード
側が破っていた)。いまは LANGUAGES に載っているものを受け付け、
tests/test_opdocs.py が両方を検査する。tr() + スナップショット registry(win._label_en / win._tt_en)。詳細は
docs/STUDIO_GUIDE.md の「多言語対応」節。例外メッセージは英語がベース(2026-08-30 に日本語のみだった 336 箇所を英語へ統一)。
その上で、切替の下地として fsi18n を用意している:
from fsi18n import msg
raise ValueError(msg("points must be (N, 3) (got shape {shape})", shape=P.shape))
FULLSEYE_LANG=ja(env)または fsi18n.set_language("ja")。既定 en は
テーブルを読まない素通し=ゼロコスト。FULLSEYE_I18N_DIR の指す
ディレクトリに <lang>.json(英語テンプレート → 訳)を置くと、同梱テーブル
(fullseye/i18n/<lang>.json)より優先される。新しい言語もファイルを置くだけ。
プログラムからは fsi18n.register(lang, mapping)。msg() 自体は決して例外を
出さない(メッセージ機構がエラー源になってはいけない)。FULLSEYE_LANG(UI の言語)を伝播する。fsi18n.msg() 経由への
置換は新規コード・主要バリデータから進める(規約は CONTRIBUTING.md)。op ヘルプ(studio_assets/op_help/**)は docs/ops/** の Markdown から生成される。
生成物を直接訳しても次の再生成で消えるので、生成の入力側を訳す。
docs/i18n/opdocs.json —— キーは原文(日本語)そのもの。
studio.py の tr() と同じ規約で、翻訳者はキーを発明しなくてよく、原文を書き換えれば
その行は自動的に「未訳」に落ちる(古い訳が黙って残らない)。言語追加は各行に 1 列。
未訳は原文のまま出て、tools/opdocs.py html が stderr に件数を出す。docs/i18n/op_summary.json —— キーは <dim>/<op>、fp は
原文の指紋。指紋が合わない訳は出さない(日本語と「未訳」の断り書きに戻る)。tools/opdocs.py html が <op>.html(日本語)に加えて
<op>.<lang>.html を 5 言語ぶん書く。ガイド(人が書いた散文)は日本語 1 枚のままで、
各言語版には日本語のみである旨の 1 行だけを冠する。lang:<code>)。UI の
言語を切り替えるとヘルプもそれに追従する。not_in_language())で行う。ja も翻訳先。原文が英語の要約が 521 本あり(0.1.7 で分母を 935 →
1,722 に増やした時点の実測。当初は 349 本)、日本語のヘルプを開いても英語の
ままだった。全部に日本語訳を入れて ja 1,722/1,722。訳がある op だけ
<op>.ja.html を生やす
(原文が日本語の op にノートと同じ中身の兄弟を並べても情報は増えない)。
docs/ops/** のノートは docstring の写しなので触らない。fsi18n.py)。既存コードは触るタイミングで併記化。docs/ops)は docstring から自動生成されるため、docstring の二言語化が
そのまま英語版ノート/help の自動生成につながる(将来ウェーブ)。vloop* / fullseye_3dgs / janken* 等、非出荷)は日本語のまま。対訳は原文の横に置く: <name>.md → <name>.en.md / <name>.zh.md。
docs/articles/exhibits/ で既にこの形が動いている(museum.ja.md / museum.en.md)。
新しい規約を増やさず、置き場所を見れば対応が分かるのが利点。
> **言語 / Language**: 日本語 · English · 中文)。これが読者側の導線。docs/ops/** の op ノート)はファイルを訳さない。生成の入力側
(見出し等の固定文字列 + op 要約の対訳表)を訳す方式に寄せる —— 生成物を直接
上書きしても次の再生成で消えるため。docs/README.md(= GitHub Pages のトップ。独自ドメイン https://furuse.work/ で
配信されている)に、README.en.md / .zh.md / .tw.md / .ko.md / .de.md の
兄弟ファイルを揃えた。入口だけが日本語のままだったのが動機 —— op ヘルプは
既に 6 言語で出ていたのに、そこへ辿り着く索引が訳されていなかった。
決めたこと 3 つ:
[日本語] · [English] · [简体中文] · [繁體中文] · [한국어] ·
[Deutsch])。読み手は自分の言語の綴りだけを探せばよい。tw)は简体(zh)の字を変えたものにしない。 台湾で通る語彙を使う
(軟體 / 程式碼 / 專案 / 函式庫 / 影像 / 搜尋 / 匯出 / 涵蓋率 / 演算法)。
ここを機械変換で済ませると「訳したふり」になる。訳し落としの検出は機械で数える: 見出し数(^#)と表の行数が 6 ファイルで
一致すること、](*.md) のリンク先が実在すること、README.??.md にかな・
カタカナが残っていないこと(言語スイッチャの 日本語 だけは例外)。
2026-09-06 の実測は見出し 8 / 表 25 行が 6 言語すべて一致、リンク切れ 0、
かな残り 0。
| 入口 | 見えるもの |
|---|---|
| PyPI プロジェクトページ | README.md(英語)。冒頭に総合紹介 en/ja へのリンク |
| GitHub リポジトリ前面 | 同上(同じ README) |
README.md の Documentation map |
総合紹介 en/ja、docs/articles/exhibits/ |
docs/articles/README.md |
記事ハブ。ファイルと言語の対応表 |
| 各記事の冒頭 | 言語スイッチャ 1 行 |
| Studio | Tools ▸ Language(ja/en/zh/tw/ko/de) |
| Studio の op ヘルプ | 頁の冒頭に言語リンク(その頁に実在する言語だけ) |
| 対象 | 原文の分量 | 状態 |
|---|---|---|
Studio UI(strings 44 + tooltips 36 + guide) |
2,870 字 | 6 言語 済(0.1.7) |
| op ヘルプの枠(見出し・ラベル・入力契約 40 件) | 3,000 字 | 6 言語 済(0.1.7) |
README.md(= PyPI 本文) |
11,881 字 | 英語のみ |
| 総合紹介記事 | ja 244,200 / en 390,197 字 | ja + en |
| op 要約(1,722 本 = 全 op) | 実測 | 6 言語すべて 1,722/1,722 済(0.1.8) |
| op の説明が無い op | — | 0 本(0.1.7 で 787 → 0。分母が 935 → 1,722 になった) |
docs/OP_CATALOG.md(全 op の要約) |
24,041 字 | 未 |
| 知識ガイド 12 本 | 24,000 字 | 未 |
| 族ガイド 26 本 | 91,889 字 | 任意 |
| op docstring 本文(1,722 本) | 54 万字超 | 対象外 |
v1.0.0 のゲート = op 要約 + OP_CATALOG + 知識ガイド(言語は需要順に足す。表に 1 列足すだけで増える形になっている)。op docstring 本文 54 万字は対象外 —— 量が 桁違いで、機械翻訳で撒くと技術的に間違った主張を 6 言語に複製することになる。 README に対象外であることを明記する。
honest: 機械翻訳で量を撒かない。この repo の実測では、翻訳を撒いても読まれない (閲覧は伸びるがストックが付かない)。訳すのは判断が移る文書に絞る。