Improve: update media tab content translation (#1044)
* refactor: rename files * update lookup result * fix style
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export * from "./media-caption-tabs";
|
||||
export * from "./tab-content-analysis";
|
||||
export * from "./tab-content-note";
|
||||
export * from "./tab-content-translation";
|
||||
export * from "./media-tab-content-analysis";
|
||||
export * from "./media-tab-content-note";
|
||||
export * from "./media-tab-content-translation";
|
||||
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
} from "@renderer/components/ui";
|
||||
import { t } from "i18next";
|
||||
import { TimelineEntry } from "echogarden/dist/utilities/Timeline.d.js";
|
||||
import { TabContentTranslation } from "./tab-content-translation";
|
||||
import { TabContentAnalysis } from "./tab-content-analysis";
|
||||
import { TabContentNote } from "./tab-content-note";
|
||||
import { MediaTabContentTranslation } from "./media-tab-content-translation";
|
||||
import { MediaTabContentAnalysis } from "./media-tab-content-analysis";
|
||||
import { MediaTabContentNote } from "./media-tab-content-note";
|
||||
|
||||
export const MediaCaptionTabs = (props: {
|
||||
caption: TimelineEntry;
|
||||
@@ -38,18 +38,18 @@ export const MediaCaptionTabs = (props: {
|
||||
{children}
|
||||
|
||||
<div className="px-4 pb-10 min-h-32">
|
||||
<TabContentNote
|
||||
<MediaTabContentNote
|
||||
currentSegmentIndex={currentSegmentIndex}
|
||||
selectedIndices={selectedIndices}
|
||||
setSelectedIndices={setSelectedIndices}
|
||||
/>
|
||||
|
||||
<TabContentTranslation
|
||||
<MediaTabContentTranslation
|
||||
caption={caption}
|
||||
selectedIndices={selectedIndices}
|
||||
/>
|
||||
|
||||
<TabContentAnalysis text={caption.text} />
|
||||
<MediaTabContentAnalysis text={caption.text} />
|
||||
</div>
|
||||
|
||||
<TabsList className="grid grid-cols-3 gap-4 rounded-none absolute w-full bottom-0 px-4">
|
||||
|
||||
@@ -9,7 +9,7 @@ import { LoaderIcon } from "lucide-react";
|
||||
import { md5 } from "js-md5";
|
||||
import Markdown from "react-markdown";
|
||||
|
||||
export function TabContentAnalysis(props: { text: string; }) {
|
||||
export function MediaTabContentAnalysis(props: { text: string }) {
|
||||
const { text } = props;
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
const [analyzing, setAnalyzing] = useState<boolean>(false);
|
||||
@@ -55,7 +55,7 @@ export function TabContentAnalysis(props: { text: string; }) {
|
||||
new URL(props.href ?? "");
|
||||
props.target = "_blank";
|
||||
props.rel = "noopener noreferrer";
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
return <a {...props}>{children}</a>;
|
||||
},
|
||||
@@ -82,8 +82,9 @@ export function TabContentAnalysis(props: { text: string; }) {
|
||||
const result = replies.map((m) => m.content).join("\n");
|
||||
setAnalysisResult(result);
|
||||
EnjoyApp.cacheObjects.set(`analyze-${md5(text)}`, result);
|
||||
} }
|
||||
tooltip={t("useAIAssistantToAnalyze")} />
|
||||
}}
|
||||
tooltip={t("useAIAssistantToAnalyze")}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
@@ -98,8 +99,9 @@ export function TabContentAnalysis(props: { text: string; }) {
|
||||
const result = replies.map((m) => m.content).join("\n");
|
||||
setAnalysisResult(result);
|
||||
EnjoyApp.cacheObjects.set(`analyze-${md5(text)}`, result);
|
||||
} }
|
||||
tooltip={t("useAIAssistantToAnalyze")} />
|
||||
}}
|
||||
tooltip={t("useAIAssistantToAnalyze")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
@@ -7,7 +7,7 @@ import { NoteCard, NoteForm } from "@renderer/components";
|
||||
/*
|
||||
* Note tab content.
|
||||
*/
|
||||
export const TabContentNote = (props: {
|
||||
export const MediaTabContentNote = (props: {
|
||||
currentSegmentIndex: number;
|
||||
selectedIndices: number[];
|
||||
setSelectedIndices: (indices: number[]) => void;
|
||||
@@ -0,0 +1,128 @@
|
||||
import { useContext } from "react";
|
||||
import {
|
||||
AppSettingsProviderContext,
|
||||
MediaPlayerProviderContext,
|
||||
DictProviderContext,
|
||||
} from "@renderer/context";
|
||||
import { TabsContent, Separator } from "@renderer/components/ui";
|
||||
import { t } from "i18next";
|
||||
import { TimelineEntry } from "echogarden/dist/utilities/Timeline.d.js";
|
||||
import { convertWordIpaToNormal } from "@/utils";
|
||||
import {
|
||||
CamdictLookupResult,
|
||||
DictLookupResult,
|
||||
AiLookupResult,
|
||||
TranslateResult,
|
||||
DictSelect,
|
||||
} from "@renderer/components";
|
||||
|
||||
/*
|
||||
* Translation tab content.
|
||||
*/
|
||||
export function MediaTabContentTranslation(props: {
|
||||
caption: TimelineEntry;
|
||||
selectedIndices: number[];
|
||||
}) {
|
||||
const { caption } = props;
|
||||
|
||||
return (
|
||||
<TabsContent value="translation">
|
||||
<SelectedWords {...props} />
|
||||
<Separator className="my-4" />
|
||||
<div className="text-sm italic text-muted-foreground mb-2">
|
||||
{t("translateSentence")}
|
||||
</div>
|
||||
<TranslateResult text={caption.text} />
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
const SelectedWords = (props: {
|
||||
caption: TimelineEntry;
|
||||
selectedIndices: number[];
|
||||
}) => {
|
||||
const { selectedIndices, caption } = props;
|
||||
|
||||
const { currentDictValue } = useContext(DictProviderContext);
|
||||
const { transcription } = useContext(MediaPlayerProviderContext);
|
||||
const { learningLanguage, ipaMappings } = useContext(
|
||||
AppSettingsProviderContext
|
||||
);
|
||||
|
||||
const word = selectedIndices
|
||||
.map((index) => caption.timeline[index]?.text || "")
|
||||
.join(" ")
|
||||
.trim();
|
||||
|
||||
if (selectedIndices.length === 0)
|
||||
return (
|
||||
<div className="text-sm text-muted-foreground py-4">
|
||||
{t("clickAnyWordToSelect")}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex justify-between items-start flex-wrap">
|
||||
<div className="flex flex-1 flex-wrap items-center space-x-2 select-text mb-4">
|
||||
{selectedIndices.map((index, i) => {
|
||||
const word = caption.timeline[index];
|
||||
if (!word) return;
|
||||
return (
|
||||
<div key={index}>
|
||||
<div className="font-serif text-lg font-semibold tracking-tight">
|
||||
{word.text}
|
||||
</div>
|
||||
{word.timeline.length > 0 && (
|
||||
<div className="text-sm text-serif text-muted-foreground">
|
||||
<span
|
||||
className={`mr-2 font-code ${
|
||||
i === 0 ? "before:content-['/']" : ""
|
||||
}
|
||||
${
|
||||
i === selectedIndices.length - 1
|
||||
? "after:content-['/']"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{word.timeline
|
||||
.map((t) =>
|
||||
learningLanguage.startsWith("en")
|
||||
? convertWordIpaToNormal(
|
||||
t.timeline.map((s) => s.text),
|
||||
{
|
||||
mappings: ipaMappings,
|
||||
}
|
||||
).join("")
|
||||
: t.text
|
||||
)
|
||||
.join(" ")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="w-60">
|
||||
<DictSelect />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="my-4" />
|
||||
|
||||
{currentDictValue === "cambridge" ? (
|
||||
<CamdictLookupResult word={word} />
|
||||
) : currentDictValue === "ai" ? (
|
||||
<AiLookupResult
|
||||
word={word}
|
||||
context={caption.text}
|
||||
sourceId={transcription.targetId}
|
||||
sourceType={transcription.targetType}
|
||||
/>
|
||||
) : (
|
||||
<DictLookupResult word={word} autoHeight={true} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,127 +0,0 @@
|
||||
import { useContext } from "react";
|
||||
import {
|
||||
AppSettingsProviderContext,
|
||||
MediaPlayerProviderContext,
|
||||
DictProviderContext,
|
||||
} from "@renderer/context";
|
||||
import { TabsContent, Separator } from "@renderer/components/ui";
|
||||
import { t } from "i18next";
|
||||
import { TimelineEntry } from "echogarden/dist/utilities/Timeline.d.js";
|
||||
import { convertWordIpaToNormal } from "@/utils";
|
||||
import {
|
||||
CamdictLookupResult,
|
||||
DictLookupResult,
|
||||
AiLookupResult,
|
||||
TranslateResult,
|
||||
} from "@renderer/components";
|
||||
|
||||
/*
|
||||
* Translation tab content.
|
||||
*/
|
||||
export function TabContentTranslation(props: {
|
||||
caption: TimelineEntry;
|
||||
selectedIndices: number[];
|
||||
}) {
|
||||
const { caption } = props;
|
||||
|
||||
return (
|
||||
<TabsContent value="translation">
|
||||
<SelectedWords {...props} />
|
||||
<Separator className="my-2" />
|
||||
<div className="text-sm italic text-muted-foreground mb-2">
|
||||
{t("translateSentence")}
|
||||
</div>
|
||||
<TranslateResult text={caption.text} />
|
||||
</TabsContent>
|
||||
);
|
||||
}
|
||||
|
||||
const SelectedWords = (props: {
|
||||
caption: TimelineEntry;
|
||||
selectedIndices: number[];
|
||||
}) => {
|
||||
const { selectedIndices, caption } = props;
|
||||
|
||||
const { currentDictValue } = useContext(DictProviderContext);
|
||||
const { transcription } = useContext(MediaPlayerProviderContext);
|
||||
const { learningLanguage, ipaMappings } = useContext(
|
||||
AppSettingsProviderContext
|
||||
);
|
||||
|
||||
const word = selectedIndices
|
||||
.map((index) => caption.timeline[index]?.text || "")
|
||||
.join(" ")
|
||||
.trim();
|
||||
|
||||
if (selectedIndices.length === 0)
|
||||
return (
|
||||
<div className="text-sm text-muted-foreground py-4">
|
||||
{t("clickAnyWordToSelect")}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-wrap items-center space-x-2 select-text mb-4">
|
||||
{selectedIndices.map((index, i) => {
|
||||
const word = caption.timeline[index];
|
||||
if (!word) return;
|
||||
return (
|
||||
<div key={index}>
|
||||
<div className="font-serif text-lg font-semibold tracking-tight">
|
||||
{word.text}
|
||||
</div>
|
||||
{word.timeline.length > 0 && (
|
||||
<div className="text-sm text-serif text-muted-foreground">
|
||||
<span
|
||||
className={`mr-2 font-code ${
|
||||
i === 0 ? "before:content-['/']" : ""
|
||||
}
|
||||
${
|
||||
i === selectedIndices.length - 1
|
||||
? "after:content-['/']"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{word.timeline
|
||||
.map((t) =>
|
||||
learningLanguage.startsWith("en")
|
||||
? convertWordIpaToNormal(
|
||||
t.timeline.map((s) => s.text),
|
||||
{
|
||||
mappings: ipaMappings,
|
||||
}
|
||||
).join("")
|
||||
: t.text
|
||||
)
|
||||
.join(" ")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{currentDictValue === "cambridge" ? (
|
||||
<>
|
||||
<Separator className="my-2" />
|
||||
<CamdictLookupResult word={word} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Separator className="my-2" />
|
||||
<DictLookupResult word={word} autoHeight={true} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Separator className="my-2" />
|
||||
<AiLookupResult
|
||||
word={word}
|
||||
context={caption.text}
|
||||
sourceId={transcription.targetId}
|
||||
sourceType={transcription.targetType}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user