Skip to content

Commit 88d7177

Browse files
committed
I18N: Set C++ locale and format sizes according to the locale
Displaying a package size, an installation size, a download speed etc. formats decimal numbers to 1-digit precision after the decimal point (49.5 KiB). However, users expect the number to be formatted according their locale. E.g. in cs_CZ.UTF-8, it is "49,5 KiB". DNF5 formats these values with fmt::format() which utilizes C++ locale if "L" formatting option is used. C++ locale (std::locale::global()) and C locale (setlocale(), C++-wrapped as std::setlocale()) are two different things and DNF5 only has set the C locale up to now. This patch starts setting C++ locale, which also implicitly sets C locale. This patch also modifies libdnf5::cli::utils::units::format_size_aligned() to use the locale-dependent decimal seperator (available since fmt-8.0.0). I manually tested dnf5 and dnf5daemon-client and they work for me. Though there is a risk that the new C++ locale will affect some code uknown to me, like regular expression matching, or thread-specific locales. If the affected code was unfixable, we can resort to saving the desired C++ locale into a dedicated object accessible to format_size_aligned() and pass it explicitly for fmt::format. Thorough testing is welcome. Related: #1687
1 parent 3b64925 commit 88d7177

File tree

5 files changed

+24
-10
lines changed

5 files changed

+24
-10
lines changed

dnf5/main.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
7777
#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
7878
#include <libdnf5/utils/locker.hpp>
7979
#include <libdnf5/version.hpp>
80-
#include <locale.h>
80+
#include <locale>
8181
#include <string.h>
8282

8383
#include <algorithm>
@@ -940,11 +940,11 @@ static void print_new_leaves(Context & context) {
940940
}
941941

942942
static void set_locale() {
943-
auto * locale = setlocale(LC_ALL, "");
944-
if (locale) {
945-
return;
943+
try {
944+
std::locale::global(std::locale(""));
945+
} catch (std::runtime_error & ex) {
946+
std::cerr << "Failed to set locale, defaulting to \"C\"" << std::endl;
946947
}
947-
std::cerr << "Failed to set locale, defaulting to \"C\"" << std::endl;
948948
}
949949

950950
} // namespace dnf5

dnf5daemon-client/main.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
4242
#include <libdnf5/logger/stream_logger.hpp>
4343
#include <libdnf5/utils/bgettext/bgettext-lib.h>
4444
#include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
45-
#include <locale.h>
45+
#include <locale>
4646
#include <string.h>
4747

4848
#include <cstring>
@@ -220,7 +220,11 @@ static void add_commands(Context & context) {
220220
int main(int argc, char * argv[]) {
221221
std::unique_ptr<sdbus::IConnection> connection;
222222

223-
setlocale(LC_ALL, "");
223+
try {
224+
std::locale::global(std::locale(""));
225+
} catch (std::runtime_error & ext) {
226+
}
227+
224228

225229
dnfdaemon::client::Context context;
226230

libdnf5-cli/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ target_link_libraries(libdnf5-cli PRIVATE common)
4747
target_link_libraries(libdnf5-cli PUBLIC libdnf5)
4848

4949
pkg_check_modules(LIBFMT REQUIRED fmt)
50+
if (LIBFMT_VERSION VERSION_LESS 8.0.0)
51+
add_definitions(-DFMT_PRE_8)
52+
endif()
5053
list(APPEND LIBDNF5_CLI_PC_REQUIRES "${LIBFMT_MODULE_NAME}")
5154
target_link_libraries(libdnf5-cli PUBLIC ${LIBFMT_LIBRARIES})
5255

libdnf5-cli/utils/units.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ std::pair<float, const char *> to_size(int64_t num) {
5252

5353
std::string format_size_aligned(int64_t num) {
5454
auto [value, unit] = to_size(num);
55-
return fmt::format("{0:.1f} {1:>3s}", value, unit);
55+
return fmt::format(
56+
#ifdef FMT_PRE_8
57+
"{0:.1f} {1:>3s}",
58+
#else
59+
"{0:.1Lf} {1:>3s}",
60+
#endif
61+
value,
62+
unit);
5663
}
5764

5865

test/libdnf5-cli/utils/test_utf8.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
2222

2323
#include "utils/utf8.hpp"
2424

25-
#include <clocale>
25+
#include <locale>
2626

2727

2828
CPPUNIT_TEST_SUITE_REGISTRATION(UTF8Test);
2929

3030

3131
void UTF8Test::setUp() {
3232
// wide characters do not work at all until we set locales in the code
33-
setlocale(LC_ALL, "C.UTF-8");
33+
std::locale::global(std::locale("C.UTF-8"));
3434

3535
hello_world_en = "Hello world!";
3636
hello_world_cs = "Ahoj světe!";

0 commit comments

Comments
 (0)