- M2M100 418M (MIT, 617 MB q8) covers 23 app languages; Basque uses converted Opus eu-en/en-eu q8 packs; all self-hosted under relay.skate-spots.org/models. - Worker uses M2M100 directly and pivots Basque through English; UI targets all languages; old pilot restriction/note removed; memory-only + guard unchanged. - Verified en<->es, ca<->gl, hi<->en from the host. Basque packs are converted and hosted; the final MarianTokenizer/ONNX runtime check is still pending. - 138 tests, 24 locales, build and smoke green. SpotChat deliberately skipped.
68 lines
2 KiB
TypeScript
68 lines
2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { clearTranslationMemory, isTranslationPairSupported, translateText } from './translation';
|
|
|
|
class FakeWorker {
|
|
onmessage: ((event: MessageEvent) => void) | null = null;
|
|
onerror: (() => void) | null = null;
|
|
|
|
postMessage(request: { id: number; text: string }) {
|
|
queueMicrotask(() => {
|
|
this.onmessage?.({
|
|
data: { type: 'result', id: request.id, text: `translated:${request.text}` },
|
|
} as MessageEvent);
|
|
});
|
|
}
|
|
|
|
terminate() {}
|
|
}
|
|
|
|
describe('translateText', () => {
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
clearTranslationMemory();
|
|
});
|
|
|
|
it('keeps the message local and never calls fetch', async () => {
|
|
const fetchSpy = vi.fn();
|
|
const received: string[] = [];
|
|
|
|
class RecordingWorker extends FakeWorker {
|
|
postMessage(request: { id: number; text: string }) {
|
|
received.push(request.text);
|
|
super.postMessage(request);
|
|
}
|
|
}
|
|
|
|
vi.stubGlobal('fetch', fetchSpy);
|
|
vi.stubGlobal('Worker', RecordingWorker);
|
|
clearTranslationMemory();
|
|
|
|
const result = await translateText({
|
|
id: 'message-1',
|
|
text: 'SENTINEL-MESSAGE-TEXT',
|
|
source: 'en',
|
|
target: 'es',
|
|
});
|
|
|
|
expect(result).toBe('translated:SENTINEL-MESSAGE-TEXT');
|
|
expect(received).toEqual(['SENTINEL-MESSAGE-TEXT']);
|
|
expect(fetchSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('returns the input when source and target match', async () => {
|
|
const result = await translateText({
|
|
id: 'message-2',
|
|
text: 'same language',
|
|
source: 'en',
|
|
target: 'en',
|
|
});
|
|
expect(result).toBe('same language');
|
|
});
|
|
|
|
it('supports all app language pairs (M2M100 + Basque Opus)', () => {
|
|
expect(isTranslationPairSupported('ca', 'en')).toBe(true);
|
|
expect(isTranslationPairSupported('eu', 'en')).toBe(true);
|
|
expect(isTranslationPairSupported('hi', 'es')).toBe(true);
|
|
expect(isTranslationPairSupported('en', 'en')).toBe(false);
|
|
});
|
|
});
|