sphinx/tests/test_builders/test_build_gettext.py

319 lines
9.5 KiB
Python
Raw Normal View History

2022-02-19 21:05:56 -06:00
"""Test the build process with gettext builder with the test root."""
2010-06-07 07:04:16 -05:00
2018-02-19 07:39:14 -06:00
import gettext
import re
import subprocess
2024-10-17 14:59:41 -05:00
from contextlib import chdir
2024-10-25 16:41:08 -05:00
from pathlib import Path
2022-10-17 09:54:59 -05:00
from subprocess import CalledProcessError
2010-06-08 23:46:30 -05:00
import pytest
from sphinx.builders.gettext import Catalog, MsgOrigin
_MSGID_PATTERN = re.compile(r'msgid "((?:\n|.)*?)"\nmsgstr', re.MULTILINE)
def get_msgids(pot):
matches = _MSGID_PATTERN.findall(pot)
return [m.replace('"\n"', '') for m in matches[1:]]
def test_Catalog_duplicated_message():
catalog = Catalog()
catalog.add('hello', MsgOrigin('/path/to/filename', 1))
catalog.add('hello', MsgOrigin('/path/to/filename', 1))
catalog.add('hello', MsgOrigin('/path/to/filename', 2))
catalog.add('hello', MsgOrigin('/path/to/yetanother', 1))
catalog.add('world', MsgOrigin('/path/to/filename', 1))
assert len(list(catalog)) == 2
msg1, msg2 = list(catalog)
assert msg1.text == 'hello'
2024-08-11 08:58:56 -05:00
assert msg1.locations == [
('/path/to/filename', 1),
('/path/to/filename', 2),
('/path/to/yetanother', 1),
]
assert msg2.text == 'world'
assert msg2.locations == [('/path/to/filename', 1)]
2024-08-11 08:58:56 -05:00
@pytest.mark.sphinx(
'gettext',
testroot='root',
2024-08-11 08:58:56 -05:00
srcdir='root-gettext',
)
def test_build_gettext(app):
# Generic build; should fail only when the builder is horribly broken.
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
2010-06-07 07:04:16 -05:00
# Do messages end up in the correct location?
# top-level documents end up in a message catalog
assert (app.outdir / 'extapi.pot').is_file()
# directory items are grouped into sections
assert (app.outdir / 'subdir.pot').is_file()
2010-06-08 23:46:30 -05:00
# regression test for issue #960
catalog = (app.outdir / 'markup.pot').read_text(encoding='utf8')
assert 'msgid "something, something else, something more"' in catalog
2010-06-17 04:46:49 -05:00
2024-08-11 08:58:56 -05:00
@pytest.mark.sphinx(
'gettext',
testroot='root',
2024-08-11 08:58:56 -05:00
srcdir='root-gettext',
)
def test_msgfmt(app):
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
(app.outdir / 'en' / 'LC_MESSAGES').mkdir(parents=True, exist_ok=True)
with chdir(app.outdir):
2010-06-08 23:46:30 -05:00
try:
2024-08-11 08:58:56 -05:00
args = [
'msginit',
'--no-translator',
'-i',
'markup.pot',
'--locale',
'en_US',
]
2022-10-17 09:54:59 -05:00
subprocess.run(args, capture_output=True, check=True)
2010-06-08 23:46:30 -05:00
except OSError:
pytest.skip() # most likely msginit was not found
except CalledProcessError as exc:
print(exc.stdout)
print(exc.stderr)
msg = f'msginit exited with return code {exc.returncode}'
raise AssertionError(msg) from exc
assert (app.outdir / 'en_US.po').is_file(), 'msginit failed'
try:
2024-08-11 08:58:56 -05:00
args = [
'msgfmt',
'en_US.po',
'-o',
2024-10-25 16:41:08 -05:00
Path('en', 'LC_MESSAGES', 'test_root.mo'),
2024-08-11 08:58:56 -05:00
]
2022-10-17 09:54:59 -05:00
subprocess.run(args, capture_output=True, check=True)
except OSError:
pytest.skip() # most likely msgfmt was not found
except CalledProcessError as exc:
print(exc.stdout)
print(exc.stderr)
msg = f'msgfmt exited with return code {exc.returncode}'
raise AssertionError(msg) from exc
mo = app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo'
assert mo.is_file(), 'msgfmt failed'
2010-08-15 05:30:13 -05:00
_ = gettext.translation('test_root', app.outdir, languages=['en']).gettext
2024-08-11 08:58:56 -05:00
assert _('Testing various markup') == 'Testing various markup'
@pytest.mark.sphinx(
2024-08-11 08:58:56 -05:00
'gettext',
testroot='intl',
srcdir='gettext',
confoverrides={'gettext_compact': False},
)
def test_gettext_index_entries(app):
# regression test for #976
2024-01-16 20:38:46 -06:00
app.build(filenames=[app.srcdir / 'index_entries.txt'])
pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8')
msg_ids = get_msgids(pot)
assert msg_ids == [
2024-08-11 08:58:56 -05:00
'i18n with index entries',
'index target section',
'this is :index:`Newsletter` target paragraph.',
'various index entries',
"That's all.",
2024-08-11 08:58:56 -05:00
'Mailing List',
'Newsletter',
'Recipients List',
'First',
'Second',
'Third',
'Entry',
'See',
2016-06-11 10:00:52 -05:00
]
@pytest.mark.sphinx(
2024-08-11 08:58:56 -05:00
'gettext',
testroot='intl',
srcdir='gettext',
confoverrides={'gettext_compact': False, 'gettext_additional_targets': []},
)
def test_gettext_disable_index_entries(app):
# regression test for #976
2023-01-03 22:22:20 -06:00
app.env._pickled_doctree_cache.clear() # clear cache
2024-01-16 20:38:46 -06:00
app.build(filenames=[app.srcdir / 'index_entries.txt'])
pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8')
msg_ids = get_msgids(pot)
assert msg_ids == [
2024-08-11 08:58:56 -05:00
'i18n with index entries',
'index target section',
'this is :index:`Newsletter` target paragraph.',
'various index entries',
"That's all.",
]
2024-08-11 08:58:56 -05:00
@pytest.mark.sphinx(
'gettext',
testroot='intl',
srcdir='gettext',
)
def test_gettext_template(app):
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
assert (app.outdir / 'sphinx.pot').is_file()
result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8')
2024-08-11 08:58:56 -05:00
assert 'Welcome' in result
assert 'Sphinx %(version)s' in result
2018-02-18 18:51:30 -06:00
@pytest.mark.sphinx('gettext', testroot='gettext-template')
def test_gettext_template_msgid_order_in_sphinxpot(app):
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
assert (app.outdir / 'sphinx.pot').is_file()
result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8')
assert re.search(
2024-08-11 08:58:56 -05:00
(
'msgid "Template 1".*'
'msgid "This is Template 1\\.".*'
'msgid "Template 2".*'
'msgid "This is Template 2\\.".*'
),
result,
2024-08-11 08:58:56 -05:00
flags=re.DOTALL,
)
@pytest.mark.sphinx('gettext', testroot='gettext-custom-output-template')
def test_gettext_custom_output_template(app):
app.build(force_all=True)
assert (app.outdir / 'index.pot').is_file()
result = (app.outdir / 'index.pot').read_text(encoding='utf8')
assert 'EVEN MORE DESCRIPTIVE TITLE' in result
@pytest.mark.sphinx(
2024-08-11 08:58:56 -05:00
'gettext',
testroot='root',
2024-08-11 08:58:56 -05:00
srcdir='root-gettext',
confoverrides={'gettext_compact': 'documentation'},
)
def test_build_single_pot(app):
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
assert (app.outdir / 'documentation.pot').is_file()
result = (app.outdir / 'documentation.pot').read_text(encoding='utf8')
assert re.search(
2024-08-11 08:58:56 -05:00
(
'msgid "Todo".*'
'msgid "Like footnotes.".*'
'msgid "The minute.".*'
'msgid "Generated section".*'
),
result,
2024-08-11 08:58:56 -05:00
flags=re.DOTALL,
)
@pytest.mark.sphinx(
'gettext',
testroot='intl_substitution_definitions',
srcdir='gettext-subst',
2024-08-11 08:58:56 -05:00
confoverrides={'gettext_compact': False, 'gettext_additional_targets': ['image']},
)
def test_gettext_prolog_epilog_substitution(app):
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
assert (app.outdir / 'prolog_epilog_substitution.pot').is_file()
pot = (app.outdir / 'prolog_epilog_substitution.pot').read_text(encoding='utf8')
msg_ids = get_msgids(pot)
assert msg_ids == [
2024-08-11 08:58:56 -05:00
'i18n with prologue and epilogue substitutions',
'This is content that contains |subst_prolog_1|.',
'Substituted image |subst_prolog_2| here.',
'subst_prolog_2',
'.. image:: /img.png',
'This is content that contains |subst_epilog_1|.',
'Substituted image |subst_epilog_2| here.',
'subst_epilog_2',
'.. image:: /i18n.png',
]
@pytest.mark.sphinx(
'gettext',
testroot='intl_substitution_definitions',
srcdir='gettext-subst',
2024-08-11 08:58:56 -05:00
confoverrides={'gettext_compact': False, 'gettext_additional_targets': ['image']},
)
def test_gettext_prolog_epilog_substitution_excluded(app):
# regression test for #9428
2024-01-16 20:38:46 -06:00
app.build(force_all=True)
assert (app.outdir / 'prolog_epilog_substitution_excluded.pot').is_file()
2024-08-11 08:58:56 -05:00
pot = (app.outdir / 'prolog_epilog_substitution_excluded.pot').read_text(
encoding='utf8'
)
msg_ids = get_msgids(pot)
assert msg_ids == [
2024-08-11 08:58:56 -05:00
'i18n without prologue and epilogue substitutions',
'This is content that does not include prologue and epilogue substitutions.',
]
@pytest.mark.sphinx(
2024-08-11 08:58:56 -05:00
'gettext',
testroot='root',
2024-08-11 08:58:56 -05:00
srcdir='gettext',
confoverrides={
'gettext_compact': False,
'gettext_additional_targets': ['literal-block', 'doctest-block'],
},
)
def test_gettext_literalblock_additional(app):
app.build(force_all=True)
assert (app.outdir / 'literalblock.pot').is_file()
pot = (app.outdir / 'literalblock.pot').read_text(encoding='utf8')
msg_ids = get_msgids(pot)
assert msg_ids == [
'i18n with literal block',
'Correct literal block::',
'this is\\nliteral block',
'Missing literal block::',
"That's all.",
'included raw.txt',
'===\\nRaw\\n===\\n\\n.. raw:: html\\n\\n <iframe src=\\"https://sphinx-doc.org\\"></iframe>\\n\\n',
'code blocks',
"def main\\n 'result'\\nend",
'#include <stdlib.h>\\nint main(int argc, char** argv)\\n{\\n return 0;\\n}',
'example of C language',
'#include <stdio.h>\\nint main(int argc, char** argv)\\n{\\n return 0;\\n}',
'literal-block\\nin list',
'test_code_for_noqa()\\ncontinued()',
'doctest blocks',
'>>> import sys # sys importing\\n>>> def main(): # define main '
"function\\n... sys.stdout.write('hello') # call write method of "
"stdout object\\n>>>\\n>>> if __name__ == '__main__': # if run this py "
'file as python script\\n... main() # call main',
]