From 2fbc811a3075bdc3b4291daf99f1df9d81de84da Mon Sep 17 00:00:00 2001 From: Sergey Novichkov Date: Mon, 24 Oct 2022 17:00:25 +0300 Subject: [PATCH] New major version --- .codecov.yml | 15 ++++++ .github/workflows/go.yml | 34 ++++++++++++ .scripts/test.sh | 15 ++++++ README.md | 37 +++++++++++++ di.go | 35 ++++++++++++ go.mod | 17 ++++-- go.sum | 36 +++++++++---- option.go | 32 +++++++++++ ut.go | 114 ++++++++++++++------------------------- 9 files changed, 245 insertions(+), 90 deletions(-) create mode 100644 .codecov.yml create mode 100644 .github/workflows/go.yml create mode 100644 .scripts/test.sh create mode 100644 di.go create mode 100644 option.go diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..dcefaba --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,15 @@ +coverage: + range: 70..98 + round: down + precision: 2 + status: + project: + default: + enabled: yes + target: 89 + if_not_found: success + if_ci_failed: error + patch: + default: + enabled: yes + target: 70 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..c5fba70 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,34 @@ +name: Unit Tests + +on: + push: + branches: [ "master" ] + + pull_request: + branches: [ "master" ] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + go-version: + - 1.18 + - 1.19 + + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + + - name: Run Tests + run: bash .scripts/test.sh + + - name: Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.scripts/test.sh b/.scripts/test.sh new file mode 100644 index 0000000..6aadd47 --- /dev/null +++ b/.scripts/test.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e + +if [[ -f coverage.txt ]]; then + rm coverage.txt +fi + +for d in $(go list ./... | grep -v ditest); do + go test -coverprofile=profile.out -coverpkg=./... -covermode=atomic "$d" + if [[ -f profile.out ]]; then + cat profile.out >>coverage.txt + rm profile.out + fi +done diff --git a/README.md b/README.md index d43be67..d2d7d27 100644 --- a/README.md +++ b/README.md @@ -1 +1,38 @@ # GoZix Universal Translator + +[documentation-img]: https://img.shields.io/badge/godoc-reference-blue.svg?color=24B898&style=for-the-badge&logo=go&logoColor=ffffff +[documentation-url]: https://pkg.go.dev/github.com/gozix/universal-translator/v3 +[license-img]: https://img.shields.io/github/license/gozix/universal-translator.svg?style=for-the-badge +[license-url]: https://github.com/gozix/universal-translator/blob/master/LICENSE +[release-img]: https://img.shields.io/github/tag/gozix/universal-translator.svg?label=release&color=24B898&logo=github&style=for-the-badge +[release-url]: https://github.com/gozix/universal-translator/releases/latest +[build-status-img]: https://img.shields.io/github/actions/workflow/status/gozix/universal-translator/go.yml?logo=github&style=for-the-badge +[build-status-url]: https://github.com/gozix/universal-translator/actions +[go-report-img]: https://img.shields.io/badge/go%20report-A%2B-green?style=for-the-badge +[go-report-url]: https://goreportcard.com/report/github.com/gozix/universal-translator +[code-coverage-img]: https://img.shields.io/codecov/c/github/gozix/universal-translator.svg?style=for-the-badge&logo=codecov +[code-coverage-url]: https://codecov.io/gh/gozix/universal-translator + +[![License][license-img]][license-url] +[![Documentation][documentation-img]][documentation-url] + +[![Release][release-img]][release-url] +[![Build Status][build-status-img]][build-status-url] +[![Go Report Card][go-report-img]][go-report-url] +[![Code Coverage][code-coverage-img]][code-coverage-url] + +The bundle provide Universal translator integration to GoZix application. + +## Installation + +```shell +go get github.com/gozix/universal-translator/v3 +``` + +## Documentation + +You can find documentation on [pkg.go.dev][documentation-url] and read source code if needed. + +## Questions + +If you have any questions, feel free to create an issue. diff --git a/di.go b/di.go new file mode 100644 index 0000000..c009cb0 --- /dev/null +++ b/di.go @@ -0,0 +1,35 @@ +// Copyright 2018 Sergey Novichkov. All rights reserved. +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +package ut + +import "github.com/gozix/di" + +const ( + // TagTranslator is a tag for marking locale translator without overriding existing. + TagTranslator = "universal-translator.locale-translator" + + // TagTranslatorOverride is a tag for marking locale translator with overriding existing. + TagTranslatorOverride = "universal-translator.locale-translator.override" +) + +func AsTranslator(override bool) di.Tags { + if override { + return di.Tags{{ + Name: TagTranslatorOverride, + }} + } + + return di.Tags{{ + Name: TagTranslator, + }} +} + +func withTranslator(override bool) di.Modifier { + if override { + return di.WithTags(TagTranslatorOverride) + } + + return di.WithTags(TagTranslator) +} diff --git a/go.mod b/go.mod index cecca24..cca500f 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,16 @@ -module github.com/gozix/universal-translator/v2 +module github.com/gozix/universal-translator/v3 -go 1.12 +go 1.18 require ( - github.com/go-playground/locales v0.12.1 - github.com/go-playground/universal-translator v0.16.0 - github.com/sarulabs/di/v2 v2.1.2 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/gozix/di v1.0.0 + github.com/gozix/glue/v3 v3.0.0 +) + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.6.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect ) diff --git a/go.sum b/go.sum index 4db66a5..0c0f491 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,28 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/gozix/di v0.0.0-20230218220045-50150892b9a1 h1:4PS2FDeBRT53+UnPL8U0q8VV8L3q9v3uJtNynVyyr78= +github.com/gozix/di v0.0.0-20230218220045-50150892b9a1/go.mod h1:VpR4iuzehn5oXLUaBcn6Mw8VgZlIpqTO/OssNIZaHHc= +github.com/gozix/di v1.0.0 h1:LKEuxqrPZ1SiZ9GC/7P3egNiHqplwNRrML73w8MXKjI= +github.com/gozix/di v1.0.0/go.mod h1:VpR4iuzehn5oXLUaBcn6Mw8VgZlIpqTO/OssNIZaHHc= +github.com/gozix/glue/v3 v3.0.0-20230218220922-f896ff0b45c0 h1:Dk9hYN4HXmJ0suxIrbcNtZZsCGeZTSR7VJDoisQxaqM= +github.com/gozix/glue/v3 v3.0.0-20230218220922-f896ff0b45c0/go.mod h1:T9PExjhCV1YCscwHb2wLayXfxBks55mG4n55xLh9T68= +github.com/gozix/glue/v3 v3.0.0 h1:nnISjcf1n7DDuI3bdabPl6oNk446JoZI3icr72LtmTQ= +github.com/gozix/glue/v3 v3.0.0/go.mod h1:+AdMEhqEnm1q13ouVItuEieGWlcdK4LNDj6IJrEK/J8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sarulabs/di/v2 v2.1.2 h1:n7HWnjD5Pizgs4y62WOFqO1GJw3cHaKEJwIw+TAlV/U= -github.com/sarulabs/di/v2 v2.1.2/go.mod h1:9mRdg8AtTjdbiirq97MvLriE+jf6q/ZCLpO/nRyR/R0= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/option.go b/option.go new file mode 100644 index 0000000..5af4d8b --- /dev/null +++ b/option.go @@ -0,0 +1,32 @@ +// Copyright 2018 Sergey Novichkov. All rights reserved. +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +package ut + +import "github.com/go-playground/locales" + +type ( + // Option interface. + Option interface { + apply(b *Bundle) + } + + // optionFunc wraps a func so it satisfies the Option interface. + optionFunc func(b *Bundle) +) + +// Fallback option. +func Fallback(fallback locales.Translator) Option { + return optionFunc(func(b *Bundle) { + b.fallback = fallback + b.locales = append(b.locales, fallback) + }) +} + +// Locales option. +func Locales(locales ...locales.Translator) Option { + return optionFunc(func(b *Bundle) { + b.locales = append(locales, locales...) + }) +} diff --git a/ut.go b/ut.go index 33a9ad2..352cc3a 100644 --- a/ut.go +++ b/ut.go @@ -1,44 +1,29 @@ +// Copyright 2018 Sergey Novichkov. All rights reserved. +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + package ut import ( + "github.com/gozix/di" + "github.com/gozix/glue/v3" + "github.com/go-playground/locales" "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" - "github.com/sarulabs/di/v2" -) - -type ( - // Bundle implements the glue.Bundle interface. - Bundle struct { - fallback locales.Translator - locales []locales.Translator - } - - // Translator type alias of ut.Translator. - Translator = ut.Translator - - // UniversalTranslator type alias of ut.UniversalTranslator. - UniversalTranslator = ut.UniversalTranslator - - // Option interface. - Option interface { - apply(b *Bundle) - } - - // optionFunc wraps a func so it satisfies the Option interface. - optionFunc func(b *Bundle) ) -const ( - // BundleName is default definition name. - BundleName = "universal-translator" +// Bundle implements the glue.Bundle interface. +type Bundle struct { + fallback locales.Translator + locales []locales.Translator +} - // TagTranslator is tag to mark injected locale translator. - TagTranslator = "universal-translator.locale-translator" +// Bundle implements the glue.Bundle interface. +var _ glue.Bundle = (*Bundle)(nil) - // TagArgOverride is tag argument name to override locale translator. - TagArgOverride = "override" -) +// BundleName is default definition name. +const BundleName = "universal-translator" // NewBundle create bundle instance. func NewBundle(options ...Option) *Bundle { @@ -57,55 +42,34 @@ func NewBundle(options ...Option) *Bundle { return &bundle } -// Fallback option. -func Fallback(fallback locales.Translator) Option { - return optionFunc(func(b *Bundle) { - b.fallback = fallback - b.locales = append(b.locales, fallback) - }) +func (b *Bundle) Name() string { + return BundleName } -// Locales option. -func Locales(locales ...locales.Translator) Option { - return optionFunc(func(b *Bundle) { - b.locales = append(locales, locales...) - }) +func (b *Bundle) Build(builder di.Builder) error { + return builder.Provide( + b.provideUT, + di.Constraint(0, di.Optional(true), withTranslator(false)), + di.Constraint(1, di.Optional(true), withTranslator(true)), + ) } -// Key implements the glue.Bundle interface. -func (b *Bundle) Name() string { - return BundleName -} +func (b *Bundle) provideUT(append []locales.Translator, override []locales.Translator) (_ *ut.UniversalTranslator, err error) { + var translator = ut.New(b.fallback, b.locales...) + + for _, localeTranslator := range append { + if err = translator.AddTranslator(localeTranslator, false); err != nil { + return nil, err + } + } + + for _, localeTranslator := range override { + if err = translator.AddTranslator(localeTranslator, true); err != nil { + return nil, err + } + } -// Build implements the glue.Bundle interface. -func (b *Bundle) Build(builder *di.Builder) error { - return builder.Add(di.Def{ - Name: BundleName, - Build: func(ctn di.Container) (_ interface{}, err error) { - var translator = ut.New(b.fallback, b.locales...) - for name, def := range ctn.Definitions() { - for _, tag := range def.Tags { - if tag.Name != TagTranslator { - continue - } - - var localeTranslator locales.Translator - if err = ctn.Fill(name, &localeTranslator); err != nil { - return nil, err - } - - _, override := tag.Args[TagArgOverride] - if err = translator.AddTranslator(localeTranslator, override); err != nil { - return nil, err - } - - break - } - } - - return translator, nil - }, - }) + return translator, nil } // apply implements Option.