-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Mark Skelton
committed
Mar 26, 2021
1 parent
8ec44fd
commit 37eb5c2
Showing
7 changed files
with
161 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,8 @@ | |
"env": { | ||
"jest": true, | ||
"node": true | ||
}, | ||
"rules": { | ||
"@typescript-eslint/no-non-null-assertion": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,47 @@ | ||
export function run(): boolean { | ||
return true | ||
import { BackendModule, ReadCallback, Services } from 'i18next' | ||
|
||
type ResourceFetcher = () => Promise<Record<string, string>> | ||
|
||
export interface AsyncBackendOptions { | ||
resources?: { | ||
[language: string]: ResourceFetcher | Record<string, ResourceFetcher> | ||
} | ||
} | ||
|
||
export default class AsyncBackend | ||
implements BackendModule<AsyncBackendOptions> { | ||
// i18next is dumb as TypeScript requires the class property for `type` | ||
// but the runtime requires the static `type` property. | ||
static type = 'backend' | ||
type = 'backend' as const | ||
|
||
private options: AsyncBackendOptions = null! | ||
|
||
constructor(services: Services, options: AsyncBackendOptions) { | ||
this.init(services, options) | ||
} | ||
|
||
init(_: Services, options: AsyncBackendOptions): void { | ||
this.options = { ...this.options, ...options } | ||
} | ||
|
||
read(lng: string, ns: string, callback: ReadCallback): void { | ||
const resourceFetcher = this.getResourceFetcher(lng, ns) | ||
|
||
if (resourceFetcher) { | ||
resourceFetcher() | ||
.then((resource) => callback(null, resource)) | ||
.catch((err) => callback(err, false)) | ||
} else { | ||
callback(new Error('resource not found'), false) | ||
} | ||
} | ||
|
||
private getResourceFetcher(lng: string, ns: string) { | ||
// Languages can specify a function if they only have a single namespace | ||
// or an object if they have multiple namespaces. | ||
const fetcher = this.options.resources?.[lng] | ||
|
||
return typeof fetcher === 'function' ? fetcher : fetcher?.[ns] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import i18next from 'i18next' | ||
import AsyncBackend, { AsyncBackendOptions } from '../src' | ||
|
||
async function init(ns: string[], resources: AsyncBackendOptions['resources']) { | ||
const i18n = i18next.createInstance().use(AsyncBackend) | ||
|
||
const t = await i18n.init({ | ||
backend: { resources }, | ||
fallbackLng: 'en', | ||
defaultNS: ns[0], | ||
ns, | ||
}) | ||
|
||
return { i18n, t } | ||
} | ||
|
||
it('should accept a function if there is only one namespace', async () => { | ||
const { t } = await init(['translation'], { | ||
en: () => Promise.resolve({ foo: 'bar' }), | ||
}) | ||
|
||
expect(t('foo')).toBe('bar') | ||
}) | ||
|
||
it('should accept an object if there are multiple namespaces', async () => { | ||
const { t } = await init(['ns1', 'ns2'], { | ||
en: { | ||
ns1: () => Promise.resolve({ fruit: 'Apples' }), | ||
ns2: () => Promise.resolve({ fruit: 'Oranges' }), | ||
}, | ||
}) | ||
|
||
expect(t('fruit')).toBe('Apples') | ||
expect(t('ns1:fruit')).toBe('Apples') | ||
expect(t('ns2:fruit')).toBe('Oranges') | ||
}) | ||
|
||
it('should load multiple languages', async () => { | ||
const { t, i18n } = await init(['ns1', 'ns2'], { | ||
en: { | ||
ns1: () => Promise.resolve({ fruit: 'Apples' }), | ||
ns2: () => Promise.resolve({ fruit: 'Oranges' }), | ||
}, | ||
es: { | ||
ns1: () => Promise.resolve({ fruit: 'Manzanas' }), | ||
ns2: () => Promise.resolve({ fruit: 'Naranjas' }), | ||
}, | ||
}) | ||
|
||
// English | ||
expect(t('fruit')).toBe('Apples') | ||
expect(t('ns1:fruit')).toBe('Apples') | ||
expect(t('ns2:fruit')).toBe('Oranges') | ||
|
||
// Spanish | ||
await i18n.changeLanguage('es') | ||
expect(t('fruit')).toBe('Manzanas') | ||
expect(t('ns1:fruit')).toBe('Manzanas') | ||
expect(t('ns2:fruit')).toBe('Naranjas') | ||
}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters