Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Tutorials section improvements #2075

Merged
merged 6 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion vercel.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
{ "source": "/guides/excluding-build-files", "destination": "/ref/cli#compile", "permanent": true},
{ "source": "/tutorials/explicit-vs-generated-ids", "destination": "/guides/explicit-vs-generated-ids", "permanent": true},
{ "source": "/tutorials/setup-vite", "destination": "/installation#vite", "permanent": true },
{ "source": "/tutorials/setup-react", "destination": "/installation", "permanent": true }
{ "source": "/tutorials/setup-react", "destination": "/installation", "permanent": true },
{ "source": "/tutorials/react-patterns", "destination": "/tutorials/react", "permanent": true }
]
}
73 changes: 73 additions & 0 deletions website/docs/guides/lazy-translations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Lazy Translations
description: Lazy translations allow you to defer translation of a message until it is actually displayed
---

# Lazy Translations

Lazy translation allows you to defer translation of a message until it's rendered, giving you flexibility in how and where you define messages in your code. With lazy translation, you can tag a string with the [`msg`](/docs/ref/macro.mdx#definemessage) macro to create a _message descriptor_ that can be saved, passed around as a variable, and rendered later.

## Usage Example

To render the message descriptor as a string-only translation, pass it to the [`i18n._()`](/docs/ref/core.md#i18n._) method:

```jsx
import { msg } from "@lingui/core/macro";
import { i18n } from "@lingui/core";

const favoriteColors = [msg`Red`, msg`Orange`, msg`Yellow`, msg`Green`];

export function getTranslatedColorNames() {
return favoriteColors.map((color) => i18n._(color));
}
```

## Usage in React

To render the message descriptor in a React component, pass its `id` to the [`Trans`](/docs/ref/react.md#trans) component as a value of the `id` prop:

```jsx
import { msg } from "@lingui/core/macro";
import { Trans } from "@lingui/react";

const favoriteColors = [msg`Red`, msg`Orange`, msg`Yellow`, msg`Green`];

export default function ColorList() {
return (
<ul>
{favoriteColors.map((color) => (
<li>
<Trans id={color.id} />
</li>
))}
</ul>
);
}
```

:::info Important
Please note that we import the `<Trans>` component from `@lingui/react` to use the runtime version, as the message is already defined and we don't need the compile-time macro here.
:::

### Picking a Message Based on a Variable

Sometimes you need to choose between different messages to display depending on the value of a variable. For example, imagine you have a numeric "status" code that comes from an API, and you need to display a message that represents the current status.

An easy way to do this is to create an object that maps the possible values of "status" to message descriptors (tagged with the [`msg`](/docs/ref/macro.mdx#definemessage) macro) and render them as needed with deferred translation:

```jsx
import { msg } from "@lingui/core/macro";
import { useLingui } from "@lingui/react";
andrii-bodnar marked this conversation as resolved.
Show resolved Hide resolved

const statusMessages = {
["STATUS_OPEN"]: msg`Open`,
["STATUS_CLOSED"]: msg`Closed`,
["STATUS_CANCELLED"]: msg`Cancelled`,
["STATUS_COMPLETED"]: msg`Completed`,
};

export default function StatusDisplay({ statusCode }) {
const { _ } = useLingui();
return <div>{_(statusMessages[statusCode])}</div>;
}
```
51 changes: 50 additions & 1 deletion website/docs/ref/macro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ const message = t({

### `defineMessage` / `msg` {#definemessage}

The `defineMessage` (alias: `msg`) macro allows to define a message for later use. It has the same signature as `t` and returns a `MessageDescriptor` that you can pass to `i18n._` to get a translated string at any time later. This is useful for [lazy translations](/tutorials/react-patterns#lazy-translations).
The `defineMessage` (alias: `msg`) macro allows to define a message for later use. It has the same signature as `t` and returns a `MessageDescriptor` that you can pass to `i18n._` to get a translated string at any time later. This is useful for [Lazy Translations](/guides/lazy-translations).

In other words, `t` returns a translated string at the time when it's called, while `msg` returns a `MessageDescriptor` that can produce translated strings later:

Expand Down Expand Up @@ -791,6 +791,55 @@ function MyComponent() {
The `useLingui` React macro is available from **Lingui v5**.
:::

## Important Notes

### Using Macros

All Core Macros cannot be used at the module level:

```jsx
import { t } from "@lingui/core/macro";

// ❌ Bad! This won't work because the `t` macro is used at the module level.
// The `t` macro returns a string, and once this string is assigned, it won't react to locale changes.
const colors = [t`Red`, t`Orange`, t`Yellow`, t`Green`];

// ✅ Good! Every time the function is executed, the `t` macro will be re-executed as well,
// and the correctly translated color labels will be returned.
function getColors() {
return [t`Red`, t`Orange`, t`Yellow`, t`Green`];
}
```

:::tip
There is an [ESLint Plugin](/docs/ref/eslint-plugin.md) rule designed to check for this misuse: `t-call-in-function`.
:::
andrii-bodnar marked this conversation as resolved.
Show resolved Hide resolved

A better option would be to use the [Lazy Translations](/guides/lazy-translations) pattern.

### Global `i18n` Instance

When you use the [`t`](#t) macro (or [`plural`](#plural), [`select`](#select), [`selectOrdinal`](#selectordinal)), it uses a global [`i18n`](/docs/ref/core.md#i18n) instance. While this generally works, there are situations, such as server-side rendering (SSR) applications, where it may not be the best solution.

For better control and flexibility, it's a good idea to avoid the global `i18n` instance and instead use a specific instance tailored to your needs:

```js
import { msg } from "@lingui/core/macro";
import { useLingui } from "@lingui/react/macro";

export function showAlert(i18n) {
alert(i18n._(msg`...`));
}

function MyComponent() {
// Get i18n instance from React Context
const { i18n } = useLingui();

// Pass the instance from outside
showAlert(i18n);
}
```

## More Examples

### Examples of JS macros
Expand Down
2 changes: 1 addition & 1 deletion website/docs/ref/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ This hook allows access to the Lingui context. It returns an object with the fol
| `_` | `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)).
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#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.

Expand Down
2 changes: 1 addition & 1 deletion website/docs/releases/migration-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ You will need to make some changes as this is a misuse of the library that actua

Due to the changes caused by hash-based message ID feature described earlier, this approach will no longer work.

Instead, please use [recommended](/docs/tutorials/react-patterns.md#lazy-translations) pattern for such translations:
Instead, please use [recommended](/guides/lazy-translations) pattern for such translations:

```tsx
import { msg } from "@lingui/macro";
Expand Down
31 changes: 19 additions & 12 deletions website/docs/tutorials/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,36 @@ description: Learn how to use Lingui's internationalization features in your van

# JavaScript Apps Internationalization

In this tutorial, we'll learn how to use Lingui's internationalization features that don't depend on React. We'll take a minimalist approach and cover the main features of the `@lingui/core` package.
This tutorial will walk you through using Lingui's internationalization (i18n) features in a vanilla JavaScript application. We'll cover the essentials of the `@lingui/core` package, which handles all translation and message catalog management.

:::tip Example
If you're looking for a working solution, check out the [Vanilla JS example](https://github.com/lingui/js-lingui/tree/main/examples/js). This example application shows a complete setup using Lingui and vanilla JavaScript.
:::

## Installing Lingui

1. Follow the [Installation and Setup](/docs/installation.mdx) page for initial setup.
2. Install the [`@lingui/core`](/docs/ref/core.md) package, which is responsible for translation and handling of message catalogs.
2. Install the [`@lingui/core`](/docs/ref/core.md) package, which is responsible for translation and message catalog handling.

## Setting up i18n

First we need to setup the i18n singleton, which is pretty simple:
First, we need to set up the i18n singleton, which is pretty simple:

```js
import { i18n } from "@lingui/core";

// messages.js is generated by the cli
import { messages } from "path-to-locale/en/messages.js";

i18n.load("en", messages);
i18n.activate("en");
```

The `messages.js` is generated by the Lingui CLI and contains compiled message catalogs. Alternatively, you can load catalogs dynamically using the [`@lingui/loader`](/docs/ref/loader.md) or [`@lingui/vite-plugin`](/docs/ref/vite-plugin.md).

## Localizing Your App

Once that is done, we can go ahead and use it! Wrap your text in [`t`](/docs/ref/macro.mdx#t) macro:
To localize your application, you need to wrap your localizable texts in [Macros](/docs/ref/macro.mdx). Lingui provides a set of Core Macros that transform tagged template literals and can be used in any JavaScript context.

Let's wrap our text in the [`t`](/docs/ref/macro.mdx#t) macro:

```js
import { t } from "@lingui/core/macro";
Expand All @@ -41,7 +47,7 @@ t`My name is ${name}`;
// becomes "Je m'appelle Fred"
```

Plurals and selections are possible using plural and select methods:
Plurals and selections are possible using [`plural`](/docs/ref/macro.mdx#plural) and [`select`](/docs/ref/macro.mdx#select) macros:

```js
import { plural } from "@lingui/core/macro";
Expand All @@ -55,10 +61,10 @@ plural(count, {
// becomes "42 livres"
```

It's also possible to nest message formats. Each message format method in i18n has a standalone companion, which only returns message without performing the translation:
It's also possible to nest message formats. Each message format method in `i18n` has a standalone companion, which only returns message without performing the translation:

```js
import { t, select, plural } from "@lingui/core/macro"
import { t, select, plural } from "@lingui/core/macro";

select(gender, {
offset: 1,
Expand All @@ -71,10 +77,11 @@ select(gender, {
}),
male: plural(value, {...}),
other: plural(value, {...}),
})
});
```

## Further Reading
## See Also

- [CLI Reference](/docs/ref/cli.md)
- [Message Extraction Guide](/docs/guides/message-extraction.md)
- [Pluralization Guide](/docs/guides/plurals.md)
- [`@lingui/cli` Reference](/docs/ref/cli.md)
Loading
Loading