diff --git a/components/admin/guide-overview-form.tsx b/components/admin/guide-overview-form.tsx index f8183f9..ebddd8c 100644 --- a/components/admin/guide-overview-form.tsx +++ b/components/admin/guide-overview-form.tsx @@ -464,6 +464,7 @@ export function GuideOverviewForm({ format="png" disabled={!posterArt.url} fileName={`${guide.name}-materials.png`} + allowWithoutNotes={false} captureClassName="p-0" > = [ ...overviewBlendModes, ]; -const DISCLAIMER = exportText("disclaimer"); +const DISCLAIMER = "ไม่สามารถเอาไปเปรียบเทียบกับการคำนวณของ TC ท่านอื่นๆได้\nเพราะแต่ละคนใช้สแตทในการคำนวณที่ไม่เหมือนกัน\nและตารางที่เห็นอาจมีการเปลี่ยนแปลงได้ในอนาคต"; function DraggablePosterLayer({ id, @@ -999,7 +998,7 @@ export function OverviewImageGenerator({ } } - async function download(includeNotes = true) { + async function download() { const node = captureRef.current; if ( !node || @@ -1029,15 +1028,14 @@ export function OverviewImageGenerator({ const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; - const fileName = overviewFileName(character.key, displayRole); - link.download = includeNotes ? fileName : withoutNotesFileName(fileName); + link.download = overviewFileName(character.key, displayRole); document.body.append(link); link.click(); link.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 0); - toast.success(exportText("overviewDownloaded")); + toast.success("ดาวน์โหลดภาพ Overview แล้ว"); } catch { - toast.error(exportText("exportError")); + toast.error("ส่งออกภาพไม่สำเร็จ กรุณาลองอีกครั้ง"); } finally { setExporting(false); } @@ -1347,16 +1345,7 @@ export function OverviewImageGenerator({ ) : ( )} - {exporting ? exportText("exporting") : exportText("downloadPng", { width: 3000, height: 3000 })} - - diff --git a/components/public/artifact-image-export.tsx b/components/public/artifact-image-export.tsx index b59a206..fa200b0 100644 --- a/components/public/artifact-image-export.tsx +++ b/components/public/artifact-image-export.tsx @@ -3,7 +3,6 @@ import { useState, type ReactNode } from "react"; import { DownloadIcon } from "lucide-react"; -import { exportText } from "@/lib/guides/export-text"; import { GuideImageExport } from "@/components/public/guide-image-export"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; @@ -19,10 +18,10 @@ import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; const sectionOptions = [ - ["tierlist", "tierlist"], - ["best-stats", "bestStats"], - ["target-stats", "targetStats"], - ["talents", "talents"], + ["tierlist", "อันดับอาร์ติแฟกต์"], + ["best-stats", "ออฟหลักและออฟรองที่ดีที่สุด"], + ["target-stats", "ค่าสถานะเป้าหมาย"], + ["talents", "ลำดับการอัพพรสวรรค์"], ] as const; type ArtifactExportSection = (typeof sectionOptions)[number][0]; @@ -79,13 +78,13 @@ export function ArtifactImageExport({ }> - {exportText("exportImage")} + ส่งออกภาพ - {exportText("sectionTitle")} + เลือกข้อมูลสำหรับส่งออก - {exportText("sectionDescription")} + เลือกได้หลายส่วน หรือเลือกทั้งหมดเพื่อส่งออกทุกส่วน @@ -97,7 +96,7 @@ export function ArtifactImageExport({ checked ? new Set(sectionOptions.map(([value]) => value)) : new Set(), )} /> - {exportText("allSections")} + ทั้งหมด {sectionOptions.map(([value, label]) => ( @@ -113,7 +112,7 @@ export function ArtifactImageExport({ }); }} /> - {exportText(label)} + {label} ))} {hasNote ? ( @@ -123,13 +122,13 @@ export function ArtifactImageExport({ checked={includeNote} onCheckedChange={(checked) => setIncludeNote(checked === true)} /> - {exportText("addNote")} + รวมโน้ต ) : null} {sections.has("best-stats") && recommendedConditionLabels.length > 1 ? (
-

{exportText("recommendedCondition")}

+

เงื่อนไขค่าสถานะแนะนำ

1 ? (
-

{exportText("targetCondition")}

+

เงื่อนไขค่าสถานะเป้าหมาย

- {exportText("constellationTitle", { name: guide.character.name })} + {`${guide.character.name}’s Constellations`}

- {exportText("teamDamage")} + Team Damage

diff --git a/components/public/guide-image-export.tsx b/components/public/guide-image-export.tsx index 82a4b62..78db04d 100644 --- a/components/public/guide-image-export.tsx +++ b/components/public/guide-image-export.tsx @@ -7,11 +7,16 @@ import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; -import { exportText, withoutNotesFileName } from "@/lib/guides/export-text"; import { cn } from "@/lib/utils"; const EXPORT_WIDTH = 1200; +function withoutNotesFileName(fileName: string): string { + return /\.[^.]+$/u.test(fileName) + ? fileName.replace(/(\.[^.]+)$/u, "-without-notes$1") + : `${fileName}-without-notes`; +} + function downloadFileName(value: string): string { return value.replace(/[\\/:*?"<>|]/gu, "-"); } @@ -23,8 +28,9 @@ export function GuideImageExport({ height, format = "png", disabled = false, + allowWithoutNotes = true, captureClassName, - buttonLabel = exportText("exportImage"), + buttonLabel = "ส่งออกภาพ", }: { children: ReactNode; fileName: string; @@ -32,6 +38,7 @@ export function GuideImageExport({ height?: number; format?: "png" | "webp"; disabled?: boolean; + allowWithoutNotes?: boolean; captureClassName?: string; buttonLabel?: string; }) { @@ -92,7 +99,7 @@ export function GuideImageExport({ link.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 0); } catch { - if (!cancelled) toast.error(exportText("exportError")); + if (!cancelled) toast.error("ส่งออกภาพไม่สำเร็จ กรุณาลองอีกครั้ง"); } finally { if (!cancelled) setCaptureMode(null); } @@ -107,7 +114,7 @@ export function GuideImageExport({ return ( <>
- {(["with-notes", "without-notes"] as const).map((mode) => ( + {(["with-notes", "without-notes"] as const).filter((mode) => allowWithoutNotes || mode === "with-notes").map((mode) => ( ))} diff --git a/components/public/material-poster.tsx b/components/public/material-poster.tsx index 3d8e76f..4eed65c 100644 --- a/components/public/material-poster.tsx +++ b/components/public/material-poster.tsx @@ -10,7 +10,6 @@ import type { } from "@/lib/catalog/lunaris"; import { mergePosterMaterials, type PosterMaterial } from "@/lib/material-poster"; import { accentGradient } from "@/lib/overview-image"; -import { exportText, type Locale } from "@/lib/guides/export-text"; import { cn } from "@/lib/utils"; export type PosterBlendMode = "normal" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity"; @@ -66,9 +65,7 @@ export function MaterialPoster({ onArtworkMove, className, bleeding = [], - locale = "en", }: { - locale?: Locale; character: PosterCharacter; characterArtUrl: string | null; artworkOffsetX: number; @@ -219,8 +216,8 @@ export function MaterialPoster({
-

{exportText("materials", {}, locale)}

-

{exportText("materialLevel", { level: 90 }, locale)}

+

MATERIALS

+

LV.90

{materials.map((material, index) => { const materialCard = ( diff --git a/components/public/structured-guide.tsx b/components/public/structured-guide.tsx index be8ffbb..82ded9f 100644 --- a/components/public/structured-guide.tsx +++ b/components/public/structured-guide.tsx @@ -54,7 +54,6 @@ import { } from "@/lib/guides/talents"; import { parseYouTubeUrl } from "@/lib/guides/youtube"; import { normalizeExtraRichText } from "@/lib/rich-text"; -import { exportText, exportStatLabel, type Locale } from "@/lib/guides/export-text"; import { cn } from "@/lib/utils"; function hasSection(guide: PublicGuide, slug: string): boolean { @@ -248,6 +247,7 @@ function GuideOverview({ height={2000} format="png" fileName={`${guide.name}-materials.png`} + allowWithoutNotes={false} captureClassName="p-0" >

- อาวุธที่แนะนำ + {exporting ? "Recommended Weapons" : "อาวุธที่แนะนำ"}

- Weapons + {exporting ? "Weapons" : "อาวุธ"}

{note ? ( @@ -438,14 +438,14 @@ function WeaponSectionContent({ group.name || `Condition ${index + 1}`)} + labels={weaponGroups.map((group, index) => group.name || (exporting ? `Condition ${index + 1}` : `เงื่อนไข ${index + 1}`))} > {weaponGroups.map((group, groupIndex, groups) => (
{groups.length > 1 || conditionNumber ? (

- {group.name || `Condition ${conditionNumber ?? groupIndex + 1}`} + {group.name || (exporting ? `Condition ${conditionNumber ?? groupIndex + 1}` : `เงื่อนไข ${conditionNumber ?? groupIndex + 1}`)}

) : } {showExportActions ? ( @@ -617,8 +617,8 @@ function ArtifactSection({ guide }: { guide: PublicGuide }) { group.name || `Condition ${index + 1}`)} - targetConditionLabels={targetConditions.map((group, index) => group.name || `Condition ${index + 1}`)} + recommendedConditionLabels={(guide.artifactProfile?.recommendedConditions ?? []).map((group, index) => group.name || `เงื่อนไข ${index + 1}`)} + targetConditionLabels={targetConditions.map((group, index) => group.name || `เงื่อนไข ${index + 1}`)} > @@ -640,31 +640,31 @@ function ArtifactSectionContent({ const recommendedConditions = profile?.recommendedConditions ?? []; const recommendedCards = recommendedConditions.map((condition, conditionIndex) => (
- {exporting && recommendedConditions.length > 1 ?

{condition.name || exportText("condition", { index: conditionIndex + 1 })}

: null} + {exporting && recommendedConditions.length > 1 ?

{condition.name || `Condition ${conditionIndex + 1}`}

: null} {condition.note ?

{condition.note}

: null} {profile ? ( - {exportText("mainStats", {}, exporting ? "en" : "th")} + {exporting ? "Best Main Stats" : "ออฟหลักที่ดีที่สุด"} - {exportText("substats", {}, exporting ? "en" : "th")} + {exporting ? "Best Substats" : "ออฟรองที่ดีที่สุด"}
{condition.substats.map((stat, index) => (

- {exportText("artifactRecommendation", {}, exporting ? "en" : "th")} + {exporting ? "Recommended Artifacts & Stats" : "อาร์ติแฟกต์และสแตทที่แนะนำ"}

- {exportText("artifactTitle", {}, exporting ? "en" : "th")} + {exporting ? "Artifacts & Stats" : "อาร์ติแฟกต์และค่าสถานะ"}

{action} @@ -741,7 +741,7 @@ function ArtifactSectionContent({ {" "}
{exporting ? recommendedCards : ( - condition.name || `Condition ${index + 1}`)}> + condition.name || `เงื่อนไข ${index + 1}`)}> {recommendedCards} )} @@ -751,9 +751,9 @@ function ArtifactSectionContent({ {group.name === "Late Game" - ? exportText("lateGame", {}, exporting ? "en" : "th") + ? (exporting ? "Late Game" : "เลทเกม") : group.name === "Early Game" - ? exportText("earlyGame", {}, exporting ? "en" : "th") + ? (exporting ? "Early Game" : "ต้นเกม") : group.name} @@ -806,7 +806,7 @@ function ArtifactSectionContent({ exporting ? ( profile.targetConditions.filter((group) => group.rows.length).map((group, groupIndex) => (
-

{exportText("minimumStats", {}, exporting ? "en" : "th")}

+

{exporting ? "Recommended Minimum Stats" : "ค่าสถานะต่ำๆที่ควรจะปั้นไว้"}

{group.note ?

{group.note}

: null}
{group.rows.map((target, index) => ( @@ -830,7 +830,7 @@ function ArtifactSectionContent({ ) : null} {statLabel( - normalizeTargetStat(target.stat) ?? target.stat, exporting ? "en" : "th", + normalizeTargetStat(target.stat) ?? target.stat, exporting, )} @@ -841,10 +841,10 @@ function ArtifactSectionContent({
)) ) : ( - group.rows.length).map((group, index) => group.name || `Condition ${index + 1}`)}> + group.rows.length).map((group, index) => group.name || `เงื่อนไข ${index + 1}`)}> {profile.targetConditions.filter((group) => group.rows.length).map((group, groupIndex) => (
-

{exportText("minimumStats", {}, exporting ? "en" : "th")}

+

{exporting ? "Recommended Minimum Stats" : "ค่าสถานะต่ำๆที่ควรจะปั้นไว้"}

{group.note ?

{group.note}

: null}
{group.rows.map((target, index) => ( @@ -865,7 +865,7 @@ function ArtifactSectionContent({ {profile.talents.length ? (

- {exportText("talents", {}, exporting ? "en" : "th")} + {exporting ? "Talent Priority" : "ลำดับการอัพพรสวรรค์"}

{talent.level - ? exportText("level", { level: talent.level }, exporting ? "en" : "th") + ? (exporting ? `Level ${talent.level}+` : `เลเวล ${talent.level}+`) : "-"}

- {exportText(talent.type === "E" ? "skill" : talent.type === "Q" ? "burst" : "normalAttack", {}, exporting ? "en" : "th")} + {talent.type === "E" + ? (exporting ? "Elemental Skill" : "สกิลธาตุ") + : talent.type === "Q" + ? (exporting ? "Elemental Burst" : "ท่าไม้ตาย") + : (exporting ? "Normal Attack" : "ตีปกติ")}

{index < talents.length - 1 ? ( @@ -963,7 +967,7 @@ function ArtifactSectionContent({ ) : null} {profile.note ? (
-

{exportText("note", {}, exporting ? "en" : "th")}

+

{exporting ? "Notes" : "โน็ต"}

{profile.note}

@@ -978,8 +982,42 @@ function ArtifactSectionContent({ ); } -function statLabel(value: string, locale: Locale = "th"): string { - return exportStatLabel(value, locale); +const thaiStats: Record = { + HP: "พลังชีวิต", + ATK: "พลังโจมตี", + DEF: "พลังป้องกัน", + EM: "ความชำนาญธาตุ", + ER: "ฟื้นฟูพลังงาน", + "CRIT RATE": "อัตราคริ", + "CRIT DAMAGE": "ความแรงคริ", + "ATK%": "พลังโจมตี%", + "HP%": "พลังชีวิต%", + "DEF%": "พลังป้องกัน%", + "CRIT Rate%/CRIT DMG%": "อัตราคริ/ความแรงคริ", + "Pyro DMG%": "ความเสียหายธาตุไฟ%", + "Hydro DMG%": "ความเสียหายธาตุน้ำ%", + "Cryo DMG%": "ความเสียหายธาตุน้ำแข็ง%", + "Electro DMG%": "ความเสียหายธาตุไฟฟ้า%", + "Anemo DMG%": "ความเสียหายธาตุลม%", + "Geo DMG%": "ความเสียหายธาตุดิน%", + "Dendro DMG%": "ความเสียหายธาตุไม้%", + "Physical DMG%": "ความเสียหายกายภาพ%", + "Healing Bonus%": "โบนัสการรักษา%", +}; + +const englishStats: Record = { + HP: "HP", + ATK: "ATK", + DEF: "DEF", + EM: "Elemental Mastery", + ER: "Energy Recharge", + "CRIT RATE": "CRIT Rate", + "CRIT DAMAGE": "CRIT DMG", + "CRIT Rate%/CRIT DMG%": "CRIT Rate / CRIT DMG", +}; + +function statLabel(value: string, exporting = false): string { + return (exporting ? englishStats : thaiStats)[value] ?? value; } function ArtifactStat({ @@ -1080,7 +1118,7 @@ function ArtifactStatValue({ className="size-5 shrink-0 object-contain brightness-0 invert" /> ) : null} - {statLabel(value, exporting ? "en" : "th")} + {statLabel(value, exporting)} ); } @@ -1105,7 +1143,7 @@ function ConstellationSection({ guide }: { guide: PublicGuide }) { className="size-14 shrink-0 object-contain" />

- Constellations + กลุ่มดาว

{note ? ( @@ -1114,7 +1152,7 @@ function ConstellationSection({ guide }: { guide: PublicGuide }) {

) : null} - group.rows.length > 0).map((group, index) => group.name || `Condition ${index + 1}`)}> + group.rows.length > 0).map((group, index) => group.name || `เงื่อนไข ${index + 1}`)}> {guide.constellationGroups.filter((group) => group.rows.length > 0).map((group, groupIndex, groups) => (
@@ -1130,7 +1168,7 @@ function ConstellationSection({ guide }: { guide: PublicGuide }) { />
- {groups.length > 1 ?

{group.name || `Condition ${groupIndex + 1}`}

: null} + {groups.length > 1 ?

{group.name || `เงื่อนไข ${groupIndex + 1}`}

: null} {group.note ?

{group.note}

: null}
{group.rows.map((row) => ( @@ -1223,7 +1261,7 @@ function ExtraSectionContent({ /> ) : null}
-

{exportText("extraGuide", {}, exporting ? "en" : "th")}

+

{exporting ? "Additional Guide" : "คู่มือเสริม"}

{extra.title}

{action}
@@ -1274,7 +1312,7 @@ function ExtraSectionContent({ ) : null}

{item.name}

- {!item.available ? {exportText("missingItem", {}, exporting ? "en" : "th")} : null} + {!item.available ? {exporting ? "Item unavailable" : "ไม่พบรายการ"} : null}