@i18n-micro/astro 1.3.25 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -64
  3. package/dist/auto-middleware.d.ts +1 -0
  4. package/dist/client/core.d.cts +86 -0
  5. package/dist/client/core.d.ts +71 -8
  6. package/dist/client/index.d.cts +2 -6
  7. package/dist/client/index.d.ts +2 -6
  8. package/dist/client/index.js +1 -6
  9. package/dist/client/preact.d.ts +12 -23
  10. package/dist/client/preact.js +13 -37
  11. package/dist/client/react.d.ts +14 -21
  12. package/dist/client/react.js +12 -37
  13. package/dist/client/svelte.d.ts +14 -14
  14. package/dist/client/svelte.js +17 -47
  15. package/dist/client/vue.d.ts +15 -15
  16. package/dist/client/vue.js +37 -2
  17. package/dist/composer.d.cts +16 -0
  18. package/dist/composer.d.ts +10 -30
  19. package/dist/core-CgrgdmGy.cjs +1 -0
  20. package/dist/core-DTAcn2yF.js +72 -0
  21. package/dist/env.d.ts +8 -2
  22. package/dist/index.cjs +11 -3
  23. package/dist/index.d.cts +10 -13
  24. package/dist/index.d.ts +10 -13
  25. package/dist/index.mjs +171 -482
  26. package/dist/integration.d.cts +26 -0
  27. package/dist/integration.d.ts +14 -15
  28. package/dist/middleware-BT3OA5YL.cjs +1 -0
  29. package/dist/middleware-Ch8E0iV_.js +257 -0
  30. package/dist/middleware.d.cts +34 -0
  31. package/dist/middleware.d.ts +17 -8
  32. package/dist/middleware.js +23 -0
  33. package/dist/node.d.ts +26 -0
  34. package/dist/node.js +22 -0
  35. package/dist/request.d.ts +69 -0
  36. package/dist/router/adapter.d.cts +9 -0
  37. package/dist/router/adapter.d.ts +5 -4
  38. package/dist/router/types.d.cts +66 -0
  39. package/dist/router/types.d.ts +3 -2
  40. package/dist/utils.d.cts +112 -0
  41. package/dist/utils.d.ts +39 -35
  42. package/dist/virtual.d.ts +21 -0
  43. package/package.json +28 -15
  44. package/src/auto-middleware.ts +26 -0
  45. package/src/client/core.ts +124 -59
  46. package/src/client/index.ts +2 -11
  47. package/src/client/preact.tsx +12 -127
  48. package/src/client/react.tsx +11 -123
  49. package/src/client/svelte.ts +6 -69
  50. package/src/client/vue.ts +22 -77
  51. package/src/components/i18n-link.astro +2 -59
  52. package/src/components/i18n-switcher.astro +46 -149
  53. package/src/components/i18n-t.astro +6 -54
  54. package/src/composer.ts +25 -115
  55. package/src/env.d.ts +7 -0
  56. package/src/index.ts +1 -6
  57. package/src/integration.ts +113 -52
  58. package/src/middleware.ts +174 -120
  59. package/src/node.ts +51 -0
  60. package/src/request.ts +177 -0
  61. package/src/router/adapter.ts +47 -149
  62. package/src/router/types.ts +3 -2
  63. package/src/utils.ts +149 -323
  64. package/src/virtual.d.ts +21 -0
  65. package/dist/components/index.d.cts +0 -0
  66. package/dist/components/index.d.ts +0 -0
  67. package/dist/core-DwkpOV-H.cjs +0 -1
  68. package/dist/core-VSnkGRWR.js +0 -28
  69. package/dist/load-translations.d.ts +0 -43
  70. package/dist/routing-context.d.ts +0 -4
  71. package/dist/vue-BNiEwZr2.cjs +0 -5
  72. package/dist/vue-CWHjIOiS.js +0 -1724
  73. package/src/components/index.ts +0 -11
  74. package/src/load-translations.ts +0 -106
  75. package/src/routing-context.ts +0 -23
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  import type { Locale } from '@i18n-micro/types'
3
- import type { I18nRoutingStrategy } from '../router/types'
4
- import { useI18n } from '../utils'
3
+ import { localeLabel, useI18n } from '../utils'
5
4
 
6
5
  interface Props {
7
6
  class?: string
@@ -12,90 +11,31 @@ interface Props {
12
11
 
13
12
  const { class: className, activeClass = 'active', customLabels = {}, ...attrs } = Astro.props
14
13
 
15
- const { locale: currentLocale, locales, defaultLocale, getBasePath } = useI18n(Astro)
16
- const localeCodes = locales.map((l: Locale) => l.code)
17
-
18
- // Get routing strategy from locals
19
- // @ts-expect-error
20
- const routingStrategy: I18nRoutingStrategy | null = Astro.locals.routingStrategy || null
21
-
22
- // Filter out disabled locales
23
- const availableLocales = locales.filter((loc: Locale) => !loc.disabled)
24
-
25
- // Find current locale object
26
- const currentLocaleObj = availableLocales.find((loc: Locale) => loc.code === currentLocale)
27
- const currentLocaleLabel = currentLocaleObj
28
- ? customLabels[currentLocaleObj.code] || currentLocaleObj.displayName || currentLocaleObj.code
29
- : currentLocale
30
-
31
- // Generate locale links
32
- const localeLinks = availableLocales.map((loc: Locale) => {
33
- const isActive = loc.code === currentLocale
34
- // Get base path without locale
35
- const basePath = getBasePath()
36
- // Generate path with locale
37
- let switchPath = basePath
38
- if (routingStrategy?.switchLocalePath) {
39
- switchPath = routingStrategy.switchLocalePath(basePath, loc.code, localeCodes, defaultLocale)
40
- } else {
41
- // Fallback: basic locale switching
42
- const segments = basePath.split('/').filter(Boolean)
43
- const firstSegment = segments[0]
44
- if (firstSegment && localeCodes.includes(firstSegment)) {
45
- segments.shift()
46
- }
47
- if (loc.code !== defaultLocale) {
48
- segments.unshift(loc.code)
49
- }
50
- switchPath = `/${segments.join('/')}`
51
- }
52
-
53
- const label = customLabels[loc.code] || loc.displayName || loc.code
54
-
55
- return {
56
- code: loc.code,
57
- displayName: label,
58
- path: switchPath,
59
- isActive,
60
- }
61
- })
62
-
63
- // Generate unique ID for this component instance
64
- const componentId = `i18n-switcher-${Math.random().toString(36).substring(2, 9)}`
14
+ const { locale: currentLocale, locales, switchLocalePath } = useI18n(Astro)
15
+ const { search } = Astro.locals.currentUrl ?? Astro.url
16
+
17
+ const links = locales
18
+ .filter((locale: Locale) => !locale.disabled)
19
+ .map((locale: Locale) => ({
20
+ code: locale.code,
21
+ label: localeLabel(locale, customLabels),
22
+ href: switchLocalePath(locale.code) + search,
23
+ isActive: locale.code === currentLocale,
24
+ }))
65
25
  ---
66
26
 
67
- {localeLinks.length > 0 && (
68
- <div
69
- class={`i18n-switcher-wrapper ${className || ''}`}
70
- data-switcher-id={componentId}
71
- {...attrs}
72
- >
73
- <button
74
- type="button"
75
- class="i18n-switcher-button"
76
- aria-haspopup="true"
77
- aria-expanded="false"
78
- data-switcher-button={componentId}
79
- >
80
- <span>{currentLocaleLabel}</span>
27
+ {links.length > 0 && (
28
+ <div class={`i18n-switcher-wrapper ${className || ''}`} data-i18n-switcher {...attrs}>
29
+ <button type="button" class="i18n-switcher-button" aria-expanded="false">
30
+ <span>{links.find((link) => link.isActive)?.label ?? currentLocale}</span>
81
31
  <span class="i18n-switcher-icon">▼</span>
82
32
  </button>
83
33
 
84
- <ul
85
- class="i18n-switcher-dropdown"
86
- data-switcher-dropdown={componentId}
87
- style="display: none;"
88
- >
89
- {localeLinks.map((link) => (
34
+ <ul class="i18n-switcher-dropdown" hidden>
35
+ {links.map((link) => (
90
36
  <li>
91
- <a
92
- href={link.path}
93
- class={link.isActive ? activeClass : ''}
94
- aria-current={link.isActive ? 'page' : undefined}
95
- data-locale={link.code}
96
- data-switcher-link={componentId}
97
- >
98
- {link.displayName}
37
+ <a href={link.href} class={link.isActive ? activeClass : ''} aria-current={link.isActive ? 'page' : undefined} data-locale={link.code}>
38
+ {link.label}
99
39
  </a>
100
40
  </li>
101
41
  ))}
@@ -103,73 +43,27 @@ const componentId = `i18n-switcher-${Math.random().toString(36).substring(2, 9)}
103
43
  </div>
104
44
  )}
105
45
 
106
- <script define:vars={{ componentId, localeLinks }}>
107
- (function() {
108
- const wrapper = document.querySelector(`[data-switcher-id="${componentId}"]`)
109
- if (!wrapper) return
110
-
111
- const button = wrapper.querySelector(`[data-switcher-button="${componentId}"]`)
112
- const dropdown = wrapper.querySelector(`[data-switcher-dropdown="${componentId}"]`)
113
- const icon = wrapper.querySelector('.i18n-switcher-icon')
114
-
115
- if (!button || !dropdown) return
116
-
117
- let isOpen = false
118
-
119
- const toggleDropdown = (event) => {
120
- if (event) {
121
- event.stopPropagation()
122
- event.preventDefault()
123
- }
124
- isOpen = !isOpen
125
- dropdown.style.display = isOpen ? 'block' : 'none'
126
- button.setAttribute('aria-expanded', String(isOpen))
127
- if (icon) {
128
- icon.style.transform = isOpen ? 'rotate(180deg)' : 'rotate(0deg)'
129
- }
130
- }
131
-
132
- const closeDropdown = () => {
133
- if (isOpen) {
134
- isOpen = false
135
- dropdown.style.display = 'none'
136
- button.setAttribute('aria-expanded', 'false')
137
- if (icon) {
138
- icon.style.transform = 'rotate(0deg)'
139
- }
140
- }
141
- }
142
-
143
- button.addEventListener('click', toggleDropdown)
144
-
145
- // Close on outside click
146
- const handleClickOutside = (event) => {
147
- const target = event.target
148
- if (!target || !wrapper.contains(target)) {
149
- closeDropdown()
150
- }
151
- }
152
-
153
- document.addEventListener('click', handleClickOutside)
154
-
155
- // Close on Escape key
156
- const handleEscape = (event) => {
157
- if (event.key === 'Escape' && isOpen) {
158
- closeDropdown()
159
- }
160
- }
161
-
162
- document.addEventListener('keydown', handleEscape)
163
-
164
- // Handle locale link clicks
165
- const links = wrapper.querySelectorAll(`[data-switcher-link="${componentId}"]`)
166
- links.forEach((link) => {
167
- link.addEventListener('click', () => {
168
- // Let the link navigate naturally, but close dropdown
169
- closeDropdown()
170
- })
171
- })
172
- })()
46
+ <script>
47
+ // One module for every switcher on every page: it runs once, also under <ClientRouter>, and the
48
+ // listeners on `document` reach the switchers a navigation swaps in.
49
+ const setOpen = (wrapper: Element, open: boolean) => {
50
+ wrapper.querySelector('button')?.setAttribute('aria-expanded', String(open))
51
+ wrapper.querySelector('ul')?.toggleAttribute('hidden', !open)
52
+ }
53
+ const closeAll = (except?: Element | null) => {
54
+ for (const wrapper of document.querySelectorAll('[data-i18n-switcher]')) if (wrapper !== except) setOpen(wrapper, false)
55
+ }
56
+
57
+ document.addEventListener('click', (event) => {
58
+ const target = event.target as Element
59
+ const wrapper = target.closest('[data-i18n-switcher]')
60
+ closeAll(wrapper)
61
+ if (wrapper && target.closest('button')) setOpen(wrapper, wrapper.querySelector('button')?.getAttribute('aria-expanded') !== 'true')
62
+ else if (wrapper && target.closest('a')) setOpen(wrapper, false)
63
+ })
64
+ document.addEventListener('keydown', (event) => {
65
+ if (event.key === 'Escape') closeAll()
66
+ })
173
67
  </script>
174
68
 
175
69
  <style>
@@ -203,6 +97,10 @@ const componentId = `i18n-switcher-${Math.random().toString(36).substring(2, 9)}
203
97
  font-size: 12px;
204
98
  }
205
99
 
100
+ .i18n-switcher-button[aria-expanded='true'] .i18n-switcher-icon {
101
+ transform: rotate(180deg);
102
+ }
103
+
206
104
  .i18n-switcher-dropdown {
207
105
  position: absolute;
208
106
  top: 100%;
@@ -214,7 +112,7 @@ const componentId = `i18n-switcher-${Math.random().toString(36).substring(2, 9)}
214
112
  padding: 0;
215
113
  margin: 4px 0 0 0;
216
114
  min-width: 150px;
217
- box-shadow: 0 2px 8px rgba(0,0,0,0.15);
115
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
218
116
  }
219
117
 
220
118
  .i18n-switcher-dropdown li {
@@ -241,4 +139,3 @@ const componentId = `i18n-switcher-${Math.random().toString(36).substring(2, 9)}
241
139
  background-color: #f0f0f0;
242
140
  }
243
141
  </style>
244
-
@@ -1,61 +1,13 @@
1
1
  ---
2
- import type { Params } from '@i18n-micro/types'
3
- import { useI18n } from '../utils'
2
+ import { resolveI18nT, type I18nTProps } from '../utils'
4
3
 
5
- interface Props {
6
- keypath: string
7
- plural?: number | string
8
- params?: Params
9
- defaultValue?: string
4
+ interface Props extends Omit<I18nTProps, 'customPluralRule'> {
10
5
  tag?: string
11
- html?: boolean
12
- number?: number | string
13
- date?: Date | string | number
14
- relativeDate?: Date | string | number
6
+ [key: string]: unknown
15
7
  }
16
8
 
17
- const { keypath, plural, params = {}, defaultValue = '', tag = 'span', html: renderHtml = false, number, date, relativeDate } = Astro.props
18
-
19
- const { t, tc, tn, td, tdr } = useI18n(Astro)
20
-
21
- let translation: string = ''
22
-
23
- // Handle number formatting
24
- if (number !== undefined) {
25
- const numberValue = Number(number)
26
- const formattedNumber = tn(numberValue)
27
- translation = t(keypath, { number: formattedNumber, ...params }, defaultValue)?.toString() || defaultValue || keypath
28
- }
29
- // Handle date formatting
30
- else if (date !== undefined) {
31
- const formattedDate = td(date)
32
- translation = t(keypath, { date: formattedDate, ...params }, defaultValue)?.toString() || defaultValue || keypath
33
- }
34
- // Handle relative date formatting
35
- else if (relativeDate !== undefined) {
36
- const formattedRelativeDate = tdr(relativeDate)
37
- translation = t(keypath, { relativeDate: formattedRelativeDate, ...params }, defaultValue)?.toString() || defaultValue || keypath
38
- }
39
- // Handle pluralization
40
- else if (plural !== undefined) {
41
- const count = Number.parseInt(plural.toString(), 10)
42
- translation = tc(keypath, { count, ...params }, defaultValue)
43
- }
44
- // Regular translation
45
- else {
46
- translation = t(keypath, params, defaultValue)?.toString() || defaultValue || keypath
47
- }
9
+ const { keypath, plural, params, defaultValue, tag: Tag = 'span', html = false, hideIfEmpty, number, date, relativeDate, ...attrs } = Astro.props
10
+ const text = resolveI18nT(Astro, { keypath, plural, params, defaultValue, html, hideIfEmpty, number, date, relativeDate })
48
11
  ---
49
12
 
50
- {renderHtml ? (
51
- <Fragment set:html={`<${tag}>${translation}</${tag}>`} />
52
- ) : tag === 'span' ? (
53
- <span>{translation}</span>
54
- ) : tag === 'div' ? (
55
- <div>{translation}</div>
56
- ) : tag === 'p' ? (
57
- <p>{translation}</p>
58
- ) : (
59
- <span>{translation}</span>
60
- )}
61
-
13
+ {text === null ? defaultValue : html ? <Tag {...attrs} set:html={text} /> : <Tag {...attrs}>{text}</Tag>}
package/src/composer.ts CHANGED
@@ -1,135 +1,45 @@
1
- import { BaseI18n, type DateTimeFormatsConfig, type NumberFormatsConfig, type TranslationStorage } from '@i18n-micro/core'
2
- import type { PluralFunc, Translations } from '@i18n-micro/types'
1
+ import { I18n, type I18nOptions } from '@i18n-micro/runtime'
2
+ import type { Translations } from '@i18n-micro/types'
3
3
 
4
- export interface AstroI18nOptions {
5
- locale: string
6
- fallbackLocale?: string
7
- messages?: Record<string, Translations>
8
- plural?: PluralFunc
9
- missingWarn?: boolean
10
- missingHandler?: (locale: string, key: string, routeName: string) => void
11
- numberFormats?: NumberFormatsConfig
12
- datetimeFormats?: DateTimeFormatsConfig
13
- _storage?: TranslationStorage
14
- }
15
-
16
- export class AstroI18n extends BaseI18n {
17
- private _locale: string
18
- private _fallbackLocale: string
19
- private _currentRoute: string
4
+ export type AstroI18nOptions = I18nOptions
20
5
 
21
- public readonly storage: TranslationStorage
22
-
23
- private initialMessages: Record<string, Translations> = {}
6
+ /** The runtime instance, plus what Astro pages use on top: per-route reads and a reset that keeps `messages`. */
7
+ export class AstroI18n extends I18n {
8
+ private initialMessages: Record<string, Translations>
9
+ private initialRouteMessages: Record<string, Record<string, Translations>>
24
10
 
25
11
  constructor(options: AstroI18nOptions) {
26
- const storage: TranslationStorage = options._storage || {
27
- translations: new Map<string, Translations>(),
28
- }
29
-
30
- super({
31
- storage,
32
- plural: options.plural,
33
- missingWarn: options.missingWarn,
34
- missingHandler: options.missingHandler,
35
- numberFormats: options.numberFormats,
36
- datetimeFormats: options.datetimeFormats,
37
- })
38
-
39
- this.storage = storage
40
- this._locale = options.locale
41
- this._fallbackLocale = options.fallbackLocale || options.locale
42
- this._currentRoute = 'index'
43
-
44
- if (options.messages) {
45
- this.initialMessages = { ...options.messages }
46
- for (const [lang, msgs] of Object.entries(options.messages)) {
47
- this.helper.loadTranslations(lang, msgs)
48
- }
49
- }
50
- }
51
-
52
- private cloneStorage(source: TranslationStorage): TranslationStorage {
53
- const translations = new Map<string, Translations>()
54
- for (const [key, value] of source.translations) {
55
- translations.set(key, { ...value })
56
- }
57
- return { translations }
58
- }
59
-
60
- public clone(newLocale?: string): AstroI18n {
61
- const isolatedStorage = this.cloneStorage(this.storage)
62
-
63
- return new AstroI18n({
64
- locale: newLocale || this._locale,
65
- fallbackLocale: this._fallbackLocale,
66
- plural: this.pluralFunc,
67
- missingWarn: this.missingWarn,
68
- missingHandler: this.missingHandler,
69
- numberFormats: this.formatter.getNumberFormats(),
70
- datetimeFormats: this.formatter.getDateTimeFormats(),
71
- _storage: isolatedStorage,
72
- })
73
- }
74
-
75
- get locale(): string {
76
- return this._locale
77
- }
78
-
79
- set locale(val: string) {
80
- this._locale = val
12
+ super(options)
13
+ const parent = options.parent as AstroI18n | undefined
14
+ this.initialMessages = parent?.initialMessages ?? { ...options.messages }
15
+ this.initialRouteMessages =
16
+ parent?.initialRouteMessages ??
17
+ Object.fromEntries(Object.entries(options.routeMessages ?? {}).map(([route, locales]) => [route, { ...locales }]))
81
18
  }
82
19
 
83
- get fallbackLocale(): string {
84
- return this._fallbackLocale
20
+ /** Dictionaries loaded after the constructor that `clearCache` keeps too: a directory read at runtime. */
21
+ public keepMessages(messages: Record<string, Translations>, routeMessages: Record<string, Record<string, Translations>>): void {
22
+ this.initialMessages = { ...this.initialMessages, ...messages }
23
+ const routes = { ...this.initialRouteMessages }
24
+ for (const [route, locales] of Object.entries(routeMessages)) routes[route] = { ...routes[route], ...locales }
25
+ this.initialRouteMessages = routes
85
26
  }
86
27
 
87
- set fallbackLocale(val: string) {
88
- this._fallbackLocale = val
89
- }
90
-
91
- setRoute(routeName: string): void {
92
- this._currentRoute = routeName
93
- }
94
-
95
- public getLocale(): string {
96
- return this._locale
97
- }
98
-
99
- public getFallbackLocale(): string {
100
- return this._fallbackLocale
101
- }
102
-
103
- public getRoute(): string {
104
- return this._currentRoute
28
+ /** The `localeIso` option: what an island needs to plural in another locale. */
29
+ public getLocaleIso(): Record<string, string> {
30
+ return this.localeIso
105
31
  }
106
32
 
107
33
  public getRouteTranslations(locale: string, routeName: string): Translations | null {
108
- const cacheKey = `${locale}:${routeName}`
109
- return this.storage.translations.get(cacheKey) ?? null
110
- }
111
-
112
- public addTranslations(locale: string, translations: Translations, merge = true): void {
113
- super.loadTranslationsCore(locale, translations, merge)
114
- }
115
-
116
- public addRouteTranslations(locale: string, routeName: string, translations: Translations, merge = true): void {
117
- super.loadRouteTranslationsCore(locale, routeName, translations, merge)
34
+ return this.helper.getCache(locale, routeName) ?? null
118
35
  }
119
36
 
120
37
  public mergeTranslations(locale: string, routeName: string, translations: Translations): void {
121
- this.helper.mergeTranslation(locale, routeName, translations, true)
38
+ this.addRouteTranslations(locale, routeName, translations)
122
39
  }
123
40
 
124
41
  public override clearCache(): void {
125
- const initialMessages = { ...this.initialMessages }
126
-
127
42
  super.clearCache()
128
-
129
- if (Object.keys(initialMessages).length > 0) {
130
- for (const [lang, msgs] of Object.entries(initialMessages)) {
131
- this.helper.loadTranslations(lang, msgs)
132
- }
133
- }
43
+ this.loadMessages(this.initialMessages, this.initialRouteMessages)
134
44
  }
135
45
  }
package/src/env.d.ts CHANGED
@@ -1,7 +1,9 @@
1
+ // It's loaded directly by Astro via entrypoint in integration config
1
2
  /// <reference types="astro/client" />
2
3
 
3
4
  import type { AstroI18n } from './composer'
4
5
  import type { Locale } from '@i18n-micro/types'
6
+ import type { MiddlewareHandler } from 'astro'
5
7
  import type { I18nRoutingStrategy } from './router/types'
6
8
 
7
9
  declare global {
@@ -11,8 +13,13 @@ declare global {
11
13
  locale: string
12
14
  defaultLocale: string
13
15
  locales: Locale[]
16
+ /** The page's URL: the original one after `Astro.rewrite`, the page's one in a server island. */
14
17
  currentUrl: URL
15
18
  routingStrategy?: I18nRoutingStrategy
19
+ /** Astro's `base`, no trailing slash. */
20
+ i18nBase?: string
21
+ /** The middleware that handled this request. */
22
+ i18nHandler?: MiddlewareHandler
16
23
  }
17
24
  }
18
25
  }
package/src/index.ts CHANGED
@@ -2,17 +2,13 @@
2
2
  import './env.d'
3
3
 
4
4
  // Re-export utilities from core
5
- export { defaultPlural, FormatService, interpolate } from '@i18n-micro/core'
5
+ export { defaultPlural, FormatService, interpolate, localeIsoMap } from '@i18n-micro/core'
6
6
  // Re-export types from @i18n-micro/types
7
7
  export type { CleanTranslation, Getter, Locale, LocaleCode, Params, PluralFunc, Translations } from '@i18n-micro/types'
8
8
  export { AstroI18n, type AstroI18nOptions } from './composer'
9
9
  // Export integration options type
10
10
  export type { I18nIntegrationOptions } from './integration'
11
11
  export { createI18n, i18nIntegration } from './integration'
12
- export { getGlobalRoutingStrategy, runWithRoutingStrategy, setGlobalRoutingStrategy } from './routing-context'
13
- export type { LoadedTranslations, LoadTranslationsOptions } from './load-translations'
14
- // Export translation loading utilities
15
- export { loadTranslationsFromDir, loadTranslationsIntoI18n } from './load-translations'
16
12
  export type { I18nMiddlewareOptions } from './middleware'
17
13
  export { createI18nMiddleware, detectLocale } from './middleware'
18
14
  export { createAstroRouterAdapter } from './router/adapter'
@@ -31,4 +27,3 @@ export {
31
27
  useI18n,
32
28
  useLocaleHead,
33
29
  } from './utils'
34
- // It's loaded directly by Astro via entrypoint in integration config