add unitUsage of numberFormat

Signed-off-by: LY <liuyong235@huawei.com>
This commit is contained in:
LY 2024-04-26 16:34:33 +08:00
parent 58539cccdb
commit 516853c944
6 changed files with 260 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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