Skip to content

Commit 9f6b0b1

Browse files
authored
feat: Webサイトにページの翻訳状態の表示を追加 (#169)
1 parent c333fbd commit 9f6b0b1

File tree

6 files changed

+121
-0
lines changed

6 files changed

+121
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export const LanguageIcon = () => {
2+
return (
3+
<svg
4+
viewBox="0 0 24 24"
5+
fill="none"
6+
stroke="currentColor"
7+
stroke-width="2"
8+
stroke-linecap="round"
9+
stroke-linejoin="round"
10+
class="icon icon-tabler icons-tabler-outline icon-tabler-language-hiragana"
11+
>
12+
<title>言語アイコン</title>
13+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
14+
<path d="M4 5h7" />
15+
<path d="M7 4c0 4.846 0 7 .5 8" />
16+
<path d="M10 8.5c0 2.286 -2 4.5 -3.5 4.5s-2.5 -1.135 -2.5 -2c0 -2 1 -3 3 -3s5 .57 5 2.857c0 1.524 -.667 2.571 -2 3.143" />
17+
<path d="M12 20l4 -9l4 9" />
18+
<path d="M19.1 18h-6.2" />
19+
</svg>
20+
);
21+
};

website/src/components/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export { AlertTriangleIcon } from "./AlertTriangleIcon";
1010
export { MenuIcon } from "./MenuIcon";
1111
export { CloseIcon } from "./CloseIcon";
1212
export { SearchIcon } from "./SearchIcon";
13+
export { LanguageIcon } from "./LanguageIcon";
1314

1415
// Simple Icons
1516
// https://simpleicons.org/

website/src/components/templates/BaseTemplate.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { FC, PropsWithChildren } from "hono/jsx";
22
import type { Page } from "../../types/model";
3+
import { getTranslationStatus } from "../../utils/translationStatus";
34
import {
45
CaretRightCircleIcon,
56
ChevronLeftIcon,
@@ -15,6 +16,7 @@ import {
1516
SideNavigation,
1617
SiteNoticeBanner,
1718
TableOfContents,
19+
TranslationStatusAlert,
1820
} from "../ui/common/";
1921

2022
export type BaseTemplateProps = PropsWithChildren<{
@@ -37,6 +39,7 @@ export const BaseTemplate: FC<BaseTemplateProps> = ({
3739
const description = page.description;
3840
const route = page.route;
3941
const outline = page.outline;
42+
const translationStatus = getTranslationStatus(route);
4043
return (
4144
<html lang="ja">
4245
<head>
@@ -173,6 +176,10 @@ export const BaseTemplate: FC<BaseTemplateProps> = ({
173176
<main class="flex-1 flex flex-col px-3.5 py-4 mb-8">
174177
<Breadcrumbs path={path} />
175178

179+
<div class="mt-4">
180+
<TranslationStatusAlert status={translationStatus} />
181+
</div>
182+
176183
<div class="prose max-w-none w-full mt-6 flex-grow">
177184
{children}
178185
</div>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { FC } from "hono/jsx";
2+
import { twMerge } from "tailwind-merge";
3+
import type { TranslationStatus } from "../../../utils/translationStatus";
4+
import { LanguageIcon } from "../../icons";
5+
6+
type StatusConfig = {
7+
bgColor: string;
8+
borderColor: string;
9+
textColor: string;
10+
iconColor: string;
11+
label: string;
12+
message: string;
13+
};
14+
15+
const getStatusConfig = (status: TranslationStatus): StatusConfig => {
16+
switch (status) {
17+
case "translated":
18+
return {
19+
bgColor: "bg-green-50",
20+
borderColor: "border-green-200",
21+
textColor: "text-green-800",
22+
iconColor: "text-green-600",
23+
label: "翻訳済み",
24+
message: "このページは日本語に翻訳済みです。",
25+
};
26+
case "partially_translated":
27+
return {
28+
bgColor: "bg-yellow-50",
29+
borderColor: "border-yellow-200",
30+
textColor: "text-yellow-800",
31+
iconColor: "text-yellow-600",
32+
label: "部分的に翻訳済み",
33+
message:
34+
"このページは部分的に翻訳されています。一部原文の内容が含まれています。",
35+
};
36+
case "untranslated":
37+
return {
38+
bgColor: "bg-red-50",
39+
borderColor: "border-red-200",
40+
textColor: "text-red-800",
41+
iconColor: "text-red-600",
42+
label: "未翻訳",
43+
message:
44+
"このページはまだ翻訳されていません。原文の内容が表示されています。",
45+
};
46+
}
47+
};
48+
49+
export type TranslationStatusAlertProps = {
50+
status: TranslationStatus;
51+
};
52+
53+
export const TranslationStatusAlert: FC<TranslationStatusAlertProps> = ({
54+
status,
55+
}) => {
56+
const config = getStatusConfig(status);
57+
return (
58+
<div
59+
class={twMerge(
60+
"border rounded-md p-4 mb-6",
61+
config.bgColor,
62+
config.borderColor,
63+
config.textColor,
64+
)}
65+
>
66+
<div class="flex items-start">
67+
<div class={twMerge("w-5 h-5 mr-3 flex-shrink-0", config.iconColor)}>
68+
<LanguageIcon />
69+
</div>
70+
<div class="flex-1">
71+
<div class="text-sm font-bold mb-1">{config.label}</div>
72+
<p class="text-sm">{config.message}</p>
73+
</div>
74+
</div>
75+
</div>
76+
);
77+
};

website/src/components/ui/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { Breadcrumbs, type BreadcrumbsProps } from "./Breadcrumbs";
66
export { TableOfContents, type TableOfContentsProps } from "./TableOfContents";
77
export { Footer } from "./Footer";
88
export { SearchWindow } from "./SearchWindow";
9+
export { TranslationStatusAlert } from "./TranslationStatusAlert";

website/src/utils/translationStatus.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,17 @@ export const calculateTranslationProgressRate = (): number => {
9090

9191
return translationScore / routes.length;
9292
};
93+
94+
let translationStatusCache: TranslationStatusMap | null = null;
95+
96+
/**
97+
* 指定されたルートの翻訳状態を取得する。
98+
* @param route 翻訳状態を取得するページのルート
99+
* @returns 翻訳状態。存在しない場合は"untranslated"を返す。
100+
*/
101+
export const getTranslationStatus = (route: string): TranslationStatus => {
102+
if (translationStatusCache === null) {
103+
translationStatusCache = loadTranslationStatus();
104+
}
105+
return translationStatusCache[route] || "untranslated";
106+
};

0 commit comments

Comments
 (0)