t

package module
v0.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 5, 2024 License: MIT Imports: 13 Imported by: 28

README

t

t: a translation util for go, inspired by GNU gettext
t: GNU gettext 的 Go 语言实现,Go 程序的国际化工具
sync-to-gitee test codecov Go Report Card Go Reference FOSSA Status

Install 安装

go get -u github.com/youthlin/t

go.mod

require (
    github.com/youthlin/t latest
)

Gitee 镜像:gitee.com/youthlin/gottext (gottext: go + gettext)

鸣谢仓库同步工具:https://github.com/Yikun/hub-mirror-action

// 使用 gitee 镜像
// go.mod:
replace github.com/youthlin/t latest => gitee.com/youthlin/gottext latest

Usage 使用

path := "path/to/filename.po" // .po, .mo file
path = "path/to/po_mo/dir"    // or dir.
// (mo po 同名的话,po 后加载,会覆盖 mo 文件,因为 po 是文本文件,方便修改生效)
// 1 bind domain 绑定翻译文件
t.Load(path) // 默认绑定在 default 域 会自动搜索路径下的文件,读取 po/mo 里的语言标签进行注册
t.Bind("my-domain", path) // 或者指定Ø文本域
// 2 set current domain 设置使用的文本域
t.SetDomain("my-domain")
// 3 set user language 设置用户语言
// t.SetLocale("zh_CN")
t.SetLocale(t.MostMatchLocale()) // empty to use system default
// 4 use the gettext api 使用 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)) // %d apples
// t.N(single, plural, n, args...)
// n => used to choose single or plural
// args => to format
// args... supported, used to format string
// 支持传入 args... 参数用于格式化输出
fmt.Println(t.N("One apple", "%d apples", 2, 2)) // 2 apples
fmt.Println(t.N("%[2]s has one apple", "%[2]s has %[1]d apples", 2, 200, "Bob"))
// Bob has 200 apples
t.X("msg_context_text", "msg_id")
t.X("msg_context_text", "msg_id")
t.XN("msg_context_text", "msg_id", "msg_plural", n)

API

T(msgID, args...)
N(msgID, msgIDPlural, n, args...) // and N64
X(msgCTxt, msgID, args...)
XN(msgCTxt, msgID, msgIDPlural, n, args...) // and XN64
D(domain)
L(locale)
// T:  gettext
// N:  ngettext
// X:  pgettext
// XN: npgettext
// D:  with domain
// L:  with locale(language)

Domain 文本域

t.Bind(domain1, path1)
t.Bind(domain2, path2)
t.SetLocale("zh_CN")

t.T("msg_id")           // use default domain

t.SetDomain(domain1)
t.T("msg_id")            // use domain1
t.D(domain2).T("msg_id") // use domain2
t.D("unknown-domain").T("msg_id") // return "msg_id" directly

Language 指定语言

If you are building a web application, you may want each request use diffenrent language, the code below may help you:
如果你写的是 web 应用而不是 cli 工具,你可能想让每个 request 使用不同的语言,请看:

t.Load(path)

// a) Specify a language 可以指定语言
t.L("zh_CN").T("msg_id")

// b) every one use his own language 每个用户使用他接受的语言
// b.1) server supports 第一步,服务器支持的语言
langs := t.Locales()
// golang.org/x/text/language
// EN: https://blog.golang.org/matchlang
// 中文: https://learnku.com/docs/go-blog/matchlang/6525
var supported []language.Tag
for _, lang =range langs{
    supported = append(supported, language.Make(lang))
}
matcher := language.NewMatcher(supported)
// b.2) user accept 第二步,用户接受的语言
// Judging by the browser header(Accept-Language)
// 根据浏览器标头获取用户语言
// or: userAccept := []language.Tag{ language.Make("lang-code-from-cookie") }
// 或从 cookie 中获取用户语言偏好
userAccept, q, err :=language.ParseAcceptLanguage("zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
// b.3) match 第三步,匹配出最合适的
matchedTag, index, confidence := matcher.Match(userAccept...)
// confidence may language.No, language.Low, language.High, language.Exact
// 这里 confidence 是指匹配度,可以根据你的实际需求决定是否使用匹配的语言。
// 如服务器支持 英文、简体中文,如果用户是繁体中文,那匹配度就不是 Exact,
// 这时根据实际需求决定是使用英文,还是简体中文。
userLang := langs[index]
t.L(userLang).T("msg_id")

// with domain, language 同时指定文本域、用户语言
t.D(domain).L(userLang).T("msg_id")

more examples can be find at: example_test.go

How to extract string 提取翻译文本

# if you use PoEdit, add a extractor
# 如果你使用 PoEdit,在设置-提取器中新增一个提取器
# Language: Go, *.go 语言填 Go 扩展名填 *.go 提取翻译的命令填写
# xgettext -C --add-comments=TRANSLATORS: --force-po -o %o %C %K %F
# 最后的三个输入框分别填写
# -k%k
# %f
# --from-code=%c
# keywords: 关键字这样设置:
# 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

Done 已完成

  • ✅ mo file 支持 mo 二进制文件
  • ✅ extract from html templates 从模板文件中提取: xtemplate
go install github.com/youthlin/t/cmd/xtemplate@latest

License

FOSSA Status

Documentation

Overview

Example (BindDomain)

Example_bindDomain 绑定到指定文本域

package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	t.SetLocale("zh")
	t.Bind("main", "testdata/zh_CN.po")
	fmt.Println("HasDomain(main) =", t.HasDomain("main"))
	fmt.Println("HasDomain(no) =", t.HasDomain("no"))
	fmt.Println("Domains =", t.Domains())
	fmt.Println(t.T("Hello, World"))
	t.SetDomain("main")
	fmt.Println(t.T("Hello, World"))
}
Output:

HasDomain(main) = true
HasDomain(no) = false
Domains = [main]
Hello, World
你好,世界
Example (Gettext)
package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	t.Load("testdata")
	t.SetLocale("zh_CN")
	fmt.Println(t.T("Hello, World"))                                 // 你好,世界
	fmt.Println(t.T("Hello, %s", "Tom"))                             // 你好,世界
	fmt.Println(t.N("One apple", "%d apples", 1))                    // %d 个苹果
	fmt.Println(t.N("One apple", "%d apples", 1, 1))                 // 1 个苹果
	fmt.Println(t.N("One apple", "%d apples", 2))                    // %d 个苹果
	fmt.Println(t.N("One apple", "%d apples", 2, 2))                 // 2 个苹果
	fmt.Println(t.N64("One apple", "%d apples", 200, 200))           // 200 个苹果
	fmt.Println(t.X("File|", "Open"))                                // 打开文件
	fmt.Println(t.X("Project|", "Open"))                             // 打开工程
	fmt.Println(t.XN("File|", "Open One", "Open %d", 1, 1))          // 打开 1 个文件
	fmt.Println(t.XN("Project|", "Open One", "Open %d", 1))          // 打开 %d 个工程
	fmt.Println(t.XN("Project|", "Open One", "Open %d", 1, 1))       // 打开 1 个工程
	fmt.Println(t.XN64("Project|", "Open One", "Open %d", 100, 100)) // 打开 100 个工程
}
Output:

你好,世界
你好,Tom
%d 个苹果
1 个苹果
%d 个苹果
2 个苹果
200 个苹果
打开文件
打开工程
打开 1 个文件
打开 %d 个工程
打开 1 个工程
打开 100 个工程
Example (InitFS)

Example_initFS LoadFS 绑定文件系统到默认文本域

package main

import (
	"embed"
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

//go:embed testdata
var pathFS embed.FS

func main() {
	defer markSeq()()
	t.LoadFS(pathFS)
	t.SetLocale("zh")
	fmt.Println(t.T("Hello, World"))
}
Output:

你好,世界
Example (Init_file)

Example_init_file Load 绑定 path 到默认文本域, path 可以是单个文件

package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	t.Load("testdata/zh_CN.po")
	// will normalize to ll_CC form => zh_CN
	// 会格式化为 ll_CC 的形式
	t.SetLocale("zh_hans")
	fmt.Println(t.T("Hello, World"))
}
Output:

你好,世界
Example (Init_fileFS)

Example_init_fileFS embed.FS 可以是单个文件或文件夹

package main

import (
	"embed"
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

//go:embed testdata/zh_CN.po
var fileFS embed.FS

func main() {
	defer markSeq()()
	t.LoadFS(fileFS)
	t.SetLocale("zh_hans")
	fmt.Println("Current locale =", t.Locale()) // zh_CN
	fmt.Println(t.T("Hello, World"))

	// 设置不支持的语言,会原样返回
	t.SetLocale("zh_hant")
	fmt.Println("Current locale =", t.Locale()) // zh_TW
	fmt.Println(t.T("Hello, World"))
}
Output:

Current locale = zh_CN
你好,世界
Current locale = zh_TW
Hello, World
Example (Init_path)

Example_init_path Load 绑定 path 到默认文本域

package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	t.Load("testdata")
	// empty means system default locale
	// 设置为使用系统语言这一步骤可以省略,因为初始化时就是使用系统语言
	t.SetLocale("")
	// 为了能在其他环境测试通过,所以指定 zh_CN
	t.SetLocale("zh_CN")
	fmt.Println(t.T("Hello, World"))
}
Output:

你好,世界
Example (Locale)

Example_locale 语言设置示例

package main

import (
	"embed"
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

//go:embed testdata
var pathFS embed.FS

func main() {
	defer markSeq()()
	t.LoadFS(pathFS)
	t.SetLocale("zh")
	fmt.Println("UsedLocale =", t.UsedLocale()) // zh_CN
	t.SetLocale("zh_TW")
	fmt.Println("UsedLocale =", t.UsedLocale())             // en_US
	fmt.Println("SourceCodeLocale =", t.SourceCodeLocale()) // en_US

	ts := t.NewTranslations()
	ts.SetSourceCodeLocale("zh_CN")
	ts.SetLocale("en_US")
	fmt.Println("empty ts SourceCodeLocale =", ts.SourceCodeLocale()) // zh_CN
	fmt.Println("empty ts Locale =", ts.Locale())                     // en_US
	fmt.Println("empty ts UsedLocale =", ts.UsedLocale())             // zh_CN
	fmt.Println(ts.T("你好,世界"))
}
Output:

UsedLocale = zh_CN
UsedLocale = en_US
SourceCodeLocale = en_US
empty ts SourceCodeLocale = zh_CN
empty ts Locale = en_US
empty ts UsedLocale = zh_CN
你好,世界
Example (Locales)
package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	fmt.Println(t.Locales()) // [en_US] // SourceCodeLocale
	t.Load("testdata")
	fmt.Println(t.Locales()) // [en_US zh_CN]

	t.Bind("main", "testdata")
	fmt.Println(t.D("main").Locales())           // [en_US zh_CN]
	fmt.Println(t.D("no-such-domain").Locales()) // [en_US]
}
Output:

[en_US]
[en_US zh_CN]
[en_US zh_CN]
[en_US]
Example (With)
package main

import (
	"fmt"
	"sync"

	"github.com/youthlin/t"
)

var mu sync.Mutex

func markSeq() func() {
	mu.Lock()
	t.SetGlobal(t.NewTranslations())
	return func() { mu.Unlock() }
}

func main() {
	defer markSeq()()
	t.Bind("main", "testdata")
	l := t.L("zh_CN")
	fmt.Println(l.T("Hello, World")) // Hello, World

	d := t.D("main").L("zh_CN")
	fmt.Println(d.T("Hello, World")) // 你好,世界
}
Output:

Hello, World
你好,世界

Index

Examples

Constants

View Source
const DefaultDomain = "default"

DefaultDomain 默认的文本域

View Source
const DefaultSourceCodeLocale = "en_US"

DefaultSourceCodeLocale 默认的源代码语言

View Source
const HTTPHeaderAcceptLanguage = "Accept-Language"

Variables

View Source
var Mark = noop(0)

Mark is used to mark translation texts

Functions

func Bind added in v0.0.4

func Bind(domain, path string)

Bind bind translation from path to specified domain

func BindFS added in v0.0.4

func BindFS(domain string, fsys fs.FS)

BindFS bind translation from file system to specified domain

func Domain added in v0.0.4

func Domain() string

Domain return current domain

func Domains added in v0.0.4

func Domains() []string

Domains return all loaded domains

func GetCtxDomain added in v0.0.7

func GetCtxDomain(ctx context.Context) (string, bool)

func GetCtxLocale added in v0.0.7

func GetCtxLocale(ctx context.Context) (string, bool)

func GetUserLang added in v0.0.7

func GetUserLang(request *http.Request, opts ...getUserLangOpt) string

func HasDomain added in v0.0.4

func HasDomain(domain string) bool

HasDomain return if we have loaded the specified domain

func Load added in v0.0.4

func Load(path string)

Load load translation from path to current domain

func LoadFS added in v0.0.4

func LoadFS(fsys fs.FS)

LoadFS load translation from file system to current domain

func Locale

func Locale() string

Locale return current locale(it may not be used locale)

func Locales added in v0.0.4

func Locales() []string

Locales return all supported locales of current used domain 返回当前文本域中支持的所有语言

func Match added in v0.0.6

func Match(supported []string, userAccept []string) (tag language.Tag, index int, c language.Confidence)

func MatchTag added in v0.0.6

func MatchTag(supportedTags []language.Tag, userAcceptTags []language.Tag) (tag language.Tag, index int, c language.Confidence)

func MostMatchLocale added in v0.0.6

func MostMatchLocale() string

MostMatchLocale return the most match language 返回最匹配的语言

func N

func N(msgID, msgIDPlural string, n int, args ...interface{}) string

N is a short name of ngettext

func N64

func N64(msgID, msgIDPlural string, n int64, args ...interface{}) string

N64 is a short name of ngettext

func SetCtxDomain added in v0.0.7

func SetCtxDomain(ctx context.Context, domain string) context.Context

func SetCtxLocale added in v0.0.7

func SetCtxLocale(ctx context.Context, lang string) context.Context

func SetDomain added in v0.0.4

func SetDomain(domain string)

SetDomain set current domain

func SetGlobal added in v0.0.4

func SetGlobal(g *Translations)

SetGlobal set the global Translations instance

func SetLocale

func SetLocale(locale string)

SetLocale set user language

func SetSourceCodeLocale added in v0.0.4

func SetSourceCodeLocale(locale string)

SetSourceCodeLocale 设置源代码的语言

func SourceCodeLocale added in v0.0.4

func SourceCodeLocale() string

SourceCodeLocale 返回源代码中使用的语言

func T

func T(msgID string, args ...interface{}) string

T is a short name of gettext

func Tag added in v0.0.6

func Tag(locale string) language.Tag

func Tags added in v0.0.6

func Tags(locales []string) (tags []language.Tag)

func UsedLocale added in v0.0.4

func UsedLocale() string

UsedLocale return the actually used locale

func WithCookieName added in v0.0.7

func WithCookieName(cookieName string) getUserLangOpt

func X

func X(msgCtxt, msgID string, args ...interface{}) string

X is a short name of pgettext

func XN

func XN(msgCtxt, msgID, msgIDPlural string, n int, args ...interface{}) string

XN is a short name of npgettext

func XN64

func XN64(msgCtxt, msgID, msgIDPlural string, n int64, args ...interface{}) string

XN64 is a short name of npgettext

Types

type Translation

type Translation struct {
	// contains filtered or unexported fields
}

Translation can provide different language translation of a domain tr. [翻译域]包含各个语言的翻译

func NewTranslation

func NewTranslation(domain string, translators ...Translator) *Translation

NewTranslation create a new Translation

func (*Translation) AddOrReplace

func (tr *Translation) AddOrReplace(tor Translator) Translator

AddOrReplace add a translator and return the previous translator of this language

func (*Translation) Get added in v0.0.4

func (tr *Translation) Get(lang string) (Translator, bool)

Get get the Translator of the specified lang

func (*Translation) GetOrNoop added in v0.0.4

func (tr *Translation) GetOrNoop(lang string) Translator

GetOrNoop return the Translator of the specified language 获取指定语言的翻译

func (*Translation) LoadFS added in v0.0.4

func (tr *Translation) LoadFS(f fs.FS) bool

LoadFS load a translator from file system

func (*Translation) LoadFile added in v0.0.4

func (tr *Translation) LoadFile(file fs.File) error

LoadFile load a translator from a file

func (*Translation) LoadMo added in v0.0.4

func (tr *Translation) LoadMo(content []byte) error

LoadMo load mo file

func (*Translation) LoadPo added in v0.0.4

func (tr *Translation) LoadPo(content []byte) error

LoadPo load po file

type Translations

type Translations struct {
	// contains filtered or unexported fields
}

Translations holds several translation domains ts. [翻译集]包含多个翻译,每个翻译分别属于一个文本域

func D added in v0.0.4

func D(domain string) *Translations

D return a new Translations with domain

func Global added in v0.0.4

func Global() *Translations

Global return the global Translations instance

func L added in v0.0.4

func L(locale string) *Translations

L return a new Translations with locale

func NewTranslations

func NewTranslations() *Translations

NewTranslations create a new Translations 新建翻译集

func WithContext added in v0.0.7

func WithContext(ctx context.Context) *Translations

func (*Translations) BindFS added in v0.0.4

func (ts *Translations) BindFS(domain string, fsys fs.FS)

BindFS load a Translation form file system and bind to a domain 从文件系统绑定翻译域

func (*Translations) D added in v0.0.4

func (ts *Translations) D(domain string) *Translations

D return a new Translations with domain

func (*Translations) Domain added in v0.0.4

func (ts *Translations) Domain() string

Domain return current domain 返回当前使用的文本域

func (*Translations) Domains added in v0.0.4

func (ts *Translations) Domains() (domains []string)

Domains return all domains

func (*Translations) Get

func (ts *Translations) Get(domain string) (*Translation, bool)

Get return the Translation of the specified domain 获取指定的的翻译域

func (*Translations) GetOrNoop

func (ts *Translations) GetOrNoop(domain string) *Translation

GetOrNoop return the Translation of the specified domain 获取指定的的翻译域

func (*Translations) HasDomain added in v0.0.4

func (ts *Translations) HasDomain(domain string) bool

HasDomain return true if ts has the specified domain

func (*Translations) L added in v0.0.4

func (ts *Translations) L(locale string) *Translations

L return a new Translations with locale

func (*Translations) Locale

func (ts *Translations) Locale() string

Locale return current locale 返回设置的希望使用的语言

func (*Translations) Locales added in v0.0.4

func (ts *Translations) Locales() (locales []string)

Locales return all supported locales of domain 返回文本域中支持的所有语言

func (*Translations) MostMatchLocale added in v0.0.6

func (ts *Translations) MostMatchLocale() string

MostMatchLocale return the most match language 返回最匹配的语言

func (*Translations) N

func (ts *Translations) N(msgID, msgIDPlural string, n int, args ...interface{}) string

N is a short name of nettext

func (*Translations) N64

func (ts *Translations) N64(msgID, msgIDPlural string, n int64, args ...interface{}) string

N64 is a short name of nettext

func (*Translations) SetDomain added in v0.0.4

func (ts *Translations) SetDomain(domain string)

SetDomain set current domain 设置要使用的文本域

func (*Translations) SetLocale

func (ts *Translations) SetLocale(lang string)

SetLocale set current locale 设置要使用的语言

func (*Translations) SetSourceCodeLocale added in v0.0.4

func (ts *Translations) SetSourceCodeLocale(lang string)

SetSourceCodeLocale 设置源代码语言

func (*Translations) SourceCodeLocale added in v0.0.4

func (ts *Translations) SourceCodeLocale() string

SourceCodeLocale 设置源代码语言

func (*Translations) T

func (ts *Translations) T(msgID string, args ...interface{}) string

T is a short name of gettext

func (*Translations) UsedLocale added in v0.0.4

func (ts *Translations) UsedLocale() string

UsedLocale return the locale that actually used

func (*Translations) X

func (ts *Translations) X(msgCtxt, msgID string, args ...interface{}) string

X is a short name of pgettext

func (*Translations) XN

func (ts *Translations) XN(msgCtxt, msgID, msgIDPlural string, n int, args ...interface{}) string

XN is a short name of npgettext

func (*Translations) XN64

func (ts *Translations) XN64(msgCtxt, msgID, msgIDPlural string, n int64, args ...interface{}) string

XN64 is a short name of npgettext

type Translator added in v0.0.4

type Translator = translator.Translator

Translator 翻译接口

func NoopTranslator added in v0.0.4

func NoopTranslator() Translator

NoopTranslator return a no-op Translator

Directories

Path Synopsis
cmd
xtemplate Module
f

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL