kk-web

yupのv1を使ってNext.jsで多言語対応を行う方法

2023-03-30

yup の v1 がリリースされて少し経ちましたが、ロケールの設定についてはバグが多いです。

バグの内容については Issue を見ていただくとして、今回は Next.js で暫定対応を行う方法を書いていこうと思います。


事象

英語 → 日本語のケースは問題ないのだが、日本語 → 英語のケースだと yup 内の defaultLocale が正しく取得できないことがわかった。

対策

Next.js の動的に環境変数を作成する方法で強引に defaultLocale を作成した。

パッケージおよびバージョン

{
  "dependencies": {
    "@hookform/resolvers": "^3.0.0",
    "@types/node": "18.15.10",
    "@types/react": "18.0.29",
    "@types/react-dom": "18.0.11",
    "next": "13.2.4",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-hook-form": "^7.43.8",
    "typescript": "5.0.2",
    "yup": "^1.0.2",
    "yup-locale-ja": "^1.0.0"
  }
}

実装

const { defaultLocale } = require("yup");

/** @type {import('next').NextConfig} */
const nextConfig = {
  env: {
    defaultLocale: JSON.stringify(defaultLocale),
  },
};

module.exports = nextConfig;
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import * as jp from "yup-locale-ja";
import { yupResolver } from "@hookform/resolvers/yup";
import { setLocale, object, string, InferType } from "yup";

setLocale(jp.descriptive);

const schema = object({
  piyo: string().label("PIYO").required(),
});

type FieldValues = InferType<typeof schema>;

export default function Hoge() {
  const { formState, handleSubmit, register } = useForm<FieldValues>({
    defaultValues: {
      piyo: "",
    },
    resolver: yupResolver(schema),
  });
  const router = useRouter();

  return (
    <>
      <h1>JP</h1>
      <form
        onSubmit={handleSubmit((values) => {
          router.push("/fuga");
        })}
      >
        <input {...register("piyo")} />
        <p>{formState.errors.piyo?.message}</p>
        <button>submit</button>
      </form>
    </>
  );
}
import { yupResolver } from "@hookform/resolvers/yup";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { setLocale, object, string, InferType } from "yup";

setLocale(JSON.parse(process.env.defaultLocale || ""));

const schema = object({
  piyo: string().label("PIYO").required(),
});

type FieldValues = InferType<typeof schema>;

export default function Fuga() {
  const { formState, handleSubmit, register } = useForm<FieldValues>({
    defaultValues: {
      piyo: "",
    },
    resolver: yupResolver(schema),
  });
  const router = useRouter();

  return (
    <>
      <h1>EN</h1>
      <form
        onSubmit={handleSubmit((values) => {
          router.push("/hoge");
        })}
      >
        <input {...register("piyo")} />
        <p>{formState.errors.piyo?.message}</p>
        <button>submit</button>
      </form>
    </>
  );
}

実装を見てもらったわかる通り、めちゃくちゃ強引です。

言わずもがな良い実装方法ではないので、公式に早く対応してほしいなぁと思いつつ。

© 2018 kk-web