113 lines
4.3 KiB
JavaScript
113 lines
4.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import {
|
|
createI18n,
|
|
resolveLocale,
|
|
} from '../src/lib/i18n/index.js';
|
|
import englishShellCatalog from '../src/lib/i18n/catalogs/en.js';
|
|
import russianShellCatalog from '../src/lib/i18n/catalogs/ru.js';
|
|
|
|
assert.deepEqual(
|
|
Object.keys(russianShellCatalog).sort(),
|
|
Object.keys(englishShellCatalog).sort(),
|
|
'English and Russian shell catalogs must have identical keys',
|
|
);
|
|
|
|
assert.equal(resolveLocale('system', ['ru-RU']), 'ru');
|
|
assert.equal(resolveLocale('system', ['uk-UA', 'en-US']), 'en');
|
|
assert.equal(resolveLocale('ru', ['en-US']), 'ru');
|
|
assert.equal(resolveLocale('en', ['ru-RU']), 'en');
|
|
assert.throws(() => resolveLocale('de', ['de-DE']), /unsupported language/);
|
|
|
|
const catalogs = {
|
|
'localized.plugin': {
|
|
en: { 'manifest.name': 'Localized Plugin', greeting: 'Hello, {name}!' },
|
|
ru: {
|
|
'manifest.name': 'Локализованный плагин',
|
|
'contributions.views.localized.view.title': 'Локализованный экран',
|
|
greeting: 'Привет, {name}!',
|
|
},
|
|
},
|
|
};
|
|
const loads = [];
|
|
const service = createI18n({
|
|
shellCatalogs: {
|
|
en: { loading: 'Loading {name}...', fallbackOnly: 'English fallback' },
|
|
ru: { loading: 'Загрузка {name}...' },
|
|
},
|
|
systemLanguages: () => ['ru-RU'],
|
|
loadPluginCatalog: async (pluginId, locale) => {
|
|
loads.push(`${pluginId}:${locale}`);
|
|
return catalogs[pluginId]?.[locale] || {};
|
|
},
|
|
});
|
|
|
|
await service.initialize('system');
|
|
assert.equal(service.getLanguagePreference(), 'system');
|
|
assert.equal(service.getLocale(), 'ru');
|
|
assert.equal(service.t('loading', { name: 'Верстак' }), 'Загрузка Верстак...');
|
|
assert.equal(service.t('fallbackOnly'), 'English fallback');
|
|
assert.equal(service.t('missing', undefined, 'Explicit fallback'), 'Explicit fallback');
|
|
assert.equal(service.t('unknown'), 'unknown');
|
|
|
|
await service.loadPlugin('localized.plugin', {
|
|
defaultLocale: 'en',
|
|
locales: { en: 'locales/en.json', ru: 'locales/ru.json' },
|
|
});
|
|
assert.deepEqual(loads.sort(), ['localized.plugin:en', 'localized.plugin:ru']);
|
|
assert.equal(service.translatePlugin('localized.plugin', 'greeting', { name: 'Мир' }), 'Привет, Мир!');
|
|
|
|
const plugin = {
|
|
manifest: {
|
|
id: 'localized.plugin',
|
|
name: 'Localized Plugin',
|
|
description: 'Literal description',
|
|
contributes: {
|
|
views: [{ id: 'localized.view', title: 'Literal View', component: 'View' }],
|
|
},
|
|
},
|
|
};
|
|
const localized = service.localizePlugin(plugin);
|
|
assert.notEqual(localized, plugin);
|
|
assert.equal(localized.manifest.name, 'Локализованный плагин');
|
|
assert.equal(localized.manifest.description, 'Literal description');
|
|
assert.equal(localized.manifest.contributes.views[0].title, 'Локализованный экран');
|
|
assert.equal(plugin.manifest.name, 'Localized Plugin');
|
|
const summary = service.localizeContributionSummary({
|
|
views: [{ pluginId: 'localized.plugin', id: 'localized.view', title: 'Literal View', component: 'View' }],
|
|
});
|
|
assert.equal(summary.views[0].title, 'Локализованный экран');
|
|
|
|
let notifications = 0;
|
|
const unsubscribe = service.subscribe(() => { notifications += 1; });
|
|
assert.equal(notifications, 1);
|
|
await service.setLanguagePreference('en');
|
|
assert.equal(service.getLocale(), 'en');
|
|
assert.equal(service.translatePlugin('localized.plugin', 'greeting', { name: 'World' }), 'Hello, World!');
|
|
assert.equal(notifications, 2);
|
|
unsubscribe();
|
|
await service.setLanguagePreference('ru');
|
|
assert.equal(notifications, 2);
|
|
|
|
const resilientService = createI18n({
|
|
shellCatalogs: { en: { title: 'Title' }, ru: { title: 'Заголовок' } },
|
|
systemLanguages: () => ['en-US'],
|
|
loadPluginCatalog: async () => { throw new Error('broken catalog'); },
|
|
});
|
|
await resilientService.initialize('en');
|
|
await assert.rejects(
|
|
resilientService.loadPlugin('broken.plugin', {
|
|
defaultLocale: 'en',
|
|
locales: { en: 'locales/en.json', ru: 'locales/ru.json' },
|
|
}),
|
|
/broken catalog/,
|
|
);
|
|
let resilientNotification = '';
|
|
resilientService.subscribe((nextLocale) => { resilientNotification = nextLocale; });
|
|
await resilientService.setLanguagePreference('ru');
|
|
assert.equal(resilientService.getLanguagePreference(), 'ru');
|
|
assert.equal(resilientService.getLocale(), 'ru');
|
|
assert.equal(resilientNotification, 'ru');
|
|
assert.equal(resilientService.t('title'), 'Заголовок');
|
|
|
|
console.log('i18n service tests passed');
|