-
Notifications
You must be signed in to change notification settings - Fork 422
feat(ui): complete i18n localization with 12 languages #508
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?
Conversation
- Add i18next, react-i18next, browser-languagedetector, http-backend - Create i18n configuration with lazy loading and browser detection - Support 12 languages (EN, DE, ES, FR, IT, PT, NL, PL, RU, JA, ZH, KO) - Add English and German translations for all namespaces: - common: buttons, labels, status, messages, navigation - agent: welcome message, header, input, session, tools - settings: all sections and options - board: columns, features, forms, categories, priorities - Integrate i18n in renderer.tsx with Suspense wrapper - Store UI language preference in localStorage (automaker:ui-language) - Fallback to English for missing translations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement full UI localization using react-i18next with support for 12 languages. Components converted to use useTranslation(): - Sidebar navigation and all sidebar components - Settings view (navigation, header, all sections) - Board/Kanban view (columns, cards, actions, badges) - Agent Runner (welcome message, header, input, sessions) - Dialogs (new project, delete, sandbox, file browser, etc.) - Shared UI components (loading, error, confirm dialogs) Languages supported: - English (en), German (de), Spanish (es), French (fr) - Italian (it), Portuguese (pt), Dutch (nl), Polish (pl) - Russian (ru), Japanese (ja), Chinese (zh), Korean (ko) Translation namespaces: - common: buttons, labels, status, navigation, dialogs - settings: all settings sections and options - agent: chat interface, sessions, tools - board: kanban columns, features, categories, priorities Features: - Browser language detection with localStorage persistence - Language selector in Settings → Interface → Language - Fallback to English for missing translations - Lazy loading of translation files via HTTP backend Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds full i18n support: new i18n dependencies and runtime module, 48 locale JSON files across 12 languages/namespaces, initializes i18n at startup with Suspense, new Language settings UI, and replaces hard-coded strings with translation lookups across many UI components. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant App as renderer.tsx
participant i18n as i18n Module
participant Storage as localStorage
participant Detector as Browser Detector
participant Backend as HTTP Backend
participant Component as UI Component
User->>App: Open app
App->>i18n: import & initialize
i18n->>Storage: check cached language
alt cached
Storage-->>i18n: return language
else
i18n->>Detector: detect browser language
Detector-->>i18n: return language
end
i18n->>Backend: load namespace JSONs for language
Backend-->>i18n: return translations
i18n->>Storage: cache language
i18n-->>App: ready
App->>Component: render
Component->>i18n: useTranslation(namespace)
i18n-->>Component: t function
Component->>User: render localized UI
sequenceDiagram
participant User
participant LangUI as LanguageSection
participant Dropdown as Language Dropdown
participant i18n as i18n (changeLanguage)
participant Backend as HTTP Backend
participant Storage as localStorage
participant UI as UI Components
User->>LangUI: open language settings
LangUI->>Dropdown: show options
User->>Dropdown: select language X
Dropdown->>i18n: changeLanguage(X)
i18n->>Backend: fetch new locale files
Backend-->>i18n: translations loaded
i18n->>Storage: save X
i18n->>UI: notify change
UI->>i18n: re-render via useTranslation
UI-->>User: display UI in X
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (13)
🚧 Files skipped from review as they are similar to previous changes (8)
🔇 Additional comments (5)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @SeoFood, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the application's accessibility and user experience by introducing full internationalization (i18n) capabilities. Users can now interact with the UI in their preferred language, with automatic detection and the option for manual switching. This foundational change prepares the application for a global audience by making it adaptable to diverse linguistic needs. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This is an impressive and extensive pull request that successfully integrates i18n localization for 12 languages across the entire UI. The use of react-i18next, namespaces, and lazy loading via an HTTP backend is well-implemented. The code changes are systematic and clean, replacing hardcoded strings with translation keys effectively. I've found a couple of areas for improvement related to pluralization and handling HTML tags in translations, which I've detailed in specific comments. Overall, this is a fantastic contribution that significantly enhances the application's accessibility for a global audience.
| "title": "Delete Session", | ||
| "description": "Are you sure you want to delete this session? This action cannot be undone.", | ||
| "confirmText": "Delete Session", | ||
| "messageCount": "{{count}} messages" |
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 current translation for messageCount doesn't handle the singular case correctly, which will result in grammatically incorrect text like "1 messages". To ensure proper pluralization, you should provide both singular and plural forms using i18next's _plural suffix convention.
This issue also applies to other languages in this PR that have plural forms. Please ensure this is corrected across all relevant translation files.
For example, in German (de/common.json), it should be:
"messageCount": "{{count}} Nachricht",
"messageCount_plural": "{{count}} Nachrichten""messageCount": "{{count}} message",
"messageCount_plural": "{{count}} messages"| <p className="text-[11px] text-muted-foreground mt-2 text-center hidden sm:block"> | ||
| Press <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium">Enter</kbd> to | ||
| send,{' '} | ||
| <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium">Shift+Enter</kbd>{' '} | ||
| for new line | ||
| {t('input.keyboardHint') | ||
| .split('<kbd>') | ||
| .map((part, i) => { | ||
| if (i === 0) return part; | ||
| const [kbdContent, rest] = part.split('</kbd>'); | ||
| return ( | ||
| <span key={i}> | ||
| <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium"> | ||
| {kbdContent} | ||
| </kbd> | ||
| {rest} | ||
| </span> | ||
| ); | ||
| })} | ||
| </p> |
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 current implementation for translating the keyboard hint by splitting the string is clever but fragile. It relies on translators not altering the <kbd> tags, which could easily break the UI. A more robust and maintainable approach is to use the Trans component from react-i18next, which is designed for embedding components within translated strings. This is already used in other parts of the codebase, like onboarding-dialog.tsx.
Here's how you could refactor it:
<p className="text-[11px] text-muted-foreground mt-2 text-center hidden sm:block">
<Trans
i18nKey="input.keyboardHint"
ns="agent"
components={{
kbd: <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium" />,
}}
/>
</p>
- Add messageCount_plural forms for languages with grammatical plurals (EN, DE, ES, FR, IT, PT, NL, PL, RU) - Refactor keyboardHint to use Trans component instead of manual string parsing for <kbd> tag interpolation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
apps/ui/src/components/views/agent-view/components/message-bubble.tsx (1)
97-101: Missing translations for image alt text and fallback labels.Lines 97 and 101 contain hardcoded English strings that should be localized for consistency with the rest of the i18n changes:
alt={image.filename || \Attached image ${index + 1}`}`{image.filename || \Image ${index + 1}`}`Suggested fix
<img src={dataUrl} - alt={image.filename || `Attached image ${index + 1}`} + alt={image.filename || t('chat.attachedImageAlt', { index: index + 1 })} className="w-20 h-20 object-cover hover:opacity-90 transition-opacity" /> <div className="absolute bottom-0 left-0 right-0 bg-black/50 px-1.5 py-0.5 text-[9px] text-white truncate"> - {image.filename || `Image ${index + 1}`} + {image.filename || t('chat.imageLabel', { index: index + 1 })} </div>Add corresponding keys to all locale files (e.g., in
agent.json):"attachedImageAlt": "Attached image {{index}}", "imageLabel": "Image {{index}}"apps/ui/src/components/views/settings-view/mcp-servers/mcp-servers-section.tsx (1)
85-93: Multiple child components missing localization.
MCPToolsWarning,MCPServerCard, and the dialog components (DeleteServerDialog,AddEditServerDialog,ImportJsonDialog,GlobalJsonEditDialog) render UI text with hardcoded strings but do not implementuseTranslationhooks. These components need localization added to support multi-language support. For example,MCPToolsWarninghas hardcoded warnings about tool count limits, andMCPServerCardhas labels like "Test" and "Available Tools" that should be translatable.Also applies to: 107-118
apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx (1)
40-46: Localize navigation labels.The navigation labels ('Ideation', 'Spec Editor', 'Context', 'Memory', 'Kanban Board', 'Graph View', 'Agent Runner', 'Terminal', 'Project', 'Tools', 'GitHub', 'Issues', 'Pull Requests') are hardcoded in English in the
useNavigationhook (apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts). SinceSidebarNavigationhas access to the translation function, move the label strings to i18n and uset()to localize them when rendering at lines 43, 124, and 166.apps/ui/src/components/views/board-view/components/empty-state-card.tsx (1)
2-97: Non-filtered empty states lack i18n support and render hardcoded English strings.
config.title,config.description, andconfig.primaryAction.labelinEMPTY_STATE_CONFIGSare hardcoded English strings that are rendered directly without translation. While filtered empty states correctly use i18n (t('emptyState.noMatchingItems'),t('emptyState.noMatchingFilters')), the normal empty states bypass localization entirely.Update
EMPTY_STATE_CONFIGSvalues to use i18n keys or translation strings, and apply thet()function when rendering them in the component.apps/ui/src/components/views/agent-view.tsx (1)
48-78: UseresolveModelString()to convert model aliases before passing to the agent.
ThemodelSelection.modelcontains an alias (e.g.,'sonnet') that needs to be resolved to a full model name. Import and useresolveModelString()from@automaker/model-resolverbefore passing touseElectronAgent.♻️ Proposed update
import { useAppStore } from '@/store/app-store'; import type { PhaseModelEntry } from '@automaker/types'; +import { resolveModelString } from '@automaker/model-resolver'; @@ + const resolvedModel = resolveModelString(modelSelection.model); @@ } = useElectronAgent({ sessionId: currentSessionId || '', workingDirectory: currentProject?.path, - model: modelSelection.model, + model: resolvedModel, thinkingLevel: modelSelection.thinkingLevel,apps/ui/src/components/dialogs/new-project-modal.tsx (1)
185-200: Hardcoded strings in file browser dialog.The
openFileBrowsercall uses hardcoded English strings fortitleanddescription. These should be translated for consistency with the rest of the modal.🐛 Proposed fix
const handleBrowseDirectory = async () => { const selectedPath = await openFileBrowser({ - title: 'Select Base Project Directory', - description: 'Choose the parent directory where your project will be created', + title: t('dialogs.newProject.selectDirectoryTitle'), + description: t('dialogs.newProject.selectDirectoryDescription'), initialPath: workspaceDir || undefined, });Add corresponding keys to the translation files:
{ "dialogs": { "newProject": { "selectDirectoryTitle": "Select Base Project Directory", "selectDirectoryDescription": "Choose the parent directory where your project will be created" } } }
🤖 Fix all issues with AI agents
In `@apps/ui/public/locales/de/agent.json`:
- Around line 41-42: The i18n init is missing the compatibility flag required to
support legacy "_plural" keys used in locale files (e.g.,
apps/ui/public/locales/de/agent.json); update the i18n initialization in
i18n.init (apps/ui/src/i18n/index.ts) to include compatibilityJSON: 'v3' in the
init options so i18next will recognize legacy plural keys, or alternatively
migrate the locale JSON files to ICU-style keys (e.g., _one/_other) if you
prefer removing legacy support.
In `@apps/ui/public/locales/de/common.json`:
- Around line 233-238: The translation for deleteSession.messageCount is using a
single plural form; update the value to use ICU pluralization so it provides a
singular ("one") and plural ("other") variant for count (e.g., one -> "1
Nachricht", other -> "N Nachrichten"); locate the "deleteSession" key and
replace the plain "{{count}} Nachrichten" with an ICU pluralized string for the
messageCount entry so the UI shows the correct German singular and plural forms.
In `@apps/ui/public/locales/fr/board.json`:
- Around line 142-149: Rename the plural key base from "blockedBy" to
"blockedBy_one" and keep "blockedBy_other" as-is so i18next uses the standard
_one/_other plural forms; update every locale file that defines "blockedBy" and
"blockedBy_other" (and any code/tests that reference the old "blockedBy" key) to
use "blockedBy_one" + "blockedBy_other" consistently, and run a quick search for
the "blockedBy" key to replace usages or add a compatibility lookup if needed.
In `@apps/ui/public/locales/it/agent.json`:
- Around line 59-65: The localized Italian strings for the keys
pending/pending_plural and filesCount/filesCount_plural may be incorrectly
identical; consult a native Italian speaker or localization guide and update the
values for "pending", "pending_plural", "filesCount", and "filesCount_plural" to
use the correct singular and plural Italian forms (e.g., adjust "{{count}}
prompt in coda" vs a pluralized form if needed) and ensure the plural forms
follow the i18n convention used in the app.
In `@apps/ui/public/locales/ko/agent.json`:
- Around line 25-27: Update the Korean locale entry for the key "filesAttached"
in agent.json to include the interpolation placeholder "{{count}}" (e.g., change
the static "파일 첨부됨" to a translated string containing "{{count}}") so the UI can
display the number of attached files; keep the placeholder exact ("{{count}}")
to match the UI interpolation and adjust wording to a natural Korean phrase that
includes that placeholder.
In `@apps/ui/public/locales/nl/agent.json`:
- Around line 25-27: Update the "filesAttached" translation to include the count
placeholder so the UI can render the number of attached files; modify the value
for the key "filesAttached" (next to "attachFiles" and "dropHere") to include
"{{count}}" in the string (e.g., include the placeholder where the count should
appear) so the component reading input.filesAttached receives and displays the
file count.
In `@apps/ui/public/locales/pl/board.json`:
- Around line 127-135: The Polish locale is missing CLDR plural variants for
count-based keys; update the entries referenced (agentInfo.toolCalls,
agentInfo.tasksDone, agentInfo.blockedBy and other count-based keys such as
agentInfo.showMore) to include the full set of plural keys (_one, _few, _many,
_other) alongside the base key, each containing the correct Polish string with
the {{count}} interpolation; ensure you follow CLDR rules (use _one for n=1,
_few for n%10 in 2–4 and n%100 not in 12–14, _many for 0 and 5–19 etc., and
_other for remaining cases) and keep the same key names (e.g., "toolCalls_one",
"toolCalls_few", "toolCalls_many", "toolCalls_other") so i18next pluralization
with t(key, { count }) works correctly.
In `@apps/ui/public/locales/pl/common.json`:
- Around line 195-201: The plural keys in apps/ui/public/locales/pl/common.json
use the `_plural` suffix (minutesAgo_plural, hoursAgo_plural, daysAgo_plural)
which is incompatible with i18next's default `_other` plural form; either rename
those keys to minutesAgo_other, hoursAgo_other, daysAgo_other (and keep
minutesAgo, hoursAgo, daysAgo for singular) so plural resolution works, or
alternatively set i18next's compatibilityJSON to the mode that accepts
`_plural`; pick one approach and apply it consistently across locale files (also
ensure any code referencing these keys uses the new names).
In `@apps/ui/public/locales/ru/agent.json`:
- Around line 41-42: Replace the deprecated i18next "_plural" usage with the
three CLDR Russian plural keys for each pluralized entry: create keys
messages_one, messages_few, messages_many (use "{{count}} сообщение", "{{count}}
сообщения", "{{count}} сообщений" respectively) and remove messages_plural; do
the same for imagesAttached, pending, filesCount, and filesAttached — add *_one,
*_few, *_many variants with correct Russian forms for 1, few (2–4, 22–24, etc.),
and many (0, 5–20, etc.) so i18next selects the proper form.
In `@apps/ui/public/locales/ru/common.json`:
- Around line 194-205: The pluralization entries under "time" (minutesAgo,
hoursAgo, daysAgo) currently only have singular and generic plural keys and must
be expanded to Russian plural forms: add keys minutesAgo_one, minutesAgo_few,
minutesAgo_many, minutesAgo_other (and likewise hoursAgo_*, daysAgo_*) with the
appropriate Russian strings (e.g., "{{count}} минута", "{{count}} минуты",
"{{count}} минут", etc.) so i18n can select one/few/many/other; also ensure the
i18n configuration does not use compatibilityJSON: 'v3' so modern plural rules
are applied.
In `@apps/ui/public/locales/zh/agent.json`:
- Around line 25-27: The "filesAttached" translation currently lacks the
interpolation token so the attached-file count is dropped; update the
"filesAttached" value for the agent.json key "filesAttached" to include the
count placeholder (e.g. add "{count}" in the string) so the UI can render the
numeric count correctly when input.filesAttached is used.
In `@apps/ui/src/components/views/settings-view/language/language-section.tsx`:
- Around line 72-74: Replace the hardcoded fallback string 'Select language' in
the LanguageSection component with a translation lookup (e.g., use the existing
i18n/t hook like t('settings.sections.language.selectLanguage') or the project's
translation utility) and update all locale settings.json files to include the
new key under sections.language.selectLanguage with the appropriate translated
text; ensure the component imports/uses the same translation function used
elsewhere in language-section.tsx so the fallback is localized consistently.
In `@apps/ui/src/components/views/settings-view/terminal/terminal-section.tsx`:
- Around line 128-135: The pluralization `count` passed to i18next is a string
because `(scrollbackLines / 1000).toFixed(0)` returns a string; change the value
to a numeric type (e.g., use Math.round(scrollbackLines / 1000) or Number(...)
around the expression) so the `t('sections.terminal.scrollbackLines', { count:
... })` call receives a number; update the usage in the terminal-section
component where `scrollbackLines` is formatted accordingly.
🧹 Nitpick comments (14)
apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx (1)
1-5: Align imports with@automakershared packages.This file still imports from app-local aliases/relative paths. The guideline requires shared packages (
@automaker/*) for TS/TSX modules—please migrate these imports if the shared exports are available.apps/ui/public/locales/zh/common.json (1)
196-201: Consider removing redundant plural keys for Chinese.Chinese does not have grammatical plural forms, so the
_pluralsuffix keys (minutesAgo_plural,hoursAgo_plural,daysAgo_plural) are redundant. In i18next, these keys would never be selected for Chinese as it uses a single form for all counts.You can safely remove these duplicate keys since they have identical values to their non-plural counterparts.
♻️ Suggested simplification
"time": { "now": "刚刚", "minutesAgo": "{{count}} 分钟前", - "minutesAgo_plural": "{{count}} 分钟前", "hoursAgo": "{{count}} 小时前", - "hoursAgo_plural": "{{count}} 小时前", "daysAgo": "{{count}} 天前", - "daysAgo_plural": "{{count}} 天前", "today": "今天", "yesterday": "昨天", "tomorrow": "明天" },apps/ui/src/renderer.tsx (1)
10-12: Consider enhancing the Suspense fallback for better UX.The i18n initialization with Suspense is correctly implemented. However, the plain
<div>Loading...</div>fallback may briefly appear during initial translation loading. Consider a more polished loading indicator that matches your app's design system.💡 Optional: Enhanced loading fallback
- <Suspense fallback={<div>Loading...</div>}> + <Suspense fallback={ + <div className="flex items-center justify-center h-screen"> + <div className="animate-pulse text-muted-foreground">Loading...</div> + </div> + }>Alternatively, if your app has a dedicated loading component, you could reuse it here.
apps/ui/public/locales/ja/agent.json (1)
41-42: Consider migrating to modern i18next pluralization format (_one,_other) across all locale files.The project uses i18next v25.7.4, which follows the CLDR plural rules format introduced in v21. Lines 41-42, 53-54, 59-60, 64-65, and 87-88 use the legacy
_pluralsuffix instead of the modern_one/_othersuffixes. While the legacy format still functions via fallbacks, the codebase consistently uses this pattern across all locales (en, de, ja), so this should be addressed project-wide rather than file-by-file.For Japanese specifically, only the
_otherform is semantically needed since Japanese has no grammatical plural distinction.apps/ui/public/locales/pl/agent.json (1)
41-42: Polish requires multiple plural forms beyond_pluralsuffix.Polish has complex plural rules requiring four forms:
one,few,many, andother. The current_pluralsuffix only provides two forms, which won't correctly handle counts like 2-4 (few) vs 5-21 (many) in Polish.For example, "2 wiadomości" (few), "5 wiadomości" (many), "22 wiadomości" (few) require different grammatical forms. Consider using i18next's full plural key syntax:
"messages_one": "{{count}} wiadomość", "messages_few": "{{count}} wiadomości", "messages_many": "{{count}} wiadomości", "messages_other": "{{count}} wiadomości"This applies to other plural keys in this file as well (lines 53-54, 59-60, 64-65, 87-88).
i18next plural forms for Polish languageapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx (1)
1-2: Note:@ts-nocheckdisables type safety.The i18n integration itself is clean and correct. However, the
@ts-nocheckdirective on line 1 suppresses all TypeScript checking for this file, which could mask type errors in the translation keys or component props. Consider removing this directive and fixing any underlying type issues when time permits.apps/ui/src/components/views/settings-view.tsx (1)
29-29: Prefer@automaker/import path for new section.*Line 29 introduces a relative import. Per repo guidelines, imports should come from shared packages (
@automaker/*) rather than relative paths. Please switch to the shared package entry point if available. As per coding guidelines.apps/ui/src/components/views/settings-view/account/account-section.tsx (1)
59-61: Consider adding user-facing error feedback for logout failures.The logout error is only logged to console. Users won't see any feedback if logout fails. Consider adding a toast notification with a translated error message.
Suggested improvement
} catch (error) { console.error('Logout failed:', error); + toast.error(t('sections.account.logOutFailed')); setIsLoggingOut(false); }This would require adding a corresponding translation key to the locale files.
apps/ui/src/components/views/settings-view/language/language-section.tsx (1)
23-25: Consider adding error handling for language change failures.The
changeLanguagecall could fail (e.g., network error loading translations). Consider wrapping in try-catch with user feedback.Suggested improvement
+import { toast } from 'sonner'; + // ... const handleLanguageChange = async (languageCode: string) => { - await changeLanguage(languageCode); + try { + await changeLanguage(languageCode); + } catch (error) { + console.error('Failed to change language:', error); + toast.error(t('sections.language.changeFailed')); + } };apps/ui/src/components/views/agent-view/input-area/input-controls.tsx (1)
188-201: Consider usingTranscomponent for embedded markup.The custom
<kbd>tag parsing assumes a specific format in translation strings and can break if translations are malformed. Thereact-i18nextTranscomponent handles embedded components more robustly.♻️ Suggested refactor using Trans component
+import { useTranslation, Trans } from 'react-i18next'; ... - {t('input.keyboardHint') - .split('<kbd>') - .map((part, i) => { - if (i === 0) return part; - const [kbdContent, rest] = part.split('</kbd>'); - return ( - <span key={i}> - <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium"> - {kbdContent} - </kbd> - {rest} - </span> - ); - })} + <Trans + i18nKey="input.keyboardHint" + ns="agent" + components={{ + kbd: <kbd className="px-1.5 py-0.5 bg-muted rounded text-[10px] font-medium" />, + }} + />Then update the translation string to use component syntax:
{ "input": { "keyboardHint": "Press <kbd>Enter</kbd> to send, <kbd>Shift+Enter</kbd> for new line" } }apps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsx (1)
33-41: Consider callinguseTranslationdirectly inPromptFieldinstead of prop drilling.Passing
tas a prop works but is not the idiomatic react-i18next pattern. CallinguseTranslation('settings')directly insidePromptFieldwould:
- Remove the need for the extra prop and its type definition
- Make
PromptFieldmore self-contained and reusable- Leverage react-i18next's internal caching (calling the hook multiple times with the same namespace is efficient)
🔧 Suggested refactor
interface PromptFieldProps { label: string; description: string; defaultValue: string; customValue?: CustomPrompt; onCustomValueChange: (value: CustomPrompt | undefined) => void; critical?: boolean; - t: (key: string) => string; } function PromptField({ label, description, defaultValue, customValue, onCustomValueChange, critical = false, - t, }: PromptFieldProps) { + const { t } = useTranslation('settings'); const isEnabled = customValue?.enabled ?? false;Then remove all
t={t}props fromPromptFieldusages.apps/ui/src/i18n/index.ts (2)
88-93: Consider validating language code inchangeLanguage.The
changeLanguagefunction accepts any string but doesn't validate againstSUPPORTED_LANGUAGE_CODES. While i18next will fall back to English for unsupported languages, explicit validation provides better developer experience and clearer error handling.🔧 Optional validation
export async function changeLanguage(languageCode: string): Promise<void> { + if (!SUPPORTED_LANGUAGE_CODES.includes(languageCode as typeof SUPPORTED_LANGUAGE_CODES[number])) { + console.warn(`Unsupported language code: ${languageCode}, falling back to 'en'`); + languageCode = 'en'; + } await i18n.changeLanguage(languageCode); }
52-54: Minor: Prefer spread over type cast for readonly array.The double cast through
unknownworks but is verbose. Using spread creates a mutable copy more cleanly:🔧 Cleaner alternative
// Namespaces - ns: NAMESPACES as unknown as string[], + ns: [...NAMESPACES], defaultNS: 'common',apps/ui/src/components/views/settings-view/components/settings-navigation.tsx (1)
2-164: Typetas i18nextTFunctionto preserve options and namespace safety.The current
(key: string) => stringloses typing and prevents options (e.g.,count,defaultValue).♻️ Proposed refactor
-import { useTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; +import type { TFunction } from 'i18next'; @@ - t: (key: string) => string; + t: TFunction<'settings'>; @@ - t: (key: string) => string; + t: TFunction<'settings'>;
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (108)
apps/ui/package.jsonapps/ui/public/locales/de/agent.jsonapps/ui/public/locales/de/board.jsonapps/ui/public/locales/de/common.jsonapps/ui/public/locales/de/settings.jsonapps/ui/public/locales/en/agent.jsonapps/ui/public/locales/en/board.jsonapps/ui/public/locales/en/common.jsonapps/ui/public/locales/en/settings.jsonapps/ui/public/locales/es/agent.jsonapps/ui/public/locales/es/board.jsonapps/ui/public/locales/es/common.jsonapps/ui/public/locales/es/settings.jsonapps/ui/public/locales/fr/agent.jsonapps/ui/public/locales/fr/board.jsonapps/ui/public/locales/fr/common.jsonapps/ui/public/locales/fr/settings.jsonapps/ui/public/locales/it/agent.jsonapps/ui/public/locales/it/board.jsonapps/ui/public/locales/it/common.jsonapps/ui/public/locales/it/settings.jsonapps/ui/public/locales/ja/agent.jsonapps/ui/public/locales/ja/board.jsonapps/ui/public/locales/ja/common.jsonapps/ui/public/locales/ja/settings.jsonapps/ui/public/locales/ko/agent.jsonapps/ui/public/locales/ko/board.jsonapps/ui/public/locales/ko/common.jsonapps/ui/public/locales/ko/settings.jsonapps/ui/public/locales/nl/agent.jsonapps/ui/public/locales/nl/board.jsonapps/ui/public/locales/nl/common.jsonapps/ui/public/locales/nl/settings.jsonapps/ui/public/locales/pl/agent.jsonapps/ui/public/locales/pl/board.jsonapps/ui/public/locales/pl/common.jsonapps/ui/public/locales/pl/settings.jsonapps/ui/public/locales/pt/agent.jsonapps/ui/public/locales/pt/board.jsonapps/ui/public/locales/pt/common.jsonapps/ui/public/locales/pt/settings.jsonapps/ui/public/locales/ru/agent.jsonapps/ui/public/locales/ru/board.jsonapps/ui/public/locales/ru/common.jsonapps/ui/public/locales/ru/settings.jsonapps/ui/public/locales/zh/agent.jsonapps/ui/public/locales/zh/board.jsonapps/ui/public/locales/zh/common.jsonapps/ui/public/locales/zh/settings.jsonapps/ui/src/components/dialogs/board-background-modal.tsxapps/ui/src/components/dialogs/delete-session-dialog.tsxapps/ui/src/components/dialogs/file-browser-dialog.tsxapps/ui/src/components/dialogs/new-project-modal.tsxapps/ui/src/components/dialogs/sandbox-rejection-screen.tsxapps/ui/src/components/dialogs/sandbox-risk-dialog.tsxapps/ui/src/components/dialogs/workspace-picker-modal.tsxapps/ui/src/components/layout/sidebar/components/bug-report-button.tsxapps/ui/src/components/layout/sidebar/components/collapse-toggle-button.tsxapps/ui/src/components/layout/sidebar/components/project-actions.tsxapps/ui/src/components/layout/sidebar/components/project-selector-with-options.tsxapps/ui/src/components/layout/sidebar/components/sidebar-footer.tsxapps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsxapps/ui/src/components/layout/sidebar/dialogs/onboarding-dialog.tsxapps/ui/src/components/layout/sidebar/dialogs/trash-dialog.tsxapps/ui/src/components/ui/confirm-dialog.tsxapps/ui/src/components/ui/delete-confirm-dialog.tsxapps/ui/src/components/ui/error-state.tsxapps/ui/src/components/ui/loading-state.tsxapps/ui/src/components/views/agent-view.tsxapps/ui/src/components/views/agent-view/components/agent-header.tsxapps/ui/src/components/views/agent-view/components/empty-states.tsxapps/ui/src/components/views/agent-view/components/message-bubble.tsxapps/ui/src/components/views/agent-view/components/thinking-indicator.tsxapps/ui/src/components/views/agent-view/input-area/file-preview.tsxapps/ui/src/components/views/agent-view/input-area/input-controls.tsxapps/ui/src/components/views/agent-view/input-area/queue-display.tsxapps/ui/src/components/views/agent-view/shared/constants.tsapps/ui/src/components/views/board-view/board-search-bar.tsxapps/ui/src/components/views/board-view/components/empty-state-card.tsxapps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-header.tsxapps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsxapps/ui/src/components/views/settings-view.tsxapps/ui/src/components/views/settings-view/account/account-section.tsxapps/ui/src/components/views/settings-view/api-keys/api-key-field.tsxapps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsxapps/ui/src/components/views/settings-view/appearance/appearance-section.tsxapps/ui/src/components/views/settings-view/audio/audio-section.tsxapps/ui/src/components/views/settings-view/components/settings-header.tsxapps/ui/src/components/views/settings-view/components/settings-navigation.tsxapps/ui/src/components/views/settings-view/config/navigation.tsapps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsxapps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsxapps/ui/src/components/views/settings-view/hooks/use-settings-view.tsapps/ui/src/components/views/settings-view/keyboard-shortcuts/keyboard-shortcuts-section.tsxapps/ui/src/components/views/settings-view/language/index.tsapps/ui/src/components/views/settings-view/language/language-section.tsxapps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsxapps/ui/src/components/views/settings-view/mcp-servers/mcp-servers-section.tsxapps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsxapps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsxapps/ui/src/components/views/settings-view/security/security-section.tsxapps/ui/src/components/views/settings-view/terminal/terminal-section.tsxapps/ui/src/components/views/settings-view/worktrees/worktrees-section.tsxapps/ui/src/i18n/index.tsapps/ui/src/renderer.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Always import from shared packages (
@automaker/*), never from old relative paths
Files:
apps/ui/src/components/views/settings-view/hooks/use-settings-view.tsapps/ui/src/components/views/agent-view/components/agent-header.tsxapps/ui/src/components/dialogs/sandbox-risk-dialog.tsxapps/ui/src/components/views/settings-view/account/account-section.tsxapps/ui/src/components/views/settings-view/keyboard-shortcuts/keyboard-shortcuts-section.tsxapps/ui/src/components/views/settings-view/audio/audio-section.tsxapps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsxapps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsxapps/ui/src/components/views/settings-view/mcp-servers/mcp-servers-section.tsxapps/ui/src/components/layout/sidebar/dialogs/trash-dialog.tsxapps/ui/src/components/views/board-view/board-search-bar.tsxapps/ui/src/components/views/agent-view.tsxapps/ui/src/components/views/agent-view/shared/constants.tsapps/ui/src/components/dialogs/delete-session-dialog.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsxapps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-header.tsxapps/ui/src/components/views/agent-view/input-area/file-preview.tsxapps/ui/src/components/views/settings-view.tsxapps/ui/src/components/views/settings-view/language/index.tsapps/ui/src/components/views/settings-view/language/language-section.tsxapps/ui/src/components/views/settings-view/terminal/terminal-section.tsxapps/ui/src/components/layout/sidebar/dialogs/onboarding-dialog.tsxapps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsxapps/ui/src/components/layout/sidebar/components/sidebar-footer.tsxapps/ui/src/components/views/board-view/components/empty-state-card.tsxapps/ui/src/components/views/agent-view/input-area/input-controls.tsxapps/ui/src/components/dialogs/board-background-modal.tsxapps/ui/src/components/layout/sidebar/components/collapse-toggle-button.tsxapps/ui/src/components/dialogs/workspace-picker-modal.tsxapps/ui/src/components/ui/delete-confirm-dialog.tsxapps/ui/src/i18n/index.tsapps/ui/src/renderer.tsxapps/ui/src/components/layout/sidebar/components/project-actions.tsxapps/ui/src/components/views/agent-view/components/empty-states.tsxapps/ui/src/components/dialogs/new-project-modal.tsxapps/ui/src/components/views/settings-view/api-keys/api-key-field.tsxapps/ui/src/components/views/settings-view/appearance/appearance-section.tsxapps/ui/src/components/layout/sidebar/components/project-selector-with-options.tsxapps/ui/src/components/ui/loading-state.tsxapps/ui/src/components/dialogs/file-browser-dialog.tsxapps/ui/src/components/ui/confirm-dialog.tsxapps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsxapps/ui/src/components/views/agent-view/input-area/queue-display.tsxapps/ui/src/components/layout/sidebar/components/bug-report-button.tsxapps/ui/src/components/ui/error-state.tsxapps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsxapps/ui/src/components/views/settings-view/components/settings-navigation.tsxapps/ui/src/components/views/settings-view/components/settings-header.tsxapps/ui/src/components/views/agent-view/components/message-bubble.tsxapps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsxapps/ui/src/components/views/settings-view/security/security-section.tsxapps/ui/src/components/views/settings-view/worktrees/worktrees-section.tsxapps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsxapps/ui/src/components/views/agent-view/components/thinking-indicator.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsxapps/ui/src/components/dialogs/sandbox-rejection-screen.tsxapps/ui/src/components/views/settings-view/config/navigation.tsapps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
resolveModelString()from@automaker/model-resolverto convert model aliases (haiku, sonnet, opus) to full model names
Files:
apps/ui/src/components/views/settings-view/hooks/use-settings-view.tsapps/ui/src/components/views/agent-view/components/agent-header.tsxapps/ui/src/components/dialogs/sandbox-risk-dialog.tsxapps/ui/src/components/views/settings-view/account/account-section.tsxapps/ui/src/components/views/settings-view/keyboard-shortcuts/keyboard-shortcuts-section.tsxapps/ui/src/components/views/settings-view/audio/audio-section.tsxapps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsxapps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsxapps/ui/src/components/views/settings-view/mcp-servers/mcp-servers-section.tsxapps/ui/src/components/layout/sidebar/dialogs/trash-dialog.tsxapps/ui/src/components/views/board-view/board-search-bar.tsxapps/ui/src/components/views/agent-view.tsxapps/ui/src/components/views/agent-view/shared/constants.tsapps/ui/src/components/dialogs/delete-session-dialog.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsxapps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-header.tsxapps/ui/src/components/views/agent-view/input-area/file-preview.tsxapps/ui/src/components/views/settings-view.tsxapps/ui/src/components/views/settings-view/language/index.tsapps/ui/src/components/views/settings-view/language/language-section.tsxapps/ui/src/components/views/settings-view/terminal/terminal-section.tsxapps/ui/src/components/layout/sidebar/dialogs/onboarding-dialog.tsxapps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsxapps/ui/src/components/layout/sidebar/components/sidebar-footer.tsxapps/ui/src/components/views/board-view/components/empty-state-card.tsxapps/ui/src/components/views/agent-view/input-area/input-controls.tsxapps/ui/src/components/dialogs/board-background-modal.tsxapps/ui/src/components/layout/sidebar/components/collapse-toggle-button.tsxapps/ui/src/components/dialogs/workspace-picker-modal.tsxapps/ui/src/components/ui/delete-confirm-dialog.tsxapps/ui/src/i18n/index.tsapps/ui/src/renderer.tsxapps/ui/src/components/layout/sidebar/components/project-actions.tsxapps/ui/src/components/views/agent-view/components/empty-states.tsxapps/ui/src/components/dialogs/new-project-modal.tsxapps/ui/src/components/views/settings-view/api-keys/api-key-field.tsxapps/ui/src/components/views/settings-view/appearance/appearance-section.tsxapps/ui/src/components/layout/sidebar/components/project-selector-with-options.tsxapps/ui/src/components/ui/loading-state.tsxapps/ui/src/components/dialogs/file-browser-dialog.tsxapps/ui/src/components/ui/confirm-dialog.tsxapps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsxapps/ui/src/components/views/agent-view/input-area/queue-display.tsxapps/ui/src/components/layout/sidebar/components/bug-report-button.tsxapps/ui/src/components/ui/error-state.tsxapps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsxapps/ui/src/components/views/settings-view/components/settings-navigation.tsxapps/ui/src/components/views/settings-view/components/settings-header.tsxapps/ui/src/components/views/agent-view/components/message-bubble.tsxapps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsxapps/ui/src/components/views/settings-view/security/security-section.tsxapps/ui/src/components/views/settings-view/worktrees/worktrees-section.tsxapps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsxapps/ui/src/components/views/agent-view/components/thinking-indicator.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsxapps/ui/src/components/dialogs/sandbox-rejection-screen.tsxapps/ui/src/components/views/settings-view/config/navigation.tsapps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsx
🧠 Learnings (5)
📚 Learning: 2025-12-30T01:02:07.114Z
Learnt from: illia1f
Repo: AutoMaker-Org/automaker PR: 324
File: apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx:122-131
Timestamp: 2025-12-30T01:02:07.114Z
Learning: Tailwind CSS v4 uses postfix syntax for the important modifier: append ! at the end of the utility class (e.g., backdrop-blur-[0px]! or hover:bg-red-500!). The older v3 style used a prefix (!) at the start (e.g., !backdrop-blur-[0px]); prefer the postfix form for consistency across TSX files.
Applied to files:
apps/ui/src/components/views/agent-view/components/agent-header.tsxapps/ui/src/components/dialogs/sandbox-risk-dialog.tsxapps/ui/src/components/views/settings-view/account/account-section.tsxapps/ui/src/components/views/settings-view/keyboard-shortcuts/keyboard-shortcuts-section.tsxapps/ui/src/components/views/settings-view/audio/audio-section.tsxapps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsxapps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsxapps/ui/src/components/views/settings-view/mcp-servers/mcp-servers-section.tsxapps/ui/src/components/layout/sidebar/dialogs/trash-dialog.tsxapps/ui/src/components/views/board-view/board-search-bar.tsxapps/ui/src/components/views/agent-view.tsxapps/ui/src/components/dialogs/delete-session-dialog.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsxapps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-header.tsxapps/ui/src/components/views/agent-view/input-area/file-preview.tsxapps/ui/src/components/views/settings-view.tsxapps/ui/src/components/views/settings-view/language/language-section.tsxapps/ui/src/components/views/settings-view/terminal/terminal-section.tsxapps/ui/src/components/layout/sidebar/dialogs/onboarding-dialog.tsxapps/ui/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsxapps/ui/src/components/layout/sidebar/components/sidebar-footer.tsxapps/ui/src/components/views/board-view/components/empty-state-card.tsxapps/ui/src/components/views/agent-view/input-area/input-controls.tsxapps/ui/src/components/dialogs/board-background-modal.tsxapps/ui/src/components/layout/sidebar/components/collapse-toggle-button.tsxapps/ui/src/components/dialogs/workspace-picker-modal.tsxapps/ui/src/components/ui/delete-confirm-dialog.tsxapps/ui/src/renderer.tsxapps/ui/src/components/layout/sidebar/components/project-actions.tsxapps/ui/src/components/views/agent-view/components/empty-states.tsxapps/ui/src/components/dialogs/new-project-modal.tsxapps/ui/src/components/views/settings-view/api-keys/api-key-field.tsxapps/ui/src/components/views/settings-view/appearance/appearance-section.tsxapps/ui/src/components/layout/sidebar/components/project-selector-with-options.tsxapps/ui/src/components/ui/loading-state.tsxapps/ui/src/components/dialogs/file-browser-dialog.tsxapps/ui/src/components/ui/confirm-dialog.tsxapps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsxapps/ui/src/components/views/agent-view/input-area/queue-display.tsxapps/ui/src/components/layout/sidebar/components/bug-report-button.tsxapps/ui/src/components/ui/error-state.tsxapps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsxapps/ui/src/components/views/settings-view/components/settings-navigation.tsxapps/ui/src/components/views/settings-view/components/settings-header.tsxapps/ui/src/components/views/agent-view/components/message-bubble.tsxapps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsxapps/ui/src/components/views/settings-view/security/security-section.tsxapps/ui/src/components/views/settings-view/worktrees/worktrees-section.tsxapps/ui/src/components/views/settings-view/prompts/prompt-customization-section.tsxapps/ui/src/components/views/agent-view/components/thinking-indicator.tsxapps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsxapps/ui/src/components/dialogs/sandbox-rejection-screen.tsxapps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsx
📚 Learning: 2026-01-07T15:21:11.144Z
Learnt from: webdevcody
Repo: AutoMaker-Org/automaker PR: 378
File: apps/server/src/lib/sdk-options.ts:141-148
Timestamp: 2026-01-07T15:21:11.144Z
Learning: AutoMaker intentionally uses `permissionMode: 'bypassPermissions'` with `allowDangerouslySkipPermissions: true` in base SDK options for fully autonomous operation. This is an accepted architectural decision, with Docker containerization as the primary security boundary.
Applied to files:
apps/ui/src/components/dialogs/sandbox-risk-dialog.tsxapps/ui/src/components/dialogs/sandbox-rejection-screen.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Frontend UI must use TanStack Router for file-based routing, organize components in components/views/, implement stores with Zustand, and use custom hooks in hooks/ directory
Applied to files:
apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Applies to **/*.{ts,tsx} : Use `resolveModelString()` from automaker/model-resolver to convert model aliases (haiku, sonnet, opus) to full model names
Applied to files:
apps/ui/src/components/dialogs/workspace-picker-modal.tsxapps/ui/src/i18n/index.tsapps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Each feature executes in an isolated git worktree created via automaker/git-utils to protect the main branch during AI agent execution
Applied to files:
apps/ui/src/components/views/settings-view/worktrees/worktrees-section.tsx
🧬 Code graph analysis (12)
apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsx (1)
apps/ui/src/components/ui/button.tsx (1)
Button(108-108)
apps/ui/src/components/views/agent-view.tsx (1)
apps/ui/src/components/views/agent-view/shared/constants.ts (2)
WELCOME_MESSAGE_ID(11-11)WELCOME_MESSAGE_ROLE(12-12)
apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx (1)
apps/ui/src/lib/utils.ts (1)
cn(6-8)
apps/ui/src/components/views/board-view/components/empty-state-card.tsx (1)
apps/ui/src/store/app-store.ts (1)
formatShortcut(174-219)
apps/ui/src/components/dialogs/board-background-modal.tsx (2)
apps/ui/src/components/ui/sheet.tsx (3)
SheetTitle(148-148)SheetDescription(149-149)SheetHeader(146-146)apps/ui/src/lib/image-utils.ts (1)
DEFAULT_MAX_FILE_SIZE(21-21)
apps/ui/src/renderer.tsx (1)
apps/ui/src/app.tsx (1)
App(14-66)
apps/ui/src/components/layout/sidebar/components/project-selector-with-options.tsx (1)
apps/ui/src/store/app-store.ts (1)
formatShortcut(174-219)
apps/ui/src/components/dialogs/file-browser-dialog.tsx (3)
apps/ui/src/hooks/use-os-detection.ts (1)
useOSDetection(39-49)apps/ui/src/hooks/index.ts (1)
useOSDetection(7-7)apps/ui/src/components/ui/button.tsx (1)
Button(108-108)
apps/ui/src/components/views/settings-view/components/settings-navigation.tsx (1)
apps/ui/src/components/views/settings-view/config/navigation.ts (1)
NavigationItem(23-28)
apps/ui/src/components/dialogs/sandbox-rejection-screen.tsx (1)
apps/ui/src/components/dialogs/index.ts (1)
SandboxRejectionScreen(6-6)
apps/ui/src/components/views/settings-view/config/navigation.ts (2)
apps/ui/src/components/views/settings-view/hooks/use-settings-view.ts (1)
SettingsViewId(3-23)apps/ui/src/components/ui/provider-icon.tsx (4)
AnthropicIcon(153-155)CursorIcon(165-167)OpenAIIcon(157-159)OpenCodeIcon(177-179)
apps/ui/src/components/views/settings-view/model-defaults/model-defaults-section.tsx (2)
apps/ui/src/components/views/settings-view/model-defaults/phase-model-selector.tsx (1)
PhaseModelSelector(143-1559)apps/ui/src/components/views/settings-view/model-defaults/index.ts (1)
PhaseModelSelector(2-2)
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
apps/ui/src/components/views/settings-view/language/language-section.tsx
Show resolved
Hide resolved
apps/ui/src/components/views/settings-view/terminal/terminal-section.tsx
Show resolved
Hide resolved
- Migrate all _plural keys to ICU-style (_one/_other) - Add Polish CLDR plural variants (_one, _few, _many, _other) - Add Russian CLDR plural variants (_one, _few, _many, _other) - Fix terminal-section.tsx: convert count to Number for i18next - Add selectLanguage translation key to all locale files - Translate hardcoded "Select language" fallback - Fix incorrectly renamed status.pending keys in common/board.json - Fix incorrectly renamed input.filesAttached in agent.json Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@apps/ui/public/locales/es/board.json`:
- Around line 133-134: Replace the singular pluralization for the count-based
keys by adding _one and _other variants: change the "toolCalls" key into
"toolCalls_one" with "{{count}} llamada a herramienta" and "toolCalls_other"
with "{{count}} llamadas a herramientas", and change "tasksDone" into
"tasksDone_one" with "{{count}} tarea completada" and "tasksDone_other" with
"{{count}} tareas completadas" so the UI uses correct Spanish singular/plural
forms for toolCalls and tasksDone.
In `@apps/ui/public/locales/ja/common.json`:
- Around line 233-238: The translation block for the "deleteSession" key defines
messageCount_one but lacks the Japanese plural form expected as
messageCount_other, causing fallback/missing-key errors; add a
messageCount_other entry alongside messageCount_one (e.g., "messageCount_other":
"{{count}}件のメッセージ") under the "deleteSession" object so the plural resolution
for Japanese ("other") is satisfied for the keys used by the app.
In `@apps/ui/public/locales/ru/board.json`:
- Around line 127-134: Add Russian plural forms for the two count-based keys
under agentInfo: replace the singular "toolCalls" and "tasksDone" entries with
pluralized variants expected by react-i18next by adding toolCalls_one,
toolCalls_few, toolCalls_many, toolCalls_other (using the provided translations)
and tasksDone_one, tasksDone_few, tasksDone_many, tasksDone_other (using the
provided translations), ensuring the original keys with plain "{{count}}" are
removed or replaced so the i18n pluralization system will pick the correct form
for agentInfo.toolCalls and agentInfo.tasksDone.
🧹 Nitpick comments (2)
apps/ui/public/locales/ko/board.json (1)
147-148: Korean plural keys are redundant but harmless.Korean doesn't have grammatical plural forms, so
blockedBy_oneandblockedBy_otherhave identical text. This works correctly with i18next but adds minor redundancy. You could simplify to a singleblockedBykey for Korean (and other East Asian languages like Japanese/Chinese), though keeping them aligned with the English structure is also a valid approach for maintainability.♻️ Optional simplification
- "blockedBy_one": "완료되지 않은 {{count}}개의 의존성에 의해 차단됨", - "blockedBy_other": "완료되지 않은 {{count}}개의 의존성에 의해 차단됨", + "blockedBy": "완료되지 않은 {{count}}개의 의존성에 의해 차단됨",Note: This requires ensuring the consuming code uses a fallback pattern, or you can keep both keys for structural consistency across all locales.
apps/ui/public/locales/en/settings.json (1)
232-234: Consider consolidating duplicate keys.
noServersandnoServersConfiguredappear to have the same meaning. Consider using a single key to avoid inconsistent usage across components.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (50)
apps/ui/public/locales/de/agent.jsonapps/ui/public/locales/de/board.jsonapps/ui/public/locales/de/common.jsonapps/ui/public/locales/de/settings.jsonapps/ui/public/locales/en/agent.jsonapps/ui/public/locales/en/board.jsonapps/ui/public/locales/en/common.jsonapps/ui/public/locales/en/settings.jsonapps/ui/public/locales/es/agent.jsonapps/ui/public/locales/es/board.jsonapps/ui/public/locales/es/common.jsonapps/ui/public/locales/es/settings.jsonapps/ui/public/locales/fr/agent.jsonapps/ui/public/locales/fr/board.jsonapps/ui/public/locales/fr/common.jsonapps/ui/public/locales/fr/settings.jsonapps/ui/public/locales/it/agent.jsonapps/ui/public/locales/it/board.jsonapps/ui/public/locales/it/common.jsonapps/ui/public/locales/it/settings.jsonapps/ui/public/locales/ja/agent.jsonapps/ui/public/locales/ja/board.jsonapps/ui/public/locales/ja/common.jsonapps/ui/public/locales/ja/settings.jsonapps/ui/public/locales/ko/agent.jsonapps/ui/public/locales/ko/board.jsonapps/ui/public/locales/ko/common.jsonapps/ui/public/locales/ko/settings.jsonapps/ui/public/locales/nl/agent.jsonapps/ui/public/locales/nl/board.jsonapps/ui/public/locales/nl/common.jsonapps/ui/public/locales/nl/settings.jsonapps/ui/public/locales/pl/agent.jsonapps/ui/public/locales/pl/board.jsonapps/ui/public/locales/pl/common.jsonapps/ui/public/locales/pl/settings.jsonapps/ui/public/locales/pt/agent.jsonapps/ui/public/locales/pt/board.jsonapps/ui/public/locales/pt/common.jsonapps/ui/public/locales/pt/settings.jsonapps/ui/public/locales/ru/agent.jsonapps/ui/public/locales/ru/board.jsonapps/ui/public/locales/ru/common.jsonapps/ui/public/locales/ru/settings.jsonapps/ui/public/locales/zh/agent.jsonapps/ui/public/locales/zh/board.jsonapps/ui/public/locales/zh/common.jsonapps/ui/public/locales/zh/settings.jsonapps/ui/src/components/views/settings-view/language/language-section.tsxapps/ui/src/components/views/settings-view/terminal/terminal-section.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/ui/public/locales/en/board.json
🚧 Files skipped from review as they are similar to previous changes (27)
- apps/ui/public/locales/es/agent.json
- apps/ui/public/locales/pt/agent.json
- apps/ui/public/locales/fr/agent.json
- apps/ui/public/locales/ja/agent.json
- apps/ui/public/locales/de/board.json
- apps/ui/public/locales/ko/common.json
- apps/ui/public/locales/zh/settings.json
- apps/ui/public/locales/ja/board.json
- apps/ui/public/locales/pt/board.json
- apps/ui/public/locales/nl/settings.json
- apps/ui/public/locales/de/settings.json
- apps/ui/public/locales/ru/settings.json
- apps/ui/public/locales/pl/agent.json
- apps/ui/src/components/views/settings-view/language/language-section.tsx
- apps/ui/public/locales/ko/agent.json
- apps/ui/public/locales/zh/agent.json
- apps/ui/public/locales/pt/common.json
- apps/ui/public/locales/es/common.json
- apps/ui/public/locales/it/common.json
- apps/ui/public/locales/nl/board.json
- apps/ui/public/locales/it/agent.json
- apps/ui/public/locales/zh/common.json
- apps/ui/public/locales/nl/common.json
- apps/ui/public/locales/it/settings.json
- apps/ui/public/locales/pl/board.json
- apps/ui/public/locales/nl/agent.json
- apps/ui/src/components/views/settings-view/terminal/terminal-section.tsx
🔇 Additional comments (35)
apps/ui/public/locales/de/common.json (1)
1-294: LGTM! Well-structured German localization file.The translation quality is good with:
- Consistent use of informal "du" form throughout
- Proper ICU-style plural forms (
_one/_other) for time expressions and message counts- Correct German grammar including dative case ("Vor {{count}} Tagen")
- Appropriate localization of keyboard shortcuts (Strg instead of Ctrl on line 270)
- All placeholders (
{{name}},{{count}},{{maxSize}}) preserved correctlyThe previous review feedback regarding
messageCountplural forms has been addressed (lines 237-238).apps/ui/public/locales/ko/board.json (1)
1-160: Korean translations look complete and well-structured.The file provides comprehensive Korean localization for the board feature:
- All UI sections are covered with natural Korean translations
- Placeholder syntax (
{{count}},{{status}}) is correct for i18next- The
(으)로particle handling infeatureMoved(line 155) correctly accounts for Korean grammar rules- JSON structure is valid and matches the expected namespace format
apps/ui/public/locales/it/board.json (1)
127-135: [rewritten comment]
[classification tag]apps/ui/public/locales/zh/board.json (3)
1-160: Overall structure and translations look good.The JSON is valid, translations are comprehensive, and the ICU-style plural keys (
blockedBy_one/blockedBy_other) at lines 147-148 correctly handle Chinese pluralization (both forms are identical since Chinese doesn't grammatically distinguish plurals).
127-135: No changes needed fortaskskey.The
taskskey correctly lacks{{count}}because the component concatenates the count separately before the translation call. Line 328 ofagent-info-panel.tsxrenders it as{effectiveTodos.length} {t('agentInfo.tasks')}, which produces the correct output. ThetasksDonekey uses a different pattern (passing count to the translation function), but this is intentional and appropriate for its use case. The translation as written is correct.
133-134: The original review assumes other locales define plural variants fortoolCallsandtasksDone, but verification shows all locales (English, German, French, etc.) use the same non-plural key format for these strings. There is no inconsistency across locales. The difference withblockedByis intentional:blockedByrequires singular/plural variants because the text changes ("dependency" vs "dependencies"), whiletoolCallsandtasksDoneare always plural forms and don't need variants.Likely an incorrect or invalid review comment.
apps/ui/public/locales/en/agent.json (2)
28-28: No changes needed. The component already uses<Trans>with proper component mapping (lines 188-194 of input-controls.tsx), which correctly renders<kbd>tags as styled React elements rather than literal text. The keyboard hint string will display properly formatted.Likely an incorrect or invalid review comment.
11-11: Theheader.messagesCounttranslation key exists but is unused in the UI. ThemessagesCountprop only controls visibility of the "Clear" button; the count itself is never rendered with this translation key, so there is no "1 messages" issue to address.Likely an incorrect or invalid review comment.
apps/ui/public/locales/de/agent.json (10)
2-4: LGTM — welcome copy reads well.
14-29: LGTM — input strings look consistent and actionable.
30-47: LGTM — session labels and pluralization look correct.
48-55: LGTM — chat copy and plural forms are consistent.
56-66: LGTM — queue strings and counts are well-formed.
67-76: LGTM — tools labels are clear.
77-81: LGTM — error messages are concise.
82-85: LGTM — no-project copy is clear.
86-90: LGTM — file attachment strings look good.
5-13: Remove unused translation keyheader.messagesCountor clarify its intended use.The translation key
header.messagesCountexists in the German locale file but is never actually used in the codebase. ThemessagesCountprop is received inagent-header.tsxand checked in a conditional, but it is never rendered with this translation key. Either remove the unused key from the locale file or add the code that renders it at the appropriate location.Likely an incorrect or invalid review comment.
apps/ui/public/locales/fr/common.json (1)
1-294: LGTM — solid FR common locale coverage.Strings, placeholders, and plural keys look consistent and complete.
apps/ui/public/locales/fr/board.json (1)
1-160: LGTM — board translations look consistent and complete.apps/ui/public/locales/ko/settings.json (1)
1-363: LGTM — KO settings translations look consistent and comprehensive.apps/ui/public/locales/es/settings.json (1)
1-363: LGTM — ES settings translations look complete and consistent.apps/ui/public/locales/en/common.json (1)
1-294: LGTM — English base locale looks correct (including plural forms).apps/ui/public/locales/pl/common.json (1)
1-302: LGTM: Polish common locale payload looks solid.No blocking issues spotted in this data-only addition.
apps/ui/public/locales/pl/settings.json (1)
1-363: LGTM: Polish settings locale data is comprehensive.Nothing to flag in this translation payload.
apps/ui/public/locales/fr/settings.json (1)
1-363: LGTM: French settings locale payload looks good.No issues found in this data-only file.
apps/ui/public/locales/ja/settings.json (1)
1-363: LGTM: Japanese settings locale payload looks clean.No blocking concerns in this translation file.
apps/ui/public/locales/pt/settings.json (1)
1-363: LGTM: Portuguese settings locale data looks consistent.No issues found in this data-only addition.
apps/ui/public/locales/en/settings.json (5)
1-31: LGTM!The top-level structure and navigation section are well-organized with consistent camelCase key naming conventions.
32-99: LGTM!The
featureDefaultsandmodelDefaultssections are well-structured with clear, descriptive keys and consistent naming patterns.
244-306: LGTM!The
appearance,terminal,keyboard,audio, andlanguagesections are well-structured. The i18next interpolation syntax ({{name}},{{count}}) is correct.
307-337: LGTM!The
account,security, anddangersections are well-organized with clear descriptions for potentially destructive actions.
339-363: LGTM!The
themesandplanningModessections provide clear, user-friendly display names. The JSON structure is valid and properly closed.apps/ui/public/locales/ru/agent.json (2)
25-27: Verify whetherinput.filesAttachedis rendered with a count.
If this string is used withcount, it should include{{count}}and Russian plural forms; if the count is rendered separately, consider clarifying the key name to avoid ambiguity.
6-12:header.messagesCountis not currently used in the UI and should not be added without implementing its display.The
messagesCountprop is passed toAgentHeaderbut is never rendered with the i18n translation. The component only checks the conditionmessagesCount > 0to show the clear button but never displays the actual count value viat('header.messagesCount', { count: messagesCount }).Adding plural forms would address a symptom, not the underlying issue: either implement the feature to display the message count in the UI (then add plural variants), or remove this unused translation key entirely.
Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
- Add _one/_other plural forms for EN, DE, FR, IT, PT, NL, ES - Add CLDR plural forms (_one/_few/_many/_other) for Polish and Russian - Add _other form for JA, ZH, KO (no grammatical plurals) - Add messageCount_other for Japanese common.json Addresses CodeRabbit review feedback on PR AutoMaker-Org#508. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
Languages Supported
Components Converted
Technical Details
react-i18nextwith lazy loading via HTTP backendcommon,settings,agent,boardTest plan
npm run dev:web🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.