99 lines
5.1 KiB
TypeScript
99 lines
5.1 KiB
TypeScript
import type { Locale } from "@/lib/i18n";
|
||
import { TOOL_LINKS, type ToolLink } from "@/lib/tools";
|
||
|
||
type ToolCopy = Record<string, { title: string; desc: string }>;
|
||
|
||
/** English titles/descriptions for the toolkit catalog (ZH lives on TOOL_LINKS). */
|
||
const EN: ToolCopy = {
|
||
trip: { title: "Trip planner", desc: "Multi-city routes and budget totals" },
|
||
spin: { title: "Destiny wheel", desc: "Randomize your next stop" },
|
||
matcher: { title: "Smart matcher", desc: "Quiz-based destination picks" },
|
||
season: { title: "Best months", desc: "Avoid rain and peak season" },
|
||
weekend: { title: "Weekend ideas", desc: "City activities by energy level" },
|
||
"rainy-day": { title: "Rainy-day plan", desc: "Indoor ideas when it pours" },
|
||
"day-plan": { title: "Remote day planner", desc: "Block work into a timeline" },
|
||
daylight: { title: "Daylight work window", desc: "Sunrise, sunset & deep work" },
|
||
calculator: { title: "Cost calculator", desc: "Estimate by housing tier" },
|
||
"cost-compare": { title: "Home vs nomad cost", desc: "Compare hometown vs travel costs" },
|
||
savings: { title: "Launch fund goal", desc: "Track savings progress" },
|
||
runway: { title: "Nomad runway", desc: "How many months can savings last" },
|
||
"first-month": { title: "First-month landing cost", desc: "Rent, deposit, SIM in one calc" },
|
||
expenses: { title: "Expense ledger", desc: "Categorize and sum spending" },
|
||
"bill-split": { title: "Bill split", desc: "Per-person + tip in seconds" },
|
||
"invoice-fx": { title: "Invoice FX", desc: "Net after fees and FX" },
|
||
tipping: { title: "Tipping cheat sheet", desc: "Local tipping norms" },
|
||
laundry: { title: "Laundry day budget", desc: "Estimate by kilo" },
|
||
flight: { title: "Flight estimate", desc: "Rough round-trip fare" },
|
||
currency: { title: "Currency converter", desc: "Multi-currency convert" },
|
||
"tax-days": { title: "Tax-day counter", desc: "Track the 183-day rule" },
|
||
timezone: { title: "Timezone board", desc: "Work-hour overlap" },
|
||
meetings: { title: "Meeting golden hours", desc: "Align shared meeting windows" },
|
||
jetlag: { title: "Jetlag recovery", desc: "Recovery tips after flights" },
|
||
sleep: { title: "Sleep cycles", desc: "Back-calculate bedtime" },
|
||
wifi: { title: "Wi‑Fi grade", desc: "Is speed enough for remote work" },
|
||
workspot: { title: "Workspot cost", desc: "Month pass vs café value" },
|
||
"data-budget": { title: "Data budget", desc: "Monthly data and plan tips" },
|
||
focus: { title: "Focus timer", desc: "Pomodoro deep work" },
|
||
mood: { title: "Mood check-in", desc: "One-minute travel mood log" },
|
||
hydration: { title: "Hydration tracker", desc: "Daily water goals by climate" },
|
||
coworking: { title: "Coworking", desc: "Popular co-working spaces" },
|
||
cafes: { title: "Cafés", desc: "Laptop-friendly coffee shops" },
|
||
visa: { title: "Visa guide", desc: "Policy and smart matching" },
|
||
"visa-stay": { title: "Stay countdown", desc: "Visa days remaining" },
|
||
housing: { title: "Housing guide", desc: "Coliving / apartment options" },
|
||
"coliving-qa": { title: "Viewing questions", desc: "Must-ask coliving checklist" },
|
||
"deposit-return": { title: "Deposit return checklist", desc: "Checkout without surprises" },
|
||
sim: { title: "Connectivity", desc: "SIM / eSIM recommendations" },
|
||
plugs: { title: "Power plugs", desc: "Voltage and plug types" },
|
||
packing: { title: "Packing list", desc: "Pre-departure checklist" },
|
||
"bag-weight": { title: "Bag weight", desc: "Estimate vs airline limits" },
|
||
arrival: { title: "Arrival checklist", desc: "First week on the ground" },
|
||
"airport-transfer": { title: "Airport transfer", desc: "Cheap / fast / easy ranking" },
|
||
phrases: { title: "Survival phrases", desc: "Copy common phrases" },
|
||
notes: { title: "City notes", desc: "Private local notes" },
|
||
insurance: { title: "Insurance guide", desc: "Compare travel health cover" },
|
||
emergency: { title: "Emergency contacts", desc: "First aid and consulates" },
|
||
atm: { title: "ATM pitfalls", desc: "Cash and FX tips" },
|
||
"food-water": { title: "Food & water", desc: "Stomach and drinking water tips" },
|
||
"scam-alerts": { title: "Local scam alerts", desc: "Common tricks at a glance" },
|
||
};
|
||
|
||
const CAT_EN: Record<string, string> = {
|
||
all: "🌏 All",
|
||
plan: "🗺️ Plan",
|
||
money: "💰 Money",
|
||
work: "💻 Work",
|
||
life: "🌴 Life",
|
||
safety: "🛡️ Safety",
|
||
};
|
||
|
||
const CAT_ZH: Record<string, string> = {
|
||
all: "🌏 全部",
|
||
plan: "🗺️ 规划",
|
||
money: "💰 金钱",
|
||
work: "💻 工作",
|
||
life: "🌴 生活",
|
||
safety: "🛡️ 安全",
|
||
};
|
||
|
||
export function localizedToolLinks(locale: Locale): ToolLink[] {
|
||
if (locale !== "en") return TOOL_LINKS;
|
||
return TOOL_LINKS.map((tool) => {
|
||
const copy = EN[tool.id];
|
||
if (!copy) return tool;
|
||
return { ...tool, title: copy.title, desc: copy.desc };
|
||
});
|
||
}
|
||
|
||
export function localizedToolCategories(locale: Locale) {
|
||
const labels = locale === "en" ? CAT_EN : CAT_ZH;
|
||
return (["all", "plan", "money", "work", "life", "safety"] as const).map((key) => ({
|
||
key,
|
||
label: labels[key],
|
||
}));
|
||
}
|
||
|
||
export function localizedTool(id: string, locale: Locale): ToolLink | undefined {
|
||
return localizedToolLinks(locale).find((t) => t.id === id);
|
||
}
|