Sphinx Internationalization Utility
sphinx-intl is a utility for Sphinx that simplifies the process of translating documentation. It helps manage `.pot` (Portable Object Template) and `.po` (Portable Object) files, making it easier to extract translatable messages, update translations, and build translated versions of Sphinx projects. The current version is 2.3.2, and it typically sees a few releases per year, keeping pace with Python and Sphinx updates.
Common errors
-
ERROR: Package 'sphinx-intl' requires a different Python: X.Y.Z not in '>=3.9'
cause Your Python version is too old for the installed or requested version of sphinx-intl.fixUpgrade your Python environment to version 3.9 or newer, or install an older compatible version of sphinx-intl (e.g., `pip install 'sphinx-intl<2.3.0'`). -
sphinx-intl: command not found
cause The `sphinx-intl` command-line tool is not installed or not available in your system's PATH.fixEnsure sphinx-intl is installed in your active Python environment (`pip install sphinx-intl`) and that your environment's `Scripts` or `bin` directory is correctly included in your system's PATH. -
sphinx-intl: error: argument -d/--locale-dir: directory not found: '_build/locale'
cause The directory specified with `-d` or `--locale-dir` does not exist. `sphinx-intl` requires this directory for `.po` and `.mo` files.fixEnsure the target locale directory exists before running `sphinx-intl` commands, or create it manually (e.g., `mkdir -p _build/locale`). The `init` command usually creates the initial structure, but `update` or `build` expect it to be present. -
WARNING: No .pot files found in the specified path: _build/gettext
cause The path provided to the `-p` or `--pot-dir` option either does not exist or contains no `.pot` (Portable Object Template) files.fixFirst, ensure `sphinx-build -b gettext ...` has been run successfully to generate `.pot` files in the specified directory. Then, verify that the `--pot-dir` argument points to the correct location.
Warnings
- breaking sphinx-intl dropped support for Python versions older than 3.9 in version 2.3.0. Projects using older Python versions will need to upgrade their Python environment or stick to an older sphinx-intl release.
- gotcha Prior to version 2.3.2, sphinx-intl's `update` command might not have correctly respected the `locale_dirs` setting when specified via `-c conf.py`. This could lead to `.po` files being generated or updated in unexpected locations.
- gotcha The behavior of `resource_name` in `.tx/config` files (used for Transifex integration) changed before 2.1.0 and was explicitly preserved to pre-2.1.0 behavior in 2.2.0. Users upgrading from very old versions might encounter unexpected resource naming if relying on Transifex.
Install
-
pip install sphinx-intl
Quickstart
import os
import shutil
import subprocess
import tempfile
# Create a temporary directory for the Sphinx project
temp_dir = tempfile.mkdtemp()
print(f"Working in temporary directory: {temp_dir}")
try:
project_dir = os.path.join(temp_dir, "myproject")
os.makedirs(project_dir)
# 1. Create a minimal conf.py
conf_content = '''
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
project = 'My Translated Project'
copyright = '2024, Author'
extensions = []
html_theme = 'alabaster'
'''
with open(os.path.join(project_dir, "conf.py"), "w") as f:
f.write(conf_content)
# 2. Create a minimal index.rst with translatable content
index_content = '''
.. _index:
Welcome to My Translated Project
================================
.. rst-class:: special
This is a paragraph that needs translation.
Another paragraph.
'''
with open(os.path.join(project_dir, "index.rst"), "w") as f:
f.write(index_content)
# 3. Generate POT files using sphinx-build
print("\n--- Generating .pot files ---")
gettext_output_dir = os.path.join(project_dir, "_build", "gettext")
subprocess.run(["sphinx-build", "-b", "gettext", project_dir, gettext_output_dir], check=True, capture_output=True, text=True)
# 4. Initialize locale directory for a target language (e.g., French)
print("\n--- Initializing French locale ---")
locale_dir = os.path.join(project_dir, "_build", "locale")
subprocess.run(["sphinx-intl", "init", "-l", "fr", "-d", locale_dir, "-p", gettext_output_dir], check=True, capture_output=True, text=True)
# 5. Update PO files (no changes yet, but good practice)
print("\n--- Updating PO files (no changes expected yet) ---")
subprocess.run(["sphinx-intl", "update", "-l", "fr", "-d", locale_dir, "-p", gettext_output_dir], check=True, capture_output=True, text=True)
# Simulate manual translation: modify the .po file
po_file_path = os.path.join(locale_dir, "fr", "LC_MESSAGES", "index.po")
if os.path.exists(po_file_path):
with open(po_file_path, "r") as f:
po_content = f.read()
po_content = po_content.replace(
'msgid "This is a paragraph that needs translation."',
'msgid "This is a paragraph that needs translation."\nmsgstr "Ceci est un paragraphe à traduire."
)
po_content = po_content.replace(
'msgid "Another paragraph."',
'msgid "Another paragraph."\nmsgstr "Un autre paragraphe."
)
with open(po_file_path, "w") as f:
f.write(po_content)
print(f"--- Translated {po_file_path} ---")
else:
print(f"Error: {po_file_path} not found.")
# 6. Build MO files from PO files using sphinx-intl build
print("\n--- Building MO files from PO files ---")
subprocess.run(["sphinx-intl", "build", "-d", locale_dir], check=True, capture_output=True, text=True)
# 7. Build HTML output for the translated language
print("\n--- Building translated HTML documentation ---")
html_output_dir_fr = os.path.join(project_dir, "_build", "html", "fr")
subprocess.run(["sphinx-build", "-b", "html", "-D", "language=fr", project_dir, html_output_dir_fr], check=True, capture_output=True, text=True)
print(f"\nSuccessfully built translated documentation in: {html_output_dir_fr}")
print("Check the generated HTML files, e.g., _build/html/fr/index.html")
except subprocess.CalledProcessError as e:
print(f"Error executing command: {e.cmd}")
print(f"Return code: {e.returncode}")
print(f"Stdout:\n{e.stdout}")
if e.stderr:
print(f"Stderr:\n{e.stderr}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
# Clean up the temporary directory
print(f"\nCleaning up temporary directory: {temp_dir}")
shutil.rmtree(temp_dir)