diff --git a/messages/ja.json b/messages/ja.json
index 922608a..34af6fb 100644
--- a/messages/ja.json
+++ b/messages/ja.json
@@ -58,30 +58,6 @@
"/components/DialectSelector/DialectSelector": {
"legend": "方言"
},
- "/components/DialectSelector/useDialects": {
- "karahuto": "樺太",
- "east_coast": "西海岸",
- "otasu": "小田洲",
- "ushiro": "鵜城",
- "raichishi": "来知志",
- "hokkaido": "北海道",
- "southwest": "南西",
- "northeast": "北東",
- "saru": "沙流",
- "chitose": "千歳",
- "mukawa": "鵡川",
- "horobetsu": "幌別",
- "abuta": "虻田",
- "shiraoi": "白老",
- "shizunai": "静内",
- "ishikari": "石狩",
- "shiranuka": "白糠",
- "tokachi": "十勝",
- "kushiro": "釧路",
- "urakawa": "浦河",
- "bihoro": "美幌",
- "samani": "様似"
- },
"/components/DialectSelector/DialectSelectorCheckbox": {
"count": "({count}件)"
},
@@ -137,5 +113,29 @@
},
"/components/Search/Search": {
"label": "キーワード"
+ },
+ "/hooks/useDialectFormatter": {
+ "karahuto": "樺太",
+ "east_coast": "西海岸",
+ "otasu": "小田洲",
+ "ushiro": "鵜城",
+ "raichishi": "来知志",
+ "hokkaido": "北海道",
+ "southwest": "南西",
+ "northeast": "北東",
+ "saru": "沙流",
+ "chitose": "千歳",
+ "mukawa": "鵡川",
+ "horobetsu": "幌別",
+ "abuta": "虻田",
+ "shiraoi": "白老",
+ "shizunai": "静内",
+ "ishikari": "石狩",
+ "shiranuka": "白糠",
+ "tokachi": "十勝",
+ "kushiro": "釧路",
+ "urakawa": "浦河",
+ "bihoro": "美幌",
+ "samani": "様似"
}
}
diff --git a/src/app/[locale]/search/Result.tsx b/src/app/[locale]/search/Result.tsx
index e16f3e4..9f9002b 100644
--- a/src/app/[locale]/search/Result.tsx
+++ b/src/app/[locale]/search/Result.tsx
@@ -50,7 +50,6 @@ const ResultRoot: FC = (props) => {
document={hit.document}
uri={hit.uri}
author={hit.author}
- dialect={hit.dialect}
dialectLv1={hit.dialect_lv1}
dialectLv2={hit.dialect_lv2}
dialectLv3={hit.dialect_lv3}
diff --git a/src/components/Hierarchy/Hierarchy.tsx b/src/components/Breadcrumb/Breadcrumb.tsx
similarity index 67%
rename from src/components/Hierarchy/Hierarchy.tsx
rename to src/components/Breadcrumb/Breadcrumb.tsx
index 572f3ef..8a5536d 100644
--- a/src/components/Hierarchy/Hierarchy.tsx
+++ b/src/components/Breadcrumb/Breadcrumb.tsx
@@ -2,21 +2,21 @@ import { FC, ReactNode, useMemo } from "react";
import { ChevronRightIcon } from "@radix-ui/react-icons";
import { Flex } from "@radix-ui/themes";
-export type HierarchyProps = {
- children: string | null;
+export type BreadcrumbProps = {
+ values: ReactNode[];
};
-export const Hierarchy: FC = (props) => {
- const { children } = props;
+export const Breadcrumb: FC = (props) => {
+ const { values } = props;
const nodes = useMemo(() => {
const nodes: ReactNode[] = [];
- if (!children) {
+ if (!values) {
return null;
}
- for (const [key, fragment] of Object.entries(children.split("/"))) {
+ for (const [key, fragment] of Object.entries(values)) {
if (nodes.length !== 0) {
nodes.push();
}
@@ -25,7 +25,7 @@ export const Hierarchy: FC = (props) => {
}
return nodes;
- }, [children]);
+ }, [values]);
if (!nodes) {
return null;
diff --git a/src/components/Breadcrumb/index.ts b/src/components/Breadcrumb/index.ts
new file mode 100644
index 0000000..3bc34d1
--- /dev/null
+++ b/src/components/Breadcrumb/index.ts
@@ -0,0 +1 @@
+export * from "./Breadcrumb";
diff --git a/src/components/DialectSelector/useDialects.ts b/src/components/DialectSelector/useDialects.ts
index 0e1dff7..e0a4e87 100644
--- a/src/components/DialectSelector/useDialects.ts
+++ b/src/components/DialectSelector/useDialects.ts
@@ -1,4 +1,4 @@
-import { useTranslations } from "next-intl";
+import { useDialectFormatter } from "@/hooks/useDialectFormatter";
export type Dialect = {
label: string;
@@ -7,52 +7,61 @@ export type Dialect = {
};
export const useDialects = (): Dialect[] => {
- const t = useTranslations("/components/DialectSelector/useDialects");
+ const format = useDialectFormatter();
const dialects: Dialect[] = [
{
- label: t("karahuto"),
+ label: format("樺太"),
value: "樺太",
children: [
{
- label: t("east_coast"),
+ label: format("樺太/西海岸"),
value: "樺太/西海岸",
children: [
- { label: t("otasu"), value: "樺太/西海岸/小田洲" },
- { label: t("ushiro"), value: "樺太/西海岸/鵜城" },
- { label: t("raichishi"), value: "樺太/西海岸/来知志" },
+ {
+ label: format("樺太/西海岸/小田洲"),
+ value: "樺太/西海岸/小田洲",
+ },
+ {
+ label: format("樺太/西海岸/鵜城"),
+ value: "樺太/西海岸/鵜城",
+ },
+ {
+ label: format("樺太/西海岸/来知志"),
+ value: "樺太/西海岸/来知志",
+ },
],
},
],
},
{
- label: t("hokkaido"),
+ label: format("北海道"),
value: "北海道",
children: [
{
- label: t("southwest"),
+ label: format("北海道/南西"),
value: "北海道/南西",
children: [
- { label: t("saru"), value: "北海道/南西/沙流" },
- { label: t("chitose"), value: "北海道/南西/千歳" },
- { label: t("mukawa"), value: "北海道/南西/鵡川" },
- { label: t("horobetsu"), value: "北海道/南西/幌別" },
- { label: t("abuta"), value: "北海道/南西/虻田" },
- { label: t("shiraoi"), value: "北海道/南西/白老" },
+ { label: format("北海道/南西/沙流"), value: "北海道/南西/沙流" },
+ { label: format("北海道/南西/千歳"), value: "北海道/南西/千歳" },
+ { label: format("北海道/南西/鵡川"), value: "北海道/南西/鵡川" },
+ { label: format("北海道/南西/幌別"), value: "北海道/南西/幌別" },
+ { label: format("北海道/南西/虻田"), value: "北海道/南西/虻田" },
+ { label: format("北海道/南西/白老"), value: "北海道/南西/白老" },
],
},
{
- label: t("northeast"),
+ label: format("北海道/北東"),
value: "北海道/北東",
children: [
- { label: t("shizunai"), value: "北海道/北東/静内" },
- { label: t("ishikari"), value: "北海道/北東/石狩" },
- { label: t("shiranuka"), value: "北海道/北東/白糠" },
- { label: t("tokachi"), value: "北海道/北東/十勝" },
- { label: t("kushiro"), value: "北海道/北東/釧路" },
- { label: t("urakawa"), value: "北海道/北東/浦河" },
- { label: t("bihoro"), value: "北海道/北東/美幌" },
- { label: t("samani"), value: "北海道/北東/様似" },
+ { label: format("北海道/北東/静内"), value: "北海道/北東/静内" },
+ { label: format("北海道/北東/石狩"), value: "北海道/北東/石狩" },
+ { label: format("北海道/北東/白糠"), value: "北海道/北東/白糠" },
+ { label: format("北海道/北東/十勝"), value: "北海道/北東/十勝" },
+ { label: format("北海道/北東/釧路"), value: "北海道/北東/釧路" },
+ { label: format("北海道/北東/浦河"), value: "北海道/北東/浦河" },
+ { label: format("北海道/北東/美幌"), value: "北海道/北東/美幌" },
+ { label: format("北海道/北東/様似"), value: "北海道/北東/様似" },
],
},
],
diff --git a/src/components/Entry/Entry.tsx b/src/components/Entry/Entry.tsx
index fdb1aa7..07e363f 100644
--- a/src/components/Entry/Entry.tsx
+++ b/src/components/Entry/Entry.tsx
@@ -30,7 +30,6 @@ export type EntryRootProps = {
collectionLv3: string | null;
uri: string | null;
author: string | null;
- dialect: string | null;
dialectLv1: string[] | null;
dialectLv2: string[] | null;
dialectLv3: string[] | null;
@@ -49,7 +48,6 @@ const EntryRoot: React.FC = (props) => {
document,
uri,
author,
- dialect,
dialectLv1,
dialectLv2,
dialectLv3,
@@ -119,9 +117,14 @@ const EntryRoot: React.FC = (props) => {
)}
- {(author || dialect) && (
+ {(author || dialectLv1 || dialectLv2 || dialectLv3) && (
-
+
)}
@@ -132,7 +135,6 @@ const EntryRoot: React.FC = (props) => {
collectionLv3={collectionLv3}
document={document}
author={author}
- dialect={dialect}
dialectLv1={dialectLv1}
dialectLv2={dialectLv2}
dialectLv3={dialectLv3}
diff --git a/src/components/Entry/EntryAuthor.tsx b/src/components/Entry/EntryAuthor.tsx
index 306654c..5c53704 100644
--- a/src/components/Entry/EntryAuthor.tsx
+++ b/src/components/Entry/EntryAuthor.tsx
@@ -1,23 +1,38 @@
+import { useDialectFormatter } from "@/hooks/useDialectFormatter";
+import { getMostDetailedDialects } from "@/utils/getMostDetailedDialects";
import { Text, VisuallyHidden } from "@radix-ui/themes";
import { useTranslations } from "next-intl";
import { FC } from "react";
type EntryAuthorProps = {
author: string | null;
- dialect: string | null;
+ dialectLv1: string[] | null;
+ dialectLv2: string[] | null;
+ dialectLv3: string[] | null;
};
export const EntryAuthor: FC = (props) => {
- const { author, dialect } = props;
+ const { author, dialectLv1, dialectLv2, dialectLv3 } = props;
const t = useTranslations("/components/Entry/EntryAuthor");
+ const formatDialect = useDialectFormatter();
- if (author && dialect) {
+ const dialects = getMostDetailedDialects(
+ dialectLv1 ?? [],
+ dialectLv2 ?? [],
+ dialectLv3 ?? [],
+ );
+ const formattedDialects =
+ dialects.length > 0
+ ? dialects.map((dialect) => formatDialect(dialect)).join(", ")
+ : null;
+
+ if (author && formattedDialects) {
return (
{t.rich("author_with_dialect", {
author,
- dialect,
+ dialect: formattedDialects,
vh: (chunks) => {chunks},
})}
@@ -35,11 +50,11 @@ export const EntryAuthor: FC = (props) => {
);
}
- if (dialect) {
+ if (formattedDialects) {
return (
{t.rich("dialect", {
- dialect,
+ dialect: formattedDialects,
vh: (chunks) => {chunks},
})}
diff --git a/src/components/Entry/EntryDetailsDialog.tsx b/src/components/Entry/EntryDetailsDialog.tsx
index 7f9a247..8b87432 100644
--- a/src/components/Entry/EntryDetailsDialog.tsx
+++ b/src/components/Entry/EntryDetailsDialog.tsx
@@ -2,7 +2,6 @@
import { CopyIcon, DotsHorizontalIcon } from "@radix-ui/react-icons";
import {
- Badge,
Button,
Code,
DataList,
@@ -12,16 +11,16 @@ import {
Link,
Text,
Tooltip,
- VisuallyHidden,
} from "@radix-ui/themes";
import { FC, useCallback } from "react";
import dayjs from "dayjs";
+import { useLocale, useTranslations } from "next-intl";
import { formatDateOrRange } from "@/utils/timestamp";
import { toHref } from "@/utils/uri";
-import { useLocale, useTranslations } from "next-intl";
+import { getMostDetailedDialects } from "@/utils/getMostDetailedDialects";
-import { Hierarchy } from "../Hierarchy/Hierarchy";
+import { Breadcrumb } from "../Breadcrumb";
const NoData = () => {
const t = useTranslations("/components/Entry/EntryDetailsDialog");
@@ -35,7 +34,6 @@ export type EntryDetailsDialogProps = {
collectionLv2: string | null;
collectionLv3: string | null;
author: string | null;
- dialect: string | null;
dialectLv1: string[] | null;
dialectLv2: string[] | null;
dialectLv3: string[] | null;
@@ -52,8 +50,10 @@ export const EntryDetailsDialog: FC = (props) => {
collectionLv3,
document,
author,
- dialect,
uri,
+ dialectLv1,
+ dialectLv2,
+ dialectLv3,
recordedAt,
publishedAt,
} = props;
@@ -62,6 +62,16 @@ export const EntryDetailsDialog: FC = (props) => {
const t = useTranslations("/components/Entry/EntryDetailsDialog");
const href = uri ? toHref(uri) : null;
+ const hasDialect = !!(dialectLv1 || dialectLv2 || dialectLv3);
+
+ const mostDetailedDialects = hasDialect
+ ? getMostDetailedDialects(
+ dialectLv1 ?? [],
+ dialectLv2 ?? [],
+ dialectLv3 ?? [],
+ )
+ : null;
+
dayjs.locale(locale);
const handleCopy = useCallback(() => {
@@ -107,9 +117,14 @@ export const EntryDetailsDialog: FC = (props) => {
{t("collection")}
{collectionLv3 || collectionLv2 || collectionLv1 ? (
-
- {collectionLv3 ?? collectionLv2 ?? collectionLv1}
-
+
) : (
)}
@@ -129,7 +144,15 @@ export const EntryDetailsDialog: FC = (props) => {
{t("dialect")}
- {dialect ? {dialect} : }
+
+ {mostDetailedDialects ? (
+ mostDetailedDialects.map((dialect) => (
+
+ ))
+ ) : (
+
+ )}
+
diff --git a/src/components/Hierarchy/index.ts b/src/components/Hierarchy/index.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/src/hooks/useDialectFormatter.ts b/src/hooks/useDialectFormatter.ts
new file mode 100644
index 0000000..640e619
--- /dev/null
+++ b/src/hooks/useDialectFormatter.ts
@@ -0,0 +1,67 @@
+import { useTranslations } from "next-intl";
+import { useCallback } from "react";
+
+type UseDialectFormatterOutput = (dialect: string) => string;
+
+export const useDialectFormatter = (): UseDialectFormatterOutput => {
+ const t = useTranslations("/hooks/useDialectFormatter");
+
+ const formatter = useCallback(
+ (dialect: string) => {
+ switch (dialect) {
+ case "樺太":
+ return t("karahuto");
+ case "樺太/西海岸":
+ return t("east_coast");
+ case "樺太/西海岸/小田洲":
+ return t("otasu");
+ case "樺太/西海岸/鵜城":
+ return t("ushiro");
+ case "樺太/西海岸/来知志":
+ return t("raichishi");
+
+ case "北海道":
+ return t("hokkaido");
+ case "北海道/南西":
+ return t("southwest");
+ case "北海道/南西/沙流":
+ return t("saru");
+ case "北海道/南西/千歳":
+ return t("chitose");
+ case "北海道/南西/鵡川":
+ return t("mukawa");
+ case "北海道/南西/幌別":
+ return t("horobetsu");
+ case "北海道/南西/虻田":
+ return t("abuta");
+ case "北海道/南西/白老":
+ return t("shiraoi");
+
+ case "北海道/北東/静内":
+ return t("shizunai");
+ case "北海道/北東/石狩":
+ return t("ishikari");
+ case "北海道/北東/白糠":
+ return t("shiranuka");
+ case "北海道/北東/十勝":
+ return t("tokachi");
+ case "北海道/北東/釧路":
+ return t("kushiro");
+ case "北海道/北東/浦河":
+ return t("urakawa");
+ case "北海道/北東/美幌":
+ return t("bihoro");
+ case "北海道/北東/様似":
+ return t("samani");
+
+ case "北海道/北東":
+ return t("northeast");
+ default:
+ return dialect;
+ }
+ },
+ [t],
+ );
+
+ return formatter;
+};
diff --git a/src/utils/getMostDetailedDialects.spec.ts b/src/utils/getMostDetailedDialects.spec.ts
new file mode 100644
index 0000000..7d9d1db
--- /dev/null
+++ b/src/utils/getMostDetailedDialects.spec.ts
@@ -0,0 +1,12 @@
+import { expect, test } from "vitest";
+import { getMostDetailedDialects } from "./getMostDetailedDialects";
+
+test("getMostDetailedDialects", () => {
+ const dialects = getMostDetailedDialects(
+ ["北海道", "樺太"],
+ ["北海道/南西"],
+ ["北海道/南西/千歳"],
+ );
+
+ expect(dialects).toEqual(["北海道/南西/千歳", "樺太"]);
+});
diff --git a/src/utils/getMostDetailedDialects.ts b/src/utils/getMostDetailedDialects.ts
new file mode 100644
index 0000000..5db390a
--- /dev/null
+++ b/src/utils/getMostDetailedDialects.ts
@@ -0,0 +1,29 @@
+export const getMostDetailedDialects = (
+ lv1: string[],
+ lv2: string[],
+ lv3: string[],
+): string[] => {
+ const dialects: string[] = [];
+
+ for (const d1 of lv1) {
+ if (lv2.some((d2) => d2.startsWith(d1))) {
+ continue;
+ }
+
+ dialects.push(d1);
+ }
+
+ for (const d2 of lv2) {
+ if (lv3.some((d3) => d3.startsWith(d3))) {
+ continue;
+ }
+
+ dialects.push(d2);
+ }
+
+ dialects.push(...lv3);
+
+ dialects.sort();
+
+ return dialects;
+};