@i18n-micro/core 1.0.28 → 1.1.1
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.
- package/dist/base.d.ts +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.mjs +141 -363
- package/dist/translation.d.ts +16 -17
- package/package.json +3 -3
- package/src/base.ts +4 -4
- package/src/helpers.ts +7 -6
- package/src/index.ts +2 -4
- package/src/translation.ts +71 -181
- package/tests/base.test.ts +11 -36
- package/dist/route-service.d.ts +0 -40
- package/src/route-service.ts +0 -474
- package/tests/route-service.test.ts +0 -397
package/dist/translation.d.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { Translations } from '@i18n-micro/types';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Bare Metal: Простое хранилище переводов без Ref, useState, devalue.
|
|
4
|
+
* Ключ Map: locale (general) или locale:routeName (page-specific).
|
|
5
|
+
*/
|
|
6
|
+
export interface TranslationStorage {
|
|
7
|
+
translations: Map<string, Translations>;
|
|
4
8
|
}
|
|
5
|
-
export
|
|
6
|
-
generalLocaleCache: RefLike<Record<string, Translations>> | Record<string, Translations>;
|
|
7
|
-
routeLocaleCache: RefLike<Record<string, Translations>> | Record<string, Translations>;
|
|
8
|
-
dynamicTranslationsCaches: RefLike<Record<string, Translations>[]> | Record<string, Translations>[];
|
|
9
|
-
serverTranslationCache: RefLike<Record<string, Map<string, Translations | unknown>>> | Record<string, Map<string, Translations | unknown>>;
|
|
10
|
-
}
|
|
11
|
-
export declare function useTranslationHelper(caches?: TranslationCache): {
|
|
9
|
+
export declare function useTranslationHelper(storage?: TranslationStorage): {
|
|
12
10
|
hasCache(locale: string, page: string): boolean;
|
|
13
|
-
getCache(locale: string, routeName: string):
|
|
14
|
-
setCache(
|
|
15
|
-
|
|
16
|
-
mergeGlobalTranslation(locale: string, newTranslations: Translations, force?: boolean): void;
|
|
11
|
+
getCache(locale: string, routeName: string): Translations | undefined;
|
|
12
|
+
setCache(_locale: string, _routeName: string, _cache: Map<string, unknown>): void;
|
|
13
|
+
hasTranslation(locale: string, key: string): boolean;
|
|
17
14
|
hasGeneralTranslation(locale: string): boolean;
|
|
18
15
|
hasPageTranslation(locale: string, routeName: string): boolean;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
getTranslation<T = unknown>(locale: string, routeName: string, key: string): T | null;
|
|
17
|
+
loadTranslations(locale: string, data: Translations): void;
|
|
18
|
+
setTranslations(locale: string, data: Translations): void;
|
|
19
|
+
loadPageTranslations(locale: string, routeName: string, data: Translations): void;
|
|
20
|
+
mergeTranslation(locale: string, routeName: string, newTranslations: Translations, _force?: boolean): void;
|
|
21
|
+
mergeGlobalTranslation(locale: string, newTranslations: Translations, _force?: boolean): void;
|
|
23
22
|
clearCache(): void;
|
|
24
23
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i18n-micro/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": "s00d/nuxt-i18n-micro",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
},
|
|
23
23
|
"keywords": [],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@i18n-micro/types": "1.0
|
|
25
|
+
"@i18n-micro/types": "1.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"vite": "^7.
|
|
28
|
+
"vite": "^7.3.1",
|
|
29
29
|
"vite-plugin-dts": "^4.5.4"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
package/src/base.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useTranslationHelper, type
|
|
1
|
+
import { useTranslationHelper, type TranslationStorage } from './translation'
|
|
2
2
|
import { FormatService } from './format-service'
|
|
3
3
|
import { interpolate, defaultPlural } from './helpers'
|
|
4
4
|
import type {
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
} from '@i18n-micro/types'
|
|
13
13
|
|
|
14
14
|
export interface BaseI18nOptions {
|
|
15
|
-
|
|
15
|
+
storage?: TranslationStorage
|
|
16
16
|
plural?: PluralFunc
|
|
17
17
|
missingWarn?: boolean
|
|
18
18
|
missingHandler?: (locale: string, key: string, routeName: string) => void
|
|
@@ -41,7 +41,7 @@ export abstract class BaseI18n {
|
|
|
41
41
|
public enablePreviousPageFallback: boolean
|
|
42
42
|
|
|
43
43
|
constructor(options: BaseI18nOptions = {}) {
|
|
44
|
-
this.helper = useTranslationHelper(options.
|
|
44
|
+
this.helper = useTranslationHelper(options.storage)
|
|
45
45
|
this.formatter = new FormatService()
|
|
46
46
|
this.pluralFunc = options.plural || defaultPlural
|
|
47
47
|
this.missingWarn = options.missingWarn ?? true
|
|
@@ -226,7 +226,7 @@ export abstract class BaseI18n {
|
|
|
226
226
|
this.helper.mergeGlobalTranslation(locale, translations, true)
|
|
227
227
|
}
|
|
228
228
|
else {
|
|
229
|
-
this.helper.
|
|
229
|
+
this.helper.setTranslations(locale, translations)
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
|
package/src/helpers.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { Params, Strategies, PluralFunc, Getter, TranslationKey } from '@i18n-micro/types'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
let result = template
|
|
3
|
+
const RE_TOKEN = /\{(\w+)\}/g
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
5
|
+
export function interpolate(template: string, params: Params): string {
|
|
6
|
+
if (!params) return template
|
|
9
7
|
|
|
10
|
-
return
|
|
8
|
+
return template.replace(RE_TOKEN, (_, key) => {
|
|
9
|
+
const value = params[key]
|
|
10
|
+
return value !== undefined ? String(value) : `{${key}}`
|
|
11
|
+
})
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export function withPrefixStrategy(strategy: Strategies) {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { useTranslationHelper, type
|
|
2
|
-
import { RouteService } from './route-service'
|
|
1
|
+
import { useTranslationHelper, type TranslationStorage } from './translation'
|
|
3
2
|
import { FormatService } from './format-service'
|
|
4
3
|
import { interpolate, withPrefixStrategy, isNoPrefixStrategy, isPrefixStrategy, isPrefixExceptDefaultStrategy, isPrefixAndDefaultStrategy, defaultPlural } from './helpers'
|
|
5
4
|
import { BaseI18n, type BaseI18nOptions } from './base'
|
|
@@ -13,9 +12,8 @@ export {
|
|
|
13
12
|
isPrefixExceptDefaultStrategy,
|
|
14
13
|
isPrefixAndDefaultStrategy,
|
|
15
14
|
defaultPlural,
|
|
16
|
-
RouteService,
|
|
17
15
|
FormatService,
|
|
18
16
|
BaseI18n,
|
|
19
|
-
type
|
|
17
|
+
type TranslationStorage,
|
|
20
18
|
type BaseI18nOptions,
|
|
21
19
|
}
|
package/src/translation.ts
CHANGED
|
@@ -1,216 +1,106 @@
|
|
|
1
1
|
import type { Translations } from '@i18n-micro/types'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Bare Metal: Простое хранилище переводов без Ref, useState, devalue.
|
|
5
|
+
* Ключ Map: locale (general) или locale:routeName (page-specific).
|
|
6
|
+
*/
|
|
7
|
+
export interface TranslationStorage {
|
|
8
|
+
translations: Map<string, Translations>
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
routeLocaleCache: RefLike<Record<string, Translations>> | Record<string, Translations>
|
|
11
|
-
dynamicTranslationsCaches: RefLike<Record<string, Translations>[]> | Record<string, Translations>[]
|
|
12
|
-
serverTranslationCache: RefLike<Record<string, Map<string, Translations | unknown>>> | Record<string, Map<string, Translations | unknown>>
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Глобальные кэши для fallback (только для unit-тестов и обратной совместимости)
|
|
16
|
-
// НЕ используются в SSR продакшене
|
|
17
|
-
const globalGeneralLocaleCache: Record<string, Translations> = {}
|
|
18
|
-
const globalRouteLocaleCache: Record<string, Translations> = {}
|
|
19
|
-
const globalDynamicTranslationsCaches: Record<string, Translations>[] = []
|
|
20
|
-
const globalServerTranslationCache: Record<string, Map<string, Translations | unknown>> = {}
|
|
21
|
-
|
|
22
|
-
function deepClone<T>(value: T): T {
|
|
23
|
-
if (Array.isArray(value)) {
|
|
24
|
-
return JSON.parse(JSON.stringify(value)) as T
|
|
25
|
-
}
|
|
26
|
-
else if (typeof value === 'object' && value !== null) {
|
|
27
|
-
return JSON.parse(JSON.stringify(value)) as T
|
|
28
|
-
}
|
|
29
|
-
return value
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function findTranslation<T = unknown>(translations: Translations | null, key: string): T | null {
|
|
33
|
-
let value: string | number | boolean | Translations | unknown | null = translations
|
|
11
|
+
function findValue<T = unknown>(data: Translations | null | undefined, key: string): T | null {
|
|
12
|
+
if (!data || typeof key !== 'string') return null
|
|
34
13
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (translations[key]) {
|
|
40
|
-
value = translations[key]
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
const parts = key.toString().split('.')
|
|
44
|
-
for (const part of parts) {
|
|
45
|
-
if (value && typeof value === 'object' && part in value) {
|
|
46
|
-
value = (value as Translations)[part]
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
return null
|
|
50
|
-
}
|
|
14
|
+
if (key in data) {
|
|
15
|
+
const value = data[key]
|
|
16
|
+
if (typeof value === 'object' && value !== null) {
|
|
17
|
+
return value as T
|
|
51
18
|
}
|
|
19
|
+
return value as T
|
|
52
20
|
}
|
|
53
21
|
|
|
54
|
-
|
|
55
|
-
|
|
22
|
+
const parts = key.split('.')
|
|
23
|
+
let value: unknown = data
|
|
24
|
+
for (const part of parts) {
|
|
25
|
+
if (value && typeof value === 'object' && part in (value as object)) {
|
|
26
|
+
value = (value as Translations)[part]
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
56
31
|
}
|
|
57
|
-
|
|
58
32
|
return (value as T) ?? null
|
|
59
33
|
}
|
|
60
34
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return typeof refOrValue === 'object' && refOrValue !== null && 'value' in refOrValue
|
|
64
|
-
? (refOrValue as RefLike<T>).value
|
|
65
|
-
: refOrValue as T
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Вспомогательная функция для установки значения в Ref или обычный объект
|
|
69
|
-
function setValue<T extends Record<string, unknown>>(
|
|
70
|
-
refOrValue: RefLike<T> | T,
|
|
71
|
-
key: string,
|
|
72
|
-
value: T[keyof T],
|
|
73
|
-
): void {
|
|
74
|
-
const target = getValue(refOrValue)
|
|
75
|
-
;(target as Record<string, unknown>)[key] = value
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Вспомогательная функция для получения значения из Ref или обычного объекта по ключу
|
|
79
|
-
function getValueByKey<T extends Record<string, unknown>>(refOrValue: RefLike<T> | T, key: string): T[keyof T] | undefined {
|
|
80
|
-
const target = getValue(refOrValue)
|
|
81
|
-
return (target as Record<string, unknown>)[key] as T[keyof T] | undefined
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function useTranslationHelper(caches?: TranslationCache) {
|
|
85
|
-
// Используем переданные кэши или глобальные (fallback для тестов)
|
|
86
|
-
const generalLocaleCache = caches?.generalLocaleCache ?? globalGeneralLocaleCache
|
|
87
|
-
const routeLocaleCache = caches?.routeLocaleCache ?? globalRouteLocaleCache
|
|
88
|
-
const dynamicTranslationsCaches = caches?.dynamicTranslationsCaches ?? globalDynamicTranslationsCaches
|
|
89
|
-
const serverTranslationCache = caches?.serverTranslationCache ?? globalServerTranslationCache
|
|
35
|
+
export function useTranslationHelper(storage?: TranslationStorage) {
|
|
36
|
+
const translations = storage?.translations ?? new Map<string, Translations>()
|
|
90
37
|
|
|
91
38
|
return {
|
|
92
39
|
hasCache(locale: string, page: string) {
|
|
93
40
|
const cacheKey = `${locale}:${page}`
|
|
94
|
-
|
|
95
|
-
return (cache ?? new Map<string, Translations | unknown>()).size > 0
|
|
41
|
+
return translations.has(cacheKey) || translations.has(locale)
|
|
96
42
|
},
|
|
97
43
|
getCache(locale: string, routeName: string) {
|
|
98
44
|
const cacheKey = `${locale}:${routeName}`
|
|
99
|
-
return
|
|
45
|
+
return translations.get(cacheKey)
|
|
100
46
|
},
|
|
101
|
-
setCache(
|
|
102
|
-
|
|
103
|
-
setValue(serverTranslationCache, cacheKey, cache)
|
|
47
|
+
setCache(_locale: string, _routeName: string, _cache: Map<string, unknown>) {
|
|
48
|
+
// No-op for bare metal
|
|
104
49
|
},
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const existing = currentCache ?? {}
|
|
111
|
-
setValue(routeLocaleCache, cacheKey, {
|
|
112
|
-
...existing,
|
|
113
|
-
...newTranslations,
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const isDev = process.env.NODE_ENV !== 'production'
|
|
118
|
-
if (!currentCache && isDev) {
|
|
119
|
-
// Если кэша нет, выводим предупреждение в dev-режиме и ничего не делаем.
|
|
120
|
-
console.warn(`[i18n] mergeTranslation called for '${cacheKey}' which was not pre-loaded. Skipping merge. Use force: true if this is intentional.`)
|
|
50
|
+
hasTranslation(locale: string, key: string): boolean {
|
|
51
|
+
for (const [k, v] of translations) {
|
|
52
|
+
if ((k === locale || k.startsWith(`${locale}:`)) && findValue(v, key) !== null) {
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
121
55
|
}
|
|
56
|
+
return false
|
|
122
57
|
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (!force && !currentCache) {
|
|
126
|
-
console.error(`marge: route ${locale} not loaded`)
|
|
127
|
-
}
|
|
128
|
-
const existing = currentCache ?? {}
|
|
129
|
-
setValue(generalLocaleCache, locale, {
|
|
130
|
-
...existing,
|
|
131
|
-
...newTranslations,
|
|
132
|
-
})
|
|
58
|
+
hasGeneralTranslation(locale: string): boolean {
|
|
59
|
+
return translations.has(locale)
|
|
133
60
|
},
|
|
134
|
-
|
|
135
|
-
return
|
|
61
|
+
hasPageTranslation(locale: string, routeName: string): boolean {
|
|
62
|
+
return translations.has(`${locale}:${routeName}`)
|
|
136
63
|
},
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
64
|
+
getTranslation<T = unknown>(locale: string, routeName: string, key: string): T | null {
|
|
65
|
+
const routeKey = `${locale}:${routeName}`
|
|
66
|
+
const routeData = translations.get(routeKey)
|
|
67
|
+
const val = findValue<T>(routeData, key)
|
|
68
|
+
if (val !== null) return val
|
|
69
|
+
|
|
70
|
+
const generalData = translations.get(locale)
|
|
71
|
+
return findValue<T>(generalData, key)
|
|
141
72
|
},
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return true
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const generalCache = getValueByKey(generalLocaleCache, locale)
|
|
151
|
-
return findTranslation(generalCache || null, key) !== null
|
|
73
|
+
loadTranslations(locale: string, data: Translations): void {
|
|
74
|
+
// Merge with existing, replacing duplicate keys
|
|
75
|
+
const existing = translations.get(locale) ?? {}
|
|
76
|
+
translations.set(locale, { ...existing, ...data })
|
|
152
77
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const dynamicCaches = getValue(dynamicTranslationsCaches)
|
|
164
|
-
for (const dynamicCache of dynamicCaches) {
|
|
165
|
-
result = findTranslation<T>(dynamicCache[locale] || null, key)
|
|
166
|
-
if (result !== null) break
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!result) {
|
|
170
|
-
const routeCache = getValueByKey(routeLocaleCache, cacheKey)
|
|
171
|
-
const generalCache = getValueByKey(generalLocaleCache, locale)
|
|
172
|
-
result = findTranslation<T>(routeCache || null, key)
|
|
173
|
-
?? findTranslation<T>(generalCache || null, key)
|
|
78
|
+
setTranslations(locale: string, data: Translations): void {
|
|
79
|
+
// Replace all translations for locale (no merge)
|
|
80
|
+
translations.set(locale, data)
|
|
81
|
+
},
|
|
82
|
+
loadPageTranslations(locale: string, routeName: string, data: Translations): void {
|
|
83
|
+
const key = `${locale}:${routeName}`
|
|
84
|
+
const existing = translations.get(key)
|
|
85
|
+
// Perf: при пустом existing — сохраняем ссылку, избегаем O(n) копирования больших объектов
|
|
86
|
+
if (!existing || Object.keys(existing).length === 0) {
|
|
87
|
+
translations.set(key, data)
|
|
174
88
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const currentServerCache = serverCache ?? new Map<string, Translations | unknown>()
|
|
178
|
-
currentServerCache.set(key, result)
|
|
179
|
-
setValue(serverTranslationCache, cacheKey, currentServerCache)
|
|
89
|
+
else {
|
|
90
|
+
translations.set(key, { ...existing, ...data })
|
|
180
91
|
}
|
|
181
|
-
|
|
182
|
-
return result
|
|
183
92
|
},
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
93
|
+
mergeTranslation(locale: string, routeName: string, newTranslations: Translations, _force = false): void {
|
|
94
|
+
const key = `${locale}:${routeName}`
|
|
95
|
+
const existing = translations.get(key) ?? {}
|
|
96
|
+
translations.set(key, { ...existing, ...newTranslations })
|
|
187
97
|
},
|
|
188
|
-
|
|
189
|
-
|
|
98
|
+
mergeGlobalTranslation(locale: string, newTranslations: Translations, _force = false): void {
|
|
99
|
+
const existing = translations.get(locale) ?? {}
|
|
100
|
+
translations.set(locale, { ...existing, ...newTranslations })
|
|
190
101
|
},
|
|
191
|
-
clearCache() {
|
|
192
|
-
|
|
193
|
-
const generalCache = getValue(generalLocaleCache)
|
|
194
|
-
Object.keys(generalCache).forEach((key) => {
|
|
195
|
-
setValue(generalLocaleCache, key, {})
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
// Clear route-specific cache
|
|
199
|
-
const routeCache = getValue(routeLocaleCache)
|
|
200
|
-
Object.keys(routeCache).forEach((key) => {
|
|
201
|
-
setValue(routeLocaleCache, key, {})
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
// Clear dynamic caches
|
|
205
|
-
const dynamicCaches = getValue(dynamicTranslationsCaches)
|
|
206
|
-
dynamicCaches.length = 0
|
|
207
|
-
|
|
208
|
-
// Clear server translation cache
|
|
209
|
-
const serverCache = getValue(serverTranslationCache)
|
|
210
|
-
Object.keys(serverCache).forEach((key) => {
|
|
211
|
-
const cacheMap = getValueByKey(serverTranslationCache, key)
|
|
212
|
-
cacheMap?.clear()
|
|
213
|
-
})
|
|
102
|
+
clearCache(): void {
|
|
103
|
+
translations.clear()
|
|
214
104
|
},
|
|
215
105
|
}
|
|
216
106
|
}
|
package/tests/base.test.ts
CHANGED
|
@@ -49,14 +49,9 @@ describe('BaseI18n', () => {
|
|
|
49
49
|
expect(i18n.getRoute()).toBe('general')
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
test('should initialize with custom
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
routeLocaleCache: {},
|
|
56
|
-
dynamicTranslationsCaches: [],
|
|
57
|
-
serverTranslationCache: {},
|
|
58
|
-
}
|
|
59
|
-
const i18n = new TestI18n('en', 'en', 'general', { cache })
|
|
52
|
+
test('should initialize with custom storage', () => {
|
|
53
|
+
const storage = { translations: new Map<string, Translations>() }
|
|
54
|
+
const i18n = new TestI18n('en', 'en', 'general', { storage })
|
|
60
55
|
expect(i18n).toBeDefined()
|
|
61
56
|
})
|
|
62
57
|
|
|
@@ -93,13 +88,8 @@ describe('BaseI18n', () => {
|
|
|
93
88
|
})
|
|
94
89
|
|
|
95
90
|
test('should interpolate params in translation', async () => {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
routeLocaleCache: {},
|
|
99
|
-
dynamicTranslationsCaches: [],
|
|
100
|
-
serverTranslationCache: {},
|
|
101
|
-
}
|
|
102
|
-
const i18n = new TestI18n('en', 'en', 'general', { cache })
|
|
91
|
+
const storage = { translations: new Map<string, Translations>() }
|
|
92
|
+
const i18n = new TestI18n('en', 'en', 'general', { storage })
|
|
103
93
|
const translations: Translations = { greeting: 'Hello, {name}!' }
|
|
104
94
|
await i18n['helper'].loadTranslations('en', translations)
|
|
105
95
|
|
|
@@ -117,13 +107,8 @@ describe('BaseI18n', () => {
|
|
|
117
107
|
})
|
|
118
108
|
|
|
119
109
|
test('should fallback to fallbackLocale when translation is missing', async () => {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
routeLocaleCache: {},
|
|
123
|
-
dynamicTranslationsCaches: [],
|
|
124
|
-
serverTranslationCache: {},
|
|
125
|
-
}
|
|
126
|
-
const i18n = new TestI18n('en', 'fr', 'general', { cache })
|
|
110
|
+
const storage = { translations: new Map<string, Translations>() }
|
|
111
|
+
const i18n = new TestI18n('en', 'fr', 'general', { storage })
|
|
127
112
|
const translations: Translations = { greeting: 'Bonjour' }
|
|
128
113
|
await i18n['helper'].loadTranslations('fr', translations)
|
|
129
114
|
|
|
@@ -139,15 +124,10 @@ describe('BaseI18n', () => {
|
|
|
139
124
|
})
|
|
140
125
|
|
|
141
126
|
test('should use previousPageInfo fallback when enabled', async () => {
|
|
142
|
-
const
|
|
143
|
-
generalLocaleCache: {},
|
|
144
|
-
routeLocaleCache: {},
|
|
145
|
-
dynamicTranslationsCaches: [],
|
|
146
|
-
serverTranslationCache: {},
|
|
147
|
-
}
|
|
127
|
+
const storage = { translations: new Map<string, Translations>() }
|
|
148
128
|
const prevInfo = { locale: 'fr', routeName: 'previous' }
|
|
149
129
|
const i18n = new TestI18n('en', 'en', 'general', {
|
|
150
|
-
|
|
130
|
+
storage,
|
|
151
131
|
getPreviousPageInfo: () => prevInfo,
|
|
152
132
|
enablePreviousPageFallback: true,
|
|
153
133
|
})
|
|
@@ -479,13 +459,8 @@ describe('BaseI18n', () => {
|
|
|
479
459
|
})
|
|
480
460
|
|
|
481
461
|
test('should handle route change', async () => {
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
routeLocaleCache: {},
|
|
485
|
-
dynamicTranslationsCaches: [],
|
|
486
|
-
serverTranslationCache: {},
|
|
487
|
-
}
|
|
488
|
-
const i18n = new TestI18n('en', 'en', 'general', { cache })
|
|
462
|
+
const storage = { translations: new Map<string, Translations>() }
|
|
463
|
+
const i18n = new TestI18n('en', 'en', 'general', { storage })
|
|
489
464
|
const generalTranslations: Translations = { greeting: 'Hello' }
|
|
490
465
|
const routeTranslations: Translations = { title: 'About Page' }
|
|
491
466
|
|
package/dist/route-service.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { NavigationFailure, RouteLocationAsPathGeneric, RouteLocationNamedRaw, RouteLocationNormalizedLoaded, RouteLocationRaw, RouteLocationResolved, RouteLocationResolvedGeneric, Router } from 'vue-router';
|
|
2
|
-
import { I18nRouteParams, Locale, ModuleOptionsExtend } from '@i18n-micro/types';
|
|
3
|
-
interface NavigateToInterface {
|
|
4
|
-
replace?: boolean;
|
|
5
|
-
redirectCode?: number;
|
|
6
|
-
external?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export declare class RouteService {
|
|
9
|
-
private i18nConfig;
|
|
10
|
-
private router;
|
|
11
|
-
private hashLocaleDefault;
|
|
12
|
-
private noPrefixDefault;
|
|
13
|
-
private navigateTo;
|
|
14
|
-
private setCookie;
|
|
15
|
-
private cookieLocaleDefault;
|
|
16
|
-
private cookieLocaleName;
|
|
17
|
-
constructor(i18nConfig: ModuleOptionsExtend, router: Router, hashLocaleDefault: string | null | undefined, noPrefixDefault: string | null | undefined, navigateTo: (to: RouteLocationRaw | undefined | null, options?: NavigateToInterface) => Promise<void | NavigationFailure | false> | false | void | RouteLocationRaw, setCookie: (name: string, value: string) => void, cookieLocaleDefault?: string | null | undefined, cookieLocaleName?: string | null | undefined);
|
|
18
|
-
/**
|
|
19
|
-
* Extracts locale from URL path by checking the first path segment
|
|
20
|
-
* @param path - URL path (e.g., '/ru/sdfsdf' or '/en/about')
|
|
21
|
-
* @returns Locale code or null if not found
|
|
22
|
-
*/
|
|
23
|
-
private extractLocaleFromPath;
|
|
24
|
-
getCurrentLocale(route?: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric): string;
|
|
25
|
-
getCurrentName(route: RouteLocationNormalizedLoaded | RouteLocationResolvedGeneric): string | null;
|
|
26
|
-
getRouteName(route: RouteLocationResolvedGeneric | RouteLocationNamedRaw, locale: string): string;
|
|
27
|
-
getPluginRouteName(route: RouteLocationResolvedGeneric | RouteLocationNamedRaw, locale: string): string;
|
|
28
|
-
getFullPathWithBaseUrl(currentLocale: Locale, route: RouteLocationRaw): string;
|
|
29
|
-
switchLocaleRoute(fromLocale: string, toLocale: string, route: RouteLocationResolvedGeneric | RouteLocationNamedRaw, i18nRouteParams: I18nRouteParams): RouteLocationRaw;
|
|
30
|
-
private resolveParams;
|
|
31
|
-
private handlePrefixStrategy;
|
|
32
|
-
private createLocalizedRoute;
|
|
33
|
-
getLocalizedRoute(to: RouteLocationResolvedGeneric | RouteLocationAsPathGeneric | RouteLocationNamedRaw | string, route: RouteLocationNormalizedLoaded, locale?: string): RouteLocationResolved;
|
|
34
|
-
updateCookies(toLocale: string): void;
|
|
35
|
-
getCurrentRoute(): RouteLocationNormalizedLoaded;
|
|
36
|
-
private resolveRouteWithStrategy;
|
|
37
|
-
switchLocaleLogic(toLocale: string, i18nRouteParams: I18nRouteParams, to?: RouteLocationNamedRaw | RouteLocationResolvedGeneric | string): string | false | void | import('vue-router').RouteLocationAsRelativeGeneric | RouteLocationAsPathGeneric | Promise<false | void | NavigationFailure>;
|
|
38
|
-
resolveLocalizedRoute(to: RouteLocationNamedRaw | RouteLocationAsPathGeneric | string, locale?: string): RouteLocationResolved;
|
|
39
|
-
}
|
|
40
|
-
export {};
|