Commit 2b62f61cc84cc1e486f68f7e8d8f26a1fab71e2b
1 parent
89f45d7aa8
Exists in
master
minor changes
Showing
1 changed file
with
16 additions
and
9 deletions
Show diff stats
localization.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/json" | 4 | "encoding/json" |
5 | "fmt" | ||
5 | "io/ioutil" | 6 | "io/ioutil" |
6 | "net/http" | 7 | "net/http" |
7 | "path" | 8 | "path" |
8 | "strconv" | 9 | "strconv" |
9 | "strings" | 10 | "strings" |
10 | "sync" | 11 | "sync" |
11 | ) | 12 | ) |
12 | 13 | ||
13 | type Dictionary struct { | 14 | type Dictionary struct { |
14 | my sync.Mutex | 15 | my sync.Mutex |
15 | locales map[string]map[string]string | 16 | locales map[string]map[string]string |
16 | supported []string | 17 | supported []string |
17 | defaultLocale string | 18 | defaultLocale string |
18 | } | 19 | } |
19 | 20 | ||
20 | func NewDictionary(def string) *Dictionary { | 21 | func NewDictionary() *Dictionary { |
21 | d := Dictionary{ | 22 | return &Dictionary{ |
22 | locales: map[string]map[string]string{}, | 23 | locales: map[string]map[string]string{}, |
23 | } | 24 | } |
24 | d.defaultLocale = def | ||
25 | return &d | ||
26 | } | 25 | } |
27 | 26 | ||
28 | func (d *Dictionary) AddTranslations(directory string) error { | 27 | func (d *Dictionary) AddTranslations(directory string) error { |
29 | files, err := ioutil.ReadDir(directory) | 28 | files, err := ioutil.ReadDir(directory) |
30 | if err != nil { | 29 | if err != nil { |
31 | return err | 30 | return err |
32 | } | 31 | } |
33 | 32 | ||
34 | for _, fileInfo := range files { | 33 | for _, fileInfo := range files { |
35 | fName := fileInfo.Name() | 34 | fName := fileInfo.Name() |
36 | path := directory + "/" + fName | 35 | path := directory + "/" + fName |
37 | file, err := ioutil.ReadFile(path) | 36 | file, err := ioutil.ReadFile(path) |
38 | if err != nil { | 37 | if err != nil { |
39 | return err | 38 | return err |
40 | } | 39 | } |
41 | 40 | ||
42 | loc := stripFileExtension(fName) | 41 | loc := stripFileExtension(fName) |
43 | 42 | ||
44 | var data interface{} | 43 | var data interface{} |
45 | err = json.Unmarshal(file, &data) | 44 | err = json.Unmarshal(file, &data) |
46 | if err != nil { | 45 | if err != nil { |
47 | return err | 46 | return err |
48 | } | 47 | } |
49 | 48 | ||
50 | l := map[string]string{} | 49 | l := map[string]string{} |
51 | for k, v := range data.(map[string]interface{}) { | 50 | for k, v := range data.(map[string]interface{}) { |
52 | l[k] = v.(string) | 51 | l[k] = v.(string) |
53 | } | 52 | } |
54 | 53 | ||
55 | mu.Lock() | 54 | mu.Lock() |
56 | defer mu.Unlock() | 55 | defer mu.Unlock() |
57 | d.locales[loc] = l | 56 | d.locales[loc] = l |
58 | d.supported = append(d.supported, loc) | 57 | d.supported = append(d.supported, loc) |
59 | } | 58 | } |
60 | 59 | ||
61 | if d.defaultLocale == "" { | 60 | if d.defaultLocale == "" && len(d.supported) > 0 { |
62 | if len(d.supported) > 0 { | 61 | d.defaultLocale = d.supported[0] |
63 | d.defaultLocale = d.supported[0] | ||
64 | } | ||
65 | } | 62 | } |
66 | 63 | ||
67 | return nil | 64 | return nil |
68 | } | 65 | } |
69 | 66 | ||
70 | func (d *Dictionary) GetBestMatchLocale(req *http.Request) (best string) { | 67 | func (d *Dictionary) GetBestMatchLocale(req *http.Request) (best string) { |
71 | accepted := d.parseAcceptedLanguages(req.Header.Get("Accept-Language")) | 68 | accepted := d.parseAcceptedLanguages(req.Header.Get("Accept-Language")) |
72 | 69 | ||
73 | for i, _ := range accepted { | 70 | for i, _ := range accepted { |
74 | if accepted[i].Code == "*" { | 71 | if accepted[i].Code == "*" { |
75 | return d.defaultLocale | 72 | return d.defaultLocale |
76 | } | 73 | } |
77 | for j, _ := range d.supported { | 74 | for j, _ := range d.supported { |
78 | if accepted[i].Code == d.supported[j] { | 75 | if accepted[i].Code == d.supported[j] { |
79 | return d.supported[j] | 76 | return d.supported[j] |
80 | } | 77 | } |
81 | } | 78 | } |
82 | } | 79 | } |
83 | 80 | ||
84 | return d.defaultLocale | 81 | return d.defaultLocale |
85 | } | 82 | } |
86 | 83 | ||
87 | func (d *Dictionary) Translate(loc, key string) string { | 84 | func (d *Dictionary) Translate(loc, key string) string { |
88 | return d.locales[loc][key] | 85 | return d.locales[loc][key] |
89 | } | 86 | } |
90 | 87 | ||
91 | func (d *Dictionary) hasLocale(loc string) bool { | 88 | func (d *Dictionary) SetDefaultLocale(loc string) error { |
89 | if !d.contains(loc) { | ||
90 | return fmt.Errorf("locale file not loaded: %s", loc) | ||
91 | } | ||
92 | |||
93 | d.defaultLocale = loc | ||
94 | |||
95 | return nil | ||
96 | } | ||
97 | |||
98 | func (d *Dictionary) contains(loc string) bool { | ||
92 | for _, v := range d.supported { | 99 | for _, v := range d.supported { |
93 | if v == loc { | 100 | if v == loc { |
94 | return true | 101 | return true |
95 | } | 102 | } |
96 | } | 103 | } |
97 | return false | 104 | return false |
98 | } | 105 | } |
99 | 106 | ||
100 | type LangWeight struct { | 107 | type LangWeight struct { |
101 | Code string | 108 | Code string |
102 | Weight float64 | 109 | Weight float64 |
103 | } | 110 | } |
104 | 111 | ||
105 | func (d *Dictionary) parseAcceptedLanguages(accepted string) (langs []LangWeight) { | 112 | func (d *Dictionary) parseAcceptedLanguages(accepted string) (langs []LangWeight) { |
106 | if accepted == "" { | 113 | if accepted == "" { |
107 | langs = append(langs, LangWeight{Code: d.defaultLocale, Weight: 1.0}) | 114 | langs = append(langs, LangWeight{Code: d.defaultLocale, Weight: 1.0}) |
108 | return langs | 115 | return langs |
109 | } | 116 | } |
110 | 117 | ||
111 | parts := strings.Split(accepted, ",") | 118 | parts := strings.Split(accepted, ",") |
112 | for i, _ := range parts { | 119 | for i, _ := range parts { |
113 | parts[i] = strings.Trim(parts[i], " ") | 120 | parts[i] = strings.Trim(parts[i], " ") |
114 | 121 | ||
115 | var code string = "" | 122 | var code string = "" |
116 | var weight float64 = 0.0 | 123 | var weight float64 = 0.0 |
117 | 124 | ||
118 | cw := strings.Split(parts[i], ";") | 125 | cw := strings.Split(parts[i], ";") |
119 | paramCount := len(cw) | 126 | paramCount := len(cw) |
120 | 127 | ||
121 | if paramCount == 1 { | 128 | if paramCount == 1 { |
122 | // default weight of 1 | 129 | // default weight of 1 |
123 | code = cw[0] | 130 | code = cw[0] |
124 | weight = 1.0 | 131 | weight = 1.0 |
125 | } else if paramCount == 2 { | 132 | } else if paramCount == 2 { |
126 | // parse weight | 133 | // parse weight |
127 | code = cw[0] | 134 | code = cw[0] |
128 | weight, _ = strconv.ParseFloat(cw[1][2:], 64) | 135 | weight, _ = strconv.ParseFloat(cw[1][2:], 64) |
129 | 136 | ||
130 | } | 137 | } |
131 | 138 | ||
132 | langs = append(langs, LangWeight{Code: code, Weight: weight}) | 139 | langs = append(langs, LangWeight{Code: code, Weight: weight}) |
133 | } | 140 | } |
134 | 141 | ||
135 | // TODO(marko): sort langs by weights? | 142 | // TODO(marko): sort langs by weights? |
136 | 143 | ||
137 | return langs | 144 | return langs |
138 | } | 145 | } |
139 | 146 | ||
140 | func stripFileExtension(full string) (stripped string) { | 147 | func stripFileExtension(full string) (stripped string) { |
141 | extension := path.Ext(full) | 148 | extension := path.Ext(full) |