Skip to content

feat(locale): add locale-aware currency formatting#467

Merged
cpcloud merged 3 commits intomainfrom
worktree-expressive-jumping-deer
Feb 28, 2026
Merged

feat(locale): add locale-aware currency formatting#467
cpcloud merged 3 commits intomainfrom
worktree-expressive-jumping-deer

Conversation

@cpcloud
Copy link
Copy Markdown
Collaborator

@cpcloud cpcloud commented Feb 22, 2026

Summary

  • Add locale-aware currency formatting with locale.Currency type wrapping golang.org/x/text/currency and golang.org/x/text/message
  • Separate currency code (what money) from formatting locale (how to display numbers) -- these are independent concerns, like timestamps and timezones
  • Currency code is persisted to SQLite for DB portability; formatting locale is detected from LC_MONETARY/LC_ALL/LANG at runtime (never persisted)
  • Resolution order: DB value > config [locale] currency > MICASA_CURRENCY env > auto-detect from locale > USD fallback
  • All money columns, forms, compact notation, mag mode, and house profile use locale-correct formatting
  • Fix multi-byte grouping separator handling (French U+00A0 non-breaking space was silently broken due to byte-level iteration)
  • Cache grouping/decimal separators at construction time instead of recomputing per format call
  • Add named symbol constants (SymbolDollar, SymbolEuro, SymbolPound, SymbolYen) and replace all hardcoded Unicode escapes

Closes #467

Test plan

All items covered by automated user-flow tests in internal/app/currency_flow_test.go (section 19).

🤖 Generated with Claude Code

@cpcloud cpcloud force-pushed the worktree-expressive-jumping-deer branch 11 times, most recently from 299c234 to 0b39672 Compare February 26, 2026 14:57
Replace hardcoded USD formatting with configurable currency support
using golang.org/x/text/currency and golang.org/x/text/message for
CLDR-compliant symbol rendering and number formatting.

Currency resolution follows a layered precedence: database setting
(authoritative once set) > MICASA_CURRENCY env var > TOML config
[locale] currency > auto-detect from LC_MONETARY/LANG > USD fallback.
The chosen currency is persisted to the database so the DB file stays
portable -- a EUR database sent to a US user still shows amounts with
the euro sign.

Key changes:
- New internal/locale package with Currency type wrapping x/text/currency
- Settings store gains GetCurrency/PutCurrency for DB persistence
- Config gains [locale] section with currency field and env override
- Currency threaded through Model, all tab handlers, forms, magnitude
  mode, pin filtering, compact notation, house profile, and chat
- Dead code removed: old data.FormatCents/ParseRequiredCents and friends
  replaced by locale.Currency methods

closes #407

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpcloud cpcloud force-pushed the worktree-expressive-jumping-deer branch from 0b39672 to bef4757 Compare February 26, 2026 21:41
cpcloud and others added 2 commits February 27, 2026 11:48
Both UnitSystemForLocale and ResolveCurrency now use
locale.DetectLocale() as the single source of truth for reading
LC_MONETARY/LC_ALL/LANG. Removes the duplicate env-var parsing
that was in data.DefaultUnitSystem().

closes #467

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Windows CI step fails when winget finds an existing package
with no available upgrade (exit code 1). Adding --force ensures
the install always succeeds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpcloud cpcloud merged commit 5c24322 into main Feb 28, 2026
13 checks passed
@cpcloud cpcloud deleted the worktree-expressive-jumping-deer branch February 28, 2026 10:47
cpcloud added a commit that referenced this pull request Mar 19, 2026
## Summary

- Add locale-aware currency formatting with `locale.Currency` type
wrapping `golang.org/x/text/currency` and `golang.org/x/text/message`
- Separate currency code (what money) from formatting locale (how to
display numbers) -- these are independent concerns, like timestamps and
timezones
- Currency code is persisted to SQLite for DB portability; formatting
locale is detected from `LC_MONETARY`/`LC_ALL`/`LANG` at runtime (never
persisted)
- Resolution order: DB value > config `[locale] currency` >
`MICASA_CURRENCY` env > auto-detect from locale > USD fallback
- All money columns, forms, compact notation, mag mode, and house
profile use locale-correct formatting
- Fix multi-byte grouping separator handling (French `U+00A0`
non-breaking space was silently broken due to byte-level iteration)
- Cache grouping/decimal separators at construction time instead of
recomputing per format call
- Add named symbol constants (`SymbolDollar`, `SymbolEuro`,
`SymbolPound`, `SymbolYen`) and replace all hardcoded Unicode escapes

Closes #467

## Test plan

All items covered by automated user-flow tests in
`internal/app/currency_flow_test.go` (section 19).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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