0
# Message Catalog Management
1
2
Complete gettext-compatible message catalog system for managing translatable strings, including catalog creation, message extraction, PO/MO file handling, and translation management. Babel provides comprehensive tools for internationalization workflows.
3
4
## Capabilities
5
6
### Message Class
7
8
Represents individual translatable messages with metadata.
9
10
```python { .api }
11
class Message:
12
"""
13
Represents a single translatable message.
14
15
Attributes:
16
id (str|tuple): Message identifier (string or tuple for plurals)
17
string (str|list): Translation string (string or list for plurals)
18
locations (list): List of (filename, lineno) tuples where message appears
19
flags (set): Set of flags (fuzzy, python-format, etc.)
20
auto_comments (list): Automatic comments from extractors
21
user_comments (list): User-provided comments
22
previous_id (str|tuple): Previous message ID (for updates)
23
lineno (int): Line number where message is defined
24
context (str): Message context for disambiguation
25
"""
26
def __init__(self, id, string='', locations=(), flags=(), auto_comments=(),
27
user_comments=(), previous_id=None, lineno=None, context=None):
28
"""
29
Initialize a message.
30
31
Args:
32
id (str|tuple): Message identifier
33
string (str|list): Translation string(s)
34
locations (list): Source locations
35
flags (set): Message flags
36
auto_comments (list): Automatic comments
37
user_comments (list): User comments
38
previous_id (str|tuple): Previous ID for updates
39
lineno (int): Line number
40
context (str): Message context
41
"""
42
43
@property
44
def pluralizable(self):
45
"""bool: Whether this message has plural forms"""
46
47
@property
48
def python_format(self):
49
"""bool: Whether this message uses Python format strings"""
50
```
51
52
Usage example:
53
54
```python
55
from babel.messages import Message
56
57
# Simple message
58
msg = Message('Hello, world!', 'Bonjour, le monde!',
59
locations=[('main.py', 10)], flags={'fuzzy'})
60
61
# Plural message
62
plural_msg = Message(
63
id=('One item', '{count} items'),
64
string=['Un élément', '{count} éléments'],
65
locations=[('inventory.py', 25)]
66
)
67
```
68
69
### Catalog Class
70
71
Collection of translatable messages with metadata and management functionality.
72
73
```python { .api }
74
class Catalog:
75
"""
76
Collection of translatable messages with catalog metadata.
77
78
Attributes:
79
locale (Locale): Target locale for translations
80
domain (str): Message domain
81
project (str): Project name
82
version (str): Project version
83
copyright_holder (str): Copyright holder
84
msgid_bugs_address (str): Bug report email address
85
last_translator (str): Last translator information
86
language_team (str): Language team information
87
charset (str): Character encoding
88
creation_date (datetime): Catalog creation date
89
revision_date (datetime): Last revision date
90
fuzzy (bool): Whether catalog is fuzzy (incomplete)
91
num_plurals (int): Number of plural forms for locale
92
plural_expr (str): Plural expression for locale
93
plural_forms (str): Gettext plural forms header
94
mime_headers (list): List of MIME headers
95
"""
96
def __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER,
97
project=None, version=None, copyright_holder=None,
98
msgid_bugs_address=None, creation_date=None, revision_date=None,
99
last_translator=None, language_team=None, charset=None,
100
plurals=None, fuzzy=True):
101
"""
102
Initialize a message catalog.
103
104
Args:
105
locale (Locale|str): Target locale
106
domain (str): Message domain
107
header_comment (str): Header comment text
108
project (str): Project name
109
version (str): Project version
110
copyright_holder (str): Copyright holder
111
msgid_bugs_address (str): Bug report address
112
creation_date (datetime): Creation timestamp
113
revision_date (datetime): Revision timestamp
114
last_translator (str): Last translator info
115
language_team (str): Language team info
116
charset (str): Character encoding
117
plurals (tuple): Plural forms (count, expression)
118
fuzzy (bool): Whether catalog is fuzzy
119
"""
120
121
def add(self, id, string=None, locations=(), flags=(), auto_comments=(),
122
user_comments=(), previous_id=None, lineno=None, context=None):
123
"""
124
Add a message to the catalog.
125
126
Args:
127
id (str|tuple): Message identifier
128
string (str|list): Translation string(s)
129
locations (list): Source locations
130
flags (set): Message flags
131
auto_comments (list): Automatic comments
132
user_comments (list): User comments
133
previous_id (str|tuple): Previous ID
134
lineno (int): Line number
135
context (str): Message context
136
137
Returns:
138
Message: The added message object
139
"""
140
141
def get(self, id, context=None):
142
"""
143
Get a message by ID and context.
144
145
Args:
146
id (str|tuple): Message identifier
147
context (str, optional): Message context
148
149
Returns:
150
Message|None: Message object or None if not found
151
"""
152
153
def delete(self, id, context=None):
154
"""
155
Delete a message from the catalog.
156
157
Args:
158
id (str|tuple): Message identifier
159
context (str, optional): Message context
160
"""
161
162
def update(self, template, no_fuzzy_matching=False, update_header_comment=False):
163
"""
164
Update catalog from a template catalog.
165
166
Args:
167
template (Catalog): Template catalog with source messages
168
no_fuzzy_matching (bool): Whether to disable fuzzy matching
169
update_header_comment (bool): Whether to update header comment
170
"""
171
172
def check(self):
173
"""
174
Run consistency checks on the catalog.
175
176
Returns:
177
list: List of check result tuples (message, checker_errors)
178
"""
179
180
def __iter__(self):
181
"""Iterate over messages in the catalog."""
182
183
def __len__(self):
184
"""Get number of messages in catalog."""
185
186
def __contains__(self, id):
187
"""Check if message ID exists in catalog."""
188
```
189
190
Usage example:
191
192
```python
193
from babel.messages import Catalog, Message
194
from babel import Locale
195
import datetime
196
197
# Create a catalog
198
catalog = Catalog(
199
locale=Locale('fr_FR'),
200
project='My Project',
201
version='1.0',
202
creation_date=datetime.datetime.now()
203
)
204
205
# Add messages
206
catalog.add('Hello', 'Bonjour', locations=[('main.py', 10)])
207
catalog.add('Goodbye', 'Au revoir', locations=[('main.py', 20)])
208
209
# Plural message
210
catalog.add(
211
('One file', '{count} files'),
212
['Un fichier', '{count} fichiers'],
213
locations=[('files.py', 15)]
214
)
215
216
# Check catalog
217
issues = catalog.check()
218
print(f"Catalog has {len(catalog)} messages")
219
```
220
221
### PO File Handling
222
223
Read and write PO (Portable Object) files for translation management.
224
225
```python { .api }
226
def read_po(fileobj, locale=None, domain=None, ignore_obsolete=True,
227
charset=None, abort_invalid=False):
228
"""
229
Read a PO file and return a Catalog.
230
231
Args:
232
fileobj (file-like): File object to read from
233
locale (Locale|str, optional): Target locale
234
domain (str, optional): Message domain
235
ignore_obsolete (bool): Whether to ignore obsolete entries
236
charset (str, optional): Character encoding
237
abort_invalid (bool): Whether to abort on invalid entries
238
239
Returns:
240
Catalog: Parsed message catalog
241
242
Raises:
243
PoFileError: If PO file parsing fails
244
"""
245
246
def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False,
247
sort_output=False, sort_by_file=False, ignore_obsolete=True,
248
include_previous=False, include_lineno=True):
249
"""
250
Write a Catalog to a PO file.
251
252
Args:
253
fileobj (file-like): File object to write to
254
catalog (Catalog): Message catalog to write
255
width (int): Maximum line width
256
no_location (bool): Whether to omit location comments
257
omit_header (bool): Whether to omit the header
258
sort_output (bool): Whether to sort messages by ID
259
sort_by_file (bool): Whether to sort by filename
260
ignore_obsolete (bool): Whether to ignore obsolete entries
261
include_previous (bool): Whether to include previous msgid
262
include_lineno (bool): Whether to include line numbers
263
"""
264
```
265
266
Usage example:
267
268
```python
269
from babel.messages.pofile import read_po, write_po
270
from babel.messages import Catalog
271
272
# Read a PO file
273
with open('messages.po', 'rb') as f:
274
catalog = read_po(f, locale='fr_FR')
275
276
# Write a PO file
277
with open('output.po', 'wb') as f:
278
write_po(f, catalog, width=80)
279
```
280
281
### MO File Handling
282
283
Read and write MO (Machine Object) files for runtime translation use.
284
285
```python { .api }
286
def read_mo(fileobj):
287
"""
288
Read a binary MO file and return a Catalog.
289
290
Args:
291
fileobj (file-like): File object to read from
292
293
Returns:
294
Catalog: Parsed message catalog
295
"""
296
297
def write_mo(fileobj, catalog, use_fuzzy=False):
298
"""
299
Write a Catalog to a binary MO file.
300
301
Args:
302
fileobj (file-like): File object to write to
303
catalog (Catalog): Message catalog to write
304
use_fuzzy (bool): Whether to include fuzzy translations
305
"""
306
```
307
308
Usage example:
309
310
```python
311
from babel.messages.mofile import read_mo, write_mo
312
313
# Read MO file
314
with open('messages.mo', 'rb') as f:
315
catalog = read_mo(f)
316
317
# Write MO file
318
with open('output.mo', 'wb') as f:
319
write_mo(f, catalog, use_fuzzy=False)
320
```
321
322
### Message Extraction
323
324
Extract translatable strings from source code files.
325
326
```python { .api }
327
def extract_from_dir(dirname, method_map=None, options_map=None, keywords=None,
328
comment_tags=None, callback=None, strip_comment_tags=False):
329
"""
330
Extract messages from a directory tree.
331
332
Args:
333
dirname (str): Directory to extract from
334
method_map (dict): File extension to extraction method mapping
335
options_map (dict): Method-specific options
336
keywords (dict): Keyword function specifications
337
comment_tags (list): Comment tags to extract
338
callback (callable): Progress callback function
339
strip_comment_tags (bool): Whether to strip comment tags
340
341
Returns:
342
Generator: Iterator of (filename, lineno, message, comments, context) tuples
343
"""
344
345
def extract_from_file(method, filename, keywords=None, comment_tags=None,
346
options=None, strip_comment_tags=False):
347
"""
348
Extract messages from a single file.
349
350
Args:
351
method (str|callable): Extraction method
352
filename (str): File to extract from
353
keywords (dict): Keyword specifications
354
comment_tags (list): Comment tags to extract
355
options (dict): Method-specific options
356
strip_comment_tags (bool): Whether to strip comment tags
357
358
Returns:
359
Generator: Iterator of (lineno, message, comments, context) tuples
360
"""
361
362
def extract_python(fileobj, keywords, comment_tags, options):
363
"""
364
Extract messages from Python source code.
365
366
Args:
367
fileobj (file-like): File object to read from
368
keywords (dict): Keyword specifications
369
comment_tags (list): Comment tags to extract
370
options (dict): Extraction options
371
372
Returns:
373
Generator: Iterator of extraction results
374
"""
375
376
def extract_javascript(fileobj, keywords, comment_tags, options):
377
"""
378
Extract messages from JavaScript source code.
379
380
Args:
381
fileobj (file-like): File object to read from
382
keywords (dict): Keyword specifications
383
comment_tags (list): Comment tags to extract
384
options (dict): Extraction options
385
386
Returns:
387
Generator: Iterator of extraction results
388
"""
389
```
390
391
Usage example:
392
393
```python
394
from babel.messages.extract import extract_from_dir, extract_python
395
396
# Extract from directory
397
method_map = {
398
'*.py': 'python',
399
'*.js': 'javascript'
400
}
401
402
keywords = {
403
'_': None,
404
'gettext': None,
405
'ngettext': (1, 2),
406
}
407
408
for filename, lineno, message, comments, context in extract_from_dir('.', method_map, keywords=keywords):
409
print(f"{filename}:{lineno}: {message}")
410
```
411
412
### Command Line Tools
413
414
Classes for setuptools integration and command-line message management.
415
416
```python { .api }
417
class ExtractMessages:
418
"""Command to extract messages from source code."""
419
420
def run(self):
421
"""Execute message extraction."""
422
423
class InitCatalog:
424
"""Command to initialize a new message catalog."""
425
426
def run(self):
427
"""Execute catalog initialization."""
428
429
class UpdateCatalog:
430
"""Command to update an existing catalog from template."""
431
432
def run(self):
433
"""Execute catalog update."""
434
435
class CompileCatalog:
436
"""Command to compile PO files to MO files."""
437
438
def run(self):
439
"""Execute catalog compilation."""
440
```
441
442
### Translation Support Classes
443
444
Extended translation classes with Babel-specific functionality.
445
446
```python { .api }
447
class Translations:
448
"""
449
Extended translation catalog with Babel features.
450
451
Inherits from gettext.GNUTranslations with additional methods.
452
"""
453
@classmethod
454
def load(cls, dirname=None, locales=None, domain=None):
455
"""
456
Load translations from directory.
457
458
Args:
459
dirname (str): Directory containing translation files
460
locales (list): List of locale identifiers
461
domain (str): Message domain
462
463
Returns:
464
Translations: Translation object
465
"""
466
467
def add(self, translations, merge=True):
468
"""
469
Add translations from another catalog.
470
471
Args:
472
translations (Translations): Translations to add
473
merge (bool): Whether to merge duplicates
474
"""
475
476
def merge(self, translations):
477
"""
478
Merge translations from another catalog.
479
480
Args:
481
translations (Translations): Translations to merge
482
"""
483
```
484
485
### String Utilities
486
487
Utilities for PO file string handling.
488
489
```python { .api }
490
def escape(string):
491
"""
492
Escape string for PO file format.
493
494
Args:
495
string (str): String to escape
496
497
Returns:
498
str: Escaped string
499
"""
500
501
def unescape(string):
502
"""
503
Unescape PO file string.
504
505
Args:
506
string (str): String to unescape
507
508
Returns:
509
str: Unescaped string
510
"""
511
512
def normalize(string, prefix='', width=76):
513
"""
514
Normalize multiline strings for PO format.
515
516
Args:
517
string (str): String to normalize
518
prefix (str): Line prefix
519
width (int): Maximum line width
520
521
Returns:
522
str: Normalized string
523
"""
524
525
def denormalize(string):
526
"""
527
Reverse normalization of PO strings.
528
529
Args:
530
string (str): String to denormalize
531
532
Returns:
533
str: Denormalized string
534
"""
535
```
536
537
### Plural Forms
538
539
Get plural form information for locales.
540
541
```python { .api }
542
def get_plural(locale):
543
"""
544
Get plural rule for locale.
545
546
Args:
547
locale (Locale|str): Target locale
548
549
Returns:
550
_PluralTuple: Tuple containing (count, expression)
551
"""
552
```
553
554
### Message Checkers
555
556
Functions to validate message catalog consistency.
557
558
```python { .api }
559
def num_plurals(catalog, message):
560
"""
561
Check that number of plural forms matches locale.
562
563
Args:
564
catalog (Catalog): Message catalog
565
message (Message): Message to check
566
567
Returns:
568
list: List of error messages
569
"""
570
571
def python_format(catalog, message):
572
"""
573
Check Python format string consistency.
574
575
Args:
576
catalog (Catalog): Message catalog
577
message (Message): Message to check
578
579
Returns:
580
list: List of error messages
581
"""
582
```
583
584
## Exception Classes
585
586
```python { .api }
587
class TranslationError(Exception):
588
"""Base exception for translation-related errors."""
589
590
class PoFileError(Exception):
591
"""Exception raised for PO file parsing errors."""
592
```
593
594
## Constants
595
596
```python { .api }
597
DEFAULT_HEADER: str
598
"""Default catalog header comment template."""
599
600
PYTHON_FORMAT: re.Pattern
601
"""Regex pattern for Python format strings."""
602
```