2020-11-29 03:31:29
构建一个支持多语言的JavaScript国际化(i18n)框架需定义语言包结构、封装核心I18n类、实现动态切换与文本替换逻辑,并支持与前端框架集成。以下是具体实现步骤与关键代码示例:
一、定义语言包结构将每种语言的翻译内容组织为嵌套的JSON对象,支持模块化分类和占位符参数。示例文件messages.js:
const messages = { en: { greeting: 'Hello, {name}!', welcome: 'Welcome to our app', error: { network: 'Network error occurred' } }, zh: { greeting: '你好,{name}!', welcome: '欢迎使用我们的应用', error: { network: '网络错误' } }, ja: { greeting: 'こんにちは、{name}!', welcome: 'アプリへようこそ', error: { network: 'ネットワークエラーが発生しました' } }};export default messages;关键点:
实现语言切换、文本查找、参数插值及错误处理逻辑。完整I18n类代码:
class I18n { constructor(messages, locale = 'en') { this.messages = messages; this.locale = locale; } // 切换语言,支持降级到默认语言'en' setLocale(locale) { if (!this.messages[locale]) { console.warn(`Locale ${locale} not found, fallback to en`); this.locale = 'en'; } else { this.locale = locale; } } // 根据键路径查找翻锋模并译文本并替换参数 t(key, params = {}) { const keys = key.split('.'); let result = this.messages[this.locale]; // 遍历嵌银迹套键路径 for (const k of keys) { if (!result || typeof result !== 'object') { console.warn(`Key path "${key}" not found in locale ${this.locale}`); return key; // 返回原始键作为降级方案 } result = result[k]; } // 处理非字符串结果(如未翻译的嵌套对象) if (typeof result !== 'string') { console.warn(`Value for key "${key}" is not a string`); return key; } // 替换占位符(如{name} → params.name) return result.replace(/{(w+)}/g, (match, propName) => { return params[propName] !== undefined ? params[propName] : match; }); }}核心功能:
创建I18n实例后,可直接调用t()方法获取翻译文本。示例代码:
import messages from './messages';const i18n = new I18n(messages, 'en');// 基础翻译console.log(i18n.t('greeting', { name: 'Alice' })); // 输出: Hello, Alice!// 切换语言i18n.setLocale('zh');console.log(i18n.t('greeting', { name: '小明' })); // 输出: 你好,小明!// 嵌套键翻译console.log(i18n.t('error.network')); // 输出: 网络错误四、集成到React框架通过React Context共享I18n实例,实现全局语言切换与组件响应式更新。
1. 创建Context与Providerimport React, { createContext, useContext, useState } from 'react';import I18n from './I18n';import messages from './messages';const I18nContext = createContext();export function I18nProvider({ children }) { const [i18n] = useState(() => new I18n(messages, 'en')); return ( <I18nContext.Provider value={{ i18n }}> {children} </I18nContext.Provider> );}2. 封装useI18n Hook简化组件内调用,自动绑定this上下文:
export function useI18n() { const { i18n } = useContext(I18nContext); return i18n.t.bind(i18n); // 确保this指向i18n实例}3. 组件中使用示例function App() { const t = useI18n(); return <div>{t('welcome')}</div>; // 输出当前语言的欢迎语}function LanguageSwitcher() { const { i18n } = useContext(I18nContext); return ( <div> <button onClick={() => i18n.setLocale('en')}>English</button> <button onClick={() => i18n.setLocale('zh')}>中文</button> <button onClick={() => i18n.setLocale('ja')}>日本语</button> </div> );}五、扩展功能建议该框架通过模块化语言包、核心类封装、Context集成三步实现国际化,具备以下优势:
可根据实际需求进一步扩展功能,如添加复数规则或集成第三方格式化库。