Mercurial > babel > mirror
annotate babel/messages/catalog.py @ 579:99d51589c822 trunk
use decorators (as we require Python 2.4+ anyway)
author | fschwarz |
---|---|
date | Tue, 31 Jul 2012 08:46:19 +0000 |
parents | b0e80df660ab |
children | c5dd3752bf2a |
rev | line source |
---|---|
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
1 # -*- coding: utf-8 -*- |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
2 # |
530 | 3 # Copyright (C) 2007-2011 Edgewall Software |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
4 # All rights reserved. |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
5 # |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
6 # This software is licensed as described in the file COPYING, which |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
7 # you should have received as part of this distribution. The terms |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
8 # are also available at http://babel.edgewall.org/wiki/License. |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
9 # |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
10 # This software consists of voluntary contributions made by many |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
11 # individuals. For the exact contribution history, see the revision |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
12 # history and logs, available at http://babel.edgewall.org/log/. |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
13 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
14 """Data structures for message catalogs.""" |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
15 |
149
d62c63280e81
Respect charset specified in PO headers in `read_po()`. Fixes #17.
cmlenz
parents:
131
diff
changeset
|
16 from cgi import parse_header |
67 | 17 from datetime import datetime |
165
628bc271ece4
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
163
diff
changeset
|
18 from difflib import get_close_matches |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
19 from email import message_from_string |
358
8f06f485a0f1
Message.clone doesn't return a shallow copy any longer. This fixes a bug with update where flags where shared.
aronacher
parents:
355
diff
changeset
|
20 from copy import copy |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
21 import re |
67 | 22 import time |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
23 |
67 | 24 from babel import __version__ as VERSION |
64 | 25 from babel.core import Locale |
131
6a284ad6c8ba
Use `dates.format_datetime` for dates in PO(T) header, as `datetime.strftime` produces wrong results on windows.
cmlenz
parents:
121
diff
changeset
|
26 from babel.dates import format_datetime |
373
b539ade22791
Added babel.messages.plurals.get_plural which returns a special tuple with the plural information.
aronacher
parents:
358
diff
changeset
|
27 from babel.messages.plurals import get_plural |
525
2baa2cedd6f9
Cleanup round #1: get rid of the frozenset/set utility code and imports.
jruigrok
parents:
478
diff
changeset
|
28 from babel.util import odict, distinct, LOCALTZ, UTC, FixedOffsetTimezone |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
29 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
30 __all__ = ['Message', 'Catalog', 'TranslationError'] |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
31 __docformat__ = 'restructuredtext en' |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
32 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
33 |
354 | 34 PYTHON_FORMAT = re.compile(r'''(?x) |
35 \% | |
36 (?:\(([\w]*)\))? | |
37 ( | |
38 [-#0\ +]?(?:\*|[\d]+)? | |
39 (?:\.(?:\*|[\d]+))? | |
40 [hlL]? | |
41 ) | |
42 ([diouxXeEfFgGcrs%]) | |
43 ''') | |
44 | |
45 | |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
46 class Message(object): |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
47 """Representation of a single message in a catalog.""" |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
48 |
149
d62c63280e81
Respect charset specified in PO headers in `read_po()`. Fixes #17.
cmlenz
parents:
131
diff
changeset
|
49 def __init__(self, id, string=u'', locations=(), flags=(), auto_comments=(), |
335 | 50 user_comments=(), previous_id=(), lineno=None, context=None): |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
51 """Create the message 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:
198
diff
changeset
|
52 |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
53 :param id: the message ID, or a ``(singular, plural)`` tuple for |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
54 pluralizable messages |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
55 :param string: the translated message string, or a |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
56 ``(singular, plural)`` tuple for pluralizable messages |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
57 :param locations: a sequence of ``(filenname, lineno)`` tuples |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
58 :param flags: a set or sequence of flags |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
59 :param auto_comments: a sequence of automatic comments for the message |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
60 :param user_comments: a sequence of user comments for the message |
203 | 61 :param previous_id: the previous message ID, or a ``(singular, plural)`` |
62 tuple for pluralizable messages | |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
63 :param lineno: the line number on which the msgid line was found in the |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
64 PO file, if any |
335 | 65 :param context: the message context |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
66 """ |
107 | 67 self.id = id #: The message ID |
68 | 68 if not string and self.pluralizable: |
69 string = (u'', u'') | |
107 | 70 self.string = string #: The message translation |
229 | 71 self.locations = list(distinct(locations)) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
72 self.flags = set(flags) |
67 | 73 if id and self.python_format: |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
74 self.flags.add('python-format') |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
75 else: |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
76 self.flags.discard('python-format') |
227 | 77 self.auto_comments = list(distinct(auto_comments)) |
78 self.user_comments = list(distinct(user_comments)) | |
203 | 79 if isinstance(previous_id, basestring): |
80 self.previous_id = [previous_id] | |
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:
198
diff
changeset
|
81 else: |
203 | 82 self.previous_id = list(previous_id) |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
83 self.lineno = lineno |
335 | 84 self.context = context |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
85 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
86 def __repr__(self): |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
87 return '<%s %r (flags: %r)>' % (type(self).__name__, self.id, |
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
88 list(self.flags)) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
89 |
248
f0b1ee94628c
add a __cmp__ to Message that correctly sorts by id, taking into account plurals
pjenvey
parents:
229
diff
changeset
|
90 def __cmp__(self, obj): |
f0b1ee94628c
add a __cmp__ to Message that correctly sorts by id, taking into account plurals
pjenvey
parents:
229
diff
changeset
|
91 """Compare Messages, taking into account plural ids""" |
565 | 92 def values_to_compare(): |
93 if isinstance(obj, Message): | |
94 plural = self.pluralizable | |
95 obj_plural = obj.pluralizable | |
96 if plural and obj_plural: | |
97 return self.id[0], obj.id[0] | |
98 elif plural: | |
99 return self.id[0], obj.id | |
100 elif obj_plural: | |
101 return self.id, obj.id[0] | |
102 return self.id, obj.id | |
103 this, other = values_to_compare() | |
104 return cmp(this, other) | |
248
f0b1ee94628c
add a __cmp__ to Message that correctly sorts by id, taking into account plurals
pjenvey
parents:
229
diff
changeset
|
105 |
564
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
106 def __gt__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
107 return self.__cmp__(other) > 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
108 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
109 def __lt__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
110 return self.__cmp__(other) < 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
111 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
112 def __ge__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
113 return self.__cmp__(other) >= 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
114 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
115 def __le__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
116 return self.__cmp__(other) <= 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
117 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
118 def __eq__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
119 return self.__cmp__(other) == 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
120 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
121 def __ne__(self, other): |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
122 return self.__cmp__(other) != 0 |
1ef087352e01
add more comparison methods to babel.messages.Catalog to ease the Python 3 transition
fschwarz
parents:
545
diff
changeset
|
123 |
313
ac8450a20e32
Merging catalogs would sometimes mix translations from different runs.
cmlenz
parents:
312
diff
changeset
|
124 def clone(self): |
358
8f06f485a0f1
Message.clone doesn't return a shallow copy any longer. This fixes a bug with update where flags where shared.
aronacher
parents:
355
diff
changeset
|
125 return Message(*map(copy, (self.id, self.string, self.locations, |
8f06f485a0f1
Message.clone doesn't return a shallow copy any longer. This fixes a bug with update where flags where shared.
aronacher
parents:
355
diff
changeset
|
126 self.flags, self.auto_comments, |
8f06f485a0f1
Message.clone doesn't return a shallow copy any longer. This fixes a bug with update where flags where shared.
aronacher
parents:
355
diff
changeset
|
127 self.user_comments, self.previous_id, |
8f06f485a0f1
Message.clone doesn't return a shallow copy any longer. This fixes a bug with update where flags where shared.
aronacher
parents:
355
diff
changeset
|
128 self.lineno, self.context))) |
313
ac8450a20e32
Merging catalogs would sometimes mix translations from different runs.
cmlenz
parents:
312
diff
changeset
|
129 |
355
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
130 def check(self, catalog=None): |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
131 """Run various validation checks on the message. Some validations |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
132 are only performed if the catalog is provided. This method returns |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
133 a sequence of `TranslationError` objects. |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
134 |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
135 :rtype: ``iterator`` |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
136 :param catalog: A catalog instance that is passed to the checkers |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
137 :see: `Catalog.check` for a way to perform checks for all messages |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
138 in a catalog. |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
139 """ |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
140 from babel.messages.checkers import checkers |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
141 errors = [] |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
142 for checker in checkers: |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
143 try: |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
144 checker(catalog, self) |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
145 except TranslationError, e: |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
146 errors.append(e) |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
147 return errors |
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
148 |
579 | 149 @property |
67 | 150 def fuzzy(self): |
579 | 151 """Whether the translation is fuzzy. |
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:
198
diff
changeset
|
152 |
67 | 153 >>> Message('foo').fuzzy |
154 False | |
175
5d32098d8352
Changed the `__repr__` output to include the flags(it can be changed back, but it was usefull to implement the fuzzy header parsing).
palgarvio
parents:
165
diff
changeset
|
155 >>> msg = Message('foo', 'foo', flags=['fuzzy']) |
5d32098d8352
Changed the `__repr__` output to include the flags(it can be changed back, but it was usefull to implement the fuzzy header parsing).
palgarvio
parents:
165
diff
changeset
|
156 >>> msg.fuzzy |
67 | 157 True |
175
5d32098d8352
Changed the `__repr__` output to include the flags(it can be changed back, but it was usefull to implement the fuzzy header parsing).
palgarvio
parents:
165
diff
changeset
|
158 >>> msg |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
159 <Message 'foo' (flags: ['fuzzy'])> |
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:
198
diff
changeset
|
160 |
579 | 161 :type: `bool`""" |
162 return 'fuzzy' in self.flags | |
67 | 163 |
579 | 164 @property |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
165 def pluralizable(self): |
579 | 166 """Whether the message is plurizable. |
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:
198
diff
changeset
|
167 |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
168 >>> Message('foo').pluralizable |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
169 False |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
170 >>> Message(('foo', 'bar')).pluralizable |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
171 True |
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:
198
diff
changeset
|
172 |
579 | 173 :type: `bool`""" |
174 return isinstance(self.id, (list, tuple)) | |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
175 |
579 | 176 @property |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
177 def python_format(self): |
579 | 178 """Whether the message contains Python-style parameters. |
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:
198
diff
changeset
|
179 |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
180 >>> Message('foo %(name)s bar').python_format |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
181 True |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
182 >>> Message(('foo %(name)s', 'foo %(name)s')).python_format |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
183 True |
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:
198
diff
changeset
|
184 |
579 | 185 :type: `bool`""" |
186 ids = self.id | |
187 if not isinstance(ids, (list, tuple)): | |
188 ids = [ids] | |
189 return bool(filter(None, [PYTHON_FORMAT.search(id) for id in ids])) | |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
190 |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
191 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
192 class TranslationError(Exception): |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
193 """Exception thrown by translation checkers when invalid message |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
194 translations are encountered.""" |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
195 |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
196 |
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
|
197 DEFAULT_HEADER = u"""\ |
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
|
198 # Translations template for PROJECT. |
120 | 199 # Copyright (C) YEAR ORGANIZATION |
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
|
200 # This file is distributed under the same license as the PROJECT project. |
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
|
201 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
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
|
202 #""" |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
203 |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
204 |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
205 class Catalog(object): |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
206 """Representation of a message catalog.""" |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
207 |
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
|
208 def __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER, |
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
|
209 project=None, version=None, copyright_holder=None, |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
210 msgid_bugs_address=None, creation_date=None, |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
211 revision_date=None, last_translator=None, language_team=None, |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
212 charset='utf-8', fuzzy=True): |
64 | 213 """Initialize the catalog 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:
198
diff
changeset
|
214 |
64 | 215 :param locale: the locale identifier or `Locale` object, or `None` |
216 if the catalog is not bound to a locale (which basically | |
217 means it's a template) | |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
218 :param domain: the message domain |
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
|
219 :param header_comment: the header comment as string, or `None` for the |
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
|
220 default header |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
221 :param project: the project's name |
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
222 :param version: the project's version |
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
|
223 :param copyright_holder: the copyright holder of the catalog |
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
|
224 :param msgid_bugs_address: the email address or URL to submit bug |
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
|
225 reports to |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
226 :param creation_date: the date the catalog was created |
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
227 :param revision_date: the date the catalog was revised |
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
228 :param last_translator: the name and email of the last translator |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
229 :param language_team: the name and email of the language team |
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
|
230 :param charset: the encoding to use in the output |
175
5d32098d8352
Changed the `__repr__` output to include the flags(it can be changed back, but it was usefull to implement the fuzzy header parsing).
palgarvio
parents:
165
diff
changeset
|
231 :param fuzzy: the fuzzy bit on the catalog header |
64 | 232 """ |
107 | 233 self.domain = domain #: The message domain |
64 | 234 if locale: |
235 locale = Locale.parse(locale) | |
107 | 236 self.locale = locale #: The locale or `None` |
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
|
237 self._header_comment = header_comment |
67 | 238 self._messages = odict() |
239 | |
107 | 240 self.project = project or 'PROJECT' #: The project name |
241 self.version = version or 'VERSION' #: The project version | |
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
|
242 self.copyright_holder = copyright_holder or 'ORGANIZATION' |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
243 self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS' |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
244 |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
245 self.last_translator = last_translator or 'FULL NAME <EMAIL@ADDRESS>' |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
246 """Name and email address of the last translator.""" |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
247 self.language_team = language_team or 'LANGUAGE <LL@li.org>' |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
248 """Name and email address of the language team.""" |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
249 |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
250 self.charset = charset or 'utf-8' |
84
3ae316b58231
Some cosmetic changes for the new translator comments support.
cmlenz
parents:
80
diff
changeset
|
251 |
67 | 252 if creation_date is None: |
97 | 253 creation_date = datetime.now(LOCALTZ) |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
254 elif isinstance(creation_date, datetime) and not creation_date.tzinfo: |
97 | 255 creation_date = creation_date.replace(tzinfo=LOCALTZ) |
107 | 256 self.creation_date = creation_date #: Creation date of the template |
67 | 257 if revision_date is None: |
97 | 258 revision_date = datetime.now(LOCALTZ) |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
259 elif isinstance(revision_date, datetime) and not revision_date.tzinfo: |
97 | 260 revision_date = revision_date.replace(tzinfo=LOCALTZ) |
107 | 261 self.revision_date = revision_date #: Last revision date of the catalog |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
262 self.fuzzy = fuzzy #: Catalog header fuzzy bit (`True` or `False`) |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
263 |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
264 self.obsolete = odict() #: Dictionary of obsolete messages |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
265 self._num_plurals = None |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
266 self._plural_expr = None |
67 | 267 |
107 | 268 def _get_header_comment(self): |
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
|
269 comment = self._header_comment |
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
|
270 comment = comment.replace('PROJECT', self.project) \ |
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
|
271 .replace('VERSION', self.version) \ |
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
|
272 .replace('YEAR', self.revision_date.strftime('%Y')) \ |
120 | 273 .replace('ORGANIZATION', self.copyright_holder) |
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
|
274 if self.locale: |
107 | 275 comment = comment.replace('Translations template', '%s translations' |
276 % self.locale.english_name) | |
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
|
277 return comment |
120 | 278 |
107 | 279 def _set_header_comment(self, string): |
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
|
280 self._header_comment = string |
107 | 281 |
282 header_comment = property(_get_header_comment, _set_header_comment, doc="""\ | |
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
|
283 The header comment for the 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:
198
diff
changeset
|
284 |
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
|
285 >>> catalog = Catalog(project='Foobar', version='1.0', |
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
|
286 ... copyright_holder='Foo Company') |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
287 >>> print catalog.header_comment #doctest: +ELLIPSIS |
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
|
288 # Translations template for Foobar. |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
289 # Copyright (C) ... Foo Company |
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
|
290 # This file is distributed under the same license as the Foobar project. |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
291 # FIRST AUTHOR <EMAIL@ADDRESS>, .... |
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
|
292 # |
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:
198
diff
changeset
|
293 |
120 | 294 The header can also be set from a string. Any known upper-case variables |
295 will be replaced when the header is retrieved again: | |
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:
198
diff
changeset
|
296 |
120 | 297 >>> catalog = Catalog(project='Foobar', version='1.0', |
298 ... copyright_holder='Foo Company') | |
299 >>> catalog.header_comment = '''\\ | |
300 ... # The POT for my really cool PROJECT project. | |
301 ... # Copyright (C) 1990-2003 ORGANIZATION | |
302 ... # This file is distributed under the same license as the PROJECT | |
303 ... # project. | |
304 ... #''' | |
305 >>> print catalog.header_comment | |
306 # The POT for my really cool Foobar project. | |
307 # Copyright (C) 1990-2003 Foo Company | |
308 # This file is distributed under the same license as the Foobar | |
309 # project. | |
310 # | |
311 | |
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
|
312 :type: `unicode` |
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
|
313 """) |
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
|
314 |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
315 def _get_mime_headers(self): |
67 | 316 headers = [] |
317 headers.append(('Project-Id-Version', | |
318 '%s %s' % (self.project, self.version))) | |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
319 headers.append(('Report-Msgid-Bugs-To', self.msgid_bugs_address)) |
67 | 320 headers.append(('POT-Creation-Date', |
131
6a284ad6c8ba
Use `dates.format_datetime` for dates in PO(T) header, as `datetime.strftime` produces wrong results on windows.
cmlenz
parents:
121
diff
changeset
|
321 format_datetime(self.creation_date, 'yyyy-MM-dd HH:mmZ', |
6a284ad6c8ba
Use `dates.format_datetime` for dates in PO(T) header, as `datetime.strftime` produces wrong results on windows.
cmlenz
parents:
121
diff
changeset
|
322 locale='en'))) |
67 | 323 if self.locale is None: |
324 headers.append(('PO-Revision-Date', 'YEAR-MO-DA HO:MI+ZONE')) | |
325 headers.append(('Last-Translator', 'FULL NAME <EMAIL@ADDRESS>')) | |
326 headers.append(('Language-Team', 'LANGUAGE <LL@li.org>')) | |
327 else: | |
328 headers.append(('PO-Revision-Date', | |
131
6a284ad6c8ba
Use `dates.format_datetime` for dates in PO(T) header, as `datetime.strftime` produces wrong results on windows.
cmlenz
parents:
121
diff
changeset
|
329 format_datetime(self.revision_date, |
6a284ad6c8ba
Use `dates.format_datetime` for dates in PO(T) header, as `datetime.strftime` produces wrong results on windows.
cmlenz
parents:
121
diff
changeset
|
330 'yyyy-MM-dd HH:mmZ', locale='en'))) |
67 | 331 headers.append(('Last-Translator', self.last_translator)) |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
332 headers.append(('Language-Team', |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
333 self.language_team.replace('LANGUAGE', |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
334 str(self.locale)))) |
84
3ae316b58231
Some cosmetic changes for the new translator comments support.
cmlenz
parents:
80
diff
changeset
|
335 headers.append(('Plural-Forms', self.plural_forms)) |
67 | 336 headers.append(('MIME-Version', '1.0')) |
68 | 337 headers.append(('Content-Type', |
338 'text/plain; charset=%s' % self.charset)) | |
67 | 339 headers.append(('Content-Transfer-Encoding', '8bit')) |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
340 headers.append(('Generated-By', 'Babel %s\n' % VERSION)) |
67 | 341 return headers |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
342 |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
343 def _set_mime_headers(self, headers): |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
344 for name, value in headers: |
545
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
345 name = name.lower() |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
346 if name == 'project-id-version': |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
347 parts = value.split(' ') |
210
9c237f83d7cb
When parsing catalog headers, look for the content-type first, to be able to use a specified encoding on all other headers.
cmlenz
parents:
206
diff
changeset
|
348 self.project = u' '.join(parts[:-1]) |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
349 self.version = parts[-1] |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
350 elif name == 'report-msgid-bugs-to': |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
351 self.msgid_bugs_address = value |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
352 elif name == 'last-translator': |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
353 self.last_translator = value |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
354 elif name == 'language-team': |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
355 self.language_team = value |
545
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
356 elif name == 'content-type': |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
357 mimetype, params = parse_header(value) |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
358 if 'charset' in params: |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
359 self.charset = params['charset'].lower() |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
360 elif name == 'plural-forms': |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
361 _, params = parse_header(' ;' + value) |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
362 self._num_plurals = int(params.get('nplurals', 2)) |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
363 self._plural_expr = params.get('plural', '(n != 1)') |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
364 elif name == 'pot-creation-date': |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
365 # FIXME: this should use dates.parse_datetime as soon as that |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
366 # is ready |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
367 value, tzoffset, _ = re.split('([+-]\d{4})$', value, 1) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
368 |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
369 tt = time.strptime(value, '%Y-%m-%d %H:%M') |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
370 ts = time.mktime(tt) |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
371 |
478 | 372 # Separate the offset into a sign component, hours, and minutes |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
373 plus_minus_s, rest = tzoffset[0], tzoffset[1:] |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
374 hours_offset_s, mins_offset_s = rest[:2], rest[2:] |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
375 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
376 # Make them all integers |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
377 plus_minus = int(plus_minus_s + '1') |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
378 hours_offset = int(hours_offset_s) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
379 mins_offset = int(mins_offset_s) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
380 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
381 # Calculate net offset |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
382 net_mins_offset = hours_offset * 60 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
383 net_mins_offset += mins_offset |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
384 net_mins_offset *= plus_minus |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
385 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
386 # Create an offset object |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
387 tzoffset = FixedOffsetTimezone(net_mins_offset) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
388 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
389 # Store the offset in a datetime object |
121 | 390 dt = datetime.fromtimestamp(ts) |
391 self.creation_date = dt.replace(tzinfo=tzoffset) | |
422 | 392 elif name == 'po-revision-date': |
393 # Keep the value if it's not the default one | |
394 if 'YEAR' not in value: | |
395 # FIXME: this should use dates.parse_datetime as soon as | |
396 # that is ready | |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
397 value, tzoffset, _ = re.split('([+-]\d{4})$', value, 1) |
422 | 398 tt = time.strptime(value, '%Y-%m-%d %H:%M') |
399 ts = time.mktime(tt) | |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
400 |
478 | 401 # Separate the offset into a sign component, hours, and |
427
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
402 # minutes |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
403 plus_minus_s, rest = tzoffset[0], tzoffset[1:] |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
404 hours_offset_s, mins_offset_s = rest[:2], rest[2:] |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
405 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
406 # Make them all integers |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
407 plus_minus = int(plus_minus_s + '1') |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
408 hours_offset = int(hours_offset_s) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
409 mins_offset = int(mins_offset_s) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
410 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
411 # Calculate net offset |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
412 net_mins_offset = hours_offset * 60 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
413 net_mins_offset += mins_offset |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
414 net_mins_offset *= plus_minus |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
415 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
416 # Create an offset object |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
417 tzoffset = FixedOffsetTimezone(net_mins_offset) |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
418 |
de2b8a211501
Fix Catalog._set_mime_headers' handing of negative offsets.
jruigrok
parents:
425
diff
changeset
|
419 # Store the offset in a datetime object |
422 | 420 dt = datetime.fromtimestamp(ts) |
421 self.revision_date = dt.replace(tzinfo=tzoffset) | |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
422 |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
423 mime_headers = property(_get_mime_headers, _set_mime_headers, doc="""\ |
67 | 424 The MIME headers of the catalog, used for the special ``msgid ""`` entry. |
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:
198
diff
changeset
|
425 |
67 | 426 The behavior of this property changes slightly depending on whether a locale |
427 is set or not, the latter indicating that the catalog is actually a template | |
428 for actual translations. | |
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:
198
diff
changeset
|
429 |
67 | 430 Here's an example of the output for such a catalog template: |
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:
198
diff
changeset
|
431 |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
432 >>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC) |
67 | 433 >>> catalog = Catalog(project='Foobar', version='1.0', |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
434 ... creation_date=created) |
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
|
435 >>> for name, value in catalog.mime_headers: |
67 | 436 ... print '%s: %s' % (name, value) |
437 Project-Id-Version: Foobar 1.0 | |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
438 Report-Msgid-Bugs-To: EMAIL@ADDRESS |
67 | 439 POT-Creation-Date: 1990-04-01 15:30+0000 |
440 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE | |
441 Last-Translator: FULL NAME <EMAIL@ADDRESS> | |
442 Language-Team: LANGUAGE <LL@li.org> | |
443 MIME-Version: 1.0 | |
444 Content-Type: text/plain; charset=utf-8 | |
445 Content-Transfer-Encoding: 8bit | |
446 Generated-By: Babel ... | |
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:
198
diff
changeset
|
447 |
67 | 448 And here's an example of the output when the locale is set: |
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:
198
diff
changeset
|
449 |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
450 >>> revised = datetime(1990, 8, 3, 12, 0, tzinfo=UTC) |
67 | 451 >>> catalog = Catalog(locale='de_DE', project='Foobar', version='1.0', |
95
f9007588a860
Fix for #11 (use local timezone in timestamps of generated POT).
cmlenz
parents:
87
diff
changeset
|
452 ... creation_date=created, revision_date=revised, |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
453 ... last_translator='John Doe <jd@example.com>', |
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
454 ... language_team='de_DE <de@example.com>') |
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
|
455 >>> for name, value in catalog.mime_headers: |
67 | 456 ... print '%s: %s' % (name, value) |
457 Project-Id-Version: Foobar 1.0 | |
78
d0d8d6cd8601
Fixed the plurals header on `Catalog` which should only be written if it's not a catalog template.
palgarvio
parents:
70
diff
changeset
|
458 Report-Msgid-Bugs-To: EMAIL@ADDRESS |
67 | 459 POT-Creation-Date: 1990-04-01 15:30+0000 |
460 PO-Revision-Date: 1990-08-03 12:00+0000 | |
461 Last-Translator: John Doe <jd@example.com> | |
206
71bc10cbc2b5
Preserve language-team header in catalogs on update. Closes #35 again.
cmlenz
parents:
203
diff
changeset
|
462 Language-Team: de_DE <de@example.com> |
84
3ae316b58231
Some cosmetic changes for the new translator comments support.
cmlenz
parents:
80
diff
changeset
|
463 Plural-Forms: nplurals=2; plural=(n != 1) |
67 | 464 MIME-Version: 1.0 |
465 Content-Type: text/plain; charset=utf-8 | |
466 Content-Transfer-Encoding: 8bit | |
467 Generated-By: Babel ... | |
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:
198
diff
changeset
|
468 |
67 | 469 :type: `list` |
470 """) | |
471 | |
579 | 472 @property |
68 | 473 def num_plurals(self): |
579 | 474 """The number of plurals used by the catalog or locale. |
475 | |
476 >>> Catalog(locale='en').num_plurals | |
477 2 | |
478 >>> Catalog(locale='ga').num_plurals | |
479 3 | |
480 | |
481 :type: `int`""" | |
373
b539ade22791
Added babel.messages.plurals.get_plural which returns a special tuple with the plural information.
aronacher
parents:
358
diff
changeset
|
482 if self._num_plurals is None: |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
483 num = 2 |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
484 if self.locale: |
373
b539ade22791
Added babel.messages.plurals.get_plural which returns a special tuple with the plural information.
aronacher
parents:
358
diff
changeset
|
485 num = get_plural(self.locale)[0] |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
486 self._num_plurals = num |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
487 return self._num_plurals |
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:
198
diff
changeset
|
488 |
579 | 489 @property |
490 def plural_expr(self): | |
491 """The plural expression used by the catalog or locale. | |
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:
198
diff
changeset
|
492 |
579 | 493 >>> Catalog(locale='en').plural_expr |
494 '(n != 1)' | |
495 >>> Catalog(locale='ga').plural_expr | |
496 '(n==1 ? 0 : n==2 ? 1 : 2)' | |
68 | 497 |
579 | 498 :type: `basestring`""" |
373
b539ade22791
Added babel.messages.plurals.get_plural which returns a special tuple with the plural information.
aronacher
parents:
358
diff
changeset
|
499 if self._plural_expr is None: |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
500 expr = '(n != 1)' |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
501 if self.locale: |
373
b539ade22791
Added babel.messages.plurals.get_plural which returns a special tuple with the plural information.
aronacher
parents:
358
diff
changeset
|
502 expr = get_plural(self.locale)[1] |
333
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
503 self._plural_expr = expr |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
504 return self._plural_expr |
0cc97bc662d3
Change Catalog class to retain the plural forms set in the MIME headers.
cmlenz
parents:
313
diff
changeset
|
505 |
579 | 506 @property |
67 | 507 def plural_forms(self): |
579 | 508 """Return the plural forms declaration for the locale. |
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:
198
diff
changeset
|
509 |
579 | 510 >>> Catalog(locale='en').plural_forms |
511 'nplurals=2; plural=(n != 1)' | |
512 >>> Catalog(locale='pt_BR').plural_forms | |
513 'nplurals=2; plural=(n > 1)' | |
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:
198
diff
changeset
|
514 |
579 | 515 :type: `str`""" |
516 return 'nplurals=%s; plural=%s' % (self.num_plurals, self.plural_expr) | |
67 | 517 |
518 def __contains__(self, id): | |
519 """Return whether the catalog has a message with the specified ID.""" | |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
520 return self._key_for(id) in self._messages |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
521 |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
522 def __len__(self): |
84
3ae316b58231
Some cosmetic changes for the new translator comments support.
cmlenz
parents:
80
diff
changeset
|
523 """The number of messages in the 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:
198
diff
changeset
|
524 |
579 | 525 This does not include the special ``msgid ""`` entry.""" |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
526 return len(self._messages) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
527 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
528 def __iter__(self): |
64 | 529 """Iterates through all the entries in the catalog, in the order they |
530 were added, yielding a `Message` object for every entry. | |
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:
198
diff
changeset
|
531 |
579 | 532 :rtype: ``iterator``""" |
67 | 533 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
|
534 for name, value in self.mime_headers: |
67 | 535 buf.append('%s: %s' % (name, value)) |
198
fcfc7403c394
Correctly handle non-ASCII chars in the catalog MIME headers.
cmlenz
parents:
196
diff
changeset
|
536 flags = set() |
175
5d32098d8352
Changed the `__repr__` output to include the flags(it can be changed back, but it was usefull to implement the fuzzy header parsing).
palgarvio
parents:
165
diff
changeset
|
537 if self.fuzzy: |
198
fcfc7403c394
Correctly handle non-ASCII chars in the catalog MIME headers.
cmlenz
parents:
196
diff
changeset
|
538 flags |= set(['fuzzy']) |
210
9c237f83d7cb
When parsing catalog headers, look for the content-type first, to be able to use a specified encoding on all other headers.
cmlenz
parents:
206
diff
changeset
|
539 yield Message(u'', '\n'.join(buf), flags=flags) |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
540 for key in self._messages: |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
541 yield self._messages[key] |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
542 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
543 def __repr__(self): |
64 | 544 locale = '' |
545 if self.locale: | |
546 locale = ' %s' % self.locale | |
547 return '<%s %r%s>' % (type(self).__name__, self.domain, locale) | |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
548 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
549 def __delitem__(self, id): |
64 | 550 """Delete the message with the specified ID.""" |
350 | 551 self.delete(id) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
552 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
553 def __getitem__(self, id): |
64 | 554 """Return the message with the specified ID. |
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:
198
diff
changeset
|
555 |
64 | 556 :param id: the message ID |
350 | 557 :return: the message with the specified ID, or `None` if no such |
558 message is in the catalog | |
67 | 559 :rtype: `Message` |
64 | 560 """ |
350 | 561 return self.get(id) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
562 |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
563 def __setitem__(self, id, message): |
64 | 564 """Add or update the message with the specified ID. |
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:
198
diff
changeset
|
565 |
64 | 566 >>> catalog = Catalog() |
567 >>> catalog[u'foo'] = Message(u'foo') | |
568 >>> catalog[u'foo'] | |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
569 <Message u'foo' (flags: [])> |
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:
198
diff
changeset
|
570 |
64 | 571 If a message with that ID is already in the catalog, it is updated |
572 to include the locations and flags of the new message. | |
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:
198
diff
changeset
|
573 |
64 | 574 >>> catalog = Catalog() |
575 >>> catalog[u'foo'] = Message(u'foo', locations=[('main.py', 1)]) | |
576 >>> catalog[u'foo'].locations | |
577 [('main.py', 1)] | |
578 >>> catalog[u'foo'] = Message(u'foo', locations=[('utils.py', 5)]) | |
579 >>> catalog[u'foo'].locations | |
580 [('main.py', 1), ('utils.py', 5)] | |
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:
198
diff
changeset
|
581 |
64 | 582 :param id: the message ID |
583 :param message: the `Message` object | |
584 """ | |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
585 assert isinstance(message, Message), 'expected a Message object' |
350 | 586 key = self._key_for(id, message.context) |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
587 current = self._messages.get(key) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
588 if current: |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
589 if message.pluralizable and not current.pluralizable: |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
590 # The new message adds pluralization |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
591 current.id = message.id |
70
f016034ff635
Fix for mixed singular/plural messages, follow-up to [70].
cmlenz
parents:
69
diff
changeset
|
592 current.string = message.string |
229 | 593 current.locations = list(distinct(current.locations + |
594 message.locations)) | |
228
6582494abc36
Follow-up to [239]: also combine duplicate comments when writing PO files.
cmlenz
parents:
227
diff
changeset
|
595 current.auto_comments = list(distinct(current.auto_comments + |
6582494abc36
Follow-up to [239]: also combine duplicate comments when writing PO files.
cmlenz
parents:
227
diff
changeset
|
596 message.auto_comments)) |
6582494abc36
Follow-up to [239]: also combine duplicate comments when writing PO files.
cmlenz
parents:
227
diff
changeset
|
597 current.user_comments = list(distinct(current.user_comments + |
6582494abc36
Follow-up to [239]: also combine duplicate comments when writing PO files.
cmlenz
parents:
227
diff
changeset
|
598 message.user_comments)) |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
599 current.flags |= message.flags |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
600 message = current |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
601 elif id == '': |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
602 # special treatment for the header message |
545
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
603 def _parse_header(header_string): |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
604 # message_from_string only works for str, not for unicode |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
605 headers = message_from_string(header_string.encode('utf8')) |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
606 decoded_headers = {} |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
607 for name, value in headers.items(): |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
608 name = name.decode('utf8') |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
609 value = value.decode('utf8') |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
610 decoded_headers[name] = value |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
611 return decoded_headers |
e8155a73ac2e
Catalog class should not do decoding of input strings (fixes #256)
fschwarz
parents:
544
diff
changeset
|
612 self.mime_headers = _parse_header(message.string).items() |
120 | 613 self.header_comment = '\n'.join(['# %s' % comment for comment |
614 in message.user_comments]) | |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
615 self.fuzzy = message.fuzzy |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
616 else: |
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
617 if isinstance(id, (list, tuple)): |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
618 assert isinstance(message.string, (list, tuple)), \ |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
619 'Expected sequence but got %s' % type(message.string) |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
620 self._messages[key] = message |
56
f40fc143439c
Add actual data structures for handling message catalogs, so that more code can be reused here between the frontends.
cmlenz
parents:
diff
changeset
|
621 |
105
c62b68a0b65e
`Message`, `read_po` and `write_po` now all handle user/auto comments correctly.
palgarvio
parents:
104
diff
changeset
|
622 def add(self, id, string=None, locations=(), flags=(), auto_comments=(), |
335 | 623 user_comments=(), previous_id=(), lineno=None, context=None): |
64 | 624 """Add or update the message with the specified ID. |
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:
198
diff
changeset
|
625 |
64 | 626 >>> catalog = Catalog() |
627 >>> catalog.add(u'foo') | |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
628 <Message ...> |
64 | 629 >>> catalog[u'foo'] |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
630 <Message u'foo' (flags: [])> |
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:
198
diff
changeset
|
631 |
64 | 632 This method simply constructs a `Message` object with the given |
633 arguments and invokes `__setitem__` with that 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:
198
diff
changeset
|
634 |
64 | 635 :param id: the message ID, or a ``(singular, plural)`` tuple for |
636 pluralizable messages | |
637 :param string: the translated message string, or a | |
638 ``(singular, plural)`` tuple for pluralizable messages | |
639 :param locations: a sequence of ``(filenname, lineno)`` tuples | |
640 :param flags: a set or sequence of flags | |
106
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
641 :param auto_comments: a sequence of automatic comments |
2cd83f77cc98
Fix for #16: the header message (`msgid = ""`) is now treated specially by `read_po` and `Catalog`.
cmlenz
parents:
105
diff
changeset
|
642 :param user_comments: a sequence of user comments |
203 | 643 :param previous_id: the previous message ID, or a ``(singular, plural)`` |
644 tuple for pluralizable messages | |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
645 :param lineno: the line number on which the msgid line was found in the |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
646 PO file, if any |
335 | 647 :param context: the message context |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
648 :return: the newly added message |
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
649 :rtype: `Message` |
64 | 650 """ |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
651 message = Message(id, string, list(locations), flags, auto_comments, |
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
652 user_comments, previous_id, lineno=lineno, |
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
653 context=context) |
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
654 self[id] = message |
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
655 return message |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
656 |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
657 def check(self): |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
658 """Run various validation checks on the translations in the catalog. |
226 | 659 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
660 For every message which fails validation, this method yield a |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
661 ``(message, errors)`` tuple, where ``message`` is the `Message` object |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
662 and ``errors`` is a sequence of `TranslationError` objects. |
226 | 663 |
220
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
664 :rtype: ``iterator`` |
97b4b289e792
Added infrastructure for adding catalog checkers, and implement a checker that validations Python format parameters in translations, closing #19.
cmlenz
parents:
210
diff
changeset
|
665 """ |
352
8860097a9765
The builtin checkers don't require setuptools any longer, validate_format and python_format from the checkers module are merged into one now.
aronacher
parents:
351
diff
changeset
|
666 for message in self._messages.values(): |
355
9a2618ab9bbc
Refactored the checker system. It's now possible to partially validate translations on a per-message level.
aronacher
parents:
354
diff
changeset
|
667 errors = message.check(catalog=self) |
352
8860097a9765
The builtin checkers don't require setuptools any longer, validate_format and python_format from the checkers module are merged into one now.
aronacher
parents:
351
diff
changeset
|
668 if errors: |
8860097a9765
The builtin checkers don't require setuptools any longer, validate_format and python_format from the checkers module are merged into one now.
aronacher
parents:
351
diff
changeset
|
669 yield message, errors |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
670 |
350 | 671 def get(self, id, context=None): |
672 """Return the message with the specified ID and context. | |
673 | |
674 :param id: the message ID | |
675 :param context: the message context, or ``None`` for no context | |
676 :return: the message with the specified ID, or `None` if no such | |
677 message is in the catalog | |
678 :rtype: `Message` | |
679 """ | |
680 return self._messages.get(self._key_for(id, context)) | |
681 | |
682 def delete(self, id, context=None): | |
683 """Delete the message with the specified ID and context. | |
684 | |
685 :param id: the message ID | |
686 :param context: the message context, or ``None`` for no context | |
687 """ | |
688 key = self._key_for(id, context) | |
689 if key in self._messages: | |
690 del self._messages[key] | |
691 | |
203 | 692 def update(self, template, no_fuzzy_matching=False): |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
693 """Update the catalog based on the given template 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:
198
diff
changeset
|
694 |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
695 >>> from babel.messages import Catalog |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
696 >>> template = Catalog() |
188 | 697 >>> template.add('green', locations=[('main.py', 99)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
698 <Message ...> |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
699 >>> template.add('blue', locations=[('main.py', 100)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
700 <Message ...> |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
701 >>> template.add(('salad', 'salads'), locations=[('util.py', 42)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
702 <Message ...> |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
703 >>> catalog = Catalog(locale='de_DE') |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
704 >>> catalog.add('blue', u'blau', locations=[('main.py', 98)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
705 <Message ...> |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
706 >>> catalog.add('head', u'Kopf', locations=[('util.py', 33)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
707 <Message ...> |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
708 >>> catalog.add(('salad', 'salads'), (u'Salat', u'Salate'), |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
709 ... locations=[('util.py', 38)]) |
544
ea0254950175
catalog.add() now returns the message instance (closes #245)
fschwarz
parents:
530
diff
changeset
|
710 <Message ...> |
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:
198
diff
changeset
|
711 |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
712 >>> catalog.update(template) |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
713 >>> len(catalog) |
188 | 714 3 |
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:
198
diff
changeset
|
715 |
188 | 716 >>> msg1 = catalog['green'] |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
717 >>> msg1.string |
188 | 718 >>> msg1.locations |
719 [('main.py', 99)] | |
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:
198
diff
changeset
|
720 |
188 | 721 >>> msg2 = catalog['blue'] |
722 >>> msg2.string | |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
723 u'blau' |
188 | 724 >>> msg2.locations |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
725 [('main.py', 100)] |
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:
198
diff
changeset
|
726 |
188 | 727 >>> msg3 = catalog['salad'] |
728 >>> msg3.string | |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
729 (u'Salat', u'Salate') |
188 | 730 >>> msg3.locations |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
731 [('util.py', 42)] |
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:
198
diff
changeset
|
732 |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
733 Messages that are in the catalog but not in the template are removed |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
734 from the main collection, but can still be accessed via the `obsolete` |
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
735 member: |
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:
198
diff
changeset
|
736 |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
737 >>> 'head' in catalog |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
738 False |
181
8a762ce37bf7
The frontends now provide ways to update existing translations catalogs from a template. Closes #22.
cmlenz
parents:
175
diff
changeset
|
739 >>> catalog.obsolete.values() |
196
b38a6b220ea2
Fix for #35, and a minor improvement to how we parse the catalog fuzzy bit.
cmlenz
parents:
188
diff
changeset
|
740 [<Message 'head' (flags: [])>] |
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:
198
diff
changeset
|
741 |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
742 :param template: the reference catalog, usually read from a POT file |
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:
198
diff
changeset
|
743 :param no_fuzzy_matching: whether to use fuzzy matching of message IDs |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
744 """ |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
745 messages = self._messages |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
746 remaining = messages.copy() |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
747 self._messages = odict() |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
748 |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
749 # Prepare for fuzzy matching |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
750 fuzzy_candidates = [] |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
751 if not no_fuzzy_matching: |
350 | 752 fuzzy_candidates = dict([ |
753 (self._key_for(msgid), messages[msgid].context) | |
754 for msgid in messages if msgid and messages[msgid].string | |
755 ]) | |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
756 fuzzy_matches = set() |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
757 |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
758 def _merge(message, oldkey, newkey): |
313
ac8450a20e32
Merging catalogs would sometimes mix translations from different runs.
cmlenz
parents:
312
diff
changeset
|
759 message = message.clone() |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
760 fuzzy = False |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
761 if oldkey != newkey: |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
762 fuzzy = True |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
763 fuzzy_matches.add(oldkey) |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
764 oldmsg = messages.get(oldkey) |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
765 if isinstance(oldmsg.id, basestring): |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
766 message.previous_id = [oldmsg.id] |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
767 else: |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
768 message.previous_id = list(oldmsg.id) |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
769 else: |
337
e6c8e462f1ee
Fix iterkeys/iteritems/itervalues/pop/popitem methods on the `odict` utility class. Thanks to Armin Ronacher for the patch.
cmlenz
parents:
335
diff
changeset
|
770 oldmsg = remaining.pop(oldkey, None) |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
771 message.string = oldmsg.string |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
772 if isinstance(message.id, (list, tuple)): |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
773 if not isinstance(message.string, (list, tuple)): |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
774 fuzzy = True |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
775 message.string = tuple( |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
776 [message.string] + ([u''] * (len(message.id) - 1)) |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
777 ) |
425
135950ca346c
Fuzzy matching regarding plurals should *NOT* be checked against `len(message.id)` because this is always 2, instead, it's should be checked against `catalog.num_plurals`.
palgarvio
parents:
422
diff
changeset
|
778 elif len(message.string) != self.num_plurals: |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
779 fuzzy = True |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
780 message.string = tuple(message.string[:len(oldmsg.string)]) |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
781 elif isinstance(message.string, (list, tuple)): |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
782 fuzzy = True |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
783 message.string = message.string[0] |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
784 message.flags |= oldmsg.flags |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
785 if fuzzy: |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
786 message.flags |= set([u'fuzzy']) |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
787 self[message.id] = message |
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
788 |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
789 for message in template: |
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
790 if message.id: |
350 | 791 key = self._key_for(message.id, message.context) |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
792 if key in messages: |
277
9886bf6f2d15
Fix for updating catalog messages that changed from gettext to ngettext or vice versa.
cmlenz
parents:
250
diff
changeset
|
793 _merge(message, key, key) |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
794 else: |
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:
198
diff
changeset
|
795 if no_fuzzy_matching is False: |
165
628bc271ece4
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
163
diff
changeset
|
796 # do some fuzzy matching with difflib |
350 | 797 if isinstance(key, tuple): |
798 matchkey = key[0] # just the msgid, no context | |
799 else: | |
800 matchkey = key | |
801 matches = get_close_matches(matchkey.lower().strip(), | |
802 fuzzy_candidates.keys(), 1) | |
165
628bc271ece4
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
163
diff
changeset
|
803 if matches: |
350 | 804 newkey = matches[0] |
805 newctxt = fuzzy_candidates[newkey] | |
806 if newctxt is not None: | |
807 newkey = newkey, newctxt | |
808 _merge(message, newkey, key) | |
188 | 809 continue |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
810 |
165
628bc271ece4
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
163
diff
changeset
|
811 self[message.id] = message |
628bc271ece4
Implement fuzzy matching to catalog updates. No frontend yet.
cmlenz
parents:
163
diff
changeset
|
812 |
312
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
813 self.obsolete = odict() |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
814 for msgid in remaining: |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
815 if no_fuzzy_matching or msgid not in fuzzy_matches: |
25b883553910
Fix catalog updating with fuzzy matches. Closes #82.
cmlenz
parents:
291
diff
changeset
|
816 self.obsolete[msgid] = remaining[msgid] |
418
22d5d7fbaa5f
Make the `POT-Creation-Date` of the catalog being updated equal to `POT-Creation-Date` of the template used to update. Fixes #148.
palgarvio
parents:
414
diff
changeset
|
817 # Make updated catalog's POT-Creation-Date equal to the template |
22d5d7fbaa5f
Make the `POT-Creation-Date` of the catalog being updated equal to `POT-Creation-Date` of the template used to update. Fixes #148.
palgarvio
parents:
414
diff
changeset
|
818 # used to update the catalog |
22d5d7fbaa5f
Make the `POT-Creation-Date` of the catalog being updated equal to `POT-Creation-Date` of the template used to update. Fixes #148.
palgarvio
parents:
414
diff
changeset
|
819 self.creation_date = template.creation_date |
163
f4ac63f27697
Added preliminary catalog updating/merging functionality.
cmlenz
parents:
149
diff
changeset
|
820 |
350 | 821 def _key_for(self, id, context=None): |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
822 """The key for a message is just the singular ID even for pluralizable |
350 | 823 messages, but is a ``(msgid, msgctxt)`` tuple for context-specific |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
824 messages. |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
825 """ |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
826 key = id |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
827 if isinstance(key, (list, tuple)): |
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
828 key = id[0] |
350 | 829 if context is not None: |
830 key = (key, context) | |
69
af75520471ed
Message catalogs can have multiple messages with the same ID, where some of them have plural strings, and others don't. Still the same message.
cmlenz
parents:
68
diff
changeset
|
831 return key |