feat: add password confirmation to register + fix i18n hardcoded strings

- Add confirmPassword field to registration form with Zod validation
- Replace ~30 hardcoded French/English strings in admin-settings-form
  with proper t() i18n calls (Ollama models, Custom models, search test)
- Extract SettingsHeader to client component for i18n support
- Add 15 i18n keys to all 15 locale files (auth + admin.ai + admin.tools)
- Remove debug "Config value" line from embeddings section

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 19:59:38 +02:00
parent bbaae76103
commit e358171c45
20 changed files with 385 additions and 114 deletions

View File

@@ -91,11 +91,11 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
else if (type === 'embeddings') setOllamaEmbeddingsModels(result.models) else if (type === 'embeddings') setOllamaEmbeddingsModels(result.models)
else setOllamaChatModels(result.models) else setOllamaChatModels(result.models)
} else { } else {
toast.error(`Failed to fetch Ollama models: ${result.error}`) toast.error(`${t('admin.ai.fetchModelsFailed')}: ${result.error}`)
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error('Failed to fetch Ollama models') toast.error(t('admin.ai.fetchModelsFailed'))
} finally { } finally {
if (type === 'tags') setIsLoadingTagsModels(false) if (type === 'tags') setIsLoadingTagsModels(false)
else if (type === 'embeddings') setIsLoadingEmbeddingsModels(false) else if (type === 'embeddings') setIsLoadingEmbeddingsModels(false)
@@ -122,11 +122,11 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
else if (type === 'embeddings') setCustomEmbeddingsModels(result.models) else if (type === 'embeddings') setCustomEmbeddingsModels(result.models)
else setCustomChatModels(result.models) else setCustomChatModels(result.models)
} else { } else {
toast.error(`Impossible de récupérer les modèles : ${result.error}`) toast.error(`${t('admin.ai.fetchModelsFailed')}: ${result.error}`)
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
toast.error('Erreur lors de la récupération des modèles') toast.error(t('admin.ai.fetchModelsFailed'))
} finally { } finally {
if (type === 'tags') setIsLoadingCustomTagsModels(false) if (type === 'tags') setIsLoadingCustomTagsModels(false)
else if (type === 'embeddings') setIsLoadingCustomEmbeddingsModels(false) else if (type === 'embeddings') setIsLoadingCustomEmbeddingsModels(false)
@@ -439,7 +439,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchOllamaModels('tags', input.value) fetchOllamaModels('tags', input.value)
}} }}
disabled={isLoadingTagsModels} disabled={isLoadingTagsModels}
title="Refresh Models" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingTagsModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingTagsModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -455,15 +455,20 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
> >
{ollamaTagsModels.length > 0 ? ( {ollamaTagsModels.length > 0 ? (
ollamaTagsModels.map((model) => ( <>
<option key={model} value={model}>{model}</option> {!ollamaTagsModels.includes(selectedTagsModel) && selectedTagsModel && (
)) <option value={selectedTagsModel}>{selectedTagsModel} ({t('admin.ai.configured')})</option>
)}
{ollamaTagsModels.map((model) => (
<option key={model} value={model}>{model}</option>
))}
</>
) : ( ) : (
<option value={selectedTagsModel || 'granite4:latest'}>{selectedTagsModel || 'granite4:latest'} {t('admin.ai.saved')}</option> <option value={selectedTagsModel || 'granite4:latest'}>{selectedTagsModel || 'granite4:latest'} {t('admin.ai.saved')}</option>
)} )}
</select> </select>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingTagsModels ? 'Fetching models...' : t('admin.ai.selectOllamaModel')} {isLoadingTagsModels ? t('admin.ai.fetchingModels') : t('admin.ai.selectOllamaModel')}
</p> </p>
</div> </div>
</div> </div>
@@ -515,7 +520,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchCustomModels('tags', urlInput.value, keyInput.value) fetchCustomModels('tags', urlInput.value, keyInput.value)
}} }}
disabled={isLoadingCustomTagsModels} disabled={isLoadingCustomTagsModels}
title="Récupérer les modèles" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingCustomTagsModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingCustomTagsModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -537,16 +542,16 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
} }
value={selectedTagsModel} value={selectedTagsModel}
onChange={setSelectedTagsModel} onChange={setSelectedTagsModel}
placeholder={selectedTagsModel || 'Cliquez sur ↺ pour charger les modèles'} placeholder={selectedTagsModel || t('admin.ai.clickToLoadModels')}
searchPlaceholder="Rechercher un modèle..." searchPlaceholder={t('admin.ai.searchModel')}
emptyMessage="Aucun modèle. Cliquez sur ↺" emptyMessage={t('admin.ai.noModels')}
/> />
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingCustomTagsModels {isLoadingCustomTagsModels
? 'Récupération des modèles...' ? t('admin.ai.fetchingModels')
: customTagsModels.length > 0 : customTagsModels.length > 0
? `${customTagsModels.length} modèle(s) disponible(s)` ? t('admin.ai.modelsAvailable', { count: customTagsModels.length })
: 'Renseignez l\'URL et cliquez sur ↺ pour charger les modèles'} : t('admin.ai.enterUrlToLoad')}
</p> </p>
</div> </div>
</div> </div>
@@ -563,7 +568,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
<Label htmlFor="AI_PROVIDER_EMBEDDING"> <Label htmlFor="AI_PROVIDER_EMBEDDING">
{t('admin.ai.provider')} {t('admin.ai.provider')}
<span className="ml-2 text-xs text-muted-foreground"> <span className="ml-2 text-xs text-muted-foreground">
(Current: {embeddingsProvider}) {t('admin.ai.currentProvider', { provider: embeddingsProvider })}
</span> </span>
</Label> </Label>
<select <select
@@ -586,9 +591,6 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
<option value="openai">{t('admin.ai.providerOpenAIOption')}</option> <option value="openai">{t('admin.ai.providerOpenAIOption')}</option>
<option value="custom">{t('admin.ai.providerCustomOption')}</option> <option value="custom">{t('admin.ai.providerCustomOption')}</option>
</select> </select>
<p className="text-xs text-muted-foreground">
Config value: {config.AI_PROVIDER_EMBEDDING || 'Not set (defaults to ollama)'}
</p>
</div> </div>
{embeddingsProvider === 'ollama' && ( {embeddingsProvider === 'ollama' && (
@@ -611,7 +613,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchOllamaModels('embeddings', input.value) fetchOllamaModels('embeddings', input.value)
}} }}
disabled={isLoadingEmbeddingsModels} disabled={isLoadingEmbeddingsModels}
title="Refresh Models" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingEmbeddingsModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingEmbeddingsModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -627,15 +629,20 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
> >
{ollamaEmbeddingsModels.length > 0 ? ( {ollamaEmbeddingsModels.length > 0 ? (
ollamaEmbeddingsModels.map((model) => ( <>
<option key={model} value={model}>{model}</option> {!ollamaEmbeddingsModels.includes(selectedEmbeddingModel) && selectedEmbeddingModel && (
)) <option value={selectedEmbeddingModel}>{selectedEmbeddingModel} ({t('admin.ai.configured')})</option>
)}
{ollamaEmbeddingsModels.map((model) => (
<option key={model} value={model}>{model}</option>
))}
</>
) : ( ) : (
<option value={selectedEmbeddingModel || 'embeddinggemma:latest'}>{selectedEmbeddingModel || 'embeddinggemma:latest'} {t('admin.ai.saved')}</option> <option value={selectedEmbeddingModel || 'embeddinggemma:latest'}>{selectedEmbeddingModel || 'embeddinggemma:latest'} {t('admin.ai.saved')}</option>
)} )}
</select> </select>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingEmbeddingsModels ? 'Fetching models...' : t('admin.ai.selectEmbeddingModel')} {isLoadingEmbeddingsModels ? t('admin.ai.fetchingModels') : t('admin.ai.selectEmbeddingModel')}
</p> </p>
</div> </div>
</div> </div>
@@ -687,7 +694,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchCustomModels('embeddings', urlInput.value, keyInput.value) fetchCustomModels('embeddings', urlInput.value, keyInput.value)
}} }}
disabled={isLoadingCustomEmbeddingsModels} disabled={isLoadingCustomEmbeddingsModels}
title="Récupérer les modèles" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingCustomEmbeddingsModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingCustomEmbeddingsModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -709,16 +716,16 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
} }
value={selectedEmbeddingModel} value={selectedEmbeddingModel}
onChange={setSelectedEmbeddingModel} onChange={setSelectedEmbeddingModel}
placeholder={selectedEmbeddingModel || 'Cliquez sur ↺ pour charger les modèles'} placeholder={selectedEmbeddingModel || t('admin.ai.clickToLoadModels')}
searchPlaceholder="Rechercher un modèle..." searchPlaceholder={t('admin.ai.searchModel')}
emptyMessage="Aucun modèle. Cliquez sur ↺" emptyMessage={t('admin.ai.noModels')}
/> />
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingCustomEmbeddingsModels {isLoadingCustomEmbeddingsModels
? 'Récupération des modèles...' ? t('admin.ai.fetchingModels')
: customEmbeddingsModels.length > 0 : customEmbeddingsModels.length > 0
? `${customEmbeddingsModels.length} modèle(s) disponible(s)` ? t('admin.ai.modelsAvailable', { count: customEmbeddingsModels.length })
: 'Renseignez l\'URL et cliquez sur ↺ pour charger les modèles'} : t('admin.ai.enterUrlToLoad')}
</p> </p>
</div> </div>
</div> </div>
@@ -776,7 +783,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchOllamaModels('chat', input.value) fetchOllamaModels('chat', input.value)
}} }}
disabled={isLoadingChatModels} disabled={isLoadingChatModels}
title="Refresh Models" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingChatModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingChatModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -792,15 +799,20 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
> >
{ollamaChatModels.length > 0 ? ( {ollamaChatModels.length > 0 ? (
ollamaChatModels.map((model) => ( <>
<option key={model} value={model}>{model}</option> {!ollamaChatModels.includes(selectedChatModel) && selectedChatModel && (
)) <option value={selectedChatModel}>{selectedChatModel} ({t('admin.ai.configured')})</option>
)}
{ollamaChatModels.map((model) => (
<option key={model} value={model}>{model}</option>
))}
</>
) : ( ) : (
<option value={selectedChatModel || 'granite4:latest'}>{selectedChatModel || 'granite4:latest'} {t('admin.ai.saved')}</option> <option value={selectedChatModel || 'granite4:latest'}>{selectedChatModel || 'granite4:latest'} {t('admin.ai.saved')}</option>
)} )}
</select> </select>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingChatModels ? 'Fetching models...' : t('admin.ai.selectOllamaModel')} {isLoadingChatModels ? t('admin.ai.fetchingModels') : t('admin.ai.selectOllamaModel')}
</p> </p>
</div> </div>
</div> </div>
@@ -852,7 +864,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
fetchCustomModels('chat', urlInput.value, keyInput.value) fetchCustomModels('chat', urlInput.value, keyInput.value)
}} }}
disabled={isLoadingCustomChatModels} disabled={isLoadingCustomChatModels}
title="Récupérer les modèles" title={t('admin.ai.refreshModels')}
> >
<RefreshCw className={`h-4 w-4 ${isLoadingCustomChatModels ? 'animate-spin' : ''}`} /> <RefreshCw className={`h-4 w-4 ${isLoadingCustomChatModels ? 'animate-spin' : ''}`} />
</Button> </Button>
@@ -874,16 +886,16 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
} }
value={selectedChatModel} value={selectedChatModel}
onChange={setSelectedChatModel} onChange={setSelectedChatModel}
placeholder={selectedChatModel || 'Cliquez sur ↺ pour charger les modèles'} placeholder={selectedChatModel || t('admin.ai.clickToLoadModels')}
searchPlaceholder="Rechercher un modèle..." searchPlaceholder={t('admin.ai.searchModel')}
emptyMessage="Aucun modèle. Cliquez sur ↺" emptyMessage={t('admin.ai.noModels')}
/> />
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isLoadingCustomChatModels {isLoadingCustomChatModels
? 'Récupération des modèles...' ? t('admin.ai.fetchingModels')
: customChatModels.length > 0 : customChatModels.length > 0
? `${customChatModels.length} modèle(s) disponible(s)` ? t('admin.ai.modelsAvailable', { count: customChatModels.length })
: 'Renseignez l\'URL et cliquez sur ↺ pour charger les modèles'} : t('admin.ai.enterUrlToLoad')}
</p> </p>
</div> </div>
</div> </div>
@@ -1105,7 +1117,7 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
onClick={handleTestSearch} onClick={handleTestSearch}
disabled={isTestingSearch} disabled={isTestingSearch}
> >
{isTestingSearch ? 'Test en cours…' : 'Tester la recherche web'} {isTestingSearch ? t('admin.tools.testing') : t('admin.tools.testSearch')}
</Button> </Button>
</CardFooter> </CardFooter>
</form> </form>

View File

@@ -1,20 +1,13 @@
import { getSystemConfig } from '@/app/actions/admin-settings' import { getSystemConfig } from '@/app/actions/admin-settings'
import { AdminSettingsForm } from './admin-settings-form' import { AdminSettingsForm } from './admin-settings-form'
import { SettingsHeader } from './settings-header'
export default async function AdminSettingsPage() { export default async function AdminSettingsPage() {
const config = await getSystemConfig() const config = await getSystemConfig()
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div> <SettingsHeader />
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Settings
</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">
Configure application-wide settings
</p>
</div>
<div className="bg-white dark:bg-zinc-900 rounded-lg shadow overflow-hidden border border-gray-200 dark:border-gray-800 p-6"> <div className="bg-white dark:bg-zinc-900 rounded-lg shadow overflow-hidden border border-gray-200 dark:border-gray-800 p-6">
<AdminSettingsForm config={config} /> <AdminSettingsForm config={config} />
</div> </div>

View File

@@ -0,0 +1,17 @@
'use client'
import { useLanguage } from '@/lib/i18n'
export function SettingsHeader() {
const { t } = useLanguage()
return (
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
{t('admin.settings')}
</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">
{t('admin.settingsDescription')}
</p>
</div>
)
}

View File

@@ -9,7 +9,11 @@ import { getSystemConfig } from '@/lib/config';
const RegisterSchema = z.object({ const RegisterSchema = z.object({
email: z.string().email(), email: z.string().email(),
password: z.string().min(6), password: z.string().min(6),
confirmPassword: z.string().min(6),
name: z.string().min(2), name: z.string().min(2),
}).refine((data) => data.password === data.confirmPassword, {
message: 'Passwords do not match',
path: ['confirmPassword'],
}); });
export async function register(prevState: string | undefined, formData: FormData) { export async function register(prevState: string | undefined, formData: FormData) {
@@ -24,6 +28,7 @@ export async function register(prevState: string | undefined, formData: FormData
const validatedFields = RegisterSchema.safeParse({ const validatedFields = RegisterSchema.safeParse({
email: formData.get('email'), email: formData.get('email'),
password: formData.get('password'), password: formData.get('password'),
confirmPassword: formData.get('confirmPassword'),
name: formData.get('name'), name: formData.get('name'),
}); });

View File

@@ -84,6 +84,25 @@ export function RegisterForm() {
/> />
</div> </div>
</div> </div>
<div className="mt-4">
<label
className="mb-3 mt-5 block text-xs font-medium text-gray-900"
htmlFor="confirmPassword"
>
{t('auth.confirmPassword')}
</label>
<div className="relative">
<Input
className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
id="confirmPassword"
type="password"
name="confirmPassword"
placeholder={t('auth.confirmPasswordPlaceholder')}
required
minLength={6}
/>
</div>
</div>
</div> </div>
<RegisterButton /> <RegisterButton />
<div <div

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(تم الحفظ)", "saved": "(تم الحفظ)",
"chatProvider": "مزود الدردشة", "chatProvider": "مزود الدردشة",
"chatDescription": "مزود الذكاء الاصطناعي لمساعد الدردشة. يستخدم مزود الوسوم إذا لم يتم تكوينه." "chatDescription": "مزود الذكاء الاصطناعي لمساعد الدردشة. يستخدم مزود الوسوم إذا لم يتم تكوينه.",
"fetchModelsFailed": "فشل في جلب النماذج",
"refreshModels": "تحديث النماذج",
"configured": "مكوّن",
"fetchingModels": "جارٍ جلب النماذج...",
"clickToLoadModels": "انقر على ↺ لتحميل النماذج",
"searchModel": "البحث عن نموذج...",
"noModels": "لا توجد نماذج. انقر على ↺",
"modelsAvailable": "{count} نموذج متاح",
"enterUrlToLoad": "أدخل الرابط وانقر على ↺ لتحميل النماذج",
"currentProvider": "(الحالي: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "اختبر مزودي الذكاء الاصطناعي لتوليد الوسوم وتضمينات البحث الدلالي", "description": "اختبر مزودي الذكاء الاصطناعي لتوليد الوسوم وتضمينات البحث الدلالي",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "يُستخدم لاستخراج الويب. يعمل بدون مفتاح ولكن مع حدود معدل.", "jinaKeyDescription": "يُستخدم لاستخراج الويب. يعمل بدون مفتاح ولكن مع حدود معدل.",
"saveSettings": "حفظ إعدادات الأدوات", "saveSettings": "حفظ إعدادات الأدوات",
"updateSuccess": "تم تحديث إعدادات الأدوات بنجاح", "updateSuccess": "تم تحديث إعدادات الأدوات بنجاح",
"updateFailed": "فشل تحديث إعدادات الأدوات" "updateFailed": "فشل تحديث إعدادات الأدوات",
} "testing": "جارٍ الاختبار...",
"testSearch": "اختبار البحث على الويب"
},
"settingsDescription": "تكوين الإعدادات العامة للتطبيق"
}, },
"ai": { "ai": {
"analyzing": "الذكاء الاصطناعي يحلل...", "analyzing": "الذكاء الاصطناعي يحلل...",
@@ -368,7 +381,9 @@
"signIn": "تسجيل الدخول", "signIn": "تسجيل الدخول",
"signInToAccount": "سجل الدخول إلى حسابك", "signInToAccount": "سجل الدخول إلى حسابك",
"signOut": "Sign out", "signOut": "Sign out",
"signUp": "إنشاء حساب" "signUp": "إنشاء حساب",
"confirmPassword": "تأكيد كلمة المرور",
"confirmPasswordPlaceholder": "أعد إدخال كلمة المرور"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "جاري تحليل الملاحظات...", "analyzing": "جاري تحليل الملاحظات...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(Gespeichert)", "saved": "(Gespeichert)",
"chatProvider": "Chat-Anbieter", "chatProvider": "Chat-Anbieter",
"chatDescription": "KI-Anbieter für den Chat-Assistenten. Fällt auf den Tags-Anbieter zurück, wenn nicht konfiguriert." "chatDescription": "KI-Anbieter für den Chat-Assistenten. Fällt auf den Tags-Anbieter zurück, wenn nicht konfiguriert.",
"fetchModelsFailed": "Modelle konnten nicht geladen werden",
"refreshModels": "Modelle aktualisieren",
"configured": "Konfiguriert",
"fetchingModels": "Modelle werden geladen...",
"clickToLoadModels": "Klicken Sie auf ↺ um Modelle zu laden",
"searchModel": "Modell suchen...",
"noModels": "Keine Modelle. Klicken Sie auf ↺",
"modelsAvailable": "{count} Modell(e) verfügbar",
"enterUrlToLoad": "URL eingeben und ↺ klicken",
"currentProvider": "(Aktuell: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Testen Sie Ihre KI-Anbieter für Tag-Generierung und semantische Such-Embeddings", "description": "Testen Sie Ihre KI-Anbieter für Tag-Generierung und semantische Such-Embeddings",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Wird für Web-Scraping verwendet. Funktioniert ohne Schlüssel, aber mit Ratenbegrenzung.", "jinaKeyDescription": "Wird für Web-Scraping verwendet. Funktioniert ohne Schlüssel, aber mit Ratenbegrenzung.",
"saveSettings": "Werkzeugeinstellungen speichern", "saveSettings": "Werkzeugeinstellungen speichern",
"updateSuccess": "Werkzeugeinstellungen erfolgreich aktualisiert", "updateSuccess": "Werkzeugeinstellungen erfolgreich aktualisiert",
"updateFailed": "Fehler beim Aktualisieren der Werkzeugeinstellungen" "updateFailed": "Fehler beim Aktualisieren der Werkzeugeinstellungen",
} "testing": "Test läuft...",
"testSearch": "Websuche testen"
},
"settingsDescription": "Anwendungseinstellungen konfigurieren"
}, },
"ai": { "ai": {
"analyzing": "KI analysiert...", "analyzing": "KI analysiert...",
@@ -368,7 +381,9 @@
"signIn": "Anmelden", "signIn": "Anmelden",
"signInToAccount": "Melden Sie sich in Ihrem Konto an", "signInToAccount": "Melden Sie sich in Ihrem Konto an",
"signOut": "Sign out", "signOut": "Sign out",
"signUp": "Registrieren" "signUp": "Registrieren",
"confirmPassword": "Passwort bestätigen",
"confirmPasswordPlaceholder": "Passwort erneut eingeben"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "Notizen werden analysiert...", "analyzing": "Notizen werden analysiert...",

View File

@@ -26,7 +26,9 @@
"sending": "Sending...", "sending": "Sending...",
"sendResetLink": "Send Reset Link", "sendResetLink": "Send Reset Link",
"backToLogin": "Back to login", "backToLogin": "Back to login",
"signOut": "Sign out" "signOut": "Sign out",
"confirmPassword": "Confirm Password",
"confirmPasswordPlaceholder": "Confirm your password"
}, },
"sidebar": { "sidebar": {
"notes": "Notes", "notes": "Notes",
@@ -721,7 +723,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"bestValue": "Best value", "bestValue": "Best value",
"bestQuality": "Best quality", "bestQuality": "Best quality",
"saved": "(Saved)" "saved": "(Saved)",
"fetchModelsFailed": "Failed to fetch models",
"refreshModels": "Refresh Models",
"configured": "Configured",
"fetchingModels": "Fetching models...",
"clickToLoadModels": "Click ↺ to load models",
"searchModel": "Search model...",
"noModels": "No models. Click ↺",
"modelsAvailable": "{count} model(s) available",
"enterUrlToLoad": "Enter URL and click ↺ to load models",
"currentProvider": "(Current: {provider})"
}, },
"resend": { "resend": {
"title": "Resend (Recommended)", "title": "Resend (Recommended)",
@@ -859,8 +871,11 @@
"jinaKeyDescription": "Used for web scraping. Works without a key but with rate limits.", "jinaKeyDescription": "Used for web scraping. Works without a key but with rate limits.",
"saveSettings": "Save Tools Settings", "saveSettings": "Save Tools Settings",
"updateSuccess": "Tools settings updated successfully", "updateSuccess": "Tools settings updated successfully",
"updateFailed": "Failed to update tools settings" "updateFailed": "Failed to update tools settings",
} "testing": "Testing...",
"testSearch": "Test web search"
},
"settingsDescription": "Configure application-wide settings"
}, },
"about": { "about": {
"title": "About", "title": "About",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(Guardado)", "saved": "(Guardado)",
"chatProvider": "Proveedor de chat", "chatProvider": "Proveedor de chat",
"chatDescription": "Proveedor de IA para el asistente de chat. Usa el proveedor de etiquetas si no está configurado." "chatDescription": "Proveedor de IA para el asistente de chat. Usa el proveedor de etiquetas si no está configurado.",
"fetchModelsFailed": "Error al obtener modelos",
"refreshModels": "Actualizar modelos",
"configured": "Configurado",
"fetchingModels": "Obteniendo modelos...",
"clickToLoadModels": "Haga clic en ↺ para cargar modelos",
"searchModel": "Buscar modelo...",
"noModels": "Sin modelos. Haga clic en ↺",
"modelsAvailable": "{count} modelo(s) disponible(s)",
"enterUrlToLoad": "Ingrese la URL y haga clic en ↺",
"currentProvider": "(Actual: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Prueba tus proveedores de IA para generación de etiquetas y embeddings de búsqueda semántica", "description": "Prueba tus proveedores de IA para generación de etiquetas y embeddings de búsqueda semántica",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Usada para scraping web. Funciona sin clave pero con límites de tasa.", "jinaKeyDescription": "Usada para scraping web. Funciona sin clave pero con límites de tasa.",
"saveSettings": "Guardar Configuración de Herramientas", "saveSettings": "Guardar Configuración de Herramientas",
"updateSuccess": "Configuración de herramientas actualizada exitosamente", "updateSuccess": "Configuración de herramientas actualizada exitosamente",
"updateFailed": "Error al actualizar la configuración de herramientas" "updateFailed": "Error al actualizar la configuración de herramientas",
} "testing": "Probando...",
"testSearch": "Probar búsqueda web"
},
"settingsDescription": "Configurar ajustes de la aplicación"
}, },
"ai": { "ai": {
"analyzing": "IA analizando...", "analyzing": "IA analizando...",
@@ -368,7 +381,9 @@
"signIn": "Iniciar sesión", "signIn": "Iniciar sesión",
"signInToAccount": "Inicia sesión en tu cuenta", "signInToAccount": "Inicia sesión en tu cuenta",
"signOut": "Sign out", "signOut": "Sign out",
"signUp": "Registrarse" "signUp": "Registrarse",
"confirmPassword": "Confirmar contraseña",
"confirmPasswordPlaceholder": "Confirme su contraseña"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "Analizando tus notas...", "analyzing": "Analizando tus notas...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 سفارشی سازگار با OpenAI", "providerCustomOption": "🔧 سفارشی سازگار با OpenAI",
"saved": "(ذخیره شد)", "saved": "(ذخیره شد)",
"chatProvider": "ارائه‌دهنده چت", "chatProvider": "ارائه‌دهنده چت",
"chatDescription": "ارائه‌دهنده هوش مصنوعی برای دستیار چت. در صورت عدم پیکربندی، به ارائه‌دهنده برچسب‌ها بازمی‌گردد." "chatDescription": "ارائه‌دهنده هوش مصنوعی برای دستیار چت. در صورت عدم پیکربندی، به ارائه‌دهنده برچسب‌ها بازمی‌گردد.",
"fetchModelsFailed": "دریافت مدل‌ها ناموفق بود",
"refreshModels": "بازنشانی مدل‌ها",
"configured": "پیکربندی شده",
"fetchingModels": "در حال دریافت مدل‌ها...",
"clickToLoadModels": "برای بارگذاری مدل‌ها روی ↺ کلیک کنید",
"searchModel": "جستجوی مدل...",
"noModels": "مدلی وجود ندارد. روی ↺ کلیک کنید",
"modelsAvailable": "{count} مدل در دسترس",
"enterUrlToLoad": "آدرس را وارد کرده و روی ↺ کلیک کنید",
"currentProvider": "(فعلی: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "تست ارائه‌دهندگان هوش مصنوعی برای تولید برچسب و تعبیه‌های جستجوی معنایی", "description": "تست ارائه‌دهندگان هوش مصنوعی برای تولید برچسب و تعبیه‌های جستجوی معنایی",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "برای استخراج وب استفاده می‌شود. بدون کلید کار می‌کند اما با محدودیت نرخ.", "jinaKeyDescription": "برای استخراج وب استفاده می‌شود. بدون کلید کار می‌کند اما با محدودیت نرخ.",
"saveSettings": "ذخیره تنظیمات ابزارها", "saveSettings": "ذخیره تنظیمات ابزارها",
"updateSuccess": "تنظیمات ابزارها با موفقیت به‌روزرسانی شد", "updateSuccess": "تنظیمات ابزارها با موفقیت به‌روزرسانی شد",
"updateFailed": "شکست در به‌روزرسانی تنظیمات ابزارها" "updateFailed": "شکست در به‌روزرسانی تنظیمات ابزارها",
} "testing": "در حال تست...",
"testSearch": "تست جستجوی وب"
},
"settingsDescription": "پیکربندی تنظیمات کلی برنامه"
}, },
"ai": { "ai": {
"analyzing": "در حال تحلیل هوش مصنوعی...", "analyzing": "در حال تحلیل هوش مصنوعی...",
@@ -368,7 +381,9 @@
"signIn": "ورود", "signIn": "ورود",
"signInToAccount": "به حساب کاربری خود وارد شوید", "signInToAccount": "به حساب کاربری خود وارد شوید",
"signOut": "خروج از حساب", "signOut": "خروج از حساب",
"signUp": "ثبت‌نام" "signUp": "ثبت‌نام",
"confirmPassword": "تکرار رمز عبور",
"confirmPasswordPlaceholder": "رمز عبور را دوباره وارد کنید"
}, },
"autoLabels": { "autoLabels": {
"aiPowered": "قدرت گرفته از هوش مصنوعی", "aiPowered": "قدرت گرفته از هوش مصنوعی",

View File

@@ -71,7 +71,17 @@
"tagsGenerationProvider": "Fournisseur de génération d'étiquettes", "tagsGenerationProvider": "Fournisseur de génération d'étiquettes",
"title": "Configuration IA", "title": "Configuration IA",
"updateFailed": "Échec de la mise à jour des paramètres IA", "updateFailed": "Échec de la mise à jour des paramètres IA",
"updateSuccess": "Paramètres IA mis à jour avec succès" "updateSuccess": "Paramètres IA mis à jour avec succès",
"fetchModelsFailed": "Failed to fetch models",
"refreshModels": "Refresh Models",
"configured": "Configured",
"fetchingModels": "Fetching models...",
"clickToLoadModels": "Click ↺ to load models",
"searchModel": "Search model...",
"noModels": "No models. Click ↺",
"modelsAvailable": "{count} model(s) available",
"enterUrlToLoad": "Enter URL and click ↺ to load models",
"currentProvider": "(Current: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Testez vos fournisseurs IA pour la génération d'étiquettes et les embeddings de recherche sémantique", "description": "Testez vos fournisseurs IA pour la génération d'étiquettes et les embeddings de recherche sémantique",
@@ -138,7 +148,9 @@
"jinaKeyDescription": "Utilisée pour le scraping web. Fonctionne sans clé mais avec des limites de débit.", "jinaKeyDescription": "Utilisée pour le scraping web. Fonctionne sans clé mais avec des limites de débit.",
"saveSettings": "Enregistrer les paramètres outils", "saveSettings": "Enregistrer les paramètres outils",
"updateSuccess": "Paramètres outils mis à jour avec succès", "updateSuccess": "Paramètres outils mis à jour avec succès",
"updateFailed": "Échec de la mise à jour des paramètres outils" "updateFailed": "Échec de la mise à jour des paramètres outils",
"testing": "Testing...",
"testSearch": "Test web search"
}, },
"security": { "security": {
"allowPublicRegistration": "Autoriser l'inscription publique", "allowPublicRegistration": "Autoriser l'inscription publique",
@@ -221,7 +233,8 @@
"name": "Nom", "name": "Nom",
"role": "Rôle" "role": "Rôle"
} }
} },
"settingsDescription": "Configure application-wide settings"
}, },
"ai": { "ai": {
"analyzing": "Analyse IA en cours...", "analyzing": "Analyse IA en cours...",
@@ -371,7 +384,9 @@
"signIn": "Connexion", "signIn": "Connexion",
"signInToAccount": "Connectez-vous à votre compte", "signInToAccount": "Connectez-vous à votre compte",
"signOut": "Déconnexion", "signOut": "Déconnexion",
"signUp": "S'inscrire" "signUp": "S'inscrire",
"confirmPassword": "Confirm Password",
"confirmPasswordPlaceholder": "Confirm your password"
}, },
"batch": { "batch": {
"organize": "Organiser", "organize": "Organiser",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(सहेजा गया)", "saved": "(सहेजा गया)",
"chatProvider": "चैट प्रदाता", "chatProvider": "चैट प्रदाता",
"chatDescription": "चैट सहायक के लिए AI प्रदाता। कॉन्फ़िगर नहीं होने पर टैग प्रदाता का उपयोग करता है।" "chatDescription": "चैट सहायक के लिए AI प्रदाता। कॉन्फ़िगर नहीं होने पर टैग प्रदाता का उपयोग करता है।",
"fetchModelsFailed": "मॉडल लाने में विफल",
"refreshModels": "मॉडल रीफ़्रेश करें",
"configured": "कॉन्फ़िगर किया गया",
"fetchingModels": "मॉडल ला रहे हैं...",
"clickToLoadModels": "मॉडल लोड करने के लिए ↺ पर क्लिक करें",
"searchModel": "मॉडल खोजें...",
"noModels": "कोई मॉडल नहीं। ↺ पर क्लिक करें",
"modelsAvailable": "{count} मॉडल उपलब्ध",
"enterUrlToLoad": "URL दर्ज करें और ↺ पर क्लिक करें",
"currentProvider": "(वर्तमान: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "टैग जनरेशन और सिमेंटिक खोज एम्बेडिंग्स के लिए अपने AI प्रदाताओं का परीक्षण करें", "description": "टैग जनरेशन और सिमेंटिक खोज एम्बेडिंग्स के लिए अपने AI प्रदाताओं का परीक्षण करें",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "वेब स्क्रैपिंग के लिए उपयोग किया जाता है। बिना कुंजी के काम करता है लेकिन दर सीमा के साथ।", "jinaKeyDescription": "वेब स्क्रैपिंग के लिए उपयोग किया जाता है। बिना कुंजी के काम करता है लेकिन दर सीमा के साथ।",
"saveSettings": "टूल सेटिंग्स सहेजें", "saveSettings": "टूल सेटिंग्स सहेजें",
"updateSuccess": "टूल सेटिंग्स सफलतापूर्वक अपडेट की गईं", "updateSuccess": "टूल सेटिंग्स सफलतापूर्वक अपडेट की गईं",
"updateFailed": "टूल सेटिंग्स अपडेट करने में विफल" "updateFailed": "टूल सेटिंग्स अपडेट करने में विफल",
} "testing": "परीक्षण हो रहा है...",
"testSearch": "वेब खोज परीक्षण"
},
"settingsDescription": "एप्लिकेशन-वाइड सेटिंग्स कॉन्फ़िगर करें"
}, },
"ai": { "ai": {
"analyzing": "AI विश्लेषण जारी है...", "analyzing": "AI विश्लेषण जारी है...",
@@ -368,7 +381,9 @@
"signIn": "साइन इन करें", "signIn": "साइन इन करें",
"signInToAccount": "अपने खाते में साइन इन करें", "signInToAccount": "अपने खाते में साइन इन करें",
"signOut": "Sign out", "signOut": "Sign out",
"signUp": "साइन अप करें" "signUp": "साइन अप करें",
"confirmPassword": "पासवर्ड की पुष्टि करें",
"confirmPasswordPlaceholder": "अपना पासवर्ड दोबारा दर्ज करें"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "नोट्स का विश्लेषण जारी है...", "analyzing": "नोट्स का विश्लेषण जारी है...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(Salvato)", "saved": "(Salvato)",
"chatProvider": "Provider chat", "chatProvider": "Provider chat",
"chatDescription": "Provider IA per l'assistente chat. Usa il provider tag se non configurato." "chatDescription": "Provider IA per l'assistente chat. Usa il provider tag se non configurato.",
"fetchModelsFailed": "Impossibile recuperare i modelli",
"refreshModels": "Aggiorna modelli",
"configured": "Configurato",
"fetchingModels": "Recupero modelli...",
"clickToLoadModels": "Clicca ↺ per caricare i modelli",
"searchModel": "Cerca modello...",
"noModels": "Nessun modello. Clicca ↺",
"modelsAvailable": "{count} modello/i disponibile/i",
"enterUrlToLoad": "Inserisci URL e clicca ↺ per caricare",
"currentProvider": "(Attuale: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Test your AI providers for tag generation and semantic search embeddings", "description": "Test your AI providers for tag generation and semantic search embeddings",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Utilizzato per lo scraping web. Funziona senza chiave ma con limiti di velocità.", "jinaKeyDescription": "Utilizzato per lo scraping web. Funziona senza chiave ma con limiti di velocità.",
"saveSettings": "Salva Impostazioni Strumenti", "saveSettings": "Salva Impostazioni Strumenti",
"updateSuccess": "Impostazioni strumenti aggiornate con successo", "updateSuccess": "Impostazioni strumenti aggiornate con successo",
"updateFailed": "Impossibile aggiornare le impostazioni strumenti" "updateFailed": "Impossibile aggiornare le impostazioni strumenti",
} "testing": "Test in corso...",
"testSearch": "Test ricerca web"
},
"settingsDescription": "Configura le impostazioni dell applicazione"
}, },
"ai": { "ai": {
"analyzing": "AI analyzing...", "analyzing": "AI analyzing...",
@@ -368,7 +381,9 @@
"signIn": "Accedi", "signIn": "Accedi",
"signInToAccount": "Accedi al tuo account", "signInToAccount": "Accedi al tuo account",
"signOut": "Sign out", "signOut": "Sign out",
"signUp": "Registrati" "signUp": "Registrati",
"confirmPassword": "Conferma password",
"confirmPasswordPlaceholder": "Conferma la tua password"
}, },
"autoLabels": { "autoLabels": {
"aiPowered": "Alimentato da AI", "aiPowered": "Alimentato da AI",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(保存済み)", "saved": "(保存済み)",
"chatProvider": "チャットプロバイダー", "chatProvider": "チャットプロバイダー",
"chatDescription": "チャットアシスタント用のAIプロバイダー。未設定の場合はタグプロバイダーにフォールバックします。" "chatDescription": "チャットアシスタント用のAIプロバイダー。未設定の場合はタグプロバイダーにフォールバックします。",
"fetchModelsFailed": "モデルの取得に失敗しました",
"refreshModels": "モデルを更新",
"configured": "設定済み",
"fetchingModels": "モデルを取得中...",
"clickToLoadModels": "↺ をクリックしてモデルを読み込む",
"searchModel": "モデルを検索...",
"noModels": "モデルなし。↺ をクリック",
"modelsAvailable": "{count} 件のモデルが利用可能",
"enterUrlToLoad": "URLを入力して↺をクリック",
"currentProvider": "(現在: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "タグ生成とセマンティック検索埋め込みのAIプロバイダーをテストします", "description": "タグ生成とセマンティック検索埋め込みのAIプロバイダーをテストします",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "ウェブスクレイピングに使用されます。キーなしでも動作しますが、レート制限があります。", "jinaKeyDescription": "ウェブスクレイピングに使用されます。キーなしでも動作しますが、レート制限があります。",
"saveSettings": "ツール設定を保存", "saveSettings": "ツール設定を保存",
"updateSuccess": "ツール設定が正常に更新されました", "updateSuccess": "ツール設定が正常に更新されました",
"updateFailed": "ツール設定の更新に失敗しました" "updateFailed": "ツール設定の更新に失敗しました",
} "testing": "テスト中...",
"testSearch": "ウェブ検索をテスト"
},
"settingsDescription": "アプリケーション設定を構成"
}, },
"ai": { "ai": {
"analyzing": "AI分析中...", "analyzing": "AI分析中...",
@@ -368,7 +381,9 @@
"signIn": "ログイン", "signIn": "ログイン",
"signInToAccount": "アカウントにログイン", "signInToAccount": "アカウントにログイン",
"signOut": "ログアウト", "signOut": "ログアウト",
"signUp": "新規登録" "signUp": "新規登録",
"confirmPassword": "パスワードの確認",
"confirmPasswordPlaceholder": "パスワードを再入力"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "ノートを分析中...", "analyzing": "ノートを分析中...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 사용자 정의 OpenAI 호환", "providerCustomOption": "🔧 사용자 정의 OpenAI 호환",
"saved": "(저장됨)", "saved": "(저장됨)",
"chatProvider": "채팅 공급자", "chatProvider": "채팅 공급자",
"chatDescription": "채팅 도우미를 위한 AI 공급자입니다. 구성되지 않은 경우 태그 공급자를 대신 사용합니다." "chatDescription": "채팅 도우미를 위한 AI 공급자입니다. 구성되지 않은 경우 태그 공급자를 대신 사용합니다.",
"fetchModelsFailed": "모델을 가져오지 못했습니다",
"refreshModels": "모델 새로고침",
"configured": "구성됨",
"fetchingModels": "모델 가져오는 중...",
"clickToLoadModels": "↺ 클릭하여 모델 로드",
"searchModel": "모델 검색...",
"noModels": "모델 없음. ↺ 클릭",
"modelsAvailable": "{count}개 모델 사용 가능",
"enterUrlToLoad": "URL 입력 후 ↺ 클릭",
"currentProvider": "(현재: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "태그 생성 및 의미 검색 임베딩을 위한 AI 공급자 테스트", "description": "태그 생성 및 의미 검색 임베딩을 위한 AI 공급자 테스트",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "웹 스크랩에 사용됩니다. 키 없이도 작동하지만 속도 제한이 적용됩니다.", "jinaKeyDescription": "웹 스크랩에 사용됩니다. 키 없이도 작동하지만 속도 제한이 적용됩니다.",
"saveSettings": "도구 설정 저장", "saveSettings": "도구 설정 저장",
"updateSuccess": "도구 설정이 성공적으로 업데이트되었습니다", "updateSuccess": "도구 설정이 성공적으로 업데이트되었습니다",
"updateFailed": "도구 설정 업데이트 실패" "updateFailed": "도구 설정 업데이트 실패",
} "testing": "테스트 중...",
"testSearch": "웹 검색 테스트"
},
"settingsDescription": "애플리케이션 설정 구성"
}, },
"ai": { "ai": {
"analyzing": "AI 분석 중...", "analyzing": "AI 분석 중...",
@@ -368,7 +381,9 @@
"signIn": "로그인", "signIn": "로그인",
"signInToAccount": "계정에 로그인하세요", "signInToAccount": "계정에 로그인하세요",
"signOut": "로그아웃", "signOut": "로그아웃",
"signUp": "회원가입" "signUp": "회원가입",
"confirmPassword": "비밀번호 확인",
"confirmPasswordPlaceholder": "비밀번호를 다시 입력하세요"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "메모 분석 중...", "analyzing": "메모 분석 중...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(Opgeslagen)", "saved": "(Opgeslagen)",
"chatProvider": "Chat Provider", "chatProvider": "Chat Provider",
"chatDescription": "AI-provider voor de chat-assistent. Val terug op Tags-provider indien niet geconfigureerd." "chatDescription": "AI-provider voor de chat-assistent. Val terug op Tags-provider indien niet geconfigureerd.",
"fetchModelsFailed": "Modellen ophalen mislukt",
"refreshModels": "Modellen vernieuwen",
"configured": "Geconfigureerd",
"fetchingModels": "Modellen ophalen...",
"clickToLoadModels": "Klik op ↺ om modellen te laden",
"searchModel": "Model zoeken...",
"noModels": "Geen modellen. Klik op ↺",
"modelsAvailable": "{count} model(len) beschikbaar",
"enterUrlToLoad": "Voer URL in en klik op ↺",
"currentProvider": "(Huidig: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Test uw AI-providers voor taggeneratie en semantische zoek-embeddings", "description": "Test uw AI-providers voor taggeneratie en semantische zoek-embeddings",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Gebruikt voor web schrapen. Werkt zonder sleutel maar met snelheidslimieten.", "jinaKeyDescription": "Gebruikt voor web schrapen. Werkt zonder sleutel maar met snelheidslimieten.",
"saveSettings": "Tools-instellingen Opslaan", "saveSettings": "Tools-instellingen Opslaan",
"updateSuccess": "Tools-instellingen succesvol bijgewerkt", "updateSuccess": "Tools-instellingen succesvol bijgewerkt",
"updateFailed": "Tools-instellingen bijwerken mislukt" "updateFailed": "Tools-instellingen bijwerken mislukt",
} "testing": "Testen...",
"testSearch": "Zoekfunctie testen"
},
"settingsDescription": "Toepassingsinstellingen configureren"
}, },
"ai": { "ai": {
"analyzing": "AI analyseert...", "analyzing": "AI analyseert...",
@@ -368,7 +381,9 @@
"signIn": "Inloggen", "signIn": "Inloggen",
"signInToAccount": "Log in op uw account", "signInToAccount": "Log in op uw account",
"signOut": "Uitloggen", "signOut": "Uitloggen",
"signUp": "Registreren" "signUp": "Registreren",
"confirmPassword": "Wachtwoord bevestigen",
"confirmPasswordPlaceholder": "Bevestig uw wachtwoord"
}, },
"autoLabels": { "autoLabels": {
"aiPowered": "AI-gestuurd", "aiPowered": "AI-gestuurd",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Niestandardowy (kompatybilny z OpenAI)", "providerCustomOption": "🔧 Niestandardowy (kompatybilny z OpenAI)",
"saved": "(Zapisano)", "saved": "(Zapisano)",
"chatProvider": "Dostawca czatu", "chatProvider": "Dostawca czatu",
"chatDescription": "Dostawca AI dla asystenta czatu. Przechodzi do dostawcy tagów, jeśli nie jest skonfigurowany." "chatDescription": "Dostawca AI dla asystenta czatu. Przechodzi do dostawcy tagów, jeśli nie jest skonfigurowany.",
"fetchModelsFailed": "Nie udało się pobrać modeli",
"refreshModels": "Odśwież modele",
"configured": "Skonfigurowany",
"fetchingModels": "Pobieranie modeli...",
"clickToLoadModels": "Kliknij ↺ aby załadować modele",
"searchModel": "Szukaj modelu...",
"noModels": "Brak modeli. Kliknij ↺",
"modelsAvailable": "{count} model(i) dostępny(e)",
"enterUrlToLoad": "Podaj URL i kliknij ↺",
"currentProvider": "(Bieżący: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Przetestuj swoich dostawców AI pod kątem generowania tagów i embeddingów wyszukiwania semantycznego", "description": "Przetestuj swoich dostawców AI pod kątem generowania tagów i embeddingów wyszukiwania semantycznego",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Używany do pobierania stron. Działa bez klucza, ale z limitami zapytań.", "jinaKeyDescription": "Używany do pobierania stron. Działa bez klucza, ale z limitami zapytań.",
"saveSettings": "Zapisz Ustawienia Narzędzi", "saveSettings": "Zapisz Ustawienia Narzędzi",
"updateSuccess": "Ustawienia narzędzi zaktualizowane pomyślnie", "updateSuccess": "Ustawienia narzędzi zaktualizowane pomyślnie",
"updateFailed": "Nie udało się zaktualizować ustawień narzędzi" "updateFailed": "Nie udało się zaktualizować ustawień narzędzi",
} "testing": "Testowanie...",
"testSearch": "Testuj wyszukiwanie"
},
"settingsDescription": "Konfiguruj ustawienia aplikacji"
}, },
"ai": { "ai": {
"analyzing": "Analiza AI...", "analyzing": "Analiza AI...",
@@ -368,7 +381,9 @@
"signIn": "Zaloguj się", "signIn": "Zaloguj się",
"signInToAccount": "Zaloguj się na swoje konto", "signInToAccount": "Zaloguj się na swoje konto",
"signOut": "Wyloguj się", "signOut": "Wyloguj się",
"signUp": "Zarejestruj się" "signUp": "Zarejestruj się",
"confirmPassword": "Potwierdź hasło",
"confirmPasswordPlaceholder": "Potwierdź swoje hasło"
}, },
"autoLabels": { "autoLabels": {
"aiPowered": "Wspierane przez AI", "aiPowered": "Wspierane przez AI",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Compatível com OpenAI (Personalizado)", "providerCustomOption": "🔧 Compatível com OpenAI (Personalizado)",
"saved": "(Salvo)", "saved": "(Salvo)",
"chatProvider": "Provedor de Chat", "chatProvider": "Provedor de Chat",
"chatDescription": "Provedor de IA para o assistente de chat. Usa o provedor de Etiquetas como alternativa se não configurado." "chatDescription": "Provedor de IA para o assistente de chat. Usa o provedor de Etiquetas como alternativa se não configurado.",
"fetchModelsFailed": "Falha ao buscar modelos",
"refreshModels": "Atualizar modelos",
"configured": "Configurado",
"fetchingModels": "Buscando modelos...",
"clickToLoadModels": "Clique em ↺ para carregar modelos",
"searchModel": "Buscar modelo...",
"noModels": "Sem modelos. Clique em ↺",
"modelsAvailable": "{count} modelo(s) disponível(is)",
"enterUrlToLoad": "Insira a URL e clique em ↺",
"currentProvider": "(Atual: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Teste seus provedores de IA para geração de etiquetas e embeddings de pesquisa semântica", "description": "Teste seus provedores de IA para geração de etiquetas e embeddings de pesquisa semântica",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Usado para extração web. Funciona sem chave, mas com limites de taxa.", "jinaKeyDescription": "Usado para extração web. Funciona sem chave, mas com limites de taxa.",
"saveSettings": "Salvar Configurações de Ferramentas", "saveSettings": "Salvar Configurações de Ferramentas",
"updateSuccess": "Configurações de ferramentas atualizadas com sucesso", "updateSuccess": "Configurações de ferramentas atualizadas com sucesso",
"updateFailed": "Falha ao atualizar configurações de ferramentas" "updateFailed": "Falha ao atualizar configurações de ferramentas",
} "testing": "Testando...",
"testSearch": "Testar pesquisa web"
},
"settingsDescription": "Configurar definições da aplicação"
}, },
"ai": { "ai": {
"analyzing": "IA analisando...", "analyzing": "IA analisando...",
@@ -368,7 +381,9 @@
"signIn": "Entrar", "signIn": "Entrar",
"signInToAccount": "Entre na sua conta", "signInToAccount": "Entre na sua conta",
"signOut": "Sair", "signOut": "Sair",
"signUp": "Cadastrar-se" "signUp": "Cadastrar-se",
"confirmPassword": "Confirmar senha",
"confirmPasswordPlaceholder": "Confirme sua senha"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "Analisando suas notas...", "analyzing": "Analisando suas notas...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Пользовательский (совместимый с OpenAI)", "providerCustomOption": "🔧 Пользовательский (совместимый с OpenAI)",
"saved": "(Сохранено)", "saved": "(Сохранено)",
"chatProvider": "Провайдер чата", "chatProvider": "Провайдер чата",
"chatDescription": "Провайдер ИИ для чат-ассистента. Если не настроен, используется провайдер тегов." "chatDescription": "Провайдер ИИ для чат-ассистента. Если не настроен, используется провайдер тегов.",
"fetchModelsFailed": "Не удалось получить модели",
"refreshModels": "Обновить модели",
"configured": "Настроен",
"fetchingModels": "Загрузка моделей...",
"clickToLoadModels": "Нажмите ↺ для загрузки моделей",
"searchModel": "Поиск модели...",
"noModels": "Нет моделей. Нажмите ↺",
"modelsAvailable": "{count} модел(ей) доступно",
"enterUrlToLoad": "Введите URL и нажмите ↺",
"currentProvider": "(Текущий: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "Протестируйте провайдеров ИИ для генерации тегов и эмбеддингов семантического поиска", "description": "Протестируйте провайдеров ИИ для генерации тегов и эмбеддингов семантического поиска",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "Используется для веб-скрейпинга. Работает без ключа, но с ограничениями скорости.", "jinaKeyDescription": "Используется для веб-скрейпинга. Работает без ключа, но с ограничениями скорости.",
"saveSettings": "Сохранить Настройки Инструментов", "saveSettings": "Сохранить Настройки Инструментов",
"updateSuccess": "Настройки инструментов успешно обновлены", "updateSuccess": "Настройки инструментов успешно обновлены",
"updateFailed": "Не удалось обновить настройки инструментов" "updateFailed": "Не удалось обновить настройки инструментов",
} "testing": "Тестирование...",
"testSearch": "Тестировать веб-поиск"
},
"settingsDescription": "Настройки приложения"
}, },
"ai": { "ai": {
"analyzing": "ИИ анализирует...", "analyzing": "ИИ анализирует...",
@@ -368,7 +381,9 @@
"signIn": "Войти", "signIn": "Войти",
"signInToAccount": "Войдите в свой аккаунт", "signInToAccount": "Войдите в свой аккаунт",
"signOut": "Выйти", "signOut": "Выйти",
"signUp": "Зарегистрироваться" "signUp": "Зарегистрироваться",
"confirmPassword": "Подтвердите пароль",
"confirmPasswordPlaceholder": "Подтвердите пароль"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "Анализ ваших заметок...", "analyzing": "Анализ ваших заметок...",

View File

@@ -71,7 +71,17 @@
"providerCustomOption": "🔧 Custom OpenAI-Compatible", "providerCustomOption": "🔧 Custom OpenAI-Compatible",
"saved": "(已保存)", "saved": "(已保存)",
"chatProvider": "聊天提供商", "chatProvider": "聊天提供商",
"chatDescription": "用于聊天助手的 AI 提供商。如果未配置,将回退到标签提供商。" "chatDescription": "用于聊天助手的 AI 提供商。如果未配置,将回退到标签提供商。",
"fetchModelsFailed": "获取模型失败",
"refreshModels": "刷新模型",
"configured": "已配置",
"fetchingModels": "正在获取模型...",
"clickToLoadModels": "点击 ↺ 加载模型",
"searchModel": "搜索模型...",
"noModels": "无模型。点击 ↺",
"modelsAvailable": "{count} 个模型可用",
"enterUrlToLoad": "输入URL并点击↺加载模型",
"currentProvider": "(当前: {provider})"
}, },
"aiTest": { "aiTest": {
"description": "测试您的 AI 提供商的标签生成和语义搜索嵌入", "description": "测试您的 AI 提供商的标签生成和语义搜索嵌入",
@@ -217,8 +227,11 @@
"jinaKeyDescription": "用于网页抓取。无密钥也可使用,但有速率限制。", "jinaKeyDescription": "用于网页抓取。无密钥也可使用,但有速率限制。",
"saveSettings": "保存工具设置", "saveSettings": "保存工具设置",
"updateSuccess": "工具设置更新成功", "updateSuccess": "工具设置更新成功",
"updateFailed": "更新工具设置失败" "updateFailed": "更新工具设置失败",
} "testing": "测试中...",
"testSearch": "测试网络搜索"
},
"settingsDescription": "配置应用程序设置"
}, },
"ai": { "ai": {
"analyzing": "AI 分析中...", "analyzing": "AI 分析中...",
@@ -368,7 +381,9 @@
"signIn": "登录", "signIn": "登录",
"signInToAccount": "登录您的账户", "signInToAccount": "登录您的账户",
"signOut": "退出登录", "signOut": "退出登录",
"signUp": "注册" "signUp": "注册",
"confirmPassword": "确认密码",
"confirmPasswordPlaceholder": "再次输入密码"
}, },
"autoLabels": { "autoLabels": {
"analyzing": "分析您的笔记...", "analyzing": "分析您的笔记...",