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