<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ollama-translations.git/src/background/translation-service.js, branch v0.1.0</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://git.takashi-2521.com/ollama-translations.git/atom?h=v0.1.0</id>
<link rel='self' href='https://git.takashi-2521.com/ollama-translations.git/atom?h=v0.1.0'/>
<link rel='alternate' type='text/html' href='https://git.takashi-2521.com/ollama-translations.git/'/>
<updated>2026-09-01T18:14:05+00:00</updated>
<entry>
<title>feat: PDF Viewer translation via context menu and two-mode Action Popup</title>
<updated>2026-09-01T18:14:05+00:00</updated>
<author>
<name>tanaka takashi</name>
<email>isazaka@gmail.com</email>
</author>
<published>2026-09-01T18:14:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.takashi-2521.com/ollama-translations.git/commit/?id=82bb55f66071b452e3bc7adeb09eafb5003de11f'/>
<id>urn:sha1:82bb55f66071b452e3bc7adeb09eafb5003de11f</id>
<content type='text'>
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 -&gt; translation -&gt; 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).
</content>
</entry>
</feed>
