Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ myorg-myplugin-plugintype/
└── package.json
```

:::note
The `src/locales/en-US/<plugin-id>.json` file is generated by translation tooling and committed for translators. Starting with Grafana 13.1.0, Grafana does not load it at runtime. `en-US` text comes from the defaults in your source code. This saves the browser from fetching a translation file the bundle already contains. Your `loadResources` function is not invoked for `en-US` either, but it continues to be called for every other language listed in `plugin.json#languages`. See [Determine the text to translate](#determine-the-text-to-translate) below for how to declare those defaults, including the special handling required for plurals.
:::

## Set up your plugin for translation

Follow these steps to update your plugin and set it up for translation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ myorg-myplugin-plugintype/
└── package.json
```

:::note
The `src/locales/en-US/<plugin-id>.json` file is generated by translation tooling and committed for translators. Starting with Grafana 13.1.0, Grafana does not load it at runtime. `en-US` text comes from the defaults in your source code. This saves the browser from fetching a translation file the bundle already contains. See [Determine the text to translate](#determine-the-text-to-translate) below for how to declare those defaults, including the special handling required for plurals.
:::

## Set up your plugin for translation

Follow these steps to update your plugin and set it up for translation.
Expand Down
40 changes: 40 additions & 0 deletions docusaurus/docs/shared/plugin-internationalization-shared.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## Determine the text to translate

After you've configured your plugin for translation, you can proceed to mark up the language strings you want to translate. Each translatable string is assigned a unique key that ends up in each translation file under `locales/<locale>/<plugin id>.json`.

:::note
The string you pass as the default (the second argument of `t()` or the children of `<Trans>`) is what Grafana renders for `en-US`. Starting with Grafana 13.1.0, translation resources for `en-US` are **not** loaded at runtime. They're read directly from your source code. This keeps both the plugin and Grafana from fetching a translation file the bundle already contains, saving hundreds of kilobytes on first paint. The `src/locales/en-US/<plugin-id>.json` file is still generated by `i18n-extract` and used as the source of truth for translators, but it is not fetched by the browser. Keep your in-source defaults meaningful and up to date.
:::

The following example uses the `t` function:

```diff
Expand Down Expand Up @@ -78,6 +83,41 @@ export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel).setPanelOption
);
```

### Handle pluralization

Be extra careful with plurals. Starting with Grafana 13.1.0, `en-US` resources aren't loaded at runtime, so every plural form has to be declared as a default in source as well, because the JSON file isn't there to fill them in. A missing `_one` or `_other` default is a missing string at runtime, not a graceful fallback. Pass `count` together with `defaultValue_one` and `defaultValue_other` (and any other [CLDR plural categories](https://cldr.unicode.org/index/cldr-spec/plural-rules) you need); `i18next` picks the right suffix at runtime and `i18next-cli` emits the matching `<key>_<suffix>` entries into `src/locales/en-US/<plugin-id>.json` on extract.

**Using `t()`**

```ts
t('panel.counts.folder', '', {
count: folderCount,
defaultValue_one: '{{count}} folder',
defaultValue_other: '{{count}} folders',
});
```

The positional default (second argument) is intentionally empty, since the plural-aware defaults come from the options object.

**Using `<Trans>`**

```tsx
<Trans
i18nKey="panel.routes.view"
count={routes.length}
tOptions={{
defaultValue_one: 'View route',
defaultValue_other: 'View routes',
}}
>
View route
</Trans>
```

Children stay in place because they carry the JSX structure (for example `<strong>`, `<br/>`, `<Icon />`) that `<n>` placeholders in the JSON values map back to at render time.

For reference, [grafana/grafana#125312](https://github.com/grafana/grafana/pull/125312) and [grafana/grafana#125316](https://github.com/grafana/grafana/pull/125316) migrated every plural `t()` and `<Trans>` in Grafana itself to this shape.

## Obtain the translated text

Use the [`i18next-cli`](https://github.com/i18next/i18next-cli#readme) and `i18n-extract` to sweep all input files, extract tagged `i18n` keys, and save the translations.
Expand Down
Loading