i18next切换语言时,组件外常量翻译未同步更新的问题
问题原因
组件外部定义的PERMISSION_OPTIONS是在模块加载阶段就执行了i18next.t生成翻译文本,属于一次性计算的静态值。切换语言时,这个常量不会重新执行翻译逻辑,所以内容不会更新。而组件内部通过useTranslation获取的t函数,会在语言切换时触发组件重新渲染,自动拉取当前语言的翻译内容,因此能正常更新。
解决方案
方案一:将常量移至组件内部,用useMemo缓存
把选项定义放在组件内部,通过useMemo监听语言变化,触发重新生成翻译后的选项:
import React from "react" import { useTranslation } from "react-i18next" export const UsersAdministration: React.FC = () => { const { t, i18n } = useTranslation() // 语言变化时重新生成选项 const PERMISSION_OPTIONS = React.useMemo(() => [ { value: [PERMISSION_ADMIN_VALUE, PERMISSION_DEFAULT_VALUE], label: t("users.adminAndOperatorOptionLabel", { ns: "admin" }), }, { value: [PERMISSION_USER_API_VALUE], label: t("users.userApiOptionLabel", { ns: "admin" }), // 修正原代码key重复问题 }, ], [t, i18n.language]) // 依赖语言状态,变化时重新计算 const [permissionsFilter, setPermissionsFilter] = React.useState(PERMISSION_OPTIONS[0]) return( <> <p>{t("title", { ns: "admin" })}</p> <p>{PERMISSION_OPTIONS[0].label}</p> {/* 现在语言切换会同步更新 */} </> ) }
方案二:封装成函数,按需调用
如果需要在多个组件复用选项逻辑,可封装成函数,每次使用时传入当前的t函数:
// 工具函数(可单独放文件或组件内部) export const getPermissionOptions = (t: any) => [ { value: [PERMISSION_ADMIN_VALUE, PERMISSION_DEFAULT_VALUE], label: t("users.adminAndOperatorOptionLabel", { ns: "admin" }), }, { value: [PERMISSION_USER_API_VALUE], label: t("users.userApiOptionLabel", { ns: "admin" }), }, ] // 组件内使用 export const UsersAdministration: React.FC = () => { const { t } = useTranslation() const permissionOptions = getPermissionOptions(t) const [permissionsFilter, setPermissionsFilter] = React.useState(permissionOptions[0]) return( <> <p>{t("title", { ns: "admin" })}</p> <p>{permissionOptions[0].label}</p> </> ) }
额外优化:语言选择器状态同步
原LanguageSelector中手动维护的currentLanguage状态容易和实际语言不同步,可直接从i18n实例获取:
import React from "react" import clsx from "clsx" import { useTranslation } from "react-i18next" export const countries: { [key: string]: string } = { fr: "fr-FR", en: "en-GB", } export const LanguageSelector: React.FC<LanguageSelectorProps> = () => { const { t, i18n } = useTranslation() // 直接从i18n获取当前语言,无需手动维护state const currentLanguage = i18n.language.substring(0, 2) const changeLanguage = (lng: string) => { // 传入完整语言码,匹配i18n配置 i18n.changeLanguage(countries[lng]) } const availableCountries = Object.keys(countries) return ( <div className={clsx("c-language-selector")}> <form> <label htmlFor="countrySelector" aria-label="Select country"> <select id="countrySelector" value={currentLanguage} onChange={(event) => changeLanguage(event.target.value)} > {availableCountries.map((country) => ( <option key={country} value={country}> {t(`availableTranslatedCountries.${country}`)} </option> ))} </select> </label> </form> </div> ) }
内容的提问来源于stack exchange,提问作者tomakazub
相关产品推荐
相关产品推荐

