mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 10:28:32 +00:00
fix: use user-preferred locale (#5444)
* Use user-preferred locale Previous fix adding `L` format specifier was correct but only fixed half of the problem, as C++ locale is set up to be "C" by default. GTK client used to call `setlocale(LC_ALL, "")` to set up user-preferred locale which only affected C functions and `std::locale` (used by libfmt) was unaware of those changes. Apply the fix to all the binaries since they're all doing some sort of output to the user and calling libtransmission helpers, as well as using libfmt directly. * Improve libtransmission's json-test Set the locale C++ way to avoid any sort of inconsistencies, and also restore it to the old one once finished testing. * Improve transmission-show test runner script Quote outputs to avoid CMake error about `message()` being called with no arguments. Capture stderr to the same output file. Fallback to `git diff` if `diff` wasn't found. A few other minor changes.
This commit is contained in:
committed by
Charles Kerr
parent
02b8535aa1
commit
411b66cf88
@@ -197,6 +197,8 @@ static std::string getConfigDir(int argc, char const** argv)
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
tr_variant settings;
|
tr_variant settings;
|
||||||
|
|
||||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||||
|
|||||||
@@ -939,6 +939,8 @@ void tr_daemon::handle_error(tr_error* error) const
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
tr_daemon daemon;
|
tr_daemon daemon;
|
||||||
bool foreground;
|
bool foreground;
|
||||||
|
|||||||
@@ -27,10 +27,8 @@
|
|||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <clocale>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -53,7 +51,7 @@ Glib::OptionEntry create_option_entry(Glib::ustring const& long_name, gchar shor
|
|||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
/* init i18n */
|
/* init i18n */
|
||||||
std::ignore = std::setlocale(LC_ALL, "");
|
tr_locale_set_global("");
|
||||||
bindtextdomain(AppTranslationDomainName, TRANSMISSIONLOCALEDIR);
|
bindtextdomain(AppTranslationDomainName, TRANSMISSIONLOCALEDIR);
|
||||||
bind_textdomain_codeset(AppTranslationDomainName, "UTF-8");
|
bind_textdomain_codeset(AppTranslationDomainName, "UTF-8");
|
||||||
textdomain(AppTranslationDomainName);
|
textdomain(AppTranslationDomainName);
|
||||||
|
|||||||
@@ -14,11 +14,14 @@
|
|||||||
#include <cstdlib> // getenv()
|
#include <cstdlib> // getenv()
|
||||||
#include <cstring> /* strerror() */
|
#include <cstring> /* strerror() */
|
||||||
#include <ctime> // nanosleep()
|
#include <ctime> // nanosleep()
|
||||||
|
#include <iostream>
|
||||||
#include <iterator> // for std::back_inserter
|
#include <iterator> // for std::back_inserter
|
||||||
|
#include <locale>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -60,6 +63,23 @@ time_t libtransmission::detail::tr_time::current_time = {};
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
void tr_locale_set_global(char const* locale_name) noexcept
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ignore = std::locale::global(std::locale{ locale_name });
|
||||||
|
|
||||||
|
std::ignore = std::cout.imbue(std::locale{});
|
||||||
|
std::ignore = std::cerr.imbue(std::locale{});
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
bool tr_loadFile(std::string_view filename, std::vector<char>& contents, tr_error** error)
|
bool tr_loadFile(std::string_view filename, std::vector<char>& contents, tr_error** error)
|
||||||
{
|
{
|
||||||
auto const szfilename = tr_pathbuf{ filename };
|
auto const szfilename = tr_pathbuf{ filename };
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ struct tr_error;
|
|||||||
#define tr_ngettext(singular, plural, count) ((count) == 1 ? (singular) : (plural))
|
#define tr_ngettext(singular, plural, count) ((count) == 1 ? (singular) : (plural))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void tr_locale_set_global(char const* locale_name) noexcept;
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
[[nodiscard]] std::string_view tr_get_mime_type_for_filename(std::string_view filename);
|
[[nodiscard]] std::string_view tr_get_mime_type_for_filename(std::string_view filename);
|
||||||
|
|||||||
@@ -4,7 +4,13 @@
|
|||||||
|
|
||||||
@import AppKit;
|
@import AppKit;
|
||||||
|
|
||||||
|
#include <libtransmission/transmission.h>
|
||||||
|
|
||||||
|
#include <libtransmission/utils.h>
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
return NSApplicationMain(argc, (char const**)argv);
|
return NSApplicationMain(argc, (char const**)argv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -667,6 +667,8 @@ FaviconCache& Application::faviconCache()
|
|||||||
|
|
||||||
int tr_main(int argc, char** argv)
|
int tr_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
InteropHelper::initialize();
|
InteropHelper::initialize();
|
||||||
|
|
||||||
Application const app(argc, argv);
|
Application const app(argc, argv);
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
|
|
||||||
#define LIBTRANSMISSION_VARIANT_MODULE
|
#define LIBTRANSMISSION_VARIANT_MODULE
|
||||||
|
|
||||||
#include <clocale> // setlocale()
|
#include <locale>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include <libtransmission/transmission.h>
|
#include <libtransmission/transmission.h>
|
||||||
#include <libtransmission/variant.h>
|
#include <libtransmission/variant.h>
|
||||||
@@ -23,11 +25,26 @@ protected:
|
|||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
auto const* locale_str = GetParam();
|
auto const* locale_str = GetParam();
|
||||||
if (setlocale(LC_NUMERIC, locale_str) == nullptr)
|
try
|
||||||
|
{
|
||||||
|
old_locale_ = std::locale::global(std::locale{ {}, new std::numpunct_byname<char>{ locale_str } });
|
||||||
|
}
|
||||||
|
catch (std::runtime_error const&)
|
||||||
{
|
{
|
||||||
GTEST_SKIP();
|
GTEST_SKIP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
if (old_locale_)
|
||||||
|
{
|
||||||
|
std::ignore = std::locale::global(*old_locale_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<std::locale> old_locale_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(JSONTest, testElements)
|
TEST_P(JSONTest, testElements)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.14)
|
if(CMAKE_VERSION VERSION_LESS 3.14)
|
||||||
# --ignore-eol was introduced in CMake 3.14
|
# --ignore-eol was introduced in CMake 3.14
|
||||||
message(status "skipping transmission-show test; cmake version too old")
|
message(STATUS "skipping transmission-show test; cmake version too old")
|
||||||
else()
|
else()
|
||||||
get_filename_component(torrent_basename "${torrent_file}" NAME)
|
get_filename_component(torrent_basename "${torrent_file}" NAME)
|
||||||
set(output_file ${CMAKE_CURRENT_BINARY_DIR}/${torrent_basename}.out)
|
set(output_file ${CMAKE_CURRENT_BINARY_DIR}/${torrent_basename}.out)
|
||||||
@@ -23,7 +23,8 @@ else()
|
|||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${transmission_show} ${torrent_file}
|
COMMAND ${transmission_show} ${torrent_file}
|
||||||
OUTPUT_FILE ${output_file})
|
OUTPUT_FILE ${output_file}
|
||||||
|
ERROR_FILE ${output_file})
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol ${reference_file} ${output_file}
|
COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol ${reference_file} ${output_file}
|
||||||
@@ -31,23 +32,29 @@ else()
|
|||||||
|
|
||||||
if(STATUS AND NOT STATUS EQUAL 0)
|
if(STATUS AND NOT STATUS EQUAL 0)
|
||||||
file(READ ${reference_file} CONTENTS)
|
file(READ ${reference_file} CONTENTS)
|
||||||
message("EXPECTED CONTENTS (${reference_file}):")
|
message(STATUS "EXPECTED CONTENTS (${reference_file}):")
|
||||||
message(${CONTENTS})
|
message("${CONTENTS}")
|
||||||
|
|
||||||
file(READ ${output_file} CONTENTS)
|
file(READ ${output_file} CONTENTS)
|
||||||
message("RECEIVED CONTENTS (${output_file}):")
|
message(STATUS "RECEIVED CONTENTS (${output_file}):")
|
||||||
message(${CONTENTS})
|
message("${CONTENTS}")
|
||||||
|
|
||||||
find_program(DIFF_EXEC diff)
|
find_program(DIFF_EXEC diff)
|
||||||
|
if(NOT DIFF_EXEC)
|
||||||
|
find_program(GIT_EXEC git)
|
||||||
|
if(GIT_EXEC)
|
||||||
|
set(DIFF_EXEC "${GIT_EXEC}" diff --no-index)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
if(DIFF_EXEC)
|
if(DIFF_EXEC)
|
||||||
message("DIFF:")
|
message(STATUS "DIFF:")
|
||||||
execute_process(COMMAND ${DIFF_EXEC} -u ${output_file} ${reference_file})
|
execute_process(COMMAND ${DIFF_EXEC} --unified ${reference_file} ${output_file})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(REMOVE ${output_file})
|
file(REMOVE ${output_file})
|
||||||
message(FATAL_ERROR "failed: files '${reference_file}' and '${output_file}' do not match")
|
message(FATAL_ERROR "failed: files '${reference_file}' and '${output_file}' do not match")
|
||||||
else()
|
else()
|
||||||
file(REMOVE ${output_file})
|
file(REMOVE ${output_file})
|
||||||
message("passed")
|
message(STATUS "passed")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ std::string tr_getcwd()
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
tr_logSetLevel(TR_LOG_ERROR);
|
tr_logSetLevel(TR_LOG_ERROR);
|
||||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||||
tr_formatter_size_init(DiskK, DiskKStr, DiskMStr, DiskGStr, DiskTStr);
|
tr_formatter_size_init(DiskK, DiskKStr, DiskMStr, DiskGStr, DiskTStr);
|
||||||
|
|||||||
@@ -322,6 +322,8 @@ static bool setSource(tr_variant* metainfo, char const* source_value)
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
int changedCount = 0;
|
int changedCount = 0;
|
||||||
|
|
||||||
tr_logSetLevel(TR_LOG_ERROR);
|
tr_logSetLevel(TR_LOG_ERROR);
|
||||||
|
|||||||
@@ -3271,6 +3271,8 @@ static void getHostAndPortAndRpcUrl(int* argc, char** argv, std::string* host, i
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
auto config = Config{};
|
auto config = Config{};
|
||||||
auto port = DefaultPort;
|
auto port = DefaultPort;
|
||||||
auto host = std::string{};
|
auto host = std::string{};
|
||||||
|
|||||||
@@ -399,6 +399,8 @@ void doScrape(tr_torrent_metainfo const& metainfo)
|
|||||||
|
|
||||||
int tr_main(int argc, char* argv[])
|
int tr_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
tr_locale_set_global("");
|
||||||
|
|
||||||
tr_logSetQueueEnabled(false);
|
tr_logSetQueueEnabled(false);
|
||||||
tr_logSetLevel(TR_LOG_ERROR);
|
tr_logSetLevel(TR_LOG_ERROR);
|
||||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||||
|
|||||||
Reference in New Issue
Block a user