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