react-adminTranslatableInputs多语言表单输入组件完整指南分语言编辑、校验与编程式赋值【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-adminTranslatableInputs是 react-admin 提供的多语言表单输入容器组件它允许开发者把一组每个字段对应多语言值的输入如name.en、name.fr组织成带语言选项卡的编辑界面。本文基于当前仓库 docs/TranslatableInputs.md 展开结合ra-ui-materialui与ra-core的源码实现系统讲解其数据模型、全部 Props、自定义语言选择器、校验联动、以及如何配合react-hook-form的setValue编程式修改各语言值。一、组件定位与适用场景在多语言业务系统如电商商品、CMS 内容、新闻稿中同一个字段往往需要保存多个语言的翻译文本。react-admin 对此有两种展示形态只读展示使用TranslatableFields分语言展示字段值编辑输入使用本文的TranslatableInputs让用户在一个表单内为每种语言分别填写值。TranslatableInputs不要求提供source属性它本身只是容器但它要求至少一个带source的子输入组件同时必须通过locales属性声明要展示的语言。其源码定义位于 packages/ra-ui-materialui/src/input/TranslatableInputs.tsx底层逻辑语言切换、记录转换由ra-core的useTranslatable提供。组件期望的字段值结构如下每个字段都是语言码 → 文本的对象{ id: 1234, name: { en: White trousers, fr: Pantalon blanc, }, description: { en: Slim fit trousers for every day use, fr: Pantalon ajusté pour un usage quotidien, } }二、基本用法将需要多语言编辑的输入组件作为TranslatableInputs的子节点传入并通过locales声明语言TranslatableInputs locales{[en, fr]} TextInput sourcename / RichTextInput sourcedescription / /TranslatableInputs页面渲染效果上方是一个 Material UI 选项卡条每个选项卡标签是语言码如en、fr下方是对应当前选中语言的一组输入框。切换选项卡时react-admin 会为该语言的每个子输入生成形如name.en、name.fr的动态source从而实现一套字段结构、多语言独立编辑。从源码来看TranslatableInputs的核心渲染流程TranslatableInputs.tsx#L72-L114是调用useTranslatable({ defaultLocale, locales })获取语言切换上下文通过TranslatableContextProvider注入该上下文渲染语言选择器默认是TranslatableInputsTabs即 Material UI 的 Tabs遍历locales为每个语言渲染一个TranslatableInputsTabContent把同一组子输入包进各语言的容器中。每个TranslatableInputsTabContentpackages/ra-ui-materialui/src/input/TranslatableInputsTabContent.tsx会做两件关键的事通过SourceContextProvider注入一个getSource: source ${source}.${locale}的上下文让子输入自动挂上语言后缀通过RecordContextProvider注入一份当前语言的值记录由getRecordForLocale从原始记录中抽取因为普通输入组件并不知道语言的存在它们只从RecordContext取当前字段值。这里getRecordForLocale的实现值得注意packages/ra-core/src/i18n/useTranslatable.ts#L55-L74它递归遍历记录的所有路径getRecordPaths支持嵌套对象与数组把形如title.fr的值提升为title从而构造出仅含指定语言值的记录。这意味着TranslatableInputs也适用于嵌套结构如数组内对象的翻译字段。三、Props 总览TranslatableInputs的 Props 定义于 TranslatableInputs.tsx#L116-L125接口继承UseTranslatableOptions完整参数如下Prop必填类型默认值说明locales必填Arraystring-语言码数组顺序即选项卡顺序defaultLocale可选string跟随用户语言默认展示的语言fullWidth可选booleantrue设为false时输入组不撑满表单宽度groupKey可选string-用于可访问性的唯一标识同页多个实例时必填selector可选ReactElementMaterial UI Tabs自定义语言选择器元素StackProps可选object{}透传给内部 MUI Stack 的属性sx可选SxProps-Material UI 样式快捷方式其余内部还支持className、marginnone \| normal \| dense。从源码可见组件支持 MUI 主题级定制其样式类名为RaTranslatableInputs包含root与fullWidth两个规则可通过 MUIcomponents覆盖见 TranslatableInputs.tsx#L146-L162。四、defaultLocale默认展示语言react-admin 默认取当前用户的语言useLocaleState中的localeFromUI作为defaultLocale这一点在 useTranslatable.ts#L26-L28 中可以看到const [localeFromUI] useLocaleState(); const { defaultLocale localeFromUI, locales } options;若希望某个表单固定以特定语言打开用defaultLocale覆盖TranslatableInputs locales{[en, fr]} defaultLocalefr TextInput sourcename / RichTextInput sourcedescription / /TranslatableInputs源码中还有一个细节selectedLocale为 falsy 时例如defaultLocale为空字符串会回退到enuseTranslatable.ts#L33。五、fullWidth宽度控制默认情况下TranslatableInputs组会撑满表单宽度——源码根节点样式为flexGrow: 1且启用fullWidth时追加width: 100%TranslatableInputs.tsx#L136-L144。如需禁用TranslatableInputs locales{[en, fr]} fullWidth{false} TextInput sourcetitle / TextInput sourcedescription / /TranslatableInputs六、groupKey同页多实例的可访问性标识TranslatableInputs内部依赖一组固定的 DOM id 建立选项卡 ↔ 内容面板的关联如translatable-header-${groupKey}${locale}、translatable-content-${groupKey}${locale}见 TranslatableInputsTabContent.tsx#L68-L76。如果同一页面出现多个TranslatableInputs这些 id 会冲突因此必须为每个实例提供唯一的groupKeyTranslatableInputs locales{[en, fr]} groupKeyessential-fields TextInput sourcename / RichTextInput sourcedescription / /TranslatableInputsgroupKey同时会被拼入FormGroupContext的名称${groupKey}${locale}确保各语言分组的表单上下文互不干扰。七、locales语言列表与选项卡标签locales传入字符串数组每个字符串既是语言码也会成为输入值的键后缀。数组顺序决定了选项卡从左到右的展示顺序TranslatableInputs locales{[en, fr]} TextInput sourcename / RichTextInput sourcedescription / /TranslatableInputs选项卡默认以语言码作为标签。如果希望显示人类可读的语言名如 English 而非 en可以使用翻译键格式为ra.locales.[locale_code]例如ra.locales.en、ra.locales.fr。以ra-i18n-polyglot或自定义翻译包在对应语言文件中配置这些键即可。八、selector自定义语言选择器默认选择器是 Material UI Tabs实现见 TranslatableInputsTabs.tsx一个AppBar容器内嵌Tabs每个选项卡的值是语言码。你可以通过selector属性替换成任意自定义元素例如一个原生select下拉框const Selector () { const { locales, selectLocale, selectedLocale, } useTranslatableContext(); const handleChange event { selectLocale(event.target.value); }; return ( select aria-labelSelect the locale onChange{handleChange} value{selectedLocale} {locales.map(locale ( option key{locale} value{locale} // This allows to correctly link the containers for each locale to their labels id{translatable-header-${locale}} {locale} /option ))} /select ); }; TranslatableInputs record{record} resourceproducts locales{[en, fr]} selector{Selector /} TextInput sourcename / RichTextInput sourcedescription / /TranslatableInputs自定义选择器通过useTranslatableContext获取上下文可用值包括locales语言码数组selectedLocale当前选中语言selectLocale(locale)切换语言的方法getRecordForLocale(record, locale)抽取指定语言记录的工具函数。注意自定义selector若用原生元素需要自己保证选项卡 ↔ 面板的id/aria-labelledby关联上例中translatable-header-${locale}正是面板aria-labelledby所引用的 id。useTranslatableContext在脱离TranslatableContextProvider使用时即组件不在TranslatableInputs内部会抛出错误这一点由 useTranslatableContext.ts#L39-L43 保证。九、StackProps控制内部布局每个语言的输入内容都被包裹在一个 MUIStack中StackProps会原样透传{...StackProps}见 TranslatableInputs.tsx#L100-L110。默认方向为垂直堆叠设置direction: row可以让输入并排显示TranslatableInputs locales{[en, fr]} StackProps{{ direction: row }} TextInput sourcetitle / TextInput sourcedescription sx{{ marginLeft: 2 }} / /TranslatableInputsStackProps支持 MUI Stack 的全部属性包括spacing、direction、alignItems、justifyContent等适合在空间紧张的表单中做紧凑排版。十、sx自定义样式TranslatableInputs根节点同样支持sx可用于设置边框、背景、间距等样式TranslatableInputs locales{[en, fr]} sx{{ border: solid 1px red }} TextInput sourcetitle / TextInput sourcedescription / /TranslatableInputssx会被应用到根容器源码中由styled(div)创建的Root同时仍可通过 MUI 主题的RaTranslatableInputs.styleOverrides做全局覆盖。十一、校验错误联动到选项卡TranslatableInputs内的任何输入组件都可以照常使用 react-admin 的校验器。当某个语言的输入出现校验错误时对应语言的选项卡标签会被标记为错误状态标红高亮TranslatableInputs locales{[en, fr]} TextInput sourcename validate{[required()]} / RichTextInput sourcedescription validate{[maxLength(100)]} / /TranslatableInputs这一行为在仓库测试 packages/ra-ui-materialui/src/input/TranslatableInputs.spec.tsx 中有明确覆盖测试通过断言tabs[1].classList.contains(RaTranslatableInputsTab-error)来验证含错误输入的选项卡是否正确获得错误样式类同时测试也验证了未选中语言的面板会附加hidden样式类display: none实现隐藏切换。实现机制上每个语言的选项卡由TranslatableInputsTab渲染它会感知所在语言的FormGroupContext状态校验错误在表单层面按语言分组记录因此可以精确反映到具体语言选项卡上。十二、编程式修改多语言值useSourceContextsetValueTranslatableInputs的表单值依然由react-hook-form管理因此可以直接调用其setValue方法修改某个输入的值。但难点在于子输入在表单中注册的name是按语言动态生成的例如description.en直接写死字段名无法适配。react-admin 为此提供了SourceContextpackages/ra-core/src/core/SourceContext.tsx通过useSourceContext钩子可以在任意层级拿到getSource(source)函数它会返回该输入在当前上下文中的真实source。在TranslatableInputs内这个函数就是字段名 当前语言后缀的拼接器见 TranslatableInputsTabContent.tsx#L41-L56。源码细节SourceContext默认值是一个恒等函数getSource: source source因此在不处于任何特殊上下文时使用也不会报错而TranslatableInputsTabContent提供的getSource在source为空时会抛出Children of TranslatableInputs must have a source从实现层面强制了子输入必须有source的约束。下面示例展示了如何利用getSource拿到各语言的动态name再用setValue把title的值预填到descriptionimport { TranslatableInputs, TextInput, useSourceContext } from react-admin; import { useFormContext } from react-hook-form; import { Button } from mui/material; const PrefillWithTitleButton () { const sourceContext useSourceContext(); const { setValue, getValues } useFormContext(); const onClick () { setValue( // sourceContext.getSource(description) will for instance return // description.en sourceContext.getSource(description), getValues(sourceContext.getSource(title)) ); }; return ( Button onClick{onClick} sizesmall sx{{ maxWidth: 140 }} Prefill with title /Button ); }; const MyInputs () ( TranslatableInputs locales{[en, fr]} TextInput sourcetitle / TextInput sourcedescription helperText{false} / PrefillWithTitleButton / /TranslatableInputs );关键点useSourceContext()可在TranslatableInputs的任何子组件中使用拿到的是当前语言上下文下的getSource由于按钮同样位于TranslatableInputsTabContent内部getSource(title)与getSource(description)会自动带上当前选中语言的后缀如title.fr、description.fr因此预填逻辑天然跟随用户正在编辑的语言若在TranslatableInputs之外使用useSourceContext得到的是恒等上下文getSource直接返回原字段名符合普通表单的行为。十三、小结TranslatableInputs是 react-admin 处理多语言编辑场景的标准方案数据模型字段值为语言码 → 文本的对象locales定义语言集合使用要点子输入必须有source多实例必须给groupKey默认语言可被defaultLocale覆盖交互定制selector可完全替换默认 Tabs 选择器StackProps/sx/MUI 主题覆盖可灵活调整布局与样式校验各语言独立校验错误自动标记到对应选项卡编程式控制配合useSourceContext().getSource与react-hook-form的setValue可在任意语言上下文中精准读写字段值。相关源码与测试可作为继续深入研究的入口TranslatableInputs.tsx、TranslatableInputsTabContent.tsx、TranslatableInputsTabs.tsx、useTranslatable.ts、SourceContext.tsx、TranslatableInputs.spec.tsx。只读展示场景可对照参考TranslatableFields。【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考