Internationalisering ter Next.js 13 met React Server Components — Smashing Tv-programma


Met den proloog van Volgende.js 13 plusteken den bètaversie van den App Router, React Server Components worden publiekelijk vacant. Dit nieuwe paradigma maakt componenten mogelijk diegene den interactieve functies van React noch nodig hebben, zoals useState Plusteken useEffectwegens schattig aan den serverzijde te blijven.

Eentje streek dat profiteert van dit nieuwe potentie is internationalisering. Traditioneel vereist internationalisering eentje vergelijk ter prestaties, daar ie laden van vertalingen resulteert ter grotere client-side bundels plusteken ie gewoonte van berichtparsers van zeggenschap is op den runtime-prestaties van uw app op den client.

Den toezegging van Reageer servercomponenten is dat wij onze cake kunnen hebben plusteken diegene zowel kunnen opeten. Mits internationalisering volledig aan den serverzijde wordt geïmplementeerd, kunnen wij nieuwe prestatieniveaus doordringen voordat onze apps, waarbij den clientzijde wordt overgelaten aan interactieve functies. Maar hoe kunnen wij met dit paradigma werken indien wij interactief gecontroleerde staten nodig hebben diegene willen wordt weerspiegeld ter geïnternationaliseerde winkelen?

Te dit wetsartikel verkennen wij eentje meertalige app diegene straatfotografie-afbeeldingen van Unsplash weergeeft. Wij zullen tradities next-intl wegens ofschoon onze internationaliseringsbehoeften ter React Server Components te implementeren, plusteken wij zullen loeren zoals eentje techniek voordat ie proposities van interactiviteit met eentje minimalistische voetafdruk aan den clientzijde.

App definitief ingelijst
U kunt zowel den interactieve demonstratie. (Grote voorvertoning)

Plaatje’s verwijderen van Unsplash

Eentje important voordeel van Server Components is den potentie wegens gegevens rechtstreeks van inwonende componenten op te halen via async/await. Wij kunnen dit tradities wegens den plaatje’s van Unsplash op te halen ter onze paginacomponent.

Maar vantevoren willen wij onze API-client maken op voet van den officiële Unsplash SDK.

invoer {createApi} from 'unsplash-js';

uitvoer default createApi({
  accessKey: process.env.UNSPLASH_ACCESS_KEY
});

Zodra wij onze Unsplash API-client hebben, kunnen wij dit tradities ter onze paginacomponent.

invoer {OrderBy} from 'unsplash-js';
invoer UnsplashApiClient from './UnsplashApiClient';

uitvoer 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
    })
  ));

  terugwedstrijd (
    <PhotoViewer
      coverPhoto={topicRequest.response.cover_photo}
      photos={photosRequest.response.results}
    />
  );
}

Opmerking: Wij tradities Promise.all wegens beide verzoeken aan te roepen diegene wij parallel willen verrichten. Op dit wijze vermijding wij eentje vraagwaterval.

Op dit punt geven onze app eentje eenvoudig fotoraster weer.

Een app die een eenvoudig fotoraster weergeeft
(Grote voorvertoning)

Den app tweedehands nu hard-coded Engelse labels plusteken den datums van den plaatje’s wordt weergegeven indien tijdstempels, watten (nog) noch hevig gebruiksvriendelijk is.

Meer na den sprong! Lees hieronder voorts ↓

Internationalisering toevoegen met next-intl

Ongeacht Engels willen wij dat onze app zowel ter ie Spaans vacant is. Sponsoring voordat servercomponenten is nu ter bèta voordat next-intlzodat wij kunnen tradities de installatie-instructies voor de nieuwste bètaversie wegens onze app ter te uitlijnen voordat internationalisering.

Datums potverteren

Overgeschreven van ie toevoegen van eentje tweede taal, hebben wij ofschoon geconstateerd dat den app zichzelf noch terdege aanpast aan Engelse gebruikers omdat den datums willen wordt opgesteld. Voordat eentje goede gebruikerservaring willen wij den gebruiker zei hoe laat den plaatje is geüpload (bijv. “8 dagen geleden”).

Eenmalig next-intl is ingesteld, kunnen wij den opmaak corrigeren met behulp van den format.relativeTime functie ter ie onderdeel dat elke plaatje weergeeft.

invoer {useFormatter} from 'next-intl';

uitvoer default function PhotoGridItem({photo}) {
  const format = useFormatter();
  const updatedAt = new Date(photo.updated_at);

  terugwedstrijd (
    <a href={photo.linksaf.html}>
        {/* ... */}
        <p>{format.relativeTime(updatedAt)}</p>
      </div>
    </a>
  );
}

Nu is den datum waarop eentje plaatje is bijgewerkt gemakkelijker uit te oplezen.

De fototijd van een app met de opgemaakte datum
(Grote voorvertoning)

Tip: Te eentje traditionele React-app diegene zowel aan den server- indien aan den clientzijde wordt weergegeven, schenkkan ie eentje behoorlijke uitdaging zijn wegens ervoor te zorgen dat den weergegeven relatieve datum synchroon loopt tussen den server plusteken den client. Aldaar dit verschillende omgevingen zijn plusteken zichzelf mogelijk ter verschillende tijdzones bevinden, moeten u eentje mechanisme configureren wegens den servertijd zoals den clientzijde overheen te dragen. Voort den formattering schattig aan den serverzijde uit te voeren, paardenhoeven wij onzerzijds ter den eerste positie geen zorgen te maken overheen dit probleem.

Hoi! 👋 Onze app vertalen zoals ie Spaans

Vervolgens kunnen wij den statische labels ter den koptekst vervangen onderbrak gelokaliseerde berichten. Dit labels wordt doorgegeven indien rekwisieten van den PhotoViewer component, dus dit is onze mogelijkheid wegens dynamische labels te proposities via den useTranslations ophanghaak.

invoer {useTranslations} from 'next-intl';

uitvoer default function PhotoViewer(/* ... */) {
  const t = useTranslations('PhotoViewer');

  terugwedstrijd (
    <>
      <Header
        title={t('title')}
        description={t('description')}
      />
      {/* ... */}
    </>
  );
}

Voordat elk geïnternationaliseerd label dat wij toevoegen, willen wij ervoor zorgen dat er voordat alle talen eentje geschikte invoer is ingesteld.

// plusteken.json
{
  "PhotoViewer": {
    "title": "Street photography",
    "description": "Street photography captures real-life moments and human interactions ter 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": "Schuiflade fotografía callejera capta momentos den schuiflade vida real y interacciones humanas plusteken lugares públicos. Es una forma den contar historias visuales y congelar momentos fugaces del tiempo, convirtiendo lo ordinario plusteken lo extraordinario."
  }
}

Tip: next-intl biedt een TypeScript-integratie dat helpt u ervoor te zorgen dat u schattig verwijst zoals geldige berichtsleutels.

Zodra dit is gebeurd, kunnen wij den Spaanse versie van den app opzoeken op /es.

De Spaanse versie van de app
(Grote voorvertoning)

Totdat nu toe, zo terdege!

Interactiviteit toevoegen: dynamische volgorde van plaatje’s

Standaard retourneert den Unsplash API den uiterst populaire plaatje’s. Wij willen dat den gebruiker den volgorde schenkkan wijzigen wegens den uiterst recente plaatje’s vantevoren weer te geven.

Hier rijst den vraag of wij onze toevlucht willen nemen totdat ie verwijderen van gegevens aan den clientzijde, zodat wij dit functie kunnen implementeren met useState. Dat zullen echter vergen dat wij ofschoon onze componenten zoals den klantzijde verschuiven, watten resulteert ter eentje grotere bundelomvang.

Hebben wij eentje alternatief? Ja. Plusteken ie is eentje potentie diegene ofschoon eeuwen op internet bestaat: zoek parameters (somwijlen zowel welnu verwoord query-parameters). Watten zoekparameters totdat eentje geweldige optie maakt voordat onze use case, is dat zij aan den serverzijde kunnen wordt lezen.

Dus permitteren wij onze paginacomponent bijstellen wegens te ontvangen searchParams via rekwisieten.

uitvoer default async function Index({searchParams}) {
  const orderBy = searchParams.orderBy || OrderBy.POPULAR;

  const (/* ... */, photosRequest) = await Promise.all((
    /* ... */,
    UnsplashApiClient.topics.getPhotos({orderBy, /* ... */})
  ));

Na dit wijziging schenkkan den gebruiker navigeren zoals /?orderBy=latest wegens den volgorde van den weergegeven plaatje’s te wijzigen.

Wegens ie voordat den gebruiker gemakkelijk te maken wegens den waarde van den zoekparameter te wijzigen, willen wij eentje interactief select element vanuit eentje onderdeel.

De volgorde van de app selecteert met de meest populaire foto's weergegeven
(Grote voorvertoning)

Wij kunnen ie onderdeel markeren met 'use client'; wegens eentje ​​gebeurtenishandler toe te voegen plusteken wijzigingsgebeurtenissen te verwerkt vanuit ie select factor. Desalniettemin willen wij den zorgen overheen internationalisering aan den serverzijde liefhebben wegens den omvang van den klantenbundel te verminderen.

Toestaan wij ooit loeren zoals den vereiste opmaak voordat onze select factor.

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

Wij kunnen dit opmaak opsplitsen ter twee porties:

  1. Geef den select factor met eentje interactieve clientcomponent.
  2. Geef den geïnternationaliseerde option elementen met eentje servercomponent plusteken geef zij onderbrak indien children zoals den select factor.

Toestaan wij den select factor voordat den clientzijde.

'use client';

invoer {useRouter} from 'next-intl/client';

uitvoer 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);
  }

  terugwedstrijd (
    <select defaultValue={orderBy} onChange={onChange}>
      {children}
    </select>
  );
}

Toestaan wij nu onze component tradities PhotoViewer plusteken zorgen voordat den gelokaliseerde option elementen indien children.

invoer {useTranslations} from 'next-intl';
invoer OrderBySelect from './OrderBySelect';

uitvoer default function PhotoViewer({orderBy, /* ... */}) {
  const t = useTranslations('PhotoViewer');

  terugwedstrijd (
    <>
      {/* ... */}
      <OrderBySelect orderBy={orderBy}>
        <option value="popular">{t('orderBy.popular')}</option>
        <option value="latest">{t('orderBy.latest')}</option>
      </OrderBySelect>
    </>
  );
}

Met dit raderblad wordt den opmaak voordat den option elementen wordt nu aan den serverzijde gegenereerd plusteken doorgegeven aan den OrderBySelectdiegene den wijzigingsgebeurtenis aan den clientzijde afhandelt.

Tip: Aldaar wij willen wachten totdat den bijgewerkte opmaak aan den serverzijde wordt gegenereerd wanneer den volgorde wordt gewijzigd, willen wij den gebruiker misschien eentje laadstatus permitteren zien. Reageer 18 geïntroduceerd de useTransition haak, dat is geïntegreerd met Server Components. Hierdoor kunnen wij den select factor ter afwachting van eentje reactie van den server.

invoer {useRouter} from 'next-intl/client';
invoer {useTransition} from 'react';

uitvoer default function OrderBySelect({orderBy, children}) {
  const (isTransitioning, startTransition) = useTransition();
  const router = useRouter();

  function onChange(event) {
    startTransition(() => {
      router.replace('/?orderBy=' + event.target.value);
    });
  }

  terugwedstrijd (
    <select disabled={isTransitioning} /* ... */>
      {children}
    </select>
  );
}

Meer interactiviteit toevoegen: paginabediening

Idem raderblad dat wij hebben onderzoeken voordat ie wijzigen van den volgorde schenkkan wordt toegepast op paginabesturingselementen onderbrak eentje pagina zoekparameter.

Paginering van de app
(Grote voorvertoning)

Merknaam op dat talen verschillende regels hebben voordat ie omgaan met scheidingstekens voordat decimalen plusteken duizendtallen. Daarenboven weten talen verschillende vormen van meervoud: terwijl ie Engels bijvoorbeeld schattig eentje grammaticaal verschil maakt tussen één plusteken nul/veel elementen, heeft ie Kroatisch eentje aparte vorm voordat ‘weinig’ elementen.

next-intl tweedehands den ICU-syntaxis diegene ie mogelijk maakt wegens dit taalsubtiliteiten uit te verklikken.

// plusteken.json
{
  "Pagination": {
    "informatie": "Pagina {pagina, number} of {totalPages, number} ({totalElements, plural, =1 {one result} other {# results}} ter total)",
    // ...
  }
}

Dit keer paardenhoeven wij geen onderdeel te markeren met 'use client';. Te positie daarvan kunnen wij dit implementeren met gewone ankertags.

invoer {ArrowLeftIcon, ArrowRightIcon} from '@heroicons/react/24/solid';
invoer {Verbinding, useTranslations} from 'next-intl';

uitvoer default function Pagination({pageInfo, orderBy}) {
  const t = useTranslations('Pagination');
  const totalPages = Math.ceil(pageInfo.totalElements / pageInfo.size);

  function getHref(pagina) {
    terugwedstrijd {
      // Since wij're using `Verbinding` from next-intl, a potential locale
      // prefix of the pathname is automatically considered.
      pathname: '/',
      // Keep a potentially existing `orderBy` parameter. 
      query: {orderBy, pagina}
    };
  }

  terugwedstrijd (
    <>
      {pageInfo.pagina > 1 && (
        <Verbinding aria-label={t('prev')} href={getHref(pageInfo.pagina - 1)}>
          <ArrowLeftIcon />
        </Verbinding>
      )}
      <p>{t('informatie', {...pageInfo, totalPages})}</p>
      {pageInfo.pagina < totalPages && (
        <Verbinding aria-label={t('prev')} href={getHref(pageInfo.pagina + 1)}>
          <ArrowRightIcon />
        </Verbinding>
      )}
    </>
  );
}

Slotbeschouwing

Servercomponenten zijn eentje geweldige match voordat internationalisering

Internationalisering is eentje important onderdeel van den gebruikerservaring, of u nu meerdere talen ondersteunt of den subtiliteiten van één taal terdege wilt toepassen. Eentje bibliotheek indien next-intl schenkkan ter beide gevallen promoten.

Ie implementeren van internationalisering ter Next.js-apps is van oudsher gepaard getogen met eentje prestatieafweging, maar met Server Components is dit noch langer ie geval. Ie schenkkan echter enige tijdstip duren wegens patronen te ontdekken plusteken te leren diegene u zullen promoten uw zorgen overheen internationalisering aan den serverzijde te liefhebben.

Te onze viewer-app voordat straatfotografie hoefden wij slechts één onderdeel zoals den klantzijde te verschuiven: OrderBySelect.

Componenten van de app
(Grote voorvertoning)

Eentje ander facet wegens op te merken is dat u zullen kunnen overwegen wegens laadstatussen te implementeren, daar den netwerklatentie eentje vertraging veroorzaakt voordat uw gebruikers ie resultaat van hun acties zien.

Zoekparameters zijn eentje omvangrijk alternatief voordat useState

Zoekparameters zijn eentje geweldige wijze wegens interactieve functies ter Next.js-apps te implementeren, omdat zij promoten wegens den bundelgrootte van den clientzijde te verminderen.

Ongeacht prestaties zijn er nog andere voordelen van ie gewoonte van zoekparameters:

  • URL’s met zoekparameters kunnen wordt verdeeld met behoud van den applicatiestatus.
  • Bladwijzers beschermen zowel den staat.
  • U kunt optioneel samenvoegen met den browsergeschiedenis, waardoor statuswijzigingen ongedaan kunnen wordt geproduceerd via den terugknop.

Merknaam echter op dat er zowel zijn afwegingen te overwegen:

  • Zoekparameterwaarden zijn tekenreeksen, dus mogelijk moeten u gegevenstypen serialiseren plusteken deserialiseren.
  • Den URL maakt portie uit van den gebruikersinterface, dus ie gewoonte van veel zoekparameters schenkkan den leesbaarheid beïnvloeden.

U kunt ie geheel bekijken code van het voorbeeld op GitHub.

Veel harmonie aan Delba de Oliveira van Vercel voordat ie geven van terugkoppeling voordat dit wetsartikel!

Voorts oplezen overheen SmashingMag

Schitterende redactie
(yk, il)