2020-09-30 11:32:02 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#include "ui/text/format_values.h"
|
|
|
|
|
|
|
|
#include "lang/lang_keys.h"
|
|
|
|
|
|
|
|
#include <QtCore/QLocale>
|
2021-03-30 14:49:41 +00:00
|
|
|
#include <locale>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
[[nodiscard]] QString FormatWithSeparators(
|
|
|
|
double amount,
|
|
|
|
char decimal,
|
|
|
|
char thousands) {
|
|
|
|
Expects(decimal != 0);
|
|
|
|
|
|
|
|
// Thanks https://stackoverflow.com/a/5058949
|
|
|
|
struct FormattingHelper : std::numpunct<char> {
|
|
|
|
FormattingHelper(char decimal, char thousands)
|
|
|
|
: decimal(decimal)
|
|
|
|
, thousands(thousands) {
|
|
|
|
}
|
|
|
|
|
|
|
|
char do_decimal_point() const override { return decimal; }
|
|
|
|
char do_thousands_sep() const override { return thousands; }
|
|
|
|
|
|
|
|
char decimal = '.';
|
|
|
|
char thousands = ',';
|
|
|
|
};
|
|
|
|
|
|
|
|
auto stream = std::ostringstream();
|
|
|
|
auto helper = FormattingHelper(decimal, thousands ? thousands : '?');
|
|
|
|
stream.imbue(std::locale(stream.getloc(), &helper));
|
|
|
|
stream << std::fixed << amount;
|
|
|
|
auto result = QString::fromStdString(stream.str());
|
|
|
|
if (!thousands) {
|
|
|
|
result.replace('?', QString());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2020-09-30 11:32:02 +00:00
|
|
|
|
|
|
|
namespace Ui {
|
|
|
|
|
2020-11-17 03:38:39 +00:00
|
|
|
namespace {
|
2020-09-30 11:32:02 +00:00
|
|
|
|
2020-11-17 03:38:39 +00:00
|
|
|
QString FormatTextWithReadyAndTotal(
|
|
|
|
tr::phrase<lngtag_ready, lngtag_total, lngtag_mb> phrase,
|
|
|
|
qint64 ready,
|
|
|
|
qint64 total) {
|
2020-09-30 11:32:02 +00:00
|
|
|
QString readyStr, totalStr, mb;
|
|
|
|
if (total >= 1024 * 1024) { // more than 1 mb
|
2020-11-17 03:38:39 +00:00
|
|
|
const qint64 readyTenthMb = (ready * 10 / (1024 * 1024));
|
|
|
|
const qint64 totalTenthMb = (total * 10 / (1024 * 1024));
|
|
|
|
readyStr = QString::number(readyTenthMb / 10)
|
|
|
|
+ '.'
|
|
|
|
+ QString::number(readyTenthMb % 10);
|
|
|
|
totalStr = QString::number(totalTenthMb / 10)
|
|
|
|
+ '.'
|
|
|
|
+ QString::number(totalTenthMb % 10);
|
2020-09-30 11:32:02 +00:00
|
|
|
mb = u"MB"_q;
|
|
|
|
} else if (total >= 1024) {
|
|
|
|
qint64 readyKb = (ready / 1024), totalKb = (total / 1024);
|
|
|
|
readyStr = QString::number(readyKb);
|
|
|
|
totalStr = QString::number(totalKb);
|
|
|
|
mb = u"KB"_q;
|
|
|
|
} else {
|
|
|
|
readyStr = QString::number(ready);
|
|
|
|
totalStr = QString::number(total);
|
|
|
|
mb = u"B"_q;
|
|
|
|
}
|
2020-11-17 03:38:39 +00:00
|
|
|
return phrase(tr::now, lt_ready, readyStr, lt_total, totalStr, lt_mb, mb);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
QString FormatSizeText(qint64 size) {
|
|
|
|
if (size >= 1024 * 1024) { // more than 1 mb
|
|
|
|
const qint64 sizeTenthMb = (size * 10 / (1024 * 1024));
|
|
|
|
return QString::number(sizeTenthMb / 10)
|
|
|
|
+ '.'
|
|
|
|
+ QString::number(sizeTenthMb % 10) + u" MB"_q;
|
|
|
|
}
|
|
|
|
if (size >= 1024) {
|
|
|
|
const qint64 sizeTenthKb = (size * 10 / 1024);
|
|
|
|
return QString::number(sizeTenthKb / 10)
|
|
|
|
+ '.'
|
|
|
|
+ QString::number(sizeTenthKb % 10) + u" KB"_q;
|
|
|
|
}
|
|
|
|
return QString::number(size) + u" B"_q;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatDownloadText(qint64 ready, qint64 total) {
|
|
|
|
return FormatTextWithReadyAndTotal(
|
|
|
|
tr::lng_save_downloaded,
|
|
|
|
ready,
|
|
|
|
total);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatProgressText(qint64 ready, qint64 total) {
|
|
|
|
return FormatTextWithReadyAndTotal(
|
|
|
|
tr::lng_media_save_progress,
|
|
|
|
ready,
|
|
|
|
total);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatDateTime(QDateTime date, QString format) {
|
|
|
|
const auto now = QDateTime::currentDateTime();
|
|
|
|
if (date.date() == now.date()) {
|
|
|
|
return tr::lng_mediaview_today(
|
|
|
|
tr::now,
|
|
|
|
lt_time,
|
|
|
|
date.time().toString(format));
|
|
|
|
} else if (date.date().addDays(1) == now.date()) {
|
|
|
|
return tr::lng_mediaview_yesterday(
|
|
|
|
tr::now,
|
|
|
|
lt_time,
|
|
|
|
date.time().toString(format));
|
|
|
|
} else {
|
|
|
|
return tr::lng_mediaview_date_time(
|
|
|
|
tr::now,
|
|
|
|
lt_date,
|
|
|
|
date.date().toString(u"dd.MM.yy"_q),
|
|
|
|
lt_time,
|
|
|
|
date.time().toString(format));
|
|
|
|
}
|
2020-09-30 11:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatDurationText(qint64 duration) {
|
|
|
|
qint64 hours = (duration / 3600), minutes = (duration % 3600) / 60, seconds = duration % 60;
|
|
|
|
return (hours ? QString::number(hours) + ':' : QString()) + (minutes >= 10 ? QString() : QString('0')) + QString::number(minutes) + ':' + (seconds >= 10 ? QString() : QString('0')) + QString::number(seconds);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatDurationWords(qint64 duration) {
|
|
|
|
if (duration > 59) {
|
|
|
|
auto minutes = (duration / 60);
|
|
|
|
auto minutesCount = tr::lng_duration_minsec_minutes(tr::now, lt_count, minutes);
|
|
|
|
auto seconds = (duration % 60);
|
|
|
|
auto secondsCount = tr::lng_duration_minsec_seconds(tr::now, lt_count, seconds);
|
|
|
|
return tr::lng_duration_minutes_seconds(tr::now, lt_minutes_count, minutesCount, lt_seconds_count, secondsCount);
|
|
|
|
}
|
|
|
|
return tr::lng_duration_seconds(tr::now, lt_count, duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatDurationAndSizeText(qint64 duration, qint64 size) {
|
|
|
|
return tr::lng_duration_and_size(tr::now, lt_duration, FormatDurationText(duration), lt_size, FormatSizeText(size));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatGifAndSizeText(qint64 size) {
|
|
|
|
return tr::lng_duration_and_size(tr::now, lt_duration, u"GIF"_q, lt_size, FormatSizeText(size));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FormatPlayedText(qint64 played, qint64 duration) {
|
|
|
|
return tr::lng_duration_played(tr::now, lt_played, FormatDurationText(played), lt_duration, FormatDurationText(duration));
|
|
|
|
}
|
|
|
|
|
2021-03-23 16:06:59 +00:00
|
|
|
QString FillAmountAndCurrency(int64 amount, const QString ¤cy) {
|
2021-03-30 14:49:41 +00:00
|
|
|
struct Rule {
|
|
|
|
//const char *name = "";
|
|
|
|
//const char *native = "";
|
|
|
|
const char *international = "";
|
|
|
|
char thousands = ',';
|
|
|
|
char decimal = '.';
|
|
|
|
bool left = true;
|
|
|
|
bool space = false;
|
2020-09-30 11:32:02 +00:00
|
|
|
};
|
2021-03-30 14:49:41 +00:00
|
|
|
static const auto kRules = std::vector<std::pair<QString, Rule>>{
|
|
|
|
{ u"AED"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"AFN"_q, {} },
|
|
|
|
{ u"ALL"_q, { "", '.', ',', false } },
|
|
|
|
{ u"AMD"_q, { "", ',', '.', false, true } },
|
|
|
|
{ u"ARS"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"AUD"_q, { "AU$" } },
|
|
|
|
{ u"AZN"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"BAM"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"BDT"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"BGN"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"BND"_q, { "", '.', ',', } },
|
|
|
|
{ u"BOB"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"BRL"_q, { "R$", '.', ',', true, true } },
|
|
|
|
{ u"BHD"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"BYR"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"CAD"_q, { "CA$" } },
|
|
|
|
{ u"CHF"_q, { "", '\'', '.', false, true } },
|
|
|
|
{ u"CLP"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"CNY"_q, { "\x43\x4E\xC2\xA5" } },
|
|
|
|
{ u"COP"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"CRC"_q, { "", '.', ',', } },
|
|
|
|
{ u"CZK"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"DKK"_q, { "", '\0', ',', false, true } },
|
|
|
|
{ u"DOP"_q, {} },
|
|
|
|
{ u"DZD"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"EGP"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"EUR"_q, { "\xE2\x82\xAC", ' ', ',', false, true } },
|
|
|
|
{ u"GBP"_q, { "\xC2\xA3" } },
|
|
|
|
{ u"GEL"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"GTQ"_q, {} },
|
|
|
|
{ u"HKD"_q, { "HK$" } },
|
|
|
|
{ u"HNL"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"HRK"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"HUF"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"IDR"_q, { "", '.', ',', } },
|
|
|
|
{ u"ILS"_q, { "\xE2\x82\xAA", ',', '.', true, true } },
|
|
|
|
{ u"INR"_q, { "\xE2\x82\xB9" } },
|
|
|
|
{ u"ISK"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"JMD"_q, {} },
|
|
|
|
{ u"JPY"_q, { "\xC2\xA5" } },
|
|
|
|
{ u"KES"_q, {} },
|
|
|
|
{ u"KGS"_q, { "", ' ', '-', false, true } },
|
|
|
|
{ u"KRW"_q, { "\xE2\x82\xA9" } },
|
|
|
|
{ u"KZT"_q, { "", ' ', '-', } },
|
|
|
|
{ u"LBP"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"LKR"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"MAD"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"MDL"_q, { "", ',', '.', false, true } },
|
|
|
|
{ u"MNT"_q, { "", ' ', ',', } },
|
|
|
|
{ u"MUR"_q, {} },
|
|
|
|
{ u"MVR"_q, { "", ',', '.', false, true } },
|
|
|
|
{ u"MXN"_q, { "MX$" } },
|
|
|
|
{ u"MYR"_q, {} },
|
|
|
|
{ u"MZN"_q, {} },
|
|
|
|
{ u"NGN"_q, {} },
|
|
|
|
{ u"NIO"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"NOK"_q, { "", ' ', ',', true, true } },
|
|
|
|
{ u"NPR"_q, {} },
|
|
|
|
{ u"NZD"_q, { "NZ$" } },
|
|
|
|
{ u"PAB"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"PEN"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"PHP"_q, {} },
|
|
|
|
{ u"PKR"_q, {} },
|
|
|
|
{ u"PLN"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"PYG"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"QAR"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"RON"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"RSD"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"RUB"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"SAR"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"SEK"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"SGD"_q, {} },
|
|
|
|
{ u"THB"_q, { "\xE0\xB8\xBF" } },
|
|
|
|
{ u"TJS"_q, { "", ' ', ';', false, true } },
|
|
|
|
{ u"TRY"_q, { "", '.', ',', false, true } },
|
|
|
|
{ u"TTD"_q, {} },
|
|
|
|
{ u"TWD"_q, { "NT$" } },
|
|
|
|
{ u"TZS"_q, {} },
|
|
|
|
{ u"UAH"_q, { "", ' ', ',', false } },
|
|
|
|
{ u"UGX"_q, {} },
|
|
|
|
{ u"USD"_q, { "$" } },
|
|
|
|
{ u"UYU"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"UZS"_q, { "", ' ', ',', false, true } },
|
|
|
|
{ u"VND"_q, { "\xE2\x82\xAB", '.', ',', false, true } },
|
|
|
|
{ u"YER"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"ZAR"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"IRR"_q, { "", ',', '/', false, true } },
|
|
|
|
{ u"IQD"_q, { "", ',', '.', true, true } },
|
|
|
|
{ u"VEF"_q, { "", '.', ',', true, true } },
|
|
|
|
{ u"SYP"_q, { "", ',', '.', true, true } },
|
|
|
|
|
|
|
|
//{ u"VUV"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"WST"_q, {} },
|
|
|
|
//{ u"XAF"_q, { "FCFA", ',', '.', false } },
|
|
|
|
//{ u"XCD"_q, {} },
|
|
|
|
//{ u"XOF"_q, { "CFA", ' ', ',', false } },
|
|
|
|
//{ u"XPF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"ZMW"_q, {} },
|
|
|
|
//{ u"ANG"_q, {} },
|
|
|
|
//{ u"RWF"_q, { "", ' ', ',', true, true } },
|
|
|
|
//{ u"PGK"_q, {} },
|
|
|
|
//{ u"TOP"_q, {} },
|
|
|
|
//{ u"SBD"_q, {} },
|
|
|
|
//{ u"SCR"_q, {} },
|
|
|
|
//{ u"SHP"_q, {} },
|
|
|
|
//{ u"SLL"_q, {} },
|
|
|
|
//{ u"SOS"_q, {} },
|
|
|
|
//{ u"SRD"_q, {} },
|
|
|
|
//{ u"STD"_q, {} },
|
|
|
|
//{ u"SVC"_q, {} },
|
|
|
|
//{ u"SZL"_q, {} },
|
|
|
|
//{ u"AOA"_q, {} },
|
|
|
|
//{ u"AWG"_q, {} },
|
|
|
|
//{ u"BBD"_q, {} },
|
|
|
|
//{ u"BIF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"BMD"_q, {} },
|
|
|
|
//{ u"BSD"_q, {} },
|
|
|
|
//{ u"BWP"_q, {} },
|
|
|
|
//{ u"BZD"_q, {} },
|
|
|
|
//{ u"CDF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"CVE"_q, {} },
|
|
|
|
//{ u"DJF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"ETB"_q, {} },
|
|
|
|
//{ u"FJD"_q, {} },
|
|
|
|
//{ u"FKP"_q, {} },
|
|
|
|
//{ u"GIP"_q, {} },
|
|
|
|
//{ u"GMD"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"GNF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"GYD"_q, {} },
|
|
|
|
//{ u"HTG"_q, {} },
|
|
|
|
//{ u"KHR"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"KMF"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"KYD"_q, {} },
|
|
|
|
//{ u"LAK"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"LRD"_q, {} },
|
|
|
|
//{ u"LSL"_q, { "", ',', '.', false } },
|
|
|
|
//{ u"MGA"_q, {} },
|
|
|
|
//{ u"MKD"_q, { "", '.', ',', false, true } },
|
|
|
|
//{ u"MOP"_q, {} },
|
|
|
|
//{ u"MWK"_q, {} },
|
|
|
|
//{ u"NAD"_q, {} },
|
|
|
|
};
|
|
|
|
static const auto kRulesMap = [] {
|
|
|
|
// flat_multi_map_pair_type lacks some required constructors :(
|
|
|
|
auto &&pairs = kRules | ranges::views::transform([](auto &&pair) {
|
|
|
|
return base::flat_multi_map_pair_type<QString, Rule>(
|
|
|
|
pair.first,
|
|
|
|
pair.second);
|
|
|
|
});
|
|
|
|
return base::flat_map<QString, Rule>(begin(pairs), end(pairs));
|
|
|
|
}();
|
|
|
|
static const auto kDenominators = base::flat_map<QString, int>{
|
2020-09-30 11:32:02 +00:00
|
|
|
{ u"CLF"_q, 10000 },
|
|
|
|
{ u"BHD"_q, 1000 },
|
|
|
|
{ u"IQD"_q, 1000 },
|
|
|
|
{ u"JOD"_q, 1000 },
|
|
|
|
{ u"KWD"_q, 1000 },
|
|
|
|
{ u"LYD"_q, 1000 },
|
|
|
|
{ u"OMR"_q, 1000 },
|
|
|
|
{ u"TND"_q, 1000 },
|
|
|
|
{ u"BIF"_q, 1 },
|
|
|
|
{ u"BYR"_q, 1 },
|
|
|
|
{ u"CLP"_q, 1 },
|
|
|
|
{ u"CVE"_q, 1 },
|
|
|
|
{ u"DJF"_q, 1 },
|
|
|
|
{ u"GNF"_q, 1 },
|
|
|
|
{ u"ISK"_q, 1 },
|
|
|
|
{ u"JPY"_q, 1 },
|
|
|
|
{ u"KMF"_q, 1 },
|
|
|
|
{ u"KRW"_q, 1 },
|
|
|
|
{ u"MGA"_q, 1 },
|
|
|
|
{ u"PYG"_q, 1 },
|
|
|
|
{ u"RWF"_q, 1 },
|
|
|
|
{ u"UGX"_q, 1 },
|
|
|
|
{ u"UYI"_q, 1 },
|
|
|
|
{ u"VND"_q, 1 },
|
|
|
|
{ u"VUV"_q, 1 },
|
|
|
|
{ u"XAF"_q, 1 },
|
|
|
|
{ u"XOF"_q, 1 },
|
|
|
|
{ u"XPF"_q, 1 },
|
|
|
|
{ u"MRO"_q, 10 },
|
|
|
|
};
|
2021-03-30 14:49:41 +00:00
|
|
|
const auto denominatorIt = kDenominators.find(currency);
|
|
|
|
const auto denominator = (denominatorIt != end(kDenominators))
|
|
|
|
? denominatorIt->second
|
|
|
|
: 100;
|
|
|
|
const auto value = amount / float64(denominator);
|
|
|
|
const auto ruleIt = kRulesMap.find(currency);
|
|
|
|
if (ruleIt == end(kRulesMap)) {
|
|
|
|
return QLocale::system().toCurrencyString(value, currency);
|
|
|
|
}
|
|
|
|
const auto &rule = ruleIt->second;
|
|
|
|
const auto name = (*rule.international)
|
|
|
|
? QString::fromUtf8(rule.international)
|
|
|
|
: currency;
|
|
|
|
auto result = QString();
|
|
|
|
if (rule.left) {
|
|
|
|
result.append(name);
|
|
|
|
if (rule.space) result.append(' ');
|
|
|
|
}
|
|
|
|
result.append(
|
|
|
|
FormatWithSeparators(value, rule.decimal, rule.thousands));
|
|
|
|
if (!rule.left) {
|
|
|
|
if (rule.space) result.append(' ');
|
|
|
|
result.append(name);
|
|
|
|
}
|
|
|
|
return result;
|
2020-09-30 11:32:02 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:11:53 +00:00
|
|
|
QString ComposeNameString(
|
|
|
|
const QString &filename,
|
|
|
|
const QString &songTitle,
|
|
|
|
const QString &songPerformer) {
|
|
|
|
if (songTitle.isEmpty() && songPerformer.isEmpty()) {
|
|
|
|
return filename.isEmpty() ? u"Unknown File"_q : filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (songPerformer.isEmpty()) {
|
|
|
|
return songTitle;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto trackTitle = (songTitle.isEmpty() ? u"Unknown Track"_q : songTitle);
|
|
|
|
return songPerformer + QString::fromUtf8(" \xe2\x80\x93 ") + trackTitle;
|
|
|
|
}
|
|
|
|
|
2020-09-30 11:32:02 +00:00
|
|
|
} // namespace Ui
|