Skip to content

Commit 4483c1f

Browse files
authored
feat: Add fallbackLang option (#38)
* feat: Add `fallbackLang` option. * docs: Add `fallbackLang` to the documentation. * style: fixes.
1 parent 84b9329 commit 4483c1f

File tree

5 files changed

+36
-11
lines changed

5 files changed

+36
-11
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ mix.i18n();
147147

148148
### Plugin Options
149149

150-
- `lang` *(optional)*: if not provided it will try to find from the `<html lang="pt">` tag, if is not available it will default to `en`.
150+
- `lang` *(optional)*: If not provided it will try to find from the `<html lang="pt">` tag.
151+
- `fallbackLang` *(optional): If the `lang` was not provided or is invalid, it will try reach for this `fallbackLang` instead, default is: `en`.
151152
- `resolve` *(required)*: The way to reach your language files.
152153

153154
```js

src/index.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const isServer = typeof window === 'undefined'
1212
* The default options, for the plugin.
1313
*/
1414
const DEFAULT_OPTIONS: OptionsInterface = {
15-
lang: !isServer && document.documentElement.lang ? document.documentElement.lang.replace('-', '_') : 'en',
15+
lang: !isServer && document.documentElement.lang ? document.documentElement.lang.replace('-', '_') : null,
16+
fallbackLang: 'en',
1617
resolve: (lang: string) => new Promise((resolve) => resolve({ default: {} }))
1718
}
1819

@@ -36,24 +37,33 @@ const activeMessages: object = reactive({})
3637
*/
3738
export function isLoaded(lang?: string): boolean {
3839
lang ??= getActiveLanguage()
39-
lang = lang.replace('-', '_')
4040

41-
return loaded.some((row) => row.lang === lang)
41+
return loaded.some((row) => row.lang.replace(/[-_]/g, '-') === lang.replace(/[-_]/g, '-'))
4242
}
4343

4444
/**
4545
* Loads the language file.
4646
*/
47-
export function loadLanguageAsync(lang: string): Promise<string | void> {
48-
lang = lang.replace('-', '_')
49-
47+
export function loadLanguageAsync(lang: string, dashLangTry = false): Promise<string | void> {
5048
const loadedLang: LanguageInterface = loaded.find((row) => row.lang === lang)
5149

5250
if (loadedLang) {
5351
return Promise.resolve(setLanguage(loadedLang))
5452
}
5553

5654
return resolveLang(options.resolve, lang).then(({ default: messages }) => {
55+
if (Object.keys(messages).length < 1) {
56+
if (/[-_]/g.test(lang) && !dashLangTry) {
57+
return loadLanguageAsync(
58+
lang.replace(/[-_]/g, (char) => (char === '-' ? '_' : '-')),
59+
true
60+
)
61+
}
62+
if (lang !== options.fallbackLang) {
63+
return loadLanguageAsync(options.fallbackLang)
64+
}
65+
}
66+
5767
const data: LanguageInterface = { lang, messages }
5868
loaded.push(data)
5969
return setLanguage(data)
@@ -104,7 +114,7 @@ export function wTransChoice(
104114
* Returns the current active language.
105115
*/
106116
export function getActiveLanguage(): string {
107-
return options.lang
117+
return options.lang || options.fallbackLang
108118
}
109119

110120
/**
@@ -225,6 +235,6 @@ export const i18nVue: Plugin = {
225235
app.config.globalProperties.$t = (key: string, replacements: ReplacementsInterface) => trans(key, replacements)
226236
app.config.globalProperties.$tChoice = (key: string, number: number, replacements: ReplacementsInterface) =>
227237
transChoice(key, number, replacements)
228-
loadLanguageAsync(options.lang)
238+
loadLanguageAsync(options.lang || options.fallbackLang)
229239
}
230240
}

src/interfaces/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ import { LanguageJsonFileInterface } from './language-json-file'
55
*/
66
export interface OptionsInterface {
77
lang?: string
8+
fallbackLang?: string
89
resolve?(lang: string): Promise<LanguageJsonFileInterface>
910
}

test/setup.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { mount } from '@vue/test-utils'
22
import { i18nVue } from '../src'
33
import { parseAll } from '../src/loader'
44

5-
global.mountPlugin = async (template = '<div />', lang = 'pt') => {
5+
global.mountPlugin = async (template = '<div />', lang = 'pt', fallbackLang = 'pt') => {
66
const wrapper = mount({ template }, {
77
global: {
88
plugins: [[i18nVue, {
99
lang,
10+
fallbackLang,
1011
resolve: lang => import(`./fixtures/lang/${lang}.json`),
1112
}]]
1213
}
@@ -17,11 +18,12 @@ global.mountPlugin = async (template = '<div />', lang = 'pt') => {
1718
return wrapper;
1819
}
1920

20-
global.mountPluginWithRequire = async (template = '<div />', lang = 'pt') => {
21+
global.mountPluginWithRequire = async (template = '<div />', lang = 'pt', fallbackLang = 'pt') => {
2122
const wrapper = mount({ template }, {
2223
global: {
2324
plugins: [[i18nVue, {
2425
lang,
26+
fallbackLang,
2527
resolve: (lang) => require(`./fixtures/lang/${lang}.json`),
2628
}]]
2729
}

test/translate.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ it('returns the same string given if it is not found on the lang file', async ()
3636
expect(wrapper.html()).toBe('<h1>This has no translation</h1>')
3737
})
3838

39+
it('fallback to the `fallbackLang` if the `lang` was not provided', async () => {
40+
await global.mountPlugin(`<div />`, null, 'pt');
41+
expect(trans('Welcome!')).toBe('Bem-vindo!');
42+
})
43+
44+
it('fallback to the `fallbackLang` if the `lang` was not found', async () => {
45+
await global.mountPlugin(`<div />`, 'ch', 'pt');
46+
47+
expect(trans('Welcome!')).toBe('Bem-vindo!');
48+
});
49+
3950
it('returns the given key if the key is not available on the lang', async () => {
4051
await global.mountPlugin(`<div />`, 'en');
4152
expect(trans('Only Available on EN')).toBe('Only Available on EN');

0 commit comments

Comments
 (0)