El contenido de esta página ha sido traducido con una IA.
Ver la última versión del contenido original en inglésEste paquete está en desarrollo. Consulte el issue para más información. Muestre su interés en Intlayer para Preact dando like al issue.
Consulte Plantilla de Aplicación en GitHub.
¿Qué es Intlayer?
Intlayer es una biblioteca de internacionalización (i18n) innovadora y de código abierto diseñada para simplificar el soporte multilingüe en aplicaciones web modernas.
Con Intlayer, puedes:
- Gestionar traducciones fácilmente utilizando diccionarios declarativos a nivel de componente.
- Localizar dinámicamente metadatos, rutas y contenido.
- Asegurar soporte para TypeScript con tipos autogenerados, mejorando la autocompletación y la detección de errores.
- Beneficiarte de características avanzadas, como la detección dinámica de locales y el cambio entre ellos.
Guía paso a paso para configurar Intlayer en una aplicación Vite y Preact
Paso 1: Instalar dependencias
Instala los paquetes necesarios utilizando npm:
npm install intlayer preact-intlayer vite-intlayer
intlayer
El paquete principal que proporciona herramientas de internacionalización para la gestión de configuración, traducción, declaración de contenido, transpilación y comandos CLI.
preact-intlayer El paquete que integra Intlayer con aplicaciones Preact. Proporciona proveedores de contexto y hooks para la internacionalización en Preact.
vite-intlayer Incluye el plugin de Vite para integrar Intlayer con el empaquetador Vite, así como middleware para detectar el idioma preferido del usuario, gestionar cookies y manejar redirecciones de URL.
Paso 2: Configuración de tu proyecto
Crea un archivo de configuración para configurar los idiomas de tu aplicación:
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // Tus otros locales ], defaultLocale: Locales.ENGLISH, },};export default config;
A través de este archivo de configuración, puedes configurar URLs localizadas, redirección de middleware, nombres de cookies, la ubicación y extensión de tus declaraciones de contenido, desactivar los logs de Intlayer en la consola y más. Para una lista completa de parámetros disponibles, consulta la documentación de configuración.
Paso 3: Integrar Intlayer en tu configuración de Vite
Agrega el plugin de Intlayer en tu configuración.
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()],});
El plugin intlayerPlugin() de Vite se utiliza para integrar Intlayer con Vite. Asegura la construcción de archivos de declaración de contenido y los monitorea en modo de desarrollo. Define variables de entorno de Intlayer dentro de la aplicación Vite. Además, proporciona alias para optimizar el rendimiento.
Paso 4: Declarar tu contenido
Crea y gestiona tus declaraciones de contenido para almacenar traducciones:
import { t, type Dictionary } from "intlayer";import type { ComponentChildren } from "preact";const appContent = { key: "app", content: { viteLogo: t({ es: "Logo Vite", en: "Vite logo", fr: "Logo Vite", }), preactLogo: t({ es: "Logo Preact", en: "Preact logo", fr: "Logo Preact", }), title: "Vite + Preact", count: t({ es: "el recuento es ", en: "count is ", fr: "le compte est ", }), edit: t<ComponentChildren>({ en: "Edit src/app.tsx and save to test HMR", fr: "Éditez src/app.tsx et enregistrez pour tester HMR", es: "Edita src/app.tsx y guarda para probar HMR", }), readTheDocs: t({ es: "Haga clic en los logotipos de Vite y Preact para obtener más información", en: "Click on the Vite and Preact logos to learn more", fr: "Cliquez sur les logos Vite et Preact pour en savoir plus", }), },} satisfies Dictionary;export default appContent;
Tus declaraciones de contenido pueden definirse en cualquier lugar de tu aplicación siempre que estén incluidas en el directorio contentDir (por defecto, ./src). Y coincidan con la extensión del archivo de declaración de contenido (por defecto, .content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}). Para más detalles, consulta la documentación de declaración de contenido. Si tu archivo de contenido incluye código TSX, es posible que necesites importar import { h } from "preact"; o asegurarte de que tu pragma JSX esté configurado correctamente para Preact.
Paso 5: Utiliza Intlayer en tu código
Accede a tus diccionarios de contenido en toda tu aplicación:
import { useState } from "preact/hooks";import type { FunctionalComponent } from "preact";import preactLogo from "./assets/preact.svg"; // Suponiendo que tienes un preact.svgimport viteLogo from "/vite.svg";import "./app.css"; // Suponiendo que tu archivo CSS se llama 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;
Si deseas usar tu contenido en un atributo string, como alt, title, href, aria-label, etc., debes llamar al valor de la función, como:
jsx<img src={content.image.src.value} alt={content.image.value} />
Nota: En Preact, className se escribe típicamente como class.
Para aprender más sobre el hook useIntlayer, consulta la documentación (La API es similar para preact-intlayer).
(Opcional) Paso 6: Cambia el idioma de tu contenido
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)}> Cambiar idioma a inglés </button> );};export default LocaleSwitcher;
Para aprender más sobre el hook useLocale, consulta la documentación (La API es similar para preact-intlayer).
(Opcional) Paso 7: Agregar enrutamiento localizado a tu aplicación
El propósito de este paso es crear rutas únicas para cada idioma. Esto es útil para SEO y URLs amigables para SEO.
Ejemplo:
- https://example.com/about- https://example.com/es/about- https://example.com/fr/about
Por defecto, las rutas no están prefijadas para la configuración regional predeterminada. Si deseas prefijar la configuración regional predeterminada, puedes establecer la opción middleware.prefixDefault en true en tu configuración. Consulta la documentación de configuración para más información.
Para agregar enrutamiento localizado a tu aplicación, puedes crear un componente LocaleRouter que envuelva las rutas de tu aplicación y maneje el enrutamiento basado en la configuración regional. Aquí hay un ejemplo usando preact-iso:
Primero, instala preact-iso:
npm install preact-iso
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;};/** * Un componente que maneja la localización y envuelve a los hijos con el contexto de configuración regional apropiado. * Gestiona la detección y validación de la configuración regional basada en la 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 la configuración regional actual, usando la predeterminada si no se proporciona const currentLocale = locale ?? defaultLocale; // Elimina el prefijo de configuración regional del camino para construir una ruta base const pathWithoutLocale = getPathWithoutLocale( pathname // Ruta actual de la URL ); /** * Si middleware.prefixDefault es verdadero, la configuración regional predeterminada siempre debe estar prefijada. */ if (middleware.prefixDefault) { // Valida la configuración regional if (!locale || !locales.includes(locale)) { // Redirige a la configuración regional predeterminada con la ruta actualizada return ( <Navigate to={`/${defaultLocale}/${pathWithoutLocale}${search}`} replace // Reemplaza la entrada actual del historial con la nueva /> ); } // Envuelve a los hijos con el IntlayerProvider y establece la configuración regional actual return ( <IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider> ); } else { /** * Cuando middleware.prefixDefault es falso, la configuración regional predeterminada no está prefijada. * Asegúrate de que la configuración regional actual sea válida y no sea la predeterminada. */ if ( currentLocale.toString() !== defaultLocale.toString() && !locales .filter( (loc) => loc.toString() !== defaultLocale.toString() // Excluye la configuración regional predeterminada ) .includes(currentLocale) // Verifica si la configuración regional actual está en la lista de configuraciones válidas ) { // Redirige a la ruta sin prefijo de configuración regional return <Navigate to={`${pathWithoutLocale}${search}`} replace />; } // Envuelve a los hijos con el IntlayerProvider y establece la configuración regional actual 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> );};/** * Un componente de enrutador que configura rutas específicas de configuración regional. * Utiliza preact-iso para gestionar la navegación y renderizar componentes localizados. */export const LocaleRouter: FunctionalComponent<{ children: ComponentChildren;}> = ({ children }) => ( <LocationProvider> <RouterContent>{children}</RouterContent> </LocationProvider>);
Luego, puedes usar el componente LocaleRouter en tu aplicación:
import { LocaleRouter } from "./components/LocaleRouter";import type { FunctionalComponent } from "preact";// ... Tu componente AppContent (definido en el Paso 5)const App: FunctionalComponent = () => ( <LocaleRouter> <AppContent /> </LocaleRouter>);export default App;
Paralelamente, también puedes usar el intLayerMiddlewarePlugin para agregar enrutamiento del lado del servidor a tu aplicación. Este plugin detectará automáticamente el locale actual basado en la URL y establecerá la cookie de locale apropiada. Si no se especifica un locale, el plugin determinará el locale más apropiado basado en las preferencias de idioma del navegador del usuario. Si no se detecta ningún locale, redirigirá al locale predeterminado.
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) Paso 8: Cambiar la URL cuando cambia el idioma
Para cambiar la URL cuando cambia el idioma, puedes usar la propiedad onLocaleChange proporcionada por el hook useLocale. Paralelamente, puedes usar useLocation y route de preact-iso para actualizar la ruta de la URL.
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 proporciona la URL completa // Construir la URL con el idioma actualizado // Ejemplo: /es/about?foo=bar const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale); // Actualizar la ruta de la URL route(pathWithLocale, true); // true para reemplazar }, }); 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); // La navegación programática después de establecer el idioma será manejada por onLocaleChange }} key={localeItem} > <span> {/* Idioma - ej. FR */} {localeItem} </span> <span> {/* Idioma en su propio idioma - ej. Français */} {getLocaleName(localeItem, localeItem)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* Idioma en el idioma actual - ej. Francés con el idioma actual configurado en Locales.SPANISH */} {getLocaleName(localeItem, locale)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* Idioma en inglés - ej. French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> </a> ))} </div> </div> );};export default LocaleSwitcher;
Referencias de documentación:
- useLocale hook (La API es similar para preact-intlayer)
- getLocaleName hook
- getLocalizedUrl hook
- getHTMLTextDir hook
- hreflang attribute
- lang attribute
- dir attribute
- aria-current attribute
- Popover API
(Opcional) Paso 9: Cambiar los atributos de idioma y dirección en HTML
Cuando tu aplicación soporta múltiples idiomas, es crucial actualizar los atributos lang y dir de la etiqueta <html> para que coincidan con el idioma actual. Esto asegura:
Accesibilidad: Los lectores de pantalla y tecnologías asistivas dependen del atributo lang correcto para pronunciar e interpretar el contenido con precisión.
SEO: Los motores de búsqueda utilizan el atributo lang para determinar el idioma de tu página, ayudando a mostrar el contenido localizado correcto en los resultados de búsqueda.
Al actualizar estos atributos dinámicamente cuando cambia la configuración regional, garantizas una experiencia consistente y accesible para los usuarios en todos los idiomas compatibles.
Implementación del Hook
Crea un hook personalizado para gestionar los atributos HTML. El hook escucha los cambios de configuración regional y actualiza los atributos en consecuencia:
import { useEffect } from "preact/hooks";import { useLocale } from "preact-intlayer";import { getHTMLTextDir } from "intlayer";/** * Actualiza los atributos `lang` y `dir` del elemento HTML <html> según la configuración regional actual. * - `lang`: Informa a los navegadores y motores de búsqueda sobre el idioma de la página. * - `dir`: Asegura el orden de lectura correcto (por ejemplo, 'ltr' para inglés, 'rtl' para árabe). * * Esta actualización dinámica es esencial para un renderizado de texto adecuado, accesibilidad y SEO. */export const useI18nHTMLAttributes = () => { const { locale } = useLocale(); useEffect(() => { // Actualiza el atributo de idioma al idioma actual. document.documentElement.lang = locale; // Establece la dirección del texto según la configuración regional actual. document.documentElement.dir = getHTMLTextDir(locale); }, [locale]);};
Uso del Hook en tu Aplicación
Integra el hook en tu componente principal para que los atributos HTML se actualicen cada vez que cambie la configuración regional:
import type { FunctionalComponent } from "preact";import { IntlayerProvider } from "preact-intlayer"; // useIntlayer ya importado si AppContent lo necesitaimport { useI18nHTMLAttributes } from "./hooks/useI18nHTMLAttributes";import "./app.css";// Definición de AppContent desde el Paso 5const AppWithHooks: FunctionalComponent = () => { // Aplica el hook para actualizar los atributos lang y dir de la etiqueta <html> según la configuración regional. useI18nHTMLAttributes(); // Suponiendo que AppContent es tu componente principal de visualización de contenido del Paso 5 return <AppContent />;};const App: FunctionalComponent = () => ( <IntlayerProvider> <AppWithHooks /> </IntlayerProvider>);export default App;
Al aplicar estos cambios, tu aplicación:
- Asegurará que el atributo idioma (lang) refleje correctamente la configuración regional actual, lo cual es importante para el SEO y el comportamiento del navegador.
- Ajustará la dirección del texto (dir) según la configuración regional, mejorando la legibilidad y usabilidad para idiomas con diferentes órdenes de lectura.
- Proporcionará una experiencia más accesible, ya que las tecnologías de asistencia dependen de estos atributos para funcionar de manera óptima.
(Opcional) Paso 10: Creación de un Componente de Enlace Localizado
Para garantizar que la navegación de tu aplicación respete la configuración regional actual, puedes crear un componente personalizado Link. Este componente automáticamente añade un prefijo a las URLs internas con el idioma actual.
Este comportamiento es útil por varias razones:
- SEO y Experiencia de Usuario: Las URLs localizadas ayudan a los motores de búsqueda a indexar correctamente las páginas específicas de cada idioma y proporcionan a los usuarios contenido en su idioma preferido.
- Consistencia: Al usar un enlace localizado en toda tu aplicación, garantizas que la navegación permanezca dentro del contexto de la configuración regional actual, evitando cambios inesperados de idioma.
- Mantenibilidad: Centralizar la lógica de localización en un único componente simplifica la gestión de URLs.
Para Preact con preact-iso, normalmente se utilizan etiquetas <a> estándar para la navegación, y preact-iso gestiona el enrutamiento. Si necesitas navegación programática al hacer clic (por ejemplo, para realizar acciones antes de navegar), puedes usar la función route de useLocation. Aquí tienes cómo crear un componente de anclaje personalizado que localiza URLs:
import { getLocalizedUrl } from "intlayer";import { useLocale, useLocation, route } from "preact-intlayer"; // Suponiendo que useLocation y route pueden ser de preact-iso vía preact-intlayer si se reexportan, o importar directamente// Si no se reexportan, importar directamente: import { useLocation, route } from "preact-iso";import type { JSX } from "preact"; // Para HTMLAttributesimport { forwardRef } from "preact/compat"; // Para reenviar referenciasexport interface LocalizedLinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> { href: string; replace?: boolean; // Opcional: para reemplazar el estado del historial}/** * Función de utilidad para verificar si una URL dada es externa. * Si la URL comienza con http:// o https://, se considera externa. */export const checkIsExternalLink = (href?: string): boolean => /^https?:\/\//.test(href ?? "");/** * Un componente de enlace personalizado que adapta el atributo href según la configuración regional actual. * Para enlaces internos, utiliza `getLocalizedUrl` para añadir un prefijo a la URL con la configuración regional (por ejemplo, /es/about). * Esto asegura que la navegación permanezca dentro del mismo contexto de configuración regional. * Utiliza una etiqueta <a> estándar pero puede activar la navegación del lado del cliente usando `route` de preact-iso. */export const LocalizedLink = forwardRef<HTMLAnchorElement, LocalizedLinkProps>( ({ href, children, onClick, replace = false, ...props }, ref) => { const { locale } = useLocale(); const location = useLocation(); // de 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 && // Asegura que href esté definido event.button === 0 && // Clic izquierdo !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey && // Verificación de modificadores estándar !props.target // No se está apuntando a una nueva pestaña/ventana ) { event.preventDefault(); if (location.url !== hrefI18n) { // Navegar solo si la URL es diferente route(hrefI18n, replace); // Usar la función route de preact-iso } } }; return ( <a href={hrefI18n} ref={ref} onClick={handleClick} {...props}> {children} </a> ); });
Cómo Funciona
- Detección de Enlaces Externos:
La función auxiliar checkIsExternalLink determina si una URL es externa. Los enlaces externos no se modifican. - Recuperación del Idioma Actual:
El hook useLocale proporciona el idioma actual. - Localización de la URL:
Para enlaces internos, getLocalizedUrl añade el prefijo del idioma actual a la URL. - Navegación en el Cliente: La función handleClick verifica si es un enlace interno y si se debe prevenir la navegación estándar. Si es así, utiliza la función route de preact-iso (obtenida mediante useLocation o importada directamente) para realizar la navegación en el cliente. Esto proporciona un comportamiento tipo SPA sin recargar toda la página.
- Devolución del Enlace:
El componente devuelve un elemento <a> con la URL localizada y el controlador de clic personalizado.
Configurar TypeScript
Intlayer utiliza la ampliación de módulos para aprovechar TypeScript y fortalecer tu base de código.
Asegúrate de que tu configuración de TypeScript incluya los tipos autogenerados.
{ // ... Tu configuración existente de TypeScript "compilerOptions": { // ... "jsx": "react-jsx", "jsxImportSource": "preact", // Recomendado para Preact 10+ // ... }, "include": [ // ... Tu configuración existente de TypeScript ".intlayer/**/*.ts", // Incluir los tipos autogenerados ],}
Asegúrate de que tu tsconfig.json esté configurado para Preact, especialmente jsx y jsxImportSource o jsxFactory/jsxFragmentFactory para versiones anteriores de Preact si no estás utilizando los valores predeterminados de preset-vite.
Configuración de Git
Se recomienda ignorar los archivos generados por Intlayer. Esto te permite evitar que se comprometan en tu repositorio Git.
Para hacerlo, puedes agregar las siguientes instrucciones a tu archivo .gitignore:
# Ignorar los archivos generados por Intlayer.intlayer
Extensión de VS Code
Para mejorar tu experiencia de desarrollo con Intlayer, puedes instalar la Extensión Oficial de Intlayer para VS Code.
Instalar desde el Marketplace de VS Code
Esta extensión proporciona:
- Autocompletado para claves de traducción.
- Detección de errores en tiempo real para traducciones faltantes.
- Previsualizaciones en línea del contenido traducido.
- Acciones rápidas para crear y actualizar traducciones fácilmente.
Para más detalles sobre cómo usar la extensión, consulta la documentación de la Extensión de Intlayer para VS Code.
Ir Más Allá
Para ir más allá, puedes implementar el editor visual o externalizar tu contenido utilizando el CMS.
Si tienes una idea para mejorar esta documentación, no dudes en contribuir enviando una pull request en GitHub.
Enlace de GitHub a la documentación