mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 07:05:14 -07:00
feat(i18n): localize ProfileList unsupported-model note and empty state
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
4f384ca64f
commit
976c6cbd8f
@@ -1,5 +1,6 @@
|
|||||||
import { Info, Mic, Sparkles } from 'lucide-react';
|
import { Info, Mic, Sparkles } from 'lucide-react';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { useProfiles } from '@/lib/hooks/useProfiles';
|
import { useProfiles } from '@/lib/hooks/useProfiles';
|
||||||
@@ -11,6 +12,7 @@ import { ProfileForm } from './ProfileForm';
|
|||||||
const PRESET_ENGINES = new Set(['kokoro', 'qwen_custom_voice']);
|
const PRESET_ENGINES = new Set(['kokoro', 'qwen_custom_voice']);
|
||||||
|
|
||||||
export function ProfileList() {
|
export function ProfileList() {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { data: profiles, isLoading, error } = useProfiles();
|
const { data: profiles, isLoading, error } = useProfiles();
|
||||||
const setDialogOpen = useUIStore((state) => state.setProfileDialogOpen);
|
const setDialogOpen = useUIStore((state) => state.setProfileDialogOpen);
|
||||||
const selectedEngine = useUIStore((state) => state.selectedEngine);
|
const selectedEngine = useUIStore((state) => state.selectedEngine);
|
||||||
@@ -45,7 +47,9 @@ export function ProfileList() {
|
|||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center p-8">
|
<div className="flex items-center justify-center p-8">
|
||||||
<div className="text-destructive">Error loading profiles: {error.message}</div>
|
<div className="text-destructive">
|
||||||
|
{t('profiles.list.errorLoading', { message: error.message })}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -73,12 +77,10 @@ export function ProfileList() {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardContent className="flex flex-col items-center justify-center py-12">
|
<CardContent className="flex flex-col items-center justify-center py-12">
|
||||||
<Mic className="h-12 w-12 text-muted-foreground mb-4" />
|
<Mic className="h-12 w-12 text-muted-foreground mb-4" />
|
||||||
<p className="text-muted-foreground mb-4">
|
<p className="text-muted-foreground mb-4">{t('profiles.list.empty')}</p>
|
||||||
No voice profiles yet. Create your first profile to get started.
|
|
||||||
</p>
|
|
||||||
<Button onClick={() => setDialogOpen(true)}>
|
<Button onClick={() => setDialogOpen(true)}>
|
||||||
<Sparkles className="mr-2 h-4 w-4" />
|
<Sparkles className="mr-2 h-4 w-4" />
|
||||||
Create Voice
|
{t('profiles.list.createVoice')}
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -99,7 +101,7 @@ export function ProfileList() {
|
|||||||
{hasUnsupported && (
|
{hasUnsupported && (
|
||||||
<div className="col-span-full flex items-center gap-2 text-xs text-muted-foreground py-2">
|
<div className="col-span-full flex items-center gap-2 text-xs text-muted-foreground py-2">
|
||||||
<Info className="h-3.5 w-3.5 shrink-0" />
|
<Info className="h-3.5 w-3.5 shrink-0" />
|
||||||
<span>Only supported voice profiles can be selected for the current model.</span>
|
<span>{t('profiles.list.unsupportedNote')}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -255,6 +255,12 @@
|
|||||||
"selectLabel": "{{name}}, {{language}}. Select as voice for generation.",
|
"selectLabel": "{{name}}, {{language}}. Select as voice for generation.",
|
||||||
"selectLabelSelected": "{{name}}, {{language}}. Selected as voice for generation."
|
"selectLabelSelected": "{{name}}, {{language}}. Selected as voice for generation."
|
||||||
},
|
},
|
||||||
|
"list": {
|
||||||
|
"errorLoading": "Error loading profiles: {{message}}",
|
||||||
|
"empty": "No voice profiles yet. Create your first profile to get started.",
|
||||||
|
"createVoice": "Create Voice",
|
||||||
|
"unsupportedNote": "Only supported voice profiles can be selected for the current model."
|
||||||
|
},
|
||||||
"deleteDialog": {
|
"deleteDialog": {
|
||||||
"title": "Delete Profile",
|
"title": "Delete Profile",
|
||||||
"body": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.",
|
"body": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.",
|
||||||
|
|||||||
@@ -255,6 +255,12 @@
|
|||||||
"selectLabel": "{{name}},{{language}}。选择用于生成的声音。",
|
"selectLabel": "{{name}},{{language}}。选择用于生成的声音。",
|
||||||
"selectLabelSelected": "{{name}},{{language}}。已选为用于生成的声音。"
|
"selectLabelSelected": "{{name}},{{language}}。已选为用于生成的声音。"
|
||||||
},
|
},
|
||||||
|
"list": {
|
||||||
|
"errorLoading": "加载声音档案时出错:{{message}}",
|
||||||
|
"empty": "还没有声音档案。创建您的第一个档案以开始使用。",
|
||||||
|
"createVoice": "创建声音",
|
||||||
|
"unsupportedNote": "当前模型仅可选择支持的声音档案。"
|
||||||
|
},
|
||||||
"deleteDialog": {
|
"deleteDialog": {
|
||||||
"title": "删除声音档案",
|
"title": "删除声音档案",
|
||||||
"body": "确定要删除 \"{{name}}\" 吗?此操作不可撤销。",
|
"body": "确定要删除 \"{{name}}\" 吗?此操作不可撤销。",
|
||||||
|
|||||||
Reference in New Issue
Block a user