feat: add missing i18n in sign up and login in page,add i18n in table.tsx

This commit is contained in:
fly6516 2025-04-14 16:47:13 +08:00
parent 983c66bdbb
commit 55a9d79965
5 changed files with 98 additions and 35 deletions

View File

@ -4,7 +4,8 @@
"Enter your email below to sign in to your account": "Enter your email below to sign in to your account", "Enter your email below to sign in to your account": "Enter your email below to sign in to your account",
"Or": "Or", "Or": "Or",
"Don't have an account?": "Don't have an account?", "Don't have an account?": "Don't have an account?",
"Sign up": "Sign up" "sign-up": "Sign up",
"signing-in": "Signing In..."
}, },
"sign-up-form": { "sign-up-form": {
"title": "Hello world!", "title": "Hello world!",
@ -12,7 +13,8 @@
"sign-up-to-your-account": "Sign up to your account", "sign-up-to-your-account": "Sign up to your account",
"or": "Or", "or": "Or",
"already-have-an-account": "Already have an account?", "already-have-an-account": "Already have an account?",
"sign-in": "Sign in" "sign-in": "Sign in",
"creating-account": "Creating Account..."
}, },
"appearance-settings": { "appearance-settings": {
"choose-a-theme": "Choose a theme", "choose-a-theme": "Choose a theme",
@ -71,5 +73,33 @@
"test": { "test": {
"case": "Case", "case": "Case",
"failed-to-submit-the-form-please-try-again": "Failed to submit the form. Please try again." "failed-to-submit-the-form-please-try-again": "Failed to submit the form. Please try again."
},
"problemset": {
"select-all": "Select all",
"select-row": "Select row",
"title": "Title",
"difficulty": "Difficulty",
"actions": "Actions",
"displayid-or-title": "DisplayId or Title...",
"filter-by-displayid-or-title": "Filter by displayId or title",
"clear-filter": "Clear filter",
"filters": "Filters",
"view": "View",
"toggle-columns": "Toggle columns",
"delete": "Delete",
"are-you-absolutely-sure": "Are you absolutely sure?",
"this-action-cannot-be-undone-this-will-permanently-delete": "This action cannot be undone. This will permanently delete",
"cancel": "Cancel",
"add-problem": "Add Problem",
"enter": "Enter",
"no-results": "No results.",
"rows-per-page": "Rows per page",
"select-number-of-results": "Select number of results",
"go-to-first-page": "Go to first page",
"go-to-previous-page": "Go to previous page",
"go-to-next-page": "Go to next page",
"go-to-last-page": "Go to last page",
"edit-item": "Edit item",
"edit": "Edit"
} }
} }

View File

@ -4,7 +4,8 @@
"Enter your email below to sign in to your account": "在下方输入你的邮箱以登录", "Enter your email below to sign in to your account": "在下方输入你的邮箱以登录",
"Or": "或", "Or": "或",
"Don't have an account?": "没有帐户?", "Don't have an account?": "没有帐户?",
"Sign up": "注册" "sign-up": "注册",
"signing-in": "正在登录。。。"
}, },
"sign-up-form": { "sign-up-form": {
"title": "Hello world!", "title": "Hello world!",
@ -12,7 +13,8 @@
"enter-your-email-below-to-sign-up-to-your-account": "在下面输入您的电子邮件以注册您的帐户", "enter-your-email-below-to-sign-up-to-your-account": "在下面输入您的电子邮件以注册您的帐户",
"or": "或", "or": "或",
"sign-in": "登录", "sign-in": "登录",
"sign-up-to-your-account": "注册您的帐户" "sign-up-to-your-account": "注册您的帐户",
"creating-account": "正在创建帐户。。。"
}, },
"appearance-settings": { "appearance-settings": {
"dark": "暗", "dark": "暗",
@ -71,5 +73,33 @@
"test": { "test": {
"case": "样例", "case": "样例",
"failed-to-submit-the-form-please-try-again": "提交失败。请重试。" "failed-to-submit-the-form-please-try-again": "提交失败。请重试。"
},
"problemset": {
"actions": "行动",
"add-problem": "添加问题",
"are-you-absolutely-sure": "你真的确定吗?",
"cancel": "取消",
"clear-filter": "清除过滤器",
"enter": "进入",
"filter-by-displayid-or-title": "按显示ID或标题筛选",
"filters": "过滤器",
"go-to-first-page": "转到第一页",
"go-to-last-page": "转到最后一页",
"select-number-of-results": "选择结果数量",
"select-row": "选定行",
"this-action-cannot-be-undone-this-will-permanently-delete": "此操作无法撤消。这将永久删除",
"title": "名称",
"toggle-columns": "切换列",
"delete": "删除",
"difficulty": "难度",
"displayid-or-title": "显示ID或标题。。。",
"edit": "编辑",
"edit-item": "编辑项目",
"view": "视图",
"go-to-next-page": "转到下一页",
"go-to-previous-page": "转到上一页",
"no-results": "没有结果。",
"rows-per-page": "每页行数",
"select-all": "选择全部"
} }
} }

View File

@ -112,7 +112,7 @@ export function CredentialsSignInForm() {
/> />
<Button type="submit" disabled={isPending} className="w-full"> <Button type="submit" disabled={isPending} className="w-full">
{isPending ? "Signing In..." : "Sign In"} {isPending ? t('sign-in-form.signing-in'): t('sign-up-form.sign-in')}
</Button> </Button>
</form> </form>
</Form> </Form>

View File

@ -117,7 +117,7 @@ export function CredentialsSignUpForm() {
/> />
<Button type="submit" disabled={isPending} className="w-full"> <Button type="submit" disabled={isPending} className="w-full">
{isPending ? "Creating Account..." : "Sign Up"} {isPending ? t('sign-up-form.creating-account'): t('sign-in-form.sign-up')}
</Button> </Button>
</form> </form>
</Form> </Form>

View File

@ -83,9 +83,12 @@ import { Checkbox } from "@/components/ui/checkbox";
import { Difficulty, Problem } from "@/generated/client"; import { Difficulty, Problem } from "@/generated/client";
import { cn, getDifficultyColorClass } from "@/lib/utils"; import { cn, getDifficultyColorClass } from "@/lib/utils";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { useTranslations } from "next-intl";
type ProblemTableItem = Pick<Problem, "id" | "displayId" | "title" | "difficulty">; type ProblemTableItem = Pick<Problem, "id" | "displayId" | "title" | "difficulty">;
const t = useTranslations('problemset');
interface ProblemTableProps { interface ProblemTableProps {
data: ProblemTableItem[]; data: ProblemTableItem[];
} }
@ -117,14 +120,14 @@ const columns: ColumnDef<ProblemTableItem>[] = [
(table.getIsSomePageRowsSelected() && "indeterminate") (table.getIsSomePageRowsSelected() && "indeterminate")
} }
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all" aria-label= {t('select-all')}
/> />
), ),
cell: ({ row }) => ( cell: ({ row }) => (
<Checkbox <Checkbox
checked={row.getIsSelected()} checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)} onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row" aria-label= {t('select-row')}
/> />
), ),
size: 28, size: 28,
@ -140,12 +143,12 @@ const columns: ColumnDef<ProblemTableItem>[] = [
enableHiding: false, enableHiding: false,
}, },
{ {
header: "Title", header: t('title'),
accessorKey: "title", accessorKey: "title",
cell: ({ row }) => <div className="font-medium">{row.getValue("title")}</div>, cell: ({ row }) => <div className="font-medium">{row.getValue("title")}</div>,
}, },
{ {
header: "Difficulty", header: t('difficulty'),
accessorKey: "difficulty", accessorKey: "difficulty",
cell: ({ row }) => { cell: ({ row }) => {
const difficulty = row.getValue("difficulty") as Difficulty; const difficulty = row.getValue("difficulty") as Difficulty;
@ -160,7 +163,7 @@ const columns: ColumnDef<ProblemTableItem>[] = [
}, },
{ {
id: "actions", id: "actions",
header: () => <span className="sr-only">Actions</span>, header: () => <span className="sr-only">t('actions')</span>,
cell: () => <RowActions />, cell: () => <RowActions />,
enableHiding: false, enableHiding: false,
}, },
@ -262,9 +265,9 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
onChange={(e) => onChange={(e) =>
table.getColumn("displayId")?.setFilterValue(e.target.value) table.getColumn("displayId")?.setFilterValue(e.target.value)
} }
placeholder="DisplayId or Title..." placeholder={t('displayid-or-title')}
type="text" type="text"
aria-label="Filter by displayId or title" aria-label={t('filter-by-displayid-or-title')}
/> />
<div className="text-muted-foreground/80 pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 peer-disabled:opacity-50"> <div className="text-muted-foreground/80 pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 peer-disabled:opacity-50">
<ListFilterIcon size={16} aria-hidden="true" /> <ListFilterIcon size={16} aria-hidden="true" />
@ -272,7 +275,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
{Boolean(table.getColumn("displayId")?.getFilterValue()) && ( {Boolean(table.getColumn("displayId")?.getFilterValue()) && (
<button <button
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50" className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
aria-label="Clear filter" aria-label={t('clear-filter')}
onClick={() => { onClick={() => {
table.getColumn("displayId")?.setFilterValue(""); table.getColumn("displayId")?.setFilterValue("");
if (inputRef.current) { if (inputRef.current) {
@ -292,7 +295,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
size={16} size={16}
aria-hidden="true" aria-hidden="true"
/> />
Difficulty {t('difficulty')}
{selectedDifficulties.length > 0 && ( {selectedDifficulties.length > 0 && (
<span className="bg-background text-muted-foreground/70 -me-1 inline-flex h-5 max-h-full items-center rounded border px-1 font-[inherit] text-[0.625rem] font-medium"> <span className="bg-background text-muted-foreground/70 -me-1 inline-flex h-5 max-h-full items-center rounded border px-1 font-[inherit] text-[0.625rem] font-medium">
{selectedDifficulties.length} {selectedDifficulties.length}
@ -303,7 +306,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
<PopoverContent className="w-auto min-w-36 p-3" align="start"> <PopoverContent className="w-auto min-w-36 p-3" align="start">
<div className="space-y-3"> <div className="space-y-3">
<div className="text-muted-foreground text-xs font-medium"> <div className="text-muted-foreground text-xs font-medium">
Filters {t('filters')}
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
{uniqueDifficultyValues.map((value) => ( {uniqueDifficultyValues.map((value) => (
@ -334,11 +337,11 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
size={16} size={16}
aria-hidden="true" aria-hidden="true"
/> />
View {t('view')}
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel> <DropdownMenuLabel>{t('toggle-columns')}</DropdownMenuLabel>
{table {table
.getAllColumns() .getAllColumns()
.filter((column) => column.getCanHide()) .filter((column) => column.getCanHide())
@ -370,7 +373,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
size={16} size={16}
aria-hidden="true" aria-hidden="true"
/> />
Delete {t('delete')}
<span className="bg-background text-muted-foreground/70 -me-1 inline-flex h-5 max-h-full items-center rounded border px-1 font-[inherit] text-[0.625rem] font-medium"> <span className="bg-background text-muted-foreground/70 -me-1 inline-flex h-5 max-h-full items-center rounded border px-1 font-[inherit] text-[0.625rem] font-medium">
{table.getSelectedRowModel().rows.length} {table.getSelectedRowModel().rows.length}
</span> </span>
@ -386,10 +389,10 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
</div> </div>
<AlertDialogHeader> <AlertDialogHeader>
<AlertDialogTitle> <AlertDialogTitle>
Are you absolutely sure? {t('are-you-absolutely-sure')}
</AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
This action cannot be undone. This will permanently delete{" "} {t('this-action-cannot-be-undone-this-will-permanently-delete')}{" "}
{table.getSelectedRowModel().rows.length} selected{" "} {table.getSelectedRowModel().rows.length} selected{" "}
{table.getSelectedRowModel().rows.length === 1 {table.getSelectedRowModel().rows.length === 1
? "row" ? "row"
@ -399,9 +402,9 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
</AlertDialogHeader> </AlertDialogHeader>
</div> </div>
<AlertDialogFooter> <AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
<AlertDialogAction onClick={handleDeleteRows}> <AlertDialogAction onClick={handleDeleteRows}>
Delete {t('delete')}
</AlertDialogAction> </AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
</AlertDialogContent> </AlertDialogContent>
@ -414,7 +417,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
size={16} size={16}
aria-hidden="true" aria-hidden="true"
/> />
Add Problem {t('add-problem')}
</Link> </Link>
</Button> </Button>
</div> </div>
@ -439,7 +442,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
onKeyDown={(e) => { onKeyDown={(e) => {
if ( if (
header.column.getCanSort() && header.column.getCanSort() &&
(e.key === "Enter" || e.key === " ") (e.key === t('enter') || e.key === " ")
) { ) {
e.preventDefault(); e.preventDefault();
header.column.getToggleSortingHandler()?.(e); header.column.getToggleSortingHandler()?.(e);
@ -499,7 +502,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. {t('problemset.no-results')}
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}
@ -508,7 +511,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
</div> </div>
<div className="flex items-center justify-between gap-8"> <div className="flex items-center justify-between gap-8">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Label className="max-sm:sr-only">Rows per page</Label> <Label className="max-sm:sr-only">{t('rows-per-page')}</Label>
<Select <Select
value={table.getState().pagination.pageSize.toString()} value={table.getState().pagination.pageSize.toString()}
onValueChange={(value) => { onValueChange={(value) => {
@ -516,7 +519,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
}} }}
> >
<SelectTrigger className="w-fit whitespace-nowrap"> <SelectTrigger className="w-fit whitespace-nowrap">
<SelectValue placeholder="Select number of results" /> <SelectValue placeholder={t('problemset.select-number-of-results')} />
</SelectTrigger> </SelectTrigger>
<SelectContent className="[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2"> <SelectContent className="[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2">
{[5, 10, 25, 50].map((pageSize) => ( {[5, 10, 25, 50].map((pageSize) => (
@ -563,7 +566,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
className="disabled:pointer-events-none disabled:opacity-50" className="disabled:pointer-events-none disabled:opacity-50"
onClick={() => table.firstPage()} onClick={() => table.firstPage()}
disabled={!table.getCanPreviousPage()} disabled={!table.getCanPreviousPage()}
aria-label="Go to first page" aria-label={t('go-to-first-page')}
> >
<ChevronFirstIcon size={16} aria-hidden="true" /> <ChevronFirstIcon size={16} aria-hidden="true" />
</Button> </Button>
@ -575,7 +578,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
className="disabled:pointer-events-none disabled:opacity-50" className="disabled:pointer-events-none disabled:opacity-50"
onClick={() => table.previousPage()} onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()} disabled={!table.getCanPreviousPage()}
aria-label="Go to previous page" aria-label={t('go-to-previous-page')}
> >
<ChevronLeftIcon size={16} aria-hidden="true" /> <ChevronLeftIcon size={16} aria-hidden="true" />
</Button> </Button>
@ -587,7 +590,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
className="disabled:pointer-events-none disabled:opacity-50" className="disabled:pointer-events-none disabled:opacity-50"
onClick={() => table.nextPage()} onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()} disabled={!table.getCanNextPage()}
aria-label="Go to next page" aria-label={t('go-to-next-page')}
> >
<ChevronRightIcon size={16} aria-hidden="true" /> <ChevronRightIcon size={16} aria-hidden="true" />
</Button> </Button>
@ -599,7 +602,7 @@ export function ProblemsetTable({ data }: ProblemTableProps) {
className="disabled:pointer-events-none disabled:opacity-50" className="disabled:pointer-events-none disabled:opacity-50"
onClick={() => table.lastPage()} onClick={() => table.lastPage()}
disabled={!table.getCanNextPage()} disabled={!table.getCanNextPage()}
aria-label="Go to last page" aria-label={t('go-to-last-page')}
> >
<ChevronLastIcon size={16} aria-hidden="true" /> <ChevronLastIcon size={16} aria-hidden="true" />
</Button> </Button>
@ -621,7 +624,7 @@ function RowActions() {
size="icon" size="icon"
variant="ghost" variant="ghost"
className="shadow-none" className="shadow-none"
aria-label="Edit item" aria-label={t('edit-item')}
> >
<EllipsisIcon size={16} aria-hidden="true" /> <EllipsisIcon size={16} aria-hidden="true" />
</Button> </Button>
@ -630,12 +633,12 @@ function RowActions() {
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuGroup> <DropdownMenuGroup>
<DropdownMenuItem> <DropdownMenuItem>
<span>Edit</span> <span>{t('edit')}</span>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuGroup> </DropdownMenuGroup>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem className="text-destructive focus:text-destructive"> <DropdownMenuItem className="text-destructive focus:text-destructive">
<span>Delete</span> <span>{t('delete')}</span>
<DropdownMenuShortcut></DropdownMenuShortcut> <DropdownMenuShortcut></DropdownMenuShortcut>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>