-
Notifications
You must be signed in to change notification settings - Fork 472
feat: Add internationalization (i18n) support #104
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 react-i18next with configuration for multiple languages - Create translation files for English and Traditional Chinese (zh-TW) - Set up 10 namespaces: common, chat, auth, git, errors, file, terminal, settings, todo, editor - Configure automatic language detection (localStorage, browser) - Add i18n initialization in main.jsx - Include number formatting utilities BREAKING CHANGE: Application now requires i18n initialization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Implement LanguageSwitcher component with dropdown menu - Support English and Traditional Chinese languages - Add dropdown-menu UI component for language selection - Enable dynamic language switching with persistence - Update UI to show current language with flags 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Create custom AlertDialog component without external dependencies - Replace window.alert in CodeEditor.jsx with AlertDialog - Replace window.alert and window.confirm in ToolsSettings.jsx - Properly handle dialog closing with action buttons - Improve user experience with modern UI components 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Update all React components to use i18n translations - Add useTranslation hook to 17+ components - Translate hundreds of UI strings to Traditional Chinese - Support dynamic content interpolation - Handle complex translations with React.Fragment - Fix star icon tooltips to use proper namespace - Move LanguageSwitcher to settings section in Sidebar - Complete translation of error messages and placeholders Components updated: - ChatInterface, Sidebar, GitPanel, FileTree, Shell - MainContent, TodoList, ClaudeStatus, QuickSettingsPanel - ImageViewer, LoginForm, SetupForm, MobileNav - DarkModeToggle, MicButton, ProtectedRoute, ClaudeLogo - Plus contexts, hooks, and utility files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Add max-width and mx-auto to center the message container - Improve visual alignment for better user experience
- Center align 'Start new Claude session' message - Center align 'Continue in terminal' button with proper styling - Add LanguageSwitcher component from feat/language-switcher branch - Add dropdown-menu UI component - Add alert-dialog UI component from feat/alert-dialog-replacement branch - Fix build errors by including all required components
@gowerlin I like this very much but it brings a very big dependency to the project. I'd suggest lets keep this PR open, merge as much as you can to resolve any conflicts and in a few weeks we can look at it again as it's not a priority for me at the moment. For example I can already see a lot of conflicts with new functionality that was added. |
- 保持 yarn 作為套件管理工具 - 解決 4 個檔案的合併衝突 - 整合國際化功能與最新更新
- 修復 ChatInterface 中缺少的 useTranslation hook - 修復 ChatInterface 函數簽名缺少 sendByCtrlEnter 參數 - 在開發模式中禁用 Service Worker 以避免快取問題 - 新增開發模式自動重設密碼功能(admin/admin123) - 修正登入除錯訊息 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- 保持使用 yarn 作為套件管理工具(刪除 package-lock.json) - 整合主分支的依賴更新與我們的 i18n 套件 - 修復 ChatInterface.jsx 中的 useTranslation hook - 保留 ErrorBoundary 和其他主分支的改進 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Implemented a service worker that skips waiting during installation. - Added an activation event to clear all caches for a fresh development environment. - Removed fetch event handler to allow all requests to go directly to the network.
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.
Pull Request Overview
This PR adds comprehensive internationalization (i18n) support to the Claude Code UI application with react-i18next, implementing English and Traditional Chinese translations across all components.
Key Changes
- i18n Infrastructure: Configured react-i18next with language detection, localStorage persistence, and namespace organization
- Translation Files: Created comprehensive translation files for all UI components in both English and Traditional Chinese
- Component Updates: Updated all components to use translation hooks instead of hardcoded strings
- Language Switcher: Added a dropdown component for easy language selection in the sidebar
- Number/Date Formatting: Included locale-aware formatting utilities
Reviewed Changes
Copilot reviewed 53 out of 64 changed files in this pull request and generated 7 comments.
Show a summary per file
File | Description |
---|---|
vite.config.js | Added path alias configuration for imports |
src/main.jsx | Initialized i18n on application startup |
src/i18n/index.js | Main i18n configuration with language detection and resources |
src/i18n/locales/ | Translation files for English and Traditional Chinese across all namespaces |
src/components/*.jsx | Updated components to use useTranslation hooks and translation keys |
src/components/LanguageSwitcher.jsx | New language selection dropdown component |
src/components/ui/ | Added dropdown menu and alert dialog UI components |
Comments suppressed due to low confidence (1)
src/components/Sidebar.jsx:772
- The translation key 'settings:sidebar.newProject.placeholder' is inconsistent with the namespace usage. This should be 'sidebar.projectNamePlaceholder' since it's accessing the sidebar namespace from the common translations.
placeholder={t('settings:sidebar.newProject.placeholder')}
export function formatFileSize(bytes, locale = 'en') { | ||
const units = ['B', 'KB', 'MB', 'GB', 'TB']; | ||
const unitIndex = Math.floor(Math.log(bytes) / Math.log(1024)); | ||
const size = bytes / Math.pow(1024, unitIndex); | ||
|
||
const formattedSize = new Intl.NumberFormat(locale, { | ||
minimumFractionDigits: 0, | ||
maximumFractionDigits: 2 | ||
}).format(size); | ||
|
||
return `${formattedSize} ${units[unitIndex]}`; | ||
} |
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 formatFileSize function will fail when bytes is 0 or negative because Math.log(0) returns -Infinity. Add a check for bytes <= 0 and return '0 B' in that case.
export function formatFileSize(bytes, locale = 'en') { | |
const units = ['B', 'KB', 'MB', 'GB', 'TB']; | |
const unitIndex = Math.floor(Math.log(bytes) / Math.log(1024)); | |
const size = bytes / Math.pow(1024, unitIndex); | |
const formattedSize = new Intl.NumberFormat(locale, { | |
minimumFractionDigits: 0, | |
maximumFractionDigits: 2 | |
}).format(size); | |
return `${formattedSize} ${units[unitIndex]}`; | |
} | |
export function formatFileSize(bytes, locale = 'en') { | |
if (bytes <= 0) { | |
return '0 B'; | |
} | |
const units = ['B', 'KB', 'MB', 'GB', 'TB']; | |
const unitIndex = Math.floor(Math.log(bytes) / Math.log(1024)); | |
const size = bytes / Math.pow(1024, unitIndex); | |
const formattedSize = new Intl.NumberFormat(locale, { | |
minimumFractionDigits: 0, | |
maximumFractionDigits: 2 | |
}).format(size); | |
return `${formattedSize} ${units[unitIndex]}`; | |
} |
Copilot uses AI. Check for mistakes.
<div className="flex items-center gap-3"> | ||
<AlertTriangle className="w-5 h-5 text-orange-500" /> | ||
<h3 className="text-lg font-medium text-foreground"> | ||
{t('tools.permissionSettings', 'Permission Settings')} |
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.
Using fallback strings in translation calls (second parameter) is not recommended. The fallback string should be defined in the translation files instead. This pattern makes it harder to maintain translations and can lead to inconsistencies.
{t('tools.permissionSettings', 'Permission Settings')} | |
{t('tools.permissionSettings')} |
Copilot uses AI. Check for mistakes.
{t('tools.skipPermissions')} | ||
</div> | ||
<div className="text-sm text-orange-700 dark:text-orange-300"> | ||
{t('tools.skipPermissionsDescription', 'Equivalent to --dangerously-skip-permissions flag')} |
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.
Similar to the previous comment, avoid using fallback strings in translation calls. Define all translation keys in the translation files instead.
{t('tools.skipPermissionsDescription', 'Equivalent to --dangerously-skip-permissions flag')} | |
{t('tools.skipPermissionsDescription')} |
Copilot uses AI. Check for mistakes.
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"> | ||
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" /> | ||
</svg> | ||
{t('buttons.saveFailed') || 'Failed to save settings'} |
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.
Using the || operator for fallback text with translations can cause issues. If the translation key exists but returns an empty string, the fallback won't be used. Use the fallback parameter in the t() function or ensure the translation key exists in all locales.
Copilot uses AI. Check for mistakes.
console.error('Failed to start recording:', err); | ||
|
||
// Provide specific error messages based on error type | ||
let errorMessage = t('microphone.accessFailed'); |
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 useTranslation hook (t function) is not imported or defined in this component. This will cause a runtime error. Add 'import { useTranslation } from 'react-i18next'; const { t } = useTranslation('common');' at the top of the component.
Copilot uses AI. Check for mistakes.
) : confirmAction.type === 'pull' ? ( | ||
<> | ||
<Download className="w-4 h-4" /> | ||
<span>{t('remoteActions.pull', { n: '' }).replace(' ', '')}</span> |
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.
Using string replacement on translated text is error-prone and makes the code harder to maintain. Create a separate translation key for the action without parameters instead of manipulating the translated string.
Copilot uses AI. Check for mistakes.
Summary
Key Changes
Test Plan
🤖 Generated with Claude Code