golang支持.po/.mo文件的i18n国际化文本模板处理插件txtemplate的使用

Golang 支持 .po/.mo 文件的 i18n 国际化文本模板处理插件 txtemplate 的使用

介绍

t 是一个受 GNU gettext 启发的 Go 语言国际化工具,支持 .po 和 .mo 文件格式。

安装

go get -u github.com/youthlin/t

或者在 go.mod 中添加:

require (
    github.com/youthlin/t latest
)

使用示例

基本用法

package main

import (
	"fmt"
	"github.com/youthlin/t"
)

func main() {
	// 1. 绑定翻译文件
	path := "path/to/filename.po" // 可以是 .po 或 .mo 文件
	// 或者目录路径
	// path = "path/to/po_mo/dir"
	
	// 默认绑定在 default 域
	t.Load(path) 
	// 或者指定文本域
	t.Bind("my-domain", path)

	// 2. 设置使用的文本域
	t.SetDomain("my-domain")

	// 3. 设置用户语言
	t.SetLocale(t.MostMatchLocale()) // 空则使用系统默认

	// 4. 使用 gettext 翻译接口
	fmt.Println(t.T("Hello, world"))
	fmt.Println(t.T("Hello, %v", "Tom"))
	
	// 单复数处理
	fmt.Println(t.N("One apple", "%d apples", 1)) // One apple
	fmt.Println(t.N("One apple", "%d apples", 2)) // 2 apples
	
	// 带上下文的翻译
	t.X("msg_context_text", "msg_id")
	t.XN("msg_context_text", "msg_id", "msg_plural", n)
}

文本域(Domain)使用

// 绑定不同域的翻译文件
t.Bind("domain1", "path1")
t.Bind("domain2", "path2")
t.SetLocale("zh_CN")

// 使用默认域
t.T("msg_id")

// 设置当前域
t.SetDomain("domain1")
t.T("msg_id") // 使用 domain1

// 临时指定域
t.D("domain2").T("msg_id") // 使用 domain2

// 不存在的域会直接返回原消息
t.D("unknown-domain").T("msg_id") // 返回 "msg_id"

多语言支持

// 指定语言
t.L("zh_CN").T("msg_id")

// 根据用户偏好自动匹配语言
langs := t.Locales()
var supported []language.Tag
for _, lang := range langs {
    supported = append(supported, language.Make(lang))
}
matcher := language.NewMatcher(supported)

// 从浏览器头获取用户语言
userAccept, _, _ := language.ParseAcceptLanguage("zh-CN,zh;q=0.9,en;q=0.8")

// 匹配最合适的语言
matchedTag, index, _ := matcher.Match(userAccept...)
userLang := langs[index]
t.L(userLang).T("msg_id")

// 同时指定域和语言
t.D("domain").L(userLang).T("msg_id")

API 概览

T(msgID, args...)                  // gettext
N(msgID, msgIDPlural, n, args...)   // ngettext
X(msgCTxt, msgID, args...)          // pgettext
XN(msgCTxt, msgID, msgIDPlural, n, args...) // npgettext
D(domain)                           // 指定域
L(locale)                           // 指定语言

提取翻译文本

使用 PoEdit 提取翻译文本:

  1. 在 PoEdit 设置中添加 Go 语言提取器
  2. 语言填 Go,扩展名填 *.go
  3. 提取命令填写:
    xgettext -C --add-comments=TRANSLATORS: --force-po -o %o %C %K %F
    
  4. 关键字设置:
    T:1;N:1,2;N64:1,2;X:2,1c;XN:2,3,1c;XN64:2,3,1c
    

或者直接使用命令行:

xgettext -C --add-comments=TRANSLATORS: --force-po -kT -kN:1,2 -kX:2,1c -kXN:2,3,1c *.go

从 HTML 模板提取

安装 xtemplate 工具:

go install github.com/youthlin/t/cmd/xtemplate@latest

已完成功能

  • ✅ 支持 .mo 二进制文件
  • ✅ 从模板文件中提取翻译文本

示例代码

以下是一个完整的示例,展示如何使用 t 库进行国际化:

package main

import (
	"fmt"
	"github.com/youthlin/t"
	"golang.org/x/text/language"
)

func main() {
	// 加载翻译文件
	t.Load("locales") // 假设 locales 目录下有 zh_CN.po 和 en_US.po

	// 设置语言为中文
	t.SetLocale("zh_CN")

	// 简单翻译
	fmt.Println(t.T("Hello, world")) // 输出: 你好,世界

	// 带参数的翻译
	fmt.Println(t.T("Hello, %s", "Alice")) // 输出: 你好,Alice

	// 单复数处理
	fmt.Println(t.N("One apple", "%d apples", 1)) // 输出: 一个苹果
	fmt.Println(t.N("One apple", "%d apples", 3)) // 输出: 3 个苹果

	// 根据浏览器头自动选择语言
	userAccept, _, _ := language.ParseAcceptLanguage("zh-CN,zh;q=0.9,en;q=0.8")
	langs := t.Locales()
	var supported []language.Tag
	for _, lang := range langs {
		supported = append(supported, language.Make(lang))
	}
	matcher := language.NewMatcher(supported)
	_, index, _ := matcher.Match(userAccept...)
	userLang := langs[index]

	// 使用匹配到的语言
	fmt.Println(t.L(userLang).T("Welcome")) // 根据用户语言输出欢迎语
}

这个示例展示了 t 库的主要功能,包括基本翻译、带参数翻译、单复数处理以及根据用户偏好自动选择语言。


更多关于golang支持.po/.mo文件的i18n国际化文本模板处理插件txtemplate的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang支持.po/.mo文件的i18n国际化文本模板处理插件txtemplate的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 txtemplate 处理 Go 中的 i18n 国际化文本

txtemplate 是一个 Go 语言的国际化(i18n)文本处理库,它支持 .po/.mo 文件格式,可以与 Go 的标准模板引擎 text/template 或 html/template 配合使用。

安装 txtemplate

首先安装 txtemplate 库:

go get github.com/tdewolff/parse/v2/txtemplate

基本用法

1. 准备 .po 文件

创建一个翻译文件,例如 translations/zh_CN.po:

msgid "Hello"
msgstr "你好"

msgid "Welcome, %s"
msgstr "欢迎, %s"

msgid "You have %d new messages"
msgstr "您有 %d 条新消息"

2. 加载翻译文件

package main

import (
	"fmt"
	"html/template"
	"log"
	"os"

	"github.com/tdewolff/parse/v2/txtemplate"
)

func main() {
	// 创建翻译器
	translator := txtemplate.NewTranslator()

	// 加载翻译文件
	if err := translator.LoadPOFile("translations/zh_CN.po"); err != nil {
		log.Fatal(err)
	}

	// 创建带有翻译功能的模板
	tmpl := template.New("example").Funcs(txtemplate.FuncMap(translator))

	// 解析模板
	tmpl, err := tmpl.Parse(`
		<p>{{ T "Hello" }}</p>
		<p>{{ T "Welcome, %s" "张三" }}</p>
		<p>{{ T "You have %d new messages" 5 }}</p>
	`)
	if err != nil {
		log.Fatal(err)
	}

	// 执行模板
	if err := tmpl.Execute(os.Stdout, nil); err != nil {
		log.Fatal(err)
	}
}

3. 输出结果

执行上面的代码会输出:

<p>你好</p>
<p>欢迎, 张三</p>
<p>您有 5 条新消息</p>

高级用法

支持复数形式

.po 文件中可以定义复数形式:

msgid "%d file"
msgid_plural "%d files"
msgstr[0] "%d 个文件"
msgstr[1] "%d 个文件"

在模板中使用:

{{ T "%d file" "%d files" 1 }}  // 输出 "1 个文件"
{{ T "%d file" "%d files" 5 }}  // 输出 "5 个文件"

上下文支持

有时相同的原文在不同上下文中需要不同翻译:

msgctxt "button"
msgid "Submit"
msgstr "提交"

msgctxt "form"
msgid "Submit"
msgstr "递交"

在模板中使用:

{{ TC "button" "Submit" }}  // 输出 "提交"
{{ TC "form" "Submit" }}    // 输出 "递交"

自动重新加载翻译文件

在开发环境中,可以启用自动重新加载:

translator := txtemplate.NewTranslator()
translator.SetAutoReload(true) // 启用自动重新加载
translator.SetWatchInterval(5 * time.Second) // 每5秒检查一次文件变化

最佳实践

  1. 组织翻译文件:按语言代码组织目录结构,如 translations/zh_CN/LC_MESSAGES/app.po

  2. 使用工具管理翻译:可以使用 Poedit 等工具编辑 .po 文件

  3. 在构建时编译 .mo 文件:虽然 txtemplate 可以直接使用 .po 文件,但生产环境建议使用编译后的 .mo 文件

  4. 处理缺失翻译:可以设置回调函数处理未翻译的文本

translator.SetMissingHandler(func(language, msgid string) string {
    log.Printf("Missing translation for %q in language %q", msgid, language)
    return msgid // 返回原文作为默认值
})

txtemplate 提供了简单而强大的国际化支持,能够很好地与 Go 的模板系统集成,是处理多语言应用的优秀选择。

回到顶部