Skip to content

Latest commit

 

History

History
256 lines (195 loc) · 9.65 KB

localization.md

File metadata and controls

256 lines (195 loc) · 9.65 KB

Localization

“Localization” refers to the practice of customizing your app to support users speaking different languages, or in different places around the world. Localization is important because it gives more people access to your application.

Translation

TODO

Setting the locale

To localize your application, you need to tell Quilt what locale your application is using. This value will be used to determine the right translations to load, how to format values, and as the lang attribute on the HTML document.

The simplest way to set the locale is to provide a hardcoded value to Quilt’s Localization component. Like the HTML lang attribute, the locale prop should be a language tag in the format defined in RFC 5646, like en for english, or fr-CA for french as spoken in Canada.

import {Localization} from '@quilted/quilt';

export function App() {
  return (
    <Localization locale="fr-CA">
      <RestOfApp />
    </Localization>
  );
}

The browser sends a special header, Accept-Language, that lets the server know what locale the user prefers. When using Quilt with server rendering, you can omit the locale prop from the Localization component, and Quilt will automatically use the locale from the Accept-Language header on the server, and its equivalent in the browser.

import {Localization} from '@quilted/quilt';

export function App() {
  return (
    <Localization>
      <RestOfApp />
    </Localization>
  );
}

You can use the useLocale hook to access the current locale elsewhere in your React application:

import {Localization, useLocale} from '@quilted/quilt';

export function App() {
  return (
    <Localization locale="fr-CA">
      <RestOfApp />
    </Localization>
  );
}

function RestOfApp() {
  // `locale` will be `'fr-CA'` in this case.
  const locale = useLocale();
  return <p>It looks like your locale is: {locale}</p>;
}

Localized routing

One strategy that is commonly used on the web is to provide different locales at different URLs. Quilt also provides a full routing library, and gives you some handy utilities for common versions of this technique.

Path-based localized routing

In path-based localization, the first part of the URL’s path is used to determine the locale of the application. For example, /en/contact and /fr-ca/contact would both be the same contact page, but in en and fr-CA locales, respectively.

To implement localized routing, you’ll use the LocalizedRouter component provided by Quilt. You will pass this component the information it needs to localize your app using the createRoutePathLocalization helper function, which takes in the information about what locales are supported in your app.

import {
  useLocale,
  useRoutes,
  Localization,
  createRoutePathLocalization,
} from '@quilted/quilt';

const routeLocalization = createRoutePathLocalization({
  default: 'en',
  locales: ['en', 'fr', 'fr-CA'],
});

export function App() {
  return (
    <LocalizedRouter localization={routeLocalization}>
      <Routes />
    </LocalizedRouter>
  );
}

function Routes() {
  const locale = useLocale();

  return useRoutes([
    {match: '/', render: () => <div>{/* home page */}</div>},
    {
      match: 'contact',
      render: () => <div>{/* contact page */}</div>,
    },
  ]);
}

Note: If you already have a Router component rendered in your application, make sure you replace it with this LocalizedRouter component — you don’t need both. You also don’t need to manually render the Localization component when using LocalizedRouter.

In the example above, /en and /en/contact would be rendered with an english locale, while /fr, /fr/contact, /fr-ca, and /fr-ca/contact would be rendered using french and french Canadian locales.

By default, the default locale is also included in the path, as shown above with the /en and /en/contact pages. If you would prefer to have the root locale be at the “root” of your app, you can pass the {nested: false} option alongside the default locale:

import {
  useLocale,
  useRoutes,
  Localization,
  createRoutePathLocalization,
} from '@quilted/quilt';

const routeLocalization = createRoutePathLocalization({
  default: {locale: 'en', nested: false},
  locales: ['en', 'fr', 'fr-CA'],
});

export function App() {
  return (
    <LocalizedRouter localization={routeLocalization}>
      <Routes />
    </LocalizedRouter>
  );
}

In the example above, the english pages would now be available at / and /contact.

When using LocalizedRouter, the locale of your application will be set to the same value as the initial request’s locale (determined by the useBrowserDetails().locale value), as long as that locale is at least in the same language as the resolved route-based locale. In the examples above, if a user visited the app with an en-CA locale, that locale would be preserved, even though the route only matches the en language.

Subdomain-based localized routing

In subdomain-based localization, the part of the URL is used to determine the locale of the application. For example, en.my-app.com and fr-ca.my-app.com would both be the same contact page, but in en and fr-CA locales, respectively.

To implement localized routing, you’ll use the LocalizedRouter component provided by Quilt. You will pass this component the information it needs to localize your app using the createRouteSubdomainLocalization helper function, which takes in the information about what locales are supported in your app.

import {
  useLocale,
  useRoutes,
  Localization,
  createRoutePathLocalization,
} from '@quilted/quilt';

const routeLocalization = createRoutePathLocalization({
  base: 'app.com',
  default: 'en',
  locales: ['en', 'fr'],
});

export function App() {
  return (
    <LocalizedRouter localization={routeLocalization}>
      <Routes />
    </LocalizedRouter>
  );
}

function Routes() {
  const locale = useLocale();

  return useRoutes([
    {match: '/', render: () => <div>{/* home page */}</div>},
    {
      match: 'contact',
      render: () => <div>{/* contact page */}</div>,
    },
  ]);
}

Note: If you already have a Router component rendered in your application, make sure you replace it with this LocalizedRouter component — you don’t need both. You also don’t need to manually render the Localization component when using LocalizedRouter.

In the example above, en.app.com and en.app.com/contact would be rendered with an english locale, while fr.app.com and fr.app.com/contact would be rendered using a french locale.

By default, the default locale is also included in the subdomain, as shown above with the en.app.com subdomain. If you would prefer to have the root locale be at the “root” of your app, you can pass the {nested: false} option alongside the default locale:

import {
  useLocale,
  useRoutes,
  Localization,
  createRoutePathLocalization,
} from '@quilted/quilt';

const routeLocalization = createRoutePathLocalization({
  base: 'app.com',
  default: {locale: 'en', nested: false},
  locales: ['en', 'fr', 'fr-CA'],
});

export function App() {
  return (
    <LocalizedRouter localization={routeLocalization}>
      <Routes />
    </LocalizedRouter>
  );
}

In the example above, the english pages would now be available at app.com.

When using LocalizedRouter, the locale of your application will be set to the same value as the initial request’s locale (determined by the useBrowserDetails().locale value), as long as that locale is at least in the same language as the resolved route-based locale. In the examples above, if a user visited the app with an en-CA locale, that locale would be preserved, even though the route only matches the en language.

Locale-based redirecting

TODO

Localized formatting

Quilt provides a useLocalizedFormatting hook that gives you access to functions capable of localizing values according to the app’s locale. This hook provides access to three functions, each useful for formatting a different kind of value for the user:

  • formatNumber() formats a number. You can pass this function any option you can pass to Intl.NumberFormat, which is used under the hood.
  • formatCurrency() formats a number as a currency value. You can also pass this function any option you can pass to Intl.NumberFormat.
  • formatDate() formats a Date object. You can pass this function any option you can pass to Intl.DateTimeFormat, which is used under the hood.
import {Localization, useLocalizedFormatting} from '@quilted/quilt';

export function App() {
  return (
    <Localization locale="en-CA">
      <RestOfApp />
    </Localization>
  );
}

const purchase = {
  date: new Date(),
  quantity: 2,
  cost: 30,
};

function RestOfApp() {
  const {formatNumber, formatCurrency, formatDate} = useLocalizedFormatting();

  return (
    <dl>
      <dt>Purchased on</dt>
      <dd>{formatDate(purchase.date, {dateStyle: 'short'})}</dd>

      <dt>Quantity</dt>
      <dd>{formatNumber(purchase.quantity)}</dd>

      <dt>Cost</dt>
      <dd>{formatCurrency(purchase.cost, {currency: 'CAD'})}</dd>
    </dl>
  );
}