diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json deleted file mode 100644 index 141da2f..0000000 --- a/.sisyphus/boulder.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "active_plan": "C:\\dev\\workspace\\kintone\\kintone-customize-manager\\.sisyphus\\plans\\i18n-integration.md", - "started_at": "2026-03-13T15:49:52.804Z", - "session_ids": [ - "ses_3181c303bffeybo48ZtQ4KkVD8" - ], - "plan_name": "i18n-integration", - "agent": "atlas" -} \ No newline at end of file diff --git a/.sisyphus/evidence/task-01-deps-installed.txt b/.sisyphus/evidence/task-01-deps-installed.txt deleted file mode 100644 index ed76ee1..0000000 --- a/.sisyphus/evidence/task-01-deps-installed.txt +++ /dev/null @@ -1,23 +0,0 @@ -# i18n Dependencies Installation Evidence - -Date: 2026-03-13 - -## Installed Packages - -``` -+-- @lobehub/i18n-cli@1.26.1 -+-- i18next-browser-languagedetector@8.2.1 -+-- i18next@25.8.18 -`-- react-i18next@16.5.8 - `-- i18next@25.8.18 deduped -``` - -## Verification Command - -```bash -npm ls i18next react-i18next i18next-browser-languagedetector @lobehub/i18n-cli -``` - -## Status: ✅ COMPLETE - -All 4 i18n dependencies installed successfully. \ No newline at end of file diff --git a/.sisyphus/evidence/task-03-locale-structure.txt b/.sisyphus/evidence/task-03-locale-structure.txt deleted file mode 100644 index 7d5a4dc..0000000 --- a/.sisyphus/evidence/task-03-locale-structure.txt +++ /dev/null @@ -1,84 +0,0 @@ -# Task 03: Locale File Structure - Evidence - -## Status: ✅ COMPLETE (Pre-existing) - -## Directory Structure Created -``` -src/renderer/src/locales/ -├── default/ -│ ├── common.json (31 keys) -│ ├── domain.json (31 keys) -│ ├── settings.json (24 keys) -│ └── errors.json (20 keys) -├── zh-CN/ -│ ├── common.json (31 keys) -│ ├── domain.json (31 keys) -│ ├── settings.json (24 keys) -│ └── errors.json (20 keys) -├── ja-JP/ -│ ├── common.json (31 keys) -│ ├── domain.json (31 keys) -│ ├── settings.json (24 keys) -│ └── errors.json (20 keys) -└── en-US/ - ├── common.json (31 keys) - ├── domain.json (31 keys) - ├── settings.json (24 keys) - └── errors.json (20 keys) -``` - -## Verification -- [x] Directories created: default/, zh-CN/, ja-JP/, en-US/ -- [x] Files created: common.json, domain.json, settings.json, errors.json -- [x] Each file has >5 translation keys (minimum 20 per file) -- [x] Flat key structure used (no nested objects) - -## Sample Content - -### common.json (default) -```json -{ - "appName": "Kintone Manager", - "save": "保存", - "cancel": "取消", - "delete": "删除", - "edit": "编辑", - ... -} -``` - -### domain.json (default) -```json -{ - "title": "域名管理", - "addDomain": "添加域名", - "editDomain": "编辑域名", - ... -} -``` - -### settings.json (default) -```json -{ - "title": "设置", - "language": "语言", - "selectLanguage": "选择语言", - ... -} -``` - -### errors.json (default) -```json -{ - "networkError": "网络错误", - "invalidDomain": "无效的域名", - "connectionFailed": "连接失败", - ... -} -``` - -## Notes -- Structure was already in place from prior work -- All translations follow flat key structure -- Chinese is the default/source language -- English and Japanese translations provided \ No newline at end of file diff --git a/.sisyphus/evidence/task-04-store-compiled.txt b/.sisyphus/evidence/task-04-store-compiled.txt deleted file mode 100644 index dd7099d..0000000 --- a/.sisyphus/evidence/task-04-store-compiled.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Task 04: Locale Store - Compilation Evidence - -## Date: 2026-03-13 - -## Files Created -- src/renderer/src/stores/localeStore.ts - -## Verification - -### TypeScript Check -```bash -npx tsc --noEmit -# Result: PASSED (no errors) -``` - -### Store Implementation -- Uses Zustand with persist middleware -- Imports LocaleCode and DEFAULT_LOCALE from @shared/types/locale -- Persists only the locale state value (partialize pattern) -- Exports useLocaleStore hook - -### State Shape -```typescript -interface LocaleState { - locale: LocaleCode; // "zh-CN" | "ja-JP" | "en-US" - setLocale: (locale: LocaleCode) => void; -} -``` - -### Default Value -- locale: "zh-CN" (from DEFAULT_LOCALE constant) - -## Status: COMPLETED diff --git a/.sisyphus/evidence/task-05-i18n-config.txt b/.sisyphus/evidence/task-05-i18n-config.txt deleted file mode 100644 index 0be2bdc..0000000 --- a/.sisyphus/evidence/task-05-i18n-config.txt +++ /dev/null @@ -1 +0,0 @@ -TypeScript compilation: SUCCESS diff --git a/.sisyphus/evidence/task-06-i18n-cli.txt b/.sisyphus/evidence/task-06-i18n-cli.txt deleted file mode 100644 index 39a5b1c..0000000 --- a/.sisyphus/evidence/task-06-i18n-cli.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Task 06: Configure @lobehub/i18n-cli - -## Completed Actions - -1. **Installed @lobehub/i18n-cli@^1.26.1** as dev dependency -2. **Added npm script**: `"i18n": "lobe-i18n"` to package.json -3. **Verified CLI works**: `npm run i18n -- --help` returns usage info - -## Existing Configuration (.i18nrc.js) - -```javascript -module.exports = { - entry: ['src/renderer/src/locales/default/*.json'], - output: 'src/renderer/src/locales', - entryLocale: 'zh-CN', - outputLocales: ['en-US', 'ja-JP'], - apiKey: process.env.OPENAI_API_KEY || '', - apiModel: 'gpt-4o-mini', -}; -``` - -## CLI Usage - -```bash -# Run translation -npm run i18n - -# With markdown translation -npm run i18n -- --with-md - -# Lint translations -npm run i18n -- --lint -``` - -## Notes - -- Source locale: zh-CN (in `locales/default/`) -- Output locales: en-US, ja-JP -- API key must be set via `OPENAI_API_KEY` environment variable -- Uses gpt-4o-mini model for translation \ No newline at end of file diff --git a/.sisyphus/notepads/core-features/learnings.md b/.sisyphus/notepads/core-features/learnings.md deleted file mode 100644 index 2b64813..0000000 --- a/.sisyphus/notepads/core-features/learnings.md +++ /dev/null @@ -1,57 +0,0 @@ -# Learnings - -## [2026-03-12] Kintone Customize Manager Core Features - -### Technical Decisions - -1. **Type System Organization** - - Created separate type files for domain, kintone, version, and ipc types - - Used `Result` pattern for unified IPC response handling - - Added path alias `@renderer/*` to tsconfig.node.json for main process imports - -2. **SafeStorage for Password Encryption** - - Used Electron's built-in `safeStorage` API instead of deprecated `keytar` - - Implemented `isSecureStorageAvailable()` check for Linux compatibility - - Store encrypted passwords as base64 strings in separate secure store - -3. **Kintone API Client** - - Used native `fetch` API (Node.js 18+) instead of axios - - Implemented 30-second timeout with AbortController - - Support both password authentication and API token authentication - -4. **IPC Architecture** - - All handlers return `{ success: boolean, data?: T, error?: string }` - - Used `contextBridge` to expose safe API to renderer - - Created typed `ElectronAPI` interface for window.api - -5. **State Management** - - Zustand with persist middleware for domain persistence - - Separate stores for domain, app, deploy, and version state - - IPC calls in store actions, not in components - -6. **UI Components** - - LobeHub UI + Ant Design 6 + antd-style for styling - - CodeMirror 6 for code viewing with syntax highlighting - - Step-by-step deploy dialog with confirmation - -### Gotchas - -1. **tsconfig.node.json needs @renderer/\* path alias** - - Main process files import from `@renderer/types` - - Without the alias, build fails - -2. **JSON import in preload requires named exports** - - Use `{ Component }` syntax, not `import Component from ...` - - Default exports don't work with contextBridge - -3. **CodeMirror extensions must match file type** - - Use `javascript()` for JS, `css()` for CSS files - - Extensions are loaded dynamically based on file type - -### Files Created - -- **Types**: domain.ts, kintone.ts, version.ts, ipc.ts -- **Main**: storage.ts, kintone-api.ts, ipc-handlers.ts -- **Preload**: index.ts, index.d.ts (updated) -- **Stores**: domainStore.ts, appStore.ts, deployStore.ts, versionStore.ts -- **Components**: DomainManager/, SpaceTree/, AppDetail/, CodeViewer/, FileUploader/, DeployDialog/, VersionHistory/ diff --git a/.sisyphus/notepads/i18n-integration/issues.md b/.sisyphus/notepads/i18n-integration/issues.md deleted file mode 100644 index 55059e2..0000000 --- a/.sisyphus/notepads/i18n-integration/issues.md +++ /dev/null @@ -1,47 +0,0 @@ - -## [2026-03-14] Locale Not Synced Between Processes - -### 问题描述 -Renderer process 和 Main process 的 locale 状态没有同步。 - -### 复现步骤 -1. 用户在 UI 中切换语言 (例如从 zh-CN 到 en-US) -2. localeStore 更新 localStorage,i18next 切换语言 -3. 但是 Main process 的 `config.json` 仍然是旧值 -4. Main process 的错误消息使用旧语言 - -### 根本原因 -- `localeStore.setLocale()` 只更新 Zustand state -- 没有调用 `window.api.setLocale()` 同步到 Main process - -### 解决方案 -需要在以下位置添加同步逻辑: - -1. **localeStore.ts**: 修改 `setLocale` action - ```typescript - setLocale: async (locale) => { - set({ locale }); - await window.api.setLocale({ locale }); - } - ``` - -2. **App.tsx**: 在初始化时从 Main process 读取 locale - ```typescript - useEffect(() => { - const initLocale = async () => { - const result = await window.api.getLocale(); - if (result.success) { - useLocaleStore.getState().setLocale(result.data); - i18n.changeLanguage(result.data); - } - }; - initLocale(); - }, []); - ``` - -### 影响范围 -- `src/renderer/src/stores/localeStore.ts` -- `src/renderer/src/App.tsx` 或 `src/renderer/src/main.tsx` - -### 优先级 -高 - 影响用户体验,Main process 错误消息语言不一致 diff --git a/.sisyphus/notepads/i18n-integration/learnings.md b/.sisyphus/notepads/i18n-integration/learnings.md deleted file mode 100644 index 1377501..0000000 --- a/.sisyphus/notepads/i18n-integration/learnings.md +++ /dev/null @@ -1,790 +0,0 @@ -# i18n Integration Learnings - -## 2026-03-13 - Locale File Structure - -### Structure Created -- **Directory**: `src/renderer/src/locales/` -- **Subdirectories**: `default/`, `zh-CN/`, `ja-JP/`, `en-US/` -- **Files per language**: `common.json`, `domain.json`, `settings.json`, `errors.json` - -### Translation Key Format -- Use flat key structure (no nested objects): `"app.title"` instead of `{"app": {"title": ""}}` -- Each file contains 20+ translation keys (exceeds minimum 5) -- Keys are organized by feature area: - - `common.json`: UI buttons, labels, status messages - - `domain.json`: Domain management specific translations - - `settings.json`: Settings page translations - - `errors.json`: Error messages and validation errors - -### Language Codes -- `default/`: Source language (Chinese) -- `zh-CN/`: Simplified Chinese -- `en-US/`: English (US) -- `ja-JP/`: Japanese - -### Best Practices -1. Keep translation keys descriptive (e.g., `collapseSidebar` not `cs`) -2. Group related keys together in the same file -3. Use consistent naming convention (camelCase for keys) -## [2026-03-13] - Locale Store Implementation - -### Pattern: Zustand Store with Persist Middleware - -Created `localeStore.ts` following the existing `domainStore.ts` pattern: - -```typescript -export const useLocaleStore = create()( - persist( - (set) => ({ - locale: DEFAULT_LOCALE, - setLocale: (locale) => set({ locale }), - }), - { - name: "locale-storage", - partialize: (state) => ({ locale: state.locale }), - }, - ), -); -``` - -### Key Decisions -- Use `partialize` to only persist the `locale` value, not actions -- Import `DEFAULT_LOCALE` from shared types to ensure consistency -- Store key is `locale-storage` in localStorage - -### File Location -- Store: `src/renderer/src/stores/localeStore.ts` -- Types: `src/shared/types/locale.ts` (LocaleCode, DEFAULT_LOCALE) - -## [2026-03-13] - i18n Instance Configuration - -### Pattern: Static Import Configuration - -Created `i18n.ts` with static imports for all locale files: - -```typescript -// Import locale files statically -import commonZHCN from "./locales/zh-CN/common.json"; -import domainZHCN from "./locales/zh-CN/domain.json"; -// ... (all 12 files imported) - -const resources = { - "zh-CN": { common: commonZHCN, domain: domainZHCN, ... }, - "ja-JP": { ... }, - "en-US": { ... }, -}; -``` - -### Key Configuration Options - -- **fallbackLng**: `zh-CN` - fallback to Chinese if translation missing -- **defaultNS**: `common` - default namespace for `t()` calls -- **ns**: `['common', 'domain', 'settings', 'errors']` - 4 namespaces -- **escapeValue**: `false` - React handles XSS protection -- **detection**: localStorage + navigator order, caches to localStorage - -### Language Detector Configuration - -```typescript -detection: { - order: ["localStorage", "navigator"], - caches: ["localStorage"], - lookupLocalStorage: "i18nextLng", -} -``` - -This ensures: -1. First check localStorage for saved preference -2. Fall back to browser language -3. Persist detected/selected language to localStorage - -### File Location -- Configuration: `src/renderer/src/i18n.ts` -- Must be imported in `main.tsx` before React renders - -## [2026-03-13] - Dependencies Installation - -### Installed Packages -- `i18next@25.8.18` - Core i18n framework -- `react-i18next@16.5.8` - React bindings for i18next -- `i18next-browser-languagedetector@8.2.1` - Browser language detection -- `@lobehub/i18n-cli@1.26.1` - LobeHub i18n CLI tool - -### Notes -- React-i18next correctly dedupes i18next dependency -- All packages are latest stable versions -- LobeHub UI uses @emoji-mart/react which has peer dependency warning for React 19 (non-blocking) - -## [2026-03-13] - @lobehub/i18n-cli Configuration - -### Configuration Pattern -- Binary name: `lobe-i18n` (not `@lobehub/i18n-cli`) -- Config file: `.i18nrc.js` (CommonJS format) -- Uses environment variable for API key: `OPENAI_API_KEY` - -### Locale Structure for CLI -- `locales/default/` - Source files (Chinese) -- `locales/zh-CN/` - Same as default (for consistency) -- `locales/en-US/` - English translations -- `locales/ja-JP/` - Japanese translations - -### Important Notes -- entryLocale = source language (zh-CN = Chinese) -- outputLocales = target languages for AI translation -- Do NOT put zh-CN in outputLocales if it's the source -- The CLI supports markdown translation with `--with-md` flag - -### npm script -```json -"i18n": "lobe-i18n" -``` - -Run with: `npm run i18n` -## 2026-03-14 - I18nextProvider Integration - -### Changes Made -- Added `I18nextProvider` import from `react-i18next` -- Added `i18n` instance import from `./i18n` -- Wrapped `` with `` to enable i18n throughout the app - -### Integration Pattern -```tsx - - - - - - - -``` - -### Notes -- The i18n instance from `./i18n` is already initialized (chained `.use().init()`) -- No additional initialization needed in main.tsx -- I18nextProvider wraps ThemeProvider (not the other way around) - -- I18nextProvider wraps ThemeProvider (not the other way around) - -## [2026-03-14] - Ant Design Locale Synchronization - -### Pattern: Locale Mapping -- Use a mapping function to convert i18next locale codes to Ant Design locale objects -- Supported mapping: - - `zh-CN` → `zhCN` (antd/locale/zh_CN) - - `ja-JP` → `jaJP` (antd/locale/ja_JP) - - `en-US` → `enUS` (antd/locale/en_US) - -### Implementation -```typescript -// Import all locales -import zhCN from "antd/locale/zh_CN"; -import jaJP from "antd/locale/ja_JP"; -import enUS from "antd/locale/en_US"; -import type { Locale } from "antd/es/locale"; - -// Map locale code to Ant Design locale -const getAntdLocale = React.useCallback((localeCode: string): Locale => { - switch (localeCode) { - case "ja-JP": - return jaJP; - case "en-US": - return enUS; - case "zh-CN": - default: - return zhCN; - } -}, []); - -// Memoize the result -const antdLocale = React.useMemo( - () => getAntdLocale(locale), - [locale, getAntdLocale] -); - -// Use in ConfigProvider - -``` - -### Key Points -- Use `React.useCallback` for the mapping function to prevent unnecessary re-renders -- Use `React.useMemo` to memoize the locale result based on locale changes -- Import `Locale` type from `antd/es/locale` for type safety -- Default fallback to `zhCN` for unsupported locales - -## [2026-03-14] - Preload Locale API Exposure - -### Files Modified -- `src/shared/types/ipc.ts` - Added `SetLocaleParams` interface -- `src/preload/index.ts` - Added `getLocale` and `setLocale` IPC invocations -- `src/preload/index.d.ts` - Added type declarations for locale API - -### Pattern: IPC Exposure in Preload -```typescript -// In preload/index.ts -const api: SelfAPI = { - // ... other APIs - - // Locale - getLocale: () => ipcRenderer.invoke("getLocale"), - setLocale: (params) => ipcRenderer.invoke("setLocale", params), -}; -``` - -### Type Declaration Pattern -```typescript -// In preload/index.d.ts -import type { SetLocaleParams } from "@shared/types/ipc"; -import type { LocaleCode } from "@shared/types/locale"; - -export interface SelfAPI { - // ... other methods - - // ==================== Locale ==================== - getLocale: () => Promise>; - setLocale: (params: SetLocaleParams) => Promise>; -} -``` - -### Key Points -- Follow existing IPC patterns (invoke with channel name and params) -- Use `Result` wrapper for return types -- Import types from `@shared/types/` path alias -- Add IPC type params interface to `ipc.ts` - -## 2026-03-14 - Main Process IPC Locale Synchronization - -### Implementation Pattern - -**Storage Layer** (`src/main/storage.ts`): -- Added `locale?: LocaleCode` to `AppConfig` interface -- Implemented `getLocale()` - reads locale from config.json, returns `DEFAULT_LOCALE` if not set -- Implemented `setLocale(locale: LocaleCode)` - saves locale to config.json -- Uses existing `readJsonFile`/`writeJsonFile` pattern for consistency - -**IPC Handlers** (`src/main/ipc-handlers.ts`): -- `getLocale` handler: Returns `Promise>` -- `setLocale` handler: Takes `SetLocaleParams`, returns `Promise>` -- Uses existing `handle` helper wrapper for error handling - -**Types** (`src/shared/types/ipc.ts`): -- `SetLocaleParams` interface already exists with `locale: LocaleCode` property -- Follows pattern of other params objects (e.g., `CreateDomainParams`, `UpdateDomainParams`) - -**Preload** (`src/preload/index.ts`): -- `getLocale: () => ipcRenderer.invoke("getLocale")` -- `setLocale: (params) => ipcRenderer.invoke("setLocale", params)` - -### Key Decisions - -1. **Not using react-i18next in main process**: Main process uses simple locale string storage, not full i18n library -2. **Params object pattern**: `setLocale` uses `SetLocaleParams` object instead of `LocaleCode` directly for consistency with other IPC handlers -3. **Default fallback**: `getLocale()` returns `DEFAULT_LOCALE` ("zh-CN") when no locale is set -4. **Storage location**: Locale stored in `config.json` alongside domains array - -### File Changes Summary - -- `src/main/storage.ts`: Added `getLocale()` and `setLocale()` functions -- `src/main/ipc-handlers.ts`: Added `registerGetLocale()` and `registerSetLocale()` handlers -- `src/shared/types/ipc.ts`: `SetLocaleParams` already existed -- `src/preload/index.d.ts`: Locale API types already existed -- `src/preload/index.ts`: Locale methods already existed - -## 2026-03-14 - App.tsx Internationalization - -### Pattern Used -- Import: `import { useTranslation } from "react-i18next";` -- Hook usage: `const { t } = useTranslation();` -- Translation call: `{t('translationKey')}` - -### Translation Keys Added -- `deployFiles` - "部署文件" / "Deploy Files" / "ファイルをデプロイ" -- `versionHistory` - "版本历史" / "Version History" / "バージョン履歴" -- `settings` - "设置" / "Settings" / "設定" - -### Existing Keys Used -- `collapseSidebar` - "收起侧边栏" -- `expandSidebar` - "展开侧边栏" - -### Files Modified -1. `src/renderer/src/App.tsx` - Added useTranslation hook, replaced hardcoded text -2. `src/renderer/src/locales/zh-CN/common.json` - Added new keys -3. `src/renderer/src/locales/en-US/common.json` - Added new keys -4. `src/renderer/src/locales/ja-JP/common.json` - Added new keys -5. `src/renderer/src/locales/default/common.json` - Added new keys - -### i18n Setup -- Uses `react-i18next` with `I18nextProvider` wrapper in main.tsx -- Default namespace: `common` -- Fallback language: `zh-CN` -- Locale files: `./locales/{lang}/{namespace}.json` - -## [2026-03-14] - DomainManager Component Internationalization - -### Files Modified -- `src/renderer/src/components/DomainManager/DomainManager.tsx` -- `src/renderer/src/locales/default/domain.json` - -### Pattern: useTranslation Hook with Namespace - -```typescript -import { useTranslation } from "react-i18next"; - -const DomainManager: React.FC = ({...}) => { - const { t } = useTranslation("domain"); - // ... - return

{t("domainManagement")}

; -}; -``` - -### Translation Keys Added -- `noDomainSelected`: "未选择 Domain" -- `addDomainTooltip`: "添加 Domain" -- `domainManagement`: "Domain 管理" -- `add`: "添加" -- `noDomainConfig`: "暂无 Domain 配置" -- `addFirstDomainConfig`: "添加第一个 Domain" - -### Key Points -1. Use `useTranslation("domain")` to specify the namespace -2. Replace all hardcoded Chinese text with `t("key")` calls -3. Use regex `[\u4e00-\u9fff]` to find remaining Chinese characters for verification -4. Keep translation keys in camelCase format - -## [2026-03-14] - Main Process Error Message Internationalization - -### Challenge: Cannot Use react-i18next in Main Process - -The main process cannot use `react-i18next` because: -1. It's designed for React rendering, not Node.js/Electron main process -2. Main process needs synchronous error message access -3. Main process errors can be thrown before renderer initializes - -### Solution: Simple Custom i18n Module - -Created `src/main/errors.ts` with a simple translation approach: - -```typescript -import type { LocaleCode } from "@shared/types/locale"; -import { getLocale } from "./storage"; - -const errorMessages: Record> = { - "zh-CN": { domainNotFound: "域名未找到", ... }, - "en-US": { domainNotFound: "Domain not found", ... }, - "ja-JP": { domainNotFound: "ドメインが見つかりません", ... }, -}; - -export function getErrorMessage( - key: MainErrorKey, - params?: ErrorParams, - locale?: LocaleCode, -): string { - const targetLocale = locale ?? getLocale(); - const messages = errorMessages[targetLocale] || errorMessages["zh-CN"]; - return interpolate(messages[key], params); -} -``` - -### Files Modified - -1. `src/main/errors.ts` - NEW: Error message module with translations -2. `src/main/ipc-handlers.ts` - Updated all error throws to use `getErrorMessage()` -3. `src/main/kintone-api.ts` - Updated fallback errors to use i18n - -### Error Keys Added - -- `domainNotFound` - Domain not found errors -- `domainDuplicate` - Duplicate domain+username errors -- `connectionFailed` - Connection test failures -- `unknownError` - Generic fallback error -- `rollbackNotImplemented` - Feature not implemented error -- `encryptPasswordFailed` - Password encryption errors -- `decryptPasswordFailed` - Password decryption errors - -### Circular Dependency Consideration - -**IMPORTANT**: `errors.ts` imports `getLocale` from `storage.ts`. Therefore, `storage.ts` CANNOT import from `errors.ts`. - -- `storage.ts` password encrypt/decrypt errors remain hardcoded (they are internal system errors) -- Only user-facing errors in IPC handlers are internationalized - -### Interpolation Pattern - -For errors with dynamic values, use `{{placeholder}}` syntax: - -```typescript -// In errors.ts -const messages = { - domainDuplicate: "Domain \"{{domain}}\" with user \"{{username}}\" already exists.", -}; - -// Usage -getErrorMessage("domainDuplicate", { domain: "example.com", username: "admin" }); -``` - -### Test Verification - -Tests show i18n working correctly: -``` -Invalid credentials test result: { success: false, error: '连接失败' } -``` -The error message '连接失败' is in Chinese (the current locale setting). - - -## [2026-03-14] Locale Persistence Verification - -### 验证结果 - -#### ✅ Renderer Process Persistence (正常) - -1. **localeStore** (`src/renderer/src/stores/localeStore.ts`) - - 使用 Zustand 的 `persist` 中间件 - - localStorage key: `locale-storage` - - 只持久化 `locale` 字段 (通过 `partialize`) - - 实现正确 - -2. **i18next** (`src/renderer/src/i18n.ts`) - - 使用 `i18next-browser-languagedetector` - - localStorage key: `i18nextLng` - - 检测顺序: localStorage → navigator - - 实现正确 - -#### ✅ Main Process Persistence (正常) - -1. **storage.ts** (`src/main/storage.ts`) - - `getLocale()`: 从 `config.json` 读取 locale - - `setLocale()`: 写入 `config.json` - - 默认值: `DEFAULT_LOCALE` (zh-CN) - - 实现正确 - -2. **IPC Handlers** (`src/main/ipc-handlers.ts`) - - `registerGetLocale()`: 返回存储的 locale - - `registerSetLocale()`: 保存 locale 到 config.json - - 实现正确 - -3. **Error Messages** (`src/main/errors.ts`) - - `getErrorMessage()`: 使用 `getLocale()` 获取当前语言 - - 支持错误消息本地化 - - 实现正确 - -#### ❌ CRITICAL ISSUE: Renderer 和 Main Process 没有同步! - -**问题**: -- Renderer 修改语言时,只更新 localStorage,**没有调用 `window.api.setLocale()`** -- Main process 的 `config.json` 与 localStorage 不同步 -- Main process 错误消息可能使用错误的语言 - -**证据**: -- `localeStore.ts` 的 `setLocale` action 只更新 Zustand state -- `App.tsx` 使用 `useLocaleStore().locale` 但没有同步到 main process -- `i18n.ts` 的 LanguageDetector 只检测 localStorage,不涉及 main process - -**影响**: -- 重启应用后,main process 的错误消息语言可能与 UI 不一致 -- `getErrorMessage()` 会使用 `config.json` 中可能过时的 locale - -### 修复建议 - -需要在 renderer 和 main process 之间建立同步机制: - -1. **方案 A (推荐): App 启动时同步** - - 在 App 初始化时,读取 main process 的 locale - - 设置 localeStore 和 i18next - - 用户修改语言时,同时调用 `window.api.setLocale()` - -2. **方案 B: 双向绑定** - - localeStore 的 `setLocale` 同时调用 IPC - - 使用 useEffect 监听 locale 变化并同步 - -### 首次启动处理 - -当前实现已经正确处理: -- `getLocale()` 返回 `DEFAULT_LOCALE` 如果没有存储 -- i18next 的 detector 会尝试使用系统语言 (`navigator`) -- 首次启动会使用系统语言 (如果支持) 或 fallback 到 zh-CN - -## [2026-03-14] - Settings Component with Language Switcher - -### Component Structure -- **Directory**: `src/renderer/src/components/Settings/` -- **Files**: `Settings.tsx`, `index.ts` -- **Pattern**: Functional component with antd-style - -### Implementation Pattern - -```typescript -import { useTranslation } from "react-i18next"; -import { Radio, Typography } from "antd"; -import { createStyles } from "antd-style"; -import { useLocaleStore } from "@renderer/stores/localeStore"; -import { LOCALES, type LocaleCode } from "@shared/types/locale"; - -const Settings: React.FC = () => { - const { t } = useTranslation("settings"); - const { styles } = useStyles(); - const { locale, setLocale } = useLocaleStore(); - const i18n = useTranslation().i18n; - - const handleLocaleChange = (newLocale: LocaleCode) => { - setLocale(newLocale); // Update Zustand store - i18n.changeLanguage(newLocale); // Update i18next - }; - - return ( - handleLocaleChange(e.target.value)}> - {LOCALES.map((loc) => ( - - {loc.nativeName} - - ))} - - ); -}; -``` - -### Key Design Decisions - -1. **Use LOCALES constant**: Import from `@shared/types/locale` for consistent locale data -2. **Dual update**: Update both localeStore and i18n when language changes -3. **Radio.Group styling**: Custom CSS for better UX with native name and English name display -4. **Namespace usage**: Use `useTranslation("settings")` for settings-specific translations - -### Translation Keys Used -- `settings.json`: `language` - "语言" / "Language" / "言語" - -### UI Design -- Radio options styled as cards with border -- Shows both native name (e.g., "简体中文") and English name (e.g., "Chinese Simplified") -- Hover effect with primary color border and background -- Selected state highlighted with primary color - -### Note on Synchronization -The component updates both `localeStore` and `i18n`, but does NOT call `window.api.setLocale()` to sync with main process. This is a known limitation documented in the learnings file above. Future work should add main process sync. -### Note on Synchronization -The component updates both `localeStore` and `i18n`, but does NOT call `window.api.setLocale()` to sync with main process. This is a known limitation documented in the learnings file above. Future work should add main process sync. - -## 2026-03-14 - Component Internationalization (Wave 3) - -### New Namespaces Created -- `app.json` - AppDetail, AppList components -- `deploy.json` - DeployDialog component -- `file.json` - FileUploader, CodeViewer components -- `version.json` - VersionHistory component - -### Translation Key Naming Convention -- Actions: `loadApps`, `saveConfig`, `testConnection` -- States: `loading`, `connected`, `deploying` -- Labels: `fileName`, `position`, `type` -- Messages: `loadAppsFailed`, `deploySuccess` - -### Cross-Namespace Reference Pattern -```typescript -// Reference other namespace's translations -t("cancel", { ns: "common" }) -t("selectApp", { ns: "app" }) -``` - -### Interpolation Pattern -```typescript -// JSON file -"totalApps": "共 {{count}} 个应用" - -// Component usage -t("totalApps", { count: displayApps.length }) -``` - -### Components Internationalized -1. **DomainManager** - domain namespace -2. **DomainForm** - domain namespace -3. **DomainList** - domain namespace -4. **AppDetail** - app namespace -5. **AppList** - app namespace -6. **CodeViewer** - file namespace -7. **DeployDialog** - deploy namespace -8. **FileUploader** - file namespace -9. **VersionHistory** - version namespace - -### i18n.ts Update Pattern -When adding new namespaces: -1. Add imports for all locales -2. Add to resources object for each language -3. Add to `ns` array - -```typescript -// Example -import appZHCN from "./locales/zh-CN/app.json"; -// ... -const resources = { - "zh-CN": { ..., app: appZHCN, ... }, - // ... -}; -// ... -ns: ["common", "domain", "settings", "errors", "app", "deploy", "file", "version"], -``` - -## [2026-03-14] - Renderer/Main Process Locale Synchronization Fix - -### Problem -Renderer stored locale in localStorage (via Zustand persist), main process stored in config.json - they were NOT synced. When user changed language in UI, main process error messages still used old language. - -### Solution: Bidirectional Sync - -**1. Settings.tsx - Sync to Main Process on Change** -```typescript -const handleLocaleChange = async (newLocale: LocaleCode) => { - setLocale(newLocale); - i18n.changeLanguage(newLocale); - // Sync locale to main process - await window.api.setLocale({ locale: newLocale }); -}; -``` - -**2. App.tsx - Sync from Main Process on Mount** -```typescript -const setLocaleStore = useLocaleStore((state) => state.setLocale); - -// Sync locale from main process on mount -React.useEffect(() => { - const syncLocaleFromMain = async () => { - const result = await window.api.getLocale(); - if (result.success && result.data) { - setLocaleStore(result.data); - i18n.changeLanguage(result.data); - } - }; - syncLocaleFromMain(); -}, [setLocaleStore]); -``` - -### Key Points -1. **On language change**: Update localStorage (Zustand), i18next, AND main process config.json -2. **On app startup**: Read locale from main process and sync to renderer -3. **Use async/await**: IPC calls are asynchronous -4. **Import i18n directly**: Need direct reference to i18n instance for changeLanguage() in useEffect - -### Files Modified -- `src/renderer/src/components/Settings/Settings.tsx` - Added `window.api.setLocale()` call -- `src/renderer/src/App.tsx` - Added useEffect to sync from main process on mount -``` - -## [2026-03-14] - Code Quality Review - Critical Parsing Errors Found - -### VERDICT: FAIL - -| Check | Status | Count | -|-------|--------|-------| -| TypeScript | PASS | 0 errors | -| ESLint | FAIL | 11 parsing errors, 1 warning | -| `as any` | PASS | 0 found | -| `@ts-ignore` | WARNING | 2 found (acceptable) | -| Empty catches | PASS | 0 found | - -### Critical Issues (P0 - Parsing Errors) - -**Root Cause**: Incomplete i18n integration - leftover duplicate code from merging translated and untranslated code versions. - -#### 1. Duplicate `import {` statements (5 files) -All files have duplicate `import {` on lines 8-9: -- `src/renderer/src/components/AppDetail/AppDetail.tsx` -- `src/renderer/src/components/AppList/AppList.tsx` -- `src/renderer/src/components/DeployDialog/DeployDialog.tsx` -- `src/renderer/src/components/VersionHistory/VersionHistory.tsx` - -#### 2. Duplicate function parameters (2 files) -Parameters duplicated inside function body: -- `src/renderer/src/components/CodeViewer/CodeViewer.tsx` (lines 68-72) -- `src/renderer/src/components/FileUploader/FileUploader.tsx` (lines 68-72) - -#### 3. Duplicate code blocks (2 files) -- `src/main/ipc-handlers.ts` (lines 127-128): Duplicate error message string - leftover hardcoded Chinese -- `src/renderer/src/components/DomainManager/DomainForm.tsx` (lines 166-169): Duplicate `else` block with hardcoded Chinese text - -### ESLint Warning (P3) -- `src/renderer/src/App.tsx:242` - Missing dependency `setIsResizing` in useCallback - -### Acceptable @ts-ignore (P2) -- `src/preload/index.ts:50,52` - Used for non-isolated context fallback (acceptable) - -### Prevention -- After large-scale refactoring (like i18n integration), always run `npm run lint` before committing -- Use automated checks in CI/CD pipeline -- Code review should catch duplicate code blocks - - - - -## [2026-03-14] - Scope Fidelity Check Results - -### Must Have Compliance [5/5 PASS] - -| Requirement | Status | Evidence | -|-------------|--------|----------| -| react-i18next + i18next 核心库 | ✅ PASS | `package.json`: i18next@25.8.18, react-i18next@16.5.8 | -| @lobehub/i18n-cli 自动化翻译 | ✅ PASS | `package.json` devDeps: @lobehub/i18n-cli@1.26.1, `.i18nrc.js` configured | -| 中日英三语完整翻译 | ✅ PASS | 32 locale files across zh-CN/, ja-JP/, en-US/ with 8 namespaces each | -| 语言切换 UI 组件 | ✅ PASS | `src/renderer/src/components/Settings/Settings.tsx` with Radio.Group | -| 用户偏好持久化 | ✅ PASS | `localeStore.ts` with Zustand persist, `storage.ts` getLocale/setLocale | - -### Must NOT Have Compliance [4/4 PASS] - -| Forbidden Pattern | Status | Evidence | -|-------------------|--------|----------| -| i18next-electron-fs-backend | ✅ PASS | Not found in dependencies or code (grep returned 0 matches) | -| RTL 语言支持 | ✅ PASS | No RTL/direction code found (grep returned 0 matches) | -| 远程翻译文件加载 | ✅ PASS | Using static imports in `i18n.ts`, no HTTP backend | -| MVP 阶段过度抽象翻译 key | ✅ PASS | Flat key structure, reasonable naming convention | - -### Tasks Compliance [17/17 PASS] - -All 17 tasks from the plan have been implemented: -- Wave 1 (Tasks 1-6): Dependencies, types, locales, store, i18n config, CLI config -- Wave 2 (Tasks 7-10): Provider, AntD locale sync, IPC handlers, Preload API -- Wave 3 (Tasks 11-14): Component i18n, main process errors -- Wave 4 (Tasks 15-17): Settings page, language switcher, persistence - -### Code Quality Issues Found - -⚠️ **CRITICAL: Duplicate Code Blocks** - -The following files contain duplicate code blocks that need cleanup: - -1. **`src/renderer/src/i18n.ts`**: - - Lines 14-17 duplicate lines 6-13 (imports) - - Lines 26-28 duplicate lines 18-25 (imports) - - Lines 38-40 duplicate lines 30-37 (imports) - - Lines 75-94 duplicate lines 43-74 (resources object) - -2. **`src/renderer/src/components/Settings/Settings.tsx`**: - - Lines 81-83 duplicate lines 76-80 (handleLocaleChange function) - -3. **`src/renderer/src/App.tsx`**: - - Lines 159-160 duplicate line 158 (`const { styles } = useStyles();`) - - Lines 191-192 duplicate lines 176-177 (useState declarations) - -4. **`src/main/ipc-handlers.ts`**: - - Lines 127-129 contain incomplete/duplicate code block after getErrorMessage call - -5. **`src/renderer/src/main.tsx`**: - - Line 14: Ant Design locale hardcoded as `locale={zhCN}` instead of dynamic - -### VERDICT - -**Must Have**: 5/5 ✅ PASS -**Must NOT Have**: 4/4 ✅ PASS -**Tasks**: 17/17 ✅ PASS - -**SCOPE FIDELITY: COMPLIANT** - -However, **code quality issues must be fixed** before final approval. The duplicate code blocks are merge conflicts or copy-paste errors that will cause: -- TypeScript compilation errors -- Runtime errors -- Incorrect behavior - -### Recommended Actions - -1. Remove duplicate imports in `i18n.ts` -2. Remove duplicate `resources` object definition in `i18n.ts` -3. Remove duplicate `handleLocaleChange` body in `Settings.tsx` -4. Remove duplicate `useStyles()` call in `App.tsx` -5. Remove duplicate useState declarations in `App.tsx` -6. Fix incomplete code block in `ipc-handlers.ts` -7. Consider making Ant Design locale dynamic in `main.tsx` (currently hardcoded) \ No newline at end of file diff --git a/.sisyphus/plans/core-features.md b/.sisyphus/plans/core-features.md deleted file mode 100644 index 2b1fa79..0000000 --- a/.sisyphus/plans/core-features.md +++ /dev/null @@ -1,857 +0,0 @@ -# Kintone Customize Manager - 核心功能实现计划 - -## TL;DR - -> **Quick Summary**: 实现 Kintone Customize Manager 的核心功能,包括多 Domain 管理、资源浏览、拖拽部署和版本管理。 -> -> **Deliverables**: -> - 多 Domain 配置管理(创建/编辑/删除/切换) -> - Space 和 App 浏览树 -> - 拖拽文件部署到 Kintone -> - 版本历史管理 -> - Kintone API 封装 -> -> **Estimated Effort**: Large -> **Parallel Execution**: YES - 6 waves -> **Critical Path**: 类型定义 → Store → API 封装 → Domain 管理 → App 详情 → 部署功能 - ---- - -## Context - -### Original Request -按照 REQUIREMENTS.md 创建任务计划,实现 Kintone Customize Manager 桌面应用的核心功能。 - -### Interview Summary -**Key Discussions**: -- **项目状态**: 全新项目,已使用 electron-vite 脚手架初始化并引入依赖库 -- **优先级**: 核心功能优先(Domain 管理 + 部署) -- **测试策略**: 仅 QA 验证(不需要单元测试) - -**Research Findings**: -- 项目已配置 electron-vite + electron-builder -- 已安装 LobeHub UI + Ant Design 6 + CodeMirror 6 -- 主进程入口已创建(src/main/index.ts) -- 基础项目结构已建立 - ---- - -## Work Objectives - -### Core Objective -实现 Kintone Customize Manager 的核心功能,让用户能够管理多个 Kintone 实例、浏览应用资源、拖拽部署自定义代码。 - -### Concrete Deliverables -- `src/main/kintone-api.ts` - Kintone REST API 封装 -- `src/main/storage.ts` - 文件系统和密码存储 -- `src/renderer/src/stores/domainStore.ts` - Domain 状态管理 -- `src/renderer/src/components/DomainManager/` - Domain 管理 UI -- `src/renderer/src/components/SpaceTree/` - Space/App 浏览树 -- `src/renderer/src/components/AppDetail/` - App 详情页 -- `src/renderer/src/components/FileUploader/` - 拖拽部署组件 -- `src/renderer/src/components/VersionHistory/` - 版本历史 - -### Definition of Done -- [ ] 可创建/编辑/删除 Domain 配置 -- [ ] 可浏览 Space 和 App 列表 -- [ ] 可拖拽文件部署到 Kintone -- [ ] 部署前自动备份当前版本 -- [ ] 可查看版本历史 - -### Must Have -- 密码使用 safeStorage 加密存储 -- 所有 Kintone API 调用有错误处理 -- 部署前有确认 Dialog 和代码对比 - -### Must NOT Have (Guardrails) -- 不包含 Plugin 管理功能(P2 需求) -- 不包含批量操作功能(P1 需求) -- 不包含国际化(初始版本仅中文) -- 不实现单元测试(仅 QA 验证) - -### Commit Policy (IMPORTANT) -**一个任务 = 一次提交** - -- ✅ 每个任务完成后必须单独提交 -- ✅ 提交信息格式:`type(scope): description`(约定式提交) -- ❌ 不要将多个任务合并到一次提交中 -- ⚠️ 如果计划中标注 "groups with N",同 Wave 任务可合并提交 - -**提交类型**:`feat` | `fix` | `refactor` | `docs` | `style` | `test` | `chore` - -**提交前检查清单**: -1. 完成该任务的所有 "What to do" 内容 -2. 通过 `npx tsc --noEmit` 类型检查 -3. 执行该任务的 QA Scenarios 并保存证据到 `.sisyphus/evidence/` -4. 代码格式化(`npm run format`) -- 不包含 Plugin 管理功能(P2 需求) -- 不包含批量操作功能(P1 需求) -- 不包含国际化(初始版本仅中文) -- 不实现单元测试(仅 QA 验证) - ---- - -## Verification Strategy - -> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions. - -### Test Decision -- **Infrastructure exists**: NO -- **Automated tests**: None -- **Framework**: None -- **Agent-Executed QA**: ALWAYS (mandatory for all tasks) - -### QA Policy -Every task MUST include agent-executed QA scenarios. Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. - -- **Frontend/UI**: Use Playwright — Navigate, interact, assert DOM, screenshot -- **API/Backend**: Use Bash (curl) — Send requests, assert status + response fields -- **Main Process**: Use Bash (ts-node) — Run IPC handlers, verify responses - ---- - -## Execution Strategy - -### Parallel Execution Waves - -``` -Wave 1 (Start Immediately — foundation + types): -├── Task 1: 共享类型定义 [quick] -├── Task 2: 主进程存储模块 [quick] -├── Task 3: Kintone API 封装 [deep] -├── Task 4: IPC 通信处理 [quick] -├── Task 5: Preload API 暴露 [quick] -└── Task 6: Zustand Store 基础 [quick] - -Wave 2 (After Wave 1 — Domain 管理): -├── Task 7: Domain Store 完整实现 [quick] -├── Task 8: DomainManager UI 组件 [visual-engineering] -├── Task 9: Domain 表单 Dialog [visual-engineering] -└── Task 10: Domain 列表连接 Store [quick] - -Wave 3 (After Wave 2 — 资源浏览): -├── Task 11: SpaceTree 组件 [visual-engineering] -├── Task 12: App 列表渲染 [visual-engineering] -├── Task 13: App 详情页布局 [visual-engineering] -└── Task 14: 代码查看器组件 [visual-engineering] - -Wave 4 (After Wave 3 — 部署功能): -├── Task 15: FileUploader 拖拽组件 [visual-engineering] -├── Task 16: 部署位置选择器 [visual-engineering] -├── Task 17: 代码 Diff 对比组件 [visual-engineering] -├── Task 18: 部署确认 Dialog [visual-engineering] -└── Task 19: 部署执行 IPC 处理 [deep] - -Wave 5 (After Wave 4 — 版本管理): -├── Task 20: 版本历史存储逻辑 [quick] -├── Task 21: VersionHistory UI 组件 [visual-engineering] -├── Task 22: 版本对比功能 [visual-engineering] -└── Task 23: 版本回滚部署 [deep] - -Wave 6 (After Wave 5 — 集成 + QA): -├── Task 24: App 页面集成 [deep] -├── Task 25: 端到端 Playwright QA [unspecified-high] -└── Task 26: Git 清理 + 标签 [git] - -Critical Path: Task 1 → Task 6 → Task 7 → Task 10 → Task 11 → Task 13 → Task 15 → Task 19 → Task 24 → Task 25 -Parallel Speedup: ~65% faster than sequential -Max Concurrent: 5-6 (Waves 1, 3, 4) -``` - ---- - -## TODOs - -- [x] 1. 共享类型定义 - - **What to do**: - - 创建 `src/renderer/src/types/domain.ts` - Domain 配置类型 - - 创建 `src/renderer/src/types/kintone.ts` - Kintone API 响应类型 - - 创建 `src/renderer/src/types/version.ts` - 版本历史类型 - - 创建 `src/renderer/src/types/ipc.ts` - IPC 通信类型 - - **Must NOT do**: - - 不要包含业务逻辑(仅类型定义) - - 不要使用 `any` 类型 - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 简单的类型定义文件,无复杂逻辑 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 2-6) - - **Blocks**: Tasks 3, 7, 11, 20 - - **Blocked By**: None - - **References**: - - `REQUIREMENTS.md:272-284` - Domain 数据结构 - - `REQUIREMENTS.md:405-437` - Download/Version 数据结构 - - `REQUIREMENTS.md:527-545` - Deploy 数据结构 - - **Acceptance Criteria**: - - [ ] `src/renderer/src/types/domain.ts` 包含 Domain 接口 - - [ ] `src/renderer/src/types/kintone.ts` 包含 Kintone API 响应类型 - - [ ] `src/renderer/src/types/version.ts` 包含 Version 接口 - - [ ] `src/renderer/src/types/ipc.ts` 包含 IPC 请求/响应类型 - - **QA Scenarios**: - ``` - Scenario: 类型定义编译检查 - Tool: Bash (tsc) - Preconditions: 项目根目录 - Steps: - 1. 运行 `npx tsc --noEmit` - 2. 验证输出无错误 - Expected Result: 编译通过,无类型错误 - Evidence: .sisyphus/evidence/task-1-types-check.txt - ``` - - **Commit**: YES (groups with 2-6) - - Message: `feat(types): add shared TypeScript type definitions` - - Files: `src/renderer/src/types/*.ts` - ---- - -- [x] 2. 主进程存储模块 - - **What to do**: - - 创建 `src/main/storage.ts` - 文件系统操作 - - 实现 safeStorage 加密存储密码 - - 实现 Domain 配置的读取/保存 - - 实现版本历史的存储逻辑 - - 实现下载文件的存储逻辑 - - **Must NOT do**: - - 不要硬编码路径(使用 electron-store) - - 不要明文存储密码 - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 主进程工具模块,无 UI 交互 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1, 3-6) - - **Blocks**: Tasks 3, 7, 20 - - **Blocked By**: None - - **References**: - - `REQUIREMENTS.md:125-145` - safeStorage 使用示例 - - `REQUIREMENTS.md:197-214` - 本地存储结构 - - `package.json:31` - electron-store 依赖 - - **Acceptance Criteria**: - - [ ] `src/main/storage.ts` 包含 saveDomain/getDomain/deleteDomain 函数 - - [ ] 密码使用 safeStorage 加密 - - [ ] 配置文件保存在 `~/.kintone-manager/config.json` - - [ ] Linux 环境检测 safeStorage 后端 - - **QA Scenarios**: - ``` - Scenario: 存储模块功能验证 - Tool: Bash (ts-node) - Preconditions: 主进程环境 - Steps: - 1. 编写测试脚本调用 saveDomain - 2. 调用 getDomain 验证读取 - 3. 调用 deleteDomain 验证删除 - Expected Result: CRUD 操作均成功,返回预期结果 - Evidence: .sisyphus/evidence/task-2-storage-test.txt - ``` - - **Commit**: YES (groups with 1, 3-6) - - Message: `feat(main): implement storage module with safeStorage` - - Files: `src/main/storage.ts` - ---- - -- [x] 3. Kintone API 封装 - - **What to do**: - - 创建 `src/main/kintone-api.ts` - Kintone REST API 客户端 - - 实现认证(密码认证 + API Token) - - 实现 Space 列表获取 - - 实现 App 列表获取 - - 实现 App 配置获取 - - 实现文件上传/下载 - - 实现应用配置更新(部署) - - **Must NOT do**: - - 不要包含 UI 逻辑 - - 不要硬编码域名和凭证 - - **Recommended Agent Profile**: - - **Category**: `deep` - - **Skills**: [] - - **Reason**: 核心业务逻辑,需要处理认证、错误重试、文件流 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1, 2, 4-6) - - **Blocks**: Tasks 11, 12, 19 - - **Blocked By**: Task 1 (types), Task 2 (storage) - - **References**: - - `REQUIREMENTS.md:331-345` - Kintone API 端点 - - `REQUIREMENTS.md:502-522` - 部署 API 端点 - - `REQUIREMENTS.md:77-88` - 密码认证 vs API Token - - **Acceptance Criteria**: - - [ ] `src/main/kintone-api.ts` 包含 KintoneClient 类 - - [ ] 支持密码认证和 API Token 认证 - - [ ] 实现 getSpaces/getApps/getAppConfig 方法 - - [ ] 实现 uploadFile/downloadFile方法 - - [ ] 实现 updateAppConfig 方法(部署) - - [ ] 所有方法有错误处理和超时控制(30 秒) - - **QA Scenarios**: - ``` - Scenario: Kintone API 连接测试 - Tool: Bash (ts-node) - Preconditions: 有效的 Kintone 凭证 - Steps: - 1. 创建 KintoneClient 实例 - 2. 调用 getSpaces() 获取 Space 列表 - 3. 调用 getApps(spaceId) 获取 App 列表 - Expected Result: 成功返回 Space 和 App 列表,无错误 - Evidence: .sisyphus/evidence/task-3-api-test.txt - - Scenario: 错误处理验证 - Tool: Bash (ts-node) - Preconditions: 无效的 Kintone 凭证 - Steps: - 1. 创建 KintoneClient 实例(错误凭证) - 2. 调用 getSpaces() - Expected Result: 抛出认证错误,错误信息清晰 - Evidence: .sisyphus/evidence/task-3-api-error.txt - ``` - - **Commit**: YES (groups with 1, 2, 4-6) - - Message: `feat(main): implement Kintone REST API client` - - Files: `src/main/kintone-api.ts` - ---- - -- [x] 4. IPC 通信处理 - - **What to do**: - - 创建 `src/main/ipc-handlers.ts` - IPC 请求处理 - - 实现 Domain 管理的 IPC 处理(create/update/delete/list) - - 实现资源浏览的 IPC 处理(getSpaces/getApps/getAppConfig) - - 实现部署的 IPC 处理(deploy/download) - - 实现版本管理的 IPC 处理(getVersions/rollback) - - **Must NOT do**: - - 不要包含业务逻辑(调用 kintone-api 和 storage) - - 不要直接操作 DOM 或 UI - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 简单的 IPC 路由和错误处理 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-3, 5-6) - - **Blocks**: Tasks 7-10, 19 - - **Blocked By**: Task 2 (storage), Task 3 (kintone-api) - - **References**: - - `src/main/index.ts:58` - 现有 IPC 示例 - - `REQUIREMENTS.md:228-268` - Domain 管理功能需求 - - **Acceptance Criteria**: - - [ ] `src/main/ipc-handlers.ts` 包含所有 Domain 管理 handler - - [ ] 包含所有资源浏览 handler - - [ ] 包含部署和下载 handler - - [ ] 包含版本管理 handler - - [ ] 所有 handler 返回统一格式:`{ success: boolean, data?: T, error?: string }` - - **QA Scenarios**: - ``` - Scenario: IPC handler 调用测试 - Tool: Bash (ts-node) - Preconditions: 主进程运行中 - Steps: - 1. 使用 ipcMain.invoke 调用 handler - 2. 验证返回格式符合约定 - Expected Result: 所有 handler 返回成功,格式正确 - Evidence: .sisyphus/evidence/task-4-ipc-test.txt - ``` - - **Commit**: YES (groups with 1-3, 5-6) - - Message: `feat(main): implement IPC handlers for all features` - - Files: `src/main/ipc-handlers.ts` - ---- - -- [x] 5. Preload API 暴露 - - **What to do**: - - 更新 `src/preload/index.ts` - 暴露 API 到渲染进程 - - 定义 `src/preload/index.d.ts` - TypeScript 类型 - - 使用 contextBridge 暴露安全的 API - - 包含所有 IPC 调用的封装 - - **Must NOT do**: - - 不要暴露完整的 ipcRenderer(不安全) - - 不要包含业务逻辑 - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 标准的 Electron preload 模式 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-4, 6) - - **Blocks**: Tasks 7-26 (all renderer tasks) - - **Blocked By**: Task 4 (ipc-handlers) - - **References**: - - `src/preload/index.ts` - 现有 preload 脚本 - - `src/preload/index.d.ts` - 现有类型定义 - - `AGENTS.md:IPC 通信规范` - IPC 通信规范 - - **Acceptance Criteria**: - - [ ] `src/preload/index.ts` 暴露 window.api 对象 - - [ ] `src/preload/index.d.ts` 定义 ElectronAPI 接口 - - [ ] 包含所有 Domain 管理 API - - [ ] 包含所有资源浏览 API - - [ ] 包含所有部署和版本管理 API - - [ ] contextIsolation 启用 - - **QA Scenarios**: - ``` - Scenario: Preload API 可用性检查 - Tool: Bash (Playwright) - Preconditions: 应用启动 - Steps: - 1. 打开开发者工具 - 2. 在 Console 中执行 `typeof window.api` - Expected Result: 返回 'object',API 对象存在 - Evidence: .sisyphus/evidence/task-5-preload-check.png - ``` - - **Commit**: YES (groups with 1-4, 6) - - Message: `feat(preload): expose IPC APIs via contextBridge` - - Files: `src/preload/index.ts`, `src/preload/index.d.ts` - ---- - -- [x] 6. Zustand Store 基础架构 - - **What to do**: - - 创建 `src/renderer/src/stores/domainStore.ts` - Domain 状态 - - 创建 `src/renderer/src/stores/appStore.ts` - App 浏览状态 - - 创建 `src/renderer/src/stores/deployStore.ts` - 部署状态 - - 创建 `src/renderer/src/stores/versionStore.ts` - 版本历史状态 - - 使用 persist 中间件持久化 - - **Must NOT do**: - - 不要包含 UI 逻辑 - - 不要直接调用 IPC(在 actions 中调用) - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 标准 Zustand 模式 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-5) - - **Blocks**: Tasks 7-26 (all UI components) - - **Blocked By**: Task 1 (types), Task 5 (preload API) - - **References**: - - `AGENTS.md:Zustand Store 规范` - Zustand 规范 - - `package.json:37` - zustand 依赖 - - `REQUIREMENTS.md:269-284` - Domain 数据结构 - - **Acceptance Criteria**: - - [ ] `domainStore.ts` 包含 domains/currentDomain/actions - - [ ] `appStore.ts` 包含 spaces/apps/currentApp - - [ ] `deployStore.ts` 包含 deployParams/status - - [ ] `versionStore.ts` 包含 versions/currentVersion - - [ ] 所有 store 使用 persist 中间件 - - [ ] TypeScript 类型完整 - - **QA Scenarios**: - ``` - Scenario: Store 基础功能验证 - Tool: Bash (Playwright) - Preconditions: 应用启动 - Steps: - 1. 打开开发者工具 Console - 2. 验证 store 存在并可访问 - Expected Result: 所有 store 可访问,无错误 - Evidence: .sisyphus/evidence/task-6-store-check.png - ``` - - **Commit**: YES (groups with 1-5) - - Message: `feat(renderer): setup Zustand stores for all features` - - Files: `src/renderer/src/stores/*.ts` - ---- - -- [x] 7. Domain Store 完整实现 - - **What to do**: - - 完善 `domainStore.ts` - 添加 IPC 调用 - - 实现 loadDomains - 加载所有 Domain - - 实现 addDomain - 添加新 Domain - - 实现 updateDomain - 更新 Domain - - 实现 deleteDomain - 删除 Domain - - 实现 setCurrentDomain - 切换 Domain - - 实现 testConnection - 测试连接 - - **Must NOT do**: - - 不要包含 UI 逻辑 - - 不要硬编码错误处理 - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: Store 逻辑扩展 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 8-10) - - **Blocks**: Tasks 8-10 (Domain UI) - - **Blocked By**: Task 6 (store基础), Task 5 (preload API) - - **References**: - - `src/renderer/src/stores/domainStore.ts` - 基础 store - - `REQUIREMENTS.md:228-268` - Domain 管理功能 - - **Acceptance Criteria**: - - [ ] 所有 actions 调用 window.api - - [ ] 错误处理完善 - - [ ] 状态更新正确 - - [ ] 连接状态检测实现 - - **QA Scenarios**: - ``` - Scenario: Domain CRUD 操作 - Tool: Bash (Playwright) - Preconditions: 应用启动 - Steps: - 1. 调用 addDomain 添加测试 Domain - 2. 调用 loadDomains 验证已添加 - 3. 调用 updateDomain 更新信息 - 4. 调用 deleteDomain 删除 - Expected Result: 所有操作成功,状态正确更新 - Evidence: .sisyphus/evidence/task-7-domain-crud.txt - ``` - - **Commit**: YES - - Message: `feat(store): implement domain store actions with IPC` - - Files: `src/renderer/src/stores/domainStore.ts` - ---- - -- [x] 8. DomainManager UI 组件 - - **What to do**: - - 创建 `src/renderer/src/components/DomainManager/DomainManager.tsx` - - 创建 `src/renderer/src/components/DomainManager/DomainList.tsx` - - 创建 `src/renderer/src/components/DomainManager/DomainItem.tsx` - - 使用 LobeHub UI + Ant Design 组件 - - 显示 Domain 列表和连接状态 - - **Must NOT do**: - - 不要包含业务逻辑(使用 store) - - 不要直接调用 IPC - - **Recommended Agent Profile**: - - **Category**: `visual-engineering` - - **Skills**: [] - - **Reason**: UI 组件开发,需要设计布局 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7, 9-10) - - **Blocks**: Tasks 10 (连接 Store) - - **Blocked By**: Task 7 (domain store) - - **References**: - - `AGENTS.md:UI 组件规范` - LobeHub UI + antd-style - - `src/renderer/src/App.tsx` - 现有组件示例 - - `package.json:27-30` - LobeHub UI + Ant Design - - **Acceptance Criteria**: - - [ ] DomainManager 组件包含 Domain 列表 - - [ ] DomainItem 显示名称、域名、连接状态 - - [ ] 使用 antd-style 样式 - - [ ] 支持暗黑模式 - - [ ] 响应式布局 - - **QA Scenarios**: - ``` - Scenario: DomainManager 渲染检查 - Tool: Playwright - Preconditions: 应用启动,有测试 Domain - Steps: - 1. 导航到 DomainManager 页面 - 2. 验证 Domain 列表渲染 - 3. 验证连接状态图标显示 - Expected Result: Domain 列表正确显示,样式正确 - Evidence: .sisyphus/evidence/task-8-domain-manager-render.png - ``` - - **Commit**: YES - - Message: `feat(ui): create DomainManager components` - - Files: `src/renderer/src/components/DomainManager/*.tsx` - ---- - -- [x] 9. Domain 表单 Dialog - - **What to do**: - - 创建 `src/renderer/src/components/DomainManager/DomainForm.tsx` - - 实现创建 Domain 表单 - - 实现编辑 Domain 表单 - - 使用 Ant Design Form + Modal - - 表单验证(必填字段、格式检查) - - **Must NOT do**: - - 不要包含业务逻辑(提交调用 store) - - 不要硬编码验证规则 - - **Recommended Agent Profile**: - - **Category**: `visual-engineering` - - **Skills**: [] - - **Reason**: 表单 UI 组件 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7-8, 10) - - **Blocks**: Tasks 10 (表单使用) - - **Blocked By**: Task 7 (domain store) - - **References**: - - `REQUIREMENTS.md:228-247` - Domain 创建/编辑需求 - - `AGENTS.md:UI 组件规范` - Ant Design 使用 - - **Acceptance Criteria**: - - [ ] DomainForm 组件支持创建和编辑模式 - - [ ] 必填字段验证(名称、域名、用户名、密码) - - [ ] 认证类型切换(密码/API Token) - - [ ] API Token 字段条件显示 - - [ ] 提交成功关闭 Dialog - - **QA Scenarios**: - ``` - Scenario: 创建 Domain 表单 - Tool: Playwright - Preconditions: 应用启动 - Steps: - 1. 点击"添加 Domain"按钮 - 2. 填写表单所有字段 - 3. 提交表单 - 4. 验证成功提示和 Dialog 关闭 - Expected Result: 表单提交成功,Domain 添加到列表 - Evidence: .sisyphus/evidence/task-9-domain-form-create.png - - Scenario: 表单验证 - Tool: Playwright - Preconditions: 打开创建 Domain Dialog - Steps: - 1. 不填写任何字段,点击提交 - 2. 验证错误提示显示 - Expected Result: 显示必填字段错误提示 - Evidence: .sisyphus/evidence/task-9-domain-form-validation.png - ``` - - **Commit**: YES - - Message: `feat(ui): create DomainForm dialog component` - - Files: `src/renderer/src/components/DomainManager/DomainForm.tsx` - ---- - -- [x] 10. Domain 列表连接 Store - - **What to do**: - - 更新 `DomainManager.tsx` - 连接 Domain Store - - 使用 useDomainStore 获取状态 - - 实现添加/编辑/删除按钮事件 - - 实现 Domain 切换功能 - - 实现连接状态检测 - - **Must NOT do**: - - 不要创建新的 store - - 不要直接调用 IPC - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Reason**: 连接现有 store 和组件 - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Sequential (after Tasks 7-9) - - **Blocks**: Tasks 11-26 (需要 Domain 切换) - - **Blocked By**: Tasks 7, 8, 9 - - **References**: - - `src/renderer/src/stores/domainStore.ts` - Domain Store - - `src/renderer/src/components/DomainManager/` - 现有组件 - - **Acceptance Criteria**: - - [ ] DomainManager 显示所有 Domain - - [ ] 点击 Domain 切换当前 Domain - - [ ] 添加按钮打开创建 Dialog - - [ ] 编辑按钮打开编辑 Dialog - - [ ] 删除按钮显示确认 Dialog - - **QA Scenarios**: - ``` - Scenario: Domain 切换 - Tool: Playwright - Preconditions: 有多个 Domain - Steps: - 1. 点击 Domain A - 2. 验证当前 Domain 状态更新 - 3. 验证连接状态检测触发 - Expected Result: Domain 切换成功,状态更新 - Evidence: .sisyphus/evidence/task-10-domain-switch.txt - ``` - - **Commit**: YES - - Message: `feat(ui): connect DomainManager to store` - - Files: `src/renderer/src/components/DomainManager/DomainManager.tsx` - ---- - -- [x] 11. SpaceTree 组件 - - **What to do**: - - 创建 `src/renderer/src/components/SpaceTree/SpaceTree.tsx` - - 创建 `src/renderer/src/components/SpaceTree/SpaceNode.tsx` - - 创建 `src/renderer/src/components/SpaceTree/AppNode.tsx` - - 使用 Ant Design Tree 组件 - - 显示 Space 分组和 App 列表 - - 支持搜索和过滤 - - **Must NOT do**: - - 不要包含业务逻辑(使用 appStore) - - 不要直接调用 IPC - - **Recommended Agent Profile**: - - **Category**: `visual-engineering` - - **Skills**: [] - - **Reason**: UI 树形组件开发 - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-14) - - **Blocks**: Tasks 13-14 (App 详情) - - **Blocked By**: Task 10 (Domain 切换) - - **References**: - - `REQUIREMENTS.md:296-330` - 资源浏览功能 - - `AGENTS.md:UI 组件规范` - Ant Design Tree - - **Acceptance Criteria**: - - [ ] SpaceTree 显示所有 Space - - [ ] 每个 Space 下显示 App 列表 - - [ ] 支持展开/折叠 Space - - [ ] 点击 App 节点触发选择事件 - - [ ] 支持按名称搜索 App - - **QA Scenarios**: - ``` - Scenario: SpaceTree 渲染 - Tool: Playwright - Preconditions: 已选择 Domain,有 Space 和 App - Steps: - 1. 导航到资源浏览页面 - 2. 验证 Space 列表渲染 - 3. 展开 Space,验证 App 列表显示 - Expected Result: Space 和 App 正确显示,树形结构完整 - Evidence: .sisyphus/evidence/task-11-spacetree-render.png - - Scenario: App 搜索 - Tool: Playwright - Preconditions: SpaceTree 已加载 - Steps: - 1. 在搜索框输入 App 名称关键词 - 2. 验证过滤后的 App 列表 - Expected Result: 只显示匹配的 App - Evidence: .sisyphus/evidence/task-11-spacetree-search.png - ``` - - **Commit**: YES - - Message: `feat(ui): create SpaceTree component for browsing resources` - - Files: `src/renderer/src/components/SpaceTree/*.tsx` - ---- - -- [ ] 12-26. [待补充 - 由于输出限制,任务 12-26 将在后续会话中补充] - - > **Note**: 受模型输出 token 限制,任务 12-26 的完整详情需要在执行过程中补充。 - > 关键任务包括: - > - Task 12: App 列表渲染 - > - Task 13: App 详情页布局 - > - Task 14: 代码查看器组件 - > - Task 15-19: 部署功能(FileUploader、位置选择、Diff 对比、确认 Dialog、部署执行) - > - Task 20-23: 版本管理(存储、UI、对比、回滚) - > - Task 24: App 页面集成 - > - Task 25: 端到端 Playwright QA - > - Task 26: Git 清理 + 标签 - - **执行策略**: 按照 Execution Strategy 中的 Wave 3-6 逐步执行,每个任务的详细规格参考 REQUIREMENTS.md 对应章节。 - ---- - -## Final Verification Wave - -> 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run. - -- [ ] F1. **Plan Compliance Audit** — `oracle` - Read the plan end-to-end. For each "Must Have": verify implementation exists (read file, curl endpoint, run command). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan. - Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT` - -- [ ] F2. **Code Quality Review** — `unspecified-high` - Run `tsc --noEmit` + linter + `bun test`. Review all changed files for: `as any`/`@ts-ignore`, empty catches, console.log in prod, commented-out code, unused imports. Check AI slop: excessive comments, over-abstraction, generic names (data/result/item/temp). - Output: `Build [PASS/FAIL] | Lint [PASS/FAIL] | Tests [N pass/N fail] | Files [N clean/N issues] | VERDICT` - -- [ ] F3. **Real Manual QA** — `unspecified-high` (+ `playwright` skill if UI) - Start from clean state. Execute EVERY QA scenario from EVERY task — follow exact steps, capture evidence. Test cross-task integration (features working together, not isolation). Test edge cases: empty state, invalid input, rapid actions. Save to `.sisyphus/evidence/final-qa/`. - Output: `Scenarios [N/N pass] | Integration [N/N] | Edge Cases [N tested] | VERDICT` - -- [ ] F4. **Scope Fidelity Check** — `deep` - For each task: read "What to do", read actual diff (git log/diff). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Detect cross-task contamination: Task N touching Task M's files. Flag unaccounted changes. - Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | Unaccounted [CLEAN/N files] | VERDICT` - ---- - -## Commit Strategy - -- **Wave 1**: `feat(core): foundation modules` — types, storage, kintone-api, ipc, preload, stores -- **Wave 2**: `feat(domain): domain management` — domain store, DomainManager UI, DomainForm -- **Wave 3**: `feat(browse): resource browsing` — SpaceTree, AppList, AppDetail, CodeViewer -- **Wave 4**: `feat(deploy): drag-and-drop deployment` — FileUploader, position selector, diff view, deploy dialog -- **Wave 5**: `feat(version): version management` — version history, diff comparison, rollback -- **Wave 6**: `feat(integration): app integration + QA` — full app page, Playwright tests - ---- - -## Success Criteria - -### Verification Commands -```bash -npx tsc --noEmit # Expected: no errors -npm run dev # Expected: dev server starts successfully -npm run build # Expected: production build completes -``` - -### Final Checklist -- [ ] 所有"Must Have"功能实现 -- [ ] 所有"Must NOT Have"功能未实现 -- [ ] 所有编译通过(tsc --noEmit) -- [ ] 所有 QA 场景证据文件存在 -- [ ] 应用可启动并运行 diff --git a/.sisyphus/plans/i18n-integration.md b/.sisyphus/plans/i18n-integration.md deleted file mode 100644 index 55e9e48..0000000 --- a/.sisyphus/plans/i18n-integration.md +++ /dev/null @@ -1,1135 +0,0 @@ -# i18n 国际化集成计划 - -## TL;DR - -> **Quick Summary**: 为 Electron + React 应用添加完整的国际化支持,使用 react-i18next + @lobehub/i18n-cli,支持中日英三语切换,包含渲染进程和主进程的全面国际化。 -> -> **Deliverables**: -> -> - 完整的 i18n 配置和语言文件结构 -> - 渲染进程所有组件的国际化 -> - 主进程 IPC 错误消息国际化 -> - 独立的设置页面(语言切换) -> - 用户语言偏好持久化 -> - Ant Design locale 同步切换 -> -> **Estimated Effort**: Medium -> **Parallel Execution**: YES - 5 waves -> **Critical Path**: Wave 1 → Wave 2 → Wave 3 → Wave 4 → Final Verification - ---- - -## Context - -### Original Request - -用户需要添加 i18n 对所有内容进行国际化,支持中日英三语,需要在设置里面加上切换组件。 - -### Interview Summary - -**Key Discussions**: - -- **翻译文件管理**: 静态导入(简单可靠,无需 IPC 文件访问) -- **自动化翻译**: 需要 @lobehub/i18n-cli(AI 自动生成翻译) -- **语言切换位置**: 创建独立设置页面 -- **支持语言**: 中文(zh-CN)、日文(ja-JP)、英文(en-US) -- **主进程国际化**: 需要(IPC 错误消息、日志等) -- **用户偏好持久化**: 需要持久化保存用户语言选择 -- **测试策略**: Agent QA - -**Research Findings**: - -- react-i18next 是成熟稳定的基础方案,社区庞大 -- LobeChat 方案本质上是 react-i18next + @lobehub/i18n-cli 自动化工具 -- 项目目前完全没有 i18n 实现,存在大量硬编码中文文本 -- 已有 Ant Design 国际化配置(固定为 zh-CN),需改为动态切换 -- 已有 Zustand stores 架构,可新增 localeStore - -### Self-Review Gaps - -**Identified Gaps** (addressed): - -- **命名空间划分**: 采用功能模块划分(common, domain, settings, errors) -- **语言检测策略**: 使用 i18next-browser-languagedetector + 持久化存储 -- **主进程同步机制**: 通过 IPC 通道同步语言状态 -- **AI 翻译质量**: 首次 AI 翻译后需要人工校验关键术语 - ---- - -## Work Objectives - -### Core Objective - -为 Kintone Customize Manager 添加完整的国际化支持,实现中日英三语切换,覆盖渲染进程 UI 和主进程错误消息。 - -### Concrete Deliverables - -- `src/renderer/src/locales/` - 语言文件目录(中日英三语) -- `src/renderer/src/stores/localeStore.ts` - 语言状态管理 -- `src/renderer/src/components/Settings/` - 设置页面组件 -- `src/renderer/src/i18n.ts` - i18n 配置文件 -- `src/shared/types/locale.ts` - 语言类型定义 -- 修改所有现有组件的硬编码文本为 `t()` 调用 -- 修改主进程 IPC 错误消息为国际化文本 - -### Definition of Done - -- [x] 用户可以在设置页面切换语言 -- [x] 切换后所有 UI 文本立即更新 -- [x] Ant Design 组件语言同步切换 -- [x] 主进程 IPC 错误消息正确显示当前语言 -- [x] 用户语言选择持久化保存 -- [x] 重启应用后语言设置保持 - -### Must Have - -- react-i18next + i18next 核心库 -- @lobehub/i18n-cli 自动化翻译 -- 中日英三语完整翻译 -- 语言切换 UI 组件 -- 用户偏好持久化 - -### Must NOT Have (Guardrails) - -- 不使用 i18next-electron-fs-backend(静态导入足够) -- 不支持 RTL 语言(中日英都是 LTR) -- 不引入远程翻译文件加载 -- 不在 MVP 阶段过度抽象翻译 key 结构 - ---- - -## Verification Strategy (MANDATORY) - -### Test Decision - -- **Infrastructure exists**: NO -- **Automated tests**: None -- **Framework**: N/A -- **Primary Verification**: Agent-Executed QA Scenarios - -### QA Policy - -Every task MUST include agent-executed QA scenarios. -Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. - -- **Frontend/UI**: Use Playwright — Navigate, interact, assert DOM, screenshot -- **Language Switch**: Verify UI text changes, Ant Design locale updates -- **Persistence**: Verify language preference saved and restored - ---- - -## Execution Strategy - -### Parallel Execution Waves - -``` -Wave 1 (Foundation - 6 tasks, MAX PARALLEL): -├── Task 1: 安装依赖 [quick] -├── Task 2: 创建类型定义 [quick] -├── Task 3: 创建语言文件目录结构 [quick] -├── Task 4: 创建 localeStore [quick] -├── Task 5: 配置 i18n 实例 [quick] -└── Task 6: 配置 @lobehub/i18n-cli [quick] - -Wave 2 (Core Integration - 4 tasks, depends on Wave 1): -├── Task 7: 渲染进程 i18n Provider 集成 [quick] -├── Task 8: Ant Design locale 同步 [quick] -├── Task 9: 主进程 IPC 语言同步 [unspecified-high] -└── Task 10: Preload 暴露语言 API [quick] - -Wave 3 (Component Migration - depends on Wave 2): -├── Task 11: App.tsx 国际化 [quick] -├── Task 12: DomainManager 国际化 [quick] -├── Task 13: 其他组件国际化 [unspecified-high] -└── Task 14: 主进程错误消息国际化 [unspecified-high] - -Wave 4 (Settings & Polish - depends on Wave 3): -├── Task 15: 创建设置页面组件 [visual-engineering] -├── Task 16: 语言切换 UI 实现 [visual-engineering] -└── Task 17: 用户偏好持久化 [quick] - -Wave FINAL (Verification - 4 parallel tasks): -├── Task F1: Plan compliance audit (oracle) -├── Task F2: Code quality review (unspecified-high) -├── Task F3: Real manual QA (unspecified-high) -└── Task F4: Scope fidelity check (deep) - -Critical Path: Wave 1 → Wave 2 → Wave 3 → Wave 4 → Final -Parallel Speedup: ~60% faster than sequential -Max Concurrent: 6 (Wave 1) -``` - -### Dependency Matrix - -| Task | Depends On | Blocks | -| ----- | ---------- | ------ | -| 1-6 | - | 7-10 | -| 7-10 | 1-6 | 11-14 | -| 11-14 | 7-10 | 15-17 | -| 15-17 | 11-14 | F1-F4 | -| F1-F4 | All | - | - -### Agent Dispatch Summary - -- **Wave 1**: 6 tasks → all `quick` -- **Wave 2**: 4 tasks → 3 `quick` + 1 `unspecified-high` -- **Wave 3**: 4 tasks → 2 `quick` + 2 `unspecified-high` -- **Wave 4**: 3 tasks → 2 `visual-engineering` + 1 `quick` -- **FINAL**: 4 tasks → oracle, unspecified-high, unspecified-high, deep - ---- - -## TODOs - -> Implementation + Test = ONE Task. Never separate. -> EVERY task MUST have: Recommended Agent Profile + Parallelization info + QA Scenarios. - -- [x] 1. 安装 i18n 相关依赖 - - **What to do**: - - 安装 `i18next` 和 `react-i18next` - - 安装 `i18next-browser-languagedetector` - - 安装 `@lobehub/i18n-cli` - - 验证安装成功 - - **Must NOT do**: - - 不要安装 `i18next-electron-fs-backend`(不需要) - - 不要安装 `i18next-http-backend`(静态导入) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 简单的 npm install 命令 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 2-6) - - **Blocks**: Tasks 7-10 - - **Blocked By**: None - - **References**: - - `package.json` - 添加依赖到项目 - - **Acceptance Criteria**: - - [x] `package.json` 包含 i18next, react-i18next, i18next-browser-languagedetector, @lobehub/i18n-cli - - [x] `npm ls i18next` 显示已安装 - - **QA Scenarios**: - - ``` - Scenario: 验证依赖安装成功 - Tool: Bash - Preconditions: package.json 已更新 - Steps: - 1. npm ls i18next react-i18next i18next-browser-languagedetector @lobehub/i18n-cli - 2. 检查所有依赖都显示版本号 - Expected Result: 所有 4 个依赖都显示已安装版本 - Failure Indicators: 任何依赖显示 "missing" 或 "UNMET" - Evidence: .sisyphus/evidence/task-01-deps-installed.txt - ``` - - **Commit**: NO - ---- - -- [x] 2. 创建语言类型定义 - - **What to do**: - - 创建 `src/shared/types/locale.ts` - - 定义 `LocaleCode` 类型('zh-CN' | 'ja-JP' | 'en-US') - - 定义 `LocaleConfig` 接口 - - 导出类型供其他模块使用 - - **Must NOT do**: - - 不要添加其他语言代码(只支持中日英) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 简单的类型定义文件 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1, 3-6) - - **Blocks**: Tasks 4, 7-10 - - **Blocked By**: None - - **References**: - - `src/shared/types/` - 参考现有类型定义风格 - - **Acceptance Criteria**: - - [x] 文件 `src/shared/types/locale.ts` 存在 - - [x] 导出 `LocaleCode` 和 `LocaleConfig` 类型 - - [x] TypeScript 编译通过 - - **QA Scenarios**: - - ``` - Scenario: 验证类型定义正确 - Tool: Bash - Preconditions: 文件已创建 - Steps: - 1. npx tsc --noEmit - 2. 检查无类型错误 - Expected Result: 编译成功,无错误 - Failure Indicators: TypeScript 报类型错误 - Evidence: .sisyphus/evidence/task-02-types-compiled.txt - ``` - - **Commit**: NO - ---- - -- [x] 3. 创建语言文件目录结构 - - **What to do**: - - 创建 `src/renderer/src/locales/` 目录 - - 创建 `default/` 子目录存放源语言文件(中文) - - 创建 `zh-CN/`, `ja-JP/`, `en-US/` 三个语言目录 - - 创建命名空间文件:`common.json`, `domain.json`, `settings.json`, `errors.json` - - 为每个命名空间添加初始翻译内容 - - **Must NOT do**: - - 不要创建空的 JSON 文件(要有初始内容) - - 不要使用嵌套对象结构(使用扁平 key) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 创建目录和文件结构 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-2, 4-6) - - **Blocks**: Tasks 5, 7 - - **Blocked By**: None - - **References**: - - LobeHub i18n 文档: https://lobehub.com/docs/development/internationalization/internationalization-implementation - - **Acceptance Criteria**: - - [x] 目录结构符合 LobeChat 规范 - - [x] 每个语言目录包含 4 个命名空间 JSON 文件 - - [x] 每个文件包含至少 5 个翻译 key - - **QA Scenarios**: - - ``` - Scenario: 验证目录结构完整 - Tool: Bash - Preconditions: 目录已创建 - Steps: - 1. ls -R src/renderer/src/locales/ - 2. 检查所有目录和文件存在 - Expected Result: 显示完整目录树,包含 default/, zh-CN/, ja-JP/, en-US/ 和 4 个 JSON 文件 - Failure Indicators: 任何目录或文件缺失 - Evidence: .sisyphus/evidence/task-03-locale-structure.txt - ``` - - **Commit**: NO - ---- - -- [x] 4. 创建 localeStore - - **What to do**: - - 创建 `src/renderer/src/stores/localeStore.ts` - - 定义语言状态:`locale: LocaleCode` - - 定义切换语言方法:`setLocale(locale: LocaleCode)` - - 集成 persist middleware 持久化语言偏好 - - 导出 `useLocaleStore` hook - - **Must NOT do**: - - 不要在 store 中存储翻译内容(由 i18next 管理) - - 不要忘记 persist 配置 - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 简单的 Zustand store - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-3, 5-6) - - **Blocks**: Tasks 7, 15-17 - - **Blocked By**: Task 2(类型定义) - - **References**: - - `src/renderer/src/stores/domainStore.ts` - 参考 store 结构 - - **Acceptance Criteria**: - - [x] 文件 `src/renderer/src/stores/localeStore.ts` 存在 - - [x] 导出 `useLocaleStore` hook - - [x] 包含 persist 配置 - - [x] TypeScript 编译通过 - - **QA Scenarios**: - - ``` - Scenario: 验证 store 功能正确 - Tool: Bash - Preconditions: store 已创建 - Steps: - 1. npx tsc --noEmit - 2. 检查无类型错误 - Expected Result: 编译成功 - Failure Indicators: TypeScript 报错 - Evidence: .sisyphus/evidence/task-04-store-compiled.txt - ``` - - **Commit**: NO - ---- - -- [x] 5. 配置 i18n 实例 - - **What to do**: - - 创建 `src/renderer/src/i18n.ts` - - 配置 i18next 初始化 - - 配置静态资源导入(从 locales 目录) - - 配置语言检测器(localStorage + navigator) - - 配置默认语言和回退语言 - - 配置命名空间 - - **Must NOT do**: - - 不要使用 HTTP backend(静态导入) - - 不要忘记设置 `escapeValue: false`(React 已处理) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 标准的 i18next 配置 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-4, 6) - - **Blocks**: Tasks 7, 8 - - **Blocked By**: Task 3(语言文件) - - **References**: - - react-i18next 文档: https://react.i18next.com - - **Acceptance Criteria**: - - [x] 文件 `src/renderer/src/i18n.ts` 存在 - - [x] i18n 实例正确初始化 - - [x] TypeScript 编译通过 - - **QA Scenarios**: - - ``` - Scenario: 验证 i18n 配置正确 - Tool: Bash - Preconditions: i18n.ts 已创建 - Steps: - 1. npx tsc --noEmit - 2. 检查无类型错误 - Expected Result: 编译成功 - Failure Indicators: TypeScript 报错 - Evidence: .sisyphus/evidence/task-05-i18n-config.txt - ``` - - **Commit**: NO - ---- - -- [x] 6. 配置 @lobehub/i18n-cli - - **What to do**: - - 创建 `.i18nrc.js` 配置文件 - - 配置源语言目录(default/) - - 配置输出语言目录(zh-CN/, ja-JP/, en-US/) - - 配置 AI 翻译服务 - - 添加 npm script `i18n` 用于生成翻译 - - **Must NOT do**: - - 不要提交 API key 到 git - - 不要在 CI 中运行 AI 翻译(成本考虑) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 配置文件创建 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 1-5) - - **Blocks**: None(可选工具) - - **Blocked By**: Task 1(依赖安装) - - **References**: - - @lobehub/i18n-cli 文档: https://www.npmjs.com/package/@lobehub/i18n-cli - - **Acceptance Criteria**: - - [x] 文件 `.i18nrc.js` 存在 - - [x] package.json 包含 `i18n` script - - [x] 配置文件格式正确 - - **QA Scenarios**: - - ``` - Scenario: 验证 i18n-cli 配置正确 - Tool: Bash - Preconditions: 配置文件已创建 - Steps: - 1. npm run i18n -- --help - 2. 检查命令可用 - Expected Result: 显示 i18n-cli 帮助信息 - Failure Indicators: 命令不存在或报错 - Evidence: .sisyphus/evidence/task-06-i18n-cli.txt - ``` - - **Commit**: NO - ---- - -- [x] 7. 渲染进程 i18n Provider 集成 - - **What to do**: - - 在 `main.tsx` 中导入 i18n 实例 - - 使用 `I18nextProvider` 包裹 App - - 或使用 `initReactI18next` 自动绑定 - - 验证 i18n 在 React 组件中可用 - - **Must NOT do**: - - 不要重复初始化 i18n - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 标准 React 集成 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 8-10) - - **Blocks**: Tasks 11-14 - - **Blocked By**: Wave 1 - - **References**: - - `src/renderer/src/main.tsx` - React 入口文件 - - `src/renderer/src/i18n.ts` - i18n 配置 - - **Acceptance Criteria**: - - [x] `useTranslation` hook 可用 - - [x] 应用启动无错误 - - [x] `t()` 函数返回正确翻译 - - **QA Scenarios**: - - ``` - Scenario: 验证 i18n Provider 集成成功 - Tool: Playwright - Preconditions: 应用已启动 - Steps: - 1. 启动应用 npm run dev - 2. 打开浏览器访问应用 - 3. 检查页面正常渲染 - Expected Result: 应用正常启动,无控制台错误 - Failure Indicators: 控制台有 i18n 相关错误 - Evidence: .sisyphus/evidence/task-07-provider-integrated.png - ``` - - **Commit**: NO - ---- - -- [x] 8. Ant Design locale 同步 - - **What to do**: - - 创建 locale 映射函数,将 i18next locale 转换为 Ant Design locale - - 在 App.tsx 中使用 `ConfigProvider` 的 locale 属性 - - 监听 i18n 语言变化,同步更新 Ant Design locale - - 导入 Ant Design 的 zhCN, jaJP, enUS locale - - **Must NOT do**: - - 不要硬编码 locale(动态获取) - - 不要忘记处理语言变化事件 - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Ant Design 配置更新 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7, 9-10) - - **Blocks**: Task 16 - - **Blocked By**: Wave 1, Task 4 - - **References**: - - `src/renderer/src/App.tsx` - 已有 ConfigProvider - - Ant Design 国际化文档: https://ant.design/docs/react/i18n - - **Acceptance Criteria**: - - [x] Ant Design 组件语言跟随 i18n 变化 - - [x] DatePicker, Pagination 等组件显示正确语言 - - [x] 切换语言后 Ant Design locale 立即更新 - - **QA Scenarios**: - - ``` - Scenario: 验证 Ant Design locale 同步 - Tool: Playwright - Preconditions: 应用已启动,i18n 已配置 - Steps: - 1. 打开设置页面 - 2. 切换语言到 English - 3. 检查 Ant Design 组件(如 DatePicker)显示英文 - 4. 切换语言到日本語 - 5. 检查组件显示日文 - Expected Result: Ant Design 组件语言随切换变化 - Failure Indicators: 组件仍显示中文 - Evidence: .sisyphus/evidence/task-08-antd-locale.png - ``` - - **Commit**: NO - ---- - -- [x] 9. 主进程 IPC 语言同步 - - **What to do**: - - 在主进程创建 IPC 处理器 `get-locale` 和 `set-locale` - - 存储当前语言设置(可与渲染进程 localStorage 同步) - - 主进程加载对应的错误消息翻译 - - IPC 错误响应使用当前语言 - - **Must NOT do**: - - 不要在主进程使用 i18next(用简单的消息映射) - - 不要忘记同步主进程和渲染进程的语言状态 - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: 涉及 IPC 通信和主进程逻辑 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7-8, 10) - - **Blocks**: Task 14 - - **Blocked By**: Wave 1 - - **References**: - - `src/main/ipc-handlers.ts` - IPC 处理器 - - `src/main/storage.ts` - 存储逻辑 - - **Acceptance Criteria**: - - [x] IPC 通道 `get-locale` 返回当前语言 - - [x] IPC 通道 `set-locale` 更新语言设置 - - [x] 主进程错误消息根据语言显示 - - **QA Scenarios**: - - ``` - Scenario: 验证主进程语言同步 - Tool: Bash - Preconditions: IPC 已实现 - Steps: - 1. 启动应用 - 2. 触发一个 IPC 错误(如无效 domain) - 3. 检查错误消息语言 - 4. 切换语言 - 5. 再次触发错误 - 6. 检查错误消息语言变化 - Expected Result: 错误消息语言跟随设置变化 - Failure Indicators: 错误消息始终是同一语言 - Evidence: .sisyphus/evidence/task-09-ipc-locale.txt - ``` - - **Commit**: NO - ---- - -- [x] 10. Preload 暴露语言 API - - **What to do**: - - 在 `preload/index.ts` 中暴露 `getLocale` 和 `setLocale` API - - 添加类型声明到 `preload/index.d.ts` - - 确保类型安全 - - **Must NOT do**: - - 不要暴露不必要的 IPC 通道 - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 简单的 preload 扩展 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7-9) - - **Blocks**: Task 14 - - **Blocked By**: Task 9 - - **References**: - - `src/preload/index.ts` - 现有 preload API - - `src/preload/index.d.ts` - 类型声明 - - **Acceptance Criteria**: - - [x] `window.api.getLocale()` 可用 - - [x] `window.api.setLocale(locale)` 可用 - - [x] TypeScript 类型正确 - - **QA Scenarios**: - - ``` - Scenario: 验证 preload API 可用 - Tool: Playwright - Preconditions: preload 已更新 - Steps: - 1. 打开开发者工具 - 2. 执行 window.api.getLocale() - 3. 检查返回当前语言 - Expected Result: 返回 'zh-CN' 或其他语言代码 - Failure Indicators: API 不存在或报错 - Evidence: .sisyphus/evidence/task-10-preload-api.png - ``` - - **Commit**: NO - ---- - -- [x] 11. App.tsx 国际化 - - **What to do**: - - 提取所有硬编码中文文本到翻译文件 - - 使用 `useTranslation` hook 获取 `t` 函数 - - 替换硬编码文本为 `t('key')` 调用 - - 更新 `default/common.ts` 添加翻译 key - - **Must NOT do**: - - 不要遗漏任何硬编码文本 - - 不要使用不存在的 key - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 文本替换工作 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-14) - - **Blocks**: Task 15 - - **Blocked By**: Wave 2 - - **References**: - - `src/renderer/src/App.tsx` - 当前组件 - - `src/renderer/src/locales/default/common.ts` - 翻译文件 - - **Acceptance Criteria**: - - [x] App.tsx 无硬编码中文文本 - - [x] 所有文本通过 `t()` 获取 - - [x] 语言切换后文本更新 - - **QA Scenarios**: - - ``` - Scenario: 验证 App.tsx 国际化 - Tool: Playwright - Preconditions: 组件已国际化 - Steps: - 1. 启动应用 - 2. 检查顶部导航文本 - 3. 切换语言到 English - 4. 检查文本变为英文 - 5. 切换语言到日本語 - 6. 检查文本变为日文 - Expected Result: 所有文本随语言切换变化 - Failure Indicators: 部分文本仍是中文 - Evidence: .sisyphus/evidence/task-11-app-i18n.png - ``` - - **Commit**: NO - ---- - -- [x] 12. DomainManager 国际化 - - **What to do**: - - 提取 DomainManager 组件所有硬编码文本 - - 添加 `domain` 命名空间翻译 key - - 使用 `useTranslation('domain')` 获取专用翻译 - - 替换所有硬编码文本 - - **Must NOT do**: - - 不要混用命名空间(domain 相关用 domain 命名空间) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: 文本替换工作 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 11, 13-14) - - **Blocks**: Task 15 - - **Blocked By**: Wave 2 - - **References**: - - `src/renderer/src/components/DomainManager/DomainManager.tsx` - - `src/renderer/src/locales/default/domain.ts` - - **Acceptance Criteria**: - - [x] DomainManager 无硬编码文本 - - [x] 所有文本通过 `t()` 获取 - - [x] 错误消息也已国际化 - - **QA Scenarios**: - - ``` - Scenario: 验证 DomainManager 国际化 - Tool: Playwright - Preconditions: 组件已国际化 - Steps: - 1. 打开 Domain 管理页面 - 2. 检查所有按钮和标签文本 - 3. 切换语言 - 4. 检查文本变化 - 5. 触发错误(如添加无效 domain) - 6. 检查错误消息语言 - Expected Result: 所有文本和错误消息随语言变化 - Failure Indicators: 部分文本仍是硬编码 - Evidence: .sisyphus/evidence/task-12-domain-i18n.png - ``` - - **Commit**: NO - ---- - -- [x] 13. 其他组件国际化 - - **What to do**: - - 扫描 `src/renderer/src/components/` 所有组件 - - 提取所有硬编码文本到对应命名空间 - - 批量替换为 `t()` 调用 - - 确保无遗漏 - - **Must NOT do**: - - 不要遗漏任何组件 - - 不要重复定义相同的 key - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: 涉及多个组件,需要仔细检查 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 11-12, 14) - - **Blocks**: Task 15 - - **Blocked By**: Wave 2 - - **References**: - - `src/renderer/src/components/` - 所有组件 - - **Acceptance Criteria**: - - [x] 所有组件无硬编码文本 - - [x] TypeScript 编译通过 - - [x] 语言切换功能正常 - - **QA Scenarios**: - - ``` - Scenario: 验证所有组件国际化 - Tool: Playwright - Preconditions: 所有组件已国际化 - Steps: - 1. 遍历应用所有页面 - 2. 检查每个页面的文本 - 3. 切换语言 - 4. 检查所有页面文本变化 - Expected Result: 所有页面文本随语言变化 - Failure Indicators: 发现硬编码文本 - Evidence: .sisyphus/evidence/task-13-all-components.png - ``` - - **Commit**: NO - ---- - -- [x] 14. 主进程错误消息国际化 - - **What to do**: - - 创建主进程错误消息映射表 - - 在 `ipc-handlers.ts` 中使用映射表 - - 在 `kintone-api.ts` 中使用映射表 - - 确保错误消息根据语言返回 - - **Must NOT do**: - - 不要在主进程使用 react-i18next - - 不要硬编码错误消息 - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: 涉及主进程逻辑修改 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 11-13) - - **Blocks**: Final Verification - - **Blocked By**: Task 9, 10 - - **References**: - - `src/main/ipc-handlers.ts` - - `src/main/kintone-api.ts` - - `src/main/storage.ts` - - **Acceptance Criteria**: - - [x] 主进程错误消息根据语言返回 - - [x] IPC 错误响应使用正确语言 - - [x] 无硬编码错误消息 - - **QA Scenarios**: - - ``` - Scenario: 验证主进程错误消息国际化 - Tool: Bash + Playwright - Preconditions: 主进程已国际化 - Steps: - 1. 启动应用 - 2. 设置语言为 English - 3. 触发错误(如无效 API token) - 4. 检查错误消息为英文 - 5. 设置语言为日本語 - 6. 再次触发错误 - 7. 检查错误消息为日文 - Expected Result: 错误消息语言正确 - Failure Indicators: 错误消息语言不正确 - Evidence: .sisyphus/evidence/task-14-main-errors.txt - ``` - - **Commit**: NO - ---- - -- [x] 15. 创建设置页面组件 - - **What to do**: - - 创建 `src/renderer/src/components/Settings/` 目录 - - 创建 `Settings.tsx` 主组件 - - 使用 Ant Design 组件构建 UI - - 包含语言切换区域 - - 添加到应用路由或状态管理 - - **Must NOT do**: - - 不要过度设计(MVP 阶段) - - 不要包含不必要的设置项 - - **Recommended Agent Profile**: - - **Category**: `visual-engineering` - - Reason: UI 组件开发 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 16-17) - - **Blocks**: Final Verification - - **Blocked By**: Wave 3 - - **References**: - - `src/renderer/src/components/DomainManager/` - 参考组件结构 - - Ant Design 组件库 - - **Acceptance Criteria**: - - [x] 设置页面可通过菜单访问 - - [x] UI 布局清晰美观 - - [x] 响应式设计 - - **QA Scenarios**: - - ``` - Scenario: 验证设置页面可访问 - Tool: Playwright - Preconditions: 设置页面已创建 - Steps: - 1. 启动应用 - 2. 点击设置菜单 - 3. 检查设置页面显示 - 4. 截图 - Expected Result: 设置页面正常显示 - Failure Indicators: 页面空白或报错 - Evidence: .sisyphus/evidence/task-15-settings-page.png - ``` - - **Commit**: NO - ---- - -- [x] 16. 语言切换 UI 实现 - - **What to do**: - - 在设置页面添加语言切换组件 - - 使用 Radio 或 Select 组件 - - 显示三个选项:中文、日本語、English - - 切换后立即更新 UI - - 同步更新 i18n 和 localeStore - - **Must NOT do**: - - 不要忘记同步 Ant Design locale - - 不要忘记持久化用户选择 - - **Recommended Agent Profile**: - - **Category**: `visual-engineering` - - Reason: UI 交互组件 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 15, 17) - - **Blocks**: Final Verification - - **Blocked By**: Task 15 - - **References**: - - `src/renderer/src/stores/localeStore.ts` - - `src/renderer/src/i18n.ts` - - **Acceptance Criteria**: - - [x] 语言切换 UI 显示正确 - - [x] 切换后 UI 立即更新 - - [x] Ant Design 组件语言同步 - - [x] 选择已持久化 - - **QA Scenarios**: - - ``` - Scenario: 验证语言切换功能 - Tool: Playwright - Preconditions: 语言切换 UI 已实现 - Steps: - 1. 打开设置页面 - 2. 当前语言是中文 - 3. 点击 English 选项 - 4. 检查所有 UI 文本变为英文 - 5. 检查 Ant Design 组件(如日期选择器)变为英文 - 6. 刷新页面 - 7. 检查语言仍为英文 - Expected Result: 语言切换立即生效,刷新后保持 - Failure Indicators: 切换后部分文本未更新,或刷新后重置 - Evidence: .sisyphus/evidence/task-16-lang-switch.png - ``` - - **Commit**: NO - ---- - -- [x] 17. 用户偏好持久化 - - **What to do**: - - 确保 localeStore 使用 persist middleware - - 验证 localStorage 正确存储语言偏好 - - 应用启动时恢复用户语言选择 - - 主进程也读取持久化的语言设置 - - **Must NOT do**: - - 不要忘记处理首次启动(无持久化数据) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Zustand persist 配置 - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 15-16) - - **Blocks**: Final Verification - - **Blocked By**: Task 4 - - **References**: - - `src/renderer/src/stores/localeStore.ts` - - **Acceptance Criteria**: - - [x] 语言选择保存到 localStorage - - [x] 重启应用后语言设置保持 - - [x] 首次启动使用系统语言 - - **QA Scenarios**: - - ``` - Scenario: 验证语言偏好持久化 - Tool: Playwright - Preconditions: 持久化已实现 - Steps: - 1. 打开应用 - 2. 切换语言到日本語 - 3. 关闭应用 - 4. 重新打开应用 - 5. 检查语言仍为日本語 - 6. 检查 localStorage 中有语言设置 - Expected Result: 重启后语言设置保持 - Failure Indicators: 重启后语言重置为默认 - Evidence: .sisyphus/evidence/task-17-persistence.png - ``` - - **Commit**: NO - ---- - -## Final Verification Wave (MANDATORY) - -- [x] F1. **Plan Compliance Audit** — `oracle` - Read the plan end-to-end. For each "Must Have": verify implementation exists. For each "Must NOT Have": search codebase for forbidden patterns. Check evidence files exist. - Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT` - -- [x] F2. **Code Quality Review** — `unspecified-high` - Run `npx tsc --noEmit` + linter. Review all changed files for: `as any`/`@ts-ignore`, empty catches, unused imports. Check AI slop patterns. - Output: `Build [PASS/FAIL] | Lint [PASS/FAIL] | Files [N clean/N issues] | VERDICT` - -- [x] F3. **Real Manual QA** — `unspecified-high` (+ `playwright` skill) - Start from clean state. Execute EVERY QA scenario from EVERY task. Test language switching across all pages. Test persistence. Save evidence. - Output: `Scenarios [N/N pass] | VERDICT` - -- [x] F4. **Scope Fidelity Check** — `deep` - Verify 1:1 — everything in spec was built, nothing beyond spec was built. Check "Must NOT do" compliance. - Output: `Tasks [N/N compliant] | VERDICT` - ---- - -## Commit Strategy - -- **Commit 1**: `feat(i18n): add i18n infrastructure and dependencies` - - Files: package.json, src/shared/types/locale.ts, src/renderer/src/locales/, src/renderer/src/stores/localeStore.ts, src/renderer/src/i18n.ts, .i18nrc.js - - Pre-commit: `npx tsc --noEmit` - -- **Commit 2**: `feat(i18n): integrate i18n into renderer and main process` - - Files: src/renderer/src/main.tsx, src/renderer/src/App.tsx, src/preload/index.ts, src/preload/index.d.ts, src/main/ipc-handlers.ts, src/main/kintone-api.ts - - Pre-commit: `npx tsc --noEmit` - -- **Commit 3**: `feat(i18n): internationalize all components` - - Files: src/renderer/src/components/**/\*.tsx, src/renderer/src/locales/**/\*.ts - - Pre-commit: `npx tsc --noEmit` - -- **Commit 4**: `feat(i18n): add settings page with language switcher` - - Files: src/renderer/src/components/Settings/ - - Pre-commit: `npx tsc --noEmit` - ---- - -## Success Criteria - -### Verification Commands - -```bash -# 检查依赖安装 -npm ls i18next react-i18next i18next-browser-languagedetector @lobehub/i18n-cli - -# 类型检查 -npx tsc --noEmit - -# 运行应用 -npm run dev - -# 生成翻译(可选) -npm run i18n -``` - -### Final Checklist - -- [x] All "Must Have" present -- [x] All "Must NOT Have" absent -- [x] All TypeScript compiles without errors -- [x] Language switcher works correctly -- [x] All UI text updates on language change -- [x] Ant Design components use correct locale -- [x] Main process errors show correct language -- [x] User preference persists across restarts -- [x] @lobehub/i18n-cli configured and usable