Skip to content

feat: add 1-click copy to text translation#605

Open
cooleymr wants to merge 1 commit into
translate-tools:masterfrom
cooleymr:my-feature
Open

feat: add 1-click copy to text translation#605
cooleymr wants to merge 1 commit into
translate-tools:masterfrom
cooleymr:my-feature

Conversation

@cooleymr
Copy link
Copy Markdown

@cooleymr cooleymr commented May 4, 2026

Closes #601

Feature request: Add a 1-click translation button to the 'Text Translation' section of the project.
Currently, if a user is translating text in the 'Text Translation' feature, they must manually highlight and copy text before they are able to use it. This is inefficient and can be sped up.

This 1-click copy button saves the user about 1-2 seconds per text copy, which compounds heavily over time.

Summary by CodeRabbit

  • New Features
    • Added a copy-to-clipboard button in the text translation results area, enabling users to quickly copy translated text to their clipboard.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

A new content-copy icon glyph is defined and registered in the icon bundle, then integrated into the TextTranslator component as a copy-to-clipboard button. The button writes the current translation result text to the clipboard and displays the appropriate label.

Changes

Icon Glyph and TextTranslator Copy Button

Layer / File(s) Summary
Icon Primitive Definition
src/components/primitives/Icon/_glyph/Icon_glyph_content-copy.tsx
New glyph module withGlyphContentCopy wraps IconConstructor for the content-copy SVG asset with optional glyph constraint.
Icon Bundle Registration
src/components/primitives/Icon/Icon.bundle/desktop.ts
Imports withGlyphContentCopy and adds it to the composeU glyph modifier chain for desktop icon behavior.
Feature Implementation
src/pages/popup/tabs/TextTranslator/TextTranslator.tsx
Copy button added to result toolbar, disabled when translation is absent, and writes resultText to navigator.clipboard on press.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Poem

A bunny's delight, so eager and quick,
Now copies with one clever click!
The glyph hops in place with content so fair,
From translator's heart to clipboard's care. 🐰📋✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature: adding a 1-click copy functionality to text translation.
Description check ✅ Passed The description includes the issue reference, explains the problem and solution, but is missing the 'How this change fixes it' section structure.
Linked Issues check ✅ Passed The PR addresses feature request #601 by implementing 1-click copy functionality for text translation as described in the PR objectives.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the 1-click copy feature: new icon glyph, icon bundle integration, and copy button in TextTranslator component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/pages/popup/tabs/TextTranslator/TextTranslator.tsx (1)

480-484: 💤 Low value

Consider handling clipboard API errors.

navigator.clipboard.writeText() returns a Promise that can reject (e.g., due to permissions). While unlikely in an extension popup, adding a .catch() would improve robustness.

Example with error handling
 onPress={() => {
-  if (resultText !== null) {
-    navigator.clipboard.writeText(resultText);
+  if (translation !== null) {
+    navigator.clipboard.writeText(translation.text).catch(() => {
+      // Optionally show error feedback to user
+    });
   }
 }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/popup/tabs/TextTranslator/TextTranslator.tsx` around lines 480 -
484, The onPress handler currently calls
navigator.clipboard.writeText(resultText) without handling rejections; update
the onPress in TextTranslator (the inline handler that checks resultText !==
null) to await or chain a .then/.catch on
navigator.clipboard.writeText(resultText) and handle errors (e.g., show a
user-facing toast/alert or log via console/processLogger) so permission or
runtime failures are caught and reported; ensure you still guard for resultText
null before calling writeText and keep the handler idempotent for multiple
presses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/popup/tabs/TextTranslator/TextTranslator.tsx`:
- Around line 478-490: The copy Button currently only disables when translation
or resultText are null, which still allows copying the placeholder ('...') or an
error string; update the Button's disabled condition to also check the
inTranslateProcess flag and errorMessage state (e.g., disabled={translation ===
null || resultText === null || inTranslateProcess || !!errorMessage}) and
tighten the onPress guard to only call navigator.clipboard.writeText(resultText)
when resultText is a valid completed translation (not the placeholder), e.g.,
ensure resultText !== '...' and errorMessage is falsy before copying; modify
references around the Button, navigator.clipboard.writeText, and the
translation/resultText state to implement this change.

---

Nitpick comments:
In `@src/pages/popup/tabs/TextTranslator/TextTranslator.tsx`:
- Around line 480-484: The onPress handler currently calls
navigator.clipboard.writeText(resultText) without handling rejections; update
the onPress in TextTranslator (the inline handler that checks resultText !==
null) to await or chain a .then/.catch on
navigator.clipboard.writeText(resultText) and handle errors (e.g., show a
user-facing toast/alert or log via console/processLogger) so permission or
runtime failures are caught and reported; ensure you still guard for resultText
null before calling writeText and keep the handler idempotent for multiple
presses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ef0bb297-edc8-4497-96dd-10b4b5686141

📥 Commits

Reviewing files that changed from the base of the PR and between 1a0c5ea and 88817fd.

⛔ Files ignored due to path filters (17)
  • .DS_Store is excluded by !**/.DS_Store
  • .github/.DS_Store is excluded by !**/.DS_Store
  • docs/.DS_Store is excluded by !**/.DS_Store
  • packages/.DS_Store is excluded by !**/.DS_Store
  • src/.DS_Store is excluded by !**/.DS_Store
  • src/components/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Button/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Icon/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Icon/Icon.assets/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Icon/Icon.assets/Material/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Icon/Icon.assets/Material/content_copy.svg is excluded by !**/*.svg
  • src/components/primitives/Modal/.DS_Store is excluded by !**/.DS_Store
  • src/components/primitives/Notification/.DS_Store is excluded by !**/.DS_Store
  • thirdparty/.DS_Store is excluded by !**/.DS_Store
  • thirdparty/bergamot/.DS_Store is excluded by !**/.DS_Store
  • thirdparty/bergamot/src/.DS_Store is excluded by !**/.DS_Store
📒 Files selected for processing (3)
  • src/components/primitives/Icon/Icon.bundle/desktop.ts
  • src/components/primitives/Icon/_glyph/Icon_glyph_content-copy.tsx
  • src/pages/popup/tabs/TextTranslator/TextTranslator.tsx

Comment on lines +478 to +490
<Button
disabled={translation === null || resultText === null}
onPress={() => {
if (resultText !== null) {
navigator.clipboard.writeText(resultText);
}
}}
view="clear"
size="s"
title={getMessage('common_copy')}
>
<Icon glyph="content-copy" scalable={false} />
</Button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Copy button can copy placeholder or error text.

The disabled condition translation === null || resultText === null allows copying when resultText is '...' (during translation) or an error message. If the user had a previous successful translation and then triggers a new one or encounters an error, the button remains enabled with undesirable content.

Consider adding inTranslateProcess and errorMessage to the disabled condition:

Proposed fix
 <Button
-  disabled={translation === null || resultText === null}
+  disabled={translation === null || inTranslateProcess || errorMessage !== null}
   onPress={() => {
-    if (resultText !== null) {
-      navigator.clipboard.writeText(resultText);
+    if (translation !== null) {
+      navigator.clipboard.writeText(translation.text);
     }
   }}
   view="clear"
   size="s"
   title={getMessage('common_copy')}
 >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button
disabled={translation === null || resultText === null}
onPress={() => {
if (resultText !== null) {
navigator.clipboard.writeText(resultText);
}
}}
view="clear"
size="s"
title={getMessage('common_copy')}
>
<Icon glyph="content-copy" scalable={false} />
</Button>
<Button
disabled={translation === null || inTranslateProcess || errorMessage !== null}
onPress={() => {
if (translation !== null) {
navigator.clipboard.writeText(translation.text);
}
}}
view="clear"
size="s"
title={getMessage('common_copy')}
>
<Icon glyph="content-copy" scalable={false} />
</Button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/popup/tabs/TextTranslator/TextTranslator.tsx` around lines 478 -
490, The copy Button currently only disables when translation or resultText are
null, which still allows copying the placeholder ('...') or an error string;
update the Button's disabled condition to also check the inTranslateProcess flag
and errorMessage state (e.g., disabled={translation === null || resultText ===
null || inTranslateProcess || !!errorMessage}) and tighten the onPress guard to
only call navigator.clipboard.writeText(resultText) when resultText is a valid
completed translation (not the placeholder), e.g., ensure resultText !== '...'
and errorMessage is falsy before copying; modify references around the Button,
navigator.clipboard.writeText, and the translation/resultText state to implement
this change.

Comment thread .github/.DS_Store
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete all irrelevant files

Comment on lines +479 to +482
disabled={translation === null || resultText === null}
onPress={() => {
if (resultText !== null) {
navigator.clipboard.writeText(resultText);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @CodeRabbit said, we should only copy text in translation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitonsky, agreed. The current code copies resultText, which can be '...' (while a new translation is in progress but a previous translation still exists) or an error string like [error message] — neither should be copied to the clipboard.

The fix is to copy translation.text directly and tighten the disabled condition:

<Button
    disabled={translation === null}
    onPress={() => {
        if (translation !== null) {
            navigator.clipboard.writeText(translation.text);
        }
    }}
    view="clear"
    size="s"
    title={getMessage('common_copy')}
>
    <Icon glyph="content-copy" scalable={false} />
</Button>

This ensures:

  1. Only the actual translated text is ever copied.
  2. The button is disabled whenever there is no valid translation object, regardless of resultText state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants