Skip to content

feat(i18n): make Pulse Finances currency-configurable - #1777

Open
takanorinishida wants to merge 1 commit into
danielmiessler:mainfrom
takanorinishida:feature/i18n/pulse-currency
Open

feat(i18n): make Pulse Finances currency-configurable#1777
takanorinishida wants to merge 1 commit into
danielmiessler:mainfrom
takanorinishida:feature/i18n/pulse-currency

Conversation

@takanorinishida

Copy link
Copy Markdown

Finances tab hardcoded $ everywhere, so a non-USD install renders its own currency's amounts as if they were dollars (e.g. an outbound total of ¥2,120,000 shows as "$2.1M" — a 1000x misread, not just a symbol mismatch).

Changes

  • LifeosPrincipal gains an optional currency field (ISO 4217), mirrored in the LIFEOS_CONFIG.toml scaffold. Unset defaults to USD, same pattern as the existing optional principal fields.
  • observability.ts's /api/life/finances envelope now reports the resolved currency (fail-open to "USD" on any config error, matching loadYaml()'s existing contract).
  • finances/page.tsx resolves a display symbol from that code (a small static table for the four currencies LifeOS ships sample data for, Intl.NumberFormat as best-effort fallback for anything else) and threads it through fmtHero/fmtExact and the trend chart's Y axis, replacing every hardcoded $.
  • parseCurrencyCell() (INCOME.md/EXPENSES.md table parsing) now strips ¥/€/£/₩/₹ and the word "円" in addition to $, and recognizes 万/億 magnitude suffixes alongside the existing K/M — data additions to an existing table, not new branches. The obligations.yaml legacy-amount parser now reuses this same function instead of a narrower ad hoc regex that silently ignored magnitude suffixes.

Non-destructive

Currency unset (or explicitly "USD") renders byte-identical to before: the fallback table is checked before Intl, so the default symbol is the same "$" literal this page has always rendered, independent of the server's locale environment.

git diff main...HEAD | rg '^-' | rg -v '^---'

Every removed line is either a doc comment or the same original $-literal line now dispatching through currencySymbol/parseCurrencyCell — same original functions, no removed capability.

Verification

  • Built and deployed to a live install with [principal] currency = "JPY" set; /api/life/finances returns currency: "JPY", and the tab renders ¥2.1M etc. instead of $2.1M.
  • Standalone unit-style checks against parseCurrencyCell ($12,000, ~$40K, ¥100,000, ¥1万, 1.2億, ...) all match expected values.

🤖 Generated with Claude Code

Finances tab hardcoded $ everywhere, so a non-USD install renders its
own currency's amounts as if they were dollars (e.g. an outbound total
of ¥2,120,000 shows as "$2.1M" — a 1000x misread, not just a symbol
mismatch).

- LifeosPrincipal gains an optional `currency` field (ISO 4217),
  mirrored in the LIFEOS_CONFIG.toml scaffold. Unset defaults to USD,
  same pattern as the existing optional principal fields.
- observability.ts's /api/life/finances envelope now reports the
  resolved currency (fail-open to "USD" on any config error, matching
  loadYaml()'s existing contract).
- finances/page.tsx resolves a display symbol from that code (a small
  static table for the four currencies LifeOS ships sample data for,
  Intl.NumberFormat as best-effort fallback for anything else) and
  threads it through fmtHero/fmtExact and the trend chart's Y axis,
  replacing every hardcoded $.
- parseCurrencyCell() (INCOME.md/EXPENSES.md table parsing) now strips
  ¥/€/£/₩/₹ and the word "円" in addition to $, and recognizes 万/億
  magnitude suffixes alongside the existing K/M — data additions to an
  existing table, not new branches. The obligations.yaml legacy-amount
  parser now reuses this same function instead of a narrower ad hoc
  regex that silently ignored magnitude suffixes.

Currency unset (or explicitly "USD") renders byte-identical to before:
the fallback table is checked before Intl, so the default symbol is
the same "$" literal this page has always rendered, independent of
the server's locale environment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVzLJHrJPj5Phmh1vaLUBV
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