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,
|
|||
|
|
};
|
|||
|
|
};
|