feat(i18n): add locale dictionaries and pilot surfaces

This commit is contained in:
2026-06-11 04:55:47 +02:00
parent 2c6d6bffcd
commit ac3dfe69cd
15 changed files with 354 additions and 19 deletions
@@ -6,9 +6,14 @@ import { useState } from "react"
import { useForm } from "react-hook-form"
import { signInAction } from "@/actions/auth.actions"
import { Button } from "@/components/ui/button"
import type { Dictionary } from "@/i18n/dictionaries"
import { type SignInFormType, signInSchema } from "@/schemas/auth.schema"
export default function SignInForm() {
type SignInFormProps = {
copy: Dictionary["login"]
}
export default function SignInForm({ copy }: SignInFormProps) {
const router = useRouter()
const searchParams = useSearchParams()
const callbackUrl = searchParams.get("callbackUrl")
@@ -37,7 +42,7 @@ export default function SignInForm() {
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<label className="flex flex-col gap-1">
Username
{copy.usernameLabel}
<input
{...register("username")}
name="username"
@@ -49,7 +54,7 @@ export default function SignInForm() {
)}
</label>
<label className="flex flex-col gap-1">
Password
{copy.passwordLabel}
<input
{...register("password")}
name="password"
@@ -61,7 +66,7 @@ export default function SignInForm() {
)}
</label>
{error && <p className="text-error">{error}</p>}
<Button type="submit">Sign In</Button>
<Button type="submit">{copy.submitLabel}</Button>
</form>
)
}
+8 -2
View File
@@ -1,6 +1,7 @@
import { redirect } from "next/navigation"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { getI18n } from "@/i18n/server"
import { auth } from "@/lib/auth"
import SignInForm from "./_components/login-form"
@@ -10,15 +11,20 @@ export default async function LoginPage() {
if (session) redirect("/")
const { dictionary } = await getI18n()
const copy = dictionary.login
return (
<div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
<div className="w-full max-w-sm">
<Card>
<CardHeader>
<CardTitle>Sign In</CardTitle>
<CardTitle>
<h1>{copy.title}</h1>
</CardTitle>
</CardHeader>
<CardContent>
<SignInForm />
<SignInForm copy={copy} />
</CardContent>
</Card>
</div>
@@ -3,11 +3,13 @@ import Link from "next/link"
export default function Card({
title,
total,
countLabel,
icon,
href,
}: {
title: string
total: number
countLabel: string
icon: React.ReactNode
href: string
}) {
@@ -18,7 +20,9 @@ export default function Card({
<div className="mr-4">{icon}</div>
<div>
<h3 className="text-lg font-medium">{title}</h3>
<p className="text-muted-foreground mt-2 text-sm">Total: {total}</p>
<p className="text-muted-foreground mt-2 text-sm">
{countLabel}: {total}
</p>
</div>
</div>
</div>
+10 -4
View File
@@ -1,3 +1,4 @@
import { getI18n } from "@/i18n/server"
import { AssetService } from "@/services/asset.service"
import { ItemService } from "@/services/item.service"
import { RecipientService } from "@/services/recipient.service"
@@ -5,17 +6,20 @@ import { RecipientService } from "@/services/recipient.service"
import Card from "./_components/card"
export default async function Home() {
const { dictionary } = await getI18n()
const copy = dictionary.dashboardHome
const totalItems = await ItemService.findAllItemsCount()
const totalAssets = await AssetService.findAllAssetsCount()
const totalRecipients = await RecipientService.findAllRecipientsCount()
return (
<div className="container mx-auto p-4">
<h1 className="mb-4 text-2xl font-bold">Dashboard</h1>
<h1 className="mb-4 text-2xl font-bold">{copy.heading}</h1>
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
<Card
title="Total Items"
title={copy.cards.items.title}
total={totalItems}
countLabel={copy.cards.items.countLabel}
href="/inventory/items"
icon={
<svg
@@ -37,8 +41,9 @@ export default async function Home() {
}
/>
<Card
title="Total Assets"
title={copy.cards.assets.title}
total={totalAssets}
countLabel={copy.cards.assets.countLabel}
href="/inventory/assets"
icon={
<svg
@@ -60,8 +65,9 @@ export default async function Home() {
}
/>
<Card
title="Total Recipients"
title={copy.cards.recipients.title}
total={totalRecipients}
countLabel={copy.cards.recipients.countLabel}
href="/recipients"
icon={
<svg
+5 -2
View File
@@ -2,6 +2,7 @@ import "@/styles/globals.css"
import type { Metadata } from "next"
import { Geist, Geist_Mono } from "next/font/google"
import { getI18n } from "@/i18n/server"
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -18,13 +19,15 @@ export const metadata: Metadata = {
description: "Manage your inventory with ease",
}
export default function RootLayout({
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
const { locale } = await getI18n()
return (
<html lang="en">
<html lang={locale}>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>