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

如何在Next.js 14 Server Actions中集成国际化?

解决Next.js 14 Server Action中Zod验证的国际化问题

核心思路

Server Action运行在服务端,无法直接使用客户端国际化hooks(如useLocale),需通过表单传递locale参数或从请求上下文提取locale获取当前语言环境,再动态生成带本地化提示的Zod校验规则。


方案一:表单传递Locale(推荐)

这种方式直接可靠,避免依赖请求头或URL解析的不确定性:

  1. 客户端表单添加Locale隐藏字段
    在提交表单的客户端组件中,获取当前locale并作为隐藏字段传入:
'use client'
import { useLocale } from 'next/navigation'
import createUser from '@/actions/createUser'

export default function UserForm() {
  const locale = useLocale()

  return (
    <form action={createUser}>
      <input type="email" name="email" placeholder="Enter email" />
      {/* 传递当前语言环境 */}
      <input type="hidden" name="locale" value={locale} />
      <button type="submit">Submit</button>
    </form>
  )
}
  1. Server Action中读取Locale并生成本地化Zod Schema
    先定义本地化错误消息文件(如locales/en.json、locales/zh.json):
// locales/en.json
{
  "errors": {
    "email": {
      "invalid_type": "Invalid Email",
      "required": "Email is required"
    }
  }
}

// locales/zh.json
{
  "errors": {
    "email": {
      "invalid_type": "无效的邮箱格式",
      "required": "邮箱不能为空"
    }
  }
}

然后在Server Action中动态加载对应语言的消息,生成校验规则:

'use server'
import { z } from 'zod'

// 定义支持的语言列表,避免非法值
const SUPPORTED_LOCALES = ['en', 'zh'] as const

export default async function createUser(formData: FormData) {
  // 从表单获取locale,默认用英文
  const rawLocale = formData.get('locale') as string
  const locale = SUPPORTED_LOCALES.includes(rawLocale as any) ? rawLocale : 'en'

  // 加载对应语言的错误消息(服务端可直接读取文件)
  const messages = require(`../locales/${locale}.json`).errors

  // 动态生成带本地化提示的Zod Schema
  const schema = z.object({
    email: z.string({
      invalid_type_error: messages.email.invalid_type,
      required_error: messages.email.required
    }).email(messages.email.invalid_type)
  })

  const validatedFields = schema.safeParse({
    email: formData.get('email')
  })

  if (!validatedFields.success) {
    return {
      errors: validatedFields.error.flatten().fieldErrors
    }
  }

  // 执行后续数据操作
}

方案二:从请求上下文提取Locale

如果不想修改表单,可以从请求头或URL解析locale(依赖Next.js官方国际化的自动配置):

  1. 从请求头或URL获取Locale
'use server'
import { headers } from 'next/headers'
import { z } from 'zod'

const SUPPORTED_LOCALES = ['en', 'zh'] as const

function getCurrentLocale() {
  // 优先从Next.js官方请求头获取
  const headerLocale = headers().get('x-nextjs-locale')
  if (headerLocale && SUPPORTED_LOCALES.includes(headerLocale as any)) {
    return headerLocale
  }

  // 降级:从请求URL解析(如/en/xxx中的en)
  const referer = headers().get('referer')
  if (referer) {
    const url = new URL(referer)
    const urlLocale = url.pathname.split('/')[1]
    if (urlLocale && SUPPORTED_LOCALES.includes(urlLocale as any)) {
      return urlLocale
    }
  }

  return 'en'
}

export default async function createUser(formData: FormData) {
  const locale = getCurrentLocale()
  const messages = require(`../locales/${locale}.json`).errors

  const schema = z.object({
    email: z.string({
      invalid_type_error: messages.email.invalid_type
    })
  })

  // 后续校验逻辑同方案一
}

注意事项

  • 确保本地化消息文件路径正确,服务端读取时可结合process.cwd()使用绝对路径
  • 对locale值做合法性校验,避免加载不存在的语言文件导致报错
  • 如果使用TypeScript,可给本地化消息文件添加类型定义,提升类型安全性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:25:05