LoginSignup
5
1

More than 1 year has passed since last update.

sveltekit-superforms でエラーメッセージを日本語化できました

Last updated at Posted at 2023-04-19

はじめに

以下の投稿で、SvelteKit で作成したアプリに入力チェックを導入しました。ただし、エラーメッセージの日本語化を実現できずに、保留していました。

日本語化できる方法が分かったので、その方法を記載します。

修正内容

前述の記事に記載した users.js を以下の様に修正することで、日本語を表示できました。

src/lib/users.js
import { z } from 'zod';
+import i18next from 'i18next';
+import translation from 'zod-i18n-map/locales/ja/zod.json' assert {type: "json"};
+import { makeZodI18nMap } from 'zod-i18n-map';
+
+i18next.init({
+	lng: 'ja',
+	resources: {
+		ja: { translation },
+	},
+});
+
+z.setErrorMap(makeZodI18nMap({ t:i18next.t, ns: 'translation' }));

// See https://zod.dev/?id=primitives for schema syntax
/**
 * ユーザーのスキーマ
 */
export const userSchema = z.object({
  id: z.string().max(20),
  name: z.string().min(2).max(20).endsWith("!"),
  email: z.string().email()
});

...

アプリを起動してアクセスすると、日本語が表示されることを確認できましたー。:joy:
image.png

解決までの経緯

この解決策に至った経緯は、node_modules フォルダ内にダウンロードされた zod-i18n-map のソースコードを確認していたところ、makeZodI18nMap() 関数の引数に tns を指定できることに気づいたのがきっかけでした。

node_modules/zod-i18n-map/dist/index.d.ts
...
type ZodI18nMapOption = {
    t?: i18n["t"];
    ns?: string | readonly string[];
    handlePath?: HandlePathOption;
};
...

これ以前にいろいろ調べた結果、i18next.init(..) した状態を zod-i18n-map 側で共有できていないっぽいことに気づいていました。ですので、この ti18next.t を指定すれば良さそう!と思いついた次第です。

z.setErrorMap(makeZodI18nMap({ t:i18next.t }));

しかし、これだけでは日本語化されませんでした。
いままで、エラーメッセージが undefined だったのが、英語で表示されるようになっただけでした。

さらに zod-i18n-map のソースコードを追っていくと、ns というパラメータがデフォルトで zod となっていることが分かりました。このパラメータは i18next におけるネームスペースに相当します。

前述の index.d.ts より、makeZodI18nMap() 関数の引数に ns というパラメータがあります。この関数のソースコードを確認すると、ここで指定した値(option.ns)によって ns が上書きされることが分かりました。

node_modules/zod-i18n-map/dist/index.js
...
var defaultNs = "zod";
var makeZodI18nMap = (option) => (issue, ctx) => {
  const { t, ns, handlePath } = {
    t: import_i18next.default.t,
    ns: defaultNs,
    ...option, // t と ns が上書きされる
    handlePath: {
      context: "with_path",
      ns: option?.ns ?? defaultNs,
      keyPrefix: void 0,
      ...option?.handlePath
    }
  };
...

そして、あてずっぽうで nsundefined を指定したところ、日本語でエラーメッセージを取得できました。

z.setErrorMap(makeZodI18nMap({ t:i18next.t, ns: undefined }));

2023/4/20 追記:

あてずっぽうではいかんですよねw
というわけで、i18next についてもっと調査してみたところ、ちゃんと理解できましたー。

以下の様に、nstranslation を指定すれば良かったのです。
(どうやら、まだJavaScript の省略記法に慣れてなかったようです。。。)
参考: https://www.i18next.com/principles/fallback#namespace-fallback

src/lib/users.js
import { z } from 'zod';
import i18next from 'i18next';
import translation from 'zod-i18n-map/locales/ja/zod.json' assert {type: "json"};
import { makeZodI18nMap } from 'zod-i18n-map';

i18next.init({
	lng: 'ja',
	resources: {
		ja: { translation }, // この記述は実際には ja: { translation: translation }。キー名が ns に相当する。
	},
});

-z.setErrorMap(makeZodI18nMap({ t:i18next.t, ns: undefined }));
+z.setErrorMap(makeZodI18nMap({ t:i18next.t, ns: 'translation' }));

// See https://zod.dev/?id=primitives for schema syntax
/**
 * ユーザーのスキーマ
 */
export const userSchema = z.object({
  id: z.string().max(20),
  name: z.string().min(2).max(20).endsWith("!"),
  email: z.string().email()
});

...

ちなみに、動的に言語を切り替える場合は以下の様に addResourceBundle()changeLanguage() を使うことで実現できます。

import ja from 'zod-i18n-map/locales/ja/zod.json' assert { type: "json" };
import es from 'zod-i18n-map/locales/es/zod.json' assert { type: "json" };

i18next.init();

i18next.addResourceBundle('ja', 'translation', ja);
i18next.changeLanguage('ja');
console.log("ja:", i18next.t('errors.custom')); // → ja: 入力形式が間違っています。

i18next.addResourceBundle('es', 'customNs', es); // 独自のネームスペースを設定可能。
i18next.changeLanguage('es');
console.log("es:", i18next.t('customNs:errors.custom')); // → es: Entrada inválida
// 独自のネームスペースをコロン区切りで先頭に記載することでネームスペースが適用される。

まとめ

これで SvelteKit で入力チェックエラーを日本語化することに成功しました。一安心です。:blush:

ドキュメントを見ただけでは把握できなかったことが、ソースコードを追うことで把握できました。JavaScritp の場合、node_modules にソースコード一式がダウンロードされるし、直接修正してデバッグもできるので便利です。

まだまだ、JavaScript 初心者なところがあるので、もっと鍛えていこうと思います。:smiley:

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1