Repository: mkdocs/mkdocs
Pull request #3272 (2023-06-22 21:31:45)

Automatically generate the list of locales for docs


Patch:
diff --git a/docs/dev-guide/translations.md b/docs/dev-guide/translations.md
index 80df04b5..ea3e5a87 100644
--- a/docs/dev-guide/translations.md
+++ b/docs/dev-guide/translations.md
@@ -213,9 +213,7 @@ Finally, run `mkdocs serve` to check out your new localized version of the theme
 
 ## Updating theme documentation
 
-Update the lists of supported translations for each translated theme located at
-[Choosing your theme](../user-guide/choosing-your-theme.md)
-(`docs/user-guide/choosing-your-theme.md`), in their __`locale`__ options.
+The page [Choosing your theme](../user-guide/choosing-your-theme.md) updates by itself with all available locale options.
 
 ## Contributing translations
 
diff --git a/docs/hooks.py b/docs/hooks.py
new file mode 100644
index 00000000..1ab58b88
--- /dev/null
+++ b/docs/hooks.py
@@ -0,0 +1,33 @@
+import os.path
+import re
+from pathlib import Path
+
+from mkdocs.config.defaults import MkDocsConfig
+from mkdocs.structure.nav import Page
+
+
+def _get_language_of_translation_file(path: Path) -> str:
+    with path.open(encoding='utf-8') as f:
+        translation_line = f.readline()
+    m = re.search('^# (.+) translations ', translation_line)
+    assert m
+    return m[1]
+
+
+def on_page_markdown(markdown: str, page: Page, config: MkDocsConfig, **kwargs):
+    if page.file.src_uri == 'user-guide/choosing-your-theme.md':
+        here = Path(config.config_file_path or '').parent
+
+        def replacement(m: re.Match) -> str:
+            lines = []
+            for d in sorted(here.glob(m[2])):
+                lang = _get_language_of_translation_file(Path(d, 'LC_MESSAGES', 'messages.po'))
+                lines.append(f'{m[1]}`{d.name}`: {lang}')
+            return '\n'.join(lines)
+
+        return re.sub(
+            r'^( *\* )\(see the list of existing directories `(.+)`\)$',
+            replacement,
+            markdown,
+            flags=re.MULTILINE,
+        )
diff --git a/docs/user-guide/choosing-your-theme.md b/docs/user-guide/choosing-your-theme.md
index 58a738c9..ea7da128 100644
--- a/docs/user-guide/choosing-your-theme.md
+++ b/docs/user-guide/choosing-your-theme.md
@@ -108,20 +108,7 @@ supports the following options:
     The following locales are supported by this theme:
 
     * `en`: English (default)
-    * `de`: German
-    * `es`: Spanish
-    * `fa`: Persian (Farsi)
-    * `fr`: French
-    * `id`: Indonesian
-    * `it`: Italian
-    * `ja`: Japanese
-    * `nb`: Norwegian Bokmål
-    * `nn`: Norwegian Nynorsk
-    * `pt_BR`: Portuguese (Brazil)
-    * `ru`: Russian
-    * `tr`: Turkish
-    * `uk`: Ukrainian
-    * `zh_CN`: Simplified Chinese
+    * (see the list of existing directories `mkdocs/themes/mkdocs/locales/*/`)
 
     See the guide on [localizing your theme] for more information.
 
@@ -198,18 +185,7 @@ theme supports the following options:
     The following locales are supported by this theme:
 
     * `en`: English (default)
-    * `de`: German
-    * `es`: Spanish
-    * `fa`: Persian (Farsi)
-    * `fr`: French
-    * `id`: Indonesian
-    * `it`: Italian
-    * `ja`: Japanese
-    * `pt_BR`: Portuguese (Brazil)
-    * `ru`: Russian
-    * `tr`: Turkish
-    * `uk`: Ukrainian
-    * `zh_CN`: Simplified Chinese
+    * (see the list of existing directories `mkdocs/themes/readthedocs/locales/*/`)
 
     See the guide on [localizing your theme] for more information.
 
diff --git a/docs/user-guide/localizing-your-theme.md b/docs/user-guide/localizing-your-theme.md
index f6de982e..ae0e7baf 100644
--- a/docs/user-guide/localizing-your-theme.md
+++ b/docs/user-guide/localizing-your-theme.md
@@ -31,8 +31,8 @@ underscore. For example, some possible locales for English might include `en`,
 For a list of locales supported by the theme you are using, see that theme's
 documentation.
 
-- [mkdocs]
-- [readthedocs]
+- [mkdocs](choosing-your-theme.md#mkdocs-locale)
+- [readthedocs](choosing-your-theme.md#readthedocs-locale)
 
 WARNING:
 If you configure a language locale which is not yet supported by the theme
@@ -58,8 +58,6 @@ If a theme has not yet been translated into your language, feel free to
 contribute a translation using the [Translation Guide].
 
 [Translation Guide]: ../dev-guide/translations.md
-[mkdocs]: choosing-your-theme.md#mkdocs-locale
-[readthedocs]: choosing-your-theme.md#readthedocs-locale
 [locale]: configuration.md#locale
 [theme]: configuration.md#theme
 [ISO-639-1]: https://en.wikipedia.org/wiki/ISO_639-1
diff --git a/mkdocs.yml b/mkdocs.yml
index b0129746..a3ed5a5c 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -46,6 +46,9 @@ markdown_extensions:
 
 copyright: Copyright &copy; 2014 <a href="https://twitter.com/starletdreaming">Tom Christie</a>, Maintained by the <a href="/about/release-notes/#maintenance-team">MkDocs Team</a>.
 
+hooks:
+    - docs/hooks.py
+
 plugins:
     - search
     - redirects:
diff --git a/mkdocs/commands/get_deps.py b/mkdocs/commands/get_deps.py
index 9c8cc436..9caaf4fd 100644
--- a/mkdocs/commands/get_deps.py
+++ b/mkdocs/commands/get_deps.py
@@ -97,8 +97,15 @@ def get_deps(projects_file_url: str, config_file_path: str | None = None) -> Non
     with _open_config_file(config_file_path) as f:
         cfg = utils.yaml_load(f, loader=YamlLoader)  # type: ignore
 
+    packages_to_install = set()
+
     if all(c not in cfg for c in ('site_name', 'theme', 'plugins', 'markdown_extensions')):
         log.warning("The passed config file doesn't seem to be a mkdocs.yml config file")
+    else:
+        if dig(cfg, 'theme.locale') not in (NotFound, 'en'):
+            packages_to_install.add('mkdocs[i18n]')
+        else:
+            packages_to_install.add('mkdocs')
 
     try:
         theme = cfg['theme']['name']
@@ -120,7 +127,6 @@ def get_deps(projects_file_url: str, config_file_path: str | None = None) -> Non
     content = download_and_cache_url(projects_file_url, datetime.timedelta(days=7))
     projects = yaml.safe_load(content)['projects']
 
-    packages_to_install = set()
     for project in projects:
         for kind, wanted in wanted_plugins:
             available = strings(project.get(kind.projects_key, ()))
diff --git a/pyproject.toml b/pyproject.toml
index e76ca8a9..4a3def01 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -168,13 +168,13 @@ lint = [
     "flake8 mkdocs",
 ]
 check = [
-    "isort --check-only --diff mkdocs",
-    "black -q --check --diff mkdocs",
+    "isort --check-only --diff mkdocs docs",
+    "black -q --check --diff mkdocs docs",
     "lint",
 ]
 format = [
-    "isort -q mkdocs",
-    "black -q mkdocs",
+    "isort -q mkdocs docs",
+    "black -q mkdocs docs",
 ]
 
 [tool.hatch.envs.lint]


Test patch:
diff --git a/mkdocs/tests/get_deps_tests.py b/mkdocs/tests/get_deps_tests.py
index 0b2153ad..18d00094 100644
--- a/mkdocs/tests/get_deps_tests.py
+++ b/mkdocs/tests/get_deps_tests.py
@@ -41,7 +41,7 @@ class TestGetDeps(unittest.TestCase):
         cfg = '''
             plugins: [search]
         '''
-        self._test_get_deps(cfg, [])
+        self._test_get_deps(cfg, ['mkdocs'])
 
     def test_mkdocs_config(self):
         cfg = '''
@@ -82,6 +82,7 @@ class TestGetDeps(unittest.TestCase):
             [
                 'markdown-callouts',
                 'mdx-gh-links',
+                'mkdocs',
                 'mkdocs-autorefs',
                 'mkdocs-click',
                 'mkdocs-literate-nav',
@@ -104,7 +105,9 @@ class TestGetDeps(unittest.TestCase):
                   emoji_index: !!python/name:materialx.emoji.twemoji
                   emoji_generator: !!python/name:materialx.emoji.to_svg
         '''
-        self._test_get_deps(cfg, ['mkdocs-code-validator', 'mkdocs-material', 'pymdown-extensions'])
+        self._test_get_deps(
+            cfg, ['mkdocs', 'mkdocs-code-validator', 'mkdocs-material', 'pymdown-extensions']
+        )
 
     def test_theme_precedence(self):
         cfg = '''
@@ -112,19 +115,19 @@ class TestGetDeps(unittest.TestCase):
               - tags
             theme: material
         '''
-        self._test_get_deps(cfg, ['mkdocs-material'])
+        self._test_get_deps(cfg, ['mkdocs', 'mkdocs-material'])
 
         cfg = '''
             plugins:
               - material/tags
         '''
-        self._test_get_deps(cfg, ['mkdocs-material'])
+        self._test_get_deps(cfg, ['mkdocs', 'mkdocs-material'])
 
         cfg = '''
             plugins:
               - tags
         '''
-        self._test_get_deps(cfg, ['mkdocs-plugin-tags'])
+        self._test_get_deps(cfg, ['mkdocs', 'mkdocs-plugin-tags'])
 
     def test_nonexistent(self):
         cfg = '''
@@ -143,7 +146,7 @@ class TestGetDeps(unittest.TestCase):
             WARNING:Extension 'saqdhyndpvpa' is not provided by any registered project
         """
         with self._assert_logs(expected_logs):
-            self._test_get_deps(cfg, ['mkdocs-redirects'])
+            self._test_get_deps(cfg, ['mkdocs', 'mkdocs-redirects'])
 
     def test_git_and_shadowed(self):
         cfg = '''
@@ -151,11 +154,19 @@ class TestGetDeps(unittest.TestCase):
             plugins: [blog]
         '''
         self._test_get_deps(
-            cfg, ['git+https://github.com/andyoakley/mkdocs-blog', 'mkdocs-bootstrap4']
+            cfg, ['git+https://github.com/andyoakley/mkdocs-blog', 'mkdocs', 'mkdocs-bootstrap4']
         )
 
     def test_multi_theme(self):
         cfg = '''
             theme: minty
         '''
-        self._test_get_deps(cfg, ['mkdocs-bootswatch'])
+        self._test_get_deps(cfg, ['mkdocs', 'mkdocs-bootswatch'])
+
+    def test_with_locale(self):
+        cfg = '''
+            theme:
+                name: mkdocs
+                locale: uk
+        '''
+        self._test_get_deps(cfg, ['mkdocs[i18n]'])