feat: update localization strings for audiobook features and enhance UI interactions
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"analyzing": "Analyzing",
|
"analyzing": "Analyzing",
|
||||||
"characters_ready": "Awaiting Character Review",
|
"characters_ready": "Awaiting Character Review",
|
||||||
"parsing": "Parsing Chapters",
|
"parsing": "Extracting Dialogue",
|
||||||
"ready": "Ready",
|
"ready": "Ready",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"generating": "Generating",
|
"generating": "Generating",
|
||||||
@@ -97,19 +97,22 @@
|
|||||||
"chapters": {
|
"chapters": {
|
||||||
"title": "Chapters ({{count}} total)",
|
"title": "Chapters ({{count}} total)",
|
||||||
"processAll": "⚡ Process All",
|
"processAll": "⚡ Process All",
|
||||||
"parseAll": "Batch Parse",
|
"parseAll": "Batch Extract",
|
||||||
"generateAll": "Batch Generate",
|
"parseAllAI": "Batch Rewrite",
|
||||||
|
"generateAll": "Batch Synthesize",
|
||||||
"defaultTitle": "Chapter {{index}}",
|
"defaultTitle": "Chapter {{index}}",
|
||||||
"parse": "Parse Chapter",
|
"parse": "Extract Dialogue",
|
||||||
"parsing": "Parsing",
|
"parseAI": "Rewrite Chapter",
|
||||||
"parseStarted": "Parsing \"{{title}}\" started",
|
"parsing": "Extracting",
|
||||||
"parseStartedDefault": "Chapter parsing started",
|
"parseStarted": "Extracting \"{{title}}\" started",
|
||||||
"reparse": "Re-parse",
|
"parseStartedDefault": "Chapter extraction started",
|
||||||
"generate": "Generate Chapter",
|
"reparse": "Re-extract",
|
||||||
"generateStarted": "Chapter {{index}} generation started",
|
"reparseAI": "Rewrite",
|
||||||
"generateAllStarted": "Full book generation started",
|
"generate": "Synthesize",
|
||||||
|
"generateStarted": "Chapter {{index}} synthesis started",
|
||||||
|
"generateAllStarted": "Full book synthesis started",
|
||||||
"processAllStarted": "All tasks triggered",
|
"processAllStarted": "All tasks triggered",
|
||||||
"parseAllStarted": "Batch parsing started",
|
"parseAllStarted": "Batch extraction started",
|
||||||
"doneBadge": "{{count}} segments done",
|
"doneBadge": "{{count}} segments done",
|
||||||
"segmentProgress": "{{done}}/{{total}} segments"
|
"segmentProgress": "{{done}}/{{total}} segments"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"pending": "未分析",
|
"pending": "未分析",
|
||||||
"analyzing": "分析中",
|
"analyzing": "分析中",
|
||||||
"characters_ready": "キャラクター確認待ち",
|
"characters_ready": "キャラクター確認待ち",
|
||||||
"parsing": "章を解析中",
|
"parsing": "対話抽出中",
|
||||||
"ready": "生成待ち",
|
"ready": "生成待ち",
|
||||||
"processing": "処理中",
|
"processing": "処理中",
|
||||||
"generating": "生成中",
|
"generating": "生成中",
|
||||||
@@ -96,19 +96,22 @@
|
|||||||
"chapters": {
|
"chapters": {
|
||||||
"title": "章一覧(全 {{count}} 章)",
|
"title": "章一覧(全 {{count}} 章)",
|
||||||
"processAll": "⚡ すべて処理",
|
"processAll": "⚡ すべて処理",
|
||||||
"parseAll": "一括解析",
|
"parseAll": "一括抽出",
|
||||||
"generateAll": "一括生成",
|
"parseAllAI": "一括書き直し",
|
||||||
|
"generateAll": "一括合成",
|
||||||
"defaultTitle": "第 {{index}} 章",
|
"defaultTitle": "第 {{index}} 章",
|
||||||
"parse": "この章を解析",
|
"parse": "対話抽出",
|
||||||
"parsing": "解析中",
|
"parseAI": "章を書き直し",
|
||||||
"parseStarted": "「{{title}}」の解析を開始しました",
|
"parsing": "抽出中",
|
||||||
"parseStartedDefault": "章の解析を開始しました",
|
"parseStarted": "「{{title}}」の抽出を開始しました",
|
||||||
"reparse": "再解析",
|
"parseStartedDefault": "章の抽出を開始しました",
|
||||||
"generate": "この章を生成",
|
"reparse": "再抽出",
|
||||||
"generateStarted": "第 {{index}} 章の生成を開始しました",
|
"reparseAI": "書き直し",
|
||||||
"generateAllStarted": "全冊生成を開始しました",
|
"generate": "音声合成",
|
||||||
|
"generateStarted": "第 {{index}} 章の合成を開始しました",
|
||||||
|
"generateAllStarted": "全冊合成を開始しました",
|
||||||
"processAllStarted": "すべてのタスクを開始しました",
|
"processAllStarted": "すべてのタスクを開始しました",
|
||||||
"parseAllStarted": "一括解析を開始しました",
|
"parseAllStarted": "一括抽出を開始しました",
|
||||||
"doneBadge": "{{count}} セグメント完了",
|
"doneBadge": "{{count}} セグメント完了",
|
||||||
"segmentProgress": "{{done}}/{{total}} セグメント"
|
"segmentProgress": "{{done}}/{{total}} セグメント"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"pending": "분석 대기",
|
"pending": "분석 대기",
|
||||||
"analyzing": "분석 중",
|
"analyzing": "분석 중",
|
||||||
"characters_ready": "캐릭터 확인 대기",
|
"characters_ready": "캐릭터 확인 대기",
|
||||||
"parsing": "챕터 파싱 중",
|
"parsing": "대화 추출 중",
|
||||||
"ready": "생성 대기",
|
"ready": "생성 대기",
|
||||||
"processing": "처리 중",
|
"processing": "처리 중",
|
||||||
"generating": "생성 중",
|
"generating": "생성 중",
|
||||||
@@ -96,19 +96,22 @@
|
|||||||
"chapters": {
|
"chapters": {
|
||||||
"title": "챕터 목록 (총 {{count}}챕터)",
|
"title": "챕터 목록 (총 {{count}}챕터)",
|
||||||
"processAll": "⚡ 전체 처리",
|
"processAll": "⚡ 전체 처리",
|
||||||
"parseAll": "일괄 파싱",
|
"parseAll": "일괄 추출",
|
||||||
"generateAll": "일괄 생성",
|
"parseAllAI": "일괄 재작성",
|
||||||
|
"generateAll": "일괄 합성",
|
||||||
"defaultTitle": "제 {{index}} 장",
|
"defaultTitle": "제 {{index}} 장",
|
||||||
"parse": "이 챕터 파싱",
|
"parse": "대화 추출",
|
||||||
"parsing": "파싱 중",
|
"parseAI": "챕터 재작성",
|
||||||
"parseStarted": "「{{title}}」 파싱이 시작되었습니다",
|
"parsing": "추출 중",
|
||||||
"parseStartedDefault": "챕터 파싱이 시작되었습니다",
|
"parseStarted": "「{{title}}」 추출이 시작되었습니다",
|
||||||
"reparse": "재파싱",
|
"parseStartedDefault": "챕터 추출이 시작되었습니다",
|
||||||
"generate": "이 챕터 생성",
|
"reparse": "재추출",
|
||||||
"generateStarted": "제 {{index}} 장 생성이 시작되었습니다",
|
"reparseAI": "재작성",
|
||||||
"generateAllStarted": "전체 책 생성이 시작되었습니다",
|
"generate": "음성 합성",
|
||||||
|
"generateStarted": "제 {{index}} 장 합성이 시작되었습니다",
|
||||||
|
"generateAllStarted": "전체 책 합성이 시작되었습니다",
|
||||||
"processAllStarted": "모든 작업이 시작되었습니다",
|
"processAllStarted": "모든 작업이 시작되었습니다",
|
||||||
"parseAllStarted": "일괄 파싱이 시작되었습니다",
|
"parseAllStarted": "일괄 추출이 시작되었습니다",
|
||||||
"doneBadge": "{{count}}개 세그먼트 완료",
|
"doneBadge": "{{count}}개 세그먼트 완료",
|
||||||
"segmentProgress": "{{done}}/{{total}} 세그먼트"
|
"segmentProgress": "{{done}}/{{total}} 세그먼트"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"pending": "待分析",
|
"pending": "待分析",
|
||||||
"analyzing": "分析中",
|
"analyzing": "分析中",
|
||||||
"characters_ready": "角色待确认",
|
"characters_ready": "角色待确认",
|
||||||
"parsing": "解析章节",
|
"parsing": "提取对话",
|
||||||
"ready": "待生成",
|
"ready": "待生成",
|
||||||
"processing": "处理中",
|
"processing": "处理中",
|
||||||
"generating": "生成中",
|
"generating": "生成中",
|
||||||
@@ -100,19 +100,22 @@
|
|||||||
"chapters": {
|
"chapters": {
|
||||||
"title": "章节列表(共 {{count}} 章)",
|
"title": "章节列表(共 {{count}} 章)",
|
||||||
"processAll": "⚡ 全部处理",
|
"processAll": "⚡ 全部处理",
|
||||||
"parseAll": "批量解析",
|
"parseAll": "批量提取",
|
||||||
"generateAll": "批量生成",
|
"parseAllAI": "批量重写",
|
||||||
|
"generateAll": "批量合成",
|
||||||
"defaultTitle": "第 {{index}} 章",
|
"defaultTitle": "第 {{index}} 章",
|
||||||
"parse": "解析此章",
|
"parse": "提取对话",
|
||||||
"parsing": "解析中",
|
"parseAI": "重写章节",
|
||||||
"parseStarted": "「{{title}}」解析已开始",
|
"parsing": "提取中",
|
||||||
"parseStartedDefault": "章节解析已开始",
|
"parseStarted": "「{{title}}」提取已开始",
|
||||||
"reparse": "重新解析",
|
"parseStartedDefault": "章节提取已开始",
|
||||||
"generate": "生成此章",
|
"reparse": "重新提取",
|
||||||
"generateStarted": "第 {{index}} 章生成已开始",
|
"reparseAI": "重写",
|
||||||
"generateAllStarted": "全书生成已开始",
|
"generate": "合成音频",
|
||||||
|
"generateStarted": "第 {{index}} 章合成已开始",
|
||||||
|
"generateAllStarted": "全书合成已开始",
|
||||||
"processAllStarted": "全部任务已触发",
|
"processAllStarted": "全部任务已触发",
|
||||||
"parseAllStarted": "批量解析已开始",
|
"parseAllStarted": "批量提取已开始",
|
||||||
"doneBadge": "已完成 {{count}} 段",
|
"doneBadge": "已完成 {{count}} 段",
|
||||||
"segmentProgress": "{{done}}/{{total}} 段"
|
"segmentProgress": "{{done}}/{{total}} 段"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"pending": "待分析",
|
"pending": "待分析",
|
||||||
"analyzing": "分析中",
|
"analyzing": "分析中",
|
||||||
"characters_ready": "角色待確認",
|
"characters_ready": "角色待確認",
|
||||||
"parsing": "解析章節",
|
"parsing": "提取對話",
|
||||||
"ready": "待生成",
|
"ready": "待生成",
|
||||||
"processing": "處理中",
|
"processing": "處理中",
|
||||||
"generating": "生成中",
|
"generating": "生成中",
|
||||||
@@ -96,19 +96,22 @@
|
|||||||
"chapters": {
|
"chapters": {
|
||||||
"title": "章節列表(共 {{count}} 章)",
|
"title": "章節列表(共 {{count}} 章)",
|
||||||
"processAll": "⚡ 全部處理",
|
"processAll": "⚡ 全部處理",
|
||||||
"parseAll": "批量解析",
|
"parseAll": "批量提取",
|
||||||
"generateAll": "批量生成",
|
"parseAllAI": "批量重寫",
|
||||||
|
"generateAll": "批量合成",
|
||||||
"defaultTitle": "第 {{index}} 章",
|
"defaultTitle": "第 {{index}} 章",
|
||||||
"parse": "解析此章",
|
"parse": "提取對話",
|
||||||
"parsing": "解析中",
|
"parseAI": "重寫章節",
|
||||||
"parseStarted": "「{{title}}」解析已開始",
|
"parsing": "提取中",
|
||||||
"parseStartedDefault": "章節解析已開始",
|
"parseStarted": "「{{title}}」提取已開始",
|
||||||
"reparse": "重新解析",
|
"parseStartedDefault": "章節提取已開始",
|
||||||
"generate": "生成此章",
|
"reparse": "重新提取",
|
||||||
"generateStarted": "第 {{index}} 章生成已開始",
|
"reparseAI": "重寫",
|
||||||
"generateAllStarted": "全書生成已開始",
|
"generate": "合成音訊",
|
||||||
|
"generateStarted": "第 {{index}} 章合成已開始",
|
||||||
|
"generateAllStarted": "全書合成已開始",
|
||||||
"processAllStarted": "全部任務已觸發",
|
"processAllStarted": "全部任務已觸發",
|
||||||
"parseAllStarted": "批量解析已開始",
|
"parseAllStarted": "批量提取已開始",
|
||||||
"doneBadge": "已完成 {{count}} 段",
|
"doneBadge": "已完成 {{count}} 段",
|
||||||
"segmentProgress": "{{done}}/{{total}} 段"
|
"segmentProgress": "{{done}}/{{total}} 段"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect, useCallback, useRef } from 'react'
|
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
import { Book, Plus, Trash2, RefreshCw, Download, ChevronDown, ChevronUp, Play, Square, Pencil, Check, X, Loader2, Zap, Settings2, PanelLeftClose, PanelLeftOpen } from 'lucide-react'
|
import { Book, Plus, Trash2, RefreshCw, Download, ChevronDown, ChevronUp, Play, Square, Pencil, Check, X, Loader2, Zap, Settings2, PanelLeftClose, PanelLeftOpen, Wand2, Volume2, Bot } from 'lucide-react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Textarea } from '@/components/ui/textarea'
|
import { Textarea } from '@/components/ui/textarea'
|
||||||
@@ -1199,6 +1199,7 @@ function ChaptersPanel({
|
|||||||
}
|
}
|
||||||
}, [segments, detail])
|
}, [segments, detail])
|
||||||
|
|
||||||
|
const isAIMode = project.source_type === 'ai_generated'
|
||||||
const hasChapters = detail && detail.chapters.length > 0 && ['ready', 'generating', 'done'].includes(status)
|
const hasChapters = detail && detail.chapters.length > 0 && ['ready', 'generating', 'done'].includes(status)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1211,11 +1212,13 @@ function ChaptersPanel({
|
|||||||
<div className="flex items-center gap-1 flex-wrap">
|
<div className="flex items-center gap-1 flex-wrap">
|
||||||
{detail!.chapters.some(c => ['pending', 'error', 'ready'].includes(c.status)) && (
|
{detail!.chapters.some(c => ['pending', 'error', 'ready'].includes(c.status)) && (
|
||||||
<Button size="xs" variant="outline" disabled={loadingAction} onClick={onParseAll}>
|
<Button size="xs" variant="outline" disabled={loadingAction} onClick={onParseAll}>
|
||||||
{t('projectCard.chapters.parseAll')}
|
{isAIMode ? <Bot className="h-3 w-3 mr-1" /> : <Wand2 className="h-3 w-3 mr-1" />}
|
||||||
|
{t(isAIMode ? 'projectCard.chapters.parseAllAI' : 'projectCard.chapters.parseAll')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{detail!.chapters.some(c => c.status === 'ready') && (
|
{detail!.chapters.some(c => c.status === 'ready') && (
|
||||||
<Button size="xs" variant="outline" disabled={loadingAction} onClick={onGenerateAll}>
|
<Button size="xs" variant="outline" disabled={loadingAction} onClick={onGenerateAll}>
|
||||||
|
<Volume2 className="h-3 w-3 mr-1" />
|
||||||
{t('projectCard.chapters.generateAll')}
|
{t('projectCard.chapters.generateAll')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@@ -1260,7 +1263,8 @@ function ChaptersPanel({
|
|||||||
<span className="shrink-0 flex items-center gap-1.5" onClick={e => e.stopPropagation()}>
|
<span className="shrink-0 flex items-center gap-1.5" onClick={e => e.stopPropagation()}>
|
||||||
{ch.status === 'pending' && (
|
{ch.status === 'pending' && (
|
||||||
<Button size="xs" variant="outline" onClick={() => onParseChapter(ch.id, ch.title)}>
|
<Button size="xs" variant="outline" onClick={() => onParseChapter(ch.id, ch.title)}>
|
||||||
{t('projectCard.chapters.parse')}
|
{isAIMode ? <Bot className="h-3 w-3 mr-1" /> : <Wand2 className="h-3 w-3 mr-1" />}
|
||||||
|
{t(isAIMode ? 'projectCard.chapters.parseAI' : 'projectCard.chapters.parse')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{ch.status === 'parsing' && (
|
{ch.status === 'parsing' && (
|
||||||
@@ -1274,10 +1278,12 @@ function ChaptersPanel({
|
|||||||
setExpandedChapters(prev => { const n = new Set(prev); n.add(ch.id); return n })
|
setExpandedChapters(prev => { const n = new Set(prev); n.add(ch.id); return n })
|
||||||
onGenerate(ch.chapter_index)
|
onGenerate(ch.chapter_index)
|
||||||
}}>
|
}}>
|
||||||
|
<Volume2 className="h-3 w-3 mr-1" />
|
||||||
{t('projectCard.chapters.generate')}
|
{t('projectCard.chapters.generate')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="xs" variant="ghost" className="text-muted-foreground" disabled={loadingAction} onClick={() => onParseChapter(ch.id, ch.title)}>
|
<Button size="xs" variant="outline" disabled={loadingAction} onClick={() => onParseChapter(ch.id, ch.title)}>
|
||||||
{t('projectCard.chapters.reparse')}
|
{isAIMode ? <Bot className="h-3 w-3 mr-1" /> : <Wand2 className="h-3 w-3 mr-1" />}
|
||||||
|
{t(isAIMode ? 'projectCard.chapters.reparseAI' : 'projectCard.chapters.reparse')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -1289,11 +1295,11 @@ function ChaptersPanel({
|
|||||||
{(ch.status === 'done' || (ch.status === 'ready' && chAllDone)) && (
|
{(ch.status === 'done' || (ch.status === 'ready' && chAllDone)) && (
|
||||||
<>
|
<>
|
||||||
<span className="text-[11px] text-muted-foreground">{t('projectCard.chapters.doneBadge', { count: chDone })}</span>
|
<span className="text-[11px] text-muted-foreground">{t('projectCard.chapters.doneBadge', { count: chDone })}</span>
|
||||||
<Button size="xs" variant="ghost" className="text-muted-foreground" disabled={loadingAction} onClick={() => {
|
<Button size="xs" variant="outline" disabled={loadingAction} onClick={() => {
|
||||||
setExpandedChapters(prev => { const n = new Set(prev); n.add(ch.id); return n })
|
setExpandedChapters(prev => { const n = new Set(prev); n.add(ch.id); return n })
|
||||||
onGenerate(ch.chapter_index, true)
|
onGenerate(ch.chapter_index, true)
|
||||||
}}>
|
}}>
|
||||||
<RefreshCw className="h-3 w-3" />{t('projectCard.chapters.generate')}
|
<RefreshCw className="h-3 w-3 mr-0.5" /><Volume2 className="h-3 w-3 mr-1" />{t('projectCard.chapters.generate')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="icon" variant="ghost" className="h-6 w-6" onClick={() => onDownload(ch.chapter_index)} title={t('projectCard.downloadAll')}>
|
<Button size="icon" variant="ghost" className="h-6 w-6" onClick={() => onDownload(ch.chapter_index)} title={t('projectCard.downloadAll')}>
|
||||||
<Download className="h-3 w-3" />
|
<Download className="h-3 w-3" />
|
||||||
@@ -1302,7 +1308,8 @@ function ChaptersPanel({
|
|||||||
)}
|
)}
|
||||||
{ch.status === 'error' && (
|
{ch.status === 'error' && (
|
||||||
<Button size="xs" variant="outline" className="text-destructive border-destructive/40" onClick={() => onParseChapter(ch.id, ch.title)}>
|
<Button size="xs" variant="outline" className="text-destructive border-destructive/40" onClick={() => onParseChapter(ch.id, ch.title)}>
|
||||||
{t('projectCard.chapters.reparse')}
|
{isAIMode ? <Bot className="h-3 w-3 mr-1" /> : <Wand2 className="h-3 w-3 mr-1" />}
|
||||||
|
{t(isAIMode ? 'projectCard.chapters.reparseAI' : 'projectCard.chapters.reparse')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user