feat(i18n) : add personal languages and compact weapon exports
CI / Verify (push) Successful in 1m18s
CI / Build immutable images and deploy (push) Successful in 1m57s

This commit is contained in:
2026-09-14 16:44:44 +07:00 Unverified
parent f214d330f0
commit e0794822b1
72 changed files with 4199 additions and 1011 deletions
+18 -17
View File
@@ -1,5 +1,6 @@
"use client";
import { useTranslation } from "@/components/i18n/locale-provider";
import { searchItems } from "@/lib/search";
import Image from "next/image";
@@ -37,6 +38,7 @@ export function GlossaryManager({
aliases: Alias[];
catalogs: Record<GlossaryKind, CatalogItem[]>;
}) {
const { t } = useTranslation();
const router = useRouter();
const [pending, startTransition] = useTransition();
const [kind, setKind] = useState<GlossaryKind>("character");
@@ -56,11 +58,11 @@ export function GlossaryManager({
const submit = () => startTransition(async () => {
const result = await addGlossaryAlias({ kind, catalogKey: item?.key, alias });
if (result.status === "error") {
toast.error(result.message);
toast.error(t(result.message));
return;
}
setAlias("");
toast.success("เพิ่ม Shortcut แล้ว");
toast.success(t("เพิ่ม Shortcut แล้ว"));
router.refresh();
});
@@ -68,13 +70,13 @@ export function GlossaryManager({
<div className="flex flex-col gap-6">
<Card>
<CardHeader>
<CardTitle>เพิ่ม Shortcut</CardTitle>
<CardDescription>ผูกคำค้นแบบย่อกับรายการจาก Catalog</CardDescription>
<CardTitle>{t("เพิ่ม Shortcut")}</CardTitle>
<CardDescription>{t("ผูกคำค้นแบบย่อกับรายการจาก Catalog")}</CardDescription>
</CardHeader>
<CardContent>
<FieldGroup>
<Field>
<FieldLabel>ประเภท</FieldLabel>
<FieldLabel>{t("ประเภท")}</FieldLabel>
<Select value={kind} onValueChange={(value) => {
setKind(value as GlossaryKind);
setItem(null);
@@ -90,7 +92,7 @@ export function GlossaryManager({
</Select>
</Field>
<Field>
<FieldLabel>รายการ</FieldLabel>
<FieldLabel>{t("รายการ")}</FieldLabel>
<FuzzyCombobox
items={catalogs[kind]}
searchNames={(value) => [value.name, ...aliases.filter((entry) => entry.kind === kind && entry.catalogKey === value.key).map((entry) => entry.alias)]}
@@ -99,9 +101,9 @@ export function GlossaryManager({
itemToStringLabel={(value) => value.name}
itemToStringValue={(value) => value.name}
>
<ComboboxInput placeholder="ค้นหารายการ…" showClear />
<ComboboxInput placeholder={t("ค้นหารายการ…")} showClear />
<ComboboxContent>
<ComboboxEmpty>ไม่พบรายการ</ComboboxEmpty>
<ComboboxEmpty>{t("ไม่พบรายการ")}</ComboboxEmpty>
<ComboboxList>
{(catalogItem) => (
<ComboboxItem key={catalogItem.key} value={catalogItem}>
@@ -119,27 +121,26 @@ export function GlossaryManager({
</FuzzyCombobox>
</Field>
<Field>
<FieldLabel htmlFor="glossary-alias">Shortcut</FieldLabel>
<FieldLabel htmlFor="glossary-alias">{t("Shortcut")}</FieldLabel>
<Input id="glossary-alias" value={alias} maxLength={120} onChange={(event) => setAlias(event.target.value)} onKeyDown={(event) => {
if (event.key === "Enter" && item && alias.trim()) submit();
}} />
</Field>
<Button disabled={pending || !item || !alias.trim()} onClick={submit}>
{pending ? <Spinner data-icon="inline-start" /> : null}
เพิ่ม Shortcut
</Button>
{t("เพิ่ม Shortcut")}</Button>
</FieldGroup>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Glossary</CardTitle>
<CardDescription>{aliases.length} shortcuts</CardDescription>
<CardTitle>{t("Glossary")}</CardTitle>
<CardDescription>{aliases.length} {t("shortcuts")}</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-3">
<Field>
<FieldLabel htmlFor="glossary-search">ค้นหา</FieldLabel>
<FieldLabel htmlFor="glossary-search">{t("ค้นหา")}</FieldLabel>
<div className="relative">
<SearchIcon className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
<Input id="glossary-search" className="pl-9" value={query} onChange={(event) => setQuery(event.target.value)} />
@@ -164,11 +165,11 @@ export function GlossaryManager({
<p className="truncate text-sm text-muted-foreground">{name ?? entry.catalogKey}</p>
</div>
<Badge variant={name ? "secondary" : "outline"}>{name ? kindLabels[entry.kind as GlossaryKind] : "Unavailable"}</Badge>
<Button variant="ghost" size="icon-sm" disabled={pending} aria-label={`ลบ ${entry.alias}`} onClick={() => startTransition(async () => {
<Button variant="ghost" size="icon-sm" disabled={pending} aria-label={t("ลบ {name}", { name: entry.alias })} onClick={() => startTransition(async () => {
const result = await removeGlossaryAlias(entry.id);
if (result.status === "error") toast.error(result.message);
if (result.status === "error") toast.error(t(result.message));
else {
toast.success("ลบ Shortcut แล้ว");
toast.success(t("ลบ Shortcut แล้ว"));
router.refresh();
}
})}><Trash2Icon /></Button>