diff --git a/README.md b/README.md index 3b1ba87..f309839 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,8 @@ You can do `import { ... } from '@intlify/utils'` the above utilities - `setCookieLocale` - `getPathLanguage` - `getPathLocale` +- `getQueryLanguage` +- `getQueryLocale` The about utilies functions accpet Web APIs such as [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and diff --git a/src/http.test.ts b/src/http.test.ts index 7c1e428..aa7b0e1 100644 --- a/src/http.test.ts +++ b/src/http.test.ts @@ -1,5 +1,10 @@ import { describe, expect, test } from 'vitest' -import { getPathLanguage, getPathLocale } from './http.ts' +import { + getPathLanguage, + getPathLocale, + getQueryLanguage, + getQueryLocale, +} from './http.ts' describe('getPathLanguage', () => { test('basic', () => { @@ -38,3 +43,47 @@ describe('getPathLocale', () => { ) }) }) + +describe('getQueryLanguage', () => { + test('basic', () => { + expect(getQueryLanguage('lang=en-US&flag=1')).toBe('en-US') + }) + + test('URL instance', () => { + const url = new URL('https://example.com/?locale=ja-JP') + expect(getQueryLanguage(url, 'locale')).toBe('ja-JP') + }) + + test('URLSearchParams instance', () => { + const params = new URLSearchParams('lang=ja-JP') + params.set('flag', '1') + expect(getQueryLanguage(params)).toBe('ja-JP') + }) + + test('empty', () => { + const params = new URLSearchParams() + expect(getQueryLanguage(params)).toBe('') + }) +}) + +describe('getQueryLocale', () => { + test('basic', () => { + expect(getQueryLocale('lang=en-US&flag=1', 'lang').toString()).toBe('en-US') + }) + + test('URL instance', () => { + const url = new URL('https://example.com/?locale=ja-JP') + expect(getQueryLocale(url).toString()).toBe('ja-JP') + }) + + test('URLSearchParams instance', () => { + const params = new URLSearchParams('lang=ja-JP') + params.set('flag', '1') + expect(getQueryLocale(params, 'lang').toString()).toBe('ja-JP') + }) + + test('RangeError', () => { + const params = new URLSearchParams() + expect(() => getQueryLocale(params)).toThrowError(RangeError) + }) +}) diff --git a/src/http.ts b/src/http.ts index e73561d..ee70154 100644 --- a/src/http.ts +++ b/src/http.ts @@ -1,5 +1,7 @@ import { isLocale, + isURL, + isURLSearchParams, parseAcceptLanguage, pathLanguageParser, validateLanguageTag, @@ -158,7 +160,7 @@ export function getExistCookies( * @param {string | URL} path the target path * @param {PathLanguageParser} parser the path language parser, optional * - * @returns {string} the language that is parsed by the path language parser + * @returns {string} the language that is parsed by the path language parser, if the language is not detected, return an empty string. */ export function getPathLanguage( path: string | URL, @@ -184,3 +186,48 @@ export function getPathLocale( ): Intl.Locale { return new Intl.Locale(getPathLanguage(path, parser)) } + +function getURLSearchParams( + input: string | URL | URLSearchParams, +): URLSearchParams { + if (isURLSearchParams(input)) { + return input + } else if (isURL(input)) { + return input.searchParams + } else { + return new URLSearchParams(input) + } +} + +/** + * get the language from the query + * + * @param {string | URL | URLSearchParams} query the target query + * @param {string} name the query param name, default `'lang'` + * + * @returns {string} the language from query, if the language is not detected, return an empty string. + */ +export function getQueryLanguage( + query: string | URL | URLSearchParams, + name = 'lang', +): string { + const queryParams = getURLSearchParams(query) + return queryParams.get(name) || '' +} + +/** + * get the locale from the query + * + * @param {string | URL | URLSearchParams} query the target query + * @param {string} name the query param name, default `'locale'` + * + * @throws {RangeError} Throws the {@link RangeError} if the language in the query, that is not a well-formed BCP 47 language tag. + * + * @returns {Intl.Locale} The locale that resolved from query + */ +export function getQueryLocale( + query: string | URL | URLSearchParams, + name = 'locale', +): Intl.Locale { + return new Intl.Locale(getQueryLanguage(query, name)) +} diff --git a/src/index.ts b/src/index.ts index 26e7f73..f7a8bf5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,5 +6,10 @@ export { registerPathLanguageParser, validateLanguageTag, } from './shared.ts' -export { getPathLanguage, getPathLocale } from './http.ts' +export { + getPathLanguage, + getPathLocale, + getQueryLanguage, + getQueryLocale, +} from './http.ts' export * from './web.ts' diff --git a/src/shared.ts b/src/shared.ts index 75f70a7..334a1a1 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -1,6 +1,14 @@ const objectToString = Object.prototype.toString const toTypeString = (value: unknown): string => objectToString.call(value) +export function isURL(val: unknown): val is URL { + return toTypeString(val) === '[object URL]' +} + +export function isURLSearchParams(val: unknown): val is URLSearchParams { + return toTypeString(val) === '[object URLSearchParams]' +} + /** * check whether the value is a {@link Intl.Locale} instance *