diff --git a/.gitignore b/.gitignore
index 4bb26a0..339fe46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ WARP.md
# Chrome extensions cannot load directories beginning with underscore
__tests__/
dist/
+UI_DESIGN/
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0ebbba..759e959 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,40 +5,60 @@ All notable changes to DualSub will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [2.5.0] - 2025-11-19
+
+### ✨ Added
+
+- **Unified AI Side Panel**: Migrated the AI Context Analysis modal into the new Side Panel interface. This provides a persistent, non-intrusive workspace for exploring cultural and linguistic context without obstructing the video playback.
+
+### 🐛 Fixed
+
+- **Side Panel Desync Edge Cases**:
+ - Fixed an issue where deselecting words in the side panel or switching videos caused synchronization errors.
+ - Implemented a "Single Source of Truth" architecture where the content script is the authoritative state holder.
+ - Eliminated race conditions by removing optimistic updates from the side panel to the background.
+- **Word Selection Order**:
+ - Ensured that selected words always maintain their original sentence order (DOM order) in the side panel, even after deselection and re-selection.
+- **Duplicate Event Listeners**:
+ - Fixed a bug where `dualsub-word-selected` listeners were accumulating, causing multiple events for a single click. Added proper cleanup logic.
+
## [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
@@ -46,40 +66,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 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
diff --git a/README.md b/README.md
index 553ade4..1cd65c0 100644
--- a/README.md
+++ b/README.md
@@ -273,7 +273,13 @@ For full license terms, see [LICENSE](LICENSE) file.
## 📋 Changelog
-### Version 2.4.0 (Current)
+### Version 2.5.0 (Current)
+
+- 🤖 **Unified AI Experience**: Integrated AI Context Analysis into the Side Panel for a seamless, persistent workspace.
+- 🐛 **Stability Improvements**: Fixed desync issues when switching videos or deselecting words in the side panel.
+- ✨ **Better UX**: Improved word selection ordering to always match sentence structure.
+
+### Version 2.4.0
- 🎉 **Full React Migration**: Popup and options pages migrated to React with 100% functional parity
- ✨ Modern component-based architecture with custom hooks
diff --git a/README_zh.md b/README_zh.md
index 33d10e4..17715fc 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -84,7 +84,7 @@
```bash
# 生产构建
npm run build
-
+
# 开发模式(自动重新构建)
npm run dev
```
@@ -259,7 +259,13 @@ npm test -- --coverage
## 📋 更新日志
-### 版本 2.4.0(当前)
+### 版本 2.5.0(当前)
+
+- 🤖 **统一 AI 体验**:将 AI 上下文分析集成到侧边栏中,提供无缝、持久的工作空间。
+- 🐛 **稳定性改进**:修复了切换视频或在侧边栏中取消选择单词时的不同步问题。
+- ✨ **体验优化**:改进了单词选择排序,使其始终与句子结构匹配。
+
+### 版本 2.4.0
- ⚛️ **React 迁移**:将弹出窗口和选项页面完全迁移到 React
- 🏗️ **现代化构建**:使用 Vite 进行快速开发和优化构建
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index acffd65..ad4abbe 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -1,34 +1,82 @@
{
- "appName": { "message": "DualSub" },
+ "appName": {
+ "message": "DualSub"
+ },
"appDesc": {
"message": "Displays dual language subtitles on streaming platforms."
},
- "pageTitle": { "message": "DualSub Settings" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "Enable Dual Subtitles:" },
- "useNativeSubtitlesLabel": { "message": "Use Official Subtitles:" },
- "originalLanguageLabel": { "message": "Language Set:" },
- "translationSettingsLegend": { "message": "Translation Settings" },
- "providerLabel": { "message": "Provider:" },
- "targetLanguageLabel": { "message": "Translate to:" },
- "batchSizeLabel": { "message": "Batch Size:" },
- "requestDelayLabel": { "message": "Request Delay (ms):" },
+ "pageTitle": {
+ "message": "DualSub Settings"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "Enable Dual Subtitles:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "Use Official Subtitles:"
+ },
+ "originalLanguageLabel": {
+ "message": "Language Set:"
+ },
+ "translationSettingsLegend": {
+ "message": "Translation Settings"
+ },
+ "providerLabel": {
+ "message": "Provider:"
+ },
+ "targetLanguageLabel": {
+ "message": "Translate to:"
+ },
+ "batchSizeLabel": {
+ "message": "Batch Size:"
+ },
+ "requestDelayLabel": {
+ "message": "Request Delay (ms):"
+ },
"subtitleAppearanceTimingLegend": {
"message": "Subtitle Appearance & Timing"
},
- "displayOrderLabel": { "message": "Display Order:" },
- "layoutLabel": { "message": "Layout:" },
- "fontSizeLabel": { "message": "Font Size:" },
- "verticalGapLabel": { "message": "Vertical Gap:" },
- "subtitleVerticalPositionLabel": { "message": "Vertical Position:" },
- "timeOffsetLabel": { "message": "Time Offset(s):" },
- "displayOrderOriginalFirst": { "message": "Original First" },
- "displayOrderTranslationFirst": { "message": "Translation First" },
- "layoutTopBottom": { "message": "Top / Bottom" },
- "layoutLeftRight": { "message": "Left / Right" },
- "uiLanguageLabel": { "message": "Language:" },
- "openOptionsButton": { "message": "Advanced Settings" },
- "statusLanguageSetTo": { "message": "Language Set (Refresh Page): " },
+ "displayOrderLabel": {
+ "message": "Display Order:"
+ },
+ "layoutLabel": {
+ "message": "Layout:"
+ },
+ "fontSizeLabel": {
+ "message": "Font Size:"
+ },
+ "verticalGapLabel": {
+ "message": "Vertical Gap:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "Vertical Position:"
+ },
+ "timeOffsetLabel": {
+ "message": "Time Offset(s):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "Original First"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "Translation First"
+ },
+ "layoutTopBottom": {
+ "message": "Top / Bottom"
+ },
+ "layoutLeftRight": {
+ "message": "Left / Right"
+ },
+ "uiLanguageLabel": {
+ "message": "Language:"
+ },
+ "openOptionsButton": {
+ "message": "Advanced Settings"
+ },
+ "statusLanguageSetTo": {
+ "message": "Language Set (Refresh Page): "
+ },
"statusDualEnabled": {
"message": "Dual Subtitles Enabled. (Refresh Page)"
},
@@ -41,81 +89,174 @@
"statusSmartTranslationDisabled": {
"message": "Smart Translation Disabled. (Refresh Page)"
},
- "statusOriginalLanguage": { "message": "Language Set (Refresh Page): " },
- "statusTimeOffset": { "message": "Time offset: " },
- "statusDisplayOrderUpdated": { "message": "Display order updated." },
+ "statusOriginalLanguage": {
+ "message": "Language Set (Refresh Page): "
+ },
+ "statusTimeOffset": {
+ "message": "Time offset: "
+ },
+ "statusDisplayOrderUpdated": {
+ "message": "Display order updated."
+ },
"statusLayoutOrientationUpdated": {
"message": "Layout orientation updated."
},
- "statusFontSize": { "message": "Font size: " },
- "statusVerticalGap": { "message": "Vertical gap: " },
- "statusVerticalPosition": { "message": "Vertical position: " },
- "statusInvalidOffset": { "message": "Invalid offset, reverting." },
+ "statusFontSize": {
+ "message": "Font size: "
+ },
+ "statusVerticalGap": {
+ "message": "Vertical gap: "
+ },
+ "statusVerticalPosition": {
+ "message": "Vertical position: "
+ },
+ "statusInvalidOffset": {
+ "message": "Invalid offset, reverting."
+ },
"statusSettingNotApplied": {
"message": "Setting not applied. Refresh page."
},
-
- "optionsPageTitle": { "message": "DualSub Options" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "General" },
- "navTranslation": { "message": "Translation" },
- "navProviders": { "message": "Providers" },
- "navAbout": { "message": "About" },
- "sectionGeneral": { "message": "General" },
- "cardUILanguageTitle": { "message": "UI Language" },
+ "optionsPageTitle": {
+ "message": "DualSub Options"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "General"
+ },
+ "navTranslation": {
+ "message": "Translation"
+ },
+ "navProviders": {
+ "message": "Providers"
+ },
+ "navAbout": {
+ "message": "About"
+ },
+ "sectionGeneral": {
+ "message": "General"
+ },
+ "cardUILanguageTitle": {
+ "message": "UI Language"
+ },
"cardUILanguageDesc": {
"message": "Choose the display language for the extension's interface."
},
- "cardHideOfficialSubtitlesTitle": { "message": "Hide Official Subtitles" },
+ "cardHideOfficialSubtitlesTitle": {
+ "message": "Hide Official Subtitles"
+ },
"cardHideOfficialSubtitlesDesc": {
"message": "Hide the official subtitles from the video platform when DualSub is active."
},
- "hideOfficialSubtitlesLabel": { "message": "Hide official subtitles:" },
- "sectionTranslation": { "message": "Translation" },
- "cardTranslationEngineTitle": { "message": "Translation Engine" },
+ "hideOfficialSubtitlesLabel": {
+ "message": "Hide official subtitles:"
+ },
+ "sectionTranslation": {
+ "message": "Translation"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "Translation Engine"
+ },
"cardTranslationEngineDesc": {
"message": "Select your preferred translation service."
},
- "cardPerformanceTitle": { "message": "Performance" },
+ "cardPerformanceTitle": {
+ "message": "Performance"
+ },
"cardPerformanceDesc": {
"message": "Adjust how the extension handles translation requests to balance speed and stability."
},
- "sectionProviders": { "message": "Provider Settings" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "Provider Settings"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "Enter your API key for DeepL Translate. Choose between Free and Pro plans."
},
- "apiKeyLabel": { "message": "API Key:" },
- "apiPlanLabel": { "message": "API Plan:" },
- "apiPlanFree": { "message": "DeepL API Free" },
- "apiPlanPro": { "message": "DeepL API Pro" },
- "sectionAbout": { "message": "About" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "Version" },
+ "apiKeyLabel": {
+ "message": "API Key:"
+ },
+ "apiPlanLabel": {
+ "message": "API Plan:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API Free"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API Pro"
+ },
+ "sectionAbout": {
+ "message": "About"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "Version"
+ },
"aboutDescription": {
"message": "This extension helps you watch videos with dual language subtitles on various platforms."
},
- "aboutDevelopment": { "message": "Developed by QuellaMC & 1jifang." },
-
- "lang_en": { "message": "English" },
- "lang_es": { "message": "Spanish" },
- "lang_fr": { "message": "French" },
- "lang_de": { "message": "German" },
- "lang_it": { "message": "Italian" },
- "lang_pt": { "message": "Portuguese" },
- "lang_ja": { "message": "Japanese" },
- "lang_ko": { "message": "Korean" },
- "lang_zh_CN": { "message": "Chinese (Simp)" },
- "lang_zh_TW": { "message": "Chinese (Trad)" },
- "lang_ru": { "message": "Russian" },
- "lang_ar": { "message": "Arabic" },
- "lang_hi": { "message": "Hindi" },
-
- "testDeepLButton": { "message": "Test DeepL Connection" },
- "deeplApiKeyError": { "message": "Please enter your DeepL API key first." },
- "deeplTestNeedsTesting": { "message": "⚠️ DeepL API key needs testing." },
- "testingButton": { "message": "Testing..." },
- "testingConnection": { "message": "Testing DeepL connection..." },
+ "aboutDevelopment": {
+ "message": "Developed by QuellaMC & 1jifang."
+ },
+ "lang_en": {
+ "message": "English"
+ },
+ "lang_es": {
+ "message": "Spanish"
+ },
+ "lang_fr": {
+ "message": "French"
+ },
+ "lang_de": {
+ "message": "German"
+ },
+ "lang_it": {
+ "message": "Italian"
+ },
+ "lang_pt": {
+ "message": "Portuguese"
+ },
+ "lang_ja": {
+ "message": "Japanese"
+ },
+ "lang_ko": {
+ "message": "Korean"
+ },
+ "lang_zh_CN": {
+ "message": "Chinese (Simp)"
+ },
+ "lang_zh_TW": {
+ "message": "Chinese (Trad)"
+ },
+ "lang_ru": {
+ "message": "Russian"
+ },
+ "lang_ar": {
+ "message": "Arabic"
+ },
+ "lang_hi": {
+ "message": "Hindi"
+ },
+ "testDeepLButton": {
+ "message": "Test DeepL Connection"
+ },
+ "deeplApiKeyError": {
+ "message": "Please enter your DeepL API key first."
+ },
+ "deeplTestNeedsTesting": {
+ "message": "⚠️ DeepL API key needs testing."
+ },
+ "testingButton": {
+ "message": "Testing..."
+ },
+ "testingConnection": {
+ "message": "Testing DeepL connection..."
+ },
"deeplTestSuccess": {
"message": "✅ DeepL API test successful!"
},
@@ -128,58 +269,108 @@
"deeplTestQuotaExceeded": {
"message": "❌ DeepL API quota exceeded. Please check your usage limits."
},
- "deeplTestApiError": { "message": "❌ DeepL API error (%d): %s" },
+ "deeplTestApiError": {
+ "message": "❌ DeepL API error (%d): %s"
+ },
"deeplTestNetworkError": {
"message": "❌ Network error: Could not connect to DeepL API. Check your internet connection."
},
- "deeplTestGenericError": { "message": "❌ Test failed: %s" },
- "deepLApiUnavailable": { "message": "DeepL API Unavailable" },
+ "deeplTestGenericError": {
+ "message": "❌ Test failed: %s"
+ },
+ "deepLApiUnavailable": {
+ "message": "DeepL API Unavailable"
+ },
"deepLApiUnavailableTooltip": {
"message": "DeepL API script failed to load"
},
"deeplApiNotLoadedError": {
"message": "❌ DeepL API script is not available. Please refresh the page."
},
- "cardGoogleTitle": { "message": "Google Translate" },
+ "cardGoogleTitle": {
+ "message": "Google Translate"
+ },
"cardGoogleDesc": {
"message": "Free translation service provided by Google. No additional configuration required."
},
- "cardMicrosoftTitle": { "message": "Microsoft Translate" },
+ "cardMicrosoftTitle": {
+ "message": "Microsoft Translate"
+ },
"cardMicrosoftDesc": {
"message": "Free translation service provided by Microsoft Edge. No additional configuration required."
},
- "cardDeepLFreeTitle": { "message": "DeepL Translate (Free)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL Translate (Free)"
+ },
"cardDeepLFreeDesc": {
"message": "Free DeepL translation service with high quality results. No API key required - uses DeepL's web interface."
},
- "providerStatus": { "message": "Status:" },
- "statusReady": { "message": "Ready to use" },
- "providerFeatures": { "message": "Features:" },
- "featureFree": { "message": "Free to use" },
- "featureNoApiKey": { "message": "No API key required" },
- "featureWideLanguageSupport": { "message": "Wide language support" },
- "featureFastTranslation": { "message": "Fast translation" },
- "featureHighQuality": { "message": "High quality translation" },
- "featureGoodPerformance": { "message": "Good performance" },
- "featureHighestQuality": { "message": "Highest quality translation" },
- "featureApiKeyRequired": { "message": "API key required" },
- "featureLimitedLanguages": { "message": "Limited language support" },
- "featureUsageLimits": { "message": "Usage limits apply" },
- "featureMultipleBackups": { "message": "Multiple backup methods" },
-
- "providerNotes": { "message": "Notes:" },
+ "providerStatus": {
+ "message": "Status:"
+ },
+ "statusReady": {
+ "message": "Ready to use"
+ },
+ "providerFeatures": {
+ "message": "Features:"
+ },
+ "featureFree": {
+ "message": "Free to use"
+ },
+ "featureNoApiKey": {
+ "message": "No API key required"
+ },
+ "featureWideLanguageSupport": {
+ "message": "Wide language support"
+ },
+ "featureFastTranslation": {
+ "message": "Fast translation"
+ },
+ "featureHighQuality": {
+ "message": "High quality translation"
+ },
+ "featureGoodPerformance": {
+ "message": "Good performance"
+ },
+ "featureHighestQuality": {
+ "message": "Highest quality translation"
+ },
+ "featureApiKeyRequired": {
+ "message": "API key required"
+ },
+ "featureLimitedLanguages": {
+ "message": "Limited language support"
+ },
+ "featureUsageLimits": {
+ "message": "Usage limits apply"
+ },
+ "featureMultipleBackups": {
+ "message": "Multiple backup methods"
+ },
+ "providerNotes": {
+ "message": "Notes:"
+ },
"noteSlowForSecurity": {
"message": "Slightly slower due to security measures"
},
"noteAutoFallback": {
"message": "Automatic fallback to alternative services"
},
- "noteRecommendedDefault": { "message": "Recommended as default provider" },
-
- "providerGoogleName": { "message": "Google Translate (Free)" },
- "providerMicrosoftName": { "message": "Microsoft Translate (Free)" },
- "providerDeepLName": { "message": "DeepL (API Key Required)" },
- "providerDeepLFreeName": { "message": "DeepL Translate (Free)" },
+ "noteRecommendedDefault": {
+ "message": "Recommended as default provider"
+ },
+ "providerGoogleName": {
+ "message": "Google Translate (Free)"
+ },
+ "providerMicrosoftName": {
+ "message": "Microsoft Translate (Free)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL (API Key Required)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL Translate (Free)"
+ },
"providerOpenAICompatibleName": {
"message": "OpenAI Compatible (API Key Required)"
},
@@ -192,75 +383,171 @@
"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." },
- "vertexAccessTokenLabel": { "message": "Access Token:" },
- "vertexProjectIdLabel": { "message": "Project ID:" },
- "vertexLocationLabel": { "message": "Location:" },
- "vertexModelLabel": { "message": "Model:" },
- "vertexMissingConfig": { "message": "Please enter access token and project ID." },
- "vertexConnectionFailed": { "message": "Connection failed: %s" },
- "vertexServiceAccountLabel": { "message": "Service Account JSON:" },
- "vertexImportButton": { "message": "Import JSON File" },
- "vertexRefreshButton": { "message": "🔄 Refresh Token" },
- "vertexImportHint": { "message": "Auto-fills credentials below" },
- "vertexImporting": { "message": "Importing..." },
- "vertexRefreshingToken": { "message": "Refreshing access token..." },
- "vertexGeneratingToken": { "message": "Generating access token..." },
- "vertexImportSuccess": { "message": "Service account imported and token generated." },
- "vertexImportFailed": { "message": "Import failed: %s" },
- "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." },
- "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." },
- "baseUrlLabel": { "message": "Base URL:" },
- "modelLabel": { "message": "Model:" },
- "featureCustomizable": { "message": "Customizable endpoint and model" },
- "fetchModelsButton": { "message": "Fetch Models" },
- "testConnectionButton": { "message": "Test Connection" },
+ "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."
+ },
+ "vertexConnectionFailed": {
+ "message": "Connection failed: %s"
+ },
+ "vertexServiceAccountLabel": {
+ "message": "Service Account JSON:"
+ },
+ "vertexImportButton": {
+ "message": "Import JSON File"
+ },
+ "vertexRefreshButton": {
+ "message": "🔄 Refresh Token"
+ },
+ "vertexImportHint": {
+ "message": "Auto-fills credentials below"
+ },
+ "vertexImporting": {
+ "message": "Importing..."
+ },
+ "vertexRefreshingToken": {
+ "message": "Refreshing access token..."
+ },
+ "vertexGeneratingToken": {
+ "message": "Generating access token..."
+ },
+ "vertexImportSuccess": {
+ "message": "Service account imported and token generated."
+ },
+ "vertexImportFailed": {
+ "message": "Import failed: %s"
+ },
+ "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."
+ },
+ "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."
+ },
+ "baseUrlLabel": {
+ "message": "Base URL:"
+ },
+ "modelLabel": {
+ "message": "Model:"
+ },
+ "featureCustomizable": {
+ "message": "Customizable endpoint and model"
+ },
+ "fetchModelsButton": {
+ "message": "Fetch Models"
+ },
+ "testConnectionButton": {
+ "message": "Test Connection"
+ },
"openaiApiKeyPlaceholder": {
"message": "Enter your OpenAI-compatible API key"
},
"openaiBaseUrlPlaceholder": {
"message": "e.g., https://api.openai.com/v1"
},
- "openaiApiKeyError": { "message": "Please enter your API key first." },
- "openaiApiKeyNeedsTesting": { "message": "⚠️ API key needs testing." },
+ "openaiApiKeyError": {
+ "message": "Please enter your API key first."
+ },
+ "openaiApiKeyNeedsTesting": {
+ "message": "⚠️ API key needs testing."
+ },
"openaiTestNeedsTesting": {
"message": "⚠️ OpenAI-compatible API key needs testing."
},
- "openaiTestingConnection": { "message": "Testing connection..." },
- "openaiConnectionSuccessful": { "message": "Connection successful!" },
- "openaiConnectionFailed": { "message": "Connection failed: %s" },
- "openaieFetchingModels": { "message": "Fetching models..." },
+ "openaiTestingConnection": {
+ "message": "Testing connection..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "Connection successful!"
+ },
+ "openaiConnectionFailed": {
+ "message": "Connection failed: %s"
+ },
+ "openaieFetchingModels": {
+ "message": "Fetching models..."
+ },
"openaiModelsFetchedSuccessfully": {
"message": "Models fetched successfully."
},
- "openaiFailedToFetchModels": { "message": "Failed to fetch models: %s" },
-
- "cardLoggingLevelTitle": { "message": "Logging Level" },
+ "openaiFailedToFetchModels": {
+ "message": "Failed to fetch models: %s"
+ },
+ "cardLoggingLevelTitle": {
+ "message": "Logging Level"
+ },
"cardLoggingLevelDesc": {
"message": "Control the amount of debug information displayed in browser console. Higher levels include all lower level messages."
},
- "loggingLevelLabel": { "message": "Logging Level:" },
- "loggingLevelOff": { "message": "Off" },
- "loggingLevelError": { "message": "Error Only" },
- "loggingLevelWarn": { "message": "Warnings & Errors" },
- "loggingLevelInfo": { "message": "Info & Above" },
- "loggingLevelDebug": { "message": "Debug (All)" },
-
- "cardBatchTranslationTitle": { "message": "Batch Translation" },
+ "loggingLevelLabel": {
+ "message": "Logging Level:"
+ },
+ "loggingLevelOff": {
+ "message": "Off"
+ },
+ "loggingLevelError": {
+ "message": "Error Only"
+ },
+ "loggingLevelWarn": {
+ "message": "Warnings & Errors"
+ },
+ "loggingLevelInfo": {
+ "message": "Info & Above"
+ },
+ "loggingLevelDebug": {
+ "message": "Debug (All)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "Batch Translation"
+ },
"cardBatchTranslationDesc": {
"message": "Batch translation processes multiple subtitle segments together, reducing API calls by 80-90% and improving performance. Configure optimal settings for your preferred translation provider."
},
- "batchingEnabledLabel": { "message": "Enable Batch Translation:" },
+ "batchingEnabledLabel": {
+ "message": "Enable Batch Translation:"
+ },
"batchingEnabledHelp": {
"message": "Groups multiple subtitle segments into single translation requests"
},
@@ -270,61 +557,87 @@
"useProviderDefaultsHelp": {
"message": "Automatically use optimal batch sizes for each translation provider"
},
- "globalBatchSizeLabel": { "message": "Global Batch Size:" },
+ "globalBatchSizeLabel": {
+ "message": "Global Batch Size:"
+ },
"globalBatchSizeHelp": {
"message": "Number of subtitle segments to process together (1-15)"
},
- "smartBatchingLabel": { "message": "Smart Batch Optimization:" },
+ "smartBatchingLabel": {
+ "message": "Smart Batch Optimization:"
+ },
"smartBatchingHelp": {
"message": "Prioritizes subtitle segments based on playback position"
},
- "maxConcurrentBatchesLabel": { "message": "Maximum Concurrent Batches:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "Maximum Concurrent Batches:"
+ },
"maxConcurrentBatchesHelp": {
"message": "Number of translation batches to process simultaneously"
},
-
- "cardProviderBatchTitle": { "message": "Provider-Specific Batch Sizes" },
+ "cardProviderBatchTitle": {
+ "message": "Provider-Specific Batch Sizes"
+ },
"cardProviderBatchDesc": {
"message": "Configure optimal batch sizes for each translation provider. These settings are used when \"Use Provider-Optimized Settings\" is enabled."
},
- "openaieBatchSizeLabel": { "message": "OpenAI Batch Size:" },
+ "openaieBatchSizeLabel": {
+ "message": "OpenAI Batch Size:"
+ },
"openaieBatchSizeHelp": {
"message": "Recommended: 5-10 segments (default: 8)"
},
- "googleBatchSizeLabel": { "message": "Google Translate Batch Size:" },
+ "googleBatchSizeLabel": {
+ "message": "Google Translate Batch Size:"
+ },
"googleBatchSizeHelp": {
"message": "Recommended: 3-5 segments (default: 4)"
},
- "deeplBatchSizeLabel": { "message": "DeepL Batch Size:" },
+ "deeplBatchSizeLabel": {
+ "message": "DeepL Batch Size:"
+ },
"deeplBatchSizeHelp": {
"message": "Recommended: 2-3 segments (default: 3)"
},
- "microsoftBatchSizeLabel": { "message": "Microsoft Translate Batch Size:" },
+ "microsoftBatchSizeLabel": {
+ "message": "Microsoft Translate Batch Size:"
+ },
"microsoftBatchSizeHelp": {
"message": "Recommended: 3-5 segments (default: 4)"
},
- "vertexBatchSizeLabel": { "message": "Vertex AI Batch Size:" },
+ "vertexBatchSizeLabel": {
+ "message": "Vertex AI Batch Size:"
+ },
"vertexBatchSizeHelp": {
"message": "Recommended: 5-10 segments (default: 8)"
},
-
- "cardProviderDelayTitle": { "message": "Provider-Specific Request Delays" },
+ "cardProviderDelayTitle": {
+ "message": "Provider-Specific Request Delays"
+ },
"cardProviderDelayDesc": {
"message": "Configure mandatory delays between translation requests to prevent account lockouts. These delays are applied even when batch processing is enabled."
},
- "openaieDelayLabel": { "message": "OpenAI Request Delay (ms):" },
+ "openaieDelayLabel": {
+ "message": "OpenAI Request Delay (ms):"
+ },
"openaieDelayHelp": {
"message": "Minimum delay between requests (default: 100ms)"
},
- "googleDelayLabel": { "message": "Google Translate Request Delay (ms):" },
+ "googleDelayLabel": {
+ "message": "Google Translate Request Delay (ms):"
+ },
"googleDelayHelp": {
"message": "Required delay to prevent temporary lockouts (default: 1500ms)"
},
- "deeplDelayLabel": { "message": "DeepL API Request Delay (ms):" },
+ "deeplDelayLabel": {
+ "message": "DeepL API Request Delay (ms):"
+ },
"deeplDelayHelp": {
"message": "Delay for DeepL API requests (default: 500ms)"
},
- "deeplFreeDelayLabel": { "message": "DeepL Free Request Delay (ms):" },
+ "deeplFreeDelayLabel": {
+ "message": "DeepL Free Request Delay (ms):"
+ },
"deeplFreeDelayHelp": {
"message": "Conservative delay for free tier (default: 2000ms)"
},
@@ -340,117 +653,246 @@
"vertexDelayHelp": {
"message": "Minimum delay between requests (default: 100ms)"
},
-
- "aiContextModalTitle": { "message": "AI Context Analysis" },
- "aiContextSelectedWords": { "message": "Selected Words" },
- "aiContextNoWordsSelected": { "message": "No words selected" },
- "aiContextClickHint": { "message": "💡 Click a word to add or remove it." },
- "aiContextStartAnalysis": { "message": "Start Analysis" },
- "aiContextPauseAnalysis": { "message": "⏸ Pause" },
- "aiContextPauseAnalysisTitle": { "message": "Pause Analysis" },
+ "aiContextModalTitle": {
+ "message": "AI Context Analysis"
+ },
+ "aiContextSelectedWords": {
+ "message": "Selected Words"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "No words selected"
+ },
+ "aiContextClickHint": {
+ "message": "💡 Click a word to add or remove it."
+ },
+ "aiContextStartAnalysis": {
+ "message": "Start Analysis"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ Pause"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "Pause Analysis"
+ },
"aiContextInitialMessage": {
"message": "Select words from the subtitles to begin analysis."
},
- "aiContextAnalyzing": { "message": "Analyzing context..." },
- "aiContextPauseNote": { "message": "Click ⏸ to pause analysis" },
- "aiContextAnalysisFailed": { "message": "Analysis Failed" },
- "aiContextNoContent": { "message": "No Analysis Content" },
+ "aiContextAnalyzing": {
+ "message": "Analyzing context..."
+ },
+ "aiContextPauseNote": {
+ "message": "Click ⏸ to pause analysis"
+ },
+ "aiContextAnalysisFailed": {
+ "message": "Analysis Failed"
+ },
+ "aiContextNoContent": {
+ "message": "No Analysis Content"
+ },
"aiContextNoContentMessage": {
"message": "Analysis completed but no content was returned."
},
- "aiContextDefinition": { "message": "📖 Definition" },
- "aiContextCultural": { "message": "🌍 Cultural Context" },
- "aiContextCulturalSignificance": { "message": "⭐ Cultural Significance" },
- "aiContextHistorical": { "message": "📜 Historical Context" },
+ "aiContextDefinition": {
+ "message": "📖 Definition"
+ },
+ "aiContextCultural": {
+ "message": "🌍 Cultural Context"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ Cultural Significance"
+ },
+ "aiContextHistorical": {
+ "message": "📜 Historical Context"
+ },
"aiContextHistoricalSignificance": {
"message": "📜 Historical Significance"
},
- "aiContextEvolution": { "message": "🔄 Evolution Over Time" },
- "aiContextLinguistic": { "message": "🔤 Linguistic Analysis" },
- "aiContextGrammar": { "message": "📝 Grammar & Semantics" },
- "aiContextUsage": { "message": "💡 Usage & Examples" },
- "aiContextExamples": { "message": "Examples:" },
- "aiContextLearningTips": { "message": "🎯 Learning Tips" },
- "aiContextRelatedExpressions": { "message": "🔗 Related Expressions" },
- "aiContextKeyInsights": { "message": "🔑 Key Insights" },
- "aiContextTypeCultural": { "message": "Cultural" },
- "aiContextTypeHistorical": { "message": "Historical" },
- "aiContextTypeLinguistic": { "message": "Linguistic" },
- "aiContextTypeComprehensive": { "message": "Comprehensive" },
- "aiContextTypeGeneric": { "message": "Context" },
- "aiContextClose": { "message": "Close" },
- "aiContextAnalysisResults": { "message": "Analysis Results" },
- "aiContextRetrying": { "message": "Analysis failed, regenerating..." },
- "aiContextRetryNotification": { "message": "Analysis failed, retrying..." },
- "aiContextRetryButton": { "message": "Try Again" },
+ "aiContextEvolution": {
+ "message": "🔄 Evolution Over Time"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 Linguistic Analysis"
+ },
+ "aiContextGrammar": {
+ "message": "📝 Grammar & Semantics"
+ },
+ "aiContextUsage": {
+ "message": "💡 Usage & Examples"
+ },
+ "aiContextExamples": {
+ "message": "Examples:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 Learning Tips"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 Related Expressions"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 Key Insights"
+ },
+ "aiContextTypeCultural": {
+ "message": "Cultural"
+ },
+ "aiContextTypeHistorical": {
+ "message": "Historical"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "Linguistic"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "Comprehensive"
+ },
+ "aiContextTypeGeneric": {
+ "message": "Context"
+ },
+ "aiContextClose": {
+ "message": "Close"
+ },
+ "aiContextAnalysisResults": {
+ "message": "Analysis Results"
+ },
+ "aiContextRetrying": {
+ "message": "Analysis failed, regenerating..."
+ },
+ "aiContextRetryNotification": {
+ "message": "Analysis failed, retrying..."
+ },
+ "aiContextRetryButton": {
+ "message": "Try Again"
+ },
"aiContextMalformedResponse": {
"message": "The AI service returned an invalid response format. This may be due to temporary service issues."
},
"aiContextJsonCodeBlock": {
"message": "The AI service returned unprocessed JSON code instead of structured data. This indicates a formatting error in the response."
},
- "aiContextCulturalContext": { "message": "Cultural Context:" },
- "aiContextSocialUsage": { "message": "Social Usage:" },
- "aiContextRegionalNotes": { "message": "Regional Notes:" },
- "aiContextOrigins": { "message": "Origins:" },
- "aiContextHistoricalContext": { "message": "Historical Context:" },
- "aiContextHistoricalSignificance": {
+ "aiContextCulturalContext": {
+ "message": "Cultural Context:"
+ },
+ "aiContextSocialUsage": {
+ "message": "Social Usage:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "Regional Notes:"
+ },
+ "aiContextOrigins": {
+ "message": "Origins:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "Historical Context:"
+ },
+ "aiContextHistoricalSignificanceLabel": {
"message": "Historical Significance:"
},
- "aiContextEvolution": { "message": "Evolution:" },
- "aiContextEtymology": { "message": "Etymology:" },
- "aiContextGrammarNotes": { "message": "Grammar Notes:" },
- "aiContextTranslationNotes": { "message": "Translation Notes:" },
- "aiContextLinguisticAnalysis": { "message": "Linguistic Analysis:" },
- "aiContextGrammarSemantics": { "message": "Grammar & Semantics:" },
- "aiContextUsageExamples": { "message": "Usage & Examples:" },
- "aiContextLearningTips": { "message": "Learning Tips:" },
- "aiContextRelatedExpressions": { "message": "Related Expressions:" },
- "aiContextKeyInsights": { "message": "Key Insights:" },
-
- "navAIContext": { "message": "AI Context" },
- "sectionAIContext": { "message": "AI Context Assistant" },
- "cardAIContextToggleTitle": { "message": "Enable AI Context Analysis" },
+ "aiContextEvolutionLabel": {
+ "message": "Evolution:"
+ },
+ "aiContextEtymology": {
+ "message": "Etymology:"
+ },
+ "aiContextGrammarNotes": {
+ "message": "Grammar Notes:"
+ },
+ "aiContextTranslationNotes": {
+ "message": "Translation Notes:"
+ },
+ "aiContextLinguisticAnalysis": {
+ "message": "Linguistic Analysis:"
+ },
+ "aiContextGrammarSemantics": {
+ "message": "Grammar & Semantics:"
+ },
+ "aiContextUsageExamples": {
+ "message": "Usage & Examples:"
+ },
+ "aiContextLearningTipsLabel": {
+ "message": "Learning Tips:"
+ },
+ "aiContextRelatedExpressionsLabel": {
+ "message": "Related Expressions:"
+ },
+ "aiContextKeyInsightsLabel": {
+ "message": "Key Insights:"
+ },
+ "navAIContext": {
+ "message": "AI Context"
+ },
+ "sectionAIContext": {
+ "message": "AI Context Assistant"
+ },
+ "cardAIContextToggleTitle": {
+ "message": "Enable AI Context Analysis"
+ },
"cardAIContextToggleDesc": {
"message": "Enable AI-powered cultural, historical, and linguistic context analysis for subtitle text. Click on words or phrases in subtitles to get detailed explanations."
},
- "aiContextEnabledLabel": { "message": "Enable AI Context:" },
- "cardAIContextProviderTitle": { "message": "AI Provider" },
+ "aiContextEnabledLabel": {
+ "message": "Enable AI Context:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "AI Provider"
+ },
"cardAIContextProviderDesc": {
"message": "Choose the AI service provider for context analysis. Different providers may offer varying quality and response times."
},
- "aiContextProviderLabel": { "message": "Provider:" },
- "cardOpenAIContextTitle": { "message": "OpenAI Configuration" },
+ "aiContextProviderLabel": {
+ "message": "Provider:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "OpenAI Configuration"
+ },
"cardOpenAIContextDesc": {
"message": "Configure your OpenAI API settings for context analysis. You need a valid OpenAI API key."
},
- "openaiApiKeyLabel": { "message": "API Key:" },
- "openaiBaseUrlLabel": { "message": "Base URL:" },
- "openaiModelLabel": { "message": "Model:" },
- "cardGeminiContextTitle": { "message": "Google Gemini Configuration" },
+ "openaiApiKeyLabel": {
+ "message": "API Key:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "Base URL:"
+ },
+ "openaiModelLabel": {
+ "message": "Model:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Google Gemini Configuration"
+ },
"cardGeminiContextDesc": {
"message": "Configure your Google Gemini API settings for context analysis. You need a valid Gemini API key."
},
- "geminiApiKeyLabel": { "message": "API Key:" },
- "geminiModelLabel": { "message": "Model:" },
- "cardAIContextTypesTitle": { "message": "Context Types" },
+ "geminiApiKeyLabel": {
+ "message": "API Key:"
+ },
+ "geminiModelLabel": {
+ "message": "Model:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "Context Types"
+ },
"cardAIContextTypesDesc": {
"message": "Enable the types of context analysis you want to use. You can enable multiple types."
},
- "contextTypeCulturalLabel": { "message": "Cultural Context:" },
+ "contextTypeCulturalLabel": {
+ "message": "Cultural Context:"
+ },
"contextTypeCulturalHelp": {
"message": "Analyze cultural references, idioms, and social context"
},
- "contextTypeHistoricalLabel": { "message": "Historical Context:" },
+ "contextTypeHistoricalLabel": {
+ "message": "Historical Context:"
+ },
"contextTypeHistoricalHelp": {
"message": "Provide historical background and time period context"
},
- "contextTypeLinguisticLabel": { "message": "Linguistic Analysis:" },
+ "contextTypeLinguisticLabel": {
+ "message": "Linguistic Analysis:"
+ },
"contextTypeLinguisticHelp": {
"message": "Explain grammar, etymology, and language structure"
},
-
- "cardAIContextPrivacyTitle": { "message": "Privacy & Data" },
+ "cardAIContextPrivacyTitle": {
+ "message": "Privacy & Data"
+ },
"cardAIContextPrivacyDesc": {
"message": "Control how your data is handled during context analysis."
},
@@ -466,26 +908,91 @@
"aiContextDataSharingHelp": {
"message": "Help improve the service by sharing anonymous usage data"
},
- "cardAIContextAdvancedTitle": { "message": "Advanced Settings" },
+ "cardAIContextAdvancedTitle": {
+ "message": "Advanced Settings"
+ },
"cardAIContextAdvancedDesc": {
"message": "Configure advanced options for AI context analysis behavior."
},
- "aiContextTimeoutLabel": { "message": "Request Timeout (ms):" },
+ "aiContextTimeoutLabel": {
+ "message": "Request Timeout (ms):"
+ },
"aiContextTimeoutHelp": {
"message": "Maximum time to wait for AI response"
},
- "aiContextRateLimitLabel": { "message": "Rate Limit (requests/min):" },
+ "aiContextRateLimitLabel": {
+ "message": "Rate Limit (requests/min):"
+ },
"aiContextRateLimitHelp": {
"message": "Maximum number of requests per minute"
},
- "aiContextCacheEnabledLabel": { "message": "Enable Caching:" },
+ "aiContextCacheEnabledLabel": {
+ "message": "Enable Caching:"
+ },
"aiContextCacheEnabledHelp": {
"message": "Cache analysis results to reduce API calls"
},
- "aiContextRetryAttemptsLabel": { "message": "Retry Attempts:" },
+ "aiContextRetryAttemptsLabel": {
+ "message": "Retry Attempts:"
+ },
"aiContextRetryAttemptsHelp": {
"message": "Number of times to retry failed requests"
},
- "showAdvancedSettings": { "message": "Show Advanced Settings" },
- "hideAdvancedSettings": { "message": "Hide Advanced Settings" }
-}
+ "sidepanelLoading": {
+ "message": "Loading..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "AI Analysis"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "Words Lists"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "Analyze"
+ },
+ "sidepanelAnalyzing": {
+ "message": "Analyzing..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "Words to Analyze"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "Click on subtitle words to add them for analysis..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "Retry"
+ },
+ "sidepanelResultsTitle": {
+ "message": "Results for \"%s\""
+ },
+ "sidepanelSectionDefinition": {
+ "message": "Definition"
+ },
+ "sidepanelSectionCultural": {
+ "message": "Cultural Context"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "Historical Context"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "Linguistic Analysis"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "My Words"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "Words Lists feature coming soon!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "This feature is currently in development. Enable it in Settings to try the preview."
+ },
+ "sidepanelErrorNoWords": {
+ "message": "No words selected for analysis"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "AI Context analysis is disabled. Enable it in settings."
+ },
+ "sidepanelErrorGeneric": {
+ "message": "An error occurred during analysis."
+ }
+}
\ No newline at end of file
diff --git a/_locales/es/messages.json b/_locales/es/messages.json
index d04809d..cc752d2 100644
--- a/_locales/es/messages.json
+++ b/_locales/es/messages.json
@@ -1,33 +1,79 @@
{
- "appName": { "message": "DualSub" },
+ "appName": {
+ "message": "DualSub"
+ },
"appDesc": {
"message": "Muestra subtítulos en dos idiomas en plataformas de streaming."
},
- "pageTitle": { "message": "Configuración de DualSub" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "Habilitar Subtítulos Duales:" },
- "useNativeSubtitlesLabel": { "message": "Usar Subtítulos Oficiales:" },
- "originalLanguageLabel": { "message": "Idioma Original:" },
- "translationSettingsLegend": { "message": "Configuración de Traducción" },
- "providerLabel": { "message": "Proveedor:" },
- "targetLanguageLabel": { "message": "Traducir a:" },
- "batchSizeLabel": { "message": "Tamaño de Lote:" },
- "requestDelayLabel": { "message": "Retraso de Solicitud (ms):" },
+ "pageTitle": {
+ "message": "Configuración de DualSub"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "Habilitar Subtítulos Duales:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "Usar Subtítulos Oficiales:"
+ },
+ "originalLanguageLabel": {
+ "message": "Idioma Original:"
+ },
+ "translationSettingsLegend": {
+ "message": "Configuración de Traducción"
+ },
+ "providerLabel": {
+ "message": "Proveedor:"
+ },
+ "targetLanguageLabel": {
+ "message": "Traducir a:"
+ },
+ "batchSizeLabel": {
+ "message": "Tamaño de Lote:"
+ },
+ "requestDelayLabel": {
+ "message": "Retraso de Solicitud (ms):"
+ },
"subtitleAppearanceTimingLegend": {
"message": "Apariencia y Sincronización de Subtítulos"
},
- "displayOrderLabel": { "message": "Orden de Visualización:" },
- "layoutLabel": { "message": "Diseño:" },
- "fontSizeLabel": { "message": "Tamaño de Fuente:" },
- "verticalGapLabel": { "message": "Espaciado Vertical:" },
- "subtitleVerticalPositionLabel": { "message": "Posición Vertical:" },
- "timeOffsetLabel": { "message": "Desfase de Tiempo(s):" },
- "displayOrderOriginalFirst": { "message": "Original Primero" },
- "displayOrderTranslationFirst": { "message": "Traducción Primero" },
- "layoutTopBottom": { "message": "Arriba / Abajo" },
- "layoutLeftRight": { "message": "Izquierda / Derecha" },
- "uiLanguageLabel": { "message": "Idioma:" },
- "openOptionsButton": { "message": "Configuración Avanzada" },
+ "displayOrderLabel": {
+ "message": "Orden de Visualización:"
+ },
+ "layoutLabel": {
+ "message": "Diseño:"
+ },
+ "fontSizeLabel": {
+ "message": "Tamaño de Fuente:"
+ },
+ "verticalGapLabel": {
+ "message": "Espaciado Vertical:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "Posición Vertical:"
+ },
+ "timeOffsetLabel": {
+ "message": "Desfase de Tiempo(s):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "Original Primero"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "Traducción Primero"
+ },
+ "layoutTopBottom": {
+ "message": "Arriba / Abajo"
+ },
+ "layoutLeftRight": {
+ "message": "Izquierda / Derecha"
+ },
+ "uiLanguageLabel": {
+ "message": "Idioma:"
+ },
+ "openOptionsButton": {
+ "message": "Configuración Avanzada"
+ },
"statusLanguageSetTo": {
"message": "Idioma Configurado (Recargar Página): "
},
@@ -46,29 +92,54 @@
"statusOriginalLanguage": {
"message": "Idioma Configurado (Recargar Página): "
},
- "statusTimeOffset": { "message": "Desfase de tiempo: " },
+ "statusTimeOffset": {
+ "message": "Desfase de tiempo: "
+ },
"statusDisplayOrderUpdated": {
"message": "Orden de visualización actualizado."
},
"statusLayoutOrientationUpdated": {
"message": "Orientación del diseño actualizada."
},
- "statusFontSize": { "message": "Tamaño de fuente: " },
- "statusVerticalGap": { "message": "Espaciado vertical: " },
- "statusVerticalPosition": { "message": "Posición vertical: " },
- "statusInvalidOffset": { "message": "Desfase inválido, revirtiendo." },
+ "statusFontSize": {
+ "message": "Tamaño de fuente: "
+ },
+ "statusVerticalGap": {
+ "message": "Espaciado vertical: "
+ },
+ "statusVerticalPosition": {
+ "message": "Posición vertical: "
+ },
+ "statusInvalidOffset": {
+ "message": "Desfase inválido, revirtiendo."
+ },
"statusSettingNotApplied": {
"message": "Configuración no aplicada. Recargar página."
},
-
- "optionsPageTitle": { "message": "Opciones de DualSub" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "General" },
- "navTranslation": { "message": "Traducción" },
- "navProviders": { "message": "Proveedores" },
- "navAbout": { "message": "Acerca de" },
- "sectionGeneral": { "message": "General" },
- "cardUILanguageTitle": { "message": "Idioma de la Interfaz" },
+ "optionsPageTitle": {
+ "message": "Opciones de DualSub"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "General"
+ },
+ "navTranslation": {
+ "message": "Traducción"
+ },
+ "navProviders": {
+ "message": "Proveedores"
+ },
+ "navAbout": {
+ "message": "Acerca de"
+ },
+ "sectionGeneral": {
+ "message": "General"
+ },
+ "cardUILanguageTitle": {
+ "message": "Idioma de la Interfaz"
+ },
"cardUILanguageDesc": {
"message": "Elige el idioma de visualización para la interfaz de la extensión."
},
@@ -81,56 +152,114 @@
"hideOfficialSubtitlesLabel": {
"message": "Ocultar subtítulos oficiales:"
},
- "sectionTranslation": { "message": "Traducción" },
- "cardTranslationEngineTitle": { "message": "Motor de Traducción" },
+ "sectionTranslation": {
+ "message": "Traducción"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "Motor de Traducción"
+ },
"cardTranslationEngineDesc": {
"message": "Selecciona tu servicio de traducción preferido."
},
- "cardPerformanceTitle": { "message": "Rendimiento" },
+ "cardPerformanceTitle": {
+ "message": "Rendimiento"
+ },
"cardPerformanceDesc": {
"message": "Ajusta cómo la extensión maneja las solicitudes de traducción para equilibrar velocidad y estabilidad."
},
- "sectionProviders": { "message": "Configuración de Proveedores" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "Configuración de Proveedores"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "Ingresa tu clave API para DeepL Translate. Elige entre planes Gratuito y Pro."
},
- "apiKeyLabel": { "message": "Clave API:" },
- "apiPlanLabel": { "message": "Plan API:" },
- "apiPlanFree": { "message": "DeepL API Gratuito" },
- "apiPlanPro": { "message": "DeepL API Pro" },
- "sectionAbout": { "message": "Acerca de" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "Versión" },
+ "apiKeyLabel": {
+ "message": "Clave API:"
+ },
+ "apiPlanLabel": {
+ "message": "Plan API:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API Gratuito"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API Pro"
+ },
+ "sectionAbout": {
+ "message": "Acerca de"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "Versión"
+ },
"aboutDescription": {
"message": "Esta extensión te ayuda a ver videos con subtítulos en dos idiomas en varias plataformas."
},
- "aboutDevelopment": { "message": "Desarrollado por QuellaMC & 1jifang." },
-
- "lang_en": { "message": "Inglés" },
- "lang_es": { "message": "Español" },
- "lang_fr": { "message": "Francés" },
- "lang_de": { "message": "Alemán" },
- "lang_it": { "message": "Italiano" },
- "lang_pt": { "message": "Portugués" },
- "lang_ja": { "message": "Japonés" },
- "lang_ko": { "message": "Coreano" },
- "lang_zh_CN": { "message": "Chino (Simp)" },
- "lang_zh_TW": { "message": "Chino (Trad)" },
- "lang_ru": { "message": "Ruso" },
- "lang_ar": { "message": "Árabe" },
- "lang_hi": { "message": "Hindi" },
-
- "testDeepLButton": { "message": "Probar Conexión DeepL" },
+ "aboutDevelopment": {
+ "message": "Desarrollado por QuellaMC & 1jifang."
+ },
+ "lang_en": {
+ "message": "Inglés"
+ },
+ "lang_es": {
+ "message": "Español"
+ },
+ "lang_fr": {
+ "message": "Francés"
+ },
+ "lang_de": {
+ "message": "Alemán"
+ },
+ "lang_it": {
+ "message": "Italiano"
+ },
+ "lang_pt": {
+ "message": "Portugués"
+ },
+ "lang_ja": {
+ "message": "Japonés"
+ },
+ "lang_ko": {
+ "message": "Coreano"
+ },
+ "lang_zh_CN": {
+ "message": "Chino (Simp)"
+ },
+ "lang_zh_TW": {
+ "message": "Chino (Trad)"
+ },
+ "lang_ru": {
+ "message": "Ruso"
+ },
+ "lang_ar": {
+ "message": "Árabe"
+ },
+ "lang_hi": {
+ "message": "Hindi"
+ },
+ "testDeepLButton": {
+ "message": "Probar Conexión DeepL"
+ },
"deeplApiKeyError": {
"message": "Por favor ingresa tu clave API de DeepL primero."
},
- "testingButton": { "message": "Probando..." },
- "testingConnection": { "message": "Probando conexión DeepL..." },
+ "testingButton": {
+ "message": "Probando..."
+ },
+ "testingConnection": {
+ "message": "Probando conexión DeepL..."
+ },
"deeplTestSuccess": {
"message": "✅ ¡Prueba de API DeepL exitosa! Tradujo \"Hello\" a \"%s\""
},
- "deeplTestSuccessSimple": { "message": "✅ ¡Prueba de API DeepL exitosa!" },
+ "deeplTestSuccessSimple": {
+ "message": "✅ ¡Prueba de API DeepL exitosa!"
+ },
"deeplTestUnexpectedFormat": {
"message": "⚠️ DeepL API respondió pero con formato inesperado"
},
@@ -140,47 +269,87 @@
"deeplTestQuotaExceeded": {
"message": "❌ Cuota de API DeepL excedida. Por favor verifica tus límites de uso."
},
- "deeplTestApiError": { "message": "❌ Error de API DeepL (%d): %s" },
+ "deeplTestApiError": {
+ "message": "❌ Error de API DeepL (%d): %s"
+ },
"deeplTestNetworkError": {
"message": "❌ Error de red: No se pudo conectar a la API de DeepL. Verifica tu conexión a internet."
},
- "deeplTestGenericError": { "message": "❌ Prueba fallida: %s" },
- "deepLApiUnavailable": { "message": "API DeepL No Disponible" },
+ "deeplTestGenericError": {
+ "message": "❌ Prueba fallida: %s"
+ },
+ "deepLApiUnavailable": {
+ "message": "API DeepL No Disponible"
+ },
"deepLApiUnavailableTooltip": {
"message": "El script de la API DeepL falló al cargar"
},
"deeplApiNotLoadedError": {
"message": "❌ El script de la API DeepL no está disponible. Por favor recarga la página."
},
-
- "cardGoogleTitle": { "message": "Google Translate" },
+ "cardGoogleTitle": {
+ "message": "Google Translate"
+ },
"cardGoogleDesc": {
"message": "Servicio de traducción gratuito proporcionado por Google. No requiere configuración adicional."
},
- "cardMicrosoftTitle": { "message": "Microsoft Translate" },
+ "cardMicrosoftTitle": {
+ "message": "Microsoft Translate"
+ },
"cardMicrosoftDesc": {
"message": "Servicio de traducción gratuito proporcionado por Microsoft Edge. No requiere configuración adicional."
},
- "cardDeepLFreeTitle": { "message": "DeepL Translate (Gratuito)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL Translate (Gratuito)"
+ },
"cardDeepLFreeDesc": {
"message": "Servicio de traducción DeepL gratuito con resultados de alta calidad. No requiere clave API - usa la interfaz web de DeepL."
},
- "providerStatus": { "message": "Estado:" },
- "statusReady": { "message": "Listo para usar" },
- "providerFeatures": { "message": "Características:" },
- "featureFree": { "message": "Gratis para usar" },
- "featureNoApiKey": { "message": "No requiere clave API" },
- "featureWideLanguageSupport": { "message": "Amplio soporte de idiomas" },
- "featureFastTranslation": { "message": "Traducción rápida" },
- "featureHighQuality": { "message": "Traducción de alta calidad" },
- "featureGoodPerformance": { "message": "Buen rendimiento" },
- "featureHighestQuality": { "message": "Traducción de la más alta calidad" },
- "featureApiKeyRequired": { "message": "Requiere clave API" },
- "featureLimitedLanguages": { "message": "Soporte limitado de idiomas" },
- "featureUsageLimits": { "message": "Se aplican límites de uso" },
- "featureMultipleBackups": { "message": "Múltiples métodos de respaldo" },
-
- "providerNotes": { "message": "Notas:" },
+ "providerStatus": {
+ "message": "Estado:"
+ },
+ "statusReady": {
+ "message": "Listo para usar"
+ },
+ "providerFeatures": {
+ "message": "Características:"
+ },
+ "featureFree": {
+ "message": "Gratis para usar"
+ },
+ "featureNoApiKey": {
+ "message": "No requiere clave API"
+ },
+ "featureWideLanguageSupport": {
+ "message": "Amplio soporte de idiomas"
+ },
+ "featureFastTranslation": {
+ "message": "Traducción rápida"
+ },
+ "featureHighQuality": {
+ "message": "Traducción de alta calidad"
+ },
+ "featureGoodPerformance": {
+ "message": "Buen rendimiento"
+ },
+ "featureHighestQuality": {
+ "message": "Traducción de la más alta calidad"
+ },
+ "featureApiKeyRequired": {
+ "message": "Requiere clave API"
+ },
+ "featureLimitedLanguages": {
+ "message": "Soporte limitado de idiomas"
+ },
+ "featureUsageLimits": {
+ "message": "Se aplican límites de uso"
+ },
+ "featureMultipleBackups": {
+ "message": "Múltiples métodos de respaldo"
+ },
+ "providerNotes": {
+ "message": "Notas:"
+ },
"noteSlowForSecurity": {
"message": "Ligeramente más lento debido a medidas de seguridad"
},
@@ -190,11 +359,18 @@
"noteRecommendedDefault": {
"message": "Recomendado como proveedor predeterminado"
},
-
- "providerGoogleName": { "message": "Google Translate (Gratuito)" },
- "providerMicrosoftName": { "message": "Microsoft Translate (Gratuito)" },
- "providerDeepLName": { "message": "DeepL (Requiere Clave API)" },
- "providerDeepLFreeName": { "message": "DeepL Translate (Gratuito)" },
+ "providerGoogleName": {
+ "message": "Google Translate (Gratuito)"
+ },
+ "providerMicrosoftName": {
+ "message": "Microsoft Translate (Gratuito)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL (Requiere Clave API)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL Translate (Gratuito)"
+ },
"providerOpenAICompatibleName": {
"message": "Compatible con OpenAI (Requiere Clave API)"
},
@@ -207,43 +383,108 @@
"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." },
- "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." },
- "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" },
- "vertexImporting": { "message": "Importando..." },
- "vertexRefreshingToken": { "message": "Actualizando token de acceso..." },
- "vertexGeneratingToken": { "message": "Generando token de acceso..." },
- "vertexImportSuccess": { "message": "Cuenta de servicio importada y token generado." },
- "vertexImportFailed": { "message": "Importación fallida: %s" },
- "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" },
- "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." },
- "baseUrlLabel": { "message": "URL Base:" },
- "modelLabel": { "message": "Modelo:" },
- "featureCustomizable": { "message": "Endpoint y modelo personalizables" },
- "fetchModelsButton": { "message": "Obtener Modelos" },
- "testConnectionButton": { "message": "Probar Conexión" },
-
+ "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."
+ },
+ "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"
+ },
+ "vertexImporting": {
+ "message": "Importando..."
+ },
+ "vertexRefreshingToken": {
+ "message": "Actualizando token de acceso..."
+ },
+ "vertexGeneratingToken": {
+ "message": "Generando token de acceso..."
+ },
+ "vertexImportSuccess": {
+ "message": "Cuenta de servicio importada y token generado."
+ },
+ "vertexImportFailed": {
+ "message": "Importación fallida: %s"
+ },
+ "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"
+ },
+ "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."
+ },
+ "baseUrlLabel": {
+ "message": "URL Base:"
+ },
+ "modelLabel": {
+ "message": "Modelo:"
+ },
+ "featureCustomizable": {
+ "message": "Endpoint y modelo personalizables"
+ },
+ "fetchModelsButton": {
+ "message": "Obtener Modelos"
+ },
+ "testConnectionButton": {
+ "message": "Probar Conexión"
+ },
"openaiApiKeyPlaceholder": {
"message": "Ingresa tu clave API compatible con OpenAI"
},
- "openaiBaseUrlPlaceholder": { "message": "ej., https://api.openai.com/v1" },
+ "openaiBaseUrlPlaceholder": {
+ "message": "ej., https://api.openai.com/v1"
+ },
"openaiApiKeyError": {
"message": "Por favor ingresa tu clave API primero."
},
@@ -253,31 +494,57 @@
"openaiTestNeedsTesting": {
"message": "⚠️ La clave API compatible con OpenAI necesita ser probada."
},
- "openaiTestingConnection": { "message": "Probando conexión..." },
- "openaiConnectionSuccessful": { "message": "¡Conexión exitosa!" },
- "openaiConnectionFailed": { "message": "Conexión falló: %s" },
- "openaieFetchingModels": { "message": "Obteniendo modelos..." },
+ "openaiTestingConnection": {
+ "message": "Probando conexión..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "¡Conexión exitosa!"
+ },
+ "openaiConnectionFailed": {
+ "message": "Conexión falló: %s"
+ },
+ "openaieFetchingModels": {
+ "message": "Obteniendo modelos..."
+ },
"openaiModelsFetchedSuccessfully": {
"message": "Modelos obtenidos exitosamente."
},
- "openaiFailedToFetchModels": { "message": "Error al obtener modelos: %s" },
-
- "cardLoggingLevelTitle": { "message": "Nivel de Registro" },
+ "openaiFailedToFetchModels": {
+ "message": "Error al obtener modelos: %s"
+ },
+ "cardLoggingLevelTitle": {
+ "message": "Nivel de Registro"
+ },
"cardLoggingLevelDesc": {
"message": "Controla la cantidad de información de depuración mostrada en la consola del navegador. Los niveles más altos incluyen todos los mensajes de niveles inferiores."
},
- "loggingLevelLabel": { "message": "Nivel de Registro:" },
- "loggingLevelOff": { "message": "Desactivado" },
- "loggingLevelError": { "message": "Solo Errores" },
- "loggingLevelWarn": { "message": "Advertencias y Errores" },
- "loggingLevelInfo": { "message": "Info y Superior" },
- "loggingLevelDebug": { "message": "Debug (Todo)" },
-
- "cardBatchTranslationTitle": { "message": "Traducción por Lotes" },
+ "loggingLevelLabel": {
+ "message": "Nivel de Registro:"
+ },
+ "loggingLevelOff": {
+ "message": "Desactivado"
+ },
+ "loggingLevelError": {
+ "message": "Solo Errores"
+ },
+ "loggingLevelWarn": {
+ "message": "Advertencias y Errores"
+ },
+ "loggingLevelInfo": {
+ "message": "Info y Superior"
+ },
+ "loggingLevelDebug": {
+ "message": "Debug (Todo)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "Traducción por Lotes"
+ },
"cardBatchTranslationDesc": {
"message": "La traducción por lotes procesa múltiples segmentos de subtítulos juntos, reduciendo las llamadas a la API en un 80-90% y mejorando el rendimiento. Configure los ajustes óptimos para su proveedor de traducción preferido."
},
- "batchingEnabledLabel": { "message": "Habilitar Traducción por Lotes:" },
+ "batchingEnabledLabel": {
+ "message": "Habilitar Traducción por Lotes:"
+ },
"batchingEnabledHelp": {
"message": "Agrupa múltiples segmentos de subtítulos en solicitudes de traducción únicas"
},
@@ -287,34 +554,45 @@
"useProviderDefaultsHelp": {
"message": "Usar automáticamente tamaños de lote óptimos para cada proveedor de traducción"
},
- "globalBatchSizeLabel": { "message": "Tamaño de Lote Global:" },
+ "globalBatchSizeLabel": {
+ "message": "Tamaño de Lote Global:"
+ },
"globalBatchSizeHelp": {
"message": "Número de segmentos de subtítulos a procesar juntos (1-15)"
},
- "smartBatchingLabel": { "message": "Optimización Inteligente de Lotes:" },
+ "smartBatchingLabel": {
+ "message": "Optimización Inteligente de Lotes:"
+ },
"smartBatchingHelp": {
"message": "Prioriza segmentos de subtítulos basándose en la posición de reproducción"
},
- "maxConcurrentBatchesLabel": { "message": "Máximo de Lotes Concurrentes:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "Máximo de Lotes Concurrentes:"
+ },
"maxConcurrentBatchesHelp": {
"message": "Número de lotes de traducción a procesar simultáneamente"
},
-
"cardProviderBatchTitle": {
"message": "Tamaños de Lote Específicos del Proveedor"
},
"cardProviderBatchDesc": {
"message": "Configure tamaños de lote óptimos para cada proveedor de traducción. Estas configuraciones se usan cuando \"Usar Configuración Optimizada del Proveedor\" está habilitado."
},
- "openaieBatchSizeLabel": { "message": "Tamaño de Lote OpenAI:" },
+ "openaieBatchSizeLabel": {
+ "message": "Tamaño de Lote OpenAI:"
+ },
"openaieBatchSizeHelp": {
"message": "Recomendado: 5-10 segmentos (predeterminado: 8)"
},
- "googleBatchSizeLabel": { "message": "Tamaño de Lote Google Translate:" },
+ "googleBatchSizeLabel": {
+ "message": "Tamaño de Lote Google Translate:"
+ },
"googleBatchSizeHelp": {
"message": "Recomendado: 3-5 segmentos (predeterminado: 4)"
},
- "deeplBatchSizeLabel": { "message": "Tamaño de Lote DeepL:" },
+ "deeplBatchSizeLabel": {
+ "message": "Tamaño de Lote DeepL:"
+ },
"deeplBatchSizeHelp": {
"message": "Recomendado: 2-3 segmentos (predeterminado: 3)"
},
@@ -324,22 +602,24 @@
"microsoftBatchSizeHelp": {
"message": "Recomendado: 3-5 segmentos (predeterminado: 4)"
},
- "vertexBatchSizeLabel": { "message": "Tamaño de Lote Vertex AI:" },
+ "vertexBatchSizeLabel": {
+ "message": "Tamaño de Lote Vertex AI:"
+ },
"vertexBatchSizeHelp": {
"message": "Recomendado: 5-10 segmentos (predeterminado: 8)"
},
-
"deeplTestNeedsTesting": {
"message": "⚠️ La clave API de DeepL necesita ser probada."
},
-
"cardProviderDelayTitle": {
"message": "Retrasos de Solicitud Específicos del Proveedor"
},
"cardProviderDelayDesc": {
"message": "Configure retrasos obligatorios entre solicitudes de traducción para prevenir bloqueos de cuenta. Estos retrasos se aplican incluso cuando el procesamiento por lotes está habilitado."
},
- "openaieDelayLabel": { "message": "Retraso de Solicitud OpenAI (ms):" },
+ "openaieDelayLabel": {
+ "message": "Retraso de Solicitud OpenAI (ms):"
+ },
"openaieDelayHelp": {
"message": "Retraso mínimo entre solicitudes (predeterminado: 100ms)"
},
@@ -349,7 +629,9 @@
"googleDelayHelp": {
"message": "Retraso requerido para prevenir bloqueos temporales (predeterminado: 1500ms)"
},
- "deeplDelayLabel": { "message": "Retraso de Solicitud API DeepL (ms):" },
+ "deeplDelayLabel": {
+ "message": "Retraso de Solicitud API DeepL (ms):"
+ },
"deeplDelayHelp": {
"message": "Retraso para solicitudes de API DeepL (predeterminado: 500ms)"
},
@@ -371,118 +653,240 @@
"vertexDelayHelp": {
"message": "Retraso mínimo entre solicitudes (predeterminado: 100ms)"
},
-
- "aiContextModalTitle": { "message": "Análisis de Contexto IA" },
- "aiContextSelectedWords": { "message": "Palabras Seleccionadas" },
- "aiContextNoWordsSelected": { "message": "No hay palabras seleccionadas" },
+ "aiContextModalTitle": {
+ "message": "Análisis de Contexto IA"
+ },
+ "aiContextSelectedWords": {
+ "message": "Palabras Seleccionadas"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "No hay palabras seleccionadas"
+ },
"aiContextClickHint": {
"message": "💡 Haz clic en una palabra para agregarla o quitarla."
},
- "aiContextStartAnalysis": { "message": "Iniciar Análisis" },
- "aiContextPauseAnalysis": { "message": "⏸ Pausar" },
- "aiContextPauseAnalysisTitle": { "message": "Pausar Análisis" },
+ "aiContextStartAnalysis": {
+ "message": "Iniciar Análisis"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ Pausar"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "Pausar Análisis"
+ },
"aiContextInitialMessage": {
"message": "Selecciona palabras de los subtítulos para comenzar el análisis."
},
- "aiContextAnalyzing": { "message": "Analizando contexto..." },
+ "aiContextAnalyzing": {
+ "message": "Analizando contexto..."
+ },
"aiContextPauseNote": {
"message": "Haz clic en ⏸ para pausar el análisis"
},
- "aiContextAnalysisFailed": { "message": "Análisis Fallido" },
- "aiContextNoContent": { "message": "Sin Contenido de Análisis" },
+ "aiContextAnalysisFailed": {
+ "message": "Análisis Fallido"
+ },
+ "aiContextNoContent": {
+ "message": "Sin Contenido de Análisis"
+ },
"aiContextNoContentMessage": {
"message": "El análisis se completó pero no se devolvió contenido."
},
- "aiContextDefinition": { "message": "📖 Definición" },
- "aiContextCultural": { "message": "🌍 Contexto Cultural" },
- "aiContextCulturalSignificance": { "message": "⭐ Significado Cultural" },
- "aiContextHistorical": { "message": "📜 Contexto Histórico" },
+ "aiContextDefinition": {
+ "message": "📖 Definición"
+ },
+ "aiContextCultural": {
+ "message": "🌍 Contexto Cultural"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ Significado Cultural"
+ },
+ "aiContextHistorical": {
+ "message": "📜 Contexto Histórico"
+ },
"aiContextHistoricalSignificance": {
"message": "📜 Significado Histórico"
},
- "aiContextEvolution": { "message": "🔄 Evolución en el Tiempo" },
- "aiContextLinguistic": { "message": "🔤 Análisis Lingüístico" },
- "aiContextGrammar": { "message": "📝 Gramática y Semántica" },
- "aiContextUsage": { "message": "💡 Uso y Ejemplos" },
- "aiContextExamples": { "message": "Ejemplos:" },
- "aiContextLearningTips": { "message": "🎯 Consejos de Aprendizaje" },
- "aiContextRelatedExpressions": { "message": "🔗 Expresiones Relacionadas" },
- "aiContextKeyInsights": { "message": "🔑 Perspectivas Clave" },
- "aiContextTypeCultural": { "message": "Cultural" },
- "aiContextTypeHistorical": { "message": "Histórico" },
- "aiContextTypeLinguistic": { "message": "Lingüístico" },
- "aiContextTypeComprehensive": { "message": "Integral" },
- "aiContextTypeGeneric": { "message": "Contexto" },
- "aiContextClose": { "message": "Cerrar" },
- "aiContextAnalysisResults": { "message": "Resultados del Análisis" },
- "aiContextRetrying": { "message": "Análisis falló, regenerando..." },
+ "aiContextEvolution": {
+ "message": "🔄 Evolución en el Tiempo"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 Análisis Lingüístico"
+ },
+ "aiContextGrammar": {
+ "message": "📝 Gramática y Semántica"
+ },
+ "aiContextUsage": {
+ "message": "💡 Uso y Ejemplos"
+ },
+ "aiContextExamples": {
+ "message": "Ejemplos:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 Consejos de Aprendizaje"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 Expresiones Relacionadas"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 Perspectivas Clave"
+ },
+ "aiContextTypeCultural": {
+ "message": "Cultural"
+ },
+ "aiContextTypeHistorical": {
+ "message": "Histórico"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "Lingüístico"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "Integral"
+ },
+ "aiContextTypeGeneric": {
+ "message": "Contexto"
+ },
+ "aiContextClose": {
+ "message": "Cerrar"
+ },
+ "aiContextAnalysisResults": {
+ "message": "Resultados del Análisis"
+ },
+ "aiContextRetrying": {
+ "message": "Análisis falló, regenerando..."
+ },
"aiContextRetryNotification": {
"message": "Análisis falló, reintentando..."
},
- "aiContextRetryButton": { "message": "Intentar de Nuevo" },
+ "aiContextRetryButton": {
+ "message": "Intentar de Nuevo"
+ },
"aiContextMalformedResponse": {
"message": "El servicio de IA devolvió un formato de respuesta inválido. Esto puede deberse a problemas temporales del servicio."
},
"aiContextJsonCodeBlock": {
"message": "El servicio de IA devolvió código JSON sin procesar en lugar de datos estructurados. Esto indica un error de formato en la respuesta."
},
- "aiContextCulturalContext": { "message": "Contexto Cultural:" },
- "aiContextSocialUsage": { "message": "Uso Social:" },
- "aiContextRegionalNotes": { "message": "Notas Regionales:" },
- "aiContextOrigins": { "message": "Orígenes:" },
- "aiContextHistoricalContext": { "message": "Contexto Histórico:" },
- "aiContextHistoricalSignificance": { "message": "Significado Histórico:" },
- "aiContextEvolution": { "message": "Evolución:" },
- "aiContextEtymology": { "message": "Etimología:" },
- "aiContextGrammarNotes": { "message": "Notas Gramaticales:" },
- "aiContextTranslationNotes": { "message": "Notas de Traducción:" },
- "aiContextLinguisticAnalysis": { "message": "Análisis Lingüístico:" },
- "aiContextGrammarSemantics": { "message": "Gramática y Semántica:" },
- "aiContextUsageExamples": { "message": "Uso y Ejemplos:" },
- "aiContextLearningTips": { "message": "Consejos de Aprendizaje:" },
- "aiContextRelatedExpressions": { "message": "Expresiones Relacionadas:" },
- "aiContextKeyInsights": { "message": "Puntos Clave:" },
-
- "navAIContext": { "message": "Contexto IA" },
- "sectionAIContext": { "message": "Asistente de Contexto IA" },
+ "aiContextCulturalContext": {
+ "message": "Contexto Cultural:"
+ },
+ "aiContextSocialUsage": {
+ "message": "Uso Social:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "Notas Regionales:"
+ },
+ "aiContextOrigins": {
+ "message": "Orígenes:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "Contexto Histórico:"
+ },
+ "aiContextHistoricalSignificanceLabel": {
+ "message": "Significado Histórico:"
+ },
+ "aiContextEvolutionLabel": {
+ "message": "Evolución:"
+ },
+ "aiContextEtymology": {
+ "message": "Etimología:"
+ },
+ "aiContextGrammarNotesLabel": {
+ "message": "Notas Gramaticales:"
+ },
+ "aiContextTranslationNotesLabel": {
+ "message": "Notas de Traducción:"
+ },
+ "aiContextLinguisticAnalysisLabel": {
+ "message": "Análisis Lingüístico:"
+ },
+ "aiContextGrammarSemanticsLabel": {
+ "message": "Gramática y Semántica:"
+ },
+ "aiContextUsageExamplesLabel": {
+ "message": "Uso y Ejemplos:"
+ },
+ "aiContextLearningTipsLabel": {
+ "message": "Consejos de Aprendizaje:"
+ },
+ "aiContextRelatedExpressionsLabel": {
+ "message": "Expresiones Relacionadas:"
+ },
+ "aiContextKeyInsightsLabel": {
+ "message": "Puntos Clave:"
+ },
+ "navAIContext": {
+ "message": "Contexto IA"
+ },
+ "sectionAIContext": {
+ "message": "Asistente de Contexto IA"
+ },
"cardAIContextToggleTitle": {
"message": "Habilitar Análisis de Contexto IA"
},
"cardAIContextToggleDesc": {
"message": "Habilita el análisis de contexto cultural, histórico y lingüístico impulsado por IA para el texto de los subtítulos. Haz clic en palabras o frases en los subtítulos para obtener explicaciones detalladas."
},
- "aiContextEnabledLabel": { "message": "Habilitar Contexto IA:" },
- "cardAIContextProviderTitle": { "message": "Proveedor de IA" },
+ "aiContextEnabledLabel": {
+ "message": "Habilitar Contexto IA:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "Proveedor de IA"
+ },
"cardAIContextProviderDesc": {
"message": "Elige el proveedor de servicios de IA para el análisis de contexto. Diferentes proveedores pueden ofrecer calidad y tiempos de respuesta variables."
},
- "aiContextProviderLabel": { "message": "Proveedor:" },
- "cardOpenAIContextTitle": { "message": "Configuración de OpenAI" },
+ "aiContextProviderLabel": {
+ "message": "Proveedor:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "Configuración de OpenAI"
+ },
"cardOpenAIContextDesc": {
"message": "Configura tus ajustes de API de OpenAI para el análisis de contexto. Necesitas una clave API válida de OpenAI."
},
- "openaiApiKeyLabel": { "message": "Clave API:" },
- "openaiBaseUrlLabel": { "message": "URL Base:" },
- "openaiModelLabel": { "message": "Modelo:" },
- "cardGeminiContextTitle": { "message": "Configuración de Google Gemini" },
+ "openaiApiKeyLabel": {
+ "message": "Clave API:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "URL Base:"
+ },
+ "openaiModelLabel": {
+ "message": "Modelo:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Configuración de Google Gemini"
+ },
"cardGeminiContextDesc": {
"message": "Configura tus ajustes de API de Google Gemini para el análisis de contexto. Necesitas una clave API válida de Gemini."
},
- "geminiApiKeyLabel": { "message": "Clave API:" },
- "geminiModelLabel": { "message": "Modelo:" },
- "cardAIContextTypesTitle": { "message": "Tipos de Contexto" },
+ "geminiApiKeyLabel": {
+ "message": "Clave API:"
+ },
+ "geminiModelLabel": {
+ "message": "Modelo:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "Tipos de Contexto"
+ },
"cardAIContextTypesDesc": {
"message": "Habilita los tipos de análisis de contexto que quieres usar. Puedes habilitar múltiples tipos."
},
- "contextTypeCulturalLabel": { "message": "Contexto Cultural:" },
+ "contextTypeCulturalLabel": {
+ "message": "Contexto Cultural:"
+ },
"contextTypeCulturalHelp": {
"message": "Analizar referencias culturales, modismos y contexto social"
},
- "contextTypeHistoricalLabel": { "message": "Contexto Histórico:" },
+ "contextTypeHistoricalLabel": {
+ "message": "Contexto Histórico:"
+ },
"contextTypeHistoricalHelp": {
"message": "Proporcionar antecedentes históricos y contexto del período de tiempo"
},
- "contextTypeLinguisticLabel": { "message": "Análisis Lingüístico:" },
+ "contextTypeLinguisticLabel": {
+ "message": "Análisis Lingüístico:"
+ },
"contextTypeLinguisticHelp": {
"message": "Explicar gramática, etimología y estructura del lenguaje"
},
@@ -498,15 +902,21 @@
"interactiveSubtitlesEnabledHelp": {
"message": "Hacer que las palabras de los subtítulos sean clicables para el análisis de contexto"
},
- "contextOnClickLabel": { "message": "Contexto al Hacer Clic:" },
+ "contextOnClickLabel": {
+ "message": "Contexto al Hacer Clic:"
+ },
"contextOnClickHelp": {
"message": "Mostrar análisis de contexto al hacer clic en palabras"
},
- "contextOnSelectionLabel": { "message": "Contexto en Selección:" },
+ "contextOnSelectionLabel": {
+ "message": "Contexto en Selección:"
+ },
"contextOnSelectionHelp": {
"message": "Mostrar análisis de contexto al seleccionar texto"
},
- "cardAIContextPrivacyTitle": { "message": "Privacidad y Datos" },
+ "cardAIContextPrivacyTitle": {
+ "message": "Privacidad y Datos"
+ },
"cardAIContextPrivacyDesc": {
"message": "Controla cómo se manejan tus datos durante el análisis de contexto."
},
@@ -522,7 +932,9 @@
"aiContextDataSharingHelp": {
"message": "Ayuda a mejorar el servicio compartiendo datos de uso anónimos"
},
- "cardAIContextAdvancedTitle": { "message": "Configuración Avanzada" },
+ "cardAIContextAdvancedTitle": {
+ "message": "Configuración Avanzada"
+ },
"cardAIContextAdvancedDesc": {
"message": "Configure opciones avanzadas para el comportamiento del análisis de contexto de IA."
},
@@ -538,14 +950,79 @@
"aiContextRateLimitHelp": {
"message": "Número máximo de solicitudes por minuto"
},
- "aiContextCacheEnabledLabel": { "message": "Habilitar Caché:" },
+ "aiContextCacheEnabledLabel": {
+ "message": "Habilitar Caché:"
+ },
"aiContextCacheEnabledHelp": {
"message": "Almacenar en caché los resultados del análisis para reducir las llamadas a la API"
},
- "aiContextRetryAttemptsLabel": { "message": "Intentos de Reintento:" },
+ "aiContextRetryAttemptsLabel": {
+ "message": "Intentos de Reintento:"
+ },
"aiContextRetryAttemptsHelp": {
"message": "Número de veces para reintentar solicitudes fallidas"
},
- "showAdvancedSettings": { "message": "Mostrar Configuración Avanzada" },
- "hideAdvancedSettings": { "message": "Ocultar Configuración Avanzada" }
-}
+ "showAdvancedSettings": {
+ "message": "Mostrar Configuración Avanzada"
+ },
+ "hideAdvancedSettings": {
+ "message": "Ocultar Configuración Avanzada"
+ },
+ "sidepanelLoading": {
+ "message": "Cargando..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "Análisis IA"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "Listas de Palabras"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "Analizar"
+ },
+ "sidepanelAnalyzing": {
+ "message": "Analizando..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "Palabras a Analizar"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "Haz clic en las palabras de los subtítulos para añadirlas al análisis..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "Reintentar"
+ },
+ "sidepanelResultsTitle": {
+ "message": "Resultados para \"%s\""
+ },
+ "sidepanelSectionDefinition": {
+ "message": "Definición"
+ },
+ "sidepanelSectionCultural": {
+ "message": "Contexto Cultural"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "Contexto Histórico"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "Análisis Lingüístico"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "Mis Palabras"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "¡La función de Listas de Palabras llegará pronto!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "Esta función está actualmente en desarrollo. Habilítala en Configuración para probar la vista previa."
+ },
+ "sidepanelErrorNoWords": {
+ "message": "No hay palabras seleccionadas para el análisis"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "El análisis de contexto IA está deshabilitado. Habilítalo en la configuración."
+ },
+ "sidepanelErrorGeneric": {
+ "message": "Ocurrió un error durante el análisis."
+ }
+}
\ No newline at end of file
diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json
index 483428d..a0e0efd 100644
--- a/_locales/ja/messages.json
+++ b/_locales/ja/messages.json
@@ -1,31 +1,79 @@
{
- "appName": { "message": "DualSub" },
+ "appName": {
+ "message": "DualSub"
+ },
"appDesc": {
"message": "ストリーミングプラットフォームで二言語字幕を表示します。"
},
- "pageTitle": { "message": "DualSub 設定" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "二言語字幕を有効にする:" },
- "useNativeSubtitlesLabel": { "message": "公式字幕を使用:" },
- "originalLanguageLabel": { "message": "言語設定:" },
- "translationSettingsLegend": { "message": "翻訳設定" },
- "providerLabel": { "message": "プロバイダー:" },
- "targetLanguageLabel": { "message": "翻訳先:" },
- "batchSizeLabel": { "message": "バッチサイズ:" },
- "requestDelayLabel": { "message": "リクエスト遅延 (ms):" },
- "subtitleAppearanceTimingLegend": { "message": "字幕の外観とタイミング" },
- "displayOrderLabel": { "message": "表示順序:" },
- "layoutLabel": { "message": "レイアウト:" },
- "fontSizeLabel": { "message": "フォントサイズ:" },
- "verticalGapLabel": { "message": "垂直間隔:" },
- "subtitleVerticalPositionLabel": { "message": "垂直位置:" },
- "timeOffsetLabel": { "message": "時間オフセット(秒):" },
- "displayOrderOriginalFirst": { "message": "原文を上に" },
- "displayOrderTranslationFirst": { "message": "翻訳を上に" },
- "layoutTopBottom": { "message": "上下配置" },
- "layoutLeftRight": { "message": "左右配置" },
- "uiLanguageLabel": { "message": "言語:" },
- "openOptionsButton": { "message": "詳細設定" },
+ "pageTitle": {
+ "message": "DualSub 設定"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "二言語字幕を有効にする:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "公式字幕を使用:"
+ },
+ "originalLanguageLabel": {
+ "message": "言語設定:"
+ },
+ "translationSettingsLegend": {
+ "message": "翻訳設定"
+ },
+ "providerLabel": {
+ "message": "プロバイダー:"
+ },
+ "targetLanguageLabel": {
+ "message": "翻訳先:"
+ },
+ "batchSizeLabel": {
+ "message": "バッチサイズ:"
+ },
+ "requestDelayLabel": {
+ "message": "リクエスト遅延 (ms):"
+ },
+ "subtitleAppearanceTimingLegend": {
+ "message": "字幕の外観とタイミング"
+ },
+ "displayOrderLabel": {
+ "message": "表示順序:"
+ },
+ "layoutLabel": {
+ "message": "レイアウト:"
+ },
+ "fontSizeLabel": {
+ "message": "フォントサイズ:"
+ },
+ "verticalGapLabel": {
+ "message": "垂直間隔:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "垂直位置:"
+ },
+ "timeOffsetLabel": {
+ "message": "時間オフセット(秒):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "原文を上に"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "翻訳を上に"
+ },
+ "layoutTopBottom": {
+ "message": "上下配置"
+ },
+ "layoutLeftRight": {
+ "message": "左右配置"
+ },
+ "uiLanguageLabel": {
+ "message": "言語:"
+ },
+ "openOptionsButton": {
+ "message": "詳細設定"
+ },
"statusLanguageSetTo": {
"message": "言語設定完了(ページを更新してください):"
},
@@ -44,83 +92,168 @@
"statusOriginalLanguage": {
"message": "言語設定完了(ページを更新してください):"
},
- "statusTimeOffset": { "message": "時間オフセット:" },
- "statusDisplayOrderUpdated": { "message": "表示順序が更新されました。" },
+ "statusTimeOffset": {
+ "message": "時間オフセット:"
+ },
+ "statusDisplayOrderUpdated": {
+ "message": "表示順序が更新されました。"
+ },
"statusLayoutOrientationUpdated": {
"message": "レイアウト方向が更新されました。"
},
- "statusFontSize": { "message": "フォントサイズ:" },
- "statusVerticalGap": { "message": "垂直間隔:" },
- "statusVerticalPosition": { "message": "垂直位置:" },
+ "statusFontSize": {
+ "message": "フォントサイズ:"
+ },
+ "statusVerticalGap": {
+ "message": "垂直間隔:"
+ },
+ "statusVerticalPosition": {
+ "message": "垂直位置:"
+ },
"statusInvalidOffset": {
"message": "無効なオフセットです。元に戻します。"
},
"statusSettingNotApplied": {
"message": "設定が適用されませんでした。ページを更新してください。"
},
-
- "optionsPageTitle": { "message": "DualSub オプション" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "一般" },
- "navTranslation": { "message": "翻訳" },
- "navProviders": { "message": "プロバイダー" },
- "navAbout": { "message": "について" },
- "sectionGeneral": { "message": "一般" },
- "cardUILanguageTitle": { "message": "UI言語" },
+ "optionsPageTitle": {
+ "message": "DualSub オプション"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "一般"
+ },
+ "navTranslation": {
+ "message": "翻訳"
+ },
+ "navProviders": {
+ "message": "プロバイダー"
+ },
+ "navAbout": {
+ "message": "について"
+ },
+ "sectionGeneral": {
+ "message": "一般"
+ },
+ "cardUILanguageTitle": {
+ "message": "UI言語"
+ },
"cardUILanguageDesc": {
"message": "拡張機能のインターフェースの表示言語を選択します。"
},
- "cardHideOfficialSubtitlesTitle": { "message": "公式字幕を非表示" },
+ "cardHideOfficialSubtitlesTitle": {
+ "message": "公式字幕を非表示"
+ },
"cardHideOfficialSubtitlesDesc": {
"message": "DualSubがアクティブな時、動画プラットフォームの公式字幕を非表示にします。"
},
- "hideOfficialSubtitlesLabel": { "message": "公式字幕を非表示:" },
- "sectionTranslation": { "message": "翻訳" },
- "cardTranslationEngineTitle": { "message": "翻訳エンジン" },
+ "hideOfficialSubtitlesLabel": {
+ "message": "公式字幕を非表示:"
+ },
+ "sectionTranslation": {
+ "message": "翻訳"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "翻訳エンジン"
+ },
"cardTranslationEngineDesc": {
"message": "お好みの翻訳サービスを選択してください。"
},
- "cardPerformanceTitle": { "message": "パフォーマンス" },
+ "cardPerformanceTitle": {
+ "message": "パフォーマンス"
+ },
"cardPerformanceDesc": {
"message": "拡張機能が翻訳リクエストを処理する方法を調整して、速度と安定性のバランスを取ります。"
},
- "sectionProviders": { "message": "プロバイダー設定" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "プロバイダー設定"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "DeepL TranslateのAPIキーを入力してください。FreeプランまたはProプランから選択できます。"
},
- "apiKeyLabel": { "message": "APIキー:" },
- "apiPlanLabel": { "message": "APIプラン:" },
- "apiPlanFree": { "message": "DeepL API Free" },
- "apiPlanPro": { "message": "DeepL API Pro" },
- "sectionAbout": { "message": "について" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "バージョン" },
+ "apiKeyLabel": {
+ "message": "APIキー:"
+ },
+ "apiPlanLabel": {
+ "message": "APIプラン:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API Free"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API Pro"
+ },
+ "sectionAbout": {
+ "message": "について"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "バージョン"
+ },
"aboutDescription": {
"message": "この拡張機能は、様々なプラットフォームで二言語字幕付きの動画を視聴するのに役立ちます。"
},
"aboutDevelopment": {
"message": "QuellaMC & 1jifang によって開発されました。"
},
-
- "lang_en": { "message": "英語" },
- "lang_es": { "message": "スペイン語" },
- "lang_fr": { "message": "フランス語" },
- "lang_de": { "message": "ドイツ語" },
- "lang_it": { "message": "イタリア語" },
- "lang_pt": { "message": "ポルトガル語" },
- "lang_ja": { "message": "日本語" },
- "lang_ko": { "message": "韓国語" },
- "lang_zh_CN": { "message": "中国語(簡体)" },
- "lang_zh_TW": { "message": "中国語(繁体)" },
- "lang_ru": { "message": "ロシア語" },
- "lang_ar": { "message": "アラビア語" },
- "lang_hi": { "message": "ヒンディー語" },
-
- "testDeepLButton": { "message": "DeepL接続をテスト" },
- "deeplApiKeyError": { "message": "まずDeepL APIキーを入力してください。" },
- "testingButton": { "message": "テスト中..." },
- "testingConnection": { "message": "DeepL接続をテストしています..." },
+ "lang_en": {
+ "message": "英語"
+ },
+ "lang_es": {
+ "message": "スペイン語"
+ },
+ "lang_fr": {
+ "message": "フランス語"
+ },
+ "lang_de": {
+ "message": "ドイツ語"
+ },
+ "lang_it": {
+ "message": "イタリア語"
+ },
+ "lang_pt": {
+ "message": "ポルトガル語"
+ },
+ "lang_ja": {
+ "message": "日本語"
+ },
+ "lang_ko": {
+ "message": "韓国語"
+ },
+ "lang_zh_CN": {
+ "message": "中国語(簡体)"
+ },
+ "lang_zh_TW": {
+ "message": "中国語(繁体)"
+ },
+ "lang_ru": {
+ "message": "ロシア語"
+ },
+ "lang_ar": {
+ "message": "アラビア語"
+ },
+ "lang_hi": {
+ "message": "ヒンディー語"
+ },
+ "testDeepLButton": {
+ "message": "DeepL接続をテスト"
+ },
+ "deeplApiKeyError": {
+ "message": "まずDeepL APIキーを入力してください。"
+ },
+ "testingButton": {
+ "message": "テスト中..."
+ },
+ "testingConnection": {
+ "message": "DeepL接続をテストしています..."
+ },
"deeplTestSuccess": {
"message": "✅ DeepL APIテストが成功しました!\"Hello\"を\"%s\"に翻訳しました"
},
@@ -136,312 +269,615 @@
"deeplTestQuotaExceeded": {
"message": "❌ DeepL APIの使用量制限に達しました。使用制限を確認してください。"
},
- "deeplTestApiError": { "message": "❌ DeepL APIエラー (%d): %s" },
+ "deeplTestApiError": {
+ "message": "❌ DeepL APIエラー (%d): %s"
+ },
"deeplTestNetworkError": {
"message": "❌ ネットワークエラー:DeepL APIに接続できませんでした。インターネット接続を確認してください。"
},
- "deeplTestGenericError": { "message": "❌ テストに失敗しました:%s" },
- "deepLApiUnavailable": { "message": "DeepL API利用不可" },
+ "deeplTestGenericError": {
+ "message": "❌ テストに失敗しました:%s"
+ },
+ "deepLApiUnavailable": {
+ "message": "DeepL API利用不可"
+ },
"deepLApiUnavailableTooltip": {
"message": "DeepL APIスクリプトの読み込みに失敗しました"
},
"deeplApiNotLoadedError": {
"message": "❌ DeepL APIスクリプトが利用できません。ページを更新してください。"
},
-
- "cardGoogleTitle": { "message": "Google翻訳" },
+ "cardGoogleTitle": {
+ "message": "Google翻訳"
+ },
"cardGoogleDesc": {
"message": "Googleが提供する無料の翻訳サービスです。追加の設定は必要ありません。"
},
- "cardMicrosoftTitle": { "message": "Microsoft翻訳" },
+ "cardMicrosoftTitle": {
+ "message": "Microsoft翻訳"
+ },
"cardMicrosoftDesc": {
"message": "Microsoft Edgeが提供する無料の翻訳サービスです。追加の設定は必要ありません。"
},
- "cardDeepLFreeTitle": { "message": "DeepL翻訳(無料)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL翻訳(無料)"
+ },
"cardDeepLFreeDesc": {
"message": "高品質な結果を提供する無料のDeepL翻訳サービス。APIキー不要 - DeepLのWebインターフェースを使用します。"
},
- "providerStatus": { "message": "ステータス:" },
- "statusReady": { "message": "使用可能" },
- "providerFeatures": { "message": "機能:" },
- "featureFree": { "message": "無料で使用可能" },
- "featureNoApiKey": { "message": "APIキー不要" },
- "featureWideLanguageSupport": { "message": "幅広い言語サポート" },
- "featureFastTranslation": { "message": "高速翻訳" },
- "featureHighQuality": { "message": "高品質翻訳" },
- "featureGoodPerformance": { "message": "良好なパフォーマンス" },
- "featureHighestQuality": { "message": "最高品質翻訳" },
- "featureApiKeyRequired": { "message": "APIキーが必要" },
- "featureLimitedLanguages": { "message": "限定的な言語サポート" },
- "featureUsageLimits": { "message": "使用制限が適用されます" },
- "featureMultipleBackups": { "message": "複数のバックアップ方法" },
-
- "providerNotes": { "message": "注意事項:" },
- "noteSlowForSecurity": { "message": "セキュリティ対策のため若干低速" },
- "noteAutoFallback": { "message": "代替サービスへの自動フォールバック" },
- "noteRecommendedDefault": { "message": "デフォルトプロバイダーとして推奨" },
-
- "providerGoogleName": { "message": "Google翻訳(無料)" },
- "providerMicrosoftName": { "message": "Microsoft翻訳(無料)" },
- "providerDeepLName": { "message": "DeepL(APIキー必須)" },
- "providerDeepLFreeName": { "message": "DeepL翻訳(無料)" },
- "providerOpenAICompatibleName": { "message": "OpenAI互換(APIキー必須)" },
- "providerVertexGeminiName": { "message": "Vertex AI Gemini(APIキー必須)" },
- "cardOpenAICompatibleTitle": { "message": "OpenAI互換(APIキー必須)" },
+ "providerStatus": {
+ "message": "ステータス:"
+ },
+ "statusReady": {
+ "message": "使用可能"
+ },
+ "providerFeatures": {
+ "message": "機能:"
+ },
+ "featureFree": {
+ "message": "無料で使用可能"
+ },
+ "featureNoApiKey": {
+ "message": "APIキー不要"
+ },
+ "featureWideLanguageSupport": {
+ "message": "幅広い言語サポート"
+ },
+ "featureFastTranslation": {
+ "message": "高速翻訳"
+ },
+ "featureHighQuality": {
+ "message": "高品質翻訳"
+ },
+ "featureGoodPerformance": {
+ "message": "良好なパフォーマンス"
+ },
+ "featureHighestQuality": {
+ "message": "最高品質翻訳"
+ },
+ "featureApiKeyRequired": {
+ "message": "APIキーが必要"
+ },
+ "featureLimitedLanguages": {
+ "message": "限定的な言語サポート"
+ },
+ "featureUsageLimits": {
+ "message": "使用制限が適用されます"
+ },
+ "featureMultipleBackups": {
+ "message": "複数のバックアップ方法"
+ },
+ "providerNotes": {
+ "message": "注意事項:"
+ },
+ "noteSlowForSecurity": {
+ "message": "セキュリティ対策のため若干低速"
+ },
+ "noteAutoFallback": {
+ "message": "代替サービスへの自動フォールバック"
+ },
+ "noteRecommendedDefault": {
+ "message": "デフォルトプロバイダーとして推奨"
+ },
+ "providerGoogleName": {
+ "message": "Google翻訳(無料)"
+ },
+ "providerMicrosoftName": {
+ "message": "Microsoft翻訳(無料)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL(APIキー必須)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL翻訳(無料)"
+ },
+ "providerOpenAICompatibleName": {
+ "message": "OpenAI互換(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ファイルをインポートしてください。" },
- "vertexAccessTokenLabel": { "message": "アクセストークン:" },
- "vertexProjectIdLabel": { "message": "プロジェクトID:" },
- "vertexLocationLabel": { "message": "ロケーション:" },
- "vertexModelLabel": { "message": "モデル:" },
- "vertexMissingConfig": { "message": "アクセストークンとプロジェクトIDを入力してください。" },
- "vertexConnectionFailed": { "message": "接続に失敗しました:%s" },
- "vertexServiceAccountLabel": { "message": "サービスアカウントJSON:" },
- "vertexImportButton": { "message": "JSONファイルをインポート" },
- "vertexRefreshButton": { "message": "🔄 トークンを更新" },
- "vertexImportHint": { "message": "以下の認証情報を自動入力" },
- "vertexImporting": { "message": "インポート中..." },
- "vertexRefreshingToken": { "message": "アクセストークンを更新中..." },
- "vertexGeneratingToken": { "message": "アクセストークンを生成中..." },
- "vertexImportSuccess": { "message": "サービスアカウントがインポートされ、トークンが生成されました。" },
- "vertexImportFailed": { "message": "インポートに失敗しました:%s" },
- "vertexTokenRefreshed": { "message": "アクセストークンが正常に更新されました。" },
- "vertexRefreshFailed": { "message": "トークンの更新に失敗しました:%s" },
- "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時間後に期限切れになります。サービスアカウントは安全に保存されており、簡単にトークンを更新できます - 必要に応じてトークン更新ボタンをクリックしてください。" },
- "baseUrlLabel": { "message": "ベースURL:" },
- "modelLabel": { "message": "モデル:" },
+ "cardVertexGeminiTitle": {
+ "message": "Vertex AI Gemini(APIキー必須)"
+ },
+ "cardVertexGeminiDesc": {
+ "message": "アクセストークンとVertex プロジェクト設定を入力するか、サービスアカウントJSONファイルをインポートしてください。"
+ },
+ "vertexAccessTokenLabel": {
+ "message": "アクセストークン:"
+ },
+ "vertexProjectIdLabel": {
+ "message": "プロジェクトID:"
+ },
+ "vertexLocationLabel": {
+ "message": "ロケーション:"
+ },
+ "vertexModelLabel": {
+ "message": "モデル:"
+ },
+ "vertexMissingConfig": {
+ "message": "アクセストークンとプロジェクトIDを入力してください。"
+ },
+ "vertexConnectionFailed": {
+ "message": "接続に失敗しました:%s"
+ },
+ "vertexServiceAccountLabel": {
+ "message": "サービスアカウントJSON:"
+ },
+ "vertexImportButton": {
+ "message": "JSONファイルをインポート"
+ },
+ "vertexRefreshButton": {
+ "message": "🔄 トークンを更新"
+ },
+ "vertexImportHint": {
+ "message": "以下の認証情報を自動入力"
+ },
+ "vertexImporting": {
+ "message": "インポート中..."
+ },
+ "vertexRefreshingToken": {
+ "message": "アクセストークンを更新中..."
+ },
+ "vertexGeneratingToken": {
+ "message": "アクセストークンを生成中..."
+ },
+ "vertexImportSuccess": {
+ "message": "サービスアカウントがインポートされ、トークンが生成されました。"
+ },
+ "vertexImportFailed": {
+ "message": "インポートに失敗しました:%s"
+ },
+ "vertexTokenRefreshed": {
+ "message": "アクセストークンが正常に更新されました。"
+ },
+ "vertexRefreshFailed": {
+ "message": "トークンの更新に失敗しました:%s"
+ },
+ "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時間後に期限切れになります。サービスアカウントは安全に保存されており、簡単にトークンを更新できます - 必要に応じてトークン更新ボタンをクリックしてください。"
+ },
+ "baseUrlLabel": {
+ "message": "ベースURL:"
+ },
+ "modelLabel": {
+ "message": "モデル:"
+ },
"featureCustomizable": {
"message": "カスタマイズ可能なエンドポイントとモデル"
},
- "fetchModelsButton": { "message": "モデルを取得" },
- "testConnectionButton": { "message": "接続をテスト" },
-
+ "fetchModelsButton": {
+ "message": "モデルを取得"
+ },
+ "testConnectionButton": {
+ "message": "接続をテスト"
+ },
"openaiApiKeyPlaceholder": {
"message": "OpenAI互換APIキーを入力してください"
},
- "openaiBaseUrlPlaceholder": { "message": "例:https://api.openai.com/v1" },
- "openaiApiKeyError": { "message": "まずAPIキーを入力してください。" },
- "openaiApiKeyNeedsTesting": { "message": "⚠️ APIキーのテストが必要です。" },
+ "openaiBaseUrlPlaceholder": {
+ "message": "例:https://api.openai.com/v1"
+ },
+ "openaiApiKeyError": {
+ "message": "まずAPIキーを入力してください。"
+ },
+ "openaiApiKeyNeedsTesting": {
+ "message": "⚠️ APIキーのテストが必要です。"
+ },
"openaiTestNeedsTesting": {
"message": "⚠️ OpenAI互換APIキーのテストが必要です。"
},
- "openaiTestingConnection": { "message": "接続をテスト中..." },
- "openaiConnectionSuccessful": { "message": "接続成功!" },
- "openaiConnectionFailed": { "message": "接続失敗:%s" },
- "openaieFetchingModels": { "message": "モデルを取得中..." },
+ "openaiTestingConnection": {
+ "message": "接続をテスト中..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "接続成功!"
+ },
+ "openaiConnectionFailed": {
+ "message": "接続失敗:%s"
+ },
+ "openaieFetchingModels": {
+ "message": "モデルを取得中..."
+ },
"openaiModelsFetchedSuccessfully": {
"message": "モデルの取得に成功しました。"
},
"openaiFailedToFetchModels": {
"message": "モデルの取得に失敗しました:%s"
},
-
- "cardLoggingLevelTitle": { "message": "ログレベル" },
+ "cardLoggingLevelTitle": {
+ "message": "ログレベル"
+ },
"cardLoggingLevelDesc": {
"message": "ブラウザコンソールに表示されるデバッグ情報の量を制御します。高いレベルには低いレベルのメッセージも含まれます。"
},
- "loggingLevelLabel": { "message": "ログレベル:" },
- "loggingLevelOff": { "message": "オフ" },
- "loggingLevelError": { "message": "エラーのみ" },
- "loggingLevelWarn": { "message": "警告とエラー" },
- "loggingLevelInfo": { "message": "情報以上" },
- "loggingLevelDebug": { "message": "デバッグ(すべて)" },
-
- "cardBatchTranslationTitle": { "message": "バッチ翻訳" },
+ "loggingLevelLabel": {
+ "message": "ログレベル:"
+ },
+ "loggingLevelOff": {
+ "message": "オフ"
+ },
+ "loggingLevelError": {
+ "message": "エラーのみ"
+ },
+ "loggingLevelWarn": {
+ "message": "警告とエラー"
+ },
+ "loggingLevelInfo": {
+ "message": "情報以上"
+ },
+ "loggingLevelDebug": {
+ "message": "デバッグ(すべて)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "バッチ翻訳"
+ },
"cardBatchTranslationDesc": {
"message": "バッチ翻訳は複数の字幕セグメントを一緒に処理し、API呼び出しを80-90%削減してパフォーマンスを向上させます。お好みの翻訳プロバイダーに最適な設定を構成してください。"
},
- "batchingEnabledLabel": { "message": "バッチ翻訳を有効にする:" },
+ "batchingEnabledLabel": {
+ "message": "バッチ翻訳を有効にする:"
+ },
"batchingEnabledHelp": {
"message": "複数の字幕セグメントを単一の翻訳リクエストにグループ化します"
},
- "useProviderDefaultsLabel": { "message": "プロバイダー最適化設定を使用:" },
+ "useProviderDefaultsLabel": {
+ "message": "プロバイダー最適化設定を使用:"
+ },
"useProviderDefaultsHelp": {
"message": "各翻訳プロバイダーに最適なバッチサイズを自動的に使用します"
},
- "globalBatchSizeLabel": { "message": "グローバルバッチサイズ:" },
+ "globalBatchSizeLabel": {
+ "message": "グローバルバッチサイズ:"
+ },
"globalBatchSizeHelp": {
"message": "一緒に処理する字幕セグメントの数(1-15)"
},
- "smartBatchingLabel": { "message": "スマートバッチ最適化:" },
+ "smartBatchingLabel": {
+ "message": "スマートバッチ最適化:"
+ },
"smartBatchingHelp": {
"message": "再生位置に基づいて字幕セグメントを優先処理します"
},
- "maxConcurrentBatchesLabel": { "message": "最大同時バッチ数:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "最大同時バッチ数:"
+ },
"maxConcurrentBatchesHelp": {
"message": "同時に処理する翻訳バッチの数"
},
-
- "cardProviderBatchTitle": { "message": "プロバイダー固有のバッチサイズ" },
+ "cardProviderBatchTitle": {
+ "message": "プロバイダー固有のバッチサイズ"
+ },
"cardProviderBatchDesc": {
"message": "各翻訳プロバイダーに最適なバッチサイズを設定します。これらの設定は「プロバイダー最適化設定を使用」が有効な場合に使用されます。"
},
- "openaieBatchSizeLabel": { "message": "OpenAIバッチサイズ:" },
+ "openaieBatchSizeLabel": {
+ "message": "OpenAIバッチサイズ:"
+ },
"openaieBatchSizeHelp": {
"message": "推奨:5-10セグメント(デフォルト:8)"
},
- "googleBatchSizeLabel": { "message": "Google翻訳バッチサイズ:" },
+ "googleBatchSizeLabel": {
+ "message": "Google翻訳バッチサイズ:"
+ },
"googleBatchSizeHelp": {
"message": "推奨:3-5セグメント(デフォルト:4)"
},
- "deeplBatchSizeLabel": { "message": "DeepLバッチサイズ:" },
+ "deeplBatchSizeLabel": {
+ "message": "DeepLバッチサイズ:"
+ },
"deeplBatchSizeHelp": {
"message": "推奨:2-3セグメント(デフォルト:3)"
},
- "microsoftBatchSizeLabel": { "message": "Microsoft翻訳バッチサイズ:" },
+ "microsoftBatchSizeLabel": {
+ "message": "Microsoft翻訳バッチサイズ:"
+ },
"microsoftBatchSizeHelp": {
"message": "推奨:3-5セグメント(デフォルト:4)"
},
- "vertexBatchSizeLabel": { "message": "Vertex AIバッチサイズ:" },
+ "vertexBatchSizeLabel": {
+ "message": "Vertex AIバッチサイズ:"
+ },
"vertexBatchSizeHelp": {
"message": "推奨:5-10セグメント(デフォルト:8)"
},
-
"deeplTestNeedsTesting": {
"message": "⚠️ DeepL APIキーのテストが必要です。"
},
-
- "cardProviderDelayTitle": { "message": "プロバイダー固有のリクエスト遅延" },
+ "cardProviderDelayTitle": {
+ "message": "プロバイダー固有のリクエスト遅延"
+ },
"cardProviderDelayDesc": {
"message": "アカウントロックアウトを防ぐため、翻訳リクエスト間の必須遅延を設定します。これらの遅延はバッチ処理が有効な場合でも適用されます。"
},
- "openaieDelayLabel": { "message": "OpenAIリクエスト遅延 (ms):" },
+ "openaieDelayLabel": {
+ "message": "OpenAIリクエスト遅延 (ms):"
+ },
"openaieDelayHelp": {
"message": "リクエスト間の最小遅延(デフォルト:100ms)"
},
- "googleDelayLabel": { "message": "Google翻訳リクエスト遅延 (ms):" },
+ "googleDelayLabel": {
+ "message": "Google翻訳リクエスト遅延 (ms):"
+ },
"googleDelayHelp": {
"message": "一時的なロックアウトを防ぐために必要な遅延(デフォルト:1500ms)"
},
- "deeplDelayLabel": { "message": "DeepL APIリクエスト遅延 (ms):" },
+ "deeplDelayLabel": {
+ "message": "DeepL APIリクエスト遅延 (ms):"
+ },
"deeplDelayHelp": {
"message": "DeepL APIリクエストの遅延(デフォルト:500ms)"
},
- "deeplFreeDelayLabel": { "message": "DeepL無料リクエスト遅延 (ms):" },
+ "deeplFreeDelayLabel": {
+ "message": "DeepL無料リクエスト遅延 (ms):"
+ },
"deeplFreeDelayHelp": {
"message": "無料プランの保守的な遅延(デフォルト:2000ms)"
},
- "microsoftDelayLabel": { "message": "Microsoft翻訳リクエスト遅延 (ms):" },
+ "microsoftDelayLabel": {
+ "message": "Microsoft翻訳リクエスト遅延 (ms):"
+ },
"microsoftDelayHelp": {
"message": "文字制限を尊重するための遅延(デフォルト:800ms)"
},
- "vertexDelayLabel": { "message": "Vertex AIリクエスト遅延 (ms):" },
+ "vertexDelayLabel": {
+ "message": "Vertex AIリクエスト遅延 (ms):"
+ },
"vertexDelayHelp": {
"message": "リクエスト間の最小遅延(デフォルト:100ms)"
},
-
- "aiContextModalTitle": { "message": "AIコンテキスト分析" },
- "aiContextSelectedWords": { "message": "選択された単語" },
- "aiContextNoWordsSelected": { "message": "単語が選択されていません" },
+ "aiContextModalTitle": {
+ "message": "AIコンテキスト分析"
+ },
+ "aiContextSelectedWords": {
+ "message": "選択された単語"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "単語が選択されていません"
+ },
"aiContextClickHint": {
"message": "💡 単語をクリックして追加または削除します。"
},
- "aiContextStartAnalysis": { "message": "分析開始" },
- "aiContextPauseAnalysis": { "message": "⏸ 一時停止" },
- "aiContextPauseAnalysisTitle": { "message": "分析を一時停止" },
+ "aiContextStartAnalysis": {
+ "message": "分析開始"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ 一時停止"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "分析を一時停止"
+ },
"aiContextInitialMessage": {
"message": "字幕から単語を選択して分析を開始してください。"
},
- "aiContextAnalyzing": { "message": "コンテキストを分析中..." },
- "aiContextPauseNote": { "message": "⏸ をクリックして分析を一時停止" },
- "aiContextAnalysisFailed": { "message": "分析失敗" },
- "aiContextNoContent": { "message": "分析コンテンツなし" },
+ "aiContextAnalyzing": {
+ "message": "コンテキストを分析中..."
+ },
+ "aiContextPauseNote": {
+ "message": "⏸ をクリックして分析を一時停止"
+ },
+ "aiContextAnalysisFailed": {
+ "message": "分析失敗"
+ },
+ "aiContextNoContent": {
+ "message": "分析コンテンツなし"
+ },
"aiContextNoContentMessage": {
"message": "分析は完了しましたが、コンテンツが返されませんでした。"
},
- "aiContextDefinition": { "message": "📖 定義" },
- "aiContextCultural": { "message": "🌍 文化的コンテキスト" },
- "aiContextCulturalSignificance": { "message": "⭐ 文化的意義" },
- "aiContextHistorical": { "message": "📜 歴史的コンテキスト" },
- "aiContextHistoricalSignificance": { "message": "📜 歴史的意義" },
- "aiContextEvolution": { "message": "🔄 時代による変遷" },
- "aiContextLinguistic": { "message": "🔤 言語学的分析" },
- "aiContextGrammar": { "message": "📝 文法と意味論" },
- "aiContextUsage": { "message": "💡 使用法と例" },
- "aiContextExamples": { "message": "例:" },
- "aiContextLearningTips": { "message": "🎯 学習のヒント" },
- "aiContextRelatedExpressions": { "message": "🔗 関連表現" },
- "aiContextKeyInsights": { "message": "🔑 重要な洞察" },
- "aiContextTypeCultural": { "message": "文化的" },
- "aiContextTypeHistorical": { "message": "歴史的" },
- "aiContextTypeLinguistic": { "message": "言語学的" },
- "aiContextTypeComprehensive": { "message": "包括的" },
- "aiContextTypeGeneric": { "message": "コンテキスト" },
- "aiContextClose": { "message": "閉じる" },
- "aiContextAnalysisResults": { "message": "分析結果" },
- "aiContextRetrying": { "message": "分析に失敗しました、再生成中..." },
+ "aiContextDefinition": {
+ "message": "📖 定義"
+ },
+ "aiContextCultural": {
+ "message": "🌍 文化的コンテキスト"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ 文化的意義"
+ },
+ "aiContextHistorical": {
+ "message": "📜 歴史的コンテキスト"
+ },
+ "aiContextHistoricalSignificance": {
+ "message": "📜 歴史的意義"
+ },
+ "aiContextEvolution": {
+ "message": "🔄 時代による変遷"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 言語学的分析"
+ },
+ "aiContextGrammar": {
+ "message": "📝 文法と意味論"
+ },
+ "aiContextUsage": {
+ "message": "💡 使用法と例"
+ },
+ "aiContextExamples": {
+ "message": "例:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 学習のヒント"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 関連表現"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 重要な洞察"
+ },
+ "aiContextTypeCultural": {
+ "message": "文化的"
+ },
+ "aiContextTypeHistorical": {
+ "message": "歴史的"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "言語学的"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "包括的"
+ },
+ "aiContextTypeGeneric": {
+ "message": "コンテキスト"
+ },
+ "aiContextClose": {
+ "message": "閉じる"
+ },
+ "aiContextAnalysisResults": {
+ "message": "分析結果"
+ },
+ "aiContextRetrying": {
+ "message": "分析に失敗しました、再生成中..."
+ },
"aiContextRetryNotification": {
"message": "分析に失敗しました、再試行中..."
},
- "aiContextRetryButton": { "message": "再試行" },
+ "aiContextRetryButton": {
+ "message": "再試行"
+ },
"aiContextMalformedResponse": {
"message": "AIサービスが無効な応答形式を返しました。これは一時的なサービスの問題が原因である可能性があります。"
},
"aiContextJsonCodeBlock": {
"message": "AIサービスが構造化データではなく未処理のJSONコードを返しました。これは応答の形式エラーを示しています。"
},
- "aiContextCulturalContext": { "message": "文化的背景:" },
- "aiContextSocialUsage": { "message": "社会的用法:" },
- "aiContextRegionalNotes": { "message": "地域的特徴:" },
- "aiContextOrigins": { "message": "語源:" },
- "aiContextHistoricalContext": { "message": "歴史的背景:" },
- "aiContextEtymology": { "message": "語源学:" },
- "aiContextGrammarNotes": { "message": "文法注記:" },
- "aiContextTranslationNotes": { "message": "翻訳注記:" },
- "aiContextLinguisticAnalysis": { "message": "言語学的分析:" },
- "aiContextGrammarSemantics": { "message": "文法と意味論:" },
- "aiContextUsageExamples": { "message": "用法と例:" },
-
- "navAIContext": { "message": "AIコンテキスト" },
- "sectionAIContext": { "message": "AIコンテキストアシスタント" },
- "cardAIContextToggleTitle": { "message": "AIコンテキスト分析を有効にする" },
+ "aiContextCulturalContext": {
+ "message": "文化的背景:"
+ },
+ "aiContextSocialUsage": {
+ "message": "社会的用法:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "地域的特徴:"
+ },
+ "aiContextOrigins": {
+ "message": "語源:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "歴史的背景:"
+ },
+ "aiContextEtymology": {
+ "message": "語源学:"
+ },
+ "aiContextGrammarNotes": {
+ "message": "文法注記:"
+ },
+ "aiContextTranslationNotes": {
+ "message": "翻訳注記:"
+ },
+ "aiContextLinguisticAnalysis": {
+ "message": "言語学的分析:"
+ },
+ "aiContextGrammarSemantics": {
+ "message": "文法と意味論:"
+ },
+ "aiContextUsageExamples": {
+ "message": "用法と例:"
+ },
+ "navAIContext": {
+ "message": "AIコンテキスト"
+ },
+ "sectionAIContext": {
+ "message": "AIコンテキストアシスタント"
+ },
+ "cardAIContextToggleTitle": {
+ "message": "AIコンテキスト分析を有効にする"
+ },
"cardAIContextToggleDesc": {
"message": "字幕テキストのAI駆動による文化的、歴史的、言語学的コンテキスト分析を有効にします。字幕の単語やフレーズをクリックして詳細な説明を取得できます。"
},
- "aiContextEnabledLabel": { "message": "AIコンテキストを有効にする:" },
- "cardAIContextProviderTitle": { "message": "AIプロバイダー" },
+ "aiContextEnabledLabel": {
+ "message": "AIコンテキストを有効にする:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "AIプロバイダー"
+ },
"cardAIContextProviderDesc": {
"message": "コンテキスト分析用のAIサービスプロバイダーを選択します。プロバイダーによって品質や応答時間が異なる場合があります。"
},
- "aiContextProviderLabel": { "message": "プロバイダー:" },
- "cardOpenAIContextTitle": { "message": "OpenAI設定" },
+ "aiContextProviderLabel": {
+ "message": "プロバイダー:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "OpenAI設定"
+ },
"cardOpenAIContextDesc": {
"message": "コンテキスト分析用のOpenAI API設定を構成します。有効なOpenAI APIキーが必要です。"
},
- "openaiApiKeyLabel": { "message": "APIキー:" },
- "openaiBaseUrlLabel": { "message": "ベースURL:" },
- "openaiModelLabel": { "message": "モデル:" },
- "cardGeminiContextTitle": { "message": "Google Gemini設定" },
+ "openaiApiKeyLabel": {
+ "message": "APIキー:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "ベースURL:"
+ },
+ "openaiModelLabel": {
+ "message": "モデル:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Google Gemini設定"
+ },
"cardGeminiContextDesc": {
"message": "コンテキスト分析用のGoogle Gemini API設定を構成します。有効なGemini APIキーが必要です。"
},
- "geminiApiKeyLabel": { "message": "APIキー:" },
- "geminiModelLabel": { "message": "モデル:" },
- "cardAIContextTypesTitle": { "message": "コンテキストタイプ" },
+ "geminiApiKeyLabel": {
+ "message": "APIキー:"
+ },
+ "geminiModelLabel": {
+ "message": "モデル:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "コンテキストタイプ"
+ },
"cardAIContextTypesDesc": {
"message": "使用したいコンテキスト分析のタイプを有効にします。複数のタイプを有効にできます。"
},
- "contextTypeCulturalLabel": { "message": "文化的コンテキスト:" },
+ "contextTypeCulturalLabel": {
+ "message": "文化的コンテキスト:"
+ },
"contextTypeCulturalHelp": {
"message": "文化的参照、慣用句、社会的コンテキストを分析"
},
- "contextTypeHistoricalLabel": { "message": "歴史的コンテキスト:" },
+ "contextTypeHistoricalLabel": {
+ "message": "歴史的コンテキスト:"
+ },
"contextTypeHistoricalHelp": {
"message": "歴史的背景と時代のコンテキストを提供"
},
- "contextTypeLinguisticLabel": { "message": "言語学的分析:" },
- "contextTypeLinguisticHelp": { "message": "文法、語源、言語構造を説明" },
- "cardAIContextInteractiveTitle": { "message": "インタラクティブ機能" },
+ "contextTypeLinguisticLabel": {
+ "message": "言語学的分析:"
+ },
+ "contextTypeLinguisticHelp": {
+ "message": "文法、語源、言語構造を説明"
+ },
+ "cardAIContextInteractiveTitle": {
+ "message": "インタラクティブ機能"
+ },
"cardAIContextInteractiveDesc": {
"message": "コンテキスト分析をトリガーするために字幕とどのように相互作用するかを設定します。"
},
@@ -451,15 +887,21 @@
"interactiveSubtitlesEnabledHelp": {
"message": "コンテキスト分析のために字幕の単語をクリック可能にする"
},
- "contextOnClickLabel": { "message": "クリック時のコンテキスト:" },
+ "contextOnClickLabel": {
+ "message": "クリック時のコンテキスト:"
+ },
"contextOnClickHelp": {
"message": "単語をクリックしたときにコンテキスト分析を表示"
},
- "contextOnSelectionLabel": { "message": "選択時のコンテキスト:" },
+ "contextOnSelectionLabel": {
+ "message": "選択時のコンテキスト:"
+ },
"contextOnSelectionHelp": {
"message": "テキストを選択したときにコンテキスト分析を表示"
},
- "cardAIContextPrivacyTitle": { "message": "プライバシーとデータ" },
+ "cardAIContextPrivacyTitle": {
+ "message": "プライバシーとデータ"
+ },
"cardAIContextPrivacyDesc": {
"message": "コンテキスト分析中のデータの処理方法を制御します。"
},
@@ -469,26 +911,103 @@
"aiContextUserConsentHelp": {
"message": "AIコンテキスト分析が機能するために必要"
},
- "aiContextDataSharingLabel": { "message": "匿名使用分析を許可:" },
+ "aiContextDataSharingLabel": {
+ "message": "匿名使用分析を許可:"
+ },
"aiContextDataSharingHelp": {
"message": "匿名使用データを共有してサービスの改善に協力"
},
- "cardAIContextAdvancedTitle": { "message": "詳細設定" },
+ "cardAIContextAdvancedTitle": {
+ "message": "詳細設定"
+ },
"cardAIContextAdvancedDesc": {
"message": "AIコンテキスト分析の動作に関する詳細オプションを設定します。"
},
- "aiContextTimeoutLabel": { "message": "リクエストタイムアウト(ms):" },
- "aiContextTimeoutHelp": { "message": "AI応答を待つ最大時間" },
- "aiContextRateLimitLabel": { "message": "レート制限(リクエスト/分):" },
- "aiContextRateLimitHelp": { "message": "1分あたりの最大リクエスト数" },
- "aiContextCacheEnabledLabel": { "message": "キャッシュを有効にする:" },
+ "aiContextTimeoutLabel": {
+ "message": "リクエストタイムアウト(ms):"
+ },
+ "aiContextTimeoutHelp": {
+ "message": "AI応答を待つ最大時間"
+ },
+ "aiContextRateLimitLabel": {
+ "message": "レート制限(リクエスト/分):"
+ },
+ "aiContextRateLimitHelp": {
+ "message": "1分あたりの最大リクエスト数"
+ },
+ "aiContextCacheEnabledLabel": {
+ "message": "キャッシュを有効にする:"
+ },
"aiContextCacheEnabledHelp": {
"message": "API呼び出しを減らすために分析結果をキャッシュ"
},
- "aiContextRetryAttemptsLabel": { "message": "再試行回数:" },
+ "aiContextRetryAttemptsLabel": {
+ "message": "再試行回数:"
+ },
"aiContextRetryAttemptsHelp": {
"message": "失敗したリクエストを再試行する回数"
},
- "showAdvancedSettings": { "message": "詳細設定を表示" },
- "hideAdvancedSettings": { "message": "詳細設定を非表示" }
-}
+ "showAdvancedSettings": {
+ "message": "詳細設定を表示"
+ },
+ "hideAdvancedSettings": {
+ "message": "詳細設定を非表示"
+ },
+ "sidepanelLoading": {
+ "message": "読み込み中..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "AI分析"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "単語リスト"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "分析"
+ },
+ "sidepanelAnalyzing": {
+ "message": "分析中..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "分析する単語"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "字幕の単語をクリックして分析に追加..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "再試行"
+ },
+ "sidepanelResultsTitle": {
+ "message": "\"%s\" の結果"
+ },
+ "sidepanelSectionDefinition": {
+ "message": "定義"
+ },
+ "sidepanelSectionCultural": {
+ "message": "文化的コンテキスト"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "歴史的コンテキスト"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "言語学的分析"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "マイ単語"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "単語リスト機能は近日公開予定!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "この機能は現在開発中です。設定で有効にしてプレビューをお試しください。"
+ },
+ "sidepanelErrorNoWords": {
+ "message": "分析する単語が選択されていません"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "AIコンテキスト分析は無効になっています。設定で有効にしてください。"
+ },
+ "sidepanelErrorGeneric": {
+ "message": "分析中にエラーが発生しました。"
+ }
+}
\ No newline at end of file
diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json
index ed66994..2e9d217 100644
--- a/_locales/ko/messages.json
+++ b/_locales/ko/messages.json
@@ -1,31 +1,79 @@
{
- "appName": { "message": "DualSub" },
+ "appName": {
+ "message": "DualSub"
+ },
"appDesc": {
"message": "스트리밍 플랫폼에서 이중 언어 자막을 표시합니다."
},
- "pageTitle": { "message": "DualSub 설정" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "이중 자막 활성화:" },
- "useNativeSubtitlesLabel": { "message": "공식 자막 사용:" },
- "originalLanguageLabel": { "message": "언어 설정:" },
- "translationSettingsLegend": { "message": "번역 설정" },
- "providerLabel": { "message": "제공업체:" },
- "targetLanguageLabel": { "message": "번역 대상:" },
- "batchSizeLabel": { "message": "배치 크기:" },
- "requestDelayLabel": { "message": "요청 지연 (ms):" },
- "subtitleAppearanceTimingLegend": { "message": "자막 외관 및 타이밍" },
- "displayOrderLabel": { "message": "표시 순서:" },
- "layoutLabel": { "message": "레이아웃:" },
- "fontSizeLabel": { "message": "글꼴 크기:" },
- "verticalGapLabel": { "message": "세로 간격:" },
- "subtitleVerticalPositionLabel": { "message": "세로 위치:" },
- "timeOffsetLabel": { "message": "시간 오프셋(초):" },
- "displayOrderOriginalFirst": { "message": "원문 먼저" },
- "displayOrderTranslationFirst": { "message": "번역 먼저" },
- "layoutTopBottom": { "message": "위아래 배치" },
- "layoutLeftRight": { "message": "좌우 배치" },
- "uiLanguageLabel": { "message": "언어:" },
- "openOptionsButton": { "message": "고급 설정" },
+ "pageTitle": {
+ "message": "DualSub 설정"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "이중 자막 활성화:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "공식 자막 사용:"
+ },
+ "originalLanguageLabel": {
+ "message": "언어 설정:"
+ },
+ "translationSettingsLegend": {
+ "message": "번역 설정"
+ },
+ "providerLabel": {
+ "message": "제공업체:"
+ },
+ "targetLanguageLabel": {
+ "message": "번역 대상:"
+ },
+ "batchSizeLabel": {
+ "message": "배치 크기:"
+ },
+ "requestDelayLabel": {
+ "message": "요청 지연 (ms):"
+ },
+ "subtitleAppearanceTimingLegend": {
+ "message": "자막 외관 및 타이밍"
+ },
+ "displayOrderLabel": {
+ "message": "표시 순서:"
+ },
+ "layoutLabel": {
+ "message": "레이아웃:"
+ },
+ "fontSizeLabel": {
+ "message": "글꼴 크기:"
+ },
+ "verticalGapLabel": {
+ "message": "세로 간격:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "세로 위치:"
+ },
+ "timeOffsetLabel": {
+ "message": "시간 오프셋(초):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "원문 먼저"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "번역 먼저"
+ },
+ "layoutTopBottom": {
+ "message": "위아래 배치"
+ },
+ "layoutLeftRight": {
+ "message": "좌우 배치"
+ },
+ "uiLanguageLabel": {
+ "message": "언어:"
+ },
+ "openOptionsButton": {
+ "message": "고급 설정"
+ },
"statusLanguageSetTo": {
"message": "언어 설정 완료 (페이지를 새로고침하세요): "
},
@@ -44,81 +92,168 @@
"statusOriginalLanguage": {
"message": "언어 설정 완료 (페이지를 새로고침하세요): "
},
- "statusTimeOffset": { "message": "시간 오프셋: " },
+ "statusTimeOffset": {
+ "message": "시간 오프셋: "
+ },
"statusDisplayOrderUpdated": {
"message": "표시 순서가 업데이트되었습니다."
},
"statusLayoutOrientationUpdated": {
"message": "레이아웃 방향이 업데이트되었습니다."
},
- "statusFontSize": { "message": "글꼴 크기: " },
- "statusVerticalGap": { "message": "세로 간격: " },
- "statusVerticalPosition": { "message": "세로 위치: " },
- "statusInvalidOffset": { "message": "잘못된 오프셋입니다. 되돌립니다." },
+ "statusFontSize": {
+ "message": "글꼴 크기: "
+ },
+ "statusVerticalGap": {
+ "message": "세로 간격: "
+ },
+ "statusVerticalPosition": {
+ "message": "세로 위치: "
+ },
+ "statusInvalidOffset": {
+ "message": "잘못된 오프셋입니다. 되돌립니다."
+ },
"statusSettingNotApplied": {
"message": "설정이 적용되지 않았습니다. 페이지를 새로고침하세요."
},
-
- "optionsPageTitle": { "message": "DualSub 옵션" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "일반" },
- "navTranslation": { "message": "번역" },
- "navProviders": { "message": "제공업체" },
- "navAbout": { "message": "정보" },
- "sectionGeneral": { "message": "일반" },
- "cardUILanguageTitle": { "message": "UI 언어" },
+ "optionsPageTitle": {
+ "message": "DualSub 옵션"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "일반"
+ },
+ "navTranslation": {
+ "message": "번역"
+ },
+ "navProviders": {
+ "message": "제공업체"
+ },
+ "navAbout": {
+ "message": "정보"
+ },
+ "sectionGeneral": {
+ "message": "일반"
+ },
+ "cardUILanguageTitle": {
+ "message": "UI 언어"
+ },
"cardUILanguageDesc": {
"message": "확장 프로그램 인터페이스의 표시 언어를 선택하세요."
},
- "cardHideOfficialSubtitlesTitle": { "message": "공식 자막 숨기기" },
+ "cardHideOfficialSubtitlesTitle": {
+ "message": "공식 자막 숨기기"
+ },
"cardHideOfficialSubtitlesDesc": {
"message": "DualSub이 활성화된 상태에서 비디오 플랫폼의 공식 자막을 숨깁니다."
},
- "hideOfficialSubtitlesLabel": { "message": "공식 자막 숨기기:" },
- "sectionTranslation": { "message": "번역" },
- "cardTranslationEngineTitle": { "message": "번역 엔진" },
+ "hideOfficialSubtitlesLabel": {
+ "message": "공식 자막 숨기기:"
+ },
+ "sectionTranslation": {
+ "message": "번역"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "번역 엔진"
+ },
"cardTranslationEngineDesc": {
"message": "선호하는 번역 서비스를 선택하세요."
},
- "cardPerformanceTitle": { "message": "성능" },
+ "cardPerformanceTitle": {
+ "message": "성능"
+ },
"cardPerformanceDesc": {
"message": "확장 프로그램이 번역 요청을 처리하는 방식을 조정하여 속도와 안정성의 균형을 맞춥니다."
},
- "sectionProviders": { "message": "제공업체 설정" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "제공업체 설정"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "DeepL Translate의 API 키를 입력하세요. 무료 플랜 또는 프로 플랜 중에서 선택할 수 있습니다."
},
- "apiKeyLabel": { "message": "API 키:" },
- "apiPlanLabel": { "message": "API 플랜:" },
- "apiPlanFree": { "message": "DeepL API 무료" },
- "apiPlanPro": { "message": "DeepL API 프로" },
- "sectionAbout": { "message": "정보" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "버전" },
+ "apiKeyLabel": {
+ "message": "API 키:"
+ },
+ "apiPlanLabel": {
+ "message": "API 플랜:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API 무료"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API 프로"
+ },
+ "sectionAbout": {
+ "message": "정보"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "버전"
+ },
"aboutDescription": {
"message": "이 확장 프로그램은 다양한 플랫폼에서 이중 언어 자막으로 비디오를 시청하는 데 도움이 됩니다."
},
- "aboutDevelopment": { "message": "QuellaMC & 1jifang이 개발했습니다." },
-
- "lang_en": { "message": "영어" },
- "lang_es": { "message": "스페인어" },
- "lang_fr": { "message": "프랑스어" },
- "lang_de": { "message": "독일어" },
- "lang_it": { "message": "이탈리아어" },
- "lang_pt": { "message": "포르투갈어" },
- "lang_ja": { "message": "일본어" },
- "lang_ko": { "message": "한국어" },
- "lang_zh_CN": { "message": "중국어(간체)" },
- "lang_zh_TW": { "message": "중국어(번체)" },
- "lang_ru": { "message": "러시아어" },
- "lang_ar": { "message": "아랍어" },
- "lang_hi": { "message": "힌디어" },
-
- "testDeepLButton": { "message": "DeepL 연결 테스트" },
- "deeplApiKeyError": { "message": "먼저 DeepL API 키를 입력해주세요." },
- "testingButton": { "message": "테스트 중..." },
- "testingConnection": { "message": "DeepL 연결을 테스트하고 있습니다..." },
+ "aboutDevelopment": {
+ "message": "QuellaMC & 1jifang이 개발했습니다."
+ },
+ "lang_en": {
+ "message": "영어"
+ },
+ "lang_es": {
+ "message": "스페인어"
+ },
+ "lang_fr": {
+ "message": "프랑스어"
+ },
+ "lang_de": {
+ "message": "독일어"
+ },
+ "lang_it": {
+ "message": "이탈리아어"
+ },
+ "lang_pt": {
+ "message": "포르투갈어"
+ },
+ "lang_ja": {
+ "message": "일본어"
+ },
+ "lang_ko": {
+ "message": "한국어"
+ },
+ "lang_zh_CN": {
+ "message": "중국어(간체)"
+ },
+ "lang_zh_TW": {
+ "message": "중국어(번체)"
+ },
+ "lang_ru": {
+ "message": "러시아어"
+ },
+ "lang_ar": {
+ "message": "아랍어"
+ },
+ "lang_hi": {
+ "message": "힌디어"
+ },
+ "testDeepLButton": {
+ "message": "DeepL 연결 테스트"
+ },
+ "deeplApiKeyError": {
+ "message": "먼저 DeepL API 키를 입력해주세요."
+ },
+ "testingButton": {
+ "message": "테스트 중..."
+ },
+ "testingConnection": {
+ "message": "DeepL 연결을 테스트하고 있습니다..."
+ },
"deeplTestSuccess": {
"message": "✅ DeepL API 테스트가 성공했습니다! \"Hello\"를 \"%s\"로 번역했습니다"
},
@@ -134,325 +269,654 @@
"deeplTestQuotaExceeded": {
"message": "❌ DeepL API 사용량 한도에 도달했습니다. 사용 제한을 확인해주세요."
},
- "deeplTestApiError": { "message": "❌ DeepL API 오류 (%d): %s" },
+ "deeplTestApiError": {
+ "message": "❌ DeepL API 오류 (%d): %s"
+ },
"deeplTestNetworkError": {
"message": "❌ 네트워크 오류: DeepL API에 연결할 수 없습니다. 인터넷 연결을 확인해주세요."
},
- "deeplTestGenericError": { "message": "❌ 테스트에 실패했습니다: %s" },
- "deepLApiUnavailable": { "message": "DeepL API 사용 불가" },
+ "deeplTestGenericError": {
+ "message": "❌ 테스트에 실패했습니다: %s"
+ },
+ "deepLApiUnavailable": {
+ "message": "DeepL API 사용 불가"
+ },
"deepLApiUnavailableTooltip": {
"message": "DeepL API 스크립트 로드에 실패했습니다"
},
"deeplApiNotLoadedError": {
"message": "❌ DeepL API 스크립트를 사용할 수 없습니다. 페이지를 새로고침해주세요."
},
-
- "cardGoogleTitle": { "message": "Google 번역" },
+ "cardGoogleTitle": {
+ "message": "Google 번역"
+ },
"cardGoogleDesc": {
"message": "Google에서 제공하는 무료 번역 서비스입니다. 추가 설정이 필요하지 않습니다."
},
- "cardMicrosoftTitle": { "message": "Microsoft 번역" },
+ "cardMicrosoftTitle": {
+ "message": "Microsoft 번역"
+ },
"cardMicrosoftDesc": {
"message": "Microsoft Edge에서 제공하는 무료 번역 서비스입니다. 추가 설정이 필요하지 않습니다."
},
- "cardDeepLFreeTitle": { "message": "DeepL 번역 (무료)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL 번역 (무료)"
+ },
"cardDeepLFreeDesc": {
"message": "고품질 결과를 제공하는 무료 DeepL 번역 서비스입니다. API 키 불필요 - DeepL 웹 인터페이스를 사용합니다."
},
- "providerStatus": { "message": "상태:" },
- "statusReady": { "message": "사용 가능" },
- "providerFeatures": { "message": "기능:" },
- "featureFree": { "message": "무료 사용" },
- "featureNoApiKey": { "message": "API 키 불필요" },
- "featureWideLanguageSupport": { "message": "광범위한 언어 지원" },
- "featureFastTranslation": { "message": "빠른 번역" },
- "featureHighQuality": { "message": "고품질 번역" },
- "featureGoodPerformance": { "message": "우수한 성능" },
- "featureHighestQuality": { "message": "최고품질 번역" },
- "featureApiKeyRequired": { "message": "API 키 필요" },
- "featureLimitedLanguages": { "message": "제한적인 언어 지원" },
- "featureUsageLimits": { "message": "사용 제한 적용" },
- "featureMultipleBackups": { "message": "다중 백업 방법" },
-
- "providerNotes": { "message": "참고사항:" },
- "noteSlowForSecurity": { "message": "보안 조치로 인해 약간 느림" },
- "noteAutoFallback": { "message": "대체 서비스로 자동 전환" },
- "noteRecommendedDefault": { "message": "기본 제공업체로 권장" },
-
- "providerGoogleName": { "message": "Google 번역 (무료)" },
- "providerMicrosoftName": { "message": "Microsoft 번역 (무료)" },
- "providerDeepLName": { "message": "DeepL (API 키 필요)" },
- "providerDeepLFreeName": { "message": "DeepL 번역 (무료)" },
- "providerOpenAICompatibleName": { "message": "OpenAI 호환 (API 키 필요)" },
- "providerVertexGeminiName": { "message": "Vertex AI Gemini (API 키 필요)" },
- "cardOpenAICompatibleTitle": { "message": "OpenAI 호환 (API 키 필요)" },
+ "providerStatus": {
+ "message": "상태:"
+ },
+ "statusReady": {
+ "message": "사용 가능"
+ },
+ "providerFeatures": {
+ "message": "기능:"
+ },
+ "featureFree": {
+ "message": "무료 사용"
+ },
+ "featureNoApiKey": {
+ "message": "API 키 불필요"
+ },
+ "featureWideLanguageSupport": {
+ "message": "광범위한 언어 지원"
+ },
+ "featureFastTranslation": {
+ "message": "빠른 번역"
+ },
+ "featureHighQuality": {
+ "message": "고품질 번역"
+ },
+ "featureGoodPerformance": {
+ "message": "우수한 성능"
+ },
+ "featureHighestQuality": {
+ "message": "최고품질 번역"
+ },
+ "featureApiKeyRequired": {
+ "message": "API 키 필요"
+ },
+ "featureLimitedLanguages": {
+ "message": "제한적인 언어 지원"
+ },
+ "featureUsageLimits": {
+ "message": "사용 제한 적용"
+ },
+ "featureMultipleBackups": {
+ "message": "다중 백업 방법"
+ },
+ "providerNotes": {
+ "message": "참고사항:"
+ },
+ "noteSlowForSecurity": {
+ "message": "보안 조치로 인해 약간 느림"
+ },
+ "noteAutoFallback": {
+ "message": "대체 서비스로 자동 전환"
+ },
+ "noteRecommendedDefault": {
+ "message": "기본 제공업체로 권장"
+ },
+ "providerGoogleName": {
+ "message": "Google 번역 (무료)"
+ },
+ "providerMicrosoftName": {
+ "message": "Microsoft 번역 (무료)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL (API 키 필요)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL 번역 (무료)"
+ },
+ "providerOpenAICompatibleName": {
+ "message": "OpenAI 호환 (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 파일을 가져오세요." },
- "vertexAccessTokenLabel": { "message": "액세스 토큰:" },
- "vertexProjectIdLabel": { "message": "프로젝트 ID:" },
- "vertexLocationLabel": { "message": "위치:" },
- "vertexModelLabel": { "message": "모델:" },
- "vertexMissingConfig": { "message": "액세스 토큰과 프로젝트 ID를 입력하세요." },
- "vertexConnectionFailed": { "message": "연결 실패: %s" },
- "vertexServiceAccountLabel": { "message": "서비스 계정 JSON:" },
- "vertexImportButton": { "message": "JSON 파일 가져오기" },
- "vertexRefreshButton": { "message": "🔄 토큰 새로고침" },
- "vertexImportHint": { "message": "아래 자격 증명을 자동으로 입력합니다" },
- "vertexImporting": { "message": "가져오는 중..." },
- "vertexRefreshingToken": { "message": "액세스 토큰 새로고침 중..." },
- "vertexGeneratingToken": { "message": "액세스 토큰 생성 중..." },
- "vertexImportSuccess": { "message": "서비스 계정을 가져오고 토큰을 생성했습니다." },
- "vertexImportFailed": { "message": "가져오기 실패: %s" },
- "vertexTokenRefreshed": { "message": "액세스 토큰이 성공적으로 새로고침되었습니다." },
- "vertexRefreshFailed": { "message": "토큰 새로고침 실패: %s" },
- "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시간 후에 만료됩니다. 서비스 계정은 안전하게 저장되어 쉽게 토큰을 새로고침할 수 있습니다 - 필요할 때 토큰 새로고침 버튼을 클릭하세요." },
- "baseUrlLabel": { "message": "기본 URL:" },
- "modelLabel": { "message": "모델:" },
+ "cardVertexGeminiTitle": {
+ "message": "Vertex AI Gemini (API 키 필요)"
+ },
+ "cardVertexGeminiDesc": {
+ "message": "액세스 토큰과 Vertex 프로젝트 설정을 입력하거나 서비스 계정 JSON 파일을 가져오세요."
+ },
+ "vertexAccessTokenLabel": {
+ "message": "액세스 토큰:"
+ },
+ "vertexProjectIdLabel": {
+ "message": "프로젝트 ID:"
+ },
+ "vertexLocationLabel": {
+ "message": "위치:"
+ },
+ "vertexModelLabel": {
+ "message": "모델:"
+ },
+ "vertexMissingConfig": {
+ "message": "액세스 토큰과 프로젝트 ID를 입력하세요."
+ },
+ "vertexConnectionFailed": {
+ "message": "연결 실패: %s"
+ },
+ "vertexServiceAccountLabel": {
+ "message": "서비스 계정 JSON:"
+ },
+ "vertexImportButton": {
+ "message": "JSON 파일 가져오기"
+ },
+ "vertexRefreshButton": {
+ "message": "🔄 토큰 새로고침"
+ },
+ "vertexImportHint": {
+ "message": "아래 자격 증명을 자동으로 입력합니다"
+ },
+ "vertexImporting": {
+ "message": "가져오는 중..."
+ },
+ "vertexRefreshingToken": {
+ "message": "액세스 토큰 새로고침 중..."
+ },
+ "vertexGeneratingToken": {
+ "message": "액세스 토큰 생성 중..."
+ },
+ "vertexImportSuccess": {
+ "message": "서비스 계정을 가져오고 토큰을 생성했습니다."
+ },
+ "vertexImportFailed": {
+ "message": "가져오기 실패: %s"
+ },
+ "vertexTokenRefreshed": {
+ "message": "액세스 토큰이 성공적으로 새로고침되었습니다."
+ },
+ "vertexRefreshFailed": {
+ "message": "토큰 새로고침 실패: %s"
+ },
+ "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시간 후에 만료됩니다. 서비스 계정은 안전하게 저장되어 쉽게 토큰을 새로고침할 수 있습니다 - 필요할 때 토큰 새로고침 버튼을 클릭하세요."
+ },
+ "baseUrlLabel": {
+ "message": "기본 URL:"
+ },
+ "modelLabel": {
+ "message": "모델:"
+ },
"featureCustomizable": {
"message": "사용자 정의 가능한 엔드포인트 및 모델"
},
- "fetchModelsButton": { "message": "모델 가져오기" },
- "testConnectionButton": { "message": "연결 테스트" },
-
- "openaiApiKeyPlaceholder": { "message": "OpenAI 호환 API 키를 입력하세요" },
- "openaiBaseUrlPlaceholder": { "message": "예: https://api.openai.com/v1" },
- "openaiApiKeyError": { "message": "먼저 API 키를 입력해주세요." },
- "openaiApiKeyNeedsTesting": { "message": "⚠️ API 키 테스트가 필요합니다." },
+ "fetchModelsButton": {
+ "message": "모델 가져오기"
+ },
+ "testConnectionButton": {
+ "message": "연결 테스트"
+ },
+ "openaiApiKeyPlaceholder": {
+ "message": "OpenAI 호환 API 키를 입력하세요"
+ },
+ "openaiBaseUrlPlaceholder": {
+ "message": "예: https://api.openai.com/v1"
+ },
+ "openaiApiKeyError": {
+ "message": "먼저 API 키를 입력해주세요."
+ },
+ "openaiApiKeyNeedsTesting": {
+ "message": "⚠️ API 키 테스트가 필요합니다."
+ },
"openaiTestNeedsTesting": {
"message": "⚠️ OpenAI 호환 API 키 테스트가 필요합니다."
},
- "openaiTestingConnection": { "message": "연결 테스트 중..." },
- "openaiConnectionSuccessful": { "message": "연결 성공!" },
- "openaiConnectionFailed": { "message": "연결 실패: %s" },
- "openaieFetchingModels": { "message": "모델 가져오는 중..." },
+ "openaiTestingConnection": {
+ "message": "연결 테스트 중..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "연결 성공!"
+ },
+ "openaiConnectionFailed": {
+ "message": "연결 실패: %s"
+ },
+ "openaieFetchingModels": {
+ "message": "모델 가져오는 중..."
+ },
"openaiModelsFetchedSuccessfully": {
"message": "모델을 성공적으로 가져왔습니다."
},
- "openaiFailedToFetchModels": { "message": "모델 가져오기 실패: %s" },
-
- "cardLoggingLevelTitle": { "message": "로깅 레벨" },
+ "openaiFailedToFetchModels": {
+ "message": "모델 가져오기 실패: %s"
+ },
+ "cardLoggingLevelTitle": {
+ "message": "로깅 레벨"
+ },
"cardLoggingLevelDesc": {
"message": "브라우저 콘솔에 표시되는 디버그 정보의 양을 제어합니다. 높은 레벨에는 낮은 레벨의 모든 메시지가 포함됩니다."
},
- "loggingLevelLabel": { "message": "로깅 레벨:" },
- "loggingLevelOff": { "message": "끄기" },
- "loggingLevelError": { "message": "오류만" },
- "loggingLevelWarn": { "message": "경고 및 오류" },
- "loggingLevelInfo": { "message": "정보 이상" },
- "loggingLevelDebug": { "message": "디버그 (모두)" },
-
- "cardBatchTranslationTitle": { "message": "배치 번역" },
+ "loggingLevelLabel": {
+ "message": "로깅 레벨:"
+ },
+ "loggingLevelOff": {
+ "message": "끄기"
+ },
+ "loggingLevelError": {
+ "message": "오류만"
+ },
+ "loggingLevelWarn": {
+ "message": "경고 및 오류"
+ },
+ "loggingLevelInfo": {
+ "message": "정보 이상"
+ },
+ "loggingLevelDebug": {
+ "message": "디버그 (모두)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "배치 번역"
+ },
"cardBatchTranslationDesc": {
"message": "배치 번역은 여러 자막 세그먼트를 함께 처리하여 API 호출을 80-90% 줄이고 성능을 향상시킵니다. 선호하는 번역 제공업체에 대한 최적 설정을 구성하세요."
},
- "batchingEnabledLabel": { "message": "배치 번역 활성화:" },
+ "batchingEnabledLabel": {
+ "message": "배치 번역 활성화:"
+ },
"batchingEnabledHelp": {
"message": "여러 자막 세그먼트를 단일 번역 요청으로 그룹화합니다"
},
- "useProviderDefaultsLabel": { "message": "제공업체 최적화 설정 사용:" },
+ "useProviderDefaultsLabel": {
+ "message": "제공업체 최적화 설정 사용:"
+ },
"useProviderDefaultsHelp": {
"message": "각 번역 제공업체에 대해 최적의 배치 크기를 자동으로 사용합니다"
},
- "globalBatchSizeLabel": { "message": "전역 배치 크기:" },
+ "globalBatchSizeLabel": {
+ "message": "전역 배치 크기:"
+ },
"globalBatchSizeHelp": {
"message": "함께 처리할 자막 세그먼트 수 (1-15)"
},
- "smartBatchingLabel": { "message": "스마트 배치 최적화:" },
+ "smartBatchingLabel": {
+ "message": "스마트 배치 최적화:"
+ },
"smartBatchingHelp": {
"message": "재생 위치를 기반으로 자막 세그먼트의 우선순위를 정합니다"
},
- "maxConcurrentBatchesLabel": { "message": "최대 동시 배치 수:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "최대 동시 배치 수:"
+ },
"maxConcurrentBatchesHelp": {
"message": "동시에 처리할 번역 배치 수"
},
-
- "cardProviderBatchTitle": { "message": "제공업체별 배치 크기" },
+ "cardProviderBatchTitle": {
+ "message": "제공업체별 배치 크기"
+ },
"cardProviderBatchDesc": {
"message": "각 번역 제공업체에 대한 최적 배치 크기를 구성합니다. 이 설정은 \"제공업체 최적화 설정 사용\"이 활성화된 경우에 사용됩니다."
},
- "openaieBatchSizeLabel": { "message": "OpenAI 배치 크기:" },
+ "openaieBatchSizeLabel": {
+ "message": "OpenAI 배치 크기:"
+ },
"openaieBatchSizeHelp": {
"message": "권장: 5-10개 세그먼트 (기본값: 8)"
},
- "googleBatchSizeLabel": { "message": "Google 번역 배치 크기:" },
+ "googleBatchSizeLabel": {
+ "message": "Google 번역 배치 크기:"
+ },
"googleBatchSizeHelp": {
"message": "권장: 3-5개 세그먼트 (기본값: 4)"
},
- "deeplBatchSizeLabel": { "message": "DeepL 배치 크기:" },
+ "deeplBatchSizeLabel": {
+ "message": "DeepL 배치 크기:"
+ },
"deeplBatchSizeHelp": {
"message": "권장: 2-3개 세그먼트 (기본값: 3)"
},
- "microsoftBatchSizeLabel": { "message": "Microsoft 번역 배치 크기:" },
+ "microsoftBatchSizeLabel": {
+ "message": "Microsoft 번역 배치 크기:"
+ },
"microsoftBatchSizeHelp": {
"message": "권장: 3-5개 세그먼트 (기본값: 4)"
},
- "vertexBatchSizeLabel": { "message": "Vertex AI 배치 크기:" },
+ "vertexBatchSizeLabel": {
+ "message": "Vertex AI 배치 크기:"
+ },
"vertexBatchSizeHelp": {
"message": "권장: 5-10개 세그먼트 (기본값: 8)"
},
-
"deeplTestNeedsTesting": {
"message": "⚠️ DeepL API 키 테스트가 필요합니다."
},
-
- "cardProviderDelayTitle": { "message": "제공업체별 요청 지연" },
+ "cardProviderDelayTitle": {
+ "message": "제공업체별 요청 지연"
+ },
"cardProviderDelayDesc": {
"message": "계정 잠금을 방지하기 위해 번역 요청 간의 필수 지연을 구성합니다. 이러한 지연은 배치 처리가 활성화된 경우에도 적용됩니다."
},
- "openaieDelayLabel": { "message": "OpenAI 요청 지연 (ms):" },
+ "openaieDelayLabel": {
+ "message": "OpenAI 요청 지연 (ms):"
+ },
"openaieDelayHelp": {
"message": "요청 간 최소 지연 (기본값: 100ms)"
},
- "googleDelayLabel": { "message": "Google 번역 요청 지연 (ms):" },
+ "googleDelayLabel": {
+ "message": "Google 번역 요청 지연 (ms):"
+ },
"googleDelayHelp": {
"message": "임시 잠금을 방지하기 위한 필수 지연 (기본값: 1500ms)"
},
- "deeplDelayLabel": { "message": "DeepL API 요청 지연 (ms):" },
+ "deeplDelayLabel": {
+ "message": "DeepL API 요청 지연 (ms):"
+ },
"deeplDelayHelp": {
"message": "DeepL API 요청 지연 (기본값: 500ms)"
},
- "deeplFreeDelayLabel": { "message": "DeepL 무료 요청 지연 (ms):" },
+ "deeplFreeDelayLabel": {
+ "message": "DeepL 무료 요청 지연 (ms):"
+ },
"deeplFreeDelayHelp": {
"message": "무료 계층을 위한 보수적 지연 (기본값: 2000ms)"
},
- "microsoftDelayLabel": { "message": "Microsoft 번역 요청 지연 (ms):" },
+ "microsoftDelayLabel": {
+ "message": "Microsoft 번역 요청 지연 (ms):"
+ },
"microsoftDelayHelp": {
"message": "문자 제한을 준수하기 위한 지연 (기본값: 800ms)"
},
- "vertexDelayLabel": { "message": "Vertex AI 요청 지연 (ms):" },
+ "vertexDelayLabel": {
+ "message": "Vertex AI 요청 지연 (ms):"
+ },
"vertexDelayHelp": {
"message": "요청 사이의 최소 지연 (기본값: 100ms)"
},
-
- "aiContextModalTitle": { "message": "AI 컨텍스트 분석" },
- "aiContextSelectedWords": { "message": "선택된 단어" },
- "aiContextNoWordsSelected": { "message": "선택된 단어가 없습니다" },
+ "aiContextModalTitle": {
+ "message": "AI 컨텍스트 분석"
+ },
+ "aiContextSelectedWords": {
+ "message": "선택된 단어"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "선택된 단어가 없습니다"
+ },
"aiContextClickHint": {
"message": "💡 단어를 클릭하여 추가하거나 제거하세요."
},
- "aiContextStartAnalysis": { "message": "분석 시작" },
- "aiContextPauseAnalysis": { "message": "⏸ 일시정지" },
- "aiContextPauseAnalysisTitle": { "message": "분석 일시정지" },
+ "aiContextStartAnalysis": {
+ "message": "분석 시작"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ 일시정지"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "분석 일시정지"
+ },
"aiContextInitialMessage": {
"message": "자막에서 단어를 선택하여 분석을 시작하세요."
},
- "aiContextAnalyzing": { "message": "컨텍스트 분석 중..." },
- "aiContextPauseNote": { "message": "⏸ 를 클릭하여 분석 일시정지" },
- "aiContextAnalysisFailed": { "message": "분석 실패" },
- "aiContextNoContent": { "message": "분석 콘텐츠 없음" },
+ "aiContextAnalyzing": {
+ "message": "컨텍스트 분석 중..."
+ },
+ "aiContextPauseNote": {
+ "message": "⏸ 를 클릭하여 분석 일시정지"
+ },
+ "aiContextAnalysisFailed": {
+ "message": "분석 실패"
+ },
+ "aiContextNoContent": {
+ "message": "분석 콘텐츠 없음"
+ },
"aiContextNoContentMessage": {
"message": "분석이 완료되었지만 콘텐츠가 반환되지 않았습니다."
},
- "aiContextDefinition": { "message": "📖 정의" },
- "aiContextCultural": { "message": "🌍 문화적 맥락" },
- "aiContextCulturalSignificance": { "message": "⭐ 문화적 의미" },
- "aiContextHistorical": { "message": "📜 역사적 맥락" },
- "aiContextHistoricalSignificance": { "message": "📜 역사적 의미" },
- "aiContextEvolution": { "message": "🔄 시대별 변화" },
- "aiContextLinguistic": { "message": "🔤 언어학적 분석" },
- "aiContextGrammar": { "message": "📝 문법 및 의미론" },
- "aiContextUsage": { "message": "💡 사용법 및 예시" },
- "aiContextExamples": { "message": "예시:" },
- "aiContextLearningTips": { "message": "🎯 학습 팁" },
- "aiContextRelatedExpressions": { "message": "🔗 관련 표현" },
- "aiContextKeyInsights": { "message": "🔑 핵심 통찰" },
- "aiContextTypeCultural": { "message": "문화적" },
- "aiContextTypeHistorical": { "message": "역사적" },
- "aiContextTypeLinguistic": { "message": "언어학적" },
- "aiContextTypeComprehensive": { "message": "포괄적" },
- "aiContextTypeGeneric": { "message": "맥락" },
- "aiContextClose": { "message": "닫기" },
- "aiContextAnalysisResults": { "message": "분석 결과" },
- "aiContextRetrying": { "message": "분석 실패, 재생성 중..." },
- "aiContextRetryNotification": { "message": "분석 실패, 재시도 중..." },
- "aiContextRetryButton": { "message": "다시 시도" },
+ "aiContextDefinition": {
+ "message": "📖 정의"
+ },
+ "aiContextCultural": {
+ "message": "🌍 문화적 맥락"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ 문화적 의미"
+ },
+ "aiContextHistorical": {
+ "message": "📜 역사적 맥락"
+ },
+ "aiContextHistoricalSignificance": {
+ "message": "📜 역사적 의미"
+ },
+ "aiContextEvolution": {
+ "message": "🔄 시대별 변화"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 언어학적 분석"
+ },
+ "aiContextGrammar": {
+ "message": "📝 문법 및 의미론"
+ },
+ "aiContextUsage": {
+ "message": "💡 사용법 및 예시"
+ },
+ "aiContextExamples": {
+ "message": "예시:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 학습 팁"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 관련 표현"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 핵심 통찰"
+ },
+ "aiContextTypeCultural": {
+ "message": "문화적"
+ },
+ "aiContextTypeHistorical": {
+ "message": "역사적"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "언어학적"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "포괄적"
+ },
+ "aiContextTypeGeneric": {
+ "message": "맥락"
+ },
+ "aiContextClose": {
+ "message": "닫기"
+ },
+ "aiContextAnalysisResults": {
+ "message": "분석 결과"
+ },
+ "aiContextRetrying": {
+ "message": "분석 실패, 재생성 중..."
+ },
+ "aiContextRetryNotification": {
+ "message": "분석 실패, 재시도 중..."
+ },
+ "aiContextRetryButton": {
+ "message": "다시 시도"
+ },
"aiContextMalformedResponse": {
"message": "AI 서비스가 잘못된 응답 형식을 반환했습니다. 이는 일시적인 서비스 문제로 인한 것일 수 있습니다."
},
"aiContextJsonCodeBlock": {
"message": "AI 서비스가 구조화된 데이터 대신 처리되지 않은 JSON 코드를 반환했습니다. 이는 응답의 형식 오류를 나타냅니다."
},
- "aiContextCulturalContext": { "message": "문화적 맥락:" },
- "aiContextSocialUsage": { "message": "사회적 용법:" },
- "aiContextRegionalNotes": { "message": "지역적 특징:" },
- "aiContextOrigins": { "message": "어원:" },
- "aiContextHistoricalContext": { "message": "역사적 배경:" },
- "aiContextHistoricalSignificance": { "message": "역사적 의미:" },
- "aiContextEvolution": { "message": "변화 과정:" },
- "aiContextEtymology": { "message": "어원학:" },
- "aiContextGrammarNotes": { "message": "문법 주석:" },
- "aiContextTranslationNotes": { "message": "번역 주석:" },
- "aiContextLinguisticAnalysis": { "message": "언어학적 분석:" },
- "aiContextGrammarSemantics": { "message": "문법과 의미론:" },
- "aiContextUsageExamples": { "message": "용법과 예시:" },
- "aiContextLearningTips": { "message": "학습 팁:" },
- "aiContextRelatedExpressions": { "message": "관련 표현:" },
- "aiContextKeyInsights": { "message": "핵심 통찰:" },
-
- "navAIContext": { "message": "AI 컨텍스트" },
- "sectionAIContext": { "message": "AI 컨텍스트 어시스턴트" },
- "cardAIContextToggleTitle": { "message": "AI 컨텍스트 분석 활성화" },
+ "aiContextCulturalContext": {
+ "message": "문화적 맥락:"
+ },
+ "aiContextSocialUsage": {
+ "message": "사회적 용법:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "지역적 특징:"
+ },
+ "aiContextOrigins": {
+ "message": "어원:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "역사적 배경:"
+ },
+ "aiContextHistoricalSignificanceLabel": {
+ "message": "역사적 의미:"
+ },
+ "aiContextEvolutionLabel": {
+ "message": "변화 과정:"
+ },
+ "aiContextEtymology": {
+ "message": "어원학:"
+ },
+ "aiContextGrammarNotesLabel": {
+ "message": "문법 주석:"
+ },
+ "aiContextTranslationNotesLabel": {
+ "message": "번역 주석:"
+ },
+ "aiContextLinguisticAnalysisLabel": {
+ "message": "언어학적 분석:"
+ },
+ "aiContextGrammarSemanticsLabel": {
+ "message": "문법과 의미론:"
+ },
+ "aiContextUsageExamplesLabel": {
+ "message": "용법과 예시:"
+ },
+ "aiContextLearningTipsLabel": {
+ "message": "학습 팁:"
+ },
+ "aiContextRelatedExpressionsLabel": {
+ "message": "관련 표현:"
+ },
+ "aiContextKeyInsightsLabel": {
+ "message": "핵심 통찰:"
+ },
+ "navAIContext": {
+ "message": "AI 컨텍스트"
+ },
+ "sectionAIContext": {
+ "message": "AI 컨텍스트 어시스턴트"
+ },
+ "cardAIContextToggleTitle": {
+ "message": "AI 컨텍스트 분석 활성화"
+ },
"cardAIContextToggleDesc": {
"message": "자막 텍스트에 대한 AI 기반 문화적, 역사적, 언어학적 컨텍스트 분석을 활성화합니다. 자막의 단어나 구문을 클릭하여 자세한 설명을 얻을 수 있습니다."
},
- "aiContextEnabledLabel": { "message": "AI 컨텍스트 활성화:" },
- "cardAIContextProviderTitle": { "message": "AI 제공업체" },
+ "aiContextEnabledLabel": {
+ "message": "AI 컨텍스트 활성화:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "AI 제공업체"
+ },
"cardAIContextProviderDesc": {
"message": "컨텍스트 분석을 위한 AI 서비스 제공업체를 선택합니다. 제공업체에 따라 품질과 응답 시간이 다를 수 있습니다."
},
- "aiContextProviderLabel": { "message": "제공업체:" },
- "cardOpenAIContextTitle": { "message": "OpenAI 구성" },
+ "aiContextProviderLabel": {
+ "message": "제공업체:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "OpenAI 구성"
+ },
"cardOpenAIContextDesc": {
"message": "컨텍스트 분석을 위한 OpenAI API 설정을 구성합니다. 유효한 OpenAI API 키가 필요합니다."
},
- "openaiApiKeyLabel": { "message": "API 키:" },
- "openaiBaseUrlLabel": { "message": "기본 URL:" },
- "openaiModelLabel": { "message": "모델:" },
- "cardGeminiContextTitle": { "message": "Google Gemini 구성" },
+ "openaiApiKeyLabel": {
+ "message": "API 키:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "기본 URL:"
+ },
+ "openaiModelLabel": {
+ "message": "모델:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Google Gemini 구성"
+ },
"cardGeminiContextDesc": {
"message": "컨텍스트 분석을 위한 Google Gemini API 설정을 구성합니다. 유효한 Gemini API 키가 필요합니다."
},
- "geminiApiKeyLabel": { "message": "API 키:" },
- "geminiModelLabel": { "message": "모델:" },
- "cardAIContextTypesTitle": { "message": "컨텍스트 유형" },
+ "geminiApiKeyLabel": {
+ "message": "API 키:"
+ },
+ "geminiModelLabel": {
+ "message": "모델:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "컨텍스트 유형"
+ },
"cardAIContextTypesDesc": {
"message": "사용하려는 컨텍스트 분석 유형을 활성화합니다. 여러 유형을 활성화할 수 있습니다."
},
- "contextTypeCulturalLabel": { "message": "문화적 컨텍스트:" },
+ "contextTypeCulturalLabel": {
+ "message": "문화적 컨텍스트:"
+ },
"contextTypeCulturalHelp": {
"message": "문화적 참조, 관용구, 사회적 맥락 분석"
},
- "contextTypeHistoricalLabel": { "message": "역사적 컨텍스트:" },
+ "contextTypeHistoricalLabel": {
+ "message": "역사적 컨텍스트:"
+ },
"contextTypeHistoricalHelp": {
"message": "역사적 배경과 시대적 맥락 제공"
},
- "contextTypeLinguisticLabel": { "message": "언어학적 분석:" },
- "contextTypeLinguisticHelp": { "message": "문법, 어원, 언어 구조 설명" },
- "cardAIContextInteractiveTitle": { "message": "상호작용 기능" },
+ "contextTypeLinguisticLabel": {
+ "message": "언어학적 분석:"
+ },
+ "contextTypeLinguisticHelp": {
+ "message": "문법, 어원, 언어 구조 설명"
+ },
+ "cardAIContextInteractiveTitle": {
+ "message": "상호작용 기능"
+ },
"cardAIContextInteractiveDesc": {
"message": "컨텍스트 분석을 트리거하기 위해 자막과 상호작용하는 방법을 구성합니다."
},
- "interactiveSubtitlesEnabledLabel": { "message": "상호작용 자막 활성화:" },
+ "interactiveSubtitlesEnabledLabel": {
+ "message": "상호작용 자막 활성화:"
+ },
"interactiveSubtitlesEnabledHelp": {
"message": "컨텍스트 분석을 위해 자막 단어를 클릭 가능하게 만들기"
},
- "contextOnClickLabel": { "message": "클릭 시 컨텍스트:" },
- "contextOnClickHelp": { "message": "단어를 클릭할 때 컨텍스트 분석 표시" },
- "contextOnSelectionLabel": { "message": "선택 시 컨텍스트:" },
+ "contextOnClickLabel": {
+ "message": "클릭 시 컨텍스트:"
+ },
+ "contextOnClickHelp": {
+ "message": "단어를 클릭할 때 컨텍스트 분석 표시"
+ },
+ "contextOnSelectionLabel": {
+ "message": "선택 시 컨텍스트:"
+ },
"contextOnSelectionHelp": {
"message": "텍스트를 선택할 때 컨텍스트 분석 표시"
},
- "cardAIContextPrivacyTitle": { "message": "개인정보 및 데이터" },
+ "cardAIContextPrivacyTitle": {
+ "message": "개인정보 및 데이터"
+ },
"cardAIContextPrivacyDesc": {
"message": "컨텍스트 분석 중 데이터 처리 방법을 제어합니다."
},
@@ -462,26 +926,103 @@
"aiContextUserConsentHelp": {
"message": "AI 컨텍스트 분석이 작동하기 위해 필요"
},
- "aiContextDataSharingLabel": { "message": "익명 사용 분석 허용:" },
+ "aiContextDataSharingLabel": {
+ "message": "익명 사용 분석 허용:"
+ },
"aiContextDataSharingHelp": {
"message": "익명 사용 데이터를 공유하여 서비스 개선에 도움"
},
- "cardAIContextAdvancedTitle": { "message": "고급 설정" },
+ "cardAIContextAdvancedTitle": {
+ "message": "고급 설정"
+ },
"cardAIContextAdvancedDesc": {
"message": "AI 컨텍스트 분석 동작에 대한 고급 옵션을 구성합니다."
},
- "aiContextTimeoutLabel": { "message": "요청 타임아웃 (ms):" },
- "aiContextTimeoutHelp": { "message": "AI 응답을 기다리는 최대 시간" },
- "aiContextRateLimitLabel": { "message": "속도 제한 (요청/분):" },
- "aiContextRateLimitHelp": { "message": "분당 최대 요청 수" },
- "aiContextCacheEnabledLabel": { "message": "캐싱 활성화:" },
+ "aiContextTimeoutLabel": {
+ "message": "요청 타임아웃 (ms):"
+ },
+ "aiContextTimeoutHelp": {
+ "message": "AI 응답을 기다리는 최대 시간"
+ },
+ "aiContextRateLimitLabel": {
+ "message": "속도 제한 (요청/분):"
+ },
+ "aiContextRateLimitHelp": {
+ "message": "분당 최대 요청 수"
+ },
+ "aiContextCacheEnabledLabel": {
+ "message": "캐싱 활성화:"
+ },
"aiContextCacheEnabledHelp": {
"message": "API 호출을 줄이기 위해 분석 결과 캐시"
},
- "aiContextRetryAttemptsLabel": { "message": "재시도 횟수:" },
+ "aiContextRetryAttemptsLabel": {
+ "message": "재시도 횟수:"
+ },
"aiContextRetryAttemptsHelp": {
"message": "실패한 요청을 재시도하는 횟수"
},
- "showAdvancedSettings": { "message": "고급 설정 표시" },
- "hideAdvancedSettings": { "message": "고급 설정 숨기기" }
-}
+ "showAdvancedSettings": {
+ "message": "고급 설정 표시"
+ },
+ "hideAdvancedSettings": {
+ "message": "고급 설정 숨기기"
+ },
+ "sidepanelLoading": {
+ "message": "로딩 중..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "AI 분석"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "단어장"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "분석"
+ },
+ "sidepanelAnalyzing": {
+ "message": "분석 중..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "분석할 단어"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "자막의 단어를 클릭하여 분석에 추가하세요..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "재시도"
+ },
+ "sidepanelResultsTitle": {
+ "message": "\"%s\"에 대한 결과"
+ },
+ "sidepanelSectionDefinition": {
+ "message": "정의"
+ },
+ "sidepanelSectionCultural": {
+ "message": "문화적 맥락"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "역사적 맥락"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "언어학적 분석"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "내 단어"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "단어장 기능이 곧 제공됩니다!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "이 기능은 현재 개발 중입니다. 설정에서 활성화하여 미리보기를 사용해보세요."
+ },
+ "sidepanelErrorNoWords": {
+ "message": "분석할 단어가 선택되지 않았습니다"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "AI 컨텍스트 분석이 비활성화되어 있습니다. 설정에서 활성화하세요."
+ },
+ "sidepanelErrorGeneric": {
+ "message": "분석 중 오류가 발생했습니다."
+ }
+}
\ No newline at end of file
diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json
index 61c8a50..67b5b03 100644
--- a/_locales/zh_CN/messages.json
+++ b/_locales/zh_CN/messages.json
@@ -1,400 +1,883 @@
{
- "appName": { "message": "DualSub" },
- "appDesc": { "message": "在流媒体平台上显示双语字幕。" },
- "pageTitle": { "message": "DualSub 设置" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "启用双语字幕:" },
- "useNativeSubtitlesLabel": { "message": "使用官方字幕:" },
- "originalLanguageLabel": { "message": "原始语言:" },
- "translationSettingsLegend": { "message": "翻译设置" },
- "providerLabel": { "message": "提供商:" },
- "targetLanguageLabel": { "message": "翻译为:" },
- "batchSizeLabel": { "message": "批量大小:" },
- "requestDelayLabel": { "message": "请求延迟 (ms):" },
- "subtitleAppearanceTimingLegend": { "message": "字幕外观和时序" },
- "displayOrderLabel": { "message": "显示顺序:" },
- "layoutLabel": { "message": "布局:" },
- "fontSizeLabel": { "message": "字体大小:" },
- "verticalGapLabel": { "message": "垂直间距:" },
- "subtitleVerticalPositionLabel": { "message": "垂直位置:" },
- "timeOffsetLabel": { "message": "时间偏移(秒):" },
- "displayOrderOriginalFirst": { "message": "原文在上" },
- "displayOrderTranslationFirst": { "message": "译文在上" },
- "layoutTopBottom": { "message": "上下排列" },
- "layoutLeftRight": { "message": "左右排列" },
- "uiLanguageLabel": { "message": "语言:" },
- "openOptionsButton": { "message": "高级设置" },
- "statusLanguageSetTo": { "message": "刷新页面后生效:" },
- "statusDualEnabled": { "message": "双语字幕已启用。(刷新页面)" },
- "statusDualDisabled": { "message": "双语字幕已禁用。(刷新页面)" },
+ "appName": {
+ "message": "DualSub"
+ },
+ "appDesc": {
+ "message": "在流媒体平台上显示双语字幕。"
+ },
+ "pageTitle": {
+ "message": "DualSub 设置"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "启用双语字幕:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "使用官方字幕:"
+ },
+ "originalLanguageLabel": {
+ "message": "原始语言:"
+ },
+ "translationSettingsLegend": {
+ "message": "翻译设置"
+ },
+ "providerLabel": {
+ "message": "提供商:"
+ },
+ "targetLanguageLabel": {
+ "message": "翻译为:"
+ },
+ "batchSizeLabel": {
+ "message": "批量大小:"
+ },
+ "requestDelayLabel": {
+ "message": "请求延迟 (ms):"
+ },
+ "subtitleAppearanceTimingLegend": {
+ "message": "字幕外观和时序"
+ },
+ "displayOrderLabel": {
+ "message": "显示顺序:"
+ },
+ "layoutLabel": {
+ "message": "布局:"
+ },
+ "fontSizeLabel": {
+ "message": "字体大小:"
+ },
+ "verticalGapLabel": {
+ "message": "垂直间距:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "垂直位置:"
+ },
+ "timeOffsetLabel": {
+ "message": "时间偏移(秒):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "原文在上"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "译文在上"
+ },
+ "layoutTopBottom": {
+ "message": "上下排列"
+ },
+ "layoutLeftRight": {
+ "message": "左右排列"
+ },
+ "uiLanguageLabel": {
+ "message": "语言:"
+ },
+ "openOptionsButton": {
+ "message": "高级设置"
+ },
+ "statusLanguageSetTo": {
+ "message": "刷新页面后生效:"
+ },
+ "statusDualEnabled": {
+ "message": "双语字幕已启用。(刷新页面)"
+ },
+ "statusDualDisabled": {
+ "message": "双语字幕已禁用。(刷新页面)"
+ },
"statusSmartTranslationEnabled": {
"message": "智能翻译已启用。(刷新页面)"
},
"statusSmartTranslationDisabled": {
"message": "智能翻译已禁用。(刷新页面)"
},
- "statusOriginalLanguage": { "message": "刷新页面后生效:" },
- "statusTimeOffset": { "message": "时间偏移:" },
- "statusDisplayOrderUpdated": { "message": "显示顺序已更新。" },
- "statusLayoutOrientationUpdated": { "message": "布局方向已更新。" },
- "statusFontSize": { "message": "字体大小:" },
- "statusVerticalGap": { "message": "垂直间距:" },
- "statusVerticalPosition": { "message": "垂直位置:" },
- "statusInvalidOffset": { "message": "无效偏移,已还原。" },
- "statusSettingNotApplied": { "message": "设置未应用。请刷新页面。" },
-
- "optionsPageTitle": { "message": "DualSub 选项" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "常规" },
- "navTranslation": { "message": "翻译" },
- "navProviders": { "message": "提供商" },
- "navAbout": { "message": "关于" },
- "sectionGeneral": { "message": "常规" },
- "cardUILanguageTitle": { "message": "界面语言" },
- "cardUILanguageDesc": { "message": "选择扩展界面的显示语言。" },
- "cardHideOfficialSubtitlesTitle": { "message": "隐藏官方字幕" },
+ "statusOriginalLanguage": {
+ "message": "刷新页面后生效:"
+ },
+ "statusTimeOffset": {
+ "message": "时间偏移:"
+ },
+ "statusDisplayOrderUpdated": {
+ "message": "显示顺序已更新。"
+ },
+ "statusLayoutOrientationUpdated": {
+ "message": "布局方向已更新。"
+ },
+ "statusFontSize": {
+ "message": "字体大小:"
+ },
+ "statusVerticalGap": {
+ "message": "垂直间距:"
+ },
+ "statusVerticalPosition": {
+ "message": "垂直位置:"
+ },
+ "statusInvalidOffset": {
+ "message": "无效偏移,已还原。"
+ },
+ "statusSettingNotApplied": {
+ "message": "设置未应用。请刷新页面。"
+ },
+ "optionsPageTitle": {
+ "message": "DualSub 选项"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "常规"
+ },
+ "navTranslation": {
+ "message": "翻译"
+ },
+ "navProviders": {
+ "message": "提供商"
+ },
+ "navAbout": {
+ "message": "关于"
+ },
+ "sectionGeneral": {
+ "message": "常规"
+ },
+ "cardUILanguageTitle": {
+ "message": "界面语言"
+ },
+ "cardUILanguageDesc": {
+ "message": "选择扩展界面的显示语言。"
+ },
+ "cardHideOfficialSubtitlesTitle": {
+ "message": "隐藏官方字幕"
+ },
"cardHideOfficialSubtitlesDesc": {
"message": "当 DualSub 激活时,隐藏视频平台的官方字幕。"
},
- "hideOfficialSubtitlesLabel": { "message": "隐藏官方字幕:" },
- "sectionTranslation": { "message": "翻译" },
- "cardTranslationEngineTitle": { "message": "翻译引擎" },
- "cardTranslationEngineDesc": { "message": "选择您喜欢的翻译服务。" },
- "cardPerformanceTitle": { "message": "性能" },
+ "hideOfficialSubtitlesLabel": {
+ "message": "隐藏官方字幕:"
+ },
+ "sectionTranslation": {
+ "message": "翻译"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "翻译引擎"
+ },
+ "cardTranslationEngineDesc": {
+ "message": "选择您喜欢的翻译服务。"
+ },
+ "cardPerformanceTitle": {
+ "message": "性能"
+ },
"cardPerformanceDesc": {
"message": "调整扩展处理翻译请求的方式,以平衡速度和稳定性。"
},
- "sectionProviders": { "message": "提供商设置" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "提供商设置"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "输入您的 DeepL 翻译 API 密钥。选择免费或专业版计划。"
},
- "apiKeyLabel": { "message": "API 密钥:" },
- "apiPlanLabel": { "message": "API 计划:" },
- "apiPlanFree": { "message": "DeepL API 免费版" },
- "apiPlanPro": { "message": "DeepL API 专业版" },
- "sectionAbout": { "message": "关于" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "版本" },
+ "apiKeyLabel": {
+ "message": "API 密钥:"
+ },
+ "apiPlanLabel": {
+ "message": "API 计划:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API 免费版"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API 专业版"
+ },
+ "sectionAbout": {
+ "message": "关于"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "版本"
+ },
"aboutDescription": {
"message": "此扩展帮助您在各种平台上观看双语字幕视频。"
},
- "aboutDevelopment": { "message": "由 QuellaMC & 1jifang 开发。" },
-
- "lang_en": { "message": "英语" },
- "lang_es": { "message": "西班牙语" },
- "lang_fr": { "message": "法语" },
- "lang_de": { "message": "德语" },
- "lang_it": { "message": "意大利语" },
- "lang_pt": { "message": "葡萄牙语" },
- "lang_ja": { "message": "日语" },
- "lang_ko": { "message": "韩语" },
- "lang_zh_CN": { "message": "中文 (简体)" },
- "lang_zh_TW": { "message": "中文 (繁体)" },
- "lang_ru": { "message": "俄语" },
- "lang_ar": { "message": "阿拉伯语" },
- "lang_hi": { "message": "印地语" },
-
- "testDeepLButton": { "message": "测试 DeepL 连接" },
- "deeplApiKeyError": { "message": "请先输入您的 DeepL API 密钥。" },
- "testingButton": { "message": "测试中..." },
- "testingConnection": { "message": "正在测试 DeepL 连接..." },
+ "aboutDevelopment": {
+ "message": "由 QuellaMC & 1jifang 开发。"
+ },
+ "lang_en": {
+ "message": "英语"
+ },
+ "lang_es": {
+ "message": "西班牙语"
+ },
+ "lang_fr": {
+ "message": "法语"
+ },
+ "lang_de": {
+ "message": "德语"
+ },
+ "lang_it": {
+ "message": "意大利语"
+ },
+ "lang_pt": {
+ "message": "葡萄牙语"
+ },
+ "lang_ja": {
+ "message": "日语"
+ },
+ "lang_ko": {
+ "message": "韩语"
+ },
+ "lang_zh_CN": {
+ "message": "中文 (简体)"
+ },
+ "lang_zh_TW": {
+ "message": "中文 (繁体)"
+ },
+ "lang_ru": {
+ "message": "俄语"
+ },
+ "lang_ar": {
+ "message": "阿拉伯语"
+ },
+ "lang_hi": {
+ "message": "印地语"
+ },
+ "testDeepLButton": {
+ "message": "测试 DeepL 连接"
+ },
+ "deeplApiKeyError": {
+ "message": "请先输入您的 DeepL API 密钥。"
+ },
+ "testingButton": {
+ "message": "测试中..."
+ },
+ "testingConnection": {
+ "message": "正在测试 DeepL 连接..."
+ },
"deeplTestSuccess": {
"message": "✅ DeepL API 测试成功"
},
- "deeplTestUnexpectedFormat": { "message": "⚠️ DeepL API 响应但格式异常" },
- "deeplTestInvalidKey": { "message": "❌ DeepL API 密钥无效或被拒绝。" },
+ "deeplTestUnexpectedFormat": {
+ "message": "⚠️ DeepL API 响应但格式异常"
+ },
+ "deeplTestInvalidKey": {
+ "message": "❌ DeepL API 密钥无效或被拒绝。"
+ },
"deeplTestQuotaExceeded": {
"message": "❌ DeepL API 配额已超限。请检查您的使用限制。"
},
- "deeplTestApiError": { "message": "❌ DeepL API 错误 (%d):%s" },
+ "deeplTestApiError": {
+ "message": "❌ DeepL API 错误 (%d):%s"
+ },
"deeplTestNetworkError": {
"message": "❌ 网络错误:无法连接到 DeepL API。请检查您的网络连接。"
},
- "deeplTestGenericError": { "message": "❌ 测试失败:%s" },
- "deepLApiUnavailable": { "message": "DeepL API 不可用" },
- "deepLApiUnavailableTooltip": { "message": "DeepL API 脚本加载失败" },
+ "deeplTestGenericError": {
+ "message": "❌ 测试失败:%s"
+ },
+ "deepLApiUnavailable": {
+ "message": "DeepL API 不可用"
+ },
+ "deepLApiUnavailableTooltip": {
+ "message": "DeepL API 脚本加载失败"
+ },
"deeplApiNotLoadedError": {
"message": "❌ DeepL API 脚本不可用。请刷新页面。"
},
-
- "cardGoogleTitle": { "message": "谷歌翻译" },
- "cardGoogleDesc": { "message": "由谷歌提供的免费翻译服务。无需额外配置。" },
- "cardMicrosoftTitle": { "message": "微软翻译" },
+ "cardGoogleTitle": {
+ "message": "谷歌翻译"
+ },
+ "cardGoogleDesc": {
+ "message": "由谷歌提供的免费翻译服务。无需额外配置。"
+ },
+ "cardMicrosoftTitle": {
+ "message": "微软翻译"
+ },
"cardMicrosoftDesc": {
"message": "由微软 Edge 提供的免费翻译服务。无需额外配置。"
},
- "cardDeepLFreeTitle": { "message": "DeepL 翻译(免费)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL 翻译(免费)"
+ },
"cardDeepLFreeDesc": {
"message": "免费的 DeepL 翻译服务,提供高质量的翻译结果。无需 API 密钥 - 使用 DeepL 的网页接口。"
},
- "providerStatus": { "message": "状态:" },
- "statusReady": { "message": "可以使用" },
- "providerFeatures": { "message": "特性:" },
- "featureFree": { "message": "免费使用" },
- "featureNoApiKey": { "message": "无需 API 密钥" },
- "featureWideLanguageSupport": { "message": "广泛的语言支持" },
- "featureFastTranslation": { "message": "快速翻译" },
- "featureHighQuality": { "message": "高质量翻译" },
- "featureGoodPerformance": { "message": "良好的性能" },
- "featureHighestQuality": { "message": "最高质量翻译" },
- "featureApiKeyRequired": { "message": "需要 API 密钥" },
- "featureLimitedLanguages": { "message": "有限的语言支持" },
- "featureUsageLimits": { "message": "使用限制适用" },
- "featureMultipleBackups": { "message": "多种备用方法" },
-
- "providerNotes": { "message": "注意事项:" },
- "noteSlowForSecurity": { "message": "由于安全措施,速度稍慢" },
- "noteAutoFallback": { "message": "自动回退到其他服务" },
- "noteRecommendedDefault": { "message": "推荐作为默认提供商" },
-
- "providerGoogleName": { "message": "谷歌翻译(免费)" },
- "providerMicrosoftName": { "message": "微软翻译(免费)" },
- "providerDeepLName": { "message": "DeepL(需要 API 密钥)" },
- "providerDeepLFreeName": { "message": "DeepL 翻译(免费)" },
+ "providerStatus": {
+ "message": "状态:"
+ },
+ "statusReady": {
+ "message": "可以使用"
+ },
+ "providerFeatures": {
+ "message": "特性:"
+ },
+ "featureFree": {
+ "message": "免费使用"
+ },
+ "featureNoApiKey": {
+ "message": "无需 API 密钥"
+ },
+ "featureWideLanguageSupport": {
+ "message": "广泛的语言支持"
+ },
+ "featureFastTranslation": {
+ "message": "快速翻译"
+ },
+ "featureHighQuality": {
+ "message": "高质量翻译"
+ },
+ "featureGoodPerformance": {
+ "message": "良好的性能"
+ },
+ "featureHighestQuality": {
+ "message": "最高质量翻译"
+ },
+ "featureApiKeyRequired": {
+ "message": "需要 API 密钥"
+ },
+ "featureLimitedLanguages": {
+ "message": "有限的语言支持"
+ },
+ "featureUsageLimits": {
+ "message": "使用限制适用"
+ },
+ "featureMultipleBackups": {
+ "message": "多种备用方法"
+ },
+ "providerNotes": {
+ "message": "注意事项:"
+ },
+ "noteSlowForSecurity": {
+ "message": "由于安全措施,速度稍慢"
+ },
+ "noteAutoFallback": {
+ "message": "自动回退到其他服务"
+ },
+ "noteRecommendedDefault": {
+ "message": "推荐作为默认提供商"
+ },
+ "providerGoogleName": {
+ "message": "谷歌翻译(免费)"
+ },
+ "providerMicrosoftName": {
+ "message": "微软翻译(免费)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL(需要 API 密钥)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL 翻译(免费)"
+ },
"providerOpenAICompatibleName": {
"message": "OpenAI 兼容(需要 API 密钥)"
},
"providerVertexGeminiName": {
"message": "Vertex AI Gemini(需要 API 密钥)"
},
- "cardOpenAICompatibleTitle": { "message": "OpenAI 兼容(需要 API 密钥)" },
+ "cardOpenAICompatibleTitle": {
+ "message": "OpenAI 兼容(需要 API 密钥)"
+ },
"cardOpenAICompatibleDesc": {
"message": "输入您的 API 密钥和设置,用于 Gemini 等 OpenAI 兼容服务。"
},
- "cardVertexGeminiTitle": { "message": "Vertex AI Gemini(需要 API 密钥)" },
- "cardVertexGeminiDesc": { "message": "输入您的访问令牌和 Vertex 项目设置,或导入服务账号 JSON 文件。" },
- "vertexAccessTokenLabel": { "message": "访问令牌:" },
- "vertexProjectIdLabel": { "message": "项目 ID:" },
- "vertexLocationLabel": { "message": "位置:" },
- "vertexModelLabel": { "message": "模型:" },
- "vertexMissingConfig": { "message": "请输入访问令牌和项目 ID。" },
- "vertexConnectionFailed": { "message": "连接失败:%s" },
- "vertexServiceAccountLabel": { "message": "服务账号 JSON:" },
- "vertexImportButton": { "message": "导入 JSON 文件" },
- "vertexRefreshButton": { "message": "🔄 刷新令牌" },
- "vertexImportHint": { "message": "自动填充下方凭据" },
- "vertexImporting": { "message": "导入中..." },
- "vertexRefreshingToken": { "message": "正在刷新访问令牌..." },
- "vertexGeneratingToken": { "message": "正在生成访问令牌..." },
- "vertexImportSuccess": { "message": "服务账号已导入并生成令牌。" },
- "vertexImportFailed": { "message": "导入失败:%s" },
- "vertexTokenRefreshed": { "message": "访问令牌刷新成功。" },
- "vertexRefreshFailed": { "message": "令牌刷新失败:%s" },
- "vertexTokenExpired": { "message": "⚠️ 访问令牌已过期。点击刷新以续期。" },
- "vertexTokenExpiringSoon": { "message": "⚠️ 令牌将在 %s 分钟后过期。建议刷新。" },
- "vertexConfigured": { "message": "⚠️ Vertex AI 已配置。请测试连接。" },
- "vertexNotConfigured": { "message": "请导入服务账号 JSON 或输入凭据。" },
- "featureVertexServiceAccount": { "message": "服务账号 JSON 导入" },
- "featureVertexAutoToken": { "message": "自动生成令牌" },
- "featureVertexGemini": { "message": "通过 Vertex AI 使用 Google Gemini 模型" },
- "providerNote": { "message": "注意:" },
- "vertexNote": { "message": "访问令牌在 1 小时后过期。您的服务账号已安全存储,需要时只需点击刷新令牌按钮即可。" },
- "baseUrlLabel": { "message": "基础 URL:" },
- "modelLabel": { "message": "模型:" },
- "featureCustomizable": { "message": "可自定义端点和模型" },
- "fetchModelsButton": { "message": "获取模型" },
- "testConnectionButton": { "message": "测试连接" },
-
- "openaiApiKeyPlaceholder": { "message": "输入您的 OpenAI 兼容 API 密钥" },
+ "cardVertexGeminiTitle": {
+ "message": "Vertex AI Gemini(需要 API 密钥)"
+ },
+ "cardVertexGeminiDesc": {
+ "message": "输入您的访问令牌和 Vertex 项目设置,或导入服务账号 JSON 文件。"
+ },
+ "vertexAccessTokenLabel": {
+ "message": "访问令牌:"
+ },
+ "vertexProjectIdLabel": {
+ "message": "项目 ID:"
+ },
+ "vertexLocationLabel": {
+ "message": "位置:"
+ },
+ "vertexModelLabel": {
+ "message": "模型:"
+ },
+ "vertexMissingConfig": {
+ "message": "请输入访问令牌和项目 ID。"
+ },
+ "vertexConnectionFailed": {
+ "message": "连接失败:%s"
+ },
+ "vertexServiceAccountLabel": {
+ "message": "服务账号 JSON:"
+ },
+ "vertexImportButton": {
+ "message": "导入 JSON 文件"
+ },
+ "vertexRefreshButton": {
+ "message": "🔄 刷新令牌"
+ },
+ "vertexImportHint": {
+ "message": "自动填充下方凭据"
+ },
+ "vertexImporting": {
+ "message": "导入中..."
+ },
+ "vertexRefreshingToken": {
+ "message": "正在刷新访问令牌..."
+ },
+ "vertexGeneratingToken": {
+ "message": "正在生成访问令牌..."
+ },
+ "vertexImportSuccess": {
+ "message": "服务账号已导入并生成令牌。"
+ },
+ "vertexImportFailed": {
+ "message": "导入失败:%s"
+ },
+ "vertexTokenRefreshed": {
+ "message": "访问令牌刷新成功。"
+ },
+ "vertexRefreshFailed": {
+ "message": "令牌刷新失败:%s"
+ },
+ "vertexTokenExpired": {
+ "message": "⚠️ 访问令牌已过期。点击刷新以续期。"
+ },
+ "vertexTokenExpiringSoon": {
+ "message": "⚠️ 令牌将在 %s 分钟后过期。建议刷新。"
+ },
+ "vertexConfigured": {
+ "message": "⚠️ Vertex AI 已配置。请测试连接。"
+ },
+ "vertexNotConfigured": {
+ "message": "请导入服务账号 JSON 或输入凭据。"
+ },
+ "featureVertexServiceAccount": {
+ "message": "服务账号 JSON 导入"
+ },
+ "featureVertexAutoToken": {
+ "message": "自动生成令牌"
+ },
+ "featureVertexGemini": {
+ "message": "通过 Vertex AI 使用 Google Gemini 模型"
+ },
+ "providerNote": {
+ "message": "注意:"
+ },
+ "vertexNote": {
+ "message": "访问令牌在 1 小时后过期。您的服务账号已安全存储,需要时只需点击刷新令牌按钮即可。"
+ },
+ "baseUrlLabel": {
+ "message": "基础 URL:"
+ },
+ "modelLabel": {
+ "message": "模型:"
+ },
+ "featureCustomizable": {
+ "message": "可自定义端点和模型"
+ },
+ "fetchModelsButton": {
+ "message": "获取模型"
+ },
+ "testConnectionButton": {
+ "message": "测试连接"
+ },
+ "openaiApiKeyPlaceholder": {
+ "message": "输入您的 OpenAI 兼容 API 密钥"
+ },
"openaiBaseUrlPlaceholder": {
"message": "例如:https://api.openai.com/v1"
},
- "openaiApiKeyError": { "message": "请先输入您的 API 密钥。" },
- "openaiApiKeyNeedsTesting": { "message": "⚠️ API 密钥需要测试。" },
+ "openaiApiKeyError": {
+ "message": "请先输入您的 API 密钥。"
+ },
+ "openaiApiKeyNeedsTesting": {
+ "message": "⚠️ API 密钥需要测试。"
+ },
"openaiTestNeedsTesting": {
"message": "⚠️ OpenAI 兼容 API 密钥需要测试。"
},
- "openaiTestingConnection": { "message": "正在测试连接..." },
- "openaiConnectionSuccessful": { "message": "连接成功!" },
- "openaiConnectionFailed": { "message": "连接失败:%s" },
- "openaieFetchingModels": { "message": "正在获取模型..." },
- "openaiModelsFetchedSuccessfully": { "message": "模型获取成功。" },
- "openaiFailedToFetchModels": { "message": "获取模型失败:%s" },
-
- "cardLoggingLevelTitle": { "message": "日志级别" },
+ "openaiTestingConnection": {
+ "message": "正在测试连接..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "连接成功!"
+ },
+ "openaiConnectionFailed": {
+ "message": "连接失败:%s"
+ },
+ "openaieFetchingModels": {
+ "message": "正在获取模型..."
+ },
+ "openaiModelsFetchedSuccessfully": {
+ "message": "模型获取成功。"
+ },
+ "openaiFailedToFetchModels": {
+ "message": "获取模型失败:%s"
+ },
+ "cardLoggingLevelTitle": {
+ "message": "日志级别"
+ },
"cardLoggingLevelDesc": {
"message": "控制浏览器控制台中显示的调试信息量。较高级别包含所有较低级别的消息。"
},
- "loggingLevelLabel": { "message": "日志级别:" },
- "loggingLevelOff": { "message": "关闭" },
- "loggingLevelError": { "message": "仅错误" },
- "loggingLevelWarn": { "message": "警告和错误" },
- "loggingLevelInfo": { "message": "信息及以上" },
- "loggingLevelDebug": { "message": "调试(全部)" },
-
- "cardBatchTranslationTitle": { "message": "批量翻译" },
+ "loggingLevelLabel": {
+ "message": "日志级别:"
+ },
+ "loggingLevelOff": {
+ "message": "关闭"
+ },
+ "loggingLevelError": {
+ "message": "仅错误"
+ },
+ "loggingLevelWarn": {
+ "message": "警告和错误"
+ },
+ "loggingLevelInfo": {
+ "message": "信息及以上"
+ },
+ "loggingLevelDebug": {
+ "message": "调试(全部)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "批量翻译"
+ },
"cardBatchTranslationDesc": {
"message": "批量翻译将多个字幕片段一起处理,减少 80-90% 的 API 调用并提高性能。为您首选的翻译提供商配置最佳设置。"
},
- "batchingEnabledLabel": { "message": "启用批量翻译:" },
+ "batchingEnabledLabel": {
+ "message": "启用批量翻译:"
+ },
"batchingEnabledHelp": {
"message": "将多个字幕片段组合成单个翻译请求"
},
- "useProviderDefaultsLabel": { "message": "使用提供商优化设置:" },
+ "useProviderDefaultsLabel": {
+ "message": "使用提供商优化设置:"
+ },
"useProviderDefaultsHelp": {
"message": "自动为每个翻译提供商使用最佳批量大小"
},
- "globalBatchSizeLabel": { "message": "全局批量大小:" },
+ "globalBatchSizeLabel": {
+ "message": "全局批量大小:"
+ },
"globalBatchSizeHelp": {
"message": "一起处理的字幕片段数量(1-15)"
},
- "smartBatchingLabel": { "message": "智能批量优化:" },
+ "smartBatchingLabel": {
+ "message": "智能批量优化:"
+ },
"smartBatchingHelp": {
"message": "根据播放位置优先处理字幕片段"
},
- "maxConcurrentBatchesLabel": { "message": "最大并发批次:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "最大并发批次:"
+ },
"maxConcurrentBatchesHelp": {
"message": "同时处理的翻译批次数量"
},
-
- "cardProviderBatchTitle": { "message": "提供商特定批量大小" },
+ "cardProviderBatchTitle": {
+ "message": "提供商特定批量大小"
+ },
"cardProviderBatchDesc": {
"message": "为每个翻译提供商配置最佳批量大小。这些设置在启用\"使用提供商优化设置\"时使用。"
},
- "openaieBatchSizeLabel": { "message": "OpenAI 批量大小:" },
+ "openaieBatchSizeLabel": {
+ "message": "OpenAI 批量大小:"
+ },
"openaieBatchSizeHelp": {
"message": "推荐:5-10 个片段(默认:8)"
},
- "googleBatchSizeLabel": { "message": "谷歌翻译批量大小:" },
+ "googleBatchSizeLabel": {
+ "message": "谷歌翻译批量大小:"
+ },
"googleBatchSizeHelp": {
"message": "推荐:3-5 个片段(默认:4)"
},
- "deeplBatchSizeLabel": { "message": "DeepL 批量大小:" },
+ "deeplBatchSizeLabel": {
+ "message": "DeepL 批量大小:"
+ },
"deeplBatchSizeHelp": {
"message": "推荐:2-3 个片段(默认:3)"
},
- "microsoftBatchSizeLabel": { "message": "微软翻译批量大小:" },
+ "microsoftBatchSizeLabel": {
+ "message": "微软翻译批量大小:"
+ },
"microsoftBatchSizeHelp": {
"message": "推荐:3-5 个片段(默认:4)"
},
- "vertexBatchSizeLabel": { "message": "Vertex AI 批量大小:" },
+ "vertexBatchSizeLabel": {
+ "message": "Vertex AI 批量大小:"
+ },
"vertexBatchSizeHelp": {
"message": "推荐:5-10 个片段(默认:8)"
},
-
- "deeplTestNeedsTesting": { "message": "⚠️ DeepL API 密钥需要测试。" },
-
- "cardProviderDelayTitle": { "message": "提供商特定请求延迟" },
+ "deeplTestNeedsTesting": {
+ "message": "⚠️ DeepL API 密钥需要测试。"
+ },
+ "cardProviderDelayTitle": {
+ "message": "提供商特定请求延迟"
+ },
"cardProviderDelayDesc": {
"message": "配置翻译请求之间的强制延迟以防止账户锁定。即使启用批量处理,这些延迟也会应用。"
},
- "openaieDelayLabel": { "message": "OpenAI 请求延迟 (ms):" },
+ "openaieDelayLabel": {
+ "message": "OpenAI 请求延迟 (ms):"
+ },
"openaieDelayHelp": {
"message": "请求之间的最小延迟(默认:100ms)"
},
- "googleDelayLabel": { "message": "谷歌翻译请求延迟 (ms):" },
+ "googleDelayLabel": {
+ "message": "谷歌翻译请求延迟 (ms):"
+ },
"googleDelayHelp": {
"message": "防止临时锁定所需的延迟(默认:1500ms)"
},
- "deeplDelayLabel": { "message": "DeepL API 请求延迟 (ms):" },
+ "deeplDelayLabel": {
+ "message": "DeepL API 请求延迟 (ms):"
+ },
"deeplDelayHelp": {
"message": "DeepL API 请求的延迟(默认:500ms)"
},
- "deeplFreeDelayLabel": { "message": "DeepL 免费请求延迟 (ms):" },
+ "deeplFreeDelayLabel": {
+ "message": "DeepL 免费请求延迟 (ms):"
+ },
"deeplFreeDelayHelp": {
"message": "免费层的保守延迟(默认:2000ms)"
},
- "microsoftDelayLabel": { "message": "微软翻译请求延迟 (ms):" },
+ "microsoftDelayLabel": {
+ "message": "微软翻译请求延迟 (ms):"
+ },
"microsoftDelayHelp": {
"message": "尊重字符限制的延迟(默认:800ms)"
},
- "vertexDelayLabel": { "message": "Vertex AI 请求延迟 (ms):" },
+ "vertexDelayLabel": {
+ "message": "Vertex AI 请求延迟 (ms):"
+ },
"vertexDelayHelp": {
"message": "请求之间的最小延迟(默认:100ms)"
},
-
- "aiContextModalTitle": { "message": "AI 上下文分析" },
- "aiContextSelectedWords": { "message": "选中的词语" },
- "aiContextNoWordsSelected": { "message": "未选择词语" },
- "aiContextClickHint": { "message": "💡 点击词语来添加或移除。" },
- "aiContextStartAnalysis": { "message": "开始分析" },
- "aiContextPauseAnalysis": { "message": "⏸ 暂停" },
- "aiContextPauseAnalysisTitle": { "message": "暂停分析" },
- "aiContextInitialMessage": { "message": "从字幕中选择词语开始分析。" },
- "aiContextAnalyzing": { "message": "正在分析上下文..." },
- "aiContextPauseNote": { "message": "点击 ⏸ 暂停分析" },
- "aiContextAnalysisFailed": { "message": "分析失败" },
- "aiContextNoContent": { "message": "无分析内容" },
- "aiContextNoContentMessage": { "message": "分析已完成但未返回内容。" },
- "aiContextDefinition": { "message": "📖 定义" },
- "aiContextCultural": { "message": "🌍 文化背景" },
- "aiContextCulturalSignificance": { "message": "⭐ 文化意义" },
- "aiContextHistorical": { "message": "📜 历史背景" },
- "aiContextHistoricalSignificance": { "message": "📜 历史意义" },
- "aiContextEvolution": { "message": "🔄 历史演变" },
- "aiContextLinguistic": { "message": "🔤 语言学分析" },
- "aiContextGrammar": { "message": "📝 语法与语义" },
- "aiContextUsage": { "message": "💡 用法与例句" },
- "aiContextExamples": { "message": "例句:" },
- "aiContextLearningTips": { "message": "🎯 学习提示" },
- "aiContextRelatedExpressions": { "message": "🔗 相关表达" },
- "aiContextKeyInsights": { "message": "🔑 关键见解" },
- "aiContextTypeCultural": { "message": "文化" },
- "aiContextTypeHistorical": { "message": "历史" },
- "aiContextTypeLinguistic": { "message": "语言学" },
- "aiContextTypeComprehensive": { "message": "综合" },
- "aiContextTypeGeneric": { "message": "上下文" },
- "aiContextClose": { "message": "关闭" },
- "aiContextAnalysisResults": { "message": "分析结果" },
- "aiContextRetrying": { "message": "分析失败,正在重新生成..." },
- "aiContextRetryNotification": { "message": "分析失败,正在重试..." },
- "aiContextRetryButton": { "message": "重试" },
+ "aiContextModalTitle": {
+ "message": "AI 上下文分析"
+ },
+ "aiContextSelectedWords": {
+ "message": "选中的词语"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "未选择词语"
+ },
+ "aiContextClickHint": {
+ "message": "💡 点击词语来添加或移除。"
+ },
+ "aiContextStartAnalysis": {
+ "message": "开始分析"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ 暂停"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "暂停分析"
+ },
+ "aiContextInitialMessage": {
+ "message": "从字幕中选择词语开始分析。"
+ },
+ "aiContextAnalyzing": {
+ "message": "正在分析上下文..."
+ },
+ "aiContextPauseNote": {
+ "message": "点击 ⏸ 暂停分析"
+ },
+ "aiContextAnalysisFailed": {
+ "message": "分析失败"
+ },
+ "aiContextNoContent": {
+ "message": "无分析内容"
+ },
+ "aiContextNoContentMessage": {
+ "message": "分析已完成但未返回内容。"
+ },
+ "aiContextDefinition": {
+ "message": "📖 定义"
+ },
+ "aiContextCultural": {
+ "message": "🌍 文化背景"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ 文化意义"
+ },
+ "aiContextHistorical": {
+ "message": "📜 历史背景"
+ },
+ "aiContextHistoricalSignificance": {
+ "message": "📜 历史意义"
+ },
+ "aiContextEvolution": {
+ "message": "🔄 历史演变"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 语言学分析"
+ },
+ "aiContextGrammar": {
+ "message": "📝 语法与语义"
+ },
+ "aiContextUsage": {
+ "message": "💡 用法与例句"
+ },
+ "aiContextExamples": {
+ "message": "例句:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 学习提示"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 相关表达"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 关键见解"
+ },
+ "aiContextTypeCultural": {
+ "message": "文化"
+ },
+ "aiContextTypeHistorical": {
+ "message": "历史"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "语言学"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "综合"
+ },
+ "aiContextTypeGeneric": {
+ "message": "上下文"
+ },
+ "aiContextClose": {
+ "message": "关闭"
+ },
+ "aiContextAnalysisResults": {
+ "message": "分析结果"
+ },
+ "aiContextRetrying": {
+ "message": "分析失败,正在重新生成..."
+ },
+ "aiContextRetryNotification": {
+ "message": "分析失败,正在重试..."
+ },
+ "aiContextRetryButton": {
+ "message": "重试"
+ },
"aiContextMalformedResponse": {
"message": "AI 服务返回了无效的响应格式。这可能是由于临时服务问题。"
},
"aiContextJsonCodeBlock": {
"message": "AI 服务返回了未处理的 JSON 代码而不是结构化数据。这表明响应中存在格式错误。"
},
- "aiContextCulturalContext": { "message": "文化背景:" },
- "aiContextSocialUsage": { "message": "社会用法:" },
- "aiContextRegionalNotes": { "message": "地区特色:" },
- "aiContextOrigins": { "message": "词源:" },
- "aiContextHistoricalContext": { "message": "历史背景:" },
- "aiContextEtymology": { "message": "词源学:" },
- "aiContextGrammarNotes": { "message": "语法注释:" },
- "aiContextTranslationNotes": { "message": "翻译注释:" },
- "aiContextLinguisticAnalysis": { "message": "语言学分析:" },
- "aiContextGrammarSemantics": { "message": "语法与语义:" },
- "aiContextUsageExamples": { "message": "用法与例句:" },
-
- "navAIContext": { "message": "AI 上下文" },
- "sectionAIContext": { "message": "AI 上下文助手" },
- "cardAIContextToggleTitle": { "message": "启用 AI 上下文分析" },
+ "aiContextCulturalContext": {
+ "message": "文化背景:"
+ },
+ "aiContextSocialUsage": {
+ "message": "社会用法:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "地区特色:"
+ },
+ "aiContextOrigins": {
+ "message": "词源:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "历史背景:"
+ },
+ "aiContextEtymology": {
+ "message": "词源学:"
+ },
+ "aiContextGrammarNotes": {
+ "message": "语法注释:"
+ },
+ "aiContextTranslationNotes": {
+ "message": "翻译注释:"
+ },
+ "aiContextLinguisticAnalysis": {
+ "message": "语言学分析:"
+ },
+ "aiContextGrammarSemantics": {
+ "message": "语法与语义:"
+ },
+ "aiContextUsageExamples": {
+ "message": "用法与例句:"
+ },
+ "navAIContext": {
+ "message": "AI 上下文"
+ },
+ "sectionAIContext": {
+ "message": "AI 上下文助手"
+ },
+ "cardAIContextToggleTitle": {
+ "message": "启用 AI 上下文分析"
+ },
"cardAIContextToggleDesc": {
"message": "为字幕文本启用 AI 驱动的文化、历史和语言学上下文分析。点击字幕中的单词或短语以获得详细解释。"
},
- "aiContextEnabledLabel": { "message": "启用 AI 上下文:" },
- "cardAIContextProviderTitle": { "message": "AI 提供商" },
+ "aiContextEnabledLabel": {
+ "message": "启用 AI 上下文:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "AI 提供商"
+ },
"cardAIContextProviderDesc": {
"message": "选择用于上下文分析的 AI 服务提供商。不同的提供商可能提供不同的质量和响应时间。"
},
- "aiContextProviderLabel": { "message": "提供商:" },
- "cardOpenAIContextTitle": { "message": "OpenAI 配置" },
+ "aiContextProviderLabel": {
+ "message": "提供商:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "OpenAI 配置"
+ },
"cardOpenAIContextDesc": {
"message": "配置用于上下文分析的 OpenAI API 设置。您需要一个有效的 OpenAI API 密钥。"
},
- "openaiApiKeyLabel": { "message": "API 密钥:" },
- "openaiBaseUrlLabel": { "message": "基础 URL:" },
- "openaiModelLabel": { "message": "模型:" },
- "cardGeminiContextTitle": { "message": "Google Gemini 配置" },
+ "openaiApiKeyLabel": {
+ "message": "API 密钥:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "基础 URL:"
+ },
+ "openaiModelLabel": {
+ "message": "模型:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Google Gemini 配置"
+ },
"cardGeminiContextDesc": {
"message": "配置用于上下文分析的 Google Gemini API 设置。您需要一个有效的 Gemini API 密钥。"
},
- "geminiApiKeyLabel": { "message": "API 密钥:" },
- "geminiModelLabel": { "message": "模型:" },
- "cardAIContextTypesTitle": { "message": "上下文类型" },
+ "geminiApiKeyLabel": {
+ "message": "API 密钥:"
+ },
+ "geminiModelLabel": {
+ "message": "模型:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "上下文类型"
+ },
"cardAIContextTypesDesc": {
"message": "启用您想要使用的上下文分析类型。您可以启用多种类型。"
},
- "contextTypeCulturalLabel": { "message": "文化上下文:" },
- "contextTypeCulturalHelp": { "message": "分析文化参考、习语和社会背景" },
- "contextTypeHistoricalLabel": { "message": "历史上下文:" },
- "contextTypeHistoricalHelp": { "message": "提供历史背景和时代背景" },
- "contextTypeLinguisticLabel": { "message": "语言学分析:" },
- "contextTypeLinguisticHelp": { "message": "解释语法、词源和语言结构" },
-
- "cardAIContextPrivacyTitle": { "message": "隐私和数据" },
+ "contextTypeCulturalLabel": {
+ "message": "文化上下文:"
+ },
+ "contextTypeCulturalHelp": {
+ "message": "分析文化参考、习语和社会背景"
+ },
+ "contextTypeHistoricalLabel": {
+ "message": "历史上下文:"
+ },
+ "contextTypeHistoricalHelp": {
+ "message": "提供历史背景和时代背景"
+ },
+ "contextTypeLinguisticLabel": {
+ "message": "语言学分析:"
+ },
+ "contextTypeLinguisticHelp": {
+ "message": "解释语法、词源和语言结构"
+ },
+ "cardAIContextPrivacyTitle": {
+ "message": "隐私和数据"
+ },
"cardAIContextPrivacyDesc": {
"message": "控制在上下文分析期间如何处理您的数据。"
},
@@ -404,22 +887,103 @@
"aiContextUserConsentHelp": {
"message": "AI 上下文分析功能正常运行所必需"
},
- "aiContextDataSharingLabel": { "message": "允许匿名使用分析:" },
+ "aiContextDataSharingLabel": {
+ "message": "允许匿名使用分析:"
+ },
"aiContextDataSharingHelp": {
"message": "通过分享匿名使用数据帮助改进服务"
},
- "cardAIContextAdvancedTitle": { "message": "高级设置" },
+ "cardAIContextAdvancedTitle": {
+ "message": "高级设置"
+ },
"cardAIContextAdvancedDesc": {
"message": "配置 AI 上下文分析行为的高级选项。"
},
- "aiContextTimeoutLabel": { "message": "请求超时 (ms):" },
- "aiContextTimeoutHelp": { "message": "等待 AI 响应的最长时间" },
- "aiContextRateLimitLabel": { "message": "速率限制 (请求/分钟):" },
- "aiContextRateLimitHelp": { "message": "每分钟最大请求数" },
- "aiContextCacheEnabledLabel": { "message": "启用缓存:" },
- "aiContextCacheEnabledHelp": { "message": "缓存分析结果以减少 API 调用" },
- "aiContextRetryAttemptsLabel": { "message": "重试次数:" },
- "aiContextRetryAttemptsHelp": { "message": "重试失败请求的次数" },
- "showAdvancedSettings": { "message": "显示高级设置" },
- "hideAdvancedSettings": { "message": "隐藏高级设置" }
-}
+ "aiContextTimeoutLabel": {
+ "message": "请求超时 (ms):"
+ },
+ "aiContextTimeoutHelp": {
+ "message": "等待 AI 响应的最长时间"
+ },
+ "aiContextRateLimitLabel": {
+ "message": "速率限制 (请求/分钟):"
+ },
+ "aiContextRateLimitHelp": {
+ "message": "每分钟最大请求数"
+ },
+ "aiContextCacheEnabledLabel": {
+ "message": "启用缓存:"
+ },
+ "aiContextCacheEnabledHelp": {
+ "message": "缓存分析结果以减少 API 调用"
+ },
+ "aiContextRetryAttemptsLabel": {
+ "message": "重试次数:"
+ },
+ "aiContextRetryAttemptsHelp": {
+ "message": "重试失败请求的次数"
+ },
+ "showAdvancedSettings": {
+ "message": "显示高级设置"
+ },
+ "hideAdvancedSettings": {
+ "message": "隐藏高级设置"
+ },
+ "sidepanelLoading": {
+ "message": "加载中..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "AI 分析"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "单词列表"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "分析"
+ },
+ "sidepanelAnalyzing": {
+ "message": "分析中..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "待分析单词"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "点击字幕中的单词以添加分析..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "重试"
+ },
+ "sidepanelResultsTitle": {
+ "message": "“%s”的结果"
+ },
+ "sidepanelSectionDefinition": {
+ "message": "定义"
+ },
+ "sidepanelSectionCultural": {
+ "message": "文化背景"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "历史背景"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "语言学分析"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "我的单词"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "单词列表功能即将推出!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "此功能目前正在开发中。在设置中启用以尝试预览。"
+ },
+ "sidepanelErrorNoWords": {
+ "message": "未选择要分析的单词"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "AI 上下文分析已禁用。请在设置中启用。"
+ },
+ "sidepanelErrorGeneric": {
+ "message": "分析过程中发生错误。"
+ }
+}
\ No newline at end of file
diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json
index 642b2ee..7cbb0f1 100644
--- a/_locales/zh_TW/messages.json
+++ b/_locales/zh_TW/messages.json
@@ -1,418 +1,922 @@
{
- "appName": { "message": "DualSub" },
- "appDesc": { "message": "在串流平台上顯示雙語字幕。" },
- "pageTitle": { "message": "DualSub 設定" },
- "h1Title": { "message": "DualSub" },
- "enableSubtitlesLabel": { "message": "啟用雙語字幕:" },
- "useNativeSubtitlesLabel": { "message": "使用官方字幕:" },
- "originalLanguageLabel": { "message": "原始語言:" },
- "translationSettingsLegend": { "message": "翻譯設定" },
- "providerLabel": { "message": "提供商:" },
- "targetLanguageLabel": { "message": "翻譯為:" },
- "batchSizeLabel": { "message": "批次大小:" },
- "requestDelayLabel": { "message": "請求延遲 (ms):" },
- "subtitleAppearanceTimingLegend": { "message": "字幕外觀和時序" },
- "displayOrderLabel": { "message": "顯示順序:" },
- "layoutLabel": { "message": "佈局:" },
- "fontSizeLabel": { "message": "字體大小:" },
- "verticalGapLabel": { "message": "垂直間距:" },
- "subtitleVerticalPositionLabel": { "message": "垂直位置:" },
- "timeOffsetLabel": { "message": "時間偏移(秒):" },
- "displayOrderOriginalFirst": { "message": "原文在上" },
- "displayOrderTranslationFirst": { "message": "譯文在上" },
- "layoutTopBottom": { "message": "上下排列" },
- "layoutLeftRight": { "message": "左右排列" },
- "uiLanguageLabel": { "message": "語言:" },
- "openOptionsButton": { "message": "進階設定" },
- "statusLanguageSetTo": { "message": "重新整理頁面後生效:" },
- "statusDualEnabled": { "message": "雙語字幕已啟用。(重新整理頁面)" },
- "statusDualDisabled": { "message": "雙語字幕已停用。(重新整理頁面)" },
+ "appName": {
+ "message": "DualSub"
+ },
+ "appDesc": {
+ "message": "在串流平台上顯示雙語字幕。"
+ },
+ "pageTitle": {
+ "message": "DualSub 設定"
+ },
+ "h1Title": {
+ "message": "DualSub"
+ },
+ "enableSubtitlesLabel": {
+ "message": "啟用雙語字幕:"
+ },
+ "useNativeSubtitlesLabel": {
+ "message": "使用官方字幕:"
+ },
+ "originalLanguageLabel": {
+ "message": "原始語言:"
+ },
+ "translationSettingsLegend": {
+ "message": "翻譯設定"
+ },
+ "providerLabel": {
+ "message": "提供商:"
+ },
+ "targetLanguageLabel": {
+ "message": "翻譯為:"
+ },
+ "batchSizeLabel": {
+ "message": "批次大小:"
+ },
+ "requestDelayLabel": {
+ "message": "請求延遲 (ms):"
+ },
+ "subtitleAppearanceTimingLegend": {
+ "message": "字幕外觀和時序"
+ },
+ "displayOrderLabel": {
+ "message": "顯示順序:"
+ },
+ "layoutLabel": {
+ "message": "佈局:"
+ },
+ "fontSizeLabel": {
+ "message": "字體大小:"
+ },
+ "verticalGapLabel": {
+ "message": "垂直間距:"
+ },
+ "subtitleVerticalPositionLabel": {
+ "message": "垂直位置:"
+ },
+ "timeOffsetLabel": {
+ "message": "時間偏移(秒):"
+ },
+ "displayOrderOriginalFirst": {
+ "message": "原文在上"
+ },
+ "displayOrderTranslationFirst": {
+ "message": "譯文在上"
+ },
+ "layoutTopBottom": {
+ "message": "上下排列"
+ },
+ "layoutLeftRight": {
+ "message": "左右排列"
+ },
+ "uiLanguageLabel": {
+ "message": "語言:"
+ },
+ "openOptionsButton": {
+ "message": "進階設定"
+ },
+ "statusLanguageSetTo": {
+ "message": "重新整理頁面後生效:"
+ },
+ "statusDualEnabled": {
+ "message": "雙語字幕已啟用。(重新整理頁面)"
+ },
+ "statusDualDisabled": {
+ "message": "雙語字幕已停用。(重新整理頁面)"
+ },
"statusSmartTranslationEnabled": {
"message": "智慧翻譯已啟用。(重新整理頁面)"
},
"statusSmartTranslationDisabled": {
"message": "智慧翻譯已停用。(重新整理頁面)"
},
- "statusOriginalLanguage": { "message": "重新整理頁面後生效:" },
- "statusTimeOffset": { "message": "時間偏移:" },
- "statusDisplayOrderUpdated": { "message": "顯示順序已更新。" },
- "statusLayoutOrientationUpdated": { "message": "佈局方向已更新。" },
- "statusFontSize": { "message": "字體大小:" },
- "statusVerticalGap": { "message": "垂直間距:" },
- "statusVerticalPosition": { "message": "垂直位置:" },
- "statusInvalidOffset": { "message": "無效偏移,已還原。" },
- "statusSettingNotApplied": { "message": "設定未套用。請重新整理頁面。" },
-
- "optionsPageTitle": { "message": "DualSub 選項" },
- "optionsH1Title": { "message": "DualSub" },
- "navGeneral": { "message": "一般" },
- "navTranslation": { "message": "翻譯" },
- "navProviders": { "message": "提供商" },
- "navAbout": { "message": "關於" },
- "sectionGeneral": { "message": "一般" },
- "cardUILanguageTitle": { "message": "介面語言" },
- "cardUILanguageDesc": { "message": "選擇擴充功能介面的顯示語言。" },
- "cardHideOfficialSubtitlesTitle": { "message": "隱藏官方字幕" },
+ "statusOriginalLanguage": {
+ "message": "重新整理頁面後生效:"
+ },
+ "statusTimeOffset": {
+ "message": "時間偏移:"
+ },
+ "statusDisplayOrderUpdated": {
+ "message": "顯示順序已更新。"
+ },
+ "statusLayoutOrientationUpdated": {
+ "message": "佈局方向已更新。"
+ },
+ "statusFontSize": {
+ "message": "字體大小:"
+ },
+ "statusVerticalGap": {
+ "message": "垂直間距:"
+ },
+ "statusVerticalPosition": {
+ "message": "垂直位置:"
+ },
+ "statusInvalidOffset": {
+ "message": "無效偏移,已還原。"
+ },
+ "statusSettingNotApplied": {
+ "message": "設定未套用。請重新整理頁面。"
+ },
+ "optionsPageTitle": {
+ "message": "DualSub 選項"
+ },
+ "optionsH1Title": {
+ "message": "DualSub"
+ },
+ "navGeneral": {
+ "message": "一般"
+ },
+ "navTranslation": {
+ "message": "翻譯"
+ },
+ "navProviders": {
+ "message": "提供商"
+ },
+ "navAbout": {
+ "message": "關於"
+ },
+ "sectionGeneral": {
+ "message": "一般"
+ },
+ "cardUILanguageTitle": {
+ "message": "介面語言"
+ },
+ "cardUILanguageDesc": {
+ "message": "選擇擴充功能介面的顯示語言。"
+ },
+ "cardHideOfficialSubtitlesTitle": {
+ "message": "隱藏官方字幕"
+ },
"cardHideOfficialSubtitlesDesc": {
"message": "當 DualSub 啟用時,隱藏影片平台的官方字幕。"
},
- "hideOfficialSubtitlesLabel": { "message": "隱藏官方字幕:" },
- "sectionTranslation": { "message": "翻譯" },
- "cardTranslationEngineTitle": { "message": "翻譯引擎" },
- "cardTranslationEngineDesc": { "message": "選擇您偏好的翻譯服務。" },
- "cardPerformanceTitle": { "message": "效能" },
+ "hideOfficialSubtitlesLabel": {
+ "message": "隱藏官方字幕:"
+ },
+ "sectionTranslation": {
+ "message": "翻譯"
+ },
+ "cardTranslationEngineTitle": {
+ "message": "翻譯引擎"
+ },
+ "cardTranslationEngineDesc": {
+ "message": "選擇您偏好的翻譯服務。"
+ },
+ "cardPerformanceTitle": {
+ "message": "效能"
+ },
"cardPerformanceDesc": {
"message": "調整擴充功能處理翻譯請求的方式,以平衡速度和穩定性。"
},
- "sectionProviders": { "message": "提供商設定" },
- "cardDeepLTitle": { "message": "DeepL" },
+ "sectionProviders": {
+ "message": "提供商設定"
+ },
+ "cardDeepLTitle": {
+ "message": "DeepL"
+ },
"cardDeepLDesc": {
"message": "輸入您的 DeepL 翻譯 API 金鑰。選擇免費或專業版方案。"
},
- "apiKeyLabel": { "message": "API 金鑰:" },
- "apiPlanLabel": { "message": "API 方案:" },
- "apiPlanFree": { "message": "DeepL API 免費版" },
- "apiPlanPro": { "message": "DeepL API 專業版" },
- "sectionAbout": { "message": "關於" },
- "cardAboutTitle": { "message": "DualSub" },
- "aboutVersion": { "message": "版本" },
+ "apiKeyLabel": {
+ "message": "API 金鑰:"
+ },
+ "apiPlanLabel": {
+ "message": "API 方案:"
+ },
+ "apiPlanFree": {
+ "message": "DeepL API 免費版"
+ },
+ "apiPlanPro": {
+ "message": "DeepL API 專業版"
+ },
+ "sectionAbout": {
+ "message": "關於"
+ },
+ "cardAboutTitle": {
+ "message": "DualSub"
+ },
+ "aboutVersion": {
+ "message": "版本"
+ },
"aboutDescription": {
"message": "此擴充功能幫助您在各種平台上觀看雙語字幕影片。"
},
- "aboutDevelopment": { "message": "由 QuellaMC & 1jifang 開發。" },
-
- "lang_en": { "message": "英語" },
- "lang_es": { "message": "西班牙語" },
- "lang_fr": { "message": "法語" },
- "lang_de": { "message": "德語" },
- "lang_it": { "message": "義大利語" },
- "lang_pt": { "message": "葡萄牙語" },
- "lang_ja": { "message": "日語" },
- "lang_ko": { "message": "韓語" },
- "lang_zh_CN": { "message": "中文 (簡體)" },
- "lang_zh_TW": { "message": "中文 (繁體)" },
- "lang_ru": { "message": "俄語" },
- "lang_ar": { "message": "阿拉伯語" },
- "lang_hi": { "message": "印地語" },
-
- "testDeepLButton": { "message": "測試 DeepL 連線" },
- "deeplApiKeyError": { "message": "請先輸入您的 DeepL API 金鑰。" },
- "testingButton": { "message": "測試中..." },
- "testingConnection": { "message": "正在測試 DeepL 連線..." },
+ "aboutDevelopment": {
+ "message": "由 QuellaMC & 1jifang 開發。"
+ },
+ "lang_en": {
+ "message": "英語"
+ },
+ "lang_es": {
+ "message": "西班牙語"
+ },
+ "lang_fr": {
+ "message": "法語"
+ },
+ "lang_de": {
+ "message": "德語"
+ },
+ "lang_it": {
+ "message": "義大利語"
+ },
+ "lang_pt": {
+ "message": "葡萄牙語"
+ },
+ "lang_ja": {
+ "message": "日語"
+ },
+ "lang_ko": {
+ "message": "韓語"
+ },
+ "lang_zh_CN": {
+ "message": "中文 (簡體)"
+ },
+ "lang_zh_TW": {
+ "message": "中文 (繁體)"
+ },
+ "lang_ru": {
+ "message": "俄語"
+ },
+ "lang_ar": {
+ "message": "阿拉伯語"
+ },
+ "lang_hi": {
+ "message": "印地語"
+ },
+ "testDeepLButton": {
+ "message": "測試 DeepL 連線"
+ },
+ "deeplApiKeyError": {
+ "message": "請先輸入您的 DeepL API 金鑰。"
+ },
+ "testingButton": {
+ "message": "測試中..."
+ },
+ "testingConnection": {
+ "message": "正在測試 DeepL 連線..."
+ },
"deeplTestSuccess": {
"message": "✅ DeepL API 測試成功!將 \"Hello\" 翻譯為 \"%s\""
},
- "deeplTestSuccessSimple": { "message": "✅ DeepL API 測試成功!" },
- "deeplTestUnexpectedFormat": { "message": "⚠️ DeepL API 回應但格式異常" },
- "deeplTestInvalidKey": { "message": "❌ DeepL API 金鑰無效或被拒絕。" },
+ "deeplTestSuccessSimple": {
+ "message": "✅ DeepL API 測試成功!"
+ },
+ "deeplTestUnexpectedFormat": {
+ "message": "⚠️ DeepL API 回應但格式異常"
+ },
+ "deeplTestInvalidKey": {
+ "message": "❌ DeepL API 金鑰無效或被拒絕。"
+ },
"deeplTestQuotaExceeded": {
"message": "❌ DeepL API 配額已超限。請檢查您的使用限制。"
},
- "deeplTestApiError": { "message": "❌ DeepL API 錯誤 (%d):%s" },
+ "deeplTestApiError": {
+ "message": "❌ DeepL API 錯誤 (%d):%s"
+ },
"deeplTestNetworkError": {
"message": "❌ 網路錯誤:無法連線到 DeepL API。請檢查您的網路連線。"
},
- "deeplTestGenericError": { "message": "❌ 測試失敗:%s" },
- "deepLApiUnavailable": { "message": "DeepL API 不可用" },
- "deepLApiUnavailableTooltip": { "message": "DeepL API 指令碼載入失敗" },
+ "deeplTestGenericError": {
+ "message": "❌ 測試失敗:%s"
+ },
+ "deepLApiUnavailable": {
+ "message": "DeepL API 不可用"
+ },
+ "deepLApiUnavailableTooltip": {
+ "message": "DeepL API 指令碼載入失敗"
+ },
"deeplApiNotLoadedError": {
"message": "❌ DeepL API 指令碼不可用。請重新整理頁面。"
},
-
- "cardGoogleTitle": { "message": "Google 翻譯" },
+ "cardGoogleTitle": {
+ "message": "Google 翻譯"
+ },
"cardGoogleDesc": {
"message": "由 Google 提供的免費翻譯服務。無需額外設定。"
},
- "cardMicrosoftTitle": { "message": "Microsoft 翻譯" },
+ "cardMicrosoftTitle": {
+ "message": "Microsoft 翻譯"
+ },
"cardMicrosoftDesc": {
"message": "由 Microsoft Edge 提供的免費翻譯服務。無需額外設定。"
},
- "cardDeepLFreeTitle": { "message": "DeepL 翻譯(免費)" },
+ "cardDeepLFreeTitle": {
+ "message": "DeepL 翻譯(免費)"
+ },
"cardDeepLFreeDesc": {
"message": "免費的 DeepL 翻譯服務,提供高品質的翻譯結果。無需 API 金鑰 - 使用 DeepL 的網頁介面。"
},
- "providerStatus": { "message": "狀態:" },
- "statusReady": { "message": "可以使用" },
- "providerFeatures": { "message": "特性:" },
- "featureFree": { "message": "免費使用" },
- "featureNoApiKey": { "message": "無需 API 金鑰" },
- "featureWideLanguageSupport": { "message": "廣泛的語言支援" },
- "featureFastTranslation": { "message": "快速翻譯" },
- "featureHighQuality": { "message": "高品質翻譯" },
- "featureGoodPerformance": { "message": "良好的效能" },
- "featureHighestQuality": { "message": "最高品質翻譯" },
- "featureApiKeyRequired": { "message": "需要 API 金鑰" },
- "featureLimitedLanguages": { "message": "有限的語言支援" },
- "featureUsageLimits": { "message": "使用限制適用" },
- "featureMultipleBackups": { "message": "多種備用方法" },
-
- "providerNotes": { "message": "注意事項:" },
- "noteSlowForSecurity": { "message": "由於安全措施,速度稍慢" },
- "noteAutoFallback": { "message": "自動回退到其他服務" },
- "noteRecommendedDefault": { "message": "推薦作為預設提供商" },
-
- "providerGoogleName": { "message": "Google 翻譯(免費)" },
- "providerMicrosoftName": { "message": "Microsoft 翻譯(免費)" },
- "providerDeepLName": { "message": "DeepL(需要 API 金鑰)" },
- "providerDeepLFreeName": { "message": "DeepL 翻譯(免費)" },
+ "providerStatus": {
+ "message": "狀態:"
+ },
+ "statusReady": {
+ "message": "可以使用"
+ },
+ "providerFeatures": {
+ "message": "特性:"
+ },
+ "featureFree": {
+ "message": "免費使用"
+ },
+ "featureNoApiKey": {
+ "message": "無需 API 金鑰"
+ },
+ "featureWideLanguageSupport": {
+ "message": "廣泛的語言支援"
+ },
+ "featureFastTranslation": {
+ "message": "快速翻譯"
+ },
+ "featureHighQuality": {
+ "message": "高品質翻譯"
+ },
+ "featureGoodPerformance": {
+ "message": "良好的效能"
+ },
+ "featureHighestQuality": {
+ "message": "最高品質翻譯"
+ },
+ "featureApiKeyRequired": {
+ "message": "需要 API 金鑰"
+ },
+ "featureLimitedLanguages": {
+ "message": "有限的語言支援"
+ },
+ "featureUsageLimits": {
+ "message": "使用限制適用"
+ },
+ "featureMultipleBackups": {
+ "message": "多種備用方法"
+ },
+ "providerNotes": {
+ "message": "注意事項:"
+ },
+ "noteSlowForSecurity": {
+ "message": "由於安全措施,速度稍慢"
+ },
+ "noteAutoFallback": {
+ "message": "自動回退到其他服務"
+ },
+ "noteRecommendedDefault": {
+ "message": "推薦作為預設提供商"
+ },
+ "providerGoogleName": {
+ "message": "Google 翻譯(免費)"
+ },
+ "providerMicrosoftName": {
+ "message": "Microsoft 翻譯(免費)"
+ },
+ "providerDeepLName": {
+ "message": "DeepL(需要 API 金鑰)"
+ },
+ "providerDeepLFreeName": {
+ "message": "DeepL 翻譯(免費)"
+ },
"providerOpenAICompatibleName": {
"message": "OpenAI 相容(需要 API 金鑰)"
},
"providerVertexGeminiName": {
"message": "Vertex AI Gemini(需要 API 金鑰)"
},
- "cardOpenAICompatibleTitle": { "message": "OpenAI 相容(需要 API 金鑰)" },
+ "cardOpenAICompatibleTitle": {
+ "message": "OpenAI 相容(需要 API 金鑰)"
+ },
"cardOpenAICompatibleDesc": {
"message": "輸入您的 API 金鑰和設定,用於 Gemini 等 OpenAI 相容服務。"
},
- "cardVertexGeminiTitle": { "message": "Vertex AI Gemini(需要 API 金鑰)" },
- "cardVertexGeminiDesc": { "message": "輸入您的存取權杖和 Vertex 專案設定,或匯入服務帳戶 JSON 檔案。" },
- "vertexAccessTokenLabel": { "message": "存取權杖:" },
- "vertexProjectIdLabel": { "message": "專案 ID:" },
- "vertexLocationLabel": { "message": "位置:" },
- "vertexModelLabel": { "message": "模型:" },
- "vertexMissingConfig": { "message": "請輸入存取權杖和專案 ID。" },
- "vertexConnectionFailed": { "message": "連線失敗:%s" },
- "vertexServiceAccountLabel": { "message": "服務帳戶 JSON:" },
- "vertexImportButton": { "message": "匯入 JSON 檔案" },
- "vertexRefreshButton": { "message": "🔄 重新整理權杖" },
- "vertexImportHint": { "message": "自動填入下方憑證" },
- "vertexImporting": { "message": "匯入中..." },
- "vertexRefreshingToken": { "message": "正在重新整理存取權杖..." },
- "vertexGeneratingToken": { "message": "正在產生存取權杖..." },
- "vertexImportSuccess": { "message": "服務帳戶已匯入並產生權杖。" },
- "vertexImportFailed": { "message": "匯入失敗:%s" },
- "vertexTokenRefreshed": { "message": "存取權杖已成功重新整理。" },
- "vertexRefreshFailed": { "message": "權杖重新整理失敗:%s" },
- "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 小時後過期。您的服務帳戶已安全儲存,需要時只需點擊重新整理權杖按鈕即可。" },
- "baseUrlLabel": { "message": "基礎 URL:" },
- "modelLabel": { "message": "模型:" },
- "featureCustomizable": { "message": "可自訂端點和模型" },
- "fetchModelsButton": { "message": "取得模型" },
- "testConnectionButton": { "message": "測試連線" },
-
- "openaiApiKeyPlaceholder": { "message": "輸入您的 OpenAI 相容 API 金鑰" },
+ "cardVertexGeminiTitle": {
+ "message": "Vertex AI Gemini(需要 API 金鑰)"
+ },
+ "cardVertexGeminiDesc": {
+ "message": "輸入您的存取權杖和 Vertex 專案設定,或匯入服務帳戶 JSON 檔案。"
+ },
+ "vertexAccessTokenLabel": {
+ "message": "存取權杖:"
+ },
+ "vertexProjectIdLabel": {
+ "message": "專案 ID:"
+ },
+ "vertexLocationLabel": {
+ "message": "位置:"
+ },
+ "vertexModelLabel": {
+ "message": "模型:"
+ },
+ "vertexMissingConfig": {
+ "message": "請輸入存取權杖和專案 ID。"
+ },
+ "vertexConnectionFailed": {
+ "message": "連線失敗:%s"
+ },
+ "vertexServiceAccountLabel": {
+ "message": "服務帳戶 JSON:"
+ },
+ "vertexImportButton": {
+ "message": "匯入 JSON 檔案"
+ },
+ "vertexRefreshButton": {
+ "message": "🔄 重新整理權杖"
+ },
+ "vertexImportHint": {
+ "message": "自動填入下方憑證"
+ },
+ "vertexImporting": {
+ "message": "匯入中..."
+ },
+ "vertexRefreshingToken": {
+ "message": "正在重新整理存取權杖..."
+ },
+ "vertexGeneratingToken": {
+ "message": "正在產生存取權杖..."
+ },
+ "vertexImportSuccess": {
+ "message": "服務帳戶已匯入並產生權杖。"
+ },
+ "vertexImportFailed": {
+ "message": "匯入失敗:%s"
+ },
+ "vertexTokenRefreshed": {
+ "message": "存取權杖已成功重新整理。"
+ },
+ "vertexRefreshFailed": {
+ "message": "權杖重新整理失敗:%s"
+ },
+ "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 小時後過期。您的服務帳戶已安全儲存,需要時只需點擊重新整理權杖按鈕即可。"
+ },
+ "baseUrlLabel": {
+ "message": "基礎 URL:"
+ },
+ "modelLabel": {
+ "message": "模型:"
+ },
+ "featureCustomizable": {
+ "message": "可自訂端點和模型"
+ },
+ "fetchModelsButton": {
+ "message": "取得模型"
+ },
+ "testConnectionButton": {
+ "message": "測試連線"
+ },
+ "openaiApiKeyPlaceholder": {
+ "message": "輸入您的 OpenAI 相容 API 金鑰"
+ },
"openaiBaseUrlPlaceholder": {
"message": "例如:https://api.openai.com/v1"
},
- "openaiApiKeyError": { "message": "請先輸入您的 API 金鑰。" },
- "openaiApiKeyNeedsTesting": { "message": "⚠️ API 金鑰需要測試。" },
+ "openaiApiKeyError": {
+ "message": "請先輸入您的 API 金鑰。"
+ },
+ "openaiApiKeyNeedsTesting": {
+ "message": "⚠️ API 金鑰需要測試。"
+ },
"openaiTestNeedsTesting": {
"message": "⚠️ OpenAI 相容 API 金鑰需要測試。"
},
- "openaiTestingConnection": { "message": "正在測試連線..." },
- "openaiConnectionSuccessful": { "message": "連線成功!" },
- "openaiConnectionFailed": { "message": "連線失敗:%s" },
- "openaieFetchingModels": { "message": "正在取得模型..." },
- "openaiModelsFetchedSuccessfully": { "message": "模型取得成功。" },
- "openaiFailedToFetchModels": { "message": "取得模型失敗:%s" },
-
- "cardLoggingLevelTitle": { "message": "日誌級別" },
+ "openaiTestingConnection": {
+ "message": "正在測試連線..."
+ },
+ "openaiConnectionSuccessful": {
+ "message": "連線成功!"
+ },
+ "openaiConnectionFailed": {
+ "message": "連線失敗:%s"
+ },
+ "openaieFetchingModels": {
+ "message": "正在取得模型..."
+ },
+ "openaiModelsFetchedSuccessfully": {
+ "message": "模型取得成功。"
+ },
+ "openaiFailedToFetchModels": {
+ "message": "取得模型失敗:%s"
+ },
+ "cardLoggingLevelTitle": {
+ "message": "日誌級別"
+ },
"cardLoggingLevelDesc": {
"message": "控制瀏覽器控制台中顯示的除錯資訊量。較高級別包含所有較低級別的訊息。"
},
- "loggingLevelLabel": { "message": "日誌級別:" },
- "loggingLevelOff": { "message": "關閉" },
- "loggingLevelError": { "message": "僅錯誤" },
- "loggingLevelWarn": { "message": "警告和錯誤" },
- "loggingLevelInfo": { "message": "資訊及以上" },
- "loggingLevelDebug": { "message": "除錯(全部)" },
-
- "cardBatchTranslationTitle": { "message": "批次翻譯" },
+ "loggingLevelLabel": {
+ "message": "日誌級別:"
+ },
+ "loggingLevelOff": {
+ "message": "關閉"
+ },
+ "loggingLevelError": {
+ "message": "僅錯誤"
+ },
+ "loggingLevelWarn": {
+ "message": "警告和錯誤"
+ },
+ "loggingLevelInfo": {
+ "message": "資訊及以上"
+ },
+ "loggingLevelDebug": {
+ "message": "除錯(全部)"
+ },
+ "cardBatchTranslationTitle": {
+ "message": "批次翻譯"
+ },
"cardBatchTranslationDesc": {
"message": "批次翻譯將多個字幕片段一起處理,減少 80-90% 的 API 呼叫並提高效能。為您偏好的翻譯提供商設定最佳設定。"
},
- "batchingEnabledLabel": { "message": "啟用批次翻譯:" },
+ "batchingEnabledLabel": {
+ "message": "啟用批次翻譯:"
+ },
"batchingEnabledHelp": {
"message": "將多個字幕片段組合成單一翻譯請求"
},
- "useProviderDefaultsLabel": { "message": "使用提供商最佳化設定:" },
+ "useProviderDefaultsLabel": {
+ "message": "使用提供商最佳化設定:"
+ },
"useProviderDefaultsHelp": {
"message": "自動為每個翻譯提供商使用最佳批次大小"
},
- "globalBatchSizeLabel": { "message": "全域批次大小:" },
+ "globalBatchSizeLabel": {
+ "message": "全域批次大小:"
+ },
"globalBatchSizeHelp": {
"message": "一起處理的字幕片段數量(1-15)"
},
- "smartBatchingLabel": { "message": "智慧批次最佳化:" },
+ "smartBatchingLabel": {
+ "message": "智慧批次最佳化:"
+ },
"smartBatchingHelp": {
"message": "根據播放位置優先處理字幕片段"
},
- "maxConcurrentBatchesLabel": { "message": "最大並行批次:" },
+ "maxConcurrentBatchesLabel": {
+ "message": "最大並行批次:"
+ },
"maxConcurrentBatchesHelp": {
"message": "同時處理的翻譯批次數量"
},
-
- "cardProviderBatchTitle": { "message": "提供商特定批次大小" },
+ "cardProviderBatchTitle": {
+ "message": "提供商特定批次大小"
+ },
"cardProviderBatchDesc": {
"message": "為每個翻譯提供商設定最佳批次大小。這些設定在啟用「使用提供商最佳化設定」時使用。"
},
- "openaieBatchSizeLabel": { "message": "OpenAI 批次大小:" },
+ "openaieBatchSizeLabel": {
+ "message": "OpenAI 批次大小:"
+ },
"openaieBatchSizeHelp": {
"message": "建議:5-10 個片段(預設:8)"
},
- "googleBatchSizeLabel": { "message": "Google 翻譯批次大小:" },
+ "googleBatchSizeLabel": {
+ "message": "Google 翻譯批次大小:"
+ },
"googleBatchSizeHelp": {
"message": "建議:3-5 個片段(預設:4)"
},
- "deeplBatchSizeLabel": { "message": "DeepL 批次大小:" },
+ "deeplBatchSizeLabel": {
+ "message": "DeepL 批次大小:"
+ },
"deeplBatchSizeHelp": {
"message": "建議:2-3 個片段(預設:3)"
},
- "microsoftBatchSizeLabel": { "message": "Microsoft 翻譯批次大小:" },
+ "microsoftBatchSizeLabel": {
+ "message": "Microsoft 翻譯批次大小:"
+ },
"microsoftBatchSizeHelp": {
"message": "建議:3-5 個片段(預設:4)"
},
- "vertexBatchSizeLabel": { "message": "Vertex AI 批次大小:" },
+ "vertexBatchSizeLabel": {
+ "message": "Vertex AI 批次大小:"
+ },
"vertexBatchSizeHelp": {
"message": "建議:5-10 個片段(預設:8)"
},
-
- "deeplTestNeedsTesting": { "message": "⚠️ DeepL API 金鑰需要測試。" },
-
- "cardProviderDelayTitle": { "message": "提供商特定請求延遲" },
+ "deeplTestNeedsTesting": {
+ "message": "⚠️ DeepL API 金鑰需要測試。"
+ },
+ "cardProviderDelayTitle": {
+ "message": "提供商特定請求延遲"
+ },
"cardProviderDelayDesc": {
"message": "設定翻譯請求之間的強制延遲以防止帳戶鎖定。即使啟用批次處理,這些延遲也會套用。"
},
- "openaieDelayLabel": { "message": "OpenAI 請求延遲 (ms):" },
+ "openaieDelayLabel": {
+ "message": "OpenAI 請求延遲 (ms):"
+ },
"openaieDelayHelp": {
"message": "請求之間的最小延遲(預設:100ms)"
},
- "googleDelayLabel": { "message": "Google 翻譯請求延遲 (ms):" },
+ "googleDelayLabel": {
+ "message": "Google 翻譯請求延遲 (ms):"
+ },
"googleDelayHelp": {
"message": "防止臨時鎖定所需的延遲(預設:1500ms)"
},
- "deeplDelayLabel": { "message": "DeepL API 請求延遲 (ms):" },
+ "deeplDelayLabel": {
+ "message": "DeepL API 請求延遲 (ms):"
+ },
"deeplDelayHelp": {
"message": "DeepL API 請求的延遲(預設:500ms)"
},
- "deeplFreeDelayLabel": { "message": "DeepL 免費請求延遲 (ms):" },
+ "deeplFreeDelayLabel": {
+ "message": "DeepL 免費請求延遲 (ms):"
+ },
"deeplFreeDelayHelp": {
"message": "免費層的保守延遲(預設:2000ms)"
},
- "microsoftDelayLabel": { "message": "Microsoft 翻譯請求延遲 (ms):" },
+ "microsoftDelayLabel": {
+ "message": "Microsoft 翻譯請求延遲 (ms):"
+ },
"microsoftDelayHelp": {
"message": "尊重字元限制的延遲(預設:800ms)"
},
- "vertexDelayLabel": { "message": "Vertex AI 請求延遲 (ms):" },
+ "vertexDelayLabel": {
+ "message": "Vertex AI 請求延遲 (ms):"
+ },
"vertexDelayHelp": {
"message": "請求之間的最小延遲(預設:100ms)"
},
-
- "aiContextModalTitle": { "message": "AI 上下文分析" },
- "aiContextSelectedWords": { "message": "選中的詞語" },
- "aiContextNoWordsSelected": { "message": "未選擇詞語" },
- "aiContextClickHint": { "message": "💡 點擊詞語來新增或移除。" },
- "aiContextStartAnalysis": { "message": "開始分析" },
- "aiContextPauseAnalysis": { "message": "⏸ 暫停" },
- "aiContextPauseAnalysisTitle": { "message": "暫停分析" },
- "aiContextInitialMessage": { "message": "從字幕中選擇詞語開始分析。" },
- "aiContextAnalyzing": { "message": "正在分析上下文..." },
- "aiContextPauseNote": { "message": "點擊 ⏸ 暫停分析" },
- "aiContextAnalysisFailed": { "message": "分析失敗" },
- "aiContextNoContent": { "message": "無分析內容" },
- "aiContextNoContentMessage": { "message": "分析已完成但未返回內容。" },
- "aiContextDefinition": { "message": "📖 定義" },
- "aiContextCultural": { "message": "🌍 文化背景" },
- "aiContextCulturalSignificance": { "message": "⭐ 文化意義" },
- "aiContextHistorical": { "message": "📜 歷史背景" },
- "aiContextHistoricalSignificance": { "message": "📜 歷史意義" },
- "aiContextEvolution": { "message": "🔄 歷史演變" },
- "aiContextLinguistic": { "message": "🔤 語言學分析" },
- "aiContextGrammar": { "message": "📝 語法與語義" },
- "aiContextUsage": { "message": "💡 用法與例句" },
- "aiContextExamples": { "message": "例句:" },
- "aiContextLearningTips": { "message": "🎯 學習提示" },
- "aiContextRelatedExpressions": { "message": "🔗 相關表達" },
- "aiContextKeyInsights": { "message": "🔑 關鍵見解" },
- "aiContextTypeCultural": { "message": "文化" },
- "aiContextTypeHistorical": { "message": "歷史" },
- "aiContextTypeLinguistic": { "message": "語言學" },
- "aiContextTypeComprehensive": { "message": "綜合" },
- "aiContextTypeGeneric": { "message": "上下文" },
- "aiContextClose": { "message": "關閉" },
- "aiContextAnalysisResults": { "message": "分析結果" },
- "aiContextRetrying": { "message": "分析失敗,正在重新生成..." },
- "aiContextRetryNotification": { "message": "分析失敗,正在重試..." },
- "aiContextRetryButton": { "message": "重試" },
+ "aiContextModalTitle": {
+ "message": "AI 上下文分析"
+ },
+ "aiContextSelectedWords": {
+ "message": "選中的詞語"
+ },
+ "aiContextNoWordsSelected": {
+ "message": "未選擇詞語"
+ },
+ "aiContextClickHint": {
+ "message": "💡 點擊詞語來新增或移除。"
+ },
+ "aiContextStartAnalysis": {
+ "message": "開始分析"
+ },
+ "aiContextPauseAnalysis": {
+ "message": "⏸ 暫停"
+ },
+ "aiContextPauseAnalysisTitle": {
+ "message": "暫停分析"
+ },
+ "aiContextInitialMessage": {
+ "message": "從字幕中選擇詞語開始分析。"
+ },
+ "aiContextAnalyzing": {
+ "message": "正在分析上下文..."
+ },
+ "aiContextPauseNote": {
+ "message": "點擊 ⏸ 暫停分析"
+ },
+ "aiContextAnalysisFailed": {
+ "message": "分析失敗"
+ },
+ "aiContextNoContent": {
+ "message": "無分析內容"
+ },
+ "aiContextNoContentMessage": {
+ "message": "分析已完成但未返回內容。"
+ },
+ "aiContextDefinition": {
+ "message": "📖 定義"
+ },
+ "aiContextCultural": {
+ "message": "🌍 文化背景"
+ },
+ "aiContextCulturalSignificance": {
+ "message": "⭐ 文化意義"
+ },
+ "aiContextHistorical": {
+ "message": "📜 歷史背景"
+ },
+ "aiContextHistoricalSignificance": {
+ "message": "📜 歷史意義"
+ },
+ "aiContextEvolution": {
+ "message": "🔄 歷史演變"
+ },
+ "aiContextLinguistic": {
+ "message": "🔤 語言學分析"
+ },
+ "aiContextGrammar": {
+ "message": "📝 語法與語義"
+ },
+ "aiContextUsage": {
+ "message": "💡 用法與例句"
+ },
+ "aiContextExamples": {
+ "message": "例句:"
+ },
+ "aiContextLearningTips": {
+ "message": "🎯 學習提示"
+ },
+ "aiContextRelatedExpressions": {
+ "message": "🔗 相關表達"
+ },
+ "aiContextKeyInsights": {
+ "message": "🔑 關鍵見解"
+ },
+ "aiContextTypeCultural": {
+ "message": "文化"
+ },
+ "aiContextTypeHistorical": {
+ "message": "歷史"
+ },
+ "aiContextTypeLinguistic": {
+ "message": "語言學"
+ },
+ "aiContextTypeComprehensive": {
+ "message": "綜合"
+ },
+ "aiContextTypeGeneric": {
+ "message": "上下文"
+ },
+ "aiContextClose": {
+ "message": "關閉"
+ },
+ "aiContextAnalysisResults": {
+ "message": "分析結果"
+ },
+ "aiContextRetrying": {
+ "message": "分析失敗,正在重新生成..."
+ },
+ "aiContextRetryNotification": {
+ "message": "分析失敗,正在重試..."
+ },
+ "aiContextRetryButton": {
+ "message": "重試"
+ },
"aiContextMalformedResponse": {
"message": "AI 服務返回了無效的回應格式。這可能是由於臨時服務問題。"
},
"aiContextJsonCodeBlock": {
"message": "AI 服務返回了未處理的 JSON 代碼而不是結構化數據。這表明回應中存在格式錯誤。"
},
- "aiContextCulturalContext": { "message": "文化背景:" },
- "aiContextSocialUsage": { "message": "社會用法:" },
- "aiContextRegionalNotes": { "message": "地區特色:" },
- "aiContextOrigins": { "message": "詞源:" },
- "aiContextHistoricalContext": { "message": "歷史背景:" },
- "aiContextHistoricalSignificance": { "message": "歷史意義:" },
- "aiContextEvolution": { "message": "演變過程:" },
- "aiContextEtymology": { "message": "詞源學:" },
- "aiContextGrammarNotes": { "message": "語法註釋:" },
- "aiContextTranslationNotes": { "message": "翻譯註釋:" },
- "aiContextLinguisticAnalysis": { "message": "語言學分析:" },
- "aiContextGrammarSemantics": { "message": "語法與語義:" },
- "aiContextUsageExamples": { "message": "用法與例句:" },
- "aiContextLearningTips": { "message": "學習技巧:" },
- "aiContextRelatedExpressions": { "message": "相關表達:" },
- "aiContextKeyInsights": { "message": "關鍵要點:" },
-
- "navAIContext": { "message": "AI 上下文" },
- "sectionAIContext": { "message": "AI 上下文助手" },
- "cardAIContextToggleTitle": { "message": "啟用 AI 上下文分析" },
+ "aiContextCulturalContext": {
+ "message": "文化背景:"
+ },
+ "aiContextSocialUsage": {
+ "message": "社會用法:"
+ },
+ "aiContextRegionalNotes": {
+ "message": "地區特色:"
+ },
+ "aiContextOrigins": {
+ "message": "詞源:"
+ },
+ "aiContextHistoricalContext": {
+ "message": "歷史背景:"
+ },
+ "aiContextHistoricalSignificanceLabel": {
+ "message": "歷史意義:"
+ },
+ "aiContextEvolutionLabel": {
+ "message": "演變過程:"
+ },
+ "aiContextEtymology": {
+ "message": "詞源學:"
+ },
+ "aiContextGrammarNotesLabel": {
+ "message": "語法註釋:"
+ },
+ "aiContextTranslationNotesLabel": {
+ "message": "翻譯註釋:"
+ },
+ "aiContextLinguisticAnalysisLabel": {
+ "message": "語言學分析:"
+ },
+ "aiContextGrammarSemanticsLabel": {
+ "message": "語法與語義:"
+ },
+ "aiContextUsageExamplesLabel": {
+ "message": "用法與例句:"
+ },
+ "aiContextLearningTipsLabel": {
+ "message": "學習技巧:"
+ },
+ "aiContextRelatedExpressionsLabel": {
+ "message": "相關表達:"
+ },
+ "aiContextKeyInsightsLabel": {
+ "message": "關鍵要點:"
+ },
+ "navAIContext": {
+ "message": "AI 上下文"
+ },
+ "sectionAIContext": {
+ "message": "AI 上下文助手"
+ },
+ "cardAIContextToggleTitle": {
+ "message": "啟用 AI 上下文分析"
+ },
"cardAIContextToggleDesc": {
"message": "為字幕文字啟用 AI 驅動的文化、歷史和語言學上下文分析。點擊字幕中的單詞或短語以獲得詳細解釋。"
},
- "aiContextEnabledLabel": { "message": "啟用 AI 上下文:" },
- "cardAIContextProviderTitle": { "message": "AI 提供商" },
+ "aiContextEnabledLabel": {
+ "message": "啟用 AI 上下文:"
+ },
+ "cardAIContextProviderTitle": {
+ "message": "AI 提供商"
+ },
"cardAIContextProviderDesc": {
"message": "選擇用於上下文分析的 AI 服務提供商。不同的提供商可能提供不同的品質和回應時間。"
},
- "aiContextProviderLabel": { "message": "提供商:" },
- "cardOpenAIContextTitle": { "message": "OpenAI 設定" },
+ "aiContextProviderLabel": {
+ "message": "提供商:"
+ },
+ "cardOpenAIContextTitle": {
+ "message": "OpenAI 設定"
+ },
"cardOpenAIContextDesc": {
"message": "設定用於上下文分析的 OpenAI API 設定。您需要一個有效的 OpenAI API 金鑰。"
},
- "openaiApiKeyLabel": { "message": "API 金鑰:" },
- "openaiBaseUrlLabel": { "message": "基礎 URL:" },
- "openaiModelLabel": { "message": "模型:" },
- "cardGeminiContextTitle": { "message": "Google Gemini 設定" },
+ "openaiApiKeyLabel": {
+ "message": "API 金鑰:"
+ },
+ "openaiBaseUrlLabel": {
+ "message": "基礎 URL:"
+ },
+ "openaiModelLabel": {
+ "message": "模型:"
+ },
+ "cardGeminiContextTitle": {
+ "message": "Google Gemini 設定"
+ },
"cardGeminiContextDesc": {
"message": "設定用於上下文分析的 Google Gemini API 設定。您需要一個有效的 Gemini API 金鑰。"
},
- "geminiApiKeyLabel": { "message": "API 金鑰:" },
- "geminiModelLabel": { "message": "模型:" },
- "cardAIContextTypesTitle": { "message": "上下文類型" },
+ "geminiApiKeyLabel": {
+ "message": "API 金鑰:"
+ },
+ "geminiModelLabel": {
+ "message": "模型:"
+ },
+ "cardAIContextTypesTitle": {
+ "message": "上下文類型"
+ },
"cardAIContextTypesDesc": {
"message": "啟用您想要使用的上下文分析類型。您可以啟用多種類型。"
},
- "contextTypeCulturalLabel": { "message": "文化上下文:" },
- "contextTypeCulturalHelp": { "message": "分析文化參考、習語和社會背景" },
- "contextTypeHistoricalLabel": { "message": "歷史上下文:" },
- "contextTypeHistoricalHelp": { "message": "提供歷史背景和時代背景" },
- "contextTypeLinguisticLabel": { "message": "語言學分析:" },
- "contextTypeLinguisticHelp": { "message": "解釋語法、詞源和語言結構" },
- "cardAIContextInteractiveTitle": { "message": "互動功能" },
+ "contextTypeCulturalLabel": {
+ "message": "文化上下文:"
+ },
+ "contextTypeCulturalHelp": {
+ "message": "分析文化參考、習語和社會背景"
+ },
+ "contextTypeHistoricalLabel": {
+ "message": "歷史上下文:"
+ },
+ "contextTypeHistoricalHelp": {
+ "message": "提供歷史背景和時代背景"
+ },
+ "contextTypeLinguisticLabel": {
+ "message": "語言學分析:"
+ },
+ "contextTypeLinguisticHelp": {
+ "message": "解釋語法、詞源和語言結構"
+ },
+ "cardAIContextInteractiveTitle": {
+ "message": "互動功能"
+ },
"cardAIContextInteractiveDesc": {
"message": "設定如何與字幕互動以觸發上下文分析。"
},
- "interactiveSubtitlesEnabledLabel": { "message": "啟用互動式字幕:" },
+ "interactiveSubtitlesEnabledLabel": {
+ "message": "啟用互動式字幕:"
+ },
"interactiveSubtitlesEnabledHelp": {
"message": "使字幕單詞可點擊以進行上下文分析"
},
- "contextOnClickLabel": { "message": "點擊時顯示上下文:" },
- "contextOnClickHelp": { "message": "點擊單詞時顯示上下文分析" },
- "contextOnSelectionLabel": { "message": "選擇時顯示上下文:" },
- "contextOnSelectionHelp": { "message": "選擇文字時顯示上下文分析" },
- "cardAIContextPrivacyTitle": { "message": "隱私和資料" },
+ "contextOnClickLabel": {
+ "message": "點擊時顯示上下文:"
+ },
+ "contextOnClickHelp": {
+ "message": "點擊單詞時顯示上下文分析"
+ },
+ "contextOnSelectionLabel": {
+ "message": "選擇時顯示上下文:"
+ },
+ "contextOnSelectionHelp": {
+ "message": "選擇文字時顯示上下文分析"
+ },
+ "cardAIContextPrivacyTitle": {
+ "message": "隱私和資料"
+ },
"cardAIContextPrivacyDesc": {
"message": "控制在上下文分析期間如何處理您的資料。"
},
@@ -422,22 +926,103 @@
"aiContextUserConsentHelp": {
"message": "AI 上下文分析功能正常運作所必需"
},
- "aiContextDataSharingLabel": { "message": "允許匿名使用分析:" },
+ "aiContextDataSharingLabel": {
+ "message": "允許匿名使用分析:"
+ },
"aiContextDataSharingHelp": {
"message": "透過分享匿名使用資料幫助改進服務"
},
- "cardAIContextAdvancedTitle": { "message": "進階設定" },
+ "cardAIContextAdvancedTitle": {
+ "message": "進階設定"
+ },
"cardAIContextAdvancedDesc": {
"message": "設定 AI 上下文分析行為的進階選項。"
},
- "aiContextTimeoutLabel": { "message": "請求逾時 (ms):" },
- "aiContextTimeoutHelp": { "message": "等待 AI 回應的最長時間" },
- "aiContextRateLimitLabel": { "message": "速率限制 (請求/分鐘):" },
- "aiContextRateLimitHelp": { "message": "每分鐘最大請求數" },
- "aiContextCacheEnabledLabel": { "message": "啟用快取:" },
- "aiContextCacheEnabledHelp": { "message": "快取分析結果以減少 API 呼叫" },
- "aiContextRetryAttemptsLabel": { "message": "重試次數:" },
- "aiContextRetryAttemptsHelp": { "message": "重試失敗請求的次數" },
- "showAdvancedSettings": { "message": "顯示進階設定" },
- "hideAdvancedSettings": { "message": "隱藏進階設定" }
-}
+ "aiContextTimeoutLabel": {
+ "message": "請求逾時 (ms):"
+ },
+ "aiContextTimeoutHelp": {
+ "message": "等待 AI 回應的最長時間"
+ },
+ "aiContextRateLimitLabel": {
+ "message": "速率限制 (請求/分鐘):"
+ },
+ "aiContextRateLimitHelp": {
+ "message": "每分鐘最大請求數"
+ },
+ "aiContextCacheEnabledLabel": {
+ "message": "啟用快取:"
+ },
+ "aiContextCacheEnabledHelp": {
+ "message": "快取分析結果以減少 API 呼叫"
+ },
+ "aiContextRetryAttemptsLabel": {
+ "message": "重試次數:"
+ },
+ "aiContextRetryAttemptsHelp": {
+ "message": "重試失敗請求的次數"
+ },
+ "showAdvancedSettings": {
+ "message": "顯示進階設定"
+ },
+ "hideAdvancedSettings": {
+ "message": "隱藏進階設定"
+ },
+ "sidepanelLoading": {
+ "message": "載入中..."
+ },
+ "sidepanelTabAIAnalysis": {
+ "message": "AI 分析"
+ },
+ "sidepanelTabWordsLists": {
+ "message": "單字列表"
+ },
+ "sidepanelAnalyzeButton": {
+ "message": "分析"
+ },
+ "sidepanelAnalyzing": {
+ "message": "分析中..."
+ },
+ "sidepanelWordsToAnalyze": {
+ "message": "待分析單字"
+ },
+ "sidepanelWordInputPlaceholder": {
+ "message": "點擊字幕中的單字以新增至分析..."
+ },
+ "sidepanelErrorRetry": {
+ "message": "重試"
+ },
+ "sidepanelResultsTitle": {
+ "message": "「%s」的結果"
+ },
+ "sidepanelSectionDefinition": {
+ "message": "定義"
+ },
+ "sidepanelSectionCultural": {
+ "message": "文化背景"
+ },
+ "sidepanelSectionHistorical": {
+ "message": "歷史背景"
+ },
+ "sidepanelSectionLinguistic": {
+ "message": "語言學分析"
+ },
+ "sidepanelMyWordsTitle": {
+ "message": "我的單字"
+ },
+ "sidepanelFeatureComingSoon": {
+ "message": "單字列表功能即將推出!"
+ },
+ "sidepanelFeatureComingSoonDesc": {
+ "message": "此功能目前正在開發中。在設定中啟用以嘗試預覽。"
+ },
+ "sidepanelErrorNoWords": {
+ "message": "未選擇要分析的單字"
+ },
+ "sidepanelErrorDisabled": {
+ "message": "AI 上下文分析已停用。請在設定中啟用。"
+ },
+ "sidepanelErrorGeneric": {
+ "message": "分析過程中發生錯誤。"
+ }
+}
\ No newline at end of file
diff --git a/background/handlers/messageHandler.js b/background/handlers/messageHandler.js
index 1130123..3fc21f7 100644
--- a/background/handlers/messageHandler.js
+++ b/background/handlers/messageHandler.js
@@ -121,15 +121,40 @@ class MessageHandler {
/**
* Set service dependencies (will be injected after services are created)
+ * Supports either positional args or an options object:
+ * setServices({ translationService, subtitleService, aiContextService?, sidePanelService? })
+ * For backward compatibility, the positional signature remains supported.
*/
- setServices(translationService, subtitleService, aiContextService = null) {
- this.translationService = translationService;
- this.subtitleService = subtitleService;
- this.aiContextService = aiContextService;
+ setServices(translationService, subtitleService, aiContextService = null, sidePanelService = null) {
+ /** @type {{translationService?: any, subtitleService?: any, aiContextService?: any, sidePanelService?: any}} */
+ let services;
+ if (
+ arguments.length === 1 &&
+ translationService &&
+ typeof translationService === 'object' &&
+ (Object.prototype.hasOwnProperty.call(translationService, 'translationService') ||
+ Object.prototype.hasOwnProperty.call(translationService, 'subtitleService'))
+ ) {
+ services = translationService;
+ } else {
+ services = {
+ translationService,
+ subtitleService,
+ aiContextService,
+ sidePanelService,
+ };
+ }
+
+ this.translationService = services.translationService || null;
+ this.subtitleService = services.subtitleService || null;
+ this.aiContextService = services.aiContextService || null;
+ this.sidePanelService = services.sidePanelService || null;
+
this.logger.debug('Services injected into message handler', {
- hasTranslation: !!translationService,
- hasSubtitle: !!subtitleService,
- hasAIContext: !!aiContextService,
+ hasTranslation: !!this.translationService,
+ hasSubtitle: !!this.subtitleService,
+ hasAIContext: !!this.aiContextService,
+ hasSidePanel: !!this.sidePanelService,
});
}
@@ -216,6 +241,24 @@ class MessageHandler {
sendResponse
);
+ case MessageActions.SIDEPANEL_OPEN:
+ return this.handleSidePanelOpenMessage(message, sender, sendResponse);
+
+ case MessageActions.SIDEPANEL_WORD_SELECTED:
+ return this.handleSidePanelWordSelectedMessage(message, sender, sendResponse);
+
+ case MessageActions.SIDEPANEL_SELECTION_SYNC:
+ return this.handleSidePanelSelectionSyncMessage(message, sender, sendResponse);
+
+ case MessageActions.SIDEPANEL_SET_ANALYZING:
+ return this.handleSidePanelSetAnalyzingMessage(message, sender, sendResponse);
+
+ case MessageActions.SIDEPANEL_PAUSE_VIDEO:
+ return this.handleSidePanelProxyToContent(message, sender, sendResponse);
+
+ case MessageActions.SIDEPANEL_RESUME_VIDEO:
+ return this.handleSidePanelProxyToContent(message, sender, sendResponse);
+
default:
this.logger.warn('Unknown message action', {
action: message.action,
@@ -967,6 +1010,194 @@ class MessageHandler {
return true;
}
+
+ /**
+ * Handle side panel open requests
+ */
+ handleSidePanelOpenMessage(message, sender, sendResponse) {
+ if (!this.sidePanelService) {
+ sendResponse({
+ success: false,
+ error: 'Side panel service not available',
+ });
+ return true;
+ }
+
+ const tabId = sender.tab?.id;
+ if (!tabId) {
+ sendResponse({
+ success: false,
+ error: 'No tab ID available',
+ });
+ return true;
+ }
+
+ this.logger.debug('Handling side panel open request', { tabId });
+
+ // Optionally store open reason before opening (do NOT override activeTab to avoid UI flips)
+ try {
+ if (message.options?.openReason) {
+ this.sidePanelService.updateTabState(tabId, {
+ ...(message.options.openReason
+ ? { openReason: message.options.openReason }
+ : {}),
+ });
+ }
+ } catch (_) {}
+
+ // Attempt to open the side panel immediately to preserve user gesture
+ this.sidePanelService
+ .openSidePanelImmediate(tabId, message.options || {})
+ .then((result) => {
+ sendResponse(result);
+ })
+ .catch((error) => {
+ this.logger.error('Failed to open side panel (immediate)', error, { tabId });
+ sendResponse({
+ success: false,
+ error: error.message || 'Failed to open side panel',
+ });
+ });
+
+ return true; // Async response
+ }
+
+ /**
+ * Handle word selection events from content scripts
+ */
+ handleSidePanelWordSelectedMessage(message, sender, sendResponse) {
+ if (!this.sidePanelService) {
+ sendResponse({
+ success: false,
+ error: 'Side panel service not available',
+ });
+ return true;
+ }
+
+ const tabId = sender.tab?.id;
+ if (!tabId) {
+ sendResponse({
+ success: false,
+ error: 'No tab ID available',
+ });
+ return true;
+ }
+
+ this.logger.debug('Handling word selection from content script', {
+ tabId,
+ word: message.word,
+ });
+
+ this.sidePanelService
+ .forwardWordSelection(tabId, message)
+ .then(() => {
+ sendResponse({ success: true });
+ })
+ .catch((error) => {
+ this.logger.error('Failed to forward word selection', error, {
+ tabId,
+ });
+ sendResponse({
+ success: false,
+ error: error.message || 'Failed to forward word selection',
+ });
+ });
+
+ return true; // Async response
+ }
+
+ handleSidePanelSelectionSyncMessage(message, sender, sendResponse) {
+ if (!this.sidePanelService) {
+ sendResponse({
+ success: false,
+ error: 'Side panel service not available',
+ });
+ return true;
+ }
+
+ const tabId = sender.tab?.id;
+ if (!tabId) {
+ sendResponse({
+ success: false,
+ error: 'No tab ID available',
+ });
+ return true;
+ }
+
+ this.sidePanelService
+ .forwardSelectionSync(tabId, message?.data ?? message)
+ .then(() => {
+ sendResponse({ success: true });
+ })
+ .catch((error) => {
+ this.logger.error('Failed to forward selection sync', error, {
+ tabId,
+ });
+ sendResponse({
+ success: false,
+ error: error.message || 'Failed to forward selection sync',
+ });
+ });
+
+ return true;
+ }
+
+ /**
+ * Proxy a side panel or content message to the tab's content script
+ */
+ handleSidePanelProxyToContent(message, sender, sendResponse) {
+ try {
+ const tabId = sender.tab?.id;
+ if (!tabId) {
+ sendResponse({ success: false, error: 'No tab ID available' });
+ return false;
+ }
+ chrome.tabs.sendMessage(tabId, message)
+ .then(() => sendResponse({ success: true }))
+ .catch((error) => {
+ this.logger.warn('Proxy to content failed', { error: error.message, action: message.action });
+ sendResponse({ success: false, error: error.message });
+ });
+ return true;
+ } catch (error) {
+ this.logger.warn('Error in proxy to content', { error: error.message, action: message.action });
+ try { sendResponse({ success: false, error: error.message }); } catch (_) {}
+ return false;
+ }
+ }
+
+ /**
+ * Handle analyzing state update from side panel
+ * Broadcasts to content script to block/unblock word clicks
+ */
+ handleSidePanelSetAnalyzingMessage(message, sender, sendResponse) {
+ const tabId = sender.tab?.id;
+ if (!tabId) {
+ sendResponse({ success: false, error: 'No tab ID available' });
+ return false;
+ }
+
+ const isAnalyzing = !!message.isAnalyzing;
+ this.logger.debug('Setting analyzing state', { tabId, isAnalyzing });
+
+ // Store state in side panel service
+ if (this.sidePanelService) {
+ this.sidePanelService.updateTabState(tabId, { isAnalyzing });
+ }
+
+ // Forward to content script to block word clicks
+ chrome.tabs.sendMessage(tabId, {
+ action: MessageActions.SIDEPANEL_SET_ANALYZING,
+ isAnalyzing,
+ }).then(() => {
+ sendResponse({ success: true });
+ }).catch((error) => {
+ this.logger.warn('Failed to send analyzing state to content script', error, { tabId });
+ sendResponse({ success: true }); // Don't fail the side panel
+ });
+
+ return true; // Async response
+ }
}
// Export singleton instance
diff --git a/background/index.js b/background/index.js
index 558fbae..28fa76c 100644
--- a/background/index.js
+++ b/background/index.js
@@ -12,6 +12,7 @@ import { translationProviders } from './services/translationService.js';
import { subtitleService } from './services/subtitleService.js';
import { batchTranslationQueue } from './services/batchTranslationQueue.js';
import { aiContextService } from './services/aiContextService.js';
+import { sidePanelService } from './services/sidePanelService.js';
import { loggingManager } from './utils/loggingManager.js';
import { messageHandler } from './handlers/messageHandler.js';
import { configService } from '../services/configService.js';
@@ -53,6 +54,10 @@ async function initializeServices() {
await aiContextService.initialize();
backgroundLogger.info('AI context service initialized');
+ // Initialize side panel service
+ await sidePanelService.initialize();
+ backgroundLogger.info('Side panel service initialized');
+
// Initialize message handler
messageHandler.initialize();
backgroundLogger.info('Message handler initialized');
@@ -74,21 +79,27 @@ async function initializeServices() {
'config',
'logging',
]);
+ serviceRegistry.register('sidePanel', sidePanelService, [
+ 'config',
+ 'logging',
+ ]);
serviceRegistry.register('logging', loggingManager, ['config']);
serviceRegistry.register('config', configService, []);
serviceRegistry.register('messageHandler', messageHandler, [
'translation',
'subtitle',
'aiContext',
+ 'sidePanel',
]);
backgroundLogger.info('Services registered in service registry');
// Inject services into message handler
- messageHandler.setServices(
- translationProviders,
+ messageHandler.setServices({
+ translationService: translationProviders,
subtitleService,
- aiContextService
- );
+ aiContextService,
+ sidePanelService,
+ });
backgroundLogger.info('Services injected into message handler');
// Initialize default settings using the configuration service
@@ -141,5 +152,6 @@ export {
subtitleService,
loggingManager,
messageHandler,
+ sidePanelService,
backgroundLogger,
};
diff --git a/background/parsers/netflixParser.js b/background/parsers/netflixParser.js
index 1c4d581..d71f860 100644
--- a/background/parsers/netflixParser.js
+++ b/background/parsers/netflixParser.js
@@ -94,21 +94,61 @@ class NetflixParser {
hasTargetTrack: !!targetTrack,
});
- // Process original language subtitles
+ // Process original language subtitles (with fallback selection)
let originalVttText = '';
let sourceLanguage = originalLanguage;
- if (originalTrack) {
+ // Choose effective original track with fallback when requested language is unavailable
+ let selectedOriginalTrack = originalTrack;
+ if (!selectedOriginalTrack) {
+ // Try English first
+ const englishCandidate = availableLanguages.find(
+ (lang) =>
+ lang?.normalizedCode === 'en' ||
+ (typeof lang?.normalizedCode === 'string' &&
+ lang.normalizedCode.startsWith('en'))
+ );
+
+ const fallbackCandidate =
+ englishCandidate || availableLanguages[0] || null;
+
+ if (fallbackCandidate) {
+ this.logger.info(
+ 'Requested original language not found, using fallback',
+ {
+ requested: normalizeLanguageCode(originalLanguage),
+ fallbackDisplayName: fallbackCandidate.displayName,
+ fallbackNormalized:
+ fallbackCandidate.normalizedCode,
+ }
+ );
+ selectedOriginalTrack = {
+ language: fallbackCandidate.rawCode,
+ trackType: fallbackCandidate.trackType,
+ downloadUrl: fallbackCandidate.downloadUrl,
+ };
+ } else {
+ this.logger.warn(
+ 'No available languages to fallback to for Netflix subtitles'
+ );
+ }
+ }
+
+ if (selectedOriginalTrack) {
this.logger.debug('Processing original track', {
- language: originalTrack.language,
- trackType: originalTrack.trackType,
+ language: selectedOriginalTrack.language,
+ trackType: selectedOriginalTrack.trackType,
});
const originalSubtitleText =
- await this.fetchNetflixSubtitleContent(originalTrack);
+ await this.fetchNetflixSubtitleContent(
+ selectedOriginalTrack
+ );
originalVttText =
ttmlParser.convertTtmlToVtt(originalSubtitleText);
- sourceLanguage = normalizeLanguageCode(originalTrack.language);
+ sourceLanguage = normalizeLanguageCode(
+ selectedOriginalTrack.language
+ );
}
// Process target language subtitles
@@ -155,7 +195,7 @@ class NetflixParser {
targetLanguage: normalizeLanguageCode(targetLanguage),
useNativeTarget: useNativeTarget,
availableLanguages: availableLanguages,
- url: originalTrack?.downloadUrl || 'Netflix TTML',
+ url: selectedOriginalTrack?.downloadUrl || 'Netflix TTML',
};
this.logger.info('Netflix subtitle processing completed', {
diff --git a/background/services/sidePanelService.js b/background/services/sidePanelService.js
new file mode 100644
index 0000000..47bc9d3
--- /dev/null
+++ b/background/services/sidePanelService.js
@@ -0,0 +1,626 @@
+/**
+ * Side Panel Service
+ *
+ * Manages Chrome Side Panel API integration for the AI Context feature.
+ * Handles opening/closing the side panel, routing messages, and managing state.
+ *
+ * @author DualSub Extension
+ * @version 2.5.0
+ */
+
+import Logger from '../../utils/logger.js';
+import { configService } from '../../services/configService.js';
+import { MessageActions } from '../../content_scripts/shared/constants/messageActions.js';
+
+class SidePanelService {
+ constructor() {
+ this.logger = Logger.create('SidePanelService', configService);
+ this.initialized = false;
+ this.activeConnections = new Map(); // Track connections from side panels
+ this.tabStates = new Map(); // Track state per tab
+ // New: window-scoped connection tracking
+ this.activeConnectionsByWindow = new Map(); // Map
- {t('aboutDevelopment', 'Developed by ')}{' '} -
+{t('aboutDevelopment', 'Developed by ')}
); diff --git a/options/components/sections/AdvancedSection.jsx b/options/components/sections/AdvancedSection.jsx new file mode 100644 index 0000000..9200293 --- /dev/null +++ b/options/components/sections/AdvancedSection.jsx @@ -0,0 +1,185 @@ +import React from 'react'; +import { SettingCard } from '../SettingCard.jsx'; +import { ToggleSwitch } from '../ToggleSwitch.jsx'; + +/** + * Advanced Settings Section + * + * Advanced configuration options for side panel behavior, + * video control, and state persistence. + */ +export function AdvancedSection({ t, settings, onSettingChange }) { + return ( ++ {t( + 'useSidePanelDescription', + 'Use Chrome Side Panel instead of modal for AI context analysis. Disable to use the legacy modal (Chrome 114+ required for side panel).' + )} +
+ ++ {t( + 'autoOpenSidePanelDescription', + 'Automatically open the side panel when you click on subtitle words.' + )} +
+ ++ {t( + 'persistAcrossTabsDescription', + 'Keep the side panel open and preserve selected words when switching between tabs.' + )} +
+ ++ {t( + 'autoPauseVideoDescription', + 'Automatically pause the video when you open the side panel to select words.' + )} +
+ ++ {t( + 'autoResumeVideoDescription', + 'Automatically resume video playback when you close the side panel.' + )} +
+