@intlayer/docs 9.1.0 → 9.1.2

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2026-06-12
3
- updatedAt: 2026-06-26
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:
@@ -23,6 +23,12 @@ history:
23
23
  - version: 9.1.0
24
24
  date: 2026-06-26
25
25
  changes: "`variant` ahora acepta una cadena o un objeto — los antiguos `meta` / registros dinámicos se declaran como variantes de objeto"
26
+ - version: 9.1.1
27
+ date: 2026-07-31
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"
26
32
  author: aymericzip
27
33
  ---
28
34
 
@@ -77,6 +83,37 @@ const dictionary = {
77
83
  export default dictionary;
78
84
  ```
79
85
 
86
+ ### Variantes parciales
87
+
88
+ Una variante declara **solo las claves que anula**; el resto se hereda de la entrada por defecto.
89
+
90
+ ```ts fileName="hero-banner.summer.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
91
+ import { t, type Dictionary } from "intlayer";
92
+
93
+ const dictionary = {
94
+ key: "hero-banner",
95
+ variant: "summer",
96
+ content: {
97
+ headline: t({
98
+ en: "Build faster all summer",
99
+ fr: "Développez plus vite tout l'été",
100
+ }),
101
+ },
102
+ } satisfies Dictionary;
103
+
104
+ export default dictionary;
105
+ ```
106
+
107
+ ```tsx
108
+ useIntlayer("hero-banner", { variant: "summer" });
109
+ // → { headline: "Développez plus vite tout l'été", cta: "Commencer" } — `cta` heredado
110
+
111
+ useIntlayer("hero-banner", { variant: "never-declared" });
112
+ // → la entrada por defecto
113
+ ```
114
+
115
+ Por lo tanto, solo debe agregar un archivo de variante donde la redacción realmente difiera. Una clave se resuelve en `null` solo cuando declara variantes pero ninguna entrada por defecto.
116
+
80
117
  ### Consumir variantes con nombre
81
118
 
82
119
  #### Variante por defecto
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
464
501
  const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
502
  ```
466
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
+
467
674
  ## Modo de carga
468
675
 
469
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-06-26
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:
@@ -23,6 +23,12 @@ history:
23
23
  - version: 9.1.0
24
24
  date: 2026-06-26
25
25
  changes: "`variant` accepte désormais une chaîne ou un objet — les anciens `meta` / enregistrements dynamiques se déclarent comme variantes objet"
26
+ - version: 9.1.1
27
+ date: 2026-07-31
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"
26
32
  author: aymericzip
27
33
  ---
28
34
 
@@ -77,6 +83,37 @@ const dictionary = {
77
83
  export default dictionary;
78
84
  ```
79
85
 
86
+ ### Variantes partielles
87
+
88
+ Une variante déclare **uniquement les clés qu'elle remplace** ; le reste est hérité de l'entrée par défaut.
89
+
90
+ ```ts fileName="hero-banner.summer.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
91
+ import { t, type Dictionary } from "intlayer";
92
+
93
+ const dictionary = {
94
+ key: "hero-banner",
95
+ variant: "summer",
96
+ content: {
97
+ headline: t({
98
+ en: "Build faster all summer",
99
+ fr: "Développez plus vite tout l'été",
100
+ }),
101
+ },
102
+ } satisfies Dictionary;
103
+
104
+ export default dictionary;
105
+ ```
106
+
107
+ ```tsx
108
+ useIntlayer("hero-banner", { variant: "summer" });
109
+ // → { headline: "Développez plus vite tout l'été", cta: "Commencer" } — `cta` hérité
110
+
111
+ useIntlayer("hero-banner", { variant: "never-declared" });
112
+ // → l'entrée par défaut
113
+ ```
114
+
115
+ Ainsi, vous n'ajoutez un fichier de variante que là où la formulation diffère réellement. Une clé se résout en `null` uniquement lorsqu'elle déclare des variantes mais aucune entrée par défaut.
116
+
80
117
  ### Consommer des variantes nommées
81
118
 
82
119
  #### Variante par défaut
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
464
501
  const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
502
  ```
466
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
+
467
674
  ## Mode de chargement
468
675
 
469
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 :