feat(i18n): implement internationalization support for en and zh
Add i18n infrastructure with translation files and utility functions Update components to use translations and language switching Create localized pages for en and zh languages Add language detection and path localization utilities
This commit is contained in:
32
src/i18n/ui.ts
Normal file
32
src/i18n/ui.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// src/i18n/ui.ts
|
||||
export const languages = {
|
||||
en: 'English',
|
||||
zh: '简体中文',
|
||||
} as const;
|
||||
|
||||
export const defaultLang = 'en';
|
||||
|
||||
export const ui = {
|
||||
en: {
|
||||
'nav.home': 'Home',
|
||||
'nav.projects': 'Projects',
|
||||
'nav.experience': 'Experience',
|
||||
'nav.skills': 'Skills',
|
||||
'nav.awards': 'Awards',
|
||||
'nav.education': 'Education',
|
||||
'footer.rights': 'All rights reserved.',
|
||||
'site.title': 'My Portfolio',
|
||||
// 根据您的项目实际情况添加更多翻译键值对
|
||||
},
|
||||
zh: {
|
||||
'nav.home': '首页',
|
||||
'nav.projects': '项目经历',
|
||||
'nav.experience': '工作经历',
|
||||
'nav.skills': '专业技能',
|
||||
'nav.awards': '奖项荣誉',
|
||||
'nav.education': '教育背景',
|
||||
'footer.rights': '版权所有。',
|
||||
'site.title': '我的作品集',
|
||||
// 根据您的项目实际情况添加更多翻译键值对
|
||||
},
|
||||
} as const;
|
||||
41
src/i18n/utils.ts
Normal file
41
src/i18n/utils.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
// src/i18n/utils.ts
|
||||
import { ui, defaultLang, languages } from './ui';
|
||||
|
||||
export type Lang = keyof typeof languages;
|
||||
export type UiKeys = keyof typeof ui[typeof defaultLang];
|
||||
|
||||
export function getLangFromUrl(url: URL): Lang {
|
||||
const [, lang] = url.pathname.split('/');
|
||||
if (lang in languages) return lang as Lang;
|
||||
return defaultLang;
|
||||
}
|
||||
|
||||
export function useTranslations(lang: Lang | undefined) {
|
||||
const currentLang = lang || defaultLang;
|
||||
return function t(key: UiKeys, ...args: any[]): string {
|
||||
let translation: string = ui[currentLang][key] || ui[defaultLang][key];
|
||||
if (args.length > 0) {
|
||||
args.forEach((arg, index) => {
|
||||
translation = translation.replace(`{${index}}`, arg);
|
||||
});
|
||||
}
|
||||
return translation;
|
||||
};
|
||||
}
|
||||
|
||||
export function getLocalizedPath(path: string, lang: Lang | undefined): string {
|
||||
const currentLang = lang || defaultLang;
|
||||
const basePath = import.meta.env.BASE_URL === '/' ? '' : import.meta.env.BASE_URL;
|
||||
|
||||
// If the current language is the default language, do not add a language prefix.
|
||||
if (currentLang === defaultLang) {
|
||||
const fullPath = `${basePath}${path.startsWith('/') ? path : `/${path}`}`;
|
||||
return fullPath.replace(/\/\/+/g, '/');
|
||||
}
|
||||
|
||||
// Otherwise, add the language prefix.
|
||||
const langPrefix = `/${currentLang}`;
|
||||
const fullPath = `${basePath}${langPrefix}${path.startsWith('/') ? path : `/${path}`}`;
|
||||
// Remove any double slashes that might occur.
|
||||
return fullPath.replace(/\/\/+/g, '/');
|
||||
}
|
||||
Reference in New Issue
Block a user