@mico_fe/i18n-react
v1.0.0
Published
React 18 i18n runtime - auto internationalization
Downloads
177
Readme
@mico_fe/i18n-react
React 18 国际化运行时 - 自动国际化解决方案
📦 安装
npm install @mico_fe/i18n-react
# 或
pnpm add @mico_fe/i18n-react
# 或
yarn add @mico_fe/i18n-react配合编译时插件使用(推荐):
# Vite 项目
npm install @mico_fe/vite-plugin-i18n-react -D
# Webpack 项目
npm install babel-plugin-auto-i18n -D🚀 快速开始
1. 创建语言包
src/locales/
├── zh-CN.json
├── en-US.json
└── index.tszh-CN.json
{
"button.submit": "提交",
"button.cancel": "取消",
"message.welcome": "欢迎使用",
"message.greeting": "你好,{name}!",
"message.items": "共 {count} 条数据"
}en-US.json
{
"button.submit": "Submit",
"button.cancel": "Cancel",
"message.welcome": "Welcome",
"message.greeting": "Hello, {name}!",
"message.items": "Total {count} items"
}index.ts
import zhCN from './zh-CN.json'
import enUS from './en-US.json'
import type { ReactLocaleModule } from '@mico_fe/i18n-react'
// 语言包数据
export const messages = {
'zh-CN': zhCN,
'en-US': enUS,
} as Record<string, Record<string, string>>
// 可用语言列表
export const availableLangs = Object.keys(messages)
// 默认语言
export const defaultLang = 'zh-CN'
// 获取初始语言
export function getInitialLang(): string {
if (typeof window === 'undefined') return defaultLang
const stored = localStorage.getItem('lang')
if (stored && availableLangs.includes(stored)) {
return stored
}
const browserLang = navigator.language
if (availableLangs.includes(browserLang)) {
return browserLang
}
return defaultLang
}
// 语言变化回调(可选)
export function onLangChange(lang: string): void {
localStorage.setItem('lang', lang)
document.documentElement.lang = lang
console.log('[i18n] Language changed to:', lang)
}
// 可选:自定义参数替换
// export function replaceParams(text: string, params: Record<string, any>): string {
// return text.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? _)
// }
// 可选:自定义语言映射
// export const langMap = {
// 'ja-JP': { name: '日本語', flag: '🇯🇵' }
// }
// 导出模块
const localeModule: ReactLocaleModule = {
messages,
availableLangs,
defaultLang,
getInitialLang,
onLangChange,
}
export default localeModule2. 初始化
// main.tsx
import { createRoot } from 'react-dom/client'
import { I18nProvider } from '@mico_fe/i18n-react'
import localeModule from './locales'
import App from './App'
createRoot(document.getElementById('root')!).render(
<I18nProvider
localeModule={localeModule}
fallbackLang="zh-CN"
warnOnMissing={true}
>
<App />
</I18nProvider>
)3. 在组件中使用
import { useTranslation } from '@mico_fe/i18n-react'
function App() {
const { t, tt, te, tte, lang, setLang } = useTranslation()
return (
<div>
{/* 基本用法 */}
<button>{t('button.submit')}</button>
{/* 带参数 */}
<p>{t('message.greeting', { name: 'React' })}</p>
{/* 按文案翻译 */}
<p>{tt('欢迎使用')}</p>
{/* 直接写中文(配合编译时插件自动转换) */}
<p>欢迎使用</p>
{/* 切换语言 */}
<button onClick={() => setLang('en-US')}>
Switch to English
</button>
{/* 当前语言 */}
<span>Current: {lang}</span>
</div>
)
}📖 API
I18nProvider
Provider 组件:
<I18nProvider
localeModule={localeModule} // 语言模块(必需)
fallbackLang="zh-CN" // 回退语言
warnOnMissing={true} // 缺少翻译时警告
onLangChange={(lang) => {}} // 语言变化回调
>
<App />
</I18nProvider>useTranslation()
主 Hook,返回所有翻译相关功能:
const {
// 翻译函数
t, // (key: string, params?: object) => string
tt, // (text: string, params?: object) => string
te, // (key: string, lang?: string) => boolean
tte, // (text: string) => boolean
// 语言状态
lang, // string - 当前语言代码
langs, // string[] - 可用语言列表
langName, // string - 当前语言名称
langFlag, // string - 当前语言旗帜
// 语言操作
setLang, // (lang: string) => void
getLangName, // (code: string) => string
getLangFlag, // (code: string) => string
} = useTranslation()useT() / useTT() / useLang()
独立的 Hooks:
// 只获取 t 函数
const t = useT()
t('button.submit')
// 只获取 tt 函数
const tt = useTT()
tt('提交')
// 只获取语言状态
const { lang, langs, setLang } = useLang()t(key, params?)
按 key 翻译:
t('button.submit') // "提交"
t('message.greeting', { name: 'React' }) // "你好,React!"
t('message.items', { count: 100 }) // "共 100 条数据"tt(text, params?)
按文案翻译(运行时根据中文查找 key):
tt('提交') // 中文环境: "提交" / 英文环境: "Submit"
tt('你好,{name}!', { name: 'React' }) // "Hello, React!"te(key, lang?) / tte(text)
检查翻译是否存在:
te('button.submit') // true
te('not.exist') // false
tte('提交') // true
tte('不存在的文案') // false🎨 内置组件
LocaleSwitcher
下拉选择式语言切换器:
import { LocaleSwitcher } from '@mico_fe/i18n-react'
function Header() {
return (
<LocaleSwitcher
placement="bottom-end"
onChange={(lang) => console.log('Changed to:', lang)}
/>
)
}Props:
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| className | string | '' | 自定义 className |
| placement | string | 'bottom-end' | 下拉框位置 |
| onChange | (lang: string) => void | - | 语言变化回调 |
FloatingLocaleSwitcher
浮动可拖动语言切换器:
import { FloatingLocaleSwitcher } from '@mico_fe/i18n-react'
function App() {
return (
<>
<FloatingLocaleSwitcher
initialX={20}
initialY={100}
storageKey="my-locale-pos"
onChange={(lang) => console.log('Changed to:', lang)}
/>
{/* 其他内容 */}
</>
)
}Props:
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| initialX | number | 20 | 初始 X 位置 |
| initialY | number | 100 | 初始 Y 位置 |
| storageKey | string | 'floating-locale-position' | localStorage 存储 key |
| onChange | (lang: string) => void | - | 语言变化回调 |
特性:
- 🖱️ 可拖动定位
- 💾 位置自动保存到 localStorage
- 📱 支持触摸设备
- 🎯 边界检测,不会拖出屏幕
📝 TypeScript
ReactLocaleModule 接口
interface ReactLocaleModule {
// 必需
messages: Record<string, Record<string, string>>
availableLangs: string[]
defaultLang: string
getInitialLang: () => string
// 可选
onLangChange?: (lang: string) => void
langMap?: Record<string, LangInfo>
replaceParams?: (text: string, params: Record<string, any>) => string
}I18nContextValue 接口
interface I18nContextValue {
lang: string
langs: string[]
langName: string
langFlag: string
setLang: (lang: string) => void
t: (key: string, params?: Record<string, any>) => string
tt: (text: string, params?: Record<string, any>) => string
te: (key: string, lang?: string) => boolean
tte: (text: string) => boolean
getLangName: (lang: string) => string
getLangFlag: (lang: string) => string
}💡 最佳实践
1. 配合 useMemo 使用
function Component() {
const { t, tt, lang } = useTranslation()
// 语言变化时重新计算
const welcomeText = useMemo(() => tt('欢迎使用'), [lang])
const greeting = useMemo(() => t('message.greeting', { name: 'React' }), [lang])
return <div>{welcomeText} - {greeting}</div>
}2. 在组件外使用
如果需要在组件外使用翻译(如工具函数),建议传入翻译函数:
// utils.ts
export function formatMessage(t: (key: string) => string) {
return t('message.welcome')
}
// Component.tsx
const { t } = useTranslation()
const msg = formatMessage(t)📄 License
MIT
