@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 o campo de metadados variant nos arquivos de conteúdo do Intlayer para declarar alternativas de conteúdo nomeadas ou estruturadas — testes A/B, banners sazonais, texto com feature flag, registros de CMS, conteúdo específico do usuário — e alternar entre elas em tempo de execução sem mudanças 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` agora aceita uma string ou um objeto — os antigos `meta` / registros dinâmicos são declarados como variantes de objeto"
26
+ - version: 9.1.1
27
+ date: 2026-07-31
28
+ changes: "Uma variante declara apenas as chaves que sobrescreve; as variantes não declaradas retornam para a entrada padrão"
29
+ - version: 9.1.2
30
+ date: 2026-08-04
31
+ changes: "Os provedores aceitam uma prop `variant` ambiente; os seletores aceitam uma cadeia de preferência 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 parciais
87
+
88
+ Uma variante declara **apenas as chaves que sobrescreve**; o restante é herdado da entrada padrão.
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` herdado
110
+
111
+ useIntlayer("hero-banner", { variant: "never-declared" });
112
+ // → a entrada padrão
113
+ ```
114
+
115
+ Portanto, adicione um arquivo de variante apenas onde o texto realmente difere. Uma chave é resolvida como `null` apenas quando declara variantes, mas nenhuma entrada padrão.
116
+
80
117
  ### Consumir variantes nomeadas
81
118
 
82
119
  #### Variante padrão
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
464
501
  const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
502
  ```
466
503
 
504
+ ## Variante ambiente
505
+
506
+ Algumas dimensões de variante são fixas durante toda uma sessão: o inquilino, o tipo de instituição, o nível do plano. São resolvidas uma única vez, e nenhum componente deveria ter de as passar à mão.
507
+
508
+ > Não envolva `useIntlayer` num hook próprio para as injetar. A otimização em tempo de compilação apenas reescreve uma chamada literal `useIntlayer("key")` importada do pacote do framework, pelo que nada atrás de um wrapper entra no bundle.
509
+
510
+ Declare antes a variante uma única vez no provedor, exatamente como `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 leitura de dicionário abaixo do provedor passa a resolver-se com essa variante, e um seletor no local da chamada ganha sempre:
619
+
620
+ ```tsx
621
+ useIntlayer("hero-banner");
622
+ // → a variante do provedor
623
+
624
+ useIntlayer("hero-banner", { variant: "summer" });
625
+ // → "summer" — substitui a variante do provedor, não a estende
626
+ ```
627
+
628
+ ### Formas
629
+
630
+ A prop `variant` aceita três formas:
631
+
632
+ | Forma | Significado |
633
+ | --------------------------------------------------------- | ----------------------------------------- |
634
+ | `variant="school1"` | uma variante nomeada para todas as chaves |
635
+ | `variant={["school1", "default"]}` | uma cadeia de preferência ordenada |
636
+ | `variant={{ "hero-banner": "school1", default: "base" }}` | uma variante por chave de dicionário |
637
+
638
+ #### Cadeia de preferência
639
+
640
+ Uma cadeia é percorrida da esquerda para a direita entre as entradas declaradas por cada chave, e a primeira declarada ganha. Quando nenhuma está declarada, usa-se a entrada padrão implícita — exatamente como para um valor único.
641
+
642
+ ```tsx
643
+ <IntlayerProvider variant={["school1", "school2"]} />
644
+ // `hero-banner` não declara uma entrada `school1`, mas declara `school2` → "school2"
645
+ // uma chave que não declara nenhuma das duas → a entrada padrão
646
+ ```
647
+
648
+ Assim, `["black_friday", "summer"]` lê-se como «black friday se esta chave tiver uma, senão summer, senão padrão». As cadeias também são aceites no local da chamada:
649
+
650
+ ```tsx
651
+ useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
652
+ ```
653
+
654
+ > Note que esta é a imagem invertida do array aceite pelo **campo** `variant` de um ficheiro de conteúdo: aí um array _declara_ uma entrada por elemento; aqui _consome_-as por ordem de prioridade.
655
+
656
+ #### Mapa por chave
657
+
658
+ Enderece cada chave de dicionário separadamente. A entrada reservada `default` cobre todas as chaves não listadas:
659
+
660
+ ```tsx
661
+ <IntlayerProvider
662
+ variant={{
663
+ "hero-banner": "school1",
664
+ product: ["school1", "default"],
665
+ default: "base",
666
+ }}
667
+ />
668
+ ```
669
+
670
+ > Num provedor, um objeto simples é **sempre** lido como o mapa por chave, nunca como uma variante de objeto — as duas são estruturalmente idênticas. Para fixar uma variante de objeto globalmente, aninhe-a sob uma entrada: `variant={{ default: { id: "prod_abc" } }}`.
671
+
672
+ Como as chaves do mapa são verificadas contra as suas chaves de dicionário declaradas, um erro de escrita — ou uma variante de objeto escrita diretamente, como `variant={{ id: "prod_abc" }}` — é um erro de compilação.
673
+
467
674
  ## Modo de carregamento
468
675
 
469
676
  As variantes de objeto costumam ser carregadas de forma preguiçosa. Defina `importMode` no dicionário para controlar isso:
@@ -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: Варианты
5
5
  description: Используйте поле метаданных variant в файлах контента Intlayer, чтобы объявлять именованные или структурированные альтернативы контента — A/B-тесты, сезонные баннеры, тексты под feature-флагами, записи CMS, контент конкретного пользователя — и переключаться между ними во время выполнения без изменений кода.
6
6
  keywords:
@@ -22,7 +22,13 @@ history:
22
22
  changes: "Выпуск функции вариантов"
23
23
  - version: 9.1.0
24
24
  date: 2026-06-26
25
- changes: "`variant` теперь принимает строку или объект — прежние `meta` / динамические записи объявляются как объектные варианты"
25
+ changes: "`variant` теперь принимает строку или объект — прежние `meta` / динамические записи объявляются как вариант объектов"
26
+ - version: 9.1.1
27
+ date: 2026-07-31
28
+ changes: "Вариант объявляет только ключи, которые он переопределяет; необъявленные варианты возвращаются к записи по умолчанию"
29
+ - version: 9.1.2
30
+ date: 2026-08-04
31
+ changes: "Провайдеры принимают внешний проп `variant`; селекторы принимают упорядоченную цепочку предпочтений"
26
32
  author: aymericzip
27
33
  ---
28
34
 
@@ -77,6 +83,37 @@ const dictionary = {
77
83
  export default dictionary;
78
84
  ```
79
85
 
86
+ ### Частичные варианты
87
+
88
+ Вариант **объявляет только ключи, которые он переопределяет**; остальные наследуются из записи по умолчанию.
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` унаследовано
110
+
111
+ useIntlayer("hero-banner", { variant: "never-declared" });
112
+ // → запись по умолчанию
113
+ ```
114
+
115
+ Поэтому вы добавляете файл варианта только там, где текст действительно отличается. Ключ разрешается в `null` только в том случае, если он объявляет варианты, но не имеет записи по умолчанию.
116
+
80
117
  ### Использование именованных вариантов
81
118
 
82
119
  #### Вариант по умолчанию
@@ -464,6 +501,176 @@ const content = useIntlayer("product", {
464
501
  const content = useIntlayer("product", { variant: { id: "prod_abc" } });
465
502
  ```
466
503
 
504
+ ## Внешний вариант
505
+
506
+ Некоторые измерения варианта неизменны в течение всей сессии — арендатор, тип учебного заведения, тарифный план. Они вычисляются один раз, и ни один компонент не должен передавать их вручную.
507
+
508
+ > Не оборачивайте `useIntlayer` в собственный хук, чтобы их подставить. Оптимизация на этапе сборки переписывает только литеральный вызов `useIntlayer("key")`, импортированный из пакета фреймворка, поэтому ничто за обёрткой не попадёт в бандл.
509
+
510
+ Вместо этого объявите вариант один раз на провайдере, точно так же, как `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
+ Теперь каждое чтение словаря под провайдером разрешается с этим вариантом, а селектор в месте вызова всегда побеждает:
619
+
620
+ ```tsx
621
+ useIntlayer("hero-banner");
622
+ // → вариант провайдера
623
+
624
+ useIntlayer("hero-banner", { variant: "summer" });
625
+ // → "summer" — заменяет вариант провайдера, а не дополняет его
626
+ ```
627
+
628
+ ### Формы
629
+
630
+ Проп `variant` принимает три формы:
631
+
632
+ | Форма | Значение |
633
+ | --------------------------------------------------------- | ---------------------------------------- |
634
+ | `variant="school1"` | один именованный вариант для всех ключей |
635
+ | `variant={["school1", "default"]}` | упорядоченная цепочка предпочтений |
636
+ | `variant={{ "hero-banner": "school1", default: "base" }}` | свой вариант для каждого ключа словаря |
637
+
638
+ #### Цепочка предпочтений
639
+
640
+ Цепочка перебирается слева направо по записям, объявленным каждым ключом, и побеждает первая объявленная. Если не объявлена ни одна, используется неявная запись по умолчанию — точно так же, как для одиночного значения.
641
+
642
+ ```tsx
643
+ <IntlayerProvider variant={["school1", "school2"]} />
644
+ // `hero-banner` не объявляет запись `school1`, но объявляет `school2` → "school2"
645
+ // ключ, не объявляющий ни одной из них → запись по умолчанию
646
+ ```
647
+
648
+ Таким образом, `["black_friday", "summer"]` читается как «black friday, если у этого ключа он есть, иначе summer, иначе по умолчанию». Цепочки также принимаются в месте вызова:
649
+
650
+ ```tsx
651
+ useIntlayer("hero-banner", { variant: ["black_friday", "summer"] });
652
+ ```
653
+
654
+ > Обратите внимание: это зеркальное отражение массива, принимаемого **полем** `variant` файла контента: там массив _объявляет_ по одной записи на элемент, здесь он _потребляет_ их в порядке приоритета.
655
+
656
+ #### Отображение по ключам
657
+
658
+ Обращайтесь к каждому ключу словаря отдельно. Зарезервированная запись `default` покрывает все не перечисленные ключи:
659
+
660
+ ```tsx
661
+ <IntlayerProvider
662
+ variant={{
663
+ "hero-banner": "school1",
664
+ product: ["school1", "default"],
665
+ default: "base",
666
+ }}
667
+ />
668
+ ```
669
+
670
+ > На провайдере обычный объект **всегда** читается как отображение по ключам, но не как объектный вариант — они структурно идентичны. Чтобы задать объектный вариант глобально, вложите его в запись: `variant={{ default: { id: "prod_abc" } }}`.
671
+
672
+ Поскольку ключи отображения сверяются с объявленными ключами словарей, опечатка — или объектный вариант, записанный напрямую, например `variant={{ id: "prod_abc" }}` — приводит к ошибке компиляции.
673
+
467
674
  ## Режим загрузки
468
675
 
469
676
  Объектные варианты часто загружаются лениво. Задайте `importMode` в словаре, чтобы управлять этим: