1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package main
import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"path/filepath"
"reflect"
"sort"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
)
type mergeCommand struct {
translationFiles []string
sourceLanguageTag string
outdir string
format string
}
func (mc *mergeCommand) execute() error {
if len(mc.translationFiles) < 1 {
return fmt.Errorf("need at least one translation file to parse")
}
if lang := language.Parse(mc.sourceLanguageTag); lang == nil {
return fmt.Errorf("invalid source locale: %s", mc.sourceLanguageTag)
}
marshal, err := newMarshalFunc(mc.format)
if err != nil {
return err
}
bundle := bundle.New()
for _, tf := range mc.translationFiles {
if err := bundle.LoadTranslationFile(tf); err != nil {
return fmt.Errorf("failed to load translation file %s because %s\n", tf, err)
}
}
translations := bundle.Translations()
sourceLanguageTag := language.NormalizeTag(mc.sourceLanguageTag)
sourceTranslations := translations[sourceLanguageTag]
if sourceTranslations == nil {
return fmt.Errorf("no translations found for source locale %s", sourceLanguageTag)
}
for translationID, src := range sourceTranslations {
for _, localeTranslations := range translations {
if dst := localeTranslations[translationID]; dst == nil || reflect.TypeOf(src) != reflect.TypeOf(dst) {
localeTranslations[translationID] = src.UntranslatedCopy()
}
}
}
for localeID, localeTranslations := range translations {
lang := language.MustParse(localeID)[0]
all := filter(localeTranslations, func(t translation.Translation) translation.Translation {
return t.Normalize(lang)
})
if err := mc.writeFile("all", all, localeID, marshal); err != nil {
return err
}
untranslated := filter(localeTranslations, func(t translation.Translation) translation.Translation {
if t.Incomplete(lang) {
return t.Normalize(lang).Backfill(sourceTranslations[t.ID()])
}
return nil
})
if err := mc.writeFile("untranslated", untranslated, localeID, marshal); err != nil {
return err
}
}
return nil
}
type marshalFunc func(interface{}) ([]byte, error)
func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string, marshal marshalFunc) error {
sort.Sort(translation.SortableByID(translations))
buf, err := marshal(marshalInterface(translations))
if err != nil {
return fmt.Errorf("failed to marshal %s strings to %s because %s", localeID, mc.format, err)
}
filename := filepath.Join(mc.outdir, fmt.Sprintf("%s.%s.%s", localeID, label, mc.format))
if err := ioutil.WriteFile(filename, buf, 0666); err != nil {
return fmt.Errorf("failed to write %s because %s", filename, err)
}
return nil
}
func filter(translations map[string]translation.Translation, filter func(translation.Translation) translation.Translation) []translation.Translation {
filtered := make([]translation.Translation, 0, len(translations))
for _, translation := range translations {
if t := filter(translation); t != nil {
filtered = append(filtered, t)
}
}
return filtered
}
func newMarshalFunc(format string) (marshalFunc, error) {
switch format {
case "json":
return func(v interface{}) ([]byte, error) {
return json.MarshalIndent(v, "", " ")
}, nil
case "yaml":
return func(v interface{}) ([]byte, error) {
return yaml.Marshal(v)
}, nil
}
return nil, fmt.Errorf("unsupported format: %s\n", format)
}
func marshalInterface(translations []translation.Translation) []interface{} {
mi := make([]interface{}, len(translations))
for i, translation := range translations {
mi[i] = translation.MarshalInterface()
}
return mi
}
|