int translation_c::look_up_translation(const std::string &locale) { try { auto hits = std::vector< std::pair<int, int> >{}; auto full = locale_string_c(locale).str(locale_string_c::full); auto half = locale_string_c(locale).str(locale_string_c::half); for (auto beg = ms_available_translations.begin(), itr = ms_available_translations.begin(), end = ms_available_translations.end(); itr != end; ++itr) { auto score = itr->matches(full) ? 2 : itr->matches(half) ? 1 : 0; if (score) hits.emplace_back(std::make_pair(score, static_cast<int>(std::distance(beg, itr)))); } if (!hits.empty()) { brng::sort(hits); return hits.back().second; } } catch (mtx::locale_string_format_x &) { } return -1; }
int translation_c::look_up_translation(const std::string &locale) { try { std::string locale_country_lang = locale_string_c(locale).str(locale_string_c::half); std::vector<translation_c>::iterator i = ms_available_translations.begin(); int idx = 0; while (i != ms_available_translations.end()) { if ( ba::iequals(locale_country_lang, i->get_locale()) #if defined(SYS_WINDOWS) || ba::iequals(locale_country_lang, i->m_windows_locale_sysname) #endif ) return idx; ++i; ++idx; } } catch (mtx::locale_string_format_x &) { } return -1; }
void init_locales(std::string locale) { auto debug = debugging_c::requested("locale"); translation_c::initialize_available_translations(); mxdebug_if(debug, boost::format("[init_locales start: locale %1%]\n") % locale); std::string locale_dir; std::string default_locale = translation_c::get_default_ui_locale(); if (-1 == translation_c::look_up_translation(locale)) { mxdebug_if(debug, boost::format("[init_locales lookup failed; clearing locale]\n")); locale = ""; } if (locale.empty()) { locale = default_locale; mxdebug_if(debug, boost::format("[init_locales setting to default locale %1%]\n") % locale); } # if defined(SYS_WINDOWS) mtx::sys::set_environment_variable("LANGUAGE", ""); if (!locale.empty()) { // The Windows system headers define LC_MESSAGES but // Windows itself doesn't know it and treats "set_locale(LC_MESSAGES, ...)" // as an error. gettext uses the LANG and LC_MESSAGE environment variables instead. // Windows knows two environments: the system environment that's // modified by SetEnvironmentVariable() and the C library's cache // of said environment which is modified via _putenv(). mtx::sys::set_environment_variable("LANG", locale); mtx::sys::set_environment_variable("LC_MESSAGES", locale); translation_c::set_active_translation(locale); } // Boost's path class uses wide chars on Windows for path // names. Tell that all narrow strings are encoded in UTF-8. std::locale utf8_locale(std::locale(), new mtx::utf8_codecvt_facet); std::locale::global(utf8_locale); boost::filesystem::path::imbue(utf8_locale); locale_dir = g_cc_local_utf8->native((mtx::sys::get_installation_path() / "locale").string()); # else // SYS_WINDOWS std::string chosen_locale; try { locale_string_c loc_default(default_locale); std::string loc_req_with_default_codeset(locale_string_c(locale).set_codeset_and_modifier(loc_default).str()); mxdebug_if(debug, boost::format("[init_locales loc_default is %1%; trying locale %3% followed by loc_req_with_default_codeset %2%]\n") % loc_default.str() % loc_req_with_default_codeset % locale); if (setlocale(LC_MESSAGES, locale.c_str())) chosen_locale = locale; else if (setlocale(LC_MESSAGES, loc_req_with_default_codeset.c_str())) chosen_locale = loc_req_with_default_codeset; else { std::string loc_req_with_utf8 = locale_string_c(locale).set_codeset_and_modifier(locale_string_c("dummy.UTF-8")).str(); mxdebug_if(debug, boost::format("[init_locales both failed; also trying %1%]\n") % loc_req_with_utf8); if (setlocale(LC_MESSAGES, loc_req_with_utf8.c_str())) chosen_locale = loc_req_with_utf8; } } catch (mtx::locale_string_format_x &error) { mxdebug_if(debug, boost::format("[init_locales format error in %1%]\n") % error.error()); } mxdebug_if(debug, boost::format("[init_locales chosen locale %1%]\n") % chosen_locale); // Hard fallback to "C" locale if no suitable locale was // selected. This can happen if the system has no locales for // "en_US" or "en_US.UTF-8" compiled. if (chosen_locale.empty() && setlocale(LC_MESSAGES, "C")) chosen_locale = "C"; if (chosen_locale.empty()) mxerror(Y("The locale could not be set properly. Check the LANG, LC_ALL and LC_MESSAGES environment variables.\n")); std::locale utf8_locale(std::locale(), new mtx::utf8_codecvt_facet); std::locale::global(utf8_locale); translation_c::set_active_translation(chosen_locale); locale_dir = MTX_LOCALE_DIR; # endif // SYS_WINDOWS # if defined(SYS_APPLE) int result = setenv("LC_MESSAGES", chosen_locale.c_str(), 1); mxdebug_if(debug, boost::format("[init_locales setenv() return code: %1%]\n") % result); # endif bindtextdomain("mkvtoolnix", locale_dir.c_str()); textdomain("mkvtoolnix"); bind_textdomain_codeset("mkvtoolnix", "UTF-8"); }