Blender V4.3
boost_locale_wrapper.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <boost/locale.hpp>
10#include <iostream>
11#include <stdio.h>
12
14
15static std::string messages_path;
16static std::string default_domain;
17static std::string locale_str;
18
19/* NOTE: We cannot use short stuff like `boost::locale::gettext`, because those return
20 * `std::basic_string` objects, which c_ptr()-returned char* is no more valid
21 * once deleted (which happens as soons they are out of scope of this func). */
22typedef boost::locale::message_format<char> char_message_facet;
23static std::locale locale_global;
25
27{
28 /* Cache facet in global variable. Not only is it better for performance,
29 * it also fixes crashes on macOS when doing translation from threads other
30 * than main. Likely because of some internal thread local variables. */
31 try {
32 /* facet_global reference is valid as long as local_global exists,
33 * so we store both. */
34 locale_global = std::locale();
35 facet_global = &std::use_facet<char_message_facet>(locale_global);
36 }
37 /* `if std::has_facet<char_message_facet>(l) == false`, LC_ALL = "C" case. */
38 catch (const std::bad_cast &e) {
39#ifndef NDEBUG
40 std::cout << "bl_locale_global_cache:" << e.what() << " \n";
41#endif
42 (void)e;
44 }
45 catch (const std::exception &e) {
46#ifndef NDEBUG
47 std::cout << "bl_locale_global_cache:" << e.what() << " \n";
48#endif
49 (void)e;
51 }
52}
53
54void bl_locale_init(const char *_messages_path, const char *_default_domain)
55{
56 /* Avoid using ICU backend, we do not need its power and it's rather heavy! */
57 boost::locale::localization_backend_manager lman =
58 boost::locale::localization_backend_manager::global();
59#if defined(_WIN32)
60 lman.select("winapi");
61#else
62 lman.select("posix");
63#endif
64 boost::locale::localization_backend_manager::global(lman);
65
66 messages_path = _messages_path;
67 default_domain = _default_domain;
68}
69
70void bl_locale_set(const char *locale)
71{
72 boost::locale::generator gen;
73 std::locale _locale;
74 /* Specify location of dictionaries. */
75 gen.add_messages_path(messages_path);
76 gen.add_messages_domain(default_domain);
77 // gen.set_default_messages_domain(default_domain);
78
79 try {
80 if (locale && locale[0]) {
81 _locale = gen(locale);
82 }
83 else {
84#if defined(__APPLE__) && !defined(WITH_HEADLESS) && !defined(WITH_GHOST_SDL)
85 std::string locale_osx = osx_user_locale() + std::string(".UTF-8");
86 _locale = gen(locale_osx.c_str());
87#else
88 _locale = gen("");
89#endif
90 }
91 std::locale::global(_locale);
92 /* NOTE: boost always uses "C" LC_NUMERIC by default! */
93
95
96 /* Generate the locale string
97 * (useful to know which locale we are actually using in case of "default" one). */
98#define LOCALE_INFO std::use_facet<boost::locale::info>(_locale)
99
100 locale_str = LOCALE_INFO.language();
101 if (LOCALE_INFO.country() != "") {
102 locale_str += "_" + LOCALE_INFO.country();
103 }
104 if (LOCALE_INFO.variant() != "") {
105 locale_str += "@" + LOCALE_INFO.variant();
106 }
107
108#undef LOCALE_INFO
109 }
110 /* Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions
111 * like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are
112 * not caught by their ancestor `std::exception`. See #88877#1177108 */
113 catch (std::runtime_error const &e) {
114 std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
115 }
116 catch (std::exception const &e) {
117 std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
118 }
119}
120
121const char *bl_locale_get(void)
122{
123 return locale_str.c_str();
124}
125
126const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
127{
128 if (facet_global) {
129 char const *r = facet_global->get(0, msgctxt, msgid);
130 if (r) {
131 return r;
132 }
133 }
134
135 return msgid;
136}
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static std::locale locale_global
static void bl_locale_global_cache()
static std::string messages_path
const char * bl_locale_get(void)
const char * bl_locale_pgettext(const char *msgctxt, const char *msgid)
static std::string locale_str
void bl_locale_set(const char *locale)
static char_message_facet const * facet_global
boost::locale::message_format< char > char_message_facet
void bl_locale_init(const char *_messages_path, const char *_default_domain)
static std::string default_domain
#define LOCALE_INFO
#define NULL
const char * osx_user_locale()