CloudTech/lib/i18n.ts

110 lines
3.1 KiB
TypeScript
Raw Normal View History

2025-09-16 18:00:27 +08:00
import { useState, useEffect } from 'react';
import { useParams, useRouter } from 'next/navigation';
type Locale = 'zh-CN' | 'zh-TW' | 'en';
interface TranslationData {
[key: string]: any;
}
const translations: Record<Locale, Record<string, TranslationData>> = {
'zh-CN': {},
'zh-TW': {},
en: {},
};
// Load translation files dynamically
const loadTranslations = async (locale: Locale, namespace: string): Promise<TranslationData> => {
if (translations[locale][namespace]) {
return translations[locale][namespace];
}
try {
const response = await fetch(`/locales/${locale}/${namespace}.json`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
translations[locale][namespace] = data;
return data;
} catch (error) {
console.error(`Failed to load translation: ${locale}/${namespace}`, error);
return {};
}
};
export const useTranslation = (namespace: string = 'common') => {
const params = useParams();
const router = useRouter();
const urlLocale = params?.locale as Locale;
const [locale, setLocale] = useState<Locale>(urlLocale || 'zh-CN');
const [translations, setTranslations] = useState<TranslationData>({});
const [loading, setLoading] = useState(true);
useEffect(() => {
// 如果URL中有locale参数优先使用URL中的语言
if (urlLocale && urlLocale !== locale) {
setLocale(urlLocale);
}
}, [urlLocale, locale]);
useEffect(() => {
const loadData = async () => {
setLoading(true);
const data = await loadTranslations(locale, namespace);
setTranslations(data);
setLoading(false);
};
loadData();
}, [locale, namespace]);
const changeLocale = (newLocale: Locale) => {
// 更新localStorage
localStorage.setItem('language', newLocale);
// 构建新的URL路径
const currentPath = window.location.pathname;
const pathWithoutLocale = currentPath.replace(/^\/[^\/]+/, '');
const newPath = `/${newLocale}${pathWithoutLocale}`;
// 导航到新的语言路径
router.push(newPath);
};
const t = (key: string, defaultValue?: string): string => {
const keys = key.split('.');
let value = translations;
for (const k of keys) {
if (value && typeof value === 'object' && k in value) {
value = value[k];
} else {
return defaultValue || key;
}
}
return typeof value === 'string' ? value : defaultValue || key;
};
return {
t,
locale,
setLocale: changeLocale,
loading,
};
};
// 语言切换工具函数
export const getLocalizedPath = (path: string, locale: Locale): string => {
return `/${locale}${path}`;
};
// 验证locale是否有效
export const isValidLocale = (locale: string): locale is Locale => {
return ['zh-CN', 'zh-TW', 'en'].includes(locale);
};
export type { Locale };