You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务端使用zod-i18n时Zod错误消息为undefined的问题

问题描述

在SvelteKit的+page.server.ts中使用Zod Schema校验表单数据,原校验逻辑正常:

const propertySchema = z.object({
    rent_type: z.enum(['rent', 'sell']),
    title: z.string().min(10),
    typ: z.enum(['house', 'flat', 'garage', 'office', 'hotel']),
    price: z.coerce.number().positive(),
    area: z.coerce.number().positive(),
    rooms: z.coerce.number().positive(),
    address: z.string().min(10),
    description: z.string().min(20),
    beds: z.coerce.number().positive(),
    bathrooms: z.coerce.number().positive(),
    garage: z.coerce.number(),
    constructionYear: z.coerce.number().int().positive().min(1900)
});

通过const propertyData = propertySchema.safeParse(formData);执行校验。

为实现错误消息国际化,引入zod-i18n-map包后,在+layout.server.ts中初始化i18next与zodI18nMap:

import i18next from "i18next";
import { z } from "zod";
import { zodI18nMap } from "zod-i18n-map";
// Import your language translation files
import translation from "zod-i18n-map/locales/es/zod.json";

// lng and resources key depend on your locale.
i18next.init({
  lng: "es",
  resources: {
    es: { zod: translation },
  },
});
z.setErrorMap(zodI18nMap);

但校验时错误消息始终为undefined,比如执行const schema = z.string().email();schema.parse("foo")返回的error.message是undefined。而在+layout.svelte的onMount()生命周期中初始化则可正常工作,需解决服务端初始化的问题。

解决方案

问题核心是i18next.init是异步操作,你在初始化完成前就设置了Zod的错误映射并执行校验,导致翻译资源未加载完成,错误消息无法正确渲染。在SvelteKit服务端环境中,需确保i18next初始化完成后再执行校验,具体修改如下:

  1. 修改+layout.server.ts,将初始化逻辑放入异步load函数:
import i18next from "i18next";
import { z } from "zod";
import { zodI18nMap } from "zod-i18n-map";
import translation from "zod-i18n-map/locales/es/zod.json";

export async function load() {
  await i18next.init({
    lng: "es",
    resources: {
      es: { zod: translation },
    },
    initImmediate: false, // 禁用立即初始化,确保资源加载完成
  });
  z.setErrorMap(zodI18nMap);
}

SvelteKit的load函数会在页面渲染前执行,保证服务端初始化逻辑完成后才处理后续请求。

  1. 保留+page.server.ts原校验逻辑即可
    SvelteKit服务端路由会等待+layout.server.ts的load函数执行完毕后,再处理+page.server.ts中的请求逻辑,无需额外修改校验代码。

  2. 可选:动态切换语言
    若需根据请求动态切换语言,可在load函数中获取请求的locale信息:

export async function load({ request }) {
  // 示例从请求头Accept-Language中提取首选语言
  const locale = request.headers.get('Accept-Language')?.split(',')[0] || 'es';
  
  // 按需导入对应语言的翻译文件
  const translation = await import(`zod-i18n-map/locales/${locale}/zod.json`);
  
  await i18next.init({
    lng: locale,
    resources: {
      [locale]: { zod: translation.default },
    },
    initImmediate: false,
  });
  z.setErrorMap(zodI18nMap);
}

内容的提问来源于stack exchange,提问作者Jul Pod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 01:23:36