# next-intl

> Edit next-intl message files in your GitHub repository with Fink: namespaces, ICU plurals, selects and rich text, pushed back as small diffs.

Fink edits next-intl message files in your GitHub repository: the `messages/{locale}.json` files that `useTranslations` and `getTranslations` read. You see each message's translations side by side, Fink flags missing ones and broken plurals, variables or tags, and it commits only the lines you changed.

## Set up

Add `project.inlang/settings.json` next to your app's `package.json`. Paths are relative to the folder that contains `project.inlang`:

```json
{
  "$schema": "https://inlang.com/schema/project-settings",
  "baseLocale": "en",
  "locales": ["en", "de", "fr"],
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-next-intl@2/dist/index.js"
  ],
  "plugin.inlang.nextIntl": {
    "pathPattern": "./messages/{locale}.json"
  }
}
```

List the locales of your `routing.ts` in `locales`. `baseLocale` is the language you write first, usually your `defaultLocale`. Commit the folder and open the repository at [fink.inlang.com](https://fink.inlang.com).

### Files per namespace

If you split messages into one file per namespace, give `pathPattern` one entry per namespace:

```json
"plugin.inlang.nextIntl": {
  "pathPattern": {
    "HomePage": "./messages/{locale}/home.json",
    "Checkout": "./messages/{locale}/checkout.json"
  }
}
```

The messages of `./messages/en/home.json` appear as `HomePage.title` and so on, as `useTranslations("HomePage")` reads them. Fink writes each one back to its own file. A new message must start with one of the namespaces, such as `HomePage.subtitle`: Fink can't push a message that has no file.

## What Fink understands

- **Namespaces.** `{ "Home": { "title": "…" } }` is the message `Home.title`, as `t("Home.title")` or `useTranslations("Home")` reads it. A new message is nested at its dots.
- **Arguments.** `{name}` appears as the variable `{name}`.
- **Plurals.** `{count, plural, =0 {…} one {# item} other {# items}}` appears as one message with a form for exactly 0 and the plural forms each language needs, for example `few` and `many` in Polish. `#` is the number. Any exact number (`=0`, `=1`, `=12`) works. See [Plurals, selects and exact numbers](/docs/plurals-and-selects).
- **Selects and ordinals.** `{gender, select, female {…} other {…}}` and `{place, selectordinal, one {#st} …}` work the same way, also nested in each other.
- **Rich text.** Tags such as `<b>…</b>` and `<link>…</link>`, for `t.rich()` and `t.markup()`, are shown as tags that translators can keep, move or wrap around text. Fink flags a translation that lost one.
- **Number and date formats.** `{price, number, ::currency/EUR}` and `{date, date, short}` are kept as written.
- **Escaping.** Quoted text like `'{name}'` shows as `{name}`. When you type `{` or a tag as text, Fink quotes it so that next-intl shows it as text.

Arrays and other values that aren't messages (for `t.raw()`) are kept in the files but not shown.

## Small diffs

Fink writes only the messages you changed. Every other line of the file, its key order, indentation and quoting, stays byte for byte. A plural you edit is written as one ICU string, such as `{count, plural, =0 {No items} one {# item} other {# items}}`.

## Limitations

- **Unused messages** are not detected for next-intl projects. Fink's code analysis only understands Paraglide JS calls.
- **Tags around a plural**, such as `<b>{count, plural, …}</b>`, are written into each form, `{count, plural, one {<b>…</b>} …}`, once you edit the message. next-intl renders both the same.
- **Self-closing tags** like `<br/>` are text in next-intl. Use `<br></br>`.
- A message next-intl can't parse is shown as text and written back as it was, unless you edit it.
- With `sourceLanguageFilePath`, the file of the reference locale, change the reference locale in `settings.json` in your repository, not in Fink.
