A solution to translating zod error messages using next-intl

1k views Asked by At

I am looking for a way of translating Zod error messages when using the next-intl package. Perhaps an alternative to Zod-i18n, instead of i18next.

The reasons for picking next-intl instead of i18next are related to NextJS app router so switching to i18next really isn't an option in this case.

EDIT: I am really looking to translate the default Zod messages, not passing in custom translations per refinement. Bulk translations are what I'm after.

2

There are 2 answers

2
Avi Cohen On

You can pass the translation as an argument.

en.json:

{
  "home": {
    "errors": {
      "Name is required": "Name is required."
    }
  }
}

schemas/index.ts:

import * as z from "zod";

export const BaseSchema = (t: (arg: string) => string) =>
  z.object({
    name: z.string().min(1, {message: t("errors.Name is required")})
  });

in client code (form):

"use client";

import { useTranslations } from "next-intl";
import { BaseSchema } from "@/schemas";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

export const Form = ()=> {
  const t = useTranslations("home");
  const formSchema = BaseSchema(t);
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      name: ""
  });
  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    // await a server action 
  };
  return(<Form></Form>);
};

in server action code:

"use server";

import { getTranslations } from "next-intl/server";
import * as z from "zod";
import { BaseSchema } from "@/schemas";

export const create = async (
  values: z.infer<ReturnType<typeof BaseSchema>>
) => {
  const t = await getTranslations("home");
  const paramsSchema = BaseSchema(t);
  const validatedFields = paramsSchema.safeParse(values);
  if (!validatedFields.success) {
    throw new Error("Invalid fields");
  }
};
0
TheDude On

I was facing the same problem and was looking into alternatives of zod-i18n that work with next-intl. After looking into the code of zod-i18n I realized that it's not that big of a deal to adapt for next-intl. You can find an example here and a blog post here. Not as convenient as having a package out of the box but it solved my problem for now.