@@ -529,45 +529,72 @@ def write_po(
529
529
updating the catalog
530
530
:param include_lineno: include line number in the location comment
531
531
"""
532
+
533
+ sort_by = None
534
+ if sort_output :
535
+ sort_by = "message"
536
+ elif sort_by_file :
537
+ sort_by = "location"
538
+
539
+ for line in generate_po (
540
+ catalog ,
541
+ ignore_obsolete = ignore_obsolete ,
542
+ include_lineno = include_lineno ,
543
+ include_previous = include_previous ,
544
+ no_location = no_location ,
545
+ omit_header = omit_header ,
546
+ sort_by = sort_by ,
547
+ width = width ,
548
+ ):
549
+ if isinstance (line , str ):
550
+ line = line .encode (catalog .charset , 'backslashreplace' )
551
+ fileobj .write (line )
552
+
553
+
554
+ def generate_po (
555
+ catalog : Catalog ,
556
+ * ,
557
+ ignore_obsolete : bool = False ,
558
+ include_lineno : bool = True ,
559
+ include_previous : bool = False ,
560
+ no_location : bool = False ,
561
+ omit_header : bool = False ,
562
+ sort_by : Literal ["message" , "location" ] | None ,
563
+ width : int = 76 ,
564
+ ) -> Iterable [str ]:
565
+ r"""Yield text strings representing a ``gettext`` PO (portable object) file.
566
+
567
+ See `write_po()` for a more detailed description.
568
+ """
569
+ # xgettext always wraps comments even if --no-wrap is passed;
570
+ # provide the same behaviour
571
+ comment_width = width if width and width > 0 else 76
572
+
532
573
def _normalize (key , prefix = '' ):
533
574
return normalize (key , prefix = prefix , width = width )
534
575
535
- def _write (text ):
536
- if isinstance (text , str ):
537
- text = text .encode (catalog .charset , 'backslashreplace' )
538
- fileobj .write (text )
539
-
540
- def _write_comment (comment , prefix = '' ):
541
- # xgettext always wraps comments even if --no-wrap is passed;
542
- # provide the same behaviour
543
- _width = width if width and width > 0 else 76
544
- for line in wraptext (comment , _width ):
545
- _write (f"#{ prefix } { line .strip ()} \n " )
576
+ def _format_comment (comment , prefix = '' ):
577
+ for line in wraptext (comment , comment_width ):
578
+ yield f"#{ prefix } { line .strip ()} \n "
546
579
547
- def _write_message (message , prefix = '' ):
580
+ def _format_message (message , prefix = '' ):
548
581
if isinstance (message .id , (list , tuple )):
549
582
if message .context :
550
- _write ( f"{ prefix } msgctxt { _normalize (message .context , prefix )} \n " )
551
- _write ( f"{ prefix } msgid { _normalize (message .id [0 ], prefix )} \n " )
552
- _write ( f"{ prefix } msgid_plural { _normalize (message .id [1 ], prefix )} \n " )
583
+ yield f"{ prefix } msgctxt { _normalize (message .context , prefix )} \n "
584
+ yield f"{ prefix } msgid { _normalize (message .id [0 ], prefix )} \n "
585
+ yield f"{ prefix } msgid_plural { _normalize (message .id [1 ], prefix )} \n "
553
586
554
587
for idx in range (catalog .num_plurals ):
555
588
try :
556
589
string = message .string [idx ]
557
590
except IndexError :
558
591
string = ''
559
- _write ( f"{ prefix } msgstr[{ idx :d} ] { _normalize (string , prefix )} \n " )
592
+ yield f"{ prefix } msgstr[{ idx :d} ] { _normalize (string , prefix )} \n "
560
593
else :
561
594
if message .context :
562
- _write (f"{ prefix } msgctxt { _normalize (message .context , prefix )} \n " )
563
- _write (f"{ prefix } msgid { _normalize (message .id , prefix )} \n " )
564
- _write (f"{ prefix } msgstr { _normalize (message .string or '' , prefix )} \n " )
565
-
566
- sort_by = None
567
- if sort_output :
568
- sort_by = "message"
569
- elif sort_by_file :
570
- sort_by = "location"
595
+ yield f"{ prefix } msgctxt { _normalize (message .context , prefix )} \n "
596
+ yield f"{ prefix } msgid { _normalize (message .id , prefix )} \n "
597
+ yield f"{ prefix } msgstr { _normalize (message .string or '' , prefix )} \n "
571
598
572
599
for message in _sort_messages (catalog , sort_by = sort_by ):
573
600
if not message .id : # This is the header "message"
@@ -580,12 +607,12 @@ def _write_message(message, prefix=''):
580
607
lines += wraptext (line , width = width ,
581
608
subsequent_indent = '# ' )
582
609
comment_header = '\n ' .join (lines )
583
- _write ( f"{ comment_header } \n " )
610
+ yield f"{ comment_header } \n "
584
611
585
612
for comment in message .user_comments :
586
- _write_comment (comment )
613
+ yield from _format_comment (comment )
587
614
for comment in message .auto_comments :
588
- _write_comment (comment , prefix = '.' )
615
+ yield from _format_comment (comment , prefix = '.' )
589
616
590
617
if not no_location :
591
618
locs = []
@@ -606,35 +633,34 @@ def _write_message(message, prefix=''):
606
633
location = f"{ location } :{ lineno :d} "
607
634
if location not in locs :
608
635
locs .append (location )
609
- _write_comment (' ' .join (locs ), prefix = ':' )
636
+ yield from _format_comment (' ' .join (locs ), prefix = ':' )
610
637
if message .flags :
611
- _write ( f"#{ ', ' .join (['' , * sorted (message .flags )])} \n " )
638
+ yield f"#{ ', ' .join (['' , * sorted (message .flags )])} \n "
612
639
613
640
if message .previous_id and include_previous :
614
- _write_comment (
641
+ yield from _format_comment (
615
642
f'msgid { _normalize (message .previous_id [0 ])} ' ,
616
643
prefix = '|' ,
617
644
)
618
645
if len (message .previous_id ) > 1 :
619
- _write_comment ('msgid_plural %s' % _normalize (
620
- message .previous_id [1 ],
621
- ), prefix = '|' )
646
+ norm_previous_id = _normalize (message .previous_id [1 ])
647
+ yield from _format_comment (f'msgid_plural { norm_previous_id } ' , prefix = '|' )
622
648
623
- _write_message (message )
624
- _write ( '\n ' )
649
+ yield from _format_message (message )
650
+ yield '\n '
625
651
626
652
if not ignore_obsolete :
627
653
for message in _sort_messages (
628
654
catalog .obsolete .values (),
629
655
sort_by = sort_by ,
630
656
):
631
657
for comment in message .user_comments :
632
- _write_comment (comment )
633
- _write_message (message , prefix = '#~ ' )
634
- _write ( '\n ' )
658
+ yield from _format_comment (comment )
659
+ yield from _format_message (message , prefix = '#~ ' )
660
+ yield '\n '
635
661
636
662
637
- def _sort_messages (messages : Iterable [Message ], sort_by : Literal ["message" , "location" ]) -> list [Message ]:
663
+ def _sort_messages (messages : Iterable [Message ], sort_by : Literal ["message" , "location" ] | None ) -> list [Message ]:
638
664
"""
639
665
Sort the given message iterable by the given criteria.
640
666
0 commit comments