
The Problem
When building dApps with ethers.js, error messages are always in English:
Error: insufficient funds for intrinsic transaction cost
While developers understand these messages, they aren’t user-friendly — especially for non-English-speaking end users. Translating ethers.js error messages manually in every project leads to duplicated effort and inconsistent quality.
ethers-i18n solves this by providing a lightweight i18n plugin for ethers.js error messages.
https://github.com/nakamura196/ethers-i18n
What is ethers-i18n?
ethers-i18n provides localized translations for ethers.js v6 error codes. It currently supports 4 languages: English, Japanese, Korean, and Chinese.
Key features:
- Simple API — Just
setLocale("ja")andt("ERROR_CODE") - Non-breaking — Works alongside existing ethers.js code without modifications
- Type-safe — Full TypeScript support with strict error code typing
- 4 languages — English, Japanese, Korean, and Chinese
- Lightweight — Only ethers.js as a peer dependency
Installation
npm install @nakamura196/ethers-i18n
Requires ethers.js v6 as a peer dependency.
Basic Usage
Setting Locale and Translating
import { setLocale, t, getSupportedLocales } from "@nakamura196/ethers-i18n";
// Check available locales
console.log(getSupportedLocales()); // ["en", "ja", "ko", "zh"]
// Set to Japanese
setLocale("ja");
// Translate error codes
console.log(t("INVALID_ARGUMENT")); // "無効な引数です"
console.log(t("INSUFFICIENT_FUNDS")); // "トランザクションに必要な残高が不足しています"
console.log(t("NETWORK_ERROR")); // "ネットワークエラーが発生しました"
Translating Error Objects
Translate ethers.js error objects directly:
import { setLocale } from "@nakamura196/ethers-i18n";
import { translateError } from "@nakamura196/ethers-i18n/wrapper";
setLocale("ja");
try {
await provider.getBalance("invalid-address");
} catch (error) {
// Automatically detects the ethers.js error code and translates
const message = translateError(error);
console.log(message); // "無効な引数です"
}
The withI18n Wrapper
Wrap async functions to automatically translate errors:
import { setLocale } from "@nakamura196/ethers-i18n";
import { withI18n } from "@nakamura196/ethers-i18n/wrapper";
setLocale("ja");
try {
const balance = await withI18n(() => provider.getBalance("invalid-address"));
} catch (error) {
// error.message is already translated
console.log(error.message); // "無効な引数です"
// Original message is preserved
console.log(error.originalMessage); // "invalid argument"
}
The advantage of withI18n is that it throws translated errors, so upstream error handlers can use the localized messages directly.
Supported Error Codes
ethers-i18n covers 17 major ethers.js v6 error codes:
| Error Code | English | Japanese |
|---|---|---|
INVALID_ARGUMENT | invalid argument | 無効な引数です |
MISSING_ARGUMENT | missing argument | 引数が不足しています |
UNEXPECTED_ARGUMENT | unexpected argument | 予期しない引数です |
CALL_EXCEPTION | call exception | コントラクト呼び出しに失敗しました |
INSUFFICIENT_FUNDS | insufficient funds | トランザクションに必要な残高が不足しています |
NETWORK_ERROR | network error | ネットワークエラーが発生しました |
SERVER_ERROR | server error | サーバーエラーが発生しました |
TIMEOUT | timeout | タイムアウトしました |
BUFFER_OVERRUN | buffer overrun | バッファオーバーランが発生しました |
NUMERIC_FAULT | numeric fault | 数値演算エラーが発生しました |
ACTION_REJECTED | action rejected | ユーザーによって操作が拒否されました |
NONCE_EXPIRED | nonce expired | ノンスは既に使用されています |
REPLACEMENT_UNDERPRICED | replacement fee too low | 置換手数料が低すぎます |
TRANSACTION_REPLACED | transaction replaced | トランザクションが置換されました |
UNPREDICTABLE_GAS_LIMIT | cannot estimate gas | ガスリミットを推定できません |
UNSUPPORTED_OPERATION | unsupported operation | サポートされていない操作です |
UNKNOWN_ERROR | unknown error | 不明なエラーが発生しました |
Design Decisions
Why a Separate Library?
In dApp projects, error message translation is typically handled on a per-project basis. However, since ethers.js error codes are part of a fixed specification, translations can be shared.
By providing this as a library:
- No reinventing the wheel — Avoid writing the same translations in every project
- Better translation quality — Community review and improvement
- Type safety — Catch error code typos at compile time
Simple API
// Configure in one line
setLocale("ja");
// Translate in one line
const msg = t("INVALID_ARGUMENT");
No complex configuration needed. By focusing on the narrow scope of ethers.js error codes, the API stays minimal and intuitive.
Fallback Mechanism
When a translation is missing, the fallback locale (default: English) is used:
import { configure } from "@nakamura196/ethers-i18n";
configure({
locale: "ja",
fallback: "en", // Falls back to English when Japanese translation is missing
});
Adding a New Language
Adding a new language is straightforward — just create one locale file:
// src/locales/fr.ts
import { LocaleMessages } from "../types";
export const fr: LocaleMessages = {
INVALID_ARGUMENT: "argument invalide",
MISSING_ARGUMENT: "argument manquant",
UNEXPECTED_ARGUMENT: "argument inattendu",
CALL_EXCEPTION: "exception d'appel de contrat",
INSUFFICIENT_FUNDS: "fonds insuffisants pour la transaction",
// ... define all error codes
};
The LocaleMessages type ensures all error codes must be defined, preventing missed translations at compile time.
Use Cases
1. dApp Error Display
// React example
import { setLocale } from "@nakamura196/ethers-i18n";
import { translateError } from "@nakamura196/ethers-i18n/wrapper";
function App() {
// Set locale based on browser language
useEffect(() => {
const lang = navigator.language.startsWith("ja") ? "ja" : "en";
setLocale(lang);
}, []);
const handleTransaction = async () => {
try {
await contract.transfer(to, amount);
} catch (error) {
// Show user-friendly localized message
toast.error(translateError(error));
}
};
}
2. CLI Tool Error Messages
import { setLocale } from "@nakamura196/ethers-i18n";
import { withI18n } from "@nakamura196/ethers-i18n/wrapper";
// Control locale via environment variable
setLocale(process.env.LANG?.startsWith("ja") ? "ja" : "en");
const balance = await withI18n(() => provider.getBalance(address));
Future Plans
- More languages — French, Spanish, German, and more
- Custom message overrides — Allow projects to override translations
- viem support — Extend beyond ethers.js to support viem error messages
Contributions are welcome! We especially appreciate PRs for new language translations.
Conclusion
ethers-i18n is a lightweight plugin that brings multilingual support to ethers.js error messages. With a simple API and TypeScript type safety, it integrates easily into existing projects and helps prevent translation gaps.
Give it a try to improve your dApp’s UX for a global audience.