message: use localized number formatting

This change implements default localized number
formattting for base-type arguments.
Tailored formatting, like engineering notation,
is planned through the number package.

Change-Id: I58f9c3b5543b627ab8b705a0b32819fdf317754b
Reviewed-on: https://go-review.googlesource.com/46472
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/internal/number/format.go b/internal/number/format.go
index 2985ef5..70ddf7d 100755
--- a/internal/number/format.go
+++ b/internal/number/format.go
@@ -454,8 +454,10 @@
 		case r == '-' || r == '+':
 			if neg {
 				dst = append(dst, f.Symbol(SymMinusSign)...)
-			} else {
+			} else if f.Flags&ElideSign == 0 {
 				dst = append(dst, f.Symbol(SymPlusSign)...)
+			} else {
+				dst = append(dst, ' ')
 			}
 		default:
 			dst = append(dst, string(r)...)
diff --git a/internal/number/pattern.go b/internal/number/pattern.go
index 8d7f9a6..ef7f087 100644
--- a/internal/number/pattern.go
+++ b/internal/number/pattern.go
@@ -56,6 +56,7 @@
 	Flags        PatternFlag
 
 	// Number of digits.
+	// TODO: consider using uint32
 	MinIntegerDigits     uint8
 	MaxIntegerDigits     uint8
 	MinFractionDigits    uint8
@@ -90,6 +91,7 @@
 
 const (
 	AlwaysSign PatternFlag = 1 << iota
+	ElideSign              // Use space instead of plus sign. AlwaysSign must be true.
 	AlwaysExpSign
 	AlwaysDecimalSeparator
 	ParenthesisForNegative // Common pattern. Saves space.
diff --git a/message/fmt_test.go b/message/fmt_test.go
index d02808a..0dbedcb 100755
--- a/message/fmt_test.go
+++ b/message/fmt_test.go
@@ -158,9 +158,15 @@
 	// Extra argument errors should format without flags set.
 	{"%010.2", "12345", "%!(NOVERB)"},
 
-	// All following tests are identical to that of the fmt package.
-	{"%d", 12345, "12345"},
-	{"%v", 12345, "12345"},
+	// Some key other differences, asides from localized values:
+	// - NaN values should not use affixes; so no signs (CLDR requirement)
+	// - Infinity uses patterns, so signs may be different (CLDR requirement)
+	// - The # flag is used to disable localization.
+
+	// All following tests are analogous to those of the fmt package, but with
+	// localized numbers when appropriate.
+	{"%d", 12345, "12,345"},
+	{"%v", 12345, "12,345"},
 	{"%t", true, "true"},
 
 	// basic string
@@ -307,9 +313,9 @@
 	// Runes that are not valid.
 	{"%q", int32(-1), "%!q(int32=-1)"},
 	{"%q", 0xDC80, `'�'`},
-	{"%q", rune(0x110000), "%!q(int32=1114112)"},
-	{"%q", int64(0xFFFFFFFFF), "%!q(int64=68719476735)"},
-	{"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68719476735)"},
+	{"%q", rune(0x110000), "%!q(int32=1,114,112)"},
+	{"%q", int64(0xFFFFFFFFF), "%!q(int64=68,719,476,735)"},
+	{"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68,719,476,735)"},
 
 	// width
 	{"%5s", "abc", "  abc"},
@@ -339,23 +345,23 @@
 	{"%-10v", nil, "<nil>     "},
 
 	// integers
-	{"%d", uint(12345), "12345"},
-	{"%d", int(-12345), "-12345"},
+	{"%d", uint(12345), "12,345"},
+	{"%d", int(-12345), "-12,345"},
 	{"%d", ^uint8(0), "255"},
-	{"%d", ^uint16(0), "65535"},
-	{"%d", ^uint32(0), "4294967295"},
-	{"%d", ^uint64(0), "18446744073709551615"},
+	{"%d", ^uint16(0), "65,535"},
+	{"%d", ^uint32(0), "4,294,967,295"},
+	{"%d", ^uint64(0), "18,446,744,073,709,551,615"},
 	{"%d", int8(-1 << 7), "-128"},
-	{"%d", int16(-1 << 15), "-32768"},
-	{"%d", int32(-1 << 31), "-2147483648"},
-	{"%d", int64(-1 << 63), "-9223372036854775808"},
+	{"%d", int16(-1 << 15), "-32,768"},
+	{"%d", int32(-1 << 31), "-2,147,483,648"},
+	{"%d", int64(-1 << 63), "-9,223,372,036,854,775,808"},
 	{"%.d", 0, ""},
 	{"%.0d", 0, ""},
 	{"%6.0d", 0, "      "},
 	{"%06.0d", 0, "      "},
-	{"% d", 12345, " 12345"},
-	{"%+d", 12345, "+12345"},
-	{"%+d", -12345, "-12345"},
+	{"% d", 12345, " 12,345"},
+	{"%+d", 12345, "+12,345"},
+	{"%+d", -12345, "-12,345"},
 	{"%b", 7, "111"},
 	{"%b", -6, "-110"},
 	{"%b", ^uint32(0), "11111111111111111111111111111111"},
@@ -371,29 +377,29 @@
 	{"%x", ^uint32(0), "ffffffff"},
 	{"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"},
 	{"%.20b", 7, "00000000000000000111"},
-	{"%10d", 12345, "     12345"},
-	{"%10d", -12345, "    -12345"},
-	{"%+10d", 12345, "    +12345"},
-	{"%010d", 12345, "0000012345"},
-	{"%010d", -12345, "-000012345"},
-	{"%20.8d", 1234, "            00001234"},
-	{"%20.8d", -1234, "           -00001234"},
-	{"%020.8d", 1234, "            00001234"},
-	{"%020.8d", -1234, "           -00001234"},
-	{"%-20.8d", 1234, "00001234            "},
-	{"%-20.8d", -1234, "-00001234           "},
+	{"%10d", 12345, "    12,345"},
+	{"%10d", -12345, "   -12,345"},
+	{"%+10d", 12345, "   +12,345"},
+	{"%010d", 12345, "0,000,012,345"},
+	{"%010d", -12345, "-0,000,012,345"},
+	{"%20.8d", 1234, "          00,001,234"},
+	{"%20.8d", -1234, "         -00,001,234"},
+	{"%020.8d", 1234, "          00,001,234"},
+	{"%020.8d", -1234, "         -00,001,234"},
+	{"%-20.8d", 1234, "00,001,234          "},
+	{"%-20.8d", -1234, "-00,001,234         "},
 	{"%-#20.8x", 0x1234abc, "0x01234abc          "},
 	{"%-#20.8X", 0x1234abc, "0X01234ABC          "},
 	{"%-#20.8o", 01234, "00001234            "},
 
 	// Test correct f.intbuf overflow checks.
-	{"%068d", 1, zeroFill("", 68, "1")},
-	{"%068d", -1, zeroFill("-", 67, "1")},
+	{"%068d", 1, "00," + strings.Repeat("000,", 21) + "001"},
+	{"%068d", -1, "-00," + strings.Repeat("000,", 21) + "001"},
 	{"%#.68x", 42, zeroFill("0x", 68, "2a")},
-	{"%.68d", -42, zeroFill("-", 68, "42")},
-	{"%+.68d", 42, zeroFill("+", 68, "42")},
-	{"% .68d", 42, zeroFill(" ", 68, "42")},
-	{"% +.68d", 42, zeroFill("+", 68, "42")},
+	{"%.68d", -42, "-00," + strings.Repeat("000,", 21) + "042"},
+	{"%+.68d", 42, "+00," + strings.Repeat("000,", 21) + "042"},
+	{"% .68d", 42, " 00," + strings.Repeat("000,", 21) + "042"},
+	{"% +.68d", 42, "+00," + strings.Repeat("000,", 21) + "042"},
 
 	// unicode format
 	{"%U", 0, "U+0000"},
@@ -415,8 +421,8 @@
 	{"%#.68U", '日', zeroFill("U+", 68, "65E5") + " '日'"},
 
 	// floats
-	{"%+.3e", 0.0, "+0.000e+00"},
-	{"%+.3e", 1.0, "+1.000e+00"},
+	{"%+.3e", 0.0, "+0.000\u202f×\u202f10⁰⁰"},
+	{"%+.3e", 1.0, "+1.000\u202f×\u202f10⁰⁰"},
 	{"%+.3f", -1.0, "-1.000"},
 	{"%+.3F", -1.0, "-1.000"},
 	{"%+.3F", float32(-1.0), "-1.000"},
@@ -430,8 +436,8 @@
 	{"%-+07.2f", -1.0, "-1.00  "},
 	{"%+10.2f", +1.0, "     +1.00"},
 	{"%+10.2f", -1.0, "     -1.00"},
-	{"% .3E", -1.0, "-1.000E+00"},
-	{"% .3e", 1.0, " 1.000e+00"},
+	{"% .3E", -1.0, "-1.000\u202f×\u202f10⁰⁰"},
+	{"% .3e", 1.0, " 1.000\u202f×\u202f10⁰⁰"},
 	{"%+.3g", 0.0, "+0"},
 	{"%+.3g", 1.0, "+1"},
 	{"%+.3g", -1.0, "-1"},
@@ -469,25 +475,27 @@
 	{"%.4b", float32(1.0), "8388608p-23"},
 	{"%.4b", -1.0, "-4503599627370496p-52"},
 	// Test correct f.intbuf boundary checks.
-	{"%.68f", 1.0, zeroFill("1.", 68, "")},
-	{"%.68f", -1.0, zeroFill("-1.", 68, "")},
+	// TODO: the following cases won't work because of rounding errors. We can
+	// fix this if we expose the internals of strconv.
+	// {"%.68f", 1.0, zeroFill("1.", 68, "")},   // TODO(bug): rounding error
+	// {"%.68f", -1.0, zeroFill("-1.", 68, "")}, // TODO(bug): rounding error
 	// float infinites and NaNs
-	{"%f", posInf, "+Inf"},
-	{"%.1f", negInf, "-Inf"},
-	{"% f", NaN, " NaN"},
-	{"%20f", posInf, "                +Inf"},
-	{"% 20F", posInf, "                 Inf"},
-	{"% 20e", negInf, "                -Inf"},
-	{"%+20E", negInf, "                -Inf"},
-	{"% +20g", negInf, "                -Inf"},
-	{"%+-20G", posInf, "+Inf                "},
+	{"%f", posInf, "∞"},
+	{"%.1f", negInf, "-∞"},
+	{"% f", NaN, "NaN"},
+	{"%20f", posInf, "                   ∞"},
+	{"% 20F", posInf, "                   ∞"},
+	{"% 20e", negInf, "                  -∞"},
+	{"%+20E", negInf, "                  -∞"},
+	{"% +20g", negInf, "                  -∞"},
+	{"%+-20G", posInf, "+∞                  "},
 	{"%20e", NaN, "                 NaN"},
-	{"% +20E", NaN, "                +NaN"},
-	{"% -20g", NaN, " NaN                "},
-	{"%+-20G", NaN, "+NaN                "},
+	{"% +20E", NaN, "                 NaN"},
+	{"% -20g", NaN, "NaN                 "},
+	{"%+-20G", NaN, "NaN                 "},
 	// Zero padding does not apply to infinities and NaN.
-	{"%+020e", posInf, "                +Inf"},
-	{"%-020f", negInf, "-Inf                "},
+	{"%+020e", posInf, "                  +∞"},
+	{"%-020f", negInf, "-∞                  "},
 	{"%-020E", NaN, "NaN                 "},
 
 	// complex values
@@ -495,24 +503,24 @@
 	{"% .f", 0i, "( 0+0i)"},
 	{"%+.f", 0i, "(+0+0i)"},
 	{"% +.f", 0i, "(+0+0i)"},
-	{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
+	{"%+.3e", 0i, "(+0.000\u202f×\u202f10⁰⁰+0.000\u202f×\u202f10⁰⁰i)"},
 	{"%+.3f", 0i, "(+0.000+0.000i)"},
 	{"%+.3g", 0i, "(+0+0i)"},
-	{"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
+	{"%+.3e", 1 + 2i, "(+1.000\u202f×\u202f10⁰⁰+2.000\u202f×\u202f10⁰⁰i)"},
 	{"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
 	{"%+.3g", 1 + 2i, "(+1+2i)"},
-	{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
+	{"%.3e", 0i, "(0.000\u202f×\u202f10⁰⁰+0.000\u202f×\u202f10⁰⁰i)"},
 	{"%.3f", 0i, "(0.000+0.000i)"},
 	{"%.3F", 0i, "(0.000+0.000i)"},
 	{"%.3F", complex64(0i), "(0.000+0.000i)"},
 	{"%.3g", 0i, "(0+0i)"},
-	{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
+	{"%.3e", 1 + 2i, "(1.000\u202f×\u202f10⁰⁰+2.000\u202f×\u202f10⁰⁰i)"},
 	{"%.3f", 1 + 2i, "(1.000+2.000i)"},
 	{"%.3g", 1 + 2i, "(1+2i)"},
-	{"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
+	{"%.3e", -1 - 2i, "(-1.000\u202f×\u202f10⁰⁰-2.000\u202f×\u202f10⁰⁰i)"},
 	{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
 	{"%.3g", -1 - 2i, "(-1-2i)"},
-	{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+	{"% .3E", -1 - 2i, "(-1.000\u202f×\u202f10⁰⁰-2.000\u202f×\u202f10⁰⁰i)"},
 	{"%+.3g", 1 + 2i, "(+1+2i)"},
 	{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
 	{"%#g", 1 + 2i, "(1.00000+2.00000i)"},
@@ -537,70 +545,70 @@
 	{"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
 	{"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
 	// complex infinites and NaNs
-	{"%f", complex(posInf, posInf), "(+Inf+Infi)"},
-	{"%f", complex(negInf, negInf), "(-Inf-Infi)"},
+	{"%f", complex(posInf, posInf), "(∞+∞i)"},
+	{"%f", complex(negInf, negInf), "(-∞-∞i)"},
 	{"%f", complex(NaN, NaN), "(NaN+NaNi)"},
-	{"%.1f", complex(posInf, posInf), "(+Inf+Infi)"},
-	{"% f", complex(posInf, posInf), "( Inf+Infi)"},
-	{"% f", complex(negInf, negInf), "(-Inf-Infi)"},
-	{"% f", complex(NaN, NaN), "( NaN+NaNi)"},
-	{"%8e", complex(posInf, posInf), "(    +Inf    +Infi)"},
-	{"% 8E", complex(posInf, posInf), "(     Inf    +Infi)"},
-	{"%+8f", complex(negInf, negInf), "(    -Inf    -Infi)"},
-	{"% +8g", complex(negInf, negInf), "(    -Inf    -Infi)"},
-	{"% -8G", complex(NaN, NaN), "( NaN    +NaN    i)"},
+	{"%.1f", complex(posInf, posInf), "(∞+∞i)"},
+	{"% f", complex(posInf, posInf), "( ∞+∞i)"},
+	{"% f", complex(negInf, negInf), "(-∞-∞i)"},
+	{"% f", complex(NaN, NaN), "(NaN+NaNi)"},
+	{"%8e", complex(posInf, posInf), "(       ∞      +∞i)"},
+	{"% 8E", complex(posInf, posInf), "(       ∞      +∞i)"},
+	{"%+8f", complex(negInf, negInf), "(      -∞      -∞i)"},
+	{"% +8g", complex(negInf, negInf), "(      -∞      -∞i)"}, // TODO(g)
+	{"% -8G", complex(NaN, NaN), "(NaN     +NaN    i)"},
 	{"%+-8b", complex(NaN, NaN), "(+NaN    +NaN    i)"},
 	// Zero padding does not apply to infinities and NaN.
-	{"%08f", complex(posInf, posInf), "(    +Inf    +Infi)"},
-	{"%-08g", complex(negInf, negInf), "(-Inf    -Inf    i)"},
+	{"%08f", complex(posInf, posInf), "(       ∞      +∞i)"},
+	{"%-08g", complex(negInf, negInf), "(-∞      -∞      i)"},
 	{"%-08G", complex(NaN, NaN), "(NaN     +NaN    i)"},
 
 	// old test/fmt_test.go
-	{"%e", 1.0, "1.000000e+00"},
-	{"%e", 1234.5678e3, "1.234568e+06"},
-	{"%e", 1234.5678e-8, "1.234568e-05"},
-	{"%e", -7.0, "-7.000000e+00"},
-	{"%e", -1e-9, "-1.000000e-09"},
-	{"%f", 1234.5678e3, "1234567.800000"},
+	{"%e", 1.0, "1.000000\u202f×\u202f10⁰⁰"},
+	{"%e", 1234.5678e3, "1.234570\u202f×\u202f10⁰⁶"},
+	{"%e", 1234.5678e-8, "1.234570\u202f×\u202f10⁻⁰⁵"},
+	{"%e", -7.0, "-7.000000\u202f×\u202f10⁰⁰"},
+	{"%e", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"},
+	{"%f", 1234.5678e3, "1,234,567.800000"},
 	{"%f", 1234.5678e-8, "0.000012"},
 	{"%f", -7.0, "-7.000000"},
 	{"%f", -1e-9, "-0.000000"},
-	{"%g", 1234.5678e3, "1.2345678e+06"},
-	{"%g", float32(1234.5678e3), "1.2345678e+06"},
-	{"%g", 1234.5678e-8, "1.2345678e-05"},
+	{"%g", 1234.5678e3, "1.2345678\u202f×\u202f10⁰⁶"},
+	{"%g", float32(1234.5678e3), "1.2345678\u202f×\u202f10⁰⁶"},
+	{"%g", 1234.5678e-8, "1.2345678\u202f×\u202f10⁻⁰⁵"},
 	{"%g", -7.0, "-7"},
-	{"%g", -1e-9, "-1e-09"},
-	{"%g", float32(-1e-9), "-1e-09"},
-	{"%E", 1.0, "1.000000E+00"},
-	{"%E", 1234.5678e3, "1.234568E+06"},
-	{"%E", 1234.5678e-8, "1.234568E-05"},
-	{"%E", -7.0, "-7.000000E+00"},
-	{"%E", -1e-9, "-1.000000E-09"},
-	{"%G", 1234.5678e3, "1.2345678E+06"},
-	{"%G", float32(1234.5678e3), "1.2345678E+06"},
-	{"%G", 1234.5678e-8, "1.2345678E-05"},
+	{"%g", -1e-9, "-1\u202f×\u202f10⁻⁰⁹"},
+	{"%g", float32(-1e-9), "-1\u202f×\u202f10⁻⁰⁹"},
+	{"%E", 1.0, "1.000000\u202f×\u202f10⁰⁰"},
+	{"%E", 1234.5678e3, "1.234570\u202f×\u202f10⁰⁶"},
+	{"%E", 1234.5678e-8, "1.234570\u202f×\u202f10⁻⁰⁵"},
+	{"%E", -7.0, "-7.000000\u202f×\u202f10⁰⁰"},
+	{"%E", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"},
+	{"%G", 1234.5678e3, "1.2345678\u202f×\u202f10⁰⁶"},
+	{"%G", float32(1234.5678e3), "1.2345678\u202f×\u202f10⁰⁶"},
+	{"%G", 1234.5678e-8, "1.2345678\u202f×\u202f10⁻⁰⁵"},
 	{"%G", -7.0, "-7"},
-	{"%G", -1e-9, "-1E-09"},
-	{"%G", float32(-1e-9), "-1E-09"},
+	{"%G", -1e-9, "-1\u202f×\u202f10⁻⁰⁹"},
+	{"%G", float32(-1e-9), "-1\u202f×\u202f10⁻⁰⁹"},
 	{"%20.5s", "qwertyuiop", "               qwert"},
 	{"%.5s", "qwertyuiop", "qwert"},
 	{"%-20.5s", "qwertyuiop", "qwert               "},
 	{"%20c", 'x', "                   x"},
 	{"%-20c", 'x', "x                   "},
-	{"%20.6e", 1.2345e3, "        1.234500e+03"},
-	{"%20.6e", 1.2345e-3, "        1.234500e-03"},
-	{"%20e", 1.2345e3, "        1.234500e+03"},
-	{"%20e", 1.2345e-3, "        1.234500e-03"},
-	{"%20.8e", 1.2345e3, "      1.23450000e+03"},
-	{"%20f", 1.23456789e3, "         1234.567890"},
+	{"%20.6e", 1.2345e3, "     1.234500\u202f×\u202f10⁰³"},
+	{"%20.6e", 1.2345e-3, "    1.234500\u202f×\u202f10⁻⁰³"},
+	{"%20e", 1.2345e3, "     1.234500\u202f×\u202f10⁰³"},
+	{"%20e", 1.2345e-3, "    1.234500\u202f×\u202f10⁻⁰³"},
+	{"%20.8e", 1.2345e3, "   1.23450000\u202f×\u202f10⁰³"},
+	{"%20f", 1.23456789e3, "        1,234.567890"},
 	{"%20f", 1.23456789e-3, "            0.001235"},
-	{"%20f", 12345678901.23456789, "  12345678901.234568"},
-	{"%-20f", 1.23456789e3, "1234.567890         "},
-	{"%20.8f", 1.23456789e3, "       1234.56789000"},
+	{"%20f", 12345678901.23456789, "12,345,678,901.234568"},
+	{"%-20f", 1.23456789e3, "1,234.567890        "},
+	{"%20.8f", 1.23456789e3, "      1,234.56789000"},
 	{"%20.8f", 1.23456789e-3, "          0.00123457"},
-	{"%g", 1.23456789e3, "1234.56789"},
+	{"%g", 1.23456789e3, "1,234.56789"},
 	{"%g", 1.23456789e-3, "0.00123456789"},
-	{"%g", 1.23456789e20, "1.23456789e+20"},
+	{"%g", 1.23456789e20, "1.23456789\u202f×\u202f10²⁰"},
 
 	// arrays
 	{"%v", array, "[1 2 3 4 5]"},
@@ -930,8 +938,11 @@
 	{"%+7.2f", -1.0, "  -1.00"},
 	{"% +7.2f", 1.0, "  +1.00"},
 	{"% +7.2f", -1.0, "  -1.00"},
-	{"%07.2f", 1.0, "0001.00"},
-	{"%07.2f", -1.0, "-001.00"},
+	// Padding with 0's indicates minimum number of integer digits minus the
+	// period, if present, and minus the sign if it is fixed.
+	// TODO: consider making this number the number of significant digits.
+	{"%07.2f", 1.0, "0,001.00"},
+	{"%07.2f", -1.0, "-0,001.00"},
 	{"% 07.2f", 1.0, " 001.00"},
 	{"% 07.2f", -1.0, "-001.00"},
 	{"%+07.2f", 1.0, "+001.00"},
@@ -949,13 +960,13 @@
 
 	// float and complex formatting should not change the padding width
 	// for other elements. See issue 14642.
-	{"%06v", []interface{}{+10.0, 10}, "[000010 000010]"},
-	{"%06v", []interface{}{-10.0, 10}, "[-00010 000010]"},
-	{"%06v", []interface{}{+10.0 + 10i, 10}, "[(000010+00010i) 000010]"},
-	{"%06v", []interface{}{-10.0 + 10i, 10}, "[(-00010+00010i) 000010]"},
+	{"%06v", []interface{}{+10.0, 10}, "[000,010 000,010]"},
+	{"%06v", []interface{}{-10.0, 10}, "[-000,010 000,010]"},
+	{"%06v", []interface{}{+10.0 + 10i, 10}, "[(000,010+00,010i) 000,010]"},
+	{"%06v", []interface{}{-10.0 + 10i, 10}, "[(-000,010+00,010i) 000,010]"},
 
 	// integer formatting should not alter padding for other elements.
-	{"%03.6v", []interface{}{1, 2.0, "x"}, "[000001 002 00x]"},
+	{"%03.6v", []interface{}{1, 2.0, "x"}, "[000,001 002 00x]"},
 	{"%03.0v", []interface{}{0, 2.0, "x"}, "[    002 000]"},
 
 	// Complex fmt used to leave the plus flag set for future entries in the array
@@ -971,10 +982,11 @@
 	{"%+10.2f", -104.66 + 440.51i, "(   -104.66   +440.51i)"},
 	{"%+10.2f", +104.66 - 440.51i, "(   +104.66   -440.51i)"},
 	{"%+10.2f", -104.66 - 440.51i, "(   -104.66   -440.51i)"},
-	{"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"},
-	{"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
-	{"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
-	{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
+	{"%010.2f", +104.66 + 440.51i, "(0,000,104.66+000,440.51i)"},
+	{"%+010.2f", +104.66 + 440.51i, "(+000,104.66+000,440.51i)"},
+	{"%+010.2f", -104.66 + 440.51i, "(-000,104.66+000,440.51i)"},
+	{"%+010.2f", +104.66 - 440.51i, "(+000,104.66-000,440.51i)"},
+	{"%+010.2f", -104.66 - 440.51i, "(-000,104.66-000,440.51i)"},
 
 	// []T where type T is a byte with a Stringer method.
 	{"%v", byteStringerSlice, "[X X X X X]"},
@@ -1043,7 +1055,7 @@
 func TestSprintf(t *testing.T) {
 	p := NewPrinter(language.Und)
 	for _, tt := range fmtTests {
-		t.Run(fmt.Sprint(tt.fmt, tt.val), func(t *testing.T) {
+		t.Run(fmt.Sprint(tt.fmt, "/", tt.val), func(t *testing.T) {
 			s := p.Sprintf(tt.fmt, tt.val)
 			i := strings.Index(tt.out, "PTR")
 			if i >= 0 && i < len(s) {
@@ -1126,6 +1138,14 @@
 						for _, imagValue := range values {
 							one := p.Sprintf(realFmt, complex(realValue, imagValue))
 							two := p.Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
+							if math.IsNaN(imagValue) {
+								p := len(two) - len("NaNi)") - 1
+								if two[p] == ' ' {
+									two = two[:p] + "+" + two[p+1:]
+								} else {
+									two = two[:p+1] + "+" + two[p+1:]
+								}
+							}
 							if one != two {
 								t.Error(f, one, two)
 							}
@@ -1626,14 +1646,14 @@
 	{"%-*d", args(4, 42), "42  "},
 	{"%*d", args(-4, 42), "42  "},
 	{"%-*d", args(-4, 42), "42  "},
-	{"%.*d", args(4, 42), "0042"},
-	{"%*.*d", args(8, 4, 42), "    0042"},
-	{"%0*d", args(4, 42), "0042"},
+	{"%.*d", args(4, 42), "0,042"},
+	{"%*.*d", args(8, 4, 42), "   0,042"},
+	{"%0*d", args(4, 42), "0,042"},
 	// Some non-int types for width. (Issue 10732).
-	{"%0*d", args(uint(4), 42), "0042"},
-	{"%0*d", args(uint64(4), 42), "0042"},
-	{"%0*d", args('\x04', 42), "0042"},
-	{"%0*d", args(uintptr(4), 42), "0042"},
+	{"%0*d", args(uint(4), 42), "0,042"},
+	{"%0*d", args(uint64(4), 42), "0,042"},
+	{"%0*d", args('\x04', 42), "0,042"},
+	{"%0*d", args(uintptr(4), 42), "0,042"},
 
 	// erroneous
 	{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
diff --git a/message/message.go b/message/message.go
index 8b3bad1..9279123 100644
--- a/message/message.go
+++ b/message/message.go
@@ -5,6 +5,10 @@
 // Package message implements formatted I/O for localized strings with functions
 // analogous to the fmt's print functions.
 //
+// These are the important differences with fmt:
+//   - Output varies per locale.
+//   - The '#' flag is used to bypass localization.
+//
 // NOTE: Under construction. See https://golang.org/design/12750-localization
 // and its corresponding proposal issue https://golang.org/issues/12750.
 package message // import "golang.org/x/text/message"
@@ -59,6 +63,8 @@
 	p := &Printer{printer{
 		tag: t,
 	}}
+	p.printer.toDecimal.InitDecimal(t)
+	p.printer.toScientific.InitScientific(t)
 	p.printer.catContext = options.cat.Context(t, &p.printer)
 	return p
 }
diff --git a/message/message_test.go b/message/message_test.go
index e411415..8490272 100644
--- a/message/message_test.go
+++ b/message/message_test.go
@@ -50,13 +50,14 @@
 	}
 }
 
-func TestFormatSelection(t *testing.T) {
+func TestLocalization(t *testing.T) {
 	type test struct {
 		tag  string
 		key  Reference
 		args []interface{}
 		want string
 	}
+	args := func(x ...interface{}) []interface{} { return x }
 	empty := []interface{}{}
 	joe := []interface{}{"Joe"}
 	joeAndMary := []interface{}{"Joe", "Mary"}
@@ -126,6 +127,20 @@
 			{"und", "hello %+%%s", joeAndMary, "hello %Joe%!(EXTRA string=Mary)"},
 			{"und", "hello %-42%%s ", joeAndMary, "hello %Joe %!(EXTRA string=Mary)"},
 		},
+	}, {
+		desc: "number formatting", // work around limitation of fmt
+		cat: []entry{
+			{"und", "files", "%d files left"},
+			{"und", "meters", "%.2f meters"},
+			{"de", "files", "%d Dateien übrig"},
+		},
+		test: []test{
+			{"en", "meters", args(3000.2), "3,000.20 meters"},
+			{"en-u-nu-gujr", "files", args(123456), "૧૨૩,૪૫૬ files left"},
+			{"de", "files", args(1234), "1.234 Dateien übrig"},
+			{"de-CH", "files", args(1234), "1'234 Dateien übrig"},
+			{"de-CH-u-nu-mong", "files", args(1234), "᠑'᠒᠓᠔ Dateien übrig"},
+		},
 	}}
 
 	for _, tc := range testCases {
diff --git a/message/print.go b/message/print.go
index caa50b6..8c8a23f 100644
--- a/message/print.go
+++ b/message/print.go
@@ -6,11 +6,12 @@
 
 import (
 	"bytes"
-	// TODO: consider copying interfaces from package fmt to avoid dependency.
-	"fmt"
+	"fmt" // TODO: consider copying interfaces from package fmt to avoid dependency.
+	"math"
 	"reflect"
 	"unicode/utf8"
 
+	"golang.org/x/text/internal/number"
 	"golang.org/x/text/language"
 	"golang.org/x/text/message/catalog"
 )
@@ -66,6 +67,9 @@
 	panicking bool
 	// erroring is set when printing an error string to guard against calling handleMethods.
 	erroring bool
+
+	toDecimal    number.Formatter
+	toScientific number.Formatter
 }
 
 func (p *printer) reset() {
@@ -188,11 +192,15 @@
 	case 'v':
 		if p.fmt.sharpV && !isSigned {
 			p.fmt0x64(v, true)
-		} else {
-			p.fmt.fmt_integer(v, 10, isSigned, ldigits)
+			return
 		}
+		fallthrough
 	case 'd':
-		p.fmt.fmt_integer(v, 10, isSigned, ldigits)
+		if p.fmt.sharp || p.fmt.sharpV {
+			p.fmt.fmt_integer(v, 10, isSigned, ldigits)
+		} else {
+			p.fmtDecimalInt(v, isSigned)
+		}
 	case 'b':
 		p.fmt.fmt_integer(v, 2, isSigned, ldigits)
 	case 'o':
@@ -220,19 +228,195 @@
 // is specified as last argument in the call to fmt_float.
 func (p *printer) fmtFloat(v float64, size int, verb rune) {
 	switch verb {
-	case 'v':
-		p.fmt.fmt_float(v, size, 'g', -1)
-	case 'b', 'g', 'G':
+	case 'b':
 		p.fmt.fmt_float(v, size, verb, -1)
-	case 'f', 'e', 'E':
-		p.fmt.fmt_float(v, size, verb, 6)
-	case 'F':
-		p.fmt.fmt_float(v, size, 'f', 6)
+	case 'v':
+		verb = 'g'
+		fallthrough
+	case 'g', 'G':
+		if p.fmt.sharp || p.fmt.sharpV {
+			p.fmt.fmt_float(v, size, verb, -1)
+		} else {
+			p.fmtVariableFloat(v, size, -1)
+		}
+	case 'e', 'E':
+		if p.fmt.sharp || p.fmt.sharpV {
+			p.fmt.fmt_float(v, size, verb, 6)
+		} else {
+			p.fmtScientific(v, size, 6)
+		}
+	case 'f', 'F':
+		if p.fmt.sharp || p.fmt.sharpV {
+			p.fmt.fmt_float(v, size, verb, 6)
+		} else {
+			p.fmtDecimalFloat(v, size, 6)
+		}
 	default:
 		p.badVerb(verb)
 	}
 }
 
+func (p *printer) setFlags(f *number.Formatter) {
+	f.Flags &^= number.ElideSign
+	if p.fmt.plus || p.fmt.space {
+		f.Flags |= number.AlwaysSign
+		if !p.fmt.plus {
+			f.Flags |= number.ElideSign
+		}
+	} else {
+		f.Flags &^= number.AlwaysSign
+	}
+}
+
+func (p *printer) updatePadding(f *number.Formatter) {
+	f.Flags &^= number.PadMask
+	if p.fmt.minus {
+		f.Flags |= number.PadAfterSuffix
+	} else {
+		f.Flags |= number.PadBeforePrefix
+	}
+	f.PadRune = ' '
+	f.FormatWidth = uint16(p.fmt.wid)
+}
+
+func (p *printer) initDecimal(minFrac, maxFrac int) {
+	f := &p.toDecimal
+	f.MinIntegerDigits = 1
+	f.MaxIntegerDigits = 0
+	f.MinFractionDigits = uint8(minFrac)
+	f.MaxFractionDigits = uint8(maxFrac)
+	p.setFlags(f)
+	f.PadRune = 0
+	if p.fmt.widPresent {
+		if p.fmt.zero {
+			wid := p.fmt.wid
+			// Use significant integers for this.
+			// TODO: this is not the same as width, but so be it.
+			if f.MinFractionDigits > 0 {
+				wid -= 1 + int(f.MinFractionDigits)
+			}
+			if p.fmt.plus || p.fmt.space {
+				wid--
+			}
+			if wid > 0 && wid > int(f.MinIntegerDigits) {
+				f.MinIntegerDigits = uint8(wid)
+			}
+		}
+		p.updatePadding(f)
+	}
+}
+
+func (p *printer) initScientific(minFrac, maxFrac int) {
+	f := &p.toScientific
+	f.MinFractionDigits = uint8(minFrac)
+	f.MaxFractionDigits = uint8(maxFrac)
+	f.MinExponentDigits = 2
+	p.setFlags(f)
+	f.PadRune = 0
+	if p.fmt.widPresent {
+		f.Flags &^= number.PadMask
+		if p.fmt.zero {
+			f.PadRune = f.Digit(0)
+			f.Flags |= number.PadAfterPrefix
+		} else {
+			f.PadRune = ' '
+			f.Flags |= number.PadBeforePrefix
+		}
+		p.updatePadding(f)
+	}
+}
+
+func (p *printer) fmtDecimalInt(v uint64, isSigned bool) {
+	var d number.Decimal
+	p.toDecimal.RoundingContext.Scale = 0
+	d.ConvertInt(&p.toDecimal.RoundingContext, isSigned, v)
+
+	f := &p.toDecimal
+	if p.fmt.precPresent {
+		p.setFlags(f)
+		f.MinIntegerDigits = uint8(p.fmt.prec)
+		f.MaxIntegerDigits = 0
+		f.MinFractionDigits = 0
+		f.MaxFractionDigits = 0
+		if p.fmt.widPresent {
+			p.updatePadding(f)
+		}
+	} else {
+		p.initDecimal(0, 0)
+	}
+
+	out := p.toDecimal.Format([]byte(nil), &d)
+	p.Buffer.Write(out)
+}
+
+func (p *printer) fmtDecimalFloat(v float64, size, prec int) {
+	var d number.Decimal
+	if p.fmt.precPresent {
+		prec = p.fmt.prec
+	}
+	p.toDecimal.RoundingContext.Scale = int32(prec)
+	d.ConvertFloat(&p.toDecimal.RoundingContext, v, size)
+
+	p.initDecimal(prec, prec)
+
+	out := p.toDecimal.Format([]byte(nil), &d)
+	p.Buffer.Write(out)
+}
+
+func (p *printer) fmtVariableFloat(v float64, size, prec int) {
+	if p.fmt.precPresent {
+		prec = p.fmt.prec
+	}
+	var d number.Decimal
+	p.toScientific.RoundingContext.Precision = int32(prec)
+	d.ConvertFloat(&p.toScientific.RoundingContext, v, size)
+
+	// Copy logic of 'g' formatting from strconv. It is simplified a bit as
+	// we don't have to mind having prec > len(d.Digits).
+	shortest := prec < 0
+	ePrec := prec
+	if shortest {
+		prec = len(d.Digits)
+		ePrec = 6
+	} else if prec == 0 {
+		prec = 1
+		ePrec = 1
+	}
+	exp := int(d.Exp) - 1
+	if exp < -4 || exp >= ePrec {
+		p.initScientific(0, prec)
+
+		out := p.toScientific.Format([]byte(nil), &d)
+		p.Buffer.Write(out)
+	} else {
+		if prec > int(d.Exp) {
+			prec = len(d.Digits)
+		}
+		if prec -= int(d.Exp); prec < 0 {
+			prec = 0
+		}
+		p.initDecimal(0, prec)
+
+		out := p.toDecimal.Format([]byte(nil), &d)
+		p.Buffer.Write(out)
+	}
+}
+
+func (p *printer) fmtScientific(v float64, size, prec int) {
+	var d number.Decimal
+	if p.fmt.precPresent {
+		prec = p.fmt.prec
+	}
+	p.toScientific.RoundingContext.Precision = int32(prec)
+	d.ConvertFloat(&p.toScientific.RoundingContext, v, size)
+
+	p.initScientific(prec, prec)
+
+	out := p.toScientific.Format([]byte(nil), &d)
+	p.Buffer.Write(out)
+
+}
+
 // fmtComplex formats a complex number v with
 // r = real(v) and j = imag(v) as (r+ji) using
 // fmtFloat for r and j formatting.
@@ -241,13 +425,39 @@
 	// calls to fmtFloat to not generate an incorrect error string.
 	switch verb {
 	case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
-		oldPlus := p.fmt.plus
 		p.WriteByte('(')
 		p.fmtFloat(real(v), size/2, verb)
 		// Imaginary part always has a sign.
+		if math.IsNaN(imag(v)) {
+			// By CLDR's rules, NaNs do not use patterns or signs. As this code
+			// relies on AlwaysSign working for imaginary parts, we need to
+			// manually handle NaNs.
+			f := &p.toScientific
+			p.setFlags(f)
+			p.updatePadding(f)
+			p.setFlags(f)
+			nan := f.Symbol(number.SymNan)
+			extra := 0
+			if w, ok := p.Width(); ok {
+				extra = w - utf8.RuneCountInString(nan) - 1
+			}
+			if f.Flags&number.PadAfterNumber == 0 {
+				for ; extra > 0; extra-- {
+					p.WriteRune(f.PadRune)
+				}
+			}
+			p.WriteString(f.Symbol(number.SymPlusSign))
+			p.WriteString(nan)
+			for ; extra > 0; extra-- {
+				p.WriteRune(f.PadRune)
+			}
+			p.WriteString("i)")
+			return
+		}
+		oldPlus := p.fmt.plus
 		p.fmt.plus = true
 		p.fmtFloat(imag(v), size/2, verb)
-		p.WriteString("i)")
+		p.WriteString("i)") // TODO: use symbol?
 		p.fmt.plus = oldPlus
 	default:
 		p.badVerb(verb)
@@ -347,6 +557,9 @@
 	case 'p':
 		p.fmt0x64(uint64(u), !p.fmt.sharp)
 	case 'b', 'o', 'd', 'x', 'X':
+		if verb == 'd' {
+			p.fmt.sharp = true // Print as standard go. TODO: does this make sense?
+		}
 		p.fmtInteger(uint64(u), unsigned, verb)
 	default:
 		p.badVerb(verb)