--- title: Setup multilingual and multi-regional storefronts with domains and subdomains description: Learn how to setup multi-region and multilingual storefront using different domains and subdomains to get the right language and currency. source_url: html: https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains md: https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains.md --- ExpandOn this page * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#requirements) * [Step 1: Create a utility that reads requested host](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-1-create-a-utility-that-reads-requested-host) * [Step 2: Add i18n to the storefront client](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-2-add-i18n-to-the-storefront-client) * [Step 3: Add @in​Context directive to your Graph​QL queries](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-3-add-incontext-directive-to-your-graphql-queries) * [Step 4: Make sure redirects are properly url encoded](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-4-make-sure-redirects-are-properly-url-encoded) * [Next steps](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#next-steps) # Setup multilingual and multi-regional storefronts with domains and subdomains In this guide you will learn how to setup your Hydrogen project for supporting multiregion and multilingual storefronts by using domains and subdomains. For example, say you have a storefront that should work in English (EN) and in non-regional French (FR) for different customers. Set up the project to handle requests as follows: | Language | URL path | | - | - | | English | `ca.hydrogen.shop` | | French | `hydrogen.fr` | *** ## Requirements * You have a working Hydrogen project. [See getting started guide](https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started). * You have setup the regions and languages you chose for your store with [Shopify Markets](https://help.shopify.com/en/manual/markets). * You're familiar with [using the Storefront API with Shopify Markets](https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/markets). *** ## Step 1: Create a utility that reads requested host Create a utility function that reads the requested host and return the right `Locale` object using the Storefronts API's supported [language](https://shopify.dev/docs/api/storefront/latest/enums/LanguageCode) and [country](https://shopify.dev/docs/api/storefront/latest/enums/CountryCode) codes. Tip You can use the `/app/lib/utils.js` in the Hydrogen demo store as a point of reference. The following is an example utility function with the following locales `en_CA`, `fr_CA` and `en_US`. ## utils ## /app/lib/utils.js ```js export function getLocaleFromRequest(request) { // Get the user request URL const url = new URL(request.url); // Match the URL host switch (url.host) { case 'ca.hydrogen.shop': return { language: 'EN', country: 'CA', }; break; case 'hydrogen.fr': return { language: 'FR', country: 'CA', }; break; default: return { language: 'EN', country: 'US', }; } } ``` ```ts export function getLocaleFromRequest(request: Request): Locale { // Get the user request URL const url = new URL(request.url); // Match the URL host switch (url.host) { case 'ca.hydrogen.shop': return { language: 'EN', country: 'CA', }; break; case 'hydrogen.fr': return { language: 'FR', country: 'CA', }; break; default: return { language: 'EN', country: 'US', }; } } ``` The `Locale` object that returned should resemble the following example, which is using the Storefont API's supported [language](https://shopify.dev/docs/api/storefront/latest/enums/LanguageCode) and [country](https://shopify.dev/docs/api/storefront/latest/enums/CountryCode) codes. ## TypeScript ```ts import { CountryCode, LanguageCode, } from '@shopify/storefront-kit-react/storefront-api-types'; export type Locale = { language: LanguageCode; country: CountryCode; }; ``` *** ## Step 2: Add i18n to the storefront client In your `server.js`, update `i18n` to the result of the utility function that you used when creating the Hydrogen storefront client. By doing this, you now have the locale available throughout the app for every storefront query. ## server ## /server.js ```js const {storefront} = createStorefrontClient({ // ... i18n: getLocaleFromRequest(request), // ... }); ``` ```ts const {storefront} = createStorefrontClient({ // ... i18n: getLocaleFromRequest(request), // ... }); ``` *** ## Step 3: Add @in​Context directive to your Graph​QL queries To [support international pricing and languages in Storefront API](https://shopify.dev/custom-storefronts/building-with-the-storefront-api/markets/international-pricing), you need to pass the `$country` and `$language` with an `@inContext` directive within any requests. Update your GraphQL queries with `inContext` directives to include `$country` and `$language`. Hydrogen automatically injects these parameters. For example: ## GraphQL queries ## Before ```jsx const FEATURED_QUERY = `#graphql query homepage { collections(first: 3, sortKey: UPDATED_AT) { nodes { id title handle image { altText width height url } } } } `; ``` ## After ```jsx const FEATURED_QUERY = `#graphql query homepage($country: CountryCode, $language: LanguageCode) @inContext(country: $country, language: $language) { collections(first: 3, sortKey: UPDATED_AT) { nodes { id title handle image { altText width height url } } } } `; ``` You don't need to manually provide query variables for `country` and `language`. You can make these queries with `storefront.query` in the data loader and you should see the right language and currencies for each request. ```js export async function loader({ context: {storefront}, }) { return json({ featureCollections: await storefront.query<{ collections; }>(FEATURED_COLLECTIONS_QUERY), }); } ``` ```ts export async function loader({ context: {storefront}, }: LoaderArgs) { return json({ featureCollections: await storefront.query<{ collections: CollectionConnection; }>(FEATURED_COLLECTIONS_QUERY), }); } ``` Hydrogen injects the locale parameters automatically to `storefront.query` based on what was defined in `i18n` when creating the client. For example, if a request came from `hydrogen.fr`, then the country `CA` and language `FR` are used as defined in the example utilities function above. The Storefront API returns the correct currency and language if the store was set up in the Shopify admin. Note if you want to override the locale determined by your utility option, you can supply the query variables to the `storefront.query`: ```js export async function loader({ context: {storefront}, }) { return json({ featureCollection: await storefront.query(FEATURED_COLLECTIONS_QUERY, { variables: { country: 'CA', // Always query back in CA currency language: 'FR', // Always query back in FR language } }), }); } ``` ```ts export async function loader({ context: {storefront}, }: LoaderArgs) { return json({ featureCollection: await storefront.query<{ collections: CollectionConnection; }>(FEATURED_COLLECTIONS_QUERY, { variables: { country: 'CA', // Always query back in CA currency language: 'FR', // Always query back in FR language } }), }); } ``` *** ## Step 4: Make sure redirects are properly url encoded If you have multilingual handles for your product or collection, for example, `products/スノーボード`, make sure to encode url when making redirects. ## Link ## /app/routes/($locale).products.$productHandle.js ```js export async function loader({params, request, context}) { const {productHandle} = params; // productHandle = 'スノーボード' ... if (noSelectedProductVariant) { // Use URL to prevent accidental double url encoding const newUrl = new URL( `/products/${productHandle}?${firstVariantSearchParams.toString()}`, 'http://example.com' // Any domain to satisfy the URL api ); // Redirect to '/products/%E3%82%B9%E3%83%8E%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89?Size=154cm&Color=Syntax' throw redirect(newUrl.pathname + newUrl.search, 302); } ... ``` ```ts export async function loader({params, request, context}: LoaderArgs) { const {productHandle} = params; // productHandle = 'スノーボード' ... if (noSelectedProductVariant) { // Use URL to prevent accidental double url encoding const newUrl = new URL( `/products/${productHandle}?${firstVariantSearchParams.toString()}`, 'http://example.com' // Any domain to satisfy the URL api ); // Redirect to '/products/%E3%82%B9%E3%83%8E%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89?Size=154cm&Color=Syntax' throw redirect(newUrl.pathname + newUrl.search, 302); } ... ``` *** ## Next steps * [Create a country selector](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/country-selector): Learn how to setup a country selector to allow users to choose their own country. *** * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#requirements) * [Step 1: Create a utility that reads requested host](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-1-create-a-utility-that-reads-requested-host) * [Step 2: Add i18n to the storefront client](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-2-add-i18n-to-the-storefront-client) * [Step 3: Add @in​Context directive to your Graph​QL queries](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-3-add-incontext-directive-to-your-graphql-queries) * [Step 4: Make sure redirects are properly url encoded](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#step-4-make-sure-redirects-are-properly-url-encoded) * [Next steps](https://shopify.dev/docs/storefronts/headless/hydrogen/markets/multiple-languages-domains#next-steps)