Internacionalización en Next.js 13 con componentes de React Server

 

 

 

  • Diseño de arquitectura de componentes de interfaz de usuario y tokens, con Nathan Curtis
  • Accesibilidad para diseñadores, con Stéphanie Walter

  • Índice
    1. Obteniendo fotos de Unsplash
    2. Agregar internacionalización connext-intl
      1. Formato de fechas
      2. ¡Hola! Traduciendo nuestra aplicación al español
    3. Agregar interactividad: ordenación dinámica de fotos
    4. Agregar más interactividad: controles de página
    5. Conclusión
      1. Los componentes del servidor son una gran combinación para la internacionalización
      2. Los parámetros de búsqueda son una gran alternativa auseState
      3. Lecturas adicionales sobre SmashingMag

    Basado en un ejemplo de una aplicación multilingüe que muestra imágenes de fotografías callejeras de Unsplash, Jan Amann explora next-intlcómo implementar todas las necesidades de internacionalización en React Server Components y comparte una técnica para introducir interactividad con una huella minimalista del lado del cliente.

     

    Con la introducción de Next.js 13 y la versión beta de App Router, los componentes de React Server estuvieron disponibles públicamente. Este nuevo paradigma permite que los componentes que no requieren las funciones interactivas de React, como useStatey useEffect, permanezcan únicamente en el lado del servidor.

    Un área que se beneficia de esta nueva capacidad es la internacionalización . Tradicionalmente, la internacionalización requiere una compensación en el rendimiento, ya que cargar traducciones genera paquetes más grandes en el lado del cliente y el uso de analizadores de mensajes afecta el rendimiento del tiempo de ejecución del cliente de su aplicación.

    La promesa de React Server Components es que podemos tener nuestro pastel y comerlo también. Si la internacionalización se implementa completamente en el lado del servidor, podemos lograr nuevos niveles de rendimiento para nuestras aplicaciones, dejando el lado del cliente para las funciones interactivas. Pero, ¿cómo podemos trabajar con este paradigma cuando necesitamos estados controlados interactivamente que deberían reflejarse en mensajes internacionalizados?

     

    En este artículo, exploraremos una aplicación multilingüe que muestra imágenes de fotografías callejeras de Unsplash. Usaremos next-intlpara implementar todas nuestras necesidades de internacionalización en React Server Components y veremos una técnica para introducir interactividad con una huella minimalista del lado del cliente.

    También puedes consultar la demostración interactiva . ( Vista previa grande )

    Obteniendo fotos de Unsplash

    Un beneficio clave de los componentes del servidor es la capacidad de recuperar datos directamente desde los componentes internos a través de async/ await. Podemos usar esto para recuperar las fotos de Unsplash en nuestro componente de página.

    Pero primero, necesitamos crear nuestro cliente API basado en el SDK oficial de Unsplash.

    import {createApi} from 'unsplash-js';export default createApi({ accessKey: process.env.UNSPLASH_ACCESS_KEY});

    Una vez que tengamos nuestro cliente API Unsplash, podemos usarlo en el componente de nuestra página.

    import {OrderBy} from 'unsplash-js';import UnsplashApiClient from './UnsplashApiClient';export default async function Index() { const topicSlug = 'street-photography'; const [topicRequest, photosRequest] = await Promise.all([ UnsplashApiClient.topics.get({topicIdOrSlug: topicSlug}), UnsplashApiClient.topics.getPhotos({ topicIdOrSlug: topicSlug, perPage: 4 }) ]); return ( PhotoViewer coverPhoto={topicRequest.response.cover_photo} photos={photosRequest.response.results} / );}

    Nota: Solemos Promise.allinvocar ambas solicitudes que debemos realizar en paralelo. De esta forma evitamos una cascada de solicitudes.

    En este punto, nuestra aplicación muestra una cuadrícula de fotografías simple.

    ( Vista previa grande )

    Actualmente, la aplicación utiliza etiquetas en inglés codificadas y las fechas de las fotos se muestran como marcas de tiempo, lo cual no es muy fácil de usar (todavía).

    Agregar internacionalización connext-intl

    Además del inglés, nos gustaría que nuestra aplicación estuviera disponible en español. El soporte para componentes de servidor se encuentra actualmente en versión beta para next-intl, por lo que podemos usar las instrucciones de instalación de la versión beta más reciente para configurar nuestra aplicación para la internacionalización.

    Formato de fechas

    Aparte de agregar un segundo idioma, ya descubrimos que la aplicación no se adapta bien a los usuarios de inglés porque las fechas deben tener formato. Para lograr una buena experiencia de usuario, nos gustaría informarle el tiempo relativo en que se cargó la foto (por ejemplo, "hace 8 días").

     

    Una vez next-intlconfigurado, podemos corregir el formato utilizando la format.relativeTimefunción en el componente que representa cada foto.

    import {useFormatter} from 'next-intl';export default function PhotoGridItem({photo}) { const format = useFormatter(); const updatedAt = new Date(photo.updated_at); return ( a href={photo.links.html} {/* ... */} p{format.relativeTime(updatedAt)}/p /div /a );}

    Ahora la fecha en la que se actualizó una foto es más fácil de leer.

    ( Vista previa grande )

    Sugerencia: en una aplicación React tradicional que se procesa tanto en el lado del servidor como en el del cliente, puede ser todo un desafío garantizar que la fecha relativa mostrada esté sincronizada en el servidor y el cliente. Dado que se trata de entornos diferentes y pueden estar en diferentes zonas horarias, es necesario configurar un mecanismo para transferir la hora del servidor al lado del cliente. Al realizar el formateo sólo en el lado del servidor, no tenemos que preocuparnos por este problema en primer lugar.

    ¡Hola! Traduciendo nuestra aplicación al español

    A continuación, podemos reemplazar las etiquetas estáticas en el encabezado con mensajes localizados. Estas etiquetas se pasan como accesorios del PhotoViewercomponente, por lo que esta es nuestra oportunidad de introducir etiquetas dinámicas a través del useTranslationsgancho.

    import {useTranslations} from 'next-intl';export default function PhotoViewer(/* ... */) { const t = useTranslations('PhotoViewer'); return ( Header title={t('title')} description={t('description')} / {/* ... */} / );}

    Para cada etiqueta internacionalizada que agreguemos, debemos asegurarnos de que haya una entrada adecuada configurada para todos los idiomas.

    // en.json{ "PhotoViewer": { "title": "Street photography", "description": "Street photography captures real-life moments and human interactions in public places. It is a way to tell visual stories and freeze fleeting moments of time, turning the ordinary into the extraordinary." }}
    // es.json{ "PhotoViewer": { "title": "Street photography", "description": "La fotografía callejera capta momentos de la vida real y interacciones humanas en lugares públicos. Es una forma de contar historias visuales y congelar momentos fugaces del tiempo, convirtiendo lo ordinario en lo extraordinario." }}

    Consejo: next-intlproporciona una integración de TypeScript que le ayuda a garantizar que solo haga referencia a claves de mensajes válidas.

    Una vez hecho esto, podremos visitar la versión en español de la aplicación en /es.

    ( Vista previa grande )

    ¡Hasta ahora, todo bien!

    Agregar interactividad: ordenación dinámica de fotos

    De forma predeterminada, la API Unsplash devuelve las fotos más populares. Queremos que el usuario pueda cambiar el orden para mostrar primero las fotos más recientes. Utensilios de cocina

     

    Aquí surge la pregunta de si deberíamos recurrir a la obtención de datos del lado del cliente para poder implementar esta característica con useState. Sin embargo, eso requeriría que trasladáramos todos nuestros componentes al lado del cliente, lo que daría como resultado un mayor tamaño del paquete.

    ¿Tenemos una alternativa? Sí. Y es una capacidad que existe en la web desde hace mucho tiempo: parámetros de búsqueda (a veces denominados parámetros de consulta ). Lo que hace que los parámetros de búsqueda sean una excelente opción para nuestro caso de uso es que se pueden leer en el lado del servidor.

    Entonces, modifiquemos el componente de nuestra página para recibir searchParamsa través de accesorios.

    export default async function Index({searchParams}) { const orderBy = searchParams.orderBy || OrderBy.POPULAR; const [/* ... */, photosRequest] = await Promise.all([ /* ... */, UnsplashApiClient.topics.getPhotos({orderBy, /* ... */}) ]);

    Después de este cambio, el usuario puede navegar para /?orderBy=latestcambiar el orden de las fotos mostradas.

    Para que al usuario le resulte más fácil cambiar el valor del parámetro de búsqueda, nos gustaría representar un selectelemento interactivo desde dentro de un componente.

    ( Vista previa grande )

    Podemos marcar el componente para 'use client';adjuntar un controlador de eventos y procesar eventos de cambio del selectelemento. Sin embargo, nos gustaría mantener las preocupaciones de internacionalización en el lado del servidor para reducir el tamaño del paquete de clientes.

    Echemos un vistazo al marcado requerido para nuestro selectelemento.

    select option value="popular"Popular/option option value="latest"Latest/option/select

    Podemos dividir este marcado en dos partes:

    1. Renderice el selectelemento con un componente de cliente interactivo.
    2. Renderice los optionelementos internacionalizados con un Componente de Servidor y páselos como childrenal selectelemento.

    Implementemos el selectelemento para el lado del cliente.

    'use client';import {useRouter} from 'next-intl/client';export default function OrderBySelect({orderBy, children}) { const router = useRouter(); function onChange(event) { // The `useRouter` hook from `next-intl` automatically // considers a potential locale prefix of the pathname. router.replace('/?orderBy=' + event.target.value); } return ( select defaultValue={orderBy} onChange={onChange} {children} /select );}

    Ahora, usemos nuestro componente PhotoViewery proporcionemos los optionelementos localizados como children.

    import {useTranslations} from 'next-intl';import OrderBySelect from './OrderBySelect';export default function PhotoViewer({orderBy, /* ... */}) { const t = useTranslations('PhotoViewer'); return ( {/* ... */} OrderBySelect orderBy={orderBy} option value="popular"{t('orderBy.popular')}/option option value="latest"{t('orderBy.latest')}/option /OrderBySelect / );}

    Con este patrón, el marcado de los optionelementos ahora se genera en el lado del servidor y se pasa al OrderBySelect, que maneja el evento de cambio en el lado del cliente.

     

    Consejo : dado que tenemos que esperar a que se genere el marcado actualizado en el lado del servidor cuando se cambia el orden, es posible que queramos mostrarle al usuario un estado de carga. React 18 introdujo el useTransitiongancho , que está integrado con los componentes del servidor. Esto nos permite deshabilitar el selectelemento mientras esperamos una respuesta del servidor.

    import {useRouter} from 'next-intl/client';import {useTransition} from 'react';export default function OrderBySelect({orderBy, children}) { const [isTransitioning, startTransition] = useTransition(); const router = useRouter(); function onChange(event) { startTransition(() = { router.replace('/?orderBy=' + event.target.value); }); } return ( select disabled={isTransitioning} /* ... */ {children} /select );}

    Agregar más interactividad: controles de página

    El mismo patrón que hemos explorado para cambiar el orden se puede aplicar a los controles de página introduciendo un pageparámetro de búsqueda.

    ( Vista previa grande )

    Tenga en cuenta que los idiomas tienen reglas diferentes para manejar separadores de decimales y miles. Además, los idiomas tienen diferentes formas de pluralización: mientras que el inglés sólo hace una distinción gramatical entre uno y cero/muchos elementos, por ejemplo, el croata tiene una forma separada para "pocos" elementos.

    next-intlutiliza la sintaxis ICU que permite expresar estas sutilezas del lenguaje.

    // en.json{ "Pagination": { "info": "Page {page, number} of {totalPages, number} ({totalElements, plural, =1 {one result} other {# results}} in total)", // ... }}

    Esta vez no necesitamos marcar un componente con 'use client';. En su lugar, podemos implementar esto con etiquetas de anclaje normales.

    import {ArrowLeftIcon, ArrowRightIcon} from '@heroicons/react/24/solid';import {Link, useTranslations} from 'next-intl';export default function Pagination({pageInfo, orderBy}) { const t = useTranslations('Pagination'); const totalPages = Math.ceil(pageInfo.totalElements / pageInfo.size); function getHref(page) { return { // Since we're using `Link` from next-intl, a potential locale // prefix of the pathname is automatically considered. pathname: '/', // Keep a potentially existing `orderBy` parameter. query: {orderBy, page} }; } return ( {pageInfo.page 1 ( Link aria-label={t('prev')} href={getHref(pageInfo.page - 1)} ArrowLeftIcon / /Link )} p{t('info', {...pageInfo, totalPages})}/p {pageInfo.page totalPages ( Link aria-label={t('prev')} href={getHref(pageInfo.page + 1)} ArrowRightIcon / /Link )} / );}

    Conclusión

    Los componentes del servidor son una gran combinación para la internacionalización

    La internacionalización es una parte importante de la experiencia del usuario, ya sea que admita varios idiomas o desee comprender correctamente las sutilezas de un solo idioma. Una biblioteca como next-intlpuede ayudar en ambos casos.

     

    Históricamente, la implementación de la internacionalización en las aplicaciones Next.js ha conllevado una compensación en el rendimiento, pero con los componentes del servidor, este ya no es el caso. Sin embargo, puede llevar algún tiempo explorar y aprender patrones que le ayudarán a mantener sus preocupaciones sobre la internacionalización en el lado del servidor.

    En nuestra aplicación de visualización de fotografías callejeras, solo necesitábamos mover un único componente al lado del cliente: OrderBySelect.

    ( Vista previa grande )

    Otro aspecto a tener en cuenta es que es posible que desee considerar implementar estados de carga, ya que la latencia de la red introduce un retraso antes de que sus usuarios vean el resultado de sus acciones.

    Los parámetros de búsqueda son una gran alternativa auseState

    Los parámetros de búsqueda son una excelente manera de implementar funciones interactivas en aplicaciones Next.js, ya que ayudan a reducir el tamaño del paquete del lado del cliente.

    Además del rendimiento, existen otros beneficios al utilizar parámetros de búsqueda :

    • Las URL con parámetros de búsqueda se pueden compartir preservando el estado de la aplicación.
    • Los marcadores también preservan el estado.
    • Opcionalmente, puede integrarse con el historial del navegador, lo que permite deshacer cambios de estado mediante el botón Atrás.

    Tenga en cuenta, sin embargo, que también hay compensaciones a considerar :

    • Los valores de los parámetros de búsqueda son cadenas, por lo que es posible que deba serializar y deserializar tipos de datos.
    • La URL es parte de la interfaz de usuario, por lo que el uso de muchos parámetros de búsqueda puede afectar la legibilidad.

    Puedes echar un vistazo al código completo del ejemplo en GitHub .

    ¡Muchas gracias a Delba de Oliveira de Vercel por brindar comentarios para este artículo!

    Lecturas adicionales sobre SmashingMag

    • “ Comprensión de la arquitectura del directorio de aplicaciones en Next.js ”, Atila Fassina
    • “ Diseño para usuarios de todas las culturas: una entrevista con Jenny Shen ”, Rachel Andrew
    • “ Obtención dinámica de datos en una aplicación Next.js autenticada ”, Caleb Olojo
    • “ Cómo implementar la funcionalidad de búsqueda en su aplicación Nuxt utilizando Algolia InstantSearch ”, Miracle Onyenma

    (yk, il)Explora más en

    • Siguiente.js
    • javascript
    • Codificación
    • Reaccionar





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Internacionalización en Next.js 13 con componentes de React Server

    Internacionalización en Next.js 13 con componentes de React Server

    Diseño de arquitectura de componentes de interfaz de usuario y tokens, con Nathan Curtis Accesibilidad para diseñadores, con Stéphanie Walter Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-internacionalizacion-en-next-1169-0.jpg

    2024-04-04

     

    Internacionalización en Next.js 13 con componentes de React Server
    Internacionalización en Next.js 13 con componentes de React Server

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20