From 25bd99abc5a72f42967756be8276c4e76562ff68 Mon Sep 17 00:00:00 2001 From: cdn0x12 Date: Mon, 3 Feb 2025 21:21:06 +0800 Subject: [PATCH 1/3] fix: the loading string updates page does not supports dark mode --- src/components/LoadingSpinner.tsx | 2 +- src/components/Timeline.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/LoadingSpinner.tsx b/src/components/LoadingSpinner.tsx index cda0d28..b330689 100644 --- a/src/components/LoadingSpinner.tsx +++ b/src/components/LoadingSpinner.tsx @@ -6,7 +6,7 @@ const LoadingSpinner: React.FC = () => { return (
-
+
{t('common.loading')}
); diff --git a/src/components/Timeline.tsx b/src/components/Timeline.tsx index fb4090f..937b622 100644 --- a/src/components/Timeline.tsx +++ b/src/components/Timeline.tsx @@ -152,7 +152,7 @@ const Timeline = () => { {isLoading ? (
-

{t('updates.loading')}

+

{t('updates.loading')}

) : updates.length > 0 ? ( <> From 47cf6171c543e1e768134da13b51f35fe53511cb Mon Sep 17 00:00:00 2001 From: cdn0x12 Date: Mon, 3 Feb 2025 22:22:07 +0800 Subject: [PATCH 2/3] feat: translations integrity validation closes #7 --- data/en-US/index.json | 25 ++-- data/zh-CN/index.json | 25 ++-- data/zh-TW/index.json | 41 ++++--- package.json | 6 +- pnpm-lock.yaml | 9 ++ scripts/check-translations.ts | 183 ++++++++++++++++++++++++++++ src/components/Comments.tsx | 4 +- src/components/LanguageSwitcher.tsx | 9 +- src/components/LoadingSpinner.tsx | 6 +- src/components/Navbar.tsx | 14 ++- src/components/ThemeSwitcher.tsx | 11 +- src/components/Timeline.tsx | 10 +- src/components/ui/Dropdown.tsx | 7 +- src/components/ui/TagFilter.tsx | 3 +- 14 files changed, 291 insertions(+), 62 deletions(-) create mode 100644 scripts/check-translations.ts diff --git a/data/en-US/index.json b/data/en-US/index.json index 220ebe4..ec68c78 100644 --- a/data/en-US/index.json +++ b/data/en-US/index.json @@ -17,9 +17,7 @@ "meta": { "title": "STARSET Mirror", "description": "STARSET Mirror, connecting STARSET and you." - }, - "latestUpdates": "Latest Updates", - "featuredProjects": "Featured Projects" + } }, "projects": { "meta": { @@ -49,7 +47,6 @@ "loading": "Loading...", "back_to_list": "Back to Updates", "filter": { - "all": "All Updates", "title": "Filter by Tags", "search_placeholder": "Search tags...", "no_results": "No matching tags found", @@ -76,7 +73,6 @@ "title": "Contributors - STARSET Mirror", "description": "Meet the amazing people behind STARSET Mirror. Our contributors work tirelessly to bring STARSET closer to you." }, - "title": "Contributors", "tabs": { "contributors": "Contributors", "sponsors": "Sponsors" @@ -99,16 +95,17 @@ }, "aria": { "mainContent": "Main content", - "breadcrumb": "Page navigation", - "navigation": "Site navigation", "menu": "Menu", + "navigation": "Navigation", "search": "Search", - "darkMode": "Dark mode", - "language": "Language selection", - "loading": "Loading", - "error": "Error", + "language": "Change language", + "darkMode": "Toggle dark mode", + "openMenu": "Open menu", "closeMenu": "Close menu", - "openMenu": "Open menu" + "error": "Error", + "loading": "Loading", + "comments": "Comments section", + "breadcrumb": "Breadcrumb" }, "hero": { "title": "Connecting STARSET and You", @@ -174,9 +171,7 @@ }, "common": { "loading": "Loading...", - "error": "An error occurred", - "retry": "Retry", - "close": "Close" + "error": "An error occurred" } } } \ No newline at end of file diff --git a/data/zh-CN/index.json b/data/zh-CN/index.json index ce86c7a..f4e3d2f 100644 --- a/data/zh-CN/index.json +++ b/data/zh-CN/index.json @@ -17,22 +17,21 @@ "meta": { "title": "STARSET Mirror", "description": "STARSET Mirror,连接星落与你" - }, - "latestUpdates": "最新动态", - "featuredProjects": "精选项目" + } }, "aria": { "mainContent": "主要内容", - "breadcrumb": "页面导航", - "navigation": "网站导航", "menu": "菜单", + "navigation": "导航", "search": "搜索", - "darkMode": "深色模式", - "language": "语言选择", - "loading": "加载中", - "error": "错误", + "language": "切换语言", + "darkMode": "切换深色模式", + "openMenu": "打开菜单", "closeMenu": "关闭菜单", - "openMenu": "打开菜单" + "error": "错误", + "loading": "加载中", + "comments": "评论区", + "breadcrumb": "面包屑导航" }, "hero": { "title": "连接星落与你", @@ -70,7 +69,6 @@ "loading": "正在加载...", "back_to_list": "返回动态列表", "filter": { - "all": "全部动态", "title": "按标签筛选", "search_placeholder": "搜索标签...", "no_results": "未找到匹配的标签", @@ -97,7 +95,6 @@ "title": "贡献者 - STARSET Mirror", "description": "认识 STARSET Mirror 背后的优秀贡献者们。他们不懈努力,让 STARSET 与你更近。" }, - "title": "贡献者", "tabs": { "contributors": "贡献者", "sponsors": "赞助人" @@ -168,9 +165,7 @@ }, "common": { "loading": "加载中...", - "error": "发生错误", - "retry": "重试", - "close": "关闭" + "error": "发生错误" } } } \ No newline at end of file diff --git a/data/zh-TW/index.json b/data/zh-TW/index.json index bce3bec..c09cb8d 100644 --- a/data/zh-TW/index.json +++ b/data/zh-TW/index.json @@ -17,22 +17,21 @@ "meta": { "title": "STARSET Mirror", "description": "STARSET Mirror,連結星落與你。" - }, - "latestUpdates": "最新動態", - "featuredProjects": "查看專案" + } }, "aria": { "mainContent": "主要內容", - "breadcrumb": "頁面導航", - "navigation": "網站導航", "menu": "選單", + "navigation": "導航", "search": "搜尋", - "darkMode": "深色模式", - "language": "語言選擇", - "loading": "載入中", - "error": "錯誤", + "language": "切換語言", + "darkMode": "切換深色模式", + "openMenu": "打開選單", "closeMenu": "關閉選單", - "openMenu": "開啟選單" + "error": "錯誤", + "loading": "載入中", + "comments": "評論區", + "breadcrumb": "麵包屑導航" }, "hero": { "title": "連接星落與你", @@ -43,6 +42,10 @@ } }, "projects": { + "meta": { + "title": "專案 - STARSET Mirror", + "description": "探索我們為 STARSET 和社群打造的專案。從翻譯到社群服務,了解我們如何為社群貢獻力量。" + }, "title": "專案", "tags": { "translation": "翻譯", @@ -58,11 +61,14 @@ } }, "updates": { + "meta": { + "title": "動態 - STARSET Mirror", + "description": "了解 STARSET Mirror 的最新動態、更新和活動。跟隨我們支持 STARSET 社群的脚步。" + }, "title": "專案動態", "loading": "正在載入...", "back_to_list": "返回動態列表", "filter": { - "all": "全部動態", "title": "按標籤篩選", "search_placeholder": "搜尋標籤...", "no_results": "未找到匹配的標籤", @@ -85,7 +91,10 @@ } }, "contributors": { - "title": "貢獻者", + "meta": { + "title": "貢獻者 - STARSET Mirror", + "description": "了解 STARSET Mirror 的核心貢獻者和贊助人。" + }, "tabs": { "contributors": "貢獻者", "sponsors": "贊助人" @@ -94,6 +103,10 @@ "regular_members": "專案成員 & 社群貢獻者" }, "about": { + "meta": { + "title": "關於 - STARSET Mirror", + "description": "了解 STARSET Mirror 的使命、價值觀,以及我们致力于连接 STARSET 与全球粉丝的愿景。" + }, "title": "關於我們", "contact": { "title": "聯絡方式" @@ -158,9 +171,7 @@ }, "common": { "loading": "載入中...", - "error": "發生錯誤", - "retry": "重試", - "close": "關閉" + "error": "發生錯誤" } } } \ No newline at end of file diff --git a/package.json b/package.json index 5bc54fc..b549135 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build && tsx scripts/generate-rss.ts && tsx scripts/generate-sitemap.ts", + "build": "tsx scripts/check-translations.ts && vite build && tsx scripts/generate-rss.ts && tsx scripts/generate-sitemap.ts", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "check-translations": "tsx scripts/check-translations.ts" }, "dependencies": { "@ant-design/icons": "^5.6.0", @@ -36,6 +37,7 @@ "@types/react-dom": "^18.3.5", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", + "chalk": "^5.4.1", "eslint": "^9.19.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 140910a..6b07920 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,9 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.1) + chalk: + specifier: ^5.4.1 + version: 5.4.1 eslint: specifier: ^9.19.0 version: 9.19.0(jiti@1.21.7) @@ -989,6 +992,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2942,6 +2949,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.4.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 diff --git a/scripts/check-translations.ts b/scripts/check-translations.ts new file mode 100644 index 0000000..9331e86 --- /dev/null +++ b/scripts/check-translations.ts @@ -0,0 +1,183 @@ +import fs from 'fs-extra'; +import path from 'path'; +import * as globModule from 'glob'; +const glob = globModule.glob; +import chalk from 'chalk'; + +interface TranslationMap { + [key: string]: string | TranslationMap; +} + +interface TranslationResult { + missingKeys: string[]; + unusedKeys: string[]; +} + +// 递归获取所有翻译键 +function getAllTranslationKeys(obj: TranslationMap, prefix = ''): string[] { + return Object.entries(obj).reduce((acc, [key, value]) => { + const currentKey = prefix ? `${prefix}.${key}` : key; + if (typeof value === 'object') { + return [...acc, ...getAllTranslationKeys(value, currentKey)]; + } + // 如果键以 translation. 开头,移除这个前缀 + const finalKey = currentKey.startsWith('translation.') + ? currentKey.substring('translation.'.length) + : currentKey; + if (!shouldIgnoreKey(finalKey)) { + return [...acc, finalKey]; + } + return acc; + }, []); +} + +// 从源代码中提取翻译键的正则表达式 +const translationKeyRegexes = [ + /(?:t|i18n\.t)\(['"]([a-zA-Z][a-zA-Z0-9._-]+)['"](?:\s*,\s*{[^}]*})?\)/gi, // t('key') or t('key', {}) + /(?:t|i18n\.t)\(\s*(?:[a-zA-Z][a-zA-Z0-9._]+\s*\?\s*)?['"]([a-zA-Z][a-zA-Z0-9._-]+)['"](?:\s*:\s*['"]([a-zA-Z][a-zA-Z0-9._-]+)['"])?(?:\s*,\s*{[^}]*})?\)/gi, // t(isOpen ? 'key1' : 'key2') or t('key') + /useTranslation\(['"]([a-zA-Z][a-zA-Z0-9._-]+)['"]\)/gi, // useTranslation('key') + /]*i18nKey=["']([a-zA-Z][a-zA-Z0-9._-]+)["']/gi, // +]; + +// 从文件内容中提取翻译键 +function extractTranslationKeys(content: string): Set { + const keys = new Set(); + for (const regex of translationKeyRegexes) { + let match; + while ((match = regex.exec(content)) !== null) { + // 如果有多个捕获组(三元运算符的情况),添加所有捕获的键 + for (let i = 1; i < match.length; i++) { + const key = match[i]; + if (key && !shouldIgnoreKey(key)) { + keys.add(key); + } + } + } + } + return keys; +} + +// 忽略的翻译键 +const ignoredKeys = new Set([ + 'content-type', + 'page', + 'tags' +]); + +// 忽略的翻译键前缀 +const ignoredPrefixes = [ + 'projects.status.', + 'projects.tags.', + 'social.links', + 'updates.tags', + 'data.' +]; + +// 检查键是否应该被忽略 +function shouldIgnoreKey(key: string): boolean { + if (ignoredKeys.has(key)) return true; + return ignoredPrefixes.some(prefix => key.startsWith(prefix)); +} + +// 比较翻译键 +function compareTranslations(usedKeys: Set, availableKeys: Set): TranslationResult { + const missingKeys = Array.from(usedKeys) + .filter(key => !availableKeys.has(key)) + .sort(); + + const unusedKeys = Array.from(availableKeys) + .filter(key => !usedKeys.has(key)) + .sort(); + + return { missingKeys, unusedKeys }; +} + +async function main() { + console.log(chalk.blue('Checking translations...')); + // 获取所有支持的语言 + const dataDir = path.resolve('data'); + const langs = fs.readdirSync(dataDir) + .filter(file => fs.statSync(path.join(dataDir, file)).isDirectory()) + .filter(dir => /^[a-z]{2}-[A-Z]{2}$/.test(dir)); + + // 扫描源代码文件 + const srcFiles = await glob('src/**/*.{ts,tsx,js,jsx}', { absolute: true }); + const usedKeys = new Set(); + + // 从所有源代码文件中提取翻译键 + for (const file of srcFiles) { + const content = await fs.readFile(file, 'utf-8'); + const keys = extractTranslationKeys(content); + keys.forEach(key => usedKeys.add(key)); + } + + // 检查每个语言的翻译 + let hasWarnings = false; + for (const lang of langs) { + const indexPath = path.join(dataDir, lang, 'index.json'); + if (fs.existsSync(indexPath)) { + const content = await fs.readJson(indexPath); + // 确保我们从 translations 对象开始 + const translationsObj = content.translations || content; + const availableKeys = new Set(getAllTranslationKeys(translationsObj)); + + const { missingKeys, unusedKeys } = compareTranslations(usedKeys, availableKeys); + + if (missingKeys.length > 0 || unusedKeys.length > 0) { + hasWarnings = true; + console.log(chalk.yellow(`\n[${lang}]`)); + + if (missingKeys.length > 0) { + console.log(chalk.yellow(` Missing translations: (${missingKeys.length} keys)`)); + // 按命名空间分组输出 + const groupedKeys = missingKeys.reduce((acc, key) => { + const namespace = key.split('.')[0]; + if (!acc[namespace]) acc[namespace] = []; + acc[namespace].push(key); + return acc; + }, {} as Record); + + Object.entries(groupedKeys) + .sort(([a], [b]) => a.localeCompare(b)) + .forEach(([namespace, keys]) => { + console.log(chalk.cyan(`\n ${namespace}:`)); + keys.forEach(key => { + console.log(chalk.red(` ${key}`)); + }); + }); + } + + if (unusedKeys.length > 0) { + console.log(chalk.yellow(`\n Unused translations: (${unusedKeys.length} keys)`)); + // 按命名空间分组输出 + const groupedKeys = unusedKeys.reduce((acc, key) => { + const namespace = key.split('.')[0]; + if (!acc[namespace]) acc[namespace] = []; + acc[namespace].push(key); + return acc; + }, {} as Record); + + Object.entries(groupedKeys) + .sort(([a], [b]) => a.localeCompare(b)) + .forEach(([namespace, keys]) => { + console.log(chalk.cyan(`\n ${namespace}:`)); + keys.forEach(key => { + console.log(chalk.yellow(` ${key}`)); + }); + }); + } + } + } + } + + if (!hasWarnings) { + console.log(chalk.green('\n✓ All translations are complete and clean!')); + } else { + console.log(chalk.yellow('\n⚠️ Please review the translation issues listed above.')); + } +} + +main().catch(error => { + console.error(chalk.red('Error:'), error); + process.exit(1); +}); diff --git a/src/components/Comments.tsx b/src/components/Comments.tsx index 7ecacc3..0f6fe37 100644 --- a/src/components/Comments.tsx +++ b/src/components/Comments.tsx @@ -59,10 +59,10 @@ const Comments = ({ title }: CommentsProps) => { }, [pathname, title]) return ( -
) diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx index a1a406c..12f94ad 100644 --- a/src/components/LanguageSwitcher.tsx +++ b/src/components/LanguageSwitcher.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Globe } from 'lucide-react'; const LanguageSwitcher = () => { - const { i18n } = useTranslation(); + const { i18n, t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const menuRef = useRef(null); @@ -32,9 +32,12 @@ const LanguageSwitcher = () => { return (
diff --git a/src/components/LoadingSpinner.tsx b/src/components/LoadingSpinner.tsx index b330689..5952e06 100644 --- a/src/components/LoadingSpinner.tsx +++ b/src/components/LoadingSpinner.tsx @@ -5,7 +5,11 @@ const LoadingSpinner: React.FC = () => { const { t } = useTranslation(); return ( -
+
{t('common.loading')}
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 93ae5af..65b0c90 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -34,7 +34,11 @@ const Navbar = () => {
{/* Desktop Navigation */} -
+
+ {/* Mobile Navigation Button */}
@@ -71,7 +75,11 @@ const Navbar = () => { {/* Mobile Navigation Menu */} {isOpen && ( -
+
{navItems.map((item) => ( { items={themes} value={theme} onChange={setTheme} - /> + > + + ); }; diff --git a/src/components/Timeline.tsx b/src/components/Timeline.tsx index 937b622..07be642 100644 --- a/src/components/Timeline.tsx +++ b/src/components/Timeline.tsx @@ -112,8 +112,12 @@ const Timeline = () => { if (error) { return ( -
-

{t('updates.error')}

+
+

{t('common.error')}

); } @@ -211,7 +215,7 @@ const Timeline = () => { ) : (
-

{t('updates.no_results')}

+

{t('updates.notFound.title')}

)}
diff --git a/src/components/ui/Dropdown.tsx b/src/components/ui/Dropdown.tsx index fbf4de5..af4b3c4 100644 --- a/src/components/ui/Dropdown.tsx +++ b/src/components/ui/Dropdown.tsx @@ -1,4 +1,5 @@ import React, { useState, useRef, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; interface DropdownProps { icon: React.ReactNode; @@ -16,6 +17,7 @@ const Dropdown = ({ icon, items, value, onChange, position = 'right' }: Dropdown const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); const menuRef = useRef(null); + const { t } = useTranslation(); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -31,9 +33,12 @@ const Dropdown = ({ icon, items, value, onChange, position = 'right' }: Dropdown return (
diff --git a/src/components/ui/TagFilter.tsx b/src/components/ui/TagFilter.tsx index f7b8ecd..b2557c7 100644 --- a/src/components/ui/TagFilter.tsx +++ b/src/components/ui/TagFilter.tsx @@ -104,10 +104,11 @@ const TagFilter: React.FC = ({ setSearchQuery(e.target.value)} placeholder={t('updates.filter.search_placeholder')} - className="w-full px-4 py-2.5 pl-10 text-sm rounded-lg bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500" + aria-label={t('aria.search')} />
From 9ac43ef4f95d436d4add33af82bcb8b0c3e51798 Mon Sep 17 00:00:00 2001 From: cdn0x12 Date: Mon, 3 Feb 2025 22:52:56 +0800 Subject: [PATCH 3/3] feat: migrate language code --- README.en.md | 2 +- README.md | 2 +- README.zh-Hant.md | 2 +- data/{en-US => en}/about.json | 0 data/{en-US => en}/contributors.json | 0 data/{en-US => en}/index.json | 0 data/{en-US => en}/projects.json | 0 data/{en-US => en}/sponsors.json | 0 data/{en-US => en}/updates.json | 0 .../starset-wiki-calls-for-contributions.md | 0 .../2024/changes-about-our-social-profiles.md | 0 .../2024/starset-wiki-project-update-2024.md | 0 .../updates/2025/introducing-tss-rocks.md | 0 data/{en-US => en}/updates/index/2023.json | 0 data/{en-US => en}/updates/index/2024.json | 0 data/{en-US => en}/updates/index/2025.json | 0 data/{zh-CN => zh-Hans}/about.json | 0 data/{zh-CN => zh-Hans}/contributors.json | 0 data/{zh-CN => zh-Hans}/index.json | 0 data/{zh-CN => zh-Hans}/projects.json | 0 data/{zh-CN => zh-Hans}/sponsors.json | 0 data/{zh-CN => zh-Hans}/updates.json | 0 .../updates/2020/journal-2020q3.md | 0 ...disclaimer-about-bilibili-horizons-dmca.md | 0 .../updates/2021/journal-2020q4.md | 0 .../updates/2021/one-year-anniversary.md | 0 .../updates/2021/summary-202102.md | 0 .../updates/2021/summary-202108.md | 0 .../updates/2022/journal-2021h2.md | 0 .../updates/2023/10th-anniversary-special.md | 0 .../updates/2023/journal-2022.md | 0 .../2023/lyrics-translation-completed.md | 0 .../updates/2023/summary-202310.md | 0 .../updates/2024/journal-2023.md | 0 .../updates/2025/introducing-tss-rocks.md | 0 .../updates/2025/journal-2024.md | 0 .../starset-mirror-now-part-of-wholetrans.md | 0 .../updates/index/2020.json | 0 .../updates/index/2021.json | 0 .../updates/index/2022.json | 0 .../updates/index/2023.json | 0 .../updates/index/2024.json | 0 .../updates/index/2025.json | 0 data/{zh-TW => zh-Hant}/about.json | 0 data/{zh-TW => zh-Hant}/contributors.json | 0 data/{zh-TW => zh-Hant}/index.json | 0 data/{zh-TW => zh-Hant}/projects.json | 0 data/{zh-TW => zh-Hant}/sponsors.json | 0 data/{zh-TW => zh-Hant}/updates.json | 0 .../updates/2020/journal-2020q3.md | 0 ...disclaimer-about-bilibili-horizons-dmca.md | 0 .../updates/2021/journal-2020q4.md | 0 .../updates/2021/one-year-anniversary.md | 0 .../updates/2021/summary-202102.md | 0 .../updates/2021/summary-202108.md | 0 .../updates/2022/journal-2021h2.md | 0 .../updates/2023/10th-anniversary-special.md | 0 .../updates/2023/journal-2022.md | 0 .../2023/lyrics-translation-completed.md | 0 .../updates/2023/summary-202310.md | 0 .../updates/2024/journal-2023.md | 0 .../updates/2025/introducing-tss-rocks.md | 0 .../updates/2025/journal-2024.md | 0 .../starset-mirror-now-part-of-wholetrans.md | 0 .../updates/index/2020.json | 0 .../updates/index/2021.json | 0 .../updates/index/2022.json | 0 .../updates/index/2023.json | 0 .../updates/index/2024.json | 0 .../updates/index/2025.json | 0 docs/README.md | 6 +- docs/{en-US => en}/CONTRIBUTING.md | 0 docs/{zh-CN => zh-Hans}/CONTRIBUTING.md | 0 docs/{zh-TW => zh-Hant}/CONTRIBUTING.md | 0 scripts/generate-rss.ts | 22 +++--- scripts/generate-sitemap.ts | 2 +- scripts/generate-update-sitemaps.js | 2 +- src/components/About.tsx | 20 ++--- src/components/Comments.tsx | 2 + src/components/Contributors.tsx | 3 +- src/components/LanguageSwitcher.tsx | 6 +- src/components/Projects.tsx | 9 ++- src/components/Sponsors.tsx | 21 ++++-- src/components/Timeline.tsx | 1 + src/components/TranslationBackground.tsx | 25 +++++++ src/i18n/index.ts | 74 +++++++++---------- 86 files changed, 119 insertions(+), 80 deletions(-) rename data/{en-US => en}/about.json (100%) rename data/{en-US => en}/contributors.json (100%) rename data/{en-US => en}/index.json (100%) rename data/{en-US => en}/projects.json (100%) rename data/{en-US => en}/sponsors.json (100%) rename data/{en-US => en}/updates.json (100%) rename data/{en-US => en}/updates/2023/starset-wiki-calls-for-contributions.md (100%) rename data/{en-US => en}/updates/2024/changes-about-our-social-profiles.md (100%) rename data/{en-US => en}/updates/2024/starset-wiki-project-update-2024.md (100%) rename data/{en-US => en}/updates/2025/introducing-tss-rocks.md (100%) rename data/{en-US => en}/updates/index/2023.json (100%) rename data/{en-US => en}/updates/index/2024.json (100%) rename data/{en-US => en}/updates/index/2025.json (100%) rename data/{zh-CN => zh-Hans}/about.json (100%) rename data/{zh-CN => zh-Hans}/contributors.json (100%) rename data/{zh-CN => zh-Hans}/index.json (100%) rename data/{zh-CN => zh-Hans}/projects.json (100%) rename data/{zh-CN => zh-Hans}/sponsors.json (100%) rename data/{zh-CN => zh-Hans}/updates.json (100%) rename data/{zh-CN => zh-Hans}/updates/2020/journal-2020q3.md (100%) rename data/{zh-CN => zh-Hans}/updates/2021/disclaimer-about-bilibili-horizons-dmca.md (100%) rename data/{zh-CN => zh-Hans}/updates/2021/journal-2020q4.md (100%) rename data/{zh-CN => zh-Hans}/updates/2021/one-year-anniversary.md (100%) rename data/{zh-CN => zh-Hans}/updates/2021/summary-202102.md (100%) rename data/{zh-CN => zh-Hans}/updates/2021/summary-202108.md (100%) rename data/{zh-CN => zh-Hans}/updates/2022/journal-2021h2.md (100%) rename data/{zh-CN => zh-Hans}/updates/2023/10th-anniversary-special.md (100%) rename data/{zh-CN => zh-Hans}/updates/2023/journal-2022.md (100%) rename data/{zh-CN => zh-Hans}/updates/2023/lyrics-translation-completed.md (100%) rename data/{zh-CN => zh-Hans}/updates/2023/summary-202310.md (100%) rename data/{zh-CN => zh-Hans}/updates/2024/journal-2023.md (100%) rename data/{zh-CN => zh-Hans}/updates/2025/introducing-tss-rocks.md (100%) rename data/{zh-CN => zh-Hans}/updates/2025/journal-2024.md (100%) rename data/{zh-CN => zh-Hans}/updates/2025/starset-mirror-now-part-of-wholetrans.md (100%) rename data/{zh-CN => zh-Hans}/updates/index/2020.json (100%) rename data/{zh-CN => zh-Hans}/updates/index/2021.json (100%) rename data/{zh-CN => zh-Hans}/updates/index/2022.json (100%) rename data/{zh-CN => zh-Hans}/updates/index/2023.json (100%) rename data/{zh-CN => zh-Hans}/updates/index/2024.json (100%) rename data/{zh-CN => zh-Hans}/updates/index/2025.json (100%) rename data/{zh-TW => zh-Hant}/about.json (100%) rename data/{zh-TW => zh-Hant}/contributors.json (100%) rename data/{zh-TW => zh-Hant}/index.json (100%) rename data/{zh-TW => zh-Hant}/projects.json (100%) rename data/{zh-TW => zh-Hant}/sponsors.json (100%) rename data/{zh-TW => zh-Hant}/updates.json (100%) rename data/{zh-TW => zh-Hant}/updates/2020/journal-2020q3.md (100%) rename data/{zh-TW => zh-Hant}/updates/2021/disclaimer-about-bilibili-horizons-dmca.md (100%) rename data/{zh-TW => zh-Hant}/updates/2021/journal-2020q4.md (100%) rename data/{zh-TW => zh-Hant}/updates/2021/one-year-anniversary.md (100%) rename data/{zh-TW => zh-Hant}/updates/2021/summary-202102.md (100%) rename data/{zh-TW => zh-Hant}/updates/2021/summary-202108.md (100%) rename data/{zh-TW => zh-Hant}/updates/2022/journal-2021h2.md (100%) rename data/{zh-TW => zh-Hant}/updates/2023/10th-anniversary-special.md (100%) rename data/{zh-TW => zh-Hant}/updates/2023/journal-2022.md (100%) rename data/{zh-TW => zh-Hant}/updates/2023/lyrics-translation-completed.md (100%) rename data/{zh-TW => zh-Hant}/updates/2023/summary-202310.md (100%) rename data/{zh-TW => zh-Hant}/updates/2024/journal-2023.md (100%) rename data/{zh-TW => zh-Hant}/updates/2025/introducing-tss-rocks.md (100%) rename data/{zh-TW => zh-Hant}/updates/2025/journal-2024.md (100%) rename data/{zh-TW => zh-Hant}/updates/2025/starset-mirror-now-part-of-wholetrans.md (100%) rename data/{zh-TW => zh-Hant}/updates/index/2020.json (100%) rename data/{zh-TW => zh-Hant}/updates/index/2021.json (100%) rename data/{zh-TW => zh-Hant}/updates/index/2022.json (100%) rename data/{zh-TW => zh-Hant}/updates/index/2023.json (100%) rename data/{zh-TW => zh-Hant}/updates/index/2024.json (100%) rename data/{zh-TW => zh-Hant}/updates/index/2025.json (100%) rename docs/{en-US => en}/CONTRIBUTING.md (100%) rename docs/{zh-CN => zh-Hans}/CONTRIBUTING.md (100%) rename docs/{zh-TW => zh-Hant}/CONTRIBUTING.md (100%) diff --git a/README.en.md b/README.en.md index 7203d6e..7683db8 100644 --- a/README.en.md +++ b/README.en.md @@ -46,7 +46,7 @@ homepage ## Contribution Guide -See [CONTRIBUTING.md](docs/en-US/CONTRIBUTING.md) in the `docs` directory to learn how to participate in the project. +See [CONTRIBUTING.md](docs/en/CONTRIBUTING.md) in the `docs` directory to learn how to participate in the project. ## License diff --git a/README.md b/README.md index c20b6c9..373b908 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ homepage ## 贡献指南 -参见 `docs` 目录中的 [CONTRIBUTING.md](docs/zh-CN/CONTRIBUTING.md) 了解如何参与项目。 +参见 `docs` 目录中的 [CONTRIBUTING.md](docs/zh-Hans/CONTRIBUTING.md) 了解如何参与项目。 ## 许可 diff --git a/README.zh-Hant.md b/README.zh-Hant.md index b55b296..43f0500 100644 --- a/README.zh-Hant.md +++ b/README.zh-Hant.md @@ -46,7 +46,7 @@ homepage ## 貢獻指南 -參見 `docs` 目錄中的 [CONTRIBUTING.md](docs/zh-TW/CONTRIBUTING.md) 了解如何參與專案。 +參見 `docs` 目錄中的 [CONTRIBUTING.md](docs/zh-Hant/CONTRIBUTING.md) 了解如何參與專案。 ## 許可 diff --git a/data/en-US/about.json b/data/en/about.json similarity index 100% rename from data/en-US/about.json rename to data/en/about.json diff --git a/data/en-US/contributors.json b/data/en/contributors.json similarity index 100% rename from data/en-US/contributors.json rename to data/en/contributors.json diff --git a/data/en-US/index.json b/data/en/index.json similarity index 100% rename from data/en-US/index.json rename to data/en/index.json diff --git a/data/en-US/projects.json b/data/en/projects.json similarity index 100% rename from data/en-US/projects.json rename to data/en/projects.json diff --git a/data/en-US/sponsors.json b/data/en/sponsors.json similarity index 100% rename from data/en-US/sponsors.json rename to data/en/sponsors.json diff --git a/data/en-US/updates.json b/data/en/updates.json similarity index 100% rename from data/en-US/updates.json rename to data/en/updates.json diff --git a/data/en-US/updates/2023/starset-wiki-calls-for-contributions.md b/data/en/updates/2023/starset-wiki-calls-for-contributions.md similarity index 100% rename from data/en-US/updates/2023/starset-wiki-calls-for-contributions.md rename to data/en/updates/2023/starset-wiki-calls-for-contributions.md diff --git a/data/en-US/updates/2024/changes-about-our-social-profiles.md b/data/en/updates/2024/changes-about-our-social-profiles.md similarity index 100% rename from data/en-US/updates/2024/changes-about-our-social-profiles.md rename to data/en/updates/2024/changes-about-our-social-profiles.md diff --git a/data/en-US/updates/2024/starset-wiki-project-update-2024.md b/data/en/updates/2024/starset-wiki-project-update-2024.md similarity index 100% rename from data/en-US/updates/2024/starset-wiki-project-update-2024.md rename to data/en/updates/2024/starset-wiki-project-update-2024.md diff --git a/data/en-US/updates/2025/introducing-tss-rocks.md b/data/en/updates/2025/introducing-tss-rocks.md similarity index 100% rename from data/en-US/updates/2025/introducing-tss-rocks.md rename to data/en/updates/2025/introducing-tss-rocks.md diff --git a/data/en-US/updates/index/2023.json b/data/en/updates/index/2023.json similarity index 100% rename from data/en-US/updates/index/2023.json rename to data/en/updates/index/2023.json diff --git a/data/en-US/updates/index/2024.json b/data/en/updates/index/2024.json similarity index 100% rename from data/en-US/updates/index/2024.json rename to data/en/updates/index/2024.json diff --git a/data/en-US/updates/index/2025.json b/data/en/updates/index/2025.json similarity index 100% rename from data/en-US/updates/index/2025.json rename to data/en/updates/index/2025.json diff --git a/data/zh-CN/about.json b/data/zh-Hans/about.json similarity index 100% rename from data/zh-CN/about.json rename to data/zh-Hans/about.json diff --git a/data/zh-CN/contributors.json b/data/zh-Hans/contributors.json similarity index 100% rename from data/zh-CN/contributors.json rename to data/zh-Hans/contributors.json diff --git a/data/zh-CN/index.json b/data/zh-Hans/index.json similarity index 100% rename from data/zh-CN/index.json rename to data/zh-Hans/index.json diff --git a/data/zh-CN/projects.json b/data/zh-Hans/projects.json similarity index 100% rename from data/zh-CN/projects.json rename to data/zh-Hans/projects.json diff --git a/data/zh-CN/sponsors.json b/data/zh-Hans/sponsors.json similarity index 100% rename from data/zh-CN/sponsors.json rename to data/zh-Hans/sponsors.json diff --git a/data/zh-CN/updates.json b/data/zh-Hans/updates.json similarity index 100% rename from data/zh-CN/updates.json rename to data/zh-Hans/updates.json diff --git a/data/zh-CN/updates/2020/journal-2020q3.md b/data/zh-Hans/updates/2020/journal-2020q3.md similarity index 100% rename from data/zh-CN/updates/2020/journal-2020q3.md rename to data/zh-Hans/updates/2020/journal-2020q3.md diff --git a/data/zh-CN/updates/2021/disclaimer-about-bilibili-horizons-dmca.md b/data/zh-Hans/updates/2021/disclaimer-about-bilibili-horizons-dmca.md similarity index 100% rename from data/zh-CN/updates/2021/disclaimer-about-bilibili-horizons-dmca.md rename to data/zh-Hans/updates/2021/disclaimer-about-bilibili-horizons-dmca.md diff --git a/data/zh-CN/updates/2021/journal-2020q4.md b/data/zh-Hans/updates/2021/journal-2020q4.md similarity index 100% rename from data/zh-CN/updates/2021/journal-2020q4.md rename to data/zh-Hans/updates/2021/journal-2020q4.md diff --git a/data/zh-CN/updates/2021/one-year-anniversary.md b/data/zh-Hans/updates/2021/one-year-anniversary.md similarity index 100% rename from data/zh-CN/updates/2021/one-year-anniversary.md rename to data/zh-Hans/updates/2021/one-year-anniversary.md diff --git a/data/zh-CN/updates/2021/summary-202102.md b/data/zh-Hans/updates/2021/summary-202102.md similarity index 100% rename from data/zh-CN/updates/2021/summary-202102.md rename to data/zh-Hans/updates/2021/summary-202102.md diff --git a/data/zh-CN/updates/2021/summary-202108.md b/data/zh-Hans/updates/2021/summary-202108.md similarity index 100% rename from data/zh-CN/updates/2021/summary-202108.md rename to data/zh-Hans/updates/2021/summary-202108.md diff --git a/data/zh-CN/updates/2022/journal-2021h2.md b/data/zh-Hans/updates/2022/journal-2021h2.md similarity index 100% rename from data/zh-CN/updates/2022/journal-2021h2.md rename to data/zh-Hans/updates/2022/journal-2021h2.md diff --git a/data/zh-CN/updates/2023/10th-anniversary-special.md b/data/zh-Hans/updates/2023/10th-anniversary-special.md similarity index 100% rename from data/zh-CN/updates/2023/10th-anniversary-special.md rename to data/zh-Hans/updates/2023/10th-anniversary-special.md diff --git a/data/zh-CN/updates/2023/journal-2022.md b/data/zh-Hans/updates/2023/journal-2022.md similarity index 100% rename from data/zh-CN/updates/2023/journal-2022.md rename to data/zh-Hans/updates/2023/journal-2022.md diff --git a/data/zh-CN/updates/2023/lyrics-translation-completed.md b/data/zh-Hans/updates/2023/lyrics-translation-completed.md similarity index 100% rename from data/zh-CN/updates/2023/lyrics-translation-completed.md rename to data/zh-Hans/updates/2023/lyrics-translation-completed.md diff --git a/data/zh-CN/updates/2023/summary-202310.md b/data/zh-Hans/updates/2023/summary-202310.md similarity index 100% rename from data/zh-CN/updates/2023/summary-202310.md rename to data/zh-Hans/updates/2023/summary-202310.md diff --git a/data/zh-CN/updates/2024/journal-2023.md b/data/zh-Hans/updates/2024/journal-2023.md similarity index 100% rename from data/zh-CN/updates/2024/journal-2023.md rename to data/zh-Hans/updates/2024/journal-2023.md diff --git a/data/zh-CN/updates/2025/introducing-tss-rocks.md b/data/zh-Hans/updates/2025/introducing-tss-rocks.md similarity index 100% rename from data/zh-CN/updates/2025/introducing-tss-rocks.md rename to data/zh-Hans/updates/2025/introducing-tss-rocks.md diff --git a/data/zh-CN/updates/2025/journal-2024.md b/data/zh-Hans/updates/2025/journal-2024.md similarity index 100% rename from data/zh-CN/updates/2025/journal-2024.md rename to data/zh-Hans/updates/2025/journal-2024.md diff --git a/data/zh-CN/updates/2025/starset-mirror-now-part-of-wholetrans.md b/data/zh-Hans/updates/2025/starset-mirror-now-part-of-wholetrans.md similarity index 100% rename from data/zh-CN/updates/2025/starset-mirror-now-part-of-wholetrans.md rename to data/zh-Hans/updates/2025/starset-mirror-now-part-of-wholetrans.md diff --git a/data/zh-CN/updates/index/2020.json b/data/zh-Hans/updates/index/2020.json similarity index 100% rename from data/zh-CN/updates/index/2020.json rename to data/zh-Hans/updates/index/2020.json diff --git a/data/zh-CN/updates/index/2021.json b/data/zh-Hans/updates/index/2021.json similarity index 100% rename from data/zh-CN/updates/index/2021.json rename to data/zh-Hans/updates/index/2021.json diff --git a/data/zh-CN/updates/index/2022.json b/data/zh-Hans/updates/index/2022.json similarity index 100% rename from data/zh-CN/updates/index/2022.json rename to data/zh-Hans/updates/index/2022.json diff --git a/data/zh-CN/updates/index/2023.json b/data/zh-Hans/updates/index/2023.json similarity index 100% rename from data/zh-CN/updates/index/2023.json rename to data/zh-Hans/updates/index/2023.json diff --git a/data/zh-CN/updates/index/2024.json b/data/zh-Hans/updates/index/2024.json similarity index 100% rename from data/zh-CN/updates/index/2024.json rename to data/zh-Hans/updates/index/2024.json diff --git a/data/zh-CN/updates/index/2025.json b/data/zh-Hans/updates/index/2025.json similarity index 100% rename from data/zh-CN/updates/index/2025.json rename to data/zh-Hans/updates/index/2025.json diff --git a/data/zh-TW/about.json b/data/zh-Hant/about.json similarity index 100% rename from data/zh-TW/about.json rename to data/zh-Hant/about.json diff --git a/data/zh-TW/contributors.json b/data/zh-Hant/contributors.json similarity index 100% rename from data/zh-TW/contributors.json rename to data/zh-Hant/contributors.json diff --git a/data/zh-TW/index.json b/data/zh-Hant/index.json similarity index 100% rename from data/zh-TW/index.json rename to data/zh-Hant/index.json diff --git a/data/zh-TW/projects.json b/data/zh-Hant/projects.json similarity index 100% rename from data/zh-TW/projects.json rename to data/zh-Hant/projects.json diff --git a/data/zh-TW/sponsors.json b/data/zh-Hant/sponsors.json similarity index 100% rename from data/zh-TW/sponsors.json rename to data/zh-Hant/sponsors.json diff --git a/data/zh-TW/updates.json b/data/zh-Hant/updates.json similarity index 100% rename from data/zh-TW/updates.json rename to data/zh-Hant/updates.json diff --git a/data/zh-TW/updates/2020/journal-2020q3.md b/data/zh-Hant/updates/2020/journal-2020q3.md similarity index 100% rename from data/zh-TW/updates/2020/journal-2020q3.md rename to data/zh-Hant/updates/2020/journal-2020q3.md diff --git a/data/zh-TW/updates/2021/disclaimer-about-bilibili-horizons-dmca.md b/data/zh-Hant/updates/2021/disclaimer-about-bilibili-horizons-dmca.md similarity index 100% rename from data/zh-TW/updates/2021/disclaimer-about-bilibili-horizons-dmca.md rename to data/zh-Hant/updates/2021/disclaimer-about-bilibili-horizons-dmca.md diff --git a/data/zh-TW/updates/2021/journal-2020q4.md b/data/zh-Hant/updates/2021/journal-2020q4.md similarity index 100% rename from data/zh-TW/updates/2021/journal-2020q4.md rename to data/zh-Hant/updates/2021/journal-2020q4.md diff --git a/data/zh-TW/updates/2021/one-year-anniversary.md b/data/zh-Hant/updates/2021/one-year-anniversary.md similarity index 100% rename from data/zh-TW/updates/2021/one-year-anniversary.md rename to data/zh-Hant/updates/2021/one-year-anniversary.md diff --git a/data/zh-TW/updates/2021/summary-202102.md b/data/zh-Hant/updates/2021/summary-202102.md similarity index 100% rename from data/zh-TW/updates/2021/summary-202102.md rename to data/zh-Hant/updates/2021/summary-202102.md diff --git a/data/zh-TW/updates/2021/summary-202108.md b/data/zh-Hant/updates/2021/summary-202108.md similarity index 100% rename from data/zh-TW/updates/2021/summary-202108.md rename to data/zh-Hant/updates/2021/summary-202108.md diff --git a/data/zh-TW/updates/2022/journal-2021h2.md b/data/zh-Hant/updates/2022/journal-2021h2.md similarity index 100% rename from data/zh-TW/updates/2022/journal-2021h2.md rename to data/zh-Hant/updates/2022/journal-2021h2.md diff --git a/data/zh-TW/updates/2023/10th-anniversary-special.md b/data/zh-Hant/updates/2023/10th-anniversary-special.md similarity index 100% rename from data/zh-TW/updates/2023/10th-anniversary-special.md rename to data/zh-Hant/updates/2023/10th-anniversary-special.md diff --git a/data/zh-TW/updates/2023/journal-2022.md b/data/zh-Hant/updates/2023/journal-2022.md similarity index 100% rename from data/zh-TW/updates/2023/journal-2022.md rename to data/zh-Hant/updates/2023/journal-2022.md diff --git a/data/zh-TW/updates/2023/lyrics-translation-completed.md b/data/zh-Hant/updates/2023/lyrics-translation-completed.md similarity index 100% rename from data/zh-TW/updates/2023/lyrics-translation-completed.md rename to data/zh-Hant/updates/2023/lyrics-translation-completed.md diff --git a/data/zh-TW/updates/2023/summary-202310.md b/data/zh-Hant/updates/2023/summary-202310.md similarity index 100% rename from data/zh-TW/updates/2023/summary-202310.md rename to data/zh-Hant/updates/2023/summary-202310.md diff --git a/data/zh-TW/updates/2024/journal-2023.md b/data/zh-Hant/updates/2024/journal-2023.md similarity index 100% rename from data/zh-TW/updates/2024/journal-2023.md rename to data/zh-Hant/updates/2024/journal-2023.md diff --git a/data/zh-TW/updates/2025/introducing-tss-rocks.md b/data/zh-Hant/updates/2025/introducing-tss-rocks.md similarity index 100% rename from data/zh-TW/updates/2025/introducing-tss-rocks.md rename to data/zh-Hant/updates/2025/introducing-tss-rocks.md diff --git a/data/zh-TW/updates/2025/journal-2024.md b/data/zh-Hant/updates/2025/journal-2024.md similarity index 100% rename from data/zh-TW/updates/2025/journal-2024.md rename to data/zh-Hant/updates/2025/journal-2024.md diff --git a/data/zh-TW/updates/2025/starset-mirror-now-part-of-wholetrans.md b/data/zh-Hant/updates/2025/starset-mirror-now-part-of-wholetrans.md similarity index 100% rename from data/zh-TW/updates/2025/starset-mirror-now-part-of-wholetrans.md rename to data/zh-Hant/updates/2025/starset-mirror-now-part-of-wholetrans.md diff --git a/data/zh-TW/updates/index/2020.json b/data/zh-Hant/updates/index/2020.json similarity index 100% rename from data/zh-TW/updates/index/2020.json rename to data/zh-Hant/updates/index/2020.json diff --git a/data/zh-TW/updates/index/2021.json b/data/zh-Hant/updates/index/2021.json similarity index 100% rename from data/zh-TW/updates/index/2021.json rename to data/zh-Hant/updates/index/2021.json diff --git a/data/zh-TW/updates/index/2022.json b/data/zh-Hant/updates/index/2022.json similarity index 100% rename from data/zh-TW/updates/index/2022.json rename to data/zh-Hant/updates/index/2022.json diff --git a/data/zh-TW/updates/index/2023.json b/data/zh-Hant/updates/index/2023.json similarity index 100% rename from data/zh-TW/updates/index/2023.json rename to data/zh-Hant/updates/index/2023.json diff --git a/data/zh-TW/updates/index/2024.json b/data/zh-Hant/updates/index/2024.json similarity index 100% rename from data/zh-TW/updates/index/2024.json rename to data/zh-Hant/updates/index/2024.json diff --git a/data/zh-TW/updates/index/2025.json b/data/zh-Hant/updates/index/2025.json similarity index 100% rename from data/zh-TW/updates/index/2025.json rename to data/zh-Hant/updates/index/2025.json diff --git a/docs/README.md b/docs/README.md index 5c0e54e..df9788c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,3 @@ -- [简体中文](./zh-CN/) -- [繁體中文](./zh-TW/) -- [English](./en-US/) +- [简体中文](./zh-Hans/) +- [繁體中文](./zh-Hant/) +- [English](./en/) diff --git a/docs/en-US/CONTRIBUTING.md b/docs/en/CONTRIBUTING.md similarity index 100% rename from docs/en-US/CONTRIBUTING.md rename to docs/en/CONTRIBUTING.md diff --git a/docs/zh-CN/CONTRIBUTING.md b/docs/zh-Hans/CONTRIBUTING.md similarity index 100% rename from docs/zh-CN/CONTRIBUTING.md rename to docs/zh-Hans/CONTRIBUTING.md diff --git a/docs/zh-TW/CONTRIBUTING.md b/docs/zh-Hant/CONTRIBUTING.md similarity index 100% rename from docs/zh-TW/CONTRIBUTING.md rename to docs/zh-Hant/CONTRIBUTING.md diff --git a/scripts/generate-rss.ts b/scripts/generate-rss.ts index 4c56dbd..81d9a8d 100644 --- a/scripts/generate-rss.ts +++ b/scripts/generate-rss.ts @@ -14,22 +14,22 @@ interface LanguageConfig { const LANGUAGES: LanguageConfig[] = [ { - code: 'en-US', - dataDir: 'en-US', - title: 'STARSET Mirror Site Updates', - description: 'Latest updates from STARSET Mirror Site' + code: 'en', + dataDir: 'en', + title: 'Starset Mirror - Updates', + description: 'Latest updates from Starset Mirror' }, { - code: 'zh-CN', - dataDir: 'zh-CN', - title: 'STARSET Mirror 项目动态', - description: 'STARSET Mirror 最新动态' + code: 'zh-Hans', + dataDir: 'zh-Hans', + title: 'Starset Mirror - 更新', + description: 'Starset Mirror 的最新更新' }, { code: 'zh-Hant', - dataDir: 'zh-TW', - title: 'STARSET Mirror 專案動态', - description: 'STARSET Mirror 最新動態' + dataDir: 'zh-Hant', + title: 'Starset Mirror - 更新', + description: 'Starset Mirror 的最新更新' } ]; diff --git a/scripts/generate-sitemap.ts b/scripts/generate-sitemap.ts index 0c1ce36..db8492e 100644 --- a/scripts/generate-sitemap.ts +++ b/scripts/generate-sitemap.ts @@ -6,7 +6,7 @@ import xml2js from 'xml2js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const LANGUAGES = ['en-US', 'zh-CN', 'zh-TW']; +const LANGUAGES = ['en', 'zh-Hans', 'zh-Hant']; const BASE_URL = 'mirror.starset.fans'; interface Update { diff --git a/scripts/generate-update-sitemaps.js b/scripts/generate-update-sitemaps.js index bc4aeed..1126697 100644 --- a/scripts/generate-update-sitemaps.js +++ b/scripts/generate-update-sitemaps.js @@ -6,7 +6,7 @@ import xml2js from 'xml2js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const LANGUAGES = ['en-US', 'zh-CN', 'zh-TW']; +const LANGUAGES = ['en', 'zh-Hans', 'zh-Hant']; const BASE_URL = 'starset.wiki'; // Replace with your actual domain async function getYearlyIndices(lang) { diff --git a/src/components/About.tsx b/src/components/About.tsx index ca5d26b..1472682 100644 --- a/src/components/About.tsx +++ b/src/components/About.tsx @@ -4,22 +4,24 @@ import iconMap from '../utils/iconMap'; const About = () => { const { t } = useTranslation(); - const aboutData = t('data.about', { returnObjects: true }); - const socialLinks = t('social.links', { returnObjects: true }); + const aboutData = t('data.about', { returnObjects: true }) || {}; + const socialLinks = t('social.links', { returnObjects: true }) || []; + + if (!aboutData) return null; return (

{t('about.title')}

- {aboutData.content.intro.map((paragraph: string, index: number) => ( + {aboutData.content?.intro?.map((paragraph: string, index: number) => (

{paragraph}

))}
- {aboutData.stats.map((stat: { value: string; label: string }, index: number) => ( + {aboutData.stats?.map((stat: { value: string; label: string }, index: number) => (

{stat.value}

{stat.label}

@@ -27,7 +29,7 @@ const About = () => { ))}
- {aboutData.content.workScope && ( + {aboutData.content?.workScope && (

工作范围

    @@ -36,7 +38,7 @@ const About = () => { {index + 1} - {item} + {item} ))}
@@ -67,14 +69,14 @@ const About = () => {

{t('about.join.title')}

- {aboutData.content.contact.description} + {aboutData.content?.contact?.description}

diff --git a/src/components/Comments.tsx b/src/components/Comments.tsx index 0f6fe37..183b282 100644 --- a/src/components/Comments.tsx +++ b/src/components/Comments.tsx @@ -1,5 +1,6 @@ import { useCallback, useRef, useEffect } from 'react' import { useLocation } from 'react-router-dom' +import { useTranslation } from 'react-i18next' import 'artalk/dist/Artalk.css' import Artalk from 'artalk' @@ -9,6 +10,7 @@ interface CommentsProps { const Comments = ({ title }: CommentsProps) => { const { pathname } = useLocation() + const { t } = useTranslation() const artalkRef = useRef() const containerRef = useRef(null) diff --git a/src/components/Contributors.tsx b/src/components/Contributors.tsx index f9aabe2..7059b00 100644 --- a/src/components/Contributors.tsx +++ b/src/components/Contributors.tsx @@ -23,7 +23,8 @@ interface Contributor { const Contributors: React.FC = () => { const { t } = useTranslation(); - const members = t('data.contributors.members', { returnObjects: true }) as Contributor[]; + const contributorsData = t('data.contributors', { returnObjects: true }) || {}; + const members = Array.isArray(contributorsData.members) ? contributorsData.members : []; // Fisher-Yates shuffle algorithm const shuffleArray = (array: T[]): T[] => { diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx index 12f94ad..7570ed9 100644 --- a/src/components/LanguageSwitcher.tsx +++ b/src/components/LanguageSwitcher.tsx @@ -8,9 +8,9 @@ const LanguageSwitcher = () => { const menuRef = useRef(null); const languages = [ - { code: 'zh-CN', name: '简体中文' }, - { code: 'zh-TW', name: '繁體中文' }, - { code: 'en-US', name: 'English' } + { code: 'zh-Hans', name: '简体中文' }, + { code: 'zh-Hant', name: '繁體中文' }, + { code: 'en', name: 'English' } ]; useEffect(() => { diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx index 03a66f3..6670df8 100644 --- a/src/components/Projects.tsx +++ b/src/components/Projects.tsx @@ -13,18 +13,19 @@ interface Project { const Projects = () => { const { t } = useTranslation(); - const projects = t('data.projects.projects', { returnObjects: true }) as Project[]; + const projectsData = t('data.projects', { returnObjects: true }) || {}; + const projects = Array.isArray(projectsData.projects) ? projectsData.projects : []; const [selectedTags, setSelectedTags] = useState([]); // 获取所有可用的标签 const allTags = Array.from( - new Set(projects.flatMap(project => project.tags)) + new Set(projects.flatMap(project => project.tags || [])) ); // 根据选中的标签筛选项目 const filteredProjects = selectedTags.length > 0 ? projects.filter(project => - selectedTags.every(tag => project.tags.includes(tag)) + selectedTags.every(tag => (project.tags || []).includes(tag)) ) : projects; @@ -119,7 +120,7 @@ const Projects = () => { {/* 标签区域固定高度 */}
- {project.tags.map((tag) => ( + {(project.tags || []).map((tag) => (
)} -

{sponsor.nickname}

+

{getMessage(sponsor)}

{sponsor.year} diff --git a/src/components/Timeline.tsx b/src/components/Timeline.tsx index 07be642..582f08c 100644 --- a/src/components/Timeline.tsx +++ b/src/components/Timeline.tsx @@ -62,6 +62,7 @@ const Pagination: React.FC = ({ const Timeline = () => { const { t, i18n } = useTranslation(); const LANGUAGE_CODE_MAP: Record = { + 'zh-CN': 'zh-Hans', 'zh-TW': 'zh-Hant' }; const [searchParams, setSearchParams] = useSearchParams(); diff --git a/src/components/TranslationBackground.tsx b/src/components/TranslationBackground.tsx index 8ff1609..9c29bc6 100644 --- a/src/components/TranslationBackground.tsx +++ b/src/components/TranslationBackground.tsx @@ -36,10 +36,33 @@ const TranslationBackground = () => { setIsVisible(true); }, []); + const getLanguageName = (language: string) => { + switch (language) { + case 'zh-Hans': + return '简体中文'; + case 'zh-Hant': + return '繁體中文'; + default: + return 'English'; + } + }; + + const getTranslationName = (language: string) => { + switch (language) { + case 'zh-Hans': + case 'zh-Hant': + return '翻译'; + default: + return 'Translation'; + } + }; + const getMainText = (translation: typeof translations.translations[0]) => { switch (i18n.language) { + case 'zh-Hans': case 'zh-CN': return translation.zh_CN; + case 'zh-Hant': case 'zh-TW': return translation.zh_TW; default: @@ -49,7 +72,9 @@ const TranslationBackground = () => { const getSecondaryText = (translation: typeof translations.translations[0]) => { switch (i18n.language) { + case 'zh-Hans': case 'zh-CN': + case 'zh-Hant': case 'zh-TW': return translation.en; default: diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 50626e6..a0d1e58 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -3,42 +3,42 @@ import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; // 导入翻译文件 -import zhCNTranslation from '../../data/zh-CN/index.json'; -import zhTWTranslation from '../../data/zh-TW/index.json'; -import enUSTranslation from '../../data/en-US/index.json'; +import zhHansTranslation from '../../data/zh-Hans/index.json'; +import zhHantTranslation from '../../data/zh-Hant/index.json'; +import enTranslation from '../../data/en/index.json'; // 导入数据文件 -import zhCNAbout from '../../data/zh-CN/about.json'; -import zhCNProjects from '../../data/zh-CN/projects.json'; -import zhCNContributors from '../../data/zh-CN/contributors.json'; -import zhCNUpdates from '../../data/zh-CN/updates.json'; +import zhHansAbout from '../../data/zh-Hans/about.json'; +import zhHansProjects from '../../data/zh-Hans/projects.json'; +import zhHansContributors from '../../data/zh-Hans/contributors.json'; +import zhHansUpdates from '../../data/zh-Hans/updates.json'; -import zhTWAbout from '../../data/zh-TW/about.json'; -import zhTWProjects from '../../data/zh-TW/projects.json'; -import zhTWContributors from '../../data/zh-TW/contributors.json'; -import zhTWUpdates from '../../data/zh-TW/updates.json'; +import zhHantAbout from '../../data/zh-Hant/about.json'; +import zhHantProjects from '../../data/zh-Hant/projects.json'; +import zhHantContributors from '../../data/zh-Hant/contributors.json'; +import zhHantUpdates from '../../data/zh-Hant/updates.json'; -import enUSAbout from '../../data/en-US/about.json'; -import enUSProjects from '../../data/en-US/projects.json'; -import enUSContributors from '../../data/en-US/contributors.json'; -import enUSUpdates from '../../data/en-US/updates.json'; +import enAbout from '../../data/en/about.json'; +import enProjects from '../../data/en/projects.json'; +import enContributors from '../../data/en/contributors.json'; +import enUpdates from '../../data/en/updates.json'; i18n .use(LanguageDetector) .use(initReactI18next) .init({ resources: { - 'zh-CN': { - translation: zhCNTranslation.translation + 'zh-Hans': { + translation: zhHansTranslation.translation }, - 'zh-TW': { - translation: zhTWTranslation.translation + 'zh-Hant': { + translation: zhHantTranslation.translation }, - 'en-US': { - translation: enUSTranslation.translation + 'en': { + translation: enTranslation.translation } }, - fallbackLng: 'zh-CN', + fallbackLng: 'zh-Hans', interpolation: { escapeValue: false, }, @@ -48,30 +48,30 @@ i18n }); // 添加数据命名空间 -i18n.addResourceBundle('zh-CN', 'translation', { +i18n.addResourceBundle('zh-Hans', 'translation', { data: { - about: zhCNAbout, - projects: zhCNProjects, - contributors: zhCNContributors, - updates: zhCNUpdates + about: zhHansAbout, + projects: zhHansProjects, + contributors: zhHansContributors, + updates: zhHansUpdates } }, true, true); -i18n.addResourceBundle('zh-TW', 'translation', { +i18n.addResourceBundle('zh-Hant', 'translation', { data: { - about: zhTWAbout, - projects: zhTWProjects, - contributors: zhTWContributors, - updates: zhTWUpdates + about: zhHantAbout, + projects: zhHantProjects, + contributors: zhHantContributors, + updates: zhHantUpdates } }, true, true); -i18n.addResourceBundle('en-US', 'translation', { +i18n.addResourceBundle('en', 'translation', { data: { - about: enUSAbout, - projects: enUSProjects, - contributors: enUSContributors, - updates: enUSUpdates + about: enAbout, + projects: enProjects, + contributors: enContributors, + updates: enUpdates } }, true, true);