@pie-players/pie-assessment-toolkit 0.2.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 +520 -0
- package/dist/attempt/TestSession.d.ts +90 -0
- package/dist/attempt/TestSession.d.ts.map +1 -0
- package/dist/attempt/TestSession.js +174 -0
- package/dist/attempt/TestSession.js.map +1 -0
- package/dist/core/TypedEventBus.d.ts +48 -0
- package/dist/core/TypedEventBus.d.ts.map +1 -0
- package/dist/core/TypedEventBus.js +63 -0
- package/dist/core/TypedEventBus.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/item-loader.d.ts +45 -0
- package/dist/item-loader.d.ts.map +1 -0
- package/dist/item-loader.js +62 -0
- package/dist/item-loader.js.map +1 -0
- package/dist/player/AssessmentPlayer.d.ts +388 -0
- package/dist/player/AssessmentPlayer.d.ts.map +1 -0
- package/dist/player/AssessmentPlayer.js +965 -0
- package/dist/player/AssessmentPlayer.js.map +1 -0
- package/dist/player/index.d.ts +17 -0
- package/dist/player/index.d.ts.map +1 -0
- package/dist/player/index.js +15 -0
- package/dist/player/index.js.map +1 -0
- package/dist/player/navigation-types.d.ts +63 -0
- package/dist/player/navigation-types.d.ts.map +1 -0
- package/dist/player/navigation-types.js +7 -0
- package/dist/player/navigation-types.js.map +1 -0
- package/dist/player/qti-navigation.d.ts +29 -0
- package/dist/player/qti-navigation.d.ts.map +1 -0
- package/dist/player/qti-navigation.js +160 -0
- package/dist/player/qti-navigation.js.map +1 -0
- package/dist/reference-layout/index.d.ts +19 -0
- package/dist/reference-layout/index.d.ts.map +1 -0
- package/dist/reference-layout/index.js +20 -0
- package/dist/reference-layout/index.js.map +1 -0
- package/dist/services/AccessibilityCatalogResolver.d.ts +141 -0
- package/dist/services/AccessibilityCatalogResolver.d.ts.map +1 -0
- package/dist/services/AccessibilityCatalogResolver.js +249 -0
- package/dist/services/AccessibilityCatalogResolver.js.map +1 -0
- package/dist/services/AssessmentAuthoringService.d.ts +60 -0
- package/dist/services/AssessmentAuthoringService.d.ts.map +1 -0
- package/dist/services/AssessmentAuthoringService.js +183 -0
- package/dist/services/AssessmentAuthoringService.js.map +1 -0
- package/dist/services/ContextVariableStore.d.ts +114 -0
- package/dist/services/ContextVariableStore.d.ts.map +1 -0
- package/dist/services/ContextVariableStore.js +207 -0
- package/dist/services/ContextVariableStore.js.map +1 -0
- package/dist/services/ElementToolStateStore.d.ts +125 -0
- package/dist/services/ElementToolStateStore.d.ts.map +1 -0
- package/dist/services/ElementToolStateStore.js +200 -0
- package/dist/services/ElementToolStateStore.js.map +1 -0
- package/dist/services/HighlightCoordinator.d.ts +179 -0
- package/dist/services/HighlightCoordinator.d.ts.map +1 -0
- package/dist/services/HighlightCoordinator.js +446 -0
- package/dist/services/HighlightCoordinator.js.map +1 -0
- package/dist/services/I18nService.d.ts +121 -0
- package/dist/services/I18nService.d.ts.map +1 -0
- package/dist/services/I18nService.js +276 -0
- package/dist/services/I18nService.js.map +1 -0
- package/dist/services/PNPMapper.d.ts +71 -0
- package/dist/services/PNPMapper.d.ts.map +1 -0
- package/dist/services/PNPMapper.js +98 -0
- package/dist/services/PNPMapper.js.map +1 -0
- package/dist/services/PNPToolResolver.d.ts +127 -0
- package/dist/services/PNPToolResolver.d.ts.map +1 -0
- package/dist/services/PNPToolResolver.js +222 -0
- package/dist/services/PNPToolResolver.js.map +1 -0
- package/dist/services/SSMLExtractor.d.ts +61 -0
- package/dist/services/SSMLExtractor.d.ts.map +1 -0
- package/dist/services/SSMLExtractor.js +181 -0
- package/dist/services/SSMLExtractor.js.map +1 -0
- package/dist/services/TTSService.d.ts +162 -0
- package/dist/services/TTSService.d.ts.map +1 -0
- package/dist/services/TTSService.js +465 -0
- package/dist/services/TTSService.js.map +1 -0
- package/dist/services/ThemeProvider.d.ts +95 -0
- package/dist/services/ThemeProvider.d.ts.map +1 -0
- package/dist/services/ThemeProvider.js +299 -0
- package/dist/services/ThemeProvider.js.map +1 -0
- package/dist/services/ToolConfigResolver.d.ts +162 -0
- package/dist/services/ToolConfigResolver.d.ts.map +1 -0
- package/dist/services/ToolConfigResolver.js +230 -0
- package/dist/services/ToolConfigResolver.js.map +1 -0
- package/dist/services/ToolCoordinator.d.ts +137 -0
- package/dist/services/ToolCoordinator.d.ts.map +1 -0
- package/dist/services/ToolCoordinator.js +318 -0
- package/dist/services/ToolCoordinator.js.map +1 -0
- package/dist/services/ToolkitCoordinator.d.ts +188 -0
- package/dist/services/ToolkitCoordinator.d.ts.map +1 -0
- package/dist/services/ToolkitCoordinator.js +252 -0
- package/dist/services/ToolkitCoordinator.js.map +1 -0
- package/dist/services/interfaces.d.ts +391 -0
- package/dist/services/interfaces.d.ts.map +1 -0
- package/dist/services/interfaces.js +12 -0
- package/dist/services/interfaces.js.map +1 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +103 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/DesmosToolProvider.js +127 -0
- package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -0
- package/dist/services/tool-providers/IToolProvider.d.ts +137 -0
- package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/IToolProvider.js +13 -0
- package/dist/services/tool-providers/IToolProvider.js.map +1 -0
- package/dist/services/tool-providers/TIToolProvider.d.ts +107 -0
- package/dist/services/tool-providers/TIToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/TIToolProvider.js +123 -0
- package/dist/services/tool-providers/TIToolProvider.js.map +1 -0
- package/dist/services/tool-providers/TTSToolProvider.d.ts +143 -0
- package/dist/services/tool-providers/TTSToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/TTSToolProvider.js +168 -0
- package/dist/services/tool-providers/TTSToolProvider.js.map +1 -0
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +165 -0
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +1 -0
- package/dist/services/tool-providers/ToolProviderRegistry.js +240 -0
- package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -0
- package/dist/services/tool-providers/index.d.ts +18 -0
- package/dist/services/tool-providers/index.d.ts.map +1 -0
- package/dist/services/tool-providers/index.js +15 -0
- package/dist/services/tool-providers/index.js.map +1 -0
- package/dist/services/tts/browser-provider.d.ts +24 -0
- package/dist/services/tts/browser-provider.d.ts.map +1 -0
- package/dist/services/tts/browser-provider.js +177 -0
- package/dist/services/tts/browser-provider.js.map +1 -0
- package/dist/services/tts/provider-interface.d.ts +131 -0
- package/dist/services/tts/provider-interface.d.ts.map +1 -0
- package/dist/services/tts/provider-interface.js +10 -0
- package/dist/services/tts/provider-interface.js.map +1 -0
- package/dist/tools/calculators/desmos-provider.d.ts +54 -0
- package/dist/tools/calculators/desmos-provider.d.ts.map +1 -0
- package/dist/tools/calculators/desmos-provider.js +384 -0
- package/dist/tools/calculators/desmos-provider.js.map +1 -0
- package/dist/tools/calculators/mathjs-provider.d.ts +50 -0
- package/dist/tools/calculators/mathjs-provider.d.ts.map +1 -0
- package/dist/tools/calculators/mathjs-provider.js +660 -0
- package/dist/tools/calculators/mathjs-provider.js.map +1 -0
- package/dist/tools/calculators/ti-provider.d.ts +122 -0
- package/dist/tools/calculators/ti-provider.d.ts.map +1 -0
- package/dist/tools/calculators/ti-provider.js +587 -0
- package/dist/tools/calculators/ti-provider.js.map +1 -0
- package/dist/tools/client.d.ts +17 -0
- package/dist/tools/client.d.ts.map +1 -0
- package/dist/tools/client.js +26 -0
- package/dist/tools/client.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/library-loader.d.ts +63 -0
- package/dist/tools/library-loader.d.ts.map +1 -0
- package/dist/tools/library-loader.js +292 -0
- package/dist/tools/library-loader.js.map +1 -0
- package/dist/tools/response-discovery.d.ts +72 -0
- package/dist/tools/response-discovery.d.ts.map +1 -0
- package/dist/tools/response-discovery.js +183 -0
- package/dist/tools/response-discovery.js.map +1 -0
- package/dist/tools/tool-coordinator.d.ts +76 -0
- package/dist/tools/tool-coordinator.d.ts.map +1 -0
- package/dist/tools/tool-coordinator.js +197 -0
- package/dist/tools/tool-coordinator.js.map +1 -0
- package/dist/tools/types.d.ts +427 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +13 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/variant-resolver.d.ts +48 -0
- package/dist/tools/variant-resolver.d.ts.map +1 -0
- package/dist/tools/variant-resolver.js +214 -0
- package/dist/tools/variant-resolver.js.map +1 -0
- package/dist/types/events.d.ts +157 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +11 -0
- package/dist/types/events.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +71 -0
- package/src/README.md +626 -0
- package/src/components/QuestionToolBar.svelte +406 -0
- package/src/player/AssessmentLayout.svelte +68 -0
- package/src/player/README.md +154 -0
- package/src/reference-layout/README.md +135 -0
- package/src/reference-layout/ReferenceLayout.svelte +209 -0
- package/src/reference-layout/components/AssessmentContent.svelte +259 -0
- package/src/reference-layout/components/AssessmentFooter.svelte +89 -0
- package/src/reference-layout/components/AssessmentHeader.svelte +250 -0
- package/src/reference-layout/components/AssessmentNavigation.svelte +134 -0
- package/src/reference-layout/components/AssessmentToolsBar.svelte +176 -0
- package/src/reference-layout/components/ItemPanel.svelte +200 -0
- package/src/reference-layout/components/NotesPanel.svelte +179 -0
- package/src/reference-layout/components/PassagePanel.svelte +76 -0
- package/src/tools/README.md +616 -0
- package/src/tools/calculators/README.md +395 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I18nService
|
|
3
|
+
*
|
|
4
|
+
* Internationalization service with hybrid loading strategy.
|
|
5
|
+
* Manages translations, locale switching, and RTL/LTR direction.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Subscriber/listener pattern for reactive updates
|
|
9
|
+
* - Hybrid loading: Bundle English, lazy-load other locales
|
|
10
|
+
* - Interpolation: {variable} syntax
|
|
11
|
+
* - Pluralization: ICU-style plural rules
|
|
12
|
+
* - RTL detection: Automatic based on locale
|
|
13
|
+
* - TypedEventBus integration: Emit locale change events
|
|
14
|
+
* - Fallback to English for missing keys
|
|
15
|
+
*
|
|
16
|
+
* Part of PIE Assessment Toolkit.
|
|
17
|
+
*/
|
|
18
|
+
import type { I18nConfig, II18nService, PluralTranslation, TranslationBundle } from "@pie-players/pie-players-shared/i18n";
|
|
19
|
+
export type { I18nConfig, II18nService, PluralTranslation, TranslationBundle };
|
|
20
|
+
/**
|
|
21
|
+
* I18nService
|
|
22
|
+
*
|
|
23
|
+
* Manages internationalization with reactive state updates.
|
|
24
|
+
*/
|
|
25
|
+
export declare class I18nService implements II18nService {
|
|
26
|
+
private locale;
|
|
27
|
+
private fallbackLocale;
|
|
28
|
+
private direction;
|
|
29
|
+
private translations;
|
|
30
|
+
private listeners;
|
|
31
|
+
private loadingPromises;
|
|
32
|
+
private config;
|
|
33
|
+
constructor(config?: I18nConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Initialize i18n with locale and loading strategy
|
|
36
|
+
*/
|
|
37
|
+
initialize(config: I18nConfig): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Translate a key with optional interpolation
|
|
40
|
+
*
|
|
41
|
+
* @param key Translation key (e.g., 'common.save')
|
|
42
|
+
* @param params Optional parameters for interpolation
|
|
43
|
+
* @returns Translated string
|
|
44
|
+
*/
|
|
45
|
+
t(key: string, params?: Record<string, any>): string;
|
|
46
|
+
/**
|
|
47
|
+
* Translate with pluralization
|
|
48
|
+
*
|
|
49
|
+
* @param key Translation key
|
|
50
|
+
* @param count Count for pluralization
|
|
51
|
+
* @param params Optional parameters for interpolation
|
|
52
|
+
* @returns Translated string with plural form
|
|
53
|
+
*/
|
|
54
|
+
tn(key: string, count: number, params?: Record<string, any>): string;
|
|
55
|
+
/**
|
|
56
|
+
* Get current locale
|
|
57
|
+
*/
|
|
58
|
+
getLocale(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Change locale (triggers async loading if needed)
|
|
61
|
+
*
|
|
62
|
+
* @param locale Locale code (e.g., 'en', 'es', 'zh', 'ar')
|
|
63
|
+
*/
|
|
64
|
+
setLocale(locale: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Get current text direction
|
|
67
|
+
*/
|
|
68
|
+
getDirection(): "ltr" | "rtl";
|
|
69
|
+
/**
|
|
70
|
+
* Get available locales
|
|
71
|
+
*/
|
|
72
|
+
getAvailableLocales(): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Check if locale is loaded
|
|
75
|
+
*/
|
|
76
|
+
isLocaleLoaded(locale: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Subscribe to locale/translation changes
|
|
79
|
+
* Returns unsubscribe function
|
|
80
|
+
*/
|
|
81
|
+
subscribe(listener: () => void): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* Check if a translation key exists
|
|
84
|
+
*/
|
|
85
|
+
hasKey(key: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Notify all listeners of state change
|
|
88
|
+
*/
|
|
89
|
+
private notifyListeners;
|
|
90
|
+
/**
|
|
91
|
+
* Apply locale and notify listeners
|
|
92
|
+
*/
|
|
93
|
+
private applyLocale;
|
|
94
|
+
/**
|
|
95
|
+
* Apply direction to DOM
|
|
96
|
+
*/
|
|
97
|
+
private applyDOMDirection;
|
|
98
|
+
/**
|
|
99
|
+
* Load translations for a locale
|
|
100
|
+
*/
|
|
101
|
+
private loadTranslationsForLocale;
|
|
102
|
+
/**
|
|
103
|
+
* Get translation for a key
|
|
104
|
+
*/
|
|
105
|
+
private getTranslation;
|
|
106
|
+
/**
|
|
107
|
+
* Interpolate variables in translation string
|
|
108
|
+
* Replaces {variable} with params.variable
|
|
109
|
+
*/
|
|
110
|
+
private interpolate;
|
|
111
|
+
/**
|
|
112
|
+
* Select plural form based on count and locale
|
|
113
|
+
* Simplified implementation - real implementation would use Intl.PluralRules
|
|
114
|
+
*/
|
|
115
|
+
private selectPluralForm;
|
|
116
|
+
/**
|
|
117
|
+
* Detect browser locale
|
|
118
|
+
*/
|
|
119
|
+
private detectBrowserLocale;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=I18nService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"I18nService.d.ts","sourceRoot":"","sources":["../../src/services/I18nService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACX,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,sCAAsC,CAAC;AAM9C,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;AAE/E;;;;GAIG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC/C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,GAAE,UAAe;IAiBnC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASnD;;;;;;OAMG;IACH,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;IAKpD;;;;;;;OAOG;IACH,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;IAYpE;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;;;OAIG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B9C;;OAEG;IACH,YAAY,IAAI,KAAK,GAAG,KAAK;IAI7B;;OAEG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAI/B;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIvC;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO3C;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK5B;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;YACW,yBAAyB;IAmBvC;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAW3B"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I18nService
|
|
3
|
+
*
|
|
4
|
+
* Internationalization service with hybrid loading strategy.
|
|
5
|
+
* Manages translations, locale switching, and RTL/LTR direction.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Subscriber/listener pattern for reactive updates
|
|
9
|
+
* - Hybrid loading: Bundle English, lazy-load other locales
|
|
10
|
+
* - Interpolation: {variable} syntax
|
|
11
|
+
* - Pluralization: ICU-style plural rules
|
|
12
|
+
* - RTL detection: Automatic based on locale
|
|
13
|
+
* - TypedEventBus integration: Emit locale change events
|
|
14
|
+
* - Fallback to English for missing keys
|
|
15
|
+
*
|
|
16
|
+
* Part of PIE Assessment Toolkit.
|
|
17
|
+
*/
|
|
18
|
+
import { createLogger } from "../utils/logger";
|
|
19
|
+
const log = createLogger("I18nService");
|
|
20
|
+
/**
|
|
21
|
+
* I18nService
|
|
22
|
+
*
|
|
23
|
+
* Manages internationalization with reactive state updates.
|
|
24
|
+
*/
|
|
25
|
+
export class I18nService {
|
|
26
|
+
locale = "en";
|
|
27
|
+
fallbackLocale = "en";
|
|
28
|
+
direction = "ltr";
|
|
29
|
+
translations = new Map();
|
|
30
|
+
listeners = new Set();
|
|
31
|
+
loadingPromises = new Map();
|
|
32
|
+
config;
|
|
33
|
+
constructor(config = {}) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.fallbackLocale = config.fallbackLocale || "en";
|
|
36
|
+
log("I18nService initialized", { fallbackLocale: this.fallbackLocale });
|
|
37
|
+
// Load bundled translations (English by default)
|
|
38
|
+
if (config.bundledTranslations) {
|
|
39
|
+
for (const [locale, bundle] of Object.entries(config.bundledTranslations)) {
|
|
40
|
+
this.translations.set(locale, bundle);
|
|
41
|
+
log(`Loaded bundled translations for: ${locale}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize i18n with locale and loading strategy
|
|
47
|
+
*/
|
|
48
|
+
async initialize(config) {
|
|
49
|
+
Object.assign(this.config, config);
|
|
50
|
+
const locale = config.locale || this.detectBrowserLocale();
|
|
51
|
+
log(`Initializing with locale: ${locale}`);
|
|
52
|
+
await this.setLocale(locale);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Translate a key with optional interpolation
|
|
56
|
+
*
|
|
57
|
+
* @param key Translation key (e.g., 'common.save')
|
|
58
|
+
* @param params Optional parameters for interpolation
|
|
59
|
+
* @returns Translated string
|
|
60
|
+
*/
|
|
61
|
+
t(key, params) {
|
|
62
|
+
const translation = this.getTranslation(key);
|
|
63
|
+
return this.interpolate(translation, params);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Translate with pluralization
|
|
67
|
+
*
|
|
68
|
+
* @param key Translation key
|
|
69
|
+
* @param count Count for pluralization
|
|
70
|
+
* @param params Optional parameters for interpolation
|
|
71
|
+
* @returns Translated string with plural form
|
|
72
|
+
*/
|
|
73
|
+
tn(key, count, params) {
|
|
74
|
+
const translation = this.getTranslation(key);
|
|
75
|
+
if (typeof translation === "object") {
|
|
76
|
+
const pluralForm = this.selectPluralForm(count, this.locale);
|
|
77
|
+
const text = translation[pluralForm] || translation.other;
|
|
78
|
+
return this.interpolate(text, { ...params, count });
|
|
79
|
+
}
|
|
80
|
+
return this.interpolate(translation, { ...params, count });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get current locale
|
|
84
|
+
*/
|
|
85
|
+
getLocale() {
|
|
86
|
+
return this.locale;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Change locale (triggers async loading if needed)
|
|
90
|
+
*
|
|
91
|
+
* @param locale Locale code (e.g., 'en', 'es', 'zh', 'ar')
|
|
92
|
+
*/
|
|
93
|
+
async setLocale(locale) {
|
|
94
|
+
log(`Setting locale to: ${locale}`);
|
|
95
|
+
// Check if already loading
|
|
96
|
+
if (this.loadingPromises.has(locale)) {
|
|
97
|
+
log(`Locale ${locale} is already loading, waiting...`);
|
|
98
|
+
await this.loadingPromises.get(locale);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Check if already loaded
|
|
102
|
+
if (this.translations.has(locale)) {
|
|
103
|
+
log(`Locale ${locale} already loaded`);
|
|
104
|
+
this.applyLocale(locale);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Load translations
|
|
108
|
+
const loadingPromise = this.loadTranslationsForLocale(locale);
|
|
109
|
+
this.loadingPromises.set(locale, loadingPromise);
|
|
110
|
+
try {
|
|
111
|
+
await loadingPromise;
|
|
112
|
+
this.applyLocale(locale);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
this.loadingPromises.delete(locale);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get current text direction
|
|
120
|
+
*/
|
|
121
|
+
getDirection() {
|
|
122
|
+
return this.direction;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get available locales
|
|
126
|
+
*/
|
|
127
|
+
getAvailableLocales() {
|
|
128
|
+
return Array.from(this.translations.keys());
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if locale is loaded
|
|
132
|
+
*/
|
|
133
|
+
isLocaleLoaded(locale) {
|
|
134
|
+
return this.translations.has(locale);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Subscribe to locale/translation changes
|
|
138
|
+
* Returns unsubscribe function
|
|
139
|
+
*/
|
|
140
|
+
subscribe(listener) {
|
|
141
|
+
this.listeners.add(listener);
|
|
142
|
+
return () => {
|
|
143
|
+
this.listeners.delete(listener);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Check if a translation key exists
|
|
148
|
+
*/
|
|
149
|
+
hasKey(key) {
|
|
150
|
+
const bundle = this.translations.get(this.locale);
|
|
151
|
+
return !!bundle?.translations[key];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Notify all listeners of state change
|
|
155
|
+
*/
|
|
156
|
+
notifyListeners() {
|
|
157
|
+
this.listeners.forEach((listener) => listener());
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Apply locale and notify listeners
|
|
161
|
+
*/
|
|
162
|
+
applyLocale(locale) {
|
|
163
|
+
const bundle = this.translations.get(locale);
|
|
164
|
+
if (!bundle) {
|
|
165
|
+
log(`No bundle found for locale: ${locale}`, "warn");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const previousLocale = this.locale;
|
|
169
|
+
this.locale = locale;
|
|
170
|
+
this.direction = bundle.direction;
|
|
171
|
+
log(`Applied locale: ${locale} (direction: ${this.direction})`);
|
|
172
|
+
this.applyDOMDirection();
|
|
173
|
+
this.notifyListeners();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Apply direction to DOM
|
|
177
|
+
*/
|
|
178
|
+
applyDOMDirection() {
|
|
179
|
+
if (typeof document === "undefined")
|
|
180
|
+
return;
|
|
181
|
+
document.documentElement.setAttribute("dir", this.direction);
|
|
182
|
+
document.documentElement.setAttribute("lang", this.locale);
|
|
183
|
+
log(`Applied DOM attributes: dir="${this.direction}" lang="${this.locale}"`);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Load translations for a locale
|
|
187
|
+
*/
|
|
188
|
+
async loadTranslationsForLocale(locale) {
|
|
189
|
+
if (!this.config.loadTranslations) {
|
|
190
|
+
throw new Error(`No translation loader configured for locale: ${locale}`);
|
|
191
|
+
}
|
|
192
|
+
log(`Loading translations for: ${locale}`);
|
|
193
|
+
try {
|
|
194
|
+
const bundle = await this.config.loadTranslations(locale);
|
|
195
|
+
this.translations.set(locale, bundle);
|
|
196
|
+
log(`Loaded translations for: ${locale} (${Object.keys(bundle.translations).length} keys)`);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
log(`Failed to load translations for: ${locale}`, "error");
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get translation for a key
|
|
205
|
+
*/
|
|
206
|
+
getTranslation(key) {
|
|
207
|
+
// Try current locale
|
|
208
|
+
const currentBundle = this.translations.get(this.locale);
|
|
209
|
+
if (currentBundle?.translations[key]) {
|
|
210
|
+
return currentBundle.translations[key];
|
|
211
|
+
}
|
|
212
|
+
// Try fallback locale
|
|
213
|
+
const fallbackBundle = this.translations.get(this.fallbackLocale);
|
|
214
|
+
if (fallbackBundle?.translations[key]) {
|
|
215
|
+
if (this.config.debug) {
|
|
216
|
+
log(`Using fallback translation for key: ${key}`);
|
|
217
|
+
}
|
|
218
|
+
return fallbackBundle.translations[key];
|
|
219
|
+
}
|
|
220
|
+
// Missing key handling
|
|
221
|
+
if (this.config.onMissingKey) {
|
|
222
|
+
this.config.onMissingKey(key, this.locale);
|
|
223
|
+
}
|
|
224
|
+
if (this.config.debug) {
|
|
225
|
+
log(`Missing translation key: ${key} (locale: ${this.locale})`, "warn");
|
|
226
|
+
}
|
|
227
|
+
return key;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Interpolate variables in translation string
|
|
231
|
+
* Replaces {variable} with params.variable
|
|
232
|
+
*/
|
|
233
|
+
interpolate(text, params) {
|
|
234
|
+
if (!params)
|
|
235
|
+
return text;
|
|
236
|
+
return text.replace(/\{(\w+)\}/g, (match, key) => {
|
|
237
|
+
return params[key]?.toString() || match;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Select plural form based on count and locale
|
|
242
|
+
* Simplified implementation - real implementation would use Intl.PluralRules
|
|
243
|
+
*/
|
|
244
|
+
selectPluralForm(count, locale) {
|
|
245
|
+
// Use Intl.PluralRules if available
|
|
246
|
+
if (typeof Intl !== "undefined" && Intl.PluralRules) {
|
|
247
|
+
try {
|
|
248
|
+
const rules = new Intl.PluralRules(locale);
|
|
249
|
+
const category = rules.select(count);
|
|
250
|
+
return category;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
log(`Failed to use Intl.PluralRules for locale: ${locale}`, "warn");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// Fallback to simple rules
|
|
257
|
+
if (count === 0)
|
|
258
|
+
return "zero";
|
|
259
|
+
if (count === 1)
|
|
260
|
+
return "one";
|
|
261
|
+
return "other";
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Detect browser locale
|
|
265
|
+
*/
|
|
266
|
+
detectBrowserLocale() {
|
|
267
|
+
if (typeof navigator === "undefined")
|
|
268
|
+
return "en";
|
|
269
|
+
const browserLang = navigator.language ||
|
|
270
|
+
(navigator.languages && navigator.languages[0]) ||
|
|
271
|
+
"en";
|
|
272
|
+
// Extract language code (e.g., 'en-US' -> 'en')
|
|
273
|
+
return browserLang.split("-")[0];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=I18nService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"I18nService.js","sourceRoot":"","sources":["../../src/services/I18nService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;AAKxC;;;;GAIG;AACH,MAAM,OAAO,WAAW;IACf,MAAM,GAAW,IAAI,CAAC;IACtB,cAAc,GAAW,IAAI,CAAC;IAC9B,SAAS,GAAkB,KAAK,CAAC;IACjC,YAAY,GAAG,IAAI,GAAG,EAA6B,CAAC;IACpD,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;IAClC,eAAe,GAAG,IAAI,GAAG,EAAyB,CAAC;IACnD,MAAM,CAAa;IAE3B,YAAY,SAAqB,EAAE;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,IAAI,CAAC;QAEpD,GAAG,CAAC,yBAAyB,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QAExE,iDAAiD;QACjD,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAC5C,MAAM,CAAC,mBAAmB,CAC1B,EAAE,CAAC;gBACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACtC,GAAG,CAAC,oCAAoC,MAAM,EAAE,CAAC,CAAC;YACnD,CAAC;QACF,CAAC;IACF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,MAAkB;QAClC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3D,GAAG,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC;QAE3C,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,CAAC,CAAC,GAAW,EAAE,MAA4B;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,WAAW,CAAC,WAAqB,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;OAOG;IACH,EAAE,CAAC,GAAW,EAAE,KAAa,EAAE,MAA4B;QAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC;YAC1D,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,WAAqB,EAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,SAAS;QACR,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,MAAc;QAC7B,GAAG,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAEpC,2BAA2B;QAC3B,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,UAAU,MAAM,iCAAiC,CAAC,CAAC;YACvD,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACvC,OAAO;QACR,CAAC;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,UAAU,MAAM,iBAAiB,CAAC,CAAC;YACvC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACzB,OAAO;QACR,CAAC;QAED,oBAAoB;QACpB,MAAM,cAAc,GAAG,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAEjD,IAAI,CAAC;YACJ,MAAM,cAAc,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAED;;OAEG;IACH,YAAY;QACX,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,mBAAmB;QAClB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,MAAc;QAC5B,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,QAAoB;QAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAW;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,eAAe;QACtB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,MAAc;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,GAAG,CAAC,+BAA+B,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;YACrD,OAAO;QACR,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAElC,GAAG,CAAC,mBAAmB,MAAM,gBAAgB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAEhE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,eAAe,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACK,iBAAiB;QACxB,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAE5C,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7D,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAE3D,GAAG,CACF,gCAAgC,IAAI,CAAC,SAAS,WAAW,IAAI,CAAC,MAAM,GAAG,CACvE,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,yBAAyB,CAAC,MAAc;QACrD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,gDAAgD,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,GAAG,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC;QAE3C,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACtC,GAAG,CACF,4BAA4B,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,QAAQ,CACtF,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,GAAG,CAAC,oCAAoC,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;YAC3D,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,GAAW;QACjC,qBAAqB;QACrB,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,aAAa,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,OAAO,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;QAED,sBAAsB;QACtB,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClE,IAAI,cAAc,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACvB,GAAG,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,GAAG,CAAC,4BAA4B,GAAG,aAAa,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,CAAC,CAAC;QACzE,CAAC;QAED,OAAO,GAAG,CAAC;IACZ,CAAC;IAED;;;OAGG;IACK,WAAW,CAAC,IAAY,EAAE,MAA4B;QAC7D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAChD,OAAO,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAC;QACzC,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,gBAAgB,CACvB,KAAa,EACb,MAAc;QAEd,oCAAoC;QACpC,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrD,IAAI,CAAC;gBACJ,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACrC,OAAO,QAAmC,CAAC;YAC5C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,GAAG,CAAC,8CAA8C,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;YACrE,CAAC;QACF,CAAC;QAED,2BAA2B;QAC3B,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC;QAC/B,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9B,OAAO,OAAO,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,mBAAmB;QAC1B,IAAI,OAAO,SAAS,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAElD,MAAM,WAAW,GAChB,SAAS,CAAC,QAAQ;YAClB,CAAC,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC;QAEN,gDAAgD;QAChD,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;CACD"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNP Mapper - Maps QTI 3.0 PNP support IDs to PIE tool identifiers
|
|
3
|
+
*
|
|
4
|
+
* Provides bidirectional mapping between QTI 3.0 Personal Needs Profile (PNP)
|
|
5
|
+
* support identifiers and PIE tool IDs. Supports custom extensions via registration.
|
|
6
|
+
*
|
|
7
|
+
* Part of PIE Assessment Toolkit.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Standard QTI 3.0 PNP support → PIE tool ID mapping
|
|
11
|
+
*
|
|
12
|
+
* Maps industry-standard PNP support identifiers to corresponding PIE tools.
|
|
13
|
+
* Based on IMS Global QTI 3.0 specification.
|
|
14
|
+
*/
|
|
15
|
+
export declare const PNP_TO_PIE_TOOL_MAP: Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Reverse mapping for debugging/export (PIE tool ID → PNP support ID)
|
|
18
|
+
*/
|
|
19
|
+
export declare const PIE_TOOL_TO_PNP_MAP: Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Map PNP support ID to PIE tool ID
|
|
22
|
+
*
|
|
23
|
+
* @param supportId QTI 3.0 PNP support identifier
|
|
24
|
+
* @returns PIE tool ID or null if no mapping exists
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* mapPNPSupportToToolId('textToSpeech') // Returns: 'pie-tool-text-to-speech'
|
|
28
|
+
* mapPNPSupportToToolId('calculator') // Returns: 'pie-tool-calculator'
|
|
29
|
+
* mapPNPSupportToToolId('unknown') // Returns: null
|
|
30
|
+
*/
|
|
31
|
+
export declare function mapPNPSupportToToolId(supportId: string): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Map PIE tool ID back to PNP support ID
|
|
34
|
+
*
|
|
35
|
+
* Useful for exporting or debugging tool configurations.
|
|
36
|
+
*
|
|
37
|
+
* @param toolId PIE tool identifier
|
|
38
|
+
* @returns QTI 3.0 PNP support ID or null if no mapping exists
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* mapToolIdToPNPSupport('pie-tool-text-to-speech') // Returns: 'textToSpeech'
|
|
42
|
+
*/
|
|
43
|
+
export declare function mapToolIdToPNPSupport(toolId: string): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Register custom PNP support mapping
|
|
46
|
+
*
|
|
47
|
+
* Allows products to extend the standard PNP vocabulary with custom tools.
|
|
48
|
+
* Custom supports should use 'x-' prefix per IMS convention.
|
|
49
|
+
*
|
|
50
|
+
* @param supportId PNP support identifier (e.g., 'x-pie-periodic-table')
|
|
51
|
+
* @param toolId PIE tool identifier (e.g., 'pie-tool-periodic-table')
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* registerCustomPNPMapping('x-pie-periodic-table', 'pie-tool-periodic-table');
|
|
55
|
+
* registerCustomPNPMapping('x-pie-graph', 'pie-tool-graphing');
|
|
56
|
+
*/
|
|
57
|
+
export declare function registerCustomPNPMapping(supportId: string, toolId: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Get all registered PNP support IDs
|
|
60
|
+
*
|
|
61
|
+
* @returns Array of all PNP support identifiers (standard + custom)
|
|
62
|
+
*/
|
|
63
|
+
export declare function getAllPNPSupports(): string[];
|
|
64
|
+
/**
|
|
65
|
+
* Check if a PNP support is registered
|
|
66
|
+
*
|
|
67
|
+
* @param supportId PNP support identifier to check
|
|
68
|
+
* @returns true if mapping exists
|
|
69
|
+
*/
|
|
70
|
+
export declare function isPNPSupportRegistered(supportId: string): boolean;
|
|
71
|
+
//# sourceMappingURL=PNPMapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PNPMapper.d.ts","sourceRoot":"","sources":["../../src/services/PNPMapper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiBtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEtD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACZ,IAAI,CAGN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEjE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNP Mapper - Maps QTI 3.0 PNP support IDs to PIE tool identifiers
|
|
3
|
+
*
|
|
4
|
+
* Provides bidirectional mapping between QTI 3.0 Personal Needs Profile (PNP)
|
|
5
|
+
* support identifiers and PIE tool IDs. Supports custom extensions via registration.
|
|
6
|
+
*
|
|
7
|
+
* Part of PIE Assessment Toolkit.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Standard QTI 3.0 PNP support → PIE tool ID mapping
|
|
11
|
+
*
|
|
12
|
+
* Maps industry-standard PNP support identifiers to corresponding PIE tools.
|
|
13
|
+
* Based on IMS Global QTI 3.0 specification.
|
|
14
|
+
*/
|
|
15
|
+
export const PNP_TO_PIE_TOOL_MAP = {
|
|
16
|
+
// Standard QTI 3.0 PNP supports
|
|
17
|
+
textToSpeech: "pie-tool-text-to-speech",
|
|
18
|
+
calculator: "pie-tool-calculator",
|
|
19
|
+
ruler: "pie-tool-ruler",
|
|
20
|
+
protractor: "pie-tool-protractor",
|
|
21
|
+
highlighter: "pie-tool-annotation-toolbar",
|
|
22
|
+
lineReader: "pie-tool-line-reader",
|
|
23
|
+
magnifier: "pie-tool-magnifier",
|
|
24
|
+
colorContrast: "pie-theme-contrast",
|
|
25
|
+
answerMasking: "pie-tool-answer-eliminator",
|
|
26
|
+
dictionaryLookup: "pie-tool-dictionary",
|
|
27
|
+
// Common extensions (not in QTI standard but widely used)
|
|
28
|
+
graphingCalculator: "pie-tool-calculator",
|
|
29
|
+
scientificCalculator: "pie-tool-calculator",
|
|
30
|
+
basicCalculator: "pie-tool-calculator",
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Reverse mapping for debugging/export (PIE tool ID → PNP support ID)
|
|
34
|
+
*/
|
|
35
|
+
export const PIE_TOOL_TO_PNP_MAP = Object.fromEntries(Object.entries(PNP_TO_PIE_TOOL_MAP).map(([pnp, tool]) => [tool, pnp]));
|
|
36
|
+
/**
|
|
37
|
+
* Map PNP support ID to PIE tool ID
|
|
38
|
+
*
|
|
39
|
+
* @param supportId QTI 3.0 PNP support identifier
|
|
40
|
+
* @returns PIE tool ID or null if no mapping exists
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* mapPNPSupportToToolId('textToSpeech') // Returns: 'pie-tool-text-to-speech'
|
|
44
|
+
* mapPNPSupportToToolId('calculator') // Returns: 'pie-tool-calculator'
|
|
45
|
+
* mapPNPSupportToToolId('unknown') // Returns: null
|
|
46
|
+
*/
|
|
47
|
+
export function mapPNPSupportToToolId(supportId) {
|
|
48
|
+
return PNP_TO_PIE_TOOL_MAP[supportId] || null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Map PIE tool ID back to PNP support ID
|
|
52
|
+
*
|
|
53
|
+
* Useful for exporting or debugging tool configurations.
|
|
54
|
+
*
|
|
55
|
+
* @param toolId PIE tool identifier
|
|
56
|
+
* @returns QTI 3.0 PNP support ID or null if no mapping exists
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* mapToolIdToPNPSupport('pie-tool-text-to-speech') // Returns: 'textToSpeech'
|
|
60
|
+
*/
|
|
61
|
+
export function mapToolIdToPNPSupport(toolId) {
|
|
62
|
+
return PIE_TOOL_TO_PNP_MAP[toolId] || null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register custom PNP support mapping
|
|
66
|
+
*
|
|
67
|
+
* Allows products to extend the standard PNP vocabulary with custom tools.
|
|
68
|
+
* Custom supports should use 'x-' prefix per IMS convention.
|
|
69
|
+
*
|
|
70
|
+
* @param supportId PNP support identifier (e.g., 'x-pie-periodic-table')
|
|
71
|
+
* @param toolId PIE tool identifier (e.g., 'pie-tool-periodic-table')
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* registerCustomPNPMapping('x-pie-periodic-table', 'pie-tool-periodic-table');
|
|
75
|
+
* registerCustomPNPMapping('x-pie-graph', 'pie-tool-graphing');
|
|
76
|
+
*/
|
|
77
|
+
export function registerCustomPNPMapping(supportId, toolId) {
|
|
78
|
+
PNP_TO_PIE_TOOL_MAP[supportId] = toolId;
|
|
79
|
+
PIE_TOOL_TO_PNP_MAP[toolId] = supportId;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get all registered PNP support IDs
|
|
83
|
+
*
|
|
84
|
+
* @returns Array of all PNP support identifiers (standard + custom)
|
|
85
|
+
*/
|
|
86
|
+
export function getAllPNPSupports() {
|
|
87
|
+
return Object.keys(PNP_TO_PIE_TOOL_MAP);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if a PNP support is registered
|
|
91
|
+
*
|
|
92
|
+
* @param supportId PNP support identifier to check
|
|
93
|
+
* @returns true if mapping exists
|
|
94
|
+
*/
|
|
95
|
+
export function isPNPSupportRegistered(supportId) {
|
|
96
|
+
return supportId in PNP_TO_PIE_TOOL_MAP;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=PNPMapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PNPMapper.js","sourceRoot":"","sources":["../../src/services/PNPMapper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IAC1D,gCAAgC;IAChC,YAAY,EAAE,yBAAyB;IACvC,UAAU,EAAE,qBAAqB;IACjC,KAAK,EAAE,gBAAgB;IACvB,UAAU,EAAE,qBAAqB;IACjC,WAAW,EAAE,6BAA6B;IAC1C,UAAU,EAAE,sBAAsB;IAClC,SAAS,EAAE,oBAAoB;IAC/B,aAAa,EAAE,oBAAoB;IACnC,aAAa,EAAE,4BAA4B;IAC3C,gBAAgB,EAAE,qBAAqB;IAEvC,0DAA0D;IAC1D,kBAAkB,EAAE,qBAAqB;IACzC,oBAAoB,EAAE,qBAAqB;IAC3C,eAAe,EAAE,qBAAqB;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B,MAAM,CAAC,WAAW,CAC5E,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CACrE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACtD,OAAO,mBAAmB,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc;IACnD,OAAO,mBAAmB,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CACvC,SAAiB,EACjB,MAAc;IAEd,mBAAmB,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC;IACxC,mBAAmB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAChC,OAAO,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACvD,OAAO,SAAS,IAAI,mBAAmB,CAAC;AACzC,CAAC"}
|