From 2690f0af876ee0a195c4f0ca10cf5189c117c111 Mon Sep 17 00:00:00 2001 From: Hazel Noack Date: Thu, 22 May 2025 15:47:46 +0200 Subject: [PATCH] edited templates --- src/templates/article.html | 16 +-- src/templates/article_translation.html | 10 +- stsg.toml | 2 + stsg/__init__.py | 1 + stsg/build.py | 157 +++++++++++++++---------- stsg/definitions.py | 29 ++++- 6 files changed, 134 insertions(+), 81 deletions(-) diff --git a/src/templates/article.html b/src/templates/article.html index 71517b8..106b1dd 100644 --- a/src/templates/article.html +++ b/src/templates/article.html @@ -4,7 +4,7 @@ - {{slug}} + {{name}} @@ -16,7 +16,7 @@ > @@ -33,7 +33,7 @@
-

{{t.language.flag}} {{t.title}}

+

{{t.language.flag}} {{t.name}}


{{t.preview}} @@ -41,7 +41,7 @@

@@ -62,15 +62,15 @@
@@ -83,7 +83,7 @@ diff --git a/src/templates/article_translation.html b/src/templates/article_translation.html index 0c7d017..fd559b2 100644 --- a/src/templates/article_translation.html +++ b/src/templates/article_translation.html @@ -4,7 +4,7 @@ - {{title}} + {{name}} @@ -18,7 +18,7 @@ @@ -39,7 +39,7 @@
-

{{c.title}}

+

{{c.name}}


{{c.preview}} @@ -47,7 +47,7 @@

@@ -61,7 +61,7 @@ diff --git a/stsg.toml b/stsg.toml index 6664dea..42865fb 100644 --- a/stsg.toml +++ b/stsg.toml @@ -1,3 +1,5 @@ +fall_back_to_overview_in_translation = false + [setup] source_directory = "src" dist_directory = "dist" diff --git a/stsg/__init__.py b/stsg/__init__.py index e10f970..bca6baa 100644 --- a/stsg/__init__.py +++ b/stsg/__init__.py @@ -1,5 +1,6 @@ class config: default_author = "anonymous" + fall_back_to_overview_in_translation = True class setup: source_directory = "src" diff --git a/stsg/build.py b/stsg/build.py index 1c16aa8..3206351 100644 --- a/stsg/build.py +++ b/stsg/build.py @@ -6,7 +6,7 @@ import os from markdown2 import markdown from typing import Optional, Union, Dict, Generator, List, DefaultDict, Any, TypedDict, Set from bs4 import BeautifulSoup -from collections import defaultdict +from collections import defaultdict, UserList import toml from datetime import datetime import jinja2 @@ -17,16 +17,6 @@ from .definitions import * from . import config -def get_first_header_content(content, fallback: str = ""): - soup = BeautifulSoup(content, 'html.parser') - for level in range(1, 7): - header = soup.find(f'h{level}') - if header: - return header.get_text(strip=True) - - return fallback - - def shorten_text_and_clean(html_string, max_length=config.formatting.preview_length): soup = BeautifulSoup(html_string, 'html.parser') @@ -128,10 +118,62 @@ def add_html_link(c): c["link"] = f'{name}' +def get_translated_articles(articles: List[Article], language_code: str = None) -> List[Union[ArticleTranslation, Article]]: + result = {} + + for a in articles: + if a.slug in result: + continue + + if language_code is None: + result[a.slug] = a + continue + + if not config.fall_back_to_overview_in_translation and language_code not in a.article_translations_map: + continue + + result[a.slug] = a.article_translations_map.get(language_code, a) + + +class ArticleList(UserList): + def __init__(self, iterable): + super().__init__(item for item in iterable) + + self.used_slugs = set() + + def append(self, a: Union[Article, str]): + if isinstance(a, str): + a = ARTICLE_LAKE[a] + + if a.slug in self.used_slugs: + return + + self.used_slugs.add(a.slug) + self.data.append(a) + + def extend(self, other): + for a in other: + self.append(a) + + def get_translated(self, language_code: str) -> ArticleList[Union[ArticleTranslation, Article]]: + res = ArticleList([]) + + for a in self: + if not config.fall_back_to_overview_in_translation and language_code not in a.article_translations_map: + continue + + res.append(a.article_translations_map.get(language_code, a)) + + return res + + @property + def context(self) -> List[Union[ArticleContext, ArticleTranslationContext]]: + return [a.context for a in self] class ArticleTranslation: article: Article + slug: str = property(fget=lambda self: self.article.slug) file: Path @cached_property @@ -178,31 +220,32 @@ class ArticleTranslation: self.article = article self.file = file - self.context = {} - self.cross_article_context = TRANSLATED_CROSS_ARTICLE_CONTEXT[self.language_code][self.article.slug] = {} + self.context = TRANSLATED_CROSS_ARTICLE_CONTEXT[self.language_code][self.article.slug] = {} + @cached_property + def name(self) -> str: + soup = BeautifulSoup(self.html_content, 'html.parser') + for level in range(1, 7): + header = soup.find(f'h{level}') + if header: + return header.get_text(strip=True) + + return self.article.name def __init_context__(self): - self.context["meta"] = self.article.context_shared + self.context["slug"] = self.article.slug + self.context["name"] = self.name self.context["url"] = self.url + add_html_link(self.context) + self.context["date"] = self.article.modified_at.strftime(config.formatting.datetime_format) + self.context["iso_date"] = self.article.modified_at.isoformat() + self.context["author"] = self.article.author + self.context["language"] = LANGUAGES[self.language_code] self.context["article_url"] = self.article.url - self.context["title"] = get_first_header_content(self.html_content, fallback=LANGUAGES[self.language_code]["native_name"]) - - self.cross_article_context.update(self.article.context_shared) - self.cross_article_context["title"] = self.context["title"] - self.cross_article_context["article_url"] = self.article.url - self.cross_article_context["url"] = self.url - add_html_link(self.cross_article_context) # get children - self.context["children"] = [ - c.article_translations_map[self.language_code].context for c in self.article.child_articles - if self.language_code in c.article_translations_map - ] - - self.linked_context = self.context["linked"] = [] - self.related_context = self.context["related"] = [] + self.context["children"] = self.article.child_articles.get_translated(self.language_code).context def __init_content_context__(self): template = jinja2.Template(self.html_content) @@ -216,17 +259,16 @@ class ArticleTranslation: template.environment.context_class = jinja2.runtime.Context accessed_keys = template.environment.accessed_keys - for key in accessed_keys: - a = ARTICLE_LAKE[key] - if self.language_code in a.article_translations_map: - self.linked_context.append(a.article_translations_map[self.language_code].context) - self.related_context.extend(self.linked_context) - self.related_context.extend(self.context["children"]) + for key in accessed_keys: + self.article.linked_articles.append(key) self.context["content"] = self.html_content self.context["preview"] = get_preview_text(html_string=self.html_content) + self.context["linked"] = self.article.linked_articles.get_translated(self.language_code).context + self.context["related"] = self.article.related_articles.get_translated(self.language_code).context + def build(self): self.dist_path.mkdir(parents=True, exist_ok=True) @@ -272,25 +314,17 @@ class Article: context_shared: Dict[str, Any] cross_article_context: Dict[str, Any] - child_articles: List[Article] - article_translations_list: List[ArticleTranslation] + child_articles: ArticleList[Article] + article_translations_list: ArticleList[ArticleTranslation] article_translations_map: Dict[str, ArticleTranslation] - linked_articles: List[Article] + linked_articles: ArticleList[Article] @cached_property - def related_articles(self) -> List[Article]: - used_slugs = set() - related = [] - - for a in [*self.child_articles, *self.linked_articles]: - if a.slug in used_slugs: - continue - - used_slugs.add(a.slug) - related.append(a) - - return related + def related_articles(self) -> ArticleList[Article]: + res = ArticleList(self.child_articles) + res.extend(self.linked_articles) + return res def __init__(self, directory: Path, article_path: Optional[List[str]] = None, is_root: bool = False, parent: Optional[Article] = None): self.directory = directory @@ -298,17 +332,15 @@ class Article: self.article_path: List[Article] = article_path or [] self.article_path.append(self) - self.context: ArticleContext = {} - self.context_shared = {} - self.cross_article_context = CROSS_ARTICLE_CONTEXT[self.slug] = {} + self.context = CROSS_ARTICLE_CONTEXT[self.slug] = {} ARTICLE_LAKE[self.slug] = self - self.linked_articles = [] + self.linked_articles = ArticleList([]) # build the tree - self.child_articles = [] - self.article_translations_list = [] + self.child_articles = ArticleList([]) + self.article_translations_list = ArticleList([]) self.article_translations_map = {} for c in self.directory.iterdir(): @@ -356,25 +388,24 @@ class Article: self.context["author"] = self.author # recursive context structures - self.context["translations"] = [t.context for t in self.self.article_translations_list] - self.context["children"] = [c.context for c in self.child_articles] + self.context["translations"] = self.article_translations_list.context + self.context["children"] = self.child_articles.context for lang, article in self.article_translations_map.items(): self.context[lang] = article.context for at in self.article_translations_list: at.__init_context__() - # the __init_context__ functions of the translations needs to be called first - # because the linked articles will be set there - self.context["linked"] = [l.context for l in self.linked_articles] - self.context["related"] = [r.context for r in self.related_articles] - for a in self.child_articles: a.__init_context__() def __init_content_context__(self): for at in self.article_translations_list: at.__init_content_context__() + + self.context["linked"] = self.linked_articles.context + self.context["related"] = self.related_articles.context + for a in self.child_articles: a.__init_content_context__() @@ -400,9 +431,9 @@ class ContextDict(jinja2.runtime.Context): # GLOBALS logger = logging.getLogger("stsg.build") +ARTICLE_LAKE: Dict[str, Article] = {} CROSS_ARTICLE_CONTEXT: Dict[str, Dict[str, Any]] = {} TRANSLATED_CROSS_ARTICLE_CONTEXT: Dict[str, Dict[str, Dict[str, Any]]] = defaultdict(dict) -ARTICLE_LAKE: Dict[str, Article] = {} ARTICLE_REFERENCE_VALUES: DefaultDict[str, Dict[str, str]] = defaultdict(dict) diff --git a/stsg/definitions.py b/stsg/definitions.py index 3537aa8..838452f 100644 --- a/stsg/definitions.py +++ b/stsg/definitions.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import TypedDict, List +from typing import TypedDict, List, Union class ArticleConfig(TypedDict): @@ -24,6 +24,14 @@ class ArticleContext(TypedDict): related: List[ArticleContext] +class TypedLanguage(TypedDict): + flag: str + name: str + native_name: str + priority: int + code: str + + class ArticleTranslationContext(TypedDict): slug: str name: str @@ -33,7 +41,18 @@ class ArticleTranslationContext(TypedDict): iso_date: str author: str - translations: List[ArticleTranslationContext] - children: List[ArticleTranslationContext] - linked: List[ArticleTranslationContext] - related: List[ArticleTranslationContext] + language: TypedLanguage + article_url: str + """ + The type Union[ArticleTranslationContext, ArticleContext] exist, + because if the article it is linked to doesn't exist in the same languages it uses the overview instead. + If you dislike this behavior set: + config.fall_back_to_overview_in_translation = False + """ + children: List[Union[ArticleTranslationContext, ArticleContext]] + + # you can't use these within the markdown text itself + content: str + preview: str + linked: List[Union[ArticleTranslationContext, ArticleContext]] + related: List[Union[ArticleTranslationContext, ArticleContext]]