---
title: "Crowdin"
description: "Use Crowdin for MainSDK translations - project setup, main.yaml, locales, missing strings caught by the check, local testing and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/crowdin"
updated: "2026-10-28"
---

# Crowdin

> Use Crowdin for MainSDK translations - project setup, main.yaml, locales, missing strings caught by the check, local testing and swapping.

Canonical: https://mainsdk.dev/docs/integrations/crowdin · Updated: 2026-10-28

Crowdin is a localization management platform where translators, reviewers and vendors work on your strings. Behind [`i18n`](https://mainsdk.dev/docs/interfaces/i18n), it holds your app's translations while your code keeps calling `t()` and `i18n.format.*`. Pick Crowdin when you work with professional translators or a translation agency, or when many languages and contributors make plain locale files hard to manage.

> **Note:** `i18n` has no spec yet. The options on this page are provisional, taken from the catalog and the product requirements, and may change when the spec lands.

## Interfaces it serves

### Languages and formats (`i18n`)

- Status: Preview · ships as a beta API
- Driver: `crowdin` (Crowdin)
- Docs: https://mainsdk.dev/docs/interfaces/i18n.md

```yaml
i18n:
  driver: crowdin
```

Swap to another provider: `files`, `tolgee`, `lokalise`, `ai-draft`.

## Before you start

1. **Create a Crowdin project** with your source language and the target languages you ship, such as Hindi and Tamil.
2. **Create an access token** with access to that project, and note the project's ID.
3. **Invite translators** or connect a vendor, and set up any glossary and translation memory you want shared.
4. **Store the token** in your secrets manager, never in code or a committed env file.

## Configure

```yaml title="main.yaml"
i18n:
  driver: crowdin
  locales: [en-IN, hi-IN, ta-IN]   # the locales you ship
  # [TBD] project ID, and the access token as secret:CROWDIN_TOKEN
```

Locales fall back along a chain: `hi-IN`, then `hi`, then `en-IN`, then `en`. A market overlay can set its own locales; see [main.yaml](https://mainsdk.dev/docs/concepts/main-yaml).

## Use it

```ts title="app/orders/heading.ts"
import { i18n, t } from "mainsdk";

export function heading(orders: unknown[]) {
  const title = t("orders.count", { count: orders.length });
  const total = i18n.format.money(125000, "INR");   // ₹1,25,000 in en-IN
  return `${title} · ${total}`;
}
```

Messages use Unicode MessageFormat 2 with ICU fallback for plurals, genders and selections; formats come from Unicode CLDR, not from Crowdin.

## Local development and testing

- **Local files:** the default `files` driver reads `locales/<locale>.yaml`, so you can build and test with no Crowdin project. Switch to `crowdin` when translators join.
- **Tests:** `createTestApp()` from `@mainsdk/testing` runs `i18n` without a network, and `chaos.on("i18n", { outage: true })` simulates Crowdin being unreachable.

## What MainSDK adds on top

- A missing translation fails `mainsdk check`, not the user.
- `mainsdk check` runs pseudo-localization (long strings, accents, right-to-left) to catch layout breaks before a translator sees them.
- Formats from Unicode CLDR, and the locale from the user's choice first, never guessed from IP alone.
- Android and iOS string files generated from the same locales.

See [Languages and formats](https://mainsdk.dev/docs/interfaces/i18n) for the full contract.

## Limits and notes

- Planned driver from the product requirements; `i18n` has no spec yet.
- How strings sync between your repo and Crowdin, and when translations reach a running app, are not defined yet [TBD].
- Translations in XLIFF, iOS `.xcstrings`, Android strings and ICU JSON import and export (`byo-content`), which helps when moving strings in or out of Crowdin.

## Swap to or from it

```yaml title="main.yaml"
i18n:
  driver: crowdin   # was files
```

Your `t()` and `i18n.*` calls stay the same.

> **Warning:** Translations, review status and translation memory live in Crowdin. Moving to another driver means exporting them and importing into the new tool first; how strings move between drivers is not decided yet [TBD]. Keep the old project until the new one has every string.

## FAQ

**Do I need Crowdin to start?** No. Start with the `files` driver and move to Crowdin when you add translators.

**Can I use AI drafts with Crowdin?** MainSDK's AI drafts come with the separate `ai-draft` driver. Whether it combines with `crowdin` is not decided yet [TBD].

## Next

- [Languages and formats](https://mainsdk.dev/docs/interfaces/i18n) and [Translate your app](https://mainsdk.dev/docs/guides/i18n)
- [Lokalise](https://mainsdk.dev/docs/integrations/lokalise) and [Tolgee](https://mainsdk.dev/docs/integrations/tolgee)
- [Swap a driver](https://mainsdk.dev/docs/guides/swap-a-driver)
