import gettext from gettext import GNUTranslations, NullTranslations from pathlib import Path from shutil import copy from typing import Any from jinja2.environment import Environment from jinja2.loaders import FileSystemLoader from jwebsite.content import Content, ContentDirectory from jwebsite.git import git_creation_date class Site: def __init__(self, root_directory: Path) -> None: self.__root_directory = root_directory self.__output_directory = root_directory / "build" self.__environment = Environment(loader=FileSystemLoader(searchpath=root_directory / "src")) self.__environment.filters.update({"output": self.__output, "git_creation_date": git_creation_date}) self.__content = ContentDirectory(root_directory / "content") self.__translations: dict[str, GNUTranslations | NullTranslations] = {} @property def content(self) -> ContentDirectory: 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: 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) content = template.render(site=self, **context) with open(output_path, "w") as output_file: output_file.write(content) def __output(self, path: str | Path) -> str: path = Path(path) if path.is_absolute(): src_path = path relative_src_path = src_path.relative_to(self.__content.path) else: src_path = self.__content.path / path relative_src_path = path dst_path = self.__output_directory / relative_src_path dst_path.parent.mkdir(parents=True, exist_ok=True) copy(src_path, dst_path, follow_symlinks=True) return f"/{relative_src_path}"