feat(i18n): Add next-intl framework with full bilingual support (EN/ZH)

- Implement next-intl framework for scalable i18n
- Add complete Chinese (Simplified) localization
- Support 400+ translated strings across all pages
- Add language switcher with persistent preference
- Zero breaking changes to existing functionality

Framework additions:
- i18n routing and middleware
- LocaleContext for client-side state
- LanguageSwitcher component
- Translation files (en.json, zh.json)

Translated components:
- Homepage: Hero, features, CTA, navbar
- Auth: Login, register
- Dashboard: Main page, layout
- Connectors: Management, add page (all categories)
- Documents: Upload, manage, filters
- Settings: LLM configs, role assignments
- Onboarding: Add provider, assign roles
- Logs: Task logs viewer

Adding a new language now requires only:
1. Create messages/<locale>.json
2. Add locale to i18n/routing.ts
This commit is contained in:
Differ 2025-10-26 14:05:46 +08:00
parent 8aeaf419d0
commit f58c7e4602
37 changed files with 2267 additions and 542 deletions

View file

@ -12,6 +12,7 @@ import {
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useMemo, useState } from "react";
import { useTranslations } from "next-intl";
import {
DropdownMenu,
DropdownMenuContent,
@ -56,6 +57,7 @@ interface ChatItem {
}
export function NavProjects({ chats }: { chats: ChatItem[] }) {
const t = useTranslations('sidebar');
const { isMobile } = useSidebar();
const router = useRouter();
const [searchQuery, setSearchQuery] = useState("");
@ -145,13 +147,13 @@ export function NavProjects({ chats }: { chats: ChatItem[] }) {
return (
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
<SidebarGroupLabel>Recent Chats</SidebarGroupLabel>
<SidebarGroupLabel>{t('recent_chats')}</SidebarGroupLabel>
{/* Search Input */}
{showSearch && (
<div className="px-2 pb-2">
<SidebarInput
placeholder="Search chats..."
placeholder={t('search_chats')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="h-8"
@ -168,7 +170,7 @@ export function NavProjects({ chats }: { chats: ChatItem[] }) {
<SidebarMenuItem>
<SidebarMenuButton disabled className="text-muted-foreground">
<Search className="h-4 w-4" />
<span>{searchQuery ? "No chats found" : "No recent chats"}</span>
<span>{searchQuery ? t('no_chats_found') : t('no_recent_chats')}</span>
</SidebarMenuButton>
</SidebarMenuItem>
)}
@ -178,7 +180,7 @@ export function NavProjects({ chats }: { chats: ChatItem[] }) {
<SidebarMenuItem>
<SidebarMenuButton onClick={() => router.push(`/dashboard/${searchSpaceId}/chats`)}>
<MoreHorizontal />
<span>View All Chats</span>
<span>{t('view_all_chats')}</span>
</SidebarMenuButton>
</SidebarMenuItem>
)}