Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 33 additions & 24 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2.4.0] - 2025-09-30

### 🎉 Major Changes

- **Full React Migration**: Migrated popup and options pages to React
- Modern component-based architecture
- Improved maintainability and code organization
- Better state management with React hooks
- 100% functional parity with vanilla JavaScript version
- Identical UI/UX experience
- Modern component-based architecture
- Improved maintainability and code organization
- Better state management with React hooks
- 100% functional parity with vanilla JavaScript version
- Identical UI/UX experience

### ✨ Added

- React-based popup interface with custom hooks:
- `useSettings` for settings management
- `useTranslation` for i18n support
- `useLogger` for error tracking
- `useChromeMessage` for Chrome API integration
- `useSettings` for settings management
- `useTranslation` for i18n support
- `useLogger` for error tracking
- `useChromeMessage` for Chrome API integration
- React-based options page with modular sections:
- `GeneralSection` for general preferences
- `TranslationSection` for translation settings and batch configuration
- `ProvidersSection` for provider management
- `AIContextSection` for AI context configuration
- `AboutSection` for extension information
- `GeneralSection` for general preferences
- `TranslationSection` for translation settings and batch configuration
- `ProvidersSection` for provider management
- `AIContextSection` for AI context configuration
- `AboutSection` for extension information
- Reusable React components:
- `SettingCard`, `ToggleSwitch`, `SettingToggle`
- `LanguageSelector`, `SliderSetting`, `StatusMessage`
- `TestResultDisplay`, `SparkleButton`
- Provider cards for all translation services
- `SettingCard`, `ToggleSwitch`, `SettingToggle`
- `LanguageSelector`, `SliderSetting`, `StatusMessage`
- `TestResultDisplay`, `SparkleButton`
- Provider cards for all translation services
- Custom hooks for advanced features:
- `useDeepLTest` for DeepL API testing
- `useOpenAITest` for OpenAI API testing and model fetching
- `useBackgroundReady` for service worker status
- `useDeepLTest` for DeepL API testing
- `useOpenAITest` for OpenAI API testing and model fetching
- `useBackgroundReady` for service worker status
- Vite build system for optimized production bundles

### 🔧 Changed

- Build system upgraded from vanilla JavaScript to Vite + React
- Popup and options pages now use React components
- All UI interactions now use React state management
- Settings updates use React hooks instead of direct DOM manipulation
- Translation loading uses React effects and state

### 🗑️ Removed

- Vanilla JavaScript popup.js and options.js files
- Old HTML templates (replaced by React JSX)
- Manual DOM manipulation code
- jQuery-style event listeners

### 📦 Dependencies

- Added `react` ^19.1.1
- Added `react-dom` ^19.1.1
- Added `vite` ^7.1.7
- Added `@vitejs/plugin-react` ^5.0.4

### 🐛 Fixed

- Container width consistency in options page across different tabs
- AI Context section structure now matches original layout exactly
- All i18n translation keys corrected to match message definitions
- Proper collapsible Advanced Settings in AI Context section

### 📝 Documentation

- Added comprehensive React migration documentation
- Updated README with React-based development information
- Added component architecture documentation
- Updated build and development instructions

### 🔬 Technical Details

- Bundle sizes (gzipped):
- Popup: 13.47 kB (4.58 kB gzipped)
- Options: 35.24 kB (8.41 kB gzipped)
- Shared translations: 218.89 kB (66.52 kB gzipped)
- Popup: 13.47 kB (4.58 kB gzipped)
- Options: 35.24 kB (8.41 kB gzipped)
- Shared translations: 218.89 kB (66.52 kB gzipped)
- Build time: ~600ms
- Total React components: 25+
- Custom hooks: 7
- Zero functional differences from vanilla JS version

## [2.3.2] - Previous Version

- All previous features and functionality
- Vanilla JavaScript implementation

Expand Down
2 changes: 1 addition & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
```bash
# 生产构建
npm run build

# 开发模式(自动重新构建)
npm run dev
```
Expand Down
40 changes: 30 additions & 10 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,19 @@
"cardOpenAICompatibleDesc": {
"message": "Enter your API key and settings for OpenAI-compatible services like Gemini."
},
"cardVertexGeminiTitle": { "message": "Vertex AI Gemini (API Key Required)" },
"cardVertexGeminiDesc": { "message": "Enter your access token and Vertex project settings." },
"cardVertexGeminiTitle": {
"message": "Vertex AI Gemini (API Key Required)"
},
"cardVertexGeminiDesc": {
"message": "Enter your access token and Vertex project settings."
},
"vertexAccessTokenLabel": { "message": "Access Token:" },
"vertexProjectIdLabel": { "message": "Project ID:" },
"vertexLocationLabel": { "message": "Location:" },
"vertexModelLabel": { "message": "Model:" },
"vertexMissingConfig": { "message": "Please enter access token and project ID." },
"vertexMissingConfig": {
"message": "Please enter access token and project ID."
},
"vertexConnectionFailed": { "message": "Connection failed: %s" },
"vertexServiceAccountLabel": { "message": "Service Account JSON:" },
"vertexImportButton": { "message": "Import JSON File" },
Expand All @@ -207,19 +213,33 @@
"vertexImporting": { "message": "Importing..." },
"vertexRefreshingToken": { "message": "Refreshing access token..." },
"vertexGeneratingToken": { "message": "Generating access token..." },
"vertexImportSuccess": { "message": "Service account imported and token generated." },
"vertexImportSuccess": {
"message": "Service account imported and token generated."
},
"vertexImportFailed": { "message": "Import failed: %s" },
"vertexTokenRefreshed": { "message": "Access token refreshed successfully." },
"vertexTokenRefreshed": {
"message": "Access token refreshed successfully."
},
"vertexRefreshFailed": { "message": "Token refresh failed: %s" },
"vertexTokenExpired": { "message": "⚠️ Access token expired. Click refresh to renew." },
"vertexTokenExpiringSoon": { "message": "⚠️ Token expires in %s minutes. Consider refreshing." },
"vertexConfigured": { "message": "⚠️ Vertex AI configured. Please test connection." },
"vertexNotConfigured": { "message": "Please import service account JSON or enter credentials." },
"vertexTokenExpired": {
"message": "⚠️ Access token expired. Click refresh to renew."
},
"vertexTokenExpiringSoon": {
"message": "⚠️ Token expires in %s minutes. Consider refreshing."
},
"vertexConfigured": {
"message": "⚠️ Vertex AI configured. Please test connection."
},
"vertexNotConfigured": {
"message": "Please import service account JSON or enter credentials."
},
"featureVertexServiceAccount": { "message": "Service account JSON import" },
"featureVertexAutoToken": { "message": "Automatic token generation" },
"featureVertexGemini": { "message": "Google Gemini models via Vertex AI" },
"providerNote": { "message": "Note:" },
"vertexNote": { "message": "Access tokens expire after 1 hour. Your service account is securely stored for easy token refresh - just click the Refresh Token button when needed." },
"vertexNote": {
"message": "Access tokens expire after 1 hour. Your service account is securely stored for easy token refresh - just click the Refresh Token button when needed."
},
"baseUrlLabel": { "message": "Base URL:" },
"modelLabel": { "message": "Model:" },
"featureCustomizable": { "message": "Customizable endpoint and model" },
Expand Down
52 changes: 39 additions & 13 deletions _locales/es/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,33 +207,59 @@
"cardOpenAICompatibleDesc": {
"message": "Ingresa tu clave API y configuraciones para servicios compatibles con OpenAI como Gemini."
},
"cardVertexGeminiTitle": { "message": "Vertex AI Gemini (Requiere Clave API)" },
"cardVertexGeminiDesc": { "message": "Ingresa tu token de acceso y configuraciones del proyecto Vertex, o importa un archivo JSON de cuenta de servicio." },
"cardVertexGeminiTitle": {
"message": "Vertex AI Gemini (Requiere Clave API)"
},
"cardVertexGeminiDesc": {
"message": "Ingresa tu token de acceso y configuraciones del proyecto Vertex, o importa un archivo JSON de cuenta de servicio."
},
"vertexAccessTokenLabel": { "message": "Token de Acceso:" },
"vertexProjectIdLabel": { "message": "ID del Proyecto:" },
"vertexLocationLabel": { "message": "Ubicación:" },
"vertexModelLabel": { "message": "Modelo:" },
"vertexMissingConfig": { "message": "Por favor ingresa el token de acceso y el ID del proyecto." },
"vertexMissingConfig": {
"message": "Por favor ingresa el token de acceso y el ID del proyecto."
},
"vertexConnectionFailed": { "message": "Conexión fallida: %s" },
"vertexServiceAccountLabel": { "message": "JSON de Cuenta de Servicio:" },
"vertexImportButton": { "message": "Importar Archivo JSON" },
"vertexRefreshButton": { "message": "🔄 Actualizar Token" },
"vertexImportHint": { "message": "Rellena automáticamente las credenciales a continuación" },
"vertexImportHint": {
"message": "Rellena automáticamente las credenciales a continuación"
},
"vertexImporting": { "message": "Importando..." },
"vertexRefreshingToken": { "message": "Actualizando token de acceso..." },
"vertexGeneratingToken": { "message": "Generando token de acceso..." },
"vertexImportSuccess": { "message": "Cuenta de servicio importada y token generado." },
"vertexImportSuccess": {
"message": "Cuenta de servicio importada y token generado."
},
"vertexImportFailed": { "message": "Importación fallida: %s" },
"vertexTokenRefreshed": { "message": "Token de acceso actualizado exitosamente." },
"vertexTokenRefreshed": {
"message": "Token de acceso actualizado exitosamente."
},
"vertexRefreshFailed": { "message": "Actualización de token fallida: %s" },
"vertexTokenExpired": { "message": "⚠️ Token de acceso expirado. Haz clic en actualizar para renovar." },
"vertexTokenExpiringSoon": { "message": "⚠️ El token expira en %s minutos. Considera actualizarlo." },
"vertexConfigured": { "message": "⚠️ Vertex AI configurado. Por favor prueba la conexión." },
"vertexNotConfigured": { "message": "Por favor importa el JSON de cuenta de servicio o ingresa las credenciales." },
"featureVertexServiceAccount": { "message": "Importación de JSON de cuenta de servicio" },
"vertexTokenExpired": {
"message": "⚠️ Token de acceso expirado. Haz clic en actualizar para renovar."
},
"vertexTokenExpiringSoon": {
"message": "⚠️ El token expira en %s minutos. Considera actualizarlo."
},
"vertexConfigured": {
"message": "⚠️ Vertex AI configurado. Por favor prueba la conexión."
},
"vertexNotConfigured": {
"message": "Por favor importa el JSON de cuenta de servicio o ingresa las credenciales."
},
"featureVertexServiceAccount": {
"message": "Importación de JSON de cuenta de servicio"
},
"featureVertexAutoToken": { "message": "Generación automática de tokens" },
"featureVertexGemini": { "message": "Modelos Google Gemini a través de Vertex AI" },
"vertexNote": { "message": "Los tokens de acceso expiran después de 1 hora. Tu cuenta de servicio está almacenada de forma segura para facilitar la actualización del token - solo haz clic en el botón Actualizar Token cuando sea necesario." },
"featureVertexGemini": {
"message": "Modelos Google Gemini a través de Vertex AI"
},
"vertexNote": {
"message": "Los tokens de acceso expiran después de 1 hora. Tu cuenta de servicio está almacenada de forma segura para facilitar la actualización del token - solo haz clic en el botón Actualizar Token cuando sea necesario."
},
"baseUrlLabel": { "message": "URL Base:" },
"modelLabel": { "message": "Modelo:" },
"featureCustomizable": { "message": "Endpoint y modelo personalizables" },
Expand Down
44 changes: 33 additions & 11 deletions _locales/ja/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,24 @@
"providerDeepLName": { "message": "DeepL(APIキー必須)" },
"providerDeepLFreeName": { "message": "DeepL翻訳(無料)" },
"providerOpenAICompatibleName": { "message": "OpenAI互換(APIキー必須)" },
"providerVertexGeminiName": { "message": "Vertex AI Gemini(APIキー必須)" },
"providerVertexGeminiName": {
"message": "Vertex AI Gemini(APIキー必須)"
},
"cardOpenAICompatibleTitle": { "message": "OpenAI互換(APIキー必須)" },
"cardOpenAICompatibleDesc": {
"message": "GeminiなどのOpenAI互換サービス用のAPIキーと設定を入力してください。"
},
"cardVertexGeminiTitle": { "message": "Vertex AI Gemini(APIキー必須)" },
"cardVertexGeminiDesc": { "message": "アクセストークンとVertex プロジェクト設定を入力するか、サービスアカウントJSONファイルをインポートしてください。" },
"cardVertexGeminiDesc": {
"message": "アクセストークンとVertex プロジェクト設定を入力するか、サービスアカウントJSONファイルをインポートしてください。"
},
"vertexAccessTokenLabel": { "message": "アクセストークン:" },
"vertexProjectIdLabel": { "message": "プロジェクトID:" },
"vertexLocationLabel": { "message": "ロケーション:" },
"vertexModelLabel": { "message": "モデル:" },
"vertexMissingConfig": { "message": "アクセストークンとプロジェクトIDを入力してください。" },
"vertexMissingConfig": {
"message": "アクセストークンとプロジェクトIDを入力してください。"
},
"vertexConnectionFailed": { "message": "接続に失敗しました:%s" },
"vertexServiceAccountLabel": { "message": "サービスアカウントJSON:" },
"vertexImportButton": { "message": "JSONファイルをインポート" },
Expand All @@ -206,18 +212,34 @@
"vertexImporting": { "message": "インポート中..." },
"vertexRefreshingToken": { "message": "アクセストークンを更新中..." },
"vertexGeneratingToken": { "message": "アクセストークンを生成中..." },
"vertexImportSuccess": { "message": "サービスアカウントがインポートされ、トークンが生成されました。" },
"vertexImportSuccess": {
"message": "サービスアカウントがインポートされ、トークンが生成されました。"
},
"vertexImportFailed": { "message": "インポートに失敗しました:%s" },
"vertexTokenRefreshed": { "message": "アクセストークンが正常に更新されました。" },
"vertexTokenRefreshed": {
"message": "アクセストークンが正常に更新されました。"
},
"vertexRefreshFailed": { "message": "トークンの更新に失敗しました:%s" },
"vertexTokenExpired": { "message": "⚠️ アクセストークンが期限切れです。更新をクリックして更新してください。" },
"vertexTokenExpiringSoon": { "message": "⚠️ トークンは%s分で期限切れになります。更新を検討してください。" },
"vertexConfigured": { "message": "⚠️ Vertex AIが設定されています。接続をテストしてください。" },
"vertexNotConfigured": { "message": "サービスアカウントJSONをインポートするか、認証情報を入力してください。" },
"featureVertexServiceAccount": { "message": "サービスアカウントJSONのインポート" },
"vertexTokenExpired": {
"message": "⚠️ アクセストークンが期限切れです。更新をクリックして更新してください。"
},
"vertexTokenExpiringSoon": {
"message": "⚠️ トークンは%s分で期限切れになります。更新を検討してください。"
},
"vertexConfigured": {
"message": "⚠️ Vertex AIが設定されています。接続をテストしてください。"
},
"vertexNotConfigured": {
"message": "サービスアカウントJSONをインポートするか、認証情報を入力してください。"
},
"featureVertexServiceAccount": {
"message": "サービスアカウントJSONのインポート"
},
"featureVertexAutoToken": { "message": "自動トークン生成" },
"featureVertexGemini": { "message": "Vertex AI経由のGoogle Geminiモデル" },
"vertexNote": { "message": "アクセストークンは1時間後に期限切れになります。サービスアカウントは安全に保存されており、簡単にトークンを更新できます - 必要に応じてトークン更新ボタンをクリックしてください。" },
"vertexNote": {
"message": "アクセストークンは1時間後に期限切れになります。サービスアカウントは安全に保存されており、簡単にトークンを更新できます - 必要に応じてトークン更新ボタンをクリックしてください。"
},
"baseUrlLabel": { "message": "ベースURL:" },
"modelLabel": { "message": "モデル:" },
"featureCustomizable": {
Expand Down
Loading