diff --git a/example/src/routes/_layout.svelte b/example/src/routes/_layout.svelte
index 7771265..36f972f 100644
--- a/example/src/routes/_layout.svelte
+++ b/example/src/routes/_layout.svelte
@@ -1,10 +1,11 @@
diff --git a/src/client/includes/loaderQueue.ts b/src/client/includes/loaderQueue.ts
index 988c541..37e0d97 100644
--- a/src/client/includes/loaderQueue.ts
+++ b/src/client/includes/loaderQueue.ts
@@ -4,11 +4,9 @@ import {
$dictionary,
addMessages,
} from '../stores/dictionary'
-import { getCurrentLocale } from '../stores/locale'
+import { getCurrentLocale, getFallbacksOf } from '../stores/locale'
import { $isLoading } from '../stores/loading'
-import { getAllFallbackLocales } from './utils'
-
type Queue = Set
const loaderQueue: Record = {}
@@ -25,7 +23,7 @@ function getLocaleQueue(locale: string) {
}
function getLocalesQueues(locale: string) {
- return getAllFallbackLocales(locale)
+ return getFallbacksOf(locale)
.reverse()
.map<[string, MessagesLoader[]]>(localeItem => {
const queue = getLocaleQueue(localeItem)
@@ -35,7 +33,7 @@ function getLocalesQueues(locale: string) {
}
export function hasLocaleQueue(locale: string) {
- return getAllFallbackLocales(locale)
+ return getFallbacksOf(locale)
.reverse()
.some(getLocaleQueue)
}
diff --git a/src/client/includes/lookup.ts b/src/client/includes/lookup.ts
index 39d0ec4..9f786c2 100644
--- a/src/client/includes/lookup.ts
+++ b/src/client/includes/lookup.ts
@@ -2,8 +2,7 @@
import resolvePath from 'object-resolve-path'
import { hasLocaleDictionary } from '../stores/dictionary'
-
-import { getFallbackLocale } from './utils'
+import { getFallbackOf } from '../stores/locale'
const lookupCache: Record> = {}
@@ -34,6 +33,6 @@ export const lookupMessage = (
return addToCache(
path,
locale,
- lookupMessage(dictionary, path, getFallbackLocale(locale))
+ lookupMessage(dictionary, path, getFallbackOf(locale))
)
}
diff --git a/src/client/includes/utils.ts b/src/client/includes/utils.ts
index fdfe24c..e3335d1 100644
--- a/src/client/includes/utils.ts
+++ b/src/client/includes/utils.ts
@@ -16,15 +16,6 @@ export function lower(str: string) {
return str.toLocaleLowerCase()
}
-export function getFallbackLocale(locale: string) {
- const index = locale.lastIndexOf('-')
- return index > 0 ? locale.slice(0, index) : null
-}
-
-export function getAllFallbackLocales(locale: string) {
- return locale.split('-').map((_, i, arr) => arr.slice(0, i + 1).join('-'))
-}
-
const getFromURL = (urlPart: string, key: string) => {
const keyVal = urlPart
.substr(1)
@@ -49,12 +40,11 @@ export const getClientLocale = ({
pathname,
hostname,
default: defaultLocale,
+ fallback = defaultLocale,
}: GetClientLocaleOptions) => {
let locale
- if (typeof window === 'undefined') {
- return defaultLocale
- }
+ if (typeof window === 'undefined') return fallback
if (hostname) {
locale = getFirstMatch(window.location.hostname, hostname)
@@ -88,5 +78,5 @@ export const getClientLocale = ({
if (locale) return locale
}
- return defaultLocale
+ return fallback
}
diff --git a/src/client/index.ts b/src/client/index.ts
index 24f88df..7b08c6c 100644
--- a/src/client/index.ts
+++ b/src/client/index.ts
@@ -1,22 +1,18 @@
import merge from 'deepmerge'
-import { GetClientLocaleOptions, MessageObject } from './types'
-import { getClientLocale } from './includes/utils'
-import { $locale } from './stores/locale'
+import { MessageObject } from './types'
// defineMessages allow us to define and extract dynamic message ids
export function defineMessages(i: Record) {
return i
}
-export function waitInitialLocale(options: GetClientLocaleOptions | string) {
- if (typeof options === 'string') {
- return $locale.set(options)
- }
- return $locale.set(getClientLocale(options))
-}
-
-export { $locale as locale, loadLocale as preloadLocale } from './stores/locale'
+export {
+ $locale as locale,
+ setInitialLocale,
+ // @deprecated
+ setInitialLocale as waitInitialLocale,
+} from './stores/locale'
export {
$dictionary as dictionary,
$locales as locales,
@@ -26,7 +22,7 @@ export { $isLoading as isLoading } from './stores/loading'
export { $format as format, $format as _, $format as t } from './stores/format'
// utilities
-export { getClientLocale, merge }
+export { merge }
export { customFormats, addCustomFormats } from './includes/formats'
export {
flushQueue as waitLocale,
diff --git a/src/client/stores/dictionary.ts b/src/client/stores/dictionary.ts
index 04428b8..ba2b729 100644
--- a/src/client/stores/dictionary.ts
+++ b/src/client/stores/dictionary.ts
@@ -3,22 +3,25 @@ import { writable, derived } from 'svelte/store'
import { LocaleDictionary } from '../types/index'
+import { getFallbackOf } from './locale'
+
let dictionary: LocaleDictionary
-
const $dictionary = writable({})
-$dictionary.subscribe(newDictionary => {
- dictionary = newDictionary
-})
-function getDictionary() {
+export function getDictionary() {
return dictionary
}
-function hasLocaleDictionary(locale: string) {
+export function hasLocaleDictionary(locale: string) {
return locale in dictionary
}
-function addMessages(locale: string, ...partials: LocaleDictionary[]) {
+export function getAvailableLocale(locale: string): string | null {
+ if (locale in dictionary || locale == null) return locale
+ return getAvailableLocale(getFallbackOf(locale))
+}
+
+export function addMessages(locale: string, ...partials: LocaleDictionary[]) {
$dictionary.update(d => {
dictionary[locale] = merge.all([dictionary[locale] || {}].concat(partials))
return d
@@ -29,10 +32,6 @@ const $locales = derived([$dictionary], ([$dictionary]) =>
Object.keys($dictionary)
)
-export {
- $dictionary,
- $locales,
- getDictionary,
- hasLocaleDictionary,
- addMessages,
-}
+$dictionary.subscribe(newDictionary => (dictionary = newDictionary))
+
+export { $dictionary, $locales }
diff --git a/src/client/stores/format.ts b/src/client/stores/format.ts
index cf86055..78b4f10 100644
--- a/src/client/stores/format.ts
+++ b/src/client/stores/format.ts
@@ -3,13 +3,7 @@ import { derived } from 'svelte/store'
import { Formatter, MessageObject } from '../types'
import { lookupMessage } from '../includes/lookup'
import { hasLocaleQueue } from '../includes/loaderQueue'
-import {
- getAllFallbackLocales,
- capital,
- upper,
- lower,
- title,
-} from '../includes/utils'
+import { capital, upper, lower, title } from '../includes/utils'
import {
getMessageFormatter,
getTimeFormatter,
@@ -18,7 +12,7 @@ import {
} from '../includes/formats'
import { getDictionary, $dictionary } from './dictionary'
-import { getCurrentLocale, $locale } from './locale'
+import { getCurrentLocale, getFallbacksOf, $locale } from './locale'
const formatMessage: Formatter = (id, options = {}) => {
if (typeof id === 'object') {
@@ -38,7 +32,7 @@ const formatMessage: Formatter = (id, options = {}) => {
if (!message) {
console.warn(
- `[svelte-i18n] The message "${id}" was not found in "${getAllFallbackLocales(
+ `[svelte-i18n] The message "${id}" was not found in "${getFallbacksOf(
locale
).join('", "')}". ${
hasLocaleQueue(getCurrentLocale())
diff --git a/src/client/stores/locale.ts b/src/client/stores/locale.ts
index 949ea87..c924da4 100644
--- a/src/client/stores/locale.ts
+++ b/src/client/stores/locale.ts
@@ -1,30 +1,54 @@
import { writable } from 'svelte/store'
-import { getFallbackLocale, getAllFallbackLocales } from '../includes/utils'
import { flushQueue, hasLocaleQueue } from '../includes/loaderQueue'
+import { getClientLocale } from '../includes/utils'
+import { GetClientLocaleOptions } from '../types'
-import { getDictionary } from './dictionary'
+import { getAvailableLocale } from './dictionary'
+let fallback: string = null
let current: string
const $locale = writable(null)
+export function getFallbackLocale() {
+ return fallback
+}
+
+export function setfallbackLocale(locale: string) {
+ fallback = locale
+}
+
+export function isFallbackLocaleOf(localeA: string, localeB: string) {
+ return localeB.indexOf(localeA) === 0
+}
+
+export function getFallbackOf(locale: string) {
+ const index = locale.lastIndexOf('-')
+ if (index > 0) return locale.slice(0, index)
+ if (fallback && !isFallbackLocaleOf(locale, fallback)) return fallback
+ return null
+}
+
+export function getFallbacksOf(locale: string): string[] {
+ const locales = locale
+ .split('-')
+ .map((_, i, arr) => arr.slice(0, i + 1).join('-'))
+
+ if (fallback != null && !isFallbackLocaleOf(locale, fallback)) {
+ return locales.concat(getFallbacksOf(fallback))
+ }
+ return locales
+}
+
function getCurrentLocale() {
return current
}
-function getAvailableLocale(locale: string): string | null {
- if (locale in getDictionary() || locale == null) return locale
- return getAvailableLocale(getFallbackLocale(locale))
-}
-
-function loadLocale(localeToLoad: string) {
- return Promise.all(
- getAllFallbackLocales(localeToLoad).map(localeItem =>
- flushQueue(localeItem)
- .then(() => [localeItem, { err: undefined }])
- .catch(e => [localeItem, { err: e }])
- )
- )
+export function setInitialLocale(options: GetClientLocaleOptions) {
+ if (typeof options.fallback === 'string') {
+ setfallbackLocale(options.fallback)
+ }
+ return $locale.set(getClientLocale(options))
}
$locale.subscribe((newLocale: string) => {
@@ -37,17 +61,13 @@ $locale.subscribe((newLocale: string) => {
const localeSet = $locale.set
$locale.set = (newLocale: string): void | Promise => {
- if (getAvailableLocale(newLocale)) {
- if (hasLocaleQueue(newLocale)) {
- return flushQueue(newLocale).then(() => localeSet(newLocale))
- }
- return localeSet(newLocale)
+ if (getAvailableLocale(newLocale) && hasLocaleQueue(newLocale)) {
+ return flushQueue(newLocale).then(() => localeSet(newLocale))
}
-
- throw Error(`[svelte-i18n] Locale "${newLocale}" not found.`)
+ return localeSet(newLocale)
}
$locale.update = (fn: (locale: string) => void | Promise) =>
localeSet(fn(current))
-export { $locale, loadLocale, flushQueue, getCurrentLocale }
+export { $locale, flushQueue, getCurrentLocale }
diff --git a/test/client/index.test.ts b/test/client/index.test.ts
index bf2e2d5..43140e7 100644
--- a/test/client/index.test.ts
+++ b/test/client/index.test.ts
@@ -4,13 +4,12 @@ import {
dictionary,
locale,
format,
- getClientLocale,
addCustomFormats,
customFormats,
- preloadLocale,
register,
waitLocale,
} from '../../src/client'
+import { getClientLocale } from '../../src/client/includes/utils'
global.Intl = require('intl')
@@ -42,19 +41,9 @@ describe('locale', () => {
await locale.set('en-US')
expect(currentLocale).toBe('en-US')
})
-
- it("should throw an error if locale doesn't exist", () => {
- expect(() => locale.set('FOO')).toThrow()
- })
})
describe('dictionary', () => {
- it('load a locale and its derived locales if dictionary is a loader', async () => {
- const loaded = await preloadLocale('pt-PT')
- expect(loaded[0][0]).toEqual('pt')
- expect(loaded[1][0]).toEqual('pt-PT')
- })
-
it('load a partial dictionary and merge it with the existing one', async () => {
await locale.set('en')
register('en', () => import('../fixtures/partials/en.json'))
@@ -96,7 +85,8 @@ describe('formatting', () => {
expect(_({ id: 'switch.lang' })).toBe('Switch language')
})
- it('should translate to passed locale', () => {
+ it('should translate to passed locale', async () => {
+ await waitLocale('pt-BR')
expect(_('switch.lang', { locale: 'pt' })).toBe('Trocar idioma')
})