golang支持上下文感知国际化并具有简洁API的i18n插件库ctxi18n的使用

Golang支持上下文感知国际化并具有简洁API的i18n插件库ctxi18n的使用

介绍

ctxi18n是一个受Ruby on Rails国际化功能启发的Go语言国际化库,旨在为Go应用提供同样简单易用的国际化支持。

该库专注于将i18n数据提供给应用的上下文实例,同时也足够灵活可以直接使用。

主要特性:

  • 加载YAML或JSON格式的本地化文件,结构类似Ruby i18n
  • 轻松将本地化对象添加到上下文中
  • 支持使用fs.FS加载数据
  • 简洁的API方法如i18n.T()i18n.N()
  • 支持简单的键值插值,如Some %{key} text
  • 支持复数规则
  • 翻译缺失时的默认值

使用示例

首先导入库:

import "github.com/invopop/ctxi18n"

加载翻译文件

创建YAML或JSON翻译文件,例如:

en:
  welcome:
    title: "Welcome to our application!"
    login: "Log in"
    signup: "Sign up"
    forgot-password: "Forgot Password?"
es:
  welcome:
    title: "¡Bienvenido a nuestra aplicación!"
    login: "Ingresarse"
    signup: "Registrarse"
    forgot-password: "¿Olvidaste tu contraseña?"

加载翻译文件:

if err := ctxi18n.Load(assets.Content); err != nil {
    panic(err)
}

或设置默认语言:

if err := ctxi18n.LoadWithDefault(assets.Content, "en"); err != nil {
    panic(err)
}

上下文中使用

在HTTP或gRPC请求上下文中设置语言:

ctx = ctxi18n.WithLocale(ctx, "en")

支持RFC9110和Accept-Language头:

ctx = ctxi18n.WithLocale(ctx, "en-US,en;q=0.9,es;q=0.8")

翻译文本

有两种使用方式:

  1. 直接使用上下文方法:
import "github.com/invopop/ctxi18n/i18n"

fmt.Println(i18n.T(ctx, "welcome.title"))
  1. 从上下文中获取本地化对象:
l := ctxi18n.Locale(ctx)
fmt.Println(l.T("welcome.title"))

默认值

当翻译缺失时:

fmt.Println(l.T("welcome.no.text"))
// 输出: !(MISSING welcome.no.text)

设置默认值:

fmt.Println(i18n.T(ctx, "welcome.question", i18n.Default("Just ask!")))
// 输出: "Just ask!"

code := "EUR"
fmt.Println(i18n.T(ctx, "currencies."+code, i18n.Default(code)))
// 输出: "EUR"

或检查是否存在:

if !i18n.Has(ctx, "welcome.question") {
  fmt.Println("Just ask!")
}

插值

简单插值:

en:
  welcome:
    title: "Hi %{name}, welcome to our App!"

使用:

i18n.T(ctx, "welcome.title", i18n.M{"name":"Sam"})

结合默认值:

i18n.T(ctx, "welcome.title", i18n.Default("Hi %{name}"), i18n.M{"name":"Sam"})

复数化

定义复数翻译:

en:
  inbox:
    emails:
      zero: "You have no emails."
      one: "You have %{count} email."
      other: "You have %{count} emails."

使用:

count := 2
fmt.Println(i18n.N(ctx, "inbox.emails", count, i18n.M{"count": count}))
// 输出: "You have 2 emails."

作用域

减少重复键:

ctx := i18n.WithScope(ctx, "welcome")
i18n.T(ctx, ".title", i18n.M{"name":"Sam"})

Templ集成

与Templ模板引擎结合使用:

en:
  welcome:
    hello: "Hello, %{name}"

Templ组件:

package main

import "github.com/invopop/ctxi18n/i18n"

templ Hello(name string) {
  <span class="hello">
    { i18n.T(ctx, "welcome.hello", i18n.M{"name": name}) }
  </span>
}

templ Greeting(person Person) {
  <div class="greeting">
    @Hello(person.Name)
  </div>
}

完整示例

package main

import (
	"fmt"
	"github.com/invopop/ctxi18n"
	"github.com/invopop/ctxi18n/i18n"
	"context"
)

func main() {
	// 模拟加载翻译(实际应用中应使用embed.FS)
	translations := `
en:
  welcome:
    title: "Welcome, %{name}"
    messages:
      zero: "You have no messages"
      one: "You have 1 message"
      other: "You have %{count} messages"
`
	
	// 加载翻译
	if err := ctxi18n.LoadWithDefault([]byte(translations), "en"); err != nil {
		panic(err)
	}
	
	// 创建上下文并设置语言
	ctx := context.Background()
	ctx = ctxi18n.WithLocale(ctx, "en")
	
	// 简单翻译
	fmt.Println(i18n.T(ctx, "welcome.title", i18n.M{"name": "Alice"}))
	// 输出: Welcome, Alice
	
	// 复数翻译
	fmt.Println(i18n.N(ctx, "welcome.messages", 0, nil))
	// 输出: You have no messages
	fmt.Println(i18n.N(ctx, "welcome.messages", 1, nil))
	// 输出: You have 1 message
	fmt.Println(i18n.N(ctx, "welcome.messages", 5, i18n.M{"count": 5}))
	// 输出: You have 5 messages
	
	// 使用作用域
	ctx = i18n.WithScope(ctx, "welcome")
	fmt.Println(i18n.T(ctx, ".title", i18n.M{"name": "Bob"}))
	// 输出: Welcome, Bob
}

这个库提供了灵活且简洁的API来处理Go应用中的国际化需求,特别适合需要上下文感知的Web应用和服务。


更多关于golang支持上下文感知国际化并具有简洁API的i18n插件库ctxi18n的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang支持上下文感知国际化并具有简洁API的i18n插件库ctxi18n的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


ctxi18n - Go语言上下文感知国际化库

ctxi18n 是一个轻量级的Go语言国际化(i18n)库,它支持上下文感知的翻译,并提供了简洁易用的API。下面我将详细介绍它的使用方法和示例代码。

主要特性

  • 上下文感知翻译(根据请求上下文自动选择语言)
  • 简洁的API设计
  • 支持多种格式的翻译文件(JSON, YAML等)
  • 支持变量插值
  • 支持复数形式处理

安装

go get github.com/gin-contrib/i18n

基本使用

1. 初始化

package main

import (
	"github.com/gin-contrib/i18n"
	"github.com/nicksnyder/go-i18n/v2/i18n"
	"golang.org/x/text/language"
)

func main() {
	// 创建bundle实例
	bundle := i18n.NewBundle(language.English)
	
	// 注册JSON解析器
	bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
	
	// 加载翻译文件
	bundle.MustLoadMessageFile("locales/en.json")
	bundle.MustLoadMessageFile("locales/zh.json")
	bundle.MustLoadMessageFile("locales/ja.json")
	
	// 初始化ctxi18n
	i18n.InitI18n(bundle)
}

2. 翻译文件示例

locales/en.json:

{
  "hello": "Hello",
  "welcome": "Welcome, {{.Name}}",
  "unread_messages": {
    "one": "You have {{.Count}} unread message",
    "other": "You have {{.Count}} unread messages"
  }
}

locales/zh.json:

{
  "hello": "你好",
  "welcome": "欢迎, {{.Name}}",
  "unread_messages": {
    "one": "你有 {{.Count}} 条未读消息",
    "other": "你有 {{.Count}} 条未读消息"
  }
}

3. 在HTTP请求中使用

func handler(c *gin.Context) {
	// 简单翻译
	hello := i18n.MustGetMessage(c, "hello")
	
	// 带变量的翻译
	welcome := i18n.MustGetMessage(c, &i18n.LocalizeConfig{
		MessageID: "welcome",
		TemplateData: map[string]interface{}{
			"Name": "John",
		},
	})
	
	// 复数形式处理
	unread := i18n.MustGetMessage(c, &i18n.LocalizeConfig{
		MessageID: "unread_messages",
		PluralCount: 5,
		TemplateData: map[string]interface{}{
			"Count": 5,
		},
	})
	
	c.JSON(200, gin.H{
		"hello": hello,
		"welcome": welcome,
		"unread": unread,
	})
}

4. 中间件设置语言

func LanguageMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头获取语言
		lang := c.GetHeader("Accept-Language")
		
		// 如果没有指定,使用默认语言
		if lang == "" {
			lang = "en"
		}
		
		// 设置到上下文
		c.Set("language", lang)
		c.Next()
	}
}

5. 自定义语言解析器

func customLanguageResolver(c *gin.Context, defaultLanguage string) string {
	// 1. 检查URL参数
	if lang := c.Query("lang"); lang != "" {
		return lang
	}
	
	// 2. 检查cookie
	if lang, err := c.Cookie("lang"); err == nil {
		return lang
	}
	
	// 3. 检查Accept-Language头
	if lang := c.GetHeader("Accept-Language"); lang != "" {
		return lang
	}
	
	// 4. 返回默认语言
	return defaultLanguage
}

// 初始化时设置自定义解析器
i18n.InitI18n(bundle, customLanguageResolver)

高级用法

1. 批量翻译

messages := i18n.MustGetMessages(c, []*i18n.LocalizeConfig{
	{
		MessageID: "hello",
	},
	{
		MessageID: "welcome",
		TemplateData: map[string]interface{}{
			"Name": "Alice",
		},
	},
})

2. 回退机制

// 如果zh-CN不存在,会尝试zh,然后尝试默认语言
message := i18n.MustGetMessage(c, &i18n.LocalizeConfig{
	MessageID: "some_key",
	DefaultMessage: &i18n.Message{
		ID: "some_key",
		Other: "Default message",
	},
})

3. 自定义语言标签匹配器

bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)

// 设置自定义匹配器
bundle.Matcher = language.NewMatcher([]language.Tag{
	language.English,
	language.SimplifiedChinese,
	language.Japanese,
})

最佳实践

  1. 组织翻译文件:按功能模块拆分翻译文件,避免单个文件过大
  2. 键命名规范:使用点分隔的命名空间,如 user.login.title
  3. 错误处理:生产环境中不要使用Must方法,应该处理错误
  4. 性能考虑:在初始化时加载所有翻译文件,不要在请求时加载
  5. 测试:为关键翻译编写测试用例

总结

ctxi18n提供了简洁而强大的国际化支持,通过上下文感知的翻译机制,可以轻松实现多语言Web应用。它的API设计直观,与Go的标准库和流行框架(如Gin)集成良好,是Go项目中实现国际化的优秀选择。

对于更复杂的需求,还可以结合其他i18n工具如go-i18n的高级功能,构建完整的国际化解决方案。

回到顶部