Chrome speaks the site's language: site.yaml lang + i18n table

The strings the portal itself says - Asked by, Also worth asking,
Sign in, the not-found page, defaults - translate via a small en/no
table selected by site.yaml's lang, which also sets the html lang
attribute. Content keeps speaking for itself; unknown languages fall
back to English per key.

Also: a scheme-gated markdown image now swallows its alt text instead
of leaking it as stray text - this is the fix for the test that has
been red since 0.3.19 (publish is tag-triggered and does not gate on
the test workflow; caught late).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y42TyF8Zu7NGRR2893vNcZ
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-01 17:23:28 +02:00
co-authored by Claude Fable 5
parent 528e2badaf
commit b259bf39bb
4 changed files with 145 additions and 18 deletions
+13 -4
View File
@@ -183,6 +183,7 @@ pub fn render_inline_markdown(text: &str) -> String {
use pulldown_cmark::{html, Event, Options, Parser, Tag, TagEnd};
let parser = Parser::new_ext(text, Options::empty());
let mut in_link = 0usize;
let mut in_dropped_image = 0usize;
let filtered = parser.filter_map(|event| match event {
Event::Html(_) | Event::InlineHtml(_) => None,
Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph) => None,
@@ -200,17 +201,20 @@ pub fn render_inline_markdown(text: &str) -> String {
None
}
// Images take the same gate as links: https or same-origin
// only - no data:, no plain http.
// only - no data:, no plain http. Unlike a dropped link (whose
// label is real text worth keeping), a dropped image's alt
// text is a caption for something that isn't there - swallow it.
Event::Start(Tag::Image { dest_url, .. })
if !(dest_url.starts_with("https://") || dest_url.starts_with('/')) =>
{
in_link += 1;
in_dropped_image += 1;
None
}
Event::End(TagEnd::Image) if in_link > 0 => {
in_link -= 1;
Event::End(TagEnd::Image) if in_dropped_image > 0 => {
in_dropped_image -= 1;
None
}
Event::Text(_) if in_dropped_image > 0 => None,
other => Some(other),
});
let mut out = String::new();
@@ -518,6 +522,11 @@ pub struct SiteConfig {
/// intrinsic pixel height.
#[serde(default)]
pub wordmark_height: Option<f32>,
/// BCP 47-ish language code for the portal's own chrome strings
/// ("Asked by", the nav lead...) and the html lang attribute.
/// `None` means "en"; unknown codes fall back to English per key.
#[serde(default)]
pub lang: Option<String>,
#[serde(default)]
pub hero: HeroConfig,
}