@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,127 +1,12 @@
1
- // Preact может использовать React Context API, так как Preact совместим с React
2
-
3
- import { defaultPlural, FormatService } from '@i18n-micro/core'
4
- import type { CleanTranslation, Params, TranslationKey } from '@i18n-micro/types'
5
- import type { ComponentChildren } from 'preact'
6
- import { createContext, createElement } from 'preact'
7
- import { useContext, useMemo, useState } from 'preact/hooks'
8
- import type { I18nClientProps } from '../utils'
9
- import { hasTranslation, type I18nState, translate } from './core'
10
-
11
- const formatter = new FormatService()
12
-
13
- const I18nContext = createContext<I18nState | null>(null)
14
-
15
- /**
16
- * Провайдер для i18n в Preact островах
17
- */
18
- export const I18nProvider = ({ children, value }: { children: ComponentChildren; value: I18nClientProps }) => {
19
- const [state] = useState<I18nState>(() => ({
20
- locale: value.locale,
21
- fallbackLocale: value.fallbackLocale,
22
- translations: value.translations,
23
- currentRoute: value.currentRoute,
24
- }))
25
-
26
- return createElement(I18nContext.Provider, { value: state }, children)
27
- }
28
-
29
- /**
30
- * Хук для использования i18n в Preact компонентах
31
- */
32
- export function useAstroI18n() {
33
- const state = useContext(I18nContext)
34
- if (!state) {
35
- throw new Error('useAstroI18n must be used within an I18nProvider')
36
- }
37
-
38
- const t = useMemo(
39
- () =>
40
- (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string): CleanTranslation => {
41
- return translate(state, key as string, params, defaultValue, routeName)
42
- },
43
- [state],
44
- )
45
-
46
- const ts = useMemo(
47
- () =>
48
- (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string => {
49
- const value = t(key, params, defaultValue, routeName)
50
- return value?.toString() ?? defaultValue ?? (key as string)
51
- },
52
- [t],
53
- )
54
-
55
- const tc = useMemo(
56
- () =>
57
- (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
58
- const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
59
-
60
- if (countValue === undefined) {
61
- return defaultValue ?? (key as string)
62
- }
63
-
64
- const getter = (k: TranslationKey, p?: Params, dv?: string) => {
65
- return t(k, p, dv)
66
- }
67
-
68
- const result = defaultPlural(key, Number.parseInt(countValue.toString(), 10), params, state.locale, getter)
69
-
70
- return result ?? defaultValue ?? (key as string)
71
- },
72
- [t, state],
73
- )
74
-
75
- const tn = useMemo(
76
- () =>
77
- (value: number, options?: Intl.NumberFormatOptions): string => {
78
- return formatter.formatNumber(value, state.locale, options)
79
- },
80
- [state.locale],
81
- )
82
-
83
- const td = useMemo(
84
- () =>
85
- (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
86
- return formatter.formatDate(value, state.locale, options)
87
- },
88
- [state.locale],
89
- )
90
-
91
- const tdr = useMemo(
92
- () =>
93
- (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
94
- return formatter.formatRelativeTime(value, state.locale, options)
95
- },
96
- [state.locale],
97
- )
98
-
99
- const has = useMemo(
100
- () =>
101
- (key: TranslationKey, routeName?: string): boolean => {
102
- return hasTranslation(state, key as string, routeName)
103
- },
104
- [state],
105
- )
106
-
107
- return {
108
- // Translation methods
109
- t,
110
- ts,
111
- tc,
112
- tn,
113
- td,
114
- tdr,
115
- has,
116
-
117
- // Locale state
118
- locale: state.locale,
119
- fallbackLocale: state.fallbackLocale,
120
- currentRoute: state.currentRoute,
121
-
122
- // Route management (read-only в клиентских островах)
123
- getRoute: (): string => {
124
- return state.currentRoute
125
- },
126
- }
127
- }
1
+ import { type ComponentChildren, createContext, createElement, type PreactContext, type VNode } from 'preact'
2
+ import { useCallback, useContext, useMemo, useState } from 'preact/hooks'
3
+ import { createIslandBinding, type I18nContextValue } from './core'
4
+
5
+ export const { I18nProvider, useAstroI18n } = /*#__PURE__*/ createIslandBinding<ComponentChildren, VNode, PreactContext<I18nContextValue | null>>({
6
+ createContext,
7
+ createElement,
8
+ useCallback,
9
+ useContext,
10
+ useMemo,
11
+ useState,
12
+ })
@@ -1,123 +1,11 @@
1
- import { defaultPlural, FormatService } from '@i18n-micro/core'
2
- import type { CleanTranslation, Params, TranslationKey } from '@i18n-micro/types'
3
- import React, { createContext, useContext, useMemo, useState } from 'react'
4
- import type { I18nClientProps } from '../utils'
5
- import { hasTranslation, type I18nState, translate } from './core'
6
-
7
- const formatter = new FormatService()
8
-
9
- const I18nContext = createContext<I18nState | null>(null)
10
-
11
- /**
12
- * Провайдер для i18n в React островах
13
- */
14
- export function I18nProvider({ children, value }: { children: React.ReactNode; value: I18nClientProps }): React.ReactElement {
15
- const [state] = useState<I18nState>(() => ({
16
- locale: value.locale,
17
- fallbackLocale: value.fallbackLocale,
18
- translations: value.translations,
19
- currentRoute: value.currentRoute,
20
- }))
21
-
22
- return React.createElement(I18nContext.Provider, { value: state }, children)
23
- }
24
-
25
- /**
26
- * Хук для использования i18n в React компонентах
27
- */
28
- export function useAstroI18n() {
29
- const state = useContext(I18nContext)
30
- if (!state) {
31
- throw new Error('useAstroI18n must be used within an I18nProvider')
32
- }
33
-
34
- const t = useMemo(
35
- () =>
36
- (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string): CleanTranslation => {
37
- return translate(state, key as string, params, defaultValue, routeName)
38
- },
39
- [state],
40
- )
41
-
42
- const ts = useMemo(
43
- () =>
44
- (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string => {
45
- const value = t(key, params, defaultValue, routeName)
46
- return value?.toString() ?? defaultValue ?? (key as string)
47
- },
48
- [t],
49
- )
50
-
51
- const tc = useMemo(
52
- () =>
53
- (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
54
- const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
55
-
56
- if (countValue === undefined) {
57
- return defaultValue ?? (key as string)
58
- }
59
-
60
- const getter = (k: TranslationKey, p?: Params, dv?: string) => {
61
- return t(k, p, dv)
62
- }
63
-
64
- const result = defaultPlural(key, Number.parseInt(countValue.toString(), 10), params, state.locale, getter)
65
-
66
- return result ?? defaultValue ?? (key as string)
67
- },
68
- [t, state],
69
- )
70
-
71
- const tn = useMemo(
72
- () =>
73
- (value: number, options?: Intl.NumberFormatOptions): string => {
74
- return formatter.formatNumber(value, state.locale, options)
75
- },
76
- [state.locale],
77
- )
78
-
79
- const td = useMemo(
80
- () =>
81
- (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
82
- return formatter.formatDate(value, state.locale, options)
83
- },
84
- [state.locale],
85
- )
86
-
87
- const tdr = useMemo(
88
- () =>
89
- (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
90
- return formatter.formatRelativeTime(value, state.locale, options)
91
- },
92
- [state.locale],
93
- )
94
-
95
- const has = useMemo(
96
- () =>
97
- (key: TranslationKey, routeName?: string): boolean => {
98
- return hasTranslation(state, key as string, routeName)
99
- },
100
- [state],
101
- )
102
-
103
- return {
104
- // Translation methods
105
- t,
106
- ts,
107
- tc,
108
- tn,
109
- td,
110
- tdr,
111
- has,
112
-
113
- // Locale state
114
- locale: state.locale,
115
- fallbackLocale: state.fallbackLocale,
116
- currentRoute: state.currentRoute,
117
-
118
- // Route management (read-only в клиентских островах)
119
- getRoute: (): string => {
120
- return state.currentRoute
121
- },
122
- }
123
- }
1
+ import { type Context, createContext, createElement, type ReactElement, type ReactNode, useCallback, useContext, useMemo, useState } from 'react'
2
+ import { createIslandBinding, type I18nContextValue } from './core'
3
+
4
+ export const { I18nProvider, useAstroI18n } = /*#__PURE__*/ createIslandBinding<ReactNode, ReactElement, Context<I18nContextValue | null>>({
5
+ createContext,
6
+ createElement,
7
+ useCallback,
8
+ useContext,
9
+ useMemo,
10
+ useState,
11
+ })
@@ -1,21 +1,13 @@
1
- import { defaultPlural, FormatService } from '@i18n-micro/core'
2
- import type { CleanTranslation, Params, TranslationKey } from '@i18n-micro/types'
3
1
  import { get, type Writable, writable } from 'svelte/store'
4
2
  import type { I18nClientProps } from '../utils'
5
- import { hasTranslation, type I18nState, translate } from './core'
6
-
7
- const formatter = new FormatService()
3
+ import { createIslandApi, type I18nState, withLocale } from './core'
8
4
 
9
5
  /**
10
- * Creates a Svelte store for i18n state
6
+ * Creates a Svelte store for i18n state. An island kept by `transition:persist` follows its new
7
+ * props with `$: store.set(i18n)` (`$effect(() => store.set(i18n))` with runes).
11
8
  */
12
9
  export function createI18nStore(props: I18nClientProps): Writable<I18nState> {
13
- return writable<I18nState>({
14
- locale: props.locale,
15
- fallbackLocale: props.fallbackLocale,
16
- translations: props.translations,
17
- currentRoute: props.currentRoute,
18
- })
10
+ return writable<I18nState>(props)
19
11
  }
20
12
 
21
13
  /**
@@ -25,63 +17,11 @@ export function createI18nStore(props: I18nClientProps): Writable<I18nState> {
25
17
  export function useAstroI18n(store: Writable<I18nState>) {
26
18
  const getState = () => get(store)
27
19
 
28
- const t = (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string): CleanTranslation => {
29
- return translate(getState(), key as string, params, defaultValue, routeName)
30
- }
31
-
32
- const ts = (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string => {
33
- const value = t(key, params, defaultValue, routeName)
34
- return value?.toString() ?? defaultValue ?? (key as string)
35
- }
36
-
37
- const tc = (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
38
- const state = getState()
39
- const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
40
-
41
- if (countValue === undefined) {
42
- return defaultValue ?? (key as string)
43
- }
44
-
45
- const getter = (k: TranslationKey, p?: Params, dv?: string) => {
46
- return t(k, p, dv)
47
- }
48
-
49
- const result = defaultPlural(key, Number.parseInt(countValue.toString(), 10), params, state.locale, getter)
50
-
51
- return result ?? defaultValue ?? (key as string)
52
- }
53
-
54
- const tn = (value: number, options?: Intl.NumberFormatOptions): string => {
55
- const state = getState()
56
- return formatter.formatNumber(value, state.locale, options)
57
- }
58
-
59
- const td = (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
60
- const state = getState()
61
- return formatter.formatDate(value, state.locale, options)
62
- }
63
-
64
- const tdr = (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
65
- const state = getState()
66
- return formatter.formatRelativeTime(value, state.locale, options)
67
- }
68
-
69
- const has = (key: TranslationKey, routeName?: string): boolean => {
70
- return hasTranslation(getState(), key as string, routeName)
71
- }
72
-
73
20
  return {
74
21
  // Store for reactivity in templates (use $i18nStore in templates)
75
22
  store,
76
23
 
77
- // Translation methods
78
- t,
79
- ts,
80
- tc,
81
- tn,
82
- td,
83
- tdr,
84
- has,
24
+ ...createIslandApi(getState),
85
25
 
86
26
  // Getters for current state (for use in scripts)
87
27
  get locale() {
@@ -96,13 +36,10 @@ export function useAstroI18n(store: Writable<I18nState>) {
96
36
 
97
37
  // Route management
98
38
  setLocale: (locale: string) => {
99
- store.update((state) => ({ ...state, locale }))
39
+ store.update((state) => withLocale(state, locale))
100
40
  },
101
41
  setRoute: (routeName: string) => {
102
42
  store.update((state) => ({ ...state, currentRoute: routeName }))
103
43
  },
104
- getRoute: (): string => {
105
- return getState().currentRoute
106
- },
107
44
  }
108
45
  }
package/src/client/vue.ts CHANGED
@@ -1,24 +1,22 @@
1
- import { defaultPlural, FormatService } from '@i18n-micro/core'
2
- import type { CleanTranslation, Params, TranslationKey } from '@i18n-micro/types'
3
- import { computed, type InjectionKey, inject, provide, type Ref, ref } from 'vue'
1
+ import { computed, type InjectionKey, inject, type MaybeRefOrGetter, provide, type Ref, shallowRef, toValue, watch } from 'vue'
4
2
  import type { I18nClientProps } from '../utils'
5
- import { hasTranslation, type I18nState, translate } from './core'
6
-
7
- const formatter = new FormatService()
3
+ import { createIslandApi, type I18nState, withLocale } from './core'
8
4
 
9
5
  const I18nSymbol = Symbol('i18n-astro') as InjectionKey<Ref<I18nState>>
10
6
 
11
7
  /**
12
- * Initializes the i18n provider for a Vue island
13
- * Call in the island's root component
8
+ * Initializes the i18n provider for a Vue island. Call in the island's root component, with a
9
+ * getter (`() => props.i18n`) so an island kept by `transition:persist` follows its new props.
10
+ * `shallowRef`: translations are never edited in place, and deep tracking costs 11× on every `t`.
14
11
  */
15
- export function provideI18n(props: I18nClientProps): Ref<I18nState> {
16
- const state = ref<I18nState>({
17
- locale: props.locale,
18
- fallbackLocale: props.fallbackLocale,
19
- translations: props.translations,
20
- currentRoute: props.currentRoute,
21
- })
12
+ export function provideI18n(props: MaybeRefOrGetter<I18nClientProps>): Ref<I18nState> {
13
+ const state = shallowRef<I18nState>(toValue(props))
14
+ watch(
15
+ () => toValue(props),
16
+ (next) => {
17
+ state.value = next
18
+ },
19
+ )
22
20
  provide(I18nSymbol, state)
23
21
  return state
24
22
  }
@@ -31,82 +29,29 @@ export function useAstroI18n() {
31
29
  if (!state) {
32
30
  throw new Error('useAstroI18n must be used within a component that calls provideI18n')
33
31
  }
34
-
35
- const t = (key: TranslationKey, params?: Params, defaultValue?: string | null, routeName?: string): CleanTranslation => {
36
- return translate(state.value, key as string, params, defaultValue, routeName)
32
+ const setLocale = (locale: string) => {
33
+ state.value = withLocale(state.value, locale)
37
34
  }
38
-
39
- const ts = (key: TranslationKey, params?: Params, defaultValue?: string, routeName?: string): string => {
40
- const value = t(key, params, defaultValue, routeName)
41
- return value?.toString() ?? defaultValue ?? (key as string)
42
- }
43
-
44
- const tc = (key: TranslationKey, count: number | Params, defaultValue?: string): string => {
45
- const { count: countValue, ...params } = typeof count === 'number' ? { count } : count
46
-
47
- if (countValue === undefined) {
48
- return defaultValue ?? (key as string)
49
- }
50
-
51
- const getter = (k: TranslationKey, p?: Params, dv?: string) => {
52
- return t(k, p, dv)
53
- }
54
-
55
- const result = defaultPlural(key, Number.parseInt(countValue.toString(), 10), params, state.value.locale, getter)
56
-
57
- return result ?? defaultValue ?? (key as string)
58
- }
59
-
60
- const tn = (value: number, options?: Intl.NumberFormatOptions): string => {
61
- return formatter.formatNumber(value, state.value.locale, options)
62
- }
63
-
64
- const td = (value: Date | number | string, options?: Intl.DateTimeFormatOptions): string => {
65
- return formatter.formatDate(value, state.value.locale, options)
66
- }
67
-
68
- const tdr = (value: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string => {
69
- return formatter.formatRelativeTime(value, state.value.locale, options)
70
- }
71
-
72
- const has = (key: TranslationKey, routeName?: string): boolean => {
73
- return hasTranslation(state.value, key as string, routeName)
35
+ const setRoute = (currentRoute: string) => {
36
+ state.value = { ...state.value, currentRoute }
74
37
  }
75
38
 
76
39
  return {
77
- // Translation methods
78
- t,
79
- ts,
80
- tc,
81
- tn,
82
- td,
83
- tdr,
84
- has,
40
+ ...createIslandApi(() => state.value),
85
41
 
86
42
  // Reactive locale state
87
43
  locale: computed({
88
44
  get: () => state.value.locale,
89
- set: (val: string) => {
90
- state.value = { ...state.value, locale: val }
91
- },
45
+ set: setLocale,
92
46
  }),
93
47
  fallbackLocale: computed(() => state.value.fallbackLocale),
94
48
  currentRoute: computed({
95
49
  get: () => state.value.currentRoute,
96
- set: (val: string) => {
97
- state.value = { ...state.value, currentRoute: val }
98
- },
50
+ set: setRoute,
99
51
  }),
100
52
 
101
53
  // Route management
102
- setLocale: (locale: string) => {
103
- state.value = { ...state.value, locale }
104
- },
105
- setRoute: (routeName: string) => {
106
- state.value = { ...state.value, currentRoute: routeName }
107
- },
108
- getRoute: (): string => {
109
- return state.value.currentRoute
110
- },
54
+ setLocale,
55
+ setRoute,
111
56
  }
112
57
  }
@@ -1,6 +1,5 @@
1
1
  ---
2
- import type { I18nRoutingStrategy } from '../router/types'
3
- import { useI18n } from '../utils'
2
+ import { resolveLinkHref } from '../utils'
4
3
 
5
4
  interface Props {
6
5
  href: string
@@ -10,64 +9,8 @@ interface Props {
10
9
  }
11
10
 
12
11
  const { href, locale, class: className, ...attrs } = Astro.props
13
- const { locale: currentLocale, defaultLocale, locales } = useI18n(Astro)
14
- const localeCodes = locales.map((l) => l.code)
15
- const currentPath = Astro.url.pathname
16
-
17
- // Get routing strategy from locals
18
- // @ts-expect-error
19
- const routingStrategy: I18nRoutingStrategy | null = Astro.locals.routingStrategy || null
20
-
21
- // Get current locale from path or use detected locale
22
- const targetLocale = locale || currentLocale
23
-
24
- // Helper to remove locale from path
25
- const removeLocale = (path: string, codes: string[]): string => {
26
- if (routingStrategy?.removeLocaleFromPath) {
27
- return routingStrategy.removeLocaleFromPath(path, codes)
28
- }
29
- // Fallback
30
- const segments = path.split('/').filter(Boolean)
31
- const firstSegment = segments[0]
32
- if (firstSegment && codes.includes(firstSegment)) {
33
- segments.shift()
34
- }
35
- return `/${segments.join('/')}`
36
- }
37
-
38
- // Remove locale from current path to get base path
39
- const basePath = removeLocale(currentPath, localeCodes)
40
-
41
- // If href is relative, resolve it relative to current base path
42
- let resolvedHref = href
43
- if (href.startsWith('/')) {
44
- // Absolute path - remove locale if present and use as base
45
- resolvedHref = removeLocale(href, localeCodes)
46
- } else {
47
- // Relative path - combine with current base path
48
- resolvedHref = basePath === '/' ? `/${href}` : `${basePath}/${href}`
49
- }
50
-
51
- // Localize the href
52
- let localizedHref = resolvedHref
53
- if (routingStrategy?.localizePath) {
54
- localizedHref = routingStrategy.localizePath(resolvedHref, targetLocale, localeCodes, defaultLocale)
55
- } else {
56
- // Fallback: basic localization
57
- const cleanPath = resolvedHref.replace(/^\//, '').replace(/\/$/, '') || ''
58
- const segments = cleanPath.split('/').filter(Boolean)
59
- const firstSegment = segments[0]
60
- if (firstSegment && localeCodes.includes(firstSegment)) {
61
- segments.shift()
62
- }
63
- if (targetLocale !== defaultLocale) {
64
- segments.unshift(targetLocale)
65
- }
66
- localizedHref = `/${segments.join('/')}`
67
- }
68
12
  ---
69
13
 
70
- <a href={localizedHref} class={className} {...attrs}>
14
+ <a href={resolveLinkHref(Astro, href, locale)} class={className} {...attrs}>
71
15
  <slot />
72
16
  </a>
73
-