一覧へ戻る
inspiraller/react-zod-next-intl(新しいタブで開きます)
主要言語: TypeScript
- star 数
- 9
- watcher 数
- 1
- fork 数
- 0
- issue 数
- 0
- 最終更新
- 2025/07/30
主要言語: TypeScript
This repo is an example of how to use form validation in React, combining:
"dependencies": { "@hookform/error-message": "^2.0.1", "i18next": "^25.3.2", "next": "^15.4.4", "next-intl": "^4.3.4", "react-hook-form": "^7.61.1", "zod": "^4.0.13" },
function App({ Component, pageProps }: AppPropsWithLayout) { const router = useRouter(); let locale = (router.locale ?? "en") as zodLocale; locale = 'de' // TODO: change to whatever. Proving changing locale updates zod locales return ( <NextIntlClientProvider locale={locale} timeZone="Europe/London" messages={pageProps.messages} > <ZodSetup locale={locale}> {locale ?<Component {...pageProps} /> : 'loading'} </ZodSetup> </NextIntlClientProvider> );
// Custom error map function for global translations import z, { locales } from "zod"; import { useEffect } from "react"; import { zodLocale } from "@/@types"; interface Props { locale: zodLocale; children: React.ReactNode; } export const ZodSetup = ({ locale, children }: Props) => { useEffect(() => { if (locale) { const localeError = locales[locale]().localeError; // type: z.core.$ZodErrorMap<z.core.$ZodIssue>; z.config({ localeError }); } }, [locale]); return <>{children}</>; };
const methods = useForm<PropsFormRegister>({ resolver: zodResolver(zodValidationSchema), });
This is a polyfill for @hookform/resolvers which currently only works with zod 3. I'm sure this will be updated to work with zod 4. In the meantime we can use this
import type { FieldErrors, FieldValues, ResolverResult, ResolverOptions } from 'react-hook-form'; import type { ZodType } from 'zod'; export const zodResolver = <T extends FieldValues = FieldValues>( schema: ZodType<T> ) => { /* eslint-disable @typescript-eslint/no-unused-vars */ return ( values: T, _context?: any, _options?: ResolverOptions<T> ): ResolverResult<T> => { /* eslint-enable @typescript-eslint/no-unused-vars */ const result = schema.safeParse(values); if (result.success) { return { values: result.data, errors: {}, }; } else { const fieldErrors: Record<string, any> = {}; result.error.issues.forEach((issue) => { const fieldName = issue.path.join('.'); if (fieldName && !fieldErrors[fieldName]) { fieldErrors[fieldName] = { type: issue.code, message: issue.message, }; } }); return { values: {}, errors: fieldErrors as FieldErrors<T>, }; } }; };