test: 💍 add some tests for locale related methods

This commit is contained in:
Christian Kaisermann 2019-11-25 17:16:38 -03:00
parent a4c9507b01
commit 07fb37e325
3 changed files with 298 additions and 209 deletions

View File

@ -6,26 +6,36 @@ import { GetClientLocaleOptions } from '../types'
import { getAvailableLocale } from './dictionary' import { getAvailableLocale } from './dictionary'
let fallback: string = null let fallbackLocale: string = null
let current: string let current: string
const $locale = writable(null) const $locale = writable(null)
export function getFallbackLocale() { export function getFallbackLocale() {
return fallback return fallbackLocale
} }
export function setfallbackLocale(locale: string) { export function setFallbackLocale(locale: string) {
fallback = locale fallbackLocale = locale
} }
export function isFallbackLocaleOf(localeA: string, localeB: string) { export function isFallbackLocaleOf(localeA: string, localeB: string) {
return localeB.indexOf(localeA) === 0 return localeB.indexOf(localeA) === 0 && localeA !== localeB
}
export function isRelatedLocale(localeA: string, localeB: string) {
return (
localeA === localeB ||
isFallbackLocaleOf(localeA, localeB) ||
isFallbackLocaleOf(localeB, localeA)
)
} }
export function getFallbackOf(locale: string) { export function getFallbackOf(locale: string) {
const index = locale.lastIndexOf('-') const index = locale.lastIndexOf('-')
if (index > 0) return locale.slice(0, index) if (index > 0) return locale.slice(0, index)
if (fallback && !isFallbackLocaleOf(fallback, locale)) return fallback if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
return fallbackLocale
}
return null return null
} }
@ -34,19 +44,19 @@ export function getFallbacksOf(locale: string): string[] {
.split('-') .split('-')
.map((_, i, arr) => arr.slice(0, i + 1).join('-')) .map((_, i, arr) => arr.slice(0, i + 1).join('-'))
if (fallback != null && !isFallbackLocaleOf(fallback, locale)) { if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
return locales.concat(getFallbacksOf(fallback)) return locales.concat(getFallbacksOf(fallbackLocale))
} }
return locales return locales
} }
function getCurrentLocale() { export function getCurrentLocale() {
return current return current
} }
export function setInitialLocale(options: GetClientLocaleOptions) { export function setInitialLocale(options: GetClientLocaleOptions) {
if (typeof options.fallback === 'string') { if (typeof options.fallback === 'string') {
setfallbackLocale(options.fallback) setFallbackLocale(options.fallback)
} }
return $locale.set(getClientLocale(options)) return $locale.set(getClientLocale(options))
} }
@ -70,4 +80,4 @@ $locale.set = (newLocale: string): void | Promise<void> => {
$locale.update = (fn: (locale: string) => void | Promise<void>) => $locale.update = (fn: (locale: string) => void | Promise<void>) =>
localeSet(fn(current)) localeSet(fn(current))
export { $locale, flushQueue, getCurrentLocale } export { $locale }

View File

@ -1,238 +1,238 @@
// TODO remake this, it's a mess // // TODO remake this, it's a mess
import { Formatter } from '../../src/client/types' // import { Formatter } from '../../src/client/types'
import { // import {
dictionary, // dictionary,
locale, // locale,
format, // format,
addCustomFormats, // addCustomFormats,
customFormats, // customFormats,
register, // register,
waitLocale, // waitLocale,
} from '../../src/client' // } from '../../src/client'
import { getClientLocale } from '../../src/client/includes/utils' // import { getClientLocale } from '../../src/client/includes/utils'
global.Intl = require('intl') // global.Intl = require('intl')
let _: Formatter // let _: Formatter
let currentLocale: string // let currentLocale: string
const dict = { // const dict = {
en: require('../fixtures/en.json'), // en: require('../fixtures/en.json'),
} // }
register('en-GB', () => import('../fixtures/en-GB.json')) // register('en-GB', () => import('../fixtures/en-GB.json'))
register('pt', () => import('../fixtures/pt.json')) // register('pt', () => import('../fixtures/pt.json'))
register('pt-BR', () => import('../fixtures/pt-BR.json')) // register('pt-BR', () => import('../fixtures/pt-BR.json'))
register('pt-PT', () => import('../fixtures/pt-PT.json')) // register('pt-PT', () => import('../fixtures/pt-PT.json'))
format.subscribe(formatFn => { // format.subscribe(formatFn => {
_ = formatFn // _ = formatFn
}) // })
dictionary.set(dict) // dictionary.set(dict)
locale.subscribe((l: string) => { // locale.subscribe((l: string) => {
currentLocale = l // currentLocale = l
}) // })
describe('locale', () => { // describe('locale', () => {
it('should change locale', async () => { // it('should change locale', async () => {
await locale.set('en') // await locale.set('en')
expect(currentLocale).toBe('en') // expect(currentLocale).toBe('en')
await locale.set('en-US') // await locale.set('en-US')
expect(currentLocale).toBe('en-US') // expect(currentLocale).toBe('en-US')
}) // })
}) // })
describe('dictionary', () => { // describe('dictionary', () => {
it('load a partial dictionary and merge it with the existing one', async () => { // it('load a partial dictionary and merge it with the existing one', async () => {
await locale.set('en') // await locale.set('en')
register('en', () => import('../fixtures/partials/en.json')) // register('en', () => import('../fixtures/partials/en.json'))
expect(_('page.title_about')).toBe('page.title_about') // expect(_('page.title_about')).toBe('page.title_about')
await waitLocale('en') // await waitLocale('en')
expect(_('page.title_about')).toBe('About') // expect(_('page.title_about')).toBe('About')
}) // })
}) // })
describe('formatting', () => { // describe('formatting', () => {
it('should translate to current locale', async () => { // it('should translate to current locale', async () => {
await locale.set('en') // await locale.set('en')
expect(_('switch.lang')).toBe('Switch language') // expect(_('switch.lang')).toBe('Switch language')
}) // })
it('should fallback to message id if id is not found', async () => { // it('should fallback to message id if id is not found', async () => {
await locale.set('en') // await locale.set('en')
expect(_('batatinha.quente')).toBe('batatinha.quente') // expect(_('batatinha.quente')).toBe('batatinha.quente')
}) // })
it('should fallback to default value if id is not found', async () => { // it('should fallback to default value if id is not found', async () => {
await locale.set('en') // await locale.set('en')
expect(_('batatinha.quente', { default: 'Hot Potato' })).toBe('Hot Potato') // expect(_('batatinha.quente', { default: 'Hot Potato' })).toBe('Hot Potato')
}) // })
it('should fallback to generic locale XX if id not found in XX-YY', async () => { // it('should fallback to generic locale XX if id not found in XX-YY', async () => {
await locale.set('en-GB') // await locale.set('en-GB')
expect(_('sneakers', { locale: 'en-GB' })).toBe('trainers') // expect(_('sneakers', { locale: 'en-GB' })).toBe('trainers')
}) // })
it('should fallback to generic locale XX if id not found in XX-YY', async () => { // it('should fallback to generic locale XX if id not found in XX-YY', async () => {
await locale.set('en-GB') // await locale.set('en-GB')
expect(_('switch.lang')).toBe('Switch language') // expect(_('switch.lang')).toBe('Switch language')
}) // })
it('should accept single object with id prop as the message path', async () => { // it('should accept single object with id prop as the message path', async () => {
await locale.set('en') // await locale.set('en')
expect(_({ id: 'switch.lang' })).toBe('Switch language') // expect(_({ id: 'switch.lang' })).toBe('Switch language')
}) // })
it('should translate to passed locale', async () => { // it('should translate to passed locale', async () => {
await waitLocale('pt-BR') // await waitLocale('pt-BR')
expect(_('switch.lang', { locale: 'pt' })).toBe('Trocar idioma') // expect(_('switch.lang', { locale: 'pt' })).toBe('Trocar idioma')
}) // })
it('should interpolate message with variables', async () => { // it('should interpolate message with variables', async () => {
await locale.set('en') // await locale.set('en')
expect(_('greeting.message', { values: { name: 'Chris' } })).toBe( // expect(_('greeting.message', { values: { name: 'Chris' } })).toBe(
'Hello Chris, how are you?' // 'Hello Chris, how are you?'
) // )
}) // })
}) // })
describe('utilities', () => { // describe('utilities', () => {
describe('get locale', () => { // describe('get locale', () => {
beforeEach(() => { // beforeEach(() => {
delete window.location // delete window.location
window.location = { // window.location = {
pathname: '/', // pathname: '/',
hostname: 'example.com', // hostname: 'example.com',
hash: '', // hash: '',
search: '', // search: '',
} as any // } as any
}) // })
it('should get the locale based on the passed hash parameter', () => { // it('should get the locale based on the passed hash parameter', () => {
window.location.hash = '#locale=en-US&lang=pt-BR' // window.location.hash = '#locale=en-US&lang=pt-BR'
expect(getClientLocale({ hash: 'lang' })).toBe('pt-BR') // expect(getClientLocale({ hash: 'lang' })).toBe('pt-BR')
}) // })
it('should get the locale based on the passed search parameter', () => { // it('should get the locale based on the passed search parameter', () => {
window.location.search = '?locale=en-US&lang=pt-BR' // window.location.search = '?locale=en-US&lang=pt-BR'
expect(getClientLocale({ search: 'lang' })).toBe('pt-BR') // expect(getClientLocale({ search: 'lang' })).toBe('pt-BR')
}) // })
it('should get the locale based on the navigator language', () => { // it('should get the locale based on the navigator language', () => {
expect(getClientLocale({ navigator: true })).toBe( // expect(getClientLocale({ navigator: true })).toBe(
window.navigator.language // window.navigator.language
) // )
}) // })
it('should get the default locale', () => { // it('should get the default locale', () => {
expect(getClientLocale({ default: 'pt' })).toBe('pt') // expect(getClientLocale({ default: 'pt' })).toBe('pt')
}) // })
it('should get the fallback locale', () => { // it('should get the fallback locale', () => {
window.location.pathname = '/en-US/foo/' // window.location.pathname = '/en-US/foo/'
expect(getClientLocale({ pathname: /^\/(.*?)\// })).toBe('en-US') // expect(getClientLocale({ pathname: /^\/(.*?)\// })).toBe('en-US')
}) // })
it('should get the fallback locale', () => { // it('should get the fallback locale', () => {
window.location.hostname = 'pt.example.com' // window.location.hostname = 'pt.example.com'
expect(getClientLocale({ hostname: /^(.*?)\./ })).toBe('pt') // expect(getClientLocale({ hostname: /^(.*?)\./ })).toBe('pt')
}) // })
}) // })
describe('format utils', () => { // describe('format utils', () => {
beforeAll(async () => { // beforeAll(async () => {
await locale.set('en') // await locale.set('en')
}) // })
it('should capital a translated message', () => { // it('should capital a translated message', () => {
expect(_.capital('hi')).toBe('Hi yo') // expect(_.capital('hi')).toBe('Hi yo')
}) // })
it('should title a translated message', () => { // it('should title a translated message', () => {
expect(_.title('hi')).toBe('Hi Yo') // expect(_.title('hi')).toBe('Hi Yo')
}) // })
it('should lowercase a translated message', () => { // it('should lowercase a translated message', () => {
expect(_.lower('hi')).toBe('hi yo') // expect(_.lower('hi')).toBe('hi yo')
}) // })
it('should uppercase a translated message', () => { // it('should uppercase a translated message', () => {
expect(_.upper('hi')).toBe('HI YO') // expect(_.upper('hi')).toBe('HI YO')
}) // })
const date = new Date(2019, 3, 24, 23, 45) // const date = new Date(2019, 3, 24, 23, 45)
it('should format a time value', async () => { // it('should format a time value', async () => {
await locale.set('en') // await locale.set('en')
expect(_.time(date)).toBe('11:45 PM') // expect(_.time(date)).toBe('11:45 PM')
expect(_.time(date, { format: 'medium' })).toBe('11:45:00 PM') // expect(_.time(date, { format: 'medium' })).toBe('11:45:00 PM')
expect(_.time(date, { format: 'medium', locale: 'pt-BR' })).toBe( // expect(_.time(date, { format: 'medium', locale: 'pt-BR' })).toBe(
'23:45:00' // '23:45:00'
) // )
}) // })
it('should format a date value', () => { // it('should format a date value', () => {
expect(_.date(date)).toBe('4/24/19') // expect(_.date(date)).toBe('4/24/19')
expect(_.date(date, { format: 'medium' })).toBe('Apr 24, 2019') // expect(_.date(date, { format: 'medium' })).toBe('Apr 24, 2019')
}) // })
// number // // number
it('should format a date value', () => { // it('should format a date value', () => {
expect(_.number(123123123)).toBe('123,123,123') // expect(_.number(123123123)).toBe('123,123,123')
}) // })
}) // })
}) // })
describe('custom formats', () => { // describe('custom formats', () => {
beforeAll(async () => { // beforeAll(async () => {
await locale.set('pt-BR') // await locale.set('pt-BR')
}) // })
it('should have default number custom formats', () => { // it('should have default number custom formats', () => {
expect(customFormats.number).toMatchObject({ // expect(customFormats.number).toMatchObject({
scientific: { notation: 'scientific' }, // scientific: { notation: 'scientific' },
engineering: { notation: 'engineering' }, // engineering: { notation: 'engineering' },
compactLong: { notation: 'compact', compactDisplay: 'long' }, // compactLong: { notation: 'compact', compactDisplay: 'long' },
compactShort: { notation: 'compact', compactDisplay: 'short' }, // compactShort: { notation: 'compact', compactDisplay: 'short' },
}) // })
}) // })
it('should allow to add custom formats', () => { // it('should allow to add custom formats', () => {
addCustomFormats({ // addCustomFormats({
number: { // number: {
usd: { style: 'currency', currency: 'USD' }, // usd: { style: 'currency', currency: 'USD' },
}, // },
}) // })
expect(customFormats.number).toMatchObject({ // expect(customFormats.number).toMatchObject({
usd: { style: 'currency', currency: 'USD' }, // usd: { style: 'currency', currency: 'USD' },
}) // })
}) // })
it('should format messages with custom formats', async () => { // it('should format messages with custom formats', async () => {
addCustomFormats({ // addCustomFormats({
number: { // number: {
usd: { style: 'currency', currency: 'USD' }, // usd: { style: 'currency', currency: 'USD' },
brl: { style: 'currency', currency: 'BRL' }, // brl: { style: 'currency', currency: 'BRL' },
}, // },
date: { // date: {
customDate: { year: 'numeric', era: 'short' }, // customDate: { year: 'numeric', era: 'short' },
}, // },
time: { // time: {
customTime: { hour: '2-digit', minute: '2-digit' }, // customTime: { hour: '2-digit', minute: '2-digit' },
}, // },
}) // })
await locale.set('en-US') // await locale.set('en-US')
expect(_.number(123123123, { format: 'usd' })).toContain('$123,123,123.00') // expect(_.number(123123123, { format: 'usd' })).toContain('$123,123,123.00')
expect(_.date(new Date(2019, 0, 1), { format: 'customDate' })).toEqual( // expect(_.date(new Date(2019, 0, 1), { format: 'customDate' })).toEqual(
'2019 AD' // '2019 AD'
) // )
expect( // expect(
_.time(new Date(2019, 0, 1, 2, 0, 0), { format: 'customTime' }) // _.time(new Date(2019, 0, 1, 2, 0, 0), { format: 'customTime' })
).toEqual('02:00') // ).toEqual('02:00')
}) // })
}) // })

View File

@ -0,0 +1,79 @@
import {
getFallbackLocale,
setFallbackLocale,
isFallbackLocaleOf,
getFallbackOf,
getFallbacksOf,
setInitialLocale,
getCurrentLocale,
$locale,
isRelatedLocale,
} from '../../src/client/stores/locale'
beforeEach(() => {
setFallbackLocale(undefined)
})
test('sets and gets the fallback locale', () => {
setFallbackLocale('en')
expect(getFallbackLocale()).toBe('en')
})
test('checks if a locale is a fallback locale of another locale', () => {
expect(isFallbackLocaleOf('en', 'en-US')).toBe(true)
expect(isFallbackLocaleOf('en', 'en')).toBe(false)
expect(isFallbackLocaleOf('it', 'en-US')).toBe(false)
})
test('checks if a locale is a fallback locale of another locale', () => {
expect(isRelatedLocale('en', 'en-US')).toBe(true)
expect(isRelatedLocale('pt-BR', 'pt')).toBe(true)
expect(isRelatedLocale('en', 'en')).toBe(true)
expect(isRelatedLocale('en', 'it-IT')).toBe(false)
expect(isRelatedLocale('en-US', 'it')).toBe(false)
})
test('gets the next fallback locale of a certain locale', () => {
expect(getFallbackOf('az-Cyrl-AZ')).toBe('az-Cyrl')
expect(getFallbackOf('en-US')).toBe('en')
expect(getFallbackOf('en')).toBe(null)
})
test('gets the global fallback locale if set', () => {
setFallbackLocale('en')
expect(getFallbackOf('it')).toBe('en')
})
test('should not get the global fallback as the fallback of itself', () => {
setFallbackLocale('en')
expect(getFallbackOf('en')).toBe(null)
})
test('if global fallback locale has a fallback, it should return it', () => {
setFallbackLocale('en-US')
expect(getFallbackOf('en-US')).toBe('en')
})
test('gets all fallback locales of a certain locale', () => {
expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US'])
expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US'])
expect(getFallbacksOf('az-Cyrl-AZ')).toEqual(['az', 'az-Cyrl', 'az-Cyrl-AZ'])
})
test('gets all fallback locales of a certain locale including the global fallback locale', () => {
setFallbackLocale('pt')
expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US', 'pt'])
expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US', 'pt'])
expect(getFallbacksOf('az-Cyrl-AZ')).toEqual([
'az',
'az-Cyrl',
'az-Cyrl-AZ',
'pt',
])
})
test('should not list fallback locale twice', () => {
setFallbackLocale('pt-BR')
expect(getFallbacksOf('pt-BR')).toEqual(['pt', 'pt-BR'])
expect(getFallbacksOf('pt')).toEqual(['pt'])
})