English | 简体中文
🚀 A lightweight, zero-dependency Python internationalization library that supports Python 2.7 through 3.12.
The API is designed to be DCC-friendly, for example, works with Maya, 3DsMax, Houdini, etc.
TransX provides a comprehensive set of features for internationalization:
- 🚀 Zero Dependencies: No external dependencies required
- 🐍 Python Support: Full support for Python 2.7-3.12
- 🌍 Context-based: Accurate translations with context support
- 📦 Standard Format: Compatible with gettext .po/.mo files
- 🎯 Simple API: Clean and intuitive interface
- 🔄 Auto Management: Automatic translation file handling
- 🔍 String Extraction: Built-in source code string extraction
- 🌐 Unicode: Complete Unicode support
- 🔠 Parameters: Named, positional and ${var} style parameters
- 💫 Variable Support: Environment variable expansion support
- ⚡ Performance: High-speed and thread-safe operations
- 🛡️ Error Handling: Comprehensive error management with fallbacks
- 🧪 Testing: 100% test coverage with extensive cases
- 🌐 Auto Translation: Built-in Google Translate API support
- 🎥 DCC Support: Tested with Maya, 3DsMax, Houdini, etc.
- 🔌 Extensible: Pluggable custom text interpreters
- 🎨 Flexible Formatting: Multiple string formatting styles
- 🔄 Runtime Switching: Dynamic locale switching at runtime
- 🔧 Qt Integration: Built-in support for Qt translations
- 📝 Message Extraction: Advanced source code message extraction with context
- 🌐 Multi-App Support: Multiple translation instances for different apps
TransX is fully compatible with the GNU gettext standard, providing seamless integration with existing translation workflows:
- Standard Formats: Full support for
.po
and.mo
file formats according to GNU gettext specifications - File Structure: Follows the standard locale directory structure (
LC_MESSAGES/domain.{po,mo}
) - Header Support: Complete support for gettext headers and metadata
- Plural Forms: Compatible with gettext plural form expressions and handling
- Context Support: Full support for msgctxt (message context) using gettext standard separators
- Encoding: Proper handling of character encodings as specified in PO/MO headers
- Tools Integration: Works with standard gettext tools (msgfmt, msginit, msgmerge, etc.)
- Binary Format: Implements the official MO file format specification with both little and big endian support
This means you can:
- Use existing PO editors like Poedit, Lokalize, or GTranslator
- Integrate with established translation workflows
- Migrate existing gettext-based translations seamlessly
- Use standard gettext tools alongside TransX
- Maintain compatibility with other gettext-based systems
pip install transx
from transx import TransX
# Initialize with locale directory
tx = TransX(locales_root="./locales")
# Basic translation
print(tx.tr("Hello")) # Output: 你好
# Translation with parameters
print(tx.tr("Hello {name}!", name="张三")) # Output: 你好 张三!
# Context-based translation
print(tx.tr("Open", context="button")) # 打开
print(tx.tr("Open", context="menu")) # 打开文件
# Switch language at runtime
tx.switch_locale("ja_JP")
print(tx.tr("Hello")) # Output: こんにちは
TransX provides two main methods for translation with different levels of functionality:
The tr()
method is the recommended high-level API that provides all translation features:
# Basic translation
tx.tr("Hello") # 你好
# Translation with parameters
tx.tr("Hello {name}!", name="张三") # 你好 张三!
# Context-based translation
tx.tr("Open", context="button") # 打开
tx.tr("Open", context="menu") # 打开文件
# Environment variable expansion
tx.tr("Home: $HOME") # Home: /Users/username
# Dollar sign escaping
tx.tr("Price: $$99.99") # Price: $99.99
# Complex parameter substitution
tx.tr("Welcome to ${city}, {country}!", city="北京", country="中国")
The translate()
method is a lower-level API that provides basic translation and parameter substitution:
# Basic translation
tx.translate("Hello") # 你好
# Translation with context
tx.translate("Open", context="button") # 打开
# Simple parameter substitution
tx.translate("Hello {name}!", name="张三") # 你好 张三!
The main differences between tr()
and translate()
:
Feature | tr() | translate() |
---|---|---|
Basic Translation | ✅ | ✅ |
Context Support | ✅ | ✅ |
Parameter Substitution | ✅ | ✅ |
Environment Variables | ✅ | ❌ |
${var} Style Variables | ✅ | ❌ |
$$ Escaping | ✅ | ❌ |
Interpreter Chain | ✅ | ❌ |
Choose tr()
for full functionality or translate()
for simpler use cases where you only need basic translation and parameter substitution.
# Named parameters
tx.tr("Welcome to {city}, {country}!", city="北京", country="中国")
# Positional parameters
tx.tr("File {0} of {1}", 1, 10)
# Dollar sign variables (useful in shell-like contexts)
tx.tr("Current user: ${USER}") # Supports ${var} syntax
tx.tr("Path: $HOME/documents") # Supports $var syntax
# Escaping dollar signs
tx.tr("Price: $$99.99") # Outputs: Price: $99.99
TransX provides a convenient way to get a list of available locales in your project:
from transx import TransX
tx = TransX(locales_root="./locales")
# Get list of available locales
print(f"Available locales: {tx.available_locales}") # e.g. ['en_US', 'zh_CN', 'ja_JP']
# Check if a locale is available before switching
if "zh_CN" in tx.available_locales:
tx.current_locale = "zh_CN"
The available_locales
property returns a sorted list of locale codes that:
- Have a valid locale directory structure (
LC_MESSAGES
folder) - Contain either
.po
or.mo
translation files - Are ready to use for translation
This is useful for:
- Building language selection interfaces
- Validating locale switches
- Checking translation file completeness
- Displaying supported languages to users
TransX provides a command-line interface for common translation tasks. When no arguments are provided for commands, TransX will use the ./locales
directory in your current working directory as the default path.
# Extract messages from source files
# Default: Will look for source files in current directory and output to ./locales
transx extract
# Same as:
transx extract . --output ./locales/messages.pot
# Update .po files with new translations
# Default: Will update .po files in ./locales
transx update
# Same as:
transx update ./locales
# Compile .po files to .mo files
# Default: Will compile .po files from ./locales
transx compile
# Same as:
transx compile ./locales
The default working directory structure:
./
└── locales/ # Default translation directory
├── messages.pot # Extracted messages template
├── en/ # English translations
│ └── LC_MESSAGES/
│ ├── messages.po
│ └── messages.mo
└── zh_CN/ # Chinese translations
└── LC_MESSAGES/
├── messages.po
└── messages.mo
# Extract from a single file
transx extract app.py -o messages.pot
# Extract from a directory with project info
transx extract ./src -o messages.pot -p "MyProject" -v "1.0"
# Extract and specify languages
transx extract ./src -l "en_US,zh_CN,ja_JP"
# Update or create PO files for specific languages
transx update messages.pot -l "zh_CN,ja_JP,ko_KR"
# Auto-discover and update all language files
transx update messages.pot
# Update with custom output directory
transx update messages.pot -o ./locales
# Compile a single PO file
transx compile path/to/messages.po
# Compile all PO files in a directory
transx compile -d ./locales
# Compile multiple specific files
transx compile file1.po file2.po
# List all available locales in default directory
transx list
# List locales in a specific directory
transx list -d /path/to/locales
-d, --directory
: Specify working directory-o, --output
: Specify output file/directory-l, --languages
: Comma-separated list of language codes-p, --project
: Project name (for POT generation)-v, --version
: Project version (for POT generation)
For detailed help on any command:
transx <command> --help
TransX can be used with Qt applications in two ways:
Use TransX directly in your Qt application:
from PySide2.QtWidgets import QMainWindow
from transx import get_transx_instance
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.tx = get_transx_instance("myapp")
# Translate window title
self.setWindowTitle(self.tx.tr("My Application"))
# Translate menu items
file_menu = self.menuBar().addMenu(self.tx.tr("&File"))
file_menu.addAction(self.tx.tr("&Open"))
file_menu.addAction(self.tx.tr("&Save"))
For Qt's built-in translation system, you'll need to:
- First convert your .po files to .qm format using Qt's lrelease tool
- Install the .qm files using TransX's Qt extension
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QTranslator
from transx.extensions.qt import install_qt_translator
app = QApplication([])
translator = QTranslator()
# Install translator for specific locale
# Make sure qt_zh_CN.qm exists in ./translations directory
install_qt_translator(app, translator, "zh_CN", "./translations")
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# Note: Qt's tr() will only work with .qm files
# For Python strings, use TransX's tr() function
self.setWindowTitle("My Application") # This won't be translated
Converting .po to .qm files:
# Using Qt's lrelease tool
lrelease translations/zh_CN/LC_MESSAGES/messages.po -qm translations/qt_zh_CN.qm
Note: The
lrelease
tool is part of Qt's Linguist tools:
- Windows: Install with Qt installer from qt.io (Look for Qt Linguist under Tools)
- Linux: Install via package manager
# Ubuntu/Debian sudo apt-get install qttools5-dev-tools # Fedora sudo dnf install qt5-linguist # Arch Linux sudo pacman -S qt5-tools- macOS: Install via Homebrew
brew install qt5
The Qt integration supports:
- Loading .qm format translation files
- Multiple translator instances
- Note: Qt's built-in tr() function requires .qm files and won't work with .mo files
Extract translatable messages from your source code with powerful context support:
from transx.api.pot import PotExtractor
# Initialize extractor with output file
extractor = PotExtractor(pot_file="messages.pot")
# Add source files or directories to scan
extractor.add_source_file("app.py")
extractor.add_source_file("utils.py")
# Or scan entire directories
extractor.add_source_directory("src")
# Extract messages with project info
extractor.save_pot(
project="MyApp",
version="1.0.0",
copyright_holder="Your Name",
bugs_address="[email protected]"
)
Manage multiple translation instances for different applications or components:
from transx import get_transx_instance
# Create instances for different apps or components
app1 = get_transx_instance("app1", default_locale="en_US")
app2 = get_transx_instance("app2", default_locale="zh_CN")
# Each instance has its own:
# - Translation catalog
# - Locale settings
# - Message domains
app1.tr("Hello") # Uses app1's translations
app2.tr("Hello") # Uses app2's translations
# Switch locales independently
app1.switch_locale("ja_JP")
app2.switch_locale("ko_KR")
Multi-app support features:
- Independent translation catalogs
- Separate locale settings per instance
- Thread-safe operation
# UI Context
print(tx.tr("Open", context="button")) # 打开
print(tx.tr("Open", context="menu")) # 打开文件
# Part of Speech
print(tx.tr("Post", context="verb")) # 发布
print(tx.tr("Post", context="noun")) # 文章
# Scene Context
print(tx.tr("Welcome", context="login")) # 欢迎登录
print(tx.tr("Welcome", context="home")) # 欢迎回来
TransX provides comprehensive error handling with fallback mechanisms:
from transx import TransX
from transx.exceptions import LocaleNotFoundError, TranslationError
# Enable strict mode for development
tx = TransX(strict_mode=True)
try:
tx.load_catalog("invalid_locale")
except LocaleNotFoundError as e:
print(f"❌ Locale error: {e.message}")
try:
result = tx.translate("Hello", target_lang="invalid")
except TranslationError as e:
print(f"❌ Translation failed: {e.message}")
TransX is designed with performance in mind. We continuously monitor and optimize its performance through automated benchmarks.
View our performance benchmarks at: TransX Benchmarks
Our benchmark suite includes:
- Translation lookup performance
- Parameter substitution performance
- Locale switching performance
- Cache efficiency
- Memory usage
- Concurrent operations
- And more...
- Clone the repository:
git clone https://github.com/loonghao/transx.git
cd transx
- Install development dependencies:
pip install -r requirements-dev.txt
TransX follows a well-organized package structure:
transx/
├── transx/ # Main package directory
│ ├── __init__.py # Package initialization
│ ├── __version__.py # Version information
│ ├── api/ # Public API modules
│ │ ├── __init__.py
│ │ ├── mo.py # MO file operations
│ │ ├── po.py # PO file operations
│ │ └── pot.py # POT file operations
│ ├── app.py # Application management
│ ├── cli.py # Command-line interface
│ ├── constants.py # Constants and configurations
│ ├── context/ # Translation context management
│ │ ├── __init__.py
│ │ └── manager.py # Context manager implementation
│ ├── core.py # Core functionality
│ ├── exceptions.py # Custom exceptions
│ ├── extensions/ # Framework integrations
│ │ ├── __init__.py
│ │ └── qt.py # Qt support
│ └── internal/ # Internal implementation details
│ ├── __init__.py
│ ├── compat.py # Python 2/3 compatibility
│ ├── filesystem.py # File system operations
│ └── logging.py # Logging utilities
├── examples/ # Example code
├── locales/ # Translation files
├── tests/ # Test suite
├── nox_actions/ # Nox automation scripts
├── CHANGELOG.md # Version history
├── LICENSE # MIT License
├── README.md # English documentation
├── README_zh.md # Chinese documentation
├── noxfile.py # Test automation config
├── pyproject.toml # Project configuration
├── requirements.txt # Production dependencies
└── requirements-dev.txt # Development dependencies
We use Nox to automate development tasks. Here are the main commands:
# Run linting
nox -s lint
# Fix linting issues automatically
nox -s lint-fix
# Run tests
nox -s pytest
Tests are written using pytest and can be run using nox:
nox -s pytest
For running specific tests:
# Run a specific test file
nox -s pytest -- tests/test_core.py
# Run tests with specific markers
nox -s pytest -- -m "not integration"
We maintain high code quality standards using various tools:
- Linting: We use ruff and isort for code linting and formatting
- Type Checking: Static type checking with mypy
- Testing: Comprehensive test suite with pytest
- Coverage: Code coverage tracking with coverage.py
- CI/CD: Automated testing and deployment with GitHub Actions
Documentation is written in Markdown and is available in:
- README.md: Main documentation
- examples/: Example code and usage
- API documentation in source code
- Fork the repository
- Create a new branch for your feature
- Make your changes
- Run tests and linting
- Submit a pull request
Please ensure your PR:
- Passes all tests
- Includes appropriate documentation
- Follows our code style
- Includes test coverage for new features
This project is licensed under the MIT License - see the LICENSE file for details.