@pie-players/pie-players-shared 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 (233) hide show
  1. package/dist/config/profile.d.ts +15 -0
  2. package/dist/config/profile.d.ts.map +1 -0
  3. package/dist/config/profile.js +27 -0
  4. package/dist/config/profile.js.map +1 -0
  5. package/dist/i18n/index.d.ts +13 -0
  6. package/dist/i18n/index.d.ts.map +1 -0
  7. package/dist/i18n/index.js +12 -0
  8. package/dist/i18n/index.js.map +1 -0
  9. package/dist/i18n/loader.d.ts +36 -0
  10. package/dist/i18n/loader.d.ts.map +1 -0
  11. package/dist/i18n/loader.js +133 -0
  12. package/dist/i18n/loader.js.map +1 -0
  13. package/dist/i18n/scripts/check-coverage.d.ts +16 -0
  14. package/dist/i18n/scripts/check-coverage.d.ts.map +1 -0
  15. package/dist/i18n/scripts/check-coverage.js +262 -0
  16. package/dist/i18n/scripts/check-coverage.js.map +1 -0
  17. package/dist/i18n/scripts/scan-hardcoded.d.ts +16 -0
  18. package/dist/i18n/scripts/scan-hardcoded.d.ts.map +1 -0
  19. package/dist/i18n/scripts/scan-hardcoded.js +266 -0
  20. package/dist/i18n/scripts/scan-hardcoded.js.map +1 -0
  21. package/dist/i18n/simple-i18n.d.ts +69 -0
  22. package/dist/i18n/simple-i18n.d.ts.map +1 -0
  23. package/dist/i18n/simple-i18n.js +199 -0
  24. package/dist/i18n/simple-i18n.js.map +1 -0
  25. package/dist/i18n/translations/ar/common.json +36 -0
  26. package/dist/i18n/translations/ar/toolkit.json +48 -0
  27. package/dist/i18n/translations/ar/tools.json +109 -0
  28. package/dist/i18n/translations/en/common.json +36 -0
  29. package/dist/i18n/translations/en/toolkit.json +48 -0
  30. package/dist/i18n/translations/en/tools.json +109 -0
  31. package/dist/i18n/translations/es/common.json +36 -0
  32. package/dist/i18n/translations/es/toolkit.json +48 -0
  33. package/dist/i18n/translations/es/tools.json +109 -0
  34. package/dist/i18n/translations/zh/common.json +36 -0
  35. package/dist/i18n/translations/zh/toolkit.json +48 -0
  36. package/dist/i18n/translations/zh/tools.json +109 -0
  37. package/dist/i18n/types.d.ts +58 -0
  38. package/dist/i18n/types.d.ts.map +1 -0
  39. package/dist/i18n/types.js +8 -0
  40. package/dist/i18n/types.js.map +1 -0
  41. package/dist/i18n/use-i18n-standalone.svelte.d.ts +87 -0
  42. package/dist/i18n/use-i18n-standalone.svelte.d.ts.map +1 -0
  43. package/dist/i18n/use-i18n-standalone.svelte.js +151 -0
  44. package/dist/i18n/use-i18n-standalone.svelte.js.map +1 -0
  45. package/dist/i18n/use-i18n.svelte.d.ts +67 -0
  46. package/dist/i18n/use-i18n.svelte.d.ts.map +1 -0
  47. package/dist/i18n/use-i18n.svelte.js +144 -0
  48. package/dist/i18n/use-i18n.svelte.js.map +1 -0
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +11 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/instrumentation/index.d.ts +53 -0
  54. package/dist/instrumentation/index.d.ts.map +1 -0
  55. package/dist/instrumentation/index.js +53 -0
  56. package/dist/instrumentation/index.js.map +1 -0
  57. package/dist/instrumentation/providers/BaseInstrumentationProvider.d.ts +197 -0
  58. package/dist/instrumentation/providers/BaseInstrumentationProvider.d.ts.map +1 -0
  59. package/dist/instrumentation/providers/BaseInstrumentationProvider.js +267 -0
  60. package/dist/instrumentation/providers/BaseInstrumentationProvider.js.map +1 -0
  61. package/dist/instrumentation/providers/ConsoleInstrumentationProvider.d.ts +106 -0
  62. package/dist/instrumentation/providers/ConsoleInstrumentationProvider.d.ts.map +1 -0
  63. package/dist/instrumentation/providers/ConsoleInstrumentationProvider.js +182 -0
  64. package/dist/instrumentation/providers/ConsoleInstrumentationProvider.js.map +1 -0
  65. package/dist/instrumentation/providers/DataDogInstrumentationProvider.d.ts +170 -0
  66. package/dist/instrumentation/providers/DataDogInstrumentationProvider.d.ts.map +1 -0
  67. package/dist/instrumentation/providers/DataDogInstrumentationProvider.js +183 -0
  68. package/dist/instrumentation/providers/DataDogInstrumentationProvider.js.map +1 -0
  69. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.d.ts +86 -0
  70. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.d.ts.map +1 -0
  71. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.js +135 -0
  72. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.js.map +1 -0
  73. package/dist/instrumentation/providers/index.d.ts +12 -0
  74. package/dist/instrumentation/providers/index.d.ts.map +1 -0
  75. package/dist/instrumentation/providers/index.js +12 -0
  76. package/dist/instrumentation/providers/index.js.map +1 -0
  77. package/dist/instrumentation/types.d.ts +348 -0
  78. package/dist/instrumentation/types.d.ts.map +1 -0
  79. package/dist/instrumentation/types.js +9 -0
  80. package/dist/instrumentation/types.js.map +1 -0
  81. package/dist/loader-config.d.ts +76 -0
  82. package/dist/loader-config.d.ts.map +1 -0
  83. package/dist/loader-config.js +12 -0
  84. package/dist/loader-config.js.map +1 -0
  85. package/dist/loaders/ElementLoader.d.ts +72 -0
  86. package/dist/loaders/ElementLoader.d.ts.map +1 -0
  87. package/dist/loaders/ElementLoader.js +52 -0
  88. package/dist/loaders/ElementLoader.js.map +1 -0
  89. package/dist/loaders/EsmElementLoader.d.ts +67 -0
  90. package/dist/loaders/EsmElementLoader.d.ts.map +1 -0
  91. package/dist/loaders/EsmElementLoader.js +71 -0
  92. package/dist/loaders/EsmElementLoader.js.map +1 -0
  93. package/dist/loaders/IifeElementLoader.d.ts +61 -0
  94. package/dist/loaders/IifeElementLoader.d.ts.map +1 -0
  95. package/dist/loaders/IifeElementLoader.js +63 -0
  96. package/dist/loaders/IifeElementLoader.js.map +1 -0
  97. package/dist/loaders/index.d.ts +28 -0
  98. package/dist/loaders/index.d.ts.map +1 -0
  99. package/dist/loaders/index.js +25 -0
  100. package/dist/loaders/index.js.map +1 -0
  101. package/dist/object/index.d.ts +12 -0
  102. package/dist/object/index.d.ts.map +1 -0
  103. package/dist/object/index.js +40 -0
  104. package/dist/object/index.js.map +1 -0
  105. package/dist/pie/asset-handler.d.ts +64 -0
  106. package/dist/pie/asset-handler.d.ts.map +1 -0
  107. package/dist/pie/asset-handler.js +238 -0
  108. package/dist/pie/asset-handler.js.map +1 -0
  109. package/dist/pie/component-context.d.ts +22 -0
  110. package/dist/pie/component-context.d.ts.map +1 -0
  111. package/dist/pie/component-context.js +30 -0
  112. package/dist/pie/component-context.js.map +1 -0
  113. package/dist/pie/config.d.ts +39 -0
  114. package/dist/pie/config.d.ts.map +1 -0
  115. package/dist/pie/config.js +174 -0
  116. package/dist/pie/config.js.map +1 -0
  117. package/dist/pie/configure-initialization.d.ts +35 -0
  118. package/dist/pie/configure-initialization.d.ts.map +1 -0
  119. package/dist/pie/configure-initialization.js +141 -0
  120. package/dist/pie/configure-initialization.js.map +1 -0
  121. package/dist/pie/esm-loader.d.ts +93 -0
  122. package/dist/pie/esm-loader.d.ts.map +1 -0
  123. package/dist/pie/esm-loader.js +308 -0
  124. package/dist/pie/esm-loader.js.map +1 -0
  125. package/dist/pie/iife-loader.d.ts +76 -0
  126. package/dist/pie/iife-loader.d.ts.map +1 -0
  127. package/dist/pie/iife-loader.js +303 -0
  128. package/dist/pie/iife-loader.js.map +1 -0
  129. package/dist/pie/index.d.ts +31 -0
  130. package/dist/pie/index.d.ts.map +1 -0
  131. package/dist/pie/index.js +34 -0
  132. package/dist/pie/index.js.map +1 -0
  133. package/dist/pie/initialization.d.ts +40 -0
  134. package/dist/pie/initialization.d.ts.map +1 -0
  135. package/dist/pie/initialization.js +349 -0
  136. package/dist/pie/initialization.js.map +1 -0
  137. package/dist/pie/logger.d.ts +64 -0
  138. package/dist/pie/logger.d.ts.map +1 -0
  139. package/dist/pie/logger.js +45 -0
  140. package/dist/pie/logger.js.map +1 -0
  141. package/dist/pie/math-rendering.d.ts +69 -0
  142. package/dist/pie/math-rendering.d.ts.map +1 -0
  143. package/dist/pie/math-rendering.js +98 -0
  144. package/dist/pie/math-rendering.js.map +1 -0
  145. package/dist/pie/overrides.d.ts +43 -0
  146. package/dist/pie/overrides.d.ts.map +1 -0
  147. package/dist/pie/overrides.js +146 -0
  148. package/dist/pie/overrides.js.map +1 -0
  149. package/dist/pie/player-initializer.d.ts +55 -0
  150. package/dist/pie/player-initializer.d.ts.map +1 -0
  151. package/dist/pie/player-initializer.js +123 -0
  152. package/dist/pie/player-initializer.js.map +1 -0
  153. package/dist/pie/registry.d.ts +11 -0
  154. package/dist/pie/registry.d.ts.map +1 -0
  155. package/dist/pie/registry.js +21 -0
  156. package/dist/pie/registry.js.map +1 -0
  157. package/dist/pie/resource-monitor.d.ts +208 -0
  158. package/dist/pie/resource-monitor.d.ts.map +1 -0
  159. package/dist/pie/resource-monitor.js +969 -0
  160. package/dist/pie/resource-monitor.js.map +1 -0
  161. package/dist/pie/scoring.d.ts +17 -0
  162. package/dist/pie/scoring.d.ts.map +1 -0
  163. package/dist/pie/scoring.js +84 -0
  164. package/dist/pie/scoring.js.map +1 -0
  165. package/dist/pie/types.d.ts +136 -0
  166. package/dist/pie/types.d.ts.map +1 -0
  167. package/dist/pie/types.js +52 -0
  168. package/dist/pie/types.js.map +1 -0
  169. package/dist/pie/updates.d.ts +20 -0
  170. package/dist/pie/updates.d.ts.map +1 -0
  171. package/dist/pie/updates.js +175 -0
  172. package/dist/pie/updates.js.map +1 -0
  173. package/dist/pie/use-resource-monitor.svelte.d.ts +56 -0
  174. package/dist/pie/use-resource-monitor.svelte.d.ts.map +1 -0
  175. package/dist/pie/use-resource-monitor.svelte.js +117 -0
  176. package/dist/pie/use-resource-monitor.svelte.js.map +1 -0
  177. package/dist/pie/utils.d.ts +44 -0
  178. package/dist/pie/utils.d.ts.map +1 -0
  179. package/dist/pie/utils.js +74 -0
  180. package/dist/pie/utils.js.map +1 -0
  181. package/dist/types/custom-elements.d.ts +183 -0
  182. package/dist/types/custom-elements.d.ts.map +1 -0
  183. package/dist/types/custom-elements.js +8 -0
  184. package/dist/types/custom-elements.js.map +1 -0
  185. package/dist/types/index.d.ts +761 -0
  186. package/dist/types/index.d.ts.map +1 -0
  187. package/dist/types/index.js +120 -0
  188. package/dist/types/index.js.map +1 -0
  189. package/dist/types/search.d.ts +105 -0
  190. package/dist/types/search.d.ts.map +1 -0
  191. package/dist/types/search.js +12 -0
  192. package/dist/types/search.js.map +1 -0
  193. package/dist/types/transform.d.ts +48 -0
  194. package/dist/types/transform.d.ts.map +1 -0
  195. package/dist/types/transform.js +21 -0
  196. package/dist/types/transform.js.map +1 -0
  197. package/dist/ui/focus-trap.d.ts +10 -0
  198. package/dist/ui/focus-trap.d.ts.map +1 -0
  199. package/dist/ui/focus-trap.js +30 -0
  200. package/dist/ui/focus-trap.js.map +1 -0
  201. package/dist/ui/safe-storage.d.ts +3 -0
  202. package/dist/ui/safe-storage.d.ts.map +1 -0
  203. package/dist/ui/safe-storage.js +21 -0
  204. package/dist/ui/safe-storage.js.map +1 -0
  205. package/package.json +118 -0
  206. package/src/components/PieItemPlayer.svelte +604 -0
  207. package/src/components/PiePreviewLayout.svelte +144 -0
  208. package/src/components/PiePreviewToggle.svelte +110 -0
  209. package/src/components/PieSpinner.svelte +85 -0
  210. package/src/components/ToolSettingsButton.svelte +31 -0
  211. package/src/components/ToolSettingsPanel.svelte +90 -0
  212. package/src/components/index.ts +6 -0
  213. package/src/i18n/README.md +223 -0
  214. package/src/i18n/index.ts +26 -0
  215. package/src/i18n/loader.ts +156 -0
  216. package/src/i18n/scripts/check-coverage.ts +345 -0
  217. package/src/i18n/scripts/scan-hardcoded.ts +342 -0
  218. package/src/i18n/simple-i18n.ts +236 -0
  219. package/src/i18n/translations/ar/common.json +36 -0
  220. package/src/i18n/translations/ar/toolkit.json +48 -0
  221. package/src/i18n/translations/ar/tools.json +109 -0
  222. package/src/i18n/translations/en/common.json +36 -0
  223. package/src/i18n/translations/en/toolkit.json +48 -0
  224. package/src/i18n/translations/en/tools.json +109 -0
  225. package/src/i18n/translations/es/common.json +36 -0
  226. package/src/i18n/translations/es/toolkit.json +48 -0
  227. package/src/i18n/translations/es/tools.json +109 -0
  228. package/src/i18n/translations/zh/common.json +36 -0
  229. package/src/i18n/translations/zh/toolkit.json +48 -0
  230. package/src/i18n/translations/zh/tools.json +109 -0
  231. package/src/i18n/types.ts +66 -0
  232. package/src/i18n/use-i18n-standalone.svelte.ts +184 -0
  233. package/src/i18n/use-i18n.svelte.ts +163 -0
@@ -0,0 +1,109 @@
1
+ {
2
+ "tool": {
3
+ "calculator": "计算器",
4
+ "calculator_aria": "打开计算器",
5
+ "graph": "图表",
6
+ "graph_aria": "打开图表工具",
7
+ "periodic_table": "元素周期表",
8
+ "periodic_table_aria": "打开元素周期表",
9
+ "protractor": "量角器",
10
+ "protractor_aria": "打开量角器",
11
+ "ruler": "尺子",
12
+ "ruler_aria": "打开尺子",
13
+ "line_reader": "行阅读器",
14
+ "line_reader_aria": "打开行阅读器",
15
+ "magnifier": "文本放大镜",
16
+ "magnifier_aria": "打开文本放大镜",
17
+ "text_to_speech": "文字转语音",
18
+ "text_to_speech_aria": "打开文字转语音",
19
+ "color_scheme": "配色方案",
20
+ "color_scheme_aria": "打开配色方案选择器",
21
+ "annotation": "注释",
22
+ "annotation_aria": "打开注释工具栏",
23
+ "answer_eliminator": "答案消除器"
24
+ },
25
+ "tts": {
26
+ "title": "文字转语音",
27
+ "close_aria": "关闭文字转语音",
28
+ "failed_init": "初始化 TTS 失败",
29
+ "initializing": "初始化中...",
30
+ "select_text": "选择页面上的文本以朗读。",
31
+ "selected": "已选择 {count} {character}",
32
+ "speed": "速度:",
33
+ "rate_slow": "慢",
34
+ "rate_slower": "较慢",
35
+ "rate_normal": "正常",
36
+ "rate_faster": "较快",
37
+ "rate_fast": "快",
38
+ "rate_very_fast": "很快",
39
+ "play": "播放",
40
+ "pause": "暂停",
41
+ "resume": "继续",
42
+ "stop": "停止",
43
+ "speaking": "朗读中...",
44
+ "paused": "已暂停"
45
+ },
46
+ "calculator": {
47
+ "title": "计算器",
48
+ "aria_label": "计算器工具 - 使用 Alt+箭头键移动,Escape 关闭",
49
+ "settings": "计算器设置",
50
+ "close": "关闭计算器",
51
+ "settings_title": "计算器设置",
52
+ "type": "计算器类型",
53
+ "basic": "基础",
54
+ "scientific": "科学",
55
+ "graphing": "图形",
56
+ "ti_84": "TI-84 Plus CE",
57
+ "ti_108": "TI-108 小学",
58
+ "ti_34": "TI-34 MultiView",
59
+ "configuration": "配置",
60
+ "config_help": "这些设置对测试很有用。在生产环境中可能对学生隐藏或限制。",
61
+ "restricted_mode": "受限模式(测试模式)",
62
+ "angle_mode": "角度模式",
63
+ "degrees": "度数",
64
+ "radians": "弧度",
65
+ "qwerty": "QWERTY 键盘",
66
+ "screen_reader": "屏幕阅读器支持",
67
+ "accessible_display": "无障碍显示",
68
+ "settings_menu": "设置菜单",
69
+ "notes": "笔记",
70
+ "folders": "文件夹",
71
+ "sliders": "滑块",
72
+ "display_mode": "显示模式",
73
+ "classic": "经典",
74
+ "mathprint": "MathPrint"
75
+ },
76
+ "color_scheme": {
77
+ "title": "配色方案",
78
+ "description": "选择配色方案以提高可读性并减少眼睛疲劳。",
79
+ "close_aria": "关闭配色方案选择器",
80
+ "select_aria": "选择配色方案",
81
+ "default": "默认",
82
+ "default_desc": "标准 PIE 颜色",
83
+ "black_on_white": "黑底白字",
84
+ "black_on_white_desc": "高对比度便于阅读",
85
+ "white_on_black": "白底黑字",
86
+ "white_on_black_desc": "反向高对比度",
87
+ "rose_on_green": "玫瑰色底绿字",
88
+ "rose_on_green_desc": "减少眩光",
89
+ "yellow_on_blue": "黄底蓝字",
90
+ "yellow_on_blue_desc": "高对比度替代方案",
91
+ "black_on_rose": "黑底玫瑰色字",
92
+ "black_on_rose_desc": "温暖的背景",
93
+ "light_gray_on_dark_gray": "浅灰底深灰字",
94
+ "light_gray_on_dark_gray_desc": "降低亮度"
95
+ },
96
+ "annotation": {
97
+ "yellow_aria": "黄色高亮",
98
+ "pink_aria": "粉色高亮",
99
+ "blue_aria": "蓝色高亮",
100
+ "green_aria": "绿色高亮",
101
+ "read_selection": "朗读选择",
102
+ "dictionary": "字典查询",
103
+ "translation": "翻译请求",
104
+ "clear": "清除高亮"
105
+ },
106
+ "ruler": {
107
+ "switched_to": "已切换到 {unit}"
108
+ }
109
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * I18n Type Definitions
3
+ *
4
+ * Shared types for internationalization system.
5
+ * Defined in players-shared to avoid circular dependencies.
6
+ */
7
+
8
+ /**
9
+ * Plural translation forms
10
+ * Follows ICU MessageFormat plural rules
11
+ */
12
+ export interface PluralTranslation {
13
+ zero?: string;
14
+ one: string;
15
+ few?: string;
16
+ many?: string;
17
+ other: string;
18
+ }
19
+
20
+ /**
21
+ * Translation bundle structure
22
+ */
23
+ export interface TranslationBundle {
24
+ locale: string;
25
+ translations: Record<string, string | PluralTranslation>;
26
+ direction: "ltr" | "rtl";
27
+ }
28
+
29
+ /**
30
+ * I18n configuration
31
+ */
32
+ export interface I18nConfig {
33
+ /** Initial locale (default: browser language) */
34
+ locale?: string;
35
+
36
+ /** Fallback locale (default: 'en') */
37
+ fallbackLocale?: string;
38
+
39
+ /** Translation loader function */
40
+ loadTranslations?: (locale: string) => Promise<TranslationBundle>;
41
+
42
+ /** Bundled translations (for hybrid loading) */
43
+ bundledTranslations?: Record<string, TranslationBundle>;
44
+
45
+ /** Missing key handler */
46
+ onMissingKey?: (key: string, locale: string) => void;
47
+
48
+ /** Debug mode */
49
+ debug?: boolean;
50
+ }
51
+
52
+ /**
53
+ * I18nService interface
54
+ */
55
+ export interface II18nService {
56
+ initialize(config: I18nConfig): Promise<void>;
57
+ t(key: string, params?: Record<string, any>): string;
58
+ tn(key: string, count: number, params?: Record<string, any>): string;
59
+ getLocale(): string;
60
+ setLocale(locale: string): Promise<void>;
61
+ getDirection(): "ltr" | "rtl";
62
+ getAvailableLocales(): string[];
63
+ isLocaleLoaded(locale: string): boolean;
64
+ subscribe(listener: () => void): () => void;
65
+ hasKey(key: string): boolean;
66
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Standalone i18n Composable
3
+ *
4
+ * Lightweight i18n for standalone components that don't use the service architecture.
5
+ * Creates its own internal I18nService instance with hybrid loading.
6
+ *
7
+ * Use this when:
8
+ * - Building standalone components (tools, players) without full toolkit integration
9
+ * - You want simple i18n without dependency injection
10
+ *
11
+ * Use `useI18n()` when:
12
+ * - Working within the full assessment toolkit architecture
13
+ * - You need centralized locale management across the application
14
+ *
15
+ * @example
16
+ * ```svelte
17
+ * <script lang="ts">
18
+ * import { useI18nStandalone } from '@pie-players/pie-players-shared/i18n';
19
+ *
20
+ * const i18n = useI18nStandalone({ locale: 'en' });
21
+ * </script>
22
+ *
23
+ * <button>{i18n.t('common.save')}</button>
24
+ * <span dir={i18n.direction}>{i18n.tn('assessment.questions', 10)}</span>
25
+ * ```
26
+ */
27
+
28
+ import { BUNDLED_TRANSLATIONS, loadTranslations } from "./loader";
29
+ import { SimpleI18n } from "./simple-i18n";
30
+
31
+ /**
32
+ * Standalone i18n configuration
33
+ */
34
+ export interface UseI18nStandaloneConfig {
35
+ /** Initial locale (default: browser language) */
36
+ locale?: string;
37
+ /** Fallback locale (default: 'en') */
38
+ fallbackLocale?: string;
39
+ /** Debug mode */
40
+ debug?: boolean;
41
+ }
42
+
43
+ /**
44
+ * Create a standalone i18n instance
45
+ *
46
+ * @param config Configuration options
47
+ * @returns Reactive i18n interface
48
+ */
49
+ export function useI18nStandalone(config: UseI18nStandaloneConfig = {}) {
50
+ let locale = $state<string>(config.locale || "en");
51
+ let direction = $state<"ltr" | "rtl">("ltr");
52
+ let isLoading = $state(false);
53
+
54
+ // Create internal service instance
55
+ const service = new SimpleI18n({
56
+ locale: config.locale,
57
+ fallbackLocale: config.fallbackLocale || "en",
58
+ bundledTranslations: BUNDLED_TRANSLATIONS,
59
+ loadTranslations,
60
+ debug: config.debug,
61
+ });
62
+
63
+ // Initialize service
64
+ $effect(() => {
65
+ service
66
+ .initialize({
67
+ locale: config.locale,
68
+ fallbackLocale: config.fallbackLocale || "en",
69
+ bundledTranslations: BUNDLED_TRANSLATIONS,
70
+ loadTranslations,
71
+ debug: config.debug,
72
+ })
73
+ .then(() => {
74
+ locale = service.getLocale();
75
+ direction = service.getDirection();
76
+ });
77
+ });
78
+
79
+ // Subscribe to service changes
80
+ $effect(() => {
81
+ const unsubscribe = service.subscribe(() => {
82
+ locale = service.getLocale();
83
+ direction = service.getDirection();
84
+ });
85
+
86
+ return unsubscribe;
87
+ });
88
+
89
+ /**
90
+ * Translate a key with optional interpolation
91
+ */
92
+ function t(key: string, params?: Record<string, any>): string {
93
+ return service.t(key, params);
94
+ }
95
+
96
+ /**
97
+ * Translate with pluralization
98
+ */
99
+ function tn(
100
+ key: string,
101
+ count: number,
102
+ params?: Record<string, any>,
103
+ ): string {
104
+ return service.tn(key, count, params);
105
+ }
106
+
107
+ /**
108
+ * Change locale (async)
109
+ */
110
+ async function setLocale(newLocale: string): Promise<void> {
111
+ isLoading = true;
112
+ try {
113
+ await service.setLocale(newLocale);
114
+ } finally {
115
+ isLoading = false;
116
+ }
117
+ }
118
+
119
+ return {
120
+ /**
121
+ * Current locale (reactive)
122
+ */
123
+ get locale() {
124
+ return locale;
125
+ },
126
+
127
+ /**
128
+ * Current text direction (reactive)
129
+ */
130
+ get direction() {
131
+ return direction;
132
+ },
133
+
134
+ /**
135
+ * Loading state (reactive)
136
+ */
137
+ get isLoading() {
138
+ return isLoading;
139
+ },
140
+
141
+ /**
142
+ * Translate function
143
+ */
144
+ t,
145
+
146
+ /**
147
+ * Translate with pluralization
148
+ */
149
+ tn,
150
+
151
+ /**
152
+ * Change locale
153
+ */
154
+ setLocale,
155
+
156
+ /**
157
+ * Get available locales
158
+ */
159
+ get availableLocales() {
160
+ return service.getAvailableLocales();
161
+ },
162
+
163
+ /**
164
+ * Check if locale is loaded
165
+ */
166
+ isLocaleLoaded(loc: string): boolean {
167
+ return service.isLocaleLoaded(loc);
168
+ },
169
+
170
+ /**
171
+ * Check if translation key exists
172
+ */
173
+ hasKey(key: string): boolean {
174
+ return service.hasKey(key);
175
+ },
176
+
177
+ /**
178
+ * Access underlying service (for advanced use cases)
179
+ */
180
+ get service() {
181
+ return service;
182
+ },
183
+ };
184
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Svelte 5 Composable for i18n
3
+ *
4
+ * Provides reactive translation functions and locale state.
5
+ * Uses Svelte 5 runes for reactivity.
6
+ *
7
+ * Usage in a Svelte 5 component:
8
+ * ```svelte
9
+ * <script lang="ts">
10
+ * import { useI18n } from '@pie-players/pie-players-shared/i18n';
11
+ *
12
+ * let { player } = $props();
13
+ * const i18n = useI18n(() => player.getI18nService());
14
+ * </script>
15
+ *
16
+ * <button>{i18n.t('common.save')}</button>
17
+ * <span dir={i18n.direction}>
18
+ * {i18n.tn('assessment.questions', totalQuestions)}
19
+ * </span>
20
+ * ```
21
+ */
22
+
23
+ import type { II18nService } from "./types";
24
+
25
+ /**
26
+ * Svelte 5 composable for internationalization
27
+ *
28
+ * @param getService - Function that returns the I18nService instance (reactive)
29
+ * @returns Object with reactive locale, direction, and translation functions
30
+ */
31
+ export function useI18n(getService: () => II18nService | undefined) {
32
+ let locale = $state<string>("en");
33
+ let direction = $state<"ltr" | "rtl">("ltr");
34
+ let isLoading = $state(false);
35
+
36
+ // Get service instance reactively
37
+ const service = $derived(getService());
38
+
39
+ // Subscribe to service changes
40
+ $effect(() => {
41
+ if (service) {
42
+ // Initialize state from service
43
+ locale = service.getLocale();
44
+ direction = service.getDirection();
45
+
46
+ // Subscribe to changes
47
+ const unsubscribe = service.subscribe(() => {
48
+ locale = service.getLocale();
49
+ direction = service.getDirection();
50
+ });
51
+
52
+ // Cleanup subscription
53
+ return unsubscribe;
54
+ }
55
+ // Return no-op cleanup if service is undefined
56
+ return () => {};
57
+ });
58
+
59
+ /**
60
+ * Translate a key with optional interpolation
61
+ *
62
+ * @param key Translation key (e.g., 'common.save')
63
+ * @param params Optional parameters for interpolation
64
+ * @returns Translated string
65
+ */
66
+ function t(key: string, params?: Record<string, any>): string {
67
+ if (!service) return key;
68
+ return service.t(key, params);
69
+ }
70
+
71
+ /**
72
+ * Translate with pluralization
73
+ *
74
+ * @param key Translation key
75
+ * @param count Count for pluralization
76
+ * @param params Optional parameters for interpolation
77
+ * @returns Translated string with plural form
78
+ */
79
+ function tn(
80
+ key: string,
81
+ count: number,
82
+ params?: Record<string, any>,
83
+ ): string {
84
+ if (!service) return key;
85
+ return service.tn(key, count, params);
86
+ }
87
+
88
+ /**
89
+ * Change locale (async)
90
+ *
91
+ * @param newLocale Locale code (e.g., 'en', 'es', 'zh', 'ar')
92
+ */
93
+ async function setLocale(newLocale: string): Promise<void> {
94
+ if (!service) return;
95
+
96
+ isLoading = true;
97
+ try {
98
+ await service.setLocale(newLocale);
99
+ } finally {
100
+ isLoading = false;
101
+ }
102
+ }
103
+
104
+ // Return reactive getters and functions
105
+ return {
106
+ /**
107
+ * Current locale (reactive)
108
+ */
109
+ get locale() {
110
+ return locale;
111
+ },
112
+
113
+ /**
114
+ * Current text direction (reactive)
115
+ */
116
+ get direction() {
117
+ return direction;
118
+ },
119
+
120
+ /**
121
+ * Loading state (reactive)
122
+ */
123
+ get isLoading() {
124
+ return isLoading;
125
+ },
126
+
127
+ /**
128
+ * Translate function
129
+ */
130
+ t,
131
+
132
+ /**
133
+ * Translate with pluralization
134
+ */
135
+ tn,
136
+
137
+ /**
138
+ * Change locale
139
+ */
140
+ setLocale,
141
+
142
+ /**
143
+ * Get available locales
144
+ */
145
+ get availableLocales() {
146
+ return service?.getAvailableLocales() || [];
147
+ },
148
+
149
+ /**
150
+ * Check if locale is loaded
151
+ */
152
+ isLocaleLoaded(loc: string): boolean {
153
+ return service?.isLocaleLoaded(loc) || false;
154
+ },
155
+
156
+ /**
157
+ * Check if translation key exists
158
+ */
159
+ hasKey(key: string): boolean {
160
+ return service?.hasKey(key) || false;
161
+ },
162
+ };
163
+ }