# General Translation Integrations: Localizzare Shopify Hydrogen con React Router
URL: https://generaltranslation.com/it/docs/integrations/shopify/guides/localizing-react-router.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Come aggiungere gt-react a uno storefront Hydrogen basato su React Router e mantenere allineato il contesto linguistico di Shopify.

In uno storefront React Router, `gt-react` traduce i testi presenti nel codice, mentre Hydrogen comunica con Shopify. L&#39;unico intervento specifico per Shopify consiste nel fornire al contesto della richiesta di Hydrogen la stessa impostazione regionale della pagina.

*Nota: questa guida fa riferimento a `@shopify/hydrogen` 2026.10 su React Router 8, oppure su React Router 7 con `future.v8_middleware: true` in `react-router.config.ts`.*

<Callout type="info">
  **Novità di Hydrogen 2026.10:** `createHydrogenContext` e il template specifico per React Router sono stati sostituiti da `createShopifyRequestContext`, indipendente dal framework. Accetta la stessa lingua e lo stesso paese di `i18n`, oltre a un `pathPrefix` facoltativo. Per l&#39;aggiornamento, è disponibile la skill `migrate-to-hydrogen-2026-10` inclusa in Hydrogen.
</Callout>

## Prima di iniziare [#before-start]

* Configura Hydrogen nella tua app React Router con `npx @shopify/hydrogen setup`. Il middleware radice crea il contesto della richiesta Shopify e il client Storefront ed esegue `handleShopifyRoutes`.
* Completa l&#39;[Avvio rapido di React Router](/docs/react/react-router-quickstart). Il loader radice restituisce un&#39;impostazione regionale e uno snapshot delle traduzioni, mentre il `Layout` root renderizza [`GTProvider`](/docs/react/reference/components/gt-provider) e `<html lang>`. Questa guida sostituisce il [`<LocaleSelector>`](/docs/react/reference/components/locale-selector) dell&#39;Avvio rapido con un selettore della lingua che modifica l&#39;URL.

## Risolvere l&#39;impostazione regionale dall&#39;URL [#request-locale]

Leggi l&#39;impostazione regionale dal percorso della richiesta, così che ogni impostazione regionale abbia un URL dedicato. Usa un unico modulo sia per `gt-react` sia per Hydrogen:

```ts title="app/lib/i18n.ts"
import gtConfig from '../../gt.config.json';

// "/fr/products/x" -> "fr"; i percorsi senza prefisso usano l'impostazione locale predefinita.
export function getRequestLocale(request: Request): string {
  const [, segment] = new URL(request.url).pathname.split('/');
  return gtConfig.locales.includes(segment) ? segment : gtConfig.defaultLocale;
}

// "/products/x" -> "/fr/products/x"; l'impostazione locale predefinita mantiene il percorso senza prefisso.
export function localizePath(pathname: string, locale: string): string {
  if (locale === gtConfig.defaultLocale) return pathname;
  return pathname === '/' ? `/${locale}` : `/${locale}${pathname}`;
}

// "/fr/products/x" -> "/products/x"; i percorsi senza prefisso vengono restituiti invariati.
export function stripLocale(pathname: string): string {
  const [, segment, ...rest] = pathname.split('/');
  return gtConfig.locales.includes(segment) ? `/${rest.join('/')}` : pathname;
}
```

Nel loader radice, chiama `getRequestLocale(request)` al posto di `parseLocale(request)` e passa il risultato a [`getTranslationsSnapshot`](/docs/react/reference/functions/get-translations-snapshot).

*Nota: `parseLocale` legge prima il cookie dell&#39;impostazione regionale, poi `Accept-Language`. Se usato da solo, serve tutte le lingue da un unico URL, quindi i motori di ricerca ne indicizzano solo una.*

Per servire percorsi con prefisso, annida le pagine sotto una route di layout facoltativa `:locale?`. Lascia per ultima la route catch-all di Hydrogen, così i percorsi senza corrispondenza raggiungono comunque i suoi reindirizzamenti:

```ts title="app/routes.ts"
import {type RouteConfig, index, route} from '@react-router/dev/routes';

export default [
  // Le pagine vengono renderizzate senza prefisso o con il prefisso dell'impostazione regionale di destinazione, ad esempio /fr.
  route(':locale?', 'routes/locale.tsx', [
    index('routes/home.tsx'),
    route('products/:handle', 'routes/product.tsx'),
  ]),
  route('*', 'routes/catchall.tsx'),
] satisfies RouteConfig;
```

Nella route di layout, rispondi con un 404 quando il segmento non corrisponde a un&#39;impostazione regionale di destinazione configurata, così che `/en/...` e i prefissi sconosciuti non renderizzino una seconda copia della pagina:

```tsx title="app/routes/locale.tsx"
import {Outlet} from 'react-router';
import gtConfig from '../../gt.config.json';

// Solo le impostazioni locali di destinazione sono prefissi validi; l'impostazione locale predefinita non ha prefisso.
export async function loader({params}: {params: {locale?: string}}) {
  if (params.locale && !gtConfig.locales.includes(params.locale)) {
    throw new Response(null, {status: 404});
  }
  return null;
}

export default function LocaleLayout() {
  return <Outlet />;
}
```

Con le route basate su file, assegna invece al layout il nome `($locale).tsx` e annida al suo interno i file delle pagine.

I gestori nativi di Hydrogen, come `/api/cart`, `/api/predictive-search`, `/checkout` e le route di Customer Account, rispondono nel middleware radice prima che venga renderizzata qualsiasi pagina, quindi restano senza prefisso.

### Mantenere i gestori di Hydrogen nella lingua della pagina [#handler-locale]

Le richieste a `/api/cart` e `/api/predictive-search` non hanno un prefisso del locale, quindi `getRequestLocale` le risolve nell&#39;impostazione locale predefinita. Di conseguenza, su una pagina in francese il carrello e i risultati di ricerca mostrerebbero il testo del catalogo in inglese.

Memorizza l&#39;impostazione regionale della pagina in un cookie e leggila solo per le richieste `/api` prive di prefisso. Per le pagine, l&#39;URL resta l&#39;unica fonte dell&#39;impostazione regionale. Sostituisci `getRequestLocale` in `app/lib/i18n.ts`:

```ts title="app/lib/i18n.ts"
export const LOCALE_COOKIE_NAME = 'shop_locale';

const allLocales = [gtConfig.defaultLocale, ...gtConfig.locales];

export function readCookie(request: Request, name: string): string | undefined {
  const cookie = request.headers.get('Cookie')?.split(/;\s*/).find((part) => part.startsWith(`${name}=`));
  return cookie?.slice(name.length + 1);
}

/** Le pagine usano il proprio prefisso URL; i gestori `/api` di Hydrogen usano l'impostazione regionale della pagina che li ha chiamati. */
export function getRequestLocale(request: Request): string {
  const {pathname} = new URL(request.url);
  const [, segment] = pathname.split('/');
  if (gtConfig.locales.includes(segment)) return segment;
  if (!pathname.startsWith('/api/')) return gtConfig.defaultLocale;
  const remembered = readCookie(request, LOCALE_COOKIE_NAME);
  // Solo un'impostazione regionale configurata è considerata attendibile; per qualsiasi altro valore si ricorre a quella predefinita.
  return remembered && allLocales.includes(remembered) ? remembered : gtConfig.defaultLocale;
}

/** Caricamenti di pagina e navigazioni lato client, ma non le chiamate `/api` né i prefetch speculativi. */
export function isPageNavigation(request: Request): boolean {
  const purpose = `${request.headers.get('Purpose') ?? ''} ${request.headers.get('Sec-Purpose') ?? ''}`;
  return (
    request.method === 'GET' &&
    !new URL(request.url).pathname.startsWith('/api/') &&
    !purpose.includes('prefetch')
  );
}
```

Il middleware radice descritto nella sezione successiva imposta il cookie quando l&#39;impostazione regionale di una navigazione di pagina è diversa da quella memorizzata. I prefetch non lo impostano, quindi un link precaricato verso un&#39;altra lingua non può cambiare la lingua del carrello prima che l&#39;acquirente lo apra.

## Passare la lingua a Shopify [#storefront-language]

Associa ogni impostazione regionale al corrispondente `LanguageCode` di Shopify e passalo a `createShopifyRequestContext` nel middleware radice. Il client Storefront popolerà così `$language` e `$country` in ogni query che dichiara `@inContext(country: $country, language: $language)`.

```ts title="app/root.tsx"
import {
  createShopifyRequestContext,
  createStorefrontClient,
  handleShopifyRedirects,
  handleShopifyRoutes,
} from '@shopify/hydrogen';
import gtConfig from '../gt.config.json';
import {getRequestLocale, isPageNavigation, LOCALE_COOKIE_NAME, readCookie} from '~/lib/i18n';
import type {Route} from './+types/root';

// Una voce per ogni impostazione regionale in gt.config.json.
const SHOPIFY_LANGUAGES = {en: 'EN', fr: 'FR', ja: 'JA'} as const;

export const middleware: Route.MiddlewareFunction[] = [
  async ({context, request}, next) => {
    const locale = getRequestLocale(request) as keyof typeof SHOPIFY_LANGUAGES;
    const requestContext = createShopifyRequestContext({
      request,
      // La lingua segue la pagina; il paese resta quello del mercato in cui vendi.
      // pathPrefix mantiene negli URL dell'impostazione regionale i reindirizzamenti di Hydrogen per le varianti e le route standard.
      i18n: {
        language: SHOPIFY_LANGUAGES[locale],
        country: 'US',
        pathPrefix: locale === gtConfig.defaultLocale ? '' : `/${locale}`,
      },
    });
    const storefrontClient = createStorefrontClient({type: 'public', requestContext, config});

    const shopifyRoute = handleShopifyRoutes({request, requestContext, storefrontClient, routeTemplates, handlers});
    if (shopifyRoute) return shopifyRoute;

    context.set(storefrontClientContext, storefrontClient);

    const response = await next();
    if (response.status === 404) {
      const redirect = await handleShopifyRedirects({request, routeTemplates, storefrontClient});
      if (redirect) return redirect;
    }
    // Memorizza l'impostazione regionale della pagina per i gestori `/api` di Hydrogen. Imposta il cookie prima di
    // applyResponseHeaders, che rende privata e non memorizzabile in cache qualsiasi risposta che imposta un cookie.
    if (isPageNavigation(request) && readCookie(request, LOCALE_COOKIE_NAME) !== locale) {
      response.headers.append('Set-Cookie', `${LOCALE_COOKIE_NAME}=${locale}; Path=/; SameSite=Lax`);
    }
    storefrontClient.requestContext.applyResponseHeaders(response.headers);
    return response;
  },
];
```

`config`, `routeTemplates`, `handlers` e `storefrontClientContext` provengono dalla configurazione Hydrogen esistente; le uniche novità sono `i18n` e il cookie dell&#39;impostazione regionale. Una risposta di pagina che imposta il cookie non viene memorizzata nella cache, quindi questo accade solo alla prima pagina visualizzata da un cliente e quando cambia lingua.

Questa guida mantiene il mercato statunitense per tutte le lingue, quindi passando al francese cambiano i testi, ma non il paese dell&#39;acquirente né la valuta del carrello. Se vendi in più mercati, consenti ai clienti di selezionare il proprio paese separatamente, oppure associa ogni impostazione regionale a un mercato e sposta il carrello quando cambia la lingua. (Vedi [Vendere in più mercati](/docs/integrations/shopify/guides/selling-in-markets)).

## Formattare i prezzi [#prices]

Formatta l&#39;importo di Shopify usando il codice valuta restituito da Shopify. [`<Currency>`](/docs/react/reference/components/currency) formatta l&#39;importo in base al locale attivo, senza mai convertirlo.

```tsx title="app/components/LocalizedMoney.tsx"
import {Currency} from 'gt-react';

/** Formatta il prezzo di Shopify secondo il locale attivo, senza convertire la valuta. */
export function LocalizedMoney({data}: {data: {amount?: string; currencyCode?: string}}) {
  // Le risposte ottimistiche del carrello possono temporaneamente non includere i campi relativi al costo.
  if (data.amount == null || !data.currencyCode) return null;
  return <Currency currency={data.currencyCode}>{data.amount}</Currency>;
}
```

## Link nella stessa impostazione regionale [#links]

Nel codice, mantieni i percorsi delle route senza prefisso e aggiungi il prefisso dell&#39;impostazione regionale corrente quando renderizzi un link. Leggi il locale attivo con [`useLocale`](/docs/react/reference/hooks/use-locale) e passa `localizePath(to, locale)` al `Link` di React Router.

Per cambiare lingua, modifica il prefisso dell&#39;URL corrente. Il loader radice legge così la nuova impostazione regionale, mentre il carrello resta invariato. In questo caso non usare [`<LocaleSelector>`](/docs/react/reference/components/locale-selector): salva l&#39;impostazione regionale in un cookie e ricarica lo stesso URL, che si risolve ancora nella vecchia impostazione regionale.

```tsx title="app/components/LanguageSwitcher.tsx"
import {useLocale, useLocales} from 'gt-react';
import {useLocation, useNavigate} from 'react-router';
import {localizePath, stripLocale} from '~/lib/i18n';

/** Cambia lingua modificando il prefisso dell'URL; il loader radice legge la nuova impostazione regionale dall'URL. */
export function LanguageSwitcher() {
  const locale = useLocale();
  const locales = useLocales();
  const {pathname, search} = useLocation();
  const navigate = useNavigate();
  return (
    <select
      aria-label="Language"
      value={locale}
      onChange={(event) => navigate(localizePath(stripLocale(pathname), event.target.value) + search)}
    >
      {locales.map((option) => (
        // Mostra il nome di ogni lingua nella lingua stessa, ad esempio «français» o «日本語».
        <option key={option} value={option} lang={option}>
          {new Intl.DisplayNames([option], {type: 'language'}).of(option)}
        </option>
      ))}
    </select>
  );
}
```

Per i link alle route di Customer Account, come `/account/login`, usa un semplice `<a>` o `<form>`, non `Link`. I relativi gestori eseguono un reindirizzamento a Shopify, che la navigazione lato client non è in grado di seguire.

## Genera traduzioni [#generate]

Racchiudi i testi in [`<T>`](/docs/react/reference/components/t), usa [`useGT`](/docs/react/reference/hooks/use-gt) per stringhe come i valori di `aria-label` ed esegui [`npx gt translate`](/docs/cli/reference/commands/translate) prima di `react-router build`. Le traduzioni incluse nel bundle dal tuo loader sono disponibili già al primo render lato server, quindi anche le risposte in cache le contengono.

Per far sì che i testi restino racchiusi e tradotti man mano che lo storefront evolve, collega il repository a [Locadex](/docs/platform/locadex/quickstart): aprirà pull request con le nuove traduzioni da sottoporre a revisione.

## Next steps

- /docs/integrations/shopify/guides/localizing-nextjs
- /docs/integrations/shopify/guides/translating-products
- /docs/integrations/shopify/guides/selling-in-markets

## Sitemap

See the full [sitemap](https://generaltranslation.com/sitemap.md) for all pages.
