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:
James Pine
2026-04-20 03:04:25 -07:00
co-authored by Claude Opus 4.7
parent 992ad96a29
commit ffa68dc356
4 changed files with 41 additions and 11 deletions
+7 -8
View File
@@ -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>
+12
View File
@@ -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}}\" 的这次生成吗?此操作不可撤销。",