summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-22 20:40:22 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-22 20:40:22 +0000
commit7a3b263af6356885628add7a8843a40dbee5b8ab (patch)
treeeff6140c44d29b6904b90366df65161364ea555f /base
parentefaba4815ff6786082583393ad06f8c22ef11fa0 (diff)
downloadchromium_src-7a3b263af6356885628add7a8843a40dbee5b8ab.zip
chromium_src-7a3b263af6356885628add7a8843a40dbee5b8ab.tar.gz
chromium_src-7a3b263af6356885628add7a8843a40dbee5b8ab.tar.bz2
Localize strings, speeds.
BUG=86527 TEST=run in non-English. For European languages, during a download the decimal separators should be commas (e.g. "0,0 MB"). (The speeds are in strings files and might take a little time to run through the translation machinery.) Review URL: http://codereview.chromium.org/7189076 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90092 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp1
-rw-r--r--base/i18n/number_formatting.cc37
-rw-r--r--base/i18n/number_formatting.h18
-rw-r--r--base/i18n/number_formatting_unittest.cc92
-rw-r--r--base/string_util.cc94
-rw-r--r--base/string_util.h30
-rw-r--r--base/string_util_unittest.cc68
7 files changed, 189 insertions, 151 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 668171d..3b7b085 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -130,6 +130,7 @@
'i18n/case_conversion_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
+ 'i18n/number_formatting_unittest.cc',
'i18n/rtl_unittest.cc',
'i18n/time_formatting_unittest.cc',
'json/json_reader_unittest.cc',
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
index a529a84..b2eeb16 100644
--- a/base/i18n/number_formatting.cc
+++ b/base/i18n/number_formatting.cc
@@ -20,6 +20,10 @@ namespace {
struct NumberFormatWrapper {
NumberFormatWrapper() {
+ Reset();
+ }
+
+ void Reset() {
// There's no ICU call to destroy a NumberFormat object other than
// operator delete, so use the default Delete, which calls operator delete.
// This can cause problems if a different allocator is used by this file
@@ -32,12 +36,14 @@ struct NumberFormatWrapper {
scoped_ptr<icu::NumberFormat> number_format;
};
-} // namespace
+LazyInstance<NumberFormatWrapper> g_number_format_int(LINKER_INITIALIZED);
+LazyInstance<NumberFormatWrapper> g_number_format_float(LINKER_INITIALIZED);
-static LazyInstance<NumberFormatWrapper> g_number_format(LINKER_INITIALIZED);
+} // namespace
string16 FormatNumber(int64 number) {
- icu::NumberFormat* number_format = g_number_format.Get().number_format.get();
+ icu::NumberFormat* number_format =
+ g_number_format_int.Get().number_format.get();
if (!number_format) {
// As a fallback, just return the raw number in a string.
@@ -49,4 +55,29 @@ string16 FormatNumber(int64 number) {
return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
}
+string16 FormatDouble(double number, int fractional_digits) {
+ icu::NumberFormat* number_format =
+ g_number_format_float.Get().number_format.get();
+
+ if (!number_format) {
+ // As a fallback, just return the raw number in a string.
+ return UTF8ToUTF16(StringPrintf("%f", number));
+ }
+ number_format->setMaximumFractionDigits(fractional_digits);
+ number_format->setMinimumFractionDigits(fractional_digits);
+ icu::UnicodeString ustr;
+ number_format->format(number, ustr);
+
+ return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+namespace testing {
+
+void ResetFormatters() {
+ g_number_format_int.Get().Reset();
+ g_number_format_float.Get().Reset();
+}
+
+} // namespace testing
+
} // namespace base
diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h
index f5ec083..5df7f17 100644
--- a/base/i18n/number_formatting.h
+++ b/base/i18n/number_formatting.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,8 +11,24 @@
namespace base {
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatNumber(1234567)
+// => "1,234,567" in English, "1.234.567" in German
string16 FormatNumber(int64 number);
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatDouble(1234567.8, 1)
+// => "1,234,567.8" in English, "1.234.567,8" in German
+string16 FormatDouble(double number, int fractional_digits);
+
+namespace testing {
+
+// Causes cached formatters to be discarded and recreated. Only useful for
+// testing.
+void ResetFormatters();
+
+} // namespace testing
+
} // namespace base
#endif // BASE_I18N_NUMBER_FORMATTING_H_
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc
new file mode 100644
index 0000000..e6a54b5
--- /dev/null
+++ b/base/i18n/number_formatting_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/i18n/number_formatting.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "unicode/locid.h"
+
+namespace {
+
+void SetICUDefaultLocale(const std::string& locale_string) {
+ icu::Locale locale(locale_string.c_str());
+ UErrorCode error_code = U_ZERO_ERROR;
+ icu::Locale::setDefault(locale, error_code);
+ EXPECT_TRUE(U_SUCCESS(error_code));
+}
+
+} // namespace
+
+TEST(NumberFormattingTest, FormatNumber) {
+ static const struct {
+ int64 number;
+ const char* expected_english;
+ const char* expected_german;
+ } cases[] = {
+ {0, "0", "0"},
+ {1024, "1,024", "1.024"},
+ {std::numeric_limits<int64>::max(),
+ "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"},
+ {std::numeric_limits<int64>::min(),
+ "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"},
+ {-42, "-42", "-42"},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ SetICUDefaultLocale("en");
+ base::testing::ResetFormatters();
+ EXPECT_EQ(cases[i].expected_english,
+ UTF16ToUTF8(base::FormatNumber(cases[i].number)));
+ SetICUDefaultLocale("de");
+ base::testing::ResetFormatters();
+ EXPECT_EQ(cases[i].expected_german,
+ UTF16ToUTF8(base::FormatNumber(cases[i].number)));
+ }
+}
+
+TEST(NumberFormattingTest, FormatDouble) {
+ static const struct {
+ double number;
+ int frac_digits;
+ const char* expected_english;
+ const char* expected_german;
+ } cases[] = {
+ {0.0, 0, "0", "0"},
+ {-0.0, 4, "-0.0000", "-0,0000"},
+ {1024.2, 0, "1,024", "1.024"},
+ {-1024.223, 2, "-1,024.22", "-1.024,22"},
+ {std::numeric_limits<double>::max(), 6,
+ "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+ "000.000000",
+ "179.769.313.486.232.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+ "000,000000"},
+ {std::numeric_limits<double>::min(), 2, "0.00", "0,00"},
+ {-42.7, 3, "-42.700", "-42,700"},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ SetICUDefaultLocale("en");
+ base::testing::ResetFormatters();
+ EXPECT_EQ(cases[i].expected_english,
+ UTF16ToUTF8(base::FormatDouble(cases[i].number,
+ cases[i].frac_digits)));
+ SetICUDefaultLocale("de");
+ base::testing::ResetFormatters();
+ EXPECT_EQ(cases[i].expected_german,
+ UTF16ToUTF8(base::FormatDouble(cases[i].number,
+ cases[i].frac_digits)));
+ }
+}
diff --git a/base/string_util.cc b/base/string_util.cc
index 81b9ee7..31c5e1a 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -604,85 +604,35 @@ bool EndsWith(const string16& str, const string16& search,
}
#endif
-DataUnits GetByteDisplayUnits(int64 bytes) {
- // The byte thresholds at which we display amounts. A byte count is displayed
- // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
- // This must match the DataUnits enum.
- static const int64 kUnitThresholds[] = {
- 0, // DATA_UNITS_BYTE,
- 3*1024, // DATA_UNITS_KIBIBYTE,
- 2*1024*1024, // DATA_UNITS_MEBIBYTE,
- 1024*1024*1024 // DATA_UNITS_GIBIBYTE,
- };
-
- if (bytes < 0) {
- NOTREACHED() << "Negative bytes value";
- return DATA_UNITS_BYTE;
- }
-
- int unit_index = arraysize(kUnitThresholds);
- while (--unit_index > 0) {
- if (bytes >= kUnitThresholds[unit_index])
- break;
- }
-
- DCHECK(unit_index >= DATA_UNITS_BYTE && unit_index <= DATA_UNITS_GIBIBYTE);
- return DataUnits(unit_index);
-}
-
-// TODO(mpcomplete): deal with locale
-// Byte suffixes. This must match the DataUnits enum.
-static const char* const kByteStrings[] = {
- "B",
- "kB",
- "MB",
- "GB"
+static const char* const kByteStringsUnlocalized[] = {
+ " B",
+ " kB",
+ " MB",
+ " GB",
+ " TB",
+ " PB"
};
-static const char* const kSpeedStrings[] = {
- "B/s",
- "kB/s",
- "MB/s",
- "GB/s"
-};
-
-string16 FormatBytesInternal(int64 bytes,
- DataUnits units,
- bool show_units,
- const char* const* suffix) {
- if (bytes < 0) {
- NOTREACHED() << "Negative bytes value";
- return string16();
- }
-
- DCHECK(units >= DATA_UNITS_BYTE && units <= DATA_UNITS_GIBIBYTE);
-
- // Put the quantity in the right units.
+string16 FormatBytesUnlocalized(int64 bytes) {
double unit_amount = static_cast<double>(bytes);
- for (int i = 0; i < units; ++i)
- unit_amount /= 1024.0;
+ size_t dimension = 0;
+ const int kKilo = 1024;
+ while (unit_amount >= kKilo &&
+ dimension < arraysize(kByteStringsUnlocalized) - 1) {
+ unit_amount /= kKilo;
+ dimension++;
+ }
char buf[64];
- if (bytes != 0 && units != DATA_UNITS_BYTE && unit_amount < 100)
- base::snprintf(buf, arraysize(buf), "%.1lf", unit_amount);
- else
- base::snprintf(buf, arraysize(buf), "%.0lf", unit_amount);
-
- std::string ret(buf);
- if (show_units) {
- ret += " ";
- ret += suffix[units];
+ if (bytes != 0 && dimension > 0 && unit_amount < 100) {
+ base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
+ kByteStringsUnlocalized[dimension]);
+ } else {
+ base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
+ kByteStringsUnlocalized[dimension]);
}
- return ASCIIToUTF16(ret);
-}
-
-string16 FormatBytes(int64 bytes, DataUnits units, bool show_units) {
- return FormatBytesInternal(bytes, units, show_units, kByteStrings);
-}
-
-string16 FormatSpeed(int64 bytes, DataUnits units, bool show_units) {
- return FormatBytesInternal(bytes, units, show_units, kSpeedStrings);
+ return ASCIIToUTF16(buf);
}
template<class StringType>
diff --git a/base/string_util.h b/base/string_util.h
index 0cb439c..f731c34 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -407,31 +407,11 @@ inline bool IsWhitespace(wchar_t c) {
return wcschr(kWhitespaceWide, c) != NULL;
}
-enum DataUnits {
- DATA_UNITS_BYTE = 0,
- DATA_UNITS_KIBIBYTE,
- DATA_UNITS_MEBIBYTE,
- DATA_UNITS_GIBIBYTE,
-};
-
-// Return the unit type that is appropriate for displaying the amount of bytes
-// passed in.
-BASE_API DataUnits GetByteDisplayUnits(int64 bytes);
-
-// Return a byte string in human-readable format, displayed in units appropriate
-// specified by 'units', with an optional unit suffix.
-// Ex: FormatBytes(512, DATA_UNITS_KIBIBYTE, true) => "0.5 KB"
-// Ex: FormatBytes(10*1024, DATA_UNITS_MEBIBYTE, false) => "0.1"
-BASE_API string16 FormatBytes(int64 bytes, DataUnits units, bool show_units);
-
-// As above, but with "/s" units.
-// Ex: FormatSpeed(512, DATA_UNITS_KIBIBYTE, true) => "0.5 KB/s"
-// Ex: FormatSpeed(10*1024, DATA_UNITS_MEBIBYTE, false) => "0.1"
-BASE_API string16 FormatSpeed(int64 bytes, DataUnits units, bool show_units);
-
-// Return a number formated with separators in the user's locale way.
-// Ex: FormatNumber(1234567) => 1,234,567
-BASE_API string16 FormatNumber(int64 number);
+// Return a byte string in human-readable format with a unit suffix. Not
+// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
+// highly recommended instead. TODO(avi): Figure out how to get callers to use
+// FormatBytes instead; remove this.
+BASE_API string16 FormatBytesUnlocalized(int64 bytes);
// Starting at |start_offset| (usually 0), replace the first instance of
// |find_this| with |replace_with|.
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index 8bdeaf5..0911aae 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -491,32 +491,10 @@ TEST(StringUtilTest, LowerCaseEqualsASCII) {
}
}
-TEST(StringUtilTest, GetByteDisplayUnits) {
+TEST(StringUtilTest, FormatBytesUnlocalized) {
static const struct {
int64 bytes;
- DataUnits expected;
- } cases[] = {
- {0, DATA_UNITS_BYTE},
- {512, DATA_UNITS_BYTE},
- {10*1024, DATA_UNITS_KIBIBYTE},
- {10*1024*1024, DATA_UNITS_MEBIBYTE},
- {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE},
- {~(1LL<<63), DATA_UNITS_GIBIBYTE},
-#ifdef NDEBUG
- {-1, DATA_UNITS_BYTE},
-#endif
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
- EXPECT_EQ(cases[i].expected, GetByteDisplayUnits(cases[i].bytes));
-}
-
-TEST(StringUtilTest, FormatBytes) {
- static const struct {
- int64 bytes;
- DataUnits units;
const char* expected;
- const char* expected_with_units;
} cases[] = {
// Expected behavior: we show one post-decimal digit when we have
// under two pre-decimal digits, except in cases where it makes no
@@ -524,39 +502,29 @@ TEST(StringUtilTest, FormatBytes) {
// Since we switch units once we cross the 1000 mark, this keeps
// the display of file sizes or bytes consistently around three
// digits.
- {0, DATA_UNITS_BYTE, "0", "0 B"},
- {512, DATA_UNITS_BYTE, "512", "512 B"},
- {512, DATA_UNITS_KIBIBYTE, "0.5", "0.5 kB"},
- {1024*1024, DATA_UNITS_KIBIBYTE, "1024", "1024 kB"},
- {1024*1024, DATA_UNITS_MEBIBYTE, "1.0", "1.0 MB"},
- {1024*1024*1024, DATA_UNITS_GIBIBYTE, "1.0", "1.0 GB"},
- {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "10.0", "10.0 GB"},
- {99LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "99.0", "99.0 GB"},
- {105LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "105", "105 GB"},
- {105LL*1024*1024*1024 + 500LL*1024*1024, DATA_UNITS_GIBIBYTE,
- "105", "105 GB"},
- {~(1LL<<63), DATA_UNITS_GIBIBYTE, "8589934592", "8589934592 GB"},
-
- {99*1024 + 103, DATA_UNITS_KIBIBYTE, "99.1", "99.1 kB"},
- {1024*1024 + 103, DATA_UNITS_KIBIBYTE, "1024", "1024 kB"},
- {1024*1024 + 205 * 1024, DATA_UNITS_MEBIBYTE, "1.2", "1.2 MB"},
- {1024*1024*1024 + (927 * 1024*1024), DATA_UNITS_GIBIBYTE,
- "1.9", "1.9 GB"},
- {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "10.0", "10.0 GB"},
- {100LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "100", "100 GB"},
-#ifdef NDEBUG
- {-1, DATA_UNITS_BYTE, "", ""},
-#endif
+ {0, "0 B"},
+ {512, "512 B"},
+ {1024*1024, "1.0 MB"},
+ {1024*1024*1024, "1.0 GB"},
+ {10LL*1024*1024*1024, "10.0 GB"},
+ {99LL*1024*1024*1024, "99.0 GB"},
+ {105LL*1024*1024*1024, "105 GB"},
+ {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"},
+ {~(1LL<<63), "8192 PB"},
+
+ {99*1024 + 103, "99.1 kB"},
+ {1024*1024 + 103, "1.0 MB"},
+ {1024*1024 + 205 * 1024, "1.2 MB"},
+ {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"},
+ {10LL*1024*1024*1024, "10.0 GB"},
+ {100LL*1024*1024*1024, "100 GB"},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
EXPECT_EQ(ASCIIToUTF16(cases[i].expected),
- FormatBytes(cases[i].bytes, cases[i].units, false));
- EXPECT_EQ(ASCIIToUTF16(cases[i].expected_with_units),
- FormatBytes(cases[i].bytes, cases[i].units, true));
+ FormatBytesUnlocalized(cases[i].bytes));
}
}
-
TEST(StringUtilTest, ReplaceSubstringsAfterOffset) {
static const struct {
const char* str;