feat: allow to define translation for jinja2 i18n

This commit is contained in:
Corentin 2024-05-21 15:15:00 +02:00
parent e6363bea4e
commit e898505125
3 changed files with 31 additions and 10 deletions

View File

@ -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

View File

@ -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)

View File

@ -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>"