Internationalization utilities for Python providing locale data, date/time/number formatting, and message catalog management
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
Represents individual translatable messages with metadata.
class Message:
"""
Represents a single translatable message.
Attributes:
id (str|tuple): Message identifier (string or tuple for plurals)
string (str|list): Translation string (string or list for plurals)
locations (list): List of (filename, lineno) tuples where message appears
flags (set): Set of flags (fuzzy, python-format, etc.)
auto_comments (list): Automatic comments from extractors
user_comments (list): User-provided comments
previous_id (str|tuple): Previous message ID (for updates)
lineno (int): Line number where message is defined
context (str): Message context for disambiguation
"""
def __init__(self, id, string='', locations=(), flags=(), auto_comments=(),
user_comments=(), previous_id=None, lineno=None, context=None):
"""
Initialize a message.
Args:
id (str|tuple): Message identifier
string (str|list): Translation string(s)
locations (list): Source locations
flags (set): Message flags
auto_comments (list): Automatic comments
user_comments (list): User comments
previous_id (str|tuple): Previous ID for updates
lineno (int): Line number
context (str): Message context
"""
@property
def pluralizable(self):
"""bool: Whether this message has plural forms"""
@property
def python_format(self):
"""bool: Whether this message uses Python format strings"""Usage example:
from babel.messages import Message
# Simple message
msg = Message('Hello, world!', 'Bonjour, le monde!',
locations=[('main.py', 10)], flags={'fuzzy'})
# Plural message
plural_msg = Message(
id=('One item', '{count} items'),
string=['Un élément', '{count} éléments'],
locations=[('inventory.py', 25)]
)Collection of translatable messages with metadata and management functionality.
class Catalog:
"""
Collection of translatable messages with catalog metadata.
Attributes:
locale (Locale): Target locale for translations
domain (str): Message domain
project (str): Project name
version (str): Project version
copyright_holder (str): Copyright holder
msgid_bugs_address (str): Bug report email address
last_translator (str): Last translator information
language_team (str): Language team information
charset (str): Character encoding
creation_date (datetime): Catalog creation date
revision_date (datetime): Last revision date
fuzzy (bool): Whether catalog is fuzzy (incomplete)
num_plurals (int): Number of plural forms for locale
plural_expr (str): Plural expression for locale
plural_forms (str): Gettext plural forms header
mime_headers (list): List of MIME headers
"""
def __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER,
project=None, version=None, copyright_holder=None,
msgid_bugs_address=None, creation_date=None, revision_date=None,
last_translator=None, language_team=None, charset=None,
plurals=None, fuzzy=True):
"""
Initialize a message catalog.
Args:
locale (Locale|str): Target locale
domain (str): Message domain
header_comment (str): Header comment text
project (str): Project name
version (str): Project version
copyright_holder (str): Copyright holder
msgid_bugs_address (str): Bug report address
creation_date (datetime): Creation timestamp
revision_date (datetime): Revision timestamp
last_translator (str): Last translator info
language_team (str): Language team info
charset (str): Character encoding
plurals (tuple): Plural forms (count, expression)
fuzzy (bool): Whether catalog is fuzzy
"""
def add(self, id, string=None, locations=(), flags=(), auto_comments=(),
user_comments=(), previous_id=None, lineno=None, context=None):
"""
Add a message to the catalog.
Args:
id (str|tuple): Message identifier
string (str|list): Translation string(s)
locations (list): Source locations
flags (set): Message flags
auto_comments (list): Automatic comments
user_comments (list): User comments
previous_id (str|tuple): Previous ID
lineno (int): Line number
context (str): Message context
Returns:
Message: The added message object
"""
def get(self, id, context=None):
"""
Get a message by ID and context.
Args:
id (str|tuple): Message identifier
context (str, optional): Message context
Returns:
Message|None: Message object or None if not found
"""
def delete(self, id, context=None):
"""
Delete a message from the catalog.
Args:
id (str|tuple): Message identifier
context (str, optional): Message context
"""
def update(self, template, no_fuzzy_matching=False, update_header_comment=False):
"""
Update catalog from a template catalog.
Args:
template (Catalog): Template catalog with source messages
no_fuzzy_matching (bool): Whether to disable fuzzy matching
update_header_comment (bool): Whether to update header comment
"""
def check(self):
"""
Run consistency checks on the catalog.
Returns:
list: List of check result tuples (message, checker_errors)
"""
def __iter__(self):
"""Iterate over messages in the catalog."""
def __len__(self):
"""Get number of messages in catalog."""
def __contains__(self, id):
"""Check if message ID exists in catalog."""Usage example:
from babel.messages import Catalog, Message
from babel import Locale
import datetime
# Create a catalog
catalog = Catalog(
locale=Locale('fr_FR'),
project='My Project',
version='1.0',
creation_date=datetime.datetime.now()
)
# Add messages
catalog.add('Hello', 'Bonjour', locations=[('main.py', 10)])
catalog.add('Goodbye', 'Au revoir', locations=[('main.py', 20)])
# Plural message
catalog.add(
('One file', '{count} files'),
['Un fichier', '{count} fichiers'],
locations=[('files.py', 15)]
)
# Check catalog
issues = catalog.check()
print(f"Catalog has {len(catalog)} messages")Read and write PO (Portable Object) files for translation management.
def read_po(fileobj, locale=None, domain=None, ignore_obsolete=True,
charset=None, abort_invalid=False):
"""
Read a PO file and return a Catalog.
Args:
fileobj (file-like): File object to read from
locale (Locale|str, optional): Target locale
domain (str, optional): Message domain
ignore_obsolete (bool): Whether to ignore obsolete entries
charset (str, optional): Character encoding
abort_invalid (bool): Whether to abort on invalid entries
Returns:
Catalog: Parsed message catalog
Raises:
PoFileError: If PO file parsing fails
"""
def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False,
sort_output=False, sort_by_file=False, ignore_obsolete=True,
include_previous=False, include_lineno=True):
"""
Write a Catalog to a PO file.
Args:
fileobj (file-like): File object to write to
catalog (Catalog): Message catalog to write
width (int): Maximum line width
no_location (bool): Whether to omit location comments
omit_header (bool): Whether to omit the header
sort_output (bool): Whether to sort messages by ID
sort_by_file (bool): Whether to sort by filename
ignore_obsolete (bool): Whether to ignore obsolete entries
include_previous (bool): Whether to include previous msgid
include_lineno (bool): Whether to include line numbers
"""Usage example:
from babel.messages.pofile import read_po, write_po
from babel.messages import Catalog
# Read a PO file
with open('messages.po', 'rb') as f:
catalog = read_po(f, locale='fr_FR')
# Write a PO file
with open('output.po', 'wb') as f:
write_po(f, catalog, width=80)Read and write MO (Machine Object) files for runtime translation use.
def read_mo(fileobj):
"""
Read a binary MO file and return a Catalog.
Args:
fileobj (file-like): File object to read from
Returns:
Catalog: Parsed message catalog
"""
def write_mo(fileobj, catalog, use_fuzzy=False):
"""
Write a Catalog to a binary MO file.
Args:
fileobj (file-like): File object to write to
catalog (Catalog): Message catalog to write
use_fuzzy (bool): Whether to include fuzzy translations
"""Usage example:
from babel.messages.mofile import read_mo, write_mo
# Read MO file
with open('messages.mo', 'rb') as f:
catalog = read_mo(f)
# Write MO file
with open('output.mo', 'wb') as f:
write_mo(f, catalog, use_fuzzy=False)Extract translatable strings from source code files.
def extract_from_dir(dirname, method_map=None, options_map=None, keywords=None,
comment_tags=None, callback=None, strip_comment_tags=False):
"""
Extract messages from a directory tree.
Args:
dirname (str): Directory to extract from
method_map (dict): File extension to extraction method mapping
options_map (dict): Method-specific options
keywords (dict): Keyword function specifications
comment_tags (list): Comment tags to extract
callback (callable): Progress callback function
strip_comment_tags (bool): Whether to strip comment tags
Returns:
Generator: Iterator of (filename, lineno, message, comments, context) tuples
"""
def extract_from_file(method, filename, keywords=None, comment_tags=None,
options=None, strip_comment_tags=False):
"""
Extract messages from a single file.
Args:
method (str|callable): Extraction method
filename (str): File to extract from
keywords (dict): Keyword specifications
comment_tags (list): Comment tags to extract
options (dict): Method-specific options
strip_comment_tags (bool): Whether to strip comment tags
Returns:
Generator: Iterator of (lineno, message, comments, context) tuples
"""
def extract_python(fileobj, keywords, comment_tags, options):
"""
Extract messages from Python source code.
Args:
fileobj (file-like): File object to read from
keywords (dict): Keyword specifications
comment_tags (list): Comment tags to extract
options (dict): Extraction options
Returns:
Generator: Iterator of extraction results
"""
def extract_javascript(fileobj, keywords, comment_tags, options):
"""
Extract messages from JavaScript source code.
Args:
fileobj (file-like): File object to read from
keywords (dict): Keyword specifications
comment_tags (list): Comment tags to extract
options (dict): Extraction options
Returns:
Generator: Iterator of extraction results
"""Usage example:
from babel.messages.extract import extract_from_dir, extract_python
# Extract from directory
method_map = {
'*.py': 'python',
'*.js': 'javascript'
}
keywords = {
'_': None,
'gettext': None,
'ngettext': (1, 2),
}
for filename, lineno, message, comments, context in extract_from_dir('.', method_map, keywords=keywords):
print(f"{filename}:{lineno}: {message}")Classes for setuptools integration and command-line message management.
class ExtractMessages:
"""Command to extract messages from source code."""
def run(self):
"""Execute message extraction."""
class InitCatalog:
"""Command to initialize a new message catalog."""
def run(self):
"""Execute catalog initialization."""
class UpdateCatalog:
"""Command to update an existing catalog from template."""
def run(self):
"""Execute catalog update."""
class CompileCatalog:
"""Command to compile PO files to MO files."""
def run(self):
"""Execute catalog compilation."""Extended translation classes with Babel-specific functionality.
class Translations:
"""
Extended translation catalog with Babel features.
Inherits from gettext.GNUTranslations with additional methods.
"""
@classmethod
def load(cls, dirname=None, locales=None, domain=None):
"""
Load translations from directory.
Args:
dirname (str): Directory containing translation files
locales (list): List of locale identifiers
domain (str): Message domain
Returns:
Translations: Translation object
"""
def add(self, translations, merge=True):
"""
Add translations from another catalog.
Args:
translations (Translations): Translations to add
merge (bool): Whether to merge duplicates
"""
def merge(self, translations):
"""
Merge translations from another catalog.
Args:
translations (Translations): Translations to merge
"""Utilities for PO file string handling.
def escape(string):
"""
Escape string for PO file format.
Args:
string (str): String to escape
Returns:
str: Escaped string
"""
def unescape(string):
"""
Unescape PO file string.
Args:
string (str): String to unescape
Returns:
str: Unescaped string
"""
def normalize(string, prefix='', width=76):
"""
Normalize multiline strings for PO format.
Args:
string (str): String to normalize
prefix (str): Line prefix
width (int): Maximum line width
Returns:
str: Normalized string
"""
def denormalize(string):
"""
Reverse normalization of PO strings.
Args:
string (str): String to denormalize
Returns:
str: Denormalized string
"""Get plural form information for locales.
def get_plural(locale):
"""
Get plural rule for locale.
Args:
locale (Locale|str): Target locale
Returns:
_PluralTuple: Tuple containing (count, expression)
"""Functions to validate message catalog consistency.
def num_plurals(catalog, message):
"""
Check that number of plural forms matches locale.
Args:
catalog (Catalog): Message catalog
message (Message): Message to check
Returns:
list: List of error messages
"""
def python_format(catalog, message):
"""
Check Python format string consistency.
Args:
catalog (Catalog): Message catalog
message (Message): Message to check
Returns:
list: List of error messages
"""class TranslationError(Exception):
"""Base exception for translation-related errors."""
class PoFileError(Exception):
"""Exception raised for PO file parsing errors."""DEFAULT_HEADER: str
"""Default catalog header comment template."""
PYTHON_FORMAT: re.Pattern
"""Regex pattern for Python format strings."""Install with Tessl CLI
npx tessl i tessl/pypi-babel