mirror of
https://github.com/retailcrm/mg-transport-core.git
synced 2024-11-25 14:46:02 +03:00
helper for easy translations check in transports
This commit is contained in:
parent
41e873016f
commit
87b694bc08
114
core/translations_extractor.go
Normal file
114
core/translations_extractor.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gobuffalo/packr/v2"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TranslationsExtractor is a tool to load raw translations data from files or from box.
|
||||||
|
// It is feasible to be used in tests in order to check translation files correctness.
|
||||||
|
// The easiest way to check correctness is to check keys in translations.
|
||||||
|
// TranslationsExtractor IS NOT supposed to check correctness of translations - it's just an extractor.
|
||||||
|
// Translations can be checked manually, or via external library like https://github.com/google/go-cmp
|
||||||
|
type TranslationsExtractor struct {
|
||||||
|
fileNameTemplate string
|
||||||
|
TranslationsBox *packr.Box
|
||||||
|
TranslationsPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslationsExtractor constructor. Use "translate.{}.yml" as template if your translations are named like "translate.en.yml"
|
||||||
|
func NewTranslationsExtractor(fileNameTemplate string) *TranslationsExtractor {
|
||||||
|
return &TranslationsExtractor{fileNameTemplate: fileNameTemplate}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalToMap returns map with unmarshaled data or error
|
||||||
|
func (t *TranslationsExtractor) unmarshalToMap(in []byte) (map[string]interface{}, error) {
|
||||||
|
var dataMap map[string]interface{}
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(in, &dataMap); err == nil {
|
||||||
|
return dataMap, nil
|
||||||
|
} else {
|
||||||
|
return dataMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadYAMLBox loads YAML from box
|
||||||
|
func (t *TranslationsExtractor) loadYAMLBox(fileName string) (map[string]interface{}, error) {
|
||||||
|
var dataMap map[string]interface{}
|
||||||
|
|
||||||
|
if data, err := t.TranslationsBox.Find(fileName); err == nil {
|
||||||
|
return t.unmarshalToMap(data)
|
||||||
|
} else {
|
||||||
|
return dataMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadYAMLFile loads YAML from file
|
||||||
|
func (t *TranslationsExtractor) loadYAMLFile(fileName string) (map[string]interface{}, error) {
|
||||||
|
var dataMap map[string]interface{}
|
||||||
|
|
||||||
|
if info, err := os.Stat(fileName); err == nil {
|
||||||
|
if !info.IsDir() {
|
||||||
|
if path, err := filepath.Abs(fileName); err == nil {
|
||||||
|
if source, err := ioutil.ReadFile(path); err == nil {
|
||||||
|
return t.unmarshalToMap(source)
|
||||||
|
} else {
|
||||||
|
return dataMap, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return dataMap, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return dataMap, errors.New("directory provided instead of file")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return dataMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadYAML loads YAML from filesystem or from packr box - depends on what was configured. Can return error.
|
||||||
|
func (t *TranslationsExtractor) loadYAML(fileName string) (map[string]interface{}, error) {
|
||||||
|
if t.TranslationsBox != nil {
|
||||||
|
return t.loadYAMLBox(fileName)
|
||||||
|
} else if t.TranslationsPath != "" {
|
||||||
|
return t.loadYAMLFile(fileName)
|
||||||
|
} else {
|
||||||
|
return map[string]interface{}{}, errors.New("nor box nor translations directory was provided")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMapKeys returns sorted map keys from map[string]interface{} - useful to check keys in several translation files
|
||||||
|
func (t *TranslationsExtractor) GetMapKeys(data map[string]interface{}) []string {
|
||||||
|
keys := make([]string, len(data))
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for k := range data {
|
||||||
|
keys[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadLocale returns translation file data with provided locale
|
||||||
|
func (t *TranslationsExtractor) LoadLocale(locale string) (map[string]interface{}, error) {
|
||||||
|
return t.loadYAML(strings.Replace(t.fileNameTemplate, "{}", locale, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadLocaleKeys returns only sorted keys from translation file
|
||||||
|
func (t *TranslationsExtractor) LoadLocaleKeys(locale string) ([]string, error) {
|
||||||
|
if data, err := t.LoadLocale(locale); err == nil {
|
||||||
|
return t.GetMapKeys(data), nil
|
||||||
|
} else {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
}
|
60
core/translations_extractor_test.go
Normal file
60
core/translations_extractor_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TranslationsExtractorTest struct {
|
||||||
|
suite.Suite
|
||||||
|
extractor *TranslationsExtractor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TranslationsExtractorTest) SetupSuite() {
|
||||||
|
translation := map[string]string{
|
||||||
|
"test": "first",
|
||||||
|
"another": "second",
|
||||||
|
}
|
||||||
|
data, _ := yaml.Marshal(translation)
|
||||||
|
errWrite := ioutil.WriteFile("/tmp/translate.en.yml", data, os.ModePerm)
|
||||||
|
require.NoError(t.T(), errWrite)
|
||||||
|
|
||||||
|
t.extractor = NewTranslationsExtractor("translate.{}.yml")
|
||||||
|
t.extractor.TranslationsPath = "/tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TranslationsExtractorTest) Test_LoadLocale() {
|
||||||
|
data, err := t.extractor.LoadLocale("en")
|
||||||
|
require.NoError(t.T(), err)
|
||||||
|
assert.Contains(t.T(), data, "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TranslationsExtractorTest) Test_GetMapKeys() {
|
||||||
|
testMap := map[string]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
"c": 3,
|
||||||
|
}
|
||||||
|
keys := []string{"a", "b", "c"}
|
||||||
|
mapKeys := t.extractor.GetMapKeys(testMap)
|
||||||
|
|
||||||
|
assert.True(t.T(), reflect.DeepEqual(keys, mapKeys))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TranslationsExtractorTest) Test_unmarshalToMap() {
|
||||||
|
translation := map[string]string{
|
||||||
|
"test": "first",
|
||||||
|
"another": "second",
|
||||||
|
}
|
||||||
|
data, _ := yaml.Marshal(translation)
|
||||||
|
mapData, err := t.extractor.unmarshalToMap(data)
|
||||||
|
require.NoError(t.T(), err)
|
||||||
|
|
||||||
|
assert.True(t.T(), reflect.DeepEqual(translation, mapData))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user