Why a set-if rule requires `context`, but only outside a show-rule function?

Accessing text.lang requires context. The following three set-if rules have conditions depending on it.

  1. The first one is a bare set-if rule.
  2. The second one is composed into a show-set rule.
  3. The third one is wrapped into the function of a show rule.
// ❌: Can only be used when context is known
#set text(font: "Libertinus Sans") if text.lang == "en"

// ❌: Can only be used when context is known
#show "Why": set text(font: "Libertinus Sans") if text.lang == "en"

// ✅
#show "Why": it => {
  set text(font: "Libertinus Sans") if text.lang == "en"
  it
}

Surprisingly, the third one compiles but the first two do not. Why?

It’s kind of hidden, but the docs state:

Aside from explicit context expressions, context is also established implicitly in some places that are also aware of their location in the document: Show rules provide context1 and numberings in the outline, for instance, also provide the proper context to resolve counters.
1: Currently, all show rules provide styling context, but only show rules on locatable elements provide a location context

2 Likes

Here’s one way to provide the context, by wrapping the rest of the document in a context block:

#show: doc => context {
  set text(font: "Libertinus Sans") if text.lang == "en"
  show "Why": set text(font: "Libertinus Sans") if text.lang == "en"
  doc
}

This could also be used inside a template function, for example.

Thanks for providing a workaround. Actually, I ended up with a new function.

#let en = text.with(lang: "en", font: "Libertinus Serif")

#set text(lang: "zh", font: "Noto Serif CJK SC")

国“Why quote”国

国#en[“Why ‘quote’”]国

国“Why ‘quote’”国

图片