From cc31d11227627de39d0b2a6579ed43aab40a33fe Mon Sep 17 00:00:00 2001 From: Ikki Nishihara Date: Sat, 10 Oct 2026 07:45:11 +0900 Subject: [PATCH] i18n: complete the Japanese catalog (105 missing strings) and check it like fr/de/ru/zh-hans (#587) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i18n: complete the Japanese catalog and check it like the other languages Japanese lacked 105 strings that other languages already have: the open-link and open-email confirmations, DPI settings, the script sandbox note, XFA form notes, signing, table and page-mode settings, and the Contributors / Models statistics. Each now has a Japanese row, so the interface no longer falls back to English for them. `japanese_covers_ui_literals` joins the French, German, Russian and Simplified Chinese checks: every `tl!("…")` literal in the UI source needs a Japanese row. ATTRIBUTION.toml carries the catalog's new SHA-256. Co-Authored-By: Claude Sonnet 5.5 * ja: the Fill & Sign flatten setting main gained meanwhile --------- Co-authored-by: Claude Sonnet 5.5 Co-authored-by: Brandon Thomas --- ATTRIBUTION.toml | 2 +- crates/ui-egui/src/i18n/ja.tsv | 107 +++++++++++++++++++++++++++++++++ crates/ui-egui/src/i18n/mod.rs | 49 +++++++++++++++ docs/localization.md | 2 +- 4 files changed, 158 insertions(+), 2 deletions(-) diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml index d1c4fcca..e318ee81 100644 --- a/ATTRIBUTION.toml +++ b/ATTRIBUTION.toml @@ -140,7 +140,7 @@ licence = "MIT OR Apache-2.0" licence_file = "LICENSE-MIT" kind = "translation" usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs" -sha256 = "0534c5852449a72af65da004b085c6d0566aa7d9cdf98d38978ba3e39493ef75" +sha256 = "e9801730750c13ce4cfe71fb5034a1a4e2984bd20b59ecaf94477c2dbc590e54" [[asset]] path = "crates/ui-egui/src/i18n/uk.tsv" diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 713bf60d..e55ba2ba 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -1997,3 +1997,110 @@ Printer properties プリンターのプロパティ Reset to printer defaults プリンターの初期設定に戻す This printer offers no settings of its own. このプリンターには独自の設定がありません。 + % of all commits 全コミットに占める割合(%) + +Bin +Bin + +LOC +LOC + @{login}: {prs} PRs, {commits} commits, +{added} / −{deleted} lines (Δ {delta}), +{bin_added} / −{bin_deleted} binary assets, {first} – {last} @{login}:PR {prs} 件、コミット {commits} 件、行数 +{added} / −{deleted}(Δ {delta})、バイナリファイル +{bin_added} / −{bin_deleted}、{first} – {last} + A button ボタン + A link リンク + A script スクリプト + About 概要 + Add {what} {what}を追加 + Align fields フィールドを整列 + Another file dialog is still open. Finish with it first. 別のファイルダイアログがまだ開いています。先にそちらの操作を終えてください。 + Basic constraints 基本制約 + Binary assets added 追加したバイナリファイル数 + Binary assets removed 削除したバイナリファイル数 + Change document properties 文書のプロパティを変更 + Change {what} {what}を変更 + Commits コミット + Company 企業 + Contributors 貢献者 + Couldn't show the file picker. Please try again. ファイル選択ダイアログを表示できませんでした。もう一度お試しください。 + Create 作成 + Create PDF from images 画像から PDF を作成 + Cut and stack 裁断して重ねる + DPI sets the printed page size without resampling the image. DPI で印刷時のページサイズが決まります。画像は再サンプリングされません。 + Default page display 既定のページ表示 + Default workspace mode 既定のワークスペースモード + Default zoom 既定のズーム + Display name 表示名 + Distribute fields フィールドを均等配置 + Documents and view 文書と表示 + Dynamic XFA form laid out from its template: {pages}, {fields}. テンプレートをもとにレイアウトした動的 XFA フォームです({pages}、{fields})。 + Files are combined in this order. Leave Pages empty to take every page. ファイルはこの順序で結合されます。すべてのページを含めるには、「ページ」を空欄のままにしてください。 + First 最初 + First commit 最初のコミット + Grab bag いろいろ + H / Space (hold) H / Space(押したまま) + Home / End Home / End + Last 最後 + Last commit 最後のコミット + Line delta 行数の増減 + Line ending 線端の形状 + Lines +/− 行数 +/− + Lines added 追加した行数 + Lines deleted 削除した行数 + Mark differences 相違点をマーク + Mark for redaction 墨消し対象としてマーク + Mark pages for redaction ページを墨消し対象としてマーク + Match field sizes フィールドのサイズを揃える + Merged PRs マージ済みの PR + Model モデル + Models モデル + Name (A–Z) 名前(A–Z) + No contributor data was built into this copy. このビルドには貢献者のデータが組み込まれていません。 + No model credits were built into this copy. このビルドにはモデルのクレジット情報が組み込まれていません。 + Only continue if you trust this document. An address can carry information from the document, such as what you typed into its form. この文書を信頼できる場合にのみ続行してください。アドレスには、フォームに入力した内容など、文書内の情報が含まれていることがあります。 + Open email app メールアプリを開く + Open link リンクを開く + Open this web page? このウェブページを開きますか? + PRs PRs + Place saved {what} 保存済みの{what}を配置 + Print single-sided. Keep the sheets in order, cut at the marks, then stack the piles left to right, top to bottom. 片面印刷してください。用紙の順序を保ったままマークに沿って裁断し、できた束を左から右、上から下の順に重ねてください。 + Real name 本名 + Remove saved {what} 保存済みの{what}を削除 + Reverse the order 並び順を逆にする + Run form script フォームのスクリプトを実行 + SHA-1 digest SHA-1 ダイジェスト + SHA-256 digest SHA-256 ダイジェスト + Scripted content must be usable with a keyboard and assistive technology. Check the document's scripts. スクリプトで動作するコンテンツは、キーボードや支援技術でも操作できる必要があります。文書のスクリプトを確認してください。 + Scripts run in a sandbox without file or network access. A script that asks to open a web page needs your permission first. With JavaScript off, Acrobat's standard format, validate and calculate functions still work. スクリプトは、ファイルやネットワークにアクセスできないサンドボックス内で実行されます。スクリプトがウェブページを開くには、事前にユーザーの許可が必要です。JavaScript がオフでも、Acrobat 標準の書式・検証・計算関数は引き続き動作します。 + Selected image files: {count} 選択した画像ファイル数:{count} + Show 表示 + Sign yourself 自分で署名 + Sort 並べ替え + Squiggly 波線 + Table 表 + Table rows belong directly in a table or its head, body or foot. Fix the table's tags. 表の行は、表、またはそのヘッダー・本体・フッターの直下に置く必要があります。表のタグを修正してください。 + Text recognition isn't installed: its models are missing (run `cargo xtask models`, or set PDFCRAFT_MODELS). テキスト認識がインストールされていません。必要なモデルがありません(`cargo xtask models` を実行するか、PDFCRAFT_MODELS を設定してください)。 + That didn't work: an internal error stopped it ({m}). 内部エラーのため、操作を完了できませんでした({m})。 + The Windows store's digital IDs couldn't be listed: {e} Windows 証明書ストアのデジタル ID の一覧を取得できませんでした:{e} + The document changed while you were choosing a file, so nothing was changed. ファイルを選択している間に文書が変更されたため、何も変更されていません。 + The document was closed before it could be saved. 保存する前に文書が閉じられました。 + The pages were extracted but not deleted, because the document changed while you were choosing a folder. フォルダーを選択している間に文書が変更されたため、ページは抽出しましたが、削除はしていません。 + This web address mixes letters from different alphabets, a common way to imitate another site's name. このウェブアドレスには、異なる文字体系の文字が混在しています。これはほかのサイトの名前を装う際によく使われる手口です。 + This web address uses letters from another alphabet, which can look like familiar ones. このウェブアドレスには別の文字体系の文字が使われており、見慣れた文字と似て見えることがあります。 + Use 72 DPI (one point per pixel) 72 DPI を使用(1 ピクセルあたり 1 ポイント) + Use custom DPI カスタム DPI を使用 + Use each image's embedded DPI; use 72 DPI when it is absent. 各画像に埋め込まれた DPI を使用します。埋め込まれていない場合は 72 DPI を使用します。 + Use image resolution 画像の解像度を使用 + Use {what} {what}を使用 + Used when a PDF doesn't ask for a layout or zoom. Continuous scrolling never snaps between pages. PDF にレイアウトやズームの指定がない場合に使用されます。連続スクロールでは、ページの境目にスナップすることはありません。 + Used when opening PDFs. An explicit launch or control mode takes precedence for the session. PDF を開くときに使用されます。起動モードや制御モードを明示的に指定した場合は、そのセッションではそちらが優先されます。 + Username ユーザー名 + Write this email? このメールを作成しますか? + XFA form: its fields and its XFA data are kept in step, so other viewers show what you fill in. XFA フォームです。フィールドと XFA データは常に同期されるため、入力した内容がほかのビューアーでも表示されます。 + {n} contributors · {c} commits 貢献者 {n} 人 · コミット {c} 件 + {who} in this document tried to open an address PdfCraft won't open: {e}. この文書内の{who}が、PdfCraft では開けないアドレスを開こうとしました:{e}。 + {who} in this document tried to open an address PdfCraft won't open: {e}. Only web (http, https) and email (mailto) links open from documents. この文書内の{who}が、PdfCraft では開けないアドレスを開こうとしました:{e}。文書から開けるのは、ウェブ(http、https)とメール(mailto)のリンクだけです。 + {who} in this document wants to open this address in your browser: この文書内の{who}が、次のアドレスをブラウザーで開こうとしています: + {who} in this document wants to open your email app with this address: この文書内の{who}が、次のアドレスでメールアプリを開こうとしています: + ΔLOC ΔLOC + −Bin −Bin + −LOC −LOC +@plural {n} field|{n} fields {n} 個のフィールド +@plural {n} page|{n} pages {n} ページ +signature pad Type 入力 + Flatten Fill & Sign when saving 保存時に入力と署名を統合する + Text, marks and signatures become part of the page. Other comments stay editable. テキスト、マーク、署名がページの一部になります。その他のコメントは引き続き編集できます。 diff --git a/crates/ui-egui/src/i18n/mod.rs b/crates/ui-egui/src/i18n/mod.rs index 15a33b78..5a05d3e3 100644 --- a/crates/ui-egui/src/i18n/mod.rs +++ b/crates/ui-egui/src/i18n/mod.rs @@ -670,6 +670,55 @@ mod tests { } } + /// Every `tl!("…")` literal in the UI source (test modules aside), unescaped. + fn ui_literals() -> std::collections::BTreeSet { + let mut stack = vec![std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src")]; + let mut literals = std::collections::BTreeSet::new(); + while let Some(dir) = stack.pop() { + for entry in std::fs::read_dir(dir).expect("UI source directory") { + let path = entry.expect("UI source entry").path(); + if path.is_dir() { + if path.file_name().is_some_and(|name| name != "i18n") { + stack.push(path); + } + } else if path.extension().is_some_and(|ext| ext == "rs") { + let source = std::fs::read_to_string(path).expect("UI source file").replace("\r\n", "\n"); + let mut rest = source.split("#[cfg(test)]\nmod ").next().unwrap_or_default(); + while let Some((_, after)) = rest.split_once("tl!(\"") { + let mut escaped = false; + let end = after + .char_indices() + .find_map(|(i, c)| { + if c == '"' && !escaped { + return Some(i); + } + escaped = c == '\\' && !escaped; + None + }) + .expect("closed tl! literal"); + let (raw, tail) = after.split_at(end); + if tail.starts_with("\")") { + let label: String = serde_json::from_str(&format!("\"{raw}\"")).expect("UI literal escapes"); + literals.insert(label); + } + rest = tail.strip_prefix('"').expect("closing quote"); + } + } + } + } + literals + } + + /// Japanese translates every `tl!("…")` literal in the UI source, so a new string can't ship in + /// English by accident (the same check French, German, Russian and Simplified Chinese have). + #[test] + fn japanese_covers_ui_literals() { + let literals = ui_literals(); + assert!(literals.len() > 900, "source scan found only {} literals", literals.len()); + let missing: Vec<_> = literals.iter().filter(|label| !has(JA(), label)).collect(); + assert!(missing.is_empty(), "untranslated Japanese UI literals: {missing:#?}"); + } + /// With craft-fonts, every Japanese translation has glyphs: with all interface faces (desktop) /// and with BIZ UDPGothic Regular alone (the web build's only Japanese face). #[test] diff --git a/docs/localization.md b/docs/localization.md index 43f77e38..e3e685a2 100644 --- a/docs/localization.md +++ b/docs/localization.md @@ -20,7 +20,7 @@ Japanese interface text uses BIZ UDPGothic from [craft-fonts](https://github.com There is no right-to-left interface language yet. File names and document titles in Arabic or Hebrew are drawn with a craft-fonts `Arab` face when the build input has one; on desktop, a character no embedded face has is drawn with one font already installed on the machine (`PDFCRAFT_SYSTEM_FONTS=0` turns this off). The tab strip, the recent-files list and Properties show such names in display order; other places (bookmarks, comments, search results) have the glyphs but may order mixed-direction text wrongly. -Simplified Chinese, French and German coverage tests, following PhotoCraft's complete-catalog approach, check every registered command, All tools label and `tl!("literal")` in the UI source. Simplified Chinese also checks direct `i18n::t` calls and multiline literals, plus the About tabs, contributor name modes, sort options, table headers and model columns. Generated history labels, contributor summaries and diagnostics are tested with user-supplied names and error details. Catalog coverage does not guarantee glyph coverage: the release-pinned craft-fonts input currently has no `Hans` face, and the web build embeds only BIZ UDPGothic Regular. Chinese font delivery remains separate work, as discussed in [#112](https://github.com/storytold/pdfcraft/pull/112) and [#140](https://github.com/storytold/pdfcraft/pull/140). +Japanese, Simplified Chinese, French and German coverage tests, following PhotoCraft's complete-catalog approach, check every registered command, All tools label and `tl!("literal")` in the UI source. Simplified Chinese also checks direct `i18n::t` calls and multiline literals, plus the About tabs, contributor name modes, sort options, table headers and model columns. Generated history labels, contributor summaries and diagnostics are tested with user-supplied names and error details. Catalog coverage does not guarantee glyph coverage: the release-pinned craft-fonts input currently has no `Hans` face, and the web build embeds only BIZ UDPGothic Regular. Chinese font delivery remains separate work, as discussed in [#112](https://github.com/storytold/pdfcraft/pull/112) and [#140](https://github.com/storytold/pdfcraft/pull/140). German labels keep nouns capitalized, including tool names inserted into notices. The certificate viewer uses the `certificate` context for `Subject` (the certificate holder), while document properties keep the plain translation (the topic). Search hints reserve room for the shortcut, and Home cards limit their title and description to the available rows; hovering shows the full text when it is shortened.