Files
Arkie-Library-Frontend/src/i18n.tsx
2026-05-16 00:18:22 +08:00

424 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from "react";
export type Lang = "zh-TW" | "zh-CN" | "en";
type Dict = Record<string, string>;
const dict: Record<Lang, Dict> = {
"zh-TW": {
brand: "ARK 資料庫",
mainNav: "網站導覽",
home: "首頁",
all: "全部資料",
categories: "分類瀏覽",
latest: "最新更新",
official: "官方推薦",
popular: "熱門資料",
favorites: "我的收藏",
search: "搜尋",
searchPlaceholder: "搜尋資料...",
searchNow: "立即搜尋資料",
viewAll: "查看全部",
heroTitle: "ARK 官方資料庫",
heroSub:
"集中、分類、管理 ARK 資料庫,讓你快速找到所需資源,推動社群共識與成長。",
categorySection: "資料分類",
officialSection: "官方推薦",
latestSection: "最新更新",
popularSection: "熱門資料",
preview: "預覽",
download: "下載",
favorite: "收藏",
share: "分享",
profile: "個人中心",
langLabel: "語言",
admin: "後台",
login: "登入",
logout: "登出",
email: "電子郵件",
password: "密碼",
dashboard: "儀表板",
resources: "資料管理",
newResource: "新增資料",
save: "儲存",
title: "標題",
description: "簡介",
type: "類型",
language: "語言",
category: "分類",
status: "狀態",
public: "公開",
downloadable: "可下載",
recommended: "首頁推薦",
cover: "封面圖 URL",
fileUrl: "檔案 URL",
externalUrl: "外部連結",
body: "文案內容",
badge: "推薦標籤",
published: "已發布",
draft: "草稿",
archived: "封存",
noResults: "找不到符合的資料,請換個關鍵字或瀏覽分類。",
copyLink: "複製連結",
related: "相關資料",
total: "總資料",
views: "瀏覽",
downloads: "下載",
wallet: "錢包",
walletPageTitle: "錢包登入",
walletPageIntro:
"連接 Web3 錢包以使用會員相關功能。採用標準簽名登入,不會發送交易、不消耗 gas。",
walletStepExtension:
"電腦已安裝擴充錢包(如 MetaMask可直接在瀏覽器連線。",
walletStepQR:
"電腦未安裝錢包時:在連線視窗選擇 WalletConnect用手機錢包掃描畫面上的 QR Code 即可連線。",
walletStepSign:
"連線成功後,點「簽署登入」並在錢包內簽署訊息,即完成網站身分驗證。",
signInWallet: "簽署登入",
walletSignedIn: "已驗證登入",
walletLogout: "登出錢包",
walletMissingProjectId:
"請設定 VITE_WALLETCONNECT_PROJECT_IDReown Cloud 免費申請),否則無法使用 WalletConnect手機掃碼。",
walletSetupNeeded: "錢包掃碼未啟用(請於伺服器設定環境變數)",
lang_zh_TW: "繁體中文",
lang_zh_CN: "简体中文",
lang_en: "English",
filterAll: "全部",
sortPublished: "發布時間",
type_ppt: "PPT",
type_video: "影片",
type_image: "圖片",
type_pdf: "PDF",
type_link: "連結",
type_text: "文字",
type_archive: "壓縮檔",
type_zip: "ZIP",
adminLoginTitle: "管理後台登入",
adminEditResource: "編輯資料",
adminVideoFileHint:
"上傳影片檔MP4/WebM/MOV 等),類型請選「影片」;儲存後前台會自動播放(預設靜音,可點喇叭開聲音)。",
adminStatTodayNew: "今日新增",
adminStatFavorites: "收藏",
adminMetricDownloads: "下載",
adminMetricFavorites: "收藏",
adminMetricViews: "瀏覽",
edit: "編輯",
backToList: "返回列表",
sortOrderLabel: "排序權重",
previewUrlLabel: "預覽網址",
tagsCommaLabel: "標籤(逗號分隔)",
uploadFile: "上傳檔案",
loading: "載入中…",
favoritesEmpty: "尚未加入收藏。",
paginationPrev: "上一頁",
paginationNext: "下一頁",
listRange: "顯示 {{from}}{{to}},共 {{total}} 筆",
pageIndicator: "{{c}} / {{p}} 頁",
resourceLangFilter: "資料語言",
filterTagClear: "清除標籤",
filterLanguageAll: "全部語言",
aboutTitle: "關於本站",
aboutIntro:
"ARK 資料庫彙整官方教材、公告、影片與常用檔案,協助社群快速取得一致版本的可信內容。\n\n本站僅作展示與索引資料權利仍以官方公告為準。",
footerAbout: "關於本站",
footerAdminLogin: "管理員登入",
adminSearchLogs: "搜尋紀錄",
adminMetricShares: "分享",
adminSearchQuery: "查詢詞",
adminSearchTime: "時間",
adminSearchId: "編號",
},
"zh-CN": {
brand: "ARK 数据库",
mainNav: "网站导航",
home: "首页",
all: "全部资料",
categories: "分类浏览",
latest: "最新更新",
official: "官方推荐",
popular: "热门资料",
favorites: "我的收藏",
search: "搜索",
searchPlaceholder: "搜索资料...",
searchNow: "立即搜索资料",
viewAll: "查看全部",
heroTitle: "ARK 官方数据库",
heroSub:
"集中、分类、管理 ARK 数据库,让你快速找到所需资源,推动社群共识与成长。",
categorySection: "资料分类",
officialSection: "官方推荐",
latestSection: "最新更新",
popularSection: "热门资料",
preview: "预览",
download: "下载",
favorite: "收藏",
share: "分享",
profile: "个人中心",
langLabel: "语言",
admin: "后台",
login: "登录",
logout: "退出",
email: "邮箱",
password: "密码",
dashboard: "仪表盘",
resources: "资料管理",
newResource: "新增资料",
save: "保存",
title: "标题",
description: "简介",
type: "类型",
language: "语言",
category: "分类",
status: "状态",
public: "公开",
downloadable: "可下载",
recommended: "首页推荐",
cover: "封面图 URL",
fileUrl: "文件 URL",
externalUrl: "外部链接",
body: "文案内容",
badge: "推荐标签",
published: "已发布",
draft: "草稿",
archived: "归档",
noResults: "找不到符合的资料,请换个关键字或浏览分类。",
copyLink: "复制链接",
related: "相关资料",
total: "总资料",
views: "浏览",
downloads: "下载",
wallet: "钱包",
walletPageTitle: "钱包登录",
walletPageIntro:
"连接 Web3 钱包以使用会员相关功能。采用标准签名登录,不发送交易、不消耗 gas。",
walletStepExtension:
"电脑已安装浏览器扩展钱包(如 MetaMask可直接连接。",
walletStepQR:
"电脑未安装钱包时:在连接窗口选择 WalletConnect用手机钱包扫描 QR Code。",
walletStepSign: "连接成功后,点击「签署登录」并在钱包内签名即可完成验证。",
signInWallet: "签署登录",
walletSignedIn: "已验证登录",
walletLogout: "退出钱包",
walletMissingProjectId:
"请配置 VITE_WALLETCONNECT_PROJECT_IDReown Cloud否则无法使用 WalletConnect/扫码。",
walletSetupNeeded: "钱包扫码未启用(请在服务器配置环境变量)",
lang_zh_TW: "繁体中文",
lang_zh_CN: "简体中文",
lang_en: "English",
filterAll: "全部",
sortPublished: "发布时间",
type_ppt: "PPT",
type_video: "视频",
type_image: "图片",
type_pdf: "PDF",
type_link: "链接",
type_text: "文字",
type_archive: "压缩包",
type_zip: "ZIP",
adminLoginTitle: "管理后台登录",
adminEditResource: "编辑资料",
adminVideoFileHint:
"上传视频文件MP4/WebM/MOV 等),类型请选择「视频」;保存后前台自动播放(默认静音,可点喇叭开声音)。",
adminStatTodayNew: "今日新增",
adminStatFavorites: "收藏",
adminMetricDownloads: "下载",
adminMetricFavorites: "收藏",
adminMetricViews: "浏览",
edit: "编辑",
backToList: "返回列表",
sortOrderLabel: "排序权重",
previewUrlLabel: "预览网址",
tagsCommaLabel: "标签(逗号分隔)",
uploadFile: "上传文件",
loading: "加载中…",
favoritesEmpty: "还没有收藏。",
paginationPrev: "上一页",
paginationNext: "下一页",
listRange: "显示 {{from}}{{to}},共 {{total}} 条",
pageIndicator: "{{c}} / {{p}} 页",
resourceLangFilter: "资料语言",
filterTagClear: "清除标签",
filterLanguageAll: "全部语言",
aboutTitle: "关于本站",
aboutIntro:
"ARK 数据库汇总官方教材、公告、视频与常用文件,帮助社区快速获取一致版本的可信内容。\n\n本站仅供展示与索引权利归属以官方公告为准。",
footerAbout: "关于本站",
footerAdminLogin: "管理员登录",
adminSearchLogs: "搜索记录",
adminMetricShares: "分享",
adminSearchQuery: "查询词",
adminSearchTime: "时间",
adminSearchId: "编号",
},
en: {
brand: "ARK Library",
mainNav: "Site menu",
home: "Home",
all: "All assets",
categories: "Categories",
latest: "Latest",
official: "Official picks",
popular: "Popular",
favorites: "Favorites",
search: "Search",
searchPlaceholder: "Search resources...",
searchNow: "Search now",
viewAll: "View all",
heroTitle: "ARK Official Library",
heroSub:
"Centralize, organize, and manage the ARK library so you can find what you need fast and help the community grow together.",
categorySection: "Categories",
officialSection: "Official recommendations",
latestSection: "Latest updates",
popularSection: "Popular assets",
preview: "Preview",
download: "Download",
favorite: "Favorite",
share: "Share",
profile: "Profile",
langLabel: "Language",
admin: "Admin",
login: "Sign in",
logout: "Sign out",
email: "Email",
password: "Password",
dashboard: "Dashboard",
resources: "Resources",
newResource: "New resource",
save: "Save",
title: "Title",
description: "Description",
type: "Type",
language: "Language",
category: "Category",
status: "Status",
public: "Public",
downloadable: "Downloadable",
recommended: "Featured",
cover: "Cover image URL",
fileUrl: "File URL",
externalUrl: "External URL",
body: "Text body",
badge: "Badge label",
published: "Published",
draft: "Draft",
archived: "Archived",
noResults: "No results. Try another keyword or browse categories.",
copyLink: "Copy link",
related: "Related",
total: "Total items",
views: "Views",
downloads: "Downloads",
wallet: "Wallet",
walletPageTitle: "Wallet sign-in",
walletPageIntro:
"Connect a Web3 wallet for member features. This uses a standard signed message — no transaction and no gas.",
walletStepExtension:
"On desktop with a browser extension (e.g. MetaMask), connect directly.",
walletStepQR:
"On desktop without an extension: choose WalletConnect in the modal and scan the QR code with your mobile wallet.",
walletStepSign:
'After connecting, tap "Sign in" and approve the message in your wallet to verify.',
signInWallet: "Sign in",
walletSignedIn: "Signed in",
walletLogout: "Disconnect",
walletMissingProjectId:
"Set VITE_WALLETCONNECT_PROJECT_ID (free on Reown Cloud). Required for WalletConnect / QR login.",
walletSetupNeeded: "Wallet QR login disabled (set env on server)",
lang_zh_TW: "Traditional Chinese",
lang_zh_CN: "Simplified Chinese",
lang_en: "English",
filterAll: "All types",
sortPublished: "Published date",
type_ppt: "PPT",
type_video: "Video",
type_image: "Image",
type_pdf: "PDF",
type_link: "Link",
type_text: "Text",
type_archive: "Archive",
type_zip: "ZIP",
adminLoginTitle: "Admin sign in",
adminEditResource: "Edit resource",
adminVideoFileHint:
"Upload a video file (MP4/WebM/MOV, etc.) and set type to Video; the site will autoplay (muted by default — user can unmute).",
adminStatTodayNew: "New today",
adminStatFavorites: "Favorites",
adminMetricDownloads: "Downloads",
adminMetricFavorites: "Favorites",
adminMetricViews: "Views",
edit: "Edit",
backToList: "Back to list",
sortOrderLabel: "Sort order",
previewUrlLabel: "Preview URL",
tagsCommaLabel: "Tags (comma-separated)",
uploadFile: "Upload",
loading: "Loading…",
favoritesEmpty: "No favorites yet.",
paginationPrev: "Previous",
paginationNext: "Next",
listRange: "Showing {{from}}{{to}} of {{total}}",
pageIndicator: "Page {{c}} / {{p}}",
resourceLangFilter: "Resource language",
filterTagClear: "Clear tag",
filterLanguageAll: "All languages",
aboutTitle: "About this site",
aboutIntro:
"The ARK library brings together official decks, announcements, videos, and common files so the community can find consistent, trustworthy versions quickly.\n\nThis site is for discovery and indexing only; rights remain with official notices.",
footerAbout: "About",
footerAdminLogin: "Admin sign-in",
adminSearchLogs: "Search logs",
adminMetricShares: "Shares",
adminSearchQuery: "Query",
adminSearchTime: "Time",
adminSearchId: "ID",
},
};
/** Fixed locale lookup (for admin UI always in Traditional Chinese). */
export function tLang(lang: Lang, key: string): string {
return dict[lang][key] || dict["zh-TW"][key] || key;
}
type Ctx = { lang: Lang; setLang: (l: Lang) => void; t: (k: string) => string };
const I18nCtx = createContext<Ctx | null>(null);
const LANG_KEY = "ark_lang";
export function I18nProvider({ children }: { children: React.ReactNode }) {
const [lang, setLangState] = useState<Lang>(() => {
const s = localStorage.getItem(LANG_KEY) as Lang | null;
if (s === "zh-CN" || s === "en" || s === "zh-TW") return s;
return "zh-TW";
});
const setLang = (l: Lang) => {
localStorage.setItem(LANG_KEY, l);
setLangState(l);
};
const t = useCallback(
(k: string) => dict[lang][k] || dict["zh-TW"][k] || k,
[lang],
);
const v = useMemo(() => ({ lang, setLang, t }), [lang, t]);
return <I18nCtx.Provider value={v}>{children}</I18nCtx.Provider>;
}
export function useI18n() {
const v = useContext(I18nCtx);
if (!v) throw new Error("I18nProvider missing");
return v;
}
export function langQuery(lang: Lang) {
if (lang === "zh-TW") return "zh-TW";
if (lang === "zh-CN") return "zh-CN";
return "en";
}