Skip to content

Conversation

gowerlin
Copy link

Summary

  • Added comprehensive internationalization support using react-i18next
  • Implemented English and Traditional Chinese (zh-TW) translations
  • Added language switcher component for easy language selection

Key Changes

  • i18n Infrastructure: Set up react-i18next with language detection and dynamic loading
  • Translation Files: Created comprehensive translation files for all UI components
  • Component Updates: Updated all components to use translation keys instead of hardcoded strings
  • Language Switcher: Added a user-friendly language switcher in the sidebar
  • Date/Time Formatting: Localized date and time displays based on selected language

Test Plan

  • Verify all UI text is properly translated in both English and Traditional Chinese
  • Test language switching persists across page refreshes
  • Ensure no hardcoded strings remain in components
  • Verify date/time formatting follows locale conventions
  • Test that language detection works correctly for new users

🤖 Generated with Claude Code

gowerlin and others added 7 commits July 20, 2025 15:06
- 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
@viper151
Copy link
Contributor

@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.

gowerlin and others added 6 commits July 27, 2025 08:49
- 保持 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.
@Copilot Copilot AI review requested due to automatic review settings August 4, 2025 14:34
Copy link

@Copilot Copilot AI left a 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')}

Comment on lines +20 to +31
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]}`;
}
Copy link
Preview

Copilot AI Aug 4, 2025

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.

Suggested change
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')}
Copy link
Preview

Copilot AI Aug 4, 2025

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.

Suggested change
{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')}
Copy link
Preview

Copilot AI Aug 4, 2025

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.

Suggested change
{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'}
Copy link
Preview

Copilot AI Aug 4, 2025

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');
Copy link
Preview

Copilot AI Aug 4, 2025

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>
Copy link
Preview

Copilot AI Aug 4, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants