Skip to content

本地化

概述

Goyave 框架提供了便捷的方式来支持应用程序中的多语言。开箱即用,Goyave 仅提供 en-US 语言,但您可以添加任意多种语言。

. └── resources    └── lang       └── en-US (语言名称)       ├── fields.json (可选)       ├── locale.json (可选)       └── rules.json (可选)

每种语言都有自己的目录,应使用 ISO 639-1 语言代码命名。您还可以为语言添加变体:en-USen-UKfr-FRfr-CA 等。大小写很重要。

每个语言目录包含三个文件。每个文件都是可选的

  • fields.json: 字段名称翻译和字段特定的规则消息。
  • locale.json: 所有其他语言行。
  • rules.json: 验证规则消息。

INFO

resources/lang 目录中的所有目录在服务器创建时会自动加载。

语言文件

字段 (Fields)

fields.json 文件包含字段名称的翻译。翻译字段名称有助于生成更具表现力的消息,而不是向用户显示技术性的字段名称。

示例:

json
{
  "email": "电子邮件地址"
}

这样,验证错误消息中的 :field 占位符将被填充为“电子邮件地址”,而不是原始字段名“email”。

INFO

有关验证消息占位符的更多信息,请参阅验证部分。

区域设置 (Locale)

locale.json 文件包含与验证相关的所有语言行。这是您应该为用户界面或控制器返回的消息编写语言行的地方。

示例:

json
{
  "product.created": "产品已成功创建。",
  "product.deleted": "产品已成功删除。"
}

TIP

使用点分隔的名称作为语言行是一个好习惯,有助于使它们更清晰、更具表现力。

规则 (Rules)

rules.json 文件包含验证规则消息。这些消息可以包含**占位符**,验证器会自动用动态值替换它们。如果您编写自定义验证规则,它们的消息应写在此文件中。

示例:

json
{
  "integer": ":field 必须是整数。",
  "starts_with": ":field 必须以以下值之一开头::values。",
  "same": ":field 和 :other 必须匹配。"
}

TIP

  • 如果在应用程序中定义了 en-US 语言,则默认语言行将被语言文件中的行覆盖,所有未定义的行将保留。
  • 验证规则的本地化在此处有更详细的说明。

手动加载

可以从其他位置手动加载语言目录。如果加载的语言已在应用程序中可用,新加载的语言将通过合并覆盖先前的语言。

go
import (
	"embed"
	"fmt"
	"os"

	"goyave.dev/goyave/v5"
	"goyave.dev/goyave/v5/lang"
	"goyave.dev/goyave/v5/util/errors"
	"goyave.dev/goyave/v5/util/fsutil"
)

//go:embed resources
var resources embed.FS

func main() {
	server, err := goyave.New(goyave.Options{})
	if err != nil {
		fmt.Fprintln(os.Stderr, err.(*errors.Error).String())
		os.Exit(1)
	}

	resources := fsutil.NewEmbed(resources)
	langFS, err := resources.Sub("resources/lang")
	if err != nil {
		server.Logger.Error(err)
		os.Exit(1)
	}

	err = server.Lang.Load(langFS, "en-CA", "lang/en-CA")
	err = server.Lang.LoadDirectory(langFS, "lang")
	//...
}

TIP

任何实现 fsutil.FS 的文件系统都可以使用。如果不想使用嵌入式文件系统,可以使用 osfs.FS

使用本地化

有两个重要的结构需要了解:

  • *lang.Languages: 所有已加载语言的容器,它还定义了默认语言。此容器对所有组件可访问。
  • *lang.Language: 单一语言,包含所有本地化的行。

当传入请求进入应用程序时,内置的语言中间件检查是否设置了 Accept-Language 头,并将 *goyave.Request.Lang 字段设置为识别出的 *lang.Language 或默认语言。

您可以使用语言的 Get() 方法获取本地化字符串。

go
func (ctrl *Controller) Handle(response *goyave.Response, request *goyave.Request) {
	request.Lang.Get("customMessage")
	// 或
	ctrl.Lang().GetDefault().Get("customMessage")
	ctrl.Lang().Get("en-US", "customMessage")
}

路径

  • locale.json 中定义的自定义行直接使用其键访问。
  • rules.json 中定义的验证规则消息使用 validation.rules 前缀访问:
    • validation.rules.<规则名称>
    • validation.rules.<规则名称>.element
    • validation.rules.<规则名称>.string
    • validation.rules.<规则名称>.numeric
    • validation.rules.<规则名称>.array
    • validation.rules.<规则名称>.file
    • validation.rules.<规则名称>.object
  • fields.json 中定义的字段名称使用 validation.fields 前缀访问:
    • validation.fields.<字段名称>

INFO

不存在的条目会按原样返回。例如,如果您 Get() 一个语言条目 validation.rules.nonExisting,返回的字符串将是 validation.rules.nonExisting

占位符

语言行可以包含占位符。占位符由冒号直接后跟占位符名称标识:

json
{
  "greetings": "问候,:username!"
}

Get() 方法的最后一个参数是占位符及其替换值的可变关联切片。在以下示例中,占位符 :username 将被用户结构中的 Name 字段替换。

go
language.Get("greetings", ":username", user.Name) // "问候,Taylor!"

您可以提供任意数量的占位符:

go
language.Get("greetings-with-date", ":username", user.Name, ":day", "星期一") // "问候,Taylor!今天是星期一"

TIP

当提供占位符时,所有出现的占位符都会被替换。

json
{
  "popular": ":product 非常受欢迎。:product 的销售额上周超过了1000。"
}

go
language.Get("popular", ":product", "割草机")
// "割草机非常受欢迎。割草机的销售额上周超过了1000。"