Skip to content

Commit

Permalink
translating admonitions
Browse files Browse the repository at this point in the history
  • Loading branch information
michalfapso authored and ultrabug committed Mar 1, 2024
1 parent 0b18dd6 commit a2c95bd
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/setup/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This plugin uses MkDocs event priority in order to reconfigure each of the build
|on_nav|-100|
|on_env|0|
|on_template_context|50|
|on_page_markdown|50|
|on_page_context|50|
|on_post_page|-100|
|on_post_build|-100|
Expand Down
1 change: 1 addition & 0 deletions docs/setup/setting-up-languages.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ plugins:
|link|no|`/<locale>/`|Used for the `mkdocs-material` language switcher. Absolute path used as the base of the language switcher|
|fixed_link|no||Used for the `mkdocs-material` language switcher. Fixed URL link used in the language switcher for this language|
|nav_translations|no||Key/value mapping used to [translate navigation items](localizing-navigation.md)|
|admonition_translations|no||Key/value mapping used to [translate admonitions](translating-content.md)|

Minimal example with two languages:

Expand Down
39 changes: 39 additions & 0 deletions docs/setup/translating-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,42 @@ site
Which means that the `image.png` and its `fr/image.png` localized counterpart can be referenced the same way as `![my image](image.png)` on both `index.md` and `index.fr.md` when using the `suffix` docs structure.

It works the same for the `folder` structure!


## Translating admonitions

This sub-option is a key/value mapping set per language and allows you to translate [admonition](https://python-markdown.github.io/extensions/admonition/) titles which don't have an explicit title defined.

### Language Sub-Option: `admonition_translations`

This example overrides admonition titles of the French version of the site.

``` yaml
plugins:
- i18n:
languages:
- locale: en
default: true
name: English
- locale: fr
name: Français
admonition_translations:
- tip: Conseil
- warning: Avertissement
```

and translates French markdowns from:

```
!!! tip
Bonjour le monde
```

to:

```
!!! tip "Conseil"
Bonjour le monde
```
1 change: 1 addition & 0 deletions mkdocs_static_i18n/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class I18nPluginLanguage(Config):
name = config_options.Type(str)
nav = config_options.Optional(config_options.Nav())
nav_translations = config_options.Optional(config_options.Type(dict))
admonition_translations = config_options.Optional(config_options.Type(dict))
site_author = config_options.Optional(config_options.Type(str))
site_description = config_options.Optional(config_options.Type(str))
site_name = config_options.Optional(config_options.Type(str))
Expand Down
35 changes: 35 additions & 0 deletions mkdocs_static_i18n/plugin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import re
import sys
from pathlib import PurePath
from typing import Optional
Expand Down Expand Up @@ -45,6 +46,14 @@ def on_config(self, config: MkDocsConfig):
f"{PurePath(config.site_dir) / path_suffix}"
)

admonition_translations = self.current_language_config.admonition_translations or {}
if len(admonition_translations) > 0 and (
"markdown_extensions" not in config or "admonition" not in config["markdown_extensions"]
):
log.warning(
"admonition_translations used, but admonitions won't be rendered properly without 'admonition' in mkdocs.yml's markdown_extensions."
)

# reconfigure the mkdocs config
return self.reconfigure_mkdocs_config(config)

Expand Down Expand Up @@ -129,6 +138,32 @@ def on_template_context(self, context, template_name, config):
context["i18n_alternates"] = self.i18n_files_per_language
return context

@plugins.event_priority(50)
def on_page_markdown(self, markdown, page, config, files):
"""
The page_markdown event is called after the page's markdown is loaded from file
and can be used to alter the Markdown source text.
Here we translate admonition types
"""
admonition_translations = self.current_language_config.admonition_translations or {}
RE = re.compile(
r'^(!!! ?)([\w\-]+(?: +[\w\-]+)*)(?: +"(.*?)")? *$'
) # Copied from https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/admonition.py and modified for a single-line processing
out = []
for line in markdown.splitlines():
m = RE.match(line)
if m:
type = m.group(2)
if (
m.group(3) is None or m.group(3).strip() == ''
) and type in admonition_translations:
title = admonition_translations[type]
line = m.group(1) + m.group(2) + f' "{title}"'
out.append(line)
markdown = "\n".join(out)
return markdown

@plugins.event_priority(50)
def on_page_context(self, context, page, config, nav):
"""
Expand Down
13 changes: 13 additions & 0 deletions tests/admonitions/index.fr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Page d'accueil (french version)

!!! tip
Titre implicite dérivé du type d'avertissement, peut être remplacé en définissant `admonition_translations`

!!!tip
Pareil sans espaces

!!! warning
Titre implicite dérivé du type d'avertissement, peut être remplacé en définissant `admonition_translations`

!!! warning "Heey"
Titre explicite, n'est pas traduit par `admonition_translations`
13 changes: 13 additions & 0 deletions tests/admonitions/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Home page

!!! tip
Implicit title derived from admonition type, can be overriden by setting `admonition_translations`

!!!tip
Same without space

!!! warning
Implicit title derived from admonition type, can be overriden by setting `admonition_translations`

!!! warning "Heey"
Explicit title, isn't translated by `admonition_translations`
103 changes: 103 additions & 0 deletions tests/test_admonitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import re
import logging
from pathlib import Path

from mkdocs.commands.build import build
from mkdocs.config.base import load_config

ADMONITIONS_CONFIG_WARNING = "mkdocs_static_i18n: admonition_translations used, but admonitions won't be rendered properly without 'admonition' in mkdocs.yml's markdown_extensions."

class LogHandlerList(logging.Handler):
def __init__(self):
super().__init__()
self.messages = []

def handle(self, record):
rv = self.filter(record)
if rv:
# Use levelno for keys so they can be sorted later
self.messages.append(record.getMessage())
return rv

def test_invalid_config():
mkdocs_config = load_config(
"tests/mkdocs.yml",
theme={"name": "material"},
docs_dir="admonitions/",
plugins={
"i18n": {
"languages": [
{
"locale": "en",
"name": "english",
"default": True,
},
{
"locale": "fr",
"name": "français",
"build": True,
"admonition_translations": {
"tip": "Conseil",
"warning": "Avertissement",
}
},
],
},
},
)

warning_list = LogHandlerList()
warning_list.setLevel(logging.WARNING)
logging.getLogger('mkdocs').addHandler(warning_list)

build(mkdocs_config)

assert(ADMONITIONS_CONFIG_WARNING in warning_list.messages)


def test_plugin_no_use_directory_urls_default_language_only():
mkdocs_config = load_config(
"tests/mkdocs.yml",
theme={"name": "material"},
docs_dir="admonitions/",
plugins={
"i18n": {
"languages": [
{
"locale": "en",
"name": "english",
"default": True,
},
{
"locale": "fr",
"name": "français",
"build": True,
"admonition_translations": {
"tip": "Conseil",
"warning": "Avertissement",
}
},
],
},
},
markdown_extensions=["admonition"],
)

warning_list = LogHandlerList()
warning_list.setLevel(logging.WARNING)
logging.getLogger('mkdocs').addHandler(warning_list)

build(mkdocs_config)

# assert(all(item == ADMONITIONS_CONFIG_WARNING) for item in warning_list.messages)
assert(ADMONITIONS_CONFIG_WARNING not in warning_list.messages)

site_dir = mkdocs_config["site_dir"]

with open(site_dir+'/index.html') as f:
admonition_titles = re.findall(r"<p class=[\"']admonition-title[\"']>([^<]*)", f.read())
assert(admonition_titles == ['Tip', 'Tip', 'Warning', 'Heey'])

with open(site_dir+'/fr/index.html') as f:
admonition_titles = re.findall(r"<p class=[\"']admonition-title[\"']>([^<]*)", f.read())
assert(admonition_titles == ['Conseil', 'Conseil', 'Avertissement', 'Heey'])
6 changes: 6 additions & 0 deletions tests/test_languages_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def test_plugin_languages_dual_lang():
"default": True,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand All @@ -95,6 +96,7 @@ def test_plugin_languages_dual_lang():
"default": False,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand Down Expand Up @@ -136,6 +138,7 @@ def test_plugin_languages_one_lang():
"default": True,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand Down Expand Up @@ -202,6 +205,7 @@ def test_plugin_languages_dual_lang_with_null():
"default": True,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand All @@ -219,6 +223,7 @@ def test_plugin_languages_dual_lang_with_null():
"default": False,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand All @@ -236,6 +241,7 @@ def test_plugin_languages_dual_lang_with_null():
"default": False,
"nav": None,
"nav_translations": None,
"admonition_translations": None,
"theme": None,
"site_name": None,
"copyright": None,
Expand Down

0 comments on commit a2c95bd

Please sign in to comment.