mirror of
https://github.com/StepanovPlaton/AboutMe.git
synced 2026-04-03 20:30:49 +04:00
210 lines
7.6 KiB
TypeScript
210 lines
7.6 KiB
TypeScript
import {
|
||
type SupportedLanguage,
|
||
SUPPORTED_LANGUAGES,
|
||
langToTranslateMap,
|
||
translateToLangMap,
|
||
LANGUAGE_CONFIG,
|
||
} from "@i18n/language";
|
||
import {
|
||
siteConfig,
|
||
} from "@/config";
|
||
|
||
|
||
// 重新导出以保持向后兼容
|
||
export { SUPPORTED_LANGUAGES, type SupportedLanguage, langToTranslateMap, translateToLangMap };
|
||
|
||
|
||
// 语言存储键
|
||
const LANG_STORAGE_KEY = "selected-language";
|
||
|
||
// 存储语言设置
|
||
export function setStoredLanguage(lang: string): void {
|
||
if (typeof localStorage !== "undefined") {
|
||
localStorage.setItem(LANG_STORAGE_KEY, lang);
|
||
}
|
||
}
|
||
|
||
// 获取存储的语言设置
|
||
export function getStoredLanguage(): string | null {
|
||
if (typeof localStorage !== "undefined") {
|
||
return localStorage.getItem(LANG_STORAGE_KEY);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 获取默认语言配置
|
||
export function getDefaultLanguage(): string {
|
||
const fallback = siteConfig.lang;
|
||
if (typeof document !== "undefined") {
|
||
const configCarrier = document.getElementById("config-carrier");
|
||
return configCarrier?.dataset.lang || fallback;
|
||
}
|
||
return fallback;
|
||
}
|
||
|
||
// 将配置文件的语言代码转换为翻译服务的语言代码
|
||
export function getTranslateLanguageFromConfig(configLang: string): string {
|
||
return langToTranslateMap[configLang] || "chinese_simplified";
|
||
}
|
||
|
||
// 获取解析后的站点语言代码
|
||
export function getResolvedSiteLang(): SupportedLanguage {
|
||
const configLang = getDefaultLanguage() as any;
|
||
if (SUPPORTED_LANGUAGES.includes(configLang)) {
|
||
return configLang as SupportedLanguage;
|
||
}
|
||
// 如果 siteConfig.lang 不合规,则使用浏览器检测到的语言
|
||
return detectBrowserLanguage();
|
||
}
|
||
|
||
// 将翻译服务的语言代码转换为配置文件的语言代码
|
||
export function getConfigLanguageFromTranslate(translateLang: string): string {
|
||
return translateToLangMap[translateLang] || "zh";
|
||
}
|
||
|
||
// 获取语言的显示名称
|
||
export function getLanguageDisplayName(langCode: string): string {
|
||
// 先尝试作为配置语言代码查找
|
||
if (langCode in LANGUAGE_CONFIG) {
|
||
return LANGUAGE_CONFIG[langCode as SupportedLanguage].displayName;
|
||
}
|
||
// 尝试作为翻译服务代码查找
|
||
const configLang = translateToLangMap[langCode];
|
||
if (configLang && configLang in LANGUAGE_CONFIG) {
|
||
return LANGUAGE_CONFIG[configLang as SupportedLanguage].displayName;
|
||
}
|
||
// 如果都找不到,返回原始代码
|
||
return langCode;
|
||
}
|
||
|
||
// 检测浏览器语言并返回支持的语言代码
|
||
export function detectBrowserLanguage(fallbackLang: SupportedLanguage = "en"): SupportedLanguage {
|
||
// 服务端渲染时返回备用语言
|
||
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
||
return fallbackLang;
|
||
}
|
||
// 获取浏览器语言列表
|
||
const browserLangs = navigator.languages || [navigator.language];
|
||
// 遍历浏览器语言列表,找到第一个支持的语言
|
||
for (const browserLang of browserLangs) {
|
||
// 提取主语言代码(例如:'zh-CN' -> 'zh', 'en-US' -> 'en')
|
||
const langCode = browserLang.toLowerCase().split("-")[0];
|
||
// 检查是否在支持的语言列表中
|
||
if (SUPPORTED_LANGUAGES.includes(langCode as SupportedLanguage)) {
|
||
return langCode as SupportedLanguage;
|
||
}
|
||
}
|
||
// 如果没有找到支持的语言,返回备用语言
|
||
return fallbackLang;
|
||
}
|
||
|
||
// 获取当前站点语言(优先使用缓存,其次是配置语言,最后是浏览器检测)
|
||
export function getSiteLanguage(configLang?: string): string {
|
||
// 优先从缓存读取
|
||
const storedLang = getStoredLanguage();
|
||
if (storedLang) return storedLang;
|
||
// 其次使用传入的配置语言或从 carrier 获取的默认语言
|
||
const defaultLang = configLang || getDefaultLanguage();
|
||
if (SUPPORTED_LANGUAGES.includes(defaultLang as SupportedLanguage)) {
|
||
return langToTranslateMap[defaultLang];
|
||
}
|
||
// 最后自动检测浏览器语言并转换为翻译服务代码
|
||
const browserLang = detectBrowserLanguage();
|
||
return langToTranslateMap[browserLang];
|
||
}
|
||
|
||
// 初始化翻译功能
|
||
export function initTranslateService(): void {
|
||
if (typeof window === "undefined" || !siteConfig.translate?.enable) return;
|
||
// 检查 translate.js 是否已加载
|
||
const translate = (window as any).translate;
|
||
if (!translate || (window as any).translateInitialized) return;
|
||
// 配置 translate.js
|
||
if (siteConfig.translate.service) {
|
||
translate.service.use(siteConfig.translate.service);
|
||
}
|
||
// 设置源语言(始终是网站渲染的语言)
|
||
const resolvedLang = getResolvedSiteLang();
|
||
const sourceLang = getTranslateLanguageFromConfig(resolvedLang);
|
||
translate.language.setLocal(sourceLang);
|
||
// 获取目标语言(缓存 -> 配置 -> 浏览器)
|
||
const targetLang = getSiteLanguage(resolvedLang);
|
||
// 如果目标语言不同于源语言,则设置目标语言
|
||
if (targetLang && targetLang !== sourceLang) {
|
||
translate.to = targetLang;
|
||
}
|
||
// 自动识别语言
|
||
if (siteConfig.translate.autoDiscriminate) {
|
||
translate.setAutoDiscriminateLocalLanguage();
|
||
}
|
||
// 设置忽略项
|
||
if (siteConfig.translate.ignoreClasses) {
|
||
siteConfig.translate.ignoreClasses.forEach((className: string) => {
|
||
translate.ignore.class.push(className);
|
||
});
|
||
}
|
||
if (siteConfig.translate.ignoreTags) {
|
||
siteConfig.translate.ignoreTags.forEach((tagName: string) => {
|
||
translate.ignore.tag.push(tagName);
|
||
});
|
||
}
|
||
// UI 配置
|
||
if (siteConfig.translate.showSelectTag === false) {
|
||
translate.selectLanguageTag.show = false;
|
||
}
|
||
// 接管存储逻辑:使用自定义缓存并同步到 translate.js
|
||
translate.storage.set = function (key: string, value: string) {
|
||
if (key === "to") { // translate.js 使用 "to" 存储目标语言
|
||
setStoredLanguage(value);
|
||
} else {
|
||
localStorage.setItem(key, value);
|
||
}
|
||
};
|
||
translate.storage.get = function (key: string) {
|
||
if (key === "to") {
|
||
return getStoredLanguage();
|
||
}
|
||
return localStorage.getItem(key);
|
||
};
|
||
// 启动翻译监听
|
||
translate.listener.start();
|
||
(window as any).translateInitialized = true;
|
||
// 如果目标语言存在且不是源语言,执行翻译
|
||
// 强制执行一次 execute 以确保初始化时应用翻译
|
||
if (translate.to && translate.to !== translate.language.getLocal()) {
|
||
// 延迟一小段时间执行,确保 DOM 完全就绪
|
||
setTimeout(() => {
|
||
translate.execute();
|
||
}, 10);
|
||
} else if (translate.to === translate.language.getLocal()) {
|
||
// 如果目标语言就是源语言,确保处于未翻译状态
|
||
// 有时插件可能会残留之前的翻译状态
|
||
translate.reset();
|
||
}
|
||
}
|
||
|
||
// 加载并初始化翻译功能
|
||
export async function loadAndInitTranslate(): Promise<void> {
|
||
if (typeof window === "undefined" || !siteConfig.translate?.enable) return;
|
||
try {
|
||
// 检查是否已经加载
|
||
if (!(window as any).translate) {
|
||
// 使用动态导入,Vite 会自动处理代码分割
|
||
await import("@/plugins/translate");
|
||
(window as any).translateScriptLoaded = true;
|
||
}
|
||
// 初始化服务
|
||
initTranslateService();
|
||
} catch (error) {
|
||
console.error('Failed to load or init translate.js:', error);
|
||
}
|
||
}
|
||
|
||
// 切换语言
|
||
export function toggleLanguage(langCode: string): void {
|
||
const translate = (window as any).translate;
|
||
if (!translate) return;
|
||
// 切换语言
|
||
translate.changeLanguage(langCode);
|
||
setStoredLanguage(langCode);
|
||
} |