From b19b69050e252120016d47540e108f6eea193c37 Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Wed, 20 Nov 2019 17:10:40 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20pathname=20and=20h?= =?UTF-8?q?ostname=20pattern=20matching?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++-- src/client/includes/utils.ts | 82 ++++++++++++++++++++++++------------ test/client/index.test.ts | 17 ++++++-- 3 files changed, 78 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 78b7f9e..72db4a2 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,11 @@ locale.set( // set the key name to look for a locale on 'window.location.hash' // 'example.com#locale=en-US' hash: 'locale', - }), + // define a pattern to look in the window.location.pathname. It returns the first capturing group. + pathname: /^\/(.*?)\//, + // define a pattern to look in the window.location.hostname. It returns the first capturing group. + hostname: /^\/(.*?)\//, + }) ) ``` @@ -82,7 +86,8 @@ dictionary.set({ ask: 'Por favor, digite seu nome', message: 'Olá {name}, como vai?', }, - photos: 'Você {n, plural, =0 {não tem fotos.} =1 {tem uma foto.} other {tem # fotos.}}', + photos: + 'Você {n, plural, =0 {não tem fotos.} =1 {tem uma foto.} other {tem # fotos.}}', cats: 'Tenho {n, number} {n,plural,=0{gatos}one{gato}other{gatos}}', }, en: { @@ -92,7 +97,8 @@ dictionary.set({ ask: 'Please type your name', message: 'Hello {name}, how are you?', }, - photos: 'You have {n, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}', + photos: + 'You have {n, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}', cats: 'I have {n, number} {n,plural,one{cat}other{cats}}', }, }) diff --git a/src/client/includes/utils.ts b/src/client/includes/utils.ts index 48b7d17..b568e70 100644 --- a/src/client/includes/utils.ts +++ b/src/client/includes/utils.ts @@ -23,47 +23,77 @@ export function getLocalesFrom(locale: string) { return locale.split('-').map((_, i, arr) => arr.slice(0, i + 1).join('-')) } +const getFromURL = (urlPart: string, key: string) => { + const keyVal = urlPart + .substr(1) + .split('&') + .find(i => i.indexOf(key) === 0) + + if (keyVal) { + return keyVal.split('=').pop() + } +} + +const getMatch = (base: string, pattern: RegExp) => { + const match = pattern.exec(base) + if (!match) return null + return match[1] || null +} + // todo add a urlPattern method/regexp export const getClientLocale = ({ navigator, hash, search, + pathname, + hostname, default: defaultLocale, }: { navigator?: boolean - hash?: string - search?: string + hash?: string | RegExp + search?: string | RegExp fallback?: string default?: string + pathname?: RegExp + hostname?: RegExp }) => { let locale - const getFromURL = (urlPart: string, key: string) => { - const keyVal = urlPart - .substr(1) - .split('&') - .find(i => i.indexOf(key) === 0) - - if (keyVal) { - return keyVal.split('=').pop() - } + if (typeof window === 'undefined') { + return defaultLocale } - // istanbul ignore else - if (typeof window !== 'undefined') { - if (navigator) { - // istanbul ignore next - locale = window.navigator.language || window.navigator.languages[0] - } - - if (search && !locale) { - locale = getFromURL(window.location.search, search) - } - - if (hash && !locale) { - locale = getFromURL(window.location.hash, hash) - } + if (hostname) { + locale = getMatch(window.location.hostname, hostname) + if (locale) return locale } - return locale || defaultLocale + if (pathname) { + locale = getMatch(window.location.pathname, pathname) + if (locale) return locale + } + + if (navigator) { + // istanbul ignore else + locale = window.navigator.language || window.navigator.languages[0] + if (locale) return locale + } + + if (search) { + locale = + typeof search === 'string' + ? getFromURL(window.location.search, search) + : getMatch(window.location.search, search) + if (locale) return locale + } + + if (hash) { + locale = + typeof hash === 'string' + ? getFromURL(window.location.hash, hash) + : getMatch(window.location.hash, hash) + if (locale) return locale + } + + return defaultLocale } diff --git a/test/client/index.test.ts b/test/client/index.test.ts index dc1800c..bf503e0 100644 --- a/test/client/index.test.ts +++ b/test/client/index.test.ts @@ -113,6 +113,8 @@ describe('utilities', () => { beforeEach(() => { delete window.location window.location = { + pathname: '/', + hostname: 'example.com', hash: '', search: '', } as any @@ -120,13 +122,11 @@ describe('utilities', () => { it('should get the locale based on the passed hash parameter', () => { window.location.hash = '#locale=en-US&lang=pt-BR' - expect(getClientLocale({ hash: 'locale' })).toBe('en-US') expect(getClientLocale({ hash: 'lang' })).toBe('pt-BR') }) it('should get the locale based on the passed search parameter', () => { window.location.search = '?locale=en-US&lang=pt-BR' - expect(getClientLocale({ search: 'locale' })).toBe('en-US') expect(getClientLocale({ search: 'lang' })).toBe('pt-BR') }) @@ -136,9 +136,18 @@ describe('utilities', () => { ) }) + it('should get the default locale', () => { + expect(getClientLocale({ default: 'pt' })).toBe('pt') + }) + it('should get the fallback locale', () => { - expect(getClientLocale({ navigator: false, default: 'pt' })).toBe('pt') - expect(getClientLocale({ hash: 'locale', default: 'pt' })).toBe('pt') + window.location.pathname = '/en-US/foo/' + expect(getClientLocale({ pathname: /^\/(.*?)\// })).toBe('en-US') + }) + + it('should get the fallback locale', () => { + window.location.hostname = 'pt.example.com' + expect(getClientLocale({ hostname: /^.*?\./ })).toBe('pt') }) })