与路由的配合
这种方式很容易出现问题,应该将 language 存储到
localStorage
或其他缓存,而非根据 url 匹配
重点是加载与切换
i18n 下的路由示例(hash 模式要加前缀)
/en-US/***
/zh-CN/***
/zh-TW/***
示意图
与 react-router 结合的核心代码
import { useHistory, useLocation } from 'react-router-dom'
import { useMemo } from 'react'
import { LanguageEnum } from '@liuli-util/i18next-util'
export function convertLanguagePrefix(value: LanguageEnum): string
export function convertLanguagePrefix(value: string): LanguageEnum
export function convertLanguagePrefix(
value: LanguageEnum | string,
): LanguageEnum | string {
const LanguagePrefixMap = {
[LanguageEnum.En]: '/en-US/',
[LanguageEnum.ZhCN]: '/zh-CN/',
'/zh-CN/': LanguageEnum.ZhCN,
'/en-US/': LanguageEnum.En,
}
return LanguagePrefixMap[value as keyof typeof LanguagePrefixMap]
}
export function useLanguage(init: LanguageEnum): LanguageEnum {
const location = useLocation()
const history = useHistory()
return useMemo(() => {
const regexp = /(\/.+?\/)/
const res = regexp.exec(location.pathname)
if (!res) {
history.push(convertLanguagePrefix(init))
return init
}
return convertLanguagePrefix(res[0])
}, [history, location.pathname])
}
function App() {
const language = useLanguage(LanguageEnum.En)
const [{ value: list }, fetch] = useAsyncFn(
async (language) => {
console.log('language: ', language)
await i18n.init({ en, zhCN }, language)
const prefix = convertLanguagePrefix(language)
return routeList().map((item) => ({
...item,
path: PathUtil.join(prefix, item.path as string),
}))
},
[language],
)
useMount(() => fetch(language))
const location = useLocation()
const history = useHistory()
async function changeLanguage(value: LanguageEnum) {
const path = location.pathname.replace(
convertLanguagePrefix(language),
convertLanguagePrefix(value),
)
console.log('path: ', language, value, path)
await fetch(value)
history.push(path)
}
return (
<div>
<header>
<ul>
{list &&
list.map((item) => (
<li key={item.path as string}>
<Link to={item.path as string}>{item.title}</Link>
</li>
))}
</ul>
<section>
<button onClick={() => changeLanguage(LanguageEnum.En)}>
English
</button>
<button onClick={() => changeLanguage(LanguageEnum.ZhCN)}>
中文
</button>
</section>
</header>
<section>
<Suspense fallback={'loading...'}>{renderRoutes(list)}</Suspense>
</section>
</div>
)
}