package float import ( "strconv" "strings" ) func split(s string, n int) (ret []string) { var pos int if rest := len(s) % n; rest > 0 { ret = append(ret, s[:rest]) pos = rest } for pos < len(s) { ret = append(ret, s[pos:pos+n]) pos += n } return ret } func fill(s string, n int) string { if len(s) >= n { return s[:n] } return s + strings.Repeat("0", n-len(s)) } // Country settings type Country struct { Thousend, Decimal, Neg string // delimiter Block, Fraction int // length } const ( Neg = "-" Space = " " Apostrophe = "'" Comma = "," FullStop = "." MiddleDot = "\u00b7" ThinSpace = "\u2009" NoBreakSpace = "\u202f" DotAbove = "\u02d9" ) var ( EN = Country{Space, FullStop, Neg, 3, 2} // SI EN FR = Country{Space, Comma, Neg, 3, 2} // SI FR US = Country{Comma, FullStop, Neg, 3, 2} DE = Country{FullStop, Comma, Neg, 3, 2} IR = Country{Space, MiddleDot, Neg, 3, 2} CH = Country{Apostrophe, FullStop, Neg, 3, 2} IT = Country{DotAbove, Comma, Neg, 3, 2} CN = Country{Comma, FullStop, Neg, 4, 2} // 10000 based ) // DefaultFormat is europeian SI format var DefaultFormat = FR // Format float value as localized representation func (c Country) Format(v float64) string { s := strconv.FormatFloat(v, 'f', -1, 64) neg := strings.HasPrefix(s, Neg) if neg { s = s[1:] // stip neg } // add extra dot for there will be at least 2 parts parts := strings.Split(s+FullStop, FullStop) lhs := split(parts[0], c.Block) s = strings.Join(lhs, c.Thousend) if neg { s = c.Neg + s // rejoin neg } rhs := fill(parts[1], c.Fraction) return s + c.Decimal + rhs } // Format float with default format func Format(v float64) string { return DefaultFormat.Format(v) }