mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-09 03:32:54 -05:00
Fix i18n language fallback for regional languages (#4185)
* Fix i18n language fallback for regional languages * Add release notes * Fix test
This commit is contained in:
committed by
GitHub
parent
66619fa20d
commit
6070166f4e
81
packages/desktop-client/src/i18n.test.ts
Normal file
81
packages/desktop-client/src/i18n.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import i18n from 'i18next';
|
||||
|
||||
import { setI18NextLanguage, availableLanguages } from './i18n';
|
||||
|
||||
vi.mock('i18next', () => {
|
||||
const i18nMock = {
|
||||
use: vi.fn().mockReturnThis(),
|
||||
init: vi.fn().mockResolvedValue(undefined),
|
||||
changeLanguage: vi.fn(),
|
||||
};
|
||||
return {
|
||||
default: i18nMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.hoisted(vi.resetModules);
|
||||
|
||||
describe('setI18NextLanguage', () => {
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(vi.unstubAllGlobals);
|
||||
|
||||
test('should set system default language when no language is provided', () => {
|
||||
vi.stubGlobal('navigator', { language: 'uk' });
|
||||
|
||||
setI18NextLanguage('');
|
||||
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith('uk');
|
||||
});
|
||||
|
||||
test('should set the provided language if it is available', () => {
|
||||
const language = availableLanguages[0];
|
||||
|
||||
setI18NextLanguage(language);
|
||||
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith(language);
|
||||
});
|
||||
|
||||
test('should fallback to English if the provided language is unavailable', () => {
|
||||
vi.spyOn(console, 'error');
|
||||
|
||||
setI18NextLanguage('unknown');
|
||||
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Unknown locale unknown, falling back to en',
|
||||
);
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith('en');
|
||||
});
|
||||
|
||||
test('should successfully use a language with a region code if it is known', () => {
|
||||
const language = 'pt-BR';
|
||||
|
||||
setI18NextLanguage(language);
|
||||
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith(language);
|
||||
});
|
||||
|
||||
test('should fallback to base language if the provided language has an unknown region code', () => {
|
||||
vi.spyOn(console, 'error');
|
||||
|
||||
setI18NextLanguage('uk-ZZ');
|
||||
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Unknown locale uk-ZZ, falling back to uk',
|
||||
);
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith('uk');
|
||||
});
|
||||
|
||||
test('should fallback to lowercase language if the provided language has uppercase letters', () => {
|
||||
vi.spyOn(console, 'error');
|
||||
|
||||
setI18NextLanguage('EN');
|
||||
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Unknown locale EN, falling back to en',
|
||||
);
|
||||
expect(i18n.changeLanguage).toHaveBeenCalledWith('en');
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,6 @@ const isLanguageAvailable = (language: string) =>
|
||||
|
||||
const loadLanguage = (language: string) => {
|
||||
if (!isLanguageAvailable(language)) {
|
||||
console.error(`Unknown locale ${language}`);
|
||||
throw new Error(`Unknown locale ${language}`);
|
||||
}
|
||||
return languages[`/locale/${language}.json`]();
|
||||
@@ -41,26 +40,39 @@ i18n
|
||||
});
|
||||
|
||||
export const setI18NextLanguage = (language: string) => {
|
||||
if (language === 'en' && !isLanguageAvailable(language)) {
|
||||
// English is always available since we use natural-language keys.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// System default
|
||||
setI18NextLanguage(navigator.language || 'en');
|
||||
return;
|
||||
}
|
||||
|
||||
language = language.toLowerCase();
|
||||
if (!availableLanguages.includes(language)) {
|
||||
if (language.includes('-')) {
|
||||
setI18NextLanguage(language.split('-')[0]);
|
||||
if (!isLanguageAvailable(language)) {
|
||||
if (language === 'en') {
|
||||
// English is always available since we use natural-language keys.
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(`Unknown locale ${language}`);
|
||||
throw new Error(`Unknown locale ${language}`);
|
||||
if (language.includes('-')) {
|
||||
const fallback = language.split('-')[0];
|
||||
console.error(`Unknown locale ${language}, falling back to ${fallback}`);
|
||||
setI18NextLanguage(fallback);
|
||||
return;
|
||||
}
|
||||
|
||||
const lowercaseLanguage = language.toLowerCase();
|
||||
if (lowercaseLanguage !== language) {
|
||||
console.error(
|
||||
`Unknown locale ${language}, falling back to ${lowercaseLanguage}`,
|
||||
);
|
||||
setI18NextLanguage(lowercaseLanguage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back to English
|
||||
console.error(`Unknown locale ${language}, falling back to en`);
|
||||
setI18NextLanguage('en');
|
||||
return;
|
||||
}
|
||||
|
||||
i18n.changeLanguage(language || 'en');
|
||||
};
|
||||
|
||||
6
upcoming-release-notes/4185.md
Normal file
6
upcoming-release-notes/4185.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Bugfix
|
||||
authors: [jfdoming]
|
||||
---
|
||||
|
||||
Fix i18n language fallback for regional languages
|
||||
Reference in New Issue
Block a user