2019-09-18 18:02:40 +03:00
|
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"io/ioutil"
|
2020-05-18 13:37:24 +03:00
|
|
|
|
"math/rand"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
"net/http"
|
2020-05-18 13:37:24 +03:00
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"net/url"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
"os"
|
|
|
|
|
"path"
|
2020-05-18 13:37:24 +03:00
|
|
|
|
"sync"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
"testing"
|
2020-05-18 13:37:24 +03:00
|
|
|
|
"time"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
|
2020-05-18 13:37:24 +03:00
|
|
|
|
"github.com/gin-gonic/gin"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
|
"golang.org/x/text/language"
|
2021-12-01 15:40:23 +03:00
|
|
|
|
|
|
|
|
|
"github.com/retailcrm/mg-transport-core/v2/core/util/errorutil"
|
2019-09-18 18:02:40 +03:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
testTranslationsDir = path.Join(os.TempDir(), "translations_test_dir")
|
2020-05-18 13:37:24 +03:00
|
|
|
|
testLangFiles = map[string][]byte{
|
|
|
|
|
"translate.en.yml": []byte("message: Test message\nmessage_template: Test message with {{.data}}"),
|
|
|
|
|
"translate.es.yml": []byte("message: Mensaje de prueba\nmessage_template: Mensaje de prueba con {{.data}}"),
|
|
|
|
|
"translate.ru.yml": []byte("message: Тестовое сообщение\nmessage_template: Тестовое сообщение с {{.data}}"),
|
|
|
|
|
}
|
2019-09-18 18:02:40 +03:00
|
|
|
|
)
|
|
|
|
|
|
2020-05-18 13:37:24 +03:00
|
|
|
|
func createTestLangFiles(t *testing.T) {
|
|
|
|
|
for name, data := range testLangFiles {
|
|
|
|
|
fileName := path.Join(testTranslationsDir, name)
|
|
|
|
|
|
|
|
|
|
if _, err := os.Stat(testTranslationsDir); err != nil && os.IsNotExist(err) {
|
|
|
|
|
err := os.Mkdir(testTranslationsDir, os.ModePerm)
|
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := os.Stat(fileName); err != nil && os.IsNotExist(err) {
|
|
|
|
|
err = ioutil.WriteFile(fileName, data, os.ModePerm)
|
|
|
|
|
require.Nil(t, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 18:02:40 +03:00
|
|
|
|
type LocalizerTest struct {
|
|
|
|
|
suite.Suite
|
|
|
|
|
localizer *Localizer
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 13:18:36 +03:00
|
|
|
|
func (l *LocalizerTest) SetupSuite() {
|
2020-05-18 13:37:24 +03:00
|
|
|
|
createTestLangFiles(l.T())
|
|
|
|
|
l.localizer = NewLocalizer(language.English, DefaultLocalizerMatcher(), testTranslationsDir)
|
2019-09-18 18:02:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *LocalizerTest) Test_SetLocale() {
|
|
|
|
|
defer func() {
|
|
|
|
|
require.Nil(l.T(), recover())
|
|
|
|
|
}()
|
|
|
|
|
|
2020-05-18 13:37:24 +03:00
|
|
|
|
l.localizer.SetLocale("es")
|
|
|
|
|
assert.Equal(l.T(), "Mensaje de prueba", l.localizer.GetLocalizedMessage("message"))
|
2019-09-18 18:02:40 +03:00
|
|
|
|
l.localizer.SetLocale("en")
|
2020-05-18 13:37:24 +03:00
|
|
|
|
assert.Equal(l.T(), "Test message", l.localizer.GetLocalizedMessage("message"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *LocalizerTest) Test_LocalizationMiddleware_Context() {
|
|
|
|
|
l.localizer.Preload(DefaultLanguages)
|
|
|
|
|
middlewareFunc := l.localizer.LocalizationMiddleware()
|
|
|
|
|
require.NotNil(l.T(), middlewareFunc)
|
|
|
|
|
|
|
|
|
|
enContext := l.getContextWithLang(language.English)
|
|
|
|
|
esContext := l.getContextWithLang(language.Spanish)
|
|
|
|
|
ruContext := l.getContextWithLang(language.Russian)
|
|
|
|
|
|
|
|
|
|
middlewareFunc(enContext)
|
|
|
|
|
middlewareFunc(esContext)
|
|
|
|
|
middlewareFunc(ruContext)
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
assert.Nil(l.T(), recover())
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
enLocalizer := MustGetContextLocalizer(enContext)
|
|
|
|
|
esLocalizer := MustGetContextLocalizer(esContext)
|
|
|
|
|
ruLocalizer := MustGetContextLocalizer(ruContext)
|
|
|
|
|
|
|
|
|
|
assert.NotNil(l.T(), enLocalizer)
|
|
|
|
|
assert.NotNil(l.T(), esLocalizer)
|
|
|
|
|
assert.NotNil(l.T(), ruLocalizer)
|
|
|
|
|
|
|
|
|
|
assert.Equal(l.T(), language.English, enLocalizer.LanguageTag)
|
|
|
|
|
assert.Equal(l.T(), language.Spanish, esLocalizer.LanguageTag)
|
|
|
|
|
assert.Equal(l.T(), language.Russian, ruLocalizer.LanguageTag)
|
|
|
|
|
|
|
|
|
|
assert.Equal(l.T(), "Test message", enLocalizer.GetLocalizedMessage("message"))
|
|
|
|
|
assert.Equal(l.T(), "Mensaje de prueba", esLocalizer.GetLocalizedMessage("message"))
|
|
|
|
|
assert.Equal(l.T(), "Тестовое сообщение", ruLocalizer.GetLocalizedMessage("message"))
|
2019-09-18 18:02:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 13:37:24 +03:00
|
|
|
|
func (l *LocalizerTest) Test_LocalizationMiddleware_Httptest() {
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
|
l.localizer.Preload(DefaultLanguages)
|
|
|
|
|
langMsgMap := map[language.Tag]string{
|
|
|
|
|
language.English: "Test message",
|
|
|
|
|
language.Russian: "Тестовое сообщение",
|
|
|
|
|
language.Spanish: "Mensaje de prueba",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fw := gin.New()
|
|
|
|
|
fw.Use(l.localizer.LocalizationMiddleware())
|
|
|
|
|
fw.GET("/test", func(c *gin.Context) {
|
|
|
|
|
loc := MustGetContextLocalizer(c)
|
|
|
|
|
c.String(http.StatusOK, loc.GetLocalizedMessage("message"))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
for i := 0; i < 1000; i++ {
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func(m map[language.Tag]string, wg *sync.WaitGroup) {
|
|
|
|
|
var tag language.Tag
|
2021-12-01 15:40:23 +03:00
|
|
|
|
switch rand.Intn(3-1) + 1 { // nolint:gosec
|
2020-05-18 13:37:24 +03:00
|
|
|
|
case 1:
|
|
|
|
|
tag = language.English
|
|
|
|
|
case 2:
|
|
|
|
|
tag = language.Russian
|
|
|
|
|
case 3:
|
|
|
|
|
tag = language.Spanish
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "/test", nil)
|
|
|
|
|
require.NoError(l.T(), err)
|
|
|
|
|
req.Header.Add("Accept-Language", tag.String())
|
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
|
fw.ServeHTTP(rr, req)
|
|
|
|
|
assert.Equal(l.T(), m[tag], rr.Body.String())
|
|
|
|
|
wg.Done()
|
|
|
|
|
}(langMsgMap, &wg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wg.Wait()
|
2019-09-18 18:02:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *LocalizerTest) Test_LocalizationFuncMap() {
|
|
|
|
|
functions := l.localizer.LocalizationFuncMap()
|
|
|
|
|
_, ok := functions["trans"]
|
|
|
|
|
assert.True(l.T(), ok)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *LocalizerTest) Test_GetLocalizedMessage() {
|
|
|
|
|
defer func() {
|
|
|
|
|
require.Nil(l.T(), recover())
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
message := l.localizer.GetLocalizedMessage("message")
|
|
|
|
|
assert.Equal(l.T(), "Test message", message)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-12 10:23:27 +03:00
|
|
|
|
func (l *LocalizerTest) Test_Clone() {
|
|
|
|
|
defer func() {
|
|
|
|
|
require.Nil(l.T(), recover())
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
localizer := l.localizer.Clone()
|
|
|
|
|
localizer.SetLanguage(language.Russian)
|
2021-02-09 14:57:14 +03:00
|
|
|
|
|
2020-11-12 10:23:27 +03:00
|
|
|
|
assert.NotEqual(l.T(), l.localizer.LanguageTag, localizer.LanguageTag)
|
|
|
|
|
assert.Equal(l.T(), "Test message", l.localizer.GetLocalizedMessage("message"))
|
|
|
|
|
assert.Equal(l.T(), "Тестовое сообщение", localizer.GetLocalizedMessage("message"))
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 18:02:40 +03:00
|
|
|
|
func (l *LocalizerTest) Test_GetLocalizedTemplateMessage() {
|
|
|
|
|
defer func() {
|
|
|
|
|
require.Nil(l.T(), recover())
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
message := l.localizer.GetLocalizedTemplateMessage("message_template", map[string]interface{}{"data": "template"})
|
|
|
|
|
assert.Equal(l.T(), "Test message with template", message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (l *LocalizerTest) Test_BadRequestLocalized() {
|
|
|
|
|
status, resp := l.localizer.BadRequestLocalized("message")
|
|
|
|
|
|
|
|
|
|
assert.Equal(l.T(), http.StatusBadRequest, status)
|
2021-12-01 15:40:23 +03:00
|
|
|
|
assert.Equal(l.T(), "Test message", resp.(errorutil.Response).Error)
|
2019-09-18 18:02:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-09 14:57:14 +03:00
|
|
|
|
// getContextWithLang generates context with Accept-Language header.
|
2020-05-18 13:37:24 +03:00
|
|
|
|
func (l *LocalizerTest) getContextWithLang(tag language.Tag) *gin.Context {
|
|
|
|
|
urlInstance, _ := url.Parse("https://example.com")
|
|
|
|
|
headers := http.Header{}
|
|
|
|
|
headers.Add("Accept-Language", tag.String())
|
|
|
|
|
return &gin.Context{
|
|
|
|
|
Request: &http.Request{
|
|
|
|
|
Method: "GET",
|
|
|
|
|
URL: urlInstance,
|
|
|
|
|
Proto: "https",
|
|
|
|
|
Header: headers,
|
|
|
|
|
Host: "example.com",
|
|
|
|
|
},
|
|
|
|
|
Keys: map[string]interface{}{},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 13:18:36 +03:00
|
|
|
|
func (l *LocalizerTest) TearDownSuite() {
|
2019-09-18 18:02:40 +03:00
|
|
|
|
err := os.RemoveAll(testTranslationsDir)
|
|
|
|
|
require.Nil(l.T(), err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLocalizer_Suite(t *testing.T) {
|
|
|
|
|
suite.Run(t, new(LocalizerTest))
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 13:37:24 +03:00
|
|
|
|
func TestLocalizer_DefaultLocalizerMatcher(t *testing.T) {
|
|
|
|
|
assert.NotNil(t, DefaultLocalizerMatcher())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLocalizer_DefaultLocalizerBundle(t *testing.T) {
|
|
|
|
|
assert.NotNil(t, DefaultLocalizerBundle())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLocalizer_LocalizerBundle(t *testing.T) {
|
|
|
|
|
assert.NotNil(t, LocalizerBundle(language.Russian))
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 18:02:40 +03:00
|
|
|
|
func TestLocalizer_NoDirectory(t *testing.T) {
|
|
|
|
|
defer func() {
|
|
|
|
|
assert.NotNil(t, recover())
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
_ = NewLocalizer(
|
|
|
|
|
language.English,
|
|
|
|
|
DefaultLocalizerMatcher(),
|
|
|
|
|
path.Join(os.TempDir(), "this directory should not exist"),
|
|
|
|
|
)
|
|
|
|
|
}
|