@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.
Files changed (194) hide show
  1. package/README.md +520 -0
  2. package/dist/attempt/TestSession.d.ts +90 -0
  3. package/dist/attempt/TestSession.d.ts.map +1 -0
  4. package/dist/attempt/TestSession.js +174 -0
  5. package/dist/attempt/TestSession.js.map +1 -0
  6. package/dist/core/TypedEventBus.d.ts +48 -0
  7. package/dist/core/TypedEventBus.d.ts.map +1 -0
  8. package/dist/core/TypedEventBus.js +63 -0
  9. package/dist/core/TypedEventBus.js.map +1 -0
  10. package/dist/index.d.ts +37 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +44 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/item-loader.d.ts +45 -0
  15. package/dist/item-loader.d.ts.map +1 -0
  16. package/dist/item-loader.js +62 -0
  17. package/dist/item-loader.js.map +1 -0
  18. package/dist/player/AssessmentPlayer.d.ts +388 -0
  19. package/dist/player/AssessmentPlayer.d.ts.map +1 -0
  20. package/dist/player/AssessmentPlayer.js +965 -0
  21. package/dist/player/AssessmentPlayer.js.map +1 -0
  22. package/dist/player/index.d.ts +17 -0
  23. package/dist/player/index.d.ts.map +1 -0
  24. package/dist/player/index.js +15 -0
  25. package/dist/player/index.js.map +1 -0
  26. package/dist/player/navigation-types.d.ts +63 -0
  27. package/dist/player/navigation-types.d.ts.map +1 -0
  28. package/dist/player/navigation-types.js +7 -0
  29. package/dist/player/navigation-types.js.map +1 -0
  30. package/dist/player/qti-navigation.d.ts +29 -0
  31. package/dist/player/qti-navigation.d.ts.map +1 -0
  32. package/dist/player/qti-navigation.js +160 -0
  33. package/dist/player/qti-navigation.js.map +1 -0
  34. package/dist/reference-layout/index.d.ts +19 -0
  35. package/dist/reference-layout/index.d.ts.map +1 -0
  36. package/dist/reference-layout/index.js +20 -0
  37. package/dist/reference-layout/index.js.map +1 -0
  38. package/dist/services/AccessibilityCatalogResolver.d.ts +141 -0
  39. package/dist/services/AccessibilityCatalogResolver.d.ts.map +1 -0
  40. package/dist/services/AccessibilityCatalogResolver.js +249 -0
  41. package/dist/services/AccessibilityCatalogResolver.js.map +1 -0
  42. package/dist/services/AssessmentAuthoringService.d.ts +60 -0
  43. package/dist/services/AssessmentAuthoringService.d.ts.map +1 -0
  44. package/dist/services/AssessmentAuthoringService.js +183 -0
  45. package/dist/services/AssessmentAuthoringService.js.map +1 -0
  46. package/dist/services/ContextVariableStore.d.ts +114 -0
  47. package/dist/services/ContextVariableStore.d.ts.map +1 -0
  48. package/dist/services/ContextVariableStore.js +207 -0
  49. package/dist/services/ContextVariableStore.js.map +1 -0
  50. package/dist/services/ElementToolStateStore.d.ts +125 -0
  51. package/dist/services/ElementToolStateStore.d.ts.map +1 -0
  52. package/dist/services/ElementToolStateStore.js +200 -0
  53. package/dist/services/ElementToolStateStore.js.map +1 -0
  54. package/dist/services/HighlightCoordinator.d.ts +179 -0
  55. package/dist/services/HighlightCoordinator.d.ts.map +1 -0
  56. package/dist/services/HighlightCoordinator.js +446 -0
  57. package/dist/services/HighlightCoordinator.js.map +1 -0
  58. package/dist/services/I18nService.d.ts +121 -0
  59. package/dist/services/I18nService.d.ts.map +1 -0
  60. package/dist/services/I18nService.js +276 -0
  61. package/dist/services/I18nService.js.map +1 -0
  62. package/dist/services/PNPMapper.d.ts +71 -0
  63. package/dist/services/PNPMapper.d.ts.map +1 -0
  64. package/dist/services/PNPMapper.js +98 -0
  65. package/dist/services/PNPMapper.js.map +1 -0
  66. package/dist/services/PNPToolResolver.d.ts +127 -0
  67. package/dist/services/PNPToolResolver.d.ts.map +1 -0
  68. package/dist/services/PNPToolResolver.js +222 -0
  69. package/dist/services/PNPToolResolver.js.map +1 -0
  70. package/dist/services/SSMLExtractor.d.ts +61 -0
  71. package/dist/services/SSMLExtractor.d.ts.map +1 -0
  72. package/dist/services/SSMLExtractor.js +181 -0
  73. package/dist/services/SSMLExtractor.js.map +1 -0
  74. package/dist/services/TTSService.d.ts +162 -0
  75. package/dist/services/TTSService.d.ts.map +1 -0
  76. package/dist/services/TTSService.js +465 -0
  77. package/dist/services/TTSService.js.map +1 -0
  78. package/dist/services/ThemeProvider.d.ts +95 -0
  79. package/dist/services/ThemeProvider.d.ts.map +1 -0
  80. package/dist/services/ThemeProvider.js +299 -0
  81. package/dist/services/ThemeProvider.js.map +1 -0
  82. package/dist/services/ToolConfigResolver.d.ts +162 -0
  83. package/dist/services/ToolConfigResolver.d.ts.map +1 -0
  84. package/dist/services/ToolConfigResolver.js +230 -0
  85. package/dist/services/ToolConfigResolver.js.map +1 -0
  86. package/dist/services/ToolCoordinator.d.ts +137 -0
  87. package/dist/services/ToolCoordinator.d.ts.map +1 -0
  88. package/dist/services/ToolCoordinator.js +318 -0
  89. package/dist/services/ToolCoordinator.js.map +1 -0
  90. package/dist/services/ToolkitCoordinator.d.ts +188 -0
  91. package/dist/services/ToolkitCoordinator.d.ts.map +1 -0
  92. package/dist/services/ToolkitCoordinator.js +252 -0
  93. package/dist/services/ToolkitCoordinator.js.map +1 -0
  94. package/dist/services/interfaces.d.ts +391 -0
  95. package/dist/services/interfaces.d.ts.map +1 -0
  96. package/dist/services/interfaces.js +12 -0
  97. package/dist/services/interfaces.js.map +1 -0
  98. package/dist/services/tool-providers/DesmosToolProvider.d.ts +103 -0
  99. package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +1 -0
  100. package/dist/services/tool-providers/DesmosToolProvider.js +127 -0
  101. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -0
  102. package/dist/services/tool-providers/IToolProvider.d.ts +137 -0
  103. package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -0
  104. package/dist/services/tool-providers/IToolProvider.js +13 -0
  105. package/dist/services/tool-providers/IToolProvider.js.map +1 -0
  106. package/dist/services/tool-providers/TIToolProvider.d.ts +107 -0
  107. package/dist/services/tool-providers/TIToolProvider.d.ts.map +1 -0
  108. package/dist/services/tool-providers/TIToolProvider.js +123 -0
  109. package/dist/services/tool-providers/TIToolProvider.js.map +1 -0
  110. package/dist/services/tool-providers/TTSToolProvider.d.ts +143 -0
  111. package/dist/services/tool-providers/TTSToolProvider.d.ts.map +1 -0
  112. package/dist/services/tool-providers/TTSToolProvider.js +168 -0
  113. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -0
  114. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +165 -0
  115. package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +1 -0
  116. package/dist/services/tool-providers/ToolProviderRegistry.js +240 -0
  117. package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -0
  118. package/dist/services/tool-providers/index.d.ts +18 -0
  119. package/dist/services/tool-providers/index.d.ts.map +1 -0
  120. package/dist/services/tool-providers/index.js +15 -0
  121. package/dist/services/tool-providers/index.js.map +1 -0
  122. package/dist/services/tts/browser-provider.d.ts +24 -0
  123. package/dist/services/tts/browser-provider.d.ts.map +1 -0
  124. package/dist/services/tts/browser-provider.js +177 -0
  125. package/dist/services/tts/browser-provider.js.map +1 -0
  126. package/dist/services/tts/provider-interface.d.ts +131 -0
  127. package/dist/services/tts/provider-interface.d.ts.map +1 -0
  128. package/dist/services/tts/provider-interface.js +10 -0
  129. package/dist/services/tts/provider-interface.js.map +1 -0
  130. package/dist/tools/calculators/desmos-provider.d.ts +54 -0
  131. package/dist/tools/calculators/desmos-provider.d.ts.map +1 -0
  132. package/dist/tools/calculators/desmos-provider.js +384 -0
  133. package/dist/tools/calculators/desmos-provider.js.map +1 -0
  134. package/dist/tools/calculators/mathjs-provider.d.ts +50 -0
  135. package/dist/tools/calculators/mathjs-provider.d.ts.map +1 -0
  136. package/dist/tools/calculators/mathjs-provider.js +660 -0
  137. package/dist/tools/calculators/mathjs-provider.js.map +1 -0
  138. package/dist/tools/calculators/ti-provider.d.ts +122 -0
  139. package/dist/tools/calculators/ti-provider.d.ts.map +1 -0
  140. package/dist/tools/calculators/ti-provider.js +587 -0
  141. package/dist/tools/calculators/ti-provider.js.map +1 -0
  142. package/dist/tools/client.d.ts +17 -0
  143. package/dist/tools/client.d.ts.map +1 -0
  144. package/dist/tools/client.js +26 -0
  145. package/dist/tools/client.js.map +1 -0
  146. package/dist/tools/index.d.ts +8 -0
  147. package/dist/tools/index.d.ts.map +1 -0
  148. package/dist/tools/index.js +10 -0
  149. package/dist/tools/index.js.map +1 -0
  150. package/dist/tools/library-loader.d.ts +63 -0
  151. package/dist/tools/library-loader.d.ts.map +1 -0
  152. package/dist/tools/library-loader.js +292 -0
  153. package/dist/tools/library-loader.js.map +1 -0
  154. package/dist/tools/response-discovery.d.ts +72 -0
  155. package/dist/tools/response-discovery.d.ts.map +1 -0
  156. package/dist/tools/response-discovery.js +183 -0
  157. package/dist/tools/response-discovery.js.map +1 -0
  158. package/dist/tools/tool-coordinator.d.ts +76 -0
  159. package/dist/tools/tool-coordinator.d.ts.map +1 -0
  160. package/dist/tools/tool-coordinator.js +197 -0
  161. package/dist/tools/tool-coordinator.js.map +1 -0
  162. package/dist/tools/types.d.ts +427 -0
  163. package/dist/tools/types.d.ts.map +1 -0
  164. package/dist/tools/types.js +13 -0
  165. package/dist/tools/types.js.map +1 -0
  166. package/dist/tools/variant-resolver.d.ts +48 -0
  167. package/dist/tools/variant-resolver.d.ts.map +1 -0
  168. package/dist/tools/variant-resolver.js +214 -0
  169. package/dist/tools/variant-resolver.js.map +1 -0
  170. package/dist/types/events.d.ts +157 -0
  171. package/dist/types/events.d.ts.map +1 -0
  172. package/dist/types/events.js +11 -0
  173. package/dist/types/events.js.map +1 -0
  174. package/dist/utils/logger.d.ts +7 -0
  175. package/dist/utils/logger.d.ts.map +1 -0
  176. package/dist/utils/logger.js +11 -0
  177. package/dist/utils/logger.js.map +1 -0
  178. package/package.json +71 -0
  179. package/src/README.md +626 -0
  180. package/src/components/QuestionToolBar.svelte +406 -0
  181. package/src/player/AssessmentLayout.svelte +68 -0
  182. package/src/player/README.md +154 -0
  183. package/src/reference-layout/README.md +135 -0
  184. package/src/reference-layout/ReferenceLayout.svelte +209 -0
  185. package/src/reference-layout/components/AssessmentContent.svelte +259 -0
  186. package/src/reference-layout/components/AssessmentFooter.svelte +89 -0
  187. package/src/reference-layout/components/AssessmentHeader.svelte +250 -0
  188. package/src/reference-layout/components/AssessmentNavigation.svelte +134 -0
  189. package/src/reference-layout/components/AssessmentToolsBar.svelte +176 -0
  190. package/src/reference-layout/components/ItemPanel.svelte +200 -0
  191. package/src/reference-layout/components/NotesPanel.svelte +179 -0
  192. package/src/reference-layout/components/PassagePanel.svelte +76 -0
  193. package/src/tools/README.md +616 -0
  194. 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":"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"}
@@ -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"}