mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-26 21:39:43 +02:00
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:
parent
8aeaf419d0
commit
f58c7e4602
37 changed files with 2267 additions and 542 deletions
70
surfsense_web/contexts/LocaleContext.tsx
Normal file
70
surfsense_web/contexts/LocaleContext.tsx
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
'use client';
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import enMessages from '../messages/en.json';
|
||||
import zhMessages from '../messages/zh.json';
|
||||
|
||||
type Locale = 'en' | 'zh';
|
||||
|
||||
interface LocaleContextType {
|
||||
locale: Locale;
|
||||
messages: typeof enMessages;
|
||||
setLocale: (locale: Locale) => void;
|
||||
}
|
||||
|
||||
const LocaleContext = createContext<LocaleContextType | undefined>(undefined);
|
||||
|
||||
const LOCALE_STORAGE_KEY = 'surfsense-locale';
|
||||
|
||||
export function LocaleProvider({ children }: { children: React.ReactNode }) {
|
||||
// Always start with 'en' to avoid hydration mismatch
|
||||
// Then sync with localStorage after mount
|
||||
const [locale, setLocaleState] = useState<Locale>('en');
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
// Get messages based on current locale
|
||||
const messages = locale === 'zh' ? zhMessages : enMessages;
|
||||
|
||||
// Load locale from localStorage after component mounts (client-side only)
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
if (typeof window !== 'undefined') {
|
||||
const stored = localStorage.getItem(LOCALE_STORAGE_KEY);
|
||||
if (stored === 'zh') {
|
||||
setLocaleState('zh');
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Update locale and persist to localStorage
|
||||
const setLocale = (newLocale: Locale) => {
|
||||
setLocaleState(newLocale);
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(LOCALE_STORAGE_KEY, newLocale);
|
||||
// Update HTML lang attribute
|
||||
document.documentElement.lang = newLocale;
|
||||
}
|
||||
};
|
||||
|
||||
// Set HTML lang attribute when locale changes
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined' && mounted) {
|
||||
document.documentElement.lang = locale;
|
||||
}
|
||||
}, [locale, mounted]);
|
||||
|
||||
return (
|
||||
<LocaleContext.Provider value={{ locale, messages, setLocale }}>
|
||||
{children}
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useLocaleContext() {
|
||||
const context = useContext(LocaleContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useLocaleContext must be used within a LocaleProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue