mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-11-16 09:59:58 +01:00
Add method to get client locale
This commit is contained in:
parent
563b400193
commit
8de3d27e09
20
README.md
20
README.md
@ -15,7 +15,7 @@
|
||||
The `locale` store defines what is the current locale.
|
||||
|
||||
```js
|
||||
import { locale, dictionary } from 'svelte-i18n'
|
||||
import { locale, dictionary, getClientLocale } from 'svelte-i18n'
|
||||
|
||||
// Set the current locale to en-US
|
||||
locale.set('en-US')
|
||||
@ -24,8 +24,26 @@ locale.set('en-US')
|
||||
locale.subscribe(() => {
|
||||
console.log('locale change')
|
||||
})
|
||||
|
||||
// svelte-i18n exports a method to help getting the current client locale
|
||||
locale.set(
|
||||
getClientLocale({
|
||||
// the fallback locale, if didn't find any
|
||||
fallback: 'en-US',
|
||||
// set to 'true' to check the 'window.navigator.language'
|
||||
navigator: true,
|
||||
// set the key name to look for a locale on 'window.location.search'
|
||||
// 'example.com?locale=en-US'
|
||||
search: 'lang',
|
||||
// set the key name to look for a locale on 'window.location.hash'
|
||||
// 'example.com#locale=en-US'
|
||||
hash: 'locale',
|
||||
}),
|
||||
)
|
||||
```
|
||||
|
||||
If a locale with the format `xx-YY` is not found, `svelte-i18n` looks for the locale `xx` as well.
|
||||
|
||||
---
|
||||
|
||||
### The dictionary
|
||||
|
@ -1,12 +1,4 @@
|
||||
import { locale, dictionary } from 'svelte-i18n'
|
||||
|
||||
// setting the locale
|
||||
locale.set('pt')
|
||||
|
||||
// subscribe to locale changes
|
||||
locale.subscribe(() => {
|
||||
console.log('locale change')
|
||||
})
|
||||
import { locale, dictionary, getClientLocale } from 'svelte-i18n'
|
||||
|
||||
// defining a locale dictionary
|
||||
dictionary.set({
|
||||
@ -16,7 +8,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: {
|
||||
@ -25,7 +18,20 @@ 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.}}',
|
||||
cats: 'I have {n, number} {n,plural,one{cat}other{cats}}'
|
||||
photos:
|
||||
'You have {n, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}',
|
||||
cats: 'I have {n, number} {n,plural,one{cat}other{cats}}',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
locale.set(
|
||||
getClientLocale({
|
||||
navigator: true,
|
||||
hash: 'lang',
|
||||
default: 'pt',
|
||||
}),
|
||||
)
|
||||
|
||||
locale.subscribe(l => {
|
||||
console.log('locale change', l)
|
||||
})
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "svelte-i18n",
|
||||
"version": "1.0.6-beta",
|
||||
"version": "1.0.7",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
38
src/index.js
38
src/index.js
@ -2,11 +2,26 @@ import { writable, derived } from 'svelte/store'
|
||||
import resolvePath from 'object-resolve-path'
|
||||
import IntlMessageFormat from 'intl-messageformat'
|
||||
import memoize from 'micro-memoize'
|
||||
import { capital, title, upper, lower } from './utils.js'
|
||||
import { capital, title, upper, lower, getClientLocale } from './utils.js'
|
||||
|
||||
let currentLocale
|
||||
let currentDictionary
|
||||
|
||||
const getAvailableLocale = newLocale => {
|
||||
if (currentDictionary[newLocale]) return newLocale
|
||||
|
||||
// istanbul ignore else
|
||||
if (typeof newLocale === 'string') {
|
||||
const fallbackLocale = newLocale.split('-').shift()
|
||||
|
||||
if (currentDictionary[fallbackLocale]) {
|
||||
return fallbackLocale
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const getMessageFormatter = memoize(
|
||||
(message, locale, formats) => new IntlMessageFormat(message, locale, formats),
|
||||
)
|
||||
@ -37,22 +52,16 @@ const getLocalizedMessage = (path, interpolations, locale = currentLocale) => {
|
||||
|
||||
getLocalizedMessage.time = (t, format = 'short', locale) =>
|
||||
formatMessage(`{t,time,${format}}`, { t }, locale)
|
||||
|
||||
getLocalizedMessage.date = (d, format = 'short', locale) =>
|
||||
formatMessage(`{d,date,${format}}`, { d }, locale)
|
||||
|
||||
getLocalizedMessage.number = (n, locale) =>
|
||||
formatMessage('{n,number}', { n }, locale)
|
||||
|
||||
getLocalizedMessage.capital = (path, interpolations, locale) =>
|
||||
capital(getLocalizedMessage(path, interpolations, locale))
|
||||
|
||||
getLocalizedMessage.title = (path, interpolations, locale) =>
|
||||
title(getLocalizedMessage(path, interpolations, locale))
|
||||
|
||||
getLocalizedMessage.upper = (path, interpolations, locale) =>
|
||||
upper(getLocalizedMessage(path, interpolations, locale))
|
||||
|
||||
getLocalizedMessage.lower = (path, interpolations, locale) =>
|
||||
lower(getLocalizedMessage(path, interpolations, locale))
|
||||
|
||||
@ -62,10 +71,21 @@ dictionary.subscribe(newDictionary => {
|
||||
})
|
||||
|
||||
const locale = writable({})
|
||||
const localeSet = locale.set
|
||||
locale.set = newLocale => {
|
||||
const availableLocale = getAvailableLocale(newLocale)
|
||||
if (availableLocale) {
|
||||
return localeSet(availableLocale)
|
||||
}
|
||||
|
||||
console.warn(`[svelte-i18n] Locale "${newLocale}" not found.`)
|
||||
return localeSet(newLocale)
|
||||
}
|
||||
locale.update = fn => localeSet(fn(currentLocale))
|
||||
locale.subscribe(newLocale => {
|
||||
currentLocale = newLocale
|
||||
})
|
||||
|
||||
const format = derived(locale, () => getLocalizedMessage)
|
||||
const format = derived([locale, dictionary], () => getLocalizedMessage)
|
||||
|
||||
export { locale, format as _, format, dictionary }
|
||||
export { locale, format as _, format, dictionary, getClientLocale }
|
||||
|
33
src/utils.js
33
src/utils.js
@ -2,3 +2,36 @@ export const capital = str => str.replace(/(^|\s)\S/, l => l.toUpperCase())
|
||||
export const title = str => str.replace(/(^|\s)\S/g, l => l.toUpperCase())
|
||||
export const upper = str => str.toLocaleUpperCase()
|
||||
export const lower = str => str.toLocaleLowerCase()
|
||||
|
||||
export const getClientLocale = ({ navigator, hash, search, fallback } = {}) => {
|
||||
let locale
|
||||
|
||||
const getFromURL = (urlPart, key) => {
|
||||
const keyVal = urlPart
|
||||
.substr(1)
|
||||
.split('&')
|
||||
.find(i => i.indexOf(key) === 0)
|
||||
|
||||
if (keyVal) {
|
||||
return keyVal.split('=').pop()
|
||||
}
|
||||
}
|
||||
|
||||
// istanbul ignore else
|
||||
if (typeof window !== 'undefined') {
|
||||
if (navigator) {
|
||||
// istanbul ignore next
|
||||
locale = window.navigator.language || window.navigator.languages[0]
|
||||
}
|
||||
|
||||
if (search) {
|
||||
locale = getFromURL(window.location.search, search)
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
locale = getFromURL(window.location.hash, hash)
|
||||
}
|
||||
}
|
||||
|
||||
return locale || fallback
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { dictionary, locale, format } from '../src/index'
|
||||
import { dictionary, locale, format, getClientLocale } from '../src/index'
|
||||
|
||||
let _
|
||||
let currentLocale
|
||||
@ -42,7 +42,19 @@ it('should change locale', () => {
|
||||
expect(currentLocale).toBe('en')
|
||||
})
|
||||
|
||||
it('should fallback to message id if id is not found', () => {
|
||||
it('should fallback to existing locale', () => {
|
||||
locale.set('pt-BR')
|
||||
expect(currentLocale).toBe('pt')
|
||||
|
||||
locale.set('en-US')
|
||||
expect(currentLocale).toBe('en')
|
||||
|
||||
locale.set('non-existent')
|
||||
expect(currentLocale).toBe('non-existent')
|
||||
})
|
||||
|
||||
it('should fallback to message id if id is not found', () => {
|
||||
locale.set('en')
|
||||
expect(_('batatinha')).toBe('batatinha')
|
||||
})
|
||||
|
||||
@ -71,39 +83,74 @@ it('should interpolate message with variables according to passed locale', () =>
|
||||
})
|
||||
|
||||
describe('utilities', () => {
|
||||
beforeAll(() => {
|
||||
locale.set('en')
|
||||
describe('get locale', () => {
|
||||
beforeEach(() => {
|
||||
delete window.location
|
||||
window.location = {
|
||||
hash: '',
|
||||
search: '',
|
||||
}
|
||||
})
|
||||
|
||||
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')
|
||||
})
|
||||
|
||||
it('should get the locale based on the navigator language', () => {
|
||||
expect(getClientLocale({ navigator: true })).toBe(
|
||||
window.navigator.language,
|
||||
)
|
||||
})
|
||||
|
||||
it('should get the fallback locale', () => {
|
||||
expect(getClientLocale({ navigator: false, fallback: 'pt' })).toBe('pt')
|
||||
expect(getClientLocale({ hash: 'locale', fallback: 'pt' })).toBe('pt')
|
||||
})
|
||||
})
|
||||
|
||||
it('should capital a translated message', () => {
|
||||
expect(_.capital('hi')).toBe('Hi yo')
|
||||
})
|
||||
describe('format utils', () => {
|
||||
beforeAll(() => {
|
||||
locale.set('en')
|
||||
})
|
||||
|
||||
it('should title a translated message', () => {
|
||||
expect(_.title('hi')).toBe('Hi Yo')
|
||||
})
|
||||
it('should capital a translated message', () => {
|
||||
expect(_.capital('hi')).toBe('Hi yo')
|
||||
})
|
||||
|
||||
it('should lowercase a translated message', () => {
|
||||
expect(_.lower('hi')).toBe('hi yo')
|
||||
})
|
||||
it('should title a translated message', () => {
|
||||
expect(_.title('hi')).toBe('Hi Yo')
|
||||
})
|
||||
|
||||
it('should uppercase a translated message', () => {
|
||||
expect(_.upper('hi')).toBe('HI YO')
|
||||
})
|
||||
it('should lowercase a translated message', () => {
|
||||
expect(_.lower('hi')).toBe('hi yo')
|
||||
})
|
||||
|
||||
const date = new Date(2019, 3, 24, 23, 45)
|
||||
it('should format a time value', () => {
|
||||
locale.set('en')
|
||||
expect(_.time(date)).toBe('11:45 PM')
|
||||
expect(_.time(date, 'medium')).toBe('11:45:00 PM')
|
||||
})
|
||||
it('should uppercase a translated message', () => {
|
||||
expect(_.upper('hi')).toBe('HI YO')
|
||||
})
|
||||
|
||||
it('should format a date value', () => {
|
||||
expect(_.date(date)).toBe('4/24/19')
|
||||
expect(_.date(date, 'medium')).toBe('Apr 24, 2019')
|
||||
})
|
||||
// number
|
||||
const date = new Date(2019, 3, 24, 23, 45)
|
||||
it('should format a time value', () => {
|
||||
locale.set('en')
|
||||
expect(_.time(date)).toBe('11:45 PM')
|
||||
expect(_.time(date, 'medium')).toBe('11:45:00 PM')
|
||||
})
|
||||
|
||||
it('should format a date value', () => {
|
||||
expect(_.date(date)).toBe('4/24/19')
|
||||
expect(_.date(date, 'medium')).toBe('Apr 24, 2019')
|
||||
})
|
||||
// number
|
||||
it('should format a date value', () => {
|
||||
expect(_.number(123123123)).toBe('123,123,123')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user