Skip to content

Commit bf88d98

Browse files
authored
feat: add getNavigatorLocale and getNavigatorLocales (#24)
1 parent e72cc8b commit bf88d98

File tree

5 files changed

+158
-6
lines changed

5 files changed

+158
-6
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ You can do `import { ... } from '@intlify/utils'` the above utilities
132132

133133
- `getNavigatorLanguages`
134134
- `getNavigatorLanguage`
135+
- `getNavigatorLocales`
136+
- `getNavigatorLocale`
135137

136138
You can do `import { ... } from '@intlify/utils'` the above utilities
137139

src/node.ts

+77-1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,18 @@ export function getNavigatorLanguages(): readonly string[] {
271271
return navigatorLanguages = [...langs].filter(Boolean)
272272
}
273273

274+
/**
275+
* get navigator locales
276+
*
277+
* @description
278+
* You can get some {@link Intl.Locale} from system environment variables.
279+
*
280+
* @returns {Array<Intl.Locale>}
281+
*/
282+
export function getNavigatorLocales(): readonly Intl.Locale[] {
283+
return getNavigatorLanguages().map((lang) => new Intl.Locale(lang))
284+
}
285+
274286
/**
275287
* in-source testing for `getNavigatorLanguages`
276288
*/
@@ -327,6 +339,37 @@ if (import.meta.vitest) {
327339
expect(mockEnv).toHaveBeenCalledTimes(2)
328340
})
329341
})
342+
343+
describe('getNavigatorLocales', () => {
344+
afterEach(() => {
345+
vi.resetAllMocks()
346+
navigatorLanguages = undefined
347+
})
348+
349+
test('basic', () => {
350+
vi.spyOn(process, 'env', 'get').mockReturnValue({
351+
LC_ALL: 'en-GB',
352+
LC_MESSAGES: 'en-US',
353+
LANG: 'ja-JP',
354+
LANGUAGE: 'en',
355+
})
356+
357+
const values = [
358+
'en-GB',
359+
'en-US',
360+
'ja-JP',
361+
'en',
362+
]
363+
expect(getNavigatorLocales().map((locale) => locale.toString())).toEqual([
364+
'en-GB',
365+
'en-US',
366+
'ja-JP',
367+
'en',
368+
])
369+
// cache checking
370+
expect(navigatorLanguages).toEqual(values)
371+
})
372+
})
330373
}
331374

332375
let navigatorLanguage = ''
@@ -345,7 +388,19 @@ export function getNavigatorLanguage(): string {
345388
}
346389

347390
/**
348-
* in-source testing for `getNavigatorLanguage`
391+
* get navigator locale
392+
*
393+
* @description
394+
* You can get the {@link Intl.Locale} from system environment variables.
395+
*
396+
* @returns {Intl.Locale}
397+
*/
398+
export function getNavigatorLocale(): Intl.Locale {
399+
return new Intl.Locale(getNavigatorLanguage())
400+
}
401+
402+
/**
403+
* in-source testing for `getNavigatorLanguage` and `getNavigatorLocale`
349404
*/
350405
if (import.meta.vitest) {
351406
const { describe, test, expect, afterEach, vi } = import.meta.vitest
@@ -391,4 +446,25 @@ if (import.meta.vitest) {
391446
expect(mockEnv).toHaveBeenCalledTimes(2)
392447
})
393448
})
449+
450+
describe('getNavigatorLocale', () => {
451+
afterEach(() => {
452+
vi.resetAllMocks()
453+
navigatorLanguages = undefined
454+
navigatorLanguage = ''
455+
})
456+
457+
test('basic', () => {
458+
vi.spyOn(process, 'env', 'get').mockReturnValue({
459+
LC_ALL: 'en-GB',
460+
LC_MESSAGES: 'en-US',
461+
LANG: 'ja-JP',
462+
LANGUAGE: 'en',
463+
})
464+
465+
expect(getNavigatorLocale().toString()).toEqual('en-GB')
466+
// cache checking
467+
expect(navigatorLanguage).toEqual('en-GB')
468+
})
469+
})
394470
}

src/web.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
getHeaderLocales,
88
getNavigatorLanguage,
99
getNavigatorLanguages,
10+
getNavigatorLocale,
11+
getNavigatorLocales,
1012
setCookieLocale,
1113
} from './web.ts'
1214
import { DEFAULT_COOKIE_NAME, DEFAULT_LANG_TAG } from './constants.ts'
@@ -257,3 +259,43 @@ describe('getNavigatorLanguage', () => {
257259
)
258260
})
259261
})
262+
263+
describe('getNavigatorLocales', () => {
264+
test('basic', () => {
265+
vi.stubGlobal('navigator', {
266+
languages: ['en-US', 'en', 'ja'],
267+
})
268+
269+
expect(getNavigatorLocales().map((locale) => locale.toString())).toEqual([
270+
'en-US',
271+
'en',
272+
'ja',
273+
])
274+
})
275+
276+
test('error', () => {
277+
vi.stubGlobal('navigator', undefined)
278+
279+
expect(() => getNavigatorLocales()).toThrowError(
280+
/not support `navigator`/,
281+
)
282+
})
283+
})
284+
285+
describe('getNavigatorLanguage', () => {
286+
test('basic', () => {
287+
vi.stubGlobal('navigator', {
288+
language: 'en-US',
289+
})
290+
291+
expect(getNavigatorLocale().toString()).toEqual('en-US')
292+
})
293+
294+
test('error', () => {
295+
vi.stubGlobal('navigator', undefined)
296+
297+
expect(() => getNavigatorLocale()).toThrowError(
298+
/not support `navigator`/,
299+
)
300+
})
301+
})

src/web.ts

+30
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,33 @@ export function getNavigatorLanguage(): string {
282282
}
283283
return navigator.language
284284
}
285+
286+
/**
287+
* get navigator locales
288+
*
289+
* @description
290+
* This function is a wrapper that maps in {@link Intl.Locale} in `navigator.languages`.
291+
* This function return values depends on the environments. if you use this function on the browser, you can get the languages, that are set in the browser, else if you use this function on the server side (Deno only), that value is the languages set in the server.
292+
*
293+
* @throws Throws the {@link Error} if the `navigator` is not exists.
294+
*
295+
* @returns {Array<Intl.Locale>}
296+
*/
297+
export function getNavigatorLocales(): readonly Intl.Locale[] {
298+
return getNavigatorLanguages().map((lang) => new Intl.Locale(lang))
299+
}
300+
301+
/**
302+
* get navigator locale
303+
*
304+
* @description
305+
* This function is the {@link Intl.Locale} wrapper of `navigator.language`.
306+
* The value depends on the environments. if you use this function on the browser, you can get the languages, that are set in the browser, else if you use this function on the server side (Deno only), that value is the language set in the server.
307+
*
308+
* @throws Throws the {@link Error} if the `navigator` is not exists.
309+
*
310+
* @returns {Intl.Locale}
311+
*/
312+
export function getNavigatorLocale(): Intl.Locale {
313+
return new Intl.Locale(getNavigatorLanguage())
314+
}

tsconfig.json

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212

1313
/* Language and Environment */
1414
"target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15-
// "lib": [
16-
// "ESNext",
17-
// "DOM",
18-
// "DOM.Iterable"
19-
// ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
15+
"lib": [
16+
"ESNext",
17+
"ES2020.Intl",
18+
"ESNext.Intl",
19+
"DOM",
20+
"DOM.Iterable"
21+
], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
2022
// "jsx": "preserve", /* Specify what JSX code is generated. */
2123
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
2224
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */

0 commit comments

Comments
 (0)