This commit is contained in:
13
.drone.yml
Normal file
13
.drone.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go test -parallel 10 ./...
|
||||
|
||||
- name: golangci-lint
|
||||
image: golangci/golangci-lint:v1.39
|
||||
commands:
|
||||
- golangci-lint run
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# ---> Go
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
46
.golangci.yml
Normal file
46
.golangci.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 100
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
golint:
|
||||
min-confidence: 0
|
||||
govet:
|
||||
check-shadowing: true
|
||||
lll:
|
||||
line-length: 140
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- exhaustivestruct
|
||||
- maligned
|
||||
- interfacer
|
||||
- scopelint
|
||||
|
||||
issues:
|
||||
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gomnd
|
||||
- exhaustivestruct
|
||||
- wrapcheck
|
||||
- path: test/*
|
||||
linters:
|
||||
- gomnd
|
||||
- exhaustivestruct
|
||||
- wrapcheck
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
MIT License Copyright (c) 2020 4devs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# translation
|
||||
|
||||
[](https://drone.gitoa.ru/go-4devs/translation)
|
||||
[](https://goreportcard.com/report/gitoa.ru/go-4devs/translation)
|
||||
[](http://godoc.org/gitoa.ru/go-4devs/translation)
|
||||
19
arg/arg.go
Normal file
19
arg/arg.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package arg
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Arg defaults argument.
|
||||
type Arg struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// String arg to string.
|
||||
func (a Arg) String() string {
|
||||
return fmt.Sprintf("key:%s, value:%v", a.Key, a.Value)
|
||||
}
|
||||
|
||||
// Val gets valuet argument.
|
||||
func (a Arg) Val() interface{} {
|
||||
return a.Value
|
||||
}
|
||||
45
arg/currency.go
Normal file
45
arg/currency.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package arg
|
||||
|
||||
import "fmt"
|
||||
|
||||
// FormatCurrency types format.
|
||||
type FormatCurrency int
|
||||
|
||||
// Currency format.
|
||||
const (
|
||||
CurrencyFormatSymbol FormatCurrency = iota + 1
|
||||
CurrencyFormatISO
|
||||
CurrencyFormatNarrowSymbol
|
||||
)
|
||||
|
||||
// CurrencyOption configures option.
|
||||
type CurrencyOption func(*Currency)
|
||||
|
||||
// WithCurrencyFormat sets format currency.
|
||||
func WithCurrencyFormat(format FormatCurrency) CurrencyOption {
|
||||
return func(c *Currency) { c.Format = format }
|
||||
}
|
||||
|
||||
// WithCurrencyISO sets ISO 4217 code currecy.
|
||||
func WithCurrencyISO(iso string) CurrencyOption {
|
||||
return func(c *Currency) { c.ISO = iso }
|
||||
}
|
||||
|
||||
// Currency argument.
|
||||
type Currency struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
Format FormatCurrency
|
||||
// ISO 3-letter ISO 4217
|
||||
ISO string
|
||||
}
|
||||
|
||||
// String gets string from currency.
|
||||
func (a Currency) String() string {
|
||||
return fmt.Sprintf("currency key:%s, value:%v", a.Key, a.Value)
|
||||
}
|
||||
|
||||
// Val gets value currency.
|
||||
func (a Currency) Val() interface{} {
|
||||
return a.Value
|
||||
}
|
||||
49
arg/number.go
Normal file
49
arg/number.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package arg
|
||||
|
||||
import "fmt"
|
||||
|
||||
// FormatNumber format number.
|
||||
type FormatNumber int
|
||||
|
||||
// format argument.
|
||||
const (
|
||||
NumberFormatDecimal FormatNumber = iota + 1
|
||||
NumberFormatPercent
|
||||
NumberFormatPerMille
|
||||
NumberFormatEngineering
|
||||
NumberFormatScientific
|
||||
)
|
||||
|
||||
// NumberOption configure number argument.
|
||||
type NumberOption func(*Number)
|
||||
|
||||
// WithNumberFormat sets format number.
|
||||
func WithNumberFormat(format FormatNumber) NumberOption {
|
||||
return func(n *Number) { n.Format = format }
|
||||
}
|
||||
|
||||
// Number argument.
|
||||
type Number struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
Format FormatNumber
|
||||
}
|
||||
|
||||
// Configure number.
|
||||
func (n Number) Configure(opts ...NumberOption) Number {
|
||||
for _, o := range opts {
|
||||
o(&n)
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Val gets number value.
|
||||
func (n Number) Val() interface{} {
|
||||
return n.Value
|
||||
}
|
||||
|
||||
// String number to string.
|
||||
func (n Number) String() string {
|
||||
return fmt.Sprintf("number key: %s, value: %v", n.Key, n.Value)
|
||||
}
|
||||
27
context.go
Normal file
27
context.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package translation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type ctxkey uint8
|
||||
|
||||
const (
|
||||
localeKey ctxkey = iota
|
||||
)
|
||||
|
||||
// WithLanguage sets language to context.
|
||||
func WithLanguage(ctx context.Context, lang language.Tag) context.Context {
|
||||
return context.WithValue(ctx, localeKey, lang)
|
||||
}
|
||||
|
||||
// FromContext get language from context or use default.
|
||||
func FromContext(ctx context.Context, def language.Tag) language.Tag {
|
||||
if t, ok := ctx.Value(localeKey).(language.Tag); ok {
|
||||
return t
|
||||
}
|
||||
|
||||
return def
|
||||
}
|
||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module gitoa.ru/go-4devs/translation
|
||||
|
||||
go 1.16
|
||||
|
||||
require golang.org/x/text v0.3.6
|
||||
3
go.sum
Normal file
3
go.sum
Normal file
@@ -0,0 +1,3 @@
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
22
icu/trans.go
Normal file
22
icu/trans.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package icu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitoa.ru/go-4devs/translation"
|
||||
"gitoa.ru/go-4devs/translation/provider/gotext"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var trans = translation.New(language.English, gotext.NewProvider())
|
||||
|
||||
// Trans translate message.
|
||||
func Trans(ctx context.Context, key string, opts ...translation.Option) string {
|
||||
return trans.Trans(ctx, key, opts...)
|
||||
}
|
||||
|
||||
// SetTranslator sets translator.
|
||||
func SetTranslator(tr *translation.Translator) {
|
||||
trans = tr
|
||||
}
|
||||
41
icu/trans_example_test.go
Normal file
41
icu/trans_example_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package icu_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"gitoa.ru/go-4devs/translation"
|
||||
"gitoa.ru/go-4devs/translation/arg"
|
||||
"gitoa.ru/go-4devs/translation/icu"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
"golang.org/x/text/message/catalog"
|
||||
)
|
||||
|
||||
func ExampleTrans_withLanguage() {
|
||||
err := message.Set(language.Russian, "Hello {city}", catalog.String("Привет %s"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = message.Set(language.Russian, "It costs {cost}", catalog.String("Это стоит %.2f."))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
lang, err := language.Parse("ru")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := translation.WithLanguage(context.Background(), lang)
|
||||
|
||||
tr := icu.Trans(ctx, "Hello {city}", translation.WithArgs("Москва"))
|
||||
fmt.Println(tr)
|
||||
tr = icu.Trans(ctx, "It costs {cost}", translation.WithNumber("cost", 1000.00, arg.WithNumberFormat(arg.NumberFormatDecimal)))
|
||||
fmt.Println(tr)
|
||||
// Output:
|
||||
// Привет Москва
|
||||
// Это стоит 1 000,00.
|
||||
}
|
||||
108
provider/gotext/provider.go
Normal file
108
provider/gotext/provider.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package gotext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitoa.ru/go-4devs/translation"
|
||||
"gitoa.ru/go-4devs/translation/arg"
|
||||
"golang.org/x/text/currency"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
"golang.org/x/text/message/catalog"
|
||||
"golang.org/x/text/number"
|
||||
)
|
||||
|
||||
var _ translation.Provider = (*Provider)(nil)
|
||||
|
||||
// Option confires message provider.
|
||||
type Option func(*Provider)
|
||||
|
||||
// WithCatalog set coatalog bu domain name.
|
||||
func WithCatalog(domain string, cat catalog.Catalog) Option {
|
||||
return func(mp *Provider) {
|
||||
mp.catalog[domain] = cat
|
||||
}
|
||||
}
|
||||
|
||||
// NewProvider creates new messgae provider.
|
||||
func NewProvider(opts ...Option) *Provider {
|
||||
mp := &Provider{
|
||||
catalog: map[string]catalog.Catalog{
|
||||
translation.DefaultDomain: message.DefaultCatalog,
|
||||
},
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(mp)
|
||||
}
|
||||
|
||||
return mp
|
||||
}
|
||||
|
||||
// Provider provider messages.
|
||||
type Provider struct {
|
||||
catalog map[string]catalog.Catalog
|
||||
}
|
||||
|
||||
// Translate by key and args.
|
||||
func (mp *Provider) Translate(ctx context.Context, key string, opt translation.Translate) string {
|
||||
return message.NewPrinter(opt.Locale, message.Catalog(mp.catalog[opt.Domain])).
|
||||
Sprintf(key, messageArgs(opt.Locale, opt.Args)...)
|
||||
}
|
||||
|
||||
func currencyMessage(lang language.Tag) func(v arg.Currency) interface{} {
|
||||
return func(v arg.Currency) interface{} {
|
||||
var u currency.Unit
|
||||
|
||||
if v.ISO != "" {
|
||||
u, _ = currency.ParseISO(v.ISO)
|
||||
} else {
|
||||
u, _ = currency.FromTag(lang)
|
||||
}
|
||||
|
||||
switch v.Format {
|
||||
case arg.CurrencyFormatISO:
|
||||
return currency.ISO(u.Amount(v.Val()))
|
||||
case arg.CurrencyFormatSymbol:
|
||||
return currency.Symbol(u.Amount(v.Val()))
|
||||
case arg.CurrencyFormatNarrowSymbol:
|
||||
return currency.NarrowSymbol(u.Amount(v.Val()))
|
||||
}
|
||||
|
||||
return u.Amount(v.Val())
|
||||
}
|
||||
}
|
||||
|
||||
func numberMessage(v arg.Number) interface{} {
|
||||
switch v.Format {
|
||||
case arg.NumberFormatPercent:
|
||||
return number.Percent(v.Val())
|
||||
case arg.NumberFormatEngineering:
|
||||
return number.Engineering(v.Val())
|
||||
case arg.NumberFormatPerMille:
|
||||
return number.PerMille(v.Val())
|
||||
case arg.NumberFormatDecimal:
|
||||
return number.Decimal(v.Val())
|
||||
case arg.NumberFormatScientific:
|
||||
return number.Scientific(v.Val())
|
||||
}
|
||||
|
||||
return v.Val()
|
||||
}
|
||||
|
||||
func messageArgs(lang language.Tag, in []translation.Arg) []interface{} {
|
||||
out := make([]interface{}, 0, len(in))
|
||||
|
||||
for _, a := range in {
|
||||
switch v := a.(type) {
|
||||
case arg.Currency:
|
||||
out = append(out, currencyMessage(lang)(v))
|
||||
case arg.Number:
|
||||
out = append(out, numberMessage(v))
|
||||
default:
|
||||
out = append(out, v.Val())
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
80
translate.go
Normal file
80
translate.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package translation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitoa.ru/go-4devs/translation/arg"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Option configures translate.
|
||||
type Option func(*Translate)
|
||||
|
||||
// Translate configure translate.
|
||||
type Translate struct {
|
||||
Domain string
|
||||
Locale language.Tag
|
||||
Args []Arg
|
||||
}
|
||||
|
||||
// ArgValues gets value arguments.
|
||||
func (t *Translate) ArgValues() []interface{} {
|
||||
a := make([]interface{}, len(t.Args))
|
||||
for i, v := range t.Args {
|
||||
a[i] = v.Val()
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// Arg arg translate.
|
||||
type Arg interface {
|
||||
Val() interface{}
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// WithNumber sets number with options.
|
||||
func WithNumber(key string, val interface{}, opts ...arg.NumberOption) Option {
|
||||
return func(t *Translate) {
|
||||
t.Args = append(t.Args, arg.Number{Key: key, Value: val}.Configure(opts...))
|
||||
}
|
||||
}
|
||||
|
||||
// WithCurrency sets date argument.
|
||||
func WithCurrency(key string, val interface{}, opts ...arg.CurrencyOption) Option {
|
||||
return func(t *Translate) {
|
||||
c := arg.Currency{Value: val, Key: key}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&c)
|
||||
}
|
||||
|
||||
t.Args = append(t.Args, c)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDomain sets domain translate.
|
||||
func WithDomain(domain string) Option {
|
||||
return func(o *Translate) {
|
||||
o.Domain = domain
|
||||
}
|
||||
}
|
||||
|
||||
// WithLocale sets locale translate.
|
||||
func WithLocale(locale string) Option {
|
||||
return func(o *Translate) {
|
||||
o.Locale = language.Make(locale)
|
||||
}
|
||||
}
|
||||
|
||||
// WithArgs sets arguments value.
|
||||
func WithArgs(vals ...interface{}) Option {
|
||||
return func(t *Translate) {
|
||||
args := make([]Arg, len(vals))
|
||||
for i, val := range vals {
|
||||
args[i] = arg.Arg{Value: val}
|
||||
}
|
||||
|
||||
t.Args = append(t.Args, args...)
|
||||
}
|
||||
}
|
||||
56
translator.go
Normal file
56
translator.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package translation
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Default values.
|
||||
const (
|
||||
DefaultDomain = "messages"
|
||||
)
|
||||
|
||||
// Provider for translate key.
|
||||
type Provider interface {
|
||||
Translate(ctx context.Context, key string, opt Translate) string
|
||||
}
|
||||
|
||||
// TranslatorOption options translator.
|
||||
type TranslatorOption func(*Translator)
|
||||
|
||||
// New creates new translator.
|
||||
func New(locale language.Tag, provider Provider, opts ...TranslatorOption) *Translator {
|
||||
tr := Translator{
|
||||
locale: locale,
|
||||
provider: provider,
|
||||
domain: DefaultDomain,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&tr)
|
||||
}
|
||||
|
||||
return &tr
|
||||
}
|
||||
|
||||
// Translator struct.
|
||||
type Translator struct {
|
||||
provider Provider
|
||||
domain string
|
||||
locale language.Tag
|
||||
}
|
||||
|
||||
// Trans translates key by options.
|
||||
func (t *Translator) Trans(ctx context.Context, key string, opts ...Option) string {
|
||||
opt := Translate{
|
||||
Locale: FromContext(ctx, t.locale),
|
||||
Domain: t.domain,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return t.provider.Translate(ctx, key, opt)
|
||||
}
|
||||
91
translator_example_test.go
Normal file
91
translator_example_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package translation_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitoa.ru/go-4devs/translation"
|
||||
"gitoa.ru/go-4devs/translation/arg"
|
||||
"gitoa.ru/go-4devs/translation/provider/gotext"
|
||||
"golang.org/x/text/feature/plural"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message/catalog"
|
||||
)
|
||||
|
||||
func ExampleTranslator_Trans() {
|
||||
cat := catalog.NewBuilder()
|
||||
|
||||
_ = cat.Set(language.Russian, "Hello World!", catalog.String("Привет Мир!"))
|
||||
_ = cat.Set(language.Slovak, "Hello World!", catalog.String("Ahoj Svet!"))
|
||||
_ = cat.Set(language.Hebrew, "Hello World!", catalog.String("שלום עולם"))
|
||||
_ = cat.Set(language.Russian, "Hello {name}!", catalog.String("Привет %[1]s!"))
|
||||
_ = cat.Set(language.English, "Hello {name}!", catalog.String("Hello %[1]s!"))
|
||||
_ = cat.Set(language.English, "There are {bikes} bikes per household.", catalog.String("There are %v bikes per household."))
|
||||
_ = cat.Set(language.Russian, "There are {bikes} bikes per household.", catalog.String("В каждом доме есть %v велосипеда."))
|
||||
_ = cat.Set(language.English, "You are {minute} minute(s) late.",
|
||||
plural.Selectf(1, "",
|
||||
"=0", "You're on time.",
|
||||
plural.One, "You are %v minute late.",
|
||||
plural.Other, "You are %v minutes late."))
|
||||
_ = cat.Set(language.Russian, "You are {minute} minute(s) late.",
|
||||
plural.Selectf(1, "",
|
||||
"=1", "Вы опоздали на одну минуту.",
|
||||
"=0", "Вы вовремя.",
|
||||
plural.One, "Вы опоздали на %v минуту.",
|
||||
plural.Few, "Вы опоздали на %v минуты.",
|
||||
plural.Other, "Вы опоздали на %v минут.",
|
||||
),
|
||||
)
|
||||
_ = cat.Set(language.Russian, "It costs {cost}.",
|
||||
catalog.String("Это стоит %.2f."))
|
||||
_ = cat.Set(language.English, "It costs {cost}.",
|
||||
catalog.String("It costs %.2f."))
|
||||
|
||||
provider := gotext.NewProvider(gotext.WithCatalog(translation.DefaultDomain, cat))
|
||||
|
||||
trans := translation.New(language.Russian, provider)
|
||||
ctx := context.Background()
|
||||
// context with language
|
||||
heCtx := translation.WithLanguage(ctx, language.Make("he"))
|
||||
|
||||
fmt.Println(trans.Trans(ctx, "Hello World!"))
|
||||
fmt.Println(trans.Trans(ctx, "Hello World!", translation.WithLocale("en")))
|
||||
fmt.Println(trans.Trans(ctx, "Hello World!", translation.WithLocale("sk")))
|
||||
fmt.Println(trans.Trans(heCtx, "Hello World!"))
|
||||
|
||||
fmt.Println(trans.Trans(ctx, "Hello {name}!", translation.WithArgs("Andrey")))
|
||||
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithNumber("minute", 1)))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithNumber("minute", 0)))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithNumber("minute", 101)))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithArgs(123456.78)))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithArgs(50)))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithArgs(1), translation.WithLocale("en")))
|
||||
fmt.Println(trans.Trans(ctx, "You are {minute} minute(s) late.", translation.WithArgs(33), translation.WithLocale("en")))
|
||||
|
||||
fmt.Println(trans.Trans(ctx, "There are {bikes} bikes per household.", translation.WithNumber("bikes", 1.2)))
|
||||
fmt.Println(trans.Trans(ctx, "There are {bikes} bikes per household.", translation.WithNumber("bikes", 1.2), translation.WithLocale("en")))
|
||||
|
||||
fmt.Println(trans.Trans(ctx, "It costs {cost}.",
|
||||
translation.WithCurrency("cost", 12.0101, arg.WithCurrencyISO("rub"), arg.WithCurrencyFormat(arg.CurrencyFormatSymbol))))
|
||||
fmt.Println(trans.Trans(ctx, "It costs {cost}.",
|
||||
translation.WithCurrency("cost", 15.0, arg.WithCurrencyISO("HKD"), arg.WithCurrencyFormat(arg.CurrencyFormatSymbol)),
|
||||
translation.WithLocale("en")))
|
||||
// Output:
|
||||
// Привет Мир!
|
||||
// Hello World!
|
||||
// Ahoj Svet!
|
||||
// שלום עולם
|
||||
// Привет Andrey!
|
||||
// Вы опоздали на одну минуту.
|
||||
// Вы вовремя.
|
||||
// Вы опоздали на 101 минуту.
|
||||
// Вы опоздали на 123 456,78 минут.
|
||||
// Вы опоздали на 50 минут.
|
||||
// You are 1 minute late.
|
||||
// You are 33 minutes late.
|
||||
// В каждом доме есть 1,2 велосипеда.
|
||||
// There are 1.2 bikes per household.
|
||||
// Это стоит ₽ 12.0101.
|
||||
// It costs HK$ 15.
|
||||
}
|
||||
32
translator_test.go
Normal file
32
translator_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package translation_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gitoa.ru/go-4devs/translation"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type TestProvider struct{}
|
||||
|
||||
func (tp *TestProvider) Translate(_ context.Context, key string, opt translation.Translate) string {
|
||||
args := make([]interface{}, 0, len(opt.Args)+1)
|
||||
args = append(args, key)
|
||||
args = append(args, opt.ArgValues()...)
|
||||
|
||||
return fmt.Sprint(args...)
|
||||
}
|
||||
|
||||
func TestTranslator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
trans := translation.New(language.Russian, &TestProvider{})
|
||||
tr := trans.Trans(ctx, "key", translation.WithArgs("arg1", "arg2"))
|
||||
|
||||
if tr != "keyarg1arg2" {
|
||||
t.Fatalf("expect: keyarg1arg2, got:%s", tr)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user