Skip to content

Whitespace in Component Macros

Component macros are processed internally through JSX-compatible machinery, but Svelte and Astro templates are not JSX.

Because of that, whitespace between child nodes can be interpreted differently if the compiler uses plain JSX rules. This especially matters for rich-text messages such as Trans, where missing or extra spaces can change the extracted message text.

The whitespace option lets you choose how those boundaries are handled. In normal use you should leave it unset, which makes component macros follow framework-aware whitespace behavior instead of raw JSX semantics.

lingui-for-svelte and lingui-for-astro default whitespace to the owning framework’s mode, so rich-text child boundaries follow framework-aware whitespace handling unless you opt into jsx.

  • In Svelte, the default is svelte.
  • In Astro, the default is astro.
  • Use jsx only when you explicitly want JSX-style whitespace semantics instead.

Consider this authoring:

<Trans>
Read
<a href="/docs">docs</a>
now
</Trans>

With the framework-aware default, the extracted rich-text message keeps the word boundaries:

Read <0>docs</0> now

With whitespace: "jsx", the same source is normalized as JSX instead, which can remove spaces that Svelte or Astro authors expect to keep.

If you already wrote an explicit space expression such as {" "}, that is treated as authoritative. The framework-aware whitespace pass does not add another space next to it.

<Trans><strong>Read</strong>{" "}<em>carefully</em></Trans>

This stays equivalent to:

<0>Read</0> <1>carefully</1>

Put the whitespace setting in lingui.config.ts under the matching framework key. The framework build transform and extractor both load that config, so you do not need to repeat the same option in Vite, Astro, and extractor setup.

lingui.config.ts
import { defineConfig } from "lingui-for-svelte/config";
import { svelteExtractor } from "lingui-for-svelte/extractor";
export default defineConfig({
framework: {
svelte: {
whitespace: "svelte",
},
},
extractors: [svelteExtractor],
});

If your project uses a non-standard config path or an inline config object, pass it with the config option to the framework plugin or integration, and to the extractor factory where needed. With the default lingui.config.* file, the config is discovered automatically.

vite.config.ts
import { defineConfig } from "vite";
import linguiForSvelte from "lingui-for-svelte/unplugin/vite";
export default defineConfig({
plugins: [linguiForSvelte()],
});

Use jsx only as a compatibility mode.

The default framework-aware mode matches how Svelte and Astro treat whitespace between template nodes, so it is usually the right choice for new code. Choose jsx only when you need to preserve messages that were previously extracted with JSX-style whitespace normalization, or when you intentionally want rich-text child boundaries to behave like JSX rather than the source framework.

Switching between jsx and the framework-aware mode can change extracted message text and generated IDs for some Component Macro calls. Keep the same whitespace setting for transforms and extractors.

See Framework Config for how build transforms and extractors share the same framework config.