Skip to content

Conversation

@arvinxx
Copy link
Member

@arvinxx arvinxx commented Oct 21, 2025

Add InputTranslate action component that allows users to translate their input text to English before sending for better LLM responses.

Changes

  • Add InputTranslate component with language icon (🌐)
  • Integrate with existing chainTranslate from @lobechat/prompts
  • Add action to Desktop and Mobile chat input configurations
  • Position between typo and fileUpload actions per UI reference
  • Add Chinese locale string for button tooltip

Closes #9164

🤖 Generated with Claude Code

Summary by Sourcery

Add a new input translation feature that enables users to translate their message content to English via the chat input toolbar before sending.

New Features:

  • Introduce InputTranslate action component with a language icon and loading state to translate editor content
  • Implement useInputTranslate hook leveraging chainTranslate and chatService to process translation tasks
  • Integrate inputTranslate action into desktop (classic and group) and mobile chat input configurations between typo and file upload buttons
  • Add 'translateToEnglish' locale entry for the button tooltip in the Chinese locale

- Add InputTranslate action component with language icon
- Integrate with existing chainTranslate from @lobechat/prompts
- Enable translation of input text to English before sending
- Add action to Desktop (ClassicChat/GroupChat) and Mobile inputs
- Position between typo and fileUpload actions as per UI reference
- Add translateToEnglish locale string for button tooltip

Closes #9164

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Arvin Xu <[email protected]>
@arvinxx arvinxx marked this pull request as draft October 21, 2025 03:37
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Oct 21, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 21, 2025

Reviewer's Guide

Introduces an InputTranslate action that lets users translate their chat input to English before sending. A new useInputTranslate hook wraps the existing chainTranslate API and chatService calls with trace payloads, while a memoized InputTranslate component handles user interactions and loading states. The action is registered in the ActionBar config and injected into both desktop and mobile chat input bars between typo and file upload icons, and a Chinese locale string is added for the tooltip.

Sequence diagram for input translation process in chat input

sequenceDiagram
    actor User
    participant InputTranslate
    participant useInputTranslate
    participant chatService
    participant chainTranslate
    participant Editor
    User->>InputTranslate: Clicks translate button
    InputTranslate->>Editor: Get current input content
    InputTranslate->>useInputTranslate: Call translateToEnglish(content)
    useInputTranslate->>chainTranslate: Prepare translation prompt
    useInputTranslate->>chatService: fetchPresetTaskResult(params)
    chatService-->>useInputTranslate: Returns translated text
    useInputTranslate-->>InputTranslate: Return translated text
    InputTranslate->>Editor: Set translated content
Loading

Class diagram for new InputTranslate component and useInputTranslate hook

classDiagram
    class InputTranslate {
      +editor: Editor
      +isTranslating: boolean
      +translateToEnglish(content: string): Promise<string>
      +handleTranslate(): void
    }
    class useInputTranslate {
      +translateToEnglish(content: string): Promise<string>
    }
    InputTranslate --> useInputTranslate: uses
    InputTranslate --> Editor: uses
    useInputTranslate --> chatService: uses
    useInputTranslate --> chainTranslate: uses
Loading

File-Level Changes

Change Details Files
Add InputTranslate action component and hook for translating input text
  • Implement useInputTranslate hook leveraging chainTranslate, merge settings, and chatService.fetchPresetTaskResult with trace data
  • Create memoized InputTranslate component with icon, loading state, and click handler that updates the editor content
src/features/ChatInput/ActionBar/InputTranslate/useInputTranslate.ts
src/features/ChatInput/ActionBar/InputTranslate/index.tsx
Register new action in action map and insert into chat inputs
  • Add inputTranslate to actionMap in config.ts
  • Insert 'inputTranslate' into leftActions arrays in Desktop/ClassicChat, Desktop/GroupChat, and Mobile chat input components
src/features/ChatInput/ActionBar/config.ts
src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/ClassicChat.tsx
src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/GroupChat.tsx
src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx
Add locale string for translation tooltip
  • Add translateToEnglish entry in default chat locale for Chinese localization
src/locales/default/chat.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#9164 Add a feature to the chat input editor that allows users to translate their input text to English before sending.
#9164 Integrate the translation feature into both Desktop and Mobile chat input configurations, positioned according to the provided UI reference.
#9164 Provide appropriate UI elements and localization (e.g., language icon, tooltip text) for the translation feature.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel
Copy link

vercel bot commented Oct 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
lobehub-lite Error Error Oct 21, 2025 3:37am

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@gru-agent
Copy link
Contributor

gru-agent bot commented Oct 21, 2025

TestGru Assignment

Summary

Link CommitId Status Reason
Detail 8e9046b 🚫 Skipped No files need to be tested {"src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/ClassicChat.tsx":"File path does not match include patterns.","src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/GroupChat.tsx":"File path does not match include patterns.","src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx":"File path does not match include patterns.","src/features/ChatInput/ActionBar/InputTranslate/index.tsx":"File path does not match include patterns.","src/features/ChatInput/ActionBar/InputTranslate/useInputTranslate.ts":"File path does not match include patterns.","src/features/ChatInput/ActionBar/config.ts":"File path does not match include patterns.","src/locales/default/chat.ts":"File path does not match include patterns."}

History Assignment

Tip

You can @gru-agent and leave your feedback. TestGru will make adjustments based on your input

@lobehubbot
Copy link
Member

👍 @arvinxx

Thank you for raising your pull request and contributing to our Community
Please make sure you have followed our contributing guidelines. We will review it as soon as possible.
If you encounter any problems, please feel free to connect with us.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In useInputTranslate you’re wrapping chatService.fetchPresetTaskResult in a new Promise—consider converting it to async/await and returning the underlying promise directly to simplify the code.
  • useInputTranslate pulls translation settings with useUserStore.getState(), so it won’t update if the user changes settings—consider subscribing to the store inside the hook instead.
  • On translation failure you only log to console; consider surfacing an error or feedback in the UI so users know when translation doesn’t succeed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In useInputTranslate you’re wrapping chatService.fetchPresetTaskResult in a new Promise—consider converting it to async/await and returning the underlying promise directly to simplify the code.
- useInputTranslate pulls translation settings with useUserStore.getState(), so it won’t update if the user changes settings—consider subscribing to the store inside the hook instead.
- On translation failure you only log to console; consider surfacing an error or feedback in the UI so users know when translation doesn’t succeed.

## Individual Comments

### Comment 1
<location> `src/features/ChatInput/ActionBar/InputTranslate/index.tsx:21-26` </location>
<code_context>
+    setIsTranslating(true);
+    try {
+      const translatedContent = await translateToEnglish(content);
+      if (translatedContent && translatedContent !== content) {
+        editor.setDocument('markdown', translatedContent);
+      }
</code_context>

<issue_to_address>
**suggestion:** Check for translatedContent equality may not handle whitespace or formatting changes.

Normalize both strings before comparison to avoid false negatives due to formatting or whitespace differences.

```suggestion
    // Helper to normalize whitespace and formatting
    const normalize = (str: string) =>
      str.replace(/\s+/g, ' ').trim();

    setIsTranslating(true);
    try {
      const translatedContent = await translateToEnglish(content);
      if (
        translatedContent &&
        normalize(translatedContent) !== normalize(content)
      ) {
        editor.setDocument('markdown', translatedContent);
      }
```
</issue_to_address>

### Comment 2
<location> `src/features/ChatInput/ActionBar/InputTranslate/index.tsx:28` </location>
<code_context>
+        editor.setDocument('markdown', translatedContent);
+      }
+    } catch (error) {
+      console.error('Translation failed:', error);
+    } finally {
+      setIsTranslating(false);
</code_context>

<issue_to_address>
**suggestion:** Logging errors to console may not be sufficient for user feedback.

Please add a user-facing notification or UI message when translation fails to ensure users are aware of the error.

Suggested implementation:

```typescript
    setErrorMessage('');
    setIsTranslating(true);
    try {
      const translatedContent = await translateToEnglish(content);
      if (translatedContent && translatedContent !== content) {
        editor.setDocument('markdown', translatedContent);
      }
    } catch (error) {
      console.error('Translation failed:', error);
      setErrorMessage('Translation failed. Please try again.');
    } finally {
      setIsTranslating(false);
    }
  };

```

```typescript
  return (
    <>
      <Action
        icon={LanguagesIcon}
        loading={isTranslating}
        onClick={handleTranslate}
        title={t('input.translateToEnglish')}
      />
      {errorMessage && (
        <div style={{ color: 'red', marginTop: 8 }}>
          {errorMessage}
        </div>
      )}
    </>

```

```typescript
    const [errorMessage, setErrorMessage] = React.useState('');
    const content = editor.getDocument('markdown') as string;
    if (!content?.trim()) return;

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +21 to +26
setIsTranslating(true);
try {
const translatedContent = await translateToEnglish(content);
if (translatedContent && translatedContent !== content) {
editor.setDocument('markdown', translatedContent);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Check for translatedContent equality may not handle whitespace or formatting changes.

Normalize both strings before comparison to avoid false negatives due to formatting or whitespace differences.

Suggested change
setIsTranslating(true);
try {
const translatedContent = await translateToEnglish(content);
if (translatedContent && translatedContent !== content) {
editor.setDocument('markdown', translatedContent);
}
// Helper to normalize whitespace and formatting
const normalize = (str: string) =>
str.replace(/\s+/g, ' ').trim();
setIsTranslating(true);
try {
const translatedContent = await translateToEnglish(content);
if (
translatedContent &&
normalize(translatedContent) !== normalize(content)
) {
editor.setDocument('markdown', translatedContent);
}

editor.setDocument('markdown', translatedContent);
}
} catch (error) {
console.error('Translation failed:', error);
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Logging errors to console may not be sufficient for user feedback.

Please add a user-facing notification or UI message when translation fails to ensure users are aware of the error.

Suggested implementation:

    setErrorMessage('');
    setIsTranslating(true);
    try {
      const translatedContent = await translateToEnglish(content);
      if (translatedContent && translatedContent !== content) {
        editor.setDocument('markdown', translatedContent);
      }
    } catch (error) {
      console.error('Translation failed:', error);
      setErrorMessage('Translation failed. Please try again.');
    } finally {
      setIsTranslating(false);
    }
  };
  return (
    <>
      <Action
        icon={LanguagesIcon}
        loading={isTranslating}
        onClick={handleTranslate}
        title={t('input.translateToEnglish')}
      />
      {errorMessage && (
        <div style={{ color: 'red', marginTop: 8 }}>
          {errorMessage}
        </div>
      )}
    </>
    const [errorMessage, setErrorMessage] = React.useState('');
    const content = editor.getDocument('markdown') as string;
    if (!content?.trim()) return;

@codecov
Copy link

codecov bot commented Oct 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.37%. Comparing base (0828988) to head (8e9046b).
⚠️ Report is 477 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9807      +/-   ##
==========================================
+ Coverage   78.98%   82.37%   +3.38%     
==========================================
  Files         780      999     +219     
  Lines       48617    66982   +18365     
  Branches     6729    10923    +4194     
==========================================
+ Hits        38401    55175   +16774     
- Misses      10216    11807    +1591     
Flag Coverage Δ
app 79.63% <ø> (+3.02%) ⬆️
database ?
packages/agent-runtime 99.63% <ø> (?)
packages/context-engine 93.53% <ø> (?)
packages/electron-server-ipc 93.76% <ø> (+0.19%) ⬆️
packages/file-loaders 93.82% <ø> (+6.09%) ⬆️
packages/model-bank 100.00% <ø> (ø)
packages/model-runtime 84.49% <ø> (+9.54%) ⬆️
packages/prompts 78.41% <ø> (-21.59%) ⬇️
packages/python-interpreter 96.50% <ø> (?)
packages/utils 95.58% <ø> (+0.77%) ⬆️
packages/web-crawler 97.17% <ø> (-0.87%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Store 77.20% <ø> (+8.71%) ⬆️
Services 65.98% <ø> (+4.43%) ⬆️
Server 66.36% <ø> (+2.52%) ⬆️
Libs 51.14% <ø> (+2.58%) ⬆️
Utils 75.16% <ø> (+1.59%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +22 to +40
chatService
.fetchPresetTaskResult({
onFinish: (result) => {
if (result && typeof result === 'string') {
resolve(result);
} else {
resolve(translatedContent);
}
},
onMessageHandle: (chunk) => {
if (chunk.type === 'text') {
translatedContent += chunk.text;
}
},
params: merge(translationSetting, chainTranslate(content, 'en-US')),
trace: getCurrentTracePayload({ traceName: TraceNameMap.Translator }),
})
.catch((error) => {
reject(error);

Choose a reason for hiding this comment

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

P1 Badge Reject translation promise on failure

The hook wraps chatService.fetchPresetTaskResult in a new promise that only resolves inside onFinish and rejects via .catch. However fetchPresetTaskResult swallows errors and invokes onError without rejecting, so when the translation call fails (e.g. network/provider error) onFinish is never triggered and the wrapper promise never settles. Because InputTranslate awaits this promise to toggle isTranslating, a failed request leaves the action permanently stuck in the loading state. Provide an onError handler that calls reject (or resolve to a fallback) so the UI can recover after errors.

Useful? React with 👍 / 👎.

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Request] [Editor] Translate input text to English for better LLM response

2 participants