Files
ComfyUI-Lora-Manager/tests/frontend/utils/i18nHelpers.test.js
T

86 lines
3.1 KiB
JavaScript

import { describe, it, afterEach, expect, vi } from 'vitest';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
import { translate } from '../../../static/js/utils/i18nHelpers.js';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
/**
* Real en.json translations backed by a minimal `window.i18n` stub that mirrors
* the nested lookup + {param} interpolation of static/js/i18n/index.js, so the
* assertions exercise actual key resolution rather than key presence.
*/
const loadEnTranslations = () =>
JSON.parse(readFileSync(resolve(repoRoot, 'locales/en.json'), 'utf8'));
const installWindowI18n = () => {
const translations = loadEnTranslations();
const interpolate = (str, params) =>
str.replace(/\{\{?(\w+)\}?\}/g, (match, key) =>
params[key] !== undefined ? params[key] : match,
);
window.i18n = {
t: (key, params = {}) => {
const keys = key.split('.');
let value = translations;
for (const k of keys) {
if (value && typeof value === 'object' && k in value) {
value = value[k];
} else {
console.warn(`Translation key not found: ${key}`);
return key;
}
}
if (typeof value !== 'string') {
console.warn(`Translation key is not a string: ${key}`);
return key;
}
return interpolate(value, params);
},
getCurrentLocale: () => 'en',
};
};
afterEach(() => {
delete window.i18n;
});
describe('translate() with real en.json locale', () => {
it('resolves undo toast keys with interpolation', () => {
installWindowI18n();
expect(translate('toast.undo.deleted', { name: 'x' })).toBe('Deleted x');
expect(translate('toast.undo.deletedBulk', { count: 3 })).toBe('Deleted 3 item(s)');
expect(translate('toast.undo.action')).toBe('Undo');
expect(translate('toast.undo.restored')).toBe('Item restored');
expect(translate('toast.undo.expired')).toBe(
'Undo window expired. The item was permanently deleted.',
);
expect(translate('toast.undo.failed', { error: 'boom' })).toBe('Undo failed: boom');
});
it('resolves delete-model modal keys with interpolation', () => {
installWindowI18n();
expect(translate('modals.deleteModel.recoverableWarning')).toBe(
'This will permanently delete the file after 20 seconds unless you undo.',
);
expect(translate('modals.deleteModel.freesSpace', { size: '1.2 MB' })).toBe(
'Frees 1.2 MB',
);
});
it('returns the raw key when no translation exists (fallback contract)', () => {
installWindowI18n();
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
expect(translate('toast.undo.nonExistentKey')).toBe('toast.undo.nonExistentKey');
warnSpy.mockRestore();
});
});