Receba notificações sobre os próximos lançamentos de Intlayer
    Criação:2025-04-18Última atualização:2025-06-29

    Começando a Internacionalizar (i18n) com Intlayer, Vite e Preact

    Este pacote está em desenvolvimento. Veja a issue para mais informações. Demonstre seu interesse no Intlayer para Preact curtindo a issue

    Veja o Modelo de Aplicação no GitHub.

    O que é o Intlayer?

    Intlayer é uma biblioteca inovadora e open-source de internacionalização (i18n) projetada para simplificar o suporte multilíngue em aplicações web modernas.

    Com o Intlayer, você pode:

    • Gerenciar traduções facilmente usando dicionários declarativos no nível do componente.
    • Localizar dinamicamente metadados, rotas e conteúdo.
    • Garantir suporte ao TypeScript com tipos gerados automaticamente, melhorando o autocompletar e a detecção de erros.
    • Beneficie de recursos avançados, como detecção e troca dinâmica de localidade.

    Guia Passo a Passo para Configurar o Intlayer em uma Aplicação Vite e Preact

    Passo 1: Instalar Dependências

    Instale os pacotes necessários usando npm:

    bash
    npm install intlayer preact-intlayernpm install vite-intlayer --save-dev
    • intlayer

    • intlayer

      O pacote principal que fornece ferramentas de internacionalização para gerenciamento de configuração, tradução, declaração de conteúdo, transpiração e comandos CLI.

    • preact-intlayer O pacote que integra o Intlayer com a aplicação Preact. Ele fornece provedores de contexto e hooks para internacionalização em Preact.

    • vite-intlayer Inclui o plugin Vite para integrar o Intlayer com o empacotador Vite, bem como middleware para detectar a localidade preferida do usuário, gerenciar cookies e lidar com redirecionamento de URL.

    Passo 2: Configuração do seu projeto

    Crie um arquivo de configuração para configurar os idiomas da sua aplicação:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Seus outros idiomas    ],    defaultLocale: Locales.ENGLISH,  },};export default config;

    Através deste arquivo de configuração, você pode configurar URLs localizadas, redirecionamento de middleware, nomes de cookies, a localização e extensão das suas declarações de conteúdo, desabilitar logs do Intlayer no console e muito mais. Para uma lista completa dos parâmetros disponíveis, consulte a documentação de configuração.

    Passo 3: Integre o Intlayer na Sua Configuração do Vite

    Adicione o plugin intlayer na sua configuração.

    vite.config.ts
    import { defineConfig } from "vite";import preact from "@preact/preset-vite";import { intlayerPlugin } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [preact(), intlayerPlugin()],});

    O plugin Vite intlayerPlugin() é usado para integrar o Intlayer com o Vite. Ele garante a construção dos arquivos de declaração de conteúdo e os monitora no modo de desenvolvimento. Define variáveis de ambiente do Intlayer dentro da aplicação Vite. Além disso, fornece aliases para otimizar o desempenho.

    Passo 4: Declare Seu Conteúdo

    Crie e gerencie suas declarações de conteúdo para armazenar traduções:

    src/app.content.tsx
    import { t, type Dictionary } from "intlayer";import type { ComponentChildren } from "preact";const appContent = {  key: "app",  content: {    viteLogo: t({      en: "Vite logo",      fr: "Logo Vite",      es: "Logo Vite",    }),    preactLogo: t({      en: "Preact logo",      fr: "Logo Preact",      es: "Logo Preact",    }),    title: "Vite + Preact",    count: t({      en: "count is ",      fr: "le compte est ",      es: "el recuento es ",    }),    edit: t<ComponentChildren>({      en: (        <>          Edite <code>src/app.tsx</code> e salve para testar HMR        </>      ),      fr: (        <>          Éditez <code>src/app.tsx</code> et enregistrez pour tester HMR        </>      ),      es: (        <>          Edita <code>src/app.tsx</code> y guarda para probar HMR        </>      ),    }),    readTheDocs: t({      en: "Clique nos logos do Vite e Preact para saber mais",      fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",      es: "Haga clic en los logotipos de Vite y Preact para obtener más información",    }),  },} satisfies Dictionary;export default appContent;

    Suas declarações de conteúdo podem ser definidas em qualquer lugar da sua aplicação, desde que estejam incluídas no diretório contentDir (por padrão, ./src). E correspondam à extensão do arquivo de declaração de conteúdo (por padrão, .content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}).

    Para mais detalhes, consulte a documentação de declaração de conteúdo.

    Se seu arquivo de conteúdo incluir código TSX, pode ser necessário importar import { h } from "preact"; ou garantir que sua pragma JSX esteja corretamente configurada para Preact.

    Passo 5: Utilize o Intlayer no Seu Código

    Acesse seus dicionários de conteúdo em toda a sua aplicação:

    src/app.tsx
    import { useState } from "preact/hooks";import type { FunctionalComponent } from "preact";import preactLogo from "./assets/preact.svg"; // Supondo que você tenha um preact.svgimport viteLogo from "/vite.svg";import "./app.css"; // Supondo que seu arquivo CSS se chame app.cssimport { IntlayerProvider, useIntlayer } from "preact-intlayer";const AppContent: FunctionalComponent = () => {  const [count, setCount] = useState(0);  const content = useIntlayer("app");  return (    <>      <div>        <a href="https://vitejs.dev" target="_blank">          <img src={viteLogo} class="logo" alt={content.viteLogo.value} />        </a>        <a href="https://preactjs.com" target="_blank">          <img            src={preactLogo}            class="logo preact"            alt={content.preactLogo.value}          />        </a>      </div>      <h1>{content.title}</h1>      <div class="card">        <button onClick={() => setCount((count) => count + 1)}>          {content.count}          {count}        </button>        <p>{content.edit}</p>      </div>      <p class="read-the-docs">{content.readTheDocs}</p>    </>  );};const App: FunctionalComponent = () => (  <IntlayerProvider>    <AppContent />  </IntlayerProvider>);export default App;

    Se você quiser usar seu conteúdo em um atributo string, como alt, title, href, aria-label, etc., você deve chamar o valor da função, assim:

    jsx
    <img src={content.image.src.value} alt={content.image.value} />

    Nota: No Preact, className é tipicamente escrito como class.

    Para saber mais sobre o hook useIntlayer, consulte a documentação (A API é semelhante para preact-intlayer).

    (Opcional) Passo 6: Alterar o idioma do seu conteúdo

    Para alterar o idioma do seu conteúdo, você pode usar a função setLocale fornecida pelo hook useLocale. Essa função permite definir o locale da aplicação e atualizar o conteúdo de acordo.

    src/components/LocaleSwitcher.tsx
    import type { FunctionalComponent } from "preact";import { Locales } from "intlayer";import { useLocale } from "preact-intlayer";const LocaleSwitcher: FunctionalComponent = () => {  const { setLocale } = useLocale();  return (    <button onClick={() => setLocale(Locales.ENGLISH)}>      Alterar idioma para Inglês    </button>  );};export default LocaleSwitcher;

    Para saber mais sobre o hook useLocale, consulte a documentação (A API é semelhante para preact-intlayer).

    (Opcional) Passo 7: Adicione roteamento localizado à sua aplicação

    O objetivo deste passo é criar rotas únicas para cada idioma. Isso é útil para SEO e URLs amigáveis para SEO. Exemplo:

    plaintext
    - https://example.com/about- https://example.com/es/about- https://example.com/fr/about

    Por padrão, as rotas não são prefixadas para o idioma padrão. Se você quiser prefixar o idioma padrão, pode definir a opção middleware.prefixDefault como true na sua configuração. Veja a documentação de configuração para mais informações.

    Para adicionar roteamento localizado à sua aplicação, você pode criar um componente LocaleRouter que envolva as rotas da sua aplicação e gerencie o roteamento baseado no idioma. Aqui está um exemplo usando preact-iso:

    Primeiro, instale o preact-iso:

    bash
    npm install preact-iso
    src/components/LocaleRouter.tsx
    import { type Locales, configuration, getPathWithoutLocale } from "intlayer";import { ComponentChildren, FunctionalComponent } from "preact";import { IntlayerProvider } from "preact-intlayer";import { LocationProvider, useLocation } from "preact-iso";import { useEffect } from "preact/hooks";const { internationalization, middleware } = configuration;const { locales, defaultLocale } = internationalization;const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({  to,  replace,}) => {  const { route } = useLocation();  useEffect(() => {    route(to, replace);  }, [to, replace, route]);  return null;};/** * Um componente que gerencia a localização e envolve os filhos com o contexto de idioma apropriado. * Ele gerencia a detecção e validação do idioma baseado na URL. */const AppLocalized: FunctionalComponent<{  children: ComponentChildren;  locale?: Locales;}> = ({ children, locale }) => {  const { path: pathname, url } = useLocation();  if (!url) {    return null;  }  const search = url.substring(pathname.length);  // Determina o idioma atual, usando o padrão caso não seja fornecido  const currentLocale = locale ?? defaultLocale;  // Remove o prefixo do idioma do caminho para construir um caminho base  const pathWithoutLocale = getPathWithoutLocale(    pathname // Caminho atual da URL  );  /**   * Se middleware.prefixDefault for verdadeiro, o locale padrão deve sempre ser prefixado.   */  if (middleware.prefixDefault) {    // Validar o locale    if (!locale || !locales.includes(locale)) {      // Redirecionar para o locale padrão com o caminho atualizado      return (        <Navigate          to={`/${defaultLocale}/${pathWithoutLocale}${search}`}          replace // Substituir a entrada atual do histórico pela nova        />      );    }    // Envolver os filhos com o IntlayerProvider e definir o locale atual    return (      <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>    );  } else {    /**     * Quando middleware.prefixDefault for falso, o locale padrão não é prefixado.     * Garantir que o idioma atual seja válido e não o idioma padrão.     */    if (      currentLocale.toString() !== defaultLocale.toString() &&      !locales        .filter(          (loc) => loc.toString() !== defaultLocale.toString() // Excluir o idioma padrão        )        .includes(currentLocale) // Verificar se o idioma atual está na lista de idiomas válidos    ) {      // Redirecionar para o caminho sem prefixo de idioma      return <Navigate to={`${pathWithoutLocale}${search}`} replace />;    }    // Envolver os filhos com o IntlayerProvider e definir o idioma atual    return (      <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>    );  }};const RouterContent: FunctionalComponent<{  children: ComponentChildren;}> = ({ children }) => {  const { path } = useLocation();  if (!path) {    return null;  }  const pathLocale = path.split("/")[1] as Locales;  const isLocaleRoute = locales    .filter((locale) => middleware.prefixDefault || locale !== defaultLocale)    .some((locale) => locale.toString() === pathLocale);  if (isLocaleRoute) {    return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;  }  return (    <AppLocalized      locale={!middleware.prefixDefault ? defaultLocale : undefined}    >      {children}    </AppLocalized>  );};/** * Um componente de roteador que configura rotas específicas para cada locale. * Ele usa preact-iso para gerenciar a navegação e renderizar componentes localizados. */export const LocaleRouter: FunctionalComponent<{  children: ComponentChildren;}> = ({ children }) => (  <LocationProvider>    <RouterContent>{children}</RouterContent>  </LocationProvider>);

    Então, você pode usar o componente LocaleRouter na sua aplicação:

    src/app.tsx
    import { LocaleRouter } from "./components/LocaleRouter";import type { FunctionalComponent } from "preact";// ... Seu componente AppContent (definido no Passo 5)const App: FunctionalComponent = () => (  <LocaleRouter>    <AppContent />  </LocaleRouter>);export default App;

    Em paralelo, você também pode usar o intLayerMiddlewarePlugin para adicionar roteamento no lado do servidor à sua aplicação. Este plugin detectará automaticamente o locale atual com base na URL e definirá o cookie de locale apropriado. Se nenhum locale for especificado, o plugin determinará o locale mais adequado com base nas preferências de idioma do navegador do usuário. Se nenhum locale for detectado, ele redirecionará para o locale padrão.

    vite.config.ts
    import { defineConfig } from "vite";import preact from "@preact/preset-vite";import { intlayerPlugin, intLayerMiddlewarePlugin } from "vite-intlayer";// https://vitejs.dev/config/export default defineConfig({  plugins: [preact(), intlayerPlugin(), intLayerMiddlewarePlugin()],});

    (Opcional) Passo 8: Alterar a URL quando o idioma mudar

    Para alterar a URL quando o locale mudar, você pode usar a prop onLocaleChange fornecida pelo hook useLocale. Em paralelo, você pode usar useLocation e route do preact-iso para atualizar o caminho da URL.

    src/components/LocaleSwitcher.tsx
    import { useLocation, route } from "preact-iso";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "preact-intlayer";import type { FunctionalComponent } from "preact";const LocaleSwitcher: FunctionalComponent = () => {  const location = useLocation();  const { locale, availableLocales, setLocale } = useLocale({    onLocaleChange: (newLocale) => {      const currentFullPath = location.url; // preact-iso fornece a URL completa      // Construir a URL com o locale atualizado      // Exemplo: /es/about?foo=bar      const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);      // Atualizar o caminho da URL      route(pathWithLocale, true); // true para substituir    },  });  return (    <div>      <button popovertarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <a            href={getLocalizedUrl(location.url, localeItem)}            hreflang={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={(e) => {              e.preventDefault();              setLocale(localeItem);              // A navegação programática após definir o locale será tratada por onLocaleChange            }}            key={localeItem}          >            <span>              {/* Locale - ex: FR */}              {localeItem}            </span>            <span>              {/* Idioma no seu próprio Locale - ex: Français */}              {getLocaleName(localeItem, localeItem)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Idioma no Locale atual - ex: Francés com o locale atual definido como Locales.SPANISH */}              {getLocaleName(localeItem, locale)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Idioma em Inglês - ex: French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>          </a>        ))}      </div>    </div>  );};export default LocaleSwitcher;

    Referências da documentação:

    -

    useLocale hook (API é similar para preact-intlayer)

    Abaixo está o Passo 9 atualizado com explicações adicionais e exemplos de código refinados:


    (Opcional) Passo 9: Alterar os atributos de idioma e direção do HTML

    Quando sua aplicação suporta múltiplos idiomas, é crucial atualizar os atributos lang e dir da tag <html> para corresponder ao locale atual. Fazer isso garante:

    • Acessibilidade: Leitores de tela e tecnologias assistivas dependem do atributo lang correto para pronunciar e interpretar o conteúdo com precisão.
    • Renderização de Texto: O atributo dir (direção) assegura que o texto seja renderizado na ordem correta (por exemplo, da esquerda para a direita para inglês, da direita para a esquerda para árabe ou hebraico), o que é essencial para a legibilidade.
    • SEO: Os motores de busca utilizam o atributo lang para determinar o idioma da sua página, ajudando a exibir o conteúdo localizado correto nos resultados de pesquisa.

    Ao atualizar esses atributos dinamicamente quando o locale muda, você garante uma experiência consistente e acessível para os usuários em todos os idiomas suportados.

    Implementando o Hook

    Crie um hook personalizado para gerenciar os atributos HTML. O hook escuta as mudanças de locale e atualiza os atributos conforme necessário:

    src/hooks/useI18nHTMLAttributes.tsx
    import { useEffect } from "preact/hooks";import { useLocale } from "preact-intlayer";import { getHTMLTextDir } from "intlayer";/** * Atualiza os atributos `lang` e `dir` do elemento HTML <html> com base no locale atual. * - `lang`: Informa aos navegadores e motores de busca o idioma da página. * - `dir`: Garante a ordem correta da leitura (por exemplo, 'ltr' para inglês, 'rtl' para árabe). * * Esta atualização dinâmica é essencial para a renderização correta do texto, acessibilidade e SEO. */export const useI18nHTMLAttributes = () => {  const { locale } = useLocale();  useEffect(() => {    // Atualiza o atributo de idioma para o locale atual.    document.documentElement.lang = locale;    // Define a direção do texto com base no locale atual.    document.documentElement.dir = getHTMLTextDir(locale);  }, [locale]);};

    Usando o Hook na Sua Aplicação

    Integre o hook no seu componente principal para que os atributos HTML sejam atualizados sempre que o locale mudar:

    src/app.tsx
    import type { FunctionalComponent } from "preact";import { IntlayerProvider } from "preact-intlayer"; // useIntlayer já importado se AppContent precisarimport { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";import "./app.css";// Definição do AppContent a partir do Passo 5const AppWithHooks: FunctionalComponent = () => {  // Aplicar o hook para atualizar os atributos lang e dir da tag <html> com base no locale.  useI18nHTMLAttributes();  // Supondo que AppContent seja seu componente principal de exibição de conteúdo do Passo 5  return <AppContent />;};const App: FunctionalComponent = () => (  <IntlayerProvider>    <AppWithHooks />  </IntlayerProvider>);export default App;

    Ao aplicar essas alterações, sua aplicação irá:

    • Garantir que o atributo language (lang) reflita corretamente a localidade atual, o que é importante para SEO e comportamento do navegador.
    • Ajustar a direção do texto (dir) de acordo com a localidade, melhorando a legibilidade e usabilidade para idiomas com ordens de leitura diferentes.
    • Proporcionar uma experiência mais acessível, pois as tecnologias assistivas dependem desses atributos para funcionar de forma otimizada.

    Para garantir que a navegação da sua aplicação respeite o idioma atual, você pode criar um componente Link personalizado. Esse componente adiciona automaticamente o prefixo do idioma atual às URLs internas.

    Esse comportamento é útil por várias razões:

    • SEO e Experiência do Usuário: URLs localizadas ajudam os motores de busca a indexar corretamente páginas específicas por idioma e fornecem aos usuários conteúdo no idioma preferido.
    • Consistência: Ao usar um link localizado em toda a sua aplicação, você garante que a navegação permaneça dentro do idioma atual, evitando mudanças inesperadas de idioma.
    • Manutenção: Centralizar a lógica de localização em um único componente simplifica o gerenciamento das URLs.

    Para Preact com preact-iso, as tags <a> padrão são tipicamente usadas para navegação, e o preact-iso gerencia o roteamento. Se você precisar de navegação programática ao clicar (por exemplo, para executar ações antes de navegar), pode usar a função route do useLocation. Aqui está como você pode criar um componente de âncora personalizado que localiza URLs:

    src/components/LocalizedLink.tsx
    import { getLocalizedUrl } from "intlayer";import { useLocale, useLocation, route } from "preact-intlayer"; // Assumindo que useLocation e route podem ser do preact-iso via preact-intlayer se reexportados, ou importar diretamente// Se não for reexportado, importe diretamente: import { useLocation, route } from "preact-iso";import type { JSX } from "preact"; // Para HTMLAttributesimport { forwardRef } from "preact/compat"; // Para encaminhar refsexport interface LocalizedLinkProps  extends JSX.HTMLAttributes<HTMLAnchorElement> {  href: string;  replace?: boolean; // Opcional: para substituir o estado do histórico}/** * Função utilitária para verificar se uma URL é externa. * Se a URL começar com http:// ou https://, é considerada externa. */export const checkIsExternalLink = (href?: string): boolean =>  /^https?:\/\//.test(href ?? "");/** * Um componente Link personalizado que adapta o atributo href com base no locale atual. * Para links internos, ele usa `getLocalizedUrl` para prefixar a URL com a localidade (por exemplo, /fr/about). * Isso garante que a navegação permaneça dentro do mesmo contexto de localidade. * Ele usa uma tag <a> padrão, mas pode disparar a navegação no lado do cliente usando o `route` do preact-iso. */export const LocalizedLink = forwardRef<HTMLAnchorElement, LocalizedLinkProps>(  ({ href, children, onClick, replace = false, ...props }, ref) => {    const { locale } = useLocale();    const location = useLocation(); // do preact-iso    const isExternalLink = checkIsExternalLink(href);    const hrefI18n =      href && !isExternalLink ? getLocalizedUrl(href, locale) : href;    const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {      if (onClick) {        onClick(event);      }      if (        !isExternalLink &&        href && // Garantir que href está definido        event.button === 0 && // Clique esquerdo        !event.metaKey &&        !event.ctrlKey &&        !event.shiftKey &&        !event.altKey && // Verificação padrão de modificadores        !props.target // Não direcionando para uma nova aba/janela      ) {        event.preventDefault();        if (location.url !== hrefI18n) {          // Navegar apenas se a URL for diferente          route(hrefI18n, replace); // Usar a rota do preact-iso        }      }    };    return (      <a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>        {children}      </a>    );  });

    Como Funciona

    • Detecção de Links Externos:
      A função auxiliar checkIsExternalLink determina se uma URL é externa. Links externos permanecem inalterados.
    • Recuperando a Localização Atual:
      O hook useLocale fornece a localização atual.
    • Localizando a URL:
      Para links internos, getLocalizedUrl adiciona o prefixo da localização atual à URL.
    • Navegação no Lado do Cliente: A função handleClick verifica se o link é interno e se a navegação padrão deve ser evitada. Se for o caso, ela usa a função route do preact-iso (obtida via useLocation ou importada diretamente) para realizar a navegação no lado do cliente. Isso proporciona um comportamento semelhante a SPA sem recarregamentos completos da página.
    • Retornando o Link:
      O componente retorna um elemento <a> com a URL localizada e o manipulador de clique personalizado.

    Configurar TypeScript

    O Intlayer usa a ampliação de módulos para aproveitar os benefícios do TypeScript e tornar sua base de código mais robusta.

    alt text

    alt text

    Garanta que sua configuração do TypeScript inclua os tipos gerados automaticamente.

    tsconfig.json
    {  // ... Suas configurações existentes do TypeScript  "compilerOptions": {    // ...    "jsx": "react-jsx",    "jsxImportSource": "preact", // Recomendado para Preact 10+    // ...  },  "include": [    // ... Suas configurações existentes do TypeScript    ".intlayer/**/*.ts", // Inclua os tipos gerados automaticamente  ],}

    Certifique-se de que seu tsconfig.json esteja configurado para Preact, especialmente jsx e jsxImportSource ou jsxFactory/jsxFragmentFactory para versões antigas do Preact, caso não esteja usando os padrões do preset-vite.

    Configuração do Git

    É recomendado ignorar os arquivos gerados pelo Intlayer. Isso permite que você evite comitar esses arquivos no seu repositório Git.

    Para isso, você pode adicionar as seguintes instruções ao seu arquivo .gitignore:

    plaintext
    # Ignorar os arquivos gerados pelo Intlayer.intlayer

    Extensão VS Code

    Para melhorar sua experiência de desenvolvimento com o Intlayer, você pode instalar a extensão oficial Intlayer VS Code Extension.

    Instalar no VS Code Marketplace

    Esta extensão oferece:

    • Autocompletar para chaves de tradução.
    • Detecção de erros em tempo real para traduções ausentes.
    • Visualizações inline do conteúdo traduzido.
    • Ações rápidas para criar e atualizar traduções facilmente.

    Para mais detalhes sobre como usar a extensão, consulte a documentação da Extensão Intlayer para VS Code.


    Ir Mais Longe

    Para ir mais longe, você pode implementar o editor visual ou externalizar seu conteúdo usando o CMS.


    Histórico do Documento

    • 5.5.10 - 2025-06-29: Histórico inicial
    Receba notificações sobre os próximos lançamentos de Intlayer