mirror of
https://gitee.com/openharmony/global_i18n
synced 2024-12-04 21:57:11 +00:00
add unitUsage of numberFormat
Signed-off-by: LY <liuyong235@huawei.com>
This commit is contained in:
parent
58539cccdb
commit
516853c944
@ -31,6 +31,8 @@ void ComputeFactorValue(const std::string &unit, const std::string &measSys, std
|
||||
double ComputeSIPrefixValue(const std::string &unit);
|
||||
void ComputePowerValue(const std::string &unit, const std::string &measSys, std::vector<double> &factors);
|
||||
int ComputeValue(const std::string &unit, const std::string &measSys, std::vector<double> &factors);
|
||||
bool ConvertByte(double& number, std::string& unit);
|
||||
bool ConvertDate(double& number, std::string& unit);
|
||||
int Convert(double &value, const std::string &fromUnit, const std::string &fromMeasSys, const std::string &toUnit,
|
||||
const std::string &toMeasSys);
|
||||
} // namespace I18n
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "number_utypes.h"
|
||||
#include "locale_info.h"
|
||||
#include "measure_data.h"
|
||||
#include "relative_time_format.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
@ -84,6 +85,7 @@ private:
|
||||
std::string unitMeasSys;
|
||||
bool createSuccess = false;
|
||||
std::unique_ptr<LocaleInfo> localeInfo = nullptr;
|
||||
std::unique_ptr<RelativeTimeFormat> relativeTimeFormat = nullptr;
|
||||
icu::number::LocalizedNumberFormatter numberFormat;
|
||||
icu::number::Notation notation = icu::number::Notation::simple();
|
||||
UNumberUnitWidth unitDisplay = UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT;
|
||||
@ -103,6 +105,8 @@ private:
|
||||
static std::unordered_map<UMeasurementSystem, std::string> measurementSystem;
|
||||
static std::unordered_map<std::string, UNumberUnitWidth> defaultUnitStyle;
|
||||
static std::unordered_map<std::string, UNumberUnitWidth> defaultCurrencyStyle;
|
||||
static std::map<std::string, std::string> RelativeTimeFormatConfigs;
|
||||
void CreateRelativeTimeFormat(const std::string& locale);
|
||||
void ParseConfigs(std::map<std::string, std::string> &configs);
|
||||
void ParseDigitsConfigs(std::map<std::string, std::string> &configs);
|
||||
void GetDigitsResolvedOptions(std::map<std::string, std::string> &map);
|
||||
@ -110,6 +114,7 @@ private:
|
||||
void InitDigitsProperties();
|
||||
void SetUnit(std::string &preferredUnit);
|
||||
void SetDefaultStyle();
|
||||
void SetPrecisionWithByte(double number, const std::string& finalUnit);
|
||||
};
|
||||
} // namespace I18n
|
||||
} // namespace Global
|
||||
|
@ -283,6 +283,24 @@ const std::unordered_map<std::string, double> PREFIX_VALUE {
|
||||
{ "mega", pow(10, 6) },
|
||||
};
|
||||
|
||||
const std::vector<std::string> BYTE_VALUE {
|
||||
"byte",
|
||||
"kilobyte",
|
||||
"megabyte",
|
||||
"gigabyte",
|
||||
"terabyte",
|
||||
"petabyte"
|
||||
};
|
||||
|
||||
const std::vector<std::pair<std::string, double>> DATE_VALUE {
|
||||
{ "second", 1 },
|
||||
{ "minute", 60 },
|
||||
{ "hour", 60 },
|
||||
{ "day", 24},
|
||||
{ "month", 30 },
|
||||
{ "year", 365 / 30 }
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, double> POWER_VALUE {
|
||||
{ "square-", 2 },
|
||||
{ "cubic-", 3 },
|
||||
@ -545,6 +563,93 @@ int ComputeValue(const string &unit, const string &measSys, vector<double> &fact
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ConvertByte(double& number, std::string& unit)
|
||||
{
|
||||
double tempNumber = number;
|
||||
if (tempNumber < 0) {
|
||||
tempNumber *= -1;
|
||||
}
|
||||
std::string tempUnit = unit;
|
||||
size_t indexFirst = -1;
|
||||
for (size_t i = 0; i < BYTE_VALUE.size(); i++) {
|
||||
if (BYTE_VALUE[i] == tempUnit) {
|
||||
indexFirst = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool status = (indexFirst >= 0);
|
||||
size_t indexSecond = indexFirst;
|
||||
for (size_t i = indexFirst; i > 0; i--) {
|
||||
if (tempNumber < 1) {
|
||||
// 10 ^ 3 is the threshold for carry
|
||||
tempNumber *= pow(10, 3);
|
||||
tempUnit = BYTE_VALUE[i - 1];
|
||||
indexSecond = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = indexSecond + 1; i < BYTE_VALUE.size(); i++) {
|
||||
// 900 is the threshold for carry
|
||||
if (tempNumber > 900) {
|
||||
// 10 ^ 3 is the threshold for carry
|
||||
tempNumber /= pow(10, 3);
|
||||
tempUnit = BYTE_VALUE[i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
number = tempNumber;
|
||||
unit = tempUnit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConvertDate(double& number, std::string& unit)
|
||||
{
|
||||
double tempNumber = number;
|
||||
if (tempNumber < 0) {
|
||||
tempNumber *= -1;
|
||||
}
|
||||
std::string tempUnit = unit;
|
||||
|
||||
size_t indexFirst = -1;
|
||||
for (size_t i = 0; i < DATE_VALUE.size(); i++) {
|
||||
if (DATE_VALUE[i].first == tempUnit) {
|
||||
indexFirst = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool status = (indexFirst >= 0);
|
||||
size_t indexSecond = indexFirst;
|
||||
for (size_t i = indexFirst; i > 0; i--) {
|
||||
if (tempNumber < 1) {
|
||||
tempNumber *= DATE_VALUE[i].second;
|
||||
tempUnit = DATE_VALUE[i - 1].first;
|
||||
indexSecond = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = indexSecond + 1; i < DATE_VALUE.size(); i++) {
|
||||
if ((tempNumber / DATE_VALUE[i].second) >= 1) {
|
||||
tempNumber /= DATE_VALUE[i].second;
|
||||
tempUnit = DATE_VALUE[i].first;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
number = floor(tempNumber);
|
||||
number *= -1;
|
||||
unit = tempUnit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Convert(double &value, const string &fromUnit, const string &fromMeasSys, const string &toUnit,
|
||||
const string &toMeasSys)
|
||||
{
|
||||
|
@ -73,6 +73,10 @@ std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultCurrencyS
|
||||
{ "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
|
||||
};
|
||||
|
||||
std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
|
||||
{ "numeric", "auto" }
|
||||
};
|
||||
|
||||
NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
|
||||
{
|
||||
SetDefaultStyle();
|
||||
@ -89,6 +93,7 @@ NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<
|
||||
}
|
||||
if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
|
||||
localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
|
||||
CreateRelativeTimeFormat(curLocale);
|
||||
if (!localeInfo->InitSuccess()) {
|
||||
continue;
|
||||
}
|
||||
@ -105,7 +110,9 @@ NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<
|
||||
}
|
||||
}
|
||||
if (!createSuccess) {
|
||||
localeInfo = std::make_unique<LocaleInfo>(LocaleConfig::GetSystemLocale(), configs);
|
||||
std::string systemLocale = LocaleConfig::GetSystemLocale();
|
||||
localeInfo = std::make_unique<LocaleInfo>(systemLocale, configs);
|
||||
CreateRelativeTimeFormat(systemLocale);
|
||||
if (localeInfo->InitSuccess()) {
|
||||
locale = localeInfo->GetLocale();
|
||||
localeBaseName = localeInfo->GetBaseName();
|
||||
@ -125,6 +132,15 @@ NumberFormat::~NumberFormat()
|
||||
{
|
||||
}
|
||||
|
||||
void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
|
||||
{
|
||||
if (unitUsage == "elapsed-time-second") {
|
||||
std::vector<std::string> locales = { locale };
|
||||
relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
|
||||
RelativeTimeFormatConfigs);
|
||||
}
|
||||
}
|
||||
|
||||
void NumberFormat::InitProperties()
|
||||
{
|
||||
if (!currency.empty()) {
|
||||
@ -309,7 +325,14 @@ std::string NumberFormat::Format(double number)
|
||||
return PseudoLocalizationProcessor("");
|
||||
}
|
||||
double finalNumber = number;
|
||||
if (!unitUsage.empty()) {
|
||||
std::string finalUnit = unit;
|
||||
if ((unitUsage == "size-file-byte" || unitUsage == "size-shortfile-byte") && ConvertByte(finalNumber, finalUnit)) {
|
||||
SetUnit(finalUnit);
|
||||
SetPrecisionWithByte(finalNumber, finalUnit);
|
||||
} else if (unitUsage == "elapsed-time-second" && ConvertDate(finalNumber, finalUnit) &&
|
||||
relativeTimeFormat != nullptr) {
|
||||
return relativeTimeFormat->Format(finalNumber, finalUnit);
|
||||
} else if (!unitUsage.empty()) {
|
||||
std::vector<std::string> preferredUnits;
|
||||
if (unitUsage == "default") {
|
||||
GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
|
||||
@ -418,6 +441,36 @@ void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &
|
||||
}
|
||||
}
|
||||
|
||||
void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
|
||||
{
|
||||
int32_t FractionDigits = -1;
|
||||
// 100 is the threshold between different decimal
|
||||
if (finalUnit == "byte" || number >= 100) {
|
||||
FractionDigits = 0;
|
||||
} else if (number < 1) {
|
||||
// 2 is the number of significant digits in the decimal
|
||||
FractionDigits = 2;
|
||||
// 10 is the threshold between different decimal
|
||||
} else if (number < 10) {
|
||||
if (unitUsage == "size-shortfile-byte") {
|
||||
FractionDigits = 1;
|
||||
} else {
|
||||
// 2 is the number of significant digits in the decimal
|
||||
FractionDigits = 2;
|
||||
}
|
||||
} else {
|
||||
if (unitUsage == "size-shortfile-byte") {
|
||||
FractionDigits = 0;
|
||||
} else {
|
||||
// 2 is the number of significant digits in the decimal
|
||||
FractionDigits = 2;
|
||||
}
|
||||
}
|
||||
if (FractionDigits != -1) {
|
||||
numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
|
||||
}
|
||||
}
|
||||
|
||||
std::string NumberFormat::GetCurrency() const
|
||||
{
|
||||
return currency;
|
||||
|
@ -98,6 +98,9 @@ int IntlFuncTest0065(void);
|
||||
int IntlFuncTest0066(void);
|
||||
int IntlFuncTest0067(void);
|
||||
int IntlFuncTest0068(void);
|
||||
int IntlFuncTest0069(void);
|
||||
int IntlFuncTest0070(void);
|
||||
int IntlFuncTest0071(void);
|
||||
} // namespace I18n
|
||||
} // namespace Global
|
||||
} // namespace OHOS
|
||||
|
@ -765,6 +765,96 @@ HWTEST_F(IntlTest, IntlFuncTest0068, TestSize.Level1)
|
||||
EXPECT_EQ(timeZoneNameRes, "18 h UTC+8");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: IntlFuncTest0069
|
||||
* @tc.desc: Test number format unitUsage
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(IntlTest, IntlFuncTest0069, TestSize.Level1)
|
||||
{
|
||||
std::string locale = "en-GB";
|
||||
std::vector<std::string> locales;
|
||||
locales.push_back(locale);
|
||||
map<string, string> options = { { "style", "unit" },
|
||||
{ "unit", "day" },
|
||||
{ "unitUsage", "elapsed-time-second"} };
|
||||
NumberFormat *numFmt = new (std::nothrow) NumberFormat(locales, options);
|
||||
if (!numFmt) {
|
||||
EXPECT_TRUE(false);
|
||||
return;
|
||||
}
|
||||
std::string nowRes = numFmt->Format(0.00001);
|
||||
std::string secondRes = numFmt->Format(0.00004);
|
||||
std::string dayRes = numFmt->Format(1.5);
|
||||
std::string monthRes = numFmt->Format(-62.5);
|
||||
|
||||
EXPECT_EQ(nowRes, "now");
|
||||
EXPECT_EQ(secondRes, "3 seconds ago");
|
||||
EXPECT_EQ(dayRes, "yesterday");
|
||||
EXPECT_EQ(monthRes, "2 months ago");
|
||||
delete numFmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: IntlFuncTest0070
|
||||
* @tc.desc: Test number format unitUsage
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(IntlTest, IntlFuncTest0070, TestSize.Level1)
|
||||
{
|
||||
std::string locale = "en-GB";
|
||||
std::vector<std::string> locales;
|
||||
locales.push_back(locale);
|
||||
map<string, string> options = { { "style", "unit" },
|
||||
{ "unit", "megabyte" },
|
||||
{ "unitUsage", "size-file-byte"} };
|
||||
NumberFormat *numFmt = new (std::nothrow) NumberFormat(locales, options);
|
||||
if (!numFmt) {
|
||||
EXPECT_TRUE(false);
|
||||
return;
|
||||
}
|
||||
std::string byteRes = numFmt->Format(0.00000812);
|
||||
std::string kbRes = numFmt->Format(0.125);
|
||||
std::string mbRes = numFmt->Format(3.5);
|
||||
std::string gbRes = numFmt->Format(23122);
|
||||
|
||||
EXPECT_EQ(byteRes, "8 byte");
|
||||
EXPECT_EQ(kbRes, "125 kB");
|
||||
EXPECT_EQ(mbRes, "3.50 MB");
|
||||
EXPECT_EQ(gbRes, "23.12 GB");
|
||||
delete numFmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: IntlFuncTest0071
|
||||
* @tc.desc: Test number format unitUsage
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(IntlTest, IntlFuncTest0071, TestSize.Level1)
|
||||
{
|
||||
std::string locale = "en-GB";
|
||||
std::vector<std::string> locales;
|
||||
locales.push_back(locale);
|
||||
map<string, string> options = { { "style", "unit" },
|
||||
{ "unit", "megabyte" },
|
||||
{ "unitUsage", "size-shortfile-byte"} };
|
||||
NumberFormat *numFmt = new (std::nothrow) NumberFormat(locales, options);
|
||||
if (!numFmt) {
|
||||
EXPECT_TRUE(false);
|
||||
return;
|
||||
}
|
||||
std::string byteRes = numFmt->Format(0.00000812);
|
||||
std::string kbRes = numFmt->Format(0.125);
|
||||
std::string mbRes = numFmt->Format(3.5);
|
||||
std::string gbRes = numFmt->Format(23122);
|
||||
|
||||
EXPECT_EQ(byteRes, "8 byte");
|
||||
EXPECT_EQ(kbRes, "125 kB");
|
||||
EXPECT_EQ(mbRes, "3.5 MB");
|
||||
EXPECT_EQ(gbRes, "23 GB");
|
||||
delete numFmt;
|
||||
}
|
||||
} // namespace I18n
|
||||
} // namespace Global
|
||||
} // namespace OHOS
|
Loading…
Reference in New Issue
Block a user