def _write_comment(comment, prefix=''): # xgettext always wraps comments even if --no-wrap is passed; # provide the same behaviour if width and width > 0: _width = width else: _width = 76 for line in wraptext(comment, _width): _write('#%s %s\n' % (prefix, line.strip()))
def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False, sort_output=False, sort_by_file=False, ignore_obsolete=False, include_previous=False, include_lineno=True): r"""Write a ``gettext`` PO (portable object) template file for a given message catalog to the provided file-like object. >>> catalog = Catalog() >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)], ... flags=('fuzzy',)) <Message...> >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)]) <Message...> >>> from io import BytesIO >>> buf = BytesIO() >>> write_po(buf, catalog, omit_header=True) >>> print(buf.getvalue().decode("utf8")) #: main.py:1 #, fuzzy, python-format msgid "foo %(name)s" msgstr "" <BLANKLINE> #: main.py:3 msgid "bar" msgid_plural "baz" msgstr[0] "" msgstr[1] "" <BLANKLINE> <BLANKLINE> :param fileobj: the file-like object to write to :param catalog: the `Catalog` instance :param width: the maximum line width for the generated output; use `None`, 0, or a negative number to completely disable line wrapping :param no_location: do not emit a location comment for every message :param omit_header: do not include the ``msgid ""`` entry at the top of the output :param sort_output: whether to sort the messages in the output by msgid :param sort_by_file: whether to sort the messages in the output by their locations :param ignore_obsolete: whether to ignore obsolete messages and not include them in the output; by default they are included as comments :param include_previous: include the old msgid as a comment when updating the catalog :param include_lineno: include line number in the location comment """ def _normalize(key, prefix=''): return normalize(key, prefix=prefix, width=width) def _write(text): if isinstance(text, str): text = text.encode(catalog.charset, 'backslashreplace') fileobj.write(text) def _write_comment(comment, prefix=''): # xgettext always wraps comments even if --no-wrap is passed; # provide the same behaviour if width and width > 0: _width = width else: _width = 76 for line in wraptext(comment, _width): _write('#%s %s\n' % (prefix, line.strip())) def _write_message(message, prefix=''): if isinstance(message.id, (list, tuple)): if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id[0], prefix))) _write('%smsgid_plural %s\n' % (prefix, _normalize(message.id[1], prefix))) for idx in range(catalog.num_plurals): try: string = message.string[idx] except IndexError: string = '' _write('%smsgstr[%d] %s\n' % (prefix, idx, _normalize(string, prefix))) else: if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id, prefix))) _write('%smsgstr %s\n' % (prefix, _normalize(message.string or '', prefix))) sort_by = None if sort_output: sort_by = "message" elif sort_by_file: sort_by = "location" for message in _sort_messages(catalog, sort_by=sort_by): if not message.id: # This is the header "message" if omit_header: continue comment_header = catalog.header_comment if width and width > 0: lines = [] for line in comment_header.splitlines(): lines += wraptext(line, width=width, subsequent_indent='# ') comment_header = u'\n'.join(lines) _write(comment_header + u'\n') for comment in message.user_comments: _write_comment(comment) for comment in message.auto_comments: _write_comment(comment, prefix='.') if not no_location: locs = [] # sort locations by filename and lineno. # if there's no <int> as lineno, use `-1`. # if no sorting possible, leave unsorted. # (see issue #606) try: locations = sorted( message.locations, key=lambda x: (x[0], isinstance(x[1], int) and x[1] or -1)) except TypeError: # e.g. "TypeError: unorderable types: NoneType() < int()" locations = message.locations for filename, lineno in locations: if lineno and include_lineno: locs.append(u'%s:%d' % (filename.replace(os.sep, '/'), lineno)) else: locs.append(u'%s' % filename.replace(os.sep, '/')) _write_comment(' '.join(locs), prefix=':') if message.flags: _write('#%s\n' % ', '.join([''] + sorted(message.flags))) if message.previous_id and include_previous: _write_comment('msgid %s' % _normalize(message.previous_id[0]), prefix='|') if len(message.previous_id) > 1: _write_comment('msgid_plural %s' % _normalize(message.previous_id[1]), prefix='|') _write_message(message) _write('\n') if not ignore_obsolete: for message in _sort_messages(catalog.obsolete.values(), sort_by=sort_by): for comment in message.user_comments: _write_comment(comment) _write_message(message, prefix='#~ ') _write('\n')
def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False, sort_output=False, sort_by_file=False, ignore_obsolete=False, include_previous=False): r"""Write a ``gettext`` PO (portable object) template file for a given message catalog to the provided file-like object. >>> catalog = Catalog() >>> catalog.add(u('foo %(name)s'), locations=[('main.py', 1)], ... flags=('fuzzy',)) <Message...> >>> catalog.add((u('bar'), u('baz')), locations=[('main.py', 3)]) <Message...> >>> from babel.compat import BytesIO >>> buf = BytesIO() >>> write_po(buf, catalog, omit_header=True) >>> print(buf.getvalue().decode('latin-1')) #: main.py:1 #, fuzzy, python-format msgid "foo %(name)s" msgstr "" <BLANKLINE> #: main.py:3 msgid "bar" msgid_plural "baz" msgstr[0] "" msgstr[1] "" <BLANKLINE> <BLANKLINE> :param fileobj: the file-like object to write to :param catalog: the `Catalog` instance :param width: the maximum line width for the generated output; use `None`, 0, or a negative number to completely disable line wrapping :param no_location: do not emit a location comment for every message :param omit_header: do not include the ``msgid ""`` entry at the top of the output :param sort_output: whether to sort the messages in the output by msgid :param sort_by_file: whether to sort the messages in the output by their locations :param ignore_obsolete: whether to ignore obsolete messages and not include them in the output; by default they are included as comments :param include_previous: include the old msgid as a comment when updating the catalog """ def _normalize(key, prefix=''): return normalize(key, prefix=prefix, width=width) def _write(text): if isinstance(text, text_type): text = text.encode(catalog.charset, 'backslashreplace') fileobj.write(text) def _write_comment(comment, prefix=''): # xgettext always wraps comments even if --no-wrap is passed; # provide the same behaviour if width and width > 0: _width = width else: _width = 76 for line in wraptext(comment, _width): _write('#%s %s\n' % (prefix, line.strip())) def _write_message(message, prefix=''): if isinstance(message.id, (list, tuple)): if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id[0], prefix))) _write('%smsgid_plural %s\n' % (prefix, _normalize(message.id[1], prefix))) for idx in range(catalog.num_plurals): try: string = message.string[idx] except IndexError: string = '' _write('%smsgstr[%d] %s\n' % (prefix, idx, _normalize(string, prefix))) else: if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id, prefix))) _write('%smsgstr %s\n' % (prefix, _normalize(message.string or '', prefix))) messages = list(catalog) if sort_output: messages.sort() elif sort_by_file: messages.sort(lambda x, y: cmp(x.locations, y.locations)) for message in messages: if not message.id: # This is the header "message" if omit_header: continue comment_header = catalog.header_comment if width and width > 0: lines = [] for line in comment_header.splitlines(): lines += wraptext(line, width=width, subsequent_indent='# ') comment_header = u('\n').join(lines) + u('\n') _write(comment_header) for comment in message.user_comments: _write_comment(comment) for comment in message.auto_comments: _write_comment(comment, prefix='.') if not no_location: locs = u(' ').join([ u('%s:%d') % (filename.replace(os.sep, '/'), lineno) for filename, lineno in message.locations ]) _write_comment(locs, prefix=':') if message.flags: _write('#%s\n' % ', '.join([''] + list(message.flags))) if message.previous_id and include_previous: _write_comment('msgid %s' % _normalize(message.previous_id[0]), prefix='|') if len(message.previous_id) > 1: _write_comment('msgid_plural %s' % _normalize(message.previous_id[1]), prefix='|') _write_message(message) _write('\n') if not ignore_obsolete: for message in catalog.obsolete.values(): for comment in message.user_comments: _write_comment(comment) _write_message(message, prefix='#~ ') _write('\n')
def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False, sort_output=False, sort_by_file=False, ignore_obsolete=False, include_previous=False): r"""Write a ``gettext`` PO (portable object) template file for a given message catalog to the provided file-like object. >>> catalog = Catalog() >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)], ... flags=('fuzzy',)) <Message...> >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)]) <Message...> >>> from io import BytesIO >>> buf = BytesIO() >>> write_po(buf, catalog, omit_header=True) >>> print buf.getvalue() #: main.py:1 #, fuzzy, python-format msgid "foo %(name)s" msgstr "" <BLANKLINE> #: main.py:3 msgid "bar" msgid_plural "baz" msgstr[0] "" msgstr[1] "" <BLANKLINE> <BLANKLINE> :param fileobj: the file-like object to write to :param catalog: the `Catalog` instance :param width: the maximum line width for the generated output; use `None`, 0, or a negative number to completely disable line wrapping :param no_location: do not emit a location comment for every message :param omit_header: do not include the ``msgid ""`` entry at the top of the output :param sort_output: whether to sort the messages in the output by msgid :param sort_by_file: whether to sort the messages in the output by their locations :param ignore_obsolete: whether to ignore obsolete messages and not include them in the output; by default they are included as comments :param include_previous: include the old msgid as a comment when updating the catalog """ def _normalize(key, prefix=''): return normalize(key, prefix=prefix, width=width) def _write(text): if isinstance(text, text_type): text = text.encode(catalog.charset, 'backslashreplace') fileobj.write(text) def _write_comment(comment, prefix=''): # xgettext always wraps comments even if --no-wrap is passed; # provide the same behaviour if width and width > 0: _width = width else: _width = 76 for line in wraptext(comment, _width): _write('#%s %s\n' % (prefix, line.strip())) def _write_message(message, prefix=''): if isinstance(message.id, (list, tuple)): if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id[0], prefix))) _write('%smsgid_plural %s\n' % ( prefix, _normalize(message.id[1], prefix) )) for idx in range(catalog.num_plurals): try: string = message.string[idx] except IndexError: string = '' _write('%smsgstr[%d] %s\n' % ( prefix, idx, _normalize(string, prefix) )) else: if message.context: _write('%smsgctxt %s\n' % (prefix, _normalize(message.context, prefix))) _write('%smsgid %s\n' % (prefix, _normalize(message.id, prefix))) _write('%smsgstr %s\n' % ( prefix, _normalize(message.string or '', prefix) )) messages = list(catalog) if sort_output: messages.sort() elif sort_by_file: messages.sort(lambda x,y: cmp(x.locations, y.locations)) for message in messages: if not message.id: # This is the header "message" if omit_header: continue comment_header = catalog.header_comment if width and width > 0: lines = [] for line in comment_header.splitlines(): lines += wraptext(line, width=width, subsequent_indent='# ') comment_header = u'\n'.join(lines) _write(comment_header + u'\n') for comment in message.user_comments: _write_comment(comment) for comment in message.auto_comments: _write_comment(comment, prefix='.') if not no_location: locs = u' '.join([u'%s:%d' % (filename.replace(os.sep, '/'), lineno) for filename, lineno in message.locations]) _write_comment(locs, prefix=':') if message.flags: _write('#%s\n' % ', '.join([''] + sorted(message.flags))) if message.previous_id and include_previous: _write_comment('msgid %s' % _normalize(message.previous_id[0]), prefix='|') if len(message.previous_id) > 1: _write_comment('msgid_plural %s' % _normalize( message.previous_id[1] ), prefix='|') _write_message(message) _write('\n') if not ignore_obsolete: for message in catalog.obsolete.values(): for comment in message.user_comments: _write_comment(comment) _write_message(message, prefix='#~ ') _write('\n')
def _write_comment(comment, prefix=''): lines = comment if width and width > 0: lines = wraptext(comment, width) for line in lines: _write('#%s %s\n' % (prefix, line.strip()))