CogniPrep's assessment centre exercises are written in British English, because
that is the English I write. They are practice for the e-tray, in-tray, written,
presentation, group and role-play exercises an employer runs at an assessment
centre, and the readers are in a lot of countries. A candidate heading to a US
assessment centre can now read all 37 scenarios in American spelling instead.
The feature sounds like one line of replace. It is not, and the reason is the
first thing anyone reaches for.
The blanket rule is wrong
The obvious implementation is -ise to -ize:
text.replace(/ise\b/g, 'ize');
Run that over an exercise brief and you get "promize", "exercize", "expertize",
"compromize", "advize" and "enterprize". Every one of those is spelled the same
way on both sides of the Atlantic. The same trap is waiting in every other
family: -our to -or turns "hour" into "hor" and "your" into "yor", -re to
-er turns "acre" into "acer", and doubling rules applied backwards turn
"filled" into "filed".
So the converter does not infer. It lists. Seven rules, built out of word
families, each matched as a whole word:
const IZE_STEMS = [
'agoni', 'amorti', 'annuali', 'anonymi', 'apologi', 'authori', 'capitali',
// ...75 more
];
const IZE_SUFFIX = '(e|es|ed|ing|er|ers|able|ation|ations|ational|ationally)';
/** Prefixes allowed in front of a stem, so "unauthorised" and "reprioritise" match. */
const PREFIX = '(un|re|de|dis|mis|non|pre|over|under|co)?';
Stems are stored without the letter that changes, which is what lets one entry
cover a whole paradigm. prioriti plus the suffix group plus the prefix group
matches "prioritise", "prioritised", "prioritising", "prioritisation",
"reprioritise" and "deprioritised". The count at the moment:
| family | stems |
|---|---|
-ise / -isation
|
82 |
-yse |
4 |
-our |
27 |
-re |
15 |
-ence |
4 |
single l before a suffix |
40 |
Plus 105 words that have no family and are written out in full: cheque, kerb,
tyre, plough, pyjamas, judgement, programme, maths, aluminium, and the medical
cluster that loses its ligature (paediatric, haemorrhage, oestrogen).
A few of the families have a comment attached explaining what is deliberately
missing from them, because the missing entry is the interesting part:
const YZE_STEMS = ['analy', 'cataly', 'dialy', 'paraly'];
// No "es": "analyses" is also the plural of "analysis", which America spells
// the same way.
const YZE_SUFFIX = '(e|ed|ing|er|ers)';
Spelling only, never vocabulary
The rule I set before writing any of it: this converts spelling and nothing
else. The scenarios stay where they are set. A public sector scenario still
allocates a budget in pounds and still briefs a minister. Swapping "queue" for "line" or
"lift" for "elevator" would be a different exercise, and a candidate practising
for a London graduate scheme would be reading something that no longer matches
the one they applied to.
Two things get protected explicitly. Capitalisation is carried over from the
original rather than lost:
function matchCase(original: string, replacement: string): string {
if (original.length > 1 && original === original.toUpperCase()) {
return replacement.toUpperCase();
}
if (original[0] !== original[0].toLowerCase()) {
return replacement[0].toUpperCase() + replacement.slice(1);
}
return replacement;
}
So "Organise" becomes "Organize" and "ORGANISATION: Thornmere" keeps its shouting.
And proper nouns keep their own spelling, because a brand does not get respelled
when it is read abroad. The fictional companies in these scenarios include a
hotel group called Harbour Hotels, which must not become Harbor Hotels:
export const PROTECTED_NAMES = ['Bright Harbour', 'Harbour Hotels'];
export function toAmericanSpelling(text: string): string {
// split() with a capturing group keeps the names at the odd indexes.
return text
.split(PROTECTED_PATTERN)
.map((segment, i) => (i % 2 === 1 ? segment : americaniseSegment(segment)))
.join('');
}
Splitting on a capturing group and only converting the even indexes is a neat
trick for "apply this transform to everything except these literal strings".
The alternative, a negative lookahead inside seven regexes, would have to be
correct seven times.
The test is the part that keeps working
A hand-written list of word families has one obvious failure mode: I write a new
exercise, I use a British word the list has never seen, and a US reader gets one
stray "behaviour" in the middle of otherwise American copy. Nothing crashes.
Nobody files a bug. It just looks careless.
So the sweep runs the other way round. Instead of asserting that known inputs
convert, it converts the entire library and then asks whether anything that
still looks British came out:
/** Shapes a British spelling takes. Deliberately broad; the allowlist below catches the rest. */
const BRITISH_SHAPES = [
/(is|ys)(e|es|ed|ing|er|ers|able|ation|ations|ational)$/,
/our(s|y|ly|ed|ing|ite|ites|able|ably|al|ally|er|ers|ful|less|hood|ist)?$/,
/(tre|bre|gre)(s|d)?$/,
/^(defence|offence|licence|pretence)s?$/,
/(e|a|i)ll(ed|ing|er|ers|or|ors|ist|ists)$/,
/dgement/,
/(haem|paed|anaes|oedem|oestr|foet|rrhoea)/,
/ogue(s|d)?$/,
/amme(s)?$/,
];
Nine patterns, and they are meant to be too broad. The precision comes from an
allowlist of 77 words that have a British shape and are spelled that way in
America too:
const SAME_IN_AMERICAN = new Set([
'advertising', 'advise', 'adviser', 'compromise', 'concise', 'dialogue',
'enterprise', 'exercise', 'expertise', 'four', 'hour', 'improvise', 'noise',
'otherwise', 'our', 'praising', 'precise', 'premise', 'promise', 'raise',
// ...57 more
]);
The failure output names the word and the exercise it is in:
const leftovers = new Map<string, string>();
// ...walk every string of every exercise, in US English
expect(Object.fromEntries(leftovers)).toEqual({});
That is the whole point. An empty-object assertion with a Map of word to
exercise id gives a diff that reads like a task list, rather than "expected
false to be true". When it fires, the comment above the allowlist tells you
which of the two fixes you want:
A word failing the sweep belongs here only if it is genuinely the same in
American English; otherwise teachlib/exercises/spelling.tsthe word.
My favourite entries in that allowlist are the ones that are not really English:
floodwise and keller. The first is an invented flood preparedness programme
competing for funding in a public sector group exercise. The second is a
colleague's surname in a markets briefing. Both match -ise and -ll shapes, both are
correct as written, and both are only in that list because the sweep found them
and refused to pass.
What it is worth
The honest version of the value here: nobody ever wrote in to say our spelling
was wrong. It is the kind of detail that does not generate complaints, it
generates a vague feeling that a product was built somewhere else. For a
practice tool whose whole job is to feel like the real assessment, that vague
feeling is the product.
If you want to see what the converter is actually operating on, the free e-tray
scenario on the
assessment centre practice page
runs in full without an account, and the format guides for the
written exercise
and the
in-tray exercise
describe what each one is marked on.
Top comments (0)