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
+31 -30
View File
@@ -1,5 +1,6 @@
"use client";
import { useTranslation } from "@/components/i18n/locale-provider";
import {
GripHorizontalIcon,
GripVerticalIcon,
@@ -118,6 +119,7 @@ function InlineDataEditor({
cell,
onChange,
}: DataEditorProps<{ value: string }>) {
const { t } = useTranslation();
const inputRef = useRef<HTMLInputElement>(null);
const text = useMemo(() => {
const document = new DOMParser().parseFromString(
@@ -138,7 +140,7 @@ function InlineDataEditor({
<input
ref={inputRef}
type="text"
aria-label="แก้ไขข้อความเซลล์"
aria-label={t("แก้ไขข้อความเซลล์")}
value={text}
onChange={(event) => onChange({ ...cell, value: event.target.value })}
/>
@@ -153,6 +155,7 @@ function EditableColumnIndicator({
selected,
onRename,
}: ColumnIndicatorProps & { id: string; onRename: (column: number) => void }) {
const { t } = useTranslation();
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id,
strategy: horizontalListSortingStrategy,
@@ -168,7 +171,7 @@ function EditableColumnIndicator({
variant="ghost"
size="icon-sm"
className="touch-none"
aria-label={`ลากเพื่อย้าย ${String(label ?? `คอลัมน์ ${column + 1}`)}`}
aria-label={t("ลากเพื่อย้าย {name}", { name: String(label ?? `คอลัมน์ ${column + 1}`) })}
{...attributes}
{...listeners}
>
@@ -188,6 +191,7 @@ function EditableColumnIndicator({
}
function SortableRowIndicator({ id, row, label, selected, onSelect }: RowIndicatorProps & { id: string }) {
const { t } = useTranslation();
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id,
strategy: verticalListSortingStrategy,
@@ -203,7 +207,7 @@ function SortableRowIndicator({ id, row, label, selected, onSelect }: RowIndicat
variant="ghost"
size="icon-sm"
className="touch-none"
aria-label={`ลากเพื่อย้ายแถว ${row + 1}`}
aria-label={t("ลากเพื่อย้ายแถว {index}", { index: row + 1 })}
{...attributes}
{...listeners}
>
@@ -233,6 +237,7 @@ export function ExtraSheetEditor({
onChange: (value: ExtraSheet) => void;
onRemove: () => void;
}) {
const { t } = useTranslation();
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
@@ -412,29 +417,29 @@ export function ExtraSheetEditor({
return (
<div
className="flex min-w-0 flex-col gap-3"
aria-label="ตารางข้อมูลเสริม"
aria-label={t("ตารางข้อมูลเสริม")}
onKeyDown={handleSheetKeyDown}
>
<div className="flex flex-wrap items-center gap-2">
<SimpleTooltip text={<>ย้อนกลับ <Kbd>Ctrl/⌘ Z</Kbd></>}>
<SimpleTooltip text={<>{t("ย้อนกลับ")}<Kbd>{t("Ctrl/⌘ Z")}</Kbd></>}>
<Button
type="button"
variant="ghost"
size="icon-sm"
disabled={!canUndo}
aria-label="ย้อนกลับการแก้ไขตาราง"
aria-label={t("ย้อนกลับการแก้ไขตาราง")}
onClick={() => travel(-1)}
>
<Undo2Icon />
</Button>
</SimpleTooltip>
<SimpleTooltip text={<>ทำซ้ำ <Kbd>Ctrl/⌘ Shift Z</Kbd></>}>
<SimpleTooltip text={<>{t("ทำซ้ำ")}<Kbd>{t("Ctrl/⌘ Shift Z")}</Kbd></>}>
<Button
type="button"
variant="ghost"
size="icon-sm"
disabled={!canRedo}
aria-label="ทำซ้ำการแก้ไขตาราง"
aria-label={t("ทำซ้ำการแก้ไขตาราง")}
onClick={() => travel(1)}
>
<Redo2Icon />
@@ -451,24 +456,22 @@ export function ExtraSheetEditor({
}}
>
<PlusIcon data-icon="inline-start" />
เพิ่มแถว
</Button>
{t("เพิ่มแถว")}</Button>
<Button type="button" variant="outline" size="sm" onClick={openAddColumn}>
<PlusIcon data-icon="inline-start" />
เพิ่มคอลัมน์
</Button>
{t("เพิ่มคอลัมน์")}</Button>
<Button type="button" variant="outline" size="sm" onClick={openActiveCellEditor}>
<PencilIcon data-icon="inline-start" />
แก้ไข {selectedCount > 1 ? `${selectedCount} เซลล์` : "เซลล์"}
{t("แก้ไข")}{" "}{selectedCount > 1 ? t("{count} เซลล์", { count: selectedCount }) : t("เซลล์")}
</Button>
<label className="relative">
<Button type="button" variant="outline" size="sm" render={<span />} nativeButton={false}>
<PaletteIcon data-icon="inline-start" />
สีพื้นหลัง {selectedCount > 1 ? `${selectedCount} เซลล์` : "เซลล์"}
{t("สีพื้นหลัง")}{" "}{selectedCount > 1 ? t("{count} เซลล์", { count: selectedCount }) : t("เซลล์")}
</Button>
<input
type="color"
aria-label="เลือกสีพื้นหลังเซลล์"
aria-label={t("เลือกสีพื้นหลังเซลล์")}
className="absolute inset-0 cursor-pointer opacity-0"
value={activeRow?.backgrounds?.[activeColumn?.id ?? ""] ?? DEFAULT_CELL_BACKGROUND}
onChange={(event) => {
@@ -486,12 +489,10 @@ export function ExtraSheetEditor({
size="sm"
onClick={() => commitSheet(updateExtraSheetCells(value, selectedPointsRef.current, { backgroundColor: null }))}
>
ล้างสีพื้นหลัง
</Button>
{t("ล้างสีพื้นหลัง")}</Button>
<Button type="button" variant="ghost" size="sm" onClick={() => setRemoveOpen(true)}>
<Trash2Icon data-icon="inline-start" />
ลบตาราง
</Button>
{t("ลบตาราง")}</Button>
</div>
<div
@@ -549,11 +550,11 @@ export function ExtraSheetEditor({
<Dialog open={cellDialogOpen} onOpenChange={setCellDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>แก้ไขเซลล์</DialogTitle>
<DialogTitle>{t("แก้ไขเซลล์")}</DialogTitle>
<DialogDescription>
{selectedCount > 1
? `การแก้ข้อความจะแทนที่ทั้ง ${selectedCount} เซลล์ แต่การเปลี่ยนรูปแบบจะเก็บข้อความเดิมของแต่ละเซลล์`
: `แถว ${active.row + 1} · ${activeColumn?.label ?? "คอลัมน์"}`}
? t("การแก้ข้อความจะแทนที่ทั้ง {count} เซลล์ แต่การเปลี่ยนรูปแบบจะเก็บข้อความเดิมของแต่ละเซลล์", { count: selectedCount })
: t("แถว {index} · {name}", { index: active.row + 1, name: activeColumn?.label ?? "คอลัมน์" })}
</DialogDescription>
</DialogHeader>
<RichTextEditor
@@ -577,7 +578,7 @@ export function ExtraSheetEditor({
: updateExtraSheetCell(value, active.row, active.column, cellDraft));
}
setCellDialogOpen(false);
}}>บันทึกเซลล์</Button>
}}>{t("บันทึกเซลล์")}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -585,12 +586,12 @@ export function ExtraSheetEditor({
<Dialog open={labelDialogOpen} onOpenChange={setLabelDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>{renaming ? "แก้ไขชื่อคอลัมน์" : "เพิ่มคอลัมน์"}</DialogTitle>
<DialogDescription>ตั้งชื่อที่ใช้อธิบายข้อมูลในคอลัมน์นี้</DialogDescription>
<DialogTitle>{renaming ? t("แก้ไขชื่อคอลัมน์") : t("เพิ่มคอลัมน์")}</DialogTitle>
<DialogDescription>{t("ตั้งชื่อที่ใช้อธิบายข้อมูลในคอลัมน์นี้")}</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field data-invalid={labelInvalid || undefined}>
<FieldLabel htmlFor="extra-sheet-column-label">ชื่อคอลัมน์</FieldLabel>
<FieldLabel htmlFor="extra-sheet-column-label">{t("ชื่อคอลัมน์")}</FieldLabel>
<Input
id="extra-sheet-column-label"
value={columnLabel}
@@ -605,7 +606,7 @@ export function ExtraSheetEditor({
</FieldGroup>
<DialogFooter showCloseButton>
<Button type="button" disabled={labelInvalid} onClick={saveColumnLabel}>
{renaming ? "บันทึกชื่อ" : "เพิ่มคอลัมน์"}
{renaming ? t("บันทึกชื่อ") : t("เพิ่มคอลัมน์")}
</Button>
</DialogFooter>
</DialogContent>
@@ -614,9 +615,9 @@ export function ExtraSheetEditor({
<DeleteConfirmationDialog
open={removeOpen}
onOpenChange={setRemoveOpen}
title="ลบตารางนี้?"
description="คอลัมน์ แถว และข้อมูลในเซลล์ทั้งหมดจะถูกลบออกจากการ์ด"
confirmLabel="ยืนยันลบตาราง"
title={t("ลบตารางนี้?")}
description={t("คอลัมน์ แถว และข้อมูลในเซลล์ทั้งหมดจะถูกลบออกจากการ์ด")}
confirmLabel={t("ยืนยันลบตาราง")}
showSuccessToast={false}
onConfirm={() => {
onRemove();