-
MID ที่ LINE ส่งมา{countKnown ? fmt(total) : "—"}ไม่ใช่จำนวนแชตใน SQLite
-
โปรไฟล์ที่ดึงสำเร็จ{countKnown ? fmt(done) : "—"}ชื่อที่ใช้แสดงผลได้จริง
-
ยังไม่สมบูรณ์{countKnown ? fmt(report?.unresolved ?? 0) : "—"}สามารถ Retry เฉพาะส่วนนี้
+
{t("MID ที่ LINE ส่งมา")}{countKnown ? fmt(total) : "—"}{t("ไม่ใช่จำนวนแชตใน SQLite")}
+
{t("โปรไฟล์ที่ดึงสำเร็จ")}{countKnown ? fmt(done) : "—"}{t("ชื่อที่ใช้แสดงผลได้จริง")}
+
{t("ยังไม่สมบูรณ์")}{countKnown ? fmt(report?.unresolved ?? 0) : "—"}{t("สามารถ Retry เฉพาะส่วนนี้")}
-
ความสมบูรณ์ของโปรไฟล์{countKnown ? `${progress}%` : "ยังไม่ได้ตรวจ"}
-
+
{t("ความสมบูรณ์ของโปรไฟล์")}{countKnown ? `${progress}%` : t("ยังไม่ได้ตรวจ")}
+
-
ตรวจล่าสุด: {localeDate(report?.finishedAt ?? 0)}
+
{t("ตรวจล่าสุด")}: {localeDate(report?.finishedAt ?? 0)}
@@ -122,19 +124,19 @@ export function FriendSyncDiagnostics() {
{fmt(report?.viaV2 ?? 0)}Contacts V2
{fmt(report?.viaSingle ?? 0)}getUser Fallback
{fmt(report?.batches ?? 0)}API Batches
-
{fmt(report?.splitBatches ?? 0)}Batch ถูกแบ่งย่อย
+
{fmt(report?.splitBatches ?? 0)}{t("Batch ถูกแบ่งย่อย")}
{Boolean(report?.unavailableEndpoints?.length) &&
-
ใช้ช่องทางสำรองอัตโนมัติ
-
{report?.unavailableEndpoints?.join(" / ")} ไม่พร้อมใช้งานกับเซสชันนี้ จึงเปลี่ยนไปใช้ API สำรองโดยไม่ต้อง Retry หรือเข้าสู่ระบบใหม่
+
{t("ใช้ช่องทางสำรองอัตโนมัติ")}
+
{report?.unavailableEndpoints?.join(" / ")} {t("ไม่พร้อมใช้งานกับเซสชันนี้ จึงเปลี่ยนไปใช้ API สำรองโดยไม่ต้อง Retry หรือเข้าสู่ระบบใหม่")}
}
{Boolean(report?.errors?.length) &&
-
{report?.unresolved === 0 && report?.phase === "complete" ? "คำขอที่ผิดพลาดแต่กู้ข้อมูลสำเร็จแล้ว" : "ข้อผิดพลาดจากรอบล่าสุด"}
+
{report?.unresolved === 0 && report?.phase === "complete" ? t("คำขอที่ผิดพลาดแต่กู้ข้อมูลสำเร็จแล้ว") : t("ข้อผิดพลาดจากรอบล่าสุด")}
{report?.errors.map((issue) =>
- {issue.source ? `${issue.source} · ` : ""}{issueNames[issue.category] ?? issue.category}{fmt(issue.count)} ครั้ง
+ {issue.source ? `${issue.source} · ` : ""}{issueNames[issue.category] ? t(issueNames[issue.category]) : issue.category}{t("{{count}} ครั้ง", { count: fmt(issue.count) })}
)}
-
ตัวเลขนี้นับจำนวนคำขอที่ผิดพลาด ไม่ใช่จำนวนเพื่อนที่ตกหล่น {report?.unresolved === 0 ? "โปรไฟล์เพื่อนครบแล้ว" : ""}
+
{t("ตัวเลขนี้นับจำนวนคำขอที่ผิดพลาด ไม่ใช่จำนวนเพื่อนที่ตกหล่น")} {report?.unresolved === 0 ? t("โปรไฟล์เพื่อนครบแล้ว") : ""}
}
{error &&
}
@@ -142,16 +144,16 @@ export function FriendSyncDiagnostics() {
- ตรวจผ่าน LINEJS บนเครื่องของคุณ · Batch เริ่มต้น 50 คน · Retry สูงสุด 100 คนต่อครั้งและพัก 60 วินาที · ไม่แสดง MID หรือ Token
+ {t("ตรวจผ่าน LINEJS บนเครื่องของคุณ · Batch เริ่มต้น 50 คน · Retry สูงสุด 100 คนต่อครั้งและพัก 60 วินาที · ไม่แสดง MID หรือ Token")}
;
}
diff --git a/src/components/ImageViewerOverlay.tsx b/src/components/ImageViewerOverlay.tsx
index 97159ac..1613e14 100644
--- a/src/components/ImageViewerOverlay.tsx
+++ b/src/components/ImageViewerOverlay.tsx
@@ -1,10 +1,12 @@
import { motion } from "motion/react";
+import { useAppTranslation } from "../lib/i18n";
import { Minus, Plus, Trash, Undo2, X } from "lucide-react";
import { useEffect, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
type ImageEditorTool = "view" | "draw" | "blur" | "text";
export function ImageViewerOverlay({ src, onClose }: { src: string; onClose: () => void }) {
+ const { t } = useAppTranslation();
const [error, setError] = useState("");
const [zoom, setZoom] = useState(1);
const [tool, setTool] = useState