mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-11-16 09:59:58 +01:00
parent
31d96f24ff
commit
e5d7b84241
@ -2,7 +2,7 @@ import { writable, derived } from 'svelte/store'
|
||||
import resolvePath from 'object-resolve-path'
|
||||
import memoize from 'micro-memoize'
|
||||
|
||||
import { capital, title, upper, lower, getClientLocale } from './utils'
|
||||
import { capital, title, upper, lower, getClientLocale, getGenericLocaleFrom } from './utils'
|
||||
import { MessageObject, Formatter } from './types'
|
||||
import {
|
||||
getMessageFormatter,
|
||||
@ -14,7 +14,9 @@ import {
|
||||
let currentLocale: string
|
||||
let currentDictionary: Record<string, any>
|
||||
|
||||
function getAvailableLocale(locale: string) {
|
||||
const hasLocale = (locale: string) => locale in currentDictionary
|
||||
|
||||
function getAvailableLocale(locale: string): { locale: string; loader?: () => Promise<any> } {
|
||||
if (currentDictionary[locale]) {
|
||||
if (typeof currentDictionary[locale] === 'function') {
|
||||
return { locale, loader: currentDictionary[locale] }
|
||||
@ -22,22 +24,29 @@ function getAvailableLocale(locale: string) {
|
||||
return { locale }
|
||||
}
|
||||
|
||||
locale = locale.split('-').shift() //
|
||||
if (currentDictionary[locale]) {
|
||||
if (typeof currentDictionary[locale] === 'function') {
|
||||
return { locale, loader: currentDictionary[locale] }
|
||||
}
|
||||
return { locale }
|
||||
locale = getGenericLocaleFrom(locale)
|
||||
if (locale != null) {
|
||||
return getAvailableLocale(locale)
|
||||
}
|
||||
|
||||
return { locale: null }
|
||||
}
|
||||
|
||||
const lookupMessage = memoize((path: string, locale: string) => {
|
||||
const lookupMessage = memoize((path: string, locale: string): string => {
|
||||
if (path in currentDictionary[locale]) {
|
||||
return currentDictionary[locale][path]
|
||||
}
|
||||
return resolvePath(currentDictionary[locale], path)
|
||||
|
||||
const message = resolvePath(currentDictionary[locale], path)
|
||||
if (message == null) {
|
||||
const genericLocale = getGenericLocaleFrom(locale)
|
||||
if (genericLocale != null && hasLocale(genericLocale)) {
|
||||
return lookupMessage(path, genericLocale)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return message
|
||||
})
|
||||
|
||||
const formatMessage: Formatter = (id, options = {}) => {
|
||||
|
@ -5,12 +5,15 @@ export const title = (str: string) =>
|
||||
export const upper = (str: string) => str.toLocaleUpperCase()
|
||||
export const lower = (str: string) => str.toLocaleLowerCase()
|
||||
|
||||
export function getGenericLocaleFrom(locale: string) {
|
||||
return locale.length > 2 ? locale.split('-').shift() : null
|
||||
}
|
||||
|
||||
export const getClientLocale = ({
|
||||
navigator,
|
||||
hash,
|
||||
search,
|
||||
default: defaultLocale,
|
||||
fallback = defaultLocale,
|
||||
}: {
|
||||
navigator?: boolean
|
||||
hash?: string
|
||||
@ -47,28 +50,5 @@ export const getClientLocale = ({
|
||||
}
|
||||
}
|
||||
|
||||
return locale || defaultLocale || fallback
|
||||
return locale || defaultLocale
|
||||
}
|
||||
|
||||
// function mergeDeep(target: any, source: any) {
|
||||
// const isObject = (obj: any) => obj && typeof obj === 'object'
|
||||
|
||||
// if (!isObject(target) || !isObject(source)) {
|
||||
// return source
|
||||
// }
|
||||
|
||||
// Object.keys(source).forEach(key => {
|
||||
// const targetValue = target[key]
|
||||
// const sourceValue = source[key]
|
||||
|
||||
// if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
|
||||
// target[key] = targetValue.concat(sourceValue)
|
||||
// } else if (isObject(targetValue) && isObject(sourceValue)) {
|
||||
// target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
|
||||
// } else {
|
||||
// target[key] = sourceValue
|
||||
// }
|
||||
// })
|
||||
|
||||
// return target
|
||||
// }
|
||||
|
@ -16,6 +16,7 @@ let currentLocale: string
|
||||
const dict = {
|
||||
pt: require('../fixtures/pt.json'),
|
||||
en: require('../fixtures/en.json'),
|
||||
'en-GB': require('../fixtures/en-GB.json'),
|
||||
}
|
||||
|
||||
format.subscribe(formatFn => {
|
||||
@ -61,6 +62,13 @@ describe('dictionary', () => {
|
||||
})
|
||||
|
||||
describe('formatting', () => {
|
||||
it('should translate to current locale', () => {
|
||||
locale.set('pt')
|
||||
expect(_('switch.lang')).toBe('Trocar idioma')
|
||||
locale.set('en')
|
||||
expect(_('switch.lang')).toBe('Switch language')
|
||||
})
|
||||
|
||||
it('should fallback to message id if id is not found', () => {
|
||||
locale.set('en')
|
||||
expect(_('batatinha.quente')).toBe('batatinha.quente')
|
||||
@ -71,10 +79,9 @@ describe('formatting', () => {
|
||||
expect(_('batatinha.quente', { default: 'Hot Potato' })).toBe('Hot Potato')
|
||||
})
|
||||
|
||||
it('should translate to current locale', () => {
|
||||
locale.set('pt')
|
||||
expect(_('switch.lang')).toBe('Trocar idioma')
|
||||
locale.set('en')
|
||||
it('should fallback to generic locale XX if id not found in XX-YY', () => {
|
||||
locale.set('en-GB')
|
||||
expect(_('sneakers')).toBe('trainers')
|
||||
expect(_('switch.lang')).toBe('Switch language')
|
||||
})
|
||||
|
||||
@ -91,15 +98,15 @@ describe('formatting', () => {
|
||||
})
|
||||
|
||||
it('should interpolate message with variables', () => {
|
||||
expect(_('greeting.message', { values: { name: 'Chris' } })).toBe(
|
||||
'Hello Chris, how are you?',
|
||||
)
|
||||
locale.set('en')
|
||||
expect(_('greeting.message', { values: { name: 'Chris' } })).toBe('Hello Chris, how are you?')
|
||||
})
|
||||
|
||||
it('should interpolate message with variables according to passed locale', () => {
|
||||
expect(
|
||||
_('greeting.message', { values: { name: 'Chris' }, locale: 'pt' }),
|
||||
).toBe('Olá Chris, como vai?')
|
||||
locale.set('en')
|
||||
expect(_('greeting.message', { values: { name: 'Chris' }, locale: 'pt' })).toBe(
|
||||
'Olá Chris, como vai?',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -126,9 +133,7 @@ describe('utilities', () => {
|
||||
})
|
||||
|
||||
it('should get the locale based on the navigator language', () => {
|
||||
expect(getClientLocale({ navigator: true })).toBe(
|
||||
window.navigator.language,
|
||||
)
|
||||
expect(getClientLocale({ navigator: true })).toBe(window.navigator.language)
|
||||
})
|
||||
|
||||
it('should get the fallback locale', () => {
|
||||
@ -163,9 +168,7 @@ describe('utilities', () => {
|
||||
locale.set('en')
|
||||
expect(_.time(date)).toBe('11:45 PM')
|
||||
expect(_.time(date, { format: 'medium' })).toBe('11:45:00 PM')
|
||||
expect(_.time(date, { format: 'medium', locale: 'pt-BR' })).toBe(
|
||||
'23:45:00',
|
||||
)
|
||||
expect(_.time(date, { format: 'medium', locale: 'pt-BR' })).toBe('23:45:00')
|
||||
})
|
||||
|
||||
it('should format a date value', () => {
|
||||
@ -224,12 +227,8 @@ describe('custom formats', () => {
|
||||
expect(_.number(123123123, { format: 'usd' })).toContain('$123,123,123.00')
|
||||
expect(_.number(123123123, { format: 'brl' })).toContain('R$123,123,123.00')
|
||||
|
||||
expect(_.date(new Date(2019, 0, 1), { format: 'customDate' })).toEqual(
|
||||
'2019 AD',
|
||||
)
|
||||
expect(_.date(new Date(2019, 0, 1), { format: 'customDate' })).toEqual('2019 AD')
|
||||
|
||||
expect(
|
||||
_.time(new Date(2019, 0, 1, 2, 0, 0), { format: 'customTime' }),
|
||||
).toEqual('Jan, 02')
|
||||
expect(_.time(new Date(2019, 0, 1, 2, 0, 0), { format: 'customTime' })).toEqual('Jan, 02')
|
||||
})
|
||||
})
|
||||
|
3
test/fixtures/en-GB.json
vendored
Normal file
3
test/fixtures/en-GB.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"sneakers": "trainers"
|
||||
}
|
3
test/fixtures/en.json
vendored
3
test/fixtures/en.json
vendored
@ -6,5 +6,6 @@
|
||||
"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}}"
|
||||
"cats": "I have {n, number} {n,plural,one{cat}other{cats}}",
|
||||
"sneakers": "sneakers"
|
||||
}
|
||||
|
3
test/fixtures/es.json
vendored
3
test/fixtures/es.json
vendored
@ -6,5 +6,6 @@
|
||||
"message": "Hola {name}, cómo estás?"
|
||||
},
|
||||
"photos": "Tienes {n, plural, =0 {0 fotos.} =1 {una foto.} other {# fotos.}}",
|
||||
"cats": "Yo tengo {n, number} {n,plural,one{gato}other{gatos}}"
|
||||
"cats": "Yo tengo {n, number} {n,plural,one{gato}other{gatos}}",
|
||||
"sneakers": "zapatillas"
|
||||
}
|
||||
|
3
test/fixtures/pt.json
vendored
3
test/fixtures/pt.json
vendored
@ -6,5 +6,6 @@
|
||||
"message": "Olá {name}, como vai?"
|
||||
},
|
||||
"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}}"
|
||||
"cats": "Tenho {n, number} {n,plural,=0{gatos}one{gato}other{gatos}}",
|
||||
"sneakers": "tênis"
|
||||
}
|
||||
|
16
yarn.lock
16
yarn.lock
@ -4322,11 +4322,6 @@ require-main-filename@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
require-relative@^0.8.7:
|
||||
version "0.8.7"
|
||||
resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de"
|
||||
integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=
|
||||
|
||||
resolve-cwd@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
|
||||
@ -4409,15 +4404,6 @@ rollup-plugin-commonjs@^10.1.0:
|
||||
resolve "^1.11.0"
|
||||
rollup-pluginutils "^2.8.1"
|
||||
|
||||
rollup-plugin-svelte@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-5.1.1.tgz#0094f94e7e6ff7579bcd9f7769b454751ba670e1"
|
||||
integrity sha512-wP3CnKHjR4fZUgNm5Iey7eItnxwnH/nAw568WJ8dpMSchBxxZ/DmKSx8e6h8k/B6SwG1wfGvWehadFJHcuFFSw==
|
||||
dependencies:
|
||||
require-relative "^0.8.7"
|
||||
rollup-pluginutils "^2.3.3"
|
||||
sourcemap-codec "^1.4.4"
|
||||
|
||||
rollup-plugin-terser@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.1.2.tgz#3e41256205cb75f196fc70d4634227d1002c255c"
|
||||
@ -4447,7 +4433,7 @@ rollup-pluginutils@2.8.1:
|
||||
dependencies:
|
||||
estree-walker "^0.6.1"
|
||||
|
||||
rollup-pluginutils@^2.3.3, rollup-pluginutils@^2.8.1:
|
||||
rollup-pluginutils@^2.8.1:
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
|
||||
integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
|
||||
|
Loading…
Reference in New Issue
Block a user