diff --git a/example/src/i18n.js b/example/src/i18n.js
index 349adb7..700dc2d 100644
--- a/example/src/i18n.js
+++ b/example/src/i18n.js
@@ -1,7 +1,18 @@
-import { register, setFallbackLocale } from 'svelte-i18n'
+import { register, configure } from 'svelte-i18n'
+
+configure({
+ fallbackLocale: 'en',
+ initialLocale: {
+ navigator: true,
+ },
+ formats: {
+ number: {
+ BRL: { style: 'currency', currency: 'BRL' },
+ },
+ },
+ loadingDelay: 200,
+})
register('en', () => import('../messages/en.json'))
register('pt-BR', () => import('../messages/pt-BR.json'))
register('es-ES', () => import('../messages/es-ES.json'))
-
-setFallbackLocale('en')
diff --git a/example/src/routes/_layout.svelte b/example/src/routes/_layout.svelte
index 7bf9195..bc62040 100644
--- a/example/src/routes/_layout.svelte
+++ b/example/src/routes/_layout.svelte
@@ -1,12 +1,8 @@
diff --git a/src/client/configs.ts b/src/client/configs.ts
new file mode 100644
index 0000000..83e575a
--- /dev/null
+++ b/src/client/configs.ts
@@ -0,0 +1,67 @@
+import { getClientLocale } from './includes/utils'
+import { ConfigureOptions } from './types'
+import { $locale } from './stores/locale'
+
+let fallbackLocale: string = null
+let loadingDelay = 200
+const formats: any = {
+ number: {
+ scientific: { notation: 'scientific' },
+ engineering: { notation: 'engineering' },
+ compactLong: { notation: 'compact', compactDisplay: 'long' },
+ compactShort: { notation: 'compact', compactDisplay: 'short' },
+ },
+ date: {
+ short: { month: 'numeric', day: 'numeric', year: '2-digit' },
+ medium: { month: 'short', day: 'numeric', year: 'numeric' },
+ long: { month: 'long', day: 'numeric', year: 'numeric' },
+ full: { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' },
+ },
+ time: {
+ short: { hour: 'numeric', minute: 'numeric' },
+ medium: { hour: 'numeric', minute: 'numeric', second: 'numeric' },
+ long: {
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ timeZoneName: 'short',
+ },
+ full: {
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ timeZoneName: 'short',
+ },
+ },
+}
+
+export function getFallbackLocale() {
+ return fallbackLocale
+}
+
+export function getLoadingDelay() {
+ return loadingDelay
+}
+
+export function getFormats() {
+ return formats
+}
+
+export function configure(opts: ConfigureOptions) {
+ fallbackLocale = opts.fallbackLocale
+
+ if (opts.initialLocale) {
+ $locale.set(getClientLocale(opts.initialLocale) || fallbackLocale)
+ } else {
+ $locale.set(fallbackLocale)
+ }
+
+ if (opts.formats) {
+ if ('number' in opts.formats)
+ Object.assign(formats.number, opts.formats.number)
+ if ('date' in opts.formats) Object.assign(formats.date, opts.formats.date)
+ if ('time' in opts.formats) Object.assign(formats.time, opts.formats.time)
+ }
+
+ if (loadingDelay != null) loadingDelay = loadingDelay
+}
diff --git a/src/client/includes/formats.ts b/src/client/includes/formatters.ts
similarity index 66%
rename from src/client/includes/formats.ts
rename to src/client/includes/formatters.ts
index 93029ba..0a8a40d 100644
--- a/src/client/includes/formats.ts
+++ b/src/client/includes/formatters.ts
@@ -1,32 +1,17 @@
-import IntlMessageFormat, { Formats } from 'intl-messageformat'
+import IntlMessageFormat from 'intl-messageformat'
import memoize from 'fast-memoize'
import { MemoizedIntlFormatter } from '../types'
import { getCurrentLocale } from '../stores/locale'
-
-export const customFormats: any = {
- number: {
- scientific: { notation: 'scientific' },
- engineering: { notation: 'engineering' },
- compactLong: { notation: 'compact', compactDisplay: 'long' },
- compactShort: { notation: 'compact', compactDisplay: 'short' },
- },
- date: {},
- time: {},
-}
-
-export function addCustomFormats(formats: Partial) {
- if ('number' in formats) Object.assign(customFormats.number, formats.number)
- if ('date' in formats) Object.assign(customFormats.date, formats.date)
- if ('time' in formats) Object.assign(customFormats.time, formats.time)
-}
+import { getFormats } from '../configs'
const getIntlFormatterOptions = (
type: 'time' | 'number' | 'date',
name: string
): any => {
- if (type in customFormats && name in customFormats[type]) {
- return customFormats[type][name]
+ const formats = getFormats()
+ if (type in formats && name in formats[type]) {
+ return formats[type][name]
}
if (
@@ -77,5 +62,5 @@ export const getTimeFormatter: MemoizedIntlFormatter<
export const getMessageFormatter = memoize(
(message: string, locale: string) =>
- new IntlMessageFormat(message, locale, customFormats)
+ new IntlMessageFormat(message, locale, getFormats())
)
diff --git a/src/client/includes/loaderQueue.ts b/src/client/includes/loaderQueue.ts
index 37e0d97..710aa8a 100644
--- a/src/client/includes/loaderQueue.ts
+++ b/src/client/includes/loaderQueue.ts
@@ -4,8 +4,9 @@ import {
$dictionary,
addMessages,
} from '../stores/dictionary'
-import { getCurrentLocale, getFallbacksOf } from '../stores/locale'
+import { getCurrentLocale, getRelatedLocalesOf } from '../stores/locale'
import { $isLoading } from '../stores/loading'
+import { getLoadingDelay } from '../configs'
type Queue = Set
const loaderQueue: Record = {}
@@ -23,7 +24,7 @@ function getLocaleQueue(locale: string) {
}
function getLocalesQueues(locale: string) {
- return getFallbacksOf(locale)
+ return getRelatedLocalesOf(locale)
.reverse()
.map<[string, MessagesLoader[]]>(localeItem => {
const queue = getLocaleQueue(localeItem)
@@ -33,7 +34,7 @@ function getLocalesQueues(locale: string) {
}
export function hasLocaleQueue(locale: string) {
- return getFallbacksOf(locale)
+ return getRelatedLocalesOf(locale)
.reverse()
.some(getLocaleQueue)
}
@@ -45,14 +46,14 @@ export function addLoaderToQueue(locale: string, loader: MessagesLoader) {
const activeLocaleFlushes: { [key: string]: Promise } = {}
export async function flushQueue(locale: string = getCurrentLocale()) {
if (!hasLocaleQueue(locale)) return
- if (activeLocaleFlushes[locale]) return activeLocaleFlushes[locale]
+ if (locale in activeLocaleFlushes) return activeLocaleFlushes[locale]
// get queue of XX-YY and XX locales
const queues = getLocalesQueues(locale)
if (queues.length === 0) return
removeLocaleFromQueue(locale)
- const loadingDelay = setTimeout(() => $isLoading.set(true), 200)
+ const loadingDelay = setTimeout(() => $isLoading.set(true), getLoadingDelay())
// TODO what happens if some loader fails
activeLocaleFlushes[locale] = Promise.all(
diff --git a/src/client/includes/utils.ts b/src/client/includes/utils.ts
index e3335d1..0256125 100644
--- a/src/client/includes/utils.ts
+++ b/src/client/includes/utils.ts
@@ -39,8 +39,6 @@ export const getClientLocale = ({
search,
pathname,
hostname,
- default: defaultLocale,
- fallback = defaultLocale,
}: GetClientLocaleOptions) => {
let locale
@@ -78,5 +76,5 @@ export const getClientLocale = ({
if (locale) return locale
}
- return fallback
+ return null
}
diff --git a/src/client/index.ts b/src/client/index.ts
index ea022dc..2f94c4f 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -1,5 +1,3 @@
-import merge from 'deepmerge'
-
import { MessageObject } from './types'
// defineMessages allow us to define and extract dynamic message ids
@@ -7,11 +5,8 @@ export function defineMessages(i: Record) {
return i
}
-export {
- $locale as locale,
- setInitialLocale,
- setFallbackLocale,
-} from './stores/locale'
+export { configure } from './configs'
+export { $locale as locale } from './stores/locale'
export {
$dictionary as dictionary,
$locales as locales,
@@ -21,12 +16,7 @@ export { $isLoading as isLoading } from './stores/loading'
export { $format as format, $format as _, $format as t } from './stores/format'
// utilities
-export { merge }
-export { customFormats, addCustomFormats } from './includes/formats'
export {
flushQueue as waitLocale,
registerLocaleLoader as register,
} from './includes/loaderQueue'
-
-// @deprecated
-export { getClientLocale } from './includes/utils'
diff --git a/src/client/stores/format.ts b/src/client/stores/format.ts
index ff18ea6..f85ee70 100644
--- a/src/client/stores/format.ts
+++ b/src/client/stores/format.ts
@@ -9,10 +9,10 @@ import {
getTimeFormatter,
getDateFormatter,
getNumberFormatter,
-} from '../includes/formats'
+} from '../includes/formatters'
import { $dictionary } from './dictionary'
-import { getCurrentLocale, getFallbacksOf, $locale } from './locale'
+import { getCurrentLocale, getRelatedLocalesOf, $locale } from './locale'
const formatMessage: Formatter = (id, options = {}) => {
if (typeof id === 'object') {
@@ -32,7 +32,7 @@ const formatMessage: Formatter = (id, options = {}) => {
if (!message) {
console.warn(
- `[svelte-i18n] The message "${id}" was not found in "${getFallbacksOf(
+ `[svelte-i18n] The message "${id}" was not found in "${getRelatedLocalesOf(
locale
).join('", "')}". ${
hasLocaleQueue(getCurrentLocale())
diff --git a/src/client/stores/locale.ts b/src/client/stores/locale.ts
index ccb65ef..b4822ee 100644
--- a/src/client/stores/locale.ts
+++ b/src/client/stores/locale.ts
@@ -5,19 +5,11 @@ import { getClientLocale } from '../includes/utils'
import { GetClientLocaleOptions } from '../types'
import { getClosestAvailableLocale } from './dictionary'
+import { setFallbackLocale, getFallbackLocale } from '../configs'
-let fallbackLocale: string = null
let current: string
const $locale = writable(null)
-export function getFallbackLocale() {
- return fallbackLocale
-}
-
-export function setFallbackLocale(locale: string) {
- fallbackLocale = locale
-}
-
export function isFallbackLocaleOf(localeA: string, localeB: string) {
return localeB.indexOf(localeA) === 0 && localeA !== localeB
}
@@ -33,19 +25,19 @@ export function isRelatedLocale(localeA: string, localeB: string) {
export function getFallbackOf(locale: string) {
const index = locale.lastIndexOf('-')
if (index > 0) return locale.slice(0, index)
- if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
- return fallbackLocale
+ if (getFallbackLocale() && !isRelatedLocale(locale, getFallbackLocale())) {
+ return getFallbackLocale()
}
return null
}
-export function getFallbacksOf(locale: string): string[] {
+export function getRelatedLocalesOf(locale: string): string[] {
const locales = locale
.split('-')
.map((_, i, arr) => arr.slice(0, i + 1).join('-'))
- if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
- return locales.concat(getFallbacksOf(fallbackLocale))
+ if (getFallbackLocale() && !isRelatedLocale(locale, getFallbackLocale())) {
+ return locales.concat(getRelatedLocalesOf(getFallbackLocale()))
}
return locales
}
@@ -54,13 +46,6 @@ export function getCurrentLocale() {
return current
}
-export function setInitialLocale(options: GetClientLocaleOptions) {
- if (typeof options.fallback === 'string') {
- setFallbackLocale(options.fallback)
- }
- return $locale.set(getClientLocale(options))
-}
-
$locale.subscribe((newLocale: string) => {
current = newLocale
diff --git a/src/client/types/index.ts b/src/client/types/index.ts
index e3bdcf4..edf8638 100644
--- a/src/client/types/index.ts
+++ b/src/client/types/index.ts
@@ -1,3 +1,5 @@
+import { Formats } from 'intl-messageformat'
+
export interface Dictionary {
[key: string]: string | string[] | Dictionary | Dictionary[]
}
@@ -50,8 +52,14 @@ export interface GetClientLocaleOptions {
navigator?: boolean
hash?: string | RegExp
search?: string | RegExp
- fallback?: string
default?: string
pathname?: RegExp
hostname?: RegExp
}
+
+export interface ConfigureOptions {
+ fallbackLocale: string
+ initialLocale?: GetClientLocaleOptions
+ formats?: Partial
+ loadingDelay?: number
+}
diff --git a/test/client/locale.test.ts b/test/client/locale.test.ts
index d5e5d89..f85eff0 100644
--- a/test/client/locale.test.ts
+++ b/test/client/locale.test.ts
@@ -1,23 +1,22 @@
+import { get } from 'svelte/store'
+
import {
- getFallbackLocale,
- setFallbackLocale,
isFallbackLocaleOf,
getFallbackOf,
- getFallbacksOf,
- setInitialLocale,
+ getRelatedLocalesOf,
getCurrentLocale,
$locale,
isRelatedLocale,
} from '../../src/client/stores/locale'
-import { get } from 'svelte/store'
+import { getFallbackLocale, configure } from '../../src/client/configs'
beforeEach(() => {
- setFallbackLocale(undefined)
+ configure({ fallbackLocale: undefined })
$locale.set(undefined)
})
test('sets and gets the fallback locale', () => {
- setFallbackLocale('en')
+ configure({ fallbackLocale: 'en' })
expect(getFallbackLocale()).toBe('en')
})
@@ -42,31 +41,35 @@ test('gets the next fallback locale of a locale', () => {
})
test('gets the global fallback locale if set', () => {
- setFallbackLocale('en')
+ configure({ fallbackLocale: 'en' })
expect(getFallbackOf('it')).toBe('en')
})
test('should not get the global fallback as the fallback of itself', () => {
- setFallbackLocale('en')
+ configure({ fallbackLocale: 'en' })
expect(getFallbackOf('en')).toBe(null)
})
test('if global fallback locale has a fallback, it should return it', () => {
- setFallbackLocale('en-US')
+ configure({ fallbackLocale: 'en-US' })
expect(getFallbackOf('en-US')).toBe('en')
})
test('gets all fallback locales of a 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'])
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US'])
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US'])
+ expect(getRelatedLocalesOf('az-Cyrl-AZ')).toEqual([
+ 'az',
+ 'az-Cyrl',
+ 'az-Cyrl-AZ',
+ ])
})
test('gets all fallback locales of a 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([
+ configure({ fallbackLocale: 'pt' })
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US', 'pt'])
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US', 'pt'])
+ expect(getRelatedLocalesOf('az-Cyrl-AZ')).toEqual([
'az',
'az-Cyrl',
'az-Cyrl-AZ',
@@ -74,10 +77,10 @@ test('gets all fallback locales of a locale including the global fallback locale
])
})
test('gets all fallback locales of a locale including the global fallback locale and its fallbacks', () => {
- setFallbackLocale('pt-BR')
- expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US', 'pt', 'pt-BR'])
- expect(getFallbacksOf('en-US')).toEqual(['en', 'en-US', 'pt', 'pt-BR'])
- expect(getFallbacksOf('az-Cyrl-AZ')).toEqual([
+ configure({ fallbackLocale: 'pt-BR' })
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US', 'pt', 'pt-BR'])
+ expect(getRelatedLocalesOf('en-US')).toEqual(['en', 'en-US', 'pt', 'pt-BR'])
+ expect(getRelatedLocalesOf('az-Cyrl-AZ')).toEqual([
'az',
'az-Cyrl',
'az-Cyrl-AZ',
@@ -87,9 +90,9 @@ test('gets all fallback locales of a locale including the global fallback locale
})
test("don't list fallback locale twice", () => {
- setFallbackLocale('pt-BR')
- expect(getFallbacksOf('pt-BR')).toEqual(['pt', 'pt-BR'])
- expect(getFallbacksOf('pt')).toEqual(['pt'])
+ configure({ fallbackLocale: 'pt-BR' })
+ expect(getRelatedLocalesOf('pt-BR')).toEqual(['pt', 'pt-BR'])
+ expect(getRelatedLocalesOf('pt')).toEqual(['pt'])
})
test('gets the current locale', () => {
@@ -98,10 +101,19 @@ test('gets the current locale', () => {
expect(getCurrentLocale()).toBe('es-ES')
})
-test('sets the global fallback when defining initial locale', () => {
- setInitialLocale({
- fallback: 'pt',
- })
+test('if no initial locale is set, set the locale to the fallback', () => {
+ configure({ fallbackLocale: 'pt' })
expect(get($locale)).toBe('pt')
expect(getFallbackLocale()).toBe('pt')
})
+
+test('if no initial locale was found, set to the fallback locale', () => {
+ configure({
+ fallbackLocale: 'en',
+ initialLocale: {
+ hash: 'lang',
+ },
+ })
+ expect(get($locale)).toBe('en')
+ expect(getFallbackLocale()).toBe('en')
+})