Skip to content

Commit 1345c99

Browse files
authored
feat: more strictly return type locale detector (#1640)
1 parent 917e00e commit 1345c99

File tree

5 files changed

+87
-26
lines changed

5 files changed

+87
-26
lines changed

packages/core-base/src/errors.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ export const CoreErrorCodes = {
1616
INVALID_DATE_ARGUMENT: inc(), // 19
1717
INVALID_ISO_DATE_ARGUMENT: inc(), // 20
1818
NOT_SUPPORT_NON_STRING_MESSAGE: inc(), // 21
19-
__EXTEND_POINT__: inc() // 22
19+
NOT_SUPPORT_LOCALE_PROMISE_VALUE: inc(), // 22
20+
NOT_SUPPORT_LOCALE_ASYNC_FUNCTION: inc(), // 23
21+
NOT_SUPPORT_LOCALE_TYPE: inc(), // 24
22+
__EXTEND_POINT__: inc() // 25
2023
} as const
2124

2225
export type CoreErrorCodes =
@@ -39,5 +42,10 @@ export const errorMessages: { [code: number]: string } = {
3942
[CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT]:
4043
'The argument provided is not a valid ISO date string',
4144
[CoreErrorCodes.NOT_SUPPORT_NON_STRING_MESSAGE]:
42-
'Not support non-string message'
45+
'Not support non-string message',
46+
[CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE]:
47+
'cannot support promise value',
48+
[CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION]:
49+
'cannot support async function',
50+
[CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE]: 'cannot support locale type'
4351
}

packages/core-base/src/fallbacker.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import {
33
isArray,
44
isBoolean,
55
isPlainObject,
6-
isObject
6+
isObject,
7+
isPromise,
8+
isFunction
79
} from '@intlify/shared'
810
import { DEFAULT_LOCALE } from './context'
11+
import { CoreErrorCodes, createCoreError } from './errors'
912

1013
import type { Locale, LocaleDetector, FallbackLocale } from './runtime'
1114
import type { CoreContext, CoreInternalContext } from './context'
@@ -33,12 +36,25 @@ let _resolveLocale: string
3336

3437
/** @internal */
3538
export function resolveLocale(locale: Locale | LocaleDetector) {
36-
// prettier-ignore
37-
return isString(locale)
38-
? locale
39-
: _resolveLocale != null && locale.resolvedOnce
40-
? _resolveLocale
41-
: (_resolveLocale = locale())
39+
if (isString(locale)) {
40+
return locale
41+
} else {
42+
if (isFunction(locale)) {
43+
if (locale.resolvedOnce && _resolveLocale != null) {
44+
return _resolveLocale
45+
} else if (locale.constructor.name === 'Function') {
46+
const resolve = locale()
47+
if (isPromise(resolve)) {
48+
throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE)
49+
}
50+
return (_resolveLocale = resolve)
51+
} else {
52+
throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION)
53+
}
54+
} else {
55+
throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE)
56+
}
57+
}
4258
}
4359

4460
/**

packages/core-base/src/runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export type Locale = string
2727
/** @VueI18nGeneral */
2828
// prettier-ignore
2929
export interface LocaleDetector<Args extends any[] = any[]> { // eslint-disable-line @typescript-eslint/no-explicit-any
30-
(...args: Args): Locale
30+
(...args: Args): Locale | Promise<Locale>
3131
resolvedOnce?: boolean
3232
}
3333

packages/core-base/test/fallbacker.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { createCoreContext as context, CoreContext } from '../src/context'
2-
import { fallbackWithLocaleChain, fallbackWithSimple } from '../src/fallbacker'
2+
import {
3+
fallbackWithLocaleChain,
4+
fallbackWithSimple,
5+
resolveLocale
6+
} from '../src/fallbacker'
7+
import { errorMessages, CoreErrorCodes } from '../src/errors'
8+
import { LocaleDetector } from '@intlify/core-base'
39

410
describe('fallbackWithSimple', () => {
511
let ctx: CoreContext<string>
@@ -283,3 +289,34 @@ describe('fallbackWithLocaleChain', () => {
283289
})
284290
})
285291
})
292+
293+
describe('resolveLocale', () => {
294+
test('string', () => {
295+
expect(resolveLocale('en')).toEqual('en')
296+
})
297+
298+
test('function return promise value', () => {
299+
expect(() => resolveLocale(() => Promise.resolve('en'))).toThrowError(
300+
errorMessages[CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE]
301+
)
302+
})
303+
304+
test('function return string', () => {
305+
const fn = vi.fn(() => 'en')
306+
expect(resolveLocale(fn)).toEqual('en')
307+
expect(resolveLocale(fn)).toEqual('en')
308+
})
309+
310+
test('async function', () => {
311+
expect(() => resolveLocale(async () => Promise.resolve('en'))).toThrowError(
312+
errorMessages[CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION]
313+
)
314+
})
315+
316+
test('other type value', () => {
317+
const fn = 1 as unknown as LocaleDetector
318+
expect(() => resolveLocale(fn)).toThrowError(
319+
errorMessages[CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE]
320+
)
321+
})
322+
})

packages/vue-i18n-core/src/errors.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@ const inc = incrementer(code)
1010

1111
export const I18nErrorCodes = {
1212
// composer module errors
13-
UNEXPECTED_RETURN_TYPE: code, // 23
13+
UNEXPECTED_RETURN_TYPE: code, // 26
1414
// legacy module errors
15-
INVALID_ARGUMENT: inc(), // 24
15+
INVALID_ARGUMENT: inc(), // 27
1616
// i18n module errors
17-
MUST_BE_CALL_SETUP_TOP: inc(), // 25
18-
NOT_INSTALLED: inc(), // 26
19-
NOT_AVAILABLE_IN_LEGACY_MODE: inc(), // 27
17+
MUST_BE_CALL_SETUP_TOP: inc(), // 28
18+
NOT_INSTALLED: inc(), // 29
19+
NOT_AVAILABLE_IN_LEGACY_MODE: inc(), // 30
2020
// directive module errors
21-
REQUIRED_VALUE: inc(), // 28
22-
INVALID_VALUE: inc(), // 29
21+
REQUIRED_VALUE: inc(), // 31
22+
INVALID_VALUE: inc(), // 32
2323
// vue-devtools errors
24-
CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN: inc(), // 30
25-
NOT_INSTALLED_WITH_PROVIDE: inc(), // 31
24+
CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN: inc(), // 33
25+
NOT_INSTALLED_WITH_PROVIDE: inc(), // 34
2626
// unexpected error
27-
UNEXPECTED_ERROR: inc(), // 32
27+
UNEXPECTED_ERROR: inc(), // 35
2828
// not compatible legacy vue-i18n constructor
29-
NOT_COMPATIBLE_LEGACY_VUE_I18N: inc(), // 33
29+
NOT_COMPATIBLE_LEGACY_VUE_I18N: inc(), // 36
3030
// bridge support vue 2.x only
31-
BRIDGE_SUPPORT_VUE_2_ONLY: inc(), // 34
31+
BRIDGE_SUPPORT_VUE_2_ONLY: inc(), // 37
3232
// need to define `i18n` option in `allowComposition: true` and `useScope: 'local' at `useI18n``
33-
MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION: inc(), // 35
33+
MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION: inc(), // 38
3434
// Not available Compostion API in Legacy API mode. Please make sure that the legacy API mode is working properly
35-
NOT_AVAILABLE_COMPOSITION_IN_LEGACY: inc(), // 36
35+
NOT_AVAILABLE_COMPOSITION_IN_LEGACY: inc(), // 39
3636
// for enhancement
37-
__EXTEND_POINT__: inc() // 37
37+
__EXTEND_POINT__: inc() // 40
3838
} as const
3939

4040
type I18nErrorCodes = (typeof I18nErrorCodes)[keyof typeof I18nErrorCodes]

0 commit comments

Comments
 (0)