diff options
Diffstat (limited to 'tests/test_builders/test_build_gettext.py')
-rw-r--r-- | tests/test_builders/test_build_gettext.py | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/tests/test_builders/test_build_gettext.py b/tests/test_builders/test_build_gettext.py new file mode 100644 index 0000000..ddc6d30 --- /dev/null +++ b/tests/test_builders/test_build_gettext.py @@ -0,0 +1,235 @@ +"""Test the build process with gettext builder with the test root.""" + +import gettext +import os +import re +import subprocess +import sys +from subprocess import CalledProcessError + +import pytest + +from sphinx.builders.gettext import Catalog, MsgOrigin + +if sys.version_info[:2] >= (3, 11): + from contextlib import chdir +else: + from sphinx.util.osutil import _chdir as chdir + +_MSGID_PATTERN = re.compile(r'msgid "(.*)"') + + +def msgid_getter(msgid): + if m := _MSGID_PATTERN.search(msgid): + return m[1] + return None + + +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' + 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)] + + +@pytest.mark.sphinx('gettext', srcdir='root-gettext') +def test_build_gettext(app): + # Generic build; should fail only when the builder is horribly broken. + app.build(force_all=True) + + # 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() + + # regression test for issue #960 + catalog = (app.outdir / 'markup.pot').read_text(encoding='utf8') + assert 'msgid "something, something else, something more"' in catalog + + +@pytest.mark.sphinx('gettext', srcdir='root-gettext') +def test_msgfmt(app): + app.build(force_all=True) + + (app.outdir / 'en' / 'LC_MESSAGES').mkdir(parents=True, exist_ok=True) + with chdir(app.outdir): + try: + args = ['msginit', '--no-translator', '-i', 'markup.pot', '--locale', 'en_US'] + subprocess.run(args, capture_output=True, check=True) + 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: + args = ['msgfmt', 'en_US.po', + '-o', os.path.join('en', 'LC_MESSAGES', 'test_root.mo')] + 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' + + _ = gettext.translation('test_root', app.outdir, languages=['en']).gettext + assert _("Testing various markup") == "Testing various markup" + + +@pytest.mark.sphinx( + 'gettext', testroot='intl', srcdir='gettext', + confoverrides={'gettext_compact': False}) +def test_gettext_index_entries(app): + # regression test for #976 + app.build(filenames=[app.srcdir / 'index_entries.txt']) + + pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8') + msg_ids = list(filter(None, map(msgid_getter, pot.splitlines()))) + + assert msg_ids == [ + "i18n with index entries", + "index target section", + "this is :index:`Newsletter` target paragraph.", + "various index entries", + "That's all.", + "Mailing List", + "Newsletter", + "Recipients List", + "First", + "Second", + "Third", + "Entry", + "See", + ] + + +@pytest.mark.sphinx( + 'gettext', testroot='intl', srcdir='gettext', + confoverrides={'gettext_compact': False, + 'gettext_additional_targets': []}) +def test_gettext_disable_index_entries(app): + # regression test for #976 + app.env._pickled_doctree_cache.clear() # clear cache + app.build(filenames=[app.srcdir / 'index_entries.txt']) + + pot = (app.outdir / 'index_entries.pot').read_text(encoding='utf8') + msg_ids = list(filter(None, map(msgid_getter, pot.splitlines()))) + + assert msg_ids == [ + "i18n with index entries", + "index target section", + "this is :index:`Newsletter` target paragraph.", + "various index entries", + "That's all.", + ] + + +@pytest.mark.sphinx('gettext', testroot='intl', srcdir='gettext') +def test_gettext_template(app): + app.build(force_all=True) + + assert (app.outdir / 'sphinx.pot').is_file() + + result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8') + assert "Welcome" in result + assert "Sphinx %(version)s" in result + + +@pytest.mark.sphinx('gettext', testroot='gettext-template') +def test_gettext_template_msgid_order_in_sphinxpot(app): + app.build(force_all=True) + assert (app.outdir / 'sphinx.pot').is_file() + + result = (app.outdir / 'sphinx.pot').read_text(encoding='utf8') + assert re.search( + ('msgid "Template 1".*' + 'msgid "This is Template 1\\.".*' + 'msgid "Template 2".*' + 'msgid "This is Template 2\\.".*'), + result, + flags=re.DOTALL) + + +@pytest.mark.sphinx( + 'gettext', srcdir='root-gettext', + confoverrides={'gettext_compact': 'documentation'}) +def test_build_single_pot(app): + app.build(force_all=True) + + assert (app.outdir / 'documentation.pot').is_file() + + result = (app.outdir / 'documentation.pot').read_text(encoding='utf8') + assert re.search( + ('msgid "Todo".*' + 'msgid "Like footnotes.".*' + 'msgid "The minute.".*' + 'msgid "Generated section".*'), + result, + flags=re.DOTALL) + + +@pytest.mark.sphinx( + 'gettext', + testroot='intl_substitution_definitions', + srcdir='gettext-subst', + confoverrides={'gettext_compact': False, + 'gettext_additional_targets': ['image']}) +def test_gettext_prolog_epilog_substitution(app): + 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 = list(filter(None, map(msgid_getter, pot.splitlines()))) + + assert msg_ids == [ + "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', + confoverrides={'gettext_compact': False, + 'gettext_additional_targets': ['image']}) +def test_gettext_prolog_epilog_substitution_excluded(app): + # regression test for #9428 + app.build(force_all=True) + + assert (app.outdir / 'prolog_epilog_substitution_excluded.pot').is_file() + pot = (app.outdir / 'prolog_epilog_substitution_excluded.pot').read_text(encoding='utf8') + msg_ids = list(filter(None, map(msgid_getter, pot.splitlines()))) + + assert msg_ids == [ + "i18n without prologue and epilogue substitutions", + "This is content that does not include prologue and epilogue substitutions.", + ] |