@@ -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,42 @@ 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
+ language = SimplifiedLocale (language )
138
+ languages = append (languages , language )
139
+ if language == "C" {
140
+ break
141
+ }
142
+ }
143
+ globalConfig .languages = languages
121
144
globalConfig .Unlock ()
122
145
123
146
loadStorage (true )
@@ -132,7 +155,7 @@ func GetLibrary() string {
132
155
return lib
133
156
}
134
157
135
- // SetLibrary sets the root path for the loale directories and files to be used at package level.
158
+ // SetLibrary sets the root path for the locale directories and files to be used at package level.
136
159
// It reloads the corresponding Translation file.
137
160
func SetLibrary (lib string ) {
138
161
globalConfig .Lock ()
@@ -173,7 +196,15 @@ func SetStorage(storage *Locale) {
173
196
func Configure (lib , lang , dom string ) {
174
197
globalConfig .Lock ()
175
198
globalConfig .library = lib
176
- globalConfig .language = SimplifiedLocale (lang )
199
+ var languages []string
200
+ for _ , language := range strings .Split (lang , ":" ) {
201
+ language = SimplifiedLocale (language )
202
+ languages = append (languages , language )
203
+ if language == "C" {
204
+ break
205
+ }
206
+ }
207
+ globalConfig .languages = languages
177
208
globalConfig .domain = dom
178
209
globalConfig .Unlock ()
179
210
@@ -198,16 +229,20 @@ func GetD(dom, str string, vars ...interface{}) string {
198
229
// Try to load default package Locale storage
199
230
loadStorage (false )
200
231
201
- // Return Translation
202
232
globalConfig .RLock ()
233
+ defer globalConfig .RUnlock ()
203
234
204
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
205
- globalConfig .storage .AddDomain (dom )
235
+ var tr string
236
+ for i , locale := range globalConfig .locales {
237
+ if _ , ok := locale .Domains [dom ]; ! ok {
238
+ locale .AddDomain (dom )
239
+ }
240
+ if ! locale .IsTranslatedD (dom , str ) && i < (len (globalConfig .locales )- 1 ) {
241
+ continue
242
+ }
243
+ tr = locale .GetD (dom , str , vars ... )
244
+ break
206
245
}
207
-
208
- tr := globalConfig .storage .GetD (dom , str , vars ... )
209
- globalConfig .RUnlock ()
210
-
211
246
return tr
212
247
}
213
248
@@ -217,16 +252,20 @@ func GetND(dom, str, plural string, n int, vars ...interface{}) string {
217
252
// Try to load default package Locale storage
218
253
loadStorage (false )
219
254
220
- // Return Translation
221
255
globalConfig .RLock ()
256
+ defer globalConfig .RUnlock ()
222
257
223
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
224
- globalConfig .storage .AddDomain (dom )
258
+ var tr string
259
+ for i , locale := range globalConfig .locales {
260
+ if _ , ok := locale .Domains [dom ]; ! ok {
261
+ locale .AddDomain (dom )
262
+ }
263
+ if ! locale .IsTranslatedND (dom , str , n ) && i < (len (globalConfig .locales )- 1 ) {
264
+ continue
265
+ }
266
+ tr = locale .GetND (dom , str , plural , n , vars ... )
267
+ break
225
268
}
226
-
227
- tr := globalConfig .storage .GetND (dom , str , plural , n , vars ... )
228
- globalConfig .RUnlock ()
229
-
230
269
return tr
231
270
}
232
271
@@ -248,11 +287,17 @@ func GetDC(dom, str, ctx string, vars ...interface{}) string {
248
287
// Try to load default package Locale storage
249
288
loadStorage (false )
250
289
251
- // Return Translation
252
290
globalConfig .RLock ()
253
- tr := globalConfig .storage .GetDC (dom , str , ctx , vars ... )
254
- globalConfig .RUnlock ()
291
+ defer globalConfig .RUnlock ()
255
292
293
+ var tr string
294
+ for i , locale := range globalConfig .locales {
295
+ if ! locale .IsTranslatedDC (dom , str , ctx ) && i < (len (globalConfig .locales )- 1 ) {
296
+ continue
297
+ }
298
+ tr = locale .GetDC (dom , str , ctx , vars ... )
299
+ break
300
+ }
256
301
return tr
257
302
}
258
303
@@ -264,62 +309,101 @@ func GetNDC(dom, str, plural string, n int, ctx string, vars ...interface{}) str
264
309
265
310
// Return Translation
266
311
globalConfig .RLock ()
267
- tr := globalConfig .storage .GetNDC (dom , str , plural , n , ctx , vars ... )
268
- globalConfig .RUnlock ()
312
+ defer globalConfig .RUnlock ()
269
313
314
+ var tr string
315
+ for i , locale := range globalConfig .locales {
316
+ if ! locale .IsTranslatedNDC (dom , str , n , ctx ) && i < (len (globalConfig .locales )- 1 ) {
317
+ continue
318
+ }
319
+ tr = locale .GetNDC (dom , str , plural , n , ctx , vars ... )
320
+ break
321
+ }
270
322
return tr
271
323
}
272
324
273
- // IsTranslated reports whether a string is translated
274
- func IsTranslated (str string ) bool {
275
- return IsTranslatedND (GetDomain (), str , 0 )
325
+ // IsTranslated reports whether a string is translated in given languages.
326
+ // When the langs argument is omitted, the output of GetLanguages is used.
327
+ func IsTranslated (str string , langs ... string ) bool {
328
+ return IsTranslatedND (GetDomain (), str , 0 , langs ... )
276
329
}
277
330
278
- // IsTranslatedN reports whether a plural string is translated
279
- func IsTranslatedN (str string , n int ) bool {
280
- return IsTranslatedND (GetDomain (), str , n )
331
+ // IsTranslatedN reports whether a plural string is translated in given languages.
332
+ // When the langs argument is omitted, the output of GetLanguages is used.
333
+ func IsTranslatedN (str string , n int , langs ... string ) bool {
334
+ return IsTranslatedND (GetDomain (), str , n , langs ... )
281
335
}
282
336
283
- // IsTranslatedD reports whether a domain string is translated
284
- func IsTranslatedD (dom , str string ) bool {
285
- return IsTranslatedND (dom , str , 0 )
337
+ // IsTranslatedD reports whether a domain string is translated in given languages.
338
+ // When the langs argument is omitted, the output of GetLanguages is used.
339
+ func IsTranslatedD (dom , str string , langs ... string ) bool {
340
+ return IsTranslatedND (dom , str , 0 , langs ... )
286
341
}
287
342
288
- // IsTranslatedND reports whether a plural domain string is translated
289
- func IsTranslatedND (dom , str string , n int ) bool {
343
+ // IsTranslatedND reports whether a plural domain string is translated in any of given languages.
344
+ // When the langs argument is omitted, the output of GetLanguages is used.
345
+ func IsTranslatedND (dom , str string , n int , langs ... string ) bool {
346
+ if len (langs ) == 0 {
347
+ langs = GetLanguages ()
348
+ }
349
+
290
350
loadStorage (false )
291
351
292
352
globalConfig .RLock ()
293
353
defer globalConfig .RUnlock ()
294
354
295
- if _ , ok := globalConfig .storage .Domains [dom ]; ! ok {
296
- globalConfig .storage .AddDomain (dom )
297
- }
355
+ for _ , lang := range langs {
356
+ lang = SimplifiedLocale (lang )
298
357
299
- return globalConfig .storage .IsTranslatedND (dom , str , n )
358
+ for _ , supportedLocale := range globalConfig .locales {
359
+ if lang != supportedLocale .GetActualLanguage (dom ) {
360
+ continue
361
+ }
362
+ return supportedLocale .IsTranslatedND (dom , str , n )
363
+ }
364
+ }
365
+ return false
300
366
}
301
367
302
- // IsTranslatedC reports whether a context string is translated
303
- func IsTranslatedC (str , ctx string ) bool {
304
- return IsTranslatedNDC (GetDomain (), str , 0 , ctx )
368
+ // IsTranslatedC reports whether a context string is translated in given languages.
369
+ // When the langs argument is omitted, the output of GetLanguages is used.
370
+ func IsTranslatedC (str , ctx string , langs ... string ) bool {
371
+ return IsTranslatedNDC (GetDomain (), str , 0 , ctx , langs ... )
305
372
}
306
373
307
- // IsTranslatedNC reports whether a plural context string is translated
308
- func IsTranslatedNC (str string , n int , ctx string ) bool {
309
- return IsTranslatedNDC (GetDomain (), str , n , ctx )
374
+ // IsTranslatedNC reports whether a plural context string is translated in given languages.
375
+ // When the langs argument is omitted, the output of GetLanguages is used.
376
+ func IsTranslatedNC (str string , n int , ctx string , langs ... string ) bool {
377
+ return IsTranslatedNDC (GetDomain (), str , n , ctx , langs ... )
310
378
}
311
379
312
- // IsTranslatedDC reports whether a domain context string is translated
313
- func IsTranslatedDC (dom , str , ctx string ) bool {
314
- return IsTranslatedNDC (dom , str , 0 , ctx )
380
+ // IsTranslatedDC reports whether a domain context string is translated in given languages.
381
+ // When the langs argument is omitted, the output of GetLanguages is used.
382
+ func IsTranslatedDC (dom , str , ctx string , langs ... string ) bool {
383
+ return IsTranslatedNDC (dom , str , 0 , ctx , langs ... )
315
384
}
316
385
317
- // IsTranslatedNDC reports whether a plural domain context string is translated
318
- func IsTranslatedNDC (dom , str string , n int , ctx string ) bool {
386
+ // IsTranslatedNDC reports whether a plural domain context string is translated in any of given languages.
387
+ // When the langs argument is omitted, the output of GetLanguages is used.
388
+ func IsTranslatedNDC (dom , str string , n int , ctx string , langs ... string ) bool {
389
+ if len (langs ) == 0 {
390
+ langs = GetLanguages ()
391
+ }
392
+
319
393
loadStorage (false )
320
394
321
395
globalConfig .RLock ()
322
396
defer globalConfig .RUnlock ()
323
397
324
- return globalConfig .storage .IsTranslatedNDC (dom , str , n , ctx )
398
+ for _ , lang := range langs {
399
+ lang = SimplifiedLocale (lang )
400
+
401
+ for _ , locale := range globalConfig .locales {
402
+ if lang != locale .GetActualLanguage (dom ) {
403
+ continue
404
+ }
405
+ return locale .IsTranslatedNDC (dom , str , n , ctx )
406
+ }
407
+ }
408
+ return false
325
409
}
0 commit comments