feat: allow to define translation for jinja2 i18n
This commit is contained in:
parent
e6363bea4e
commit
e898505125
|
|
@ -1,5 +1,4 @@
|
||||||
from functools import cache
|
from functools import cache
|
||||||
from gettext import textdomain
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable, Iterator
|
from typing import Any, Iterable, Iterator
|
||||||
|
|
||||||
|
|
@ -8,6 +7,8 @@ from yaml import Loader, load
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
|
current_language: str | None = None
|
||||||
|
|
||||||
def __init__(self, path: Path) -> None:
|
def __init__(self, path: Path) -> None:
|
||||||
self.__path = path
|
self.__path = path
|
||||||
|
|
||||||
|
|
@ -30,7 +31,7 @@ class ContentDirectory(Content):
|
||||||
|
|
||||||
def glob(self, pattern: str) -> Iterable[Content]:
|
def glob(self, pattern: str) -> Iterable[Content]:
|
||||||
for item in self.path.glob(pattern):
|
for item in self.path.glob(pattern):
|
||||||
yield self.load(str(item))
|
yield self.load(str(item.relative_to(self.path)))
|
||||||
|
|
||||||
@cache # noqa: B019
|
@cache # noqa: B019
|
||||||
def __load_children(self, name: str) -> Content:
|
def __load_children(self, name: str) -> Content:
|
||||||
|
|
@ -52,8 +53,9 @@ class ContentDirectory(Content):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_localized_path(path: Path) -> Path:
|
def __get_localized_path(path: Path) -> Path:
|
||||||
domain = textdomain()
|
if Content.current_language is None:
|
||||||
localized_path = path.with_name(f"{path.stem}-{domain}{path.suffix}")
|
return path
|
||||||
|
localized_path = path.with_name(f"{path.stem}-{Content.current_language}{path.suffix}")
|
||||||
if not localized_path.exists():
|
if not localized_path.exists():
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import gettext
|
||||||
|
from gettext import GNUTranslations, NullTranslations
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
@ -5,7 +7,7 @@ from typing import Any
|
||||||
from jinja2.environment import Environment
|
from jinja2.environment import Environment
|
||||||
from jinja2.loaders import FileSystemLoader
|
from jinja2.loaders import FileSystemLoader
|
||||||
|
|
||||||
from jwebsite.content import ContentDirectory
|
from jwebsite.content import Content, ContentDirectory
|
||||||
from jwebsite.git import git_creation_date
|
from jwebsite.git import git_creation_date
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -16,16 +18,34 @@ class Site:
|
||||||
self.__environment = Environment(loader=FileSystemLoader(searchpath=root_directory / "src"))
|
self.__environment = Environment(loader=FileSystemLoader(searchpath=root_directory / "src"))
|
||||||
self.__environment.filters.update({"output": self.__output, "git_creation_date": git_creation_date})
|
self.__environment.filters.update({"output": self.__output, "git_creation_date": git_creation_date})
|
||||||
self.__content = ContentDirectory(root_directory / "content")
|
self.__content = ContentDirectory(root_directory / "content")
|
||||||
|
self.__translations: dict[str, GNUTranslations | NullTranslations] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def content(self) -> ContentDirectory:
|
def content(self) -> ContentDirectory:
|
||||||
return self.__content
|
return self.__content
|
||||||
|
|
||||||
|
def set_translations(self, domain: str, locale_dir: str, languages: list[str]) -> None:
|
||||||
|
self.__environment.add_extension("jinja2.ext.i18n")
|
||||||
|
self.__translations["en"] = NullTranslations()
|
||||||
|
for language in languages:
|
||||||
|
self.__translations[language] = gettext.translation(
|
||||||
|
domain, localedir=str(locale_dir), languages=[language]
|
||||||
|
)
|
||||||
|
|
||||||
def render(self, source: str, output: str | Path, **context: Any) -> None:
|
def render(self, source: str, output: str | Path, **context: Any) -> None:
|
||||||
self.__output_directory.mkdir(parents=True, exist_ok=True)
|
if self.__translations:
|
||||||
|
for language, translation in self.__translations.items():
|
||||||
|
Content.current_language = language
|
||||||
|
self.__environment.install_gettext_translations(translation, newstyle=True) # type: ignore
|
||||||
|
self.__render(source, self.__output_directory / language / output, **context)
|
||||||
|
self.__environment.uninstall_gettext_translations(translation) # type: ignore
|
||||||
|
else:
|
||||||
|
self.__render(source, self.__output_directory / output, **context)
|
||||||
|
|
||||||
|
def __render(self, source: str, output_path: Path, **context: Any) -> None:
|
||||||
|
output_path.parent.mkdir(exist_ok=True, parents=True)
|
||||||
template = self.__environment.get_template(source)
|
template = self.__environment.get_template(source)
|
||||||
content = template.render(site=self, **context)
|
content = template.render(site=self, **context)
|
||||||
output_path = self.__output_directory / output
|
|
||||||
|
|
||||||
with open(output_path, "w") as output_file:
|
with open(output_path, "w") as output_file:
|
||||||
output_file.write(content)
|
output_file.write(content)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
from gettext import textdomain
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from pytest import raises
|
from pytest import raises
|
||||||
|
|
||||||
from jwebsite.content import ContentDirectory
|
from jwebsite.content import Content, ContentDirectory
|
||||||
|
|
||||||
|
|
||||||
def test_load_directory(datadir: Path) -> None:
|
def test_load_directory(datadir: Path) -> None:
|
||||||
|
|
@ -50,7 +49,7 @@ def test_load_markdown(datadir: Path) -> None:
|
||||||
|
|
||||||
def test_localized_content(datadir: Path) -> None:
|
def test_localized_content(datadir: Path) -> None:
|
||||||
content = ContentDirectory(datadir)
|
content = ContentDirectory(datadir)
|
||||||
textdomain("fr")
|
Content.current_language = "fr"
|
||||||
page = content.load(Path("page.md"))
|
page = content.load(Path("page.md"))
|
||||||
|
|
||||||
assert page.html == "<p>Contenu</p>"
|
assert page.html == "<p>Contenu</p>"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue