diff --git a/CHANGES b/CHANGES index 33d20a45bf..2278f24864 100644 --- a/CHANGES +++ b/CHANGES @@ -43,6 +43,8 @@ Features added * #9691: C, added new info-field ``retval`` for :rst:dir:`c:function` and :rst:dir:`c:macro`. * C++, added new info-field ``retval`` for :rst:dir:`cpp:function`. +* #9618: i18n: Add :confval:`gettext_allow_fuzzy_translations` to allow "fuzzy" + messages for translation * #9672: More CSS classes on Python domain descriptions * #9695: More CSS classes on Javascript domain descriptions * #9683: Revert the removal of ``add_stylesheet()`` API. It will be kept until diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index 46c82e56d5..6725bd3e0c 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -802,6 +802,13 @@ documentation on :ref:`intl` for details. .. versionchanged:: 1.5 Use ``locales`` directory as a default value +.. confval:: gettext_allow_fuzzy_translations + + If true, "fuzzy" messages in the message catalogs are used for translation. + The default is ``False``. + + .. versionadded:: 4.3 + .. confval:: gettext_compact .. versionadded:: 1.1 diff --git a/sphinx/application.py b/sphinx/application.py index 4a75a83fec..ec0234a4e6 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -284,7 +284,8 @@ def _init_i18n(self) -> None: self.config.language, self.config.source_encoding) for catalog in repo.catalogs: if catalog.domain == 'sphinx' and catalog.is_outdated(): - catalog.write_mo(self.config.language) + catalog.write_mo(self.config.language, + self.config.gettext_allow_fuzzy_translations) locale_dirs: List[Optional[str]] = list(repo.locale_dirs) locale_dirs += [None] diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 5ad9895390..64c621a1c5 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -217,7 +217,8 @@ def cat2relpath(cat: CatalogInfo) -> str: for catalog in status_iterator(catalogs, __('writing output... '), "darkgreen", len(catalogs), self.app.verbosity, stringify_func=cat2relpath): - catalog.write_mo(self.config.language) + catalog.write_mo(self.config.language, + self.config.gettext_allow_fuzzy_translations) def compile_all_catalogs(self) -> None: repo = CatalogRepository(self.srcdir, self.config.locale_dirs, diff --git a/sphinx/config.py b/sphinx/config.py index 2ca20cb488..05bcdeccc5 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -103,6 +103,7 @@ class Config: 'language': (None, 'env', [str]), 'locale_dirs': (['locales'], 'env', []), 'figure_language_filename': ('{root}.{language}{ext}', 'env', [str]), + 'gettext_allow_fuzzy_translations': (False, 'gettext', []), 'master_doc': ('index', 'env', []), 'root_doc': (lambda config: config.master_doc, 'env', []), diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index e82e33f578..02b42cf0b3 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -59,7 +59,7 @@ def is_outdated(self) -> bool: not path.exists(self.mo_path) or path.getmtime(self.mo_path) < path.getmtime(self.po_path)) - def write_mo(self, locale: str) -> None: + def write_mo(self, locale: str, use_fuzzy: bool = False) -> None: with open(self.po_path, encoding=self.charset) as file_po: try: po = read_po(file_po, locale) @@ -69,7 +69,7 @@ def write_mo(self, locale: str) -> None: with open(self.mo_path, 'wb') as file_mo: try: - write_mo(file_mo, po) + write_mo(file_mo, po, use_fuzzy) except Exception as exc: logger.warning(__('writing error: %s, %s'), self.mo_path, exc) diff --git a/tests/test_intl.py b/tests/test_intl.py index 30beb11355..3b54063efc 100644 --- a/tests/test_intl.py +++ b/tests/test_intl.py @@ -1301,6 +1301,44 @@ def getwarning(warnings): return strip_escseq(warnings.getvalue().replace(os.sep, '/')) +@pytest.mark.sphinx('html', testroot='basic', + srcdir='gettext_allow_fuzzy_translations', + confoverrides={ + 'language': 'de', + 'gettext_allow_fuzzy_translations': True + }) +def test_gettext_allow_fuzzy_translations(app): + locale_dir = app.srcdir / 'locales' / 'de' / 'LC_MESSAGES' + locale_dir.makedirs() + with (locale_dir / 'index.po').open('wb') as f: + catalog = Catalog() + catalog.add('features', 'FEATURES', flags=('fuzzy',)) + pofile.write_po(f, catalog) + + app.build() + content = (app.outdir / 'index.html').read_text() + assert 'FEATURES' in content + + +@pytest.mark.sphinx('html', testroot='basic', + srcdir='gettext_disallow_fuzzy_translations', + confoverrides={ + 'language': 'de', + 'gettext_allow_fuzzy_translations': False + }) +def test_gettext_disallow_fuzzy_translations(app): + locale_dir = app.srcdir / 'locales' / 'de' / 'LC_MESSAGES' + locale_dir.makedirs() + with (locale_dir / 'index.po').open('wb') as f: + catalog = Catalog() + catalog.add('features', 'FEATURES', flags=('fuzzy',)) + pofile.write_po(f, catalog) + + app.build() + content = (app.outdir / 'index.html').read_text() + assert 'FEATURES' not in content + + @pytest.mark.sphinx('html', testroot='basic', confoverrides={'language': 'de'}) def test_customize_system_message(make_app, app_params, sphinx_test_tempdir): try: