mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-16 21:30:39 -07:00
feat(i18n): localize history item and story item dropdown menus
Covers the "..." action menu on both the History table (Play, Export Audio, Export Package, Apply Effects, Regenerate, Delete) and on individual story chat items (Play from here, Remove from Story). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
992ad96a29
commit
ffa68dc356
@@ -673,7 +673,7 @@ export function HistoryTable() {
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 text-muted-foreground/50 hover:bg-muted-foreground/20 hover:text-muted-foreground"
|
||||
aria-label="Actions"
|
||||
aria-label={t('history.actions.menu')}
|
||||
disabled={isGenerating}
|
||||
>
|
||||
<MoreHorizontal className="h-2 w-2" />
|
||||
@@ -684,37 +684,36 @@ export function HistoryTable() {
|
||||
onClick={() => handlePlay(gen.id, gen.text, gen.profile_id)}
|
||||
>
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
Play
|
||||
{t('history.actions.play')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDownloadAudio(gen.id, gen.text)}
|
||||
disabled={exportGenerationAudio.isPending}
|
||||
>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Export Audio
|
||||
{t('history.actions.exportAudio')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleExportPackage(gen.id, gen.text)}
|
||||
disabled={exportGeneration.isPending}
|
||||
>
|
||||
<FileArchive className="mr-2 h-4 w-4" />
|
||||
Export Package
|
||||
{t('history.actions.exportPackage')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleApplyEffects(gen.id)}>
|
||||
<Wand2 className="mr-2 h-4 w-4" />
|
||||
Apply Effects
|
||||
{t('history.actions.applyEffects')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleRegenerate(gen.id)}>
|
||||
<RotateCcw className="mr-2 h-4 w-4" />
|
||||
Regenerate
|
||||
{t('history.actions.regenerate')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteClick(gen.id, gen.profile_name)}
|
||||
disabled={deleteGeneration.isPending}
|
||||
// className="text-destructive focus:text-destructive"
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
{t('common.delete')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { GripVertical, Mic, MoreHorizontal, Play, Trash2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -34,6 +35,7 @@ export function StoryChatItem({
|
||||
dragHandleProps,
|
||||
isDragging,
|
||||
}: StoryChatItemProps) {
|
||||
const { t } = useTranslation();
|
||||
const seek = useStoryStore((state) => state.seek);
|
||||
const serverUrl = useServerStore((state) => state.serverUrl);
|
||||
const [avatarError, setAvatarError] = useState(false);
|
||||
@@ -118,21 +120,26 @@ export function StoryChatItem({
|
||||
<div className="shrink-0">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" aria-label="Actions">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
aria-label={t('history.actions.menu')}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={handlePlay}>
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
Play from here
|
||||
{t('storyContent.itemActions.playFromHere')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={onRemove}
|
||||
className="text-destructive focus:text-destructive"
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Remove from Story
|
||||
{t('storyContent.itemActions.removeFromStory')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -104,6 +104,10 @@
|
||||
"title": "No items in this story",
|
||||
"hint": "Generate speech using the box below to add items"
|
||||
},
|
||||
"itemActions": {
|
||||
"playFromHere": "Play from here",
|
||||
"removeFromStory": "Remove from Story"
|
||||
},
|
||||
"toast": {
|
||||
"removeFailed": "Failed to remove item",
|
||||
"reorderFailed": "Failed to reorder items",
|
||||
@@ -112,6 +116,14 @@
|
||||
}
|
||||
},
|
||||
"history": {
|
||||
"actions": {
|
||||
"menu": "Actions",
|
||||
"play": "Play",
|
||||
"exportAudio": "Export Audio",
|
||||
"exportPackage": "Export Package",
|
||||
"applyEffects": "Apply Effects",
|
||||
"regenerate": "Regenerate"
|
||||
},
|
||||
"deleteDialog": {
|
||||
"title": "Delete Generation",
|
||||
"body": "Are you sure you want to delete this generation from \"{{name}}\"? This action cannot be undone.",
|
||||
|
||||
@@ -104,6 +104,10 @@
|
||||
"title": "此故事暂无项目",
|
||||
"hint": "使用下方输入框生成语音以添加项目"
|
||||
},
|
||||
"itemActions": {
|
||||
"playFromHere": "从此处播放",
|
||||
"removeFromStory": "从故事中移除"
|
||||
},
|
||||
"toast": {
|
||||
"removeFailed": "移除项目失败",
|
||||
"reorderFailed": "重新排序项目失败",
|
||||
@@ -112,6 +116,14 @@
|
||||
}
|
||||
},
|
||||
"history": {
|
||||
"actions": {
|
||||
"menu": "操作",
|
||||
"play": "播放",
|
||||
"exportAudio": "导出音频",
|
||||
"exportPackage": "导出包",
|
||||
"applyEffects": "应用效果",
|
||||
"regenerate": "重新生成"
|
||||
},
|
||||
"deleteDialog": {
|
||||
"title": "删除生成",
|
||||
"body": "确定要删除来自 \"{{name}}\" 的这次生成吗?此操作不可撤销。",
|
||||
|
||||
Reference in New Issue
Block a user