-
-
Notifications
You must be signed in to change notification settings - Fork 36
Transition from currency-aware formatting to locale-aware formatting #98
Description
The money2 library currently relies on a "self-sustained" approach where formatting logic and patterns are hardcoded within currency definitions. While there is a shared understanding within the community that currency-based formatting is not ideal, the solution discussed thus far has been to build an internal database of locales.
I propose that we instead adopt the intl package as a core dependency for formatting. While this library will continue to maintain its own dataset of currencies (ISO codes, names, and precision), we should offload the responsibility of locale-specific representation to a dedicated, widely-used localization engine.
The Problem: The Limits of Self-Sustained Logic
The current model treats formatting as a property of the Currency, whereas industry standards treat it as a property of the Locale.
- Incompatibility with Device Settings: Formatting is "locked" at the app or currency level and does not automatically adjust to the user's device settings. A user in Germany and a user in the US viewing the same currency should see different separators (e.g.,
$1.000,00vs.$1,000.00), but the library currently forces a static style. - Diminishing Returns on Heuristics: As seen in PR parse decimal inference #97 ("parse decimal inference"), we have implemented heuristics to improve separator accuracy without breaking backward compatibility. While PR parse decimal inference #97 was a successful stop-gap, it highlights that we are now relying on "guessing" intent. This is inherently more fragile than using a standardized, data-driven locale engine.
- The Maintenance Trap of Localization: While this library must maintain currency-specific data (which is not provided by
intl), maintaining a separate database of locales is a massive undertaking. Leveragingintlallows us to focus on financial logic while letting a standard library handle the regional display logic.
Proposed Solution: Standardized Dependency for Formatting
Rather than reinventing the localization wheel, we should leverage the infrastructure provided by the intl package:
- Adopt
intlas the Internal Formatting Engine: Replace custom formatting logic and heuristics with the standardintllibrary. - Preserve the Fowler Pattern: The
MoneyandCurrencyobjects should remain clean Value Objects. Formatting logic should be decoupled into a locale-aware resolver called internally by.format()or.toString(). - Initialization-Phase Warning: Since it is difficult to distinguish between legacy and new format strings during runtime usage, I propose a warning during library or currency initialization. This informs the developer that the library is moving toward a locale-first model and that the current approach of declaring formats via the currency is being deprecated.
Areas for Discussion: Fallback and Deprecation
- Deprecation Acknowledgment: How should developers acknowledge this shift to silence the initialization warning? (e.g., a global configuration flag like
MoneyConfig.acknowledgeLocaleMigration()). - Fallback Strategy: What should happen if a
Localecannot be automatically detected or resolved?- Option A: Fail Initialization: Make
intla hard requirement and throw an error if no valid locale context is found. - Option B: Neutral/ISO Fallback: Fallback to a neutral "Safety" format (e.g.,
USD 1,234.56). - Option C: Global Default: Allow a
Money.defaultLocaleto be defined once at the application level.
- Option A: Fail Initialization: Make