Merge branch 'bug/6036'
This commit is contained in:
commit
7d242f1ac4
6 changed files with 78 additions and 58 deletions
|
@ -26,6 +26,7 @@ set(GETTEXT_XGETTEXT_OPTIONS
|
|||
--keyword=vgettext
|
||||
--keyword=VGETTEXT
|
||||
--keyword=_n:1,2
|
||||
--keyword=N_n:1,2
|
||||
--keyword=sngettext:1,2
|
||||
--keyword=vngettext:1,2
|
||||
--keyword=VNGETTEXT:1,2
|
||||
|
|
|
@ -58,7 +58,7 @@ if "pot-update" in COMMAND_LINE_TARGETS:
|
|||
"""xgettext --force-po --default-domain=%s --directory=. --add-comments=TRANSLATORS: \
|
||||
--from-code=UTF-8 --sort-by-file \
|
||||
--keyword=_ --keyword=N_ --keyword=sgettext --keyword=vgettext --keyword=VGETTEXT \
|
||||
--keyword=_n:1,2 --keyword=sngettext:1,2 --keyword=vngettext:1,2 --keyword=VNGETTEXT:1,2 \
|
||||
--keyword=_n:1,2 --keyword=N_n:1,2 --keyword=sngettext:1,2 --keyword=vngettext:1,2 --keyword=VNGETTEXT:1,2 \
|
||||
--files-from=%s --copyright-holder='Wesnoth development team' --msgid-bugs-address=https://bugs.wesnoth.org/ \
|
||||
--output=$TARGET \
|
||||
; sed -i s/charset=CHARSET/charset=UTF-8/ $TARGET \
|
||||
|
|
|
@ -289,7 +289,7 @@ std::string format_disjunct_list(const t_string& empty, const std::vector<t_stri
|
|||
return VGETTEXT("disjunct end^$prefix, or $last", {{"prefix", prefix}, {"last", elems.back()}});
|
||||
}
|
||||
|
||||
std::string format_timespan(std::time_t time)
|
||||
std::string format_timespan(std::time_t time, bool detailed)
|
||||
{
|
||||
if(time <= 0) {
|
||||
return _("timespan^expired");
|
||||
|
@ -298,26 +298,37 @@ std::string format_timespan(std::time_t time)
|
|||
typedef std::tuple<std::time_t, const char*, const char*> time_factor;
|
||||
|
||||
static const std::vector<time_factor> TIME_FACTORS{
|
||||
time_factor{ 31104000, N_("timespan^$num year"), N_("timespan^$num years") }, // 12 months
|
||||
time_factor{ 2592000, N_("timespan^$num month"), N_("timespan^$num months") }, // 30 days
|
||||
time_factor{ 604800, N_("timespan^$num week"), N_("timespan^$num weeks") },
|
||||
time_factor{ 86400, N_("timespan^$num day"), N_("timespan^$num days") },
|
||||
time_factor{ 3600, N_("timespan^$num hour"), N_("timespan^$num hours") },
|
||||
time_factor{ 60, N_("timespan^$num minute"), N_("timespan^$num minutes") },
|
||||
time_factor{ 1, N_("timespan^$num second"), N_("timespan^$num seconds") },
|
||||
// TRANSLATORS: The "timespan^$num xxxxx" strings originating from the same file
|
||||
// as the string with this comment MUST be translated following the usual rules
|
||||
// for WML variable interpolation -- that is, without including or translating
|
||||
// the caret^ prefix, and leaving the $num variable specification intact, since
|
||||
// it is technically code. The only translatable natural word to be found here
|
||||
// is the time unit (year, month, etc.) For example, for French you would
|
||||
// translate "timespan^$num years" as "$num ans", thus allowing the game UI to
|
||||
// generate output such as "39 ans" after variable interpolation.
|
||||
time_factor{ 31104000, N_n("timespan^$num year", "timespan^$num years") }, // 12 months
|
||||
time_factor{ 2592000, N_n("timespan^$num month", "timespan^$num months") }, // 30 days
|
||||
time_factor{ 604800, N_n("timespan^$num week", "timespan^$num weeks") },
|
||||
time_factor{ 86400, N_n("timespan^$num day", "timespan^$num days") },
|
||||
time_factor{ 3600, N_n("timespan^$num hour", "timespan^$num hours") },
|
||||
time_factor{ 60, N_n("timespan^$num minute", "timespan^$num minutes") },
|
||||
time_factor{ 1, N_n("timespan^$num second", "timespan^$num seconds") },
|
||||
};
|
||||
|
||||
std::vector<t_string> display_text;
|
||||
string_map i18n;
|
||||
|
||||
for(const auto& factor : TIME_FACTORS) {
|
||||
const int amount = time / std::get<0>(factor);
|
||||
const auto [ secs, fmt_singular, fmt_plural ] = factor;
|
||||
const int amount = time / secs;
|
||||
|
||||
if(amount) {
|
||||
time -= std::get<0>(factor) * amount;
|
||||
time -= secs * amount;
|
||||
i18n["num"] = std::to_string(amount);
|
||||
const auto fmt = amount == 1 ? std::get<1>(factor) : std::get<2>(factor);
|
||||
display_text.emplace_back(VGETTEXT(fmt, i18n));
|
||||
display_text.emplace_back(VNGETTEXT(fmt_singular, fmt_plural, amount, i18n));
|
||||
if(!detailed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,12 +78,26 @@ std::string format_conjunct_list(const t_string& empty, const std::vector<t_stri
|
|||
std::string format_disjunct_list(const t_string& empty, const std::vector<t_string>& elems);
|
||||
|
||||
/**
|
||||
* Formats a timespan into human-readable text.
|
||||
* @param time The timespan in seconds.
|
||||
* @return A string such as "6 days, 12 hours, 4 minutes, 13 seconds". Years,
|
||||
* months and weeks are also considered.
|
||||
* Formats a timespan into human-readable text for player authentication functions.
|
||||
*
|
||||
* This is intentionally not a very thorough representation of time intervals.
|
||||
* See <https://github.com/wesnoth/wesnoth/issues/6036> for more information.
|
||||
*
|
||||
* @param time The timespan in seconds.
|
||||
* @param detailed Whether to display more specific values such as "3 months, 2 days,
|
||||
* 30 minutes, and 1 second". If not specified or set to @a false, the
|
||||
* return value will ONLY include most significant time unit (e.g. "3
|
||||
* months").
|
||||
* @return A human-readable timespan description.
|
||||
*
|
||||
* @note The implementation is not very precise because not all months in the Gregorian
|
||||
* calendar have 30 days. Furthermore, it doesn't take into account leap years or
|
||||
* leap seconds. If you need to account for those, you are better off importing
|
||||
* a new library and providing it with more specific information about the start and
|
||||
* end times of the interval; otherwise your next best option is to hire a fortune
|
||||
* teller to manually service your requests every time instead of this function.
|
||||
*/
|
||||
std::string format_timespan(std::time_t time);
|
||||
std::string format_timespan(std::time_t time, bool detailed = false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,3 +99,4 @@ namespace translation
|
|||
|
||||
#define gettext_noop(String) String
|
||||
#define N_(String) gettext_noop (String)
|
||||
#define N_n(String1, String2) String1, String2
|
||||
|
|
|
@ -82,72 +82,65 @@ inline std::string gen_as_str(const time_detailed& params)
|
|||
return utils::format_conjunct_list("expired", bits);
|
||||
}
|
||||
|
||||
inline void test_format_timespan(const time_detailed& tcase, const std::string& detailed, const std::string& fuzzy="")
|
||||
{
|
||||
BOOST_CHECK_EQUAL(detailed, utils::format_timespan(gen_as_time_t(tcase), true));
|
||||
|
||||
if(!fuzzy.empty()) {
|
||||
BOOST_REQUIRE_NE(detailed, fuzzy); // ensure test case params are not borked
|
||||
BOOST_CHECK_EQUAL(fuzzy, utils::format_timespan(gen_as_time_t(tcase)));
|
||||
BOOST_CHECK_NE(utils::format_timespan(gen_as_time_t(tcase)), utils::format_timespan(gen_as_time_t(tcase), true));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_formula_timespan )
|
||||
{
|
||||
time_detailed t;
|
||||
test_format_timespan({ 1, 0, 0, 0, 0, 0, 0 }, "1 second");
|
||||
|
||||
t = time_detailed{ 1, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 second", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 2, 0, 0, 0, 0, 0, 0 }, "2 seconds");
|
||||
|
||||
t = time_detailed{ 2, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 1, 0, 0, 0, 0, 0 }, "1 minute");
|
||||
|
||||
t = time_detailed{ 0, 1, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 minute", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 2, 0, 0, 0, 0, 0 }, "2 minutes");
|
||||
|
||||
t = time_detailed{ 0, 2, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 minutes", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 1, 0, 0, 0, 0 }, "1 hour");
|
||||
|
||||
t = time_detailed{ 0, 0, 1, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 hour", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 2, 0, 0, 0, 0 }, "2 hours");
|
||||
|
||||
t = time_detailed{ 0, 0, 2, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 hours", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 1, 0, 0, 0 }, "1 day");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 1, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 day", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 2, 0, 0, 0 }, "2 days");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 2, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 days", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 1, 0, 0 }, "1 week");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 1, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 week", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 2, 0, 0 }, "2 weeks");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 2, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 weeks", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 0, 1, 0 }, "1 month");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 0, 1, 0 };
|
||||
BOOST_CHECK_EQUAL("1 month", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 0, 2, 0 }, "2 months");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 0, 2, 0 };
|
||||
BOOST_CHECK_EQUAL("2 months", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 0, 0, 1 }, "1 year");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 0, 0, 1 };
|
||||
BOOST_CHECK_EQUAL("1 year", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 0, 0, 0, 0, 2 }, "2 years");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 0, 0, 2 };
|
||||
BOOST_CHECK_EQUAL("2 years", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = time_detailed{ 12, 1, 23, 3, 2, 5, 2 };
|
||||
BOOST_CHECK_EQUAL(gen_as_str(t), utils::format_timespan(gen_as_time_t(t)));
|
||||
auto t = time_detailed{ 12, 1, 23, 3, 2, 5, 2 };
|
||||
test_format_timespan(t, gen_as_str(t), "2 years");
|
||||
|
||||
t = time_detailed{ 0, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t)), utils::format_timespan(0));
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t), true), utils::format_timespan(0));
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t)), utils::format_timespan(-10000));
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t), true), utils::format_timespan(-10000));
|
||||
|
||||
t = time_detailed{ 4, 0, 49, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 days, 1 hour, and 4 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 4, 0, 49, 0, 0, 0, 0 }, "2 days, 1 hour, and 4 seconds", "2 days");
|
||||
|
||||
t = time_detailed{ 0, 40, 0, 11, 1, 0, 4 };
|
||||
BOOST_CHECK_EQUAL("4 years, 2 weeks, 4 days, and 40 minutes", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 40, 0, 11, 1, 0, 4 }, "4 years, 2 weeks, 4 days, and 40 minutes", "4 years");
|
||||
|
||||
t = time_detailed{ 0, 0, 1, 0, 0, 3, 4 };
|
||||
BOOST_CHECK_EQUAL("4 years, 3 months, and 1 hour", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 0, 0, 1, 0, 0, 3, 4 }, "4 years, 3 months, and 1 hour", "4 years");
|
||||
|
||||
t = time_detailed{ 10, 0, 0, 0, 0, 2, 0 };
|
||||
BOOST_CHECK_EQUAL("2 months and 10 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
test_format_timespan({ 10, 0, 0, 0, 0, 2, 0 }, "2 months and 10 seconds", "2 months");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Add table
Reference in a new issue