React中如何结合i18n/intl国际化转换Formik与Yup的报错信息
Formik+Yup 表单校验错误国际化实现方案
你现有的多语言JSON配置方案可以直接复用,不需要额外引入复杂依赖,按以下步骤配置即可:
先在各语言JSON配置文件中补充校验类词条
按你现有的多语言文件结构,把所有表单校验用到的提示文案提前写到对应语言包中,支持插值占位符匹配动态参数,示例:// 中文语言包 zh-CN.json { "validation": { "required": "此项为必填项", "invalidEmail": "请输入格式正确的邮箱地址", "minLength": "输入内容最少需要{min}个字符", "maxLength": "输入内容最多不能超过{max}个字符", "confirmPasswordNotMatch": "两次输入的密码不一致" } }// 英文语言包 en-US.json { "validation": { "required": "This field is required", "invalidEmail": "Please enter a valid email address", "minLength": "Minimum {min} characters required", "maxLength": "Maximum {max} characters allowed", "confirmPasswordNotMatch": "Passwords do not match" } }Yup校验规则直接对接i18n实例取多语言文案
不要在Yup校验Schema中硬编码任何提示文案,直接调用i18n的翻译方法获取对应语言词条,带动态参数的规则直接传插值对象即可。注意:如果在React组件外部定义校验Schema,直接引入项目中初始化完成的i18n实例调用
t方法即可,不要在组件外使用React版i18n的hook,会触发报错;组件内定义Schema可以直接用useTranslationhook拿到翻译方法。
示例代码:import * as Yup from 'yup' // 组件外引入初始化好的i18n实例 import i18n from '@/i18n' // 组件外定义的通用校验规则 export const baseUserSchema = Yup.object({ email: Yup.string() .required(i18n.t('validation.required')) .email(i18n.t('validation.invalidEmail')), password: Yup.string() .required(i18n.t('validation.required')) .min(8, i18n.t('validation.minLength', { min: 8 })) })处理语言切换时校验文案不更新的问题
很多人接入后会遇到切语言后表单报错还是旧语言的问题,原因是校验Schema只在组件首次渲染时生成了一次,没有跟着语言变化更新。只需要把Schema的生成逻辑用useMemo包裹,把当前语言作为依赖项即可,Formik会自动使用最新的校验规则:import { useFormik } from 'formik' import { useTranslation } from 'react-i18next' import * as Yup from 'yup' const AccountForm = () => { const { t, i18n } = useTranslation() // 语言变化时自动重新生成校验Schema const validationSchema = useMemo(() => { return Yup.object({ confirmPassword: Yup.string() .required(t('validation.required')) .oneOf([Yup.ref('password'), null], t('validation.confirmPasswordNotMatch')) }) }, [i18n.language, t]) const formik = useFormik({ initialValues: { password: '', confirmPassword: '' }, validationSchema, onSubmit: (values) => { // 表单提交逻辑 } }) // 渲染部分直接取formik.errors即可,内容已经是当前语言的提示 return ( <form onSubmit={formik.handleSubmit}> <div> <input name="confirmPassword" type="password" value={formik.values.confirmPassword} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.touched.confirmPassword && formik.errors.confirmPassword && ( <div className="error-tip">{formik.errors.confirmPassword}</div> )} </div> <button type="submit">提交</button> </form> ) }可选优化:全局配置Yup默认提示,减少重复代码
如果项目里表单多、校验规则重复度高,可以用Yup的setLocale方法全局配置默认校验提示,写规则的时候不需要重复传文案参数。只需要在i18n初始化完成后配置一次,同时监听语言切换事件更新全局配置即可:// i18n初始化文件中 import * as Yup from 'yup' import i18n from './index' const updateYupDefaultMessage = () => { Yup.setLocale({ mixed: { required: i18n.t('validation.required') }, string: { email: i18n.t('validation.invalidEmail'), min: ({ min }) => i18n.t('validation.minLength', { min }), max: ({ max }) => i18n.t('validation.maxLength', { max }) } }) } // 初始化时执行一次 updateYupDefaultMessage() // 语言切换时自动更新默认提示 i18n.on('languageChanged', updateYupDefaultMessage)配置完成后写校验规则不需要再传message参数,默认就会使用对应语言的全局配置:
// 不需要每个规则都写t方法传文案 const simpleSchema = Yup.object({ email: Yup.string().required().email(), password: Yup.string().required().min(8) })
内容的提问来源于stack exchange,提问作者Puneet Phull
相关产品推荐
相关产品推荐

