@lokascript/i18n 1.0.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 +286 -0
- package/dist/browser.cjs +7669 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +50 -0
- package/dist/browser.d.ts +50 -0
- package/dist/browser.js +7592 -0
- package/dist/browser.js.map +1 -0
- package/dist/hyperfixi-i18n.min.js +2 -0
- package/dist/hyperfixi-i18n.min.js.map +1 -0
- package/dist/hyperfixi-i18n.mjs +8558 -0
- package/dist/hyperfixi-i18n.mjs.map +1 -0
- package/dist/index.cjs +14205 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +947 -0
- package/dist/index.d.ts +947 -0
- package/dist/index.js +14095 -0
- package/dist/index.js.map +1 -0
- package/dist/transformer-Ckask-yw.d.cts +1041 -0
- package/dist/transformer-Ckask-yw.d.ts +1041 -0
- package/package.json +84 -0
- package/src/browser.ts +122 -0
- package/src/compatibility/browser-tests/grammar-demo.spec.ts +169 -0
- package/src/constants.ts +366 -0
- package/src/dictionaries/ar.ts +233 -0
- package/src/dictionaries/bn.ts +156 -0
- package/src/dictionaries/de.ts +233 -0
- package/src/dictionaries/derive.ts +515 -0
- package/src/dictionaries/en.ts +237 -0
- package/src/dictionaries/es.ts +233 -0
- package/src/dictionaries/fr.ts +233 -0
- package/src/dictionaries/hi.ts +270 -0
- package/src/dictionaries/id.ts +233 -0
- package/src/dictionaries/index.ts +238 -0
- package/src/dictionaries/it.ts +233 -0
- package/src/dictionaries/ja.ts +233 -0
- package/src/dictionaries/ko.ts +233 -0
- package/src/dictionaries/ms.ts +276 -0
- package/src/dictionaries/pl.ts +239 -0
- package/src/dictionaries/pt.ts +237 -0
- package/src/dictionaries/qu.ts +233 -0
- package/src/dictionaries/ru.ts +270 -0
- package/src/dictionaries/sw.ts +233 -0
- package/src/dictionaries/th.ts +156 -0
- package/src/dictionaries/tl.ts +276 -0
- package/src/dictionaries/tr.ts +233 -0
- package/src/dictionaries/uk.ts +270 -0
- package/src/dictionaries/vi.ts +210 -0
- package/src/dictionaries/zh.ts +233 -0
- package/src/enhanced-i18n.test.ts +454 -0
- package/src/enhanced-i18n.ts +713 -0
- package/src/examples/new-languages.ts +326 -0
- package/src/formatting.test.ts +213 -0
- package/src/formatting.ts +416 -0
- package/src/grammar/direct-mappings.ts +353 -0
- package/src/grammar/grammar.test.ts +1053 -0
- package/src/grammar/index.ts +59 -0
- package/src/grammar/profiles/index.ts +860 -0
- package/src/grammar/transformer.ts +1318 -0
- package/src/grammar/types.ts +630 -0
- package/src/index.ts +202 -0
- package/src/new-languages.test.ts +389 -0
- package/src/parser/analyze-conflicts.test.ts +229 -0
- package/src/parser/ar.ts +40 -0
- package/src/parser/create-provider.ts +309 -0
- package/src/parser/de.ts +36 -0
- package/src/parser/es.ts +31 -0
- package/src/parser/fr.ts +31 -0
- package/src/parser/id.ts +34 -0
- package/src/parser/index.ts +50 -0
- package/src/parser/ja.ts +36 -0
- package/src/parser/ko.ts +37 -0
- package/src/parser/locale-manager.test.ts +198 -0
- package/src/parser/locale-manager.ts +197 -0
- package/src/parser/parser-integration.test.ts +439 -0
- package/src/parser/pt.ts +37 -0
- package/src/parser/qu.ts +37 -0
- package/src/parser/sw.ts +37 -0
- package/src/parser/tr.ts +38 -0
- package/src/parser/types.ts +113 -0
- package/src/parser/zh.ts +38 -0
- package/src/plugins/vite.ts +224 -0
- package/src/plugins/webpack.ts +124 -0
- package/src/pluralization.test.ts +197 -0
- package/src/pluralization.ts +393 -0
- package/src/runtime.ts +441 -0
- package/src/ssr-integration.ts +225 -0
- package/src/test-setup.ts +195 -0
- package/src/translation-validation.test.ts +171 -0
- package/src/translator.test.ts +252 -0
- package/src/translator.ts +297 -0
- package/src/types.ts +209 -0
- package/src/utils/locale.ts +190 -0
- package/src/utils/tokenizer-adapter.ts +469 -0
- package/src/utils/tokenizer.ts +19 -0
- package/src/validators/index.ts +174 -0
- package/src/validators/schema.ts +129 -0
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced I18n Implementation
|
|
3
|
+
* Type-safe internationalization following enhanced pattern
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
// Note: Dictionary, I18nConfig, TranslationOptions, TranslationResult are defined in ./types.js
|
|
8
|
+
// but may not be used directly in this file (used for documentation purposes)
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Local Type Definitions
|
|
12
|
+
// These types were previously imported from core but are defined locally
|
|
13
|
+
// to avoid cross-package dependencies and missing module errors.
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Validation result for i18n operations
|
|
18
|
+
*/
|
|
19
|
+
export interface ValidationResult {
|
|
20
|
+
isValid: boolean;
|
|
21
|
+
errors: Array<{ type: string; message: string; path?: string }>;
|
|
22
|
+
suggestions?: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Evaluation result wrapper
|
|
27
|
+
*/
|
|
28
|
+
export interface EvaluationResult<T = unknown> {
|
|
29
|
+
success: boolean;
|
|
30
|
+
value?: T;
|
|
31
|
+
type?: string;
|
|
32
|
+
errors?: Array<{ type: string; message: string }>;
|
|
33
|
+
suggestions?: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Context metadata for enhanced pattern
|
|
38
|
+
*/
|
|
39
|
+
export interface ContextMetadata {
|
|
40
|
+
contextId?: string;
|
|
41
|
+
timestamp?: number;
|
|
42
|
+
category: string;
|
|
43
|
+
capabilities?: string[];
|
|
44
|
+
state?: string;
|
|
45
|
+
// Extended metadata properties
|
|
46
|
+
complexity?: string;
|
|
47
|
+
sideEffects?: string[];
|
|
48
|
+
dependencies?: string[];
|
|
49
|
+
returnTypes?: string[];
|
|
50
|
+
relatedContexts?: string[];
|
|
51
|
+
examples?: Array<{
|
|
52
|
+
input: string;
|
|
53
|
+
description: string;
|
|
54
|
+
expectedOutput: string;
|
|
55
|
+
}>;
|
|
56
|
+
// Additional extended properties
|
|
57
|
+
frameworkDependencies?: string[];
|
|
58
|
+
environmentRequirements?: {
|
|
59
|
+
browser?: boolean;
|
|
60
|
+
server?: boolean;
|
|
61
|
+
nodejs?: boolean;
|
|
62
|
+
};
|
|
63
|
+
performance?: {
|
|
64
|
+
averageTime?: number;
|
|
65
|
+
complexity?: string;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* LLM documentation interface for AI-friendly descriptions
|
|
71
|
+
*/
|
|
72
|
+
export interface LLMDocumentation {
|
|
73
|
+
summary: string;
|
|
74
|
+
description?: string;
|
|
75
|
+
examples?: Array<
|
|
76
|
+
| string
|
|
77
|
+
| {
|
|
78
|
+
title: string;
|
|
79
|
+
code: string;
|
|
80
|
+
explanation: string;
|
|
81
|
+
output: string;
|
|
82
|
+
}
|
|
83
|
+
>;
|
|
84
|
+
category?: string;
|
|
85
|
+
parameters?: Array<{
|
|
86
|
+
name: string;
|
|
87
|
+
type: string;
|
|
88
|
+
description: string;
|
|
89
|
+
required?: boolean;
|
|
90
|
+
default?: string;
|
|
91
|
+
optional?: boolean;
|
|
92
|
+
examples?: string[];
|
|
93
|
+
}>;
|
|
94
|
+
returns?: {
|
|
95
|
+
type: string;
|
|
96
|
+
description: string;
|
|
97
|
+
examples?: string[];
|
|
98
|
+
};
|
|
99
|
+
tips?: string[];
|
|
100
|
+
commonMistakes?: string[];
|
|
101
|
+
seeAlso?: string[];
|
|
102
|
+
tags?: string[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Evaluation type enumeration
|
|
107
|
+
*/
|
|
108
|
+
export type EvaluationType = 'sync' | 'async' | 'streaming' | 'Context';
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Enhanced context base interface
|
|
112
|
+
*/
|
|
113
|
+
export interface EnhancedContextBase extends ContextMetadata {
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Typed context implementation interface
|
|
119
|
+
*/
|
|
120
|
+
export interface TypedContextImplementation<TInput, TOutput> {
|
|
121
|
+
inputSchema: z.ZodType<TInput>;
|
|
122
|
+
outputSchema: z.ZodType<TOutput>;
|
|
123
|
+
evaluate(input: TInput): Promise<EvaluationResult<TOutput>>;
|
|
124
|
+
validate(input: unknown): ValidationResult;
|
|
125
|
+
metadata: ContextMetadata;
|
|
126
|
+
documentation: LLMDocumentation;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// Enhanced I18n Input/Output Schemas
|
|
131
|
+
// ============================================================================
|
|
132
|
+
|
|
133
|
+
export const EnhancedI18nInputSchema = z.object({
|
|
134
|
+
/** Locale configuration */
|
|
135
|
+
locale: z.string().min(2, 'Locale must be at least 2 characters'),
|
|
136
|
+
fallbackLocale: z.string().optional(),
|
|
137
|
+
/** Dictionary data for translations */
|
|
138
|
+
dictionaries: z
|
|
139
|
+
.record(
|
|
140
|
+
z.string(),
|
|
141
|
+
z
|
|
142
|
+
.object({
|
|
143
|
+
commands: z.record(z.string(), z.string()),
|
|
144
|
+
modifiers: z.record(z.string(), z.string()),
|
|
145
|
+
events: z.record(z.string(), z.string()),
|
|
146
|
+
logical: z.record(z.string(), z.string()),
|
|
147
|
+
temporal: z.record(z.string(), z.string()),
|
|
148
|
+
values: z.record(z.string(), z.string()),
|
|
149
|
+
attributes: z.record(z.string(), z.string()),
|
|
150
|
+
})
|
|
151
|
+
.catchall(z.record(z.string(), z.string()))
|
|
152
|
+
)
|
|
153
|
+
.optional(),
|
|
154
|
+
/** Translation options */
|
|
155
|
+
options: z
|
|
156
|
+
.object({
|
|
157
|
+
detectLocale: z.boolean().default(true),
|
|
158
|
+
rtlLocales: z.array(z.string()).default([]),
|
|
159
|
+
preserveOriginalAttribute: z.string().optional(),
|
|
160
|
+
validate: z.boolean().default(true),
|
|
161
|
+
})
|
|
162
|
+
.optional(),
|
|
163
|
+
/** Context variables for translation */
|
|
164
|
+
variables: z.record(z.string(), z.unknown()).optional(),
|
|
165
|
+
/** Environment and debug settings */
|
|
166
|
+
environment: z.enum(['frontend', 'backend', 'universal']).default('universal'),
|
|
167
|
+
debug: z.boolean().default(false),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Note: Using z.any() for function types because Zod's z.function() inference
|
|
171
|
+
// produces (...args: unknown[]) => unknown which is incompatible with specific signatures
|
|
172
|
+
export const EnhancedI18nOutputSchema = z.object({
|
|
173
|
+
/** Context identifier */
|
|
174
|
+
contextId: z.string(),
|
|
175
|
+
timestamp: z.number(),
|
|
176
|
+
category: z.literal('Universal'),
|
|
177
|
+
capabilities: z.array(z.string()),
|
|
178
|
+
state: z.enum(['ready', 'loading', 'error']),
|
|
179
|
+
|
|
180
|
+
/** I18n specific capabilities */
|
|
181
|
+
translate: z.any(),
|
|
182
|
+
translateHyperscript: z.any(),
|
|
183
|
+
setLocale: z.any(),
|
|
184
|
+
getLocale: z.any(),
|
|
185
|
+
validateTranslation: z.any(),
|
|
186
|
+
|
|
187
|
+
/** Locale management */
|
|
188
|
+
locale: z.object({
|
|
189
|
+
current: z.string(),
|
|
190
|
+
fallback: z.string().optional(),
|
|
191
|
+
direction: z.enum(['ltr', 'rtl']),
|
|
192
|
+
available: z.array(z.string()),
|
|
193
|
+
}),
|
|
194
|
+
|
|
195
|
+
/** Dictionary access */
|
|
196
|
+
dictionary: z.object({
|
|
197
|
+
get: z.any(),
|
|
198
|
+
set: z.any(),
|
|
199
|
+
has: z.any(),
|
|
200
|
+
keys: z.any(),
|
|
201
|
+
}),
|
|
202
|
+
|
|
203
|
+
/** Formatting utilities */
|
|
204
|
+
format: z.object({
|
|
205
|
+
number: z.any(),
|
|
206
|
+
date: z.any(),
|
|
207
|
+
currency: z.any(),
|
|
208
|
+
relative: z.any(),
|
|
209
|
+
}),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
export type EnhancedI18nInput = z.infer<typeof EnhancedI18nInputSchema>;
|
|
213
|
+
export type EnhancedI18nOutput = z.infer<typeof EnhancedI18nOutputSchema>;
|
|
214
|
+
|
|
215
|
+
// ============================================================================
|
|
216
|
+
// Enhanced I18n Context Implementation
|
|
217
|
+
// ============================================================================
|
|
218
|
+
|
|
219
|
+
export class TypedI18nContextImplementation {
|
|
220
|
+
public readonly name = 'i18nContext';
|
|
221
|
+
public readonly category = 'Universal' as const;
|
|
222
|
+
public readonly description =
|
|
223
|
+
'Type-safe internationalization context with enhanced validation and LLM integration';
|
|
224
|
+
public readonly inputSchema = EnhancedI18nInputSchema;
|
|
225
|
+
public readonly outputType: EvaluationType = 'Context';
|
|
226
|
+
|
|
227
|
+
private evaluationHistory: Array<{
|
|
228
|
+
input: EnhancedI18nInput;
|
|
229
|
+
output: EnhancedI18nOutput | undefined;
|
|
230
|
+
success: boolean;
|
|
231
|
+
duration: number;
|
|
232
|
+
timestamp: number;
|
|
233
|
+
}> = [];
|
|
234
|
+
|
|
235
|
+
public readonly metadata: ContextMetadata = {
|
|
236
|
+
category: 'Universal',
|
|
237
|
+
complexity: 'moderate',
|
|
238
|
+
sideEffects: ['locale-detection', 'dictionary-loading', 'text-transformation'],
|
|
239
|
+
dependencies: ['dictionaries', 'locale-detection', 'formatting-apis'],
|
|
240
|
+
returnTypes: ['Context'],
|
|
241
|
+
examples: [
|
|
242
|
+
{
|
|
243
|
+
input: '{ locale: "es", options: { detectLocale: true } }',
|
|
244
|
+
description: 'Initialize Spanish locale with auto-detection',
|
|
245
|
+
expectedOutput: 'TypedI18nContext with Spanish translations and RTL support',
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
input:
|
|
249
|
+
'{ locale: "ar", dictionaries: { ar: arabicDict }, options: { rtlLocales: ["ar"] } }',
|
|
250
|
+
description: 'Arabic locale with custom dictionary and RTL configuration',
|
|
251
|
+
expectedOutput: 'Arabic-aware context with right-to-left text direction',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
input: '{ locale: "qu", environment: "frontend" }',
|
|
255
|
+
description: 'Quechua locale for frontend environment',
|
|
256
|
+
expectedOutput: 'Indigenous language support with browser integration',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
relatedContexts: ['frontendContext', 'backendContext', 'templateContext'],
|
|
260
|
+
frameworkDependencies: ['intl-apis', 'locale-detection'],
|
|
261
|
+
environmentRequirements: {
|
|
262
|
+
browser: true,
|
|
263
|
+
server: true,
|
|
264
|
+
nodejs: true,
|
|
265
|
+
},
|
|
266
|
+
performance: {
|
|
267
|
+
averageTime: 8.5,
|
|
268
|
+
complexity: 'O(n)', // n = dictionary size
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
public readonly documentation: LLMDocumentation = {
|
|
273
|
+
summary:
|
|
274
|
+
'Creates type-safe internationalization context for multi-language hyperscript development with dictionary management, locale detection, and formatting utilities',
|
|
275
|
+
parameters: [
|
|
276
|
+
{
|
|
277
|
+
name: 'i18nConfig',
|
|
278
|
+
type: 'EnhancedI18nInput',
|
|
279
|
+
description:
|
|
280
|
+
'Internationalization configuration including locale, dictionaries, and options',
|
|
281
|
+
optional: false,
|
|
282
|
+
examples: [
|
|
283
|
+
'{ locale: "fr", options: { detectLocale: true } }',
|
|
284
|
+
'{ locale: "zh", dictionaries: { zh: chineseDict } }',
|
|
285
|
+
'{ locale: "sw", environment: "backend", options: { validate: true } }',
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
returns: {
|
|
290
|
+
type: 'EnhancedI18nContext',
|
|
291
|
+
description:
|
|
292
|
+
'Initialized internationalization context with translation capabilities and locale management',
|
|
293
|
+
examples: [
|
|
294
|
+
'context.translate("commands.click") → "cliquer"',
|
|
295
|
+
'context.translateHyperscript("on click") → "sur clic"',
|
|
296
|
+
'context.setLocale("ja") → switches to Japanese',
|
|
297
|
+
'context.format.number(1234.56) → "1,234.56" or "1.234,56" based on locale',
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
examples: [
|
|
301
|
+
{
|
|
302
|
+
title: 'Multi-language hyperscript development',
|
|
303
|
+
code: 'const i18n = await createI18nContext({ locale: "es", options: { detectLocale: true } })',
|
|
304
|
+
explanation: 'Create Spanish internationalization context with automatic locale detection',
|
|
305
|
+
output: 'Spanish-aware hyperscript translation and formatting capabilities',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
title: 'Custom dictionary integration',
|
|
309
|
+
code: 'await i18n.initialize({ locale: "qu", dictionaries: { qu: quechuaDict } })',
|
|
310
|
+
explanation: 'Initialize Quechua language support with custom dictionary',
|
|
311
|
+
output: 'Indigenous language hyperscript translation support',
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
title: 'RTL language support',
|
|
315
|
+
code: 'await i18n.initialize({ locale: "ar", options: { rtlLocales: ["ar", "he"] } })',
|
|
316
|
+
explanation: 'Arabic locale with right-to-left text direction support',
|
|
317
|
+
output: 'RTL-aware hyperscript with proper text direction and layout',
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
seeAlso: ['frontendContext', 'backendContext', 'templateIntegration', 'formatting'],
|
|
321
|
+
tags: [
|
|
322
|
+
'i18n',
|
|
323
|
+
'internationalization',
|
|
324
|
+
'locale',
|
|
325
|
+
'translation',
|
|
326
|
+
'type-safe',
|
|
327
|
+
'enhanced-pattern',
|
|
328
|
+
],
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
async initialize(input: EnhancedI18nInput): Promise<EvaluationResult<EnhancedI18nOutput>> {
|
|
332
|
+
const startTime = Date.now();
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
// Validate input using enhanced pattern
|
|
336
|
+
const validation = this.validate(input);
|
|
337
|
+
if (!validation.isValid) {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
errors: validation.errors,
|
|
341
|
+
suggestions: validation.suggestions || [],
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Initialize locale and dictionaries
|
|
346
|
+
const locale = await this.initializeLocale(input);
|
|
347
|
+
const dictionaries = await this.loadDictionaries(input);
|
|
348
|
+
|
|
349
|
+
// Create enhanced i18n context
|
|
350
|
+
const context: EnhancedI18nOutput = {
|
|
351
|
+
contextId: `i18n-${Date.now()}`,
|
|
352
|
+
timestamp: startTime,
|
|
353
|
+
category: 'Universal',
|
|
354
|
+
capabilities: [
|
|
355
|
+
'translation',
|
|
356
|
+
'locale-management',
|
|
357
|
+
'formatting',
|
|
358
|
+
'validation',
|
|
359
|
+
'rtl-support',
|
|
360
|
+
],
|
|
361
|
+
state: 'ready',
|
|
362
|
+
|
|
363
|
+
// Enhanced translation functions
|
|
364
|
+
translate: this.createTranslateFunction(dictionaries, locale),
|
|
365
|
+
translateHyperscript: this.createHyperscriptTranslator(dictionaries, locale),
|
|
366
|
+
setLocale: this.createLocaleChanger(dictionaries),
|
|
367
|
+
getLocale: () => locale.current,
|
|
368
|
+
validateTranslation: this.createValidationFunction(dictionaries),
|
|
369
|
+
|
|
370
|
+
// Locale management
|
|
371
|
+
locale: {
|
|
372
|
+
current: locale.current,
|
|
373
|
+
fallback: locale.fallback,
|
|
374
|
+
direction: locale.direction,
|
|
375
|
+
available: Object.keys(dictionaries),
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
// Dictionary access
|
|
379
|
+
dictionary: {
|
|
380
|
+
get: (key: string) => this.getDictionaryValue(dictionaries, locale.current, key),
|
|
381
|
+
set: (key: string, value: string) =>
|
|
382
|
+
this.setDictionaryValue(dictionaries, locale.current, key, value),
|
|
383
|
+
has: (key: string) => this.hasDictionaryValue(dictionaries, locale.current, key),
|
|
384
|
+
keys: () => this.getDictionaryKeys(dictionaries, locale.current),
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
// Enhanced formatting utilities
|
|
388
|
+
format: {
|
|
389
|
+
number: this.createNumberFormatter(locale.current),
|
|
390
|
+
date: this.createDateFormatter(locale.current),
|
|
391
|
+
currency: this.createCurrencyFormatter(locale.current),
|
|
392
|
+
relative: this.createRelativeTimeFormatter(locale.current),
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Track performance using enhanced pattern
|
|
397
|
+
this.trackPerformance(startTime, true, context);
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
success: true,
|
|
401
|
+
value: context,
|
|
402
|
+
type: 'Context',
|
|
403
|
+
};
|
|
404
|
+
} catch (error) {
|
|
405
|
+
this.trackPerformance(startTime, false);
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
success: false,
|
|
409
|
+
errors: [
|
|
410
|
+
{
|
|
411
|
+
type: 'runtime-error',
|
|
412
|
+
message: `I18n context initialization failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
suggestions: [
|
|
416
|
+
'Verify locale code is valid (ISO 639-1 format)',
|
|
417
|
+
'Check dictionary structure matches expected format',
|
|
418
|
+
'Ensure dictionaries are properly loaded',
|
|
419
|
+
'Validate environment requirements are met',
|
|
420
|
+
],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
validate(input: unknown): ValidationResult {
|
|
426
|
+
try {
|
|
427
|
+
const parsed = this.inputSchema.parse(input);
|
|
428
|
+
const errors: Array<{ type: string; message: string; path?: string }> = [];
|
|
429
|
+
const suggestions: string[] = [];
|
|
430
|
+
|
|
431
|
+
// Enhanced validation logic
|
|
432
|
+
const data = parsed as EnhancedI18nInput;
|
|
433
|
+
|
|
434
|
+
// Validate locale format
|
|
435
|
+
if (data.locale && !/^[a-z]{2}(-[A-Z]{2})?$/.test(data.locale)) {
|
|
436
|
+
errors.push({
|
|
437
|
+
type: 'invalid-locale',
|
|
438
|
+
message: 'Locale must be in ISO 639-1 format (e.g., "en", "es", "zh-CN")',
|
|
439
|
+
path: 'locale',
|
|
440
|
+
});
|
|
441
|
+
suggestions.push('Use standard locale codes like "en", "es", "fr", "de", "ja", "zh"');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Validate fallback locale
|
|
445
|
+
if (data.fallbackLocale && !/^[a-z]{2}(-[A-Z]{2})?$/.test(data.fallbackLocale)) {
|
|
446
|
+
errors.push({
|
|
447
|
+
type: 'invalid-fallback-locale',
|
|
448
|
+
message: 'Fallback locale must be in ISO 639-1 format',
|
|
449
|
+
path: 'fallbackLocale',
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Validate dictionary structure
|
|
454
|
+
if (data.dictionaries) {
|
|
455
|
+
Object.entries(data.dictionaries).forEach(([locale, dict]) => {
|
|
456
|
+
const requiredCategories = [
|
|
457
|
+
'commands',
|
|
458
|
+
'modifiers',
|
|
459
|
+
'events',
|
|
460
|
+
'logical',
|
|
461
|
+
'temporal',
|
|
462
|
+
'values',
|
|
463
|
+
'attributes',
|
|
464
|
+
];
|
|
465
|
+
const missingCategories = requiredCategories.filter(cat => !dict[cat]);
|
|
466
|
+
|
|
467
|
+
if (missingCategories.length > 0) {
|
|
468
|
+
errors.push({
|
|
469
|
+
type: 'incomplete-dictionary',
|
|
470
|
+
message: `Dictionary for ${locale} is missing categories: ${missingCategories.join(', ')}`,
|
|
471
|
+
path: `dictionaries.${locale}`,
|
|
472
|
+
});
|
|
473
|
+
suggestions.push(
|
|
474
|
+
`Add missing categories to ${locale} dictionary for complete hyperscript translation`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
isValid: errors.length === 0,
|
|
482
|
+
errors,
|
|
483
|
+
suggestions,
|
|
484
|
+
};
|
|
485
|
+
} catch (error) {
|
|
486
|
+
return {
|
|
487
|
+
isValid: false,
|
|
488
|
+
errors: [
|
|
489
|
+
{
|
|
490
|
+
type: 'schema-validation',
|
|
491
|
+
message: error instanceof Error ? error.message : 'Invalid input format',
|
|
492
|
+
},
|
|
493
|
+
],
|
|
494
|
+
suggestions: [
|
|
495
|
+
'Ensure input matches EnhancedI18nInput schema',
|
|
496
|
+
'Check locale is a valid string',
|
|
497
|
+
'Verify dictionaries follow the expected structure',
|
|
498
|
+
],
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// Enhanced Helper Methods
|
|
505
|
+
// ============================================================================
|
|
506
|
+
|
|
507
|
+
private async initializeLocale(input: EnhancedI18nInput) {
|
|
508
|
+
const { locale, fallbackLocale = 'en', options } = input;
|
|
509
|
+
|
|
510
|
+
// Detect RTL languages
|
|
511
|
+
const rtlLocales = options?.rtlLocales || ['ar', 'he', 'fa', 'ur'];
|
|
512
|
+
const direction = rtlLocales.includes(locale) ? 'rtl' : 'ltr';
|
|
513
|
+
|
|
514
|
+
return {
|
|
515
|
+
current: locale,
|
|
516
|
+
fallback: fallbackLocale,
|
|
517
|
+
direction: direction as 'ltr' | 'rtl',
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private async loadDictionaries(input: EnhancedI18nInput) {
|
|
522
|
+
// Return provided dictionaries or load defaults
|
|
523
|
+
return input.dictionaries || {};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private createTranslateFunction(dictionaries: Record<string, any>, locale: any) {
|
|
527
|
+
return (key: string, category: string = 'commands') => {
|
|
528
|
+
const dict = dictionaries[locale.current];
|
|
529
|
+
if (!dict || !dict[category]) {
|
|
530
|
+
return key; // Return original if no translation found
|
|
531
|
+
}
|
|
532
|
+
return dict[category][key] || key;
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private createHyperscriptTranslator(dictionaries: Record<string, any>, locale: any) {
|
|
537
|
+
return (hyperscript: string) => {
|
|
538
|
+
// Enhanced hyperscript translation logic
|
|
539
|
+
const dict = dictionaries[locale.current];
|
|
540
|
+
if (!dict) return hyperscript;
|
|
541
|
+
|
|
542
|
+
let translated = hyperscript;
|
|
543
|
+
|
|
544
|
+
// Translate commands, modifiers, events, etc.
|
|
545
|
+
Object.entries(dict.commands || {}).forEach(([en, translated_word]) => {
|
|
546
|
+
translated = translated.replace(new RegExp(`\\b${en}\\b`, 'g'), translated_word as string);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
Object.entries(dict.modifiers || {}).forEach(([en, translated_word]) => {
|
|
550
|
+
translated = translated.replace(new RegExp(`\\b${en}\\b`, 'g'), translated_word as string);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
return translated;
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private createLocaleChanger(dictionaries: Record<string, any>) {
|
|
558
|
+
return (newLocale: string) => {
|
|
559
|
+
if (dictionaries[newLocale]) {
|
|
560
|
+
// Logic to change locale
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
return false;
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private createValidationFunction(dictionaries: Record<string, any>) {
|
|
568
|
+
return (locale: string, _hyperscript: string) => {
|
|
569
|
+
const dict = dictionaries[locale];
|
|
570
|
+
if (!dict) {
|
|
571
|
+
return {
|
|
572
|
+
valid: false,
|
|
573
|
+
errors: [`No dictionary found for locale: ${locale}`],
|
|
574
|
+
coverage: 0,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Validation logic here
|
|
579
|
+
return {
|
|
580
|
+
valid: true,
|
|
581
|
+
errors: [],
|
|
582
|
+
coverage: 100,
|
|
583
|
+
};
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private getDictionaryValue(dictionaries: Record<string, any>, locale: string, key: string) {
|
|
588
|
+
const [category, ...keyParts] = key.split('.');
|
|
589
|
+
const actualKey = keyParts.join('.');
|
|
590
|
+
const dict = dictionaries[locale];
|
|
591
|
+
return dict?.[category]?.[actualKey];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private setDictionaryValue(
|
|
595
|
+
dictionaries: Record<string, any>,
|
|
596
|
+
locale: string,
|
|
597
|
+
key: string,
|
|
598
|
+
value: string
|
|
599
|
+
) {
|
|
600
|
+
const [category, ...keyParts] = key.split('.');
|
|
601
|
+
const actualKey = keyParts.join('.');
|
|
602
|
+
if (!dictionaries[locale]) dictionaries[locale] = {};
|
|
603
|
+
if (!dictionaries[locale][category]) dictionaries[locale][category] = {};
|
|
604
|
+
dictionaries[locale][category][actualKey] = value;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
private hasDictionaryValue(
|
|
608
|
+
dictionaries: Record<string, any>,
|
|
609
|
+
locale: string,
|
|
610
|
+
key: string
|
|
611
|
+
): boolean {
|
|
612
|
+
return this.getDictionaryValue(dictionaries, locale, key) !== undefined;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private getDictionaryKeys(dictionaries: Record<string, any>, locale: string): string[] {
|
|
616
|
+
const dict = dictionaries[locale];
|
|
617
|
+
if (!dict) return [];
|
|
618
|
+
|
|
619
|
+
const keys: string[] = [];
|
|
620
|
+
Object.entries(dict).forEach(([category, categoryDict]) => {
|
|
621
|
+
if (typeof categoryDict === 'object' && categoryDict !== null) {
|
|
622
|
+
Object.keys(categoryDict as object).forEach(key => {
|
|
623
|
+
keys.push(`${category}.${key}`);
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
return keys;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private createNumberFormatter(locale: string) {
|
|
631
|
+
return (number: number, options?: Intl.NumberFormatOptions) => {
|
|
632
|
+
return new Intl.NumberFormat(locale, options).format(number);
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private createDateFormatter(locale: string) {
|
|
637
|
+
return (date: Date | number, options?: Intl.DateTimeFormatOptions) => {
|
|
638
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
private createCurrencyFormatter(locale: string) {
|
|
643
|
+
return (amount: number, currency: string = 'USD', options?: Intl.NumberFormatOptions) => {
|
|
644
|
+
return new Intl.NumberFormat(locale, {
|
|
645
|
+
style: 'currency',
|
|
646
|
+
currency,
|
|
647
|
+
...options,
|
|
648
|
+
}).format(amount);
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
private createRelativeTimeFormatter(locale: string) {
|
|
653
|
+
return (
|
|
654
|
+
value: number,
|
|
655
|
+
unit: Intl.RelativeTimeFormatUnit,
|
|
656
|
+
options?: Intl.RelativeTimeFormatOptions
|
|
657
|
+
) => {
|
|
658
|
+
return new Intl.RelativeTimeFormat(locale, options).format(value, unit);
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
private trackPerformance(startTime: number, success: boolean, output?: EnhancedI18nOutput): void {
|
|
663
|
+
const duration = Date.now() - startTime;
|
|
664
|
+
this.evaluationHistory.push({
|
|
665
|
+
input: {} as EnhancedI18nInput, // Would store actual input in real implementation
|
|
666
|
+
output,
|
|
667
|
+
success,
|
|
668
|
+
duration,
|
|
669
|
+
timestamp: startTime,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
getPerformanceMetrics() {
|
|
674
|
+
return {
|
|
675
|
+
totalInitializations: this.evaluationHistory.length,
|
|
676
|
+
successRate:
|
|
677
|
+
this.evaluationHistory.filter(h => h.success).length /
|
|
678
|
+
Math.max(this.evaluationHistory.length, 1),
|
|
679
|
+
averageDuration:
|
|
680
|
+
this.evaluationHistory.reduce((sum, h) => sum + h.duration, 0) /
|
|
681
|
+
Math.max(this.evaluationHistory.length, 1),
|
|
682
|
+
lastEvaluationTime: this.evaluationHistory[this.evaluationHistory.length - 1]?.timestamp || 0,
|
|
683
|
+
evaluationHistory: this.evaluationHistory.slice(-10), // Last 10 evaluations
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// ============================================================================
|
|
689
|
+
// Convenience Factory Functions
|
|
690
|
+
// ============================================================================
|
|
691
|
+
|
|
692
|
+
export function createI18nContext(): TypedI18nContextImplementation {
|
|
693
|
+
return new TypedI18nContextImplementation();
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export async function createEnhancedI18n(
|
|
697
|
+
locale: string,
|
|
698
|
+
options?: Partial<EnhancedI18nInput>
|
|
699
|
+
): Promise<EvaluationResult<EnhancedI18nOutput>> {
|
|
700
|
+
const i18n = new TypedI18nContextImplementation();
|
|
701
|
+
return i18n.initialize({
|
|
702
|
+
locale,
|
|
703
|
+
environment: options?.environment || 'universal',
|
|
704
|
+
debug: options?.debug || false,
|
|
705
|
+
...options,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// ============================================================================
|
|
710
|
+
// Export for Registry Registration
|
|
711
|
+
// ============================================================================
|
|
712
|
+
|
|
713
|
+
export const enhancedI18nImplementation = new TypedI18nContextImplementation();
|