diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..c6d1f23 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,59 @@ +name: Tests + +on: + pull_request: + branches: [main] + push: + branches: [main] + paths-ignore: + - '**.md' + - 'docs/**' + - '.github/workflows/claude*.yml' + +permissions: + contents: read + +jobs: + backend: + name: Backend Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Set up Python + run: uv python install + + - name: Install dependencies + run: uv sync + + - name: Run tests + run: uv run pytest tests/ -v + + frontend: + name: Frontend Tests + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test diff --git a/frontend/src/lib/locales/en-US/index.ts b/frontend/src/lib/locales/en-US/index.ts index 0c3c36e..e02bc17 100644 --- a/frontend/src/lib/locales/en-US/index.ts +++ b/frontend/src/lib/locales/en-US/index.ts @@ -36,22 +36,16 @@ export const enUS = { warning: "Warning", error: "Error", success: "Success", - sessions: "Sessions", model: "Model", - send: "Send", back: "Back", next: "Next", done: "Done", processing: "Processing...", creating: "Creating...", - tokenCount: "Tokens", - charCount: "Chars", linked: "Linked", - added: "Added on {date}", adding: "Adding...", addSelected: "Add Selected", customModel: "Custom Model", - messages: "Messages", failed: "failed", current: "Current", save: "Save", @@ -72,7 +66,6 @@ export const enUS = { unknown: "Unknown", notes: "Notes", chat: "Chat", - details: "Details", deleteForever: "Delete Forever", connectionError: "Connection Error", unableToConnect: "Unable to connect to the API server", @@ -85,7 +78,6 @@ export const enUS = { checkConsoleLogs: "Check browser console for detailed logs (look for 🔧 [Config] messages)", yes: "Yes", no: "No", - simple: "Simple", saving: "Saving...", description: "Description", saveToNote: "Save to note", @@ -103,7 +95,6 @@ export const enUS = { nameRequired: "Name is required", modelConfiguration: "Model Configuration", resetToDefault: "Reset to Default", - notFound: "Not found", reasoning: "Reasoning", searchTerms: "Search Terms", strategy: "Strategy", @@ -112,14 +103,12 @@ export const enUS = { notebookLabel: "Notebook: {name}", itemNotFound: "This {type} could not be found", accessibility: { - navigation: "Navigation", transformationViews: "Transformation views", searchKB: "Ask or search your knowledge base", enterQuestion: "Enter your question to ask the knowledge base", enterSearch: "Enter search query", searchKBBtn: "Search knowledge base", podcastViews: "Podcast views", - chatSessions: "Chat sessions", ytVideo: "YouTube video", askResponse: "Ask Response", searchNotebooks: "Search notebooks", @@ -127,7 +116,6 @@ export const enUS = { url: "URL", errorDetails: "Error Details", editTransformation: "Edit Transformation", - comingSoon: "Coming soon", retry: "Try Again", traditionalChinese: "繁體中文", portuguese: "Português", @@ -165,7 +153,6 @@ export const enUS = { failedToSendMessage: "Failed to send message", unauthorized: "Unauthorized access, please check your password", invalidPassword: "Invalid password", - missingAuth: "Missing authorization", embeddingModelRequired: "This feature requires an embedding model. Please configure one in the Models section.", strategyModelNotFound: "Strategy model not found", answerModelNotFound: "Answer model not found", @@ -206,7 +193,6 @@ export const enUS = { passwordPlaceholder: "Password", signingIn: "Signing in...", signIn: "Sign In", - unhandledError: "Unhandled error during login", connectErrorHint: "Unable to connect to server. Please check if the API is running.", }, navigation: { @@ -226,7 +212,6 @@ export const enUS = { nav: "Navigation", language: "Toggle language", theme: "Theme", - search: "Search", ask: "Ask", }, notebooks: { @@ -248,12 +233,8 @@ export const enUS = { keepExclusiveSourcesLabel: "Unlink and keep them", activeNotebooks: "Active Notebooks", archivedNotebooks: "Archived Notebooks", - emptyDescription: "Start by creating your first notebook to organize your research.", - noActiveNotebooks: "No active notebooks", - noArchivedNotebooks: "No archived notebooks", notFound: "Notebook not found", notFoundDesc: "The requested notebook does not exist.", - noDescription: "No description...", updated: "Updated", namePlaceholder: "Notebook name", addDescription: "Add description...", @@ -278,10 +259,7 @@ export const enUS = { add: "Add Source", addNew: "Add New Source", addExisting: "Add Existing Source", - empty: "No sources yet", - emptyDesc: "Add your first source to start building your knowledge base.", delete: "Delete Source", - deleteMsg: "Are you sure you want to delete this source? This action cannot be undone.", statusPreparing: "Preparing", statusQueued: "Queued", statusProcessing: "Processing", @@ -321,7 +299,6 @@ export const enUS = { sourceRequeued: "Source Retry Queued", sourceRequeuedDesc: "The source has been requeued for processing.", failedToRetry: "Retry Failed", - failedToRetryDesc: "Failed to retry source processing. Please try again.", sourcesAddedToNotebook: "{count} source(s) added to notebook", failedToAddSourcesToNotebook: "Failed to add sources to notebook", partialAddSuccess: "{success} source(s) added, {failed} failed", @@ -359,34 +336,31 @@ export const enUS = { deleteInsight: "Delete Insight", deleteInsightConfirm: "Are you sure you want to delete this insight? This action cannot be undone.", insightGenerationStarted: "Insight generation started. It will appear shortly.", - deleteNoteConfirm: 'Are you sure you want to delete this note? This action cannot be undone.', - editNote: 'Edit note', - createNote: 'Create note', - addTitle: 'Add a title...', - untitledNote: 'Untitled Note', - writeNotePlaceholder: 'Write your note content here...', - saveNote: 'Save Note', - createNoteBtn: 'Create Note', - noNotesYet: "No notes yet", + editNote: "Edit note", + createNote: "Create note", + addTitle: "Add a title...", + untitledNote: "Untitled Note", + writeNotePlaceholder: "Write your note content here...", + saveNote: "Save Note", + createNoteBtn: "Create Note", createFirstNote: "Create your first note to capture insights and observations.", - deleteNote: "Delete Note", - urlLabel: 'URL(s) *', - fileLabel: 'File(s) *', - textContentLabel: 'Text Content *', - enterUrlsPlaceholder: 'Enter URLs, one per line\nhttps://example.com/article1\nhttps://example.com/article2', - batchUrlHint: 'Paste multiple URLs (one per line) to batch import', - invalidUrlsDetected: 'Invalid URLs detected:', - lineLabel: 'Line {line}', - fixInvalidUrls: 'Please fix or remove invalid URLs to continue', - selectMultipleFilesHint: 'Select multiple files to batch import. Supported: Documents (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD), Media (MP4, MP3, WAV, M4A), Images (JPG, PNG), Archives (ZIP)', - selectedFiles: 'Selected files:', - textPlaceholder: 'Paste or type your content here...', - htmlDetected: 'HTML content detected. It will be converted to Markdown after processing.', - titlePlaceholder: 'Give your source a descriptive title', - batchTitlesAuto: 'Titles will be automatically generated for each source.', - batchCommonSettings: 'The same notebooks and transformations will be applied to all items.', - urlsCount: '{count} URL(s)', - filesCount: '{count} file(s)', + urlLabel: "URL(s) *", + fileLabel: "File(s) *", + textContentLabel: "Text Content *", + enterUrlsPlaceholder: "Enter URLs, one per line\nhttps://example.com/article1\nhttps://example.com/article2", + batchUrlHint: "Paste multiple URLs (one per line) to batch import", + invalidUrlsDetected: "Invalid URLs detected:", + lineLabel: "Line {line}", + fixInvalidUrls: "Please fix or remove invalid URLs to continue", + selectMultipleFilesHint: "Select multiple files to batch import. Supported: Documents (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD), Media (MP4, MP3, WAV, M4A), Images (JPG, PNG), Archives (ZIP)", + selectedFiles: "Selected files:", + textPlaceholder: "Paste or type your content here...", + htmlDetected: "HTML content detected. It will be converted to Markdown after processing.", + titlePlaceholder: "Give your source a descriptive title", + batchTitlesAuto: "Titles will be automatically generated for each source.", + batchCommonSettings: "The same notebooks and transformations will be applied to all items.", + urlsCount: "{count} URL(s)", + filesCount: "{count} file(s)", addSource: "Add Source", notEmbeddedAlert: "Content Not Embedded", notEmbeddedDesc: "This content hasn't been embedded for vector search. Embedding enables advanced search capabilities and better content discovery.", @@ -403,7 +377,6 @@ export const enUS = { retryProcessing: "Retry Processing", deleteSource: "Delete Source", retry: "Retry", - progress: "Progress", addExistingTitle: "Add Existing Sources", addExistingDesc: "Select existing sources from across all your notebooks to add to the current one.", searchPlaceholder: "Search sources by name or URL...", @@ -435,8 +408,6 @@ export const enUS = { batchFailed: "Failed to create all {count} sources", batchPartial: "{success} succeeded, {failed} failed", submittingSource: "Submitting source for processing...", - contentRequired: "Please provide the required content for the selected source type", - titleRequiredForText: "Title is required for text sources", processingBatchSources: "Processing {count} sources. This may take a few moments.", processingSource: "Your source is being processed. This may take a few moments.", maxFilesAllowed: "Maximum {count} files allowed per batch", @@ -445,26 +416,20 @@ export const enUS = { sessions: "Sessions", sessionTitlePlaceholder: "Type a title here...", noSessions: "No chat sessions yet", - startChatting: "Start chatting about your sources.", deleteSession: "Delete Session", deleteSessionDesc: "Are you sure you want to delete this chat session? This action cannot be undone.", sendPlaceholder: "Ask anything about your sources...", - newChat: "New Chat", sessionsTitle: "Chat Sessions", - clearhistory: "Clear History", - renameSession: "Rename Session", - noSourcesLinked: "No sources linked", - thinking: "AI is thinking...", chatWith: "Chat with {name}", startConversation: "Start a conversation about this {type}", askQuestions: "Ask questions to understand the content better", pressToSend: "Press {key} to send", model: "Model", - createToStart: 'Create a session to start.', - chatWithNotebook: 'Chat with Notebook', - unableToLoadChat: 'Unable to load chat', - noDescription: 'No description', - startByCreating: 'Start by creating your first notebook to organize your research.', + createToStart: "Create a session to start.", + chatWithNotebook: "Chat with Notebook", + unableToLoadChat: "Unable to load chat", + noDescription: "No description", + startByCreating: "Start by creating your first notebook to organize your research.", messagesCount: "{count} messages", sessionCreated: "Chat session created", sessionUpdated: "Session updated", @@ -508,8 +473,6 @@ export const enUS = { saveSuccess: "Successfully saved to notebook", saveError: "Failed to save to notebook", selectNotebook: "Select Notebook", - createNewNotebook: "Create New Notebook", - cancel: "Cancel", searchAndAsk: "Search & Ask", searchResultsFor: "Search results for “{query}”", askAbout: "Ask about “{query}”", @@ -734,8 +697,6 @@ export const enUS = { speakerCountMin: "At least one speaker is required", speakerCountMax: "You can configure up to 4 speakers", delete: "Delete", - unknown: "Unknown", - deleteSuccess: "Podcast deleted successfully", failedToDelete: "Failed to delete podcast", }, settings: { @@ -772,13 +733,8 @@ export const enUS = { title: "AdvancedTools", desc: "Advanced tools and utilities for power users", systemInfo: "System Info", - systemInfoDesc: "View the status of underlying system components", rebuildEmbeddings: "Rebuild Embeddings", rebuildEmbeddingsDesc: "Rebuild vector search index for all sources", - rebuildWarning: "This action can be very time-consuming depending on the number of sources you have. It will clear existing vector indices and re-generate embeddings for everything.", - startRebuild: "Start Rebuild", - rebuilding: "Rebuilding...", - rebuildSuccess: "Embedding rebuild started successfully", currentVersion: "Current Version", latestVersion: "Latest Version", status: "Status", @@ -823,105 +779,53 @@ export const enUS = { defaultPrompt: "Default Transformation Prompt", defaultPromptDesc: "This will be added to all your transformation prompts", defaultPromptPlaceholder: "Enter your default transformation instructions...", - saveDefault: "Save Default", listTitle: "Custom Transformations", createNew: "Create New", - testInPlayground: "Test in Playground", inputLabel: "Input Text", - inputPlaceholder: 'Enter some text to transform...', - outputLabel: 'Output', - runTest: 'Run Transformation', - running: 'Running...', - selectToStart: 'Select a transformation to start', - name: 'Name', - namePlaceholder: 'Unique identifier, e.g. key_topics', - titlePlaceholder: 'Displayed title, defaults to name', - promptPlaceholder: 'Write the prompt that will power this transformation...', - descriptionPlaceholder: 'Describe what this transformation does.', - suggestDefault: 'Suggest by default on new sources', - promptHint: 'Prompts should be written with the source content in mind. You can ask the model to summarise, extract insights, or produce structured outputs such as tables.', - createSuccess: 'Transformation created successfully', - updateSuccess: 'Transformation updated successfully', - deleteSuccess: 'Transformation deleted successfully', + inputPlaceholder: "Enter some text to transform...", + outputLabel: "Output", + runTest: "Run Transformation", + running: "Running...", + selectToStart: "Select a transformation to start", + name: "Name", + namePlaceholder: "Unique identifier, e.g. key_topics", + titlePlaceholder: "Displayed title, defaults to name", + promptPlaceholder: "Write the prompt that will power this transformation...", + descriptionPlaceholder: "Describe what this transformation does.", + suggestDefault: "Suggest by default on new sources", + promptHint: "Prompts should be written with the source content in mind. You can ask the model to summarise, extract insights, or produce structured outputs such as tables.", + createSuccess: "Transformation created successfully", + updateSuccess: "Transformation updated successfully", + deleteSuccess: "Transformation deleted successfully", noTransformations: "No transformations yet", createOne: "Create a transformation to get started", - deleteDesc: "Deleting this transformation cannot be undone.", selectModel: "Select a model", deleteConfirm: "Are you sure you want to delete this transformation?", model: "Model", systemPrompt: "System Prompt", - type: "Type", - extraction: "Extraction", - summary: "Summary", - custom: "Custom", - saveChanges: "Save Changes", overrideModelDesc: "Override the default model for this chat session. Leave empty to use the system default.", sessionUseReplacement: "This session will use {name} instead of the default model.", systemDefault: "System Default", }, models: { - title: "Model Management", - desc: "Configure AI models for different purposes across Open Notebook", - failedToLoad: "Failed to load models data", - language: "Language Models", embedding: "Embedding Models", tts: "Text to Speech (TTS)", stt: "Speech to Text (STT)", - providers: "Providers", - defaultModels: "Default Models", - status: "Status", - notConfigured: "Not configured", - active: "Active", - inactive: "Inactive", - configure: "Configure", - saveChanges: "Save Changes", - addModel: "Add Model", - modelName: "Model Name", provider: "Provider", apiKey: "API Key", - baseUrl: "Base URL", - capabilities: "Capabilities", - enabled: "Enabled", - disabled: "Disabled", - deleteConfirm: "Are you sure you want to delete this model?", deleteSuccess: "Model deleted successfully", saveSuccess: "Model saved successfully", - providerStatus: "Provider Status", - connectionOk: "Connection OK", - connectionFailed: "Connection failed", - changeEmbeddingWarning: "Changing the default embedding model will affect new sources. Existing sources might need to be re-indexed.", - changeEmbeddingTitle: "Change Default Embedding Model?", - aiProviders: "AI Providers", - providerConfigDesc: "Configure providers through environment variables to enable their models.", - configuredCount: "{count} of {total} configured", noModels: "No models", - learnMore: "Learn how to configure providers →", - seeLess: "See less", - seeAll: "See all {count} providers", - language_models: "Language Models", - embedding_models: "Embedding Models", - text_to_speech: "Text to Speech (TTS)", - speech_to_text: "Speech to Text (STT)", - languageDesc: "Chat, transformations, and text generation", - embeddingDesc: "Semantic search and vector embeddings", - ttsDesc: "Generate audio from text", - sttDesc: "Transcribe audio to text", - all: "All", - noModelsConfigured: "No models configured", - noProviderModelsConfigured: "No {provider} models configured", - showMore: "Show {count} more", discoverModels: "Discover Models", noModelsFound: "No models found from this provider", modelType: "Model Type", modelTypeHint: "Select the type for the models you want to add. If you need different types, add them in separate batches.", deleteModel: "Delete Model", - deleteModelDesc: "Are you sure you want to delete \"{name}\"? This action cannot be undone.", defaultAssignments: "Default Model Assignments", defaultAssignmentsDesc: "Configure which models to use for different purposes across Open Notebook", missingRequiredModels: "Missing required models: {models}. Open Notebook may not function properly without these.", selectModelPlaceholder: "Select a model", requiredModelPlaceholder: "⚠️ Required - Select a model", - whichModelToChoose: "Which model should I choose? →", chatModelLabel: "Chat Model", chatModelDesc: "Used for chat conversations", transformationModelLabel: "Transformation Model", @@ -936,16 +840,9 @@ export const enUS = { ttsModelDesc: "Used for podcast generation", sttModelLabel: "Speech-to-Text Model", sttModelDesc: "Used for audio transcription", - addSpecificModel: "Add {type} Model", - addSpecificModelDesc: "Configure a new {type} model from available providers.", - noProvidersForType: "No providers available for {type} models", selectProviderPlaceholder: "Select a provider", providerRequired: "Provider is required", - modelNameRequired: "Model name is required", modelRequired: "Model is required", - adding: "Adding...", - azureHint: "For Azure, use the deployment name as the model name", - enterModelName: "Enter model name", embeddingChangeTitle: "Embedding Model Change", embeddingChangeConfirm: "You are about to change your embedding model from {from} to {to}.", rebuildRequired: "Important: Rebuild Required", @@ -959,7 +856,6 @@ export const enUS = { changeModelOnly: "Change Model Only", changeAndRebuild: "Change & Go to Rebuild", autoAssign: "Auto-assign Defaults", - autoAssignDesc: "Automatically assign the best available model for each slot", autoAssigning: "Assigning...", autoAssignSuccess: "{count} default models automatically assigned", autoAssignNoModels: "No models available to assign. Please sync models first.", @@ -967,25 +863,16 @@ export const enUS = { testModel: "Test Model", testModelSuccess: "Model Test Passed", testModelFailed: "Model Test Failed", - testingModel: "Testing model...", searchOrAddModel: "Search or type a model name...", - addCustomModel: 'Add "{name}"', + addCustomModel: "Add \"{name}\"", }, apiKeys: { title: "Configure your AI with your own API keys", description: "Store API keys securely in the database to enable AI providers in Open Notebook.", - loadFailed: "Failed to load API keys status", encryptionRequired: "Encryption key not configured", encryptionRequiredDescription: "Set the OPEN_NOTEBOOK_ENCRYPTION_KEY environment variable to any secret string to enable storing API keys in the database.", configured: "Configured", notConfigured: "Not configured", - sourceDatabase: "Database", - sourceEnvironment: "Environment", - enterApiKey: "Enter your API key", - enterBaseUrl: "Enter the base URL", - saveSuccess: "API key saved successfully", - deleteSuccess: "API key deleted successfully", - fromEnvironmentHint: "This key is set via environment variable. Save a new key to override it in the database.", migrationAvailable: "Environment Variables Detected", migrationDescription: "{count} API key(s) are configured via environment variables and can be migrated to the database for easier management.", migrateToDatabase: "Migrate to Database", @@ -993,67 +880,29 @@ export const enUS = { migrationSuccess: "{count} API key(s) migrated successfully", migrationErrors: "{count} key(s) failed to migrate", migrationNothingToMigrate: "All keys are already in the database", - serviceType: "Service Type", - serviceLlm: "Language Model (LLM)", - serviceEmbedding: "Embedding", - serviceStt: "Speech to Text (STT)", - serviceTts: "Text to Speech (TTS)", - serviceEndpoints: "Service Endpoints (optional)", - azureEndpointsHint: "Configure different endpoints for each service type if needed.", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "Configure an OpenAI-compatible API endpoint. Each service type can have its own configuration.", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "Learn how to configure API keys →", testConnection: "Test Connection", - testing: "Testing...", testSuccess: "Connection successful", testFailed: "Connection test failed", syncModels: "Sync Models", - syncing: "Syncing...", syncSuccess: "Discovered {discovered} models, added {new} new", syncNoNew: "Discovered {count} models, all already registered", syncFailed: "Failed to sync models", - syncAllModels: "Sync All Providers", - syncAllSuccess: "Discovered {discovered} models across all providers, added {new} new", - modelsConfigured: "{count} models", - noModelsConfigured: "No models", - viewModels: "View Models", - supportedTypes: "Supported types", - typeLanguage: "Language", - typeEmbedding: "Embedding", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "API Endpoint", getApiKey: "Get API Key", vertexProject: "GCP Project ID", vertexLocation: "Region", vertexCredentials: "Service Account JSON Path", - vertexCredentialsHint: "Path to your Google Cloud service account JSON file inside the container.", - - // Multi-config translations - configsCount: "{count} configs", - configuredMultiple: "Configured", addConfig: "Add Configuration", editConfig: "Edit Configuration", deleteConfig: "Delete Configuration", - setAsDefault: "Set as Default", - defaultBadge: "Default", - defaultDescription: "Default configuration for this provider", configName: "Configuration Name", configNameHint: "A descriptive name for this configuration (e.g., 'Production', 'Development')", baseUrl: "Base URL", - baseUrlHint: "Default: {url}", baseUrlOverrideHint: "Only change this if you need to override the provider's default API endpoint.", - ollamaApiKeyHint: "Only required for Ollama Cloud. Leave empty for local Ollama.", - noConfigs: "No configurations yet", - noConfigsHint: "Add a configuration to start using this provider", deleteConfigConfirm: "Are you sure you want to delete '{name}'? This cannot be undone.", - setDefaultConfirm: "Set '{name}' as the default configuration?", configSaveSuccess: "Configuration saved successfully", configUpdateSuccess: "Configuration updated successfully", configDeleteSuccess: "Configuration deleted successfully", - configSetDefaultSuccess: "Default configuration updated", - apiKeyHint: "Enter your API key for this configuration", apiKeyEditHint: "Leave blank to keep the existing API key", }, setupBanner: { diff --git a/frontend/src/lib/locales/index.test.ts b/frontend/src/lib/locales/index.test.ts index 731710f..11d760d 100644 --- a/frontend/src/lib/locales/index.test.ts +++ b/frontend/src/lib/locales/index.test.ts @@ -1,56 +1,68 @@ import { describe, it, expect } from 'vitest' +import fs from 'fs' +import path from 'path' +import { resources } from './index' import { enUS } from './en-US' -import { zhCN } from './zh-CN' -import { zhTW } from './zh-TW' -import { jaJP } from './ja-JP' -import { ruRU } from './ru-RU' -describe('Internationalization Locales Integrity', () => { - const getKeys = (obj: Record, prefix = ''): string[] => { - return Object.keys(obj).reduce((res: string[], el) => { - const val = obj[el] - if (typeof val === 'object' && val !== null && !Array.isArray(val)) { - return [...res, ...getKeys(val as Record, prefix + el + '.')] - } - return [...res, prefix + el] - }, []) - } +const getKeys = (obj: Record, prefix = ''): string[] => { + return Object.keys(obj).reduce((res: string[], el) => { + const val = obj[el] + if (typeof val === 'object' && val !== null && !Array.isArray(val)) { + return [...res, ...getKeys(val as Record, prefix + el + '.')] + } + return [...res, prefix + el] + }, []) +} +describe('Locale Parity', () => { const enKeys = getKeys(enUS) - const zhCNKeys = getKeys(zhCN) - const zhTWKeys = getKeys(zhTW) - const jaJPKeys = getKeys(jaJP) - const ruRUKeys = getKeys(ruRU) - it('zh-CN should have the same keys as en-US', () => { - const missingInZhCN = enKeys.filter(key => !zhCNKeys.includes(key)) - const extraInZhCN = zhCNKeys.filter(key => !enKeys.includes(key)) + const locales = Object.entries(resources).filter(([code]) => code !== 'en-US') - expect(missingInZhCN, `Missing keys in zh-CN: ${missingInZhCN.join(', ')}`).toEqual([]) - expect(extraInZhCN, `Extra keys in zh-CN: ${extraInZhCN.join(', ')}`).toEqual([]) - }) + it.each(locales.map(([code, resource]) => [code, resource] as const))( + '%s should have the same keys as en-US', + (code, resource) => { + const localeKeys = getKeys(resource.translation as Record) - it('zh-TW should have the same keys as en-US', () => { - const missingInZhTW = enKeys.filter(key => !zhTWKeys.includes(key)) - const extraInZhTW = zhTWKeys.filter(key => !enKeys.includes(key)) + const missing = enKeys.filter(key => !localeKeys.includes(key)) + const extra = localeKeys.filter(key => !enKeys.includes(key)) - expect(missingInZhTW, `Missing keys in zh-TW: ${missingInZhTW.join(', ')}`).toEqual([]) - expect(extraInZhTW, `Extra keys in zh-TW: ${extraInZhTW.join(', ')}`).toEqual([]) - }) - - it('ja-JP should have the same keys as en-US', () => { - const missingInJaJP = enKeys.filter(key => !jaJPKeys.includes(key)) - const extraInJaJP = jaJPKeys.filter(key => !enKeys.includes(key)) - - expect(missingInJaJP, `Missing keys in ja-JP: ${missingInJaJP.join(', ')}`).toEqual([]) - expect(extraInJaJP, `Extra keys in ja-JP: ${extraInJaJP.join(', ')}`).toEqual([]) - }) - - it('ru-RU should have the same keys as en-US', () => { - const missingInRuRU = enKeys.filter(key => !ruRUKeys.includes(key)) - const extraInRuRU = ruRUKeys.filter(key => !enKeys.includes(key)) - - expect(missingInRuRU, `Missing keys in ru-RU: ${missingInRuRU.join(', ')}`).toEqual([]) - expect(extraInRuRU, `Extra keys in ru-RU: ${extraInRuRU.join(', ')}`).toEqual([]) - }) + expect(missing, `Missing keys in ${code}: ${missing.join(', ')}`).toEqual([]) + expect(extra, `Extra keys in ${code}: ${extra.join(', ')}`).toEqual([]) + }, + ) +}) + +describe('Unused Key Detection', () => { + it( + 'all en-US leaf keys should be referenced in source files', + () => { + const srcDir = path.resolve(__dirname, '../../..') + const localesDir = path.resolve(__dirname) + + const files = fs.readdirSync(srcDir, { recursive: true }) as string[] + const sourceFiles = files.filter(f => { + const full = path.join(srcDir, f) + if (full.startsWith(localesDir)) return false + if (f.endsWith('.test.ts') || f.endsWith('.test.tsx')) return false + return f.endsWith('.ts') || f.endsWith('.tsx') + }) + + // Normalize optional chaining (t?.common?.key → t.common.key) + // so that keys like "common.errorDetails" match "common?.errorDetails" + const corpus = sourceFiles + .map(f => fs.readFileSync(path.join(srcDir, f), 'utf-8')) + .join('\n') + .replace(/\?\./g, '.') + + const leafKeys = getKeys(enUS) + const unused = leafKeys.filter(key => !corpus.includes(key)) + + expect( + unused, + `Found ${unused.length} unused i18n key(s):\n${unused.join('\n')}`, + ).toEqual([]) + }, + 30_000, + ) }) diff --git a/frontend/src/lib/locales/it-IT/index.ts b/frontend/src/lib/locales/it-IT/index.ts index beaa42f..4dfad9b 100644 --- a/frontend/src/lib/locales/it-IT/index.ts +++ b/frontend/src/lib/locales/it-IT/index.ts @@ -23,7 +23,7 @@ export const itIT = { english: "English", chinese: "简体中文", japanese: "日本語", - italian: "Italiano", + russian: "Русский", source: "Fonte", notebook: "Quaderno", podcast: "Podcast", @@ -36,22 +36,16 @@ export const itIT = { warning: "Attenzione", error: "Errore", success: "Successo", - sessions: "Sessioni", model: "Modello", - send: "Invia", back: "Indietro", next: "Avanti", done: "Fatto", processing: "Elaborazione...", creating: "Creazione...", - tokenCount: "Token", - charCount: "Caratteri", linked: "Collegato", - added: "Aggiunto il {date}", adding: "Aggiunta in corso...", addSelected: "Aggiungi selezionati", customModel: "Modello personalizzato", - messages: "Messaggi", failed: "fallito", current: "Corrente", save: "Salva", @@ -72,7 +66,6 @@ export const itIT = { unknown: "Sconosciuto", notes: "Note", chat: "Chat", - details: "Dettagli", deleteForever: "Elimina definitivamente", connectionError: "Errore di connessione", unableToConnect: "Impossibile connettersi al server API", @@ -85,7 +78,6 @@ export const itIT = { checkConsoleLogs: "Controlla la console del browser per log dettagliati (cerca i messaggi 🔧 [Config])", yes: "Sì", no: "No", - simple: "Semplice", saving: "Salvataggio...", description: "Descrizione", saveToNote: "Salva come nota", @@ -103,7 +95,6 @@ export const itIT = { nameRequired: "Il nome è obbligatorio", modelConfiguration: "Configurazione modello", resetToDefault: "Ripristina predefinito", - notFound: "Non trovato", reasoning: "Ragionamento", searchTerms: "Termini di ricerca", strategy: "Strategia", @@ -112,14 +103,12 @@ export const itIT = { notebookLabel: "Quaderno: {name}", itemNotFound: "Questo {type} non è stato trovato", accessibility: { - navigation: "Navigazione", transformationViews: "Viste trasformazioni", searchKB: "Chiedi o cerca nella tua base di conoscenza", enterQuestion: "Inserisci la tua domanda per interrogare la base di conoscenza", enterSearch: "Inserisci la query di ricerca", searchKBBtn: "Cerca nella base di conoscenza", podcastViews: "Viste podcast", - chatSessions: "Sessioni chat", ytVideo: "Video YouTube", askResponse: "Risposta alla domanda", searchNotebooks: "Cerca quaderni", @@ -127,7 +116,6 @@ export const itIT = { url: "URL", errorDetails: "Dettagli errore", editTransformation: "Modifica trasformazione", - comingSoon: "Prossimamente", retry: "Riprova", traditionalChinese: "繁體中文", portuguese: "Português", @@ -165,7 +153,6 @@ export const itIT = { failedToSendMessage: "Impossibile inviare il messaggio", unauthorized: "Accesso non autorizzato, controlla la password", invalidPassword: "Password non valida", - missingAuth: "Autenticazione mancante", embeddingModelRequired: "Questa funzionalità richiede un modello di embedding. Configurane uno nella sezione Modelli.", strategyModelNotFound: "Modello strategia non trovato", answerModelNotFound: "Modello risposta non trovato", @@ -206,7 +193,6 @@ export const itIT = { passwordPlaceholder: "Password", signingIn: "Accesso in corso...", signIn: "Accedi", - unhandledError: "Errore non gestito durante l'accesso", connectErrorHint: "Impossibile connettersi al server. Verifica che l'API sia in esecuzione.", }, navigation: { @@ -226,7 +212,6 @@ export const itIT = { nav: "Navigazione", language: "Cambia lingua", theme: "Tema", - search: "Cerca", ask: "Chiedi", }, notebooks: { @@ -248,12 +233,8 @@ export const itIT = { keepExclusiveSourcesLabel: "Scollega e mantieni", activeNotebooks: "Quaderni attivi", archivedNotebooks: "Quaderni archiviati", - emptyDescription: "Inizia creando il tuo primo quaderno per organizzare la tua ricerca.", - noActiveNotebooks: "Nessun quaderno attivo", - noArchivedNotebooks: "Nessun quaderno archiviato", notFound: "Quaderno non trovato", notFoundDesc: "Il quaderno richiesto non esiste.", - noDescription: "Nessuna descrizione...", updated: "Aggiornato", namePlaceholder: "Nome quaderno", addDescription: "Aggiungi descrizione...", @@ -278,10 +259,7 @@ export const itIT = { add: "Aggiungi fonte", addNew: "Aggiungi nuova fonte", addExisting: "Aggiungi fonte esistente", - empty: "Ancora nessuna fonte", - emptyDesc: "Aggiungi la tua prima fonte per iniziare a costruire la tua base di conoscenza.", delete: "Elimina Fonte", - deleteMsg: "Sei sicuro di voler eliminare questa fonte? Questa azione non può essere annullata.", statusPreparing: "In preparazione", statusQueued: "In coda", statusProcessing: "In elaborazione", @@ -321,7 +299,6 @@ export const itIT = { sourceRequeued: "Fonte rimessa in coda", sourceRequeuedDesc: "La fonte è stata rimessa in coda per l'elaborazione.", failedToRetry: "Nuovo tentativo fallito", - failedToRetryDesc: "Impossibile ritentare l'elaborazione della fonte. Riprova.", sourcesAddedToNotebook: "{count} fonte/i aggiunte al quaderno", failedToAddSourcesToNotebook: "Impossibile aggiungere le fonti al quaderno", partialAddSuccess: "{success} fonte/i aggiunte, {failed} fallite", @@ -358,7 +335,7 @@ export const itIT = { viewInsight: "Visualizza approfondimento", deleteInsight: "Elimina approfondimento", deleteInsightConfirm: "Sei sicuro di voler eliminare questo approfondimento? Questa azione non può essere annullata.", - deleteNoteConfirm: "Sei sicuro di voler eliminare questa nota? Questa azione non può essere annullata.", + insightGenerationStarted: "Generazione dell'approfondimento avviata. Apparirà a breve.", editNote: "Modifica nota", createNote: "Crea nota", addTitle: "Aggiungi un titolo...", @@ -366,9 +343,7 @@ export const itIT = { writeNotePlaceholder: "Scrivi il contenuto della tua nota qui...", saveNote: "Salva nota", createNoteBtn: "Crea nota", - noNotesYet: "Ancora nessuna nota", createFirstNote: "Crea la tua prima nota per catturare intuizioni e osservazioni.", - deleteNote: "Elimina nota", urlLabel: "URL *", fileLabel: "File *", textContentLabel: "Contenuto testo *", @@ -402,7 +377,6 @@ export const itIT = { retryProcessing: "Riprova elaborazione", deleteSource: "Elimina fonte", retry: "Riprova", - progress: "Progresso", addExistingTitle: "Aggiungi fonti esistenti", addExistingDesc: "Seleziona fonti esistenti da tutti i tuoi quaderni per aggiungerle a quello corrente.", searchPlaceholder: "Cerca fonti per nome o URL...", @@ -434,8 +408,6 @@ export const itIT = { batchFailed: "Impossibile creare tutte le {count} fonti", batchPartial: "{success} riuscite, {failed} fallite", submittingSource: "Invio fonte per l'elaborazione...", - contentRequired: "Fornisci il contenuto richiesto per il tipo di fonte selezionato", - titleRequiredForText: "Il titolo è obbligatorio per le fonti testuali", processingBatchSources: "Elaborazione di {count} fonti. Potrebbe richiedere qualche istante.", processingSource: "La tua fonte è in elaborazione. Potrebbe richiedere qualche istante.", maxFilesAllowed: "Massimo {count} file consentiti per batch", @@ -444,16 +416,10 @@ export const itIT = { sessions: "Sessioni", sessionTitlePlaceholder: "Digita un titolo qui...", noSessions: "Ancora nessuna sessione chat", - startChatting: "Inizia a chattare sulle tue fonti.", deleteSession: "Elimina sessione", deleteSessionDesc: "Sei sicuro di voler eliminare questa sessione chat? Questa azione non può essere annullata.", sendPlaceholder: "Chiedi qualsiasi cosa sulle tue fonti...", - newChat: "Nuova chat", sessionsTitle: "Sessioni chat", - clearhistory: "Cancella cronologia", - renameSession: "Rinomina sessione", - noSourcesLinked: "Nessuna fonte collegata", - thinking: "L'IA sta pensando...", chatWith: "Chatta con {name}", startConversation: "Inizia una conversazione su questo {type}", askQuestions: "Fai domande per capire meglio il contenuto", @@ -507,8 +473,6 @@ export const itIT = { saveSuccess: "Salvato con successo nel quaderno", saveError: "Impossibile salvare nel quaderno", selectNotebook: "Seleziona quaderno", - createNewNotebook: "Crea nuovo quaderno", - cancel: "Annulla", searchAndAsk: "Cerca e chiedi", searchResultsFor: "Risultati di ricerca per \"{query}\"", askAbout: "Chiedi riguardo \"{query}\"", @@ -733,8 +697,6 @@ export const itIT = { speakerCountMin: "È richiesto almeno uno speaker", speakerCountMax: "Puoi configurare fino a 4 speaker", delete: "Elimina", - unknown: "Sconosciuto", - deleteSuccess: "Podcast eliminato con successo", failedToDelete: "Impossibile eliminare il podcast", }, settings: { @@ -771,13 +733,8 @@ export const itIT = { title: "Strumenti avanzati", desc: "Strumenti e utilità avanzate per utenti esperti", systemInfo: "Informazioni sistema", - systemInfoDesc: "Visualizza lo stato dei componenti di sistema sottostanti", rebuildEmbeddings: "Ricostruisci indicizzazioni", rebuildEmbeddingsDesc: "Ricostruisci l'indice di ricerca vettoriale per tutte le fonti", - rebuildWarning: "Questa azione può richiedere molto tempo a seconda del numero di fonti. Cancellerà gli indici vettoriali esistenti e rigenererà le indicizzazioni per tutto.", - startRebuild: "Avvia ricostruzione", - rebuilding: "Ricostruzione...", - rebuildSuccess: "Ricostruzione indicizzazioni avviata con successo", currentVersion: "Versione corrente", latestVersion: "Ultima versione", status: "Stato", @@ -822,10 +779,8 @@ export const itIT = { defaultPrompt: "Prompt trasformazione predefinito", defaultPromptDesc: "Questo verrà aggiunto a tutti i tuoi prompt di trasformazione", defaultPromptPlaceholder: "Inserisci le tue istruzioni di trasformazione predefinite...", - saveDefault: "Salva predefinito", listTitle: "Trasformazioni personalizzate", createNew: "Crea Nuova", - testInPlayground: "Testa nel playground", inputLabel: "Testo di input", inputPlaceholder: "Inserisci del testo da trasformare...", outputLabel: "Output", @@ -844,83 +799,33 @@ export const itIT = { deleteSuccess: "Trasformazione eliminata con successo", noTransformations: "Ancora nessuna trasformazione", createOne: "Crea una trasformazione per iniziare", - deleteDesc: "L'eliminazione di questa trasformazione non può essere annullata.", selectModel: "Seleziona un modello", deleteConfirm: "Sei sicuro di voler eliminare questa trasformazione?", model: "Modello", systemPrompt: "Prompt di sistema", - type: "Tipo", - extraction: "Estrazione", - summary: "Riepilogo", - custom: "Personalizzato", - saveChanges: "Salva modifiche", overrideModelDesc: "Sovrascrivi il modello predefinito per questa sessione chat. Lascia vuoto per usare il default di sistema.", sessionUseReplacement: "Questa sessione userà {name} invece del modello predefinito.", systemDefault: "Predefinito di sistema", }, models: { - title: "Gestione modelli", - desc: "Configura i modelli IA per diversi scopi in Open Notebook", - failedToLoad: "Impossibile caricare i dati dei modelli", - language: "Modelli linguistici", embedding: "Modelli di embedding", tts: "Text to Speech (TTS)", stt: "Speech to Text (STT)", - providers: "Provider", - defaultModels: "Modelli predefiniti", - status: "Stato", - notConfigured: "Non configurato", - active: "Attivo", - inactive: "Inattivo", - configure: "Configura", - saveChanges: "Salva modifiche", - addModel: "Aggiungi modello", - modelName: "Nome modello", provider: "Provider", apiKey: "Chiave API", - baseUrl: "URL Base", - capabilities: "Capacità", - enabled: "Abilitato", - disabled: "Disabilitato", - deleteConfirm: "Sei sicuro di voler eliminare questo modello?", deleteSuccess: "Modello eliminato con successo", saveSuccess: "Modello salvato con successo", - providerStatus: "Stato provider", - connectionOk: "Connessione OK", - connectionFailed: "Connessione fallita", - changeEmbeddingWarning: "Cambiare il modello di embedding predefinito influenzerà le nuove fonti. Le fonti esistenti potrebbero dover essere re-indicizzate.", - changeEmbeddingTitle: "Cambiare il modello di embedding predefinito?", - aiProviders: "Provider IA", - providerConfigDesc: "Configura i provider tramite variabili d'ambiente per abilitare i loro modelli.", - configuredCount: "{count} di {total} configurati", noModels: "Nessun modello", - learnMore: "Scopri come configurare i provider →", - seeLess: "Mostra meno", - seeAll: "Mostra tutti i {count} provider", - language_models: "Modelli linguistici", - embedding_models: "Modelli di embedding", - text_to_speech: "Text to Speech (TTS)", - speech_to_text: "Speech to Text (STT)", - languageDesc: "Chat, trasformazioni e generazione testo", - embeddingDesc: "Ricerca semantica e embedding vettoriali", - ttsDesc: "Genera audio da testo", - sttDesc: "Trascrivi audio in testo", - all: "Tutti", - noModelsConfigured: "Nessun modello configurato", - noProviderModelsConfigured: "Nessun modello {provider} configurato", - showMore: "Mostra altri {count}", discoverModels: "Scopri Modelli", noModelsFound: "Nessun modello trovato per questo provider", modelType: "Tipo di Modello", modelTypeHint: "Seleziona il tipo per i modelli che vuoi aggiungere. Se hai bisogno di tipi diversi, aggiungili in lotti separati.", deleteModel: "Elimina modello", - deleteModelDesc: "Sei sicuro di voler eliminare \"{name}\"? Questa azione non può essere annullata.", defaultAssignments: "Assegnazioni modelli predefiniti", defaultAssignmentsDesc: "Configura quali modelli usare per diversi scopi in Open Notebook", missingRequiredModels: "Modelli richiesti mancanti: {models}. Open Notebook potrebbe non funzionare correttamente senza questi.", selectModelPlaceholder: "Seleziona un modello", requiredModelPlaceholder: "⚠️ Richiesto - Seleziona un modello", - whichModelToChoose: "Quale modello dovrei scegliere? →", chatModelLabel: "Modello chat", chatModelDesc: "Usato per le conversazioni chat", transformationModelLabel: "Modello trasformazione", @@ -935,16 +840,9 @@ export const itIT = { ttsModelDesc: "Usato per la generazione podcast", sttModelLabel: "Modello Speech-to-Text", sttModelDesc: "Usato per la trascrizione audio", - addSpecificModel: "Aggiungi modello {type}", - addSpecificModelDesc: "Configura un nuovo modello {type} dai provider disponibili.", - noProvidersForType: "Nessun provider disponibile per modelli {type}", selectProviderPlaceholder: "Seleziona un provider", providerRequired: "Il provider è obbligatorio", - modelNameRequired: "Il nome del modello è obbligatorio", modelRequired: "Il modello è obbligatorio", - adding: "Aggiunta...", - azureHint: "Per Azure, usa il nome del deployment come nome del modello", - enterModelName: "Inserisci nome modello", embeddingChangeTitle: "Cambio modello di embedding", embeddingChangeConfirm: "Stai per cambiare il modello di embedding da {from} a {to}.", rebuildRequired: "Importante: ricostruzione richiesta", @@ -957,28 +855,24 @@ export const itIT = { proceedToRebuildPrompt: "Vuoi procedere alla pagina avanzate per avviare la ricostruzione ora?", changeModelOnly: "Cambia solo modello", changeAndRebuild: "Cambia e vai a ricostruzione", + autoAssign: "Assegnazione automatica predefiniti", + autoAssigning: "Assegnazione in corso...", + autoAssignSuccess: "{count} modelli predefiniti assegnati automaticamente", + autoAssignNoModels: "Nessun modello disponibile da assegnare. Sincronizza prima i modelli.", + autoAssignAlreadySet: "Tutti i modelli predefiniti sono già configurati", testModel: "Testa Modello", testModelSuccess: "Test del Modello Superato", testModelFailed: "Test del Modello Fallito", - testingModel: "Test del modello in corso...", searchOrAddModel: "Cerca o digita un nome modello...", - addCustomModel: 'Aggiungi "{name}"', + addCustomModel: "Aggiungi \"{name}\"", }, apiKeys: { title: "Configura la tua IA con le tue chiavi API", description: "Salva le chiavi API in modo sicuro nel database per abilitare i provider IA in Open Notebook.", - loadFailed: "Impossibile caricare lo stato delle chiavi API", encryptionRequired: "Chiave di crittografia non configurata", encryptionRequiredDescription: "Imposta la variabile d'ambiente OPEN_NOTEBOOK_ENCRYPTION_KEY su una stringa segreta qualsiasi per abilitare il salvataggio delle chiavi API nel database.", configured: "Configurato", notConfigured: "Non configurato", - sourceDatabase: "Database", - sourceEnvironment: "Variabile d'ambiente", - enterApiKey: "Inserisci la tua chiave API", - enterBaseUrl: "Inserisci l'URL base", - saveSuccess: "Chiave API salvata con successo", - deleteSuccess: "Chiave API eliminata con successo", - fromEnvironmentHint: "Questa chiave è impostata tramite variabile d'ambiente. Salva una nuova chiave per sovrascriverla nel database.", migrationAvailable: "Variabili d'ambiente rilevate", migrationDescription: "{count} chiave/i API configurata/e tramite variabili d'ambiente. Puoi migrarle nel database per una gestione più semplice.", migrateToDatabase: "Migra nel database", @@ -986,67 +880,29 @@ export const itIT = { migrationSuccess: "{count} chiave/i API migrata/e con successo", migrationErrors: "{count} chiave/i non migrata/e", migrationNothingToMigrate: "Tutte le chiavi sono già nel database", - serviceType: "Tipo di servizio", - serviceLlm: "Modello linguistico (LLM)", - serviceEmbedding: "Embedding", - serviceStt: "Riconoscimento vocale (STT)", - serviceTts: "Sintesi vocale (TTS)", - serviceEndpoints: "Endpoint dei servizi (opzionale)", - azureEndpointsHint: "Se necessario, configura endpoint diversi per ogni tipo di servizio.", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "Configura un endpoint API compatibile con OpenAI. Ogni tipo di servizio può avere la propria configurazione.", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "Scopri come configurare le chiavi API →", testConnection: "Testa connessione", - testing: "Test in corso...", testSuccess: "Connessione riuscita", testFailed: "Test di connessione fallito", syncModels: "Sincronizza modelli", - syncing: "Sincronizzazione...", syncSuccess: "Trovati {discovered} modelli, aggiunti {new} nuovi", syncNoNew: "Trovati {count} modelli, tutti già registrati", syncFailed: "Sincronizzazione modelli fallita", - syncAllModels: "Sincronizza tutti i provider", - syncAllSuccess: "Trovati {discovered} modelli da tutti i provider, aggiunti {new} nuovi", - modelsConfigured: "{count} modelli", - noModelsConfigured: "Nessun modello", - viewModels: "Visualizza modelli", - supportedTypes: "Tipi supportati", - typeLanguage: "Linguistico", - typeEmbedding: "Embedding", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "Endpoint API", getApiKey: "Ottieni chiave API", vertexProject: "ID progetto GCP", vertexLocation: "Regione", vertexCredentials: "Percorso JSON account di servizio", - vertexCredentialsHint: "Percorso del file JSON dell'account di servizio Google Cloud all'interno del container.", - - // Traduzioni multi-configurazione - configsCount: "{count} configurazioni", - configuredMultiple: "Configurato", addConfig: "Aggiungi configurazione", editConfig: "Modifica configurazione", deleteConfig: "Elimina configurazione", - setAsDefault: "Imposta come predefinito", - defaultBadge: "Predefinito", - defaultDescription: "Configurazione predefinita per questo provider", configName: "Nome configurazione", configNameHint: "Un nome descrittivo per questa configurazione (es. 'Produzione', 'Sviluppo')", baseUrl: "URL base", - baseUrlHint: "Predefinito: {url}", baseUrlOverrideHint: "Modifica solo se devi sovrascrivere l'endpoint API predefinito del provider.", - ollamaApiKeyHint: "Necessaria solo per Ollama Cloud. Lascia vuoto per Ollama locale.", - noConfigs: "Nessuna configurazione presente", - noConfigsHint: "Aggiungi una configurazione per iniziare a usare questo provider", deleteConfigConfirm: "Sei sicuro di voler eliminare '{name}'? Questa azione non può essere annullata.", - setDefaultConfirm: "Impostare '{name}' come configurazione predefinita?", configSaveSuccess: "Configurazione salvata con successo", configUpdateSuccess: "Configurazione aggiornata con successo", configDeleteSuccess: "Configurazione eliminata con successo", - configSetDefaultSuccess: "Configurazione predefinita aggiornata", - apiKeyHint: "Inserisci la chiave API per questa configurazione", apiKeyEditHint: "Lascia vuoto per mantenere la chiave API esistente", }, setupBanner: { diff --git a/frontend/src/lib/locales/ja-JP/index.ts b/frontend/src/lib/locales/ja-JP/index.ts index 90aee8b..daf6cdf 100644 --- a/frontend/src/lib/locales/ja-JP/index.ts +++ b/frontend/src/lib/locales/ja-JP/index.ts @@ -36,22 +36,16 @@ export const jaJP = { warning: "警告", error: "エラー", success: "成功", - sessions: "セッション", model: "モデル", - send: "送信", back: "戻る", next: "次へ", done: "完了", processing: "処理中...", creating: "作成中...", - tokenCount: "トークン数", - charCount: "文字数", linked: "リンク済み", - added: "{date}に追加", adding: "追加中...", addSelected: "選択項目を追加", customModel: "カスタムモデル", - messages: "メッセージ", failed: "失敗", current: "現在", save: "保存", @@ -72,7 +66,6 @@ export const jaJP = { unknown: "不明", notes: "ノート", chat: "チャット", - details: "詳細", deleteForever: "完全に削除", connectionError: "接続エラー", unableToConnect: "APIサーバーに接続できません", @@ -85,7 +78,6 @@ export const jaJP = { checkConsoleLogs: "ブラウザコンソールで詳細ログを確認してください(🔧 [Config] メッセージを探してください)", yes: "はい", no: "いいえ", - simple: "シンプル", saving: "保存中...", description: "説明", saveToNote: "ノートに保存", @@ -103,7 +95,6 @@ export const jaJP = { nameRequired: "名前は必須です", modelConfiguration: "モデル設定", resetToDefault: "デフォルトに戻す", - notFound: "見つかりません", reasoning: "推論", searchTerms: "検索ワード", strategy: "戦略", @@ -112,14 +103,12 @@ export const jaJP = { notebookLabel: "ノートブック: {name}", itemNotFound: "この{type}は見つかりませんでした", accessibility: { - navigation: "ナビゲーション", transformationViews: "トランスフォーメーション表示", searchKB: "ナレッジベースに質問・検索", enterQuestion: "ナレッジベースへの質問を入力", enterSearch: "検索クエリを入力", searchKBBtn: "ナレッジベースを検索", podcastViews: "ポッドキャスト表示", - chatSessions: "チャットセッション", ytVideo: "YouTube動画", askResponse: "質問への回答", searchNotebooks: "ノートブックを検索", @@ -127,7 +116,6 @@ export const jaJP = { url: "URL", errorDetails: "エラー詳細", editTransformation: "トランスフォーメーションを編集", - comingSoon: "近日公開", retry: "再試行", traditionalChinese: "繁體中文", portuguese: "Português", @@ -165,7 +153,6 @@ export const jaJP = { failedToSendMessage: "メッセージの送信に失敗しました", unauthorized: "認証エラー。パスワードを確認してください", invalidPassword: "パスワードが無効です", - missingAuth: "認証情報がありません", embeddingModelRequired: "この機能にはEmbeddingモデルが必要です。モデルセクションで設定してください。", strategyModelNotFound: "戦略モデルが見つかりません", answerModelNotFound: "回答モデルが見つかりません", @@ -206,7 +193,6 @@ export const jaJP = { passwordPlaceholder: "パスワード", signingIn: "サインイン中...", signIn: "サインイン", - unhandledError: "ログイン中に予期しないエラーが発生しました", connectErrorHint: "サーバーに接続できません。APIが起動しているか確認してください。", }, navigation: { @@ -226,7 +212,6 @@ export const jaJP = { nav: "ナビゲーション", language: "言語を切り替え", theme: "テーマ", - search: "検索", ask: "質問", }, notebooks: { @@ -248,12 +233,8 @@ export const jaJP = { keepExclusiveSourcesLabel: "リンク解除して保持", activeNotebooks: "アクティブなノートブック", archivedNotebooks: "アーカイブ済みノートブック", - emptyDescription: "最初のノートブックを作成してリサーチを整理しましょう。", - noActiveNotebooks: "アクティブなノートブックがありません", - noArchivedNotebooks: "アーカイブ済みノートブックがありません", notFound: "ノートブックが見つかりません", notFoundDesc: "指定されたノートブックは存在しません。", - noDescription: "説明なし...", updated: "更新日時", namePlaceholder: "ノートブック名", addDescription: "説明を追加...", @@ -278,10 +259,7 @@ export const jaJP = { add: "ソースを追加", addNew: "新規ソースを追加", addExisting: "既存ソースを追加", - empty: "ソースがまだありません", - emptyDesc: "最初のソースを追加してナレッジベースの構築を始めましょう。", delete: "ソースを削除", - deleteMsg: "このソースを削除しますか?この操作は元に戻せません。", statusPreparing: "準備中", statusQueued: "キュー待ち", statusProcessing: "処理中", @@ -321,7 +299,6 @@ export const jaJP = { sourceRequeued: "ソースの再処理をキューに追加", sourceRequeuedDesc: "ソースを再処理キューに追加しました。", failedToRetry: "再試行に失敗", - failedToRetryDesc: "ソースの再処理に失敗しました。もう一度お試しください。", sourcesAddedToNotebook: "{count}件のソースをノートブックに追加しました", failedToAddSourcesToNotebook: "ノートブックへのソース追加に失敗しました", partialAddSuccess: "{success}件追加成功、{failed}件失敗", @@ -359,34 +336,31 @@ export const jaJP = { deleteInsight: "インサイトを削除", deleteInsightConfirm: "このインサイトを削除しますか?この操作は元に戻せません。", insightGenerationStarted: "インサイトの生成が開始されました。まもなく表示されます。", - deleteNoteConfirm: 'このノートを削除しますか?この操作は元に戻せません。', - editNote: 'ノートを編集', - createNote: 'ノートを作成', - addTitle: 'タイトルを追加...', - untitledNote: '無題のノート', - writeNotePlaceholder: 'ノートの内容をここに入力...', - saveNote: 'ノートを保存', - createNoteBtn: 'ノートを作成', - noNotesYet: "ノートがまだありません", + editNote: "ノートを編集", + createNote: "ノートを作成", + addTitle: "タイトルを追加...", + untitledNote: "無題のノート", + writeNotePlaceholder: "ノートの内容をここに入力...", + saveNote: "ノートを保存", + createNoteBtn: "ノートを作成", createFirstNote: "最初のノートを作成してインサイトや気づきを記録しましょう。", - deleteNote: "ノートを削除", - urlLabel: 'URL *', - fileLabel: 'ファイル *', - textContentLabel: 'テキストコンテンツ *', - enterUrlsPlaceholder: 'URLを1行ずつ入力\nhttps://example.com/article1\nhttps://example.com/article2', - batchUrlHint: '複数のURLを貼り付けて一括インポート(1行に1つ)', - invalidUrlsDetected: '無効なURLが検出されました:', - lineLabel: '{line}行目', - fixInvalidUrls: '無効なURLを修正または削除してください', - selectMultipleFilesHint: '複数ファイルを選択して一括インポート。対応形式:ドキュメント(PDF、DOC、DOCX、PPT、XLS、EPUB、TXT、MD)、メディア(MP4、MP3、WAV、M4A)、画像(JPG、PNG)、アーカイブ(ZIP)', - selectedFiles: '選択されたファイル:', - textPlaceholder: 'コンテンツを貼り付けまたは入力...', - htmlDetected: 'HTMLコンテンツが検出されました。処理後にMarkdownに変換されます。', - titlePlaceholder: 'ソースにわかりやすいタイトルを付けてください', - batchTitlesAuto: 'タイトルは各ソースごとに自動生成されます。', - batchCommonSettings: '同じノートブックとトランスフォーメーションがすべてのアイテムに適用されます。', - urlsCount: '{count}件のURL', - filesCount: '{count}件のファイル', + urlLabel: "URL *", + fileLabel: "ファイル *", + textContentLabel: "テキストコンテンツ *", + enterUrlsPlaceholder: "URLを1行ずつ入力\nhttps://example.com/article1\nhttps://example.com/article2", + batchUrlHint: "複数のURLを貼り付けて一括インポート(1行に1つ)", + invalidUrlsDetected: "無効なURLが検出されました:", + lineLabel: "{line}行目", + fixInvalidUrls: "無効なURLを修正または削除してください", + selectMultipleFilesHint: "複数ファイルを選択して一括インポート。対応形式:ドキュメント(PDF、DOC、DOCX、PPT、XLS、EPUB、TXT、MD)、メディア(MP4、MP3、WAV、M4A)、画像(JPG、PNG)、アーカイブ(ZIP)", + selectedFiles: "選択されたファイル:", + textPlaceholder: "コンテンツを貼り付けまたは入力...", + htmlDetected: "HTMLコンテンツが検出されました。処理後にMarkdownに変換されます。", + titlePlaceholder: "ソースにわかりやすいタイトルを付けてください", + batchTitlesAuto: "タイトルは各ソースごとに自動生成されます。", + batchCommonSettings: "同じノートブックとトランスフォーメーションがすべてのアイテムに適用されます。", + urlsCount: "{count}件のURL", + filesCount: "{count}件のファイル", addSource: "ソースを追加", notEmbeddedAlert: "コンテンツが未Embedding", notEmbeddedDesc: "このコンテンツはベクトル検索用にEmbeddingされていません。Embeddingを行うと高度な検索機能やコンテンツの発見性が向上します。", @@ -403,7 +377,6 @@ export const jaJP = { retryProcessing: "処理を再試行", deleteSource: "ソースを削除", retry: "再試行", - progress: "進捗", addExistingTitle: "既存ソースを追加", addExistingDesc: "すべてのノートブックから既存のソースを選択して現在のノートブックに追加します。", searchPlaceholder: "名前またはURLでソースを検索...", @@ -435,8 +408,6 @@ export const jaJP = { batchFailed: "{count}件すべてのソース作成に失敗しました", batchPartial: "{success}件成功、{failed}件失敗", submittingSource: "ソースを処理に送信中...", - contentRequired: "選択したソースタイプに必要なコンテンツを入力してください", - titleRequiredForText: "テキストソースにはタイトルが必要です", processingBatchSources: "{count}件のソースを処理中。しばらくお待ちください。", processingSource: "ソースを処理中です。しばらくお待ちください。", maxFilesAllowed: "一括処理は最大{count}件までです", @@ -445,26 +416,20 @@ export const jaJP = { sessions: "セッション", sessionTitlePlaceholder: "タイトルを入力...", noSessions: "チャットセッションがまだありません", - startChatting: "ソースについてチャットを始めましょう。", deleteSession: "セッションを削除", deleteSessionDesc: "このチャットセッションを削除しますか?この操作は元に戻せません。", sendPlaceholder: "ソースについて何でも質問してください...", - newChat: "新規チャット", sessionsTitle: "チャットセッション", - clearhistory: "履歴をクリア", - renameSession: "セッション名を変更", - noSourcesLinked: "リンクされたソースがありません", - thinking: "AIが考え中...", chatWith: "{name}とチャット", startConversation: "この{type}について会話を始めましょう", askQuestions: "コンテンツをより深く理解するために質問してください", pressToSend: "{key}を押して送信", model: "モデル", - createToStart: 'セッションを作成して開始', - chatWithNotebook: 'ノートブックとチャット', - unableToLoadChat: 'チャットを読み込めません', - noDescription: '説明なし', - startByCreating: '最初のノートブックを作成してリサーチを整理しましょう。', + createToStart: "セッションを作成して開始", + chatWithNotebook: "ノートブックとチャット", + unableToLoadChat: "チャットを読み込めません", + noDescription: "説明なし", + startByCreating: "最初のノートブックを作成してリサーチを整理しましょう。", messagesCount: "{count}件のメッセージ", sessionCreated: "チャットセッションを作成しました", sessionUpdated: "セッションを更新しました", @@ -508,8 +473,6 @@ export const jaJP = { saveSuccess: "ノートブックに保存しました", saveError: "ノートブックへの保存に失敗しました", selectNotebook: "ノートブックを選択", - createNewNotebook: "新規ノートブックを作成", - cancel: "キャンセル", searchAndAsk: "検索と質問", searchResultsFor: "「{query}」の検索結果", askAbout: "「{query}」について質問", @@ -734,8 +697,6 @@ export const jaJP = { speakerCountMin: "最低1人のスピーカーが必要です", speakerCountMax: "最大4人まで設定できます", delete: "削除", - unknown: "不明", - deleteSuccess: "ポッドキャストを削除しました", failedToDelete: "ポッドキャストの削除に失敗しました", }, settings: { @@ -772,13 +733,8 @@ export const jaJP = { title: "詳細ツール", desc: "パワーユーザー向けの詳細ツールとユーティリティ", systemInfo: "システム情報", - systemInfoDesc: "基盤システムコンポーネントのステータスを表示", rebuildEmbeddings: "Embeddingを再構築", rebuildEmbeddingsDesc: "すべてのソースのベクトル検索インデックスを再構築", - rebuildWarning: "このアクションはソース数によっては非常に時間がかかる場合があります。既存のベクトルインデックスをクリアし、すべてのEmbeddingを再生成します。", - startRebuild: "再構築を開始", - rebuilding: "再構築中...", - rebuildSuccess: "Embedding再構築を開始しました", currentVersion: "現在のバージョン", latestVersion: "最新バージョン", status: "ステータス", @@ -823,105 +779,53 @@ export const jaJP = { defaultPrompt: "デフォルトトランスフォーメーションプロンプト", defaultPromptDesc: "これはすべてのトランスフォーメーションプロンプトに追加されます", defaultPromptPlaceholder: "デフォルトのトランスフォーメーション指示を入力...", - saveDefault: "デフォルトを保存", listTitle: "カスタムトランスフォーメーション", createNew: "新規作成", - testInPlayground: "プレイグラウンドでテスト", inputLabel: "入力テキスト", - inputPlaceholder: '変換するテキストを入力...', - outputLabel: '出力', - runTest: 'トランスフォーメーションを実行', - running: '実行中...', - selectToStart: 'トランスフォーメーションを選択して開始', - name: '名前', - namePlaceholder: '一意の識別子、例: key_topics', - titlePlaceholder: '表示タイトル、空欄の場合は名前を使用', - promptPlaceholder: 'このトランスフォーメーションを実行するプロンプトを書いてください...', - descriptionPlaceholder: 'このトランスフォーメーションの機能を説明してください。', - suggestDefault: '新しいソースでデフォルトで提案', - promptHint: 'プロンプトはソースコンテンツを念頭に置いて書いてください。モデルに要約、インサイトの抽出、テーブルなどの構造化出力の生成を依頼できます。', - createSuccess: 'トランスフォーメーションを作成しました', - updateSuccess: 'トランスフォーメーションを更新しました', - deleteSuccess: 'トランスフォーメーションを削除しました', + inputPlaceholder: "変換するテキストを入力...", + outputLabel: "出力", + runTest: "トランスフォーメーションを実行", + running: "実行中...", + selectToStart: "トランスフォーメーションを選択して開始", + name: "名前", + namePlaceholder: "一意の識別子、例: key_topics", + titlePlaceholder: "表示タイトル、空欄の場合は名前を使用", + promptPlaceholder: "このトランスフォーメーションを実行するプロンプトを書いてください...", + descriptionPlaceholder: "このトランスフォーメーションの機能を説明してください。", + suggestDefault: "新しいソースでデフォルトで提案", + promptHint: "プロンプトはソースコンテンツを念頭に置いて書いてください。モデルに要約、インサイトの抽出、テーブルなどの構造化出力の生成を依頼できます。", + createSuccess: "トランスフォーメーションを作成しました", + updateSuccess: "トランスフォーメーションを更新しました", + deleteSuccess: "トランスフォーメーションを削除しました", noTransformations: "トランスフォーメーションがまだありません", createOne: "開始するにはトランスフォーメーションを作成してください", - deleteDesc: "このトランスフォーメーションを削除すると元に戻せません。", selectModel: "モデルを選択", deleteConfirm: "このトランスフォーメーションを削除しますか?", model: "モデル", systemPrompt: "システムプロンプト", - type: "タイプ", - extraction: "抽出", - summary: "要約", - custom: "カスタム", - saveChanges: "変更を保存", overrideModelDesc: "このチャットセッションのデフォルトモデルを上書きします。空欄の場合はシステムデフォルトを使用します。", sessionUseReplacement: "このセッションはデフォルトモデルの代わりに{name}を使用します。", systemDefault: "システムデフォルト", }, models: { - title: "モデル管理", - desc: "Open Notebook全体で異なる目的に使用するAIモデルを設定", - failedToLoad: "モデルデータの読み込みに失敗しました", - language: "言語モデル", embedding: "Embeddingモデル", tts: "音声合成(TTS)", stt: "音声認識(STT)", - providers: "プロバイダー", - defaultModels: "デフォルトモデル", - status: "ステータス", - notConfigured: "未設定", - active: "アクティブ", - inactive: "非アクティブ", - configure: "設定", - saveChanges: "変更を保存", - addModel: "モデルを追加", - modelName: "モデル名", provider: "プロバイダー", apiKey: "APIキー", - baseUrl: "ベースURL", - capabilities: "機能", - enabled: "有効", - disabled: "無効", - deleteConfirm: "このモデルを削除しますか?", deleteSuccess: "モデルを削除しました", saveSuccess: "モデルを保存しました", - providerStatus: "プロバイダーステータス", - connectionOk: "接続OK", - connectionFailed: "接続失敗", - changeEmbeddingWarning: "デフォルトのEmbeddingモデルを変更すると新しいソースに影響します。既存のソースは再インデックスが必要になる場合があります。", - changeEmbeddingTitle: "デフォルトEmbeddingモデルを変更しますか?", - aiProviders: "AIプロバイダー", - providerConfigDesc: "環境変数を通じてプロバイダーを設定し、モデルを有効にしてください。", - configuredCount: "{total}件中{count}件設定済み", noModels: "モデルなし", - learnMore: "プロバイダーの設定方法を見る →", - seeLess: "折りたたむ", - seeAll: "{count}件すべてのプロバイダーを表示", - language_models: "言語モデル", - embedding_models: "Embeddingモデル", - text_to_speech: "音声合成(TTS)", - speech_to_text: "音声認識(STT)", - languageDesc: "チャット、トランスフォーメーション、テキスト生成", - embeddingDesc: "セマンティック検索とベクトルEmbedding", - ttsDesc: "テキストから音声を生成", - sttDesc: "音声をテキストに書き起こし", - all: "すべて", - noModelsConfigured: "モデルが設定されていません", - noProviderModelsConfigured: "{provider}モデルが設定されていません", - showMore: "さらに{count}件表示", discoverModels: "モデルを検出", noModelsFound: "このプロバイダーからモデルが見つかりません", modelType: "モデルタイプ", modelTypeHint: "追加するモデルのタイプを選択してください。異なるタイプが必要な場合は、別々のバッチで追加してください。", deleteModel: "モデルを削除", - deleteModelDesc: "「{name}」を削除しますか?この操作は元に戻せません。", defaultAssignments: "デフォルトモデル割り当て", defaultAssignmentsDesc: "Open Notebook全体で異なる目的に使用するモデルを設定", missingRequiredModels: "必須モデルがありません: {models}。これらがないとOpen Notebookが正しく機能しない可能性があります。", selectModelPlaceholder: "モデルを選択", requiredModelPlaceholder: "⚠️ 必須 - モデルを選択", - whichModelToChoose: "どのモデルを選ぶべき? →", chatModelLabel: "チャットモデル", chatModelDesc: "チャット会話に使用", transformationModelLabel: "トランスフォーメーションモデル", @@ -936,16 +840,9 @@ export const jaJP = { ttsModelDesc: "ポッドキャスト生成に使用", sttModelLabel: "音声認識モデル", sttModelDesc: "音声の書き起こしに使用", - addSpecificModel: "{type}を追加", - addSpecificModelDesc: "利用可能なプロバイダーから新しい{type}を設定します。", - noProvidersForType: "{type}用のプロバイダーがありません", selectProviderPlaceholder: "プロバイダーを選択", providerRequired: "プロバイダーは必須です", - modelNameRequired: "モデル名は必須です", modelRequired: "モデルは必須です", - adding: "追加中...", - azureHint: "Azureの場合、デプロイメント名をモデル名として使用してください", - enterModelName: "モデル名を入力", embeddingChangeTitle: "Embeddingモデルの変更", embeddingChangeConfirm: "Embeddingモデルを{from}から{to}に変更しようとしています。", rebuildRequired: "重要:再構築が必要", @@ -959,7 +856,6 @@ export const jaJP = { changeModelOnly: "モデルのみ変更", changeAndRebuild: "変更して再構築へ", autoAssign: "デフォルトを自動割り当て", - autoAssignDesc: "各スロットに最適なモデルを自動的に割り当てます", autoAssigning: "割り当て中...", autoAssignSuccess: "{count}件のデフォルトモデルを自動的に割り当てました", autoAssignNoModels: "割り当て可能なモデルがありません。先にモデルを同期してください。", @@ -967,25 +863,16 @@ export const jaJP = { testModel: "モデルをテスト", testModelSuccess: "モデルテスト成功", testModelFailed: "モデルテスト失敗", - testingModel: "モデルをテスト中...", searchOrAddModel: "検索またはモデル名を入力...", - addCustomModel: '"{name}" を追加', + addCustomModel: "\"{name}\" を追加", }, apiKeys: { title: "独自のAPIキーでAIを設定", description: "APIキーをデータベースに安全に保存し、Open NotebookでAIプロバイダーを有効にします。", - loadFailed: "APIキーのステータスの読み込みに失敗しました", encryptionRequired: "暗号化キーが設定されていません", encryptionRequiredDescription: "OPEN_NOTEBOOK_ENCRYPTION_KEY 環境変数に任意の秘密文字列を設定して、データベースへのAPIキーの保存を有効にしてください。", configured: "設定済み", notConfigured: "未設定", - sourceDatabase: "データベース", - sourceEnvironment: "環境変数", - enterApiKey: "APIキーを入力してください", - enterBaseUrl: "ベースURLを入力してください", - saveSuccess: "APIキーを保存しました", - deleteSuccess: "APIキーを削除しました", - fromEnvironmentHint: "このキーは環境変数で設定されています。新しいキーを保存するとデータベースで上書きされます。", migrationAvailable: "環境変数を検出", migrationDescription: "{count}個のAPIキーが環境変数で設定されています。管理を容易にするためにデータベースに移行できます。", migrateToDatabase: "データベースに移行", @@ -993,67 +880,29 @@ export const jaJP = { migrationSuccess: "{count}個のAPIキーを移行しました", migrationErrors: "{count}個のキーの移行に失敗しました", migrationNothingToMigrate: "すべてのキーはすでにデータベースにあります", - serviceType: "サービスタイプ", - serviceLlm: "言語モデル(LLM)", - serviceEmbedding: "Embedding", - serviceStt: "音声認識(STT)", - serviceTts: "音声合成(TTS)", - serviceEndpoints: "サービスエンドポイント(任意)", - azureEndpointsHint: "必要に応じて、各サービスタイプに異なるエンドポイントを設定します。", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "OpenAI互換のAPIエンドポイントを設定します。各サービスタイプに独自の設定が可能です。", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "APIキーの設定方法を確認 →", testConnection: "接続テスト", - testing: "テスト中...", testSuccess: "接続成功", testFailed: "接続テストに失敗", syncModels: "モデル同期", - syncing: "同期中...", syncSuccess: "{discovered} モデルを発見、{new} 個を新規追加", syncNoNew: "{count} モデルを発見、すべて登録済み", syncFailed: "モデルの同期に失敗", - syncAllModels: "全プロバイダーを同期", - syncAllSuccess: "全プロバイダーで {discovered} モデルを発見、{new} 個を新規追加", - modelsConfigured: "{count} モデル", - noModelsConfigured: "モデルなし", - viewModels: "モデルを表示", - supportedTypes: "対応タイプ", - typeLanguage: "言語", - typeEmbedding: "埋め込み", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "APIエンドポイント", getApiKey: "APIキーを取得", vertexProject: "GCPプロジェクトID", vertexLocation: "リージョン", vertexCredentials: "サービスアカウントJSONパス", - vertexCredentialsHint: "コンテナ内のGoogle Cloudサービスアカウント JSON ファイルへのパス。", - - // Multi-config translations - configsCount: "{count} 設定", - configuredMultiple: "設定済み", addConfig: "設定を追加", editConfig: "設定を編集", deleteConfig: "設定を削除", - setAsDefault: "デフォルトに設定", - defaultBadge: "デフォルト", - defaultDescription: "このプロバイダーのデフォルト設定", configName: "設定名", configNameHint: "この設定の説明的な名前(例:本番環境、開発環境)", baseUrl: "ベースURL", - baseUrlHint: "デフォルト:{url}", baseUrlOverrideHint: "プロバイダーのデフォルト API エンドポイントを上書きする場合のみ変更してください。", - ollamaApiKeyHint: "Ollama Cloud でのみ必要です。ローカル Ollama の場合は空のままにしてください。", - noConfigs: "設定がありません", - noConfigsHint: "このプロバイダーの使用を開始するには設定を追加してください", deleteConfigConfirm: "「{name}」を削除してもよろしいですか?この操作は元に戻せません。", - setDefaultConfirm: "「{name}」をデフォルト設定にしますか?", configSaveSuccess: "設定が正常に保存されました", configUpdateSuccess: "設定が正常に変更されました", configDeleteSuccess: "設定が正常に削除されました", - configSetDefaultSuccess: "デフォルト設定が更新されました", - apiKeyHint: "この設定のAPIキーを入力してください", apiKeyEditHint: "既存のAPIキーを維持するには空白のままにしてください", }, setupBanner: { diff --git a/frontend/src/lib/locales/pt-BR/index.ts b/frontend/src/lib/locales/pt-BR/index.ts index 6b700cc..1b657b8 100644 --- a/frontend/src/lib/locales/pt-BR/index.ts +++ b/frontend/src/lib/locales/pt-BR/index.ts @@ -36,22 +36,16 @@ export const ptBR = { warning: "Aviso", error: "Erro", success: "Sucesso", - sessions: "Sessões", model: "Modelo", - send: "Enviar", back: "Voltar", next: "Próximo", done: "Concluído", processing: "Processando...", creating: "Criando...", - tokenCount: "Tokens", - charCount: "Caracteres", linked: "Vinculado", - added: "Adicionado em {date}", adding: "Adicionando...", addSelected: "Adicionar Selecionados", customModel: "Modelo Personalizado", - messages: "Mensagens", failed: "falhou", current: "Atual", save: "Salvar", @@ -72,7 +66,6 @@ export const ptBR = { unknown: "Desconhecido", notes: "Notas", chat: "Chat", - details: "Detalhes", deleteForever: "Excluir Permanentemente", connectionError: "Erro de Conexão", unableToConnect: "Não foi possível conectar ao servidor da API", @@ -85,7 +78,6 @@ export const ptBR = { checkConsoleLogs: "Verifique o console do navegador para logs detalhados (procure por mensagens 🔧 [Config])", yes: "Sim", no: "Não", - simple: "Simples", saving: "Salvando...", description: "Descrição", saveToNote: "Salvar em nota", @@ -103,7 +95,6 @@ export const ptBR = { nameRequired: "Nome é obrigatório", modelConfiguration: "Configuração do Modelo", resetToDefault: "Restaurar Padrão", - notFound: "Não encontrado", reasoning: "Raciocínio", searchTerms: "Termos de Busca", strategy: "Estratégia", @@ -112,14 +103,12 @@ export const ptBR = { notebookLabel: "Caderno: {name}", itemNotFound: "Este {type} não foi encontrado", accessibility: { - navigation: "Navegação", transformationViews: "Visualizações de transformação", searchKB: "Perguntar ou buscar na base de conhecimento", enterQuestion: "Digite sua pergunta para a base de conhecimento", enterSearch: "Digite sua busca", searchKBBtn: "Buscar na base de conhecimento", podcastViews: "Visualizações de podcast", - chatSessions: "Sessões de chat", ytVideo: "Vídeo do YouTube", askResponse: "Resposta da Consulta", searchNotebooks: "Buscar cadernos", @@ -127,9 +116,9 @@ export const ptBR = { url: "URL", errorDetails: "Detalhes do Erro", editTransformation: "Editar Transformação", - comingSoon: "Em breve", retry: "Tentar Novamente", traditionalChinese: "繁體中文", + portuguese: "Português", completed: "concluído", saveSuccess: "Salvo com sucesso", contextModes: { @@ -139,7 +128,6 @@ export const ptBR = { clickToCycle: "Clique para alternar", }, clickToEdit: "Clique para editar", - portuguese: "Português", }, apiErrors: { notebookNotFound: "Caderno não encontrado", @@ -165,7 +153,6 @@ export const ptBR = { failedToSendMessage: "Falha ao enviar mensagem", unauthorized: "Acesso não autorizado, verifique sua senha", invalidPassword: "Senha inválida", - missingAuth: "Autenticação ausente", embeddingModelRequired: "Este recurso requer um modelo de embedding. Configure um na seção Modelos.", strategyModelNotFound: "Modelo de estratégia não encontrado", answerModelNotFound: "Modelo de resposta não encontrado", @@ -206,7 +193,6 @@ export const ptBR = { passwordPlaceholder: "Senha", signingIn: "Entrando...", signIn: "Entrar", - unhandledError: "Erro não tratado durante login", connectErrorHint: "Não foi possível conectar ao servidor. Verifique se a API está rodando.", }, navigation: { @@ -226,7 +212,6 @@ export const ptBR = { nav: "Navegação", language: "Alternar idioma", theme: "Tema", - search: "Buscar", ask: "Perguntar", }, notebooks: { @@ -248,12 +233,8 @@ export const ptBR = { keepExclusiveSourcesLabel: "Desvincular e manter", activeNotebooks: "Cadernos Ativos", archivedNotebooks: "Cadernos Arquivados", - emptyDescription: "Comece criando seu primeiro caderno para organizar sua pesquisa.", - noActiveNotebooks: "Nenhum caderno ativo", - noArchivedNotebooks: "Nenhum caderno arquivado", notFound: "Caderno não encontrado", notFoundDesc: "O caderno solicitado não existe.", - noDescription: "Sem descrição...", updated: "Atualizado", namePlaceholder: "Nome do caderno", addDescription: "Adicionar descrição...", @@ -278,10 +259,7 @@ export const ptBR = { add: "Adicionar Fonte", addNew: "Adicionar Nova Fonte", addExisting: "Adicionar Fonte Existente", - empty: "Nenhuma fonte ainda", - emptyDesc: "Adicione sua primeira fonte para começar a construir sua base de conhecimento.", delete: "Excluir Fonte", - deleteMsg: "Tem certeza que deseja excluir esta fonte? Esta ação não pode ser desfeita.", statusPreparing: "Preparando", statusQueued: "Na Fila", statusProcessing: "Processando", @@ -321,7 +299,6 @@ export const ptBR = { sourceRequeued: "Fonte Reenfileirada", sourceRequeuedDesc: "A fonte foi reenfileirada para processamento.", failedToRetry: "Falha ao Tentar Novamente", - failedToRetryDesc: "Falha ao tentar processar fonte novamente. Por favor, tente de novo.", sourcesAddedToNotebook: "{count} fonte(s) adicionada(s) ao caderno", failedToAddSourcesToNotebook: "Falha ao adicionar fontes ao caderno", partialAddSuccess: "{success} fonte(s) adicionada(s), {failed} falhou(aram)", @@ -359,7 +336,6 @@ export const ptBR = { deleteInsight: "Excluir Insight", deleteInsightConfirm: "Tem certeza que deseja excluir este insight? Esta ação não pode ser desfeita.", insightGenerationStarted: "Geração de insight iniciada. Aparecerá em breve.", - deleteNoteConfirm: "Tem certeza que deseja excluir esta nota? Esta ação não pode ser desfeita.", editNote: "Editar nota", createNote: "Criar nota", addTitle: "Adicionar título...", @@ -367,9 +343,7 @@ export const ptBR = { writeNotePlaceholder: "Escreva o conteúdo da sua nota aqui...", saveNote: "Salvar Nota", createNoteBtn: "Criar Nota", - noNotesYet: "Nenhuma nota ainda", createFirstNote: "Crie sua primeira nota para capturar insights e observações.", - deleteNote: "Excluir Nota", urlLabel: "URL(s) *", fileLabel: "Arquivo(s) *", textContentLabel: "Conteúdo de Texto *", @@ -403,7 +377,6 @@ export const ptBR = { retryProcessing: "Tentar Processamento Novamente", deleteSource: "Excluir Fonte", retry: "Tentar Novamente", - progress: "Progresso", addExistingTitle: "Adicionar Fontes Existentes", addExistingDesc: "Selecione fontes existentes de todos os seus cadernos para adicionar ao atual.", searchPlaceholder: "Buscar fontes por nome ou URL...", @@ -435,8 +408,6 @@ export const ptBR = { batchFailed: "Falha ao criar todas as {count} fontes", batchPartial: "{success} sucesso, {failed} falhou(aram)", submittingSource: "Enviando fonte para processamento...", - contentRequired: "Por favor, forneça o conteúdo necessário para o tipo de fonte selecionado", - titleRequiredForText: "Título é obrigatório para fontes de texto", processingBatchSources: "Processando {count} fontes. Isso pode levar alguns momentos.", processingSource: "Sua fonte está sendo processada. Isso pode levar alguns momentos.", maxFilesAllowed: "Máximo de {count} arquivos permitidos por lote", @@ -445,16 +416,10 @@ export const ptBR = { sessions: "Sessões", sessionTitlePlaceholder: "Digite um título aqui...", noSessions: "Nenhuma sessão de chat ainda", - startChatting: "Comece a conversar sobre suas fontes.", deleteSession: "Excluir Sessão", deleteSessionDesc: "Tem certeza que deseja excluir esta sessão de chat? Esta ação não pode ser desfeita.", sendPlaceholder: "Pergunte qualquer coisa sobre suas fontes...", - newChat: "Novo Chat", sessionsTitle: "Sessões de Chat", - clearhistory: "Limpar Histórico", - renameSession: "Renomear Sessão", - noSourcesLinked: "Nenhuma fonte vinculada", - thinking: "IA está pensando...", chatWith: "Conversar com {name}", startConversation: "Inicie uma conversa sobre este {type}", askQuestions: "Faça perguntas para entender melhor o conteúdo", @@ -508,8 +473,6 @@ export const ptBR = { saveSuccess: "Salvo no caderno com sucesso", saveError: "Falha ao salvar no caderno", selectNotebook: "Selecionar Caderno", - createNewNotebook: "Criar Novo Caderno", - cancel: "Cancelar", searchAndAsk: "Buscar e Perguntar", searchResultsFor: "Resultados da busca para \"{query}\"", askAbout: "Perguntar sobre \"{query}\"", @@ -734,8 +697,6 @@ export const ptBR = { speakerCountMin: "Pelo menos um locutor é necessário", speakerCountMax: "Você pode configurar até 4 locutores", delete: "Excluir", - unknown: "Desconhecido", - deleteSuccess: "Podcast excluído com sucesso", failedToDelete: "Falha ao excluir podcast", }, settings: { @@ -772,13 +733,8 @@ export const ptBR = { title: "Ferramentas Avançadas", desc: "Ferramentas e utilitários avançados para usuários avançados", systemInfo: "Informações do Sistema", - systemInfoDesc: "Visualize o status dos componentes subjacentes do sistema", rebuildEmbeddings: "Reconstruir Embeddings", rebuildEmbeddingsDesc: "Reconstruir índice de busca vetorial para todas as fontes", - rebuildWarning: "Esta ação pode ser muito demorada dependendo do número de fontes que você tem. Ela limpará os índices vetoriais existentes e regerará embeddings para tudo.", - startRebuild: "Iniciar Reconstrução", - rebuilding: "Reconstruindo...", - rebuildSuccess: "Reconstrução de embedding iniciada com sucesso", currentVersion: "Versão Atual", latestVersion: "Última Versão", status: "Status", @@ -823,10 +779,8 @@ export const ptBR = { defaultPrompt: "Prompt de Transformação Padrão", defaultPromptDesc: "Isso será adicionado a todos os seus prompts de transformação", defaultPromptPlaceholder: "Digite suas instruções padrão de transformação...", - saveDefault: "Salvar Padrão", listTitle: "Transformações Personalizadas", createNew: "Criar Nova", - testInPlayground: "Testar no Playground", inputLabel: "Texto de Entrada", inputPlaceholder: "Digite algum texto para transformar...", outputLabel: "Saída", @@ -845,83 +799,33 @@ export const ptBR = { deleteSuccess: "Transformação excluída com sucesso", noTransformations: "Nenhuma transformação ainda", createOne: "Crie uma transformação para começar", - deleteDesc: "Excluir esta transformação não pode ser desfeito.", selectModel: "Selecione um modelo", deleteConfirm: "Tem certeza que deseja excluir esta transformação?", model: "Modelo", systemPrompt: "Prompt do Sistema", - type: "Tipo", - extraction: "Extração", - summary: "Resumo", - custom: "Personalizado", - saveChanges: "Salvar Alterações", overrideModelDesc: "Substitua o modelo padrão para esta sessão de chat. Deixe vazio para usar o padrão do sistema.", sessionUseReplacement: "Esta sessão usará {name} em vez do modelo padrão.", systemDefault: "Padrão do Sistema", }, models: { - title: "Gerenciamento de Modelos", - desc: "Configure modelos de IA para diferentes propósitos no Open Notebook", - failedToLoad: "Falha ao carregar dados dos modelos", - language: "Modelos de Linguagem", embedding: "Modelos de Embedding", tts: "Text to Speech (TTS)", stt: "Speech to Text (STT)", - providers: "Provedores", - defaultModels: "Modelos Padrão", - status: "Status", - notConfigured: "Não configurado", - active: "Ativo", - inactive: "Inativo", - configure: "Configurar", - saveChanges: "Salvar Alterações", - addModel: "Adicionar Modelo", - modelName: "Nome do Modelo", provider: "Provedor", apiKey: "Chave da API", - baseUrl: "URL Base", - capabilities: "Capacidades", - enabled: "Habilitado", - disabled: "Desabilitado", - deleteConfirm: "Tem certeza que deseja excluir este modelo?", deleteSuccess: "Modelo excluído com sucesso", saveSuccess: "Modelo salvo com sucesso", - providerStatus: "Status do Provedor", - connectionOk: "Conexão OK", - connectionFailed: "Conexão falhou", - changeEmbeddingWarning: "Alterar o modelo de embedding padrão afetará novas fontes. Fontes existentes podem precisar ser reindexadas.", - changeEmbeddingTitle: "Alterar Modelo de Embedding Padrão?", - aiProviders: "Provedores de IA", - providerConfigDesc: "Configure provedores através de variáveis de ambiente para habilitar seus modelos.", - configuredCount: "{count} de {total} configurados", noModels: "Sem modelos", - learnMore: "Saiba como configurar provedores →", - seeLess: "Ver menos", - seeAll: "Ver todos os {count} provedores", - language_models: "Modelos de Linguagem", - embedding_models: "Modelos de Embedding", - text_to_speech: "Text to Speech (TTS)", - speech_to_text: "Speech to Text (STT)", - languageDesc: "Chat, transformações e geração de texto", - embeddingDesc: "Busca semântica e embeddings vetoriais", - ttsDesc: "Gerar áudio a partir de texto", - sttDesc: "Transcrever áudio para texto", - all: "Todos", - noModelsConfigured: "Nenhum modelo configurado", - noProviderModelsConfigured: "Nenhum modelo {provider} configurado", - showMore: "Mostrar mais {count}", discoverModels: "Descobrir Modelos", noModelsFound: "Nenhum modelo encontrado para este provedor", modelType: "Tipo do Modelo", modelTypeHint: "Selecione o tipo para os modelos que deseja adicionar. Se precisar de tipos diferentes, adicione em lotes separados.", deleteModel: "Excluir Modelo", - deleteModelDesc: "Tem certeza que deseja excluir \"{name}\"? Esta ação não pode ser desfeita.", defaultAssignments: "Atribuições de Modelo Padrão", defaultAssignmentsDesc: "Configure quais modelos usar para diferentes propósitos no Open Notebook", missingRequiredModels: "Modelos obrigatórios ausentes: {models}. O Open Notebook pode não funcionar corretamente sem eles.", selectModelPlaceholder: "Selecione um modelo", requiredModelPlaceholder: "⚠️ Obrigatório - Selecione um modelo", - whichModelToChoose: "Qual modelo devo escolher? →", chatModelLabel: "Modelo de Chat", chatModelDesc: "Usado para conversas de chat", transformationModelLabel: "Modelo de Transformação", @@ -936,16 +840,9 @@ export const ptBR = { ttsModelDesc: "Usado para geração de podcast", sttModelLabel: "Modelo Speech-to-Text", sttModelDesc: "Usado para transcrição de áudio", - addSpecificModel: "Adicionar Modelo de {type}", - addSpecificModelDesc: "Configure um novo modelo de {type} dos provedores disponíveis.", - noProvidersForType: "Nenhum provedor disponível para modelos de {type}", selectProviderPlaceholder: "Selecione um provedor", providerRequired: "Provedor é obrigatório", - modelNameRequired: "Nome do modelo é obrigatório", modelRequired: "Modelo é obrigatório", - adding: "Adicionando...", - azureHint: "Para Azure, use o nome do deployment como nome do modelo", - enterModelName: "Digite o nome do modelo", embeddingChangeTitle: "Alteração de Modelo de Embedding", embeddingChangeConfirm: "Você está prestes a alterar seu modelo de embedding de {from} para {to}.", rebuildRequired: "Importante: Reconstrução Necessária", @@ -959,7 +856,6 @@ export const ptBR = { changeModelOnly: "Apenas Alterar Modelo", changeAndRebuild: "Alterar e Ir para Reconstrução", autoAssign: "Atribuir Automaticamente", - autoAssignDesc: "Atribuir automaticamente o melhor modelo disponível para cada slot", autoAssigning: "Atribuindo...", autoAssignSuccess: "{count} modelos padrão atribuídos automaticamente", autoAssignNoModels: "Nenhum modelo disponível para atribuir. Por favor, sincronize os modelos primeiro.", @@ -967,25 +863,16 @@ export const ptBR = { testModel: "Testar Modelo", testModelSuccess: "Teste do Modelo Passou", testModelFailed: "Teste do Modelo Falhou", - testingModel: "Testando modelo...", searchOrAddModel: "Pesquisar ou digitar nome do modelo...", - addCustomModel: 'Adicionar "{name}"', + addCustomModel: "Adicionar \"{name}\"", }, apiKeys: { title: "Configure sua IA com suas próprias chaves de API", description: "Armazene chaves de API com segurança no banco de dados para habilitar provedores de IA no Open Notebook.", - loadFailed: "Falha ao carregar status das chaves de API", encryptionRequired: "Chave de criptografia não configurada", encryptionRequiredDescription: "Configure a variável de ambiente OPEN_NOTEBOOK_ENCRYPTION_KEY com qualquer string secreta para armazenar chaves de API no banco de dados.", configured: "Configurado", notConfigured: "Não configurado", - sourceDatabase: "Banco de dados", - sourceEnvironment: "Ambiente", - enterApiKey: "Digite sua chave de API", - enterBaseUrl: "Digite a URL base", - saveSuccess: "Chave de API salva com sucesso", - deleteSuccess: "Chave de API excluída com sucesso", - fromEnvironmentHint: "Esta chave é definida via variável de ambiente. Salve uma nova chave para sobrescrevê-la no banco de dados.", migrationAvailable: "Variáveis de Ambiente Detectadas", migrationDescription: "{count} chave(s) de API estão configuradas via variáveis de ambiente e podem ser migradas para o banco de dados para facilitar o gerenciamento.", migrateToDatabase: "Migrar para Banco de Dados", @@ -993,67 +880,29 @@ export const ptBR = { migrationSuccess: "{count} chave(s) de API migrada(s) com sucesso", migrationErrors: "{count} chave(s) falhou ao migrar", migrationNothingToMigrate: "Todas as chaves já estão no banco de dados", - serviceType: "Tipo de Serviço", - serviceLlm: "Modelo de Linguagem (LLM)", - serviceEmbedding: "Embedding", - serviceStt: "Speech to Text (STT)", - serviceTts: "Text to Speech (TTS)", - serviceEndpoints: "Endpoints de Serviço (opcional)", - azureEndpointsHint: "Configure endpoints diferentes para cada tipo de serviço se necessário.", - endpointPlaceholder: "https://seu-recurso.openai.azure.com/", - openaiCompatibleHint: "Configure um endpoint de API compatível com OpenAI. Cada tipo de serviço pode ter sua própria configuração.", - baseUrlPlaceholder: "https://api.exemplo.com/v1", learnMore: "Saiba como configurar chaves de API →", testConnection: "Testar Conexão", - testing: "Testando...", testSuccess: "Conexão bem-sucedida", testFailed: "Falha no teste de conexão", syncModels: "Sincronizar Modelos", - syncing: "Sincronizando...", syncSuccess: "Descobertos {discovered} modelos, {new} novos adicionados", syncNoNew: "Descobertos {count} modelos, todos já registrados", syncFailed: "Falha ao sincronizar modelos", - syncAllModels: "Sincronizar Todos os Provedores", - syncAllSuccess: "Descobertos {discovered} modelos em todos os provedores, {new} novos adicionados", - modelsConfigured: "{count} modelos", - noModelsConfigured: "Sem modelos", - viewModels: "Ver Modelos", - supportedTypes: "Tipos suportados", - typeLanguage: "Linguagem", - typeEmbedding: "Embedding", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "Endpoint da API", getApiKey: "Obter Chave de API", vertexProject: "ID do Projeto GCP", vertexLocation: "Região", vertexCredentials: "Caminho do JSON da Conta de Serviço", - vertexCredentialsHint: "Caminho para o arquivo JSON da conta de serviço do Google Cloud dentro do contêiner.", - - // Multi-config translations - configsCount: "{count} configurações", - configuredMultiple: "Configurado", addConfig: "Adicionar Configuração", editConfig: "Editar Configuração", deleteConfig: "Excluir Configuração", - setAsDefault: "Definir como Padrão", - defaultBadge: "Padrão", - defaultDescription: "Configuração padrão para este provedor", configName: "Nome da Configuração", configNameHint: "Um nome descritivo para esta configuração (ex.: 'Produção', 'Desenvolvimento')", baseUrl: "URL Base", - baseUrlHint: "Padrão: {url}", baseUrlOverrideHint: "Altere apenas se precisar sobrescrever o endpoint padrão do provedor.", - ollamaApiKeyHint: "Necessária apenas para Ollama Cloud. Deixe vazio para Ollama local.", - noConfigs: "Sem configurações ainda", - noConfigsHint: "Adicione uma configuração para começar a usar este provedor", deleteConfigConfirm: "Tem certeza de que deseja excluir '{name}'? Esta ação não pode ser desfeita.", - setDefaultConfirm: "Definir '{name}' como a configuração padrão?", configSaveSuccess: "Configuração salva com sucesso", configUpdateSuccess: "Configuração atualizada com sucesso", configDeleteSuccess: "Configuração excluída com sucesso", - configSetDefaultSuccess: "Configuração padrão atualizada", - apiKeyHint: "Digite sua chave de API para esta configuração", apiKeyEditHint: "Deixe em branco para manter a chave de API existente", }, setupBanner: { diff --git a/frontend/src/lib/locales/ru-RU/index.ts b/frontend/src/lib/locales/ru-RU/index.ts index 9cf1e1a..7410b81 100644 --- a/frontend/src/lib/locales/ru-RU/index.ts +++ b/frontend/src/lib/locales/ru-RU/index.ts @@ -36,22 +36,16 @@ export const ruRU = { warning: "Предупреждение", error: "Ошибка", success: "Успешно", - sessions: "Сессии", model: "Модель", - send: "Отправить", back: "Назад", next: "Далее", done: "Готово", processing: "Обработка...", creating: "Создание...", - tokenCount: "Токены", - charCount: "Символы", linked: "Связано", - added: "Добавлено {date}", adding: "Добавление...", addSelected: "Добавить выбранное", customModel: "Своя модель", - messages: "Сообщения", failed: "не удалось", current: "Текущий", save: "Сохранить", @@ -72,7 +66,6 @@ export const ruRU = { unknown: "Неизвестно", notes: "Заметки", chat: "Чат", - details: "Подробности", deleteForever: "Удалить навсегда", connectionError: "Ошибка подключения", unableToConnect: "Не удаётся подключиться к API-серверу", @@ -85,7 +78,6 @@ export const ruRU = { checkConsoleLogs: "Проверьте консоль браузера для подробных логов (ищите сообщения 🔧 [Config])", yes: "Да", no: "Нет", - simple: "Простой", saving: "Сохранение...", description: "Описание", saveToNote: "Сохранить в заметку", @@ -103,7 +95,6 @@ export const ruRU = { nameRequired: "Название обязательно", modelConfiguration: "Настройка модели", resetToDefault: "Сбросить по умолчанию", - notFound: "Не найдено", reasoning: "Рассуждение", searchTerms: "Поисковые запросы", strategy: "Стратегия", @@ -112,14 +103,12 @@ export const ruRU = { notebookLabel: "Блокнот: {name}", itemNotFound: "Этот {type} не найден", accessibility: { - navigation: "Навигация", transformationViews: "Представления трансформаций", searchKB: "Спросить или найти в базе знаний", enterQuestion: "Введите вопрос для базы знаний", enterSearch: "Введите поисковый запрос", searchKBBtn: "Поиск по базе знаний", podcastViews: "Представления подкастов", - chatSessions: "Сессии чата", ytVideo: "Видео YouTube", askResponse: "Ответ на запрос", searchNotebooks: "Поиск блокнотов", @@ -127,7 +116,6 @@ export const ruRU = { url: "URL", errorDetails: "Детали ошибки", editTransformation: "Редактировать трансформацию", - comingSoon: "Скоро будет", retry: "Повторить", traditionalChinese: "繁體中文", portuguese: "Português", @@ -165,7 +153,6 @@ export const ruRU = { failedToSendMessage: "Не удалось отправить сообщение", unauthorized: "Неавторизованный доступ, проверьте пароль", invalidPassword: "Неверный пароль", - missingAuth: "Отсутствует авторизация", embeddingModelRequired: "Для этой функции требуется модель эмбеддингов. Настройте её в разделе «Модели».", strategyModelNotFound: "Модель стратегии не найдена", answerModelNotFound: "Модель ответов не найдена", @@ -206,7 +193,6 @@ export const ruRU = { passwordPlaceholder: "Пароль", signingIn: "Вход...", signIn: "Войти", - unhandledError: "Необработанная ошибка при входе", connectErrorHint: "Не удаётся подключиться к серверу. Проверьте, запущен ли API.", }, navigation: { @@ -226,7 +212,6 @@ export const ruRU = { nav: "Навигация", language: "Переключить язык", theme: "Тема", - search: "Поиск", ask: "Запрос", }, notebooks: { @@ -248,12 +233,8 @@ export const ruRU = { keepExclusiveSourcesLabel: "Отвязать и сохранить", activeNotebooks: "Активные блокноты", archivedNotebooks: "Архивные блокноты", - emptyDescription: "Начните с создания первого блокнота для организации исследований.", - noActiveNotebooks: "Нет активных блокнотов", - noArchivedNotebooks: "Нет архивных блокнотов", notFound: "Блокнот не найден", notFoundDesc: "Запрошенный блокнот не существует.", - noDescription: "Без описания...", updated: "Обновлено", namePlaceholder: "Название блокнота", addDescription: "Добавить описание...", @@ -278,10 +259,7 @@ export const ruRU = { add: "Добавить источник", addNew: "Добавить новый источник", addExisting: "Добавить существующий источник", - empty: "Пока нет источников", - emptyDesc: "Добавьте первый источник, чтобы начать создание базы знаний.", delete: "Удалить источник", - deleteMsg: "Вы уверены, что хотите удалить этот источник? Это действие нельзя отменить.", statusPreparing: "Подготовка", statusQueued: "В очереди", statusProcessing: "Обработка", @@ -321,7 +299,6 @@ export const ruRU = { sourceRequeued: "Повторная обработка в очереди", sourceRequeuedDesc: "Источник поставлен в очередь на повторную обработку.", failedToRetry: "Повтор не удался", - failedToRetryDesc: "Не удалось повторить обработку источника. Попробуйте ещё раз.", sourcesAddedToNotebook: "Добавлено источников в блокнот: {count}", failedToAddSourcesToNotebook: "Не удалось добавить источники в блокнот", partialAddSuccess: "Добавлено: {success}, не удалось: {failed}", @@ -359,7 +336,6 @@ export const ruRU = { deleteInsight: "Удалить инсайт", deleteInsightConfirm: "Вы уверены, что хотите удалить этот инсайт? Это действие нельзя отменить.", insightGenerationStarted: "Генерация инсайта запущена. Скоро он появится.", - deleteNoteConfirm: "Вы уверены, что хотите удалить эту заметку? Это действие нельзя отменить.", editNote: "Редактировать заметку", createNote: "Создать заметку", addTitle: "Добавьте название...", @@ -367,9 +343,7 @@ export const ruRU = { writeNotePlaceholder: "Напишите содержимое заметки здесь...", saveNote: "Сохранить заметку", createNoteBtn: "Создать заметку", - noNotesYet: "Пока нет заметок", createFirstNote: "Создайте первую заметку для записи идей и наблюдений.", - deleteNote: "Удалить заметку", urlLabel: "URL(ы) *", fileLabel: "Файл(ы) *", textContentLabel: "Текстовое содержимое *", @@ -403,7 +377,6 @@ export const ruRU = { retryProcessing: "Повторить обработку", deleteSource: "Удалить источник", retry: "Повторить", - progress: "Прогресс", addExistingTitle: "Добавить существующие источники", addExistingDesc: "Выберите существующие источники из всех блокнотов для добавления в текущий.", searchPlaceholder: "Поиск источников по названию или URL...", @@ -435,8 +408,6 @@ export const ruRU = { batchFailed: "Не удалось создать все источники: {count}", batchPartial: "Успешно: {success}, не удалось: {failed}", submittingSource: "Отправка источника на обработку...", - contentRequired: "Пожалуйста, предоставьте необходимое содержимое для выбранного типа источника", - titleRequiredForText: "Для текстовых источников требуется название", processingBatchSources: "Обработка источников: {count}. Это может занять некоторое время.", processingSource: "Источник обрабатывается. Это может занять некоторое время.", maxFilesAllowed: "Максимальное количество файлов в пакете: {count}", @@ -445,16 +416,10 @@ export const ruRU = { sessions: "Сессии", sessionTitlePlaceholder: "Введите название...", noSessions: "Пока нет сессий чата", - startChatting: "Начните общение о ваших источниках.", deleteSession: "Удалить сессию", deleteSessionDesc: "Вы уверены, что хотите удалить эту сессию чата? Это действие нельзя отменить.", sendPlaceholder: "Задайте вопрос о ваших источниках...", - newChat: "Новый чат", sessionsTitle: "Сессии чата", - clearhistory: "Очистить историю", - renameSession: "Переименовать сессию", - noSourcesLinked: "Нет связанных источников", - thinking: "ИИ размышляет...", chatWith: "Чат с {name}", startConversation: "Начните разговор об этом {type}", askQuestions: "Задавайте вопросы, чтобы лучше понять содержимое", @@ -508,8 +473,6 @@ export const ruRU = { saveSuccess: "Успешно сохранено в блокнот", saveError: "Не удалось сохранить в блокнот", selectNotebook: "Выберите блокнот", - createNewNotebook: "Создать новый блокнот", - cancel: "Отмена", searchAndAsk: "Поиск и запрос", searchResultsFor: "Результаты поиска для «{query}»", askAbout: "Спросить о «{query}»", @@ -734,8 +697,6 @@ export const ruRU = { speakerCountMin: "Требуется минимум один говорящий", speakerCountMax: "Можно настроить до 4 говорящих", delete: "Удалить", - unknown: "Неизвестно", - deleteSuccess: "Подкаст успешно удалён", failedToDelete: "Не удалось удалить подкаст", }, settings: { @@ -772,13 +733,8 @@ export const ruRU = { title: "Дополнительные инструменты", desc: "Расширенные инструменты и утилиты для опытных пользователей", systemInfo: "Информация о системе", - systemInfoDesc: "Просмотр состояния системных компонентов", rebuildEmbeddings: "Пересоздать эмбеддинги", rebuildEmbeddingsDesc: "Пересоздать индекс векторного поиска для всех источников", - rebuildWarning: "Это действие может занять много времени в зависимости от количества источников. Существующие векторные индексы будут очищены и эмбеддинги будут созданы заново.", - startRebuild: "Начать пересоздание", - rebuilding: "Пересоздание...", - rebuildSuccess: "Пересоздание эмбеддингов успешно запущено", currentVersion: "Текущая версия", latestVersion: "Последняя версия", status: "Статус", @@ -823,10 +779,8 @@ export const ruRU = { defaultPrompt: "Промпт трансформации по умолчанию", defaultPromptDesc: "Этот текст будет добавлен ко всем промптам трансформаций", defaultPromptPlaceholder: "Введите инструкции трансформации по умолчанию...", - saveDefault: "Сохранить по умолчанию", listTitle: "Пользовательские трансформации", createNew: "Создать новую", - testInPlayground: "Тестировать в песочнице", inputLabel: "Входной текст", inputPlaceholder: "Введите текст для трансформации...", outputLabel: "Результат", @@ -845,83 +799,33 @@ export const ruRU = { deleteSuccess: "Трансформация успешно удалена", noTransformations: "Пока нет трансформаций", createOne: "Создайте трансформацию для начала", - deleteDesc: "Удаление трансформации нельзя отменить.", selectModel: "Выберите модель", deleteConfirm: "Вы уверены, что хотите удалить эту трансформацию?", model: "Модель", systemPrompt: "Системный промпт", - type: "Тип", - extraction: "Извлечение", - summary: "Резюме", - custom: "Пользовательский", - saveChanges: "Сохранить изменения", overrideModelDesc: "Переопределить модель по умолчанию для этой сессии чата. Оставьте пустым для использования системной модели.", sessionUseReplacement: "Эта сессия будет использовать {name} вместо модели по умолчанию.", systemDefault: "Системная по умолчанию", }, models: { - title: "Управление моделями", - desc: "Настройте ИИ-модели для различных задач в Open Notebook", - failedToLoad: "Не удалось загрузить данные моделей", - language: "Языковые модели", embedding: "Модели эмбеддинга", tts: "Озвучивание (TTS)", stt: "Распознавание речи (STT)", - providers: "Провайдеры", - defaultModels: "Модели по умолчанию", - status: "Статус", - notConfigured: "Не настроено", - active: "Активно", - inactive: "Неактивно", - configure: "Настроить", - saveChanges: "Сохранить изменения", - addModel: "Добавить модель", - modelName: "Название модели", provider: "Провайдер", apiKey: "API-ключ", - baseUrl: "Базовый URL", - capabilities: "Возможности", - enabled: "Включено", - disabled: "Отключено", - deleteConfirm: "Вы уверены, что хотите удалить эту модель?", deleteSuccess: "Модель успешно удалена", saveSuccess: "Модель успешно сохранена", - providerStatus: "Статус провайдера", - connectionOk: "Подключение OK", - connectionFailed: "Ошибка подключения", - changeEmbeddingWarning: "Изменение модели эмбеддинга по умолчанию повлияет на новые источники. Существующие источники могут потребовать переиндексации.", - changeEmbeddingTitle: "Изменить модель эмбеддинга по умолчанию?", - aiProviders: "ИИ-провайдеры", - providerConfigDesc: "Настройте провайдеров через переменные окружения для включения их моделей.", - configuredCount: "Настроено {count} из {total}", noModels: "Нет моделей", - learnMore: "Узнать, как настроить провайдеров →", - seeLess: "Свернуть", - seeAll: "Показать все {count} провайдеров", - language_models: "Языковые модели", - embedding_models: "Модели эмбеддинга", - text_to_speech: "Озвучивание (TTS)", - speech_to_text: "Распознавание речи (STT)", - languageDesc: "Чат, трансформации и генерация текста", - embeddingDesc: "Семантический поиск и векторные эмбеддинги", - ttsDesc: "Генерация аудио из текста", - sttDesc: "Транскрибация аудио в текст", - all: "Все", - noModelsConfigured: "Модели не настроены", - noProviderModelsConfigured: "Модели {provider} не настроены", - showMore: "Показать ещё {count}", discoverModels: "Обнаружение моделей", noModelsFound: "Модели от этого провайдера не найдены", modelType: "Тип модели", modelTypeHint: "Выберите тип для добавляемых моделей. Если нужны разные типы, добавляйте их отдельными партиями.", deleteModel: "Удалить модель", - deleteModelDesc: "Вы уверены, что хотите удалить «{name}»? Это действие нельзя отменить.", defaultAssignments: "Назначение моделей по умолчанию", defaultAssignmentsDesc: "Настройте, какие модели использовать для различных задач в Open Notebook", missingRequiredModels: "Отсутствуют необходимые модели: {models}. Open Notebook может работать некорректно без них.", selectModelPlaceholder: "Выберите модель", requiredModelPlaceholder: "⚠️ Обязательно — выберите модель", - whichModelToChoose: "Какую модель выбрать? →", chatModelLabel: "Модель чата", chatModelDesc: "Используется для чат-разговоров", transformationModelLabel: "Модель трансформаций", @@ -936,16 +840,9 @@ export const ruRU = { ttsModelDesc: "Используется для генерации подкастов", sttModelLabel: "Модель распознавания речи", sttModelDesc: "Используется для транскрибации аудио", - addSpecificModel: "Добавить модель {type}", - addSpecificModelDesc: "Настройте новую модель {type} от доступных провайдеров.", - noProvidersForType: "Нет доступных провайдеров для моделей {type}", selectProviderPlaceholder: "Выберите провайдера", providerRequired: "Требуется провайдер", - modelNameRequired: "Требуется название модели", modelRequired: "Требуется модель", - adding: "Добавление...", - azureHint: "Для Azure используйте название деплоймента как название модели", - enterModelName: "Введите название модели", embeddingChangeTitle: "Изменение модели эмбеддинга", embeddingChangeConfirm: "Вы собираетесь изменить модель эмбеддинга с {from} на {to}.", rebuildRequired: "Важно: Требуется пересоздание", @@ -958,28 +855,24 @@ export const ruRU = { proceedToRebuildPrompt: "Хотите перейти на страницу «Дополнительно», чтобы начать пересоздание сейчас?", changeModelOnly: "Только изменить модель", changeAndRebuild: "Изменить и перейти к пересозданию", + autoAssign: "Автоназначение по умолчанию", + autoAssigning: "Назначение...", + autoAssignSuccess: "{count} моделей по умолчанию автоматически назначено", + autoAssignNoModels: "Нет доступных моделей для назначения. Сначала синхронизируйте модели.", + autoAssignAlreadySet: "Все модели по умолчанию уже настроены", testModel: "Тестировать модель", testModelSuccess: "Тест модели пройден", testModelFailed: "Тест модели не пройден", - testingModel: "Тестирование модели...", searchOrAddModel: "Поиск или введите имя модели...", - addCustomModel: 'Добавить "{name}"', + addCustomModel: "Добавить \"{name}\"", }, apiKeys: { title: "Настройте ИИ с помощью собственных API-ключей", description: "Храните API-ключи в базе данных для безопасного подключения провайдеров ИИ в Open Notebook.", - loadFailed: "Не удалось загрузить статус API-ключей", encryptionRequired: "Ключ шифрования не настроен", encryptionRequiredDescription: "Установите переменную окружения OPEN_NOTEBOOK_ENCRYPTION_KEY в любую секретную строку для хранения API-ключей в базе данных.", configured: "Настроено", notConfigured: "Не настроено", - sourceDatabase: "База данных", - sourceEnvironment: "Переменная окружения", - enterApiKey: "Введите ваш API-ключ", - enterBaseUrl: "Введите базовый URL", - saveSuccess: "API-ключ успешно сохранён", - deleteSuccess: "API-ключ успешно удалён", - fromEnvironmentHint: "Этот ключ задан через переменную окружения. Сохраните новый ключ, чтобы переопределить его в базе данных.", migrationAvailable: "Обнаружены переменные окружения", migrationDescription: "{count} API-ключ(ей) настроено через переменные окружения и может быть перенесено в базу данных для удобного управления.", migrateToDatabase: "Перенести в базу данных", @@ -987,67 +880,29 @@ export const ruRU = { migrationSuccess: "{count} API-ключ(ей) успешно перенесено", migrationErrors: "{count} ключ(ей) не удалось перенести", migrationNothingToMigrate: "Все ключи уже находятся в базе данных", - serviceType: "Тип сервиса", - serviceLlm: "Языковая модель (LLM)", - serviceEmbedding: "Эмбеддинг", - serviceStt: "Распознавание речи (STT)", - serviceTts: "Синтез речи (TTS)", - serviceEndpoints: "Эндпоинты сервисов (необязательно)", - azureEndpointsHint: "При необходимости настройте отдельные эндпоинты для каждого типа сервиса.", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "Настройте совместимый с OpenAI API-эндпоинт. Каждый тип сервиса может иметь собственную конфигурацию.", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "Узнайте, как настроить API-ключи →", testConnection: "Проверить подключение", - testing: "Проверка...", testSuccess: "Подключение успешно", testFailed: "Проверка подключения не удалась", syncModels: "Синхронизировать модели", - syncing: "Синхронизация...", syncSuccess: "Обнаружено {discovered} моделей, добавлено {new} новых", syncNoNew: "Обнаружено {count} моделей, все уже зарегистрированы", syncFailed: "Не удалось синхронизировать модели", - syncAllModels: "Синхронизировать всех провайдеров", - syncAllSuccess: "Обнаружено {discovered} моделей у всех провайдеров, добавлено {new} новых", - modelsConfigured: "{count} моделей", - noModelsConfigured: "Нет моделей", - viewModels: "Посмотреть модели", - supportedTypes: "Поддерживаемые типы", - typeLanguage: "Языковая", - typeEmbedding: "Эмбеддинг", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "API-эндпоинт", getApiKey: "Получить API-ключ", vertexProject: "ID проекта GCP", vertexLocation: "Регион", vertexCredentials: "Путь к JSON сервисного аккаунта", - vertexCredentialsHint: "Путь к JSON-файлу сервисного аккаунта Google Cloud внутри контейнера.", - - // Мультиконфигурация - configsCount: "{count} конфигураций", - configuredMultiple: "Настроено", addConfig: "Добавить конфигурацию", editConfig: "Редактировать конфигурацию", deleteConfig: "Удалить конфигурацию", - setAsDefault: "Установить по умолчанию", - defaultBadge: "По умолчанию", - defaultDescription: "Конфигурация по умолчанию для этого провайдера", configName: "Название конфигурации", configNameHint: "Описательное название для этой конфигурации (например, «Продакшн», «Разработка»)", baseUrl: "Базовый URL", - baseUrlHint: "По умолчанию: {url}", baseUrlOverrideHint: "Изменяйте только если нужно переопределить стандартную конечную точку API провайдера.", - ollamaApiKeyHint: "Требуется только для Ollama Cloud. Оставьте пустым для локальной Ollama.", - noConfigs: "Конфигурации ещё не созданы", - noConfigsHint: "Добавьте конфигурацию, чтобы начать использовать этого провайдера", deleteConfigConfirm: "Вы уверены, что хотите удалить «{name}»? Это действие необратимо.", - setDefaultConfirm: "Установить «{name}» как конфигурацию по умолчанию?", configSaveSuccess: "Конфигурация успешно сохранена", configUpdateSuccess: "Конфигурация успешно обновлена", configDeleteSuccess: "Конфигурация успешно удалена", - configSetDefaultSuccess: "Конфигурация по умолчанию обновлена", - apiKeyHint: "Введите API-ключ для этой конфигурации", apiKeyEditHint: "Оставьте пустым, чтобы сохранить текущий API-ключ", }, setupBanner: { diff --git a/frontend/src/lib/locales/zh-CN/index.ts b/frontend/src/lib/locales/zh-CN/index.ts index ea0c5a7..8fbb2fe 100644 --- a/frontend/src/lib/locales/zh-CN/index.ts +++ b/frontend/src/lib/locales/zh-CN/index.ts @@ -1,16 +1,11 @@ export const zhCN = { common: { search: "搜索...", - chat: '聊天', - notes: '笔记', create: "新建", new: "新建", cancel: "取消", - save: "保存", - nameRequired: "这是必填项", delete: "删除", edit: "编辑", - actions: "快捷操作", theme: "主题", signOut: "退出登录", noMatches: "未找到匹配项", @@ -41,33 +36,27 @@ export const zhCN = { warning: "警告", error: "操作失败", success: "操作成功", - modelConfiguration: "模型配置", - resetToDefault: "重置为默认", - sessions: "会话", model: "模型", - send: "发送", back: "返回", next: "下一步", done: "完成", processing: "处理中...", creating: "创建中...", - tokenCount: "Token", - charCount: "字符", linked: "已关联", - added: "已于 {date} 添加", adding: "正在添加...", addSelected: "添加所选", customModel: "自定义模型", - messages: "消息", failed: "失败", current: "当前", - writeNote: '撰写笔记', + save: "保存", + writeNote: "撰写笔记", batchMode: "批量模式", optional: "可选", type: "类型", title: "标题", created: "创建于 {time}", updated: "更新于 {time}", + actions: "快捷操作", noResults: "未找到结果", references: "引用", refreshPage: "请重试刷新页面", @@ -75,7 +64,8 @@ export const zhCN = { aiGenerated: "AI 生成", human: "人类", unknown: "未知", - details: "详情", + notes: "笔记", + chat: "聊天", deleteForever: "永久删除", connectionError: "连接错误", unableToConnect: "无法连接到 API 服务器", @@ -88,7 +78,6 @@ export const zhCN = { checkConsoleLogs: "请检查浏览器控制台获取详细日志(搜索 🔧 [Config] 消息)", yes: "是", no: "否", - simple: "简单", saving: "正在保存...", description: "描述", saveToNote: "保存到笔记", @@ -103,7 +92,9 @@ export const zhCN = { saveChanges: "保存更改", name: "名称", default: "默认", - notFound: "未找到", + nameRequired: "这是必填项", + modelConfiguration: "模型配置", + resetToDefault: "重置为默认", reasoning: "推理过程", searchTerms: "搜索词", strategy: "策略", @@ -112,22 +103,19 @@ export const zhCN = { notebookLabel: "笔记本: {name}", itemNotFound: "未找到该 {type}", accessibility: { - navigation: "导航", transformationViews: "转换视图", searchKB: "向知识库提问或搜索", - searchNotebooks: "搜索笔记本", enterQuestion: "输入您的问题以询问知识库", enterSearch: "输入搜索词", searchKBBtn: "搜索知识库", podcastViews: "播客视图", - chatSessions: "对话 Session", ytVideo: "YouTube 视频", askResponse: "提问回答", + searchNotebooks: "搜索笔记本", }, url: "URL", errorDetails: "错误详情", editTransformation: "编辑转换规则", - comingSoon: "敬请期待", retry: "重试", traditionalChinese: "繁体中文", portuguese: "葡萄牙语", @@ -155,17 +143,16 @@ export const zhCN = { invalidSortOrder: "排序方向必须是 'asc' 或 'desc'", accessDenied: "文件访问被拒绝", fileNotFoundOnServer: "服务器上找不到该文件", + searchFailed: "搜索失败", + askFailed: "提问失败", + pleaseEnterQuestion: "请输入问题", + pleaseConfigureModels: "请配置所有必选模型", failedToCreateSession: "创建对话失败", failedToUpdateSession: "更新会话失败", failedToDeleteSession: "删除会话失败", failedToSendMessage: "发送消息失败", - pleaseEnterQuestion: "请输入问题", - pleaseConfigureModels: "请配置所有必选模型", - askFailed: "提问失败", - searchFailed: "搜索失败", unauthorized: "无权访问,请检查您的密码", invalidPassword: "密码错误", - missingAuth: "缺少身份验证信息", embeddingModelRequired: "此功能需要嵌入模型。请在模型设置中配置一个。", strategyModelNotFound: "未找到策略模型", answerModelNotFound: "未找到回答模型", @@ -206,7 +193,6 @@ export const zhCN = { passwordPlaceholder: "密码", signingIn: "正在登录...", signIn: "登录", - unhandledError: "登录过程中出现未处理的错误", connectErrorHint: "无法连接到服务器。请检查 API 是否正在运行。", }, navigation: { @@ -217,8 +203,6 @@ export const zhCN = { sources: "来源", notebooks: "笔记本", askAndSearch: "询问与搜索", - search: "搜索", - ask: "提问", podcasts: "播客", models: "模型", transformations: "转换", @@ -228,6 +212,7 @@ export const zhCN = { nav: "导航", language: "切换语言", theme: "主题", + ask: "提问", }, notebooks: { title: "笔记本", @@ -248,12 +233,8 @@ export const zhCN = { keepExclusiveSourcesLabel: "取消关联并保留", activeNotebooks: "活动的笔记本", archivedNotebooks: "归档的笔记本", - emptyDescription: "从创建您的第一个笔记本开始,组织您的研究。", - noActiveNotebooks: "没有活动的笔记本", - noArchivedNotebooks: "没有归档的笔记本", notFound: "未找到笔记本", notFoundDesc: "请求的笔记本不存在。", - noDescription: "暂无描述...", updated: "已更新", namePlaceholder: "笔记本名称", addDescription: "添加描述...", @@ -278,12 +259,7 @@ export const zhCN = { add: "添加来源", addNew: "添加新来源", addExisting: "添加现有来源", - allSourcesDescShort: "在此查看所有来源。", - cannotSaveNoteNoNotebook: "无法保存笔记:缺少笔记本 ID", - empty: "暂无来源", - emptyDesc: "添加您的第一个来源,开始构建您的知识库。", delete: "删除来源", - deleteMsg: "确定要删除此来源吗?此操作无法撤销。", statusPreparing: "正在准备", statusQueued: "已排队", statusProcessing: "正在处理", @@ -301,6 +277,11 @@ export const zhCN = { yes: "是", no: "否", loadingMore: "正在加载更多...", + noSourcesYet: "暂无来源", + allSourcesDescShort: "在此查看所有来源。", + cannotSaveNoteNoNotebook: "无法保存笔记:缺少笔记本 ID", + createFirstSource: "添加您的第一个来源开始构建知识库。", + deleteSourceConfirm: "确定要删除此来源吗?", deleteConfirm: "确定要删除吗?", deleteConfirmWithTitle: "确定要删除 \"{title}\" 吗?", deleteSuccess: "来源删除成功。注意:要从存储中删除文件,必须在设置页面中启用“删除文件”选项。", @@ -318,16 +299,12 @@ export const zhCN = { sourceRequeued: "来源重试已加入队列", sourceRequeuedDesc: "来源已重新加入处理队列。", failedToRetry: "重试失败", - failedToRetryDesc: "重试来源处理失败。请重试。", sourcesAddedToNotebook: "{count} 个来源已添加到笔记本", failedToAddSourcesToNotebook: "添加来源到笔记本失败", partialAddSuccess: "{success} 个来源已添加,{failed} 个失败", sourceRemovedFromNotebook: "来源已成功从笔记本中移除", failedToRemoveSourceFromNotebook: "从笔记本中移除来源失败", removeConfirm: "确定要从此笔记本移除吗?", - noSourcesYet: "暂无来源", - createFirstSource: "添加您的第一个来源开始构建知识库。", - deleteSourceConfirm: "确定要删除此来源吗?", checking: "正在检查...", untitledSource: "未命名来源", maxItems: "最多 {count} 个", @@ -356,25 +333,50 @@ export const zhCN = { noInsightsYet: "暂无见解", createFirstInsight: "使用上方的转换规则创建您的第一个见解", viewInsight: "查看见解", + deleteInsight: "删除见解", + deleteInsightConfirm: "确定要删除此见解吗?此操作无法撤销。", + insightGenerationStarted: "见解生成已开始,稍后将显示。", + editNote: "编辑笔记", + createNote: "创建笔记", + addTitle: "添加标题...", + untitledNote: "无标题笔记", + writeNotePlaceholder: "在此处编写您的笔记内容...", + saveNote: "保存笔记", + createNoteBtn: "创建笔记", + createFirstNote: "创建您的第一条笔记,记录见解与观察。", + urlLabel: "URL(s) *", + fileLabel: "文件(s) *", + textContentLabel: "文本内容 *", + enterUrlsPlaceholder: "每行输入一个 URL\nhttps://example.com/article1\nhttps://example.com/article2", + batchUrlHint: "粘贴多个 URL(每行一个)进行批量导入", + invalidUrlsDetected: "检测到无效的 URL:", + lineLabel: "第 {line} 行", + fixInvalidUrls: "请修正或移除无效的 URL 以继续", + selectMultipleFilesHint: "选择多个文件进行批量导入。支持:文档 (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD),媒体 (MP4, MP3, WAV, M4A),图片 (JPG, PNG),归档 (ZIP)", + selectedFiles: "已选择文件:", + textPlaceholder: "在此处粘贴或输入您的内容...", + htmlDetected: "检测到 HTML 内容。处理后将转换为 Markdown。", + titlePlaceholder: "为您的来源起一个描述性的标题", + batchTitlesAuto: "将为每个来源自动生成标题。", + batchCommonSettings: "同样的笔记本和转换将应用于所有项目。", + urlsCount: "{count} 个 URL", + filesCount: "{count} 个文件", + addSource: "添加来源", + notEmbeddedAlert: "内容未嵌入向量", + notEmbeddedDesc: "此内容尚未为了向量搜索进行嵌入。嵌入可以启用高级搜索功能并更好地发现内容。", + openOnYoutube: "在 YouTube 上打开", + urlCopied: "URL 已复制到剪贴板", viewSource: "查看来源", noInsightSelected: "未选择见解", sourceInsight: "来源见解", manageNotebooks: "管理所属笔记本", manageNotebooksDesc: "管理包含此来源的笔记本", noNotebooksAvailable: "暂无可用笔记本", - deleteInsight: "删除见解", - deleteInsightConfirm: "确定要删除此见解吗?此操作无法撤销。", - insightGenerationStarted: "见解生成已开始,稍后将显示。", - notEmbeddedAlert: "内容未嵌入向量", - notEmbeddedDesc: "此内容尚未为了向量搜索进行嵌入。嵌入可以启用高级搜索功能并更好地发现内容。", - openOnYoutube: "在 YouTube 上打开", - urlCopied: "URL 已复制到剪贴板", loadFailed: "加载来源详情失败", removeFromNotebook: "从笔记本移除", retryProcessing: "重试处理", deleteSource: "删除来源", retry: "重试", - progress: "进度", addExistingTitle: "添加现有来源", addExistingDesc: "从您的所有笔记本中选择已有的来源添加到当前笔记本。", searchPlaceholder: "通过名称或 URL 搜索来源...", @@ -382,35 +384,6 @@ export const zhCN = { showingFirst100: "仅显示前 100 个来源。请使用搜索功能查找特定来源。", selectedCount: "已选择 {count} 个来源", added: "已添加于 {date}", - noNotesYet: '暂无笔记', - createFirstNote: '创建您的第一条笔记,记录见解与观察。', - deleteNote: '删除笔记', - deleteNoteConfirm: '您确定要删除此笔记吗?此操作无法撤销。', - editNote: '编辑笔记', - createNote: '创建笔记', - addTitle: '添加标题...', - untitledNote: '无标题笔记', - writeNotePlaceholder: '在此处编写您的笔记内容...', - saveNote: '保存笔记', - createNoteBtn: '创建笔记', - urlLabel: 'URL(s) *', - fileLabel: '文件(s) *', - textContentLabel: '文本内容 *', - enterUrlsPlaceholder: '每行输入一个 URL\nhttps://example.com/article1\nhttps://example.com/article2', - batchUrlHint: '粘贴多个 URL(每行一个)进行批量导入', - invalidUrlsDetected: '检测到无效的 URL:', - lineLabel: '第 {line} 行', - fixInvalidUrls: '请修正或移除无效的 URL 以继续', - selectMultipleFilesHint: '选择多个文件进行批量导入。支持:文档 (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD),媒体 (MP4, MP3, WAV, M4A),图片 (JPG, PNG),归档 (ZIP)', - selectedFiles: '已选择文件:', - textPlaceholder: '在此处粘贴或输入您的内容...', - htmlDetected: '检测到 HTML 内容。处理后将转换为 Markdown。', - titlePlaceholder: '为您的来源起一个描述性的标题', - batchTitlesAuto: '将为每个来源自动生成标题。', - batchCommonSettings: '同样的笔记本和转换将应用于所有项目。', - urlsCount: '{count} 个 URL', - filesCount: '{count} 个文件', - addSource: "添加来源", addUrl: "添加 URL", uploadFile: "上传文件", enterText: "输入文本", @@ -435,8 +408,6 @@ export const zhCN = { batchFailed: "全部 {count} 个来源创建失败", batchPartial: "{success} 个成功,{failed} 个失败", submittingSource: "正在提交来源进行处理...", - contentRequired: "请提供所选来源类型所需的内容", - titleRequiredForText: "文本来源需要提供标题", processingBatchSources: "正在处理 {count} 个来源,请稍候...", processingSource: "正在处理您的来源,请稍候...", maxFilesAllowed: "每批最多允许 {count} 个文件", @@ -445,26 +416,20 @@ export const zhCN = { sessions: "会话", sessionTitlePlaceholder: "在此输入标题...", noSessions: "暂无会话", - startChatting: "开始针对您的来源进行聊天。", deleteSession: "删除会话", deleteSessionDesc: "确定要删除此聊天会话吗?此操作无法撤销。", sendPlaceholder: "向您的来源提问...", - newChat: "新建对话", sessionsTitle: "对话列表", - clearhistory: "清空历史", - renameSession: "重命名会话", - noSourcesLinked: "未关联来源", - thinking: "AI 正在思考...", chatWith: "与{name}对话", startConversation: "开始针对{type}进行对话", askQuestions: "提出问题以更好地理解内容", pressToSend: "按 {key} 发送", model: "模型", - createToStart: '创建一个会话以开始。', - chatWithNotebook: '与笔记本对话', - unableToLoadChat: '无法加载聊天', - noDescription: '暂无描述', - startByCreating: '从创建您的第一个笔记本开始,组织您的研究。', + createToStart: "创建一个会话以开始。", + chatWithNotebook: "与笔记本对话", + unableToLoadChat: "无法加载聊天", + noDescription: "暂无描述", + startByCreating: "从创建您的第一个笔记本开始,组织您的研究。", messagesCount: "{count} 条消息", sessionCreated: "聊天会话已创建", sessionUpdated: "会话已更新", @@ -508,8 +473,10 @@ export const zhCN = { saveSuccess: "成功保存到笔记本", saveError: "保存到笔记本失败", selectNotebook: "选择笔记本", - createNewNotebook: "创建新笔记本", - cancel: "取消", + searchAndAsk: "搜索与提问", + searchResultsFor: "搜索 “{query}”", + askAbout: "提问关于 “{query}”", + orSearchKb: "或搜索您的知识库", saving: "保存中...", advancedModelTitle: "高级模型选择", advancedModelDesc: "为提问过程的每个阶段选择特定的模型", @@ -520,10 +487,6 @@ export const zhCN = { selectAnswerPlaceholder: "选择回答模型", selectFinalPlaceholder: "选择最终回答模型", saveChanges: "保存更改", - searchAndAsk: "搜索与提问", - searchResultsFor: "搜索 “{query}”", - askAbout: "提问关于 “{query}”", - orSearchKb: "或搜索您的知识库", processingQuestion: "正在处理您的问题...", }, podcasts: { @@ -637,8 +600,41 @@ export const zhCN = { createProfile: "创建简介", createSpeakerFirst: "在添加单集简介之前,请先创建一个发言人简介。", noEpisodeProfiles: "暂无单集简介。创建一个以启动播客生成。", + speakerCreated: "发言人配置已创建", + speakerCreatedDesc: "发言人配置已准备就绪。", + failedToCreateSpeaker: "创建发言人配置失败", + speakerUpdated: "发言人配置已更新", + speakerUpdatedDesc: "更改已成功保存。", + failedToUpdateSpeaker: "更新发言人配置失败", + speakerDeleted: "发言人配置已删除", + speakerDeletedDesc: "配置已成功移除。", + failedToDeleteSpeaker: "删除发言人配置失败", + speakerDuplicated: "发言人配置已复制", + speakerDuplicatedDesc: "已创建配置副本。", + failedToDuplicateSpeaker: "复制发言人配置失败", + generationStarted: "播客启动生成", + generationStartedDesc: "剧集 \"{name}\" 正在创建中。", + failedToStartGeneration: "启动播客生成失败", + tryAgainMoment: "请稍后再试。", deleteProfileTitle: "删除简介?", deleteProfileDesc: "这将移除 “{name}”。现有单集将保留其数据,但新单集将不再使用此配置。", + profileCreated: "剧集配置已创建", + profileCreatedDesc: "新的剧集配置已准备就绪。", + failedToCreateProfile: "创建剧集配置失败", + profileUpdated: "剧集配置已更新", + profileUpdatedDesc: "更改已成功保存。", + failedToUpdateProfile: "更新剧集配置失败", + profileDeleted: "剧集配置已删除", + profileDeletedDesc: "配置已成功移除。", + failedToDeleteProfile: "删除剧集配置失败", + failedToDeleteProfileDesc: "请确保配置未在使用中并重试。", + profileDuplicated: "剧集配置已复制", + profileDuplicatedDesc: "已创建配置副本。", + failedToDuplicateProfile: "复制剧集配置失败", + episodeDeleted: "剧集已删除", + episodeDeletedDesc: "播客剧集已成功移除。", + failedToDeleteEpisode: "删除剧集失败", + failedToDeleteSpeakerDesc: "请确保配置未在使用中并重试。", outlineModel: "大纲模型", transcriptModel: "脚本模型", segments: "分段数量", @@ -701,42 +697,7 @@ export const zhCN = { speakerCountMin: "至少需要一个发言人", speakerCountMax: "最多只能配置 4 个发言人", delete: "删除", - unknown: "未知", - deleteSuccess: "播客删除成功", failedToDelete: "删除播客失败", - episodeDeleted: "剧集已删除", - episodeDeletedDesc: "播客剧集已成功移除。", - failedToDeleteEpisode: "删除剧集失败", - profileCreated: "剧集配置已创建", - profileCreatedDesc: "新的剧集配置已准备就绪。", - failedToCreateProfile: "创建剧集配置失败", - profileUpdated: "剧集配置已更新", - profileUpdatedDesc: "更改已成功保存。", - failedToUpdateProfile: "更新剧集配置失败", - profileDeleted: "剧集配置已删除", - profileDeletedDesc: "配置已成功移除。", - failedToDeleteProfile: "删除剧集配置失败", - failedToDeleteProfileDesc: "请确保配置未在使用中并重试。", - profileDuplicated: "剧集配置已复制", - profileDuplicatedDesc: "已创建配置副本。", - failedToDuplicateProfile: "复制剧集配置失败", - speakerCreated: "发言人配置已创建", - speakerCreatedDesc: "发言人配置已准备就绪。", - failedToCreateSpeaker: "创建发言人配置失败", - speakerUpdated: "发言人配置已更新", - speakerUpdatedDesc: "更改已成功保存。", - failedToUpdateSpeaker: "更新发言人配置失败", - speakerDeleted: "发言人配置已删除", - speakerDeletedDesc: "配置已成功移除。", - failedToDeleteSpeaker: "删除发言人配置失败", - failedToDeleteSpeakerDesc: "请确保配置未在使用中并重试。", - speakerDuplicated: "发言人配置已复制", - speakerDuplicatedDesc: "已创建配置副本。", - failedToDuplicateSpeaker: "复制发言人配置失败", - generationStarted: "播客启动生成", - generationStartedDesc: "剧集 \"{name}\" 正在创建中。", - failedToStartGeneration: "启动播客生成失败", - tryAgainMoment: "请稍后再试。", }, settings: { contentProcessing: "内容处理", @@ -772,13 +733,8 @@ export const zhCN = { title: "高级工具", desc: "面向进阶用户的调试和实用工具", systemInfo: "系统信息", - systemInfoDesc: "查看底层系统组件的状态", rebuildEmbeddings: "重建索引", rebuildEmbeddingsDesc: "为所有来源重建向量索引", - rebuildWarning: "此操作可能非常耗时,具体取决于您的来源数量。它将清除现有的向量索引并重新为所有内容生成嵌入。", - startRebuild: "开始重建", - rebuilding: "正在重建...", - rebuildSuccess: "索引重建已成功启动", currentVersion: "当前版本", latestVersion: "最新版本", status: "状态", @@ -823,105 +779,53 @@ export const zhCN = { defaultPrompt: "默认全局提示词", defaultPromptDesc: "该提示词将被添加到您所有的转换提示词中", defaultPromptPlaceholder: "输入您的默认转换指令...", - saveDefault: "保存默认设置", listTitle: "自定义转换", createNew: "新建转换", - testInPlayground: "在实验室测试", inputLabel: "输入文本", - inputPlaceholder: '请输入要转换的文本...', - outputLabel: '输出', - runTest: '运行转换', - running: '运行中...', - selectToStart: '选择一个转换规则开始', - name: '名称', - namePlaceholder: '唯一标识符,例如 key_topics', - titlePlaceholder: '显示名称,默认为名称', - promptPlaceholder: '编写驱动此转换的提示词...', - descriptionPlaceholder: '描述此转换的作用。', - suggestDefault: '新来源默认建议', - promptHint: '提示词应根据源内容编写。您可以要求模型总结、提取见解或生成表格等结构化输出。', - createSuccess: '转换规则创建成功', - updateSuccess: '转换规则更新成功', - deleteSuccess: '转换规则删除成功', + inputPlaceholder: "请输入要转换的文本...", + outputLabel: "输出", + runTest: "运行转换", + running: "运行中...", + selectToStart: "选择一个转换规则开始", + name: "名称", + namePlaceholder: "唯一标识符,例如 key_topics", + titlePlaceholder: "显示名称,默认为名称", + promptPlaceholder: "编写驱动此转换的提示词...", + descriptionPlaceholder: "描述此转换的作用。", + suggestDefault: "新来源默认建议", + promptHint: "提示词应根据源内容编写。您可以要求模型总结、提取见解或生成表格等结构化输出。", + createSuccess: "转换规则创建成功", + updateSuccess: "转换规则更新成功", + deleteSuccess: "转换规则删除成功", noTransformations: "暂无转换规则", createOne: "创建一个转换规则以开始", - deleteDesc: "删除此转换无法撤销。", selectModel: "选择模型", deleteConfirm: "确定要删除此转换规则吗?", model: "模型", systemPrompt: "系统提示词", - type: "类型", - extraction: "提取", - summary: "摘要", - custom: "自定义", - saveChanges: "保存更改", overrideModelDesc: "为此聊天会话覆盖默认模型。留空则使用系统默认。", sessionUseReplacement: "此会话将使用 {name} 而不是默认模型。", systemDefault: "系统默认", }, models: { - title: "模型管理", - desc: "配置用于 Open Notebook 不同用途的 AI 模型", - failedToLoad: "加载模型数据失败", - language: "语言模型", embedding: "嵌入模型", tts: "文字转语音", stt: "语音转文字", - providers: "服务商", - defaultModels: "默认模型", - status: "状态", - notConfigured: "未配置", - active: "活动", - inactive: "不活动", - configure: "配置", - saveChanges: "保存更改", - addModel: "添加模型", - modelName: "模型名称", provider: "服务商", apiKey: "API 密钥", - baseUrl: "基础 URL", - capabilities: "功能", - enabled: "已启用", - disabled: "已禁用", - deleteConfirm: "确定要删除此模型吗?", deleteSuccess: "模型删除成功", saveSuccess: "模型保存成功", - providerStatus: "服务商状态", - connectionOk: "连接正常", - connectionFailed: "连接失败", - changeEmbeddingWarning: "更改默认嵌入模型将影响新的来源。现有来源可能需要重建索引。", - changeEmbeddingTitle: "更改默认嵌入模型?", - aiProviders: "AI 服务商", - providerConfigDesc: "通过环境变量配置服务商以启用其模型。", - configuredCount: "已配置 {count} / {total}", noModels: "暂无模型", - learnMore: "了解如何配置服务商 →", - seeLess: "收起", - seeAll: "查看全部 {count} 个服务商", - language_models: "语言模型", - embedding_models: "嵌入模型", - text_to_speech: "文字转语音", - speech_to_text: "语音转文字", - languageDesc: "聊天、内容转换和文本生成", - embeddingDesc: "语义搜索和向量嵌入", - ttsDesc: "根据文本生成音频", - sttDesc: "将语音转录为文本", - all: "全部", - noModelsConfigured: "未配置模型", - noProviderModelsConfigured: "未配置 {provider} 模型", - showMore: "显示更多 ({count})", discoverModels: "发现模型", noModelsFound: "未从此提供商找到模型", modelType: "模型类型", modelTypeHint: "选择要添加的模型类型。如果需要不同类型,请分批添加。", deleteModel: "删除模型", - deleteModelDesc: "确定要删除模型 “{name}” 吗?该操作无法撤销。", defaultAssignments: "默认模型分配", defaultAssignmentsDesc: "配置用于 Open Notebook 不同用途的默认模型", missingRequiredModels: "缺少必需的模型:{models}。如果没有这些模型,Open Notebook 可能无法正常运行。", selectModelPlaceholder: "选择一个模型", requiredModelPlaceholder: "⚠️ 必需 - 请选择一个模型", - whichModelToChoose: "我该选择哪个模型?→", chatModelLabel: "聊天模型", chatModelDesc: "用于聊天对话", transformationModelLabel: "转换模型", @@ -936,16 +840,9 @@ export const zhCN = { ttsModelDesc: "用于生成播客", sttModelLabel: "语音转文字模型", sttModelDesc: "用于音频转录", - addSpecificModel: "添加 {type} 模型", - addSpecificModelDesc: "从可用服务商配置一个新的 {type} 模型。", - noProvidersForType: "暂无可用于 {type} 模型的服务商", selectProviderPlaceholder: "选择服务商", providerRequired: "服务商是必填项", - modelNameRequired: "模型名称是必填项", modelRequired: "模型是必填项", - adding: "正在添加...", - azureHint: "对于 Azure,请使用部署名称作为模型名称", - enterModelName: "输入模型名称", embeddingChangeTitle: "嵌入模型变更", embeddingChangeConfirm: "您即将将嵌入模型从 {from} 更改为 {to}。", rebuildRequired: "重要提示:需要重建索引", @@ -959,7 +856,6 @@ export const zhCN = { changeModelOnly: "仅更改模型", changeAndRebuild: "更改并前往重建", autoAssign: "自动分配默认值", - autoAssignDesc: "为每个槽位自动分配最佳可用模型", autoAssigning: "正在分配...", autoAssignSuccess: "已自动分配 {count} 个默认模型", autoAssignNoModels: "没有可分配的模型。请先同步模型。", @@ -967,25 +863,16 @@ export const zhCN = { testModel: "测试模型", testModelSuccess: "模型测试通过", testModelFailed: "模型测试失败", - testingModel: "正在测试模型...", searchOrAddModel: "搜索或输入模型名称...", - addCustomModel: '添加 "{name}"', + addCustomModel: "添加 \"{name}\"", }, apiKeys: { title: "使用您自己的 API 密钥配置 AI", description: "将 API 密钥安全地存储在数据库中,以在 Open Notebook 中启用 AI 服务商。", - loadFailed: "加载 API 密钥状态失败", encryptionRequired: "未配置加密密钥", encryptionRequiredDescription: "请将 OPEN_NOTEBOOK_ENCRYPTION_KEY 环境变量设置为任意密钥字符串,以启用将 API 密钥存储到数据库。", configured: "已配置", notConfigured: "未配置", - sourceDatabase: "数据库", - sourceEnvironment: "环境变量", - enterApiKey: "输入您的 API 密钥", - enterBaseUrl: "输入基础 URL", - saveSuccess: "API 密钥保存成功", - deleteSuccess: "API 密钥删除成功", - fromEnvironmentHint: "此密钥通过环境变量设置。保存新密钥将在数据库中覆盖它。", migrationAvailable: "检测到环境变量", migrationDescription: "{count} 个 API 密钥通过环境变量配置,可以迁移到数据库以便于管理。", migrateToDatabase: "迁移到数据库", @@ -993,67 +880,29 @@ export const zhCN = { migrationSuccess: "{count} 个 API 密钥迁移成功", migrationErrors: "{count} 个密钥迁移失败", migrationNothingToMigrate: "所有密钥已在数据库中", - serviceType: "服务类型", - serviceLlm: "语言模型 (LLM)", - serviceEmbedding: "嵌入", - serviceStt: "语音转文字 (STT)", - serviceTts: "文字转语音 (TTS)", - serviceEndpoints: "服务端点(可选)", - azureEndpointsHint: "如有需要,为每种服务类型配置不同的端点。", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "配置 OpenAI 兼容的 API 端点。每种服务类型可以有自己的配置。", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "了解如何配置 API 密钥 →", testConnection: "测试连接", - testing: "测试中...", testSuccess: "连接成功", testFailed: "连接测试失败", syncModels: "同步模型", - syncing: "同步中...", syncSuccess: "发现 {discovered} 个模型,新增 {new} 个", syncNoNew: "发现 {count} 个模型,全部已注册", syncFailed: "同步模型失败", - syncAllModels: "同步所有提供商", - syncAllSuccess: "在所有提供商中发现 {discovered} 个模型,新增 {new} 个", - modelsConfigured: "{count} 个模型", - noModelsConfigured: "无模型", - viewModels: "查看模型", - supportedTypes: "支持的类型", - typeLanguage: "语言", - typeEmbedding: "嵌入", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "API 端点", getApiKey: "获取 API 密钥", vertexProject: "GCP 项目 ID", vertexLocation: "区域", vertexCredentials: "服务账户 JSON 路径", - vertexCredentialsHint: "容器内 Google Cloud 服务账户 JSON 文件的路径。", - - // Multi-config translations - configsCount: "{count} 个配置", - configuredMultiple: "已配置", addConfig: "添加配置", editConfig: "编辑配置", deleteConfig: "删除配置", - setAsDefault: "设为默认", - defaultBadge: "默认", - defaultDescription: "此提供商的默认配置", configName: "配置名称", configNameHint: "此配置的描述性名称(例如:'生产环境'、'开发环境')", baseUrl: "基础 URL", - baseUrlHint: "默认:{url}", baseUrlOverrideHint: "仅在需要覆盖提供商默认 API 端点时更改此项。", - ollamaApiKeyHint: "仅 Ollama Cloud 需要 API 密钥。本地 Ollama 请留空。", - noConfigs: "暂无配置", - noConfigsHint: "添加配置以开始使用此提供商", deleteConfigConfirm: "确定要删除 '{name}' 吗?此操作无法撤销。", - setDefaultConfirm: "将 '{name}' 设为默认配置?", configSaveSuccess: "配置保存成功", configUpdateSuccess: "配置更新成功", configDeleteSuccess: "配置删除成功", - configSetDefaultSuccess: "默认配置已更新", - apiKeyHint: "输入此配置的 API 密钥", apiKeyEditHint: "留空以保留现有 API 密钥", }, setupBanner: { diff --git a/frontend/src/lib/locales/zh-TW/index.ts b/frontend/src/lib/locales/zh-TW/index.ts index 3d7c128..6e25ba4 100644 --- a/frontend/src/lib/locales/zh-TW/index.ts +++ b/frontend/src/lib/locales/zh-TW/index.ts @@ -1,29 +1,24 @@ export const zhTW = { common: { search: "搜尋...", - chat: '聊天', - notes: '筆記', create: "新增", new: "新建", cancel: "取消", - save: "儲存", delete: "刪除", edit: "編輯", - actions: "快捷操作", theme: "主題", signOut: "登出", + noMatches: "沒有找到匹配項", + tryDifferentSearch: "請嘗試使用不同的關鍵詞搜尋。", + light: "亮色", + dark: "暗色", + system: "系統", loading: "載入中...", note: "筆記", insight: "洞察", newSource: "新增來源", newNotebook: "新增筆記本", newPodcast: "新增播客", - nameRequired: "此為必填項", - noMatches: "沒有找到匹配項", - tryDifferentSearch: "請嘗試使用不同的關鍵詞搜尋。", - light: "亮色", - dark: "暗色", - system: "系統", language: "語言", english: "English", chinese: "簡體中文", @@ -41,31 +36,27 @@ export const zhTW = { warning: "警告", error: "錯誤", success: "成功", - sessions: "對話", model: "模型", - send: "發送", back: "返回", next: "下一步", done: "完成", processing: "處理中...", creating: "正在新增...", - tokenCount: "Token", - charCount: "字元", linked: "已連結", - added: "已於 {date} 新增", adding: "正在新增...", addSelected: "新增所選", customModel: "自訂模型", - messages: "訊息", failed: "失敗", current: "目前", - writeNote: '撰寫筆記', + save: "儲存", + writeNote: "撰寫筆記", batchMode: "批次模式", optional: "可選", type: "類型", title: "標題", created: "建立於 {time}", updated: "更新於 {time}", + actions: "快捷操作", noResults: "未找到結果", references: "引用", refreshPage: "請嘗試重新整理頁面", @@ -73,7 +64,8 @@ export const zhTW = { aiGenerated: "AI 生成", human: "人類", unknown: "未知", - details: "詳情", + notes: "筆記", + chat: "聊天", deleteForever: "永久刪除", connectionError: "連線錯誤", unableToConnect: "無法連線至 API 伺服器", @@ -86,7 +78,6 @@ export const zhTW = { checkConsoleLogs: "請檢查瀏覽器主控台以獲取詳細日誌(搜尋 🔧 [Config] 訊息)", yes: "是", no: "否", - simple: "簡單", saving: "正在儲存...", description: "描述", saveToNote: "儲存到筆記", @@ -101,9 +92,9 @@ export const zhTW = { saveChanges: "儲存更改", name: "名稱", default: "預設", + nameRequired: "此為必填項", modelConfiguration: "模型設定", resetToDefault: "重置為預設", - notFound: "未找到", reasoning: "推理過程", searchTerms: "搜尋詞", strategy: "策略", @@ -112,22 +103,19 @@ export const zhTW = { notebookLabel: "筆記本: {name}", itemNotFound: "未找到該 {type}", accessibility: { - navigation: "導覽", transformationViews: "轉換視圖", searchKB: "向知識庫提問或搜尋", - searchNotebooks: "搜尋筆記本", enterQuestion: "輸入您的問題以詢問知識庫", enterSearch: "輸入搜尋詞", searchKBBtn: "搜尋知識庫", podcastViews: "播客視圖", - chatSessions: "對話 Session", ytVideo: "YouTube 影片", askResponse: "提問回答", + searchNotebooks: "搜尋筆記本", }, url: "URL", errorDetails: "錯誤詳情", editTransformation: "編輯轉換規則", - comingSoon: "敬請期待", retry: "重試", traditionalChinese: "繁體中文", portuguese: "葡萄牙語", @@ -155,17 +143,16 @@ export const zhTW = { invalidSortOrder: "排序方向必須是 'asc' 或 'desc'", accessDenied: "檔案存取被拒絕", fileNotFoundOnServer: "伺服器上找不到該檔案", + searchFailed: "搜尋失敗", + askFailed: "提問失敗", + pleaseEnterQuestion: "請輸入問題", + pleaseConfigureModels: "請設定所有必選模型", failedToCreateSession: "新增對話失敗", failedToUpdateSession: "更新對話失敗", failedToDeleteSession: "刪除對話失敗", failedToSendMessage: "發送訊息失敗", - pleaseEnterQuestion: "請輸入問題", - pleaseConfigureModels: "請設定所有必選模型", - askFailed: "提問失敗", - searchFailed: "搜尋失敗", unauthorized: "無權存取,請檢查您的密碼", invalidPassword: "密碼錯誤", - missingAuth: "缺少身分驗證資訊", embeddingModelRequired: "此功能需要嵌入模型。請在模型設定中設定一個。", strategyModelNotFound: "未找到策略模型", answerModelNotFound: "未找到回答模型", @@ -206,7 +193,6 @@ export const zhTW = { passwordPlaceholder: "密碼", signingIn: "正在登入...", signIn: "登入", - unhandledError: "登入過程中出現未處理的錯誤", connectErrorHint: "無法連線至伺服器。請檢查 API 是否正在運行。", }, navigation: { @@ -217,8 +203,6 @@ export const zhTW = { sources: "來源", notebooks: "筆記本", askAndSearch: "詢問與搜尋", - search: "搜尋", - ask: "提問", podcasts: "播客", models: "模型", transformations: "轉換", @@ -228,6 +212,7 @@ export const zhTW = { nav: "導覽", language: "切換語言", theme: "主題", + ask: "提問", }, notebooks: { title: "筆記本", @@ -248,12 +233,8 @@ export const zhTW = { keepExclusiveSourcesLabel: "取消關聯並保留", activeNotebooks: "活動中的筆記本", archivedNotebooks: "封存的筆記本", - emptyDescription: "從新增您的第一個筆記本開始,組織您的研究。", - noActiveNotebooks: "沒有活動中的筆記本", - noArchivedNotebooks: "沒有封存的筆記本", notFound: "未找到筆記本", notFoundDesc: "請求的筆記本不存在。", - noDescription: "暫無描述...", updated: "已更新", namePlaceholder: "筆記本名稱", addDescription: "新增描述...", @@ -278,12 +259,7 @@ export const zhTW = { add: "新增來源", addNew: "新增新來源", addExisting: "新增現有來源", - allSourcesDescShort: "在此檢視所有來源。", - cannotSaveNoteNoNotebook: "無法儲存筆記:缺少筆記本 ID", - empty: "暫無來源", - emptyDesc: "新增您的第一個來源,開始構建您的知識庫。", delete: "刪除來源", - deleteMsg: "確定要刪除此來源嗎?此操作無法撤銷。", statusPreparing: "正在準備", statusQueued: "已排隊", statusProcessing: "正在處理", @@ -301,6 +277,11 @@ export const zhTW = { yes: "是", no: "否", loadingMore: "正在載入更多...", + noSourcesYet: "暫無來源", + allSourcesDescShort: "在此檢視所有來源。", + cannotSaveNoteNoNotebook: "無法儲存筆記:缺少筆記本 ID", + createFirstSource: "新增您的第一個來源開始構建知識庫。", + deleteSourceConfirm: "確定要刪除此來源嗎?", deleteConfirm: "確定要刪除嗎?", deleteConfirmWithTitle: "確定要刪除 \"{title}\" 嗎?", deleteSuccess: "來源刪除成功。注意:要從儲存中刪除檔案,必須在設定頁面中啟用「刪除檔案」選項。", @@ -318,16 +299,12 @@ export const zhTW = { sourceRequeued: "來源重試已加入隊列", sourceRequeuedDesc: "來源已重新加入處理隊列。", failedToRetry: "重試失敗", - failedToRetryDesc: "重試來源處理失敗。請重試。", sourcesAddedToNotebook: "{count} 個來源已新增到筆記本", failedToAddSourcesToNotebook: "新增來源到筆記本失敗", partialAddSuccess: "{success} 個來源已新增,{failed} 個失敗", sourceRemovedFromNotebook: "來源已成功從筆記本中移除", failedToRemoveSourceFromNotebook: "從筆記本中移除來源失敗", removeConfirm: "確定要從此筆記本移除嗎?", - noSourcesYet: "暫無來源", - createFirstSource: "新增您的第一個來源開始構建知識庫。", - deleteSourceConfirm: "確定要刪除此來源嗎?", checking: "正在檢查...", untitledSource: "未命名來源", maxItems: "最多 {count} 個", @@ -356,25 +333,50 @@ export const zhTW = { noInsightsYet: "暫無見解", createFirstInsight: "使用上方的轉換規則新增您的第一個見解", viewInsight: "查看見解", + deleteInsight: "刪除見解", + deleteInsightConfirm: "確定要刪除此見解嗎?此操作無法撤銷。", + insightGenerationStarted: "見解生成已開始,稍後將顯示。", + editNote: "編輯筆記", + createNote: "新增筆記", + addTitle: "新增標題...", + untitledNote: "無標題筆記", + writeNotePlaceholder: "在此處編寫您的筆記內容...", + saveNote: "儲存筆記", + createNoteBtn: "新增筆記", + createFirstNote: "新增您的第一條筆記,記錄見解與觀察。", + urlLabel: "URL(s) *", + fileLabel: "檔案(s) *", + textContentLabel: "文字內容 *", + enterUrlsPlaceholder: "每行輸入一個 URL\nhttps://example.com/article1\nhttps://example.com/article2", + batchUrlHint: "貼上多個 URL(每行一個)進行批次導入", + invalidUrlsDetected: "檢測到無效的 URL:", + lineLabel: "第 {line} 行", + fixInvalidUrls: "請修正或移除無效的 URL 以繼續", + selectMultipleFilesHint: "選擇多個檔案進行批次導入。支援:文件 (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD),媒體 (MP4, MP3, WAV, M4A),圖片 (JPG, PNG),歸檔 (ZIP)", + selectedFiles: "已選擇檔案:", + textPlaceholder: "在此處貼上或輸入您的內容...", + htmlDetected: "偵測到 HTML 內容。處理後將轉換為 Markdown。", + titlePlaceholder: "為您的來源取一個描述性的標題", + batchTitlesAuto: "將為每個來源自動生成標題。", + batchCommonSettings: "相同的筆記本和轉換將應用於所有項目。", + urlsCount: "{count} 個 URL", + filesCount: "{count} 個檔案", + addSource: "新增來源", + notEmbeddedAlert: "內容未嵌入向量", + notEmbeddedDesc: "此內容尚未為了向量搜尋進行嵌入。嵌入可以啟用進階搜尋功能並更好地發現內容。", + openOnYoutube: "在 YouTube 上開啟", + urlCopied: "URL 已複製到剪貼簿", viewSource: "查看來源", noInsightSelected: "未選擇見解", sourceInsight: "來源見解", manageNotebooks: "管理所屬筆記本", manageNotebooksDesc: "管理包含此來源的筆記本", noNotebooksAvailable: "暫無可用筆記本", - deleteInsight: "刪除見解", - deleteInsightConfirm: "確定要刪除此見解嗎?此操作無法撤銷。", - insightGenerationStarted: "見解生成已開始,稍後將顯示。", - notEmbeddedAlert: "內容未嵌入向量", - notEmbeddedDesc: "此內容尚未為了向量搜尋進行嵌入。嵌入可以啟用進階搜尋功能並更好地發現內容。", - openOnYoutube: "在 YouTube 上開啟", - urlCopied: "URL 已複製到剪貼簿", loadFailed: "載入來源詳情失敗", removeFromNotebook: "從筆記本移除", retryProcessing: "重試處理", deleteSource: "刪除來源", retry: "重試", - progress: "進度", addExistingTitle: "新增現有來源", addExistingDesc: "從您的所有筆記本中選擇已有的來源新增到當前筆記本。", searchPlaceholder: "通過名稱或 URL 搜尋來源...", @@ -382,35 +384,6 @@ export const zhTW = { showingFirst100: "僅顯示前 100 個來源。請使用搜尋功能查找特定來源。", selectedCount: "已選擇 {count} 個來源", added: "已新增於 {date}", - noNotesYet: '暫無筆記', - createFirstNote: "新增您的第一條筆記,記錄見解與觀察。", - deleteNote: '刪除筆記', - deleteNoteConfirm: '您確定要刪除此筆記嗎?此操作無法撤銷。', - editNote: '編輯筆記', - createNote: "新增筆記", - addTitle: '新增標題...', - untitledNote: '無標題筆記', - writeNotePlaceholder: '在此處編寫您的筆記內容...', - saveNote: '儲存筆記', - createNoteBtn: "新增筆記", - urlLabel: 'URL(s) *', - fileLabel: '檔案(s) *', - textContentLabel: '文字內容 *', - enterUrlsPlaceholder: '每行輸入一個 URL\nhttps://example.com/article1\nhttps://example.com/article2', - batchUrlHint: '貼上多個 URL(每行一個)進行批次導入', - invalidUrlsDetected: '檢測到無效的 URL:', - lineLabel: '第 {line} 行', - fixInvalidUrls: '請修正或移除無效的 URL 以繼續', - selectMultipleFilesHint: '選擇多個檔案進行批次導入。支援:文件 (PDF, DOC, DOCX, PPT, XLS, EPUB, TXT, MD),媒體 (MP4, MP3, WAV, M4A),圖片 (JPG, PNG),歸檔 (ZIP)', - selectedFiles: '已選擇檔案:', - textPlaceholder: '在此處貼上或輸入您的內容...', - htmlDetected: '偵測到 HTML 內容。處理後將轉換為 Markdown。', - titlePlaceholder: '為您的來源取一個描述性的標題', - batchTitlesAuto: '將為每個來源自動生成標題。', - batchCommonSettings: '相同的筆記本和轉換將應用於所有項目。', - urlsCount: '{count} 個 URL', - filesCount: '{count} 個檔案', - addSource: "新增來源", addUrl: "新增 URL", uploadFile: "上傳檔案", enterText: "輸入文字", @@ -435,8 +408,6 @@ export const zhTW = { batchFailed: "全部 {count} 個來源新增失敗", batchPartial: "{success} 個成功,{failed} 個失敗", submittingSource: "正在提交來源進行處理...", - contentRequired: "請提供所選來源類型所需的內容", - titleRequiredForText: "文字來源需要提供標題", processingBatchSources: "正在處理 {count} 個來源,請稍候...", processingSource: "正在處理您的來源,請稍候...", maxFilesAllowed: "每批最多允許 {count} 個檔案", @@ -445,25 +416,19 @@ export const zhTW = { sessions: "對話", sessionTitlePlaceholder: "在此輸入標題...", noSessions: "暫無對話", - startChatting: "開始針對您的來源進行聊天。", deleteSession: "刪除對話", deleteSessionDesc: "確定要刪除此聊天會話嗎?此操作無法撤銷。", sendPlaceholder: "向您的來源提問...", - newChat: "新建對話", sessionsTitle: "對話列表", - clearhistory: "清空歷史", - renameSession: "重新命名對話", - noSourcesLinked: "未連結來源", - thinking: "AI 正在思考...", chatWith: "與 {name} 對話", startConversation: "開始針對 {type} 進行對話", askQuestions: "提出問題以更好地理解內容", pressToSend: "按 {key} 發送", model: "模型", createToStart: "新增一個會話以開始。", - chatWithNotebook: '與筆記本對話', - unableToLoadChat: '無法載入聊天', - noDescription: '暫無描述', + chatWithNotebook: "與筆記本對話", + unableToLoadChat: "無法載入聊天", + noDescription: "暫無描述", startByCreating: "從新增您的第一個筆記本開始,組織您的研究。", messagesCount: "{count} 條訊息", sessionCreated: "聊天會話已建立", @@ -508,8 +473,10 @@ export const zhTW = { saveSuccess: "成功儲存到筆記本", saveError: "儲存到筆記本失敗", selectNotebook: "選擇筆記本", - createNewNotebook: "建立新筆記本", - cancel: "取消", + searchAndAsk: "搜尋與提問", + searchResultsFor: "搜尋 “{query}”", + askAbout: "提問關於 “{query}”", + orSearchKb: "或搜尋您的知識庫", saving: "儲存中...", advancedModelTitle: "進階模型選擇", advancedModelDesc: "為提問過程的每個階段選擇模型", @@ -520,10 +487,6 @@ export const zhTW = { selectAnswerPlaceholder: "選擇回答模型", selectFinalPlaceholder: "選擇最終回答模型", saveChanges: "儲存更改", - searchAndAsk: "搜尋與提問", - searchResultsFor: "搜尋 “{query}”", - askAbout: "提問關於 “{query}”", - orSearchKb: "或搜尋您的知識庫", processingQuestion: "正在處理您的問題...", }, podcasts: { @@ -637,8 +600,41 @@ export const zhTW = { createProfile: "建立簡介", createSpeakerFirst: "在新增單集簡介之前,請先建立一個發言人簡介。", noEpisodeProfiles: "暫無單集簡介。建立一個以啟動播客生成。", + speakerCreated: "發言人設定已建立", + speakerCreatedDesc: "發言人設定已準備就緒。", + failedToCreateSpeaker: "建立發言人設定失敗", + speakerUpdated: "發言人設定已更新", + speakerUpdatedDesc: "更改已成功儲存。", + failedToUpdateSpeaker: "更新發言人設定失敗", + speakerDeleted: "發言人設定已刪除", + speakerDeletedDesc: "設定已成功移除。", + failedToDeleteSpeaker: "刪除發言人設定失敗", + speakerDuplicated: "發言人設定已複製", + speakerDuplicatedDesc: "已建立設定副本。", + failedToDuplicateSpeaker: "複製發言人設定失敗", + generationStarted: "播客啟動生成", + generationStartedDesc: "劇集 \"{name}\" 正在建立中。", + failedToStartGeneration: "啟動播客生成失敗", + tryAgainMoment: "請稍後再試。", deleteProfileTitle: "刪除簡介?", deleteProfileDesc: "這將移除 “{name}”。現有單集將保留其資料,但新單集將不再使用此設定。", + profileCreated: "劇集設定已建立", + profileCreatedDesc: "新的劇集設定已準備就緒。", + failedToCreateProfile: "建立劇集設定失敗", + profileUpdated: "劇集設定已更新", + profileUpdatedDesc: "更改已成功儲存。", + failedToUpdateProfile: "更新劇集設定失敗", + profileDeleted: "劇集設定已刪除", + profileDeletedDesc: "設定已成功移除。", + failedToDeleteProfile: "刪除劇集設定失敗", + failedToDeleteProfileDesc: "請確保設定未在使用中並重試。", + profileDuplicated: "劇集設定已複製", + profileDuplicatedDesc: "已建立設定副本。", + failedToDuplicateProfile: "複製劇集設定失敗", + episodeDeleted: "劇集已刪除", + episodeDeletedDesc: "播客劇集已成功移除。", + failedToDeleteEpisode: "刪除劇集失敗", + failedToDeleteSpeakerDesc: "請確保設定未在使用中並重試。", outlineModel: "大綱模型", transcriptModel: "腳本模型", segments: "分段數量", @@ -701,42 +697,7 @@ export const zhTW = { speakerCountMin: "至少需要一個發言人", speakerCountMax: "最多只能設定 4 個發言人", delete: "刪除", - unknown: "未知", - deleteSuccess: "播客刪除成功", failedToDelete: "刪除播客失敗", - episodeDeleted: "劇集已刪除", - episodeDeletedDesc: "播客劇集已成功移除。", - failedToDeleteEpisode: "刪除劇集失敗", - profileCreated: "劇集設定已建立", - profileCreatedDesc: "新的劇集設定已準備就緒。", - failedToCreateProfile: "建立劇集設定失敗", - profileUpdated: "劇集設定已更新", - profileUpdatedDesc: "更改已成功儲存。", - failedToUpdateProfile: "更新劇集設定失敗", - profileDeleted: "劇集設定已刪除", - profileDeletedDesc: "設定已成功移除。", - failedToDeleteProfile: "刪除劇集設定失敗", - failedToDeleteProfileDesc: "請確保設定未在使用中並重試。", - profileDuplicated: "劇集設定已複製", - profileDuplicatedDesc: "已建立設定副本。", - failedToDuplicateProfile: "複製劇集設定失敗", - speakerCreated: "發言人設定已建立", - speakerCreatedDesc: "發言人設定已準備就緒。", - failedToCreateSpeaker: "建立發言人設定失敗", - speakerUpdated: "發言人設定已更新", - speakerUpdatedDesc: "更改已成功儲存。", - failedToUpdateSpeaker: "更新發言人設定失敗", - speakerDeleted: "發言人設定已刪除", - speakerDeletedDesc: "設定已成功移除。", - failedToDeleteSpeaker: "刪除發言人設定失敗", - failedToDeleteSpeakerDesc: "請確保設定未在使用中並重試。", - speakerDuplicated: "發言人設定已複製", - speakerDuplicatedDesc: "已建立設定副本。", - failedToDuplicateSpeaker: "複製發言人設定失敗", - generationStarted: "播客啟動生成", - generationStartedDesc: "劇集 \"{name}\" 正在建立中。", - failedToStartGeneration: "啟動播客生成失敗", - tryAgainMoment: "請稍後再試。", }, settings: { contentProcessing: "內容處理", @@ -772,13 +733,8 @@ export const zhTW = { title: "進階工具", desc: "針對進階使用者的調試和實用工具", systemInfo: "系統資訊", - systemInfoDesc: "查看底層系統組件的狀態", rebuildEmbeddings: "重建索引", rebuildEmbeddingsDesc: "為所有來源重建向量索引", - rebuildWarning: "此操作可能非常耗時,具體取決於您的來源數量。它將清除現有的向量索引並重新為所有內容生成嵌入。", - startRebuild: "開始重建", - rebuilding: "正在重建...", - rebuildSuccess: "索引重建已成功啟動", currentVersion: "目前版本", latestVersion: "最新版本", status: "狀態", @@ -823,105 +779,53 @@ export const zhTW = { defaultPrompt: "預設全局提示詞", defaultPromptDesc: "該提示詞將被新增到您所有的轉換提示詞中", defaultPromptPlaceholder: "輸入您的預設轉換指令...", - saveDefault: "儲存預設設定", listTitle: "自訂轉換", createNew: "新建轉換", - testInPlayground: "在實驗室測試", inputLabel: "輸入文本", - inputPlaceholder: '請輸入要轉換的文本...', - outputLabel: '輸出', - runTest: '運行轉換', - running: '運行中...', - selectToStart: '選擇一個轉換規則開始', - name: '名稱', - namePlaceholder: '唯一標識符,例如 key_topics', - titlePlaceholder: '顯示名稱,預設為名稱', - promptPlaceholder: '編寫驅動此轉換的提示詞...', - descriptionPlaceholder: '描述此轉換的作用。', - suggestDefault: '新來源預設建議', - promptHint: '提示詞應根據源內容編寫。您可以要求模型總結、提取見解或生成表格等結構化輸出。', - createSuccess: '轉換規則建立成功', - updateSuccess: '轉換規則更新成功', - deleteSuccess: '轉換規則刪除成功', + inputPlaceholder: "請輸入要轉換的文本...", + outputLabel: "輸出", + runTest: "運行轉換", + running: "運行中...", + selectToStart: "選擇一個轉換規則開始", + name: "名稱", + namePlaceholder: "唯一標識符,例如 key_topics", + titlePlaceholder: "顯示名稱,預設為名稱", + promptPlaceholder: "編寫驅動此轉換的提示詞...", + descriptionPlaceholder: "描述此轉換的作用。", + suggestDefault: "新來源預設建議", + promptHint: "提示詞應根據源內容編寫。您可以要求模型總結、提取見解或生成表格等結構化輸出。", + createSuccess: "轉換規則建立成功", + updateSuccess: "轉換規則更新成功", + deleteSuccess: "轉換規則刪除成功", noTransformations: "暫無轉換規則", createOne: "建立一個轉換規則以開始", - deleteDesc: "刪除此轉換無法復原。", selectModel: "選擇模型", deleteConfirm: "確定要刪除此轉換規則嗎?", model: "模型", systemPrompt: "系統提示詞", - type: "類型", - extraction: "提取", - summary: "摘要", - custom: "自訂", - saveChanges: "儲存更改", overrideModelDesc: "為此對話會話覆蓋預設模型。留空則使用系統預設。", sessionUseReplacement: "此會話將使用 {name} 而不是預設模型。", systemDefault: "系統預設", }, models: { - title: "模型管理", - desc: "設定用於 Open Notebook 不同用途的 AI 模型", - failedToLoad: "載入模型資料失敗", - language: "語言模型", embedding: "嵌入模型", tts: "文字轉語音", stt: "語音轉文字", - providers: "提供商", - defaultModels: "預設模型", - status: "狀態", - notConfigured: "未設定", - active: "活動", - inactive: "不活動", - configure: "設定", - saveChanges: "儲存更改", - addModel: "新增模型", - modelName: "模型名稱", provider: "提供商", apiKey: "API 密鑰", - baseUrl: "基礎 URL", - capabilities: "功能", - enabled: "已啟用", - disabled: "已禁用", - deleteConfirm: "確定要刪除此模型嗎?", deleteSuccess: "模型刪除成功", saveSuccess: "模型儲存成功", - providerStatus: "提供商狀態", - connectionOk: "連線正常", - connectionFailed: "連線失敗", - changeEmbeddingWarning: "更改預設嵌入模型將影響新的來源。現有來源可能需要重建索引。", - changeEmbeddingTitle: "更改預設嵌入模型?", - aiProviders: "AI 提供商", - providerConfigDesc: "通過環境變數設定提供商以啟用其模型。", - configuredCount: "已設定 {count} / {total}", noModels: "暫無模型", - learnMore: "了解如何設定提供商 →", - seeLess: "收起", - seeAll: "查看全部 {count} 個提供商", - language_models: "語言模型", - embedding_models: "嵌入模型", - text_to_speech: "文字轉語音", - speech_to_text: "語音轉文字", - languageDesc: "聊天、內容轉換和文本生成", - embeddingDesc: "語義搜尋和向量嵌入", - ttsDesc: "根據文本生成音訊", - sttDesc: "將語音轉錄為文本", - all: "全部", - noModelsConfigured: "未設定模型", - noProviderModelsConfigured: "未設定 {provider} 模型", - showMore: "顯示更多 ({count})", discoverModels: "探索模型", noModelsFound: "未從此提供商找到模型", modelType: "模型類型", modelTypeHint: "選擇要新增的模型類型。如果需要不同類型,請分批新增。", deleteModel: "刪除模型", - deleteModelDesc: "確定要刪除模型 “{name}” 嗎?該操作無法撤銷。", defaultAssignments: "預設模型分配", defaultAssignmentsDesc: "設定用於 Open Notebook 不同用途的預設模型", missingRequiredModels: "缺少必需的模型:{models}。如果没有這些模型,Open Notebook 可能無法正常運行。", selectModelPlaceholder: "選擇一個模型", requiredModelPlaceholder: "⚠️ 必需 - 請選擇一個模型", - whichModelToChoose: "我該選擇哪個模型?→", chatModelLabel: "聊天模型", chatModelDesc: "用於聊天對話", transformationModelLabel: "轉換模型", @@ -936,16 +840,9 @@ export const zhTW = { ttsModelDesc: "用於生成播客", sttModelLabel: "語音轉文字模型", sttModelDesc: "用於音訊轉錄", - addSpecificModel: "新增 {type} 模型", - addSpecificModelDesc: "從可用提供商設定一個新的 {type} 模型。", - noProvidersForType: "暫無可用於 {type} 模型的提供商", selectProviderPlaceholder: "選擇提供商", providerRequired: "提供商是必填項", - modelNameRequired: "模型名稱是必填項", modelRequired: "模型是必填項", - adding: "正在新增...", - azureHint: "對於 Azure,請使用部署名稱作為模型名稱", - enterModelName: "輸入模型名稱", embeddingChangeTitle: "嵌入模型變更", embeddingChangeConfirm: "您即將將嵌入模型從 {from} 更改為 {to}。", rebuildRequired: "重要提示:需要重建索引", @@ -959,7 +856,6 @@ export const zhTW = { changeModelOnly: "僅更改模型", changeAndRebuild: "更改並前往重建", autoAssign: "自動指派預設值", - autoAssignDesc: "為每個插槽自動指派最佳可用模型", autoAssigning: "正在指派...", autoAssignSuccess: "已自動指派 {count} 個預設模型", autoAssignNoModels: "沒有可指派的模型。請先同步模型。", @@ -967,25 +863,16 @@ export const zhTW = { testModel: "測試模型", testModelSuccess: "模型測試通過", testModelFailed: "模型測試失敗", - testingModel: "正在測試模型...", searchOrAddModel: "搜尋或輸入模型名稱...", - addCustomModel: '新增 "{name}"', + addCustomModel: "新增 \"{name}\"", }, apiKeys: { title: "使用您自己的 API 金鑰設定 AI", description: "將 API 金鑰安全地儲存在資料庫中,以在 Open Notebook 中啟用 AI 服務商。", - loadFailed: "載入 API 金鑰狀態失敗", encryptionRequired: "未設定加密金鑰", encryptionRequiredDescription: "請將 OPEN_NOTEBOOK_ENCRYPTION_KEY 環境變數設定為任意密鑰字串,以啟用將 API 金鑰儲存至資料庫。", configured: "已設定", notConfigured: "未設定", - sourceDatabase: "資料庫", - sourceEnvironment: "環境變數", - enterApiKey: "輸入您的 API 金鑰", - enterBaseUrl: "輸入基礎 URL", - saveSuccess: "API 金鑰儲存成功", - deleteSuccess: "API 金鑰刪除成功", - fromEnvironmentHint: "此金鑰通過環境變數設定。儲存新金鑰將在資料庫中覆蓋它。", migrationAvailable: "偵測到環境變數", migrationDescription: "{count} 個 API 金鑰通過環境變數設定,可以遷移到資料庫以便於管理。", migrateToDatabase: "遷移到資料庫", @@ -993,67 +880,29 @@ export const zhTW = { migrationSuccess: "{count} 個 API 金鑰遷移成功", migrationErrors: "{count} 個金鑰遷移失敗", migrationNothingToMigrate: "所有金鑰已在資料庫中", - serviceType: "服務類型", - serviceLlm: "語言模型 (LLM)", - serviceEmbedding: "嵌入", - serviceStt: "語音轉文字 (STT)", - serviceTts: "文字轉語音 (TTS)", - serviceEndpoints: "服務端點(選填)", - azureEndpointsHint: "如有需要,為每種服務類型設定不同的端點。", - endpointPlaceholder: "https://your-resource.openai.azure.com/", - openaiCompatibleHint: "設定 OpenAI 相容的 API 端點。每種服務類型可以有自己的設定。", - baseUrlPlaceholder: "https://api.example.com/v1", learnMore: "瞭解如何設定 API 金鑰 →", testConnection: "測試連線", - testing: "測試中...", testSuccess: "連線成功", testFailed: "連線測試失敗", syncModels: "同步模型", - syncing: "同步中...", syncSuccess: "發現 {discovered} 個模型,新增 {new} 個", syncNoNew: "發現 {count} 個模型,全部已註冊", syncFailed: "同步模型失敗", - syncAllModels: "同步所有供應商", - syncAllSuccess: "在所有供應商中發現 {discovered} 個模型,新增 {new} 個", - modelsConfigured: "{count} 個模型", - noModelsConfigured: "無模型", - viewModels: "查看模型", - supportedTypes: "支援的類型", - typeLanguage: "語言", - typeEmbedding: "嵌入", - typeTts: "TTS", - typeStt: "STT", - apiEndpoint: "API 端點", getApiKey: "取得 API 金鑰", vertexProject: "GCP 專案 ID", vertexLocation: "區域", vertexCredentials: "服務帳戶 JSON 路徑", - vertexCredentialsHint: "容器內 Google Cloud 服務帳戶 JSON 檔案的路徑。", - - // Multi-config translations - configsCount: "{count} 個設定", - configuredMultiple: "已設定", addConfig: "新增設定", editConfig: "編輯設定", deleteConfig: "刪除設定", - setAsDefault: "設為預設", - defaultBadge: "預設", - defaultDescription: "此供應商的預設設定", configName: "設定名稱", configNameHint: "此設定的描述性名稱(例如:'生產環境'、'開發環境')", baseUrl: "基礎 URL", - baseUrlHint: "預設:{url}", baseUrlOverrideHint: "僅在需要覆蓋提供商預設 API 端點時更改此項。", - ollamaApiKeyHint: "僅 Ollama Cloud 需要 API 金鑰。本地 Ollama 請留空。", - noConfigs: "暫無設定", - noConfigsHint: "新增設定以開始使用此供應商", deleteConfigConfirm: "確定要刪除 '{name}' 嗎?此操作無法撤銷。", - setDefaultConfirm: "將 '{name}' 設為預設設定?", configSaveSuccess: "設定儲存成功", configUpdateSuccess: "設定更新成功", configDeleteSuccess: "設定刪除成功", - configSetDefaultSuccess: "預設設定已更新", - apiKeyHint: "輸入此設定的 API 金鑰", apiKeyEditHint: "留空以保留現有 API 金鑰", }, setupBanner: {