@stacksjs/components 0.2.93 → 0.2.94

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 (187) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +5 -6
  3. package/src/components/CodeBlock.stx +0 -54
  4. package/src/components/Footer.stx +0 -66
  5. package/src/components/Hero.stx +0 -25
  6. package/src/components/Installation.stx +0 -37
  7. package/src/components/index.ts +0 -4
  8. package/src/composables/index.ts +0 -4
  9. package/src/composables/useCopyCode.ts +0 -73
  10. package/src/composables/useDarkMode.ts +0 -100
  11. package/src/composables/useSEO.ts +0 -230
  12. package/src/composables/utilities/index.ts +0 -7
  13. package/src/composables/utilities/useClickOutside.ts +0 -72
  14. package/src/composables/utilities/useFocusTrap.ts +0 -159
  15. package/src/composables/utilities/useKeyboard.ts +0 -124
  16. package/src/composables/utilities/useLocalStorage.ts +0 -132
  17. package/src/composables/utilities/useMediaQuery.ts +0 -118
  18. package/src/index.ts +0 -99
  19. package/src/stx.d.ts +0 -4
  20. package/src/ui/accordion/Accordion.stx +0 -146
  21. package/src/ui/accordion/AccordionItem.stx +0 -37
  22. package/src/ui/accordion/index.ts +0 -47
  23. package/src/ui/audio/Audio.stx +0 -50
  24. package/src/ui/audio/README.md +0 -41
  25. package/src/ui/audio/index.ts +0 -13
  26. package/src/ui/auth/Login.stx +0 -161
  27. package/src/ui/auth/README.md +0 -142
  28. package/src/ui/auth/Signup.stx +0 -159
  29. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  30. package/src/ui/auth/index.ts +0 -32
  31. package/src/ui/avatar/Avatar.stx +0 -77
  32. package/src/ui/avatar/index.ts +0 -12
  33. package/src/ui/badge/Badge.stx +0 -62
  34. package/src/ui/badge/index.ts +0 -10
  35. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  36. package/src/ui/breadcrumb/index.ts +0 -15
  37. package/src/ui/button/Button.stx +0 -74
  38. package/src/ui/button/README.md +0 -80
  39. package/src/ui/button/index.ts +0 -85
  40. package/src/ui/calendar/Calendar.stx +0 -189
  41. package/src/ui/calendar/README.md +0 -254
  42. package/src/ui/calendar/index.ts +0 -14
  43. package/src/ui/card/Card.stx +0 -68
  44. package/src/ui/card/index.ts +0 -13
  45. package/src/ui/checkbox/Checkbox.stx +0 -86
  46. package/src/ui/checkbox/index.ts +0 -16
  47. package/src/ui/combobox/Combobox.stx +0 -96
  48. package/src/ui/combobox/ComboboxButton.stx +0 -25
  49. package/src/ui/combobox/ComboboxInput.stx +0 -32
  50. package/src/ui/combobox/ComboboxOption.stx +0 -49
  51. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  52. package/src/ui/combobox/README.md +0 -150
  53. package/src/ui/combobox/index.ts +0 -40
  54. package/src/ui/command-palette/CommandPalette.stx +0 -81
  55. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  56. package/src/ui/command-palette/README.md +0 -42
  57. package/src/ui/command-palette/index.ts +0 -15
  58. package/src/ui/dialog/Dialog.stx +0 -41
  59. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  60. package/src/ui/dialog/DialogDescription.stx +0 -11
  61. package/src/ui/dialog/DialogPanel.stx +0 -16
  62. package/src/ui/dialog/DialogTitle.stx +0 -11
  63. package/src/ui/dialog/README.md +0 -121
  64. package/src/ui/dialog/index.ts +0 -32
  65. package/src/ui/drawer/Drawer.stx +0 -120
  66. package/src/ui/drawer/README.md +0 -90
  67. package/src/ui/drawer/index.ts +0 -9
  68. package/src/ui/dropdown/Dropdown.stx +0 -82
  69. package/src/ui/dropdown/DropdownButton.stx +0 -29
  70. package/src/ui/dropdown/DropdownItem.stx +0 -35
  71. package/src/ui/dropdown/DropdownItems.stx +0 -18
  72. package/src/ui/dropdown/README.md +0 -114
  73. package/src/ui/dropdown/index.ts +0 -29
  74. package/src/ui/form/Form.stx +0 -95
  75. package/src/ui/form/index.ts +0 -67
  76. package/src/ui/heatmap/Heatmap.stx +0 -294
  77. package/src/ui/image/Image.stx +0 -165
  78. package/src/ui/image/README.md +0 -164
  79. package/src/ui/image/index.ts +0 -22
  80. package/src/ui/input/EmailInput.stx +0 -30
  81. package/src/ui/input/NumberInput.stx +0 -126
  82. package/src/ui/input/PasswordInput.stx +0 -143
  83. package/src/ui/input/SearchInput.stx +0 -44
  84. package/src/ui/input/TextInput.stx +0 -132
  85. package/src/ui/input/index.ts +0 -180
  86. package/src/ui/listbox/Listbox.stx +0 -101
  87. package/src/ui/listbox/ListboxButton.stx +0 -28
  88. package/src/ui/listbox/ListboxLabel.stx +0 -11
  89. package/src/ui/listbox/ListboxOption.stx +0 -49
  90. package/src/ui/listbox/ListboxOptions.stx +0 -16
  91. package/src/ui/listbox/README.md +0 -135
  92. package/src/ui/listbox/index.ts +0 -39
  93. package/src/ui/navigator/Navigator.stx +0 -113
  94. package/src/ui/navigator/README.md +0 -352
  95. package/src/ui/navigator/index.ts +0 -20
  96. package/src/ui/notification/Notification.stx +0 -117
  97. package/src/ui/notification/README.md +0 -114
  98. package/src/ui/notification/index.ts +0 -12
  99. package/src/ui/pagination/Pagination.stx +0 -150
  100. package/src/ui/pagination/index.ts +0 -11
  101. package/src/ui/payment/Checkout.stx +0 -31
  102. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  103. package/src/ui/payment/PaymentMethods.stx +0 -104
  104. package/src/ui/payment/README.md +0 -345
  105. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  106. package/src/ui/payment/index.ts +0 -59
  107. package/src/ui/popover/Popover.stx +0 -60
  108. package/src/ui/popover/PopoverButton.stx +0 -29
  109. package/src/ui/popover/PopoverPanel.stx +0 -23
  110. package/src/ui/popover/README.md +0 -91
  111. package/src/ui/popover/index.ts +0 -22
  112. package/src/ui/portal/Portal.stx +0 -57
  113. package/src/ui/portal/index.ts +0 -6
  114. package/src/ui/progress/Progress.stx +0 -131
  115. package/src/ui/progress/index.ts +0 -12
  116. package/src/ui/radio/Radio.stx +0 -77
  117. package/src/ui/radio/index.ts +0 -15
  118. package/src/ui/radio-group/README.md +0 -139
  119. package/src/ui/radio-group/RadioGroup.stx +0 -60
  120. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  121. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  123. package/src/ui/radio-group/index.ts +0 -30
  124. package/src/ui/select/README.md +0 -180
  125. package/src/ui/select/Select.stx +0 -82
  126. package/src/ui/select/index.ts +0 -21
  127. package/src/ui/sidebar/Sidebar.stx +0 -476
  128. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  129. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  130. package/src/ui/sidebar/SidebarItem.stx +0 -86
  131. package/src/ui/sidebar/SidebarSection.stx +0 -83
  132. package/src/ui/sidebar/index.ts +0 -153
  133. package/src/ui/sidebar/themes.ts +0 -240
  134. package/src/ui/skeleton/Skeleton.stx +0 -48
  135. package/src/ui/skeleton/index.ts +0 -11
  136. package/src/ui/spinner/Spinner.stx +0 -109
  137. package/src/ui/spinner/index.ts +0 -9
  138. package/src/ui/stepper/README.md +0 -36
  139. package/src/ui/stepper/Stepper.stx +0 -17
  140. package/src/ui/stepper/StepperStep.stx +0 -57
  141. package/src/ui/stepper/index.ts +0 -19
  142. package/src/ui/storage/README.md +0 -193
  143. package/src/ui/storage/index.ts +0 -347
  144. package/src/ui/switch/README.md +0 -114
  145. package/src/ui/switch/Switch.stx +0 -72
  146. package/src/ui/switch/index.ts +0 -10
  147. package/src/ui/table/README.md +0 -39
  148. package/src/ui/table/Table.stx +0 -14
  149. package/src/ui/table/TableBody.stx +0 -10
  150. package/src/ui/table/TableCell.stx +0 -10
  151. package/src/ui/table/TableHead.stx +0 -10
  152. package/src/ui/table/TableHeader.stx +0 -20
  153. package/src/ui/table/TableRow.stx +0 -11
  154. package/src/ui/table/index.ts +0 -35
  155. package/src/ui/tabs/TabPanel.stx +0 -25
  156. package/src/ui/tabs/Tabs.stx +0 -202
  157. package/src/ui/tabs/index.ts +0 -50
  158. package/src/ui/teleport/Teleport.stx +0 -65
  159. package/src/ui/teleport/index.ts +0 -7
  160. package/src/ui/textarea/Textarea.stx +0 -108
  161. package/src/ui/textarea/index.ts +0 -20
  162. package/src/ui/tooltip/Tooltip.stx +0 -71
  163. package/src/ui/tooltip/index.ts +0 -10
  164. package/src/ui/transition/README.md +0 -30
  165. package/src/ui/transition/Transition.stx +0 -102
  166. package/src/ui/transition/index.ts +0 -25
  167. package/src/ui/video/README.md +0 -47
  168. package/src/ui/video/Video.stx +0 -45
  169. package/src/ui/video/index.ts +0 -16
  170. package/src/ui/virtual-list/VirtualList.stx +0 -67
  171. package/src/ui/virtual-list/index.ts +0 -10
  172. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  173. package/src/ui/virtual-table/index.ts +0 -21
  174. package/src/utils/PROP_VALIDATION.md +0 -458
  175. package/src/utils/THEME_SYSTEM.md +0 -702
  176. package/src/utils/accessibility.ts +0 -841
  177. package/src/utils/animation/easing.ts +0 -368
  178. package/src/utils/animation/helpers.ts +0 -223
  179. package/src/utils/animation/index.ts +0 -5
  180. package/src/utils/animation/keyframes.ts +0 -230
  181. package/src/utils/error-handling.ts +0 -475
  182. package/src/utils/highlighter.ts +0 -93
  183. package/src/utils/i18n.ts +0 -634
  184. package/src/utils/keep-alive.ts +0 -819
  185. package/src/utils/lazy-loading.ts +0 -530
  186. package/src/utils/prop-validation.ts +0 -478
  187. package/src/utils/theme.ts +0 -626
@@ -1,93 +0,0 @@
1
- import type { Highlighter as TSHighlighter } from 'ts-syntax-highlighter'
2
- import { createHighlighter } from 'ts-syntax-highlighter'
3
-
4
- let highlighterInstance: TSHighlighter | null = null
5
-
6
- export interface HighlighterOptions {
7
- theme?: 'light' | 'dark' | 'auto'
8
- language?: string
9
- lineNumbers?: boolean
10
- wrapLines?: boolean
11
- }
12
-
13
- export interface HighlightResult {
14
- html: string
15
- language: string
16
- theme: string
17
- }
18
-
19
- /**
20
- * Initialize or get the syntax highlighter instance
21
- */
22
- export async function getHighlighter(): Promise<TSHighlighter> {
23
- if (!highlighterInstance) {
24
- highlighterInstance = await createHighlighter({
25
- theme: 'github-light',
26
- })
27
- }
28
- return highlighterInstance
29
- }
30
-
31
- /**
32
- * Highlight code with syntax highlighting
33
- */
34
- export async function highlight(
35
- code: string,
36
- options: HighlighterOptions = {},
37
- ): Promise<HighlightResult> {
38
- const {
39
- theme = 'auto',
40
- language = 'typescript',
41
- lineNumbers: _lineNumbers = false,
42
- wrapLines: _wrapLines = true,
43
- } = options
44
-
45
- const highlighter = await getHighlighter()
46
-
47
- // Auto-detect theme based on system preference
48
- const effectiveTheme = theme === 'auto'
49
- ? (globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'github-dark' : 'github-light')
50
- : theme === 'dark' ? 'github-dark' : 'github-light'
51
-
52
- const html = await highlighter.highlight(code, language)
53
-
54
- return {
55
- html: typeof html === 'string' ? html : String(html),
56
- language,
57
- theme: effectiveTheme,
58
- }
59
- }
60
-
61
- /**
62
- * Detect language from code content
63
- */
64
- export function detectLanguage(code: string): string {
65
- // Simple heuristics for language detection
66
- if (code.includes('<!DOCTYPE') || code.includes('<html'))
67
- return 'html'
68
- if (code.includes('<?php'))
69
- return 'php'
70
- if (code.includes('import') && code.includes('from'))
71
- return 'typescript'
72
- if (code.includes('function') || code.includes('const'))
73
- return 'javascript'
74
- if (code.includes('{') && code.includes('}'))
75
- return 'json'
76
- if (code.includes('$') && code.includes('|'))
77
- return 'bash'
78
- if (code.includes('#') && code.includes('##'))
79
- return 'markdown'
80
-
81
- return 'typescript' // Default
82
- }
83
-
84
- /**
85
- * Apply headwind utility classes to highlighted code
86
- */
87
- export function applyHeadwindClasses(html: string, additionalClasses?: string): string {
88
- const baseClasses = 'rounded-md overflow-auto text-sm leading-relaxed font-mono'
89
- const classes = additionalClasses ? `${baseClasses} ${additionalClasses}` : baseClasses
90
-
91
- // Wrap the highlighted HTML with headwind classes
92
- return `<div class="${classes}">${html}</div>`
93
- }
package/src/utils/i18n.ts DELETED
@@ -1,634 +0,0 @@
1
- /**
2
- * Internationalization (i18n) system for @stacksjs/components
3
- *
4
- * Provides translation, locale management, pluralization, and date/number formatting
5
- *
6
- * @example
7
- * ```ts
8
- * import { createI18n, t } from '@stacksjs/components'
9
- *
10
- * // Create i18n instance
11
- * const i18n = createI18n({
12
- * locale: 'en',
13
- * fallbackLocale: 'en',
14
- * messages: {
15
- * en: { welcome: 'Welcome' },
16
- * es: { welcome: 'Bienvenido' }
17
- * }
18
- * })
19
- *
20
- * // Use translations
21
- * t('welcome') // 'Welcome' or 'Bienvenido' based on locale
22
- * ```
23
- */
24
-
25
- /**
26
- * Translation messages structure
27
- */
28
- export type MessageValue = string | { [key: string]: MessageValue }
29
- export type Messages = Record<string, MessageValue>
30
-
31
- /**
32
- * Locale messages
33
- */
34
- export type LocaleMessages = Record<string, Messages>
35
-
36
- /**
37
- * Pluralization rules
38
- */
39
- export type PluralRule = (_count: number, _locale: string) => number
40
-
41
- /**
42
- * I18n configuration
43
- */
44
- export interface I18nConfig {
45
- /** Current locale */
46
- locale: string
47
- /** Fallback locale when translation is missing */
48
- fallbackLocale?: string
49
- /** Translation messages for all locales */
50
- messages: LocaleMessages
51
- /** Custom pluralization rules */
52
- pluralRules?: Record<string, PluralRule>
53
- /** Date formatting options */
54
- dateTimeFormats?: Record<string, Intl.DateTimeFormatOptions>
55
- /** Number formatting options */
56
- numberFormats?: Record<string, Intl.NumberFormatOptions>
57
- /** Missing translation handler */
58
- missing?: (locale: string, key: string) => string | void
59
- /** Whether to warn about missing translations */
60
- warnMissing?: boolean
61
- }
62
-
63
- /**
64
- * I18n instance
65
- */
66
- export interface I18n {
67
- /** Current locale */
68
- locale: string
69
- /** Available locales */
70
- availableLocales: string[]
71
- /** Set current locale */
72
- setLocale: (locale: string) => void
73
- /** Get translation */
74
- t: (key: string, params?: Record<string, any>) => string
75
- /** Get pluralized translation */
76
- tc: (key: string, count: number, params?: Record<string, any>) => string
77
- /** Format date */
78
- d: (date: Date | number, format?: string) => string
79
- /** Format number */
80
- n: (value: number, format?: string) => string
81
- /** Check if translation exists */
82
- te: (key: string) => boolean
83
- /** Add locale messages */
84
- addMessages: (locale: string, messages: Messages) => void
85
- /** Remove locale */
86
- removeLocale: (locale: string) => void
87
- }
88
-
89
- /**
90
- * Global i18n instance
91
- */
92
- let globalI18n: I18n | null = null
93
-
94
- /**
95
- * Default pluralization rule (English-like)
96
- */
97
- const defaultPluralRule: PluralRule = (count: number) => {
98
- return count === 1 ? 0 : 1
99
- }
100
-
101
- /**
102
- * Get nested property from object by path
103
- */
104
- function getNestedProperty(obj: any, path: string): any {
105
- return path.split('.').reduce((current, key) => current?.[key], obj)
106
- }
107
-
108
- /**
109
- * Interpolate parameters in translation string
110
- */
111
- function interpolate(template: string, params: Record<string, any> = {}): string {
112
- return template.replace(/\{(\w+)\}/g, (match, key) => {
113
- return params[key] !== undefined ? String(params[key]) : match
114
- })
115
- }
116
-
117
- /**
118
- * Create an i18n instance
119
- *
120
- * @param config - I18n configuration
121
- * @returns I18n instance
122
- *
123
- * @example
124
- * ```ts
125
- * const i18n = createI18n({
126
- * locale: 'en',
127
- * fallbackLocale: 'en',
128
- * messages: {
129
- * en: {
130
- * welcome: 'Welcome, {name}!',
131
- * items: 'No items | One item | {count} items'
132
- * },
133
- * es: {
134
- * welcome: 'Bienvenido, {name}!',
135
- * items: 'Sin elementos | Un elemento | {count} elementos'
136
- * }
137
- * }
138
- * })
139
- * ```
140
- */
141
- export function createI18n(config: I18nConfig): I18n {
142
- let {
143
- locale,
144
- fallbackLocale = 'en',
145
- messages,
146
- pluralRules = {},
147
- dateTimeFormats = {},
148
- numberFormats = {},
149
- missing,
150
- warnMissing = true,
151
- } = config
152
-
153
- /**
154
- * Get translation for key
155
- */
156
- function t(key: string, params: Record<string, any> = {}): string {
157
- // Try current locale
158
- let translation = getNestedProperty(messages[locale], key)
159
-
160
- // Try fallback locale
161
- if (translation === undefined && fallbackLocale) {
162
- translation = getNestedProperty(messages[fallbackLocale], key)
163
- }
164
-
165
- // Handle missing translation
166
- if (translation === undefined) {
167
- if (missing) {
168
- const result = missing(locale, key)
169
- if (result) {
170
- return interpolate(result, params)
171
- }
172
- }
173
-
174
- if (warnMissing && typeof console !== 'undefined') {
175
- console.warn(`[i18n] Missing translation for key "${key}" in locale "${locale}"`)
176
- }
177
-
178
- return key
179
- }
180
-
181
- // Interpolate parameters
182
- if (typeof translation === 'string') {
183
- return interpolate(translation, params)
184
- }
185
-
186
- return String(translation)
187
- }
188
-
189
- /**
190
- * Get pluralized translation
191
- */
192
- function tc(key: string, count: number, params: Record<string, any> = {}): string {
193
- const translation = t(key, { ...params, count })
194
-
195
- // If translation contains plural forms separated by |
196
- if (translation.includes('|')) {
197
- const forms = translation.split('|').map(s => s.trim())
198
- const pluralRule = pluralRules[locale] || defaultPluralRule
199
- const index = pluralRule(count, locale)
200
-
201
- const form = forms[index] || forms[forms.length - 1]
202
- return interpolate(form, { ...params, count })
203
- }
204
-
205
- return translation
206
- }
207
-
208
- /**
209
- * Format date
210
- */
211
- function d(date: Date | number, format = 'default'): string {
212
- const dateObj = typeof date === 'number' ? new Date(date) : date
213
- const formatOptions = dateTimeFormats[format] || dateTimeFormats.default || {}
214
-
215
- return new Intl.DateTimeFormat(locale, formatOptions).format(dateObj)
216
- }
217
-
218
- /**
219
- * Format number
220
- */
221
- function n(value: number, format = 'default'): string {
222
- const formatOptions = numberFormats[format] || numberFormats.default || {}
223
-
224
- return new Intl.NumberFormat(locale, formatOptions).format(value)
225
- }
226
-
227
- /**
228
- * Check if translation exists
229
- */
230
- function te(key: string): boolean {
231
- const translation = getNestedProperty(messages[locale], key)
232
- if (translation !== undefined) {
233
- return true
234
- }
235
-
236
- if (fallbackLocale) {
237
- const fallbackTranslation = getNestedProperty(messages[fallbackLocale], key)
238
- return fallbackTranslation !== undefined
239
- }
240
-
241
- return false
242
- }
243
-
244
- /**
245
- * Set locale
246
- */
247
- function setLocale(newLocale: string): void {
248
- if (!messages[newLocale]) {
249
- console.warn(`[i18n] Locale "${newLocale}" not found. Available locales: ${Object.keys(messages).join(', ')}`)
250
- return
251
- }
252
- locale = newLocale
253
- }
254
-
255
- /**
256
- * Add messages for a locale
257
- */
258
- function addMessages(addLocale: string, newMessages: Messages): void {
259
- if (!messages[addLocale]) {
260
- messages[addLocale] = {}
261
- }
262
-
263
- // Deep merge messages
264
- messages[addLocale] = {
265
- ...messages[addLocale],
266
- ...newMessages,
267
- }
268
- }
269
-
270
- /**
271
- * Remove a locale
272
- */
273
- function removeLocale(removeLocale: string): void {
274
- delete messages[removeLocale]
275
- }
276
-
277
- return {
278
- get locale() {
279
- return locale
280
- },
281
- get availableLocales() {
282
- return Object.keys(messages)
283
- },
284
- setLocale,
285
- t,
286
- tc,
287
- d,
288
- n,
289
- te,
290
- addMessages,
291
- removeLocale,
292
- }
293
- }
294
-
295
- /**
296
- * Set global i18n instance
297
- *
298
- * @param i18n - I18n instance
299
- */
300
- export function setI18n(i18n: I18n): void {
301
- globalI18n = i18n
302
- }
303
-
304
- /**
305
- * Get global i18n instance
306
- *
307
- * @returns Global i18n instance or null
308
- */
309
- export function getI18n(): I18n | null {
310
- return globalI18n
311
- }
312
-
313
- /**
314
- * Global translation function
315
- * Uses global i18n instance
316
- *
317
- * @param key - Translation key
318
- * @param params - Interpolation parameters
319
- * @returns Translated string
320
- */
321
- export function t(key: string, params?: Record<string, any>): string {
322
- if (!globalI18n) {
323
- console.warn('[i18n] No global i18n instance set. Call setI18n() first.')
324
- return key
325
- }
326
- return globalI18n.t(key, params)
327
- }
328
-
329
- /**
330
- * Global pluralization function
331
- *
332
- * @param key - Translation key
333
- * @param count - Count for pluralization
334
- * @param params - Interpolation parameters
335
- * @returns Pluralized translated string
336
- */
337
- export function tc(key: string, count: number, params?: Record<string, any>): string {
338
- if (!globalI18n) {
339
- console.warn('[i18n] No global i18n instance set. Call setI18n() first.')
340
- return key
341
- }
342
- return globalI18n.tc(key, count, params)
343
- }
344
-
345
- /**
346
- * Global date formatting function
347
- *
348
- * @param date - Date to format
349
- * @param format - Format name
350
- * @returns Formatted date string
351
- */
352
- export function d(date: Date | number, format?: string): string {
353
- if (!globalI18n) {
354
- console.warn('[i18n] No global i18n instance set. Call setI18n() first.')
355
- return String(date)
356
- }
357
- return globalI18n.d(date, format)
358
- }
359
-
360
- /**
361
- * Global number formatting function
362
- *
363
- * @param value - Number to format
364
- * @param format - Format name
365
- * @returns Formatted number string
366
- */
367
- export function n(value: number, format?: string): string {
368
- if (!globalI18n) {
369
- console.warn('[i18n] No global i18n instance set. Call setI18n() first.')
370
- return String(value)
371
- }
372
- return globalI18n.n(value, format)
373
- }
374
-
375
- /**
376
- * Predefined pluralization rules for common languages
377
- */
378
- export const pluralRules: Record<string, PluralRule> = {
379
- // English, German, Dutch, Swedish, Danish, Norwegian, Finnish
380
- en: count => count === 1 ? 0 : 1,
381
- de: count => count === 1 ? 0 : 1,
382
- nl: count => count === 1 ? 0 : 1,
383
- sv: count => count === 1 ? 0 : 1,
384
-
385
- // French, Brazilian Portuguese
386
- fr: count => count === 0 || count === 1 ? 0 : 1,
387
- pt_BR: count => count === 0 || count === 1 ? 0 : 1,
388
-
389
- // Russian, Ukrainian, Serbian, Croatian
390
- ru: (count) => {
391
- if (count % 10 === 1 && count % 100 !== 11)
392
- return 0
393
- if (count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 10 || count % 100 >= 20))
394
- return 1
395
- return 2
396
- },
397
-
398
- // Polish
399
- pl: (count) => {
400
- if (count === 1)
401
- return 0
402
- if (count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 10 || count % 100 >= 20))
403
- return 1
404
- return 2
405
- },
406
-
407
- // Czech, Slovak
408
- cs: (count) => {
409
- if (count === 1)
410
- return 0
411
- if (count >= 2 && count <= 4)
412
- return 1
413
- return 2
414
- },
415
-
416
- // Arabic
417
- ar: (count) => {
418
- if (count === 0)
419
- return 0
420
- if (count === 1)
421
- return 1
422
- if (count === 2)
423
- return 2
424
- if (count % 100 >= 3 && count % 100 <= 10)
425
- return 3
426
- if (count % 100 >= 11)
427
- return 4
428
- return 5
429
- },
430
-
431
- // Japanese, Korean, Chinese, Thai, Vietnamese
432
- ja: () => 0,
433
- ko: () => 0,
434
- zh: () => 0,
435
- th: () => 0,
436
- vi: () => 0,
437
- }
438
-
439
- /**
440
- * Common date/time format presets
441
- */
442
- export const dateTimeFormats: Record<string, Intl.DateTimeFormatOptions> = {
443
- short: {
444
- year: 'numeric',
445
- month: 'numeric',
446
- day: 'numeric',
447
- },
448
- long: {
449
- year: 'numeric',
450
- month: 'long',
451
- day: 'numeric',
452
- },
453
- full: {
454
- weekday: 'long',
455
- year: 'numeric',
456
- month: 'long',
457
- day: 'numeric',
458
- },
459
- time: {
460
- hour: 'numeric',
461
- minute: 'numeric',
462
- },
463
- datetime: {
464
- year: 'numeric',
465
- month: 'numeric',
466
- day: 'numeric',
467
- hour: 'numeric',
468
- minute: 'numeric',
469
- },
470
- }
471
-
472
- /**
473
- * Common number format presets
474
- */
475
- export const numberFormats: Record<string, Intl.NumberFormatOptions> = {
476
- decimal: {
477
- style: 'decimal',
478
- minimumFractionDigits: 2,
479
- maximumFractionDigits: 2,
480
- },
481
- currency: {
482
- style: 'currency',
483
- currency: 'USD',
484
- },
485
- percent: {
486
- style: 'percent',
487
- minimumFractionDigits: 0,
488
- maximumFractionDigits: 2,
489
- },
490
- compact: {
491
- notation: 'compact',
492
- },
493
- }
494
-
495
- /**
496
- * RTL (Right-to-Left) language detection
497
- *
498
- * @param locale - Locale code
499
- * @returns Whether locale is RTL
500
- */
501
- export function isRTL(locale: string): boolean {
502
- const rtlLocales = ['ar', 'he', 'fa', 'ur', 'yi']
503
- const lang = locale.split('-')[0].toLowerCase()
504
- return rtlLocales.includes(lang)
505
- }
506
-
507
- /**
508
- * Load locale messages dynamically
509
- *
510
- * @param locale - Locale code
511
- * @param loadFn - Function to load messages
512
- * @returns Promise of messages
513
- *
514
- * @example
515
- * ```ts
516
- * const messages = await loadLocaleMessages('es', async () => {
517
- * const module = await import('./locales/es.json')
518
- * return module.default
519
- * })
520
- * ```
521
- */
522
- export async function loadLocaleMessages(
523
- locale: string,
524
- loadFn: () => Promise<Messages>,
525
- ): Promise<Messages> {
526
- try {
527
- return await loadFn()
528
- }
529
- catch (error) {
530
- console.error(`[i18n] Failed to load messages for locale "${locale}":`, error)
531
- return {}
532
- }
533
- }
534
-
535
- /**
536
- * Component-specific i18n messages
537
- *
538
- * Provides default translations for component library
539
- */
540
- export const componentMessages: LocaleMessages = {
541
- en: {
542
- common: {
543
- loading: 'Loading...',
544
- error: 'Error',
545
- retry: 'Retry',
546
- cancel: 'Cancel',
547
- confirm: 'Confirm',
548
- close: 'Close',
549
- save: 'Save',
550
- delete: 'Delete',
551
- edit: 'Edit',
552
- search: 'Search',
553
- clear: 'Clear',
554
- submit: 'Submit',
555
- reset: 'Reset',
556
- },
557
- form: {
558
- required: 'This field is required',
559
- invalid: 'Invalid value',
560
- tooShort: 'Value is too short (minimum {min} characters)',
561
- tooLong: 'Value is too long (maximum {max} characters)',
562
- invalidEmail: 'Invalid email address',
563
- invalidUrl: 'Invalid URL',
564
- },
565
- pagination: {
566
- previous: 'Previous',
567
- next: 'Next',
568
- page: 'Page {page}',
569
- of: 'of {total}',
570
- },
571
- },
572
- es: {
573
- common: {
574
- loading: 'Cargando...',
575
- error: 'Error',
576
- retry: 'Reintentar',
577
- cancel: 'Cancelar',
578
- confirm: 'Confirmar',
579
- close: 'Cerrar',
580
- save: 'Guardar',
581
- delete: 'Eliminar',
582
- edit: 'Editar',
583
- search: 'Buscar',
584
- clear: 'Limpiar',
585
- submit: 'Enviar',
586
- reset: 'Restablecer',
587
- },
588
- form: {
589
- required: 'Este campo es obligatorio',
590
- invalid: 'Valor inválido',
591
- tooShort: 'El valor es demasiado corto (mínimo {min} caracteres)',
592
- tooLong: 'El valor es demasiado largo (máximo {max} caracteres)',
593
- invalidEmail: 'Dirección de correo electrónico inválida',
594
- invalidUrl: 'URL inválida',
595
- },
596
- pagination: {
597
- previous: 'Anterior',
598
- next: 'Siguiente',
599
- page: 'Página {page}',
600
- of: 'de {total}',
601
- },
602
- },
603
- fr: {
604
- common: {
605
- loading: 'Chargement...',
606
- error: 'Erreur',
607
- retry: 'Réessayer',
608
- cancel: 'Annuler',
609
- confirm: 'Confirmer',
610
- close: 'Fermer',
611
- save: 'Enregistrer',
612
- delete: 'Supprimer',
613
- edit: 'Modifier',
614
- search: 'Rechercher',
615
- clear: 'Effacer',
616
- submit: 'Soumettre',
617
- reset: 'Réinitialiser',
618
- },
619
- form: {
620
- required: 'Ce champ est obligatoire',
621
- invalid: 'Valeur invalide',
622
- tooShort: 'La valeur est trop courte (minimum {min} caractères)',
623
- tooLong: 'La valeur est trop longue (maximum {max} caractères)',
624
- invalidEmail: 'Adresse e-mail invalide',
625
- invalidUrl: 'URL invalide',
626
- },
627
- pagination: {
628
- previous: 'Précédent',
629
- next: 'Suivant',
630
- page: 'Page {page}',
631
- of: 'sur {total}',
632
- },
633
- },
634
- }