From 9e9ecfe2a95c6fa9aaa36fbde7898b694d2d4cb1 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 17 Oct 2023 13:58:52 +0900 Subject: [PATCH] feat!: support `lang` option for path and query detection APIs --- src/http.test.ts | 36 +++++++++++++++++++++++++----------- src/http.ts | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/http.test.ts b/src/http.test.ts index 75807f9..b804d49 100644 --- a/src/http.test.ts +++ b/src/http.test.ts @@ -16,9 +16,17 @@ describe('getPathLanguage', () => { expect(getPathLanguage(url)).toBe('en') }) + test('default language, when the language is not detected', () => { + expect(getPathLanguage('/')).toBe('en-US') + }) + test('parser option', () => { const nullLangParser = () => 'null' - expect(getPathLanguage('/en/foo', nullLangParser)).toBe('null') + expect(getPathLanguage('/en/foo', { parser: nullLangParser })).toBe('null') + }) + + test('lang option', () => { + expect(getPathLanguage('/', { lang: 'ja' })).toBe('ja') }) }) @@ -32,11 +40,16 @@ describe('getPathLocale', () => { expect(getPathLocale(url).toString()).toBe('ja-JP') }) + test('default locale, when the language is not detected', () => { + expect(getPathLocale('/').toString()).toBe('en-US') + }) + test('RangeError', () => { const nullLangParser = () => 'null' - expect(() => getPathLocale('/en/foo', nullLangParser)).toThrowError( - RangeError, - ) + expect(() => getPathLocale('/en/foo', { parser: nullLangParser })) + .toThrowError( + RangeError, + ) }) }) @@ -47,7 +60,7 @@ describe('getQueryLanguage', () => { test('URL instance', () => { const url = new URL('https://example.com/?locale=ja-JP') - expect(getQueryLanguage(url, 'locale')).toBe('ja-JP') + expect(getQueryLanguage(url, { name: 'locale' })).toBe('ja-JP') }) test('URLSearchParams instance', () => { @@ -56,15 +69,16 @@ describe('getQueryLanguage', () => { expect(getQueryLanguage(params)).toBe('ja-JP') }) - test('empty', () => { + test('default language, when the language is not detected', () => { const params = new URLSearchParams() - expect(getQueryLanguage(params)).toBe('') + expect(getQueryLanguage(params)).toBe('en-US') }) }) describe('getQueryLocale', () => { test('basic', () => { - expect(getQueryLocale('lang=en-US&flag=1', 'lang').toString()).toBe('en-US') + expect(getQueryLocale('lang=en-US&flag=1', { name: 'lang' }).toString()) + .toBe('en-US') }) test('URL instance', () => { @@ -75,11 +89,11 @@ describe('getQueryLocale', () => { test('URLSearchParams instance', () => { const params = new URLSearchParams('lang=ja-JP') params.set('flag', '1') - expect(getQueryLocale(params, 'lang').toString()).toBe('ja-JP') + expect(getQueryLocale(params, { name: 'lang' }).toString()).toBe('ja-JP') }) - test('RangeError', () => { + test('default language, when the language is not detected', () => { const params = new URLSearchParams() - expect(() => getQueryLocale(params)).toThrowError(RangeError) + expect(getQueryLanguage(params)).toBe('en-US') }) }) diff --git a/src/http.ts b/src/http.ts index 654de43..e4d0b26 100644 --- a/src/http.ts +++ b/src/http.ts @@ -7,7 +7,7 @@ import { toLocale, validateLangTag, } from './shared.ts' -import { ACCEPT_LANGUAGE_HEADER } from './constants.ts' +import { ACCEPT_LANGUAGE_HEADER, DEFAULT_LANG_TAG } from './constants.ts' import type { PathLanguageParser } from './shared.ts' // import type { CookieSerializeOptions } from 'cookie-es' @@ -175,26 +175,33 @@ export function getExistCookies( return setCookies as string[] } +export type PathOptions = { + lang?: string + parser?: PathLanguageParser +} + /** * get the language from the path * * @param {string | URL} path the target path - * @param {PathLanguageParser} parser the path language parser, optional + * @param {PathOptions['lang']} options.lang the language tag, which is as default `'en-US'`. optional + * @param {PathOptions['parser']} options.parser the path language parser, optional * - * @returns {string} the language that is parsed by the path language parser, if the language is not detected, return an empty string. + * @returns {string} the language that is parsed by the path language parser, if the language is not detected, return a `options.lang` value */ export function getPathLanguage( path: string | URL, - parser?: PathLanguageParser, + { lang = DEFAULT_LANG_TAG, parser = pathLanguageParser }: PathOptions = {}, ): string { - return (parser || pathLanguageParser)(path) + return (parser || pathLanguageParser)(path) || lang } /** * get the locale from the path * * @param {string | URL} path the target path - * @param {PathLanguageParser} parser the path language parser, optional + * @param {PathOptions['lang']} options.lang the language tag, which is as default `'en-US'`. optional + * @param {PathOptions['parser']} options.parser the path language parser, optional * * @throws {RangeError} Throws the {@link RangeError} if the language in the path, that is not a well-formed BCP 47 language tag. * @@ -202,9 +209,9 @@ export function getPathLanguage( */ export function getPathLocale( path: string | URL, - parser?: PathLanguageParser, + { lang = DEFAULT_LANG_TAG, parser = pathLanguageParser }: PathOptions = {}, ): Intl.Locale { - return new Intl.Locale(getPathLanguage(path, parser)) + return new Intl.Locale(getPathLanguage(path, { lang, parser })) } function getURLSearchParams( @@ -219,27 +226,34 @@ function getURLSearchParams( } } +export type QueryOptions = { + lang?: string + name?: string +} + /** * get the language from the query * * @param {string | URL | URLSearchParams} query the target query - * @param {string} name the query param name, default `'lang'` + * @param {QueryOptions['lang']} options.lang the language tag, which is as default `'en-US'`. optional + * @param {QueryOptions['name']} options.name the query param name, default `'lang'`. optional * - * @returns {string} the language from query, if the language is not detected, return an empty string. + * @returns {string} the language from query, if the language is not detected, return an `options.lang` option string. */ export function getQueryLanguage( query: string | URL | URLSearchParams, - name = 'lang', + { lang = DEFAULT_LANG_TAG, name = 'lang' }: QueryOptions = {}, ): string { const queryParams = getURLSearchParams(query) - return queryParams.get(name) || '' + return queryParams.get(name) || lang } /** * get the locale from the query * * @param {string | URL | URLSearchParams} query the target query - * @param {string} name the query param name, default `'locale'` + * @param {QueryOptions['lang']} options.lang the language tag, which is as default `'en-US'`. optional + * @param {QueryOptions['name']} options.name the query param name, default `'locale'`. optional * * @throws {RangeError} Throws the {@link RangeError} if the language in the query, that is not a well-formed BCP 47 language tag. * @@ -247,7 +261,7 @@ export function getQueryLanguage( */ export function getQueryLocale( query: string | URL | URLSearchParams, - name = 'locale', + { lang = DEFAULT_LANG_TAG, name = 'locale' }: QueryOptions = {}, ): Intl.Locale { - return new Intl.Locale(getQueryLanguage(query, name)) + return new Intl.Locale(getQueryLanguage(query, { lang, name })) }