[gettext] fix flaky test on windows (#11940)

This commit is contained in:
Bénédikt Tran 2024-02-24 13:34:52 +01:00 committed by GitHub
parent faa33a53a3
commit 707bfbd669
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,7 +8,6 @@ import os.path
import re import re
import shutil import shutil
import time import time
from pathlib import Path
import pytest import pytest
from babel.messages import mofile, pofile from babel.messages import mofile, pofile
@ -19,10 +18,12 @@ from sphinx import locale
from sphinx.testing.util import assert_node, etree_parse, strip_escseq from sphinx.testing.util import assert_node, etree_parse, strip_escseq
from sphinx.util.nodes import NodeMatcher from sphinx.util.nodes import NodeMatcher
_CATALOG_LOCALE = 'xx'
sphinx_intl = pytest.mark.sphinx( sphinx_intl = pytest.mark.sphinx(
testroot='intl', testroot='intl',
confoverrides={ confoverrides={
'language': 'xx', 'locale_dirs': ['.'], 'language': _CATALOG_LOCALE, 'locale_dirs': ['.'],
'gettext_compact': False, 'gettext_compact': False,
}, },
) )
@ -38,22 +39,20 @@ def write_mo(pathname, po):
return mofile.write_mo(f, po) return mofile.write_mo(f, po)
@pytest.fixture(autouse=True) def _set_mtime_ns(target, value):
def _setup_intl(app_params): os.utime(target, ns=(value, value))
assert isinstance(app_params.kwargs['srcdir'], Path) return os.stat(target).st_mtime_ns
srcdir = app_params.kwargs['srcdir']
for dirpath, _dirs, files in os.walk(srcdir):
dirpath = Path(dirpath)
for f in [f for f in files if f.endswith('.po')]:
po = str(dirpath / f)
mo = srcdir / 'xx' / 'LC_MESSAGES' / (
os.path.relpath(po[:-3], srcdir) + '.mo')
if not mo.parent.exists():
mo.parent.mkdir(parents=True, exist_ok=True)
if not mo.exists() or os.stat(mo).st_mtime < os.stat(po).st_mtime:
# compile .mo file only if needed def _get_bom_intl_path(app):
write_mo(mo, read_po(po)) basedir = app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES'
return basedir / 'bom.po', basedir / 'bom.mo'
def _get_update_targets(app):
app.env.find_files(app.config, app.builder)
added, changed, removed = app.env.get_outdated_files(config_changed=False)
return added, changed, removed
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@ -316,7 +315,7 @@ def test_text_glossary_term_inconsistencies(app, warning):
def test_gettext_section(app): def test_gettext_section(app):
app.build() app.build()
# --- section # --- section
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'section.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'section.po')
actual = read_po(app.outdir / 'section.pot') actual = read_po(app.outdir / 'section.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -329,7 +328,7 @@ def test_text_section(app):
app.build() app.build()
# --- section # --- section
result = (app.outdir / 'section.txt').read_text(encoding='utf8') result = (app.outdir / 'section.txt').read_text(encoding='utf8')
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'section.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'section.po')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.string in result assert expect_msg.string in result
@ -468,12 +467,12 @@ def test_text_admonitions(app):
def test_gettext_toctree(app): def test_gettext_toctree(app):
app.build() app.build()
# --- toctree (index.rst) # --- toctree (index.rst)
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'index.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'index.po')
actual = read_po(app.outdir / 'index.pot') actual = read_po(app.outdir / 'index.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
# --- toctree (toctree.rst) # --- toctree (toctree.rst)
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'toctree.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'toctree.po')
actual = read_po(app.outdir / 'toctree.pot') actual = read_po(app.outdir / 'toctree.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -485,7 +484,7 @@ def test_gettext_toctree(app):
def test_gettext_table(app): def test_gettext_table(app):
app.build() app.build()
# --- toctree # --- toctree
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'table.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'table.po')
actual = read_po(app.outdir / 'table.pot') actual = read_po(app.outdir / 'table.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -498,7 +497,7 @@ def test_text_table(app):
app.build() app.build()
# --- toctree # --- toctree
result = (app.outdir / 'table.txt').read_text(encoding='utf8') result = (app.outdir / 'table.txt').read_text(encoding='utf8')
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'table.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'table.po')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.string in result assert expect_msg.string in result
@ -515,7 +514,7 @@ def test_text_toctree(app):
assert 'TABLE OF CONTENTS' in result assert 'TABLE OF CONTENTS' in result
# --- toctree (toctree.rst) # --- toctree (toctree.rst)
result = (app.outdir / 'toctree.txt').read_text(encoding='utf8') result = (app.outdir / 'toctree.txt').read_text(encoding='utf8')
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'toctree.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'toctree.po')
for expect_msg in (m for m in expect if m.id): for expect_msg in (m for m in expect if m.id):
assert expect_msg.string in result assert expect_msg.string in result
@ -526,7 +525,7 @@ def test_text_toctree(app):
def test_gettext_topic(app): def test_gettext_topic(app):
app.build() app.build()
# --- topic # --- topic
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'topic.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'topic.po')
actual = read_po(app.outdir / 'topic.pot') actual = read_po(app.outdir / 'topic.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -539,7 +538,7 @@ def test_text_topic(app):
app.build() app.build()
# --- topic # --- topic
result = (app.outdir / 'topic.txt').read_text(encoding='utf8') result = (app.outdir / 'topic.txt').read_text(encoding='utf8')
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'topic.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'topic.po')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.string in result assert expect_msg.string in result
@ -550,7 +549,7 @@ def test_text_topic(app):
def test_gettext_definition_terms(app): def test_gettext_definition_terms(app):
app.build() app.build()
# --- definition terms: regression test for #2198, #2205 # --- definition terms: regression test for #2198, #2205
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'definition_terms.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'definition_terms.po')
actual = read_po(app.outdir / 'definition_terms.pot') actual = read_po(app.outdir / 'definition_terms.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -562,7 +561,7 @@ def test_gettext_definition_terms(app):
def test_gettext_glossary_terms(app, warning): def test_gettext_glossary_terms(app, warning):
app.build() app.build()
# --- glossary terms: regression test for #1090 # --- glossary terms: regression test for #1090
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'glossary_terms.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'glossary_terms.po')
actual = read_po(app.outdir / 'glossary_terms.pot') actual = read_po(app.outdir / 'glossary_terms.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -576,7 +575,7 @@ def test_gettext_glossary_terms(app, warning):
def test_gettext_glossary_term_inconsistencies(app): def test_gettext_glossary_term_inconsistencies(app):
app.build() app.build()
# --- glossary term inconsistencies: regression test for #1090 # --- glossary term inconsistencies: regression test for #1090
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'glossary_terms_inconsistency.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'glossary_terms_inconsistency.po')
actual = read_po(app.outdir / 'glossary_terms_inconsistency.pot') actual = read_po(app.outdir / 'glossary_terms_inconsistency.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -588,7 +587,7 @@ def test_gettext_glossary_term_inconsistencies(app):
def test_gettext_literalblock(app): def test_gettext_literalblock(app):
app.build() app.build()
# --- gettext builder always ignores ``only`` directive # --- gettext builder always ignores ``only`` directive
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'literalblock.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'literalblock.po')
actual = read_po(app.outdir / 'literalblock.pot') actual = read_po(app.outdir / 'literalblock.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
if len(expect_msg.id.splitlines()) == 1: if len(expect_msg.id.splitlines()) == 1:
@ -604,7 +603,7 @@ def test_gettext_literalblock(app):
def test_gettext_buildr_ignores_only_directive(app): def test_gettext_buildr_ignores_only_directive(app):
app.build() app.build()
# --- gettext builder always ignores ``only`` directive # --- gettext builder always ignores ``only`` directive
expect = read_po(app.srcdir / 'xx' / 'LC_MESSAGES' / 'only.po') expect = read_po(app.srcdir / _CATALOG_LOCALE / 'LC_MESSAGES' / 'only.po')
actual = read_po(app.outdir / 'only.pot') actual = read_po(app.outdir / 'only.pot')
for expect_msg in [m for m in expect if m.id]: for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id] assert expect_msg.id in [m.id for m in actual if m.id]
@ -633,7 +632,7 @@ def test_translation_progress_substitution(app):
@pytest.mark.sphinx(testroot='intl', freshenv=True, confoverrides={ @pytest.mark.sphinx(testroot='intl', freshenv=True, confoverrides={
'language': 'xx', 'locale_dirs': ['.'], 'language': _CATALOG_LOCALE, 'locale_dirs': ['.'],
'gettext_compact': False, 'gettext_compact': False,
'translation_progress_classes': True, 'translation_progress_classes': True,
}) })
@ -681,50 +680,188 @@ def test_translation_progress_classes_true(app):
assert len(doctree[0]) == 20 assert len(doctree[0]) == 20
class _MockClock:
"""Object for mocking :func:`time.time_ns` (if needed).
Use :meth:`sleep` to make this specific clock sleep for some time.
"""
def time(self) -> int:
"""Nanosecond since 'fake' epoch."""
raise NotImplementedError
def sleep(self, ds: float) -> None:
"""Sleep *ds* seconds."""
raise NotImplementedError
class _MockWindowsClock(_MockClock):
"""Object for mocking :func:`time.time_ns` on Windows platforms.
The result is in 'nanoseconds' but with a microsecond resolution
so that the division by 1_000 does not cause rounding issues.
"""
def __init__(self) -> None:
self.us: int = 0 # current microsecond 'tick'
def time(self) -> int:
ret = 1_000 * self.us
self.us += 1
return ret
def sleep(self, ds: float) -> None:
self.us += int(ds * 1e6)
class _MockUnixClock(_MockClock):
"""Object for mocking :func:`time.time_ns` on Unix platforms.
Since nothing is needed for Unix platforms, this object acts as
a proxy so that the API is the same as :class:`_MockWindowsClock`.
"""
def time(self) -> int:
return time.time_ns()
def sleep(self, ds: float) -> None:
time.sleep(ds)
@pytest.fixture()
def mock_time_and_i18n(
monkeypatch: pytest.MonkeyPatch,
) -> tuple[pytest.MonkeyPatch, _MockClock]:
from sphinx.util.i18n import CatalogInfo
# save the 'original' definition
catalog_write_mo = CatalogInfo.write_mo
def mock_write_mo(self, locale, use_fuzzy=False):
catalog_write_mo(self, locale, use_fuzzy)
# ensure that the .mo file being written has a correct fake timestamp
_set_mtime_ns(self.mo_path, time.time_ns())
# see: https://github.com/pytest-dev/pytest/issues/363
with pytest.MonkeyPatch.context() as mock:
if os.name == 'posix':
clock = _MockUnixClock()
else:
# When using pytest.mark.parametrize() to emulate test repetition,
# the teardown phase on Windows fails due to an error apparently in
# the colorama.ansitowin32 module, so we forcibly disable colors.
mock.setenv('NO_COLOR', '1')
# apply the patch only for Windows
clock = _MockWindowsClock()
mock.setattr('time.time_ns', clock.time)
# Use clock.sleep() to emulate time.sleep() but do not try
# to mock the latter since this might break other libraries.
mock.setattr('sphinx.util.i18n.CatalogInfo.write_mo', mock_write_mo)
yield mock, clock
@sphinx_intl @sphinx_intl
# use individual shared_result directory to avoid "incompatible doctree" error # use the same testroot as 'gettext' since the latter contains less PO files
@pytest.mark.sphinx(testroot='builder-gettext-dont-rebuild-mo') @pytest.mark.sphinx('dummy', testroot='builder-gettext-dont-rebuild-mo', freshenv=True)
def test_gettext_dont_rebuild_mo(make_app, app_params): def test_dummy_should_rebuild_mo(mock_time_and_i18n, make_app, app_params):
# --- don't rebuild by .mo mtime mock, clock = mock_time_and_i18n
def get_update_targets(app_): assert os.name == 'posix' or clock.time() == 0
app_.env.find_files(app_.config, app_.builder)
added, changed, removed = app_.env.get_outdated_files(config_changed=False)
return added, changed, removed
args, kwargs = app_params args, kwargs = app_params
app = make_app(*args, **kwargs)
po_path, mo_path = _get_bom_intl_path(app)
# creation time of the those files (order does not matter)
bom_rst = app.srcdir / 'bom.rst'
bom_rst_time = time.time_ns()
index_rst = app.srcdir / 'index.rst'
index_rst_time = time.time_ns()
po_time = time.time_ns()
# patch the 'creation time' of the source files
assert _set_mtime_ns(po_path, po_time) == po_time
assert _set_mtime_ns(bom_rst, bom_rst_time) == bom_rst_time
assert _set_mtime_ns(index_rst, index_rst_time) == index_rst_time
assert not mo_path.exists()
# when writing mo files, the counter is updated by calling
# patch_write_mo which is called to create .mo files (and
# thus the timestamp of the files are not those given by
# the OS but our fake ones)
app.build()
assert mo_path.exists()
# Do a real sleep on POSIX, or simulate a sleep on Windows
# to ensure that calls to time.time_ns() remain consistent.
clock.sleep(0.1 if os.name == 'posix' else 1)
# check that the source files were not modified
assert bom_rst.stat().st_mtime_ns == bom_rst_time
assert index_rst.stat().st_mtime_ns == index_rst_time
# check that the 'bom' document is discovered after the .mo
# file has been written on the disk (i.e., read_doc() is called
# after the creation of the .mo files)
assert app.env.all_docs['bom'] > mo_path.stat().st_mtime_ns // 1000
# phase1: build document with non-gettext builder and generate mo file in srcdir
app0 = make_app('dummy', *args, **kwargs)
app0.build()
time.sleep(0.01)
assert (app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').exists()
# Since it is after the build, the number of documents to be updated is 0 # Since it is after the build, the number of documents to be updated is 0
update_targets = get_update_targets(app0) update_targets = _get_update_targets(app)
assert update_targets[1] == set(), update_targets assert update_targets[1] == set()
# When rewriting the timestamp of mo file, the number of documents to be # When rewriting the timestamp of mo file, the number of documents to be
# updated will be changed. # updated will be changed.
mtime = (app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').stat().st_mtime new_mo_time = time.time_ns()
os.utime(app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo', (mtime + 5, mtime + 5)) assert _set_mtime_ns(mo_path, new_mo_time) == new_mo_time
update_targets = get_update_targets(app0) update_targets = _get_update_targets(app)
assert update_targets[1] == {'bom'}, update_targets assert update_targets[1] == {'bom'}
mock.undo() # explicit call since it's not a context
# Because doctree for gettext builder can not be shared with other builders, # remove all sources for the next test
# erase doctreedir before gettext build. shutil.rmtree(app.srcdir, ignore_errors=True)
shutil.rmtree(app0.doctreedir) time.sleep(0.1 if os.name == 'posix' else 0.5) # real sleep
# phase2: build document with gettext builder.
@sphinx_intl
@pytest.mark.sphinx('gettext', testroot='builder-gettext-dont-rebuild-mo', freshenv=True)
def test_gettext_dont_rebuild_mo(mock_time_and_i18n, app):
mock, clock = mock_time_and_i18n
assert os.name == 'posix' or clock.time() == 0
assert app.srcdir.exists()
# patch the 'creation time' of the source files
bom_rst = app.srcdir / 'bom.rst'
bom_rst_time = time.time_ns()
assert _set_mtime_ns(bom_rst, bom_rst_time) == bom_rst_time
index_rst = app.srcdir / 'index.rst'
index_rst_time = time.time_ns()
assert _set_mtime_ns(index_rst, index_rst_time) == index_rst_time
# phase 1: create fake MO file in the src directory
po_path, mo_path = _get_bom_intl_path(app)
write_mo(mo_path, read_po(po_path))
po_time = time.time_ns()
assert _set_mtime_ns(po_path, po_time) == po_time
# phase 2: build document with gettext builder.
# The mo file in the srcdir directory is retained. # The mo file in the srcdir directory is retained.
app = make_app('gettext', *args, **kwargs)
app.build() app.build()
time.sleep(0.01) # Do a real sleep on POSIX, or simulate a sleep on Windows
# to ensure that calls to time.time_ns() remain consistent.
clock.sleep(0.5 if os.name == 'posix' else 1)
# Since it is after the build, the number of documents to be updated is 0 # Since it is after the build, the number of documents to be updated is 0
update_targets = get_update_targets(app) update_targets = _get_update_targets(app)
assert update_targets[1] == set(), update_targets assert update_targets[1] == set()
# Even if the timestamp of the mo file is updated, the number of documents # Even if the timestamp of the mo file is updated, the number of documents
# to be updated is 0. gettext builder does not rebuild because of mo update. # to be updated is 0. gettext builder does not rebuild because of mo update.
os.utime(app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo', (mtime + 10, mtime + 10)) new_mo_time = time.time_ns()
update_targets = get_update_targets(app) assert _set_mtime_ns(mo_path, new_mo_time) == new_mo_time
assert update_targets[1] == set(), update_targets update_targets = _get_update_targets(app)
assert update_targets[1] == set()
mock.undo() # remove the patch
# remove all sources for the next test
shutil.rmtree(app.srcdir, ignore_errors=True)
time.sleep(0.1 if os.name == 'posix' else 0.5) # real sleep
@sphinx_intl @sphinx_intl
@ -875,15 +1012,16 @@ def test_html_rebuild_mo(app):
app.build() app.build()
# --- rebuild by .mo mtime # --- rebuild by .mo mtime
app.build() app.build()
app.env.find_files(app.config, app.builder) _, updated, _ = _get_update_targets(app)
_, updated, _ = app.env.get_outdated_files(config_changed=False) assert updated == set()
assert len(updated) == 0
mtime = (app.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').stat().st_mtime _, bom_file = _get_bom_intl_path(app)
os.utime(app.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo', (mtime + 5, mtime + 5)) old_mtime = bom_file.stat().st_mtime
app.env.find_files(app.config, app.builder) new_mtime = old_mtime + (dt := 5)
_, updated, _ = app.env.get_outdated_files(config_changed=False) os.utime(bom_file, (new_mtime, new_mtime))
assert len(updated) == 1 assert old_mtime + dt == new_mtime, (old_mtime + dt, new_mtime)
_, updated, _ = _get_update_targets(app)
assert updated == {'bom'}
@sphinx_intl @sphinx_intl
@ -1222,7 +1360,7 @@ def test_additional_targets_should_not_be_translated(app):
'html', 'html',
srcdir='test_additional_targets_should_be_translated', srcdir='test_additional_targets_should_be_translated',
confoverrides={ confoverrides={
'language': 'xx', 'locale_dirs': ['.'], 'language': _CATALOG_LOCALE, 'locale_dirs': ['.'],
'gettext_compact': False, 'gettext_compact': False,
'gettext_additional_targets': [ 'gettext_additional_targets': [
'index', 'index',
@ -1300,7 +1438,7 @@ def test_additional_targets_should_be_translated(app):
'html', 'html',
testroot='intl_substitution_definitions', testroot='intl_substitution_definitions',
confoverrides={ confoverrides={
'language': 'xx', 'locale_dirs': ['.'], 'language': _CATALOG_LOCALE, 'locale_dirs': ['.'],
'gettext_compact': False, 'gettext_compact': False,
'gettext_additional_targets': [ 'gettext_additional_targets': [
'index', 'index',
@ -1342,7 +1480,7 @@ def test_text_references(app, warning):
'text', 'text',
testroot='intl_substitution_definitions', testroot='intl_substitution_definitions',
confoverrides={ confoverrides={
'language': 'xx', 'locale_dirs': ['.'], 'language': _CATALOG_LOCALE, 'locale_dirs': ['.'],
'gettext_compact': False, 'gettext_compact': False,
}, },
) )
@ -1368,7 +1506,7 @@ SUBSTITUTED IMAGE [image: SUBST_EPILOG_2 TRANSLATED][image] HERE.
@pytest.mark.sphinx( @pytest.mark.sphinx(
'dummy', testroot='images', 'dummy', testroot='images',
srcdir='test_intl_images', srcdir='test_intl_images',
confoverrides={'language': 'xx'}, confoverrides={'language': _CATALOG_LOCALE},
) )
def test_image_glob_intl(app): def test_image_glob_intl(app):
app.build() app.build()
@ -1412,7 +1550,7 @@ def test_image_glob_intl(app):
'dummy', testroot='images', 'dummy', testroot='images',
srcdir='test_intl_images', srcdir='test_intl_images',
confoverrides={ confoverrides={
'language': 'xx', 'language': _CATALOG_LOCALE,
'figure_language_filename': '{root}{ext}.{language}', 'figure_language_filename': '{root}{ext}.{language}',
}, },
) )