You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-06-29 00:52:03 +02:00
tools/text-translator: automatically translate translation files
This commit is contained in:
9
tools/text-translator/README.md
Normal file
9
tools/text-translator/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SaaS Starter Kit
|
||||||
|
|
||||||
|
Copyright 2019, Geeks Accelerator
|
||||||
|
twins@geeksaccelerator.com
|
||||||
|
|
||||||
|
|
||||||
|
## Description
|
||||||
|
_text-translator_ is a tool for automatic translation of messages using
|
||||||
|
AWS Translator service and universal-translator json files.
|
46
tools/text-translator/aws/awsTranslator.go
Normal file
46
tools/text-translator/aws/awsTranslator.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/translate"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Translator is an instance of AWS Translator service
|
||||||
|
type Translator struct {
|
||||||
|
t *translate.Translate
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a AWS Translator service which credentials are
|
||||||
|
// retrieved by the default AWS SDK credential chain (env, conf)
|
||||||
|
func New() (*Translator, error) {
|
||||||
|
s, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
SharedConfigState: session.SharedConfigEnable,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error creating AWS session")
|
||||||
|
}
|
||||||
|
|
||||||
|
t := translate.New(s, aws.NewConfig().WithMaxRetries(3))
|
||||||
|
|
||||||
|
return &Translator{
|
||||||
|
t: t,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// T translate text from an origin locale to a set of target locales,
|
||||||
|
// the results are in the same order of target locales.
|
||||||
|
func (awsT *Translator) T(text string, sourceLocale string, targetLocale string) (string, error) {
|
||||||
|
input := &translate.TextInput{
|
||||||
|
SourceLanguageCode: aws.String(sourceLocale),
|
||||||
|
Text: &text,
|
||||||
|
}
|
||||||
|
input.TargetLanguageCode = aws.String(targetLocale)
|
||||||
|
output, err := awsT.t.Text(input)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "error while translating for locale %v", targetLocale)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *output.TranslatedText, nil
|
||||||
|
}
|
49
tools/text-translator/cmd/main.go
Normal file
49
tools/text-translator/cmd/main.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/tools/text-translator/aws"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/tools/text-translator/internal/jsontranslator"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
inFile = flag.String("i", "", "source file to translate")
|
||||||
|
outDir = flag.String("o", "", "output file to translate")
|
||||||
|
csvTargetLocales = flag.String("t", "", "comma separated list of target locales")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
flag.VisitAll(func(f *flag.Flag) {
|
||||||
|
if f.Value.String() == "" {
|
||||||
|
fmt.Printf("-%s flag is required\n", f.Name)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t, err := aws.New()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceTrans, err := jsontranslator.Read(*inFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error while reading json file: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
targetLocales := strings.Split(*csvTargetLocales, ",")
|
||||||
|
targetTranslations := jsontranslator.Translate(t, sourceTrans, targetLocales)
|
||||||
|
|
||||||
|
_, name := filepath.Split(*inFile)
|
||||||
|
err = jsontranslator.Save(*outDir, name, targetTranslations)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error while saving translations: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
114
tools/text-translator/internal/jsontranslator/translator.go
Normal file
114
tools/text-translator/internal/jsontranslator/translator.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package jsontranslator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JSONTranslation represents a translation for a locale
|
||||||
|
type JSONTranslation struct {
|
||||||
|
Locale string
|
||||||
|
Items []Translation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translation represent a translation item for a locale
|
||||||
|
type Translation struct {
|
||||||
|
Locale string `json:"locale"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Translation string `json:"trans"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslateService translates a text from the sourceLocale to the
|
||||||
|
// targetLocale
|
||||||
|
type TranslateService interface {
|
||||||
|
T(text string, sourceLocale string, targetLocale string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read parses a JSON file
|
||||||
|
func Read(path string) (*JSONTranslation, error) {
|
||||||
|
// TODO: possibly use os.Stat to support paths of directories to make translate multiple files easier
|
||||||
|
log.Printf("reading %s json file...\n", path)
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error while opening template file %v", path)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
content, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error while reading contents of template file")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []Translation
|
||||||
|
err = json.Unmarshal(content, &res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error while unmarshaling template content")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) == 0 {
|
||||||
|
return nil, errors.New("file doesn't have any translation items")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &JSONTranslation{
|
||||||
|
Locale: res[0].Locale,
|
||||||
|
Items: res,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate translates items to multiple target locales using the provided
|
||||||
|
// translator service
|
||||||
|
func Translate(ts TranslateService, source *JSONTranslation, targetLocales []string) []JSONTranslation {
|
||||||
|
res := make([]JSONTranslation, len(targetLocales))
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := range targetLocales {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int) {
|
||||||
|
log.Printf("translating into %v...\n", targetLocales[i])
|
||||||
|
res[i] = JSONTranslation{
|
||||||
|
Locale: targetLocales[i],
|
||||||
|
Items: make([]Translation, 0, len(source.Items)),
|
||||||
|
}
|
||||||
|
for _, m := range source.Items {
|
||||||
|
output, err := ts.T(m.Translation, m.Locale, targetLocales[i])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("coudn't translate %v: %v\n", m.Translation, err)
|
||||||
|
}
|
||||||
|
res[i].Items = append(res[i].Items, Translation{
|
||||||
|
Locale: targetLocales[i],
|
||||||
|
Key: m.Key,
|
||||||
|
Translation: output,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save saves the translations in the path directory
|
||||||
|
func Save(dirPath string, name string, translations []JSONTranslation) error {
|
||||||
|
// TODO: consider "merge" option to avoid overriding existing files
|
||||||
|
for _, t := range translations {
|
||||||
|
log.Printf("saving locale %v json file...\n", t.Locale)
|
||||||
|
b, err := json.MarshalIndent(t.Items, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error while serializing json file")
|
||||||
|
}
|
||||||
|
folderPath := filepath.Join(dirPath, t.Locale)
|
||||||
|
os.MkdirAll(folderPath, os.ModePerm)
|
||||||
|
err = ioutil.WriteFile(filepath.Join(folderPath, name), b, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error while writing to the json file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Reference in New Issue
Block a user