# How to Set Up i18n Localization for Cards in GitHub Readme Stats

> Learn how to set up i18n localization for your GitHub Readme Stats cards. This guide shows you how to easily add multilingual support to your stats using the built-in i18n subsystem and locale parameter.

- Repository: [Anurag Hazra/github-readme-stats](https://github.com/anuraghazra/github-readme-stats)
- Tags: how-to-guide
- Published: 2026-02-28

---

**GitHub Readme Stats includes a built-in i18n subsystem that enables multilingual card rendering by passing a `locale` parameter to the API or programmatic renderer, leveraging centralized translation dictionaries in [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js).**

The **anuraghazra/github-readme-stats** repository ships with a custom **i18n** implementation that supports dozens of languages across all card types including stats, repository, top languages, and WakaTime cards. Mastering **i18n localization for cards** allows contributors to extend language support and helps users display metrics in their native languages.

## How the i18n System Works

The localization architecture consists of three core components working together to deliver translated content.

### The I18n Class ([`src/common/I18n.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/I18n.js))

The `I18n` class serves as the translation engine. It accepts a `locale` string and a `translations` object during instantiation, then provides a `t(key)` method for retrieving localized strings.

```js
// src/cards/stats.js – I18n instantiation pattern
// https://github.com/anuraghazra/github-readme-stats/blob/master/src/cards/stats.js#L14-L22
const i18n = new I18n({
  locale,
  translations: {
    ...statCardLocales({ name, apostrophe }),
    ...wakatimeCardLocales,
  },
});

```

If a translation key is missing for the requested locale, the `t()` method throws an error, which surfaces as a clear error message in the generated card.

### Translation Dictionaries ([`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js))

All locale strings live in [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js), organized by card type:

- **`statCardLocales`** – Labels for the stats card (stars, commits, PRs)
- **`repoCardLocales`** – Repository card strings (stars, forks, archived)
- **`langCardLocales`** – Top languages card text
- **`wakatimeCardLocales`** – Wakatime coding metrics labels

Each locale map follows a nested structure where keys like `"statcard.totalstars"` map to language-specific strings:

```js
// Excerpt from src/translations.js
"statcard.totalstars": {
  en: "Total Stars Earned",
  fr: "Total d'étoiles",
  es: "Estrellas Totales",
  // ... additional locales
}

```

## Implementing i18n in Card Renderers

Card renderers in `src/cards/*.js` files instantiate the `I18n` class and use it to localize all user-facing labels before generating SVG output.

### Creating the I18n Instance

Each renderer merges the relevant locale maps and creates an `I18n` instance at the top of the rendering function:

```js
// Pattern used across card renderers
const i18n = new I18n({
  locale: options.locale || "en",
  translations: {
    ...statCardLocales({ name, apostrophe }),
  },
});

```

### Translating Labels

To render localized text, call `i18n.t()` with the specific key:

```js
// src/cards/stats.js – localized label usage
// https://github.com/anuraghazra/github-readme-stats/blob/master/src/cards/stats.js#L27-L33
label: i18n.t("statcard.totalstars"),

```

This pattern ensures that every label in the final SVG reflects the user's selected language while numeric values remain unchanged.

## Validating Locales in the API Layer

The public API endpoints validate locale parameters before rendering to prevent errors from invalid language codes.

In [`src/api/index.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/api/index.js), the system checks locale availability using `isLocaleAvailable`:

```js
// src/api/index.js – locale validation
// https://github.com/anuraghazra/github-readme-stats/blob/master/src/api/index.js#L70-L77
if (locale && !isLocaleAvailable(locale)) {
  return renderErrorCard({
    message: `Locale "${locale}" is not supported`,
    // ... error details
  });
}

```

If validation passes, the locale string flows into the card renderer. Available locales are derived from the keys in `repoCardLocales["repocard.archived"]` within [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js).

## Adding Custom Language Support

To extend the repository with a new language, modify [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) and update the test suite.

1. **Add translations** for each card type. For example, to add a custom locale `"xx"`:

```js
// Extension in src/translations.js
const statCardLocales = ({ name, apostrophe }) => ({
  "statcard.title": {
    en: `${encodedName}'${apostrophe} GitHub Stats`,
    xx: `${encodedName}'${apostrophe} Demo Stats`, // New entry
  },
  "statcard.totalstars": {
    en: "Total Stars Earned",
    xx: "Demo Stars", // New entry
  },
  // ... remaining keys
});

```

2. **Verify availability** by ensuring the new locale appears in the `availableLocales` array, which the system derives from `repoCardLocales`.

3. **Test the implementation** in [`tests/i18n.test.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/tests/i18n.test.js):

```js
// Verification test
it("should translate to custom locale xx", () => {
  const i18n = new I18n({
    locale: "xx",
    translations: statCardLocales({ name: "Test", apostrophe: "s" })
  });
  expect(i18n.t("statcard.title")).toBe("Test's Demo Stats");
});

```

Run `npm test` to confirm the key lookups function correctly.

## Usage Examples

### Public API Endpoint

Request localized cards via query parameter:

```bash
curl "https://github-readme-stats.vercel.app/api?username=anuraghazra&locale=es"

```

The `locale=es` parameter passes through [`src/api/index.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/api/index.js), validates against available locales, and renders the stats card with Spanish labels.

### Programmatic Rendering

Render a stats card in French within a Node.js application:

```js
import { renderStatsCard } from "./src/cards/stats.js";

const stats = {
  name: "Jean Dupont",
  totalStars: 42,
  totalCommits: 128,
  totalIssues: 3,
  totalPRs: 7,
  totalPRsMerged: 5,
  mergedPRsPercentage: 71.4,
  totalReviews: 2,
  totalDiscussionsStarted: 1,
  totalDiscussionsAnswered: 0,
  contributedTo: 4,
  rank: { percentile: 12, level: "A" },
};

const svg = renderStatsCard(stats, {
  locale: "fr",
  hide: [],
  show_icons: true,
  custom_title: "Mes stats GitHub",
});

```

The renderer creates an `I18n` instance with `locale: "fr"`, retrieves French strings like `"Total d'étoiles"` for `"statcard.totalstars"`, and generates the localized SVG.

## Summary

- **GitHub Readme Stats** uses a custom `I18n` class in [`src/common/I18n.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/common/I18n.js) to handle all card localization through a simple `t(key)` interface.
- Translation dictionaries in [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) organize strings by card type (`statCardLocales`, `repoCardLocales`, etc.), supporting dozens of languages out of the box.
- Card renderers instantiate `I18n` with merged locale maps and call `i18n.t()` for every label, ensuring consistent multilingual output.
- The API layer validates locales using `isLocaleAvailable` in [`src/api/index.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/api/index.js), returning error cards for unsupported language codes.
- Adding new languages requires extending [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) with new keys and running `npm test` to verify integration.

## Frequently Asked Questions

### What happens if I request an unsupported locale?

The API returns an error card. In [`src/api/index.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/api/index.js), the `isLocaleAvailable` function checks the requested locale against the supported list. If the check fails, the system calls `renderErrorCard` with the message `Locale "${locale}" is not supported`, preventing the renderer from attempting invalid translations.

### How do I add a completely new language to the repository?

Extend [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) by adding your language code as a key in each locale map (`statCardLocales`, `repoCardLocales`, etc.). Ensure you provide translations for every string key used by the cards you want to support. After adding the translations, run `npm test` to verify that the `I18n` class correctly retrieves your new strings without throwing missing-key errors.

### Can I override translations for a specific card without modifying core files?

Currently, the system requires modifying [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) to add or change locale data. The `I18n` constructor receives a static translations object built from the exported locale maps. To customize text for a single deployment, fork the repository and modify the locale dictionaries directly, then deploy your instance to Vercel.

### Which cards support i18n localization?

All major card types support **i18n localization**: the stats card ([`src/cards/stats.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/cards/stats.js)), repository card ([`src/cards/repo.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/cards/repo.js)), top languages card ([`src/cards/top-languages.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/cards/top-languages.js)), and WakaTime card ([`src/cards/wakatime.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/cards/wakatime.js)). Each renderer imports the appropriate locale maps from [`src/translations.js`](https://github.com/anuraghazra/github-readme-stats/blob/main/src/translations.js) and instantiates the `I18n` class to localize labels, titles, and descriptive text.