diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 9196e6fb6..6aa285f5d 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -24,14 +24,14 @@ from sphinx.errors import SphinxError from sphinx.locale import __ from sphinx.util import logging from sphinx.util.matching import Matcher -from sphinx.util.osutil import SEP, relpath +from sphinx.util.osutil import SEP, canon_path, relpath logger = logging.getLogger(__name__) if False: # For type annotation - from typing import Callable, List, Set # NOQA + from typing import Callable, Generator, List, Set, Tuple # NOQA from sphinx.environment import BuildEnvironment # NOQA LocaleFileInfoBase = namedtuple('CatalogInfo', 'base_dir,domain,charset') @@ -81,6 +81,51 @@ class CatalogInfo(LocaleFileInfoBase): logger.warning(__('writing error: %s, %s'), self.mo_path, exc) +class CatalogRepository: + """A repository for message catalogs.""" + + def __init__(self, basedir, locale_dirs, language, encoding): + # type: (str, List[str], str, str) -> None + self.basedir = basedir + self._locale_dirs = locale_dirs + self.language = language + self.encoding = encoding + + @property + def locale_dirs(self): + # type: () -> Generator[str, None, None] + if not self.language: + return + + for locale_dir in self._locale_dirs: + locale_dir = path.join(self.basedir, locale_dir) + if path.exists(path.join(locale_dir, self.language, 'LC_MESSAGES')): + yield locale_dir + + @property + def pofiles(self): + # type: () -> Generator[Tuple[str, str], None, None] + for locale_dir in self.locale_dirs: + basedir = path.join(locale_dir, self.language, 'LC_MESSAGES') + for root, dirnames, filenames in os.walk(basedir): + # skip dot-directories + for dirname in dirnames: + if dirname.startswith('.'): + dirnames.remove(dirname) + + for filename in filenames: + if filename.endswith('.po'): + fullpath = path.join(root, filename) + yield basedir, relpath(fullpath, basedir) + + @property + def catalogs(self): + # type: () -> Generator[CatalogInfo, None, None] + for basedir, filename in self.pofiles: + domain = canon_path(path.splitext(filename)[0]) + yield CatalogInfo(basedir, domain, self.encoding) + + def find_catalog(docname, compaction): # type: (str, bool) -> str if compaction: diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py index b25e29575..5208689e8 100644 --- a/tests/test_util_i18n.py +++ b/tests/test_util_i18n.py @@ -255,3 +255,47 @@ def test_get_filename_for_language(app): app.env.config.figure_language_filename = '{root}.{invalid}{ext}' with pytest.raises(SphinxError): i18n.get_image_filename_for_language('foo.png', app.env) + + +def test_CatalogRepository(tempdir): + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES').makedirs() + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#') + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub').makedirs() + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test3.po').write_text('#') + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#') + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / '.dotdir').makedirs() + (tempdir / 'loc1' / 'xx' / 'LC_MESSAGES' / '.dotdir' / 'test5.po').write_text('#') + (tempdir / 'loc1' / 'yy' / 'LC_MESSAGES').makedirs() + (tempdir / 'loc1' / 'yy' / 'LC_MESSAGES' / 'test6.po').write_text('#') + (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES').makedirs() + (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#') + (tempdir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test7.po').write_text('#') + + # for language xx + repo = i18n.CatalogRepository(tempdir, ['loc1', 'loc2'], 'xx', 'utf-8') + assert list(repo.locale_dirs) == [str(tempdir / 'loc1'), + str(tempdir / 'loc2')] + assert all(isinstance(c, i18n.CatalogInfo) for c in repo.catalogs) + assert sorted(c.domain for c in repo.catalogs) == ['sub/test3', 'sub/test4', + 'test1', 'test1', 'test2', 'test7'] + + # for language yy + repo = i18n.CatalogRepository(tempdir, ['loc1', 'loc2'], 'yy', 'utf-8') + assert sorted(c.domain for c in repo.catalogs) == ['test6'] + + # unknown languages + repo = i18n.CatalogRepository(tempdir, ['loc1', 'loc2'], 'zz', 'utf-8') + assert sorted(c.domain for c in repo.catalogs) == [] + + # no languages + repo = i18n.CatalogRepository(tempdir, ['loc1', 'loc2'], None, 'utf-8') + assert sorted(c.domain for c in repo.catalogs) == [] + + # unknown locale_dirs + repo = i18n.CatalogRepository(tempdir, ['loc3'], None, 'utf-8') + assert sorted(c.domain for c in repo.catalogs) == [] + + # no locale_dirs + repo = i18n.CatalogRepository(tempdir, [], None, 'utf-8') + assert sorted(c.domain for c in repo.catalogs) == []