andrey1s
4 years ago
commit
9129f25c31
18 changed files with 678 additions and 0 deletions
@ -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 |
@ -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/ |
||||
|
|
@ -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 |
@ -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. |
@ -0,0 +1,5 @@ |
|||||
|
# translation |
||||
|
|
||||
|
[![Build Status](https://drone.gitoa.ru/api/badges/go-4devs/translation/status.svg)](https://drone.gitoa.ru/go-4devs/translation) |
||||
|
[![Go Report Card](https://goreportcard.com/badge/gitoa.ru/go-4devs/translation)](https://goreportcard.com/report/gitoa.ru/go-4devs/translation) |
||||
|
[![GoDoc](https://godoc.org/gitoa.ru/go-4devs/translation?status.svg)](http://godoc.org/gitoa.ru/go-4devs/translation) |
@ -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 |
||||
|
} |
@ -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 |
||||
|
} |
@ -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) |
||||
|
} |
@ -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 |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
module gitoa.ru/go-4devs/translation |
||||
|
|
||||
|
go 1.16 |
||||
|
|
||||
|
require golang.org/x/text v0.3.6 |
@ -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= |
@ -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 |
||||
|
} |
@ -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.
|
||||
|
} |
@ -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 |
||||
|
} |
@ -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...) |
||||
|
} |
||||
|
} |
@ -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) |
||||
|
} |
@ -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.
|
||||
|
} |
@ -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) |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue