139 lines
4.6 KiB
TypeScript
139 lines
4.6 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
|
||
import { Language, defaultLanguage } from './config';
|
||
import { getTranslation } from './translations';
|
||
import {
|
||
getLanguageFromPath,
|
||
removeLanguageFromPath,
|
||
addLanguageToPath,
|
||
getStoredLanguage,
|
||
setStoredLanguage,
|
||
getBrowserLanguage,
|
||
} from './utils';
|
||
|
||
export const useTranslation = (initialLanguage?: Language) => {
|
||
const router = useRouter();
|
||
const pathname = usePathname();
|
||
const searchParams = useSearchParams();
|
||
const isChangingLanguage = useRef(false);
|
||
|
||
const [language, setLanguage] = useState<Language>(() => {
|
||
if (initialLanguage) return initialLanguage;
|
||
return defaultLanguage;
|
||
});
|
||
|
||
const [isInitialized, setIsInitialized] = useState(false);
|
||
|
||
const t = getTranslation(language);
|
||
|
||
const changeLanguage = useCallback(
|
||
(newLanguage: Language) => {
|
||
if (isChangingLanguage.current) return;
|
||
|
||
isChangingLanguage.current = true;
|
||
setLanguage(newLanguage);
|
||
setStoredLanguage(newLanguage);
|
||
|
||
// 使用 setTimeout 来避免状态更新冲突
|
||
setTimeout(() => {
|
||
// 首页特殊处理,切换语言时加上 ?lang=xx
|
||
if (pathname === '/' || pathname === '') {
|
||
const url = newLanguage === defaultLanguage ? '/' : `/?lang=${newLanguage}`;
|
||
router.push(url);
|
||
}
|
||
// 产品页面特殊处理
|
||
else if (pathname === '/products') {
|
||
const url =
|
||
newLanguage === defaultLanguage
|
||
? '/products'
|
||
: `/products?lang=${newLanguage}`;
|
||
router.push(url);
|
||
}
|
||
// 新闻页面特殊处理
|
||
else if (pathname === '/news') {
|
||
const url =
|
||
newLanguage === defaultLanguage ? '/news' : `/news?lang=${newLanguage}`;
|
||
router.push(url);
|
||
}
|
||
// 其他页面保持原有逻辑
|
||
else {
|
||
const currentPath = removeLanguageFromPath(pathname);
|
||
const newPath = addLanguageToPath(currentPath, newLanguage);
|
||
if (newPath !== pathname) {
|
||
router.push(newPath);
|
||
}
|
||
}
|
||
|
||
// 重置标志
|
||
setTimeout(() => {
|
||
isChangingLanguage.current = false;
|
||
}, 100);
|
||
}, 0);
|
||
},
|
||
[pathname, router],
|
||
);
|
||
|
||
const getLocalizedPath = useCallback(
|
||
(path: string) => {
|
||
return addLanguageToPath(path, language);
|
||
},
|
||
[language],
|
||
);
|
||
|
||
// 初始化语言设置
|
||
useEffect(() => {
|
||
if (isInitialized || isChangingLanguage.current) return;
|
||
|
||
let detectedLanguage = defaultLanguage;
|
||
|
||
if (initialLanguage) {
|
||
detectedLanguage = initialLanguage;
|
||
} else {
|
||
// 首页和产品页面支持 ?lang=xx
|
||
const search = searchParams ? `?${searchParams.toString()}` : '';
|
||
const urlLanguage = getLanguageFromPath(pathname, search);
|
||
|
||
if (urlLanguage !== defaultLanguage) {
|
||
detectedLanguage = urlLanguage;
|
||
} else {
|
||
// 尝试从存储中获取语言
|
||
const storedLanguage = getStoredLanguage();
|
||
if (storedLanguage !== defaultLanguage) {
|
||
detectedLanguage = storedLanguage;
|
||
} else {
|
||
// 最后尝试浏览器语言
|
||
detectedLanguage = getBrowserLanguage();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (detectedLanguage !== language) {
|
||
setLanguage(detectedLanguage);
|
||
}
|
||
|
||
setIsInitialized(true);
|
||
}, [initialLanguage, pathname, searchParams, language, isInitialized]);
|
||
|
||
// 监听URL变化,但避免在语言切换过程中触发
|
||
useEffect(() => {
|
||
if (!isInitialized || isChangingLanguage.current) return;
|
||
|
||
const search = searchParams ? `?${searchParams.toString()}` : '';
|
||
const urlLanguage = getLanguageFromPath(pathname, search);
|
||
|
||
if (urlLanguage !== language) {
|
||
setLanguage(urlLanguage);
|
||
}
|
||
}, [pathname, searchParams, language, isInitialized]);
|
||
|
||
return {
|
||
language,
|
||
t,
|
||
changeLanguage,
|
||
getLocalizedPath,
|
||
isInitialized,
|
||
};
|
||
};
|