@@ -79,8 +79,8 @@ Example:
79
79
80
80
*/
81
81
type Po struct {
82
- // Headers
83
- RawHeaders string
82
+ // Headers storage
83
+ Headers textproto. MIMEHeader
84
84
85
85
// Language header
86
86
Language string
@@ -140,7 +140,6 @@ func (po *Po) ParseFile(f string) {
140
140
func (po * Po ) Parse (str string ) {
141
141
// Lock while parsing
142
142
po .Lock ()
143
- defer po .Unlock ()
144
143
145
144
// Init storage
146
145
if po .translations == nil {
@@ -195,38 +194,42 @@ func (po *Po) Parse(str string) {
195
194
196
195
// Multi line strings and headers
197
196
if strings .HasPrefix (l , "\" " ) && strings .HasSuffix (l , "\" " ) {
198
- state = po .parseString (l , state )
197
+ po .parseString (l , state )
199
198
continue
200
199
}
201
200
}
202
201
203
202
// Save last translation buffer.
204
203
po .saveBuffer ()
205
204
205
+ // Unlock to parse headers
206
+ po .Unlock ()
207
+
206
208
// Parse headers
207
209
po .parseHeaders ()
208
210
}
209
211
210
212
// saveBuffer takes the context and translation buffers
211
213
// and saves it on the translations collection
212
214
func (po * Po ) saveBuffer () {
213
- // If we have something to save...
214
- if po .trBuffer .id != "" {
215
- // With no context...
216
- if po .ctxBuffer == "" {
217
- po .translations [po .trBuffer .id ] = po .trBuffer
218
- } else {
219
- // With context...
220
- if _ , ok := po .contexts [po .ctxBuffer ]; ! ok {
221
- po .contexts [po .ctxBuffer ] = make (map [string ]* translation )
222
- }
223
- po .contexts [po .ctxBuffer ][po .trBuffer .id ] = po .trBuffer
215
+ // With no context...
216
+ if po .ctxBuffer == "" {
217
+ po .translations [po .trBuffer .id ] = po .trBuffer
218
+ } else {
219
+ // With context...
220
+ if _ , ok := po .contexts [po .ctxBuffer ]; ! ok {
221
+ po .contexts [po .ctxBuffer ] = make (map [string ]* translation )
224
222
}
223
+ po .contexts [po .ctxBuffer ][po .trBuffer .id ] = po .trBuffer
225
224
226
- // Flush buffer
227
- po .trBuffer = newTranslation ()
228
- po .ctxBuffer = ""
225
+ // Cleanup current context buffer if needed
226
+ if po .trBuffer .id != "" {
227
+ po .ctxBuffer = ""
228
+ }
229
229
}
230
+
231
+ // Flush translation buffer
232
+ po .trBuffer = newTranslation ()
230
233
}
231
234
232
235
// parseContext takes a line starting with "msgctxt",
@@ -286,70 +289,72 @@ func (po *Po) parseMessage(l string) {
286
289
287
290
// parseString takes a well formatted string without prefix
288
291
// and creates headers or attach multi-line strings when corresponding
289
- func (po * Po ) parseString (l string , state parseState ) parseState {
292
+ func (po * Po ) parseString (l string , state parseState ) {
293
+ clean , _ := strconv .Unquote (l )
294
+
290
295
switch state {
291
296
case msgStr :
292
- // Check for multiline from previously set msgid
293
- if po .trBuffer .id != "" {
294
- // Append to last translation found
295
- uq , _ := strconv .Unquote (l )
296
- po .trBuffer .trs [len (po .trBuffer .trs )- 1 ] += uq
297
+ // Append to last translation found
298
+ po .trBuffer .trs [len (po .trBuffer .trs )- 1 ] += clean
297
299
298
- }
299
300
case msgID :
300
301
// Multiline msgid - Append to current id
301
- uq , _ := strconv . Unquote ( l )
302
- po . trBuffer . id += uq
302
+ po . trBuffer . id += clean
303
+
303
304
case msgIDPlural :
304
305
// Multiline msgid - Append to current id
305
- uq , _ := strconv . Unquote ( l )
306
- po . trBuffer . pluralID += uq
306
+ po . trBuffer . pluralID += clean
307
+
307
308
case msgCtxt :
308
309
// Multiline context - Append to current context
309
- ctxt , _ := strconv .Unquote (l )
310
- po .ctxBuffer += ctxt
311
- default :
312
- // Otherwise is a header
313
- h , _ := strconv .Unquote (strings .TrimSpace (l ))
314
- po .RawHeaders += h
315
- return head
316
- }
310
+ po .ctxBuffer += clean
317
311
318
- return state
312
+ }
319
313
}
320
314
321
315
// isValidLine checks for line prefixes to detect valid syntax.
322
316
func (po * Po ) isValidLine (l string ) bool {
323
- // Skip empty lines
324
- if l == "" {
325
- return false
317
+ // Check prefix
318
+ valid := []string {
319
+ "\" " ,
320
+ "msgctxt" ,
321
+ "msgid" ,
322
+ "msgid_plural" ,
323
+ "msgstr" ,
326
324
}
327
325
328
- // Check prefix
329
- if ! strings .HasPrefix (l , "\" " ) && ! strings .HasPrefix (l , "msgctxt" ) && ! strings .HasPrefix (l , "msgid" ) && ! strings .HasPrefix (l , "msgid_plural" ) && ! strings .HasPrefix (l , "msgstr" ) {
330
- return false
326
+ for _ , v := range valid {
327
+ if strings .HasPrefix (l , v ) {
328
+ return true
329
+ }
331
330
}
332
331
333
- return true
332
+ return false
334
333
}
335
334
336
335
// parseHeaders retrieves data from previously parsed headers
337
336
func (po * Po ) parseHeaders () {
338
337
// Make sure we end with 2 carriage returns.
339
- po .RawHeaders += "\n \n "
338
+ raw := po .Get ( "" ) + "\n \n "
340
339
341
340
// Read
342
- reader := bufio .NewReader (strings .NewReader (po . RawHeaders ))
341
+ reader := bufio .NewReader (strings .NewReader (raw ))
343
342
tp := textproto .NewReader (reader )
344
343
345
- mimeHeader , err := tp .ReadMIMEHeader ()
344
+ var err error
345
+
346
+ // Sync Headers write.
347
+ po .Lock ()
348
+ defer po .Unlock ()
349
+
350
+ po .Headers , err = tp .ReadMIMEHeader ()
346
351
if err != nil {
347
352
return
348
353
}
349
354
350
355
// Get/save needed headers
351
- po .Language = mimeHeader .Get ("Language" )
352
- po .PluralForms = mimeHeader .Get ("Plural-Forms" )
356
+ po .Language = po . Headers .Get ("Language" )
357
+ po .PluralForms = po . Headers .Get ("Plural-Forms" )
353
358
354
359
// Parse Plural-Forms formula
355
360
if po .PluralForms == "" {
@@ -422,12 +427,12 @@ func (po *Po) Get(str string, vars ...interface{}) string {
422
427
423
428
if po .translations != nil {
424
429
if _ , ok := po .translations [str ]; ok {
425
- return fmt . Sprintf (po .translations [str ].get (), vars ... )
430
+ return po . printf (po .translations [str ].get (), vars ... )
426
431
}
427
432
}
428
433
429
434
// Return the same we received by default
430
- return fmt . Sprintf (str , vars ... )
435
+ return po . printf (str , vars ... )
431
436
}
432
437
433
438
// GetN retrieves the (N)th plural form of translation for the given string.
@@ -439,15 +444,14 @@ func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string {
439
444
440
445
if po .translations != nil {
441
446
if _ , ok := po .translations [str ]; ok {
442
- return fmt . Sprintf (po .translations [str ].getN (po .pluralForm (n )), vars ... )
447
+ return po . printf (po .translations [str ].getN (po .pluralForm (n )), vars ... )
443
448
}
444
449
}
445
450
446
451
if n == 1 {
447
- return fmt . Sprintf (str , vars ... )
452
+ return po . printf (str , vars ... )
448
453
}
449
-
450
- return fmt .Sprintf (plural , vars ... )
454
+ return po .printf (plural , vars ... )
451
455
}
452
456
453
457
// GetC retrieves the corresponding translation for a given string in the given context.
@@ -461,14 +465,14 @@ func (po *Po) GetC(str, ctx string, vars ...interface{}) string {
461
465
if _ , ok := po .contexts [ctx ]; ok {
462
466
if po .contexts [ctx ] != nil {
463
467
if _ , ok := po.contexts [ctx ][str ]; ok {
464
- return fmt . Sprintf (po.contexts [ctx ][str ].get (), vars ... )
468
+ return po . printf (po.contexts [ctx ][str ].get (), vars ... )
465
469
}
466
470
}
467
471
}
468
472
}
469
473
470
474
// Return the string we received by default
471
- return fmt . Sprintf (str , vars ... )
475
+ return po . printf (str , vars ... )
472
476
}
473
477
474
478
// GetNC retrieves the (N)th plural form of translation for the given string in the given context.
@@ -482,14 +486,23 @@ func (po *Po) GetNC(str, plural string, n int, ctx string, vars ...interface{})
482
486
if _ , ok := po .contexts [ctx ]; ok {
483
487
if po .contexts [ctx ] != nil {
484
488
if _ , ok := po.contexts [ctx ][str ]; ok {
485
- return fmt . Sprintf (po.contexts [ctx ][str ].getN (po .pluralForm (n )), vars ... )
489
+ return po . printf (po.contexts [ctx ][str ].getN (po .pluralForm (n )), vars ... )
486
490
}
487
491
}
488
492
}
489
493
}
490
494
491
495
if n == 1 {
496
+ return po .printf (str , vars ... )
497
+ }
498
+ return po .printf (plural , vars ... )
499
+ }
500
+
501
+ // printf applies text formatting only when needed to parse variables.
502
+ func (po * Po ) printf (str string , vars ... interface {}) string {
503
+ if len (vars ) > 0 {
492
504
return fmt .Sprintf (str , vars ... )
493
505
}
494
- return fmt .Sprintf (plural , vars ... )
506
+
507
+ return str
495
508
}
0 commit comments