diff --git a/apps/website/docs/.vitepress/config.js b/apps/website/docs/.vitepress/config.js index 064fcb63..434d1350 100644 --- a/apps/website/docs/.vitepress/config.js +++ b/apps/website/docs/.vitepress/config.js @@ -56,6 +56,17 @@ export default defineConfig({ sidebar: { ...createSidebar('i18next', [ { text: 'Get Started', link: '/i18next/' }, + { + text: 'API', + items: [ + { text: '$t', link: '/i18next/t' }, + { text: 'translated', link: '/i18next/translated' }, + { text: '$isReady', link: '/i18next/is_ready' }, + { text: 'reporting', link: '/i18next/reporting' }, + { text: '$language', link: '/i18next/language' }, + { text: 'changeLanguageFx', link: '/i18next/change_language_fx' }, + ], + }, { text: 'Release policy', link: '/i18next/releases' }, ]), ...createSidebar('redux', [ diff --git a/apps/website/docs/i18next/change_language.md b/apps/website/docs/i18next/change_language.md new file mode 100644 index 00000000..a5262ac8 --- /dev/null +++ b/apps/website/docs/i18next/change_language.md @@ -0,0 +1,15 @@ +# `changeLanguageFx` + +An [_Effect_](https://effector.dev/en/api/effector/effect/) that can be called with a language code to change the current language. + +```ts +const { changeLanguageFx } = createI18nextIntegration({ + /* ... */ +}); + +sample({ + clock: someButtonClicked, + fn: () => 'en', + target: changeLanguageFx, +}); +``` diff --git a/apps/website/docs/i18next/index.md b/apps/website/docs/i18next/index.md index d54fb44a..dddc241f 100644 --- a/apps/website/docs/i18next/index.md +++ b/apps/website/docs/i18next/index.md @@ -1,7 +1,3 @@ ---- -outline: [2, 3] ---- - # i18next A powerful internationalization framework for Effector which is based on [i18next](https://www.i18next.com/). @@ -26,17 +22,19 @@ npm install @withease/i18next i18next ::: -## API - -### Initialization +## Initialization All you need to do is to create an integration by calling `createI18nextIntegration` with an integration options: -- `instance`: an instance of i18next or [_Store_](https://effector.dev/docs/api/effector/store) with i18next instance; it is better to pass a [_Store_](https://effector.dev/docs/api/effector/store) because it will be possible to use isolated i18next instance and [avoid using global state](/magazine/global_variables). +- `instance`: an instance of i18next in various forms. - `setup`: after this [_Event_](https://effector.dev/en/api/effector/event/) all listeners will be installed, and the integration will be ready to use; it is required because it is better to use [explicit initialization _Event_ in the application](/magazine/explicit_start). - `teardown?`: after this [_Event_](https://effector.dev/en/api/effector/event/) all listeners will be removed, and the integration will be ready to be destroyed. -```ts +### Use replaceable static `i18next` instance + +In the simplest case, you can pass an i18next instance to the integration. + +```ts{9-11} import i18next from 'i18next'; import { createStore, createEvent, fork, allSettled } from 'effector'; import { createI18nextIntegration } from '@withease/i18next'; @@ -45,7 +43,9 @@ import { createI18nextIntegration } from '@withease/i18next'; const appStarted = createEvent(); // Create Store for i18next instance -const $i18nextInstance = createStore(null); +const $i18nextInstance = createStore(i18next.createInstance(/* ... */), { + serialize: 'ignore', +}); const integration = createI18nextIntegration({ // Pass Store with i18next instance to the integration @@ -53,136 +53,80 @@ const integration = createI18nextIntegration({ setup: appStarted, }); -// You can fill $someInstance later during runtime +// You can replace $someInstance later during runtime // e.g., during fork on client or server - -const scope = fork({ - values: [[$i18nextInstance, i18next.createInstance(/* ... */)]], -}); - -await allSettled(appStarted, { scope }); ``` -### Usage - -Returned from `createI18nextIntegration` integration contains the following fields: - -#### `$t` - -A [_Store_](https://effector.dev/docs/api/effector/store) containing a [translation function](https://www.i18next.com/overview/api#t), can be used anywhere in your app. - -```ts -const { $t } = createI18nextIntegration({ - /* ... */ -}); - -const $someTranslatedString = $t.map((t) => t('cityPois.buttonText')); -``` +### Use replaceable asynchronous `i18next` instance -The second argument is an optional object with options for the translation function. +Sometimes you need to create an instance asynchronously. In this case, you can pass an [_Effect_](https://effector.dev/docs/api/effector/effect) that creates an instance. -```ts -const $city = createStore({ name: 'Moscow' }); +```ts{9-11} +import i18next from 'i18next'; +import { createStore, createEvent, fork, allSettled } from 'effector'; +import { createI18nextIntegration } from '@withease/i18next'; -const { $t } = createI18nextIntegration({ - /* ... */ -}); +// Event that should be called after application initialization +const appStarted = createEvent(); -const $someTranslatedString = combine({ city: $city, t: $t }, ({ city, t }) => - t('cityPois.buttonText', { - cityName: city.name, - }) +// Create Effect that creates i18next instance +const createI18nextFx = createEffect(() => + i18next.use(/* ... */).init(/* ... */) ); -``` - -In both cases, result will be a [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. It will be updated automatically when the language or available translations will be changed. - -#### `translated` - -A factory that returns [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. - -```ts -const { translated } = createI18nextIntegration({ - /* ... */ -}); - -const $someTranslatedString = translated('premiumLabel.BrandOne'); -``` - -The second argument is an optional object with options for the translation function. Options can be a [_Store_](https://effector.dev/docs/api/effector/store) or a plain value. - -```ts -const $city = createStore({ name: 'Moscow' }); -const { translated } = createI18nextIntegration({ - /* ... */ +const integration = createI18nextIntegration({ + // Pass Effect that creates i18next instance to the integration + instance: createI18nextFx, + setup: appStarted, }); -const $someTranslatedString = translated('cityPois.buttonText', { - cityName: $city.map((city) => city.name), -}); +// You can replace createI18nextFx later during runtime +// e.g., during fork on client or server ``` -Also, you can pass a template string with [_Store_](https://effector.dev/docs/api/effector/store) parts of a key: - -```ts -const $pathOfAKey = createStore('BrandOne'); - -const { translated } = createI18nextIntegration({ - /* ... */ -}); - -const $someTranslatedString = translated`premiumLabel.${$pathOfAKey}`; -``` +### Use static `i18next` instance -Result of the factory will be a [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. It will be updated automatically when the language or available translations will be changed. +Even though it is better to use a replaceable instance to [avoid global state](/magazine/global_variables) and make it possible to replace the instance during runtime, you can pass a static instance as well. -#### `$isReady` +```ts{9} +import i18next from 'i18next'; +import { createStore, createEvent } from 'effector'; +import { createI18nextIntegration } from '@withease/i18next'; -A [_Store_](https://effector.dev/docs/api/effector/store) containing a boolean value that indicates whether the integration is ready to use. +// Event that should be called after application initialization +const appStarted = createEvent(); -```ts -const { $isReady } = createI18nextIntegration({ - /* ... */ +const integration = createI18nextIntegration({ + instance: i18next.createInstance(/* ... */), + setup: appStarted, }); ``` -#### `$language` +### Use static asynchronous `i18next` instance -A [_Store_](https://effector.dev/docs/api/effector/store) containing the current language. +The same approach can be used with an asynchronous instance. -```ts -const { $language } = createI18nextIntegration({ - /* ... */ -}); -``` - -#### `changeLanguageFx` - -An [_Effect_](https://effector.dev/en/api/effector/effect/) that can be called with a language code to change the current language. +```ts{9} +import i18next from 'i18next'; +import { createStore, createEvent } from 'effector'; +import { createI18nextIntegration } from '@withease/i18next'; -```ts -const { changeLanguageFx } = createI18nextIntegration({ - /* ... */ -}); +// Event that should be called after application initialization +const appStarted = createEvent(); -sample({ - clock: someButtonClicked, - fn: () => 'en', - target: changeLanguageFx, +const integration = createI18nextIntegration({ + instance: () => i18next.use(/* ... */).init(/* ... */), + setup: appStarted, }); ``` -#### `reporting` - -An object with the following fields: - -- `missingKey`, [_Event_](https://effector.dev/en/api/effector/event/) will be triggered when a key is missing in the translation resources, requires [adding `saveMissing` option to the i18next instance](https://www.i18next.com/overview/api#onmissingkey). +## Usage -```ts -const { reporting } = createI18nextIntegration({ - /* ... */ -}); +Returned from `createI18nextIntegration` integration contains the following fields: -sample({ clock: reporting.missingKey, target: sendWarningToSentry }); -``` +- [`$t`](/i18next/t) is a [_Store_](https://effector.dev/docs/api/effector/store) containing a [translation function](https://www.i18next.com/overview/api#t) +- [`translated`](/i18next/translated) which can be used as a shorthand for `$t` +- [`$isReady`](/i18next/is_ready) is a [_Store_](https://effector.dev/docs/api/effector/store) containing a boolean value that indicates whether the integration is ready to use +- [`reporting`](/i18next/reporting) is an object with the fields that allow you to track different events of the integration +- [`$language`](/i18next/language) is a [_Store_](https://effector.dev/docs/api/effector/store) containing the current language +- [`changeLanguageFx`](/i18next/change_language) is an [_Effect_](https://effector.dev/docs/api/effector/effect) that changes the current language diff --git a/apps/website/docs/i18next/is_ready.md b/apps/website/docs/i18next/is_ready.md new file mode 100644 index 00000000..598eb89f --- /dev/null +++ b/apps/website/docs/i18next/is_ready.md @@ -0,0 +1,9 @@ +# `$isReady` + +A [_Store_](https://effector.dev/docs/api/effector/store) containing a boolean value that indicates whether the integration is ready to use. + +```ts +const { $isReady } = createI18nextIntegration({ + /* ... */ +}); +``` diff --git a/apps/website/docs/i18next/language.md b/apps/website/docs/i18next/language.md new file mode 100644 index 00000000..bf660d5a --- /dev/null +++ b/apps/website/docs/i18next/language.md @@ -0,0 +1,9 @@ +# `$language` + +A [_Store_](https://effector.dev/docs/api/effector/store) containing the current language. + +```ts +const { $language } = createI18nextIntegration({ + /* ... */ +}); +``` diff --git a/apps/website/docs/i18next/reporting.md b/apps/website/docs/i18next/reporting.md new file mode 100644 index 00000000..f356f0ed --- /dev/null +++ b/apps/website/docs/i18next/reporting.md @@ -0,0 +1,13 @@ +# `reporting` + +An object with the following fields: + +- `missingKey`, [_Event_](https://effector.dev/en/api/effector/event/) will be triggered when a key is missing in the translation resources, requires [adding `saveMissing` option to the i18next instance](https://www.i18next.com/overview/api#onmissingkey). + +```ts +const { reporting } = createI18nextIntegration({ + /* ... */ +}); + +sample({ clock: reporting.missingKey, target: sendWarningToSentry }); +``` diff --git a/apps/website/docs/i18next/t.md b/apps/website/docs/i18next/t.md new file mode 100644 index 00000000..1e8615dc --- /dev/null +++ b/apps/website/docs/i18next/t.md @@ -0,0 +1,29 @@ +# `$t` + +A [_Store_](https://effector.dev/docs/api/effector/store) containing a [translation function](https://www.i18next.com/overview/api#t), can be used anywhere in your app. + +```ts +const { $t } = createI18nextIntegration({ + /* ... */ +}); + +const $someTranslatedString = $t.map((t) => t('cityPois.buttonText')); +``` + +The second argument is an optional object with options for the translation function. + +```ts +const $city = createStore({ name: 'Moscow' }); + +const { $t } = createI18nextIntegration({ + /* ... */ +}); + +const $someTranslatedString = combine({ city: $city, t: $t }, ({ city, t }) => + t('cityPois.buttonText', { + cityName: city.name, + }) +); +``` + +In both cases, result will be a [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. It will be updated automatically when the language or available translations will be changed. diff --git a/apps/website/docs/i18next/translated.md b/apps/website/docs/i18next/translated.md new file mode 100644 index 00000000..ea3173de --- /dev/null +++ b/apps/website/docs/i18next/translated.md @@ -0,0 +1,39 @@ +# `translated` + +A factory that returns [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. + +```ts +const { translated } = createI18nextIntegration({ + /* ... */ +}); + +const $someTranslatedString = translated('premiumLabel.BrandOne'); +``` + +The second argument is an optional object with options for the translation function. Options can be a [_Store_](https://effector.dev/docs/api/effector/store) or a plain value. + +```ts +const $city = createStore({ name: 'Moscow' }); + +const { translated } = createI18nextIntegration({ + /* ... */ +}); + +const $someTranslatedString = translated('cityPois.buttonText', { + cityName: $city.map((city) => city.name), +}); +``` + +Also, you can pass a template string with [_Store_](https://effector.dev/docs/api/effector/store) parts of a key: + +```ts +const $pathOfAKey = createStore('BrandOne'); + +const { translated } = createI18nextIntegration({ + /* ... */ +}); + +const $someTranslatedString = translated`premiumLabel.${$pathOfAKey}`; +``` + +Result of the factory will be a [_Store_](https://effector.dev/docs/api/effector/store) containing a translated string. It will be updated automatically when the language or available translations will be changed.