diff --git a/web/app/features/prepare-html-for-translate/utils/extractNumberedElements.ts b/web/app/features/prepare-html-for-translate/utils/extractNumberedElements.ts
index 0a31d75c..2bb05f46 100644
--- a/web/app/features/prepare-html-for-translate/utils/extractNumberedElements.ts
+++ b/web/app/features/prepare-html-for-translate/utils/extractNumberedElements.ts
@@ -2,9 +2,12 @@ import { JSDOM } from "jsdom";
export function extractNumberedElements(
content: string,
+ title: string,
): Array<{ number: number; text: string }> {
const doc = new JSDOM(content);
- const numberedElements: Array<{ number: number; text: string }> = [];
+ const numberedElements: Array<{ number: number; text: string }> = [
+ { number: 0, text: title },
+ ];
// のみを改行とする
doc.window.document.body.innerHTML = doc.window.document.body.innerHTML
.replace(/\n/g, "")
diff --git a/web/app/routes/$userName+/page+/$slug+/components/ContentWithTranslations.tsx b/web/app/routes/$userName+/page+/$slug+/components/ContentWithTranslations.tsx
index 064b2ab9..63a44c96 100644
--- a/web/app/routes/$userName+/page+/$slug+/components/ContentWithTranslations.tsx
+++ b/web/app/routes/$userName+/page+/$slug+/components/ContentWithTranslations.tsx
@@ -5,16 +5,22 @@ import type { SourceTextWithTranslations } from "../types";
import { Translation } from "./Translation";
interface ContentWithTranslationsProps {
+ title: string;
content: string;
sourceTextWithTranslations: SourceTextWithTranslations[];
userId: number | null;
}
export const ContentWithTranslations = memo(function ContentWithTranslations({
+ title,
content,
sourceTextWithTranslations,
userId,
}: ContentWithTranslationsProps) {
+ const titleTranslation = useMemo(() => {
+ return sourceTextWithTranslations.find((info) => info.number === 0);
+ }, [sourceTextWithTranslations]);
+
const parsedContent = useMemo(() => {
if (typeof window === "undefined") {
return null;
@@ -63,5 +69,19 @@ export const ContentWithTranslations = memo(function ContentWithTranslations({
return
Loading...
;
}
- return <>{parsedContent}>;
+ return (
+ <>
+
+ {title}
+ {titleTranslation && (
+
+ )}
+
+ {parsedContent}
+ >
+ );
});
diff --git a/web/app/routes/$userName+/page+/$slug+/components/Translation.tsx b/web/app/routes/$userName+/page+/$slug+/components/Translation.tsx
index b380137a..6e72cbec 100644
--- a/web/app/routes/$userName+/page+/$slug+/components/Translation.tsx
+++ b/web/app/routes/$userName+/page+/$slug+/components/Translation.tsx
@@ -46,14 +46,22 @@ export function Translation({
const alternativeTranslationsWithVotes = useMemo(
() =>
- translationsWithVotes.filter((t) => t.id !== bestTranslationWithVote.id),
+ bestTranslationWithVote
+ ? translationsWithVotes.filter(
+ (t) => t.id !== bestTranslationWithVote.id,
+ )
+ : [],
[translationsWithVotes, bestTranslationWithVote],
);
const sanitizedAndParsedText = useMemo(() => {
- const sanitized = sanitizeAndParseText(bestTranslationWithVote.text);
- return sanitized;
- }, [bestTranslationWithVote.text]);
+ if (!bestTranslationWithVote) return null;
+ return sanitizeAndParseText(bestTranslationWithVote.text);
+ }, [bestTranslationWithVote]);
+
+ if (!bestTranslationWithVote || !sanitizedAndParsedText) {
+ return null;
+ }
return (
diff --git a/web/app/routes/$userName+/page+/$slug+/components/UserAITranslationStatus.tsx b/web/app/routes/$userName+/page+/$slug+/components/UserAITranslationStatus.tsx
index bf2b698e..2f2c1014 100644
--- a/web/app/routes/$userName+/page+/$slug+/components/UserAITranslationStatus.tsx
+++ b/web/app/routes/$userName+/page+/$slug+/components/UserAITranslationStatus.tsx
@@ -34,7 +34,7 @@ export function UserAITranslationStatus({
return (
- Translation Status
+ Your AI Translation Status
{
const { title, pageContent } = submission.value;
const numberedContent = addNumbersToContent(pageContent);
- console.log(numberedContent);
const page = await getOrCreatePage(safeUser.id, slug, title, numberedContent);
- const numberedElements = extractNumberedElements(numberedContent);
+ const numberedElements = extractNumberedElements(numberedContent, title);
await createOrUpdateSourceTexts(numberedElements, page.id);
return redirect(`/${userName}/page/${slug}`);
diff --git a/web/app/routes/$userName+/page+/$slug+/index.tsx b/web/app/routes/$userName+/page+/$slug+/index.tsx
index 9c80f6a7..0081cc5a 100644
--- a/web/app/routes/$userName+/page+/$slug+/index.tsx
+++ b/web/app/routes/$userName+/page+/$slug+/index.tsx
@@ -9,8 +9,8 @@ import { Languages } from "lucide-react";
import { useState } from "react";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { LoadingSpinner } from "~/components/LoadingSpinner";
+import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import { Button } from "~/components/ui/button";
-import { extractNumberedElements } from "~/features/prepare-html-for-translate/utils/extractNumberedElements";
import { AIModelSelector } from "~/features/translate/components/AIModelSelector";
import { getTranslateUserQueue } from "~/features/translate/translate-user-queue";
import { GeminiApiKeyDialog } from "~/routes/resources+/gemini-api-key-dialog";
@@ -31,7 +31,7 @@ import {
getDbUser,
} from "./functions/queries.server";
import { actionSchema } from "./types";
-
+import { extractNumberedElements } from "./utils/extractNumberedElements";
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const { slug } = params;
@@ -77,10 +77,11 @@ export const action = async ({ request }: ActionFunctionArgs) => {
return {
intent: null,
lastResult: submission.reply({ formErrors: ["User not authenticated"] }),
+ slug: null,
};
}
if (submission.status !== "success") {
- return { intent: null, lastResult: submission.reply() };
+ return { intent: null, lastResult: submission.reply(), slug: null };
}
const { intent } = submission.value;
switch (intent) {
@@ -90,7 +91,11 @@ export const action = async ({ request }: ActionFunctionArgs) => {
submission.value.isUpvote,
safeUserId,
);
- return { intent, lastResult: submission.reply({ resetForm: true }) };
+ return {
+ intent,
+ lastResult: submission.reply({ resetForm: true }),
+ slug: null,
+ };
case "add":
handleAddTranslationAction(
submission.value.sourceTextId,
@@ -98,7 +103,11 @@ export const action = async ({ request }: ActionFunctionArgs) => {
safeUserId,
targetLanguage,
);
- return { intent, lastResult: submission.reply({ resetForm: true }) };
+ return {
+ intent,
+ lastResult: submission.reply({ resetForm: true }),
+ slug: null,
+ };
case "translate": {
const dbUser = await getDbUser(safeUser.id);
if (!dbUser?.geminiApiKey) {
@@ -106,6 +115,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
lastResult: submission.reply({
formErrors: ["Gemini API key is not set"],
}),
+ intent: null,
slug: null,
};
}
@@ -115,6 +125,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
lastResult: submission.reply({
formErrors: ["Page not found"],
}),
+ intent: null,
slug: null,
};
}
@@ -125,7 +136,10 @@ export const action = async ({ request }: ActionFunctionArgs) => {
targetLanguage,
);
- const numberedElements = extractNumberedElements(page.content);
+ const numberedElements = extractNumberedElements(
+ page.content,
+ page.title,
+ );
const queue = getTranslateUserQueue(safeUser.id);
const job = await queue.add(`translate-${safeUser.id}`, {
userAITranslationInfoId: userAITranslationInfo.id,
@@ -138,7 +152,11 @@ export const action = async ({ request }: ActionFunctionArgs) => {
numberedContent: page.content,
numberedElements,
});
- return { intent, lastResult: submission.reply({ resetForm: true }) };
+ return {
+ intent,
+ lastResult: submission.reply({ resetForm: true }),
+ slug: page.slug,
+ };
}
default:
throw new Error("Invalid Intent");
@@ -205,17 +223,23 @@ export default function ReaderView() {
)}
+ {actionData?.slug && (
+
+
+ Translation Job Started
+
+
+ {actionData.slug}
+
+
+ )}
-
- {pageData.title}
- {pageData.translationTitle}
-
-
t.userVote?.isUpvote,
);
diff --git a/web/app/routes/$userName+/page+/$slug+/edit/utils/addNumbersToContent.ts b/web/app/routes/$userName+/page+/$slug+/utils/addNumbersToContent.ts
similarity index 100%
rename from web/app/routes/$userName+/page+/$slug+/edit/utils/addNumbersToContent.ts
rename to web/app/routes/$userName+/page+/$slug+/utils/addNumbersToContent.ts
diff --git a/web/app/routes/$userName+/page+/$slug+/edit/utils/extractArticle.ts b/web/app/routes/$userName+/page+/$slug+/utils/extractArticle.ts
similarity index 100%
rename from web/app/routes/$userName+/page+/$slug+/edit/utils/extractArticle.ts
rename to web/app/routes/$userName+/page+/$slug+/utils/extractArticle.ts
diff --git a/web/app/routes/$userName+/page+/$slug+/edit/utils/extractNumberedElements.ts b/web/app/routes/$userName+/page+/$slug+/utils/extractNumberedElements.ts
similarity index 93%
rename from web/app/routes/$userName+/page+/$slug+/edit/utils/extractNumberedElements.ts
rename to web/app/routes/$userName+/page+/$slug+/utils/extractNumberedElements.ts
index 0a31d75c..2bb05f46 100644
--- a/web/app/routes/$userName+/page+/$slug+/edit/utils/extractNumberedElements.ts
+++ b/web/app/routes/$userName+/page+/$slug+/utils/extractNumberedElements.ts
@@ -2,9 +2,12 @@ import { JSDOM } from "jsdom";
export function extractNumberedElements(
content: string,
+ title: string,
): Array<{ number: number; text: string }> {
const doc = new JSDOM(content);
- const numberedElements: Array<{ number: number; text: string }> = [];
+ const numberedElements: Array<{ number: number; text: string }> = [
+ { number: 0, text: title },
+ ];
// のみを改行とする
doc.window.document.body.innerHTML = doc.window.document.body.innerHTML
.replace(/\n/g, "")
diff --git a/web/app/routes/resources+/footer.tsx b/web/app/routes/resources+/footer.tsx
index e071e396..4797798b 100644
--- a/web/app/routes/resources+/footer.tsx
+++ b/web/app/routes/resources+/footer.tsx
@@ -42,50 +42,36 @@ export function Footer({ safeUser }: FooterProps) {
return (
-
-
-
-
-
-
-
-
{safeUser?.userName}
-
-
-
-
- Privacy Policy
-
-
- Terms of Service
-
-
© {currentYear} EveEve
-
-
-
- {safeUser ? (
-
- ) : (
+
+
+
+
+
+
+ {safeUser && (
+ <>
+
+
{safeUser.userName}
+
+
+ >
+ )}
+
+ {!safeUser && (
+
+
+
+ Privacy Policy
+
+
+ Terms of Service
+
+
+
© {currentYear} EveEve
+
diff --git a/web/app/routes/translator/route.tsx b/web/app/routes/translator/route.tsx
index 48a10600..eec246f5 100644
--- a/web/app/routes/translator/route.tsx
+++ b/web/app/routes/translator/route.tsx
@@ -127,7 +127,10 @@ export async function action({ request }: ActionFunctionArgs) {
targetLanguage,
);
- const numberedElements = extractNumberedElements(numberedContent);
+ const numberedElements = extractNumberedElements(
+ numberedContent,
+ title,
+ );
await createOrUpdateSourceTexts(numberedElements, page.id);
// ファイルの翻訳ジョブをキューに追加
await queue.add(`translate-${safeUser.id}`, {