Apply i18n to client components

This commit is contained in:
Takeshi Kimata
2024-05-03 17:39:07 +09:00
parent 72c71efedc
commit e25acad76c
8 changed files with 146 additions and 83 deletions

View File

@@ -3,21 +3,21 @@
"title": "Hello world!"
},
"Projects": {
"projects": "プロジェクト",
"project": "プロジェクト",
"new_project": "新規プロジェクト",
"edit_project": "プロジェクトの編集",
"delete_project": "プロジェクトの削除",
"projects": "Projects",
"project": "Project",
"new_project": "New Project",
"edit_project": "Edit Project",
"delete_project": "Delete Project",
"id": "ID",
"name": "名前",
"detail": "詳細",
"last_update": "最終更新",
"actions": "アクション",
"project_name": "プロジェクト名",
"project_detail": "プロジェクト詳細",
"close": "閉じる",
"create": "作成",
"update": "作成",
"please_enter": "プロジェクト名を入力してください"
"name": "Name",
"detail": "Detail",
"last_update": "Last update",
"actions": "Actions",
"project_name": "Project Name",
"project_detail": "Project Detail",
"close": "Close",
"create": "Create",
"update": "Update",
"please_enter": "Please enter project name"
}
}

View File

@@ -3,21 +3,21 @@
"title": "はろー"
},
"Projects": {
"projects": "Projects",
"project": "Project",
"new_project": "New Project",
"edit_project": "Edit Project",
"delete_project": "Delete Project",
"projects": "プロジェクト",
"project": "プロジェクト",
"new_project": "新規プロジェクト",
"edit_project": "プロジェクトの編集",
"delete_project": "プロジェクトの削除",
"id": "ID",
"name": "Name",
"detail": "Detail",
"last_update": "Last update",
"actions": "Actions",
"project_name": "Project Name",
"project_detail": "Project Detail",
"close": "Close",
"create": "Create",
"update": "Update",
"please_enter": "Please enter project name"
"name": "名前",
"detail": "詳細",
"last_update": "最終更新",
"actions": "アクション",
"project_name": "プロジェクト名",
"project_detail": "プロジェクト詳細",
"close": "閉じる",
"create": "作成",
"update": "更新",
"please_enter": "プロジェクト名を入力してください"
}
}

View File

@@ -1,7 +1,6 @@
import {
Navbar as NextUINavbar,
NavbarContent,
NavbarMenuToggle,
NavbarBrand,
NavbarItem,
Link as NextUiLink
@@ -36,7 +35,20 @@ export default function Header(params: { locale: string }) {
<p className="font-bold text-inherit">Test Case Manager</p>
</Link>
</NavbarBrand>
{siteConfig.navItems.map((item) => (
<ul className="hidden lg:flex gap-4 justify-start ml-2">
{siteConfig.navItems.map((item) => (
<NavbarItem key={item.href}>
<Link
className="data-[active=true]:text-primary data-[active=true]:font-medium"
href={item.href}
locale={params.locale}
>
{item.label}
</Link>
</NavbarItem>
))}
</ul>
{/* {siteConfig.navItems.map((item) => (
<NavbarItem key={item.href}>
<Link
className="data-[active=true]:text-primary data-[active=true]:font-medium"
@@ -46,7 +58,7 @@ export default function Header(params: { locale: string }) {
{item.label}
</Link>
</NavbarItem>
))}
))} */}
</NavbarContent>
<NavbarContent className="basis-1 pl-4" justify="end">

View File

@@ -11,13 +11,14 @@ import {
ModalBody,
ModalFooter,
} from "@nextui-org/react";
import { ProjectType } from "@/types/project";
import { ProjectType, ProjectsMessages } from "@/types/project";
type Props = {
isOpen: boolean;
editingProject: ProjectType;
onCancel: () => void;
onSubmit: (name: string, detail: string) => void;
messages: ProjectsMessages;
};
export default function ProjectDialog({
@@ -25,6 +26,7 @@ export default function ProjectDialog({
editingProject,
onCancel,
onSubmit,
messages,
}: Props) {
const [projectName, setProjectName] = useState({
text: editingProject ? editingProject.name : "",
@@ -80,7 +82,7 @@ export default function ProjectDialog({
setProjectName({
text: "",
isValid: false,
errorMessage: "Please enter project name",
errorMessage: messages.pleaseEnter,
});
return;
@@ -98,11 +100,13 @@ export default function ProjectDialog({
}}
>
<ModalContent>
<ModalHeader className="flex flex-col gap-1">Project</ModalHeader>
<ModalHeader className="flex flex-col gap-1">
{messages.project}
</ModalHeader>
<ModalBody>
<Input
type="text"
label="Project Name"
label={messages.projectName}
value={projectName.text}
isInvalid={projectName.isValid}
errorMessage={projectName.errorMessage}
@@ -114,7 +118,7 @@ export default function ProjectDialog({
}}
/>
<Textarea
label="Project Detail"
label={messages.projectDetail}
value={projectDetail.text}
isInvalid={projectDetail.isValid}
errorMessage={projectDetail.errorMessage}
@@ -128,10 +132,10 @@ export default function ProjectDialog({
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onCancel}>
Close
{messages.close}
</Button>
<Button color="primary" onPress={validate}>
{editingProject ? "Update" : "Create"}
{editingProject ? messages.update : messages.create}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,8 +1,8 @@
// "use client";
"use client";
import { useEffect, useState } from "react";
import { Button } from "@nextui-org/react";
import { Plus } from "lucide-react";
import { ProjectType } from "@/types/project";
import { ProjectType, ProjectsMessages } from "@/types/project";
import ProjectsTable from "./ProjectsTable";
import ProjectDialog from "./ProjectDialog";
import {
@@ -11,10 +11,12 @@ import {
updateProject,
deleteProject,
} from "./projectsControl";
import { useTranslations } from "next-intl";
export default function ProjectsPage() {
const t = useTranslations("ProjectsPage");
export type Props = {
messages: ProjectsMessages;
};
export default function ProjectsPage({ messages }: Props) {
const [projects, setProjects] = useState([]);
useEffect(() => {
@@ -78,33 +80,37 @@ export default function ProjectsPage() {
};
return (
<div className="container mx-auto max-w-3xl pt-16 px-6 flex-grow">
<div className="w-full p-3 flex items-center justify-between">
<h3 className="font-bold">{t("project.project")}</h3>
<div>
<Button
startContent={<Plus size={16} />}
size="sm"
color="primary"
onClick={openDialogForCreate}
>
{t("newProject")}
</Button>
<div className="flex justify-center">
<div className="container mx-auto max-w-3xl pt-16 px-6 flex-grow">
<div className="w-full p-3 flex items-center justify-between">
<h3 className="font-bold">{messages.project}</h3>
<div>
<Button
startContent={<Plus size={16} />}
size="sm"
color="primary"
onClick={openDialogForCreate}
>
{messages.newProject}
</Button>
</div>
</div>
<ProjectsTable
projects={projects}
onEditProject={onEditClick}
onDeleteProject={onDeleteClick}
messages={messages}
/>
<ProjectDialog
isOpen={isProjectDialogOpen}
editingProject={editingProject}
onCancel={closeDialog}
onSubmit={onSubmit}
messages={messages}
/>
</div>
<ProjectsTable
projects={projects}
onEditProject={onEditClick}
onDeleteProject={onDeleteClick}
/>
<ProjectDialog
isOpen={isProjectDialogOpen}
editingProject={editingProject}
onCancel={closeDialog}
onSubmit={onSubmit}
/>
</div>
);
}

View File

@@ -15,28 +15,30 @@ import {
Link,
} from "@nextui-org/react";
import { MoreVertical } from "lucide-react";
import { ProjectType } from "@/types/project";
import { ProjectType, ProjectsMessages } from "@/types/project";
import dayjs from "dayjs";
const headerColumns = [
{ name: "ID", uid: "id", sortable: true },
{ name: "Name", uid: "name", sortable: true },
{ name: "Detail", uid: "detail", sortable: true },
{ name: "Last update", uid: "updatedAt", sortable: true },
{ name: "Actions", uid: "actions" },
];
type Props = {
projects: ProjectType[];
onEditProject: (project: ProjectType) => void;
onDeleteProject: (projectId: number) => void;
messages: ProjectsMessages;
};
export default function ProjectsTable({
projects,
onEditProject,
onDeleteProject,
messages,
}: Props) {
const headerColumns = [
{ name: messages.id, uid: "id", sortable: true },
{ name: messages.name, uid: "name", sortable: true },
{ name: messages.detail, uid: "detail", sortable: true },
{ name: messages.lastUpdate, uid: "updatedAt", sortable: true },
{ name: messages.actions, uid: "actions" },
];
const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
column: "id",
direction: "ascending",
@@ -92,13 +94,13 @@ export default function ProjectsTable({
</DropdownTrigger>
<DropdownMenu aria-label="project actions">
<DropdownItem onClick={() => onEditProject(project)}>
Edit project
{messages.editProject}
</DropdownItem>
<DropdownItem
className="text-danger"
onClick={() => onDeleteProject(project.id)}
>
Delete project
{messages.deleteProject}
</DropdownItem>
</DropdownMenu>
</Dropdown>

View File

@@ -1,9 +1,29 @@
import ProjectsPage from "./ProjectsPage";
import { useTranslations } from "next-intl";
export default function Page() {
const t = useTranslations("Projects");
const messages = {
projects: t("projects"),
project: t("project"),
newProject: t("new_project"),
editProject: t("edit_project"),
deleteProject: t("delete_project"),
id: t("id"),
name: t("name"),
detail: t("detail"),
lastUpdate: t("last_update"),
actions: t("actions"),
projectName: t("project_name"),
projectDetail: t("project_detail"),
close: t("close"),
create: t("create"),
update: t("update"),
pleaseEnter: t("please_enter"),
};
return (
<>
<ProjectsPage />
<ProjectsPage messages={messages} />
</>
);
}

View File

@@ -4,4 +4,23 @@ export type ProjectType = {
detail: string;
createdAt: string;
updatedAt: string;
};
};
export type ProjectsMessages = {
project: string;
projects: string;
newProject: string;
editProject: string;
deleteProject: string;
id: string;
name: string;
detail: string;
lastUpdate: string;
actions: string;
projectName: string;
projectDetail: string;
close: string;
create: string;
update: string;
pleaseEnter: string;
};