Skip to content

Commit

Permalink
feat: 🎸 also look for message in generic locale
Browse files Browse the repository at this point in the history
Issues: #19
  • Loading branch information
kaisermann committed Nov 22, 2019
1 parent 31d96f2 commit e5d7b84
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 75 deletions.
29 changes: 19 additions & 10 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -14,30 +14,39 @@ 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] }
}
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 = {}) => {
Expand Down
30 changes: 5 additions & 25 deletions src/client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
// }
43 changes: 21 additions & 22 deletions test/client/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -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')
Expand All @@ -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')
})

Expand All @@ -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?',
)
})
})

Expand All @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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 changes: 3 additions & 0 deletions test/fixtures/en-GB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"sneakers": "trainers"
}
3 changes: 2 additions & 1 deletion test/fixtures/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 2 additions & 1 deletion test/fixtures/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 2 additions & 1 deletion test/fixtures/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 1 addition & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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==
Expand Down

0 comments on commit e5d7b84

Please sign in to comment.