---
title: Metro Transformer
description: Use Lingui with React Native and compile your message catalogs on the fly
---

# Metro Transformer

[Metro bundler](https://metrobundler.dev/) is a JavaScript bundler used in React Native apps. The `@lingui/metro-transformer` offers an alternative to the [`lingui compile`](/ref/cli#compile) command: a transformer that enables Metro to compile `.po` files on the fly.

The transformer enables you to `import` `.po` files directly, instead of running `lingui compile` and `import`ing the resulting JavaScript (or TypeScript) files.

## Installation

> Only Expo SDK 50 and React Native v0.73.0 or newer are supported.

Install `@lingui/metro-transformer` as a development dependency:

```bash npm2yarn
npm install --save-dev @lingui/metro-transformer
```

Set up the transformer in your `metro.config.js` by specifying [`babelTransformerPath`](https://metrobundler.dev/docs/configuration/#babeltransformerpath) and updating `sourceExts`.

If you need to combine multiple transformers, use [this approach](https://stackoverflow.com/a/57660231/2070942):

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

<Tabs groupId="babel-swc">
  <TabItem value="expo" label="Expo" default>

```js title="metro.config.js"
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("expo/metro-config");

const config = getDefaultConfig(__dirname);
const { transformer, resolver } = config;

config.transformer = {
  ...transformer,
  babelTransformerPath: require.resolve("@lingui/metro-transformer/expo"),
};
config.resolver = {
  ...resolver,
  sourceExts: [...resolver.sourceExts, "po", "pot"],
};

module.exports = config;
```

  </TabItem>
<TabItem value="plain-RN" label="Plain React Native">

```js title="metro.config.js"
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");

const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;

/**
 * Metro configuration
 * https://reactnative.dev/docs/metro
 *
 * @type {import('metro-config').MetroConfig}
 */
const config = {
  transformer: {
    babelTransformerPath: require.resolve("@lingui/metro-transformer/react-native"),
  },
  resolver: {
    sourceExts: [...sourceExts, "po", "pot"],
  },
};

module.exports = mergeConfig(defaultConfig, config);
```

</TabItem>
</Tabs>

## Usage

:::tip
Take a look at the [example app](https://github.com/lingui/js-lingui/tree/main/examples/react-native) that uses the transformer. The transformer only supports catalogs based on `po` and `pot` files.

The library is currently in beta. If you encounter any issues, please [report them](https://github.com/lingui/js-lingui/issues).
:::

1.  Import `.po` files directly in your code:

    ```diff
    -import { messages } from "./src/locales/en/messages.ts";
    +import { messages } from "./src/locales/en/messages.po";
    ```

2.  If you are using TypeScript, you need to add `.po` file declaration so that TypeScript understands the file extension:

    ```ts title="src/po-types.d.ts"
    declare module "*.po" {
      import type { Messages } from "@lingui/core";
      export const messages: Messages;
    }
    ```

3.  Restart Metro bundler with `expo start -c` or `yarn start --reset-cache` to clear the transformer cache.
4.  Profit! 🎉

:::danger
Whenever you make a change to the Lingui config file (this should not happen often), restart Metro bundler.
:::

## See Also

- [React Native i18n Tutorial](/tutorials/react-native)
- [Lingui React Native Example App](https://github.com/lingui/js-lingui/tree/main/examples/react-native)
