When pre-normalizing makes sense
There are two cases where pre-normalization in your application is worth the cost:- The input falls into a known gap. A small set of patterns aren’t reliably expanded today. Pre-expanding those specific patterns is the reliable fix.
- You need guaranteed consistency across regenerations. For utterances that must read identically every time, such as regulatory disclosures, legal read-backs, or confirmation flows, pre-normalizing removes a source of variability.
/textnorm to verify anything that sounds off. If you find a pattern Rime doesn’t handle, flag it to Rime; fixes ship on Rime’s side instead of in every customer’s pre-processing layer.
Known gaps
These patterns aren’t reliably expanded today. Either avoid them at the source, or pre-expand them in the layer that generates your text.Dates
- MM/DD without a year (
04/21). Expand toApril 21storApril twenty-first. - Financial periods (
1H 2024,Q1 2025,1Q,2Q). Not consistently expanded. - Cross-month date ranges (
May-June 2024). Not a recognized pattern.
Times
- European
15h30times. Thehseparator isn’t recognized. Use15:30. - Suffixed approximations.
9:00-ishreads the colon literally. Avoid or pre-normalize.
Numbers
- Bare 5+ digit runs (
10000000) read digit-by-digit. Add thousands separators (10,000,000) to get the quantity reading, or use shorthand (10M). - Bare caret exponents (
10^6without a leadingx10) aren’t rewritten. Use1e6or superscripts (10⁶), which are recognized. - Very large ordinals (
1,000,000th) fall back to digit-by-digit. Prefer writing out (one millionth).
Money
- Minus-sign glyphs (
−€100with U+2212). Use the ASCII hyphen (-€100); ASCII negative amounts are handled.
Measurements
- Bare
mwith no denominator.1mreads as “one million.” Write1 meter, or use a denominator (7m/sreads correctly as “seven meters per second”). - Ampere and joule units (
5A,J) pass through unexpanded. Spell out (5 amperes) if verbalization matters. - Uncommon units (
btu,psi,dyne,‰) are not reliably expanded. - Parenthesized compound units (
5(kg/m²)) aren’t a recognized form.
Ranges
- Inconsistent connector. Hyphen ranges are usually read as “to,” but in some contexts the hyphen is read literally. If consistency matters, use the word “to” directly.
Roman numerals
- Roman numerals always pass through unchanged in English, with or without a context word. Use
spell()to force letter-by-letter, or write out the number. - Mixed-format numbering (
section 2.IV.3) isn’t handled.
Phone numbers
- Vanity numbers (
1-800-FLOWERS) keep the letters as a literal string. Usespell(FLOWERS)if you need letter-by-letter. - Extensions (
555-1234 ext. 567,555-1234 x 567) aren’t explicitly handled.
Miscellaneous
- Context-dependent abbreviations (
Dr.,Mr.,St.) rely on context and may not always resolve as expected. See Abbreviations. - Repeating decimals (
0.3̄,0.(3)) aren’t recognized. - Internationalized domain names (non-ASCII in URLs) aren’t supported.
Pre-normalization prompt template
If your application uses an LLM to generate text before sending it to Rime, you can add the rules below to its system prompt or run them as a post-processing pass. The template targets only the known gaps; Rime’s normalizer handles the rest, so there’s no need to pre-expand everything.System prompt template
System prompt template

