Skip to content

Commit

Permalink
docs: update for v5 (#1992)
Browse files Browse the repository at this point in the history
Co-authored-by: Vojtech Novak <[email protected]>
  • Loading branch information
timofei-iatsenko and vonovak authored Aug 22, 2024
1 parent 894759c commit ae82906
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 157 deletions.
1 change: 1 addition & 0 deletions website/.remarkrc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default {
],

// Rules enabled by default by presents above that we don't want
["remark-lint-code-block-style", false],
["remark-lint-file-extension", false],
["remark-lint-heading-style", false],
["remark-lint-list-item-indent", false],
Expand Down
22 changes: 0 additions & 22 deletions website/docs/guides/typescript.md

This file was deleted.

18 changes: 8 additions & 10 deletions website/docs/ref/macro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ import TabItem from "@theme/TabItem";

<Tabs groupId="babel-swc">
<TabItem value="babel" label="Babel" default>
Babel macros require [babel-plugin-macros](https://github.com/kentcdodds/babel-plugin-macros) to work. If you use a framework (for example GatsbyJS, Create React App > 2.0) you might already have macros enabled. Otherwise, install it as any other Babel plugin:
- Install `babel-plugin-macros` as a dev dependency and `@lingui/macro` as dependency:
Lingui macros require `@lingui/babel-plugin-lingui-macro` or [babel-plugin-macros](https://github.com/kentcdodds/babel-plugin-macros) to work.

The recommended way is to use `@lingui/babel-plugin-lingui-macro` directly, but if you use a framework which is does not allow to change babel configuration (for example Create React App > 2.0), that frameworks might support `babel-plugin-macros` out of the box.

- Install `@lingui/babel-plugin-lingui-macro` as a dev dependency:

```bash npm2yarn
npm install --save-dev babel-plugin-macros
npm install --save @lingui/macro
```

- Add `macros` to the top of plugins section in your Babel config:
- Add `@lingui/babel-plugin-lingui-macro` to the top of plugins section in your Babel config:

```json
{
"plugins": ["macros"]
"plugins": ["@lingui/babel-plugin-lingui-macro"]
}
```

Expand All @@ -46,10 +48,6 @@ import TabItem from "@theme/TabItem";
</TabItem>
</Tabs>

:::note
It's recommended to install `@lingui/macro` package as a production dependency rather than development one to avoid `import/no-extraneous-dependencies` errors in ESLint.
:::

:::tip
Don't miss the [Lingui ESLint Plugin](/docs/ref/eslint-plugin.md) which can help you find and prevent common l10n mistakes in your code.
:::
Expand Down Expand Up @@ -1026,7 +1024,7 @@ Use `<Select>` inside `<Trans>` macro if you want to provide `id`, `context` or
### `useLingui`

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

Gives access to a [`t`](/docs/ref/macro.mdx#t) macro bound to the local i18n object passed from React context.
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 @@ -206,7 +206,7 @@ It's also possible to use `Trans` component directly without macros. In that cas

### Plurals

If you cannot use [@lingui/macro](/docs/ref/macro.mdx) for some reason, you can render plurals using the plain Trans component like this:
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:

```jsx
import React from "react";
Expand Down
185 changes: 96 additions & 89 deletions website/docs/releases/migration-5.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,157 +4,164 @@

TBD

## Split React and JS Macro into separate packages
## React and JS Macros were split to separate packages

The current Lingui macro is tightly coupled with React, which poses problems for developers using vanilla JavaScript or other frameworks such as Vue.
The previous Lingui macro was tightly coupled with React, which posed problems for developers using Lingui with vanilla JavaScript or other frameworks such as Vue.

#### Issues

- The existing macro assumes React usage, which isn't ideal for non-React projects.
- Using `@types/react` and `@lingui/react` adds React dependencies to projects that don't use React, which is unnecessary.

#### Benefits of the Split

- Allows the macro to be used with other JSX-based frameworks in the future.
- Removes unwanted React dependencies, making Lingui more versatile.

#### Solution

To address this, the macro package has been split into two separate packages:
The macro package has been split into two separate entrypoints from existing packages:

- `@lingui/react/macro`
- `@lingui/core/macro`

Also, the transformation code has been extracted into a separate Babel plugin `@lingui/babel-plugin-lingui-macro`, which can be used independently of `babel-plugin-macros`.

**Example Usage:**

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

const colors = [msg`Red`, msg`Yellow`, msg`Green`];

function MyComponent() {
<Trans>Hi, my name is {name}</Trans>
<span title={t`Title`} />
<Trans>Hi, my name is {name}</Trans>;
}
```

#### Migration Strategy
### Migration

This is not a breaking change.

Imports from `@lingui/macro` still work, but are marked as deprecated. They will be removed in the next major release.

- Users can migrate gradually by starting with `@lingui/macro`, which consolidates macros from both core and React-specific packages.
- Over time, users are encouraged to migrate directly to `@lingui/core/macro` or `@lingui/react/macro` depending on their specific needs.
You can use an automatic [codemod](https://www.npmjs.com/package/@lingui/codemods) to convert your codebase to the new imports:

```bash
npx @lingui/codemods split-macro-imports <path>
```

:::tip
There is a Codemod [@lingui/codemods](https://www.npmjs.com/package/@lingui/codemods) to help you with the migration. Check out the [`split-macro-imports.ts`](https://github.com/lingui/codemods/blob/main/transforms/split-macro-imports.ts) for more details.
:::
After running this codemod you can drop `@lingui/macro` from your dependencies.

## Full Vue.js support

TBD ([#1925](https://github.com/lingui/js-lingui/pull/1925))

## Whitespaces handling changes
## Changes in whitespaces handling

The current whitespace handling in Lingui, specifically through `normalizeWhitespace`, has been identified as problematic due to occasional incorrect processing of whitespace normalization. This proposal suggests a revised approach that uses stricter rules based on JSX node types to ensure more accurate and predictable whitespace handling.
### Robust whitespace cleaning in JSX

#### Issues
Whitespace cleaning in JSX expression is unavoidable, otherwise formatting your JSX code, for example with Prettier, will cause changes in extracted message.

- The existing `normalizeWhitespace` function uses regex to manage whitespace, which sometimes leads to unintended normalization results.
- Complex JSX structures and interactions with Babel transformations can further complicate whitespace management.
- The current method merges various JSX node types into a single string before normalization, potentially losing context-specific whitespace information.
```jsx
// prettier-ignore
<Trans>
Hello◦{""}◦world
</Trans>

// should be extracted as
// "Hello◦◦◦world"
// without new lines in start and end of tag
```

Previously, Lingui used a regexp based approach to normalize whitespaces in the JSX nodes processed by macro. That approach was not perfect and didn't follow JSX language grammar, which sometimes lead to unexpected results.

#### Solution
With v5, Lingui uses the same set of rules to clean whitespaces as it's done in JSX. This leads to more predictable results without unwanted cleaning of whitespaces.

- **Utilize JSX Node Information:**
- Instead of treating JSX content as a single string for normalization, use specific JSX node types (e.g., JSXText, JSXExpressionContainer) to apply appropriate whitespace rules.
- Implement a function (cleanJSXElementLiteralChild) that adheres to JSX's intrinsic whitespace handling rules, similar to those defined in Babel's sources.
### No whitespaces cleaning in `t` and other JS macros

**Before:**
Based on feedback from developers, it was agreed that whitespace cleaning in the JS macros is redundant and counterintuitive.

```ts
<Trans>Hello◦{""}◦world</Trans>
// -> normalizeWhitespace("Hello◦◦◦world") we lost here information that middle space came from explicit `{"◦"}`
```js
t`Label:◦` + value;
```

**After:**
Note the space after ":" - it's expected by developer to stay in the extracted string, but "normalization" would previously remove it.

Other example would be markdown, or any reason for which developer wants to keep the original formatting.

Starting from v5, cleaning whitespaces for JS macros is completely removed.

### Migration

This is a breaking change. Some messages in catalogs might be extracted with different whitespaces and therefore with different ids.

There is no way to automatically convert your catalogs to pick-up existing translation.

If you use TMS (such as Crowdin or Translation.io), migration should be pretty simple. Use Translation Memory feature (or analog).

If you don't use a TMS you will need to migrate catalogs manually.

```ts
<Trans>Hello◦{""}◦world</Trans>
## Standalone `babel-plugin-lingui-macro`

// there are strict rules how whitespaces processed in JSXText,
// use `cleanJSXElementLiteralChild` function which follows this rules (taken from babel's sources)
cleanJSXElementLiteralChild("processHello◦") // JSXText
{""} // JSXExpressionContainer - arbitary content, left as is
cleanJSXElementLiteralChild("◦world") // JSXText
Starting with this version there two ways of using Lingui macro with Babel. With `babel-macro-plugin` and with `babel-plugin-lingui-macro`.

```bash npm2yarn
npm install --save-dev @lingui/babel-plugin-lingui-macro
```

This revised approach to whitespace handling in Lingui addresses current limitations and aligns with best practices observed in JSX processing. The processing now mirrors how JSX handles whitespace.
### Migration

If you have access to the babel configuration and don't use any other macro in your code, you can drop `babel-macro-plugin` and add `babel-plugin-lingui-macro` to your babel config.

You will benefit from a slightly faster transpiling time and more configuration options for the plugin which are not available for `babel-macro-plugin` version.

## Introducing `useLingui` Macro for Simplified Localization in React
## Introducing `useLingui` macro

The `useLingui` macro simplifies the handling of non-JSX messages in React components, making internationalization (i18n) integration easy. It replaces direct `t` function calls with cleaner syntax and supports advanced usage within React hooks.
The `useLingui` macro simplify working with non-jsx messages in react components.

**For example:**
Before this macro you had to combine `t` or `msg` macro with the i18n instance returned from `useLingui` hook:

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

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

const a = t(i18n)`Text`;
// or
const b = _(msg`Text`);
}
```

// ↓ ↓ ↓ ↓ ↓ ↓
With the new macro code above simplifies to:

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

import { useLingui } from "@lingui/react";
function MyComponent() {
const { _: _t } = useLingui();
const a = _t(
/*i18n*/
{
id: "xeiujy",
message: "Text",
}
);
const { t } = useLingui();

const a = t`Text`;
}
```

As a result, it reduces complexity by consolidating i18n handling into a single macro call.
Note that `useLingui()` is imported from `@lingui/react/macro`, because it's a macro and not a runtime function. This will be transpiled to the regular `useLingui` from `@lingui/react` under the hood by Lingui.

## Dependency tree crawling extractor improvements

TBD ([#1958](https://github.com/lingui/js-lingui/pull/1958))

## Improved context

This proposal improves Lingui messages by automatically adding placeholder values as comments in PO files. This improves clarity for translators and AI tools. This feature provides critical **context** to support accurate translations.
## Print placeholder values for better translation context

For example:
If the message contains unnamed placeholders such as `{0}`, Lingui will print their values into PO comments, so that translators and AI get more context on what the placeholder is about.

```js title="Message"
t`from ${myTrip.date}`;
```js
t`Hello ${user.name} ${value}`;
```

```po title="PO file" {1}
#. placeholder {0}: myTrip.date
msgid "from {0}"
```

In case the string is used in multiple places with different values, the context will be more specific:

```js title="Messages"
t`from ${myTrip.date}`;
This will be extracted as

// ...
Before:

t`from ${eventDate}`;
```po
msgid "Hello {0} {value}"
```

```po title="PO file" {1,2}
#. placeholder {0}: myTrip.date
#. placeholder {0}: eventDate
msgid "from {0}"
```
After:

By improving the handling of placeholder contexts, Lingui enhances the **usability for translators and AI**, promoting more accurate and efficient localization processes.
```po
#. placeholder {0}: user.name
msgid "Hello {0} {value}"
```

## Deprecations

Expand Down
8 changes: 4 additions & 4 deletions website/docs/tutorials/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ Let's start with the three major packages:

> The core library responsible for translation and handling of message catalogs
`@lingui/macro`
`@lingui/babel-plugin-lingui-macro`

> Transforms messages wrapped in tagged template literals to ICU MessageFormat and validates them.
1. Install `@lingui/cli`, `@lingui/macro`, `babel-plugin-macros` and Babel core packages as a development dependencies and `@lingui/core` as a runtime dependency:
1. Install `@lingui/cli`, `@lingui/babel-plugin-lingui-macro` and Babel core packages as development dependencies and `@lingui/core` as a runtime dependency:

```bash npm2yarn
npm install --save-dev @lingui/cli @lingui/macro babel-plugin-macros @babel/core
npm install --save-dev @lingui/cli @lingui/babel-plugin-lingui-macro @babel/core
npm install --save @lingui/core
```

2. Add `macros` plugin to Babel config (e.g: `.babelrc`):

```json
{
"plugins": ["macros"]
"plugins": ["@lingui/babel-plugin-lingui-macro"]
}
```

Expand Down
4 changes: 2 additions & 2 deletions website/docs/tutorials/react-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ First, we need to wrap our app with [`I18nProvider`](/docs/ref/react.md#i18nprov

```tsx
import { I18nProvider } from "@lingui/react";
import { Trans } from "@lingui/macro";
import { Trans } from "@lingui/react/macro";
import { i18n } from "@lingui/core";
import { Text } from "react-native";

Expand All @@ -126,7 +126,7 @@ Translating the heading is done. Now, let's translate the `title` prop in the `<
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
import { useLingui } from '@lingui/macro';
import { useLingui } from '@lingui/react/macro';

const { t } = useLingui()
...
Expand Down
2 changes: 1 addition & 1 deletion website/docs/tutorials/react-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function MyComponent() {
}
```

Note that we import `useLingui` 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 that we import `useLingui` from `@lingui/react/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 returned by both.

:::

Expand Down
Loading

0 comments on commit ae82906

Please sign in to comment.