Skip to content

Install hyphenation package when babel fails with an undefined language - #15029

Merged
cderv merged 4 commits into
mainfrom
fix/issue-15027
Oct 12, 2026
Merged

cderv merged 4 commits into
mainfrom
fix/issue-15027

Conversation

@cderv

@cderv cderv commented Oct 12, 2026

Copy link
Copy Markdown
Member

When rendering to PDF with lang: de-CH on a TinyTeX without German hyphenation patterns, Quarto installs babel-german but the compilation still fails, and hyphen-german is never installed:

! Package babel Error: You haven't defined the language 'ngerman' yet.

This was first reported in rstudio/tinytex#515, and rstudio/tinytex#516 fixes it in the R package. This PR ports the same changes to Quarto.

Root cause

Missing hyphenation patterns usually show up as a babel warning, which findMissingHyphenationFiles() already handles after a successful compilation. With lang: de-CH, babel-german defines nswissgerman and then checks \iflanguage{ngerman}, which is a fatal error when hyphen-german is not installed. The error is not about a missing file, so the tlmgr search based detection finds nothing to install.

Fix

  • findMissingHyphenationPackages() detects the babel error and the hyphenation package is installed by name with the other missing packages, without a tlmgr search.
  • Language names are mapped to their package using the execute AddHyphen entries of texlive.tlpdb. Some names are in a package with another name, e.g. swissgerman in hyphen-german, nynorsk in hyphen-norwegian, and all Indic languages in hyphen-indic. Only ngerman was mapped before. The table was checked against the current texlive.tlpdb from CTAN (same 37 names as in Install hyphen-* packages when babel can't define the language rstudio/tinytex#516).
  • Names come from the log and are passed to tlmgr, so only names matching ^hyphen-[a-z0-9-]+$ are kept. On Windows, tlmgr.bat is called through a temporary .bat file and requireQuoting() does not handle ", %, ^ or !. I did not try to exploit it, this is from reading the code. All hyphenation names in texlive.tlpdb pass this filter. It also applies to the existing babel warning detection, which shares the mapping.

The german-x-* names from dehyph-exptl are not handled, as they are not hyphen-* packages. This is the same in rstudio/tinytex#516.

The new smoke test removes hyphen-german and babel-german before rendering, only on CI, so local runs don't modify the TinyTeX installation.

Fixes #15027

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes
  • updated the appropriate changelog in the PR
  • ensured the present test suite passes
  • added new tests
  • created a separate documentation PR in Quarto's website repo and linked it to this PR
AI-assisted PR

Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.

claude and others added 4 commits October 12, 2026 09:33
With `lang: de-CH` and no hyphen-german installed, babel-german checks
`\iflanguage{ngerman}` at begin document, and babel raises a fatal
"You haven't defined the language 'ngerman' yet" error. Missing hyphenation
patterns were only handled as babel warnings on a successful compile, so the
failure branch found nothing to install and gave up.

Detect this error on the failure path and install the matching
`hyphen-<lang>` package directly by name, reusing the language-to-package
mapping of findMissingHyphenationFiles (now a shared helper).

Fixes rstudio/tinytex#515

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPRhHuCKXMd1s1wZgEe1M4
The test now removes hyphen-german and babel-german only on CI, so the
CI run exercises the auto-installation path, and local runs no longer
uninstall packages from the developer's TinyTeX. The document and the
changelog entry now point at the quarto-cli issue.
The language name in babel messages comes from the LaTeX log and ends up
as a tlmgr argument. On Windows tlmgr.bat is called through a temporary
.bat file, and requireQuoting() does not handle `"`, `%`, `^` or `!`, so a
crafted name in a document's log could be interpreted by cmd.

Every hyphenation name in texlive.tlpdb (102 names and synonyms) is made of
lowercase letters, digits and hyphens, so names that don't match
^hyphen-[a-z0-9-]+$ are dropped. This applies to both the babel error and
the older babel warning detection, which share the mapping function.

Same validation as rstudio/tinytex#516.
Only ngerman was mapped, so any other pattern name whose package is not
hyphen-<name> asked tlmgr for a package that doesn't exist, e.g.
swissgerman (hyphen-german), nynorsk (hyphen-norwegian) or hindi
(hyphen-indic).

The table lists every such name from the `execute AddHyphen` lines
(name= and synonyms=) of the current texlive.tlpdb: 16 pattern names, 9
older synonyms and 12 Indic languages, 37 in total. That's the same table as
rstudio/tinytex#516. The 4 german-x-* names provided by dehyph-exptl are left
out, as they are not hyphen-* packages.

Names are lowercased before the lookup, since language.dat uses mixed
case names such as UKenglish.
@posit-snyk-bot

posit-snyk-bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cderv cderv added this to the v1.11 milestone Oct 12, 2026
@cderv
cderv merged commit db1d1c7 into main Oct 12, 2026
51 checks passed
@cderv
cderv deleted the fix/issue-15027 branch October 12, 2026 14:15
cderv added a commit that referenced this pull request Oct 16, 2026
The hyphenation table in parse-error.ts was a hand copy of tinytex's
and had drifted. With `\begin{hyphenrules}{ngerman-x-latest}` and no
dehyph-exptl installed, babel stops with "You haven't defined the
language 'ngerman-x-latest' yet". The package was always built as
`hyphen-<name>`, so tlmgr was asked for the non-existent
`hyphen-ngerman-x-latest` and the render failed.

Detection now follows tinytex main (rstudio/tinytex#517, follow-up to
rstudio/tinytex#516), and builds on #15029:

- The map holds full package names, with the 4 dehyph-exptl entries, and
  the language name is validated instead of the resulting package name.
- A language given as a description keeps its first word, so "German
  (current orthography)" gives hyphen-german.
- The babel regex only reads warning blocks, so a (babel) continuation
  of an Info message can't produce a package.
- Every warned language is installed, not only the first, and
  polyglossia warnings are detected.
- The daily TinyTeX workflow also compares tinytex's hyphen.json. It
  reports a skipped comparison when the download fails, and an invalid
  hyphen.json fails the first run instead of being cached.

The chinese skip list (#10291), the `\l@nil` fallback and unquoted names
in the babel error regex are kept.

Fixes #15035
See #15027, rstudio/tinytex#518
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PDF render with lang: de-CH fails when hyphen-german is not installed

3 participants