@intlayer/docs 9.1.1 → 9.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/ar/dynamic_dictionaries/variants.md +214 -1
- package/docs/de/dynamic_dictionaries/variants.md +174 -1
- package/docs/en/dynamic_dictionaries/variants.md +174 -1
- package/docs/en-GB/dynamic_dictionaries/variants.md +174 -1
- package/docs/es/dynamic_dictionaries/variants.md +174 -1
- package/docs/fr/dynamic_dictionaries/variants.md +174 -1
- package/docs/hi/dynamic_dictionaries/variants.md +174 -1
- package/docs/id/dynamic_dictionaries/variants.md +174 -1
- package/docs/it/dynamic_dictionaries/variants.md +174 -1
- package/docs/ja/dynamic_dictionaries/variants.md +174 -1
- package/docs/ko/dynamic_dictionaries/variants.md +174 -1
- package/docs/pl/dynamic_dictionaries/variants.md +174 -1
- package/docs/pt/dynamic_dictionaries/variants.md +174 -1
- package/docs/ru/dynamic_dictionaries/variants.md +174 -1
- package/docs/tr/dynamic_dictionaries/variants.md +174 -1
- package/docs/uk/dynamic_dictionaries/variants.md +174 -1
- package/docs/vi/dynamic_dictionaries/variants.md +174 -1
- package/docs/zh/dynamic_dictionaries/variants.md +174 -1
- package/package.json +6 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-08-04
|
|
4
4
|
title: Variants
|
|
5
5
|
description: Use the variant metadata field in Intlayer content files to declare named or structured content alternatives — A/B tests, seasonal banners, feature-flagged copy, CMS records, user-specific content — and switch between them at runtime without code changes.
|
|
6
6
|
keywords:
|
|
@@ -26,6 +26,9 @@ history:
|
|
|
26
26
|
- version: 9.1.1
|
|
27
27
|
date: 2026-07-31
|
|
28
28
|
changes: "A variant declares only the keys it overrides; undeclared variants fall back to the default entry"
|
|
29
|
+
- version: 9.1.2
|
|
30
|
+
date: 2026-08-04
|
|
31
|
+
changes: "Providers accept an ambient `variant` prop; selectors accept an ordered preference chain"
|
|
29
32
|
author: aymericzip
|
|
30
33
|
---
|
|
31
34
|
|
|
@@ -498,6 +501,176 @@ const content = useIntlayer("product", {
|
|
|
498
501
|
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
499
502
|
```
|
|
500
503
|
|
|
504
|
+
## Ambient variant
|
|
505
|
+
|
|
506
|
+
Some variant dimensions are fixed for a whole session — the tenant, the school type, the plan tier. They are resolved once, and no component should have to pass them by hand.
|
|
507
|
+
|
|
508
|
+
> Do not wrap `useIntlayer` in your own hook to inject them. The build-time optimisation only rewrites a literal `useIntlayer("key")` imported from the framework package, so nothing behind a wrapper gets bundled.
|
|
509
|
+
|
|
510
|
+
Declare the variant once on the provider instead, exactly like `locale`:
|
|
511
|
+
|
|
512
|
+
<Tabs group="framework">
|
|
513
|
+
<Tab label="React" value="react">
|
|
514
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
515
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
516
|
+
|
|
517
|
+
export const App = ({ locale, schoolType }) => (
|
|
518
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
519
|
+
<Hero />
|
|
520
|
+
</IntlayerProvider>
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
</Tab>
|
|
525
|
+
<Tab label="Next.js" value="nextjs">
|
|
526
|
+
```tsx fileName="layout.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
527
|
+
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
528
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
529
|
+
|
|
530
|
+
export default async function Layout({ children, params }) {
|
|
531
|
+
const { locale } = await params;
|
|
532
|
+
const schoolType = await getSchoolType();
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<IntlayerServerProvider locale={locale} variant={schoolType}>
|
|
536
|
+
<IntlayerClientProvider locale={locale} variant={schoolType}>
|
|
537
|
+
{children}
|
|
538
|
+
</IntlayerClientProvider>
|
|
539
|
+
</IntlayerServerProvider>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
</Tab>
|
|
545
|
+
<Tab label="Vue" value="vue">
|
|
546
|
+
```ts fileName="main.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
547
|
+
import { createApp } from "vue";
|
|
548
|
+
import { installIntlayer } from "vue-intlayer";
|
|
549
|
+
import App from "./App.vue";
|
|
550
|
+
|
|
551
|
+
const app = createApp(App);
|
|
552
|
+
|
|
553
|
+
installIntlayer(app, { locale: "en", variant: schoolType });
|
|
554
|
+
|
|
555
|
+
app.mount("#app");
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
</Tab>
|
|
559
|
+
<Tab label="Svelte" value="svelte">
|
|
560
|
+
```svelte fileName="+layout.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
561
|
+
<script lang="ts">
|
|
562
|
+
import { setupIntlayer } from "svelte-intlayer";
|
|
563
|
+
|
|
564
|
+
export let schoolType: string;
|
|
565
|
+
|
|
566
|
+
setupIntlayer("en", schoolType);
|
|
567
|
+
</script>
|
|
568
|
+
|
|
569
|
+
<slot />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
</Tab>
|
|
573
|
+
<Tab label="Preact" value="preact">
|
|
574
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
575
|
+
import { IntlayerProvider } from "preact-intlayer";
|
|
576
|
+
|
|
577
|
+
export const App = ({ locale, schoolType }) => (
|
|
578
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
579
|
+
<Hero />
|
|
580
|
+
</IntlayerProvider>
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
</Tab>
|
|
585
|
+
<Tab label="Solid" value="solid">
|
|
586
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
587
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
588
|
+
|
|
589
|
+
export const App = (props) => (
|
|
590
|
+
<IntlayerProvider locale={props.locale} variant={props.schoolType}>
|
|
591
|
+
<Hero />
|
|
592
|
+
</IntlayerProvider>
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</Tab>
|
|
597
|
+
<Tab label="Angular" value="angular">
|
|
598
|
+
```typescript fileName="app.config.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
599
|
+
import { ApplicationConfig } from "@angular/core";
|
|
600
|
+
import { provideIntlayer } from "angular-intlayer";
|
|
601
|
+
|
|
602
|
+
export const appConfig: ApplicationConfig = {
|
|
603
|
+
providers: [provideIntlayer("en", true, schoolType)],
|
|
604
|
+
};
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
</Tab>
|
|
608
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
609
|
+
```javascript fileName="main.js"
|
|
610
|
+
import { installIntlayer } from "vanilla-intlayer";
|
|
611
|
+
|
|
612
|
+
installIntlayer({ locale: "en", variant: schoolType });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
</Tab>
|
|
616
|
+
</Tabs>
|
|
617
|
+
|
|
618
|
+
Every dictionary read below the provider now resolves against that variant, and a call-site selector always wins:
|
|
619
|
+
|
|
620
|
+
```tsx
|
|
621
|
+
useIntlayer("hero-banner");
|
|
622
|
+
// → the provider variant
|
|
623
|
+
|
|
624
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
625
|
+
// → "summer" — replaces the provider variant, it is not extended
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Forms
|
|
629
|
+
|
|
630
|
+
The `variant` prop accepts three forms:
|
|
631
|
+
|
|
632
|
+
| Form | Meaning |
|
|
633
|
+
| --------------------------------------------------------- | ------------------------------- |
|
|
634
|
+
| `variant="school1"` | one named variant for every key |
|
|
635
|
+
| `variant={["school1", "default"]}` | an ordered preference chain |
|
|
636
|
+
| `variant={{ "hero-banner": "school1", default: "base" }}` | one variant per dictionary key |
|
|
637
|
+
|
|
638
|
+
#### Preference chain
|
|
639
|
+
|
|
640
|
+
A chain is tried left to right against the entries each key declares, and the first declared one wins. When none is declared, the implicit default entry is used — exactly as for a single value.
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
<IntlayerProvider variant={["school1", "school2"]} />
|
|
644
|
+
// `hero-banner` declares no `school1` entry but declares `school2` → "school2"
|
|
645
|
+
// a key declaring neither → the default entry
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
So `["black_friday", "summer"]` reads as "black friday if this key has one, else summer, else default". Chains are also accepted at the call site:
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
> Note this is the mirror image of the array accepted by the `variant` **field** of a content file: there an array _declares_ one entry per element, here it _consumes_ them in priority order.
|
|
655
|
+
|
|
656
|
+
#### Per-key map
|
|
657
|
+
|
|
658
|
+
Address each dictionary key separately. The reserved `default` entry covers every key not listed:
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
<IntlayerProvider
|
|
662
|
+
variant={{
|
|
663
|
+
"hero-banner": "school1",
|
|
664
|
+
product: ["school1", "default"],
|
|
665
|
+
default: "base",
|
|
666
|
+
}}
|
|
667
|
+
/>
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
> On a provider a plain object is **always** read as the per-key map, never as an object variant — the two are structurally identical. To pin an object variant globally, nest it under an entry: `variant={{ default: { id: "prod_abc" } }}`.
|
|
671
|
+
|
|
672
|
+
Because the map's keys are checked against your declared dictionary keys, a typo — or an object variant written directly, such as `variant={{ id: "prod_abc" }}` — is a compile-time error.
|
|
673
|
+
|
|
501
674
|
## Loading mode
|
|
502
675
|
|
|
503
676
|
Object variants are often loaded lazily. Set `importMode` on the dictionary to control this:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-08-04
|
|
4
4
|
title: Variantes
|
|
5
5
|
description: Use el campo de metadatos variant en los archivos de contenido de Intlayer para declarar alternativas de contenido con nombre o estructuradas — pruebas A/B, banners de temporada, copia con feature flag, registros de CMS, contenido específico de usuario — y cambiar entre ellas en tiempo de ejecución sin cambios de código.
|
|
6
6
|
keywords:
|
|
@@ -26,6 +26,9 @@ history:
|
|
|
26
26
|
- version: 9.1.1
|
|
27
27
|
date: 2026-07-31
|
|
28
28
|
changes: "Una variante declara solo las claves que anula; las variantes no declaradas recurren a la entrada por defecto"
|
|
29
|
+
- version: 9.1.2
|
|
30
|
+
date: 2026-08-04
|
|
31
|
+
changes: "Los proveedores aceptan una prop `variant` ambiental; los selectores aceptan una cadena de preferencia ordenada"
|
|
29
32
|
author: aymericzip
|
|
30
33
|
---
|
|
31
34
|
|
|
@@ -498,6 +501,176 @@ const content = useIntlayer("product", {
|
|
|
498
501
|
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
499
502
|
```
|
|
500
503
|
|
|
504
|
+
## Variante ambiental
|
|
505
|
+
|
|
506
|
+
Algunas dimensiones de variante son fijas durante toda una sesión: el inquilino, el tipo de centro, el nivel de plan. Se resuelven una sola vez, y ningún componente debería tener que pasarlas a mano.
|
|
507
|
+
|
|
508
|
+
> No envuelvas `useIntlayer` en tu propio hook para inyectarlas. La optimización en tiempo de compilación solo reescribe una llamada literal `useIntlayer("key")` importada del paquete del framework, por lo que nada detrás de un wrapper se incluye en el bundle.
|
|
509
|
+
|
|
510
|
+
En su lugar, declara la variante una sola vez en el proveedor, exactamente igual que `locale`:
|
|
511
|
+
|
|
512
|
+
<Tabs group="framework">
|
|
513
|
+
<Tab label="React" value="react">
|
|
514
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
515
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
516
|
+
|
|
517
|
+
export const App = ({ locale, schoolType }) => (
|
|
518
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
519
|
+
<Hero />
|
|
520
|
+
</IntlayerProvider>
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
</Tab>
|
|
525
|
+
<Tab label="Next.js" value="nextjs">
|
|
526
|
+
```tsx fileName="layout.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
527
|
+
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
528
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
529
|
+
|
|
530
|
+
export default async function Layout({ children, params }) {
|
|
531
|
+
const { locale } = await params;
|
|
532
|
+
const schoolType = await getSchoolType();
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<IntlayerServerProvider locale={locale} variant={schoolType}>
|
|
536
|
+
<IntlayerClientProvider locale={locale} variant={schoolType}>
|
|
537
|
+
{children}
|
|
538
|
+
</IntlayerClientProvider>
|
|
539
|
+
</IntlayerServerProvider>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
</Tab>
|
|
545
|
+
<Tab label="Vue" value="vue">
|
|
546
|
+
```ts fileName="main.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
547
|
+
import { createApp } from "vue";
|
|
548
|
+
import { installIntlayer } from "vue-intlayer";
|
|
549
|
+
import App from "./App.vue";
|
|
550
|
+
|
|
551
|
+
const app = createApp(App);
|
|
552
|
+
|
|
553
|
+
installIntlayer(app, { locale: "en", variant: schoolType });
|
|
554
|
+
|
|
555
|
+
app.mount("#app");
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
</Tab>
|
|
559
|
+
<Tab label="Svelte" value="svelte">
|
|
560
|
+
```svelte fileName="+layout.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
561
|
+
<script lang="ts">
|
|
562
|
+
import { setupIntlayer } from "svelte-intlayer";
|
|
563
|
+
|
|
564
|
+
export let schoolType: string;
|
|
565
|
+
|
|
566
|
+
setupIntlayer("en", schoolType);
|
|
567
|
+
</script>
|
|
568
|
+
|
|
569
|
+
<slot />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
</Tab>
|
|
573
|
+
<Tab label="Preact" value="preact">
|
|
574
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
575
|
+
import { IntlayerProvider } from "preact-intlayer";
|
|
576
|
+
|
|
577
|
+
export const App = ({ locale, schoolType }) => (
|
|
578
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
579
|
+
<Hero />
|
|
580
|
+
</IntlayerProvider>
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
</Tab>
|
|
585
|
+
<Tab label="Solid" value="solid">
|
|
586
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
587
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
588
|
+
|
|
589
|
+
export const App = (props) => (
|
|
590
|
+
<IntlayerProvider locale={props.locale} variant={props.schoolType}>
|
|
591
|
+
<Hero />
|
|
592
|
+
</IntlayerProvider>
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</Tab>
|
|
597
|
+
<Tab label="Angular" value="angular">
|
|
598
|
+
```typescript fileName="app.config.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
599
|
+
import { ApplicationConfig } from "@angular/core";
|
|
600
|
+
import { provideIntlayer } from "angular-intlayer";
|
|
601
|
+
|
|
602
|
+
export const appConfig: ApplicationConfig = {
|
|
603
|
+
providers: [provideIntlayer("en", true, schoolType)],
|
|
604
|
+
};
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
</Tab>
|
|
608
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
609
|
+
```javascript fileName="main.js"
|
|
610
|
+
import { installIntlayer } from "vanilla-intlayer";
|
|
611
|
+
|
|
612
|
+
installIntlayer({ locale: "en", variant: schoolType });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
</Tab>
|
|
616
|
+
</Tabs>
|
|
617
|
+
|
|
618
|
+
Cada lectura de diccionario bajo el proveedor se resuelve ahora con esa variante, y un selector en el punto de llamada siempre gana:
|
|
619
|
+
|
|
620
|
+
```tsx
|
|
621
|
+
useIntlayer("hero-banner");
|
|
622
|
+
// → la variante del proveedor
|
|
623
|
+
|
|
624
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
625
|
+
// → "summer" — sustituye la variante del proveedor, no la extiende
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Formas
|
|
629
|
+
|
|
630
|
+
La prop `variant` acepta tres formas:
|
|
631
|
+
|
|
632
|
+
| Forma | Significado |
|
|
633
|
+
| --------------------------------------------------------- | ------------------------------------------- |
|
|
634
|
+
| `variant="school1"` | una variante nombrada para todas las claves |
|
|
635
|
+
| `variant={["school1", "default"]}` | una cadena de preferencia ordenada |
|
|
636
|
+
| `variant={{ "hero-banner": "school1", default: "base" }}` | una variante por clave de diccionario |
|
|
637
|
+
|
|
638
|
+
#### Cadena de preferencia
|
|
639
|
+
|
|
640
|
+
Una cadena se recorre de izquierda a derecha frente a las entradas que declara cada clave, y gana la primera declarada. Cuando no hay ninguna declarada, se usa la entrada por defecto implícita, exactamente igual que con un valor único.
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
<IntlayerProvider variant={["school1", "school2"]} />
|
|
644
|
+
// `hero-banner` no declara una entrada `school1` pero sí declara `school2` → "school2"
|
|
645
|
+
// una clave que no declara ninguna de las dos → la entrada por defecto
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Así, `["black_friday", "summer"]` se lee como «black friday si esta clave la tiene, si no summer, si no por defecto». Las cadenas también se aceptan en el punto de llamada:
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
> Ten en cuenta que esto es la imagen especular del array aceptado por el **campo** `variant` de un archivo de contenido: allí un array _declara_ una entrada por elemento; aquí las _consume_ por orden de prioridad.
|
|
655
|
+
|
|
656
|
+
#### Mapa por clave
|
|
657
|
+
|
|
658
|
+
Dirígete a cada clave de diccionario por separado. La entrada reservada `default` cubre todas las claves no listadas:
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
<IntlayerProvider
|
|
662
|
+
variant={{
|
|
663
|
+
"hero-banner": "school1",
|
|
664
|
+
product: ["school1", "default"],
|
|
665
|
+
default: "base",
|
|
666
|
+
}}
|
|
667
|
+
/>
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
> En un proveedor, un objeto simple se lee **siempre** como el mapa por clave, nunca como una variante de objeto: ambos son estructuralmente idénticos. Para fijar una variante de objeto globalmente, anídala bajo una entrada: `variant={{ default: { id: "prod_abc" } }}`.
|
|
671
|
+
|
|
672
|
+
Como las claves del mapa se comprueban contra tus claves de diccionario declaradas, una errata —o una variante de objeto escrita directamente, como `variant={{ id: "prod_abc" }}`— es un error de compilación.
|
|
673
|
+
|
|
501
674
|
## Modo de carga
|
|
502
675
|
|
|
503
676
|
Las variantes de objeto suelen cargarse de forma diferida. Establezca `importMode` en el diccionario para controlarlo:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-
|
|
3
|
+
updatedAt: 2026-08-04
|
|
4
4
|
title: Variantes
|
|
5
5
|
description: Utilisez le champ de métadonnées variant dans les fichiers de contenu Intlayer pour déclarer des alternatives de contenu nommées ou structurées — tests A/B, bannières saisonnières, contenu sous feature flag, enregistrements de CMS, contenu propre à un utilisateur — et basculer entre elles à l'exécution sans changement de code.
|
|
6
6
|
keywords:
|
|
@@ -26,6 +26,9 @@ history:
|
|
|
26
26
|
- version: 9.1.1
|
|
27
27
|
date: 2026-07-31
|
|
28
28
|
changes: "Une variante déclare uniquement les clés qu'elle remplace ; les variantes non déclarées se rabattent sur l'entrée par défaut"
|
|
29
|
+
- version: 9.1.2
|
|
30
|
+
date: 2026-08-04
|
|
31
|
+
changes: "Les fournisseurs acceptent une prop `variant` ambiante ; les sélecteurs acceptent une chaîne de préférence ordonnée"
|
|
29
32
|
author: aymericzip
|
|
30
33
|
---
|
|
31
34
|
|
|
@@ -498,6 +501,176 @@ const content = useIntlayer("product", {
|
|
|
498
501
|
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
499
502
|
```
|
|
500
503
|
|
|
504
|
+
## Variante ambiante
|
|
505
|
+
|
|
506
|
+
Certaines dimensions de variante sont fixes pour toute une session — le locataire, le type d'établissement, le niveau d'abonnement. Elles sont résolues une seule fois, et aucun composant ne devrait avoir à les passer à la main.
|
|
507
|
+
|
|
508
|
+
> N'encapsulez pas `useIntlayer` dans votre propre hook pour les injecter. L'optimisation à la compilation ne réécrit qu'un appel littéral `useIntlayer("key")` importé depuis le paquet du framework : rien derrière un wrapper n'est intégré au bundle.
|
|
509
|
+
|
|
510
|
+
Déclarez plutôt la variante une seule fois sur le fournisseur, exactement comme `locale` :
|
|
511
|
+
|
|
512
|
+
<Tabs group="framework">
|
|
513
|
+
<Tab label="React" value="react">
|
|
514
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
515
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
516
|
+
|
|
517
|
+
export const App = ({ locale, schoolType }) => (
|
|
518
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
519
|
+
<Hero />
|
|
520
|
+
</IntlayerProvider>
|
|
521
|
+
);
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
</Tab>
|
|
525
|
+
<Tab label="Next.js" value="nextjs">
|
|
526
|
+
```tsx fileName="layout.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
527
|
+
import { IntlayerServerProvider } from "next-intlayer/server";
|
|
528
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
529
|
+
|
|
530
|
+
export default async function Layout({ children, params }) {
|
|
531
|
+
const { locale } = await params;
|
|
532
|
+
const schoolType = await getSchoolType();
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<IntlayerServerProvider locale={locale} variant={schoolType}>
|
|
536
|
+
<IntlayerClientProvider locale={locale} variant={schoolType}>
|
|
537
|
+
{children}
|
|
538
|
+
</IntlayerClientProvider>
|
|
539
|
+
</IntlayerServerProvider>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
</Tab>
|
|
545
|
+
<Tab label="Vue" value="vue">
|
|
546
|
+
```ts fileName="main.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
547
|
+
import { createApp } from "vue";
|
|
548
|
+
import { installIntlayer } from "vue-intlayer";
|
|
549
|
+
import App from "./App.vue";
|
|
550
|
+
|
|
551
|
+
const app = createApp(App);
|
|
552
|
+
|
|
553
|
+
installIntlayer(app, { locale: "en", variant: schoolType });
|
|
554
|
+
|
|
555
|
+
app.mount("#app");
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
</Tab>
|
|
559
|
+
<Tab label="Svelte" value="svelte">
|
|
560
|
+
```svelte fileName="+layout.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
561
|
+
<script lang="ts">
|
|
562
|
+
import { setupIntlayer } from "svelte-intlayer";
|
|
563
|
+
|
|
564
|
+
export let schoolType: string;
|
|
565
|
+
|
|
566
|
+
setupIntlayer("en", schoolType);
|
|
567
|
+
</script>
|
|
568
|
+
|
|
569
|
+
<slot />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
</Tab>
|
|
573
|
+
<Tab label="Preact" value="preact">
|
|
574
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
575
|
+
import { IntlayerProvider } from "preact-intlayer";
|
|
576
|
+
|
|
577
|
+
export const App = ({ locale, schoolType }) => (
|
|
578
|
+
<IntlayerProvider locale={locale} variant={schoolType}>
|
|
579
|
+
<Hero />
|
|
580
|
+
</IntlayerProvider>
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
</Tab>
|
|
585
|
+
<Tab label="Solid" value="solid">
|
|
586
|
+
```tsx fileName="App.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
587
|
+
import { IntlayerProvider } from "solid-intlayer";
|
|
588
|
+
|
|
589
|
+
export const App = (props) => (
|
|
590
|
+
<IntlayerProvider locale={props.locale} variant={props.schoolType}>
|
|
591
|
+
<Hero />
|
|
592
|
+
</IntlayerProvider>
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
</Tab>
|
|
597
|
+
<Tab label="Angular" value="angular">
|
|
598
|
+
```typescript fileName="app.config.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
599
|
+
import { ApplicationConfig } from "@angular/core";
|
|
600
|
+
import { provideIntlayer } from "angular-intlayer";
|
|
601
|
+
|
|
602
|
+
export const appConfig: ApplicationConfig = {
|
|
603
|
+
providers: [provideIntlayer("en", true, schoolType)],
|
|
604
|
+
};
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
</Tab>
|
|
608
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
609
|
+
```javascript fileName="main.js"
|
|
610
|
+
import { installIntlayer } from "vanilla-intlayer";
|
|
611
|
+
|
|
612
|
+
installIntlayer({ locale: "en", variant: schoolType });
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
</Tab>
|
|
616
|
+
</Tabs>
|
|
617
|
+
|
|
618
|
+
Chaque lecture de dictionnaire sous le fournisseur se résout désormais avec cette variante, et un sélecteur au point d'appel l'emporte toujours :
|
|
619
|
+
|
|
620
|
+
```tsx
|
|
621
|
+
useIntlayer("hero-banner");
|
|
622
|
+
// → la variante du fournisseur
|
|
623
|
+
|
|
624
|
+
useIntlayer("hero-banner", { variant: "summer" });
|
|
625
|
+
// → "summer" — remplace la variante du fournisseur, elle ne l'étend pas
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Formes
|
|
629
|
+
|
|
630
|
+
La prop `variant` accepte trois formes :
|
|
631
|
+
|
|
632
|
+
| Forme | Signification |
|
|
633
|
+
| --------------------------------------------------------- | ---------------------------------------- |
|
|
634
|
+
| `variant="school1"` | une variante nommée pour toutes les clés |
|
|
635
|
+
| `variant={["school1", "default"]}` | une chaîne de préférence ordonnée |
|
|
636
|
+
| `variant={{ "hero-banner": "school1", default: "base" }}` | une variante par clé de dictionnaire |
|
|
637
|
+
|
|
638
|
+
#### Chaîne de préférence
|
|
639
|
+
|
|
640
|
+
Une chaîne est parcourue de gauche à droite parmi les entrées déclarées par chaque clé, et la première déclarée l'emporte. Si aucune ne l'est, l'entrée par défaut implicite est utilisée — exactement comme pour une valeur unique.
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
<IntlayerProvider variant={["school1", "school2"]} />
|
|
644
|
+
// `hero-banner` ne déclare pas d'entrée `school1` mais déclare `school2` → "school2"
|
|
645
|
+
// une clé qui ne déclare ni l'une ni l'autre → l'entrée par défaut
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Ainsi `["black_friday", "summer"]` se lit « black friday si cette clé en a une, sinon summer, sinon par défaut ». Les chaînes sont également acceptées au point d'appel :
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
> Notez qu'il s'agit de l'image inverse du tableau accepté par le **champ** `variant` d'un fichier de contenu : là, un tableau _déclare_ une entrée par élément ; ici, il les _consomme_ par ordre de priorité.
|
|
655
|
+
|
|
656
|
+
#### Table par clé
|
|
657
|
+
|
|
658
|
+
Adressez chaque clé de dictionnaire séparément. L'entrée réservée `default` couvre toutes les clés non listées :
|
|
659
|
+
|
|
660
|
+
```tsx
|
|
661
|
+
<IntlayerProvider
|
|
662
|
+
variant={{
|
|
663
|
+
"hero-banner": "school1",
|
|
664
|
+
product: ["school1", "default"],
|
|
665
|
+
default: "base",
|
|
666
|
+
}}
|
|
667
|
+
/>
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
> Sur un fournisseur, un objet simple est **toujours** lu comme la table par clé, jamais comme une variante objet — les deux sont structurellement identiques. Pour fixer une variante objet globalement, imbriquez-la sous une entrée : `variant={{ default: { id: "prod_abc" } }}`.
|
|
671
|
+
|
|
672
|
+
Comme les clés de la table sont vérifiées par rapport à vos clés de dictionnaire déclarées, une faute de frappe — ou une variante objet écrite directement, telle que `variant={{ id: "prod_abc" }}` — est une erreur de compilation.
|
|
673
|
+
|
|
501
674
|
## Mode de chargement
|
|
502
675
|
|
|
503
676
|
Les variantes objet sont souvent chargées de façon différée. Définissez `importMode` sur le dictionnaire pour contrôler ce comportement :
|