-
-
Notifications
You must be signed in to change notification settings - Fork 165
feat: add context menu translate option #718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add context menu translate option #718
Conversation
Add a right-click context menu option for quick page translation: - Add "Translate/Show Original" menu item that appears directly in the browser context menu (not in a submenu) - Menu title dynamically updates based on current translation state - Add toggle switch in Settings > Floating Button & Toolbar > Context Menu - Support 5 languages: English, Chinese (Simplified/Traditional), Japanese, Korean - Config schema migrated to v31 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
🦋 Changeset detectedLatest commit: dcbd358 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Related Documentation 1 document(s) may need updating based on files changed in this PR: Read Frog - Open Source Immersive Translate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 16 files
Prompt for AI agents (all 2 issues)
Understand the root cause of the following 2 issues and fix them.
<file name="src/entrypoints/background/index.ts">
<violation number="1" location="src/entrypoints/background/index.ts:82">
`setupContextMenu()` is invoked before the config is initialized, so on fresh installs it returns early and never creates the context menu. Await the config initialization (e.g., call `ensureInitializedConfig()` first) before running `setupContextMenu()` to guarantee the menu is registered.</violation>
</file>
<file name="src/entrypoints/background/context-menu.ts">
<violation number="1" location="src/entrypoints/background/context-menu.ts:75">
The context-menu label never updates when translation is toggled by other UI (floating button, auto-translate, etc.) because `updateTranslateMenuTitle` is only triggered on tab activation/update or when this menu item is clicked. Listen for translation state changes (e.g., via `storage.watch` or the existing `translationStateChanged` message) so the title immediately reflects the actual state.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
src/entrypoints/background/index.ts
Outdated
|
|
||
| newUserGuide() | ||
| translationMessage() | ||
| void setupContextMenu() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setupContextMenu() is invoked before the config is initialized, so on fresh installs it returns early and never creates the context menu. Await the config initialization (e.g., call ensureInitializedConfig() first) before running setupContextMenu() to guarantee the menu is registered.
Prompt for AI agents
Address the following comment on src/entrypoints/background/index.ts at line 82:
<comment>`setupContextMenu()` is invoked before the config is initialized, so on fresh installs it returns early and never creates the context menu. Await the config initialization (e.g., call `ensureInitializedConfig()` first) before running `setupContextMenu()` to guarantee the menu is registered.</comment>
<file context>
@@ -78,6 +79,7 @@ export default defineBackground({
newUserGuide()
translationMessage()
+ void setupContextMenu()
void setUpRequestQueue()
</file context>
| void setupContextMenu() | |
| void ensureInitializedConfig().then(() => setupContextMenu()) |
✅ Addressed in b224925
| /** | ||
| * Update translate menu title based on current translation state | ||
| */ | ||
| async function updateTranslateMenuTitle(tabId: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context-menu label never updates when translation is toggled by other UI (floating button, auto-translate, etc.) because updateTranslateMenuTitle is only triggered on tab activation/update or when this menu item is clicked. Listen for translation state changes (e.g., via storage.watch or the existing translationStateChanged message) so the title immediately reflects the actual state.
Prompt for AI agents
Address the following comment on src/entrypoints/background/context-menu.ts at line 75:
<comment>The context-menu label never updates when translation is toggled by other UI (floating button, auto-translate, etc.) because `updateTranslateMenuTitle` is only triggered on tab activation/update or when this menu item is clicked. Listen for translation state changes (e.g., via `storage.watch` or the existing `translationStateChanged` message) so the title immediately reflects the actual state.</comment>
<file context>
@@ -0,0 +1,131 @@
+/**
+ * Update translate menu title based on current translation state
+ */
+async function updateTranslateMenuTitle(tabId: number) {
+ if (!currentConfig?.contextMenu.translateEnabled) {
+ return
</file context>
✅ Addressed in b224925
Fix two issues identified in PR review:
1. Ensure config is initialized before setupContextMenu
- Changed main() to async and await ensureInitializedConfig()
- Prevents context menu from failing to create on fresh installs
2. Update menu title when translation state changes from other UI
- Listen to setEnablePageTranslation messages
- Listen to setEnablePageTranslationOnContentScript messages
- Listen to checkAndSetAutoTranslation messages
- Menu title now updates when translation is toggled via floating
button, auto-translate, or any other UI component
- Only update menu for currently active tab to improve performance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
修复完成 / Fixes Applied已经修复了 @cubic-dev-ai 提出的两个问题: Issue 1: Config initialization timing ✅问题: 修复:
影响文件: Issue 2: Menu title not updating from other UI ✅问题: 通过其他 UI(浮动按钮、自动翻译等)切换翻译状态时,上下文菜单标题不更新。 修复:
影响文件: 所有测试通过 (306/306) ✅ |
Remove readEnabled field from context menu configuration as it will not be implemented. Changes: - Remove readEnabled from contextMenuSchema - Remove readEnabled from DEFAULT_CONFIG - Remove readEnabled from v030-to-v031 migration script - Remove readEnabled from test examples The context menu will only support translate functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 2 files (reviewed changes from recent commits).
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="src/entrypoints/background/context-menu.ts">
<violation number="1" location="src/entrypoints/background/context-menu.ts:66">
`checkAndSetAutoTranslation` updates the context-menu title even for background tabs, so the visible menu can show the wrong state. Guard this handler the same way as the other message listeners by ensuring only the active tab can change the title.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
Fix issue where background tabs triggering auto-translation would incorrectly update the visible context menu title. Now the checkAndSetAutoTranslation handler checks if the tab is active before updating the menu title, consistent with other message handlers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
已修复 @cubic-dev-ai 指出的问题:后台标签自动翻译时不应更新可见菜单标题。现在添加了活动标签检查,只有当前活动标签才会更新菜单。 Fix: Added active tab check in checkAndSetAutoTranslation handler. Now only the currently active tab will update the context menu title. All tests pass ✅ (306/306) |
|
Wait, there's a problem. Let me fix it. |
Fix translation failure caused by conflicting message handlers. Previously, context-menu.ts listened to setEnablePageTranslation and related messages, which interfered with the same handlers in translation-signal.ts, breaking the translation functionality. Solution: - Use browser.storage.session.onChanged to listen for translation state changes in storage instead of intercepting messages - This approach monitors state changes from all sources (floating button, auto-translate, context menu) without interfering with the translation logic - Only updates menu title for the currently active tab 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
紧急修复:翻译功能失效问题 ✅之前的修复导致翻译功能完全失效。问题根源和解决方案: 问题根源在 context-menu.ts 中监听了 解决方案改用
验证所有测试通过 ✅ (306/306),翻译功能已恢复正常。 Fix: Translation functionality broken Root cause: Conflicting message handlers between context-menu.ts and translation-signal.ts. Solution: Use storage.session.onChanged listener instead of message handlers to monitor translation state changes without interfering with core translation logic. |
Add configuration validation before enabling translation from context
menu, preventing silent failures when config is invalid.
Changes:
1. Add validateTranslationConfigInBackground() function
- Validates provider exists
- Checks source/target language mismatch
- Verifies API key configuration
- Logs warnings instead of showing toasts (background context)
2. Validate config before setting translation state
- Only validates when enabling translation
- Shows error notification to user via content script
- Prevents state change if validation fails
3. Add showTranslationConfigError message
- Sent from background to content script
- Content script calls validateTranslationConfig to show
proper error toasts with specific error messages
4. Update changeset with permission warning
- Alert users about new contextMenus permission requirement
- Explain browser permission prompt behavior on upgrade
This ensures context menu behaves consistently with other UI
components (floating button, popup, keyboard shortcut).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
✅ 已修复两个重要问题1. Medium 优先级:添加配置校验 ✅问题:右键菜单点击直接切换翻译状态,没有像其他 UI(浮动按钮、快捷键、弹窗)那样进行配置校验。 修复:
影响文件:
现在右键菜单的行为与其他 UI 组件保持一致。 2. Release Note:权限变更说明 ✅问题:新增 修复:在 changeset 中添加了明确的警告说明:
影响文件:
所有测试通过 ✅ (306/306) |
mengxi-ream
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haven't done the full review yet, but there is a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 4 files (reviewed changes from recent commits).
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="src/entrypoints/background/context-menu.ts">
<violation number="1" location="src/entrypoints/background/context-menu.ts:159">
Auto-mode same-language detection now blocks translation in the context menu, unlike the existing validation which only warns, so right-click translations get incorrectly rejected whenever the detected language equals the target language.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| // Check if provider exists | ||
| if (!providerConfig) { | ||
| logger.warn('[ContextMenu] Translation provider not found') | ||
| return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-mode same-language detection now blocks translation in the context menu, unlike the existing validation which only warns, so right-click translations get incorrectly rejected whenever the detected language equals the target language.
Prompt for AI agents
Address the following comment on src/entrypoints/background/context-menu.ts at line 159:
<comment>Auto-mode same-language detection now blocks translation in the context menu, unlike the existing validation which only warns, so right-click translations get incorrectly rejected whenever the detected language equals the target language.</comment>
<file context>
@@ -142,6 +145,41 @@ async function handleContextMenuClick(
+ // Check if provider exists
+ if (!providerConfig) {
+ logger.warn('[ContextMenu] Translation provider not found')
+ return false
+ }
+
</file context>
✅ Addressed in bca207f
…cycle - Replace storage.watch() with browser.storage.local.onChanged to ensure listener survives service worker sleep/wake cycles - Fix auto-mode validation to only warn (not block) when detected language matches target language, matching original validateTranslationConfig behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
修复完成已修复 review 中指出的两个问题: 1. Service Worker 生命周期持久化问题位置: 问题: 修复: 替换为 native Chrome API // Listen for config changes using native Chrome API for persistence
// This ensures the listener survives service worker sleep/wake cycles
browser.storage.local.onChanged.addListener(async (changes) => {
const configChange = changes[CONFIG_STORAGE_KEY]
if (configChange?.newValue) {
currentConfig = configChange.newValue as Config
await updateContextMenuItems(currentConfig)
}
})2. 自动模式语言验证逻辑问题位置: 问题: 自动模式下检测到的语言与目标语言相同时错误地阻止了翻译 修复: 改为只警告不阻止翻译,与 // Check if detected language and target language are the same in auto mode
// Note: Unlike the case above, this only warns but does NOT block translation
// This matches the behavior of validateTranslationConfig in translate-text.ts
if (languageConfig.sourceCode === 'auto' && languageConfig.detectedCode === languageConfig.targetCode) {
logger.warn('[ContextMenu] Detected language matches target language in auto mode')
// Don't return false - allow translation to proceed with warning
}验证结果:
提交: bca207f |
|
@mengxi-ream |
|
I may review your code tomorrow, it's midnight in my time zone |
mengxi-ream
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The design has a serious bug, which will cause onInstalled listener fails to work
The Problem
What Doesn't Work
When a user installs the extension from Chrome Web Store:
// Current code (broken)
main: async () => {
logger.info('Hello background!')
// ❌ Config init happens BEFORE listener registration
await ensureInitializedConfig()
browser.runtime.onInstalled.addListener(async (details) => {
await ensureInitializedConfig()
if (details.reason === 'install') {
// This code never runs on fresh install ❌
await browser.tabs.create({
url: `${WEBSITE_URL}/guide/step-1`,
})
}
})
void setupContextMenu()
}Expected: Guide tab opens on install
Actual: Nothing happens, event is silently lost
Root Cause Analysis
Code Changes in PR 718
Commit: b224925d - "fix: address context menu initialization and update issues"
Date: 2025-11-21
The change:
export default defineBackground({
type: 'module',
- main: () => {
+ main: async () => {
logger.info('Hello background!', { id: browser.runtime.id })
+
+ // Ensure config is initialized before setting up features that depend on it
+ await ensureInitializedConfig()
browser.runtime.onInstalled.addListener(async (details) => {Why this change was made:
setupContextMenu()requires initialized config to work properly- Adding top-level
await ensureInitializedConfig()guaranteed config readiness - Fixed context menu issues on fresh installs
Unintended consequence:
- Broke the install event handler due to async timing issues
Deep Dive: Chrome Extension Event Mechanics
Mechanism 1: Chrome Extension Event Buffering
Chrome Extension API is implemented in C++ within the Chrome browser process. When an extension is installed:
Chrome C++ Event Processing:
┌─────────────────────────────────────────┐
│ 1. Extension Installed │
│ ↓ │
│ 2. Fire onInstalled event │
│ ↓ │
│ 3. Check: Is background script loaded? │
│ ├─ Yes → Check for listeners │
│ │ ├─ Has listener → Dispatch ✅ │
│ │ └─ No listener → WAIT (buffer) │
│ └─ No → WAIT for script to load │
└─────────────────────────────────────────┘
Key insight: Chrome doesn't immediately discard the onInstalled event. Instead, it buffers the event and waits for background script initialization to complete.
However, "initialization complete" has a specific definition that causes our bug...
Mechanism 2: JavaScript Event Loop and Execution Context
JavaScript execution follows a specific model:
Event Loop Cycle:
┌─── Macrotask Queue ───────┐
│ - Script evaluation │
│ - setTimeout callbacks │
│ - I/O completion events │
└────────────────────────────┘
↓
Execute one
↓
┌─── Microtask Queue ────┐
│ - Promise.then() │
│ - queueMicrotask() │
│ - async/await resume │
└────────────────────────┘
↓
Execute all
↓
(Repeat cycle)
Critical behavior of await:
- When JavaScript hits an
await, the current function pauses and returns a Promise - Code after the
awaitis scheduled as a microtask/continuation - Control returns to the event loop immediately
Chrome's View: When Is "Initialization Complete"?
// Chrome C++ pseudocode
void BackgroundScriptLoaded(Script script) {
ExecuteScript(script); // Executes main()
// main() returns here (sync return OR Promise return)
if (IsInitializationComplete()) {
DispatchBufferedEvents(); // ← Checks for listeners NOW
}
}
bool IsInitializationComplete() {
// Initialization = top-level code finished executing
return topLevelCodeExecuted;
// NOTE: async function calls return immediately with a Promise,
// so Chrome considers this "executed" even though the Promise
// hasn't resolved yet!
}The key misunderstanding:
- Chrome considers initialization complete when
main()returns - For async functions,
main()returns immediately (a Promise), not when the Promise resolves - Listener registration after an
awaithappens after Chrome checks for listeners
Timeline Comparisons
Before PR 718: Synchronous Version (Working ✅)
main: () => { // Synchronous function
logger.info('Hello background!')
browser.runtime.onInstalled.addListener(async (details) => {
await ensureInitializedConfig()
if (details.reason === 'install') {
await browser.tabs.create({ url: `${WEBSITE_URL}/guide/step-1` })
}
})
// ... rest of code
}Execution timeline:
t=0ms: User clicks "Install" in Chrome Web Store
↓
t=0ms: Chrome C++: Fire onInstalled event
↓
t=0ms: Chrome C++: Buffer event, wait for background script init
↓
t=1ms: Load background.js
↓
t=2ms: V8 Engine: Start executing main() [MACROTASK START]
├─ t=2ms: logger.info() executes
├─ t=3ms: addListener() executes ← Listener registered ✅
├─ t=4ms: ... rest of synchronous code
└─ t=5ms: main() returns [MACROTASK END]
↓
t=6ms: V8: "Macrotask complete, no more synchronous code"
↓
t=6ms: Chrome C++: "Background script initialized"
↓
t=6ms: Chrome C++: Check for onInstalled listeners → Found! ✅
↓
t=6ms: Chrome C++: Dispatch buffered event to listener
↓
t=7ms: Listener callback executes
├─ Await config init
└─ Open guide tab ✅
Key: Entire main() function executes as one continuous macrotask. Chrome checks for listeners after the macrotask completes, finding the listener that was registered during execution.
After PR 718: Async + Await Version (Broken ❌)
main: async () => { // Async function
logger.info('Hello background!')
await ensureInitializedConfig() // ← BLOCKING POINT
browser.runtime.onInstalled.addListener(async (details) => {
await ensureInitializedConfig()
if (details.reason === 'install') {
await browser.tabs.create({ url: `${WEBSITE_URL}/guide/step-1` })
}
})
void setupContextMenu()
}Execution timeline:
t=0ms: User clicks "Install" in Chrome Web Store
↓
t=0ms: Chrome C++: Fire onInstalled event
↓
t=0ms: Chrome C++: Buffer event, wait for background script init
↓
t=1ms: Load background.js
↓
t=2ms: V8 Engine: Start executing main() [MACROTASK START]
├─ t=2ms: logger.info() executes
├─ t=3ms: Hit 'await ensureInitializedConfig()'
│ ↓
│ Start async I/O (browser.storage.local.get)
│ ↓
└─ t=3ms: main() PAUSES and returns Promise [MACROTASK END] ⚠️
t=4ms: V8: "Macrotask complete (main() returned Promise)"
↓
t=4ms: Chrome C++: "Background script initialized" ⚠️
↓
t=4ms: Chrome C++: Check for onInstalled listeners → None found! ❌
↓
t=4ms: Chrome C++: No listeners, discard buffered event ❌
[Meanwhile, async operations continue in parallel...]
t=5ms: ensureInitializedConfig() running (storage I/O)
t=20ms: Storage I/O completes
t=21ms: V8: Schedule microtask to resume main()
t=22ms: V8: Resume main() execution after await
├─ t=22ms: addListener() NOW executes ← Too late! ❌
├─ t=23ms: setupContextMenu() executes
└─ t=24ms: main() Promise resolves
Result: Listener registered 18ms after Chrome already discarded the event ❌
Key difference:
awaitcausesmain()to return a Promise immediately (t=3ms)- Chrome considers this "initialization complete" and checks for listeners (t=4ms)
- No listener exists yet, so event is discarded
- Listener is registered later (t=22ms) after async operation completes, but it's too late
|
Please review the design that the AI provided to you carefully. I will conduct several more reviews, hopefully I won't see these design flaws persist Don't rely entirely on AI; instead, you should take the lead and guide AI, rather than letting it guide you. |
Revert main() from async to sync to ensure runtime.onInstalled listener is registered before Chrome completes initialization. The previous async implementation caused the listener to register too late, missing install events. setupContextMenu() already handles config initialization internally, so no pre-initialization is needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
Still fixing it, I'll tag you when it's done. |
Split setupContextMenu() into two functions to comply with Chrome Extension event listener registration requirements: 1. registerContextMenuListeners() - Synchronously registers all event listeners during main() execution, ensuring they're registered before Chrome completes initialization and checks for listeners 2. initializeContextMenu() - Asynchronously initializes menu items after config is loaded This fixes the architectural issue where listeners registered after await would be registered too late, potentially missing events during extension installation or updates. Addresses review feedback in mengxi-ream#718 (review 3495276550) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
已修复 Review #3495276550 中指出的架构问题问题根源Review 详细分析指出:在 Chrome Extension 中,所有事件监听器必须在 之前的实现存在致命缺陷: // ❌ 错误的实现
export async function setupContextMenu() {
await ensureInitializedConfig() // 在这里 await 导致函数暂停
// 这些监听器在 await 之后注册(太晚了)
browser.contextMenus.onClicked.addListener(...)
browser.tabs.onActivated.addListener(...)
}时间线问题: 解决方案将 1. export function registerContextMenuListeners() {
// ✅ 纯同步函数,无 await
browser.storage.local.onChanged.addListener(async (changes) => { ... })
browser.tabs.onActivated.addListener(async (activeInfo) => { ... })
browser.tabs.onUpdated.addListener(async (tabId, changeInfo) => { ... })
browser.storage.session.onChanged.addListener(async (changes) => { ... })
browser.contextMenus.onClicked.addListener(handleContextMenuClick)
}2. export async function initializeContextMenu() {
// ✅ 异步获取 config 并创建菜单项
const config = await ensureInitializedConfig()
if (!config) return
currentConfig = config
await updateContextMenuItems(config)
}3. 在 main: () => {
// ✅ 同步注册所有监听器
browser.runtime.onInstalled.addListener(...)
onMessage('openPage', ...)
registerContextMenuListeners() // ← 同步调用,立即注册
// ✅ 异步初始化(不阻塞)
void initializeContextMenu() // ← 异步调用,不等待
}新的执行时间线架构优势
验证结果
提交: fd9aa1c 现在所有 Review #3495276550 中指出的问题都已经修复。 |
Remove v030-to-v031 migration scripts and revert CONFIG_SCHEMA_VERSION to v30. Version migrations should be handled separately in release process. Changes: - Delete src/utils/config/migration-scripts/v030-to-v031.ts - Delete src/utils/config/__tests__/example/v031.ts - Revert CONFIG_SCHEMA_VERSION from 31 to 30 - Remove v031 references from migration.ts The contextMenu feature will work with the default config without requiring a schema version bump. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
已移除版本迁移相关内容该功能分支不应包含版本升级相关的内容。已移除所有版本迁移代码: 删除的文件
修改的文件
功能实现Context menu 功能使用 default config 中的 export const DEFAULT_CONFIG: Config = {
// ... other configs
contextMenu: {
translateEnabled: true,
},
}提交: ba88b79 现在该分支只包含纯功能代码,不包含任何版本升级相关内容。 |
|
Please don't review yet; I need to wait for the results from the Cubic AI code reviewer. |
|
I think I've fixed it. I roughly understand the loading timing issue you mentioned, but I don't know much about Chrome extensions, so I had to rely on AI to help me fix it. And after testing, all functions are working correctly. I've removed the AI-generated version updates and migration-related content. Please review again, thank you. |


Type of Changes
Description
This PR adds a context menu option that allows users to translate webpages directly from the browser's right-click menu, providing a more convenient way to access translation functionality.
Key Features
Technical Implementation
Background Script (
src/entrypoints/background/context-menu.ts):Configuration Updates:
contextMenufield withtranslateEnabledpropertySettings UI:
Permissions: Added
contextMenuspermission to manifestFiles Changed
src/entrypoints/background/context-menu.tssrc/entrypoints/options/pages/floating-button-and-toolbar/context-menu-translate-toggle.tsxsrc/utils/config/migration-scripts/v030-to-v031.tssrc/utils/config/__tests__/example/v031.ts.changeset/context-menu-translate.mdRelated Issue
N/A - Internal feature request
How Has This Been Tested?
Checklist
Additional Information
Design Decision
Initially planned to add both "Translate" and "Read" options, but Chrome automatically creates a submenu when multiple context menu items are registered under the same extension. To keep the menu at the top level for better UX, only the "Translate" option was implemented (with "Read" disabled by default in config for potential future use).
Technical Note
The implementation avoids background-to-background message passing (which doesn't work in WXT) by directly updating storage and sending messages to content scripts instead.
Summary by cubic
Adds a right-click “Translate” menu item that toggles page translation and switches to “Show Original” when active. Includes a settings toggle and full i18n support.
New Features
Migration
Written for commit ba88b79. Summary will update automatically on new commits.