diff --git a/frontend/src/CLAUDE.md b/frontend/src/CLAUDE.md index 5959f83..5ccc9af 100644 --- a/frontend/src/CLAUDE.md +++ b/frontend/src/CLAUDE.md @@ -64,8 +64,8 @@ User interactions trigger mutations/queries via hooks, which communicate with th #### `lib/locales/` — Internationalization (i18n) - **Locale files** (`en-US/`, `pt-BR/`, `zh-CN/`, `zh-TW/`, `ja-JP/`): Translation strings organized by feature - **`i18n.ts`**: i18next configuration with language detection -- **`use-translation.ts`**: Custom hook with Proxy-based `t.section.key` access pattern -- **Pattern**: Components call `useTranslation()` hook; access strings via `t.common.save`, `t.notebooks.title` +- **`use-translation.ts`**: Thin wrapper around react-i18next's `useTranslation` with language change events +- **Pattern**: Components call `useTranslation()` hook; access strings via `t('common.save')`, `t('notebooks.title')` ## Data & Control Flow Walkthrough diff --git a/frontend/src/lib/hooks/CLAUDE.md b/frontend/src/lib/hooks/CLAUDE.md index e2d00a8..fc56b40 100644 --- a/frontend/src/lib/hooks/CLAUDE.md +++ b/frontend/src/lib/hooks/CLAUDE.md @@ -10,7 +10,7 @@ React hooks for API data fetching, state management, and complex workflows (chat - **Streaming hooks** (`useAsk`): SSE parsing for multi-stage Ask workflows (strategy → answers → final answer) - **Model/config hooks** (`useModels`, `useSettings`, `useTransformations`): Application-level settings and model management - **Utility hooks** (`useMediaQuery`, `useToast`, `useNavigation`, `useAuth`): UI state and auth checking -- **i18n hook** (`useTranslation`): Proxy-based translation access with `t.section.key` pattern and language switching +- **i18n hook** (`useTranslation`): Thin wrapper around react-i18next with `t('section.key')` pattern and language switching ## Important Patterns @@ -22,7 +22,7 @@ React hooks for API data fetching, state management, and complex workflows (chat - **SSE streaming pattern**: `useAsk` manually parses newline-delimited JSON from `/api/search/ask`; handles incomplete buffers - **Status polling**: `useSourceStatus` auto-refetches every 2s while `status === 'running' | 'queued' | 'new'` - **Context building**: `useNotebookChat.buildContext()` assembles selected sources + notes with token/char counts -- **i18n Proxy pattern**: `useTranslation` returns `t` object with Proxy; access `t.section.key` instead of `t('section.key')` +- **i18n pattern**: `useTranslation` returns standard react-i18next `t` function; access translations via `t('section.key')` ## Key Dependencies @@ -49,8 +49,7 @@ React hooks for API data fetching, state management, and complex workflows (chat - **Status polling race**: `useSourceStatus` may refetch stale data before server catches up; retry logic has 3-attempt limit - **Keyboard trap in dialogs**: Some hooks manage modal state; ensure Dialog/Modal components handle escape key properly - **Form data handling**: `useFileUpload` and source creation convert JSON fields to strings in FormData -- **useTranslation depth limit**: Proxy limits nesting to 4 levels; deeper access returns path string as fallback -- **useTranslation loop detection**: >1000 accesses to same key in 1s triggers error and breaks recursion +- **useTranslation**: Thin wrapper preserving `setLanguage` with language change events for `LanguageLoadingOverlay` ## Testing Patterns @@ -187,7 +186,7 @@ function CredentialSettings() { ### Important Notes - **Toast notifications**: All mutations show success/error toasts automatically -- **i18n integration**: Toast messages use translation keys from `t.apiKeys.*` and `t.common.*` +- **i18n integration**: Toast messages use translation keys from `t('apiKeys.*')` and `t('common.*')` - **Error handling**: Uses `getApiErrorKey()` utility to extract error messages from API responses - **Local test results**: `useTestCredential` stores results in local state (not cached in TanStack Query) - **Migration feedback**: Migration hooks show different toasts based on migrated/skipped/error counts diff --git a/frontend/src/lib/hooks/use-settings.ts b/frontend/src/lib/hooks/use-settings.ts index f5416cc..736a1f2 100644 --- a/frontend/src/lib/hooks/use-settings.ts +++ b/frontend/src/lib/hooks/use-settings.ts @@ -3,7 +3,7 @@ import { settingsApi } from '@/lib/api/settings' import { QUERY_KEYS } from '@/lib/api/query-client' import { useToast } from '@/lib/hooks/use-toast' import { useTranslation } from '@/lib/hooks/use-translation' -import { getApiErrorKey } from '@/lib/utils/error-handler' +import { getApiErrorMessage } from '@/lib/utils/error-handler' import { SettingsResponse } from '@/lib/types/api' export function useSettings() { @@ -30,7 +30,7 @@ export function useUpdateSettings() { onError: (error: unknown) => { toast({ title: t('common.error'), - description: getApiErrorKey(error, t('common.error')), + description: getApiErrorMessage(error, (key) => t(key), 'common.error'), variant: 'destructive', }) }, diff --git a/frontend/src/lib/locales/CLAUDE.md b/frontend/src/lib/locales/CLAUDE.md index 6d4b929..23b9eb8 100644 --- a/frontend/src/lib/locales/CLAUDE.md +++ b/frontend/src/lib/locales/CLAUDE.md @@ -1,6 +1,6 @@ # Locales Module (i18n) -Internationalization system providing multi-language UI support using i18next with type-safe translation access. +Internationalization system providing multi-language UI support using i18next with standard `t()` function calls. ## Architecture @@ -9,7 +9,7 @@ lib/ ├── i18n.ts # i18next initialization and configuration ├── i18n-events.ts # Language change event emitters ├── hooks/ -│ └── use-translation.ts # Custom hook with Proxy-based API +│ └── use-translation.ts # Thin wrapper around react-i18next with language change events ├── utils/ │ └── date-locale.ts # date-fns locale mapping └── locales/ @@ -28,7 +28,7 @@ lib/ - **`i18n.ts`**: i18next initialization with language detection (localStorage → browser) - **`i18n-events.ts`**: Event emitters for language change start/end (used by loading overlay) - **`locales/index.ts`**: Central registry exporting all locales and `LanguageCode` type -- **`use-translation.ts`**: Custom hook providing `t` object with nested property access +- **`use-translation.ts`**: Thin wrapper around react-i18next returning `{ t, i18n, language, setLanguage }` ## Translation Structure @@ -67,24 +67,36 @@ import { useTranslation } from '@/lib/hooks/use-translation' function MyComponent() { const { t, language, setLanguage } = useTranslation() - // Nested property access (Proxy-based) - return

{t.notebooks.title}

+ // Standard t() function call + return

{t('notebooks.title')}

- // With interpolation - return

{t.common.updated.replace('{time}', timeAgo)}

+ // With string interpolation + return

{t('common.updated').replace('{time}', timeAgo)}

// Change language await setLanguage('zh-CN') } ``` +### Functions that accept t as a parameter + +Use `TFunction` from i18next: + +```typescript +import type { TFunction } from 'i18next' + +const getNavigation = (t: TFunction) => [ + { name: t('navigation.sources'), href: '/sources' }, +] +``` + ## Important Patterns -- **Proxy-based access**: `t.section.key` instead of `t('section.key')` for better DX -- **Type safety**: `TranslationKeys` type derived from `enUS` locale +- **Standard t() calls**: `t('section.key')` — standard react-i18next pattern - **Language persistence**: Saved to localStorage, auto-detected on load - **Fallback**: Falls back to `en-US` if key missing in current locale - **Date localization**: Use `getDateLocale(language)` from `utils/date-locale.ts` +- **Language change events**: `setLanguage` emits start/end events for `LanguageLoadingOverlay` ## Key Dependencies @@ -117,13 +129,10 @@ function MyComponent() { ## Important Quirks & Gotchas -- **Proxy depth limit**: `useTranslation` limits nesting to 4 levels to prevent infinite loops -- **Blocked properties**: React internals (`__proto__`, `$$typeof`, etc.) are blocked from Proxy traversal -- **Loop detection**: Access counts reset every 1s; >1000 accesses triggers error and breaks recursion -- **String methods**: `.replace()`, `.split()` work on translated strings via Proxy magic - **Language change events**: `emitLanguageChangeStart/End` used by `LanguageLoadingOverlay` for UX - **No SSR**: `useSuspense: false` disables React Suspense for i18next (avoids hydration issues) - **All keys required**: Missing keys in non-English locales fall back to English; keep locales in sync +- **ErrorBoundary**: Uses raw `enUS` locale object directly (class component, can't use hooks) ## Testing Patterns @@ -131,7 +140,7 @@ function MyComponent() { // Mock useTranslation in tests (see test/setup.ts) vi.mock('@/lib/hooks/use-translation', () => ({ useTranslation: () => ({ - t: enUS, // Use English locale directly + t: (key: string) => key, // Identity function returns the key language: 'en-US', setLanguage: vi.fn(), }),