mirror of
https://github.com/StepanovPlaton/AboutMe.git
synced 2026-04-04 04:40:51 +04:00
Initial commit
This commit is contained in:
210
src/utils/language.ts
Normal file
210
src/utils/language.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user