mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 17:12:27 +03:00
* fix(compression): add i18n support for less-code and terse-prose Translates less-code output style to pt-BR, vi, ja, and id. Adds missing vi translation to terse-prose caveman mode. Removes less-code from English-only allowlist and updates matrix tests. Fixes #10426 * docs(compression): add output styles coverage table Adds the requested Output Styles matrix to the compression guide covering styles, supported languages, and intensity levels. Fixes #10426
139 lines
5.1 KiB
TypeScript
139 lines
5.1 KiB
TypeScript
/**
|
||
* Guard for the output-style × language matrix.
|
||
*
|
||
* Why this exists: the compression INPUT engines understand 10 languages (rule
|
||
* packs under open-sse/services/compression/rules/ + the detector), but the
|
||
* OUTPUT styles only instruct in a subset. `less-code` shipped English-only and
|
||
* nobody noticed for months, because every other test is per-style. This test
|
||
* is per-MATRIX: it pins the expected coverage so a new style cannot silently
|
||
* be born English-only, and so an existing style cannot silently lose a locale.
|
||
*
|
||
* Adding a language to a style: extend BASELINE_LANGUAGES below (the assertion
|
||
* is "at least these", so growth never fails the gate).
|
||
* Adding a NEW style: it must cover REQUIRED_LANGUAGES, or be listed in
|
||
* KNOWN_ENGLISH_ONLY with a tracking issue.
|
||
*/
|
||
|
||
import test from "node:test";
|
||
import assert from "node:assert/strict";
|
||
import {
|
||
OUTPUT_STYLE_CATALOG,
|
||
OUTPUT_STYLE_IDS,
|
||
outputStyleMeta,
|
||
} from "../../../open-sse/services/compression/outputStyles/catalog.ts";
|
||
|
||
/** Minimum i18n coverage every new non-locale-gated style must ship with. */
|
||
const REQUIRED_LANGUAGES = ["pt-BR"];
|
||
|
||
/**
|
||
* Styles that predate this guard and are still English-only.
|
||
* Do NOT add entries here without an issue — fix the coverage instead.
|
||
*/
|
||
const KNOWN_ENGLISH_ONLY: Record<string, string> = {
|
||
};
|
||
|
||
/**
|
||
* Frozen per-style coverage. The assertion is a SUPERSET check, so adding a
|
||
* language is always allowed; removing one fails the gate.
|
||
*/
|
||
const BASELINE_LANGUAGES: Record<string, string[]> = {
|
||
// terse-prose reuses CAVEMAN_INSTRUCTION_BY_LANGUAGE (outputMode.ts), which
|
||
// localizes to pt-BR/ja/id/vi — keep the two in sync when adding a language.
|
||
"terse-prose": ["pt-BR", "ja", "id", "vi"],
|
||
"less-code": ["pt-BR", "vi", "ja", "id"],
|
||
ponytail: ["pt-BR", "vi", "ja", "id"],
|
||
"i-have-adhd": ["pt-BR", "vi", "ja", "id"],
|
||
// locale-gated to zh: the single-language instruction IS the feature.
|
||
"terse-cjk": [],
|
||
};
|
||
|
||
function languagesOf(id: string): string[] {
|
||
return Object.keys(outputStyleMeta(id).i18n ?? {});
|
||
}
|
||
|
||
test("every catalog style is covered by the matrix baseline", () => {
|
||
for (const id of OUTPUT_STYLE_IDS) {
|
||
assert.ok(
|
||
id in BASELINE_LANGUAGES,
|
||
`style "${id}" is missing from BASELINE_LANGUAGES — add its expected languages ` +
|
||
`(and translate it: a new style must cover ${REQUIRED_LANGUAGES.join(", ")})`
|
||
);
|
||
}
|
||
});
|
||
|
||
test("no style loses a language it already had", () => {
|
||
for (const [id, expected] of Object.entries(BASELINE_LANGUAGES)) {
|
||
if (!OUTPUT_STYLE_CATALOG[id]) continue; // style removed — covered by the catalog tests
|
||
const actual = languagesOf(id);
|
||
for (const lang of expected) {
|
||
assert.ok(
|
||
actual.includes(lang),
|
||
`style "${id}" lost its "${lang}" translation (has: ${actual.join(", ") || "none"})`
|
||
);
|
||
}
|
||
}
|
||
});
|
||
|
||
test("a non-locale-gated style ships the required languages, or is a known gap", () => {
|
||
for (const id of OUTPUT_STYLE_IDS) {
|
||
const meta = outputStyleMeta(id);
|
||
// A locale-gated style is only ever offered under its own locale, so a
|
||
// single-language instruction is correct by design (e.g. terse-cjk → zh).
|
||
if (meta.locale) continue;
|
||
if (id in KNOWN_ENGLISH_ONLY) continue;
|
||
const actual = languagesOf(id);
|
||
for (const lang of REQUIRED_LANGUAGES) {
|
||
assert.ok(
|
||
actual.includes(lang),
|
||
`style "${id}" must ship a "${lang}" translation (has: ${actual.join(", ") || "none"}). ` +
|
||
`English-only styles need an entry in KNOWN_ENGLISH_ONLY with a tracking issue.`
|
||
);
|
||
}
|
||
}
|
||
});
|
||
|
||
test("every declared translation has all three intensity levels", () => {
|
||
for (const id of OUTPUT_STYLE_IDS) {
|
||
const i18n = outputStyleMeta(id).i18n ?? {};
|
||
for (const [lang, levels] of Object.entries(i18n)) {
|
||
for (const level of ["lite", "full", "ultra"] as const) {
|
||
assert.equal(
|
||
typeof levels[level],
|
||
"string",
|
||
`${id}.i18n["${lang}"].${level} must be a string`
|
||
);
|
||
assert.ok(levels[level].length > 0, `${id}.i18n["${lang}"].${level} must be non-empty`);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
test("every translated level carries the shared boundaries clause", () => {
|
||
// The boundary clause is what keeps code, paths, commands, errors and URLs
|
||
// verbatim. A translation that drops it would let the model rewrite them.
|
||
const anchor = "Code blocks";
|
||
for (const id of OUTPUT_STYLE_IDS) {
|
||
const i18n = outputStyleMeta(id).i18n ?? {};
|
||
for (const [lang, levels] of Object.entries(i18n)) {
|
||
for (const level of ["lite", "full", "ultra"] as const) {
|
||
assert.ok(
|
||
levels[level].includes(anchor),
|
||
`${id}.i18n["${lang}"].${level} is missing the shared boundaries clause`
|
||
);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
test("KNOWN_ENGLISH_ONLY does not hide a style that is actually translated", () => {
|
||
// Stale-allowlist guard: once a gap is fixed, its entry must be removed.
|
||
for (const id of Object.keys(KNOWN_ENGLISH_ONLY)) {
|
||
if (!OUTPUT_STYLE_CATALOG[id]) continue;
|
||
assert.equal(
|
||
languagesOf(id).length,
|
||
0,
|
||
`style "${id}" now has translations — remove it from KNOWN_ENGLISH_ONLY`
|
||
);
|
||
}
|
||
});
|