or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

collation.mdencoding.mdformatting.mdindex.mdlanguage.mdlocalization.mdsearch-and-security.mdtext-transformation.mdunicode.md
tile.json

formatting.mddocs/

Number and Currency Formatting

This document covers locale-specific formatting for numbers, percentages, and currencies.

Package Overview

  • number: Locale-specific number formatting
  • currency: Currency units and formatting
  • date: Internal date/timezone data tables (under construction, no public API)

Number Package

Import path: golang.org/x/text/number

Formats numbers according to the customs of different locales.

Formatter Type

// Formatter formats numbers for display
type Formatter interface{}

Formatting Functions

// Decimal formats a number as a floating point decimal
func Decimal(x interface{}, opts ...Option) Formatter

// Percent formats a number as a percentage (1.0 = 100%)
func Percent(x interface{}, opts ...Option) Formatter

// PerMille formats a number as a per mille indication (1.0 = 1000‰)
func PerMille(x interface{}, opts ...Option) Formatter

// Scientific formats a number in scientific notation
func Scientific(x interface{}, opts ...Option) Formatter

// Engineering formats a number using engineering notation
func Engineering(x interface{}, opts ...Option) Formatter

Formatter Methods

func (f Formatter) Format(state format.State, verb rune)
func (f Formatter) Digits(buf []byte, tag language.Tag, scale int) number.Digits

Option Type

// Option configures a Formatter
type Option interface{}

Option Functions

// Scale simultaneously sets MinFractionDigits and MaxFractionDigits
func Scale(decimals int) Option

// Precision sets the maximum number of significant digits
func Precision(prec int) Option

// MinIntegerDigits specifies the minimum number of integer digits
func MinIntegerDigits(min int) Option

// MaxIntegerDigits limits the number of integer digits
func MaxIntegerDigits(max int) Option

// MinFractionDigits specifies the minimum number of fractional digits
func MinFractionDigits(min int) Option

// MaxFractionDigits specifies the maximum number of fractional digits
func MaxFractionDigits(max int) Option

// IncrementString sets the incremental value for rounding
func IncrementString(decimal string) Option

// FormatWidth sets the total format width
func FormatWidth(n int) Option

// Pad sets the rune to be used for padding
func Pad(r rune) Option

// NoSeparator causes a number to be displayed without grouping separators
func NoSeparator() Option

// PatternOverrides allows users to specify alternative patterns for specific languages
func PatternOverrides(patterns map[string]string) Option

FormatFunc Type

// FormatFunc formats a number
type FormatFunc func(x interface{}, opts ...Option) Formatter

// NewFormat creates a FormatFunc based on another FormatFunc and new options
func NewFormat(format FormatFunc, opts ...Option) FormatFunc

Usage Examples

import (
    "fmt"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "golang.org/x/text/number"
)

// Basic decimal formatting
p := message.NewPrinter(language.English)
fmt.Fprintln(p, number.Decimal(1234.56)) // "1,234.56"

// German formatting
p = message.NewPrinter(language.German)
fmt.Fprintln(p, number.Decimal(1234.56)) // "1.234,56"

// Percentage formatting
p = message.NewPrinter(language.English)
fmt.Fprintln(p, number.Percent(0.1234)) // "12.34%"

// Per mille formatting
fmt.Fprintln(p, number.PerMille(0.1234)) // "123.4‰"

// Scientific notation
fmt.Fprintln(p, number.Scientific(1234.56)) // "1.23456E3"

// Engineering notation (powers of 3)
fmt.Fprintln(p, number.Engineering(1234.56)) // "1.23456E3"

// Control decimal places
fmt.Fprintln(p, number.Decimal(1234.5678, number.Scale(2))) // "1,234.57"

// Minimum and maximum fraction digits
fmt.Fprintln(p, number.Decimal(1234, number.MinFractionDigits(2))) // "1,234.00"
fmt.Fprintln(p, number.Decimal(1234.5678, number.MaxFractionDigits(2))) // "1,234.57"

// Precision (significant digits)
fmt.Fprintln(p, number.Decimal(1234.5678, number.Precision(4))) // "1,235"

// No separator
fmt.Fprintln(p, number.Decimal(1234.56, number.NoSeparator())) // "1234.56"

// Padding
fmt.Fprintln(p, number.Decimal(12.34,
    number.FormatWidth(10),
    number.Pad('0'),
)) // "000012.34"

// Minimum integer digits
fmt.Fprintln(p, number.Decimal(12.34, number.MinIntegerDigits(4))) // "0,012.34"

// Increment (rounding)
fmt.Fprintln(p, number.Decimal(12.34, number.IncrementString("0.25"))) // "12.25"

// Create custom format function
percentFormat := number.NewFormat(
    number.Percent,
    number.Scale(1),
)
fmt.Fprintln(p, percentFormat(0.1234)) // "12.3%"

Currency Package

Import path: golang.org/x/text/currency

Provides currency-related functionality including currency units, queries, and formatting.

NOTE: The formatting functionality is currently under development and may change without notice.

Unit Type

// Unit is an ISO 4217 currency designator
type Unit struct{}

func ParseISO(s string) (Unit, error)
func MustParseISO(s string) Unit
func FromRegion(r language.Region) (currency Unit, ok bool)
func FromTag(t language.Tag) (Unit, language.Confidence)

func (u Unit) String() string
func (u Unit) Amount(amount interface{}) Amount

Common Currency Units

// G10 currencies
var XXX Unit // Undefined and testing
var XTS Unit // Testing
var USD Unit // US Dollar
var EUR Unit // Euro
var JPY Unit // Japanese Yen
var GBP Unit // British Pound
var CHF Unit // Swiss Franc
var AUD Unit // Australian Dollar
var NZD Unit // New Zealand Dollar
var CAD Unit // Canadian Dollar
var SEK Unit // Swedish Krona
var NOK Unit // Norwegian Krone

// Additional common currencies
var BRL Unit // Brazilian Real
var CNY Unit // Chinese Yuan
var DKK Unit // Danish Krone
var INR Unit // Indian Rupee
var RUB Unit // Russian Ruble
var HKD Unit // Hong Kong Dollar
var IDR Unit // Indonesian Rupiah
var KRW Unit // South Korean Won
var MXN Unit // Mexican Peso
var PLN Unit // Polish Zloty
var SAR Unit // Saudi Riyal
var THB Unit // Thai Baht
var TRY Unit // Turkish Lira
var TWD Unit // New Taiwan Dollar
var ZAR Unit // South African Rand

// Precious metals
var XAG Unit // Silver
var XAU Unit // Gold
var XPT Unit // Platinum
var XPD Unit // Palladium

Amount Type

// Amount is an amount-currency unit pair
type Amount struct{}

func (a Amount) Currency() Unit
func (a Amount) Format(s fmt.State, verb rune)

Formatter Type

// Formatter decorates a number, Unit or Amount with formatting options
type Formatter func(amount interface{}) formattedValue

// Predefined formatters
var NarrowSymbol Formatter // Use narrow symbols
var Symbol Formatter       // Use symbols instead of ISO codes
var ISO Formatter          // Use ISO code as symbol

func Default(currency Unit) Formatter
func Kind(k Kind) Formatter

Kind Type

// Kind determines the rounding and rendering properties
type Kind struct{}

var Standard Kind   // Standard rounding and formatting
var Cash Kind       // Rounding for cash transactions
var Accounting Kind // Rounding for accounting

func (k Kind) Rounding(cur Unit) (scale, increment int)

Query Functions

// Query represents a set of currency units
func Query(options ...QueryOption) QueryIter

// QueryIter represents a set of Units
type QueryIter interface {
    Next() bool
    Unit() Unit
    Region() language.Region
    From() (time.Time, bool)
    To() (time.Time, bool)
    IsTender() bool
}

// QueryOption modifies the set of unit information returned
type QueryOption func(*iter)

var Historical QueryOption // Select units for all dates
var NonTender QueryOption  // Include matching units that are not legal tender

func Date(t time.Time) QueryOption
func Region(r language.Region) QueryOption

Constants

const CLDRVersion string = "32"

Usage Examples

import (
    "fmt"
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
)

// Parse currency from ISO code
usd, err := currency.ParseISO("USD")
eur := currency.MustParseISO("EUR")

// Get currency for region
curr, ok := currency.FromRegion(language.MustParseRegion("US")) // USD
curr, ok = currency.FromRegion(language.MustParseRegion("DE"))  // EUR

// Get currency from language tag
curr, conf := currency.FromTag(language.Make("en-US")) // USD

// Create amounts
amount := usd.Amount(123.45)
fmt.Println(amount.Currency()) // USD

// Format currency
p := message.NewPrinter(language.English)
fmt.Fprintf(p, "%v", usd.Amount(1234.56)) // "$1,234.56" (with symbol)

// Use ISO code instead of symbol
fmt.Fprintf(p, "%v", currency.ISO(usd.Amount(1234.56))) // "USD 1,234.56"

// Use narrow symbol
fmt.Fprintf(p, "%v", currency.NarrowSymbol(eur.Amount(1234.56)))

// Set default currency for bare numbers
formatter := currency.Default(usd)
fmt.Fprintf(p, "%v", formatter(1234.56)) // "$1,234.56"

// Query currencies
iter := currency.Query(currency.Region(language.MustParseRegion("US")))
for iter.Next() {
    unit := iter.Unit()
    from, hasFrom := iter.From()
    to, hasTo := iter.To()
    isTender := iter.IsTender()
    // Process currency
}

// Query historical currencies
iter = currency.Query(
    currency.Region(language.MustParseRegion("DE")),
    currency.Historical,
)
for iter.Next() {
    unit := iter.Unit() // EUR, DEM (Deutsche Mark), etc.
}

// Query at specific date
import "time"
date := time.Date(1995, 1, 1, 0, 0, 0, 0, time.UTC)
iter = currency.Query(
    currency.Region(language.MustParseRegion("DE")),
    currency.Date(date),
)
for iter.Next() {
    unit := iter.Unit() // DEM (before Euro)
}

// Include non-tender currencies
iter = currency.Query(
    currency.Region(language.MustParseRegion("US")),
    currency.NonTender,
)

// Get rounding information
scale, increment := currency.Standard.Rounding(usd)
// scale = 2 (cents), increment = 0 (round to any cent)

scale, increment = currency.Cash.Rounding(currency.MustParseISO("CHF"))
// scale = 2, increment = 5 (round to 0.05 CHF)

Date Package

Import path: golang.org/x/text/date

NOTE: The date package is UNDER CONSTRUCTION and currently contains only internal data tables for CLDR date/time information. It does not provide a public API for date or time formatting.

Constants

const CLDRVersion string = "32"

The package contains generated data tables used internally by other golang.org/x/text packages but does not expose date formatting functionality to users.

Common Patterns

Formatting Numbers in Different Locales

import (
    "fmt"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "golang.org/x/text/number"
)

func formatNumber(value float64, lang language.Tag) string {
    p := message.NewPrinter(lang)
    return p.Sprintf("%v", number.Decimal(value))
}

// Usage
fmt.Println(formatNumber(1234567.89, language.English))  // "1,234,567.89"
fmt.Println(formatNumber(1234567.89, language.German))   // "1.234.567,89"
fmt.Println(formatNumber(1234567.89, language.French))   // "1 234 567,89"

Currency Conversion Display

import (
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
)

type ConversionRate struct {
    From currency.Unit
    To   currency.Unit
    Rate float64
}

func displayConversion(rate ConversionRate, amount float64, lang language.Tag) string {
    p := message.NewPrinter(lang)

    fromAmount := rate.From.Amount(amount)
    toAmount := rate.To.Amount(amount * rate.Rate)

    return p.Sprintf("%v = %v", fromAmount, toAmount)
}

// Usage
rate := ConversionRate{
    From: currency.USD,
    To:   currency.EUR,
    Rate: 0.85,
}
result := displayConversion(rate, 100, language.English)
// "$100.00 = €85.00"

Financial Statement Formatting

import (
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "golang.org/x/text/number"
)

func formatFinancialValue(value float64, curr currency.Unit, lang language.Tag) string {
    p := message.NewPrinter(lang)

    formatter := number.NewFormat(
        number.Decimal,
        number.Scale(2),
        number.MinFractionDigits(2),
    )

    amount := curr.Amount(value)

    if value < 0 {
        // Use accounting format for negative numbers
        amount = currency.Accounting(amount)
    }

    return p.Sprintf("%v", formatter(amount))
}

Price Formatting with Rounding

import (
    "math"
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
)

func formatPrice(value float64, curr currency.Unit, kind currency.Kind, lang language.Tag) string {
    // Get rounding rules for currency
    scale, increment := kind.Rounding(curr)

    // Apply rounding
    multiplier := math.Pow(10, float64(scale))
    if increment > 0 {
        multiplier /= float64(increment)
    }

    rounded := math.Round(value*multiplier) / multiplier

    // Format
    p := message.NewPrinter(lang)
    return p.Sprintf("%v", curr.Amount(rounded))
}

// Usage
price := formatPrice(12.347, currency.USD, currency.Standard, language.English)
// "$12.35" (rounded to nearest cent)

// Swiss Franc cash rounding (0.05)
price = formatPrice(12.347, currency.CHF, currency.Cash, language.German)
// "CHF 12.35" (rounded to nearest 0.05)

Percentage Change Display

import (
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "golang.org/x/text/number"
)

func formatPercentageChange(oldValue, newValue float64, lang language.Tag) string {
    change := (newValue - oldValue) / oldValue

    p := message.NewPrinter(lang)

    sign := ""
    if change > 0 {
        sign = "+"
    }

    return sign + p.Sprintf("%v", number.Percent(change, number.Scale(2)))
}

// Usage
fmt.Println(formatPercentageChange(100, 120, language.English)) // "+20.00%"
fmt.Println(formatPercentageChange(100, 85, language.English))  // "-15.00%"

Multi-Currency Summary

import (
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
    "golang.org/x/text/message"
)

type Balance struct {
    Currency currency.Unit
    Amount   float64
}

func displayBalances(balances []Balance, lang language.Tag) []string {
    p := message.NewPrinter(lang)

    results := make([]string, len(balances))
    for i, bal := range balances {
        amount := bal.Currency.Amount(bal.Amount)
        results[i] = p.Sprintf("%v", amount)
    }

    return results
}

// Usage
balances := []Balance{
    {currency.USD, 1000.00},
    {currency.EUR, 850.00},
    {currency.GBP, 750.00},
}
lines := displayBalances(balances, language.English)
// ["$1,000.00", "€850.00", "£750.00"]

Scientific Notation Formatting

import (
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "golang.org/x/text/number"
)

func formatScientific(value float64, precision int, lang language.Tag) string {
    p := message.NewPrinter(lang)

    formatter := number.Scientific(value,
        number.Precision(precision),
    )

    return p.Sprintf("%v", formatter)
}

// Usage
fmt.Println(formatScientific(0.00001234, 3, language.English)) // "1.23E-5"
fmt.Println(formatScientific(1234567890, 4, language.English)) // "1.235E9"

Locale-Aware Number Parsing (conceptual)

import (
    "strconv"
    "strings"
    "golang.org/x/text/language"
)

// Note: This is a simplified example. The package doesn't provide
// built-in parsing, so you'd need to implement it based on locale rules.
func parseNumber(s string, lang language.Tag) (float64, error) {
    // This is simplified - real implementation would need to handle
    // locale-specific decimal and grouping separators

    // For English: "1,234.56"
    // For German: "1.234,56"

    if lang == language.German {
        s = strings.ReplaceAll(s, ".", "")
        s = strings.ReplaceAll(s, ",", ".")
    } else {
        s = strings.ReplaceAll(s, ",", "")
    }

    return strconv.ParseFloat(s, 64)
}

Available Currencies Lookup

import (
    "golang.org/x/text/currency"
    "golang.org/x/text/language"
)

func getActiveCurrencies() []currency.Unit {
    var currencies []currency.Unit

    iter := currency.Query()
    for iter.Next() {
        if iter.IsTender() {
            currencies = append(currencies, iter.Unit())
        }
    }

    return currencies
}

func getCurrenciesForRegion(region language.Region) []currency.Unit {
    var currencies []currency.Unit

    iter := currency.Query(
        currency.Region(region),
        currency.Historical,
    )

    for iter.Next() {
        currencies = append(currencies, iter.Unit())
    }

    return currencies
}

// Usage
allActive := getActiveCurrencies()
usHistory := getCurrenciesForRegion(language.MustParseRegion("US"))

Version Information

Based on:

  • CLDR 32
  • ISO 4217 currency codes
  • Unicode CLDR Number Formatting Patterns