mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-11-16 09:59:58 +01:00
refactor: 💡 split getClientLocale into multiple utilities
This commit is contained in:
parent
a574444f60
commit
6b0ba2b902
@ -64,7 +64,7 @@ After populating your [`$dictionary`](/docs/Dictionary.md) with [`addMessages()`
|
||||
|
||||
```js
|
||||
// src/i18n.js
|
||||
import { register, init, getClientLocale } from 'svelte-i18n'
|
||||
import { register, init, getLocaleFromNavigator } from 'svelte-i18n'
|
||||
|
||||
register('en', () => import('./en.json'))
|
||||
register('en-US', () => import('./en-US.json'))
|
||||
@ -73,9 +73,7 @@ register('pt', () => import('./pt.json'))
|
||||
|
||||
init({
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getClientLocale({
|
||||
navigator: true, // i.e 'en-US'
|
||||
}),
|
||||
initialLocale: getLocaleFromNavigator(),
|
||||
})
|
||||
// starts loading 'en-US' and 'en'
|
||||
```
|
||||
|
117
docs/Methods.md
117
docs/Methods.md
@ -22,7 +22,7 @@ interface InitOptions {
|
||||
**Example**:
|
||||
|
||||
```js
|
||||
import { init, getClientLocale } from 'svelte-i18n'
|
||||
import { init } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
@ -68,47 +68,100 @@ init({
|
||||
<!-- 123.456,79 € -->
|
||||
```
|
||||
|
||||
#### getClientLocale
|
||||
#### getLocaleFromHostname
|
||||
|
||||
> `import { getClientLocale } from 'svelte-i18n'`
|
||||
> `import { getLocaleFromHostname } from 'svelte-i18n'
|
||||
|
||||
`getClientLocale(options: GetClientLocaleOptions): void`
|
||||
|
||||
Optional utility method to help getting the initial locale of a user. Use it together with the [`init()`](#init) method.
|
||||
|
||||
```ts
|
||||
interface GetClientLocaleOptions {
|
||||
// the fallback locale to use if no message is found in the current one
|
||||
fallback?: string
|
||||
// when 'true', check the 'window.navigator.language' to set the current locale
|
||||
navigator?: boolean
|
||||
// key to look for a locale on 'window.location.search'
|
||||
// 'example.com?locale=en-US'
|
||||
search?: string
|
||||
// key to look for a locale on 'window.location.hash'
|
||||
// 'example.com#locale=en-US'
|
||||
hash?: string
|
||||
// pattern to look in the window.location.pathname.
|
||||
// It returns the first capturing group.
|
||||
pathname?: RegExp
|
||||
// pattern to look in the window.location.hostname.
|
||||
// It returns the first capturing group.
|
||||
hostname?: RegExp
|
||||
}
|
||||
```
|
||||
`getLocaleFromHostname(hostnamePattern: RegExp): string`
|
||||
Utility method to help getting a initial locale based on a pattern of the current `hostname`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```js
|
||||
import { init, getClientLocale } from 'svelte-i18n'
|
||||
import { init, getLocaleFromHostname } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getClientLocale({
|
||||
// based on the user's browser
|
||||
navigator: true,
|
||||
}),
|
||||
initialLocale: getLocaleFromHostname(/^(.*?)\./),
|
||||
})
|
||||
```
|
||||
|
||||
#### getLocaleFromPathname
|
||||
|
||||
> `import { getLocaleFromPathname } from 'svelte-i18n'
|
||||
|
||||
`getLocaleFromPathname(pathnamePattern: RegExp): string`
|
||||
|
||||
Utility method to help getting a initial locale based on a pattern of the current `pathname`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```js
|
||||
import { init, getLocaleFromPathname } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getLocaleFromPathname(/^\/(.*?)\//),
|
||||
})
|
||||
```
|
||||
|
||||
#### getLocaleFromNavigator
|
||||
|
||||
> `import { getLocaleFromNavigator } from 'svelte-i18n'
|
||||
|
||||
`getLocaleFromNavigator(): string`
|
||||
|
||||
Utility method to help getting a initial locale based on the browser's `navigator` settings.
|
||||
|
||||
**Example**:
|
||||
|
||||
```js
|
||||
import { init, getLocaleFromNavigator } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getLocaleFromNavigator(),
|
||||
})
|
||||
```
|
||||
|
||||
#### getLocaleFromQueryString
|
||||
|
||||
> `import { getLocaleFromQueryString } from 'svelte-i18n'
|
||||
|
||||
`getLocaleFromQueryString(queryKey: string): string`
|
||||
|
||||
Utility method to help getting a initial locale based on a query string value.
|
||||
|
||||
```js
|
||||
import { init, getLocaleFromQueryString } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getLocaleFromQueryString('lang'),
|
||||
})
|
||||
```
|
||||
|
||||
#### getLocaleFromHash
|
||||
|
||||
> `import { getLocaleFromHash } from 'svelte-i18n'
|
||||
|
||||
`getLocaleFromHash(): string`
|
||||
|
||||
Utility method to help getting a initial locale based on a hash `{key}={value}` string.
|
||||
|
||||
**Example**:
|
||||
|
||||
```js
|
||||
import { init, getLocaleFromHash } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
// fallback to en if current locale is not in the dictionary
|
||||
fallbackLocale: 'en',
|
||||
initialLocale: getLocaleFromHash('lang'),
|
||||
})
|
||||
```
|
||||
|
||||
|
@ -71,7 +71,7 @@ capital($_('message.id'))
|
||||
In `v2`, the [`init`](/docs/Methods.md#init) method could automatically set the initial locale based on some heuristcs from the client:
|
||||
|
||||
```js
|
||||
import { init, getClientLocale } from 'svelte-i18n'
|
||||
import { init } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
initialLocale: {
|
||||
@ -80,13 +80,19 @@ init({
|
||||
})
|
||||
```
|
||||
|
||||
However, many people didn't need that kind of extra weight in their apps. So in `v3`, to have the same behavior as `v2`, you have to import the [`getClientLocale`](/docs/Methods.md#getclientlocale) method.
|
||||
However, many people didn't need that kind of extra weight in their apps. So in `v3` you have to explicitly import the utility desired:
|
||||
|
||||
- [`getLocaleFromHostname`](/docs/Methods.md#getlocalefromhostname)
|
||||
- [`getLocaleFromPathname`](/docs/Methods.md#getlocalefrompathname)
|
||||
- [`getLocaleFromNavigator`](/docs/Methods.md#getlocalefromnavigator)
|
||||
- [`getLocaleFromQueryString`](/docs/Methods.md#getlocalefromquerystring)
|
||||
- [`getLocaleFromHash`](/docs/Methods.md#getlocalefromhash)
|
||||
|
||||
```js
|
||||
import { init, getClientLocale } from 'svelte-i18n'
|
||||
import { init, getLocaleFromNavigator } from 'svelte-i18n'
|
||||
|
||||
init({
|
||||
initialLocale: getClientLocale({ ... })
|
||||
initialLocale: getLocaleFromNavigator(),
|
||||
})
|
||||
```
|
||||
|
||||
|
9555
package-lock.json
generated
Normal file
9555
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "svelte-i18n",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"main": "dist/runtime.cjs.js",
|
||||
"module": "dist/runtime.esm.js",
|
||||
"types": "types/runtime/index.d.ts",
|
||||
|
@ -1,59 +0,0 @@
|
||||
import { GetClientLocaleOptions } from '../types'
|
||||
|
||||
const getFromQueryString = (queryString: string, key: string) => {
|
||||
const keyVal = queryString.split('&').find(i => i.indexOf(`${key}=`) === 0)
|
||||
|
||||
if (keyVal) {
|
||||
return keyVal.split('=').pop()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const getFirstMatch = (base: string, pattern: RegExp) => {
|
||||
const match = pattern.exec(base)
|
||||
// istanbul ignore if
|
||||
if (!match) return null
|
||||
// istanbul ignore else
|
||||
return match[1] || null
|
||||
}
|
||||
|
||||
export const getClientLocale = ({
|
||||
navigator,
|
||||
hash,
|
||||
search,
|
||||
pathname,
|
||||
hostname,
|
||||
}: GetClientLocaleOptions) => {
|
||||
let locale
|
||||
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
|
||||
if (hostname) {
|
||||
locale = getFirstMatch(window.location.hostname, hostname)
|
||||
if (locale) return locale
|
||||
}
|
||||
|
||||
if (pathname) {
|
||||
locale = getFirstMatch(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 = getFromQueryString(window.location.search.substr(1), search)
|
||||
if (locale) return locale
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
locale = getFromQueryString(window.location.hash.substr(1), hash)
|
||||
if (locale) return locale
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
46
src/runtime/includes/localeGetters.ts
Normal file
46
src/runtime/includes/localeGetters.ts
Normal file
@ -0,0 +1,46 @@
|
||||
const getFromQueryString = (queryString: string, key: string) => {
|
||||
const keyVal = queryString.split('&').find(i => i.indexOf(`${key}=`) === 0)
|
||||
|
||||
if (keyVal) {
|
||||
return keyVal.split('=').pop()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const getFirstMatch = (base: string, pattern: RegExp) => {
|
||||
const match = pattern.exec(base)
|
||||
// istanbul ignore if
|
||||
if (!match) return null
|
||||
// istanbul ignore else
|
||||
return match[1] || null
|
||||
}
|
||||
|
||||
export const getLocaleFromHostname = (hostname: RegExp) => {
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
return getFirstMatch(window.location.hostname, hostname)
|
||||
}
|
||||
|
||||
export const getLocaleFromPathname = (pathname: RegExp) => {
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
return getFirstMatch(window.location.pathname, pathname)
|
||||
}
|
||||
|
||||
export const getLocaleFromNavigator = () => {
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
return window.navigator.language || window.navigator.languages[0]
|
||||
}
|
||||
|
||||
export const getLocaleFromQueryString = (search: string) => {
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
return getFromQueryString(window.location.search.substr(1), search)
|
||||
}
|
||||
|
||||
export const getLocaleFromHash = (hash: string) => {
|
||||
// istanbul ignore next
|
||||
if (typeof window === 'undefined') return null
|
||||
return getFromQueryString(window.location.hash.substr(1), hash)
|
||||
}
|
@ -13,7 +13,13 @@ export function waitLocale(locale?: string) {
|
||||
}
|
||||
|
||||
export { init } from './configs'
|
||||
export { getClientLocale } from './includes/getClientLocale'
|
||||
export {
|
||||
getLocaleFromHostname,
|
||||
getLocaleFromPathname,
|
||||
getLocaleFromNavigator,
|
||||
getLocaleFromQueryString,
|
||||
getLocaleFromHash,
|
||||
} from './includes/localeGetters'
|
||||
|
||||
export { $locale as locale } from './stores/locale'
|
||||
|
||||
|
@ -47,17 +47,9 @@ export interface MessagesLoader {
|
||||
(): Promise<any>
|
||||
}
|
||||
|
||||
export interface GetClientLocaleOptions {
|
||||
navigator?: boolean
|
||||
hash?: string
|
||||
search?: string
|
||||
pathname?: RegExp
|
||||
hostname?: RegExp
|
||||
}
|
||||
|
||||
export interface ConfigureOptions {
|
||||
fallbackLocale: string
|
||||
initialLocale?: string | GetClientLocaleOptions
|
||||
initialLocale?: string
|
||||
formats?: Partial<Formats>
|
||||
loadingDelay?: number
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { getClientLocale } from '../../../src/runtime/includes/getClientLocale'
|
||||
import {
|
||||
getLocaleFromQueryString,
|
||||
getLocaleFromHash,
|
||||
getLocaleFromNavigator,
|
||||
getLocaleFromPathname,
|
||||
getLocaleFromHostname,
|
||||
} from '../../../src/runtime/includes/localeGetters'
|
||||
import { flatObj } from '../../../src/runtime/includes/flatObj'
|
||||
|
||||
describe('getting client locale', () => {
|
||||
@ -14,96 +20,30 @@ describe('getting client locale', () => {
|
||||
|
||||
test('gets the locale based on the passed hash parameter', () => {
|
||||
window.location.hash = '#locale=en-US&lang=pt-BR'
|
||||
expect(
|
||||
getClientLocale({
|
||||
hash: 'lang',
|
||||
})
|
||||
).toBe('pt-BR')
|
||||
expect(getLocaleFromHash('lang')).toBe('pt-BR')
|
||||
})
|
||||
|
||||
test('gets the locale based on the passed search parameter', () => {
|
||||
window.location.search = '?locale=en-US&lang=pt-BR'
|
||||
expect(
|
||||
getClientLocale({
|
||||
search: 'lang',
|
||||
})
|
||||
).toBe('pt-BR')
|
||||
expect(getLocaleFromQueryString('lang')).toBe('pt-BR')
|
||||
})
|
||||
|
||||
test('gets the locale based on the navigator language', () => {
|
||||
expect(
|
||||
getClientLocale({
|
||||
navigator: true,
|
||||
})
|
||||
).toBe(window.navigator.language)
|
||||
expect(getLocaleFromNavigator()).toBe(window.navigator.language)
|
||||
})
|
||||
|
||||
test('gets the locale based on the pathname', () => {
|
||||
window.location.pathname = '/en-US/foo/'
|
||||
expect(
|
||||
getClientLocale({
|
||||
pathname: /^\/(.*?)\//,
|
||||
})
|
||||
).toBe('en-US')
|
||||
expect(getLocaleFromPathname(/^\/(.*?)\//)).toBe('en-US')
|
||||
})
|
||||
|
||||
test('gets the locale base on the hostname', () => {
|
||||
window.location.hostname = 'pt.example.com'
|
||||
expect(
|
||||
getClientLocale({
|
||||
hostname: /^(.*?)\./,
|
||||
})
|
||||
).toBe('pt')
|
||||
})
|
||||
|
||||
test('hostname precedes pathname', () => {
|
||||
window.location.pathname = '/en-US/foo/'
|
||||
window.location.hostname = 'pt.example.com'
|
||||
expect(
|
||||
getClientLocale({
|
||||
hostname: /^(.*?)\./,
|
||||
pathname: /^\/(.*?)\//,
|
||||
})
|
||||
).toBe('pt')
|
||||
})
|
||||
|
||||
test('pathname precedes navigator', () => {
|
||||
window.location.pathname = '/it-IT/foo/'
|
||||
expect(
|
||||
getClientLocale({
|
||||
pathname: /^\/(.*?)\//,
|
||||
navigator: true,
|
||||
})
|
||||
).toBe('it-IT')
|
||||
})
|
||||
|
||||
test('navigator precedes search', () => {
|
||||
window.location.search = '?lang=pt-BR'
|
||||
expect(
|
||||
getClientLocale({
|
||||
navigator: true,
|
||||
search: 'lang',
|
||||
})
|
||||
).toBe('en-US')
|
||||
})
|
||||
|
||||
test('search precedes hash', () => {
|
||||
window.location.hash = '#lang=pt-BR'
|
||||
window.location.search = '?lang=it-IT'
|
||||
expect(
|
||||
getClientLocale({
|
||||
hash: 'lang',
|
||||
search: 'lang',
|
||||
})
|
||||
).toBe('it-IT')
|
||||
expect(getLocaleFromHostname(/^(.*?)\./)).toBe('pt')
|
||||
})
|
||||
|
||||
test('returns null if no locale was found', () => {
|
||||
expect(
|
||||
getClientLocale({
|
||||
search: 'lang',
|
||||
})
|
||||
).toBe(null)
|
||||
expect(getLocaleFromQueryString('lang')).toBe(null)
|
||||
})
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user