@exodus/i18n

中文文档
5.3.4发布于 2026/11/07MITES Module近 30 天下载 1.4万

Tooling, CLI and React components for cross-platform internationalization

原始使用文档
文档目录12 节
  1. Usage
  2. React components
  3. Best practices
  4. Always import i18n where you use it
  5. When to use which translation method
  6. Avoid conditional expressions in t
  7. No optional chaining in t
  8. Use eslint-plugin-i18n
  9. CLI
  10. Ignore files when extracting
  11. Re-exported expressions
  12. HOC and decorators

@exodus/i18n

The gateway to a more accessible crypto world for all of our users, no matter what language they speak.

Usage

@exodus/i18n is built on three pillars:

  • A set of React components, a hook, and a factory for a static i18n
  • Build tooling that ensures that these react components are a no-brainer to use and helps with loading the translation files
  • A CLI that deals with the automatic extraction of message IDs from <T> and t invocations

React components

I18nProvider

At the top of your component hierarchy, include the I18NProvider. It is responsible for providing the current language and available locales to components further downstream.

import { I18nProvider } from '@exodus/i18n'

const I18n = () => {
  // ...
  return (
    <I18nProvider
      locale={locale}
      locales={locales}
      setLocale={setLocale}
      currency={currency}
      defaultLanguage={DEFAULT_LANGUAGE}
      defaultCurrency={DEFAULT_CURRENCY}
    >
      {children}
    </I18nProvider>
  )
}

// Where `locales` are created from the PO files:
// locales.js
import en from '~/locales/en/messages.po'
import de from '~/locales/de/messages.po'

export default { en, de }

T and t

T is a component that can be used in jsx directly, whereas t is a function that returns a translated string.

import { T, useI18n } from '@exodus/i18n'

const MyComponent = () => (
  <Title>
    <T>This is a localized message</T>
  </Title>
)

const MyOtherComponent = () => {
  const { t } = useI18n()
  const title = t('Buy all the crypto')

  useEffect(() => {
    showModal({ title })
  }, [title])

  return null
}

Warning It is also possible to import t globally, as opposed to using it with the useI18n hook. The global version of t returns <T>{arg}</T> instead of the translated input.

Best practices

You can use this library in many different ways. See best practices below.

Always import i18n where you use it

The CLI of this library relies on imports to detect where it is used. If you use a translation method inside a file without importing i18n or specifying a custom module in the config, an extraction might not work correctly.

The following example shows how not to do it since the newline won't get escaped and will be in the PO file as an actual newline, breaking it in the end.

// Bad

const BatmobileFuel = ({ t, quantity }) => (
  <>
    <FuelIcon />
    {t(`Fuel Quantity:\n${quantity}`)}
  </>
)

If the hook is imported and used, everything will be as expected.

// Good

import { useI18n } from '@exodus/i18n'

const BatmobileFuel = ({ quantity }) => {
  const { t } = useI18n()

  return (
    <>
      <FuelIcon />
      {t(`Fuel Quantity:\n${quantity}`)}
    </>
  )
}

Lastly, here is an example that shows a i18n config with custom module that exports a static i18n instance.

{
  "sourceLocale": "en",
  "locales": "src/locales/{locale}/messages.po",
  "additionalModules": ["./localization"]
}
// Good with corresponding config

import { t } from './localization'

const getBatmobileFuel = (quantity) => t(`Fuel Quantity:\n${quantity}`)
}

When to use which translation method

As a rule of thumb, try to use the hook whenever possible. t and T exported from the library are just utility wrappers around the hook and add unnecessary layers.

There are situations where you have nested JSX in a localized string. In this case, you want to use T since the hook only supports strings.

<T>
  This is <Highlight>important</Highlight>
</T>

If you are outside of a React component, fear not, there is also a factory method, createI18NStatic, that allows you to create a static i18n instance without a context. This does not support locale switching on the fly and most likely requires you to restart your application.

Avoid conditional expressions in t

A conditional expression, also called a ternary operator, makes it hard for the translator to understand the message to be translated and might create grammar issues in other languages.

Try to move these to the outside of your translation function.

// Bad

t(evil ? 'Joker' : 'Batman')

// Good

evil ? t('Joker') : t('Batman')

No optional chaining in t

We currently do not support optional chaining inside of t.

// Bad

t(`Joker's real name is ${data.joker?.realName}`)
t(`Batman's health is ${data.joker?.getHealth()}`)
t(`Batman's health is ${batman.getHealth?.()}`)

// Good

const health = batman.getHealth?.()
t(`Batman's health is ${health}`)

Use eslint-plugin-i18n

We provide an ESlint plugin for the above-mentioned things. Use the linter, Luke!

CLI

The CLI extracts message IDs from your app, and creates corresponding entries in the translation files. It can be used calling i18n extract . or added as a script to your package.json, f.i. in the root package.json:

{
  //...
  scripts: {
    'i18n:extract': './src/node_modules/.bin/i18n extract ./src',
  },
}

Ignore files when extracting

You can exclude specific files from the extraction using the ignoreRegex property of the .i18nrc config file. It requires a valid regular expression and defaults to node_modules|__tests__ when none is provided.

{
  "sourceLocale": "en",
  "locales": "src/locales/{locale}/messages.po",
  "ignoreRegex": "node_modules|__tests__|vendor"
}

Re-exported expressions

To ensure the CLI only extracts relevant expressions, it checks the module name of import statements. If you want to use i18n from another module than the lib itself and have a successful extraction, you must first adapt your project according to one of the following approaches.

Config

The .i18nrc config file allows you to specify module names that the CLI should check in addition its own name. Add your custom module to the additionalModules property.

{
  "sourceLocale": "en",
  "locales": "src/locales/{locale}/messages.po",
  "additionalModules": ["#/localization"]
}

Alias

Provide an alias pointing to your custom module, so that you can import it as @exodus/i18n.

Alias setup:

{
  "~": "project-root",
  "@exodus/i18n": "./localization.js"
}

localization.js:

export { T } from '~/node_modules/@exodus/i18n'

potter.js:

import { T } from '@exodus/i18n'

const Potter = () => <T>Harry Potter</T>

export default Potter

HOC and decorators

This lib comes with the withI18n HOC that allows you to wrap your class components and get a t instance via the props. One way of using it would be via a decorator.

import { withI18n } from '@exodus/i18n'

class SomeComponent extends React.PureComponent {
  render = () => {
    const { t } = this.props
    return <div title={t('Some String')} />
  }
}

export default withI18n(SomeComponent)

If you want use a custom decorator, you need to specify this decorator in the .i18nrc config file. Otherwise, i18n will not be able to detect your translations properly and transform them.

The additionalDecorators property allows you to specify decorator names that i18n should look for in addition to the built-in one withI18n.

{
  "sourceLocale": "en",
  "locales": "src/locales/{locale}/messages.po",
  "additionalDecorators": ["withCustomI18n"]
}

版本与发布记录

@exodus/i18n 共发布 49 个版本,首次发布于 2023/04/13;过去 12 个月发布了 5 个版本。

版本发布日期距今
5.3.4latest2026/11/077 天前
5.3.32026/10/141 个月前
5.3.22026/06/065 个月前
5.3.12026/05/056 个月前
5.3.02026/03/307 个月前
5.2.12025/10/081.1 年前

关于 @exodus/i18n 的常见问题

@exodus/i18n 是什么?

Tooling, CLI and React components for cross-platform internationalization

如何安装 @exodus/i18n?

在项目目录运行 npm install @exodus/i18n,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^16.0.0)、@babel/core(^7.0.0)、@babel/types(^7.0.0)、@babel/traverse(^7.0.0)、@babel/generator(^7.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。它还提供命令行工具 i18n,可以用 npx i18n 直接运行。

@exodus/i18n 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/exodus__i18n 是否存在。

@exodus/i18n 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@exodus/i18n 可以商用吗?

@exodus/i18n 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@exodus/i18n 的下载量有多少?

根据 npm 官方下载统计,@exodus/i18n 在 2026/10/14 – 2026/11/12 这 30 天内被下载 14,088 次,日均约 470 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@exodus/i18n 还在维护吗?

最新版本 5.3.4 发布于 2026/11/07(7 天前);至今共发布 49 个版本,其中过去 12 个月发布了 5 个;首次发布于 2023/04/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。