From 2c55a1a81b5dd34baf5d0e5b9bd8e49e6e1ede1a Mon Sep 17 00:00:00 2001 From: blam Date: Sat, 9 Dec 2023 11:07:59 +0100 Subject: [PATCH 1/4] docs: start some i18n docs Signed-off-by: blam --- docs/plugins/internationalization.md | 89 ++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 13bb098262..de53e45abe 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -46,6 +46,95 @@ return ( ); ``` +### Guidelines for `i18n` messages and keys + +The API for `i18n` messages and keys can be pretty tricky to get right, as it's a pretty flexible API. We've put together some guidelines to help you get started that encourage good practices when thinking about translating plugins: + +#### Key names + +Dot notation is used when consuming these keys, and should represent a semantic hierarchy in your translations. This allows for better organization and understanding of the structure. For example: + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + dashboardPage: { + title: 'All your components', + subtitle: 'Create new component', + widgets: { + weather: { + title: 'Weather', + description: 'Shows the weather', + }, + calendar: { + title: 'Calendar', + description: 'Shows the calendar', + }, + }, + }, + entityPage: { + notFound: 'Entity not found', + }, + }, +}); +``` + +Think about the semantic placement of content rather than the text content itself. Group related translations under a common prefix, and use nesting to represent relationships between different parts of your application. It's good to start grouping under extensions, page sections, or visual scopes and experiences. + +The translations should avoid where possible having their text content in the keys, as this can lead to ambiguity and confusion when the translation changes. + +#### Key reuse + +Discourage key reuse to prevent ambiguity and maintain a clear separation of concerns. Consider creating duplicate keys that are grouped under a semantic section instead. + +#### Flat keys + +Avoid a flat key structure at the root level, as it can lead to naming conflicts and make the translation file harder to manage and change evolve over time. Instead, group translations under a common prefix. + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + // this is BAD + title: 'My page', + subtitle: 'My subtitle', + // this is GOOD + dashboardPage: { + header: { + title: 'All your components', + subtitle: 'Create new component', + }, + }, + }, +}); +``` + +#### Plurals + +There's build in support for pluralization in our `i18n` library which closely follows the `react-i18next` API. You can read more about it [here](https://www.i18next.com/translation-function/plurals). + +We enourage you to use this feature and avoid creating duplicate keys for pluralized content. For example: + +```ts +export const myPluginTranslationRef = createTranslationRef({ + id: 'plugin.my-plugin', + messages: { + dashboardPage: { + title: 'All your components', + subtitle: 'Create new component', + cards: { + title_one: 'You have one card', + title_two: 'You have two cards', + title_other: 'You have many cards ({{count}})', + }, + }, + entityPage: { + notFound: 'Entity not found', + }, + }, +}); +``` + ## For an application developer overwrite plugin messages In an app you can both override the default messages, as well as register translations for additional languages: From e40ee6597d5ebe07d9d475ec72a3afafb09b6474 Mon Sep 17 00:00:00 2001 From: blam Date: Sat, 9 Dec 2023 11:15:34 +0100 Subject: [PATCH 2/4] chore: fix spelling Signed-off-by: blam --- docs/plugins/internationalization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index de53e45abe..040e75874f 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -113,7 +113,7 @@ export const myPluginTranslationRef = createTranslationRef({ There's build in support for pluralization in our `i18n` library which closely follows the `react-i18next` API. You can read more about it [here](https://www.i18next.com/translation-function/plurals). -We enourage you to use this feature and avoid creating duplicate keys for pluralized content. For example: +We encourage you to use this feature and avoid creating different key prefixes for pluralized content. For example: ```ts export const myPluginTranslationRef = createTranslationRef({ From bdd5d99e4c2cb1e042fa1b28d164a3f01d1bd1a0 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Wed, 13 Dec 2023 13:29:50 +0100 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Patrik Oldsberg Signed-off-by: Ben Lambert Signed-off-by: blam --- docs/plugins/internationalization.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 040e75874f..98f6a05a58 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -52,7 +52,7 @@ The API for `i18n` messages and keys can be pretty tricky to get right, as it's #### Key names -Dot notation is used when consuming these keys, and should represent a semantic hierarchy in your translations. This allows for better organization and understanding of the structure. For example: +When defining messages it is recommended to use a nested structure that represents the semantic hierarchy in your translations. This allows for better organization and understanding of the structure. For example: ```ts export const myPluginTranslationRef = createTranslationRef({ @@ -81,11 +81,11 @@ export const myPluginTranslationRef = createTranslationRef({ Think about the semantic placement of content rather than the text content itself. Group related translations under a common prefix, and use nesting to represent relationships between different parts of your application. It's good to start grouping under extensions, page sections, or visual scopes and experiences. -The translations should avoid where possible having their text content in the keys, as this can lead to ambiguity and confusion when the translation changes. +Translations should avoid using their own text content as key where possible, as this can lead to confusion if the translation changes. Instead prefer to use keys that describe the location or usage of the text. #### Key reuse -Discourage key reuse to prevent ambiguity and maintain a clear separation of concerns. Consider creating duplicate keys that are grouped under a semantic section instead. +Reusing the same key in multiple places is discouraged. This helps prevent ambiguity, and instead keeps the usage of each key as clear as possible. Consider creating duplicate keys that are grouped under a semantic section instead. #### Flat keys @@ -111,7 +111,7 @@ export const myPluginTranslationRef = createTranslationRef({ #### Plurals -There's build in support for pluralization in our `i18n` library which closely follows the `react-i18next` API. You can read more about it [here](https://www.i18next.com/translation-function/plurals). +The `i18next` library, which is used as the underlying implementation, has built-in support for pluralization. You can use this feature as is described in [the documentation](https://www.i18next.com/translation-function/plurals). We encourage you to use this feature and avoid creating different key prefixes for pluralized content. For example: From 627dabd6d36501e13c85e806eabc70d9c03e9c82 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 14 Dec 2023 15:46:49 +0100 Subject: [PATCH 4/4] chore: some more smaller tweaks Signed-off-by: blam --- docs/plugins/internationalization.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 98f6a05a58..fd12452cff 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -6,7 +6,7 @@ description: Documentation on adding internationalization to the plugin ## Overview -The Backstage core function provides internationalization for plugins +The Backstage core function provides internationalization for plugins. The underlying library is [`i18next`](https://www.i18next.com/) with some additional Backstage typescript magic for type safety with keys. ## For a plugin developer @@ -46,6 +46,8 @@ return ( ); ``` +You will see how the initial dictionary structure and nesting gets converted into dot notation, so we encourage `camelCase` in key names and lean on the nesting structure to separate keys. + ### Guidelines for `i18n` messages and keys The API for `i18n` messages and keys can be pretty tricky to get right, as it's a pretty flexible API. We've put together some guidelines to help you get started that encourage good practices when thinking about translating plugins: @@ -83,6 +85,16 @@ Think about the semantic placement of content rather than the text content itsel Translations should avoid using their own text content as key where possible, as this can lead to confusion if the translation changes. Instead prefer to use keys that describe the location or usage of the text. +#### Common Key names + +This list is intended to grow over time, but below are some examples of common key names and patterns that we encourage you to use where possible: + +- `${page}.title` +- `${page}.subtitle` +- `${page}.description` + +- `${page}.header.title` + #### Key reuse Reusing the same key in multiple places is discouraged. This helps prevent ambiguity, and instead keeps the usage of each key as clear as possible. Consider creating duplicate keys that are grouped under a semantic section instead.