Mercurial > babel > mirror
annotate babel/messages/pofile.py @ 586:46410022772a trunk
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
author | fschwarz |
---|---|
date | Mon, 06 Aug 2012 07:41:21 +0000 |
parents | 5c9dba5dd311 |
children |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
530 | 3 # Copyright (C) 2007-2011 Edgewall Software |
1 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
8 # are also available at http://babel.edgewall.org/wiki/License. | |
9 # | |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
12 # history and logs, available at http://babel.edgewall.org/log/. | |
13 | |
14 """Reading and writing of files in the ``gettext`` PO (portable object) | |
15 format. | |
16 | |
17 :see: `The Format of PO Files | |
18 <http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files>`_ | |
19 """ | |
20 | |
531 | 21 from datetime import datetime |
134 | 22 import os |
1 | 23 import re |
24 | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
25 from babel.messages.catalog import Catalog, Message |
531 | 26 from babel.util import wraptext |
1 | 27 |
178
749c0f6863bc
Minor change to what symbols are ?exported?, primarily for the generated docs.
cmlenz
parents:
175
diff
changeset
|
28 __all__ = ['read_po', 'write_po'] |
161 | 29 __docformat__ = 'restructuredtext en' |
158 | 30 |
31 def unescape(string): | |
32 r"""Reverse `escape` the given string. | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
33 |
158 | 34 >>> print unescape('"Say:\\n \\"hello, world!\\"\\n"') |
35 Say: | |
36 "hello, world!" | |
37 <BLANKLINE> | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
38 |
158 | 39 :param string: the string to unescape |
40 :return: the unescaped string | |
41 :rtype: `str` or `unicode` | |
42 """ | |
582 | 43 def replace_escapes(match): |
44 m = match.group(1) | |
45 if m == 'n': | |
46 return '\n' | |
47 elif m == 't': | |
48 return '\t' | |
49 elif m == 'r': | |
50 return '\r' | |
51 # m is \ or " | |
52 return m | |
53 return re.compile(r'\\([\\trn"])').sub(replace_escapes, string[1:-1]) | |
158 | 54 |
55 def denormalize(string): | |
56 r"""Reverse the normalization done by the `normalize` function. | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
57 |
158 | 58 >>> print denormalize(r'''"" |
59 ... "Say:\n" | |
60 ... " \"hello, world!\"\n"''') | |
61 Say: | |
62 "hello, world!" | |
63 <BLANKLINE> | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
64 |
158 | 65 >>> print denormalize(r'''"" |
66 ... "Say:\n" | |
67 ... " \"Lorem ipsum dolor sit " | |
68 ... "amet, consectetur adipisicing" | |
69 ... " elit, \"\n"''') | |
70 Say: | |
71 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " | |
72 <BLANKLINE> | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
73 |
158 | 74 :param string: the string to denormalize |
75 :return: the denormalized string | |
76 :rtype: `unicode` or `str` | |
77 """ | |
585
5c9dba5dd311
handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
fschwarz
parents:
582
diff
changeset
|
78 if '\n' in string: |
5c9dba5dd311
handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
fschwarz
parents:
582
diff
changeset
|
79 escaped_lines = string.splitlines() |
5c9dba5dd311
handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
fschwarz
parents:
582
diff
changeset
|
80 if string.startswith('""'): |
5c9dba5dd311
handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
fschwarz
parents:
582
diff
changeset
|
81 escaped_lines = escaped_lines[1:] |
5c9dba5dd311
handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
fschwarz
parents:
582
diff
changeset
|
82 lines = map(unescape, escaped_lines) |
158 | 83 return ''.join(lines) |
84 else: | |
85 return unescape(string) | |
1 | 86 |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
87 def read_po(fileobj, locale=None, domain=None, ignore_obsolete=False): |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
88 """Read messages from a ``gettext`` PO (portable object) file from the given |
64 | 89 file-like object and return a `Catalog`. |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
90 |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
91 >>> from StringIO import StringIO |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
92 >>> buf = StringIO(''' |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
93 ... #: main.py:1 |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
94 ... #, fuzzy, python-format |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
95 ... msgid "foo %(name)s" |
586
46410022772a
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
fschwarz
parents:
585
diff
changeset
|
96 ... msgstr "quux %(name)s" |
21
cd9aa202568e
Change pot header's first line, "Translations Template for %%(project)s." instead of "SOME DESCRIPTIVE TITLE.". '''`project`''' and '''`version`''' now default to '''PROJECT''' and '''VERSION''' respectively. Fixed a bug regarding '''Content-Transfer-Encoding''', it shouldn't be the charset, and we're defaulting to `8bit` untill someone complains.
palgarvio
parents:
17
diff
changeset
|
97 ... |
94
96037779b518
Updated `read_po` to add user comments besides just auto comments.
palgarvio
parents:
84
diff
changeset
|
98 ... # A user comment |
96037779b518
Updated `read_po` to add user comments besides just auto comments.
palgarvio
parents:
84
diff
changeset
|
99 ... #. An auto comment |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
100 ... #: main.py:3 |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
101 ... msgid "bar" |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
102 ... msgid_plural "baz" |
586
46410022772a
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
fschwarz
parents:
585
diff
changeset
|
103 ... msgstr[0] "bar" |
46410022772a
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
fschwarz
parents:
585
diff
changeset
|
104 ... msgstr[1] "baaz" |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
105 ... ''') |
64 | 106 >>> catalog = read_po(buf) |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
107 >>> catalog.revision_date = datetime(2007, 04, 01) |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
108 |
64 | 109 >>> for message in catalog: |
67 | 110 ... if message.id: |
111 ... print (message.id, message.string) | |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
112 ... print ' ', (message.locations, message.flags) |
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
113 ... print ' ', (message.user_comments, message.auto_comments) |
586
46410022772a
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
fschwarz
parents:
585
diff
changeset
|
114 (u'foo %(name)s', u'quux %(name)s') |
149
d62c63280e81
Respect charset specified in PO headers in `read_po()`. Fixes #17.
cmlenz
parents:
134
diff
changeset
|
115 ([(u'main.py', 1)], set([u'fuzzy', u'python-format'])) |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
116 ([], []) |
586
46410022772a
fix doctests on Python 2.4: In 2.4 re.sub(..., ..., u'') will return '' (str, not unicode) so just fill in some msgstr to avoid that problem
fschwarz
parents:
585
diff
changeset
|
117 ((u'bar', u'baz'), (u'bar', u'baaz')) |
149
d62c63280e81
Respect charset specified in PO headers in `read_po()`. Fixes #17.
cmlenz
parents:
134
diff
changeset
|
118 ([(u'main.py', 3)], set([])) |
d62c63280e81
Respect charset specified in PO headers in `read_po()`. Fixes #17.
cmlenz
parents:
134
diff
changeset
|
119 ([u'A user comment'], [u'An auto comment']) |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
120 |
1 | 121 :param fileobj: the file-like object to read the PO file from |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
122 :param locale: the locale identifier or `Locale` object, or `None` |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
123 if the catalog is not bound to a locale (which basically |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
124 means it's a template) |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
125 :param domain: the message domain |
227 | 126 :param ignore_obsolete: whether to ignore obsolete messages in the input |
334 | 127 :return: a catalog object representing the parsed PO file |
128 :rtype: `Catalog` | |
1 | 129 """ |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
130 catalog = Catalog(locale=locale, domain=domain) |
64 | 131 |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
132 counter = [0] |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
133 offset = [0] |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
134 messages = [] |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
135 translations = [] |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
136 locations = [] |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
137 flags = [] |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
138 user_comments = [] |
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
139 auto_comments = [] |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
140 obsolete = [False] |
335 | 141 context = [] |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
142 in_msgid = [False] |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
143 in_msgstr = [False] |
342
2ee7dc04836c
Fixed a bug in pofile (in_msgctxt was not defined). Test follows.
aronacher
parents:
335
diff
changeset
|
144 in_msgctxt = [False] |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
145 |
64 | 146 def _add_message(): |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
147 translations.sort() |
64 | 148 if len(messages) > 1: |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
149 msgid = tuple([denormalize(m) for m in messages]) |
64 | 150 else: |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
151 msgid = denormalize(messages[0]) |
370
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
152 if isinstance(msgid, (list, tuple)): |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
153 string = [] |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
154 for idx in range(catalog.num_plurals): |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
155 try: |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
156 string.append(translations[idx]) |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
157 except IndexError: |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
158 string.append((idx, '')) |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
159 string = tuple([denormalize(t[1]) for t in string]) |
64 | 160 else: |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
161 string = denormalize(translations[0][1]) |
335 | 162 if context: |
163 msgctxt = denormalize('\n'.join(context)) | |
164 else: | |
165 msgctxt = None | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
166 message = Message(msgid, string, list(locations), set(flags), |
335 | 167 auto_comments, user_comments, lineno=offset[0] + 1, |
168 context=msgctxt) | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
169 if obsolete[0]: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
170 if not ignore_obsolete: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
171 catalog.obsolete[msgid] = message |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
172 else: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
173 catalog[msgid] = message |
335 | 174 del messages[:]; del translations[:]; del context[:]; del locations[:]; |
175 del flags[:]; del auto_comments[:]; del user_comments[:]; | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
176 obsolete[0] = False |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
177 counter[0] += 1 |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
178 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
179 def _process_message_line(lineno, line): |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
180 if line.startswith('msgid_plural'): |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
181 in_msgid[0] = True |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
182 msg = line[12:].lstrip() |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
183 messages.append(msg) |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
184 elif line.startswith('msgid'): |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
185 in_msgid[0] = True |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
186 offset[0] = lineno |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
187 txt = line[5:].lstrip() |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
188 if messages: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
189 _add_message() |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
190 messages.append(txt) |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
191 elif line.startswith('msgstr'): |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
192 in_msgid[0] = False |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
193 in_msgstr[0] = True |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
194 msg = line[6:].lstrip() |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
195 if msg.startswith('['): |
441
942afedbb3d7
Make sure to only strip on the first occurence of ].
jruigrok
parents:
428
diff
changeset
|
196 idx, msg = msg[1:].split(']', 1) |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
197 translations.append([int(idx), msg.lstrip()]) |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
198 else: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
199 translations.append([0, msg]) |
335 | 200 elif line.startswith('msgctxt'): |
428
a974d298400f
Fix for msgctxt parsing in PO files. Thanks to Asheesh Laroia for the patch. Closes #159.
cmlenz
parents:
423
diff
changeset
|
201 if messages: |
a974d298400f
Fix for msgctxt parsing in PO files. Thanks to Asheesh Laroia for the patch. Closes #159.
cmlenz
parents:
423
diff
changeset
|
202 _add_message() |
335 | 203 in_msgid[0] = in_msgstr[0] = False |
204 context.append(line[7:].lstrip()) | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
205 elif line.startswith('"'): |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
206 if in_msgid[0]: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
207 messages[-1] += u'\n' + line.rstrip() |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
208 elif in_msgstr[0]: |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
209 translations[-1][1] += u'\n' + line.rstrip() |
335 | 210 elif in_msgctxt[0]: |
211 context.append(line.rstrip()) | |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
212 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
213 for lineno, line in enumerate(fileobj.readlines()): |
414
05487ae7696e
fix Python 2.3 compat: rearrange set/itemgetter/rsplit/sorted/unicode.decode
pjenvey
parents:
370
diff
changeset
|
214 line = line.strip() |
05487ae7696e
fix Python 2.3 compat: rearrange set/itemgetter/rsplit/sorted/unicode.decode
pjenvey
parents:
370
diff
changeset
|
215 if not isinstance(line, unicode): |
05487ae7696e
fix Python 2.3 compat: rearrange set/itemgetter/rsplit/sorted/unicode.decode
pjenvey
parents:
370
diff
changeset
|
216 line = line.decode(catalog.charset) |
1 | 217 if line.startswith('#'): |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
218 in_msgid[0] = in_msgstr[0] = False |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
219 if messages and translations: |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
220 _add_message() |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
221 if line[1:].startswith(':'): |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
222 for location in line[2:].lstrip().split(): |
356
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
223 pos = location.rfind(':') |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
224 if pos >= 0: |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
225 try: |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
226 lineno = int(location[pos + 1:]) |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
227 except ValueError: |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
228 continue |
4cdca48fc832
Fixed #59 by falling back silently on invalid location comments.
aronacher
parents:
342
diff
changeset
|
229 locations.append((location[:pos], lineno)) |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
230 elif line[1:].startswith(','): |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
231 for flag in line[2:].lstrip().split(','): |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
232 flags.append(flag.strip()) |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
233 elif line[1:].startswith('~'): |
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
234 obsolete[0] = True |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
235 _process_message_line(lineno, line[2:].lstrip()) |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
236 elif line[1:].startswith('.'): |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
237 # These are called auto-comments |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
238 comment = line[2:].strip() |
199
a0d22f2f2df0
Handle obsolete messages when parsing catalogs. Closes #32.
cmlenz
parents:
196
diff
changeset
|
239 if comment: # Just check that we're not adding empty comments |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
240 auto_comments.append(comment) |
120 | 241 else: |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
242 # These are called user comments |
120 | 243 user_comments.append(line[1:].strip()) |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
244 else: |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
203
diff
changeset
|
245 _process_message_line(lineno, line) |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
246 |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
247 if messages: |
64 | 248 _add_message() |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
249 |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
250 # No actual messages found, but there was some info in comments, from which |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
251 # we'll construct an empty header message |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
252 elif not counter[0] and (flags or user_comments or auto_comments): |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
253 messages.append(u'') |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
254 translations.append([0, u'']) |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
255 _add_message() |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
191
diff
changeset
|
256 |
64 | 257 return catalog |
1 | 258 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
259 WORD_SEP = re.compile('(' |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
260 r'\s+|' # any whitespace |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
261 r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
262 r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w)' # em-dash |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
263 ')') |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
264 |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
265 def escape(string): |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
266 r"""Escape the given string so that it can be included in double-quoted |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
267 strings in ``PO`` files. |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
268 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
269 >>> escape('''Say: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
270 ... "hello, world!" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
271 ... ''') |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
272 '"Say:\\n \\"hello, world!\\"\\n"' |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
273 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
274 :param string: the string to escape |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
275 :return: the escaped string |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
276 :rtype: `str` or `unicode` |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
277 """ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
278 return '"%s"' % string.replace('\\', '\\\\') \ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
279 .replace('\t', '\\t') \ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
280 .replace('\r', '\\r') \ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
281 .replace('\n', '\\n') \ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
282 .replace('\"', '\\"') |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
283 |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
284 def normalize(string, prefix='', width=76): |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
285 r"""Convert a string into a format that is appropriate for .po files. |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
286 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
287 >>> print normalize('''Say: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
288 ... "hello, world!" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
289 ... ''', width=None) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
290 "" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
291 "Say:\n" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
292 " \"hello, world!\"\n" |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
293 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
294 >>> print normalize('''Say: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
295 ... "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
296 ... ''', width=32) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
297 "" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
298 "Say:\n" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
299 " \"Lorem ipsum dolor sit " |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
300 "amet, consectetur adipisicing" |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
301 " elit, \"\n" |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
302 |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
303 :param string: the string to normalize |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
304 :param prefix: a string that should be prepended to every line |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
305 :param width: the maximum line width; use `None`, 0, or a negative number |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
306 to completely disable line wrapping |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
307 :return: the normalized string |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
308 :rtype: `unicode` |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
309 """ |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
310 if width and width > 0: |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
311 prefixlen = len(prefix) |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
312 lines = [] |
568 | 313 for line in string.splitlines(True): |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
314 if len(escape(line)) + prefixlen > width: |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
315 chunks = WORD_SEP.split(line) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
316 chunks.reverse() |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
317 while chunks: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
318 buf = [] |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
319 size = 2 |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
320 while chunks: |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
321 l = len(escape(chunks[-1])) - 2 + prefixlen |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
322 if size + l < width: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
323 buf.append(chunks.pop()) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
324 size += l |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
325 else: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
326 if not buf: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
327 # handle long chunks by putting them on a |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
328 # separate line |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
329 buf.append(chunks.pop()) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
330 break |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
331 lines.append(u''.join(buf)) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
332 else: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
333 lines.append(line) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
334 else: |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
335 lines = string.splitlines(True) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
336 |
67 | 337 if len(lines) <= 1: |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
338 return escape(string) |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
339 |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
340 # Remove empty trailing line |
67 | 341 if lines and not lines[-1]: |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
342 del lines[-1] |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
343 lines[-1] += '\n' |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
344 return u'""\n' + u'\n'.join([(prefix + escape(l)) for l in lines]) |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
345 |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
346 def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False, |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
347 sort_output=False, sort_by_file=False, ignore_obsolete=False, |
203 | 348 include_previous=False): |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
349 r"""Write a ``gettext`` PO (portable object) template file for a given |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
350 message catalog to the provided file-like object. |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
351 |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
352 >>> catalog = Catalog() |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
353 >>> catalog.add(u'foo %(name)s', locations=[('main.py', 1)], |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
354 ... flags=('fuzzy',)) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
531
diff
changeset
|
355 <Message...> |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
356 >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
531
diff
changeset
|
357 <Message...> |
1 | 358 >>> from StringIO import StringIO |
359 >>> buf = StringIO() | |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
360 >>> write_po(buf, catalog, omit_header=True) |
1 | 361 >>> print buf.getvalue() |
362 #: main.py:1 | |
6
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
363 #, fuzzy, python-format |
c3b1b0b3d129
Add basic PO file parsing, and change the PO writing procedure to also take flags (such as "python-format" or "fuzzy").
cmlenz
parents:
5
diff
changeset
|
364 msgid "foo %(name)s" |
1 | 365 msgstr "" |
366 <BLANKLINE> | |
367 #: main.py:3 | |
368 msgid "bar" | |
369 msgid_plural "baz" | |
370 msgstr[0] "" | |
371 msgstr[1] "" | |
372 <BLANKLINE> | |
373 <BLANKLINE> | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
374 |
1 | 375 :param fileobj: the file-like object to write to |
67 | 376 :param catalog: the `Catalog` instance |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
377 :param width: the maximum line width for the generated output; use `None`, |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
378 0, or a negative number to completely disable line wrapping |
1 | 379 :param no_location: do not emit a location comment for every message |
380 :param omit_header: do not include the ``msgid ""`` entry at the top of the | |
381 output | |
227 | 382 :param sort_output: whether to sort the messages in the output by msgid |
383 :param sort_by_file: whether to sort the messages in the output by their | |
384 locations | |
385 :param ignore_obsolete: whether to ignore obsolete messages and not include | |
386 them in the output; by default they are included as | |
387 comments | |
203 | 388 :param include_previous: include the old msgid as a comment when |
229 | 389 updating the catalog |
1 | 390 """ |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
391 def _normalize(key, prefix=''): |
547
1631d555d7e4
babel.messages.pofile should only apply encoding when actually writing a file (eases Python 3 transition, closes #251)
fschwarz
parents:
544
diff
changeset
|
392 return normalize(key, prefix=prefix, width=width) |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
393 |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
394 def _write(text): |
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
395 if isinstance(text, unicode): |
547
1631d555d7e4
babel.messages.pofile should only apply encoding when actually writing a file (eases Python 3 transition, closes #251)
fschwarz
parents:
544
diff
changeset
|
396 text = text.encode(catalog.charset, 'backslashreplace') |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
397 fileobj.write(text) |
1 | 398 |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
399 def _write_comment(comment, prefix=''): |
423
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
400 # xgettext always wraps comments even if --no-wrap is passed; |
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
401 # provide the same behaviour |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
402 if width and width > 0: |
423
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
403 _width = width |
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
404 else: |
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
405 _width = 76 |
fb926f48efba
Now, the `--width` option, although with a default value of 76, it's not set to any value initially so that the `--no-wrap` option can be passed without throwing an error. Fixes #145.
palgarvio
parents:
421
diff
changeset
|
406 for line in wraptext(comment, _width): |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
407 _write('#%s %s\n' % (prefix, line.strip())) |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
408 |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
409 def _write_message(message, prefix=''): |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
410 if isinstance(message.id, (list, tuple)): |
421 | 411 if message.context: |
412 _write('%smsgctxt %s\n' % (prefix, | |
413 _normalize(message.context, prefix))) | |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
414 _write('%smsgid %s\n' % (prefix, _normalize(message.id[0], prefix))) |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
415 _write('%smsgid_plural %s\n' % ( |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
416 prefix, _normalize(message.id[1], prefix) |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
417 )) |
370
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
418 |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
419 for idx in range(catalog.num_plurals): |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
420 try: |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
421 string = message.string[idx] |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
422 except IndexError: |
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
423 string = '' |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
424 _write('%smsgstr[%d] %s\n' % ( |
370
bc18179832b7
We no longer neglect `catalog.plurals`. Added tests for it. Fixes #120.
palgarvio
parents:
356
diff
changeset
|
425 prefix, idx, _normalize(string, prefix) |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
426 )) |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
427 else: |
421 | 428 if message.context: |
429 _write('%smsgctxt %s\n' % (prefix, | |
430 _normalize(message.context, prefix))) | |
190
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
431 _write('%smsgid %s\n' % (prefix, _normalize(message.id, prefix))) |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
432 _write('%smsgstr %s\n' % ( |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
433 prefix, _normalize(message.string or '', prefix) |
5041d90edf0c
Correctly write out obsolete messages spanning multiple lines. Fixes #33.
cmlenz
parents:
181
diff
changeset
|
434 )) |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
435 |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
436 messages = list(catalog) |
71 | 437 if sort_output: |
248
f0b1ee94628c
add a __cmp__ to Message that correctly sorts by id, taking into account plurals
pjenvey
parents:
229
diff
changeset
|
438 messages.sort() |
71 | 439 elif sort_by_file: |
440 messages.sort(lambda x,y: cmp(x.locations, y.locations)) | |
68 | 441 |
71 | 442 for message in messages: |
67 | 443 if not message.id: # This is the header "message" |
444 if omit_header: | |
445 continue | |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
446 comment_header = catalog.header_comment |
103
dacfbaf0d1e0
Implement wrapping of header comments in PO(T) output. Related to #14.
cmlenz
parents:
102
diff
changeset
|
447 if width and width > 0: |
dacfbaf0d1e0
Implement wrapping of header comments in PO(T) output. Related to #14.
cmlenz
parents:
102
diff
changeset
|
448 lines = [] |
104
395704fda00b
Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
cmlenz
parents:
103
diff
changeset
|
449 for line in comment_header.splitlines(): |
315 | 450 lines += wraptext(line, width=width, |
451 subsequent_indent='# ') | |
581 | 452 comment_header = u'\n'.join(lines) |
453 _write(comment_header + u'\n') | |
102
14a3d766a701
Project name and version, and the charset are available via the `Catalog` object, and do not need to be passed to `write_pot()`.
cmlenz
parents:
97
diff
changeset
|
454 |
227 | 455 for comment in message.user_comments: |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
456 _write_comment(comment) |
227 | 457 for comment in message.auto_comments: |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
458 _write_comment(comment, prefix='.') |
1 | 459 |
460 if not no_location: | |
134 | 461 locs = u' '.join([u'%s:%d' % (filename.replace(os.sep, '/'), lineno) |
462 for filename, lineno in message.locations]) | |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
463 _write_comment(locs, prefix=':') |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
464 if message.flags: |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
55
diff
changeset
|
465 _write('#%s\n' % ', '.join([''] + list(message.flags))) |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
466 |
203 | 467 if message.previous_id and include_previous: |
309
43dca73da5b5
Fix for unicode problem when the previous message id is included as a comment in PO serialization. Closes #78.
cmlenz
parents:
248
diff
changeset
|
468 _write_comment('msgid %s' % _normalize(message.previous_id[0]), |
203 | 469 prefix='|') |
470 if len(message.previous_id) > 1: | |
309
43dca73da5b5
Fix for unicode problem when the previous message id is included as a comment in PO serialization. Closes #78.
cmlenz
parents:
248
diff
changeset
|
471 _write_comment('msgid_plural %s' % _normalize( |
203 | 472 message.previous_id[1] |
473 ), prefix='|') | |
200
1c778cccd330
Added `--no-fuzzy-matching` to the frontends and also `--previous` which adds the old msgid's as comments. The latest closes #31.
palgarvio
parents:
199
diff
changeset
|
474 |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
475 _write_message(message) |
24
b09e90803d1b
Reimplement line wrapping for PO writing (as the `textwrap` module is too destructive with white space) and move it to the `normalize` function (which was already doing some handling of line breaks).
cmlenz
parents:
23
diff
changeset
|
476 _write('\n') |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
178
diff
changeset
|
477 |
191
c171a0041ad2
Add an option to the frontend commands for catalog updating that removes completely any obsolete messages, instead of putting them comments.
cmlenz
parents:
190
diff
changeset
|
478 if not ignore_obsolete: |
c171a0041ad2
Add an option to the frontend commands for catalog updating that removes completely any obsolete messages, instead of putting them comments.
cmlenz
parents:
190
diff
changeset
|
479 for message in catalog.obsolete.values(): |
227 | 480 for comment in message.user_comments: |
191
c171a0041ad2
Add an option to the frontend commands for catalog updating that removes completely any obsolete messages, instead of putting them comments.
cmlenz
parents:
190
diff
changeset
|
481 _write_comment(comment) |
c171a0041ad2
Add an option to the frontend commands for catalog updating that removes completely any obsolete messages, instead of putting them comments.
cmlenz
parents:
190
diff
changeset
|
482 _write_message(message, prefix='#~ ') |
c171a0041ad2
Add an option to the frontend commands for catalog updating that removes completely any obsolete messages, instead of putting them comments.
cmlenz
parents:
190
diff
changeset
|
483 _write('\n') |