Skip to content

Commit

Permalink
Merge pull request #1 from gohugoio/sync20230805
Browse files Browse the repository at this point in the history
  • Loading branch information
bep authored Aug 5, 2023
2 parents 4c28c89 + 9d0cd88 commit e63c132
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 15 deletions.
145 changes: 145 additions & 0 deletions .github/README.zh-Hans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# go-i18n ![Build status](https://github.com/nicksnyder/go-i18n/workflows/Build/badge.svg) [![Report card](https://goreportcard.com/badge/github.com/nicksnyder/go-i18n)](https://goreportcard.com/report/github.com/nicksnyder/go-i18n) [![codecov](https://codecov.io/gh/nicksnyder/go-i18n/branch/master/graph/badge.svg)](https://codecov.io/gh/nicksnyder/go-i18n) [![Sourcegraph](https://sourcegraph.com/github.com/nicksnyder/go-i18n/-/badge.svg)](https://sourcegraph.com/github.com/nicksnyder/go-i18n?badge)

go-i18n 是一个帮助您将 Go 程序翻译成多种语言的 Go [](#package-i18n)[命令](#command-goi18n)

- 支持 [Unicode Common Locale Data Repository (CLDR)](https://www.unicode.org/cldr/charts/28/supplemental/language_plural_rules.html) 中所有 200 多种语言的 [复数字符](http://cldr.unicode.org/index/cldr-spec/plural-rules)
- 代码和测试是从 [CLDR 数据](http://cldr.unicode.org/index/downloads)[自动生成](https://github.com/nicksnyder/go-i18n/tree/main/v2/internal/plural/codegen) 的。
- 使用 [text/template](http://golang.org/pkg/text/template/) 语法支持带有命名变量的字符串。
- 支持任何格式的消息文件(例如:JSON、TOML、YAML)。

<strong align="center">
<samp>

[**English**](../README.md) · [**简体中文**](README.zh-Hans.md)

</samp>
</strong>

## Package i18n

[![GoDoc](https://godoc.org/github.com/nicksnyder/go-i18n?status.svg)](https://godoc.org/github.com/nicksnyder/go-i18n/v2/i18n)

i18n 包支持根据一组语言环境首选项查找消息。

```go
import "github.com/nicksnyder/go-i18n/v2/i18n"
```

创建一个 Bundle 以在应用程序的整个生命周期中使用。

```go
bundle := i18n.NewBundle(language.English)
```

在初始化期间将翻译加载到您的 bundle 中。

```go
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile("es.toml")
```

```go
// 如果使用 go:embed
//go:embed locale.*.toml
var LocaleFS embed.FS

bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFileFS(LocaleFS, "locale.es.toml")
```

创建一个 Localizer 以用于一组语言首选项。

```go
func(w http.ResponseWriter, r *http.Request) {
lang := r.FormValue("lang")
accept := r.Header.Get("Accept-Language")
localizer := i18n.NewLocalizer(bundle, lang, accept)
}
```

使用 Localizer 查找消息。

```go
localizer.Localize(&i18n.LocalizeConfig{
DefaultMessage: &i18n.Message{
ID: "PersonCats",
One: "{{.Name}} has {{.Count}} cat.",
Other: "{{.Name}} has {{.Count}} cats.",
},
TemplateData: map[string]interface{}{
"Name": "Nick",
"Count": 2,
},
PluralCount: 2,
}) // Nick has 2 cats.
```

## goi18n 命令

[![GoDoc](https://godoc.org/github.com/nicksnyder/go-i18n?status.svg)](https://godoc.org/github.com/nicksnyder/go-i18n/v2/goi18n)

goi18n 命令管理 i18n 包使用的消息文件。

```
go install -v github.com/nicksnyder/go-i18n/v2/goi18n@latest
goi18n -help
```

### 提取消息

使用 `goi18n extract` 将 Go 源文件中的所有 i18n.Message 结构文字提取到消息文件中以进行翻译。

```toml
# active.en.toml
[PersonCats]
description = "The number of cats a person has"
one = "{{.Name}} has {{.Count}} cat."
other = "{{.Name}} has {{.Count}} cats."
```

### 翻译一种新语言

1. 为您要添加的语言创建一个空消息文件(例如:`translate.es.toml`)。
2. 运行 `goi18n merge active.en.toml translate.es.toml` 以填充 `translate.es.toml` 要翻译的消息。

```toml
# translate.es.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "Hello {{.Name}}"
```

3. 翻译完成 `translate.es.toml` 后,将其重命名为 `active.es.toml``。

```toml
# active.es.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "Hola {{.Name}}"
```

4. 加载 `active.es.toml` 到您的 bundle 中。

```go
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile("active.es.toml")
```

### 翻译新消息

如果您在程序中添加了新消息:

1. 运行 `goi18n extract` 以使用新消息更新 `active.en.toml`
2. 运行 `goi18n merge active.*.toml` 以生成更新的 `translate.*.toml` 文件。
3. 翻译 `translate.*.toml` 文件中的所有消息。
4. 运行 `goi18n merge active.*.toml translate.*.toml` 将翻译后的消息合并到 active 消息文件中。

## 有关更多信息和示例:

- 阅读 [文档](https://godoc.org/github.com/nicksnyder/go-i18n/v2)
- 查看 [代码示例](https://github.com/nicksnyder/go-i18n/blob/main/v2/i18n/example_test.go)[测试](https://github.com/nicksnyder/go-i18n/blob/main/v2/i18n/localizer_test.go)
- 查看一个示例 [程序](https://github.com/nicksnyder/go-i18n/tree/main/v2/example)

## 许可证

go-i18n 在 MIT 许可下可用。有关更多信息,请参阅 [许可证](LICENSE) 文件。
19 changes: 10 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ jobs:
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'pull_request'
steps:
- name: Install Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: 1.15.2
go-version: stable
- name: Git checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build
uses: goreleaser/goreleaser-action@v2
with:
Expand All @@ -25,23 +25,24 @@ jobs:
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage
uses: codecov/codecov-action@v1
build_1_9_7:
name: Build with Go 1.9.7
build_1_12:
name: Build with Go 1.12.17
runs-on: ubuntu-latest
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'pull_request'
steps:
- name: Install Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: 1.9.7
go-version: '1.12.17'
- name: Git checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: gopath/src/github.com/nicksnyder/go-i18n
- name: Build and test
working-directory: gopath/src/github.com/nicksnyder/go-i18n/v2
env:
GOPATH: ${{ github.workspace }}/gopath
GO111MODULE: on
run: |
go get -t ./...
go get ./...
go test -race ./...
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '^1.15.2'
go-version: '^1.19.3'
-
name: Release
uses: goreleaser/goreleaser-action@v2
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/lsif-go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ jobs:
- uses: actions/checkout@v1
- name: Generate LSIF data
run: lsif-go
working-directory: v2
- name: Upload LSIF data to Sourcegraph.com
run: src lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} -ignore-upload-failure
working-directory: v2
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ go-i18n is a Go [package](#package-i18n) and a [command](#command-goi18n) that h
- Supports strings with named variables using [text/template](http://golang.org/pkg/text/template/) syntax.
- Supports message files of any format (e.g. JSON, TOML, YAML).

<strong align="center">
<samp>

[**English**](README.md) · [**简体中文**](.github/README.zh-Hans.md)

</samp>
</strong>

## Package i18n
[![GoDoc](https://godoc.org/github.com/nicksnyder/go-i18n?status.svg)](https://godoc.org/github.com/nicksnyder/go-i18n/v2/i18n)

Expand All @@ -29,6 +37,15 @@ bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile("es.toml")
```

```go
// If use go:embed
//go:embed locale.*.toml
var LocaleFS embed.FS

bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFileFS(LocaleFS, "locale.es.toml")
```

Create a Localizer to use for a set of language preferences.

```go
Expand Down Expand Up @@ -62,7 +79,7 @@ localizer.Localize(&i18n.LocalizeConfig{
The goi18n command manages message files used by the i18n package.

```
go get -u github.com/nicksnyder/go-i18n/v2/goi18n
go install -v github.com/nicksnyder/go-i18n/v2/goi18n@latest
goi18n -help
```

Expand Down
2 changes: 1 addition & 1 deletion v2/i18n/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (b *Bundle) LoadMessageFile(path string) (*MessageFile, error) {
return b.ParseMessageFileBytes(buf, path)
}

// MustLoadMessageFile is similar to LoadTranslationFile
// MustLoadMessageFile is similar to LoadMessageFile
// except it panics if an error happens.
func (b *Bundle) MustLoadMessageFile(path string) {
if _, err := b.LoadMessageFile(path); err != nil {
Expand Down
9 changes: 9 additions & 0 deletions v2/i18n/localizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ import (
)

// Localizer provides Localize and MustLocalize methods that return localized messages.
// Localize and MustLocalize methods use a language.Tag matching algorithm based
// on the best possible value. This algorithm may cause an unexpected language.Tag returned
// value depending on the order of the tags stored in memory. For example, if the bundle
// used to create a Localizer instance ingested locales following this order
// ["en-US", "en-GB", "en-IE", "en"] and the locale "en" is asked, the underlying matching
// algorithm will return "en-US" thinking it is the best match possible. More information
// about the algorithm in this Github issue: https://github.com/golang/go/issues/49176.
// There is additionnal informations inside the Go code base:
// https://github.com/golang/text/blob/master/language/match.go#L142
type Localizer struct {
// bundle contains the messages that can be returned by the Localizer.
bundle *Bundle
Expand Down
7 changes: 4 additions & 3 deletions v2/internal/template_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package internal

import (
"strings"
"testing"
"text/template"
)
Expand Down Expand Up @@ -45,16 +46,16 @@ func TestExecute(t *testing.T) {
template: &Template{
Src: "hello {{",
},
err: "template: :1: unexpected unclosed action in command",
err: "unclosed action",
noallocs: true,
},
}

for _, test := range tests {
t.Run(test.template.Src, func(t *testing.T) {
result, err := test.template.Execute(test.funcs, test.data)
if actual := str(err); actual != test.err {
t.Errorf("expected err %q; got %q", test.err, actual)
if actual := str(err); !strings.Contains(str(err), test.err) {
t.Errorf("expected err %q to contain %q", actual, test.err)
}
if result != test.result {
t.Errorf("expected result %q; got %q", test.result, result)
Expand Down

0 comments on commit e63c132

Please sign in to comment.