123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- package ut
- import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "io"
- "github.com/go-playground/locales"
- )
- type translation struct {
- Locale string `json:"locale"`
- Key interface{} `json:"key"` // either string or integer
- Translation string `json:"trans"`
- PluralType string `json:"type,omitempty"`
- PluralRule string `json:"rule,omitempty"`
- OverrideExisting bool `json:"override,omitempty"`
- }
- const (
- cardinalType = "Cardinal"
- ordinalType = "Ordinal"
- rangeType = "Range"
- )
- // ImportExportFormat is the format of the file import or export
- type ImportExportFormat uint8
- // supported Export Formats
- const (
- FormatJSON ImportExportFormat = iota
- )
- // Export writes the translations out to a file on disk.
- //
- // NOTE: this currently only works with string or int translations keys.
- func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error {
- _, err := os.Stat(dirname)
- fmt.Println(dirname, err, os.IsNotExist(err))
- if err != nil {
- if !os.IsNotExist(err) {
- return err
- }
- if err = os.MkdirAll(dirname, 0744); err != nil {
- return err
- }
- }
- // build up translations
- var trans []translation
- var b []byte
- var ext string
- for _, locale := range t.translators {
- for k, v := range locale.(*translator).translations {
- trans = append(trans, translation{
- Locale: locale.Locale(),
- Key: k,
- Translation: v.text,
- })
- }
- for k, pluralTrans := range locale.(*translator).cardinalTanslations {
- for i, plural := range pluralTrans {
- // leave enough for all plural rules
- // but not all are set for all languages.
- if plural == nil {
- continue
- }
- trans = append(trans, translation{
- Locale: locale.Locale(),
- Key: k.(string),
- Translation: plural.text,
- PluralType: cardinalType,
- PluralRule: locales.PluralRule(i).String(),
- })
- }
- }
- for k, pluralTrans := range locale.(*translator).ordinalTanslations {
- for i, plural := range pluralTrans {
- // leave enough for all plural rules
- // but not all are set for all languages.
- if plural == nil {
- continue
- }
- trans = append(trans, translation{
- Locale: locale.Locale(),
- Key: k.(string),
- Translation: plural.text,
- PluralType: ordinalType,
- PluralRule: locales.PluralRule(i).String(),
- })
- }
- }
- for k, pluralTrans := range locale.(*translator).rangeTanslations {
- for i, plural := range pluralTrans {
- // leave enough for all plural rules
- // but not all are set for all languages.
- if plural == nil {
- continue
- }
- trans = append(trans, translation{
- Locale: locale.Locale(),
- Key: k.(string),
- Translation: plural.text,
- PluralType: rangeType,
- PluralRule: locales.PluralRule(i).String(),
- })
- }
- }
- switch format {
- case FormatJSON:
- b, err = json.MarshalIndent(trans, "", " ")
- ext = ".json"
- }
- if err != nil {
- return err
- }
- err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644)
- if err != nil {
- return err
- }
- trans = trans[0:0]
- }
- return nil
- }
- // Import reads the translations out of a file or directory on disk.
- //
- // NOTE: this currently only works with string or int translations keys.
- func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error {
- fi, err := os.Stat(dirnameOrFilename)
- if err != nil {
- return err
- }
- processFn := func(filename string) error {
- f, err := os.Open(filename)
- if err != nil {
- return err
- }
- defer f.Close()
- return t.ImportByReader(format, f)
- }
- if !fi.IsDir() {
- return processFn(dirnameOrFilename)
- }
- // recursively go through directory
- walker := func(path string, info os.FileInfo, err error) error {
- if info.IsDir() {
- return nil
- }
- switch format {
- case FormatJSON:
- // skip non JSON files
- if filepath.Ext(info.Name()) != ".json" {
- return nil
- }
- }
- return processFn(path)
- }
- return filepath.Walk(dirnameOrFilename, walker)
- }
- // ImportByReader imports the the translations found within the contents read from the supplied reader.
- //
- // NOTE: generally used when assets have been embedded into the binary and are already in memory.
- func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error {
- b, err := ioutil.ReadAll(reader)
- if err != nil {
- return err
- }
- var trans []translation
- switch format {
- case FormatJSON:
- err = json.Unmarshal(b, &trans)
- }
- if err != nil {
- return err
- }
- for _, tl := range trans {
- locale, found := t.FindTranslator(tl.Locale)
- if !found {
- return &ErrMissingLocale{locale: tl.Locale}
- }
- pr := stringToPR(tl.PluralRule)
- if pr == locales.PluralRuleUnknown {
- err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting)
- if err != nil {
- return err
- }
- continue
- }
- switch tl.PluralType {
- case cardinalType:
- err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting)
- case ordinalType:
- err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting)
- case rangeType:
- err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting)
- default:
- return &ErrBadPluralDefinition{tl: tl}
- }
- if err != nil {
- return err
- }
- }
- return nil
- }
- func stringToPR(s string) locales.PluralRule {
- switch s {
- case "One":
- return locales.PluralRuleOne
- case "Two":
- return locales.PluralRuleTwo
- case "Few":
- return locales.PluralRuleFew
- case "Many":
- return locales.PluralRuleMany
- case "Other":
- return locales.PluralRuleOther
- default:
- return locales.PluralRuleUnknown
- }
- }
|