@sheet-i18n/react 1.5.3 β 1.6.0-canary.0
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 +201 -23
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ This package provides tools to handle translations in React applications using c
|
|
|
13
13
|
- **`IntlProvider`**: _React Translation Provider_ for managing current locale.
|
|
14
14
|
- **`useTranslation`**: _Client Side Translation Hook_ for easy access to translation messages on the client side.
|
|
15
15
|
- **`getTranslation`**: _Static Translation Function_ for easy access to translation messages on Static module files.
|
|
16
|
+
- **`ruleFactory`**: _Rule Factory Function_ for creating custom translation rules with conditional logic.
|
|
16
17
|
|
|
17
18
|
## π Getting Started(Manually)
|
|
18
19
|
|
|
@@ -232,6 +233,8 @@ Generates React context, including the `IntlProvider` and `useTranslation`.
|
|
|
232
233
|
#### Parameters:
|
|
233
234
|
|
|
234
235
|
- **`i18nStore`**: Instance of `I18nStore`.
|
|
236
|
+
- **`plugins`** (optional): Plugin configuration object.
|
|
237
|
+
- **`rules`** (optional): Custom rules object for conditional translations. See [Plugins](#-plugins) section for details.
|
|
235
238
|
|
|
236
239
|
> β οΈ Caveats:
|
|
237
240
|
>
|
|
@@ -303,31 +306,93 @@ A function to access translations in the environment where cannot use react cont
|
|
|
303
306
|
|
|
304
307
|
### `t Function`
|
|
305
308
|
|
|
306
|
-
The t function is used to retrieve
|
|
309
|
+
The `t` function is used to retrieve translation strings based on keys and optionally interpolate variables. It provides flexibility to include dynamic values, such as plain strings or React components, for enhanced localization capabilities.
|
|
307
310
|
|
|
308
|
-
####
|
|
311
|
+
#### **Overview: `t()`, `t.rule()`, and `t.dynamic()`**
|
|
312
|
+
|
|
313
|
+
| Method | Use Case | Key Type | When to Use |
|
|
314
|
+
| ----------------------------------- | ------------------------------------------ | ------------------------------------ | ------------------------------------------------------------------- |
|
|
315
|
+
| **`t(key, values?)`** | Standard translation with explicit keys | Static (known at build time) | When you know the translation key beforehand |
|
|
316
|
+
| **`t.rule(ruleKey, values?)`** | Conditional translation using custom rules | Determined by rule function | When you need conditional logic (pluralization, gender-based, etc.) |
|
|
317
|
+
| **`t.dynamic(id, values?, opts?)`** | Translation with runtime keys | Dynamic (from API, user input, etc.) | When the translation key comes from runtime data |
|
|
318
|
+
|
|
319
|
+
#### **`t()` - Standard Translation**
|
|
320
|
+
|
|
321
|
+
Retrieve translations for explicit keys that are known at build time.
|
|
322
|
+
|
|
323
|
+
##### Parameters:
|
|
309
324
|
|
|
310
|
-
- key (string): The translation key to retrieve the localized string.
|
|
325
|
+
- **`key`** (string): The translation key to retrieve the localized string.
|
|
326
|
+
- **`values`** (object, optional): An object containing key-value pairs to interpolate into the translation string.
|
|
327
|
+
|
|
328
|
+
##### Examples:
|
|
311
329
|
|
|
312
330
|
```tsx
|
|
313
|
-
const
|
|
331
|
+
const { t } = useTranslation('header');
|
|
332
|
+
|
|
333
|
+
// Simple translation
|
|
334
|
+
const loginText = t('login'); // "Login" or "λ‘κ·ΈμΈ"
|
|
335
|
+
|
|
336
|
+
// Translation with interpolation
|
|
337
|
+
const welcomeMessage = t('{username} shown', { username: 'John Doe' });
|
|
338
|
+
// Result: "John Doe shown"
|
|
339
|
+
|
|
340
|
+
// Interpolation with React components
|
|
341
|
+
const message = t('{username} shown', { username: <Username /> });
|
|
314
342
|
```
|
|
315
343
|
|
|
316
|
-
|
|
344
|
+
π‘ **Note**: The values object can contain any type of data, including React components.
|
|
345
|
+
|
|
346
|
+
#### **`t.rule()` - Conditional Translation with Custom Rules**
|
|
347
|
+
|
|
348
|
+
Use custom rules for conditional translations based on dynamic values. This method is available when custom rules are registered via the `createI18nContext` plugins option.
|
|
349
|
+
|
|
350
|
+
##### Parameters:
|
|
351
|
+
|
|
352
|
+
- **`ruleKey`** (string): The key of the registered custom rule.
|
|
353
|
+
- **`values`** (object, optional): An object containing values to be passed to the rule function and used for interpolation.
|
|
354
|
+
|
|
355
|
+
##### Examples:
|
|
317
356
|
|
|
318
357
|
```tsx
|
|
319
|
-
//
|
|
320
|
-
const
|
|
358
|
+
// Assuming custom rules are registered
|
|
359
|
+
const { t } = useTranslation('landing');
|
|
360
|
+
|
|
361
|
+
// Call rule with values
|
|
362
|
+
const message = t.rule('plural', { age: 21 });
|
|
363
|
+
// The rule function determines which translation key to use based on age
|
|
321
364
|
```
|
|
322
365
|
|
|
323
|
-
π‘ Note
|
|
366
|
+
π‘ **Note**: `t.rule()` works exactly like `t()` in terms of interpolation. If the translation key returned by the rule function contains `{slot}` placeholders, they will be automatically replaced using the values object passed to `t.rule()`.
|
|
367
|
+
|
|
368
|
+
For more details, see the [Plugins](#-plugins) section.
|
|
369
|
+
|
|
370
|
+
#### **`t.dynamic()` - Runtime Key Translation**
|
|
371
|
+
|
|
372
|
+
Resolve translation keys that are not known at build time (e.g., values coming from API responses, user input, or other runtime sources).
|
|
373
|
+
|
|
374
|
+
##### Parameters:
|
|
375
|
+
|
|
376
|
+
- **`id`** (string): A runtime string to match against the current locale's translation keys.
|
|
377
|
+
- **`values`** (object, optional): Interpolation values, identical to `t()`.
|
|
378
|
+
- **`opts`** (object, optional): Formatter options.
|
|
379
|
+
|
|
380
|
+
##### Examples:
|
|
324
381
|
|
|
325
382
|
```tsx
|
|
326
|
-
|
|
327
|
-
const
|
|
383
|
+
const { t } = useTranslation('header');
|
|
384
|
+
const { data } = useQuery(...queryOptions);
|
|
385
|
+
|
|
386
|
+
// Runtime key from API response
|
|
387
|
+
const deviceName = data?.device?.name; // e.g., "smartphone"
|
|
388
|
+
|
|
389
|
+
// Will translate the runtime key if it exists in the current locale
|
|
390
|
+
const label = t.dynamic(deviceName);
|
|
391
|
+
// If "smartphone" exists in locale JSON, returns translated value
|
|
392
|
+
// Otherwise, returns "smartphone" as fallback
|
|
328
393
|
```
|
|
329
394
|
|
|
330
|
-
|
|
395
|
+
π‘ **Tip**: Ensure your locale JSON contains possible runtime keys; otherwise `t.dynamic` will fall back to the provided id string.
|
|
331
396
|
|
|
332
397
|
## π Best Practices of Translation utilities
|
|
333
398
|
|
|
@@ -383,11 +448,6 @@ return <div>{t.dynamic(deviceName)}</div>;
|
|
|
383
448
|
|
|
384
449
|
The `getTranslation` function allows you to use translations outside of React components, such as in static configuration files, constants, or utility modules.
|
|
385
450
|
|
|
386
|
-
It provide two possible supports
|
|
387
|
-
|
|
388
|
-
1. **`t` (Synchronous Translation)** β Use when translation values are available **at runtime**.
|
|
389
|
-
2. **`t.promise` (Asynchronous Translation)** β Use when the moduleβs evaluation order is uncertain.
|
|
390
|
-
|
|
391
451
|
#### **β
Usage Scenarios**
|
|
392
452
|
|
|
393
453
|
#### **[Scenario 1]: Context where the call expression of `t` function is evaluated at runtime**
|
|
@@ -422,32 +482,46 @@ export default function App() {
|
|
|
422
482
|
|
|
423
483
|
- If the module is **imported dynamically in a client-side component**, the evaluation order of `getTranslation` and `t` call expression may not be guaranteed.
|
|
424
484
|
- Since JavaScript **evaluates modules at import time**, it may attempt to access translation values before `IntlProvider` has fully initialized the locale.
|
|
425
|
-
- In this case, use **`
|
|
485
|
+
- In this case, use **`getTranslation`** and **`watch`** CLI for easy translation workflow.
|
|
426
486
|
|
|
427
487
|
#### **Example**
|
|
428
488
|
|
|
429
489
|
```tsx
|
|
430
490
|
// module.ts
|
|
431
|
-
//
|
|
491
|
+
// the "t" function from "getTranslation" is used as the "marker" of "watch" CLI
|
|
432
492
|
import { getTranslation } from './i18nContext';
|
|
433
493
|
|
|
434
494
|
const { t } = getTranslation('header');
|
|
435
495
|
|
|
436
496
|
export const STATUS_CATEGORY = [
|
|
437
|
-
t
|
|
438
|
-
t
|
|
497
|
+
t('Total Energy Usage'), // Marked
|
|
498
|
+
t('Total Waste Usage'), // Marked
|
|
439
499
|
];
|
|
440
500
|
|
|
501
|
+
// Pre-requisite: install @sheet-i18n/cli and run `npx sheet-i18n watch`
|
|
502
|
+
// You can register your translation data with ease
|
|
503
|
+
Detected Translations:
|
|
504
|
+
|
|
505
|
+
π [Sheet Title]: header
|
|
506
|
+
- Total Energy Usage
|
|
507
|
+
- Total Waste Usage
|
|
508
|
+
|
|
509
|
+
# You can proceed using the shortcuts below:
|
|
510
|
+
- Press <Shift + R> to register the detected changes. // <-- you can register your translation data
|
|
511
|
+
- Press <Ctrl + C> to cancel the watch command.
|
|
512
|
+
|
|
441
513
|
// App.tsx
|
|
442
|
-
//
|
|
443
|
-
//
|
|
514
|
+
// After update of translation data, t.dynamic will resolve the translations
|
|
515
|
+
// If you want to translate the text with type safety, use "t" function which works like t.dynamic after register and import your translation data.
|
|
444
516
|
import { STATUS_CATEGORY } from './module.ts';
|
|
445
517
|
|
|
446
518
|
export default function App() {
|
|
519
|
+
const { t } = useTranslation('header');
|
|
520
|
+
|
|
447
521
|
return (
|
|
448
522
|
<div>
|
|
449
523
|
{STATUS_CATEGORY.map((item, index) => {
|
|
450
|
-
return <div key={index}>{item}</div>;
|
|
524
|
+
return <div key={index}>{t.dynamic(item)}</div>;
|
|
451
525
|
})}
|
|
452
526
|
</div>
|
|
453
527
|
);
|
|
@@ -586,6 +660,110 @@ const customStorageManager = getLocaleStorageManager(
|
|
|
586
660
|
- **Custom Storage**: Implement your own persistence strategy (e.g., server-side storage, encrypted storage)
|
|
587
661
|
- **Memory Storage**: No persistence (for testing or temporary use cases)
|
|
588
662
|
|
|
663
|
+
## π Plugins
|
|
664
|
+
|
|
665
|
+
sheet-i18n provides an extensible plugin system that allows you to customize translation logic and easily implement conditional translations or complex translation rules.
|
|
666
|
+
|
|
667
|
+
### π― Custom Rules Plugin
|
|
668
|
+
|
|
669
|
+
**Custom Rules** is a plugin that enables dynamic selection of different translation keys based on conditions. This allows you to implement various scenarios such as pluralization, gender-based translations, age-based message changes, and more.
|
|
670
|
+
|
|
671
|
+
#### **Key Features**
|
|
672
|
+
|
|
673
|
+
- β
**Conditional Translation**: Automatically select different translation keys based on values
|
|
674
|
+
- β
**Interpolation Support**: Same `{slot}` replacement functionality as the `t` function
|
|
675
|
+
- β
**Extensible**: Combine multiple rules to implement complex logic
|
|
676
|
+
|
|
677
|
+
##### **Key Points**
|
|
678
|
+
|
|
679
|
+
```tsx
|
|
680
|
+
import { ruleFactory } from '@sheet-i18n/react';
|
|
681
|
+
import { i18nStore } from './i18nStore';
|
|
682
|
+
|
|
683
|
+
// Step 1: Create factory service
|
|
684
|
+
// ruleFactory takes your i18nStore and returns an object with createRule method
|
|
685
|
+
const { createRule } = ruleFactory(i18nStore);
|
|
686
|
+
|
|
687
|
+
// Step 2: Use createRule to define custom rules
|
|
688
|
+
// `createRule` can take a rule function and support the current localeSet data use registered in the localeSet of `i18nStore`
|
|
689
|
+
// In the body of the rule function, you can defined the translation logic as you want
|
|
690
|
+
|
|
691
|
+
// π‘ Note: Highly recommended to return the translation key from the localeSet
|
|
692
|
+
// When you use `t.rule()` from the component, the translation key will be resolved and the translated text will be returned
|
|
693
|
+
// If you return the normal string, that string will be used as the translation key
|
|
694
|
+
// and If no matched translation key is found, the string will be used rendered
|
|
695
|
+
const myRule = createRule<{ count: number }>((values, localeSet) => {
|
|
696
|
+
if (values.count > 10) {
|
|
697
|
+
return localeSet.sheetTitle['many_items'];
|
|
698
|
+
}
|
|
699
|
+
return localeSet.sheetTitle['few_items'];
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
##### **Complete Flow Example**
|
|
704
|
+
|
|
705
|
+
```tsx
|
|
706
|
+
// Translation data example from your sheet
|
|
707
|
+
// en.json
|
|
708
|
+
{
|
|
709
|
+
...
|
|
710
|
+
"userSheet": {
|
|
711
|
+
"adult_message": "You are an adult. Your age is {age}",
|
|
712
|
+
"youth_message": "You are a youth. Your age is {age}"
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// 1. Initialize i18nStore
|
|
717
|
+
const i18nStore = new I18nStore({
|
|
718
|
+
/* ... */
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
// 2. Create factory service (binds createRule to i18nStore)
|
|
722
|
+
const { createRule } = ruleFactory(i18nStore);
|
|
723
|
+
|
|
724
|
+
// 3. Define custom rules using createRule
|
|
725
|
+
export const customRules = {
|
|
726
|
+
ageRule: createRule<{ age: number }>((values, localeSet) => {
|
|
727
|
+
if (values.age > 20) {
|
|
728
|
+
return localeSet.userSheet['adult_message'];
|
|
729
|
+
}
|
|
730
|
+
return localeSet.userSheet['youth_message'];
|
|
731
|
+
}),
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
// 4. Register rules in context
|
|
735
|
+
const { useTranslation } = createI18nContext(i18nStore, { rules: customRules });
|
|
736
|
+
|
|
737
|
+
// 5. Use in components
|
|
738
|
+
const { t } = useTranslation('userSheet');
|
|
739
|
+
const translatedText = t.rule('ageRule', { age: 25 }); // 'You are an adult. Your age is 25'
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
π‘ **Core Concept**:
|
|
743
|
+
|
|
744
|
+
- `localeSet` contains the complete translation data for the current locale, accessible via `localeSet.landing['key_name']`.
|
|
745
|
+
- The returned translation key is processed the same way as the `t()` function to convert it to the final translated value.
|
|
746
|
+
- If the returned translation key contains `{slot}` placeholders, they will be automatically replaced using the `values` object passed to `t.rule()`.
|
|
747
|
+
|
|
748
|
+
π‘ **Important**: If you want to use auto-replaced interpolation, you should use the same sheetTitle in the `useTranslation` hook and the localeSet in the `t.rule` function
|
|
749
|
+
|
|
750
|
+
```ts
|
|
751
|
+
// Example
|
|
752
|
+
// you return the translation key from 'userSheet' in the localeSet
|
|
753
|
+
const customRules = {
|
|
754
|
+
ageRule: createRule<{ age: number }>((values, localeSet) => {
|
|
755
|
+
if (values.age > 20) {
|
|
756
|
+
return localeSet.userSheet['adult_message'];
|
|
757
|
+
}
|
|
758
|
+
return localeSet.userSheet['youth_message'];
|
|
759
|
+
}),
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// you should use the 't.rule' function from the same sheetTitle for the argument of `useTranslation`
|
|
763
|
+
const { t } = useTranslation('userSheet');
|
|
764
|
+
const translatedText = t.rule('ageRule', { age: 25 }); // 'You are an adult. Your age is 25'
|
|
765
|
+
```
|
|
766
|
+
|
|
589
767
|
## License π
|
|
590
768
|
|
|
591
769
|
This project is licensed under the ISC License. See the LICENSE file for details.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sheet-i18n/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-canary.0",
|
|
4
4
|
"description": "i18n client logic based on react",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"@sheet-i18n/typescript-config": "1.8.1"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@sheet-i18n/react-core": "1.
|
|
36
|
-
"@sheet-i18n/react-client": "1.
|
|
35
|
+
"@sheet-i18n/react-core": "1.6.0-canary.0",
|
|
36
|
+
"@sheet-i18n/react-client": "1.6.0-canary.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsup",
|