
本文详解如何在 React 中使用 i18next 对存储于常量数组(如 bananeData)中的文本字段(如 periode、info)进行动态国际化翻译,涵盖命名空间配置、键名拼接、组件级与列表级翻译策略及常见陷阱规避。
本文详解如何在 react 中使用 i18next 对存储于常量数组(如 `bananedata`)中的文本字段(如 `periode`、`info`)进行动态国际化翻译,涵盖命名空间配置、键名拼接、组件级与列表级翻译策略及常见陷阱规避。
在基于 react-i18next 的多语言项目中,直接将翻译键(如 "project_AAA_periode")嵌入数据结构并动态解析,是处理项目列表类内容(如作品集、案例卡片)的高效方式。但若直接将原始字符串(如 'text to translate')写入 bananeData,再试图用 t(item.periode) 翻译——而该字符串并未作为 key 出现在 translation.json 中——则必然返回原值或 fallback,导致翻译失效。
✅ 正确做法是:让数据项携带可拼接的翻译键,而非待翻译的原文。例如:
// ✅ bananeData.js —— 使用语义化键名,而非原文
export const bananeData = [
{
id: 1,
key: 'project_AAA', // 核心标识符,用于动态构建翻译键
picture: './media/banane.png'
},
{
id: 2,
key: 'project_BBB',
picture: './media/kiwi.png'
}
];对应地,translation.json 中需预定义所有组合键:
{
"project_AAA_periode": "2022 – 2023",
"project_AAA_info": "基于 React 与 TypeScript 构建的响应式管理后台。",
"project_BBB_periode": "2019 – 2023",
"project_BBB_info": "全栈电商系统,支持多语言与支付集成。"
}? 在组件中动态调用翻译函数
方案一:在子组件(Banana)内完成键拼接与翻译(推荐)
// Banana.jsx
import React, { Component } from 'react';
import { withNamespaces } from 'react-i18next';
class Banana extends Component {
state = { showInfo: false };
handleInfo = () => {
this.setState(prev => ({ showInfo: !prev.showInfo }));
};
render() {
const { item } = this.props;
const { t } = this.props; // 获取 t 函数
// ✅ 动态拼接翻译键:item.key + '_periode' → 'project_AAA_periode'
const periodeKey = `${item.key}_periode`;
const infoKey = `${item.key}_info`;
return (
<div className="project">
<h5>{t(periodeKey)}</h5>
<h3>{t(`${item.key}_name`)}</h3> {/* 同理支持 name 字段 */}
<img src={item.picture} alt="" onClick={this.handleInfo} />
<span className="infos" onClick={this.handleInfo}>
<i className="fas fa-plus-circle"></i>
</span>
{this.state.showInfo && (
<div className="showInfos">
<div className="infosContent">
<div className="head"><h2>{t(`${item.key}_name`)}</h2></div>
<p className="text">{t(infoKey)}</p>
<div className="button return" onClick={this.handleInfo}>{t('common_close')}</div>
</div>
</div>
)}
</div>
);
}
}
// ⚠️ 必须指定 namespace,否则 t() 无法定位 translation.json
export default withNamespaces('translation')(Banana);方案二:在父组件(BananaList)预翻译后透传(适合纯展示场景)
// BananaList.jsx
import React, { Component } from 'react';
import { bananeData } from '../data/bananeData';
import Banana from './Banana';
import { withNamespaces } from 'react-i18next';
class BananaList extends Component {
state = { projects: bananeData };
render() {
const { projects } = this.state;
const { t } = this.props;
return (
<div>
<h3>{t('navigation_bananes')}</h3>
<div>
{projects.map(item => {
// ✅ 预翻译:生成带值的新对象,避免子组件重复计算
const translatedItem = {
...item,
periode: t(`${item.key}_periode`),
info: t(`${item.key}_info`),
name: t(`${item.key}_name`)
};
return <Banana key={item.id} item={translatedItem} />;
})}
</div>
</div>
);
}
}
export default withNamespaces('translation')(BananaList);⚠️ 关键注意事项
- 命名空间不可省略:withNamespaces('translation') 中的 'translation' 必须与 i18n.init() 中 resources 的 key 一致(即 languageResources.en.translation),否则翻译资源无法加载。
- 键名严格匹配:t('project_AAA_periode') 要求 JSON 中存在完全相同的 key;大小写、下划线、空格均敏感。
-
避免运行时拼错键:建议封装安全翻译工具函数,防止因 item.key 为空或非法导致 t(undefined_periode):
const safeT = (key) => key && t(key) || key;
- 性能考量:若 bananeData 数据量极大且频繁更新,方案二(父组件预翻译)更利于减少子组件重渲染时的重复计算;若逻辑复杂需子组件独立控制,则方案一更灵活。
-
TypeScript 用户注意:为 bananeData 添加类型定义,确保 key: string 字段存在,可提前捕获拼接错误:
export interface BananaItem { id: number; key: string; // ← 必填,用于翻译键生成 picture: string; }
通过将数据结构设计为“翻译键驱动”而非“原文驱动”,配合 react-i18next 的 t() 动态调用能力,即可优雅、可维护地实现 JSON 数组内容的多语言支持——无需修改数据源,不侵入业务逻辑,且完全兼容 SSR 与 Hooks 写法(useTranslation 替代 withNamespaces)。


















