@nkzw/eslint-plugin-fbtee 1.2.1 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -26
- package/lib/index.cjs +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
_**fbtee** (Far Better Translations, Extended Edition) is an internationalization framework for JavaScript & React designed to be **powerful**, **flexible**, and **intuitive**._
|
|
4
4
|
|
|
5
|
-
## Why
|
|
5
|
+
## Why **fbtee**?
|
|
6
6
|
|
|
7
7
|
- **Inline translations for Better Developer Experience:** Embed translations directly into your code. No need to manage translation keys or wrap your code with `t()` functions. **fbtee** uses a compiler to extract strings from your code and prepare them for translation providers.
|
|
8
8
|
- **Proven in Production:** Built on Facebook's `fbt`, with over a decade of production usage, serving billions of users and two years of production usage in [Athena Crisis](https://athenacrisis.com).
|
|
9
9
|
- **Optimized Performance with IR:** Compiles translations into an Intermediate Representation (IR) for extracting strings, then optimizes the runtime output for performance.
|
|
10
10
|
- **Easy Setup:** Quick integration with tools like Babel and Vite means you can get started instantly.
|
|
11
11
|
|
|
12
|
-
## Status: Ready for Early Adopters
|
|
13
|
-
|
|
14
|
-
This is a fork of Facebook's original `fbt` library, which has been archived. The aim of this fork is to create the best and most modern internationalization library for JavaScript & React.
|
|
15
|
-
|
|
16
12
|
## Getting Started
|
|
17
13
|
|
|
18
14
|
Tired of setting up new projects? Check out these templates for web and React Native that come with **fbtee** pre-configured:
|
|
@@ -20,6 +16,13 @@ Tired of setting up new projects? Check out these templates for web and React Na
|
|
|
20
16
|
- [Web App Template](https://github.com/nkzw-tech/web-app-template)
|
|
21
17
|
- [Expo App Template](https://github.com/nkzw-tech/expo-app-template)
|
|
22
18
|
|
|
19
|
+
### Examples
|
|
20
|
+
|
|
21
|
+
Sometimes it's easiest to learn by example and copy-paste the setup from existing projects. Here are some examples of using **fbtee**:
|
|
22
|
+
|
|
23
|
+
- [Next.js App fbtee Example](https://github.com/cpojer/nextjs-fbtee-example) - A Next.js App Router example using **fbtee** with Server Components.
|
|
24
|
+
- [Athena Crisis](https://github.com/nkzw-tech/athena-crisis) - an open source video game using **fbtee**
|
|
25
|
+
|
|
23
26
|
### Installation
|
|
24
27
|
|
|
25
28
|
**fbtee** requires at least Node 22, and React 19 if you are using React.
|
|
@@ -28,14 +31,20 @@ Tired of setting up new projects? Check out these templates for web and React Na
|
|
|
28
31
|
npm install fbtee
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
In addition to `fbtee`, you need to install the Babel preset
|
|
34
|
+
In addition to `fbtee`, you need to install the Babel preset.
|
|
32
35
|
|
|
33
36
|
```bash
|
|
34
|
-
npm install -D @nkzw/babel-preset-fbtee
|
|
37
|
+
npm install -D @nkzw/babel-preset-fbtee
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
### Tooling Setup
|
|
38
41
|
|
|
42
|
+
If you are using Vite, install the React plugin for Vite:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -D @vitejs/plugin-react
|
|
46
|
+
```
|
|
47
|
+
|
|
39
48
|
In your `vite.config.ts`:
|
|
40
49
|
|
|
41
50
|
```ts
|
|
@@ -55,7 +64,7 @@ export default {
|
|
|
55
64
|
|
|
56
65
|
#### Using Babel directly instead of Vite's React Plugin
|
|
57
66
|
|
|
58
|
-
If you are not using `@vitejs/plugin-react`, for example because you are using the latest version of React Router in framework mode, you can use `vite-plugin-babel` instead:
|
|
67
|
+
If you are not using `@vitejs/plugin-react`, for example, because you are using the latest version of React Router in framework mode, you can use `vite-plugin-babel` instead:
|
|
59
68
|
|
|
60
69
|
```tsx
|
|
61
70
|
import fbteePreset from '@nkzw/babel-preset-fbtee';
|
|
@@ -73,6 +82,16 @@ export default defineConfig({
|
|
|
73
82
|
});
|
|
74
83
|
```
|
|
75
84
|
|
|
85
|
+
#### Using **fbtee** with Next.js
|
|
86
|
+
|
|
87
|
+
Create a `babel.config.js` file in the root of your Next.js project and add the **fbtee** preset:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
export default {
|
|
91
|
+
presets: ['next/babel', '@nkzw/babel-preset-fbtee'],
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
76
95
|
#### Scripts
|
|
77
96
|
|
|
78
97
|
**fbtee** uses two scripts to manage translations. These scripts help automate the process of collecting, creating, and compiling translations.
|
|
@@ -102,7 +121,7 @@ Now, run the collect command to set up the initial strings for translation:
|
|
|
102
121
|
pnpm fbtee collect
|
|
103
122
|
```
|
|
104
123
|
|
|
105
|
-
|
|
124
|
+
Add the files generated by these commands to your `.gitignore`:
|
|
106
125
|
|
|
107
126
|
```
|
|
108
127
|
.enum_manifest.json
|
|
@@ -110,14 +129,14 @@ source_strings.json
|
|
|
110
129
|
src/translations/
|
|
111
130
|
```
|
|
112
131
|
|
|
113
|
-
|
|
132
|
+
Because no translations exist yet, you can run this command to create an empty file for now:
|
|
114
133
|
|
|
115
134
|
```bash
|
|
116
135
|
mkdir -p translations
|
|
117
136
|
echo '{"fb-locale": "ja_JP", "translations": {}}' > translations/ja_JP.json
|
|
118
137
|
```
|
|
119
138
|
|
|
120
|
-
If you are not using a translation provider, you can also run `fbtee prepare-translations --
|
|
139
|
+
If you are not using a translation provider, you can also run `fbtee prepare-translations --locales ja_JP` to generate a JSON file that can be edited directly.
|
|
121
140
|
|
|
122
141
|
### App Setup
|
|
123
142
|
|
|
@@ -148,7 +167,7 @@ const loadLocale = async (locale: string) => {
|
|
|
148
167
|
};
|
|
149
168
|
|
|
150
169
|
const LocaleContext = createLocaleContext({
|
|
151
|
-
|
|
170
|
+
availableLanguages,
|
|
152
171
|
clientLocales: clientLocalesWeb, // or clientLocalesRN for React Native
|
|
153
172
|
loadLocale,
|
|
154
173
|
});
|
|
@@ -227,11 +246,19 @@ setupFbtee({
|
|
|
227
246
|
});
|
|
228
247
|
```
|
|
229
248
|
|
|
249
|
+
### Usage with Next.js
|
|
250
|
+
|
|
251
|
+
If you are using Next.js with App Router, check out the [Next.js App fbtee Example](https://github.com/cpojer/nextjs-fbtee-example). You'll need to set up a `<LocaleContext />` as a Client Component, and call `setupFbtee` in the root layout of your app for Server Component support.
|
|
252
|
+
|
|
253
|
+
When using Next.js with **fbtee**, translated strings are inserted when your Server Components are rendered. This means that changing locales on the client will not automatically update the Server Component's translated strings. To handle locale changes, you need to call a server action that updates the locale, and then re-render your app with the new locale, for example by reloading the page.
|
|
254
|
+
|
|
255
|
+
If you are exclusively using **fbtee** within Client Components, you can handle locale changes directly on the client only.
|
|
256
|
+
|
|
230
257
|
## Usage
|
|
231
258
|
|
|
232
259
|
_If you want to learn by example, check out the [examples](https://github.com/nkzw-tech/fbtee/tree/main/example) directory. You can also check out [Athena Crisis](https://github.com/nkzw-tech/athena-crisis), a large open source video game using **fbtee**_
|
|
233
260
|
|
|
234
|
-
With **fbtee**, all strings
|
|
261
|
+
With **fbtee**, all strings must be wrapped using `<fbt>` (for React/JSX) or `fbt()` (for JavaScript). This ensures strings can be extracted and translated properly. The `desc` attribute is required and provides context for translators, helping them understand the intended meaning of the string.
|
|
235
262
|
|
|
236
263
|
Here are some basic examples:
|
|
237
264
|
|
|
@@ -249,7 +276,39 @@ const Greeting = () => (
|
|
|
249
276
|
);
|
|
250
277
|
```
|
|
251
278
|
|
|
252
|
-
`<fbt>` is a special React component that marks text for translation. The
|
|
279
|
+
`<fbt>` is a special React component that marks text for translation. The **fbtee** compiler analyzes them to extract strings, and compiles them into an Intermediate Representation (IR). Here is a more complex example of what you can do with **fbtee**:
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
<fbt desc="Feed item">
|
|
283
|
+
<fbt:list items={users} name="userList" />{' '}
|
|
284
|
+
<fbt:plural
|
|
285
|
+
count={users.length}
|
|
286
|
+
many="are"
|
|
287
|
+
name="number of players"
|
|
288
|
+
showCount="no"
|
|
289
|
+
>
|
|
290
|
+
is
|
|
291
|
+
</fbt:plural>{' '}
|
|
292
|
+
playing on
|
|
293
|
+
<fbt:param name="mapName">{game.mapName}</fbt:param>
|
|
294
|
+
</fbt>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
_Note: `<fbt>` is auto-imported for you by the `@nkzw/babel-preset-fbtee` plugin._
|
|
298
|
+
|
|
299
|
+
This example highlights several features of **fbtee**:
|
|
300
|
+
|
|
301
|
+
- `<fbt:list>`: Renders a list of items, automatically handling conjunctions and delimiters.
|
|
302
|
+
- `<fbt:plural>`: Handles singular and plural forms based on a count value.
|
|
303
|
+
- `<fbt:param>`: Allows you to insert dynamic content into your strings, such as variables or React components.
|
|
304
|
+
|
|
305
|
+
With the above components, you can handle complex strings that are translatable into multiple languages while maintaining clarity and context for translators. This sentence structure supports many variations, such as "Alice is playing on Forest Battle.", or "Alice, Bob and Charlie are playing on Giant Crisis".
|
|
306
|
+
|
|
307
|
+
Let's look at each of these features in detail:
|
|
308
|
+
|
|
309
|
+
### Dynamic Content
|
|
310
|
+
|
|
311
|
+
**fbtee** supports dynamic content through <fbt:param> or by using other React components within your text. For example, if you want to greet a specific user based on a name passed as a prop, you can use `<fbt:param>`:
|
|
253
312
|
|
|
254
313
|
```tsx
|
|
255
314
|
const Greeting = ({ name }) => (
|
|
@@ -273,7 +332,74 @@ const Greeting = ({ name }) => (
|
|
|
273
332
|
);
|
|
274
333
|
```
|
|
275
334
|
|
|
276
|
-
|
|
335
|
+
### Lists
|
|
336
|
+
|
|
337
|
+
`<fbt:list>` is used to render a list of items with conjunctions and delimiters. It automatically handles the grammatical structure of the list based on the locale:
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
<fbt:list
|
|
341
|
+
conjunction="or"
|
|
342
|
+
delimiter="comma"
|
|
343
|
+
items={['Alice', 'Bob', <CharlieNameExampleComponent key="charlieUserID" />]}
|
|
344
|
+
name="userList"
|
|
345
|
+
/> // "Alice, Bob, or Charlie"
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The default conjunction is "and", and the default delimiter is "comma". You can use "or" or "none" as conjunction, and "bullet", "comma", or "semicolon" as delimiters. The `name` attribute is required to provide context for translators. **fbtee** also exports a `list` function that can be used in contexts outside of React:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { list } from 'fbtee';
|
|
352
|
+
|
|
353
|
+
const userList = list(['Alice', 'Bob', 'Charlie'], 'or', 'comma');
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Singular & Plural Forms
|
|
357
|
+
|
|
358
|
+
**fbtee** supports singular and plural forms using the `<fbt:plural>` component. While in English, the plural form is often just an "s" at the end of a word, in other languages, it can be more complex. **fbtee** handles this automatically based on the count value you provide. Here's an example:
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
<fbt desc="end turn confirmation">
|
|
362
|
+
Do you want to play against
|
|
363
|
+
<fbt:plural count={bots} many="bots" name="numberOfBots" showCount="ifMany">
|
|
364
|
+
a bot
|
|
365
|
+
</fbt:plural>?
|
|
366
|
+
</fbt>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
This sentence might be translated to one of the following variations:
|
|
370
|
+
|
|
371
|
+
- "Do you want to play against 1 bot?"
|
|
372
|
+
- "Do you want to play against 2 bots?"
|
|
373
|
+
|
|
374
|
+
`<fbt:plural>` expects the singular phrase as children, and an item `count` as prop. You can provide the plural form using the `many` prop. The `showCount` prop can be used to control whether the count should be displayed in the string. `ifMany` only shows the count in the plural case, while `yes` shows it in all cases, and `no` hides it completely. The `name` prop is required to provide context for translators.
|
|
375
|
+
|
|
376
|
+
### Using Pronouns
|
|
377
|
+
|
|
378
|
+
You can use `<fbt:pronoun>` to handle pronouns in your strings. This is particularly useful for gendered languages where the pronoun changes based on the subject:
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
<fbt desc="Photo sharing text">
|
|
382
|
+
<fbt:param name="name">{user.name}</fbt:param>
|
|
383
|
+
shared
|
|
384
|
+
<fbt:pronoun type="possessive" gender={user.pronounGender} human />
|
|
385
|
+
photo with you.
|
|
386
|
+
</fbt>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Plain Text Usage
|
|
390
|
+
|
|
391
|
+
In some situations, you may want to use **fbtee** to represent plain text strings without any React components, for example when using alert dialogs or HTML attributes like `placeholder`. For these situations, you can use the `fbs()` function, which is a subset of `fbt` that only supports plain text.
|
|
392
|
+
|
|
393
|
+
```tsx
|
|
394
|
+
import { fbs } from 'fbtee';
|
|
395
|
+
|
|
396
|
+
<input
|
|
397
|
+
type="text"
|
|
398
|
+
placeholder={fbs('Enter your name', 'Placeholder for name input')}
|
|
399
|
+
/>;
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Extracting Strings & Translating
|
|
277
403
|
|
|
278
404
|
After marking your strings for translation with `<fbt>`, run the following commands to extract, and compile translations:
|
|
279
405
|
|
|
@@ -281,9 +407,9 @@ After marking your strings for translation with `<fbt>`, run the following comma
|
|
|
281
407
|
pnpm fbtee collect
|
|
282
408
|
```
|
|
283
409
|
|
|
284
|
-
You can now upload the `source_strings.json` file to your translation provider
|
|
410
|
+
You can now upload the `source_strings.json` file to your translation provider, for example [Crowdin](https://crowdin.com/). If you'd like to manually edit the strings, you can use the `fbtee prepare-translations --locales de_DE` to generate a JSON file that can be edited directly.
|
|
285
411
|
|
|
286
|
-
|
|
412
|
+
#### Generated File Structure
|
|
287
413
|
|
|
288
414
|
Your `source_strings.json` might look like this:
|
|
289
415
|
|
|
@@ -356,24 +482,23 @@ And German (`translations/de_DE.json`) might look like this:
|
|
|
356
482
|
}
|
|
357
483
|
```
|
|
358
484
|
|
|
359
|
-
Once you have the translated strings stored in a `translations/` folder as JSON files, you can run the following command to generate the translations
|
|
485
|
+
Once you have the translated strings stored in a `translations/` folder as JSON files using the locale name, for example `en_US.json` or `de_DE.json`, you can run the following command to generate the translations for use in your app:
|
|
360
486
|
|
|
361
487
|
```bash
|
|
362
488
|
pnpm fbtee translate
|
|
363
489
|
```
|
|
364
490
|
|
|
365
|
-
|
|
491
|
+
By default, **fbtee** outputs the generated translations in `src/translations`. It will create one JSON file per locale. For example, if you have `translations/en_US.json` and `translations/de_DE.json`, it will generate `src/translations/en_US.json` and `src/translations/de_DE.json`. These files are an optimized representation of your translation file, ready to be used in your app:
|
|
366
492
|
|
|
367
493
|
```json
|
|
368
494
|
{
|
|
369
|
-
"de_DE": {
|
|
370
|
-
|
|
495
|
+
"de_DE": {
|
|
496
|
+
"2HVYhv": "Was kommt jetzt?"
|
|
497
|
+
}
|
|
371
498
|
}
|
|
372
499
|
```
|
|
373
500
|
|
|
374
|
-
After generating the
|
|
375
|
-
|
|
376
|
-
Since the `translations.json` is an auto-generated file part of your build process, the `fbtee translate` command should be added to your build step.
|
|
501
|
+
After generating the translation files, your app is ready to display translated content in other languages. Since the `src/translations` folder is auto-generated, it should be ignored by version control and be part of your build process.
|
|
377
502
|
|
|
378
503
|
## ESLint Plugin
|
|
379
504
|
|
|
@@ -401,7 +526,7 @@ If you want stricter enforcement of translation rules, you can use the strict co
|
|
|
401
526
|
}
|
|
402
527
|
```
|
|
403
528
|
|
|
404
|
-
|
|
529
|
+
Alternatively, if you'd like more granular control over the rules:
|
|
405
530
|
|
|
406
531
|
```js
|
|
407
532
|
{
|
|
@@ -423,7 +548,7 @@ The open-source version of `fbt`, however, became unmaintained, difficult to set
|
|
|
423
548
|
- **Easier Setup:** fbtee works with modern tools like Vite.
|
|
424
549
|
- **Statically Typed:** The fbtee compiler ensures correct usage of fbtee, library TypeScript types are provided, and an eslint plugin helps fix common mistakes.
|
|
425
550
|
- **Improved React Compatibility:** Removed React-specific hacks and added support for implicit React fragments (`<>`).
|
|
426
|
-
- **Enhanced Features:** Fixed and exported `
|
|
551
|
+
- **Enhanced Features:** Fixed and exported `intlList` as a new `<fbt:list>` construct, which was not functional in the original `fbt`.
|
|
427
552
|
- **Modernized Codebase:** Rewritten using TypeScript, ES modules (ESM), eslint, and modern JavaScript standards. Removed cruft and legacy code.
|
|
428
553
|
- **Updated Tooling:** Uses modern tools like pnpm, Vite, and esbuild for faster and more efficient development of **fbtee**.
|
|
429
554
|
|
package/lib/index.cjs
CHANGED
|
@@ -25,7 +25,7 @@ const __typescript_eslint_utils = __toESM(require("@typescript-eslint/utils"));
|
|
|
25
25
|
|
|
26
26
|
//#region package.json
|
|
27
27
|
var name = "@nkzw/eslint-plugin-fbtee";
|
|
28
|
-
var version = "1.2.
|
|
28
|
+
var version = "1.2.5";
|
|
29
29
|
var description = "";
|
|
30
30
|
var keywords = [];
|
|
31
31
|
var repository = {
|
package/lib/index.js
CHANGED