diff --git a/app/src/components/StoriesTab/StoryContent.tsx b/app/src/components/StoriesTab/StoryContent.tsx index 0f53c2c9..10099a09 100644 --- a/app/src/components/StoriesTab/StoryContent.tsx +++ b/app/src/components/StoriesTab/StoryContent.tsx @@ -17,6 +17,7 @@ import { Link } from '@tanstack/react-router'; import { AnimatePresence, motion } from 'framer-motion'; import { Download, Plus } from 'lucide-react'; import { useEffect, useMemo, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import Loader from 'react-loaders'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -36,6 +37,7 @@ import { useStoryStore } from '@/stores/storyStore'; import { SortableStoryChatItem } from './StoryChatItem'; export function StoryContent() { + const { t } = useTranslation(); const selectedStoryId = useStoryStore((state) => state.selectedStoryId); const { data: story, isLoading } = useStory(selectedStoryId); const removeItem = useRemoveStoryItem(); @@ -147,7 +149,7 @@ export function StoryContent() { { onError: (error) => { toast({ - title: 'Failed to remove item', + title: t('storyContent.toast.removeFailed'), description: error.message, variant: 'destructive', }); @@ -179,7 +181,7 @@ export function StoryContent() { { onError: (error) => { toast({ - title: 'Failed to reorder items', + title: t('storyContent.toast.reorderFailed'), description: error.message, variant: 'destructive', }); @@ -199,7 +201,7 @@ export function StoryContent() { { onError: (error) => { toast({ - title: 'Failed to export audio', + title: t('storyContent.toast.exportFailed'), description: error.message, variant: 'destructive', }); @@ -223,7 +225,7 @@ export function StoryContent() { }, onError: (error) => { toast({ - title: 'Failed to add generation', + title: t('storyContent.toast.addFailed'), description: error.message, variant: 'destructive', }); @@ -236,8 +238,8 @@ export function StoryContent() { return (
-

Select a story

-

Choose a story from the list to view its content

+

{t('storyContent.selectStory.title')}

+

{t('storyContent.selectStory.hint')}

); @@ -246,7 +248,7 @@ export function StoryContent() { if (isLoading) { return (
-
Loading story...
+
{t('storyContent.loading')}
); } @@ -255,8 +257,8 @@ export function StoryContent() { return (
-

Story not found

-

The selected story could not be loaded

+

{t('storyContent.notFound.title')}

+

{t('storyContent.notFound.hint')}

); @@ -291,7 +293,7 @@ export function StoryContent() { - Generating {pendingCount} {pendingCount === 1 ? 'audio' : 'audios'} + {t('storyContent.generatingCount', { count: pendingCount })} @@ -301,13 +303,13 @@ export function StoryContent() {
setSearchQuery(e.target.value)} autoFocus @@ -316,7 +318,9 @@ export function StoryContent() {
{availableGenerations.length === 0 ? (
- {searchQuery ? 'No matching generations found' : 'No available generations'} + {searchQuery + ? t('storyContent.searchNoMatches') + : t('storyContent.searchNoAvailable')}
) : ( availableGenerations.map((gen) => ( @@ -344,7 +348,7 @@ export function StoryContent() { disabled={exportAudio.isPending} > - Export Audio + {t('storyContent.exportAudio')} )}
@@ -358,8 +362,8 @@ export function StoryContent() { > {sortedItems.length === 0 ? (
-

No items in this story

-

Generate speech using the box below to add items

+

{t('storyContent.empty.title')}

+

{t('storyContent.empty.hint')}

) : ( state.selectedStoryId); const setSelectedStoryId = useStoryStore((state) => state.setSelectedStoryId); @@ -72,8 +74,8 @@ export function StoryList() { const handleCreateStory = () => { if (!newStoryName.trim()) { toast({ - title: 'Name required', - description: 'Please enter a story name', + title: t('stories.toast.nameRequired'), + description: t('stories.toast.nameRequiredDescription'), variant: 'destructive', }); return; @@ -91,13 +93,13 @@ export function StoryList() { setNewStoryName(''); setNewStoryDescription(''); toast({ - title: 'Story created', - description: `"${story.name}" has been created`, + title: t('stories.toast.created'), + description: t('stories.toast.createdDescription', { name: story.name }), }); }, onError: (error) => { toast({ - title: 'Failed to create story', + title: t('stories.toast.createFailed'), description: error.message, variant: 'destructive', }); @@ -116,8 +118,8 @@ export function StoryList() { const handleUpdateStory = () => { if (!editingStory || !newStoryName.trim()) { toast({ - title: 'Name required', - description: 'Please enter a story name', + title: t('stories.toast.nameRequired'), + description: t('stories.toast.nameRequiredDescription'), variant: 'destructive', }); return; @@ -140,7 +142,7 @@ export function StoryList() { }, onError: (error) => { toast({ - title: 'Failed to update story', + title: t('stories.toast.updateFailed'), description: error.message, variant: 'destructive', }); @@ -168,7 +170,7 @@ export function StoryList() { }, onError: (error) => { toast({ - title: 'Failed to delete story', + title: t('stories.toast.deleteFailed'), description: error.message, variant: 'destructive', }); @@ -179,7 +181,7 @@ export function StoryList() { if (isLoading) { return (
-
Loading stories...
+
{t('stories.loading')}
); } @@ -195,10 +197,10 @@ export function StoryList() { {/* Fixed Header */}
-

Stories

+

{t('stories.title')}

@@ -211,8 +213,8 @@ export function StoryList() { {storyList.length === 0 ? (
-

No stories yet

-

Create your first story to get started

+

{t('stories.empty.title')}

+

{t('stories.empty.hint')}

) : (
@@ -225,7 +227,11 @@ export function StoryList() { 'px-5 py-3 rounded-lg transition-colors group flex items-center cursor-pointer', selectedStoryId === story.id ? 'bg-muted' : 'hover:bg-muted/50', )} - aria-label={`Story ${story.name}, ${story.item_count} ${story.item_count === 1 ? 'item' : 'items'}, ${formatDate(story.updated_at)}`} + aria-label={t('stories.row.ariaLabel', { + name: story.name, + count: story.item_count, + updated: formatDate(story.updated_at), + })} aria-pressed={selectedStoryId === story.id} onClick={() => setSelectedStoryId(story.id)} onKeyDown={(e) => { @@ -240,9 +246,7 @@ export function StoryList() {

{story.name}

- - {story.item_count} {story.item_count === 1 ? 'item' : 'items'} - + {t('stories.row.itemCount', { count: story.item_count })} · {formatDate(story.updated_at)}
@@ -254,7 +258,7 @@ export function StoryList() { size="icon" className="h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity" onClick={(e) => e.stopPropagation()} - aria-label={`Actions for ${story.name}`} + aria-label={t('stories.row.actionsLabel', { name: story.name })} > @@ -262,14 +266,14 @@ export function StoryList() { handleEditClick(story)}> - Edit + {t('common.edit')} handleDeleteClick(story.id)} className="text-destructive focus:text-destructive" > - Delete + {t('common.delete')} @@ -284,17 +288,15 @@ export function StoryList() { - Create New Story - - Create a new story to organize your voice generations into conversations. - + {t('stories.createDialog.title')} + {t('stories.createDialog.description')}
- + setNewStoryName(e.target.value)} onKeyDown={(e) => { @@ -305,10 +307,10 @@ export function StoryList() { />
- +