From 82bb55f66071b452e3bc7adeb09eafb5003de11f Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Wed, 2 Sep 2026 03:14:05 +0900 Subject: feat: PDF Viewer translation via context menu and two-mode Action Popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Firefox built-in PDF Viewer support using only public WebExtensions APIs: a selection context menu ("選択したテキストを翻訳") starts a translation and the toolbar Action Popup shows the streaming result. No content-script injection into the privileged PDF Viewer, no PDF.js internals, no separate windows, no custom viewer (Specifications.md §4.6). Specification alignment (Phase 1) - Specifications.md: new requirements PDF-01..04 (PDF selection translation), CTX-01..03 (context menu translation), POP-01..06 (popup two modes); SEL-06 updated to route PDF through the menus API; section 13.4 adds a 14-item manual PDF verification checklist; section 15 removes "Firefox内蔵PDF Viewerへの対応" from out-of-scope - Design.md: architecture diagram with the menus path, menu-translation component, menus permission, popup translation-result state machine (idle/starting/streaming/completed/error/cancelled), shared translation state (§9.2), context-menu integration phase, test plan and API audit checklist items (menus permission scope, no PDF Viewer internals) - Security.md: menus permission restricted to selection-context translation; PDF Viewer treated as privileged browser UI (no injection, no wrappedJSObject/cloneInto/exportFunction, no internal DOM access); menus.OnClickData.selectionText treated as untrusted input passing the same validation pipeline; popup result rendering stays textContent-only Background (Phase 2) - translation-service.js (new): the single translation pipeline shared by every entry point - selection validation (type/trim/empty/control chars/max length), prompt building, Ollama request, session/abort, and the shared translation state (requestId, sourceText, translatedText, status, model, error, startedAt, source). "source" is metadata only; a PDF-specific translation engine does not exist - menu-translation.js (new): validates menus.OnClickData.selectionText and starts a sink-less translation observed via GET_POPUP_STATE - message-router.js: routes port translations through the shared service; new runtime messages GET_POPUP_STATE and REGENERATE_LAST; popup-state port handler broadcasts live state (initial push + every chunk/status change) so an open popup shows streaming progress in real time - index.js: registers the selection context menu (contexts: ["selection"] only, no menus.onShown) and calls browser.action.openPopup() synchronously inside the click user gesture, catching failures so a popup-open problem never breaks the translation itself - manifest.json: permissions now ["storage", "menus"] - settings-service.js: __resetCacheForTests hook for test isolation Popup two-mode UI (Phase 3) - popup.html/js/css: mode nav (設定 / 翻訳). Translation mode shows status, model, streaming text (textContent only), user-safe error, and copy (Clipboard API only, no execCommand fallback), regenerate (new requestId reusing the stored source text) and a settings shortcut. Closing the popup never cancels the request; reopening shows the latest text and continues receiving chunks live. Initial mode: active (starting/streaming) translation wins, otherwise the last tab the user picked is restored (storage.local.popupMode, default settings) Fresh-install model auto-selection - translation-service.js ensureModelConfigured(): when storage.model is empty, pick the first model from the running Ollama and persist it before translating, mirroring the popup/options auto-select. A user who never opened any settings UI can translate immediately; when Ollama is unreachable a clear OLLAMA_UNAVAILABLE message is shown User-safe error details - detailForUser(): strips URLs (no internal host names echoed to the UI), caps length at 120 chars, drops full JSON response bodies, and hides meaningless low-level network errors so the popover/popup shows the base message plus at most a short, safe detail Tests: 85 passed, 0 failed - selectionText validation (untrusted input pipeline) - menu selection -> translation -> popup state streaming/completed - empty selection rejected without starting a request - streaming status transitions observed through GET_POPUP_STATE - Ollama unreachable surfaces a user-safe error into popup state - newer request replaces older state (abort semantics) - regenerateLast reuses source text with a fresh requestId - popup-state port receives live broadcasts; wrong port names ignored - fresh-install auto-select persists the first Ollama model - error detail sanitization (URL stripping, length cap, JSON drop) - popup/options smoke tests updated for the two-mode markup - setupRouter resets the shared settings cache for test isolation Docs: README documents the two-mode popup and PDF flow; Testing-Results records automated results and the manual PDF checklist (to be executed). No git-side surprises: this commit was created explicitly on request (requirement 18 of the PDF task had deferred commits until now). --- doc/Specifications.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'doc/Specifications.md') diff --git a/doc/Specifications.md b/doc/Specifications.md index ac6600d..617ddfd 100644 --- a/doc/Specifications.md +++ b/doc/Specifications.md @@ -57,7 +57,7 @@ Firefox上でユーザーがWebページ内の文字列を選択した際、選 | SEL-03 | 選択解除時は翻訳アイコンを非表示にすること | | SEL-04 | 選択範囲の位置を取得し、その近傍に翻訳アイコンを表示すること | | SEL-05 | 初期版ではトップレベル文書のみ対象とし、iframe内は対象外とすること | -| SEL-06 | Firefox内部ページ、Reader View、view-source、内蔵PDF Viewer等、Content Scriptを利用できないページは対象外とすること | +| SEL-06 | Firefox内部ページ、Reader View、view-source等、Content Scriptを利用できないページは対象外とすること。Firefox内蔵PDF Viewerはcontent scriptでなく menus APIで対応する(PDF-01) | ### 4.2 翻訳アイコン @@ -104,6 +104,40 @@ Firefox上でユーザーがWebページ内の文字列を選択した際、選 | EN-01 | 拡張機能の翻訳機能を設定画面から有効/無効に切り替えられること | | EN-02 | 無効時は選択文字列に対して翻訳アイコンを表示しないこと | +### 4.6 PDF Selection Translation + +Firefox内蔵PDF Viewer上でテキストを選択し、右クリックで context menu の「選択したテキストを翻訳」を実行すると翻訳を開始できること。 + +| ID | 要件 | +|---|---| +| PDF-01 | Firefox内蔵PDF Viewerでのみ、context menu経由で翻訳を開始できること | +| PDF-02 | context menu翻訳の結果は Action Popup に streaming 表示すること | +| PDF-03 | PDF Viewer への content script注入・translation popover表示は対象外 | +| PDF-04 | 独自PDF Viewer・PDF.js同梱・外部変換サービスの利用は対象外 | + +### 4.7 Context Menu Translation + +通常Webページでも同じ context menu操作を使用可能とすること。 + +| ID | 要件 | +|---|---| +| CTX-01 | 選択文字列の `menus.OnClickData.selectionText` を取得し translationを実行できること | +| CTX-02 | 通常ページとFirefox PDF Viewerで同じ操作を利用できること | +| CTX-03 | `menus` permission は selection context translationのみに使用すること | + +### 4.8 Popup 2モード化 + +Action Popupに「設定モード」と「翻訳結果モード」を実装すること。 + +| ID | 要件 | +|---|---| +| POP-01 | Action Popupが設定UIと翻訳結果UIの2モードを切り替えられること | +| POP-02 | 翻訳結果モードはコピー・再生成・エラー表示・status表示を提供すること | +| POP-03 | popupが閉じられた場合でも翻訳requestを自動cancelしないこと | +| POP-04 | 新しい翻訳request開始時に進行中 requestを abortしてもよい | +| POP-05 | popup 開いた時に最新の translation stateを取得できること | +| POP-06 | streaming中にpopupが開かれた場合でも、その時点までのtranslation textを表示し、その後のchunkを継続受信できること | + --- ## 5. 設定要件 @@ -352,6 +386,27 @@ Firefox上でユーザーがWebページ内の文字列を選択した際、選 13. ページ内のHTMLらしき文字列やscript文字列を選択してもDOM実行されない。 14. LLM出力にHTML文字列が含まれてもHTMLとして解釈されない。 +### 13.4 PDF Viewer実機動作確認 + +以下の操作を実Firefox + 実Ollamaで確認すること。 + +| # | 確認項目 | +|---|---| +| 1 | 通常Webページで文字列を選択する | +| 2 | context menuに「選択したテキストを翻訳」が表示される | +| 3 | menuからtranslationを開始できる | +| 4 | Firefox内蔵PDF ViewerでPDFを開く | +| 5 | PDF内のテキストを選択する | +| 6 | context menuに翻訳項目が表示される | +| 7 | `selectionText` が取得される | +| 8 | Action Popupが開く | +| 9 | Ollama streaming結果が逐次表示される | +| 10 | Copyが動く | +| 11 | Regenerateが動く | +| 12 | Ollama停止時に安全なエラー表示になる | +| 13 | HTML/script風のPDF文字列を選択しても実行されない | +| 14 | 新しい翻訳開始時に古いrequestが正しくcancelされる | + --- ## 14. 受け入れ条件 @@ -379,7 +434,6 @@ Firefox上でユーザーがWebページ内の文字列を選択した際、選 - Chrome/Edge完全互換 - iframe内翻訳 -- Firefox内蔵PDF Viewerへの対応 - 翻訳履歴管理 - チャット機能 - 複数同時翻訳 @@ -389,3 +443,5 @@ Firefox上でユーザーがWebページ内の文字列を選択した際、選 - Markdown/HTMLリッチレンダリング - 自動翻訳(選択しただけでLLM実行) - `tfs_z` / `mirostat*` +- Firefox内蔵PDF Viewerへのページ内translation icon / popover表示(content script注入不可のため) +- 独自PDF Viewer・外部PDF変換サービス -- cgit v1.2.3