diff --git a/website/docs/guides/custom-extractor.md b/website/docs/guides/custom-extractor.md index 05a9e8b20..162bf637e 100644 --- a/website/docs/guides/custom-extractor.md +++ b/website/docs/guides/custom-extractor.md @@ -5,21 +5,19 @@ description: Learn how to write a custom message extractor for your project # Custom Extractor -## Supported Syntax of the Default Extractor +Lingui's default extractor supports JavaScript (Stage 3), TypeScript, and Flow out of the box, covering most standard and modern syntax features. However, if your project relies on experimental ECMAScript syntax or custom file formats, a custom extractor gives you the flexibility to handle these scenarios. -The default extractor supports **TypeScript**, **Flow**, and **JavaScript** (Stage 3) out of the box. It does **not** intentionally use your project's Babel configuration. +### Why It Doesn't Use Your Babel Config? -### Why doesn't it use the project's Babel config? +Babel plugins from your configuration define transformations, and some of these may interfere with or slow down the extraction process. The extractor doesn't have to transform your code, it just analyzes it. Therefore, it's designed to understand different syntax without worrying about how the code is transpiled or down-levelled. -Babel plugins from your configuration define transformations, and some of these may interfere with or slow down the extraction process. The extractor doesn't need to transform your code; it only analyzes it. Therefore, it's designed to understand different syntax without concern for how the code is transpiled or down-leveled. - -We continually update the extractor to stay in line with the latest ECMAScript features. However, if you find that a recently added Stage 3 feature isn't working as expected, please [create an issue](https://github.com/lingui/js-lingui/issues/new/choose). - -## Supporting Experimental ECMAScript Syntax (Stage 0 - Stage 2) +:::info +We are constantly updating the extractor to keep up with the latest ECMAScript features. However, if you find that a recently added Stage 3 feature doesn't work as expected, please [create an issue](https://github.com/lingui/js-lingui/issues/new/choose). +::: -If you use experimental features (Stage 0 - Stage 2), you'll need to configure a custom list of parser plugins. This can be done by overriding the default extractor and using the `extractFromFileWithBabel()` function. +## Experimental ECMAScript Syntax -### Example: Configuring Parser Plugins +If you are using experimental features (Stage 0 - Stage 2), you'll need to configure a custom list of parser plugins. This can be done by overriding the default extractor and using the `extractFromFileWithBabel()` function: ```ts title="lingui.config.ts" import { extractFromFileWithBabel } from "@lingui/cli/api"; @@ -60,11 +58,9 @@ const config: LinguiConfig = { export default config; ``` -## Supporting Other Frameworks or Custom Syntax +## Other Frameworks or Custom Syntax -If you're working with files that aren't valid JavaScript, you can create a custom extractor to handle them. - -### Example: Custom Extractor Implementation +If you're working with files that aren't valid JavaScript, you can create a custom extractor to handle them: ```ts title="./my-custom-extractor.ts" import { extractor as defaultExtractor } from "@lingui/cli/api"; @@ -87,9 +83,11 @@ export const extractor: ExtractorType = { }; ``` -### Adding the Custom Extractor to Your Configuration +### Adding the Custom Extractor to the Configuration -```ts title="lingui.config.ts" +To use the custom extractor, you need to add it to your Lingui configuration file: + +```ts title="lingui.config.ts" {1,6} import { extractor } from "./my-custom-extractor.ts"; import { LinguiConfig } from "@lingui/conf"; @@ -102,5 +100,5 @@ export default config; ``` :::caution Important -If you're using TypeScript to create your extractor, ensure that your Lingui configuration file has the `.ts` extension. +If you are using TypeScript to create your extractor, you should use the `.ts` extension for your Lingui configuration file. ::: diff --git a/website/docs/guides/custom-formatter.md b/website/docs/guides/custom-formatter.md index 3dcced19a..566104096 100644 --- a/website/docs/guides/custom-formatter.md +++ b/website/docs/guides/custom-formatter.md @@ -5,24 +5,28 @@ description: Learn how to write a custom localization message formatter for your # Custom Formatter -If your project requires some special format or handling logic, you can write your own format implementation. +If your project requires a message catalog format that Lingui doesn't [natively support](/docs/ref/catalog-formats.md), you can create a custom formatter to handle it. A custom formatter allows you to define how extracted strings are formatted into a custom catalog format, providing flexibility for specialized workflows and integration with unique file structures. -Formatter is a simple object with 2 main functions `parse` and `serialize`, which should take Lingui catalog and serialize it to string and vice versa. +## Overview -You don't need to create a separate package for formatter, you can write it directly in `lingui.config.{ts,js}`. +A formatter is an object with two main functions, `parse` and `serialize`, which define how catalogs are read from and written to your custom format. + +The formatter can be configured directly in your `lingui.config.{ts,js}` file - no separate package is needed: ```ts title="lingui.config.{ts,js}" -import { extractor } from './my-custom-extractor.ts' +import { extractor } from "./my-custom-extractor.ts"; module.exports = { - [...] + // [...] format: { catalogExtension: "json", parse: (content: string): CatalogType => JSON.parse(content), serialize: (catalog: CatalogType): string => JSON.stringify(catalog), - } -} + }, +}; ``` +## Reference + The shape of formatter is the following: ```ts @@ -70,5 +74,5 @@ export type MessageType = { ``` :::caution Important -If you are using TypeScript to build your formatter, you should use the `ts` extension for your Lingui configuration file. +If you are using TypeScript to create your formatter, you should use the `.ts` extension for your Lingui configuration file. ::: diff --git a/website/docs/ref/catalog-formats.md b/website/docs/ref/catalog-formats.md index ceb1707de..1fa7300e7 100644 --- a/website/docs/ref/catalog-formats.md +++ b/website/docs/ref/catalog-formats.md @@ -77,14 +77,26 @@ msgid "msg.inbox" msgstr "Message Inbox" ``` -Messages with plurals are exported in ICU format: +Messages with plurals are exported in [ICU MessageFormat](/docs/guides/message-format.md): ```po msgid "{count, plural, one {Message} other {Messages}}" msgstr "{count, plural, one {Message} other {Messages}}" ``` -Read more about [ICU MessageFormat](/docs/guides/message-format.md). +Messages with placeholders: + +```js +t`Hello ${user.name} ${value}`; +``` + +are exported as: + +```po +#. placeholder {0}: user.name +msgid "Hello {0} {value}" +msgstr "Hello {0} {value}" +``` ## PO with gettext Plurals {#po-gettext} diff --git a/website/docs/ref/cli.md b/website/docs/ref/cli.md index 3e8d959e3..23c018efe 100644 --- a/website/docs/ref/cli.md +++ b/website/docs/ref/cli.md @@ -5,7 +5,7 @@ description: Learn how to set up and use Lingui CLI to extract, merge and compil # Lingui CLI -The `@lingui/cli` tool provides the `lingui` command, which allows the extraction of messages from source files into message catalogs and the compilation of message catalogs for production use. +The `@lingui/cli` tool provides the `lingui` command which allows you to extract messages from source files into message catalogs and compile these catalogs for production use. ## Installation @@ -39,11 +39,11 @@ If you use TypeScript, you can add the `--typescript` flag to the `compile` scri ::: -## Global options +## Global Options ### `--config ` -Path to the configuration file. If not set, the default file is loaded as described in the [Lingui configuration](/docs/ref/conf.md) reference. +Path to the configuration file. If not set, the default file is loaded as described in the [Configuration](/docs/ref/conf.md) reference. ## Commands @@ -60,30 +60,30 @@ lingui extract [files...] [--watch [--debounce ]] ``` -The `extract` command looks for messages in the source files and extracts them +The `extract` command scans source files to locate and extract messages, generating separate message catalogs for each language. -This command scans the source files, identifies messages, and creates a separate message catalog for each language. The process includes the following steps: +This process involves: -1. Extract messages from files based on the `include` and `exclude` options in the [`catalogs`](/docs/ref/conf.md#catalogs) section of the configuration file. -2. Merge them with existing message catalogs (if any) -3. Write updated message catalogs. -4. Print statistics about the extracted messages for each language, showing the total number of messages and the number of missing translations. +1. Extracting messages from files based on the `include` and `exclude` settings in the [`catalogs`](/docs/ref/conf.md#catalogs) section of the configuration file. +2. Merging the newly extracted messages with any existing message catalogs. +3. Updating and saving the message catalogs. +4. Printing extraction statistics for each language, including the total number of messages and any missing translations. :::tip -Visit the [Message Extraction](/docs/guides/message-extraction.md) guide to learn more about how it works. +Refer to the [Message Extraction](/docs/guides/message-extraction.md) guide to learn more about this process and the options available. ::: #### `files` {#extract-files} -Filters source paths to only extract messages from passed files. For ex: +Filter source paths to extract messages only from specific files. For example: ```shell lingui extract src/components ``` -Will only extract messages from `src/components/**/*` files, you can pass multiple paths. +This command extracts messages from files within the `src/components/**/*` path. You can also pass multiple paths for extraction. -It's useful if you want to run the extract command on files that are staged, for example using `husky`, before committing will extract messages from staged files: +This feature is useful when you want to extract messages from files that are staged for commit. For example, you can use husky to automatically extract messages from staged files before committing: ```json title="package.json" { @@ -97,9 +97,9 @@ It's useful if you want to run the extract command on files that are staged, for #### `--clean` {#extract-clean} -By default, the `extract` command merges messages extracted from source files with the existing message catalogs. This is safe as we won't accidentally lose translated messages. +By default, the extract command merges messages extracted from source files with existing message catalogs, ensuring that translated messages are preserved and not accidentally lost. -However, over time, some messages may be removed from the source code. We can use this option to clean up our message catalogs from obsolete messages. +However, over time, some messages may be removed from the source code. You can use the following option to clean up your message catalogs and remove obsolete messages. #### `--overwrite` {#extract-overwrite} @@ -119,15 +119,15 @@ Convert message catalogs from the previous format (see the [`format`](/docs/ref/ #### `--verbose` {#extract-verbose} -Prints additional information. +Print additional information. #### `--watch` {#extract-watch} -Watch mode. Only watches for changes in files in paths defined in the config file or in the command itself. Remember to use this only in development, as this command does not clean up obsolete translations. +Enable watch mode to monitor changes in files located in the paths specified in the configuration file or in the command itself. Note that this feature is intended for development use only, as it does not remove obsolete translations. #### `--debounce ` {#extract-debounce} -Delays the extraction by `` milliseconds, bundling multiple file changes together. +Delay the extraction by `` milliseconds, bundling multiple file changes together. ### `extract-template` @@ -135,11 +135,13 @@ Delays the extraction by `` milliseconds, bundling multiple file changes lingui extract-template [--verbose] ``` -This command extracts messages from source files and creates a `.pot` template file. Any artifacts created by this command may be ignored in version control. If your message catalogs are not synchronized with the source and don't contain some messages, the application will fall back to the template file. This command is useful to run before building the application. +This command extracts messages from your source files and generates a `.pot` template file. Any artifacts created by this command can be safely ignored in version control. + +If your message catalogs are not synchronized with the source and some messages are missing, the application will fallback to the template file. Running this command before building the application is recommended to ensure all messages are accounted for. #### `--verbose` {#extract-template-verbose} -Prints additional information. +Print additional information. ### `compile` @@ -153,7 +155,7 @@ lingui compile [--watch [--debounce ]] ``` -Once we have all the catalogs ready and translated, we can use this command to compile all the catalogs into minified JS/TS files. It compiles message catalogs in the [`path`](/docs/ref/conf.md#catalogs) directory and outputs minified JavaScript files. The resulting file is basically a string that is parsed into a plain JS object using `JSON.parse`. +Once you have all the catalogs ready and translated, you can use this command to compile all the catalogs into minified JS/TS files. It compiles message catalogs located in the [`path`](/docs/ref/conf.md#catalogs) directory and generates minified JavaScript files. The resulting file is a string that is parsed into a plain JS object using `JSON.parse`. The output looks like this: @@ -165,10 +167,10 @@ export const messages = JSON.parse(`{ Messages added to the compiled file are collected in a specific order: -1. Translated messages from the specified locale. -2. Translated messages from the fallback locale for the specified locale. -3. Translated message from default fallback locale. -4. Message key. +1. Translated messages from the specified locale. +2. Translated messages from the fallback locale for the specified locale. +3. Translated message from default fallback locale. +4. Message key. It is also possible to merge the translated catalogs into a single file per locale by specifying [`catalogsMergePath`](/docs/ref/conf.md#catalogsmergepath) in the configuration. @@ -195,7 +197,7 @@ Format of message catalogs (see the [`format`](/docs/ref/conf.md#format) option #### `--verbose` {#compile-verbose} -Prints additional information. +Print additional information. #### `--namespace` {#compile-namespace} @@ -213,9 +215,9 @@ Watch mode. Watches only for changes in locale files in your defined locale cata Delays compilation by `` milliseconds to avoid multiple compilations for subsequent file changes. -## Configuring the source locale +## Configuring the Source Locale -One drawback to checking for missing translations is that the English message catalog doesn't need translations because our source code is in English. This can be addressed by configuring the [`sourceLocale`](/docs/ref/conf.md#sourcelocale) in the configuration file. +One limitation of checking for missing translations is that the English message catalog typically does not require translations since our source code is in English. This issue can be resolved by configuring the [`sourceLocale`](/docs/ref/conf.md#sourcelocale) in the configuration file. ## Compiling Catalogs in CI {#compiling-catalogs-in-ci} diff --git a/website/docs/ref/conf.md b/website/docs/ref/conf.md index 7cbd86f46..8af080507 100644 --- a/website/docs/ref/conf.md +++ b/website/docs/ref/conf.md @@ -19,7 +19,7 @@ In the case of TypeScript-based config you can use ESM format and _export defaul ## catalogs -Default: +Default value: ```js [ @@ -31,16 +31,15 @@ Default: ]; ``` -Defines location of message catalogs and what files are included when [`extract`](/docs/ref/cli.md#extract) is scanning for messages. +The `catalogs` configuration defines the location of message catalogs and specifies which files are included when the [`extract`](/docs/ref/cli.md#extract) command scans for messages. -`path` shouldn't end with slash and it shouldn't include file extension which depends on [`format`](/docs/ref/catalog-formats.md). -`{locale}` token is replaced by catalog locale. +- `path`: the directory where the message catalogs are located. It should not end with a slash and must not include a file extension, which depends on the [`format`](#format) configuration. The `{locale}` token will be replaced by the catalog's locale. +- `include` and `exclude`: these patterns specify which files to include or exclude during the extraction process. They are passed to [minimatch](https://github.com/isaacs/minimatch) for pattern matching. +- [``](#rootdir): represents the root directory of the project. It is replaced with the actual root directory when the configuration is loaded. By default, [``](#rootdir) represents the configuration file's location. -Patterns in `include` and `exclude` are passed to [minimatch](https://github.com/isaacs/minimatch). +The `path`, `include`, and `exclude` patterns are interpreted relative to the current process CWD (current working directory). -`path`, `include`, and `exclude` are interpreted from the current process CWD. If you want to make these paths relative to the configuration file, you can prefix them with a [`rootDir`](#rootdir) token. By default, [`rootDir`](#rootdir) represents the configuration file's location. - -`{name}` token in `path` is replaced with a catalog name. Source path must include `{name}` pattern as well and it works as a `*` glob pattern: +The `{name}` token in the `path` will be replaced with the catalog name. Be sure to include the `{name}` pattern in the source path as well, as it acts like a `*` glob pattern: ```json { @@ -87,7 +86,7 @@ locales/ } ``` -```bash +```bash {3,5} locales ├── en/ │ └── messages.po @@ -95,7 +94,7 @@ locales └── messages.po ``` -#### Separate catalogs per component, placed inside component dir +#### Separate catalogs per component, placed inside component directory ```json { @@ -108,7 +107,7 @@ locales } ``` -```shell +```shell {4,5,10,11} components/ ├── RegistrationForm/ │ ├── locale/ @@ -137,7 +136,7 @@ components/ } ``` -```shell +```shell {4,5,7,8} . ├── locale/ │ ├── en/ @@ -155,17 +154,82 @@ components/ └── LoginForm.js ``` +## locales + +Default value: `[]` + +The locale tags used in the project. The [`extract`](/docs/ref/cli.md#extract) and [`compile`](/docs/ref/cli.md#compile) commands write a catalog for each locale specified. Each locale should be a valid [BCP-47 code](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html): + +```json +{ + "locales": ["en", "cs"] +} +``` + +## fallbackLocales + +Default value: `{}` + +Translations from `fallbackLocales` are used if the translation for the given locale is missing. It uses [CLDR Parent Locales](https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/parentLocales.json) by default, unless you override it with a `false` to use the default message or message ID instead: + +```json +{ + "fallbackLocales": false +} +``` + +The `fallbackLocales` object allows to configure fallback locales for each locale instance: + +```json +{ + "fallbackLocales": { + "en-US": ["en-GB", "en"], + "es-MX": "es" + } +} +``` + +In this example, if any translation isn't found on `en-US`, then it will search on `en-GB`, after that if not found we'll search in `en`. + +it's also possible to configure a `default` fallback locale for all locales: + +```json {5} +{ + "fallbackLocales": { + "en-US": ["en-GB", "en"], + "es-MX": "es", + "default": "en" + } +} +``` + +## sourceLocale + +Default value: `""` + +`sourceLocale` specifies the default language of message IDs in your source files. The catalog for `sourceLocale` doesn't need actual translations since message IDs are used as-is by default. However, you can still override any message ID by providing a custom translation. + +The main difference between `sourceLocale` and [`fallbackLocales`](#fallbacklocales) is their purpose: `sourceLocale` defines the language used for message IDs, while `fallbackLocales` provides alternative translations when specific messages are missing for a particular locale. + +## pseudoLocale + +Default value: `""` + +Locale used for pseudolocalization. For example, when you set `pseudoLocale: "en"`, all messages in the `en` catalog will be pseudo-localized. The locale must be included in the `locales` config. + +Read more about [Pseudolocalization](/docs/guides/pseudolocalization.md). + ## catalogsMergePath -Default: `""` +Default value: `""` -Specify the path to merge translated catalogs into a single file per locale during compile. +Define the path where translated catalogs are merged into a single file per locale during the [`compile`](/docs/ref/cli.md#compile) process. #### Example -Let's assume we have [separate catalogs for `locales: ["en", "cs"]` per component placed inside shared directory](#separate-catalogs-per-component-placed-inside-shared-directory). +Let's assume we have [separate catalogs per component, placed inside shared directory](#separate-catalogs-per-component-placed-inside-shared-directory). -Using `catalogsMergePath`, separate catalogs can be merged during [`compile`](/docs/ref/cli.md#compile): +Using the `catalogsMergePath`, separate catalogs can be merged into a single file: ```diff { @@ -206,7 +270,7 @@ Using `catalogsMergePath`, separate catalogs can be merged during [`compile`](/d ## compileNamespace -Default: `cjs` +Default value: `cjs` Specify namespace for exporting compiled messages. See [`compile`](/docs/ref/cli.md#compile) command. @@ -228,7 +292,7 @@ Use ES6 named export: #### ts -Use ES6 named export + .ts file with an additional `{compiledFile}.d.ts` file: +Use ES6 named export + `.ts` file with an additional `{compiledFile}.d.ts` file: ```js /* eslint-disable */export const messages = {"..."} @@ -258,7 +322,7 @@ For example, setting [`compileNamespace`](#compilenamespace) to `window.i18n` cr ## extractorParserOptions -Default: `{}` +Default value: `{}` Specify additional options used to parse source files when extracting messages. @@ -273,19 +337,19 @@ Specify additional options used to parse source files when extracting messages. #### tsExperimentalDecorators -Default: `false` +Default value: `false` By default, standard decorators (Stage3) are applied to TS files. Enable this if you want to use TypeScript's experimental decorators. #### flow -Default: `false` +Default value: `false` Lingui does not ship with [Flow](https://flow.org/) typing. However, you can use Lingui in projects written in Flow. Enable this option to tell the extractor that your sources use Flow syntax. ## compilerBabelOptions -Default: +Default value: ```json { @@ -310,50 +374,9 @@ Specify extra babel options used to generate files when messages are being compi This example configuration will compile with escaped ASCII characters ([jsesc#minimal](https://github.com/mathiasbynens/jsesc#minimal)). -## fallbackLocales - -Default: `{}` - -`fallbackLocales` by default is using [CLDR Parent Locales](https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/parentLocales.json), unless you disable it with a `false`: - -```json -{ - "fallbackLocales": false -} -``` - -`fallbackLocales` object lets us configure fallback locales to each locale instance. - -```json -{ - "fallbackLocales": { - "en-US": ["en-GB", "en"], - "es-MX": "es" - } -} -``` - -On this example if any translation isn't found on `en-US` then will search on `en-GB`, after that if not found we'll search in `en`. - -Also, we can configure a default one for everything: - -```json -{ - "fallbackLocales": { - "en-US": ["en-GB", "en"], - "es-MX": "es", - "default": "en" - } -} -``` - -Translations from `fallbackLocales` is used when translation for given locale is missing. - -If `fallbackLocales` is `false` default message or message ID is used instead. - ## format -Default: `po` +Default value: `po` Message catalog format. The `po` formatter is used by default. Other formatters are available as separate packages. @@ -368,15 +391,9 @@ export default { Read more about available formatters in [Catalog Formats](/docs/ref/catalog-formats.md) or create your own [Custom Formatter](/docs/guides/custom-formatter.md). -## locales - -Default: `[]` - -Locale tags which are used in the project. [`extract`](/docs/ref/cli.md#extract) and [`compile`](/docs/ref/cli.md#compile) writes one catalog for each locale. Each locale should be a valid [BCP-47 code](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html). - ## orderBy -Default: `message` +Default value: `message` Order of messages in catalog: @@ -392,68 +409,64 @@ Sort by the message ID, `js-lingui-id` will be used if no custom id provided. Sort by message origin (e.g. `App.js:3`) -## pseudoLocale - -Default: `""` - -Locale used for pseudolocalization. For example when you set `pseudoLocale: "en"` then all messages in `en` catalog will be pseudo localized. The locale has to be included in `locales` config. - ## rootDir -Default: The root of the directory containing your Lingui config file or the `package.json`. +Default: The root of the directory containing your Lingui configuration file or the `package.json`. -The root directory that Lingui CLI should scan when extracting messages from source files. +This is the directory where the Lingui CLI scans for messages in your source files during the extraction process. Note that using `` as a string token in any other path-based config settings will refer back to this value. ## runtimeConfigModule -Default: `["@lingui/core", "i18n"]` +Default value: `["@lingui/core", "i18n"]` -Module path with exported i18n object. The first value in array is module path, the second is the import identifier. This value is used in macros, which need to reference the global `i18n` object. +This setting specifies the module path for the exported `i18n` object. The first value in the array is the module path, and the second is the name of the import. This configuration is essential for [macros](/docs/ref/macro.mdx) that need to reference the global `i18n` object. You only need to set this value if you use custom object created using [`setupI18n`](/docs/ref/core.md#setupi18n): +For example, if you have a custom module that exports the `i18n` object: + ```jsx -// If you import `i18n` object from custom module like this: import { i18n } from "./custom-i18n-config"; +``` -// ... then add following line to Lingui configuration: -// "runtimeConfigModule": ["./custom-i18n-config", "i18n"] +```json +{ + "runtimeConfigModule": ["./custom-i18n-config", "i18n"] +} ``` You may use a different named export: ```jsx import { myI18n } from "./custom-i18n-config"; -// "runtimeConfigModule": ["./custom-i18n-config", "myI18n"] ``` -In some advanced cases you may also need to change the module from which [Trans](/docs/ref/macro.mdx#trans) or [useLingui](/docs/ref/macro.mdx#uselingui) is imported. To do that, pass an object to `runtimeConfigModule`: - -```jsx -// If you import `i18n` object from custom module like this: -import { Trans, i18n } from "./custom-config"; - -// ... then add following line to Lingui configuration: -// "runtimeConfigModule": { -// i18n: ["./custom-config", "i18n"], -// Trans: ["./custom-config", "Trans"] -// useLingui: ["./custom-useLingui", "myUseLingui"] -// } +```json +{ + "runtimeConfigModule": ["./custom-i18n-config", "myI18n"] +} ``` -## sourceLocale - -Default: `''` +In more advanced scenarios, you may need to change the module from which the [`Trans`](/docs/ref/macro.mdx#trans) or [`useLingui`](/docs/ref/macro.mdx#uselingui) macros are imported: -Locale of message IDs, which is used in source files. Catalog for `sourceLocale` doesn't require translated messages, because message IDs are used by default. However, it's still possible to override message ID by providing custom translation. +```jsx +import { Trans, useLingui } from "./custom-config"; +``` -The difference between [`fallbackLocales`](#fallbacklocales) and `sourceLocale` is that [`fallbackLocales`](#fallbacklocales) is used in translation, while `sourceLocale` is used for the message ID. +```json +{ + "runtimeConfigModule": { + "Trans": ["./custom-config", "Trans"], + "useLingui": ["./custom-config", "useLingui"] + } +} +``` ## extractors -Default: `[babel]` +Default value: `[babel]` Extractors it's the way to customize which extractor you want for your codebase. @@ -465,4 +478,4 @@ Extractors it's the way to customize which extractor you want for your codebase. } ``` -Visit [Advanced: Custom Extractor](/docs/guides/custom-extractor.md) to learn how to create a custom extractor. +See the [Custom Extractor](/docs/guides/custom-extractor.md) guide for instructions on creating your own extractor. diff --git a/website/docs/ref/core.md b/website/docs/ref/core.md index 2bbbc8f6d..e76601487 100644 --- a/website/docs/ref/core.md +++ b/website/docs/ref/core.md @@ -15,14 +15,14 @@ npm install --save @lingui/core ## Overview -`@lingui/core` package exports the global instance of `i18n` object. Simply import it and use it: +The `@lingui/core` package provides a global instance of the `i18n` object, which you can import and use directly: ```ts import { i18n } from "@lingui/core"; /** - * Load messages for requested locale and activate it. - * This function isn't part of the LinguiJS library because there are + * Load messages for the requested locale and activate it. + * This function isn't part of the Lingui because there are * many ways how to load messages — from REST API, from file, from cache, etc. */ async function activate(locale: string) { @@ -36,29 +36,21 @@ activate("cs"); const translation = i18n._("Hello World"); ``` -If you don't want to use the global `i18n` instance and you want to setup your own, you can use [`setupI18n`](#setupi18n) method. You also need to set [`runtimeConfigModule`](/docs/ref/conf.md#runtimeconfigmodule) for macros to work correctly: - -```ts -// If you import `i18n` object from custom module like this: -import { i18n } from "./custom-i18n-config"; - -// ... then add following line to your Lingui configuration: -// "runtimeConfigModule": ["./custom-i18n-config", "i18n"] -``` - -## Reference +:::info Advanced +If you prefer not to use the global `i18n` instance and want to set up your own, you can utilize the [`setupI18n`](#setupi18n) method. Additionally, you'll need to configure the [`runtimeConfigModule`](/docs/ref/conf.md#runtimeconfigmodule) to ensure that macros work properly. +::: -### Class `i18n()` {#i18n} +## Class `i18n()` {#i18n} ### `i18n.loadAndActivate(options)` {#i18n.loadAndActivate} -`options` is an object with following properties: +The `options` parameter is an object with the following properties: -- `locale`: initial active locale -- `locales`: list of alternative locales (BCP 47 language tags) which are used for number and date formatting -- `messages`: **compiled** message catalog +- `locale`: The initial active locale. +- `locales`: A list of alternative locales ([BCP-47](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) language tags) used for number and date formatting. +- `messages`: The **compiled** message catalog. -Sets (overwrites) the catalog for given locale and activates the locale. +It allows to set (overwrite) the catalog for a given locale and activate the locale: ```ts import { i18n } from "@lingui/core"; @@ -78,13 +70,13 @@ When some messages for the provided locale are already loaded, calling `i18n.loa ```ts import { i18n } from "@lingui/core"; +/** + * This is just an example of what the catalog looks like internally. + * Formatting of string messages only works in development. See note below. + */ const messagesEn = { Hello: "Hello", "Good bye": "Good bye", - - // Just an example how catalog looks internally. - // Formatting of string messages works in development only. - // See note below. "My name is {name}": "My name is {name}", }; @@ -94,10 +86,12 @@ const messagesCs = { "My name is {name}": "Jmenuji se {name}", }; +// highlight-start i18n.load({ en: messagesEn, cs: messagesCs, }); +// highlight-end // This is the same as loading message catalogs separately per language: // i18n.load('en', messagesEn) @@ -105,14 +99,11 @@ i18n.load({ ``` :::tip +Don't write catalogs manually. The code above is an example of message catalogs. In real applications, messages are loaded from external message catalogs generated by the [`compile`](/docs/ref/cli.md#compile) command or by using tools such as [Vite Plugin](/docs/ref/vite-plugin.md), [Webpack Loader](/docs/ref/loader.md), or [Metro Transformer](/docs/ref/metro-transformer.mdx). -Don't write catalogs manually. - -Code above contains an example of message catalogs. In real applications, messages are loaded from external message catalogs generated by [`compile`](/docs/ref/cli.md#compile) command. +Formatting of messages as strings (e.g: `"My name is {name}"`) works in development only, when messages are parsed on the fly. In production, however, messages must be compiled using the [`compile`](/docs/ref/cli.md#compile) command. -Formatting of messages as strings (e.g: `"My name is {name}"`) works in development only, when messages are parsed on the fly. In production, however, messages must be compiled using [`compile`](/docs/ref/cli.md#compile) command. - -The same example would in real application look like this: +Here's how the same example would look in a real application: ```ts import { i18n } from "@lingui/core"; @@ -143,7 +134,7 @@ i18n.setMessagesCompiler(compileMessage); ### `i18n.activate(locale[, locales])` {#i18n.activate} -Activate a locale and locales. From now on, calling `i18n._` will return messages in given locale. +Activate the specified locale and any alternate locales. After calling this method, calling `i18n._` will return messages in the activated locale. ```ts import { i18n } from "@lingui/core"; @@ -159,11 +150,9 @@ i18n._("Hello"); // Return "Hello" in Czech The core method for translating and formatting messages. -`messageId` is a unique message ID which identifies message in catalog. - -`values` is an object of variables used in translated message. - -`options.message` is the default translation (optional). This is mostly used when application doesn't use message IDs in natural language (e.g.: `msg.id` or `Component.title`). +- `messageId`: a unique message ID which identifies message in catalog. +- `values`: an object containing variables used in translated message. +- `options.message`: the default translation (optional). This is mostly used when application doesn't use message IDs in natural language (e.g.: `msg.id` or `Component.title`). ```ts import { i18n } from "@lingui/core"; @@ -180,7 +169,7 @@ i18n._("msg.id", { name: "Tom" }, { message: "My name is {name}" }); ### `i18n._(messageDescriptor)` -`messageDescriptor` is an object of message parameters. +`messageDescriptor` is an object with a message ID, default message and other parameters. It's useful when you need to use the declared message later in the code. ```ts import { i18n } from "@lingui/core"; @@ -203,30 +192,24 @@ i18n._({ }); ``` +Read more about [Message Descriptor](/docs/ref/macro.mdx#core-macros). + ### `i18n.t(...)` {#i18n.t} -Alias for [`i18n._`](#i18n._) +Alias for [`i18n._`](#i18n._). ```ts import { i18n } from "@lingui/core"; -i18n.t({ - id: "msg.name", - message: "My name is {name}", - comment: "Message showing the passed in name", - values: { name: "Tom" }, -}); - -i18n.t("msg.id", { name: "Tom" }, { message: "My name is {name}" }); +i18n.t({ id: "Hello" }); ``` ### `i18n.date(value: string | Date[, format: Intl.DateTimeFormatOptions])` {#i18n.date} -> **Returns**: Formatted date string Format a date using the conventional format for the active language. - -`date` is a Date object to be formatted. When `date` is a string, the Date object is created by `new Date(date)`. +Format a date using the conventional format for the active language. -`format` is an object passed to the `options` argument of the [Intl.DateTimeFormat constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) (optional). +- `date`: a `Date` object to be formatted. When `date` is a string, the `Date` object is created using `new Date(date)`. +- `format`: an optional object that is passed to the `options` argument of the [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) constructor. This allows for customization of the date formatting. ```ts import { i18n } from "@lingui/core"; @@ -250,13 +233,10 @@ i18n.date(d); ### `i18n.number(value: number[, format: Intl.NumberFormatOptions])` {#i18n.number} -> **Returns**: Formatted number string - Format a number using the conventional format for the active language. -`number` is a number to be formatted. - -`format` is an object passed to the `options` argument of the [Intl.NumberFormat constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) (optional). +- `number`: a number to be formatted. +- `format`: an optional object that is passed to the `options` argument of the [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) constructor. This allows for customization of the date formatting. ```ts import { i18n } from "@lingui/core"; @@ -276,27 +256,14 @@ i18n.number(12345.678, { style: "currency", currency: "CZK" }); // Returns "12 345,68 Kč" ``` -### `setupI18n([options])` {#setupi18n} - -> **Returns**: Instance of I18n +## `setupI18n([options])` {#setupi18n} -Initialize and return a new I18n instance. Usually you want to call it just once and then use returned `i18n` object across whole codebase. +Initialize and return a new `I18n` instance. Typically, you should call this function only once and then use the returned `i18n` object throughout your entire codebase. -:::note -You don't need to setup i18n instance - -In most cases you can use the global `i18n` object exported from `@lingui/core` directly. - -However, if you do need to setup your own `i18n` instance, remember to also set [`runtimeConfigModule`](/docs/ref/conf.md#runtimeconfigmodule) work macros to work properly: - -```ts -// If you import `i18n` object from custom module like this: -import { i18n } from "./custom-i18n-config"; - -// ... then add following line to your Lingui configuration: -// "runtimeConfigModule": ["./custom-i18n-config", "i18n"] -``` +:::info +You typically don't need to set up your own `i18n` instance. In most cases, you can use the global `i18n` object exported from `@lingui/core` directly. +However, if you need to do this, make sure to also configure the [`runtimeConfigModule`](/docs/ref/conf.md#runtimeconfigmodule) to ensure macros work properly. ::: ```ts @@ -305,7 +272,7 @@ import { setupI18n } from "@lingui/core"; const i18n = setupI18n(); ``` -The factory function accepts one optional parameter, `options`: +The factory function accepts an optional `options` parameter, which can be used to configure the initial state of the `i18n` instance. ### `options.locale` @@ -323,7 +290,7 @@ const i18n = setupI18n({ locale: "en" }); ### `options.locales` -List of alternative locales (BCP 47 language tags) which are used for number and date formatting (some countries use more than one number/date format). If not set, active locale is used instead. +List of alternative locales ([BCP-47](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) language tags) which are used for number and date formatting (some countries use more than one number/date format). If not set, the active locale is used instead. ```tsx import { setupI18n } from "@lingui/core"; @@ -358,16 +325,16 @@ const i18n = setupI18n({ messages }); ### `options.missing` -Custom message to be returned when translation is missing. This is useful for debugging: +A custom message to be returned when a translation is missing. This feature is useful for debugging: ```tsx import { setupI18n } from "@lingui/core"; const i18n = setupI18n({ missing: "🚨" }); -i18n._("missing translation") === "🚨"; +i18n._("missing translation") === "🚨"; // Returns the custom missing message ``` -This might be also a function which is called with active locale and message ID: +Alternatively, `missing` can be a function that receives the active locale and message ID as arguments: ```tsx import { setupI18n } from "@lingui/core"; @@ -378,18 +345,18 @@ function missing(locale, id) { } const i18n = setupI18n({ missing }); -i18n._("missing translation"); // raises alert +i18n._("missing translation"); // Triggers an alert ``` -### Catalogs +## AllMessages -Type of `catalogs` parameters in [`I18n.load`](#i18n.load) method: +The `AllMessages` parameter in the [`I18n.load`](#i18n.load) method is of the following type: ```ts -type Catalogs = { [locale: string]: Catalog }; +type AllMessages = { [locale: string]: CompiledMessage }; -// Example: -const catalogs: Catalogs = { +// Example +const messages: AllMessages = { en: { messages: { Hello: "Hello", @@ -405,22 +372,9 @@ const catalogs: Catalogs = { }; ``` -### Catalog +## Messages -Message catalog contains messages and language data (plurals). This object is usually generated in CLI: - -```ts -type Catalog = { - languageData: { - plurals: Function; - }; - messages: Messages; -}; -``` - -### Messages - -Type of messages in [`Catalogs`](#catalogs). It's a mapping of a **messageId** to a translation in given language. This may be a function if messages are compiled. +Type of messages in [`AllMessages`](#allmessages). It's a mapping of a message ID to a translation in given language. This may be a function if messages are compiled. ```ts type Messages = { [messageId: string]: string | Function }; @@ -436,14 +390,14 @@ const messagesEn: Messages = { ### `change` -Triggered **after** locale is changed or new catalog is loaded. There are no arguments. +The `change` event is triggered **after** changing the locale or loading a new message catalog. No arguments are passed to this event. ### `missing` -Triggered when a translation is requested with [`i18n._`](/docs/ref/core.md#i18n._) that does not exist in the active locale's messages. Information about the locale and message are available from the event. +The `missing` event is triggered when a translation is requested using [`i18n._`](/docs/ref/core.md#i18n._) that does not exist in the messages of the active locale.The event provides information about the locale and the missing message ID. ```ts -i18n.on('missing', (event) => { - alert(`alert(`Translation in ${event.locale} for ${event.id} is missing!`)`) -}) +i18n.on("missing", (event) => { + alert(`Translation in ${event.locale} for ${event.id} is missing!`); +}); ``` diff --git a/website/docs/ref/extractor-vue.md b/website/docs/ref/extractor-vue.md index b0b9b71f7..ef0c3a369 100644 --- a/website/docs/ref/extractor-vue.md +++ b/website/docs/ref/extractor-vue.md @@ -32,8 +32,7 @@ const linguiConfig = { export default linguiConfig; ``` -## Further reading +## See Also - [Message Extraction](/docs/guides/message-extraction.md) - [Custom Extractor](/docs/guides/custom-extractor.md) -- [GitHub Repository](https://github.com/lingui/js-lingui/tree/main/packages/extractor-vue) diff --git a/website/docs/ref/loader.md b/website/docs/ref/loader.md index c87185e8c..8a1c12c80 100644 --- a/website/docs/ref/loader.md +++ b/website/docs/ref/loader.md @@ -1,6 +1,8 @@ # Webpack Loader -The Webpack loader compiles catalogs on the fly. It's an alternative to the [`lingui compile`](/ref/cli#compile) command: the loader enables you to `import` `.po` files directly, instead of running `lingui compile` and `import`ing the resulting JavaScript (or TypeScript) files. +The `@lingui/loader` is a Webpack loader for Lingui message catalogs. It offers an alternative to the [`lingui compile`](/ref/cli#compile) and compiles catalogs on the fly. + +It enables you to `import` `.po` files directly, instead of running `lingui compile` and `import`ing the resulting JavaScript (or TypeScript) files. ## Installation @@ -12,9 +14,9 @@ npm install --save-dev @lingui/loader ## Usage -Simply prepend `@lingui/loader!` in front of path to message catalog you want to import. Here's an example of dynamic import: +Simply prepend `@lingui/loader!` in front of path to message catalog you want to import. -The extension is mandatory. +Here's an example of dynamic import: ```ts export async function dynamicActivate(locale: string) { @@ -24,6 +26,8 @@ export async function dynamicActivate(locale: string) { } ``` +Remember that the file extension is mandatory. + :::note Catalogs with the `.json` extension are treated differently by Webpack. They load as ES module with default export, so your import should look like this: @@ -33,4 +37,7 @@ const { messages } = (await import(`@lingui/loader!./locales/${locale}/messages. ::: -See the [guide about dynamic loading catalogs](/docs/guides/dynamic-loading-catalogs.md) for more info. +## See Also + +- [Dynamic Loading of Message Catalogs](/docs/guides/dynamic-loading-catalogs.md) +- [Catalog Formats](/docs/ref/catalog-formats.md) diff --git a/website/docs/ref/locale-detector.md b/website/docs/ref/locale-detector.md index 35ef0e0d0..0847e5a98 100644 --- a/website/docs/ref/locale-detector.md +++ b/website/docs/ref/locale-detector.md @@ -5,34 +5,55 @@ description: Detect the user's locale with the `@lingui/detect-locale` package # Locale Detection -`@lingui/detect-locale` is little package _just (1 kB Gzip)_ with some helper functions that will help you detect the locale of the user: +The `@lingui/detect-locale` is a lightweight package _(only ~1 kB Gzip)_ providing several methods and helpers to determine the user's locale using different detection strategies. -## Installation +Most of the detectors accept custom document, location or window objects as parameters, which is especially useful for testing purposes or when implementing server-side detection strategies. -Install `@lingui/detect-locale` as a dependency: +## Installation ```bash npm2yarn npm install --save @lingui/detect-locale ``` -## Usage +## Reference + +### `detect` + +The `detect` method accepts multiple detectors as arguments and returns the first valid locale detected. + +### `multipleDetect` + +The `multipleDetect` method also accepts multiple detectors as arguments and returns an array with all locales detected by each detector. + +### `fromCookie(key: string)` {#fromCookie} + +Accepts a key as a parameter and retrieves the locale value from the browser's cookies based on that key. + +### `fromHtmlTag(tag: string)` {#fromHtmlTag} + +Looks for the specified attribute in the HTML document (commonly `lang` or `xml:lang`) to detect the locale. + +### `fromNavigator()` {#fromNavigator} + +Retrieves the user's language setting from the browser, compatible with older browsers such as IE11. + +### `fromPath(localePathIndex: number)` {#fromPath} + +Splits `location.pathname` into an array, requiring you to specify the index where the locale is located. + +### `fromStorage(key: string, { useSessionStorage: boolean })` {#fromStorage} + +Searches for the item with the specified key in `localStorage` by default. If the `useSessionStorage` parameter is passed, it will search in `sessionStorage`. -`@lingui/detect-locale:` exports multiple methods: +### `fromSubdomain(localeSubdomainIndex: number)` {#fromSubdomain} -- `detect` - Will return the first occurrence of detectors -- `multipleDetect` - Will return an array with all the locales detected by each detector +Splits `location.href` by subdomain segments, requiring the index where the locale is specified. -and some helpers: +### `fromUrl(parameter: string)` {#fromUrl} -- `fromCookie(key: string)` - Accepts a key as param will recover from navigator cookies the value -- `fromHtmlTag(tag: string)` - Will find on HtmlDocument the attribute passed in params (normally it's used lang or xml:lang) -- `fromNavigator()` - Recovers the navigator language, it's also compatible with old browsers like IE11 -- `fromPath(localePathIndex: number)` - Splits the location.pathname in an array so you have to specify the index of the array where's locale is set -- `fromStorage(key: string, { useSessionStorage: boolean }` - Will search on localStorage by default the item that has that key, if **useSessionStorage** is passed, will search on sessionStorage -- `fromSubdomain(localeSubdomainIndex: number)` - Like fromPath, splits the location.href on segments you must specify the index of that segment -- `fromUrl(parameter: string)` - Uses a query-string parser to recover the correct parameter +Uses a query string parser to find the locale by the specified parameter in the URL. -Practically all detectors accepts a custom document, location, or window object as param, it's useful when testing or using some server-side strategy. +## Usage Examples ### Usage with `detect` diff --git a/website/docs/ref/macro.mdx b/website/docs/ref/macro.mdx index f9d7f3ffc..a0498bdb6 100644 --- a/website/docs/ref/macro.mdx +++ b/website/docs/ref/macro.mdx @@ -542,7 +542,7 @@ Available Props: | `id` | string | Custom message ID | | `comment` | string | Comment for translators | | `context` | string | Allows to extract the same messages with different IDs | -| `render` | func | Render prop function used to render translation | +| `render` | func | Custom render callback to render translation | #### `id` @@ -566,7 +566,7 @@ Comment for translators to give them additional information about the message. I Allows to extract the same messages with different IDs. It is useful when the same message has different meanings in different contexts. See [Context](/docs/guides/explicit-vs-generated-ids.md#context) for more details. -Similarly to [`comment`](#comment), it will be added to the message catalog, visible in TMS and will be removed from the production code. +Similarly to [`comment`](#comment), it will be added to the message catalog, visible in TMS and will be removed from the production code: ```jsx import { Trans } from "@lingui/react/macro"; @@ -603,11 +603,11 @@ Components and HTML tags are replaced by dummy indexed tags (`<0>`) which ha #### `render` -Render prop function used to render translation. This prop is passed directly to the [`Trans`](/docs/ref/react.md#trans) component from the [`@lingui/react`](/docs/ref/react.md) package. +Custom render callback to render translation. This prop is passed directly to the [`Trans`](/docs/ref/react.md#trans) component from the [`@lingui/react`](/docs/ref/react.md) package. ### `Plural` -The `Plural` JSX macro is used to handle plural forms. It's similar to the [`plural`](#plural) macro from the core macros, but it's used in JSX elements. +The `Plural` JSX macro is used to handle plural forms. It's similar to the [`plural`](#plural) core macro, but is used in JSX elements. ```jsx import { Plural } from "@lingui/react/macro"; @@ -621,18 +621,22 @@ import { Trans } from "@lingui/react"; Available Props: -| Prop name | Type | Description | -| ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -| `value` | number | (required) Value is mapped to plural form below | -| `format` | string\|Object | Number format passed as options to [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) | -| `offset` | number | Offset of value when calculating plural forms | -| `zero` | string | Form for empty `value` | -| `one` | string | _Singular_ form | -| `two` | string | _Dual_ form | -| `few` | string | _Paucal_ form | -| `many` | string | _Plural_ form | -| `other` | string | (required) general _plural_ form | -| `_` | string | Exact match form, corresponds to `=N` rule | +| Prop name | Type | Description | +| ----------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `other` | string | _(required)_ general _plural_ form | +| `value` | number | _(required)_ Value is mapped to plural form below | +| `format` | string\|Object | Number format passed as options to [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) | +| `offset` | number | Offset of value when calculating plural forms | +| `zero` | string | Form for empty `value` | +| `one` | string | _Singular_ form | +| `two` | string | _Dual_ form | +| `few` | string | _Paucal_ form | +| `many` | string | _Plural_ form | +| `_` | string | Exact match form, corresponds to `=N` rule | +| `id` | string | Custom message ID | +| `comment` | string | Comment for translators | +| `context` | string | Allows to extract the same messages with different IDs | +| `render` | func | Custom render callback to render translation | Exact matches in MessageFormat syntax are expressed as `=int` (e.g. `=0`), but in React this isn't a valid prop name. Therefore, exact matches are expressed as `_int` prop (e.g. `_0`). This is commonly used in combination with `offset` prop. `offset` affects only plural forms, not exact matches. @@ -662,21 +666,9 @@ import { Plural } from "@lingui/react/macro"; */ ``` -:::tip - -Use `` inside `` macro if you want to add custom `id`, `context` or `comment` for translators. - -```jsx - - ; - -``` - -::: - ### `SelectOrdinal` -The `SelectOrdinal` JSX macro is used to handle ordinal numbers. It's similar to the [`selectOrdinal`](#selectordinal) macro from the core macros, but it's used in JSX elements. +The `SelectOrdinal` JSX macro is used to handle ordinal numbers. It's similar to the [`selectOrdinal`](#selectordinal) core macro, but is used in JSX elements. ```jsx import { SelectOrdinal } from "@lingui/react/macro"; @@ -690,34 +682,22 @@ import { SelectOrdinal } from "@lingui/react/macro"; Available Props: -| Prop name | Type | Description | -| ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -| `value` | number | (required) Value is mapped to plural form below | -| `offset` | number | Offset of value for plural forms | -| `zero` | string | Form for empty `value` | -| `one` | string | _Singular_ form | -| `two` | string | _Dual_ form | -| `few` | string | _Paucal_ form | -| `many` | string | _Plural_ form | -| `other` | string | (required) general _plural_ form | -| `_` | string | Exact match form, correspond to `=N` rule. (e.g: `_0`, `_1`) | -| `format` | string\|Object | Number format passed as options to [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) | - -:::tip - -Use `` inside `` macro if you want to add custom `id`, `context` or `comment` for translators. - -```jsx - - - -``` - -::: +| Prop name | Type | Description | +| ----------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `value` | number | _(required)_ Value is mapped to plural form below | +| `other` | string | _(required)_ general _plural_ form | +| `offset` | number | Offset of value for plural forms | +| `zero` | string | Form for empty `value` | +| `one` | string | _Singular_ form | +| `two` | string | _Dual_ form | +| `few` | string | _Paucal_ form | +| `many` | string | _Plural_ form | +| `_` | string | Exact match form, correspond to `=N` rule. (e.g: `_0`, `_1`) | +| `format` | string\|Object | Number format passed as options to [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) | ### `Select` -The `Select` JSX macro is used to handle different forms of a message based on a value. It's similar to the [`select`](#select) macro from the core macros, but it's used in JSX elements. +The `Select` JSX macro is used to handle different forms of a message based on a value. It's similar to the [`select`](#select) core macro, but is used in JSX elements. ```jsx import { Select } from "@lingui/react/macro"; @@ -730,26 +710,18 @@ import { Select } from "@lingui/react/macro"; Available Props: -| Prop name | Type | Description | -| --------- | ------ | ------------------------------------------------ | -| `value` | number | (required) Value determines which form is output | -| `_` | string | Form for specific case | -| `other` | number | (required) Default, catch-all form | +| Prop name | Type | Description | +| --------- | ------ | ------------------------------------------------------ | +| `value` | number | _(required)_ Value determines which form is output | +| `other` | number | _(required)_ Default, catch-all form | +| `_` | string | Form for specific case | +| `id` | string | Custom message ID | +| `comment` | string | Comment for translators | +| `context` | string | Allows to extract the same messages with different IDs | +| `render` | func | Custom render callback to render translation | The select cases except `other` should be prefixed with underscore: `_male` or `_female`. -:::tip - -Use ` - -``` - -::: - ### `useLingui` The `useLingui` React macro gives access to a [`t`](/docs/ref/macro.mdx#t) macro that is bound to the local `i18n` object passed from the React context. @@ -773,6 +745,7 @@ function MyComponent() { } // ↓ ↓ ↓ ↓ ↓ ↓ + import { useLingui } from "@lingui/react"; function MyComponent() { diff --git a/website/docs/ref/metro-transformer.mdx b/website/docs/ref/metro-transformer.mdx index bfc74e2b6..2a3f9b157 100644 --- a/website/docs/ref/metro-transformer.mdx +++ b/website/docs/ref/metro-transformer.mdx @@ -1,6 +1,13 @@ -# Metro transformer +--- +title: Metro Transformer +description: Use Lingui with React Native and compile your message catalogs on the fly +--- -[Metro bundler](https://metrobundler.dev/) is a JavaScript bundler used in React Native apps. This package offers an alternative to the [`lingui compile`](/ref/cli#compile) command: a transformer that enables Metro to compile `.po` files on the fly. The transformer enables you to `import` `.po` files directly, instead of running `lingui compile` and `import`ing the resulting JavaScript (or TypeScript) files. +# Metro Transformer + +[Metro bundler](https://metrobundler.dev/) is a JavaScript bundler used in React Native apps. The `@lingui/metro-transformer` offers an alternative to the [`lingui compile`](/ref/cli#compile) command: a transformer that enables Metro to compile `.po` files on the fly. + +The transformer enables you to `import` `.po` files directly, instead of running `lingui compile` and `import`ing the resulting JavaScript (or TypeScript) files. ## Installation @@ -42,7 +49,7 @@ module.exports = config; ``` - + ```js title="metro.config.js" const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config"); diff --git a/website/docs/ref/react.md b/website/docs/ref/react.md index af6d1c3db..37d3441d2 100644 --- a/website/docs/ref/react.md +++ b/website/docs/ref/react.md @@ -5,7 +5,9 @@ description: Reference for the Lingui React API and components # React API Reference -Components from `@lingui/react` wrap the vanilla JS API from `@lingui/core`. React components handle changes of active language or interpolated variables better than low-level API and also take care of re-rendering when locale or messages change. +The Lingui React API, provided by the `@lingui/react` package, integrates Lingui's core JavaScript functionality directly into React, extending React components with the ability to dynamically manage localization. + +This API provides React-specific components that automatically update the user interface when the active language or interpolated variables change, simplifying translation management and reactivity in the application. ## Installation @@ -15,34 +17,29 @@ npm install --save @lingui/react ## Rendering of Translations {#rendering-translations} -All i18n components render translation as text without a wrapping tag. This can be customized in two different ways: +All i18n components render translations as plain text by default, without a wrapping tag. You can customize this behavior in two ways: -- globally: using `defaultComponent` prop on [`I18nProvider`](#i18nprovider) component -- locally: using `render` prop or `component` on i18n components +- Globally: Set the `defaultComponent` prop on the [`I18nProvider`](#i18nprovider) component. +- Locally: Use the `render` or `component` props on individual i18n components. ### Global Configuration -Default rendering component can be set using `defaultComponent` prop in [`I18nProvider`](#i18nprovider). The main use case for this is rendering translations in `` component in React Native. +You can set a default rendering component using the `defaultComponent` prop in [`I18nProvider`](#i18nprovider). This is especially useful in cases like React Native, where you may want translations to be rendered inside a `` component by default. ### Local Configuration +You can customize how translations are rendered locally within individual i18n components using the following props: + | Prop name | Type | Description | | ----------- | ------------------------------------ | ------------------------------------------------------------- | | `className` | string | Class name to be added to `` element | | `render` | Function(props) -> Element \| `null` | Custom render callback to render translation | -| `component` | Component \| `null` | Custom component to render translation | +| `component` | Component \| `null` | React component to wrap the translation | | `comment` | string | Comment picked up by extractor to provide translation context | -`className` is used only for built-in components (when _render_ is string). - -When you use the `render` callback, it obtains an object of type `TransRenderProps` as an argument. If you use `component` prop, you will get the same object as props. - -`TransRenderProps` contains +The `className` prop is applicable only to built-in components when the `render` prop is specified as a string. -- `translation`: the translated message -- `children`: same as `translation` (for compatibility with React components that expect `children` prop) -- `id`: the message id -- `message`: the compiled message; you probably don't need this +When using the `render` callback, it accepts an object of type `TransRenderProps` as an argument: ```ts type TransRenderProps = { @@ -53,46 +50,58 @@ type TransRenderProps = { }; ``` +- `id` - The message ID. +- `translation` - The translated message. +- `children` - The same as `translation`, provided for compatibility with components that expect a `children` prop. +- `message` - The compiled message (generally not needed). + +If you choose to use the `component` prop, the same object will be passed as a prop to your custom component. This allows you to access the necessary information for rendering translations directly within your component. + +#### Important Notes + +- You cannot use both `render` and `component` props simultaneously. +- Both `render` and `component` can be set to `null` to override the global `defaultComponent` and render a string without a wrapping component. +- The `component` supports nested elements with the `asChild` pattern. + +#### Examples + +Using a custom component: + ```jsx import { Text } from "react-native"; Link to docs; // renders as Link to docs - - }>Sign in; -// renders as ``` -`render` and `component` also accept `null` value to render string without a wrapping component. This can be used to override custom `defaultComponent` config. +Using render prop for custom rendering logic: ```jsx -Heading; -// renders as "Heading" - -Heading; -// renders as "Heading" + }>Sign in +// renders as ``` ## Lingui Context -Message catalogs and the active locale are passed via context in [`I18nProvider`](#i18nprovider). Use the [`useLingui`](#uselingui) hook to access the Lingui context. +Message catalogs and the active locale are provided through the context in the [`I18nProvider`](#i18nprovider). You can access this context using the [`useLingui`](#uselingui) hook. -Lingui context object is exported from the package (`import { LinguiContext } from '@lingui/react'`). It is not expected that you would need it, but it enables advanced scenarios if the behavior of `I18nProvider` doesn't fit your needs. +The `LinguiContext` object is exported from the `@lingui/react` package. While most users will not need to interact with it directly, it can be useful for advanced scenarios where the default behavior of `I18nProvider` doesn't meet your specific needs. -### I18nProvider +### `I18nProvider` -`I18nProvider` provides Lingui context to all components in the subtree. It should be rendered as top-level component of your application. +The `I18nProvider` provides Lingui context to all components in the subtree. It should be rendered as top-level component of your application. -`I18nProvider` renders its children only after a locale is activated. This ensures that the components consuming `i18n` have access to the translations. -Additionally, it subscribes to change events emitted by the `i18n` object and re-renders all components consuming the Lingui context when messages are updated or when a new locale is activated. +It ensures that its children are only rendered after a locale has been activated, guaranteeing that any components relying on `i18n` have access to the translations. Additionally, the `I18nProvider` subscribes to change events emitted by the `i18n` object, automatically re-rendering all components that consume the Lingui context whenever messages are updated or a new locale is activated. | Prop name | Type | Description | | ------------------ | --------------------- | ------------------------------------------------------------------------------ | -| `i18n` | `I18n` | The i18n instance (usually the one imported from `@lingui/core`) | +| `i18n` | `I18n` | The `I18n` object instance (usually the one imported from `@lingui/core`) | | `children` | `React.ReactNode` | React Children node | | `defaultComponent` | `React.ComponentType` | A React component within which translation strings will be rendered (optional) | -`defaultComponent` has the same meaning as `component` in other i18n components. [`Rendering of translations`](#rendering-translations) is explained at the beginning of this document. +The `defaultComponent` serves the same purpose as the `component` prop in other i18n components. For a detailed explanation of how translations are rendered, see the [Rendering of Translations](#rendering-translations) section at the beginning of this document. + +#### Examples ```jsx import React from "react"; @@ -116,33 +125,38 @@ const App = () => { }; ``` -### useLingui +### `useLingui` -This hook allows access to the Lingui context. It returns an object with the following content: +The `useLingui` hook provides access to the Lingui context. It returns an object with the following properties: | Key | Type | Description | | ------------------ | --------------------- | ----------------------------------------------------------------------- | -| `i18n` | `I18n` | the `I18` object instance that you passed to `I18nProvider` | -| `_` | `I18n[_]` | reference to the [`i18n._`](/ref/core#i18n._) function, explained below | -| `defaultComponent` | `React.ComponentType` | the same `defaultComponent` you passed to `I18nProvider`, if provided | +| `i18n` | `I18n` | The `I18n` object instance that you passed to `I18nProvider` | +| `_` | `I18n[_]` | Reference to the [`i18n._`](/ref/core#i18n._) function, explained below | +| `defaultComponent` | `React.ComponentType` | The same `defaultComponent` you passed to `I18nProvider`, if provided | Components that use `useLingui` hook will re-render when locale and / or catalogs change. However, the reference to the `i18n` object is stable and doesn't change between re-renders. This can lead to unexpected behavior with memoization (see [memoization pitfall](/tutorials/react-patterns#memoization-pitfall)). -To alleviate the issue, `useLingui` provides the `_` function, which is the same as [`i18n._`](/ref/core#i18n._) but _its reference changes_ with each update of the Lingui context. Thanks to that, you can safely use this `_` function as a hook dependency. +To alleviate the issue, `useLingui` provides the `_` function, which is the same as [`i18n._`](/ref/core#i18n._) but _its reference changes_ with each update of the Lingui context. Thanks to that, you can safely use this `_` function as a hook dependency: ```jsx import React from "react"; +import { msg } from "@lingui/core/macro"; import { useLingui } from "@lingui/react"; const CurrentLocale = () => { - const { i18n } = useLingui(); + const { _, i18n } = useLingui(); - return Current locale: {i18n.locale}; + return ( + + {_(msg`Current locale`)}: {i18n.locale} + + ); }; ``` :::tip -There is a [macro version](/docs/ref/macro.mdx#uselingui) of the `useLingui` hook which supports all features of the [`t` macro](/docs/ref/macro.mdx#t) and uses the runtime `useLingui` hook (from `@lingui/react`) under the hood. +There is a [macro version](/docs/ref/macro.mdx#uselingui) of the `useLingui` hook which supports all features of the [`t` macro](/docs/ref/macro.mdx#t) and uses the runtime `useLingui` hook (from `@lingui/react`) under the hood: ```jsx import { useLingui } from "@lingui/react/macro"; @@ -160,63 +174,85 @@ You also can safely use the returned `t` function in a dependency array of React ## Components -The `@lingui/react` package provides `Trans` component to render translations. However, you're more likely to use [macros](/docs/ref/macro.mdx) instead because they are more convenient and easier to use. +The `@lingui/react` package provides the `Trans` component for rendering translations in your application. It is a low-level component that allows you to render translations with dynamic values and components. + +:::caution +While this component is available, you will likely find [Macros](/docs/ref/macro.mdx) to be more convenient and developer-friendly. Macros simplify the translation process and reduce boilerplate code. +::: -This section is intended for reference purposes. +This section serves as a reference for those who prefer to use the components directly. -### Trans +### `Trans` -| Prop name | Type | Description | -| --------- | -------- | ------------------- | -| `id` | `string` | Key, the message ID | +| Prop name | Type | Description | +| --------- | -------- | ----------------------------------------- | +| `id` | `string` | Key, the message ID | +| `message` | `string` | Default message | +| `values` | `object` | Variables to interpolate into the message | -:::important +The `values` and `components` props allow to pass dynamic values and components used for formatting the translation. In addition, the `comment` prop provides context to translators, helping them to understand the intent behind the message. -Import [`Trans`](/docs/ref/macro.mdx#trans) macro instead of [`Trans`](#trans) component if you use macros: +:::tip +Import the [`Trans`](/docs/ref/macro.mdx#trans) macro instead if you use macros. It will be transformed into the runtime `Trans` component automatically: ```jsx import { Trans } from "@lingui/react/macro"; +Refresh inbox; -// Trans from @lingui/react won't work in this case -// import { Trans } from "@lingui/react" +// ↓ ↓ ↓ ↓ ↓ ↓ -Hello, my name is {name}; +import { Trans } from "@lingui/react"; +; ``` ::: -It's also possible to use `Trans` component directly without macros. In that case, `id` identifies the message being translated. `values` and `components` are arguments and components used for formatting translation. `comment` helps add context for translators: +It's also possible to use the `Trans` component directly without macros. In this case `id` identifies the message to be translated. + +#### Examples ```jsx - - - - - - -// number of tag corresponds to index in `components` prop - }} -/> +import React from "react"; +import { Trans } from "@lingui/react"; + +const MyComponent = () => { + return ( +
+ {/* Simple translation without dynamic values */} + + + {/* Translation with dynamic values */} + + + {/* Translation with a comment for translators */} + + + {/* Translation with a component for formatting */} + Documentation }} + /> +
+ ); +}; ``` -### Plurals +#### Plurals -If you cannot use [@lingui/react/macro](/docs/ref/macro.mdx) for some reason, you can render plurals using the plain Trans component like this: +If for some reason you cannot use [Macros](/docs/ref/macro.mdx), you can render plurals using the simple `Trans` component by passing the [ICU MessageFormat](/docs/guides/message-format.md) string as the `message` prop: ```jsx import React from "react"; import { Trans } from "@lingui/react"; -; +const CarCount = ({ cars }) => { + return ( + + ); +}; ``` diff --git a/website/docs/ref/swc-plugin.md b/website/docs/ref/swc-plugin.md index 7b3fd3c87..13a3c3a7d 100644 --- a/website/docs/ref/swc-plugin.md +++ b/website/docs/ref/swc-plugin.md @@ -30,18 +30,18 @@ npm install --save-dev @lingui/swc-plugin To ensure that the resolved version of `@swc/core` is one of the supported versions, you can use the `resolutions` field in the `package.json` file, which is supported by Yarn: -```json +```json title="package.json" "resolutions": { "@swc/core": "1.3.56" -}, +} ``` or `overrides` for >npm@8.3 -```json +```json title="package.json" "overrides": { "@swc/core": "1.3.56" -}, +} ``` ## Usage @@ -57,13 +57,7 @@ Add the following configuration to your [`.swcrc`](https://swc.rs/docs/configura [ "@lingui/swc-plugin", { - // Optional - // Unlike the JS version this option must be passed as object only. - // Docs https://lingui.dev/ref/conf#runtimeconfigmodule - // "runtimeModules": { - // "i18n": ["@lingui/core", "i18n"], - // "trans": ["@lingui/react", "Trans"] - // } + // Additional Configuration } ] ] @@ -83,7 +77,7 @@ const nextConfig = { [ "@lingui/swc-plugin", { - // the same options as in .swcrc + // Additional Configuration }, ], ], @@ -93,12 +87,29 @@ const nextConfig = { module.exports = nextConfig; ``` +### Additional Configuration + +You can configure the plugin by passing the `runtimeModules` option. This option is an object that maps runtime module names to their corresponding module paths and export names. It is essential for macros, which rely on referencing the global `i18n` object. + +```json +[ + "@lingui/swc-plugin", + { + "runtimeModules": { + "i18n": ["@lingui/core", "i18n"], + "trans": ["@lingui/react", "Trans"] + } + } +] +``` + +For more details, refer to the [Runtime Configuration](/docs/ref/conf.md#runtimeconfigmodule) section of the documentation. + +:::info +If you would like to suggest a new feature or report a bug, please [open an issue](https://github.com/lingui/swc-plugin/issues) on the GitHub repository. +::: + ## Examples - [React with Vite and SWC](https://github.com/lingui/js-lingui/tree/main/examples/vite-project-react-swc) - [Next.js with SWC](https://github.com/lingui/js-lingui/tree/main/examples/nextjs-swc) - -## Links - -- [GitHub Repository](https://github.com/lingui/swc-plugin) -- [NPM Package](https://www.npmjs.com/package/@lingui/swc-plugin) diff --git a/website/docs/ref/vite-plugin.md b/website/docs/ref/vite-plugin.md index f14519761..b3ca7f1df 100644 --- a/website/docs/ref/vite-plugin.md +++ b/website/docs/ref/vite-plugin.md @@ -5,7 +5,9 @@ description: Use Lingui with Vite and compile your message catalogs on the fly # Vite Plugin -`@lingui/vite-plugin` is a Vite plugin, which compiles Lingui catalogs on the fly and provides additional required configuration for Vite. +Vite is a blazing fast frontend build tool powering the next generation of web applications. + +The `@lingui/vite-plugin` is a Vite plugin that compiles Lingui catalogs on the fly and provides the necessary configuration for seamless integration with Vite. [![npm-version](https://img.shields.io/npm/v/@lingui/vite-plugin?logo=npm&cacheSeconds=1800)](https://www.npmjs.com/package/@lingui/vite-plugin) [![npm-downloads](https://img.shields.io/npm/dt/@lingui/vite-plugin?cacheSeconds=500)](https://www.npmjs.com/package/@lingui/vite-plugin) @@ -22,7 +24,7 @@ For a complete installation guide, see [Installation and Setup](/docs/installati ## Usage -Simply add `@lingui/vite-plugin` inside your `vite.config.ts`: +To integrate Lingui with Vite, add the `@lingui/vite-plugin` inside your `vite.config.ts` as follows: ```ts title="vite.config.ts" import { UserConfig } from "vite"; @@ -33,7 +35,7 @@ const config: UserConfig = { }; ``` -Then in your code all you need is to use [dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) to load only necessary catalog. Extension is mandatory. +Then use [dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) in your code to load only necessary catalog: ```ts export async function dynamicActivate(locale: string) { @@ -44,6 +46,8 @@ export async function dynamicActivate(locale: string) { } ``` +Remember that the file extension is mandatory. + :::tip If you are using a format that has a different extension than `*.po`, you need to specify the `?lingui` suffix: diff --git a/website/sidebars.ts b/website/sidebars.ts index 2c6db10f0..fdb807f51 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -101,6 +101,11 @@ const sidebar = [ label: "Configuration", id: "ref/conf", }, + { + type: "doc", + label: "Macros", + id: "ref/macro", + }, { type: "doc", label: "Catalog Formats", @@ -116,11 +121,6 @@ const sidebar = [ label: "@lingui/react", id: "ref/react", }, - { - type: "doc", - label: "@lingui/macro", - id: "ref/macro", - }, { type: "doc", label: "@lingui/cli", @@ -128,7 +128,7 @@ const sidebar = [ }, { type: "doc", - label: "@lingui/locale-detector", + label: "@lingui/detect-locale", id: "ref/locale-detector", }, {