@@ -24,54 +24,62 @@ package gotext
24
24
25
25
import (
26
26
"encoding/gob"
27
+ "strings"
27
28
"sync"
28
29
)
29
30
30
31
// Global environment variables
31
32
type config struct {
32
33
sync.RWMutex
33
34
35
+ // Path to library directory where all locale directories and Translation files are.
36
+ library string
37
+
34
38
// Default domain to look at when no domain is specified. Used by package level functions.
35
39
domain string
36
40
37
41
// Language set.
38
- language string
39
-
40
- // Path to library directory where all locale directories and Translation files are.
41
- library string
42
+ languages []string
42
43
43
44
// Storage for package level methods
44
- storage * Locale
45
+ locales [] * Locale
45
46
}
46
47
47
48
var globalConfig * config
48
49
49
50
func init () {
50
51
// Init default configuration
51
52
globalConfig = & config {
52
- domain : "default" ,
53
- language : "en_US" ,
54
- library : "/usr/local/share/locale" ,
55
- storage : nil ,
53
+ domain : "default" ,
54
+ languages : [] string { "en_US" } ,
55
+ library : "/usr/local/share/locale" ,
56
+ locales : nil ,
56
57
}
57
58
58
59
// Register Translator types for gob encoding
59
60
gob .Register (TranslatorEncoding {})
60
61
}
61
62
62
- // loadStorage creates a new Locale object at package level based on the Global variables settings.
63
+ // loadStorage creates a new Locale object at package level based on the Global variables settings
64
+ // for every language specified using Configure.
63
65
// It's called automatically when trying to use Get or GetD methods.
64
66
func loadStorage (force bool ) {
65
67
globalConfig .Lock ()
66
68
67
- if globalConfig .storage == nil || force {
68
- globalConfig .storage = NewLocale (globalConfig .library , globalConfig .language )
69
+ if globalConfig .locales == nil || force {
70
+ var locales []* Locale
71
+ for _ , language := range globalConfig .languages {
72
+ locales = append (locales , NewLocale (globalConfig .library , language ))
73
+ }
74
+ globalConfig .locales = locales
69
75
}
70
76
71
- if _ , ok := globalConfig .storage .Domains [globalConfig .domain ]; ! ok || force {
72
- globalConfig .storage .AddDomain (globalConfig .domain )
77
+ for _ , locale := range globalConfig .locales {
78
+ if _ , ok := locale .Domains [globalConfig .domain ]; ! ok || force {
79
+ locale .AddDomain (globalConfig .domain )
80
+ }
81
+ locale .SetDomain (globalConfig .domain )
73
82
}
74
- globalConfig .storage .SetDomain (globalConfig .domain )
75
83
76
84
globalConfig .Unlock ()
77
85
}
@@ -80,8 +88,9 @@ func loadStorage(force bool) {
80
88
func GetDomain () string {
81
89
var dom string
82
90
globalConfig .RLock ()
83
- if globalConfig .storage != nil {
84
- dom = globalConfig .storage .GetDomain ()
91
+ if globalConfig .locales != nil {
92
+ // All locales have the same domain
93
+ dom = globalConfig .locales [0 ].GetDomain ()
85
94
}
86
95
if dom == "" {
87
96
dom = globalConfig .domain
@@ -96,28 +105,38 @@ func GetDomain() string {
96
105
func SetDomain (dom string ) {
97
106
globalConfig .Lock ()
98
107
globalConfig .domain = dom
99
- if globalConfig .storage != nil {
100
- globalConfig .storage .SetDomain (dom )
108
+ if globalConfig .locales != nil {
109
+ for _ , locale := range globalConfig .locales {
110
+ locale .SetDomain (dom )
111
+ }
101
112
}
102
113
globalConfig .Unlock ()
103
114
104
115
loadStorage (true )
105
116
}
106
117
107
- // GetLanguage is the language getter for the package configuration
118
+ // GetLanguage returns the language gotext will translate into.
119
+ // If multiple languages have been supplied, the first one will be returned.
108
120
func GetLanguage () string {
109
- globalConfig .RLock ()
110
- lang := globalConfig .language
111
- globalConfig .RUnlock ()
121
+ return GetLanguages ()[0 ]
122
+ }
112
123
113
- return lang
124
+ // GetLanguages returns all languages that have been supplied.
125
+ func GetLanguages () []string {
126
+ globalConfig .RLock ()
127
+ defer globalConfig .RUnlock ()
128
+ return globalConfig .languages
114
129
}
115
130
116
- // SetLanguage sets the language code to be used at package level.
131
+ // SetLanguage sets the language code (or colon separated language codes) to be used at package level.
117
132
// It reloads the corresponding Translation file.
118
133
func SetLanguage (lang string ) {
119
134
globalConfig .Lock ()
120
- globalConfig .language = SimplifiedLocale (lang )
135
+ var languages []string
136
+ for _ , language := range strings .Split (lang , ":" ) {
137
+ languages = append (languages , SimplifiedLocale (language ))
138
+ }
139
+ globalConfig .languages = languages
121
140
globalConfig .Unlock ()
122
141
123
142
loadStorage (true )
@@ -149,7 +168,11 @@ func SetLibrary(lib string) {
149
168
func Configure (lib , lang , dom string ) {
150
169
globalConfig .Lock ()
151
170
globalConfig .library = lib
152
- globalConfig .language = SimplifiedLocale (lang )
171
+ var languages []string
172
+ for _ , language := range strings .Split (lang , ":" ) {
173
+ languages = append (languages , SimplifiedLocale (language ))
174
+ }
175
+ globalConfig .languages = languages
153
176
globalConfig .domain = dom
154
177
globalConfig .Unlock ()
155
178
@@ -174,16 +197,20 @@ func GetD(dom, str string, vars ...interface{}) string {
174
197
// Try to load default package Locale storage
175
198
loadStorage (false )
176
199
177
- // Return Translation
178
200
globalConfig .RLock ()
201
+ defer globalConfig .RUnlock ()
179
202
180
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
181
- globalConfig .storage .AddDomain (dom )
203
+ var tr string
204
+ for i , locale := range globalConfig .locales {
205
+ if _ , ok := locale .Domains [dom ]; ! ok {
206
+ locale .AddDomain (dom )
207
+ }
208
+ if ! locale .IsTranslatedD (dom , str ) && i < (len (globalConfig .locales )- 1 ) {
209
+ continue
210
+ }
211
+ tr = locale .GetD (dom , str , vars ... )
212
+ break
182
213
}
183
-
184
- tr := globalConfig .storage .GetD (dom , str , vars ... )
185
- globalConfig .RUnlock ()
186
-
187
214
return tr
188
215
}
189
216
@@ -193,16 +220,20 @@ func GetND(dom, str, plural string, n int, vars ...interface{}) string {
193
220
// Try to load default package Locale storage
194
221
loadStorage (false )
195
222
196
- // Return Translation
197
223
globalConfig .RLock ()
224
+ defer globalConfig .RUnlock ()
198
225
199
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
200
- globalConfig .storage .AddDomain (dom )
226
+ var tr string
227
+ for i , locale := range globalConfig .locales {
228
+ if _ , ok := locale .Domains [dom ]; ! ok {
229
+ locale .AddDomain (dom )
230
+ }
231
+ if ! locale .IsTranslatedND (dom , str , n ) && i < (len (globalConfig .locales )- 1 ) {
232
+ continue
233
+ }
234
+ tr = locale .GetND (dom , str , plural , n , vars ... )
235
+ break
201
236
}
202
-
203
- tr := globalConfig .storage .GetND (dom , str , plural , n , vars ... )
204
- globalConfig .RUnlock ()
205
-
206
237
return tr
207
238
}
208
239
@@ -224,11 +255,17 @@ func GetDC(dom, str, ctx string, vars ...interface{}) string {
224
255
// Try to load default package Locale storage
225
256
loadStorage (false )
226
257
227
- // Return Translation
228
258
globalConfig .RLock ()
229
- tr := globalConfig .storage .GetDC (dom , str , ctx , vars ... )
230
- globalConfig .RUnlock ()
259
+ defer globalConfig .RUnlock ()
231
260
261
+ var tr string
262
+ for i , locale := range globalConfig .locales {
263
+ if ! locale .IsTranslatedDC (dom , str , ctx ) && i < (len (globalConfig .locales )- 1 ) {
264
+ continue
265
+ }
266
+ tr = locale .GetDC (dom , str , ctx , vars ... )
267
+ break
268
+ }
232
269
return tr
233
270
}
234
271
@@ -240,62 +277,101 @@ func GetNDC(dom, str, plural string, n int, ctx string, vars ...interface{}) str
240
277
241
278
// Return Translation
242
279
globalConfig .RLock ()
243
- tr := globalConfig .storage .GetNDC (dom , str , plural , n , ctx , vars ... )
244
- globalConfig .RUnlock ()
280
+ defer globalConfig .RUnlock ()
245
281
282
+ var tr string
283
+ for i , locale := range globalConfig .locales {
284
+ if ! locale .IsTranslatedNDC (dom , str , n , ctx ) && i < (len (globalConfig .locales )- 1 ) {
285
+ continue
286
+ }
287
+ tr = locale .GetNDC (dom , str , plural , n , ctx , vars ... )
288
+ break
289
+ }
246
290
return tr
247
291
}
248
292
249
- // IsTranslated reports whether a string is translated
250
- func IsTranslated (str string ) bool {
251
- return IsTranslatedND (GetDomain (), str , 0 )
293
+ // IsTranslated reports whether a string is translated in given languages.
294
+ // When the langs argument is omitted, the output of GetLanguages is used.
295
+ func IsTranslated (str string , langs ... string ) bool {
296
+ return IsTranslatedND (GetDomain (), str , 0 , langs ... )
252
297
}
253
298
254
- // IsTranslatedN reports whether a plural string is translated
255
- func IsTranslatedN (str string , n int ) bool {
256
- return IsTranslatedND (GetDomain (), str , n )
299
+ // IsTranslatedN reports whether a plural string is translated in given languages.
300
+ // When the langs argument is omitted, the output of GetLanguages is used.
301
+ func IsTranslatedN (str string , n int , langs ... string ) bool {
302
+ return IsTranslatedND (GetDomain (), str , n , langs ... )
257
303
}
258
304
259
- // IsTranslatedD reports whether a domain string is translated
260
- func IsTranslatedD (dom , str string ) bool {
261
- return IsTranslatedND (dom , str , 0 )
305
+ // IsTranslatedD reports whether a domain string is translated in given languages.
306
+ // When the langs argument is omitted, the output of GetLanguages is used.
307
+ func IsTranslatedD (dom , str string , langs ... string ) bool {
308
+ return IsTranslatedND (dom , str , 0 , langs ... )
262
309
}
263
310
264
- // IsTranslatedND reports whether a plural domain string is translated
265
- func IsTranslatedND (dom , str string , n int ) bool {
311
+ // IsTranslatedND reports whether a plural domain string is translated in any of given languages.
312
+ // When the langs argument is omitted, the output of GetLanguages is used.
313
+ func IsTranslatedND (dom , str string , n int , langs ... string ) bool {
314
+ if len (langs ) == 0 {
315
+ langs = GetLanguages ()
316
+ }
317
+
266
318
loadStorage (false )
267
319
268
320
globalConfig .RLock ()
269
321
defer globalConfig .RUnlock ()
270
322
271
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
272
- globalConfig .storage .AddDomain (dom )
273
- }
323
+ for _ , lang := range langs {
324
+ lang = SimplifiedLocale (lang )
274
325
275
- return globalConfig .storage .IsTranslatedND (dom , str , n )
326
+ for _ , supportedLocale := range globalConfig .locales {
327
+ if lang != supportedLocale .GetActualLanguage (dom ) {
328
+ continue
329
+ }
330
+ return supportedLocale .IsTranslatedND (dom , str , n )
331
+ }
332
+ }
333
+ return false
276
334
}
277
335
278
- // IsTranslatedC reports whether a context string is translated
279
- func IsTranslatedC (str , ctx string ) bool {
280
- return IsTranslatedNDC (GetDomain (), str , 0 , ctx )
336
+ // IsTranslatedC reports whether a context string is translated in given languages.
337
+ // When the langs argument is omitted, the output of GetLanguages is used.
338
+ func IsTranslatedC (str , ctx string , langs ... string ) bool {
339
+ return IsTranslatedNDC (GetDomain (), str , 0 , ctx , langs ... )
281
340
}
282
341
283
- // IsTranslatedNC reports whether a plural context string is translated
284
- func IsTranslatedNC (str string , n int , ctx string ) bool {
285
- return IsTranslatedNDC (GetDomain (), str , n , ctx )
342
+ // IsTranslatedNC reports whether a plural context string is translated in given languages.
343
+ // When the langs argument is omitted, the output of GetLanguages is used.
344
+ func IsTranslatedNC (str string , n int , ctx string , langs ... string ) bool {
345
+ return IsTranslatedNDC (GetDomain (), str , n , ctx , langs ... )
286
346
}
287
347
288
- // IsTranslatedDC reports whether a domain context string is translated
289
- func IsTranslatedDC (dom , str , ctx string ) bool {
290
- return IsTranslatedNDC (dom , str , 0 , ctx )
348
+ // IsTranslatedDC reports whether a domain context string is translated in given languages.
349
+ // When the langs argument is omitted, the output of GetLanguages is used.
350
+ func IsTranslatedDC (dom , str , ctx string , langs ... string ) bool {
351
+ return IsTranslatedNDC (dom , str , 0 , ctx , langs ... )
291
352
}
292
353
293
- // IsTranslatedNDC reports whether a plural domain context string is translated
294
- func IsTranslatedNDC (dom , str string , n int , ctx string ) bool {
354
+ // IsTranslatedNDC reports whether a plural domain context string is translated in any of given languages.
355
+ // When the langs argument is omitted, the output of GetLanguages is used.
356
+ func IsTranslatedNDC (dom , str string , n int , ctx string , langs ... string ) bool {
357
+ if len (langs ) == 0 {
358
+ langs = GetLanguages ()
359
+ }
360
+
295
361
loadStorage (false )
296
362
297
363
globalConfig .RLock ()
298
364
defer globalConfig .RUnlock ()
299
365
300
- return globalConfig .storage .IsTranslatedNDC (dom , str , n , ctx )
366
+ for _ , lang := range langs {
367
+ lang = SimplifiedLocale (lang )
368
+
369
+ for _ , locale := range globalConfig .locales {
370
+ if lang != locale .GetActualLanguage (dom ) {
371
+ continue
372
+ }
373
+ return locale .IsTranslatedNDC (dom , str , n , ctx )
374
+ }
375
+ }
376
+ return false
301
377
}
0 commit comments