Skip to content

feat(en): add toCurrencyIn, so a bundle that names one currency ships one - #461

Open
TylerVigario wants to merge 2 commits into
mainfrom
feat/currency-in
Open

TylerVigario wants to merge 2 commits into
mainfrom
feat/currency-in

Conversation

@TylerVigario

@TylerVigario TylerVigario commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Adds toCurrencyIn to the English entry points, the shape from my comment on #437.

import { toCurrencyIn } from 'n2words/en-US'
import { GBP } from 'n2words/en/currencies'

toCurrencyIn(42.50, GBP)                  // 'forty-two pounds and fifty pence'
toCurrencyIn(42.50, GBP, { and: false })  // 'forty-two pounds fifty pence'
toCurrency(42.50, { currency: 'GBP' })    // unchanged

Size

en-US with GBP, bundled with rollup 4.64.9 (4.63.1 gives the same bytes) and the individualTerserConfig options from rollup.config.js. Bytes, gzip in parentheses:

toCurrency toCurrencyIn + GBP
exported, arguments unknown 5,207 B (2,203) 4,448 B (2,011)
called, options passed through 5,237 B (2,216) 4,443 B (2,010)
called with no options 5,228 B (2,212) 3,994 B (1,838)

toCurrency keeps every English currency however it's called. toCurrencyIn is smallest when the bundler sees every call and none passes options, because Rollup then drops the options handling. A second currency adds 74 B (exported with USD and GBP: 4,522 B). v6.3.0's toCurrency is 32 B smaller than this branch's in every row.

Corrections to the first version of this table and to my #437 comment. Both set toCurrencyIn called with no options against toCurrency exported, which overstated the saving. Like for like, it saves 759 B with arguments unknown and 1,234 B with no options. The ~4,069 B target in #437 is met only in the no-options case. Both tables also counted characters rather than bytes, a few fewer.

The check on the currency object costs 323 B, or 443 B with no options. The 3,513 B in my #437 comment had no check. Without one, a hand-built object with an empty word list returns malformed output, which the conversion contract rules out.

How

  • currency-vocab.js gives each English currency its own EN_<CODE> binding and builds the en map from them. src/en/currencies.js re-exports each with its code added, so the words still live in one place. The map itself stays without codes: toCurrency already has the code it was passed, and a code per entry made dist/en-US/currency.js 344 B larger instead of 32 B.
  • en-US, en-GB, en-CA and en-IN each move the body of toCurrency into a shared builder, which toCurrency and toCurrencyIn both call. The 13 profiles and en forward toCurrencyIn through export *.
  • assertCurrencyVocab throws TypeError for a malformed currency object, as resolveOptions does for malformed options.
  • dist/ leaves toCurrencyIn out (rollup.config.js). A CDN page can't import one currency yet, because src/en/currencies.js pulls in the whole matrix. Every non-English file in dist/ is byte-identical to v6.3.0. Every English full, UMD and currency bundle is 31-32 B larger, from the call into the shared builder.

Tests

test/currency-in.test.js:

  • toCurrencyIn matches toCurrency, errors included, for all 18 English entry points × 24 currencies × and unset/true/false × 15 amounts, the range ceiling among them.
  • A malformed currency throws TypeError, and options are validated as toCurrency's are.
  • Bundling each of the four implementations with KES leaves "shilling" as the only one of the 14 English major nouns. A toCurrency bundle, as the control, keeps all 14.

I checked that the gate fails when the object path reads the map again, when and is ignored, and when the guard is removed. npm test is 877 passing, lint is clean, and LANGUAGES.md regenerates unchanged.

Not in this PR

  • The other 55 implementations. Each reads its table the same way, so it's the same change per file once the shape is agreed.
  • A CDN path. dist/ would need a file per currency.
  • The name. toCurrencyIn was a placeholder.

Refs #437

🤖 Generated with Claude Code

https://claude.ai/code/session_01NfrA9rAkb8oHNcNHDaPVC4

… one

toCurrency looks its currency up by code, which keeps every English
currency in any bundle that uses it. toCurrencyIn takes the currency as an
object imported from n2words/en/currencies, so a bundler drops the rest:
en-US with GBP bundles to 3,992 B minified, against 5,169 B for toCurrency.

Both share one builder and give the same output. The dist bundles leave
toCurrencyIn out, since a CDN page has no way yet to import one currency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NfrA9rAkb8oHNcNHDaPVC4

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant