diff --git a/news/changelog-1.11.md b/news/changelog-1.11.md index 35f6ee3a28..33d99e7049 100644 --- a/news/changelog-1.11.md +++ b/news/changelog-1.11.md @@ -1,5 +1,11 @@ All changes included in 1.11: +## Formats + +### All Formats + +- ([#14772](https://github.com/quarto-dev/quarto-cli/issues/14772)): Custom `language` keys now reach templates through `$quarto.language.$`. A key that Quarto does not ship passed schema validation and was merged over the defaults, then discarded before templates saw it, so it expanded to an empty string with no warning. (author: @mcanouil) + ## Engines ### `knitr` diff --git a/src/core/language.ts b/src/core/language.ts index 52f3d39294..09b76a6228 100644 --- a/src/core/language.ts +++ b/src/core/language.ts @@ -163,10 +163,13 @@ export function translationsForLang(language: FormatLanguage, lang: string) { let translations = {} as FormatLanguage; Object.keys(language).forEach((key) => { // crossrefs can be custom, so be more lenient + // any other non-object value is a user or extension defined string, + // objects are locale variations and are merged below instead if ( kLanguageDefaultsKeys.includes(key) || key.match(/^crossref-.*-title$/) || - key.match(/^crossref-.*-prefix$/) + key.match(/^crossref-.*-prefix$/) || + typeof language[key] !== "object" ) { translations[key] = language[key]; } diff --git a/tests/docs/smoke-all/2026/08/13/issue-14772.qmd b/tests/docs/smoke-all/2026/08/13/issue-14772.qmd new file mode 100644 index 0000000000..f9a88d2c6c --- /dev/null +++ b/tests/docs/smoke-all/2026/08/13/issue-14772.qmd @@ -0,0 +1,41 @@ +--- +title: "Custom `language` keys reach the template namespace (#14772)" +format: + typst: + template-partials: + - typst-show.typ + keep-typ: true +language: + toc-title-document: "Overridden built-in" + custom-key: "Custom value" + en: + variation-key: "Variation value" +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - 'built-in overridden: `Overridden built-in`' + - 'built-in untouched: `Abstract`' + - 'custom key: `Custom value`' + - 'variation key: `Variation value`' + - + - 'custom key: ``' + - 'variation key: ``' + noErrors: true +--- + +Regression test for #14772. `translationsForLang` rebuilt the language table +from an allow-list, and `formatLanguage` ran it after merging the user's +`language` object over the defaults, so a key Quarto does not ship was +accepted by the schema, merged, and then discarded before templates saw it. +`$quarto.language.custom-key$` expanded to an empty string with no warning. + +The four keys read back by `typst-show.typ` isolate the parts that must keep +working alongside the fix: an override of a built-in key still wins over the +default, an untouched built-in key still resolves to its default, and a +locale-variation sub-object still merges through the variation loop rather +than leaking as an object, which is what the non-object test in the filter +protects. Only the custom key regressed. + +The end. diff --git a/tests/docs/smoke-all/2026/08/13/typst-show.typ b/tests/docs/smoke-all/2026/08/13/typst-show.typ new file mode 100644 index 0000000000..8e8eb08c24 --- /dev/null +++ b/tests/docs/smoke-all/2026/08/13/typst-show.typ @@ -0,0 +1,10 @@ +#show: doc => { + [built-in overridden: `$quarto.language.toc-title-document$`] + linebreak() + [built-in untouched: `$quarto.language.section-title-abstract$`] + linebreak() + [custom key: `$quarto.language.custom-key$`] + linebreak() + [variation key: `$quarto.language.variation-key$`] + doc +}