@nlabs/reaktor 0.10.6 → 0.10.8
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/package.json +12 -1
- package/.env +0 -1
- package/.env.example +0 -1
- package/DATABASE_I18N_GUIDE.md +0 -434
- package/TEST_UTILITIES_GUIDE.md +0 -360
- package/coverage/actions/groups.ts.html +0 -1039
- package/coverage/actions/images.ts.html +0 -2500
- package/coverage/actions/index.html +0 -116
- package/coverage/actions/notifications.ts.html +0 -223
- package/coverage/actions/posts.ts.html +0 -2356
- package/coverage/actions/tags.ts.html +0 -1000
- package/coverage/adapters/arangoAdapter.ts.html +0 -301
- package/coverage/adapters/fileAdapter.ts.html +0 -445
- package/coverage/adapters/index.html +0 -176
- package/coverage/adapters/postAdapter.ts.html +0 -436
- package/coverage/adapters/reaktorAdapter.ts.html +0 -310
- package/coverage/adapters/tagAdapter.ts.html +0 -409
- package/coverage/adapters/userAdapter.ts.html +0 -829
- package/coverage/analyticsUtils.ts.html +0 -286
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -6
- package/coverage/config.ts.html +0 -766
- package/coverage/coverage-final.json +0 -1
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -221
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -101
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -0
- package/coverage/mocks/file.ts.html +0 -118
- package/coverage/mocks/group.ts.html +0 -145
- package/coverage/mocks/image.ts.html +0 -142
- package/coverage/mocks/index.html +0 -176
- package/coverage/mocks/post.ts.html +0 -169
- package/coverage/mocks/tag.ts.html +0 -121
- package/coverage/mocks/user.ts.html +0 -271
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/testUtils.ts.html +0 -1309
- package/coverage/translationQueue.ts.html +0 -592
- package/coverage/types/error.ts.html +0 -145
- package/coverage/types/error.types.ts.html +0 -148
- package/coverage/types/index.html +0 -116
- package/coverage/utils/adapterUtils.ts.html +0 -163
- package/coverage/utils/analyticsUtils.ts.html +0 -286
- package/coverage/utils/arangodbUtils.ts.html +0 -463
- package/coverage/utils/authUtils.ts.html +0 -328
- package/coverage/utils/dbI18n.ts.html +0 -280
- package/coverage/utils/googleTranslate.ts.html +0 -385
- package/coverage/utils/index.html +0 -131
- package/coverage/utils/localeUtils.ts.html +0 -193
- package/coverage/utils/sessionUtils.ts.html +0 -211
- package/coverage/utils/testUtils.ts.html +0 -1309
- package/index.js +0 -5
- package/jpg:- +0 -0
- package/lex.config.mjs +0 -34
- package/tsconfig.build.json +0 -21
- package/tsconfig.lint.json +0 -33
- package/tsconfig.test.json +0 -31
package/package.json
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nlabs/reaktor",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.8",
|
|
4
4
|
"description": "Reaktor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"module": "./lib/index.js",
|
|
8
8
|
"types": "./lib/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"lib"
|
|
11
|
+
],
|
|
12
|
+
"typesVersions": {
|
|
13
|
+
"*": {
|
|
14
|
+
"*": [
|
|
15
|
+
"./lib/*"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
9
19
|
"exports": {
|
|
10
20
|
".": {
|
|
11
21
|
"types": "./lib/index.d.ts",
|
|
12
22
|
"import": "./lib/index.js",
|
|
23
|
+
"require": "./lib/index.js",
|
|
13
24
|
"default": "./lib/index.js"
|
|
14
25
|
}
|
|
15
26
|
},
|
package/.env
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
GOOGLE_API_KEY="AIzaSyB5gXFPS7bkEtqr48yS66C79HZUf1g6sEM"
|
package/.env.example
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
GOOGLE_API_KEY=""
|
package/DATABASE_I18N_GUIDE.md
DELETED
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
# Database-Driven I18N System
|
|
2
|
-
|
|
3
|
-
This guide explains how to use the new database-driven internationalization (i18n) system for TorchOne API.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The database-driven i18n system allows you to:
|
|
8
|
-
- Store translations in the database for dynamic content management
|
|
9
|
-
- Provide fallback content when translations are not found
|
|
10
|
-
- Support interpolation for dynamic values
|
|
11
|
-
- Batch fetch translations for better performance
|
|
12
|
-
- Manage translations through the database without code changes
|
|
13
|
-
|
|
14
|
-
## Database Schema
|
|
15
|
-
|
|
16
|
-
### Content Collection
|
|
17
|
-
|
|
18
|
-
The system uses a `content` collection with the following structure:
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
interface ContentType {
|
|
22
|
-
_id?: string;
|
|
23
|
-
_key?: string;
|
|
24
|
-
contentId?: string;
|
|
25
|
-
key: string; // Translation key (e.g., 'sms.welcome')
|
|
26
|
-
locale: Locale; // Language code ('en', 'es', 'fr', 'de', 'pt', 'it')
|
|
27
|
-
content: string; // Translated content
|
|
28
|
-
description?: string; // Optional description
|
|
29
|
-
category?: string; // Optional category for organization
|
|
30
|
-
isActive?: boolean; // Whether this translation is active
|
|
31
|
-
userId?: string; // User who created the content
|
|
32
|
-
added?: number; // Timestamp when created
|
|
33
|
-
modified?: number; // Timestamp when last modified
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Locale Support
|
|
38
|
-
|
|
39
|
-
The system supports both primary languages and regional variants for comprehensive internationalization:
|
|
40
|
-
|
|
41
|
-
### **Primary Languages**
|
|
42
|
-
- `en` - English
|
|
43
|
-
- `es` - Spanish
|
|
44
|
-
- `fr` - French
|
|
45
|
-
- `de` - German
|
|
46
|
-
- `pt` - Portuguese
|
|
47
|
-
- `it` - Italian
|
|
48
|
-
|
|
49
|
-
### **Regional Variants**
|
|
50
|
-
- `en-us`, `en-gb`, `en-ca`, `en-au` - English variants
|
|
51
|
-
- `es-mx`, `es-es`, `es-ar` - Spanish variants
|
|
52
|
-
- `fr-fr`, `fr-ca` - French variants
|
|
53
|
-
- `de-de`, `de-at` - German variants
|
|
54
|
-
- `pt-br`, `pt-pt` - Portuguese variants
|
|
55
|
-
- `it-it` - Italian variants
|
|
56
|
-
|
|
57
|
-
### **Locale Strategy**
|
|
58
|
-
- **Storage**: Full locale with region (e.g., "en-us") for regional formatting
|
|
59
|
-
- **Translation**: Language extraction (e.g., "en-us" → "en") for API calls
|
|
60
|
-
- **Fallback**: Regional → Language → App default hierarchy
|
|
61
|
-
|
|
62
|
-
### **Locale Utilities**
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
import {
|
|
66
|
-
extractLanguage,
|
|
67
|
-
isRegionalLocale,
|
|
68
|
-
getFallbackChain,
|
|
69
|
-
isValidLocale
|
|
70
|
-
} from './src/utils/localeUtils';
|
|
71
|
-
|
|
72
|
-
// Extract language for translation APIs
|
|
73
|
-
const language = extractLanguage('en-us'); // 'en'
|
|
74
|
-
|
|
75
|
-
// Check if locale includes region
|
|
76
|
-
const isRegional = isRegionalLocale('es-mx'); // true
|
|
77
|
-
|
|
78
|
-
// Get fallback chain
|
|
79
|
-
const fallbacks = getFallbackChain('fr-ca'); // ['fr-ca', 'fr']
|
|
80
|
-
|
|
81
|
-
// Validate locale
|
|
82
|
-
const isValid = isValidLocale('en-us'); // true
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Core Functions
|
|
86
|
-
|
|
87
|
-
### 1. Basic Translation with Fallback
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
import { dbI18n } from './src/utils/dbI18n';
|
|
91
|
-
|
|
92
|
-
const message = await dbI18n(
|
|
93
|
-
context,
|
|
94
|
-
'sms.welcome',
|
|
95
|
-
'Welcome to TorchOne, {{username}}! Thank you for joining our platform.',
|
|
96
|
-
'en'
|
|
97
|
-
);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Parameters:**
|
|
101
|
-
- `context`: API context with database connection
|
|
102
|
-
- `key`: Content key to look up in database
|
|
103
|
-
- `fallbackContent`: Content to return if not found in database
|
|
104
|
-
- `locale`: Optional locale (defaults to 'en')
|
|
105
|
-
|
|
106
|
-
**Returns:** Promise<string> - The translated content or fallback
|
|
107
|
-
|
|
108
|
-
### 2. Translation with Interpolation
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
import { dbI18nWithInterpolation } from './src/utils/dbI18n';
|
|
112
|
-
|
|
113
|
-
const message = await dbI18nWithInterpolation(
|
|
114
|
-
context,
|
|
115
|
-
'sms.verificationCode',
|
|
116
|
-
'Your verification code is: {{code}}',
|
|
117
|
-
{ code: '123456' },
|
|
118
|
-
'es'
|
|
119
|
-
);
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Parameters:**
|
|
123
|
-
- `context`: API context with database connection
|
|
124
|
-
- `key`: Content key to look up
|
|
125
|
-
- `fallbackContent`: Content to return if not found
|
|
126
|
-
- `interpolation`: Object with values to interpolate
|
|
127
|
-
- `locale`: Optional locale (defaults to 'en')
|
|
128
|
-
|
|
129
|
-
**Returns:** Promise<string> - The translated content with interpolated values
|
|
130
|
-
|
|
131
|
-
### 3. Multiple Translations
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
import { dbI18nMultiple } from './src/utils/dbI18n';
|
|
135
|
-
|
|
136
|
-
const [welcome, getStarted, signature] = await dbI18nMultiple(context, [
|
|
137
|
-
{
|
|
138
|
-
key: 'email.welcome',
|
|
139
|
-
fallback: 'Welcome to TorchOne!',
|
|
140
|
-
locale: 'en'
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
key: 'email.getStarted',
|
|
144
|
-
fallback: 'To get started, complete your profile.',
|
|
145
|
-
locale: 'en'
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
key: 'email.teamSignature',
|
|
149
|
-
fallback: 'The TorchOne Team',
|
|
150
|
-
locale: 'en'
|
|
151
|
-
}
|
|
152
|
-
]);
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### 4. Batch Translation
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
import { dbI18nBatch } from './src/utils/dbI18n';
|
|
159
|
-
|
|
160
|
-
const keys = ['welcome', 'verification', 'passwordReset'];
|
|
161
|
-
const fallbackMap = {
|
|
162
|
-
'welcome': 'Welcome!',
|
|
163
|
-
'verification': 'Please verify your account.',
|
|
164
|
-
'passwordReset': 'Your password has been reset.'
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const translations = await dbI18nBatch(context, keys, fallbackMap, 'fr');
|
|
168
|
-
// Returns: { welcome: '...', verification: '...', passwordReset: '...' }
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Database Operations
|
|
172
|
-
|
|
173
|
-
### Adding Content
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
import { addContent } from './src/actions/content';
|
|
177
|
-
|
|
178
|
-
const newContent = await addContent(context, {
|
|
179
|
-
key: 'sms.welcome',
|
|
180
|
-
locale: 'es',
|
|
181
|
-
content: '¡Bienvenido a TorchOne, {{username}}!',
|
|
182
|
-
description: 'Welcome SMS message in Spanish',
|
|
183
|
-
category: 'sms',
|
|
184
|
-
isActive: true
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Updating Content
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
import { updateContent } from './src/actions/content';
|
|
192
|
-
|
|
193
|
-
const updatedContent = await updateContent(context, {
|
|
194
|
-
contentId: 'content-abc123',
|
|
195
|
-
content: 'Updated welcome message',
|
|
196
|
-
description: 'Updated description'
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Searching Content
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
import { searchContent } from './src/actions/content';
|
|
204
|
-
|
|
205
|
-
// Search by category
|
|
206
|
-
const smsContent = await searchContent(context, { category: 'sms' });
|
|
207
|
-
|
|
208
|
-
// Search by locale
|
|
209
|
-
const spanishContent = await searchContent(context, { locale: 'es' });
|
|
210
|
-
|
|
211
|
-
// Search by key
|
|
212
|
-
const welcomeContent = await searchContent(context, { key: 'sms.welcome' });
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Usage Examples
|
|
216
|
-
|
|
217
|
-
### SMS Notifications
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
export async function sendWelcomeSMS(context: ApiContext, username: string, phoneNumber: string) {
|
|
221
|
-
const message = await dbI18nWithInterpolation(
|
|
222
|
-
context,
|
|
223
|
-
'sms.welcome',
|
|
224
|
-
'Welcome to TorchOne, {{username}}! Thank you for joining our platform.',
|
|
225
|
-
{ username },
|
|
226
|
-
'en'
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
// Send SMS logic here
|
|
230
|
-
console.log(`Sending SMS to ${phoneNumber}: ${message}`);
|
|
231
|
-
return message;
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Email Templates
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
export async function generateWelcomeEmail(context: ApiContext, username: string, locale: Locale = 'en') {
|
|
239
|
-
const [welcomeMessage, getStartedMessage, teamSignature] = await dbI18nMultiple(context, [
|
|
240
|
-
{
|
|
241
|
-
key: 'email.welcome',
|
|
242
|
-
fallback: 'Welcome to TorchOne, {{username}}!',
|
|
243
|
-
locale
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
key: 'email.getStarted',
|
|
247
|
-
fallback: 'To get started, please complete your profile and explore our features.',
|
|
248
|
-
locale
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
key: 'email.teamSignature',
|
|
252
|
-
fallback: 'The TorchOne Team',
|
|
253
|
-
locale
|
|
254
|
-
}
|
|
255
|
-
]);
|
|
256
|
-
|
|
257
|
-
// Apply interpolation
|
|
258
|
-
const interpolatedWelcome = welcomeMessage.replace(/\{\{username\}\}/g, username);
|
|
259
|
-
|
|
260
|
-
return {
|
|
261
|
-
subject: interpolatedWelcome,
|
|
262
|
-
body: `${interpolatedWelcome}\n\n${getStartedMessage}\n\n${teamSignature}`
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### Error Messages
|
|
268
|
-
|
|
269
|
-
```typescript
|
|
270
|
-
export async function getErrorMessage(context: ApiContext, errorCode: string, locale: Locale = 'en') {
|
|
271
|
-
try {
|
|
272
|
-
const message = await dbI18n(
|
|
273
|
-
context,
|
|
274
|
-
`error.${errorCode}`,
|
|
275
|
-
`An error occurred: ${errorCode}`,
|
|
276
|
-
locale
|
|
277
|
-
);
|
|
278
|
-
return message;
|
|
279
|
-
} catch (error) {
|
|
280
|
-
// If database is unavailable, return fallback
|
|
281
|
-
console.error('Database error, using fallback:', error);
|
|
282
|
-
return `An error occurred: ${errorCode}`;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Best Practices
|
|
288
|
-
|
|
289
|
-
### 1. Key Naming Convention
|
|
290
|
-
|
|
291
|
-
Use hierarchical keys for better organization:
|
|
292
|
-
- `sms.welcome`
|
|
293
|
-
- `email.verification.subject`
|
|
294
|
-
- `error.invalid_email`
|
|
295
|
-
- `notification.profile_updated`
|
|
296
|
-
|
|
297
|
-
### 2. Fallback Content
|
|
298
|
-
|
|
299
|
-
Always provide meaningful fallback content:
|
|
300
|
-
```typescript
|
|
301
|
-
// Good
|
|
302
|
-
await dbI18n(context, 'welcome', 'Welcome to our platform!', 'en');
|
|
303
|
-
|
|
304
|
-
// Bad
|
|
305
|
-
await dbI18n(context, 'welcome', '', 'en');
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### 3. Error Handling
|
|
309
|
-
|
|
310
|
-
Handle database errors gracefully:
|
|
311
|
-
```typescript
|
|
312
|
-
try {
|
|
313
|
-
const message = await dbI18n(context, key, fallback, locale);
|
|
314
|
-
return message;
|
|
315
|
-
} catch (error) {
|
|
316
|
-
console.error('Translation error:', error);
|
|
317
|
-
return fallback; // Always return fallback on error
|
|
318
|
-
}
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### 4. Performance
|
|
322
|
-
|
|
323
|
-
Use batch operations for multiple translations:
|
|
324
|
-
```typescript
|
|
325
|
-
// Good - Single database query
|
|
326
|
-
const translations = await dbI18nBatch(context, keys, fallbackMap, locale);
|
|
327
|
-
|
|
328
|
-
// Bad - Multiple database queries
|
|
329
|
-
const translations = await Promise.all(
|
|
330
|
-
keys.map(key => dbI18n(context, key, fallbackMap[key], locale))
|
|
331
|
-
);
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### 5. Caching
|
|
335
|
-
|
|
336
|
-
Consider implementing caching for frequently accessed translations:
|
|
337
|
-
```typescript
|
|
338
|
-
// Example with simple in-memory cache
|
|
339
|
-
const translationCache = new Map<string, string>();
|
|
340
|
-
|
|
341
|
-
export async function cachedI18n(context: ApiContext, key: string, fallback: string, locale: Locale = 'en') {
|
|
342
|
-
const cacheKey = `${key}:${locale}`;
|
|
343
|
-
|
|
344
|
-
if (translationCache.has(cacheKey)) {
|
|
345
|
-
return translationCache.get(cacheKey)!;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const content = await dbI18n(context, key, fallback, locale);
|
|
349
|
-
translationCache.set(cacheKey, content);
|
|
350
|
-
|
|
351
|
-
return content;
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
## Migration from Static Translations
|
|
356
|
-
|
|
357
|
-
To migrate from the static translation system:
|
|
358
|
-
|
|
359
|
-
1. **Export existing translations:**
|
|
360
|
-
```typescript
|
|
361
|
-
import { torchoneResources } from './src/translations';
|
|
362
|
-
|
|
363
|
-
// Convert static translations to database format
|
|
364
|
-
const translations = Object.entries(torchoneResources).flatMap(([locale, data]) =>
|
|
365
|
-
Object.entries(data.translation).map(([key, content]) => ({
|
|
366
|
-
key,
|
|
367
|
-
locale,
|
|
368
|
-
content: typeof content === 'string' ? content : JSON.stringify(content),
|
|
369
|
-
category: key.split('.')[0], // Extract category from key
|
|
370
|
-
isActive: true
|
|
371
|
-
}))
|
|
372
|
-
);
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
2. **Bulk insert into database:**
|
|
376
|
-
```typescript
|
|
377
|
-
for (const translation of translations) {
|
|
378
|
-
await addContent(context, translation);
|
|
379
|
-
}
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
3. **Update code to use database-driven functions:**
|
|
383
|
-
```typescript
|
|
384
|
-
// Before
|
|
385
|
-
const message = dbI18n('sms.welcome', { username: 'John' });
|
|
386
|
-
|
|
387
|
-
// After
|
|
388
|
-
const message = await dbI18nWithInterpolation(
|
|
389
|
-
context,
|
|
390
|
-
'sms.welcome',
|
|
391
|
-
'Welcome to TorchOne, {{username}}!',
|
|
392
|
-
{ username: 'John' }
|
|
393
|
-
);
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## Benefits
|
|
397
|
-
|
|
398
|
-
1. **Dynamic Content Management**: Update translations without code changes
|
|
399
|
-
2. **Fallback Support**: Always provide content even if database is unavailable
|
|
400
|
-
3. **Interpolation**: Support for dynamic values in translations
|
|
401
|
-
4. **Performance**: Batch operations for multiple translations
|
|
402
|
-
5. **Organization**: Categorize and manage translations effectively
|
|
403
|
-
6. **Audit Trail**: Track who created/modified translations
|
|
404
|
-
7. **Active/Inactive**: Control which translations are available
|
|
405
|
-
|
|
406
|
-
## Troubleshooting
|
|
407
|
-
|
|
408
|
-
### Common Issues
|
|
409
|
-
|
|
410
|
-
1. **Database Connection Errors**: Always provide fallback content
|
|
411
|
-
2. **Missing Translations**: Check if content exists in database
|
|
412
|
-
3. **Type Errors**: Ensure locale parameter is of type `Locale`
|
|
413
|
-
4. **Performance Issues**: Use batch operations for multiple translations
|
|
414
|
-
|
|
415
|
-
### Debugging
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
// Enable debug logging
|
|
419
|
-
const DEBUG_I18N = process.env.DEBUG_I18N === 'true';
|
|
420
|
-
|
|
421
|
-
export async function debugI18n(context: ApiContext, key: string, fallback: string, locale: Locale = 'en') {
|
|
422
|
-
if (DEBUG_I18N) {
|
|
423
|
-
console.log(`[I18N] Looking up key: ${key}, locale: ${locale}`);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const content = await dbI18n(context, key, fallback, locale);
|
|
427
|
-
|
|
428
|
-
if (DEBUG_I18N) {
|
|
429
|
-
console.log(`[I18N] Result: ${content}`);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
return content;
|
|
433
|
-
}
|
|
434
|
-
```
|