locadex 0.0.2-alpha.1 → 0.0.2-alpha.4
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/.locadex-mcp-stdio.json +9 -0
- package/.locadex-mcp.json +2 -3
- package/LICENSE.md +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +44 -9
- package/dist/cli.js.map +1 -1
- package/dist/commands/i18n.d.ts +2 -1
- package/dist/commands/i18n.d.ts.map +1 -1
- package/dist/commands/i18n.js +255 -140
- package/dist/commands/i18n.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +141 -86
- package/dist/commands/setup.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -68
- package/dist/index.js.map +1 -1
- package/dist/{utils/logging.d.ts → logging/console.d.ts} +9 -12
- package/dist/logging/console.d.ts.map +1 -0
- package/dist/logging/console.js +137 -0
- package/dist/logging/console.js.map +1 -0
- package/dist/logging/logger.d.ts +44 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +142 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/mcp/debugger.d.ts +3 -0
- package/dist/mcp/debugger.d.ts.map +1 -0
- package/dist/mcp/debugger.js +37 -0
- package/dist/mcp/debugger.js.map +1 -0
- package/dist/mcp/getDocs.d.ts.map +1 -0
- package/dist/mcp/getDocs.js +56 -0
- package/dist/mcp/getDocs.js.map +1 -0
- package/dist/mcp/getGuide.d.ts +5 -0
- package/dist/mcp/getGuide.d.ts.map +1 -0
- package/dist/mcp/getGuide.js +17 -0
- package/dist/mcp/getGuide.js.map +1 -0
- package/dist/{tools → mcp/tools}/docs.d.ts +3 -0
- package/dist/mcp/tools/docs.d.ts.map +1 -0
- package/dist/mcp/tools/docs.js +86 -0
- package/dist/mcp/tools/docs.js.map +1 -0
- package/dist/mcp/tools/guides.d.ts +11 -0
- package/dist/mcp/tools/guides.d.ts.map +1 -0
- package/dist/mcp/tools/guides.js +118 -0
- package/dist/mcp/tools/guides.js.map +1 -0
- package/dist/mcp-sse.d.ts +3 -0
- package/dist/mcp-sse.d.ts.map +1 -0
- package/dist/mcp-sse.js +95 -0
- package/dist/mcp-sse.js.map +1 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +34 -0
- package/dist/mcp.js.map +1 -0
- package/dist/prompts/system.d.ts +4 -0
- package/dist/prompts/system.d.ts.map +1 -0
- package/dist/prompts/system.js +17 -0
- package/dist/prompts/system.js.map +1 -0
- package/dist/telemetry.d.ts +11 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +104 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types/claude-sdk.d.ts +39 -0
- package/dist/types/claude-sdk.d.ts.map +1 -0
- package/dist/types/claude-sdk.js +5 -0
- package/dist/types/claude-sdk.js.map +1 -0
- package/dist/types/cli.d.ts +7 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +5 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/utils/agentManager.d.ts +34 -0
- package/dist/utils/agentManager.d.ts.map +1 -0
- package/dist/utils/agentManager.js +123 -0
- package/dist/utils/agentManager.js.map +1 -0
- package/dist/utils/claudeCode.d.ts +14 -6
- package/dist/utils/claudeCode.d.ts.map +1 -1
- package/dist/utils/claudeCode.js +170 -102
- package/dist/utils/claudeCode.js.map +1 -1
- package/dist/utils/dag/createDag.d.ts +24 -0
- package/dist/utils/dag/createDag.d.ts.map +1 -0
- package/dist/utils/dag/createDag.js +181 -0
- package/dist/utils/dag/createDag.js.map +1 -0
- package/dist/utils/debugLogger.d.ts +3 -0
- package/dist/utils/debugLogger.d.ts.map +1 -0
- package/dist/utils/debugLogger.js +36 -0
- package/dist/utils/debugLogger.js.map +1 -0
- package/dist/utils/fs/findConfigs.d.ts +11 -0
- package/dist/utils/fs/findConfigs.d.ts.map +1 -0
- package/dist/utils/fs/findConfigs.js +63 -0
- package/dist/utils/fs/findConfigs.js.map +1 -0
- package/dist/utils/fs/getFiles.d.ts +2 -0
- package/dist/utils/fs/getFiles.d.ts.map +1 -0
- package/dist/utils/fs/getFiles.js +8 -0
- package/dist/utils/fs/getFiles.js.map +1 -0
- package/dist/utils/fs/writeFiles.d.ts +2 -0
- package/dist/utils/fs/writeFiles.d.ts.map +1 -0
- package/dist/utils/fs/writeFiles.js +19 -0
- package/dist/utils/fs/writeFiles.js.map +1 -0
- package/dist/utils/getFiles.d.ts +30 -0
- package/dist/utils/getFiles.d.ts.map +1 -0
- package/dist/utils/getFiles.js +152 -0
- package/dist/utils/getFiles.js.map +1 -0
- package/dist/utils/getPaths.d.ts +1 -0
- package/dist/utils/getPaths.d.ts.map +1 -1
- package/dist/utils/getPaths.js +19 -3
- package/dist/utils/getPaths.js.map +1 -1
- package/dist/utils/mcpConfig.d.ts.map +1 -1
- package/dist/utils/mcpConfig.js +5 -2
- package/dist/utils/mcpConfig.js.map +1 -1
- package/dist/utils/shared.d.ts +4 -0
- package/dist/utils/shared.d.ts.map +1 -0
- package/dist/utils/shared.js +26 -0
- package/dist/utils/shared.js.map +1 -0
- package/dist/utils/stats.d.ts +25 -0
- package/dist/utils/stats.d.ts.map +1 -0
- package/dist/utils/stats.js +40 -0
- package/dist/utils/stats.js.map +1 -0
- package/dist/utils/validateConfig.d.ts +2 -0
- package/dist/utils/validateConfig.d.ts.map +1 -0
- package/dist/utils/validateConfig.js +12 -0
- package/dist/utils/validateConfig.js.map +1 -0
- package/guides/next/advanced/complicated-mapping-expressions.md +200 -0
- package/guides/next/advanced/interpolated-strings.md +162 -0
- package/guides/next/advanced/migrating.md +86 -0
- package/guides/next/advanced/ternary-operators.md +217 -0
- package/guides/next/advanced/var-outside-client-component.md +446 -0
- package/guides/next/advanced/var-outside-client-server-component.md +550 -0
- package/guides/next/advanced/var-outside-server-component.md +545 -0
- package/guides/next/basic/branches.md +310 -0
- package/guides/next/basic/client-side-components.md +221 -0
- package/guides/next/basic/jsx.md +268 -0
- package/guides/next/basic/server-side-components.md +165 -0
- package/guides/next/basic/strings.md +144 -0
- package/guides/next/basic/variables.md +161 -0
- package/guides/next/important/functions.md +37 -0
- package/package.json +27 -13
- package/dist/resources/docs.d.ts +0 -4
- package/dist/resources/docs.d.ts.map +0 -1
- package/dist/resources/docs.js +0 -176
- package/dist/resources/docs.js.map +0 -1
- package/dist/tools/docs.d.ts.map +0 -1
- package/dist/tools/docs.js +0 -140
- package/dist/tools/docs.js.map +0 -1
- package/dist/utils/getDocs.d.ts.map +0 -1
- package/dist/utils/getDocs.js +0 -113
- package/dist/utils/getDocs.js.map +0 -1
- package/dist/utils/logging.d.ts.map +0 -1
- package/dist/utils/logging.js +0 -226
- package/dist/utils/logging.js.map +0 -1
- /package/dist/{utils → mcp}/getDocs.d.ts +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Internationalization Patterns for Dynamic Content
|
|
2
|
+
|
|
3
|
+
**Objective**: Implement internationalization for mapping expressions using `<T>`, `useGT()`/`getGT()`, and `useDict()`/`getDict()`.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
### `<T>` Component Usage
|
|
8
|
+
|
|
9
|
+
**Rule**: `<T>` components translate static JSX content only. Dynamic content requires alternative approaches.
|
|
10
|
+
|
|
11
|
+
**Valid pattern**:
|
|
12
|
+
```jsx
|
|
13
|
+
<T>
|
|
14
|
+
<div> Here's some translated text </div>
|
|
15
|
+
Here is some more translated text!
|
|
16
|
+
</T>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Invalid pattern** - `<T>` cannot process dynamic mapping:
|
|
20
|
+
```jsx
|
|
21
|
+
const MyComponent = () => {
|
|
22
|
+
const someList = [
|
|
23
|
+
<div>Hello Archie</div>,
|
|
24
|
+
<div>Hello Ernest</div>,
|
|
25
|
+
<div>Hello Brian</div>,
|
|
26
|
+
];
|
|
27
|
+
return <T>{someList.map((item) => item)}</T>; // INVALID
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Solution**: Apply `<T>` to individual static items, not the mapping operation:
|
|
32
|
+
```jsx
|
|
33
|
+
const MyComponent = () => {
|
|
34
|
+
const someList = [
|
|
35
|
+
<T><div>Hello Archie</div></T>,
|
|
36
|
+
<T><div>Hello Ernest</div></T>,
|
|
37
|
+
<T><div>Hello Brian</div></T>,
|
|
38
|
+
];
|
|
39
|
+
return <>{someList.map((item) => item)}</>;
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Key requirement**: Each `<T>` component must have direct access to static text content.
|
|
44
|
+
|
|
45
|
+
### String Translation Methods
|
|
46
|
+
|
|
47
|
+
#### `useGT()` and `getGT()` Pattern
|
|
48
|
+
|
|
49
|
+
**Implementation**: Translate individual strings within data structures before mapping:
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
import { useGT } from "gt-next/client";
|
|
53
|
+
import { getGT } from "gt-next/server";
|
|
54
|
+
|
|
55
|
+
const MyComponent = () => {
|
|
56
|
+
// Client-side: const t = useGT();
|
|
57
|
+
// Server-side: const t = await getGT();
|
|
58
|
+
const t = useGT(); // or await getGT()
|
|
59
|
+
|
|
60
|
+
const someList = [
|
|
61
|
+
t('Hello Archie'),
|
|
62
|
+
t('Hello Ernest'),
|
|
63
|
+
t('Hello Brian'),
|
|
64
|
+
];
|
|
65
|
+
return <>{someList.map((item) => item)}</>;
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### `useDict()` and `getDict()` Pattern
|
|
70
|
+
|
|
71
|
+
**Note**: Dictionary approach separates content from implementation context. Use sparingly - only when content reuse across components justifies the separation.
|
|
72
|
+
|
|
73
|
+
**Dictionary structure**:
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"Greetings": {
|
|
77
|
+
"Archie": "Archie",
|
|
78
|
+
"Ernest": "Ernest",
|
|
79
|
+
"Brian": "Brian"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Implementation**:
|
|
85
|
+
```jsx
|
|
86
|
+
import { useDict } from "gt-next/client";
|
|
87
|
+
import { getDict } from "gt-next/server";
|
|
88
|
+
|
|
89
|
+
const MyComponent = () => {
|
|
90
|
+
// Client-side: const t = useDict();
|
|
91
|
+
// Server-side: const t = await getDict();
|
|
92
|
+
const t = useDict(); // or await getDict()
|
|
93
|
+
|
|
94
|
+
const someList = [
|
|
95
|
+
t('Greetings.Archie'),
|
|
96
|
+
t('Greetings.Ernest'),
|
|
97
|
+
t('Greetings.Brian'),
|
|
98
|
+
];
|
|
99
|
+
return <>{someList.map((item) => item)}</>;
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Complex Nested Object Translation
|
|
104
|
+
|
|
105
|
+
### Challenge: Multi-level Data Structures
|
|
106
|
+
|
|
107
|
+
**Scenario**: Nested objects with translatable content at multiple levels require systematic translation approach.
|
|
108
|
+
|
|
109
|
+
**Non-internationalized example**:
|
|
110
|
+
```jsx
|
|
111
|
+
const MyComponent = () => {
|
|
112
|
+
const users = {
|
|
113
|
+
archie: {
|
|
114
|
+
name: 'Archie',
|
|
115
|
+
role: 'Developer',
|
|
116
|
+
skills: ['JavaScript', 'React', 'TypeScript'],
|
|
117
|
+
},
|
|
118
|
+
ernest: {
|
|
119
|
+
name: 'Ernest',
|
|
120
|
+
role: 'Designer',
|
|
121
|
+
skills: ['UI/UX', 'Figma', 'Illustration'],
|
|
122
|
+
},
|
|
123
|
+
brian: {
|
|
124
|
+
name: 'Brian',
|
|
125
|
+
role: 'Product Manager',
|
|
126
|
+
skills: ['Strategy', 'Planning', 'Communication'],
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div>
|
|
132
|
+
{Object.entries(users).map(([key, user]) => (
|
|
133
|
+
<div key={key}>
|
|
134
|
+
<h2>{user.name}</h2>
|
|
135
|
+
<p>Role: {user.role}</p>
|
|
136
|
+
<ul>
|
|
137
|
+
{user.skills.map((skill, index) => (
|
|
138
|
+
<li key={index}>{skill}</li>
|
|
139
|
+
))}
|
|
140
|
+
</ul>
|
|
141
|
+
</div>
|
|
142
|
+
))}
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Solution: Comprehensive Translation Strategy
|
|
149
|
+
|
|
150
|
+
**Requirements**:
|
|
151
|
+
- Translate role labels and skill names
|
|
152
|
+
- Handle string interpolation for template text
|
|
153
|
+
- Provide contextual information for ambiguous terms
|
|
154
|
+
|
|
155
|
+
**Implementation**:
|
|
156
|
+
```jsx
|
|
157
|
+
import { useGT } from 'gt-next/client';
|
|
158
|
+
|
|
159
|
+
const MyComponent = () => {
|
|
160
|
+
const t = useGT();
|
|
161
|
+
const users = {
|
|
162
|
+
archie: {
|
|
163
|
+
name: 'Archie',
|
|
164
|
+
role: t('Developer', { context: 'As in a software developer' }),
|
|
165
|
+
skills: [t('JavaScript'), t('React'), t('TypeScript')],
|
|
166
|
+
},
|
|
167
|
+
ernest: {
|
|
168
|
+
name: 'Ernest',
|
|
169
|
+
role: t('Designer', { context: 'As in a UI/UX designer' }),
|
|
170
|
+
skills: [t('UI/UX'), t('Figma'), t('Illustration')],
|
|
171
|
+
},
|
|
172
|
+
brian: {
|
|
173
|
+
name: 'Brian',
|
|
174
|
+
role: t('Product Manager'),
|
|
175
|
+
skills: [t('Strategy'), t('Planning'), t('Communication')],
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<div>
|
|
181
|
+
{Object.entries(users).map(([key, user]) => (
|
|
182
|
+
<div key={key}>
|
|
183
|
+
<h2>{user.name}</h2>
|
|
184
|
+
<p>{t('Role: {role}', { variables: { role: user.role } })}</p>
|
|
185
|
+
<ul>
|
|
186
|
+
{user.skills.map((skill, index) => (
|
|
187
|
+
<li key={index}>{skill}</li>
|
|
188
|
+
))}
|
|
189
|
+
</ul>
|
|
190
|
+
</div>
|
|
191
|
+
))}
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Key techniques**:
|
|
198
|
+
1. **Context provision**: `{ context: 'As in a software developer' }` for disambiguation
|
|
199
|
+
2. **Variable interpolation**: `t('Role: {role}', { variables: { role: user.role } })`
|
|
200
|
+
3. **Systematic translation**: Apply `t()` to all user-facing strings within data structure
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# String Interpolation Internationalization Patterns
|
|
2
|
+
|
|
3
|
+
**Objective**: Transform template literal strings with dynamic variables into translatable strings using `useGT()`/`getGT()` and `useDict()`/`getDict()`.
|
|
4
|
+
|
|
5
|
+
## Core Pattern: Variable Injection
|
|
6
|
+
|
|
7
|
+
### `useGT()`/`getGT()` Method
|
|
8
|
+
|
|
9
|
+
**Transform**: Template literals → Translatable strings with variable placeholders
|
|
10
|
+
|
|
11
|
+
**Non-internationalized pattern**:
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
const MyComponent = ({ name, count }) => {
|
|
15
|
+
return <div>{`Welcome ${name}, you have ${count} items`}</div>;
|
|
16
|
+
};
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Internationalized implementation**:
|
|
20
|
+
|
|
21
|
+
**Option A** the `<T>` component (preferred for JSX/HTML):
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
import { T } from 'gt-next';
|
|
25
|
+
|
|
26
|
+
const MyComponent = ({ name, count }) => {
|
|
27
|
+
return (
|
|
28
|
+
<div>
|
|
29
|
+
<T>
|
|
30
|
+
Welcome <Var>{name}</Var>, you have <Var>{count}</Var> items
|
|
31
|
+
</T>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Option B** the `useGT()` hook:
|
|
38
|
+
|
|
39
|
+
```jsx
|
|
40
|
+
'use client';
|
|
41
|
+
import { useGT } from 'gt-next/client';
|
|
42
|
+
|
|
43
|
+
const MyComponent = ({ name, count }) => {
|
|
44
|
+
const t = useGT(); // Client-side
|
|
45
|
+
// const t = await getGT(); // Server-side
|
|
46
|
+
return (
|
|
47
|
+
<div>
|
|
48
|
+
{t('Welcome {name}, you have {count} items', {
|
|
49
|
+
variables: { name, count },
|
|
50
|
+
})}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Key requirements**:
|
|
57
|
+
|
|
58
|
+
- Replace `${variable}` syntax with `{variable}` placeholders
|
|
59
|
+
- Pass dynamic values via `variables` object
|
|
60
|
+
- Variable names must match placeholder names exactly
|
|
61
|
+
|
|
62
|
+
### `useDict()`/`getDict()` Method
|
|
63
|
+
|
|
64
|
+
**Option C**: Template literals → Dictionary keys with variable placeholders
|
|
65
|
+
|
|
66
|
+
**Non-internationalized pattern**:
|
|
67
|
+
|
|
68
|
+
```jsx
|
|
69
|
+
const MyComponent = ({ username, role }) => {
|
|
70
|
+
return <div>{`User ${username} has the role of ${role}`}</div>;
|
|
71
|
+
};
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Dictionary structure**:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"Users": {
|
|
79
|
+
"Profile": "User {username} has the role of {role}"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Implementation**:
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
'use client';
|
|
88
|
+
import { useDict } from 'gt-next/client';
|
|
89
|
+
const MyComponent = ({ username, role }) => {
|
|
90
|
+
const t = useDict(); // Client-side
|
|
91
|
+
// const t = await getDict(); // Server-side
|
|
92
|
+
return (
|
|
93
|
+
<div>
|
|
94
|
+
{t('Users.Profile', {
|
|
95
|
+
variables: { username, role },
|
|
96
|
+
})}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Advanced Patterns
|
|
103
|
+
|
|
104
|
+
### Multi-Variable Interpolation
|
|
105
|
+
|
|
106
|
+
**Scenario**: Multiple dynamic values in a single translatable string
|
|
107
|
+
|
|
108
|
+
**Implementation**:
|
|
109
|
+
|
|
110
|
+
```jsx
|
|
111
|
+
'use client';
|
|
112
|
+
import { useGT } from 'gt-next/client';
|
|
113
|
+
const MyComponent = ({ firstName, lastName, age, city }) => {
|
|
114
|
+
const t = useGT(); // Client-side
|
|
115
|
+
// const t = await getGT(); // Server-side
|
|
116
|
+
return (
|
|
117
|
+
<div>
|
|
118
|
+
{t('{firstName} {lastName} is {age} years old and lives in {city}', {
|
|
119
|
+
variables: { firstName, lastName, age, city },
|
|
120
|
+
})}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Requirements**: All placeholder names must have corresponding entries in `variables` object.
|
|
127
|
+
|
|
128
|
+
### Object Property Extraction
|
|
129
|
+
|
|
130
|
+
**Scenario**: Extract values from nested objects for interpolation
|
|
131
|
+
|
|
132
|
+
**Dictionary definition**:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"Users": {
|
|
137
|
+
"Details": "{name} works as a {role} in the {department} department"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Implementation**:
|
|
143
|
+
|
|
144
|
+
```jsx
|
|
145
|
+
const MyComponent = ({ user }) => {
|
|
146
|
+
const t = useDict(); // Client-side
|
|
147
|
+
// const t = await getDict(); // Server-side
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
{t('Users.Details', {
|
|
151
|
+
variables: {
|
|
152
|
+
name: user.name,
|
|
153
|
+
role: user.role,
|
|
154
|
+
department: user.department,
|
|
155
|
+
},
|
|
156
|
+
})}
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Pattern**: Explicitly map object properties to named variables for clear placeholder relationships.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Migration Patterns for Existing i18n Projects
|
|
2
|
+
|
|
3
|
+
**Objective**: Transform existing i18n implementations to `gt-next` using systematic migration strategies.
|
|
4
|
+
|
|
5
|
+
## Core Migration Principles
|
|
6
|
+
|
|
7
|
+
### Library Replacement Requirements
|
|
8
|
+
|
|
9
|
+
- Replace existing i18n library hooks/functions with `gt-next` equivalents
|
|
10
|
+
- Transform string keys to inline content or maintain dictionary structure
|
|
11
|
+
- Preserve existing translation content during transition
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
The project should be setup with `gt-next`. See the guide on setting up gt-next in a Next.js project.
|
|
16
|
+
|
|
17
|
+
## Migration Strategy Implementation
|
|
18
|
+
|
|
19
|
+
**Objective**: Full transformation from existing i18n library to `gt-next` with string key elimination.
|
|
20
|
+
|
|
21
|
+
**Hook replacement pattern**:
|
|
22
|
+
|
|
23
|
+
- Replace old i18n library hooks/functions with `gt-next` equivalents
|
|
24
|
+
- Transform string keys → inline content
|
|
25
|
+
|
|
26
|
+
**Implementation transformation**:
|
|
27
|
+
|
|
28
|
+
**Legacy pattern**:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"hello": {
|
|
33
|
+
"description": "Hello, world!"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
export default function MyComponent() {
|
|
40
|
+
const { t } = useTranslation();
|
|
41
|
+
return <div>{t('hello.description')}</div>;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Migrated implementations**:
|
|
46
|
+
|
|
47
|
+
**Option A - Component-based** (preferred):
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
export default function MyComponent() {
|
|
51
|
+
return (
|
|
52
|
+
<T>
|
|
53
|
+
<div>Hello, world!</div>
|
|
54
|
+
</T>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Option B - Hook-based**:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
'use client'; // Always add 'use client' when working with the useGT() hook
|
|
63
|
+
import { useGT } from 'gt-next/client';
|
|
64
|
+
export default function MyComponent() {
|
|
65
|
+
const t = useGT();
|
|
66
|
+
return <div>{t('Hello, world!')}</div>;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Requirements**: Systematic replacement of all legacy i18n library instances.
|
|
71
|
+
|
|
72
|
+
## Migration Implementation Guidelines
|
|
73
|
+
|
|
74
|
+
### Primary Pattern Preference
|
|
75
|
+
|
|
76
|
+
**Rule**: Prioritize `useGT()` hook, `getGT()` function, and `<T>` component usage whenever possible.
|
|
77
|
+
|
|
78
|
+
**Benefits**:
|
|
79
|
+
|
|
80
|
+
- Enhanced content editability
|
|
81
|
+
- Improved code readability
|
|
82
|
+
- Contextual content management
|
|
83
|
+
|
|
84
|
+
### Dictionary Hook Usage
|
|
85
|
+
|
|
86
|
+
**Rule**: Only apply `useDict()` and `getDict()` during migration when necessary.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Conditional Content Internationalization Patterns
|
|
2
|
+
|
|
3
|
+
**Objective**: Transform ternary operators and conditional rendering into translatable patterns using `<T>`, `<Branch>`, `<Plural>`, `<Var>`, `useGT()`/`getGT()`, and `useDict()`/`getDict()`.
|
|
4
|
+
|
|
5
|
+
## Core Constraint: Dynamic Content in `<T>` Components
|
|
6
|
+
|
|
7
|
+
### `<Branch>` Component Pattern
|
|
8
|
+
|
|
9
|
+
**Rules**:
|
|
10
|
+
|
|
11
|
+
- `<T>` components cannot contain dynamic expressions. Use `<Branch>` for conditional JSX within `<T>`.
|
|
12
|
+
- When working with `useGT()` always add a `"use client"` directive.
|
|
13
|
+
|
|
14
|
+
**Non-internationalized conditional**:
|
|
15
|
+
|
|
16
|
+
```jsx
|
|
17
|
+
const MyComponent = ({ isLoggedIn }) => {
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
{isLoggedIn ? (
|
|
21
|
+
<div>Welcome back!</div>
|
|
22
|
+
) : (
|
|
23
|
+
<div>Please log in to continue</div>
|
|
24
|
+
)}
|
|
25
|
+
</>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Invalid approach** - Dynamic ternary inside `<T>`:
|
|
31
|
+
|
|
32
|
+
```jsx
|
|
33
|
+
const MyComponent = ({ isLoggedIn }) => {
|
|
34
|
+
return (
|
|
35
|
+
<T>
|
|
36
|
+
{isLoggedIn ? (
|
|
37
|
+
<div>Welcome back!</div>
|
|
38
|
+
) : (
|
|
39
|
+
<div>Please log in to continue</div>
|
|
40
|
+
)}
|
|
41
|
+
</T>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Correct implementation** - `<Branch>` component:
|
|
47
|
+
|
|
48
|
+
```jsx
|
|
49
|
+
const MyComponent = ({ isLoggedIn }) => {
|
|
50
|
+
return (
|
|
51
|
+
<T>
|
|
52
|
+
<Branch
|
|
53
|
+
branch={isLoggedIn.toString()}
|
|
54
|
+
true={<div>Welcome back!</div>}
|
|
55
|
+
false={<div>Please log in to continue</div>}
|
|
56
|
+
/>
|
|
57
|
+
</T>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Requirements**:
|
|
63
|
+
|
|
64
|
+
- Convert boolean to string: `isLoggedIn.toString()`
|
|
65
|
+
- Define static JSX for `true` and `false` props
|
|
66
|
+
- Wrap entire structure in `<T>` component
|
|
67
|
+
|
|
68
|
+
**Recommendation**:
|
|
69
|
+
|
|
70
|
+
- Whenever possible, use `<T>` component with Branches for internationalizing ternaries.
|
|
71
|
+
- All ternaries used in JSX components can be converted to use Branches.
|
|
72
|
+
- Use Variable components to wrap dynamic content.
|
|
73
|
+
|
|
74
|
+
### String-Based Conditional Translation
|
|
75
|
+
|
|
76
|
+
**Pattern**: Apply translation functions to each branch of ternary operators
|
|
77
|
+
|
|
78
|
+
**Non-internationalized ternary**:
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
const getCountMessage = ({ count }) => {
|
|
82
|
+
return count === 1 ? 'You have 1 item' : `You have ${count} items`;
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Internationalized implementation**:
|
|
87
|
+
|
|
88
|
+
```jsx
|
|
89
|
+
'use client'; // TIP: always add the 'use client' directive when importing useGT()
|
|
90
|
+
import { useGT } from 'gt-next/client';
|
|
91
|
+
const getCountMessage = ({ count }) => {
|
|
92
|
+
const t = useGT();
|
|
93
|
+
return count === 1
|
|
94
|
+
? t('You have 1 item')
|
|
95
|
+
: t('You have {count} items', { variables: { count } });
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Key technique**: Apply `t()` function to each branch separately, using variable interpolation where needed.
|
|
100
|
+
|
|
101
|
+
## Advanced Conditional Patterns
|
|
102
|
+
|
|
103
|
+
### Multi-Level Nested Conditions
|
|
104
|
+
|
|
105
|
+
**Pattern**: Chain ternary operators with translation applied to each outcome
|
|
106
|
+
|
|
107
|
+
**Technique**:
|
|
108
|
+
|
|
109
|
+
- For JSX: Use a `<Branch>` or `<Plural>` component.
|
|
110
|
+
- For Strings: Each condition level receives separate translation call.
|
|
111
|
+
|
|
112
|
+
### Numerical Condition Branching
|
|
113
|
+
|
|
114
|
+
**Pattern**: Handle zero, singular, and plural cases with appropriate translations
|
|
115
|
+
|
|
116
|
+
#### JSX Approach
|
|
117
|
+
|
|
118
|
+
Original
|
|
119
|
+
|
|
120
|
+
```jsx
|
|
121
|
+
const getItemsFoundMessage = ({ items }) => {
|
|
122
|
+
return (
|
|
123
|
+
<>
|
|
124
|
+
{items.color === 'red' ? (
|
|
125
|
+
<>An amazing color was found</>
|
|
126
|
+
) : items.shape === 'square' ? (
|
|
127
|
+
<>A disgusting color but an amazing shape was found</>
|
|
128
|
+
) : (
|
|
129
|
+
<>A disgusting color and disgusting shape was found</>
|
|
130
|
+
)}
|
|
131
|
+
</>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Internationalized
|
|
137
|
+
|
|
138
|
+
```jsx
|
|
139
|
+
import { T, Branch } from 'gt-next';
|
|
140
|
+
const getItemsFoundMessage = ({ items }) => {
|
|
141
|
+
return (
|
|
142
|
+
<T>
|
|
143
|
+
<Branch branch={items.color} red={<>An amazing color was found</>}>
|
|
144
|
+
{/* Children are the catch all for the branch component */}
|
|
145
|
+
<Branch
|
|
146
|
+
branch={items.shape}
|
|
147
|
+
square={<>A disgusting color but an amazing shape was found</>}
|
|
148
|
+
>
|
|
149
|
+
A disgusting color and disgusting shape was found
|
|
150
|
+
</Branch>
|
|
151
|
+
</Branch>
|
|
152
|
+
</T>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### String Approach
|
|
158
|
+
|
|
159
|
+
Original
|
|
160
|
+
|
|
161
|
+
```jsx
|
|
162
|
+
const getItemsFoundMessage = ({ items }) => {
|
|
163
|
+
return items.color === 'red'
|
|
164
|
+
? 'An amazing color was found'
|
|
165
|
+
: items.shape === 'square'
|
|
166
|
+
? 'A disgusting color but an amazing shape was found'
|
|
167
|
+
: 'A disgusting color and disgusting shape was found';
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Internationalized
|
|
172
|
+
|
|
173
|
+
```jsx
|
|
174
|
+
'use client';
|
|
175
|
+
import { useGT } from 'gt-next/client';
|
|
176
|
+
|
|
177
|
+
const getItemsFoundMessage = ({ items }) => {
|
|
178
|
+
const t = useGT();
|
|
179
|
+
return items.color === 'red'
|
|
180
|
+
? t('An amazing color was found')
|
|
181
|
+
: items.shape === 'square'
|
|
182
|
+
? t('A disgusting color but an amazing shape was found')
|
|
183
|
+
: t('A disgusting color and disgusting shape was found');
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Key requirements**:
|
|
188
|
+
|
|
189
|
+
- Handle zero state explicitly
|
|
190
|
+
- Use singular form for count === 1
|
|
191
|
+
- Apply variable interpolation for plural cases
|
|
192
|
+
|
|
193
|
+
### Complex JSX Conditional Rendering
|
|
194
|
+
|
|
195
|
+
**Pattern**: Wrap each conditional JSX branch in separate `<T>` components
|
|
196
|
+
|
|
197
|
+
```jsx
|
|
198
|
+
const MyComponent = ({ error, loading }) => {
|
|
199
|
+
return (
|
|
200
|
+
<div>
|
|
201
|
+
{loading ? (
|
|
202
|
+
<T>
|
|
203
|
+
<div>Loading...</div>
|
|
204
|
+
</T>
|
|
205
|
+
) : error ? (
|
|
206
|
+
<T>
|
|
207
|
+
<div>An error occurred</div>
|
|
208
|
+
</T>
|
|
209
|
+
) : (
|
|
210
|
+
<T>
|
|
211
|
+
<div>Content loaded successfully</div>
|
|
212
|
+
</T>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
```
|