From 846fc04444151017f0fd779f5a0b99e62d5e70b4 Mon Sep 17 00:00:00 2001 From: m Date: Wed, 1 Apr 2026 12:49:34 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20i18n=20template=20infrastructure=20?= =?UTF-8?q?=E2=80=94=20render.sh=20reads=20=5Fen=20vars,=20emits=20data-de?= =?UTF-8?q?/data-en?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 of i18n rollout: - render.sh: i18n_attrs helper, reads *_en fields from site.yaml, emits data-de/data-en attributes on title, description, role, tagline, cta, tags, section titles, card titles/descriptions, bio, content - base.html: i18n.js auto-included, title/description get i18n attrs - All 6 templates: translatable elements get i18n attr placeholders, footer toggle button with machine-translation disclaimer - ichbinotto.de pilot: added machine-translation disclaimer per m's request Templated sites can now be translated by adding _en fields to site.yaml. --- render.sh | 69 ++++++++++++++++++++++++++++++---- sites/ichbinotto.de/index.html | 3 +- templates/base.html | 5 ++- templates/editorial.html | 9 +++-- templates/fun.html | 8 +++- templates/minimal.html | 8 +++- templates/person-dark.html | 7 +++- templates/person-light.html | 7 +++- templates/product-dark.html | 9 +++-- 9 files changed, 101 insertions(+), 24 deletions(-) diff --git a/render.sh b/render.sh index dbaa74b..d01189c 100755 --- a/render.sh +++ b/render.sh @@ -34,13 +34,42 @@ cta_text=$(yq -r '.vars.cta.text // ""' "$SITE_YAML") cta_href=$(yq -r '.vars.cta.href // "#"' "$SITE_YAML") year=$(date +%Y) +# i18n: helper to generate data-de/data-en attribute string +i18n_attrs() { + local de="$1" en="$2" + if [ -n "$en" ] && [ "$en" != "null" ]; then + de=$(echo "$de" | sed 's/"/\"/g') + en=$(echo "$en" | sed 's/"/\"/g') + echo " data-de=\"${de}\" data-en=\"${en}\"" + fi +} + +# i18n: read English overrides +title_en=$(yq -r '.title_en // ""' "$SITE_YAML") +description_en=$(yq -r '.description_en // ""' "$SITE_YAML") +role_en=$(yq -r '.vars.role_en // ""' "$SITE_YAML") +tagline_en=$(yq -r '.vars.tagline_en // ""' "$SITE_YAML") +cta_text_en=$(yq -r '.vars.cta.text_en // ""' "$SITE_YAML") + +# i18n: build attribute strings for simple fields +title_i18n=$(i18n_attrs "$title" "$title_en") +description_i18n=$(i18n_attrs "$description" "$description_en") +role_i18n=$(i18n_attrs "$role" "$role_en") +tagline_i18n=$(i18n_attrs "$tagline" "$tagline_en") +cta_i18n=$(i18n_attrs "$cta_text" "$cta_text_en") + # Build tags HTML tags_html="" tag_count=$(yq -r '.vars.tags | length' "$SITE_YAML" 2>/dev/null || echo "0") if [ "$tag_count" -gt 0 ]; then for i in $(seq 0 $((tag_count - 1))); do tag=$(yq -r ".vars.tags[$i]" "$SITE_YAML") - tags_html="${tags_html} ${tag}\n" + tag_en=$(yq -r ".vars.tags_en[$i] // \"\"" "$SITE_YAML" 2>/dev/null || echo "") + tag_i18n="" + if [ -n "$tag_en" ] && [ "$tag_en" != "null" ]; then + tag_i18n="$(i18n_attrs "$tag" "$tag_en")" + fi + tags_html="${tags_html} ${tag}\n" done fi @@ -53,17 +82,25 @@ if [ "$section_count" -gt 0 ]; then sec_title=$(yq -r ".vars.sections[$i].title // \"\"" "$SITE_YAML") if [ "$sec_type" = "features" ]; then + sec_title_en=$(yq -r ".vars.sections[$i].title_en // \"\"" "$SITE_YAML") sections_html="${sections_html}
\n" - [ -n "$sec_title" ] && sections_html="${sections_html}

${sec_title}

\n" + if [ -n "$sec_title" ]; then + sec_title_i18n=$(i18n_attrs "$sec_title" "$sec_title_en") + sections_html="${sections_html} ${sec_title}\n" + fi sections_html="${sections_html}
\n" item_count=$(yq -r ".vars.sections[$i].items | length" "$SITE_YAML" 2>/dev/null || echo "0") for j in $(seq 0 $((item_count - 1))); do item_title=$(yq -r ".vars.sections[$i].items[$j].title" "$SITE_YAML") item_desc=$(yq -r ".vars.sections[$i].items[$j].desc // \"\"" "$SITE_YAML") + item_title_en=$(yq -r ".vars.sections[$i].items[$j].title_en // \"\"" "$SITE_YAML") + item_desc_en=$(yq -r ".vars.sections[$i].items[$j].desc_en // \"\"" "$SITE_YAML") + item_title_i18n=$(i18n_attrs "$item_title" "$item_title_en") + item_desc_i18n=$(i18n_attrs "$item_desc" "$item_desc_en") sections_html="${sections_html}
\n" - sections_html="${sections_html}

${item_title}

\n" - [ -n "$item_desc" ] && sections_html="${sections_html}

${item_desc}

\n" + sections_html="${sections_html} ${item_title}\n" + [ -n "$item_desc" ] && sections_html="${sections_html} ${item_desc}

\n" sections_html="${sections_html}
\n" done @@ -71,9 +108,15 @@ if [ "$section_count" -gt 0 ]; then elif [ "$sec_type" = "profile" ]; then bio=$(yq -r ".vars.sections[$i].bio // \"\"" "$SITE_YAML") + bio_en=$(yq -r ".vars.sections[$i].bio_en // \"\"" "$SITE_YAML") + sec_title_en=$(yq -r ".vars.sections[$i].title_en // \"\"" "$SITE_YAML") sections_html="${sections_html}
\n" - [ -n "$sec_title" ] && sections_html="${sections_html}

${sec_title}

\n" - sections_html="${sections_html}

${bio}

\n" + if [ -n "$sec_title" ]; then + sec_title_i18n=$(i18n_attrs "$sec_title" "$sec_title_en") + sections_html="${sections_html} ${sec_title}\n" + fi + bio_i18n=$(i18n_attrs "$bio" "$bio_en") + sections_html="${sections_html}

${bio}

\n" sections_html="${sections_html}
\n" fi done @@ -82,9 +125,15 @@ fi # Build content HTML (for editorial template) content_html="" content=$(yq -r '.vars.content // ""' "$SITE_YAML") +content_i18n="" if [ -n "$content" ] && [ "$content" != "null" ]; then # Convert newlines to paragraphs content_html=$(echo "$content" | sed 's/^$/<\/p>

/g' | sed '1s/^/

/' | sed '$s/$/<\/p>/') + content_en=$(yq -r '.vars.content_en // ""' "$SITE_YAML") + if [ -n "$content_en" ] && [ "$content_en" != "null" ]; then + content_html_en=$(echo "$content_en" | sed 's/^$/<\/p>

/g' | sed '1s/^/

/' | sed '$s/$/<\/p>/') + content_i18n=$(i18n_attrs "$content_html" "$content_html_en") + fi fi # Read template file and extract CSS/body sections @@ -184,7 +233,13 @@ BEGIN { -e "s|{{cta_text}}|${cta_text}|g" \ -e "s|{{cta_href}}|${cta_href}|g" \ -e "s|{{year}}|${year}|g" \ - -e "s|{{domain}}|${domain}|g" | \ + -e "s|{{domain}}|${domain}|g" \ + -e "s|{{title_i18n}}|$(echo "$title_i18n" | sed 's/[&/\]/\\&/g')|g" \ + -e "s|{{description_i18n}}|$(echo "$description_i18n" | sed 's/[&/\]/\\&/g')|g" \ + -e "s|{{role_i18n}}|$(echo "$role_i18n" | sed 's/[&/\]/\\&/g')|g" \ + -e "s|{{tagline_i18n}}|$(echo "$tagline_i18n" | sed 's/[&/\]/\\&/g')|g" \ + -e "s|{{cta_i18n}}|$(echo "$cta_i18n" | sed 's/[&/\]/\\&/g')|g" \ + -e "s|{{content_i18n}}|$(echo "$content_i18n" | sed 's/[&/\]/\\&/g')|g" | \ sed "s|{{tags_html}}|$(printf '%b' "$tags_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g" | \ sed "s|{{sections_html}}|$(printf '%b' "$sections_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g" | \ sed "s|{{content_html}}|$(printf '%b' "$content_html" | sed 's/[&/\]/\\&/g; s/$/\\/' | sed '$ s/\\$//')|g" diff --git a/sites/ichbinotto.de/index.html b/sites/ichbinotto.de/index.html index 1640f16..d6d84e6 100644 --- a/sites/ichbinotto.de/index.html +++ b/sites/ichbinotto.de/index.html @@ -435,7 +435,8 @@

Otto — mai-otto.de — ein Projekt von msbls.de

- + +
Maschinell übersetzt
diff --git a/templates/base.html b/templates/base.html index 5920c01..619c868 100644 --- a/templates/base.html +++ b/templates/base.html @@ -3,8 +3,8 @@ - {{title}} - + {{title}} + {{fonts}} @@ -18,5 +18,6 @@ {{body}} + diff --git a/templates/editorial.html b/templates/editorial.html index cdc98a7..74e2d03 100644 --- a/templates/editorial.html +++ b/templates/editorial.html @@ -70,14 +70,17 @@ {{template_body_start}}
-

{{title}}

-
{{tagline}}
+ {{title}} +
{{tagline}}
-
+
{{content_html}}
{{template_body_end}} diff --git a/templates/fun.html b/templates/fun.html index dcd5bcb..3365b5a 100644 --- a/templates/fun.html +++ b/templates/fun.html @@ -56,8 +56,12 @@ {{template_body_start}}
{{emoji}}
-

{{title}}

-
{{tagline}}
+ {{title}} +
{{tagline}}
{{sections_html}} +
+ +
Maschinell übersetzt +
{{template_body_end}} diff --git a/templates/minimal.html b/templates/minimal.html index c74035c..265d006 100644 --- a/templates/minimal.html +++ b/templates/minimal.html @@ -30,7 +30,11 @@ {{template_css_end}} {{template_body_start}}
-

{{title}}

-
{{tagline}}
+ {{title}} +
{{tagline}}
+
+ +
Maschinell übersetzt +
{{template_body_end}} diff --git a/templates/person-dark.html b/templates/person-dark.html index 5f802f0..557a1de 100644 --- a/templates/person-dark.html +++ b/templates/person-dark.html @@ -139,8 +139,8 @@
{{initials}}

{{name}}

-
{{role}}
-
{{tagline}}
+
{{role}}
+
{{tagline}}
@@ -151,6 +151,9 @@
{{template_body_end}} diff --git a/templates/person-light.html b/templates/person-light.html index 2ca8089..a567ca6 100644 --- a/templates/person-light.html +++ b/templates/person-light.html @@ -141,8 +141,8 @@
{{initials}}

{{name}}

-
{{role}}
-
{{tagline}}
+
{{role}}
+
{{tagline}}
@@ -153,6 +153,9 @@
{{template_body_end}} diff --git a/templates/product-dark.html b/templates/product-dark.html index 4da0832..26cea33 100644 --- a/templates/product-dark.html +++ b/templates/product-dark.html @@ -95,18 +95,21 @@ {{template_body_start}}
-

{{title}}

-
{{tagline}}
+ {{title}} +
{{tagline}}
{{sections_html}}
{{template_body_end}}