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.
Default behavior
Section titled “Default behavior”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
jsxonly when you explicitly want JSX-style whitespace semantics instead.
What changes
Section titled “What changes”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> nowWith whitespace: "jsx", the same source is normalized as JSX instead, which can remove spaces
that Svelte or Astro authors expect to keep.
Explicit whitespace takes precedence
Section titled “Explicit whitespace takes precedence”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>Configure the option
Section titled “Configure the option”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.
import { defineConfig } from "lingui-for-svelte/config";import { svelteExtractor } from "lingui-for-svelte/extractor";
export default defineConfig({ framework: { svelte: { whitespace: "svelte", }, }, extractors: [svelteExtractor],});import { defineConfig } from "lingui-for-astro/config";import { astroExtractor } from "lingui-for-astro/extractor";
export default defineConfig({ framework: { astro: { whitespace: "astro", }, }, extractors: [astroExtractor],});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.
import { defineConfig } from "vite";import linguiForSvelte from "lingui-for-svelte/unplugin/vite";
export default defineConfig({ plugins: [linguiForSvelte()],});import { defineConfig } from "astro/config";import linguiForAstro from "lingui-for-astro/integration";
export default defineConfig({ integrations: [linguiForAstro()],});When to use jsx
Section titled “When to use jsx”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.