feat: P0a i18n 基础设施 + UI 语言切换

- 创建 i18n 模块 (provider + useT hook + useLang hook)
- 中/英翻译文件 (zh.ts / en.ts),覆盖沙盒/学习/会员/对比等核心页面
- LanguageProvider 包装 layout,支持 localStorage 持久化
- Header 添加语言切换按钮 (中<>EN)
- AGENTS.md 新增国际化约定
- opencode 源码克隆到 /tmp/opencode-source/ 供参考
This commit is contained in:
yuzhiran-dev
2026-05-18 10:12:37 +08:00
parent 11bb86854c
commit 9efa2d0425
10 changed files with 400 additions and 27 deletions
+11 -1
View File
@@ -6,9 +6,10 @@ import { usePathname } from 'next/navigation';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { ThemeToggle } from '@/components/ui/theme-toggle';
import { Search, Menu, X, Bell } from 'lucide-react';
import { Search, Menu, X, Bell, Languages } from 'lucide-react';
import { apiFetch } from '@/lib/auth';
import { useAuth } from '@/lib/auth-context';
import { useLang } from '@/i18n';
const navItems = [
{ href: '/', label: '首页' },
@@ -60,6 +61,7 @@ export function Header() {
const [mobileOpen, setMobileOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const { isLoggedIn, logout } = useAuth();
const { lang, setLang } = useLang();
function isActive(href: string) {
if (href === '/') return pathname === '/';
@@ -114,6 +116,10 @@ export function Header() {
/>
</form>
<ThemeToggle />
<button onClick={() => setLang(lang === 'zh' ? 'en' : 'zh')}
className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-colors text-xs font-medium">
{lang === 'zh' ? 'EN' : '中'}
</button>
</div>
<div className="hidden md:flex items-center gap-2">
@@ -145,6 +151,10 @@ export function Header() {
<div className="flex md:hidden items-center gap-2">
<ThemeToggle />
<button onClick={() => setLang(lang === 'zh' ? 'en' : 'zh')}
className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-colors text-xs font-medium">
{lang === 'zh' ? 'EN' : '中'}
</button>
<Button
variant="ghost"
size="icon"