mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-09-28 15:14:45 +02:00
fix: 🐛 also wait for loaders added while loading
This commit is contained in:
parent
1148b72c7d
commit
e560514b1d
@ -7,24 +7,28 @@ import {
|
|||||||
import { getRelatedLocalesOf } from '../stores/locale'
|
import { getRelatedLocalesOf } from '../stores/locale'
|
||||||
|
|
||||||
type Queue = Set<MessagesLoader>
|
type Queue = Set<MessagesLoader>
|
||||||
const loaderQueue: Record<string, Queue> = {}
|
const queue: Record<string, Queue> = {}
|
||||||
|
|
||||||
export function resetQueues() {
|
export function resetQueues() {
|
||||||
Object.keys(loaderQueue).forEach(key => {
|
Object.keys(queue).forEach(key => {
|
||||||
delete loaderQueue[key]
|
delete queue[key]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLocaleQueue(locale: string) {
|
function createLocaleQueue(locale: string) {
|
||||||
loaderQueue[locale] = new Set()
|
queue[locale] = new Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLocaleFromQueue(locale: string) {
|
function removeLoaderFromQueue(locale: string, loader: MessagesLoader) {
|
||||||
delete loaderQueue[locale]
|
queue[locale].delete(loader)
|
||||||
|
|
||||||
|
if (queue[locale].size === 0) {
|
||||||
|
delete queue[locale]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLocaleQueue(locale: string) {
|
function getLocaleQueue(locale: string) {
|
||||||
return loaderQueue[locale]
|
return queue[locale]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLocalesQueues(locale: string) {
|
function getLocalesQueues(locale: string) {
|
||||||
@ -40,33 +44,46 @@ function getLocalesQueues(locale: string) {
|
|||||||
export function hasLocaleQueue(locale: string) {
|
export function hasLocaleQueue(locale: string) {
|
||||||
return getRelatedLocalesOf(locale)
|
return getRelatedLocalesOf(locale)
|
||||||
.reverse()
|
.reverse()
|
||||||
.some(getLocaleQueue)
|
.some(locale => getLocaleQueue(locale)?.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeLocaleFlushes: { [key: string]: Promise<void> } = {}
|
function loadLocaleQueue(locale: string, queue: MessagesLoader[]) {
|
||||||
export function flush(locale: string) {
|
const allLoadersPromise = Promise.all(
|
||||||
if (!hasLocaleQueue(locale)) return
|
queue.map(loader => {
|
||||||
if (locale in activeLocaleFlushes) return activeLocaleFlushes[locale]
|
// todo: maybe don't just remove, but add to a `loading` set?
|
||||||
|
removeLoaderFromQueue(locale, loader)
|
||||||
|
|
||||||
|
return loader().then(partial => partial.default || partial)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return allLoadersPromise.then(partials => addMessages(locale, ...partials))
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeFlushes: { [key: string]: Promise<void> } = {}
|
||||||
|
export function flush(locale: string): Promise<void> {
|
||||||
|
if (!hasLocaleQueue(locale)) {
|
||||||
|
if (locale in activeFlushes) {
|
||||||
|
return activeFlushes[locale]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// get queue of XX-YY and XX locales
|
// get queue of XX-YY and XX locales
|
||||||
const queues = getLocalesQueues(locale)
|
const queues = getLocalesQueues(locale)
|
||||||
// istanbul ignore if
|
|
||||||
if (queues.length === 0) return
|
|
||||||
|
|
||||||
// TODO what happens if some loader fails
|
// todo: what happens if some loader fails?
|
||||||
activeLocaleFlushes[locale] = Promise.all(
|
activeFlushes[locale] = Promise.all(
|
||||||
queues.map(([locale, queue]) => {
|
queues.map(([locale, queue]) => loadLocaleQueue(locale, queue))
|
||||||
return Promise.all(queue.map(loader => loader())).then(partials => {
|
|
||||||
removeLocaleFromQueue(locale)
|
|
||||||
partials = partials.map(partial => partial.default || partial)
|
|
||||||
addMessages(locale, ...partials)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
).then(() => {
|
).then(() => {
|
||||||
delete activeLocaleFlushes[locale]
|
if (hasLocaleQueue(locale)) {
|
||||||
|
return flush(locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete activeFlushes[locale]
|
||||||
})
|
})
|
||||||
|
|
||||||
return activeLocaleFlushes[locale]
|
return activeFlushes[locale]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerLocaleLoader(locale: string, loader: MessagesLoader) {
|
export function registerLocaleLoader(locale: string, loader: MessagesLoader) {
|
||||||
|
@ -50,3 +50,22 @@ test('consecutive flushes return the same promise', async () => {
|
|||||||
expect(flushB).toStrictEqual(flushA)
|
expect(flushB).toStrictEqual(flushA)
|
||||||
expect(flushC).toStrictEqual(flushA)
|
expect(flushC).toStrictEqual(flushA)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('waits for loaders added while already flushing', async () => {
|
||||||
|
registerLocaleLoader(
|
||||||
|
'en',
|
||||||
|
() => new Promise(res => setTimeout(() => res({ foo: 'foo' }), 300))
|
||||||
|
)
|
||||||
|
|
||||||
|
const flushPromise = flush('en')
|
||||||
|
|
||||||
|
registerLocaleLoader(
|
||||||
|
'en',
|
||||||
|
() => new Promise(res => setTimeout(() => res({ bar: 'bar' })))
|
||||||
|
)
|
||||||
|
|
||||||
|
await flushPromise
|
||||||
|
|
||||||
|
expect(getMessageFromDictionary('en', 'foo')).toBe('foo')
|
||||||
|
expect(getMessageFromDictionary('en', 'bar')).toBe('bar')
|
||||||
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user