Translate your React app using Format.js
Tags: react, webdev
Published: 2023-04-12 13:50:03

**Written by [Emmanuel Odioko](https://blog.logrocket.com/author/emmanuelodioko/)✏️**

Making sure your [React app](https://blog.logrocket.com/tag/react/) is available in several languages is one of the most significant ways to ensure people worldwide can access it in today's globally integrated society. Localization is helpful in this situation. Format.js, an open source toolkit, offers a selection of tools for localizing your React application. 

Format.js enables you to translate the [UI elements](https://blog.logrocket.com/top-10-react-ui-libraries-kits/), messages, and dates in your app — making it easier for users outside of your country to use it. This tutorial will show you how to translate your React application using Format.js. 

To follow along with this article, you'll need a [basic knowledge of React](https://blog.logrocket.com/top-react-boilerplates-2023/), a terminal, and a code editor (I recommend [VS Code](https://blog.logrocket.com/learn-these-keyboard-shortcuts-to-become-a-vs-code-ninja/)). Let's get started! 

_Jump ahead:_

*   [Getting started with React](#getting-started-with-react)
    *   [Building the `ProductCard` and `Cart` components](#building-product-card-cart-components)
*   [Creating functions to add to our React app](#creating-functions-add-react-app)
*   [Setting up Format.js in React](#setting-up-format-js-react)
    *   [Adding the `IntlProvider`](#adding-intl-provider)
    *   [Using the `FormattedMessage` component](#using-formatted-message-component)
*   [Translating the `Cart` and `ProductItem` components](#translating-cart-product-item-components)
    *   [Translate the `Cart`](#translate-cart)
    *   [Translate the `ProductItem`](#translate-product-item)
*   [Switching between languages](#switching-between-languages)
    *   [Create locale JSON files](#create-locale-json-files)
    *   [Dynamically import locale messages](#dynamically-import-locale-messages)

## Getting started with React <a name="getting-started-with-react">

First, we use [Create React App](https://blog.logrocket.com/tag/create-react-app/) to create a React application:

```bash
npx create-react-app translate-app 
```

Then, we can navigate to the newly created project after the installation with the `cd translate-app/` command. Let's quickly set up a very simple [ecommerce application](https://blog.logrocket.com/implementing-scroll-restoration-in-ecommerce-react-apps/) where we have a bunch of products displayed in cards. Our simple app will also have a cart component that shows products we've added to our cart and allows us to remove those products.

### Building the `ProductCard` and `Cart` components <a name="building-product-card-cart-components">

Now, create a new `./src/components/ProductItem.jsx` file and enter the following code:

```javascript
// ./src/components/ProductItem.jsx
const ProductItem = ({ product, addToCart }) => {
  return (
    <li className="product">
      <div className="product-image img-cont">
        <img src={product.thumbnail} alt="" />
      </div>
      <div className="product-details">
        <h3>{product.title}</h3>
        <p>{product.description}</p>
        <span className="product-price">${product.price}</span>
      </div>
      <div className="product-actions">
        <button
          disabled={product?.isInCart}
          onClick={() => addToCart(product)}
          className="cta"
        >
          Add to cart
        </button>
      </div>
    </li>
  );
};
export default ProductItem;
```

The code above shows that this is a simple component with two props — `product` and `addToCart`. These components are for the product information displayed on the component and the function to add a specified product to the cart. 

Now, to create the `Cart` component, create a new `./src/components/Cart.jsx` file and enter the following code:

```javascript
// ./src/components/Cart.jsx
const Cart = ({ cart, removeItem }) => {
  return (
    <div className="dropdown">
      <div className="trigger group">
        <button className="cta">Cart</button>
        <span className="badge"> {cart?.length}</span>
      </div>
      <div className="content">
        <aside className="cart">
          <header className="cart-header">
            <h2>Your Cart</h2>
            <p>
              You have <span>{cart.length}</span> items in your cart
            </p>
          </header>
          <ul className="items">
            {cart.map((item) => {
              return (
                <li tabIndex={0} key={item.id} className="item">
                  <div className="item-image img-cont">
                    <img src={item.thumbnail} alt={item.name} />
                  </div>
                  <div className="item-details">
                    <h3>{item.title}</h3>
                    <p className="item-price">${item.price}</p>
                    <button onClick={() => removeItem(item)} className="cta">
                      Remove
                    </button>
                  </div>
                </li>
              );
            })}
          </ul>
        </aside>
      </div>
    </div>
  );
};
export default Cart;
```

In this component, we also accept two props. The `cart` prop contains the list of products that have been added to the cart. The `removeItem` prop will be used to pass the removed item to the parent component.

## Creating functions to add to our React app <a name="creating-functions-add-react-app">

Next, in `./src/App.js`, we’ll import our components and create a few functions to fetch products from `dummyjson.com`. These will be used for our dummy products, to add products to the cart, and to remove products from the cart. First, enter the following code into the `./src/App.js` file:

```javascript
// ./src/App.js
import "./App.css";
import { useEffect, useState } from "react";
import ProductItem from "./components/ProductItem";
import Cart from "./components/Cart";
// function to fetch products from dummyjson.com
const getProducts = async () => {
  try {
    const res = await fetch("https://dummyjson.com/products");
    const data = await res.json();
    return data;
  } catch (error) {
    console.log({
      error,
    });
    return [];
  }
};
function App() {
  // set up state for products and cart
  const [products, setProducts] = useState([]);
  const [cart, setCart] = useState([]);
  // function to add product to cart
  const handleAddToCart = (product) => {
    console.log("product", product);
    setCart((cart) => {
      return [...cart, product];
    });
    setProducts((products) => {
      return products.map((p) => {
        if (p.id === product.id) {
          return {
            ...p,
            isInCart: true,
          };
        }
        return p;
      });
    });
  };

 // function to remove product from cart
const handleRemoveFromCart = (product) => {
    setCart((cart) => {
      return cart.filter((p) => p.id !== product.id);
    });
    setProducts((products) => {
      return products.map((p) => {
        if (p.id === product.id) {
          return {
            ...p,
            isInCart: false,
          };
        }
        return p;
      });
    });
  };
  // fetch products on component mount
  useEffect(() => {
    getProducts().then((data) => {
      setProducts(data.products);
    });
  }, []);
  return (
    <div className="app">
      <header className="app-header">
        <div className="wrapper">
          <div className="app-name">Simple store</div>
          <div>
            <Cart cart={cart} removeItem={handleRemoveFromCart} />
          </div>
        </div>
      </header>
      <main className="app-main">
        <div className="wrapper">
          <section className="products app-section">
            <div className="wrapper">
              <header className="section-header products-header">
                <div className="wrapper">
                  <h2 className="caption">Browse our products</h2>
                  <p className="text">
                    We have a wide range of products to choose from. Browse our
                    products and add them to your cart.
                  </p>
                </div>
              </header>
              <ul className="products-list">
                {products.map((product) => (
                  <ProductItem
                    key={product.id}
                    product={product}
                    addToCart={handleAddToCart}
                  />
                ))}
              </ul>
            </div>
          </section>
        </div>
      </main>
    </div>
  );
}
export default App;
```

Awesome! For purposes of this article, the styles used to create this example project will be placed in the `./src/App.css` file of the project and are available on GitHub. You can also copy the [styles from Pastebin](https://pastebin.com/kbVUQLbv) or use your own styles. 

Now, if we start our app by running the `npm start` command, we should see something like this: ![Translating React Apps With Format.js](https://blog.logrocket.com/wp-content/uploads/2023/04/translating-react-app-format-js.png) 

Nice! Next, we'll install and set up Format.js to start translating our React application.

## Setting up Format.js in React <a name="setting-up-format-js-react">

To get started setting up Format.js in React, use the following commands:

```bash
Install react-intl, a Format.js package for React:
npm i -S react react-intl
```

Once installed, we can access different `helper` functions, components, and [H](https://blog.logrocket.com/react-hooks-cheat-sheet-solutions-common-problems/)[ooks](https://blog.logrocket.com/react-hooks-cheat-sheet-solutions-common-problems/) from Format.js that we can use in our React app.

### Adding the `IntlProvider` <a name="adding-intl-provider">

This component helps us add [i18n functionality](https://blog.logrocket.com/react-intl-internationalize-your-react-apps/) to our application by providing configurations like the current locale and set of translated strings/messages to the root of the application. This makes these configurations available to the different `<Formatted />` components used throughout the application. 

In our `./src/App.js` file, we'll wrap our app with the `<IntlProvider />` component:

```javascript
// ./src/App.js
// ...
import { IntlProvider } from "react-intl";
function App() {
  // ...
  // set up state for locale and messages
  const [locale, setLocale] = useState("es");
  const [messages, setMessages] = useState({
    "app.name": "Tienda sencilla",
  })
  // ...
  return (
    <IntlProvider messages={messages} key={locale} locale={locale}>
      {/* ... */}
    </IntlProvider>
  );
export default App;
```

Based on the code above, we import the `IntlProvider` component from the `react-intl` library. We also set up the state for `locale` and `messages` variables with the initial values of `"es"` and `{"app.name": "Tienda sencilla"}`, respectively. 

The `IntlProvider` component is then used to wrap the content of the `App` component. We also pass `messages` and `locale` variables as props to the `IntlProvider`. The `key` prop is set to the `locale` state to force React to re-render the component when the `locale` value changes. 

The `IntlProvider` component provides [internationalization support](https://blog.logrocket.com/internationalization-and-localization-in-react-native/) to the wrapped component by supplying it with translations for the current locale. By using the `messages` and `locale` state variables, the content of the wrapped component can be translated based on the selected locale. In this example, the `app.name` message key is translated to `"Tienda sencilla"` for the Spanish locale. Next, we'll use the `<FormattedMesage />` component to see the translation in action.

### Using the `FormattedMessage` component <a name="using-formatted-message-component">

First, we'll use the `FormattedMessage` component to translate the app name that appears in the `app-header` in `./src/App.js` using the `"app.name"` property from our `messages`, as shown below:

```javascript
// ./src/App.js
// ...
import { IntlProvider } from "react-intl";
function App() {
  // ...
  // set up state for locale and messages
  const [locale, setLocale] = useState("es");
  const [messages, setMessages] = useState({
    "app.name": "Tienda sencilla",
  })
  // ...
  return (
    <IntlProvider messages={messages} key={locale} locale={locale}>
      <div className="app">
        <header className="app-header">
          <div className="wrapper">
            <div className="app-name">
              <FormattedMessage id="app.name" defaultMessage={"Simple Store"} />
            </div>
            {/* ... */}
          </div>
        </header>
        {/* ... */}
      </div>
    </IntlProvider>
  );
export default App;
```

Here, we use the `FormattedMessage` component from the `react-intl` library to translate the app name that appears in the `app-header`. The `FormattedMessage` component takes two props: `ID` and `defaultMessage`. The `ID` prop is used to identify the translation message in the `messages` object. In this case, it is set to `"app.name"`. 

The `defaultMessage` prop is used as a fallback message in case the translation for the specified `ID` is not found. In this case, it is set to `"Simple Store"`. 

By using `FormattedMessage`, the app name is translated based on the currently selected locale. When the `locale` state variable changes, the `IntlProvider` component will re-render and provide `FormattedMessage` with the translations for the new locale. With that, we should have something like this: ![Translating React Apps With Format.js Step One](https://blog.logrocket.com/wp-content/uploads/2023/04/translate-react-format-js-step-one.png) 

Similarly, we can translate other text in our `.src/App.js` file by adding more properties to the `messages` object and using `<FormattedMessage />` to display the values like this:

```javascript
// ./src/App.js
// ...
import { IntlProvider } from "react-intl";
function App() {
  // ...
  // set up state for locale and messages
  const [locale, setLocale] = useState("es");
  const [messages, setMessages] = useState({
    "app.name": "Tienda sencilla",
    "app.description": "Una tienda sencilla con React",
    "app.products.caption": "Explora nuestros productos",
    "app.products.text":
      "Tenemos una amplia gama de productos para elegir. Explora nuestros productos y agrégalos a tu carrito.",
  })
  // ...
  return (
    <IntlProvider messages={messages} key={locale} locale={locale}>
      <div className="app">
        {/* ... */}
        <main className="app-main">
          <div className="wrapper">
            <section className="products app-section">
              <div className="wrapper">
                <header className="section-header products-header">
                  <div className="wrapper">
                    <h2 className="caption">
                      <FormattedMessage
                        id="app.products.caption"
                        defaultMessage={"Browse our products"}
                      />
                    </h2>
                    <p className="text">
                      <FormattedMessage
                        id="app.products.text"
                        defaultMessage={"We have a wide range of products to choose from. Browse our products and add them to your cart."}
                      />
                    </p>
                  </div>
                </header>
                <ul className="products-list">
                  {products.map((product) => (
                    <ProductItem
                      key={product.id}
                      product={product}
                      addToCart={handleAddToCart}
                    />
                  ))}
                </ul>
              </div>
            </section>
          </div>
        </main>
      </div>
    </IntlProvider>
  );
export default App;
```

Here, we see how to use `<FormattedMessage />` to translate other text in the `./src/App.js` file by adding more properties to the `messages` object. In this example, `messages` contains properties for the app name, description, product caption, and product text. 

The component displays these values by passing the relevant `ID` to the `FormattedMessage`, along with a default `message` to display if a translation is unavailable. In this example, the component displays the product caption and text using the `ID` corresponding to the property keys in the `messages` object with a fallback text passed to `defaultMessage`. 

With that, we should have something like this: ![Translating React Apps With Format.js Step Two](https://blog.logrocket.com/wp-content/uploads/2023/04/translate-react-format-js-step-two.png) 

Nice!

## Translating the `Cart` and `ProductItem` components <a name="translating-cart-product-item-components">

We can take it even further by translating our `Cart` and `ProductItem` components. First, we need to add the translations in the `messages` object in `./src/App.js` with the code below:

```javascript
const [messages, setMessages] = useState({
  "app.name": "Tienda sencilla",
  "app.description": "Una tienda sencilla con React",
  "app.products.caption": "Explora nuestros productos",
  "app.products.text":
    "Tenemos una amplia gama de productos para elegir. Explora nuestros productos y agrégalos a tu carrito.",
  "app.cart": "Carrito",
  "app.cart.title": "Tu carrito",
  "app.cart.empty": "El carrito está vacío",
  "app.cart.items":
    "{count, plural, =0 {No tienes artículos} one {# articulo} other {# artículos }} en tu carrito",
  "app.cart.remove": "Eliminar",
  "app.cart.add": "Añadir a la cesta",
  "app.item.price": "{price, number, ::currency/EUR}",
});
```

Here, we update the `messages` object in `./src/App.js` by adding translations for the new components. The translations include strings such as `"app.cart.title"`, `"app.cart.empty"`, `"app.cart.items"`, and `"app.item.price"`. These translations will display the correct text in the `Cart` and `ProductItem` components.

### Translate the `Cart` <a name="translate-cart">

Moving forward, we'll translate the `Cart` component. Go ahead and add the code below into `./src/components/Cart.jsx`:

```javascript
// ./src/components/Cart.jsx
import { FormattedMessage } from "react-intl";
const Cart = ({ cart, removeItem }) => {
  return (
    <div className="dropdown">
      <div className="trigger group">
        <button className="cta">
          <FormattedMessage id="app.cart" defaultMessage="Cart" />
        </button>
        <span className="badge"> {cart?.length}</span>
      </div>
      <div className="content">
        <aside className="cart">
          <header className="cart-header">
            <h2>
              <FormattedMessage
                id="app.cart.title"
                defaultMessage="Your Cart"
              />
            </h2>
            <p>
              <FormattedMessage
                id="app.cart.items"
                defaultMessage={`You have {count, plural, =0 {no items} one {one item} other {# items}} in your cart`}
                values={{ count: cart.length }}
              />
            </p>
          </header>
          <ul className="items">
            {cart.map((item) => {
              return (
                <li tabIndex={0} key={item.id} className="item">
                  <div className="item-image img-cont">
                    <img src={item.thumbnail} alt={item.name} />
                  </div>
                  <div className="item-details">
                    <h3>{item.title}</h3>
                    <p className="item-price">
                      <FormattedMessage
                        id="app.item.price"
                        defaultMessage={`{price, number, ::currency/USD}`}
                        values={{ price: item.price }}
                      />
                    </p>
                    <button onClick={() => removeItem(item)} className="cta">
                      <FormattedMessage
                        id="app.cart.remove"
                        defaultMessage="Remove"
                      />
                    </button>
                  </div>
                </li>
              );
            })}
          </ul>
        </aside>
      </div>
    </div>
  );
};
export default Cart;
```

In the code above, we use `FormattedMessage` to display the translated strings. The `FormattedMessage` component takes an `ID` prop corresponding to the `message` object's translation key. It also takes a `defaultMessage` prop, which displays a default value if the translation is not found. 

For example, `FormattedMessage` with `id="app.cart.title"` and `defaultMessage="Your Cart"` displays the text `"Tu carrito"` in Spanish when the `locale` is set to `"es"`. 

Take a close look at the code block below:

```javascript
<p>
  <FormattedMessage
    id="app.cart.items"
    defaultMessage={`You have {count, plural, =0 {no items} one {one item} other {# items}} in your cart`}
    values={{ count: cart.length }}
  />
</p>
Here, "app.cart.items" corresponds to:
const [messages, setMessages] = useState({
  "app.cart.items":
    "{count, plural, =0 {No tienes artículos} one {# articulo} other {# artículos }} en tu carrito",
});
```

Note that the `message` template uses `count` as a variable representing the cart's number of items. It has three possible options depending on the value of `count`:

*   `=0 {no items}:`: If the value of `count` is zero, this option is used, and the message will say `"no items"`
*   `one {one item}:`: If the value of `count` is one, this option is used, and the message will say `"one item"`
*   `other {# items}:`: If the value of `count` is anything other than zero or one, this option is used, and the message will say `# items`, where `#` is replaced with the value of `count`

This is for the message specified in `defaultMessage` and the one specified in the `messages` state. It is a `message` string that includes a plural form in Spanish. The message contains a `count` variable used to determine the correct plural form of the message. The syntax for the plural form is `{count, plural, ...}`. 

In this syntax, the first argument is the variable name (`count` in this case), and the second is the type of pluralization used. Inside the plural argument, there are three cases:

*   `=0 {No tienes artículos}`: This is the case when the `count` variable is equal to zero, which means the cart is empty. The message, in this case, is `No tienes artículos` (you have no items)
*   `one {# articulo}`: This is when the `count` variable equals one. The message, in this case, is `"# articulo"` (one item)
*   `other {# artículos}`: The default case for all other counts. The message, in this case, is `"# artículos"` (X items), where X is the value of the `count` variable

So, the full message in Spanish would be `"No tienes artículos"` (you have no items) for an empty cart, `"1 artículo"` (1 item) for a cart with one item, and `"# artículos"`  for carts with two or more items. This follows the `Intl MessageFormat` that you can [learn more about in the docs](https://formatjs.io/docs/intl-messageformat).

### Translate the `ProductItem` <a name="translate-product-item">

For the `ProductItem` component in `./src/components/ProductItem.jsx`, add the following code:

```javascript
// ./src/components/ProductItem.jsx
import { FormattedMessage } from "react-intl";
const ProductItem = ({ product, addToCart }) => {
  return (
    <li className="product">
      <div className="product-image img-cont">
        <img src={product.thumbnail} alt="" />
      </div>
      <div className="product-details">
        <h3>{product.title}</h3>
        <p>{product.description}</p>
        <span className="product-price">
          <FormattedMessage
            id="app.item.price"
            defaultMessage={`{price, number, ::currency/USD}`}
            values={{ price: product.price }}
          />
        </span>
      </div>
      <div className="product-actions">
        <button
          disabled={product?.isInCart}
          onClick={() => addToCart(product)}
          className="cta"
        >
          <FormattedMessage id="app.cart.add" defaultMessage="Add to Cart" />
        </button>
      </div>
    </li>
  );
};
export default ProductItem;
```

One thing we should take note of is the `product-price`, as shown below:

```javascript
<span className="product-price">
  <FormattedMessage
    id="app.item.price"
    defaultMessage={`{price, number, ::currency/USD}`}
    values={{ price: product.price }}
  />
</span>
"app.item.price" corresponds to:
const [messages, setMessages] = useState({
  "app.item.price": "{price, number, ::currency/EUR}",
});
```

In the code above, `"{price, number, ::currency/EUR}"` is a message format pattern used in the `react-intl` library. It specifies how to format a `price` variable as a number with a currency symbol of `EUR`. 

The curly braces `{}` indicate placeholders in the message pattern. Meanwhile, `price` is the name of the variable that should be substituted into the pattern. The `number` keyword specifies that the variable should be formatted as a number. 

The `::currency/EUR` option indicates that the number should be formatted as a currency value using the `EUR` currency symbol. With all that done, our app should be completely translated: ![Translated React App Using Format.js](https://blog.logrocket.com/wp-content/uploads/2023/04/translated-react-app-format-js.gif) Awesome!

## Switching between languages <a name="switching-between-languages">

One final and important feature to add to our application is a language switch feature. Follow along below.

### Create locale JSON files <a name="create-locale-json-files">

First, we’ll create the JSON files for each locale. For the Spanish locale, we create a new `./src/locales/es.json` file, as shown below:

```json
{
  "app.name": "Tienda sencilla",
  "app.description": "Una tienda sencilla con React",
  "app.products.caption": "Explora nuestros productos",
  "app.products.text": "Tenemos una amplia gama de productos para elegir. Explora nuestros productos y agrégalos a tu carrito.",
  "app.cart": "Carrito",
  "app.cart.title": "Tu carrito",
  "app.cart.empty": "El carrito está vacío",
  "app.cart.items": "{count, plural, =0 {No tienes artículos} one {# articulo} other {# artículos }} en tu carrito",
  "app.cart.remove": "Eliminar",
  "app.cart.add": "Añadir a la cesta",
  "app.item.price": "{price, number, ::currency/EUR}"
}
For the English locale, we create a ./src/locales/en.json file:
{
  "app.name": "Simple store",
  "app.description": "A simple store with React",
  "app.products.caption": "Explore our products",
  "app.products.text": "We have a wide range of products to choose from. Explore our products and add them to your cart.",
  "app.cart": "Cart",
  "app.cart.title": "Your Cart",
  "app.cart.empty": "Your cart is empty",
  "app.cart.items": "{count, plural, =0 {You have no items} one {You have one item} other {You have # items}} in your cart",
  "app.cart.remove": "Remove",
  "app.cart.add": "Add to cart",
  "app.item.price": "{price, number, ::currency/USD}"
}
```

Bravo!

### Dynamically import locale messages <a name="dynamically-import-locale-messages">

Now, we'll use the [`useEffect` Hook](https://blog.logrocket.com/useeffect-hook-complete-guide/) to asynchronously load the messages for the selected locale when the component is mounted or when the `locale` state is changed. Here's the code:

```javascript
// ./src/App.js
// ...
function App() {
  // ....
  const [locale, setLocale] = useState("es");
  const [messages, setMessages] = useState({
    // ...
  });
  // ...
  // function to dynamically import messages depending on locale
  useEffect(() => {
    import(`./locales/${locale}.json`).then((messages) => {
      console.log({
        messages,
      });
      setMessages(messages);
    });
  }, [locale]);
  return (
    // ...
  )
};
export default App;
```

The code above uses [dynamic import](https://blog.logrocket.com/react-dynamic-imports-route-centric-code-splitting-guide/)[s](https://blog.logrocket.com/react-dynamic-imports-route-centric-code-splitting-guide/) to load the JSON file containing the messages for the selected locale. Once the messages are loaded, it sets the `messages` state with the loaded messages. Finally, add a `select` input to switch between the locales, as shown below:

```javascript
// ./src/App.js
// ...
function App() {

  // ...
  return (
    <IntlProvider messages={messages} key={locale} locale={locale}>
      <div className="app">
        <header className="app-header">
          <div className="wrapper">
            <div className="app-name">
              <FormattedMessage id="app.name" defaultMessage={"Simple Store"} />
            </div>
            <div style={{ display: "flex", gap: "1rem" }}>
              <Cart cart={cart} removeItem={handleRemoveFromCart} />
              <select
                onChange={(e) => {
                  setLocale(e.target.value);
                }}
                value={locale}
                name="language-select"
                id="language-select"
                className="select-input"
              >
                <option value="es">Español</option>
                <option value="en">English</option>
              </select>
            </div>
          </div>
        </header>
        {/* ... */}
      </div>
    </IntlProvider>
  );
}
export default App;
```

With that, we should have something like this: ![Final Translated React App Using Format.js](https://blog.logrocket.com/wp-content/uploads/2023/04/final-product-react-format-js.gif) Awesome.

## Conclusion

In this article, we learned how to use Format.js to translate your React application. Ultimately, by following the instructions in this article, you can quickly translate your React application using Format.js, expanding your audience and [improving the](https://blog.logrocket.com/category/ux-design/) [UX](https://blog.logrocket.com/category/ux-design/) of your app. 

Whether you're building a simple store or a complex web app, internationalization is an important consideration that can significantly enhance the UX for non-native speakers of your language. By using the power of Format.js, you can easily add support for multiple languages and cultures to your React applications. Here is a [link](https://react-translated-app.netlify.app/) to a deployed preview of the example project built in this tutorial. 

If you want to learn more about Format.js or internationalization in general, several resources are available online. Here are a few recommended ones:

*   [Format.js documentation](https://formatjs.io/docs/getting-started/installation): This is the official documentation for Format.js. It provides a comprehensive guide to using Format.js and details the features and APIs
*   [React Intl documentation](https://formatjs.io/docs/react-intl/): If you're specifically interested in using Format.js with React, this documentation provides a guide to using the React Intl library, built on top of Format.js
*   [Unicode Common Locale Data Repository](https://cldr.unicode.org/): The Unicode CLDR provides a comprehensive set of locale data, including information about date and time formats, currency symbols, and other language-specific details. This is a valuable resource if you need to support multiple languages and cultures

---
##[LogRocket](https://lp.logrocket.com/blg/react-signup-general): Full visibility into your production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket](https://lp.logrocket.com/blg/react-signup-general).

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://lp.logrocket.com/blg/react-signup-general)

[LogRocket](https://lp.logrocket.com/blg/react-signup-general) combines session replay, product analytics, and error tracking – empowering software teams to create the ideal web and mobile product experience. What does that mean for you?

Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay problems as if they happened in your own browser to quickly understand what went wrong.

No more noisy alerting. Smart error tracking lets you triage and categorize issues, then learns from this. Get notified of impactful user issues, not false positives. Less alerts, way more useful signal.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — [start monitoring for free](https://lp.logrocket.com/blg/react-signup-general).