Files
Arkie-Library-Frontend/src/i18n.tsx
2026-05-28 15:32:15 +08:00

371 lines
10 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-CN" | "en" | "ja" | "ko" | "vi" | "id" | "ms";
type Dict = Record<string, string>;
const zhDict: Dict = {
brand: "ARK 资料库",
mainNav: "网站导航",
home: "首页",
all: "全部资料",
categories: "资料分类",
latest: "最新更新",
official: "官方推荐",
popular: "热门资料",
search: "搜索",
searchPlaceholder: "搜索资料...",
searchNow: "立即搜索资料",
viewAll: "查看全部",
heroTitle: "ARK 官方数据库",
heroSub:
"集中、分类、管理 ARK 数据库,让你快速找到所需资源,推动社群共识与成长。",
categorySection: "资料分类",
officialSection: "官方推荐",
latestSection: "最新更新",
popularSection: "热门资料",
preview: "预览",
download: "下载",
downloading: "下载中…",
share: "分享",
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: "下载",
lang_zh_CN: "中文",
lang_en: "English",
lang_ja: "日本語",
lang_ko: "한국어",
lang_vi: "Tiếng Việt",
lang_id: "Bahasa Indonesia",
lang_ms: "Bahasa Melayu",
filterAll: "全部",
sortPublished: "发布时间",
type_ppt: "PPT",
type_music: "音乐",
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: "加载中…",
paginationPrev: "上一页",
paginationNext: "下一页",
listRange: "显示 {{from}}{{to}},共 {{total}} 条",
pageIndicator: "{{c}} / {{p}} 页",
resourceLangFilter: "资料语言",
filterTagClear: "清除标签",
filterLanguageAll: "全部语言",
aboutTitle: "关于本站",
aboutIntro:
"ARK 数据库汇总官方教材、公告、视频与常用文件,帮助社区快速获取一致版本的可信内容。\n\n本站仅供展示与索引权利归属以官方公告为准。",
footerAbout: "关于本站",
footerAdminLogin: "管理员登录",
adminSearchLogs: "搜索记录",
adminMetricShares: "分享",
adminSearchQuery: "查询词",
adminSearchTime: "时间",
adminSearchId: "编号",
favorites: "我的收藏",
favoritesComingSoon: "功能即将推出",
favoritesComingSoonDesc: "登入与收藏功能开发中,敬请期待。",
backToHome: "返回首页",
};
const enDict: Dict = {
brand: "ARK Library",
mainNav: "Site menu",
home: "Home",
all: "All assets",
categories: "Categories",
latest: "Latest",
official: "Official picks",
popular: "Popular",
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",
downloading: "Downloading…",
share: "Share",
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",
lang_zh_CN: "Chinese",
lang_en: "English",
lang_ja: "Japanese",
lang_ko: "Korean",
lang_vi: "Vietnamese",
lang_id: "Indonesian",
lang_ms: "Malay",
filterAll: "All types",
sortPublished: "Published date",
type_ppt: "PPT",
type_music: "Music",
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…",
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",
favorites: "My Favorites",
favoritesComingSoon: "Coming Soon",
favoritesComingSoonDesc:
"Sign-in and favorites are in development. Stay tuned.",
backToHome: "Back to Home",
};
const languageNames: Record<Lang, Dict> = {
"zh-CN": {
lang_zh_CN: "中文",
lang_en: "English",
lang_ja: "日本語",
lang_ko: "한국어",
lang_vi: "Tiếng Việt",
lang_id: "Bahasa Indonesia",
lang_ms: "Bahasa Melayu",
},
en: {
lang_zh_CN: "Chinese",
lang_en: "English",
lang_ja: "Japanese",
lang_ko: "Korean",
lang_vi: "Vietnamese",
lang_id: "Indonesian",
lang_ms: "Malay",
},
ja: {
brand: "ARK ライブラリー",
lang_zh_CN: "中国語",
lang_en: "英語",
lang_ja: "日本語",
lang_ko: "韓国語",
lang_vi: "ベトナム語",
lang_id: "インドネシア語",
lang_ms: "マレー語",
},
ko: {
brand: "ARK 라이브러리",
lang_zh_CN: "중국어",
lang_en: "영어",
lang_ja: "일본어",
lang_ko: "한국어",
lang_vi: "베트남어",
lang_id: "인도네시아어",
lang_ms: "말레이어",
},
vi: {
brand: "Thư viện ARK",
lang_zh_CN: "Tiếng Trung",
lang_en: "Tiếng Anh",
lang_ja: "Tiếng Nhật",
lang_ko: "Tiếng Hàn",
lang_vi: "Tiếng Việt",
lang_id: "Tiếng Indonesia",
lang_ms: "Tiếng Mã Lai",
},
id: {
brand: "Perpustakaan ARK",
lang_zh_CN: "Bahasa Tionghoa",
lang_en: "Bahasa Inggris",
lang_ja: "Bahasa Jepang",
lang_ko: "Bahasa Korea",
lang_vi: "Bahasa Vietnam",
lang_id: "Bahasa Indonesia",
lang_ms: "Bahasa Melayu",
},
ms: {
brand: "Perpustakaan ARK",
lang_zh_CN: "Bahasa Cina",
lang_en: "Bahasa Inggeris",
lang_ja: "Bahasa Jepun",
lang_ko: "Bahasa Korea",
lang_vi: "Bahasa Vietnam",
lang_id: "Bahasa Indonesia",
lang_ms: "Bahasa Melayu",
},
};
const dict: Record<Lang, Dict> = {
"zh-CN": { ...zhDict, ...languageNames["zh-CN"] },
en: { ...enDict, ...languageNames.en },
ja: { ...enDict, ...languageNames.ja },
ko: { ...enDict, ...languageNames.ko },
vi: { ...enDict, ...languageNames.vi },
id: { ...enDict, ...languageNames.id },
ms: { ...enDict, ...languageNames.ms },
};
/** Fixed locale lookup (admin UI uses Simplified Chinese). */
export function tLang(lang: Lang, key: string): string {
return dict[lang][key] || dict.en[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);
if (s === "zh" || s === "zh-TW") return "zh-CN";
if (
s === "zh-CN" ||
s === "en" ||
s === "ja" ||
s === "ko" ||
s === "vi" ||
s === "id" ||
s === "ms"
)
return s;
return "en";
});
const setLang = (l: Lang) => {
localStorage.setItem(LANG_KEY, l);
setLangState(l);
};
const t = useCallback(
(k: string) => dict[lang][k] || dict.en[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) {
return lang;
}