0.0
No release in over 3 years
HumanNumber implements accurate number formatting based on international standards including Microsoft Globalization documentation and Unicode CLDR. Provides human-readable number formats with precise locale-specific decimal separators, thousand separators, currency formats, and cultural number conventions.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 1.6, < 2
 Project Readme

HumanNumber

HumanNumber is a Ruby gem that implements accurate number formatting based on international standards. It references Microsoft Globalization documentation and Unicode CLDR standards to provide human-readable number formats that respect the unique formatting conventions of each country and region.

Features

  • 🌍 International Standards Compliance: Based on Microsoft Globalization and Unicode CLDR standards
  • πŸ”’ Cultural Number Systems: Automatic selection of Western (K/M/B/T), East Asian (만/μ–΅/μ‘°), or Indian (lakh/crore) systems
  • πŸ’° Currency Formatting: ISO 4217 currency codes with native locale precision rules
  • πŸ—οΈ Intelligent Abbreviations: Culturally-appropriate large number simplification
  • πŸ”§ Rails Integration: Complete compatibility with Rails I18n infrastructure
  • πŸ“š rails-i18n Based: Leverages verified locale data

Quick Start

Add to your Gemfile and install:

gem 'human_number'
bundle install

Start formatting numbers:

require 'human_number'

# Human-readable numbers
HumanNumber.human_number(1_234_567)           #=> "1.2M"
HumanNumber.human_number(50_000, locale: :ko) #=> "5만"

# Currency formatting
HumanNumber.currency(1234.56, currency_code: 'USD', locale: :en) #=> "$1,234.56"
HumanNumber.human_currency(1_234_567, currency_code: 'USD', locale: :en) #=> "$1M"

Installation

Add this line to your application's Gemfile:

gem 'human_number'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install human_number

API Reference

Core Methods

HumanNumber.human_number(number, **options)

Formats numbers with intelligent, culturally-appropriate abbreviations.

# Basic usage
HumanNumber.human_number(1_234_567)           #=> "1.2M"
HumanNumber.human_number(50_000, locale: :ko) #=> "5만"
HumanNumber.human_number(50_000, locale: :ja) #=> "5δΈ‡"

# Significant digits control (default: max_digits: 2)  
HumanNumber.human_number(1_234_567, max_digits: 1)   #=> "1M"     # 1 significant digit
HumanNumber.human_number(1_234_567, max_digits: 3)   #=> "1.23M"  # 3 significant digits  
HumanNumber.human_number(1_234_567, max_digits: nil) #=> "1M 234K 567" # Complete breakdown

# Unit preferences (Western locales only)
HumanNumber.human_number(1_000_000, abbr_units: true)  #=> "1M"
HumanNumber.human_number(1_000_000, abbr_units: false) #=> "1 million"

# Minimum thresholds
HumanNumber.human_number(5_000, min_unit: 10_000)  #=> "5,000"
HumanNumber.human_number(50_000, min_unit: 10_000) #=> "50K"

# Zero trimming (default: true)
HumanNumber.human_number(1_000_000, trim_zeros: true)  #=> "1M"
HumanNumber.human_number(1_000_000, trim_zeros: false) #=> "1.0M"

Parameters:

  • locale (Symbol): Target locale for cultural number systems
  • max_digits (Integer|nil): Maximum significant digits (default: 2, nil for complete mode)
  • abbr_units (Boolean): Use abbreviated vs full units (default: true)
  • min_unit (Integer): Minimum unit threshold for abbreviation (default: nil)
  • trim_zeros (Boolean): Remove trailing decimal zeros (default: true)

HumanNumber.currency(number, currency_code:, locale:)

Standard currency formatting with native locale precision rules.

HumanNumber.currency(1234.56, currency_code: 'USD', locale: :en) #=> "$1,234.56"
HumanNumber.currency(50_000, currency_code: 'KRW', locale: :ko)  #=> "50,000원"
HumanNumber.currency(1234.99, currency_code: 'JPY', locale: :ja) #=> "1,235円"

# Cross-locale consistency (USD always 2 decimals, JPY always 0)
HumanNumber.currency(1234.56, currency_code: 'USD', locale: :ko) #=> "$1,234.56"  
HumanNumber.currency(1234.56, currency_code: 'JPY', locale: :en) #=> "1,235円"

HumanNumber.human_currency(number, currency_code:, locale:, **options)

Human-readable currency formatting with cultural abbreviations.

HumanNumber.human_currency(1_234_567, currency_code: 'USD', locale: :en) #=> "$1M"
HumanNumber.human_currency(50_000, currency_code: 'KRW', locale: :ko)    #=> "5λ§Œμ›"

# Combined options
HumanNumber.human_currency(1_234_567, currency_code: 'USD', locale: :en, max_digits: 3) #=> "$1.23M"
HumanNumber.human_currency(1_234_567, currency_code: 'USD', locale: :en, max_digits: nil) #=> "$1M 234K 567"

Rails Integration

In Rails applications, helper methods are automatically available:

<%= human_number(1_234_567) %>                         <!-- 1.2M -->
<%= human_currency(1_234_567, currency_code: 'USD') %> <!-- $1M -->
<%= currency(1234.56, currency_code: 'USD') %>         <!-- $1,234.56 -->

<!-- With options -->
<%= human_number(1_234_567, max_digits: 3, locale: :ko) %> <!-- 123만 -->
<%= number_to_human_size(1_234_567) %>                     <!-- 1.2M (legacy) -->

Cultural Number Systems

Different cultures have fundamentally different concepts for large numbers:

Western System (K/M/B/T)

Used by: English, German, French, Spanish, Italian, Portuguese, Russian, Dutch, Swedish, Danish, Norwegian

HumanNumber.human_number(1_234_567, locale: :en) #=> "1.2M"
HumanNumber.human_number(1_000_000_000, locale: :en) #=> "1B"

Units: thousand (1,000), million (1,000,000), billion (1,000,000,000), trillion (1,000,000,000,000)

East Asian System (千/δΈ‡/ε„„/ε…†)

Used by: Korean (ko), Japanese (ja), Chinese (zh, zh-CN, zh-TW)

HumanNumber.human_number(1_234_567, locale: :ko) #=> "120만"  
HumanNumber.human_number(1_234_567, locale: :ja) #=> "120δΈ‡"
HumanNumber.human_number(100_000_000, locale: :ko) #=> "1μ–΅"

# Complete mode shows cultural spacing differences
HumanNumber.human_number(12_345_678, locale: :ko, max_digits: nil) #=> "1234만 5678"  # Korean: spaces
HumanNumber.human_number(12_345_678, locale: :ja, max_digits: nil) #=> "1234δΈ‡5678"   # Japanese: no spaces

Units: 만/δΈ‡ (ten thousand), μ–΅/ε„„ (hundred million), μ‘°/ε…† (trillion)
Cultural spacing: Japanese uses no spaces between units, Korean/Chinese use spaces (configurable via locale files)

Indian System (lakh/crore)

Used by: Hindi (hi), Urdu (ur), Bengali (bn), Indian English (en-IN)

HumanNumber.human_number(100_000, locale: :hi) #=> "1 lakh"
HumanNumber.human_number(10_000_000, locale: :hi) #=> "1 crore"

Units: thousand (1,000), lakh (100,000), crore (10,000,000)

The gem automatically selects the appropriate system based on locale, ensuring cultural accuracy.

Architecture & Design Philosophy

Direct Method Design

HumanNumber uses direct class methods rather than instance-based objects for simplicity:

# Direct approach (current)
HumanNumber.human_number(1234567, locale: :ko, max_digits: 2)

# Instance approach (rejected)
formatter = HumanNumber::Formatter.new(locale: :ko, max_digits: 2)
formatter.format(1234567)

Why Direct Methods?

  • Simplicity: Clean, straightforward API
  • Thread Safety: No shared mutable state
  • Rails Compatibility: Matches Rails helper patterns

Separation of Concerns

HumanNumber uses a two-stage formatting process:

  1. Number Formatting: Converts numbers to human-readable strings with cultural units
  2. Currency Application: Applies currency symbols and format strings
# Internal flow for HumanNumber.human_currency(1234567, currency_code: 'USD', locale: :en)
formatted_number = Formatters::Number.format(1234567, locale: :en, max_digits: 2)     #=> "1.2M"
final_result = Formatters::Currency.format("1.2M", currency_code: 'USD', locale: :en) #=> "$1.2M"

This separation enables:

  • Independent testing of number vs currency logic
  • Reusability of number formatting for non-currency contexts
  • Maintainability when adding new currencies or number systems

Centralized Locale Logic

Currency-locale relationships are managed centrally in LocaleSupport:

CURRENCY_NATIVE_LOCALES = {
  "USD" => [:en], "EUR" => %i[de fr es it nl], 
  "KRW" => [:ko], "JPY" => [:ja]
  # ... 40+ currencies
}

This ensures:

  • Consistent precision rules: USD always shows 2 decimals, JPY shows 0
  • Smart fallbacks: When user locale doesn't match currency's native locale
  • Easy maintenance: New currencies require only one mapping entry

Configuration-Free Design

HumanNumber deliberately avoids runtime configuration in favor of explicit parameters:

# No global configuration
HumanNumber.human_number(1234567, locale: :ko, max_digits: 2)

# Application defaults handled at application level
class ApplicationController
  def format_money(amount, currency)
    HumanNumber.human_currency(amount, currency_code: currency, locale: I18n.locale, max_digits: 2)
  end
end

Benefits:

  • No shared state or thread safety concerns
  • Predictable behavior (each call is independent)
  • Easier testing (no configuration setup/teardown)

Development

After checking out the repo:

$ cd human_number
$ bundle install
$ rake spec

Run tests:

$ rake spec

Run linting:

$ rake rubocop

Run all quality checks:

$ rake  # Runs both spec and rubocop

Contributing

  1. Fork it (https://github.com/ether-moon/human_number/fork)
  2. Create your feature branch (git checkout -b feature/my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin feature/my-new-feature)
  5. Create a new Pull Request

Contribution Guidelines

  • Please write tests when adding new features
  • Follow RuboCop style guidelines
  • Write clear and descriptive commit messages
  • Update documentation for API changes
  • Ensure 100% test coverage for new features

Adding New Locales

To add support for a new locale:

  1. Add locale to appropriate number system in lib/human_number/formatters/number.rb
  2. Create locale file in config/locales/ with unit translations
  3. Add currency mapping to CURRENCY_NATIVE_LOCALES if applicable
  4. Add comprehensive tests

License

MIT License. See the LICENSE file for details.

Standards Reference

This project is based on the following international standards and documentation:

Changelog

See CHANGELOG.md for details.

Issues

Please report bugs and feature requests at GitHub Issues.