Skip to content

Commit

Permalink
docs: update docs for useLingui
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko committed Feb 26, 2024
1 parent 51b68c3 commit 17621bf
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 62 deletions.
4 changes: 3 additions & 1 deletion website/docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ Low-level React API is very similar to react-intl and the message format is the

```jsx
import React from "react";
import { t, Trans, Plural } from "@lingui/macro";
import { Trans, Plural, useLingui } from "@lingui/macro";

export default function Lingui({ numUsers, name = "You" }) {
const { t } = useLingui();

return (
<div>
<h1>
Expand Down
3 changes: 2 additions & 1 deletion website/docs/ref/conf.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ 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.md#trans) is imported. To do that, pass an object to `runtimeConfigModule`:
In some advanced cases you may also need to change the module from which [Trans](/docs/ref/macro.md#trans) or [useLingui](/docs/ref/macro.md#useLingui) is imported. To do that, pass an object to `runtimeConfigModule`:

```jsx
// If you import `i18n` object from custom module like this:
Expand All @@ -408,6 +408,7 @@ import { Trans, i18n } from "./custom-config";
// "runtimeConfigModule": {
// i18n: ["./custom-config", "i18n"],
// Trans: ["./custom-config", "Trans"]
// useLingui: ["./custom-useLingui", "myUseLingui"]
// }
```

Expand Down
43 changes: 41 additions & 2 deletions website/docs/ref/macro.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ const msg = /*i18n*/ {
/>
```

## JS macros
## Core macros

These macros can be used in any context (e.g. outside JSX). All JS macros are transformed into a _Message Descriptor_ wrapped inside of [`i18n._`](/docs/ref/core.md#i18n._) call.

Expand Down Expand Up @@ -774,7 +774,7 @@ const message = /*i18n*/ {

:::

## JSX Macros
## React Macros

### `Trans`

Expand Down Expand Up @@ -1010,3 +1010,42 @@ Use `<Select>` inside `<Trans>` macro if you want to provide `id`, `context` or
<Select value={gender} _male="His book" _female="Her book" other="Their book" />
</Trans>
```

### `useLingui`

:::note
`useLingui` is available from `@lingui/macro@4.8.0` and not available yet in the `@lingui/swc-plugin`
:::

Gives access to a [`t`](/docs/ref/macro.md#t) macro bound to the local i18n object passed from React context.

It returns an object with the following content:

| Key | Type | Description |
| ------------------ | --------------------- | --------------------------------------------------------------------- |
| `i18n` | `I18n` | the `I18` object instance that you passed to `I18nProvider` |
| `t` | `t` | reference to `t` macro, described above |
| `defaultComponent` | `React.ComponentType` | the same `defaultComponent` you passed to `I18nProvider`, if provided |

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

function MyComponent() {
const { t } = useLingui();
const a = t`Text`;
}

// ↓ ↓ ↓ ↓ ↓ ↓
import { useLingui } from "@lingui/react";

function MyComponent() {
const { _ } = useLingui();
const a = _(
/*i18n*/
{
id: "xeiujy",
message: "Text",
}
);
}
```
17 changes: 17 additions & 0 deletions website/docs/ref/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,23 @@ const CurrentLocale = () => {
};
```

:::tip
There is a [macro version](/ref/macro#uselingui) of `useLingui` hook. Which supports all features of [`t` macro](/docs/ref/macro.md#t) and uses runtime `useLingui` hook under the hood.

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

const CurrentLocale = () => {
const { t } = useLingui();

const userName = "Tim";
return <span>{t`Hello ${userName}`}</span>;
};
```

You also can safely use returned `t` function in a dependency array of React hooks.
:::

## Components

The `@lingui/react` package provides `Trans` component to render translations. However, you're more likely to use [macros](/docs/ref/macro.md) instead because they are more convenient and easier to use.
Expand Down
2 changes: 1 addition & 1 deletion website/docs/tutorials/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ i18n.activate("en");

## Localizing your app

Once that is done, we can go ahead and use it! Wrap you text in [`t`](/docs/ref/macro.md#t) macro and pass it to [`i18n._()`](/docs/ref/core.md#i18n._) method:
Once that is done, we can go ahead and use it! Wrap you text in [`t`](/docs/ref/macro.md#t) macro:

```js
import { t } from "@lingui/macro";
Expand Down
14 changes: 8 additions & 6 deletions website/docs/tutorials/react-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,14 @@ We're importing the default `i18n` object from `@lingui/core`. Read more about t

Translating the heading is done. Now, let's translate the `title` prop in the `<Button title="mark messages as read" />` element. In this case, `Button` expects to receive a `string`, so we cannot use the [`Trans`](/docs/ref/macro.md#trans) macro here!

The solution is to use the `t` macro together with the `i18n` object which we can obtain from the `useLingui` hook. We use the two like this to get a translated string:
The solution is to use the `t` macro which we can obtain from the `useLingui` hook. We use it like this to get a translated string:

```tsx
const { i18n } = useLingui()
import { useLingui } from '@lingui/macro';

const { t } = useLingui()
...
<Button title={t(i18n)`this will be translated and rerendered with locale changes`}/>
<Button title={t`this will be translated and rerendered with locale changes`}/>
```

Under the hood, [`I18nProvider`](/docs/ref/react.md#i18nprovider) takes the instance of the `i18n` object and passes it to `Trans` components through React context. `I18nProvider` will update the context value (which then rerenders components that consume the provided context value) when locale or message catalogs are updated.
Expand All @@ -128,21 +130,21 @@ The interplay of `I18nProvider` and `useLingui` is shown in the following simpli

```tsx
import { I18nProvider } from "@lingui/react";
import { t, Trans } from "@lingui/macro";
import { Trans, useLingui } from "@lingui/macro";
import { i18n } from "@lingui/core";

<I18nProvider i18n={i18n}>
<AppRoot />
</I18nProvider>;
//...
const Inbox = ({ markAsRead }) => {
const { i18n } = useLingui();
const { t } = useLingui();
return (
<View>
<Text style={styles.heading}>
<Trans>Message Inbox</Trans>
</Text>
<Button onPress={markAsRead} title={t(i18n)`Mark messages as read`} />
<Button onPress={markAsRead} title={t`Mark messages as read`} />
</View>
);
};
Expand Down
82 changes: 36 additions & 46 deletions website/docs/tutorials/react-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,19 @@ Sometimes you can't use [`Trans`](/docs/ref/macro.md#trans) component, for examp
<img src="..." alt="Image caption" />
```

In such case you need to use the [`useLingui()`](/docs/ref/react.md#uselingui) hook with the [`msg`](/docs/ref/macro.md#definemessage) macro.
In such case you need to use the [`useLingui()`](/docs/ref/macro.md#uselingui) macro.

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

export default function ImageWithCaption() {
const { t } = useLingui();

return <img src="..." alt={t`Image caption`} />;
}
```

If `useLingui` macro is not available in your setup you can use the [`useLingui()`](/docs/ref/react.md#uselingui) runtime hook with the [`msg`](/docs/ref/macro.md#definemessage) macro.

```jsx
import { msg } from "@lingui/macro";
Expand Down Expand Up @@ -68,11 +80,11 @@ When you use [`t`](/docs/ref/macro.md#t) macro (and [`plural`](/docs/ref/macro.m
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.

```ts
import { msg } from "@lingui/macro";
import { msg, useLingui } from "@lingui/macro";
import { I18n } from "@lingui/core";

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

function MyComponent() {
Expand All @@ -84,6 +96,8 @@ function MyComponent() {
}
```

Note that we import `useLingui` component from `@lingui/macro`. There is also a runtime version of `useLingui` hook exported from `@lingui/react`. In the case above, it doesn't matter what version to choose since we use only `i18n` object which is presented in both.

:::

:::note
Expand Down Expand Up @@ -148,49 +162,6 @@ export function getTranslatedColorNames() {
}
```

### Passing messages as props

It's often convenient to pass messages around as component props, for example as a "label" prop on a button. The easiest way to do this is to pass a [`Trans`](/docs/ref/macro.md#trans) element as the prop:

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

export default function FancyButton(props) {
return <button>{props.label}</button>;
}

export function LoginLogoutButtons(props) {
return (
<div>
<FancyButton label={<Trans>Log in</Trans>} />
<FancyButton label={<Trans>Log out</Trans>} />
</div>
);
}
```

If you need the prop to be displayed as a string-only translation, you can pass a message tagged with the [`msg`](/docs/ref/macro.md#defineMessage) macro:

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

export default function ImageWithCaption(props) {
return <img src="..." alt={props.caption} />;
}

export function HappySad(props) {
const { _ } = useLingui();

return (
<div>
<ImageWithCaption caption={_(msg`I'm so happy!`)} />
<ImageWithCaption caption={_(msg`I'm so sad.`)} />
</div>
);
}
```

### Picking a message based on a variable

Sometimes you need to pick 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 representing the current status.
Expand Down Expand Up @@ -272,3 +243,22 @@ export function Welcome() {
return <div>{welcome}</div>;
}
```

:::note
Note on [`useLingui`](ref/macro#uselingui) macro usage. The `t` function destructured from this hook, behaves the same way as `_` from runtime [`useLingui`](/ref/react#uselingui) counterpart, so you can safely use it in the dependency array.

```ts
import { useLingui } from "@lingui/macro";

export function Welcome() {
const { t } = useLingui();

const welcome = useMemo(() => {
return t`Welcome!`;
}, [t]);

return <div>{welcome}</div>;
}
```

:::
48 changes: 43 additions & 5 deletions website/docs/tutorials/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,45 @@ It isn't necessary to extract/translate messages one by one. This usually happen

For more info about CLI, checkout the [CLI tutorial](/docs/tutorials/cli.md).

## Non-JSX Translation

Until now learned how to translate string inside a JSX elements, but what if we want to translate something that is not in a JSX? Or pass a translation as prop to another component?

We have this piece of code in our example:

```js
const markAsRead = () => {
alert("Marked as read.");
};
```

To translate it we will use a `useLingui` macro hook:

```js
import { useLingui } from '@lingui/macro';

...

const { t } = useLingui();

const markAsRead = () => {
alert(t`Marked as read.`);
};
```

Now the `Marked as read.` message would be picked up by extractor, and available for translation in the catalog.

You also could pass variables and use any other macro in the message.

```jsx
const { t } = useLingui();

const markAsRead = () => {
const userName = "User1234";
alert(t`Hello {userName}, your messages marked as read!`);
};
```

## Formatting

Let's move on to another paragraph in our project. This paragraph has some variables, some HTML and components inside:
Expand Down Expand Up @@ -633,7 +672,7 @@ The last message in our component is again a bit specific:
`lastLogin` is a date object, and we need to format it properly. Dates are formatted differently in different languages, but we don't have to do this manually. The heavy lifting is done by the [Intl object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl), we'll just use [`i18n.date()`](/docs/ref/core.md#i18n.date) function. The `i18n` object can be accessed by [`useLingui`](/docs/ref/react.md#uselingui) hook:
```jsx title="src/Inbox.js"
import { useLingui } from "@lingui/react";
import { useLingui } from "@lingui/macro";
export default function Inbox() {
const { i18n } = useLingui();
Expand All @@ -658,16 +697,15 @@ After all modifications, the final component with i18n looks like this:
```jsx title="src/Inbox.js"
import React from "react";
import { Trans, Plural } from "@lingui/macro";
import { useLingui } from "@lingui/react";
import { Trans, Plural, useLingui } from "@lingui/macro";
export default function Inbox() {
const { i18n } = useLingui();
const { i18n, t } = useLingui();
const messages = [{}, {}];
const messagesCount = messages.length;
const lastLogin = new Date();
const markAsRead = () => {
alert("Marked as read.");
alert(t`Marked as read.`);
};
return (
Expand Down

0 comments on commit 17621bf

Please sign in to comment.