const vowels = ['A', 'E', 'I', 'O', 'U'] const consonants = [ 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z', ] const startsWiths = ['XR', 'YT', 'AY'] const rule1 = (word: string) => // If a word begins with a vowel, or starts with `"xr"` or `"yt"`, // add an `"ay"` sound to the end of the word. vowels.concat(startsWiths).some(s => word.toUpperCase().startsWith(s)) ? `${word}ay` : word const rule2RegExp = new RegExp(`^([${consonants.join('')}]+)(.*)`, 'i') const rule2 = (word: string): string => // If a word begins with a one or more consonants, first move // those consonants to the end of the word and then add an `"ay"` // sound to the end of the word. word.replace( rule2RegExp, (_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`, ) const rule3RegExp = new RegExp(`^(qu|[${consonants.join('')}]*qu)(.*)`, 'i') const rule3 = (word: string): string => // If a word starts with zero or more consonants followed by `"qu"`, // first move those consonants (if any) and the `"qu"` part to the end // of the word, and then add an `"ay"` sound to the end of the word. word.replace( rule3RegExp, (_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`, ) const rule4RegExp = new RegExp(`^([${consonants.join('')}]+)(y.*)`, 'i') const rule4 = (word: string): string => // If a word starts with one or more consonants followed by `"y"`, // first move the consonants preceding the `"y"`to the end of the word, // and then add an `"ay"` sound to the end of the word. word.replace( rule4RegExp, (_, match, rest) => `${rest}${match}${match ? 'ay' : ''}`, ) const applyRule = (rule: (word: string) => string) => ({ originalWord, hasChanged, }: { originalWord: string hasChanged: boolean }) => { if (hasChanged) return { originalWord, hasChanged } const word = rule(originalWord) return { originalWord: word, hasChanged: word !== originalWord } } export const translate = (text: string): string => { return text .split(' ') .filter(Boolean) .map(word => ({ originalWord: word, hasChanged: false })) .map(applyRule(rule1)) .map(applyRule(rule3)) .map(applyRule(rule4)) .map(applyRule(rule2)) .map(({ originalWord }) => originalWord) .join(' ') }