diff options
Diffstat (limited to 'src/FbTk')
-rw-r--r-- | src/FbTk/I18n.cc | 165 |
1 files changed, 121 insertions, 44 deletions
diff --git a/src/FbTk/I18n.cc b/src/FbTk/I18n.cc index f53e5ed..18eb67c 100644 --- a/src/FbTk/I18n.cc +++ b/src/FbTk/I18n.cc | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | #include <cstdlib> | 38 | #include <cstdlib> |
39 | #include <cstring> | 39 | #include <cstring> |
40 | #include <cstdarg> | ||
40 | #include <iostream> | 41 | #include <iostream> |
41 | 42 | ||
42 | #ifdef HAVE_LOCALE_H | 43 | #ifdef HAVE_LOCALE_H |
@@ -65,15 +66,54 @@ using std::string; | |||
65 | 66 | ||
66 | namespace { | 67 | namespace { |
67 | 68 | ||
68 | const nl_catd INVALID_CATALOG = ((nl_catd)(-1)); | 69 | const char UTF8_SUFFIX[] = "-UTF-8.cat"; |
69 | nl_catd s_catalog_fd = INVALID_CATALOG; | 70 | const size_t UTF8_SUFFIX_LEN = sizeof(UTF8_SUFFIX)-1; // without \0 |
71 | const char DEFAULT_CATFILE[] = "fluxbox.cat"; | ||
72 | const char ENV_CATFILE[] = "FLUXBOX_CATFILE"; | ||
73 | const char ENV_CATDIR[] = "FLUXBOX_CATDIR"; | ||
74 | |||
75 | const nl_catd INVALID_CATALOG = (nl_catd)(-1); | ||
76 | nl_catd s_catalog_fd = INVALID_CATALOG; | ||
77 | |||
78 | |||
79 | const char* getCatalogDir() { | ||
80 | const char* cat_dir = getenv(ENV_CATDIR); | ||
81 | if (cat_dir) { | ||
82 | return cat_dir; | ||
83 | } | ||
84 | return LOCALEPATH; | ||
85 | } | ||
86 | |||
87 | |||
88 | std::string join_str(size_t n, ...) { | ||
89 | std::string s; | ||
90 | va_list args; | ||
91 | va_start(args, n); | ||
92 | for (; n > 0; n--) { | ||
93 | s.append(va_arg(args, const char*)); | ||
94 | } | ||
95 | return s; | ||
96 | } | ||
70 | 97 | ||
71 | } | 98 | } |
72 | 99 | ||
73 | 100 | ||
74 | namespace FbTk { | 101 | namespace FbTk { |
75 | 102 | ||
103 | |||
104 | // initialize the i18n-system be opening the catalog-file | ||
105 | // named by 'catalog'. per default we expect 'catalog' to | ||
106 | // be 0/NULL, the code picks a sane default then: | ||
107 | // | ||
108 | // - environment variable FLUXBOX_CATFILE is set? use it | ||
109 | // - DEFAULT_CATFILE ("fluxbox.cat") | ||
110 | // - the utf8 encoded translation for the current locale | ||
111 | // | ||
112 | // handling things this was allows us to test catalog files | ||
113 | // without putting them into the install path | ||
114 | // $PREFIX/share/fluxbox/nls/XYZ/ | ||
76 | void I18n::init(const char* catalog) { | 115 | void I18n::init(const char* catalog) { |
116 | |||
77 | static bool init = false; | 117 | static bool init = false; |
78 | if (init) { | 118 | if (init) { |
79 | return; | 119 | return; |
@@ -81,50 +121,87 @@ void I18n::init(const char* catalog) { | |||
81 | 121 | ||
82 | #if defined(NLS) && defined(HAVE_CATOPEN) | 122 | #if defined(NLS) && defined(HAVE_CATOPEN) |
83 | 123 | ||
124 | if (!catalog) { | ||
125 | const char* c = getenv(ENV_CATFILE); | ||
126 | if (!c) { | ||
127 | c = DEFAULT_CATFILE; | ||
128 | } | ||
129 | catalog = c; | ||
130 | } | ||
131 | |||
84 | FbStringUtil::init(); | 132 | FbStringUtil::init(); |
85 | 133 | ||
134 | int flag; | ||
135 | |||
86 | I18n& i18n = I18n::instance(); | 136 | I18n& i18n = I18n::instance(); |
137 | const string dir = getCatalogDir(); | ||
138 | const string locale = i18n.m_locale; | ||
139 | string clean_locale = locale; | ||
140 | size_t i; | ||
87 | 141 | ||
88 | string filename = LOCALEPATH; | 142 | // clean the locale, we have to append something later on |
89 | filename += '/'; | 143 | i = clean_locale.find('.'); |
90 | filename += i18n.m_locale; | 144 | if (i != string::npos) |
91 | filename += '/'; | 145 | clean_locale.erase(i); |
92 | filename += catalog; | ||
93 | 146 | ||
94 | if (!FileUtil::isRegularFile(filename.c_str()) && i18n.m_locale != "C" && FbStringUtil::haveUTF8()) { | 147 | #ifdef MCLoadBySet |
95 | // try the UTF-8 catalog, this also picks up situations where | 148 | flag = MCLoadBySet; |
96 | // the codeset somehow isn't specified | 149 | #else |
150 | flag = NL_CAT_LOCALE; | ||
151 | #endif | ||
97 | 152 | ||
98 | // remove everything after @ | 153 | struct { std::string catalog; std::string locale; bool utf8; } _catalog[] = { |
99 | string::size_type index = i18n.m_locale.find('.'); | ||
100 | // erase all characters starting at index | ||
101 | if (index != string::npos) | ||
102 | i18n.m_locale.erase(index); | ||
103 | 154 | ||
104 | i18n.m_locale.append(".UTF-8"); | 155 | // first try pure 'catalog'. catopen() will use NLSPATH if it's |
105 | i18n.m_utf8_translate = true; | 156 | // set and replaces '%N' by 'catalog'. eg: with catalog="fluxbox.cat" |
157 | // "/usr/share/fluxbox/nls/C/%N" becomes "/usr/share/fluxbox/nls/C/fluxbox.cat" | ||
158 | { string(catalog), locale, false }, | ||
106 | 159 | ||
107 | filename = LOCALEPATH; | 160 | // try full-path to 'catalog' |
108 | filename += '/'; | 161 | { join_str(5, dir.c_str(), "/", locale.c_str(), "/", catalog), locale, false }, |
109 | filename += i18n.m_locale; | ||
110 | filename += '/'; | ||
111 | filename += catalog; | ||
112 | } | ||
113 | 162 | ||
114 | #ifdef MCLoadBySet | 163 | // try the UTF-8 catalog, this also picks up situations where |
115 | s_catalog_fd = catopen(filename.c_str(), MCLoadBySet); | 164 | // the codeset somehow isn't specified |
116 | #else // !MCLoadBySet | 165 | { join_str(5, dir.c_str(), "/", clean_locale.c_str(), ".UTF-8/", catalog), |
117 | s_catalog_fd = catopen(filename.c_str(), NL_CAT_LOCALE); | 166 | join_str(2, clean_locale.c_str(), ".UTF8"), true}, |
118 | #endif // MCLoadBySet | 167 | |
168 | }; | ||
169 | |||
170 | for (i = 0; i < sizeof(_catalog)/sizeof(_catalog[0]); i++) { | ||
171 | |||
172 | if (_catalog[i].utf8 && locale == "C") { | ||
173 | continue; | ||
174 | } | ||
175 | |||
176 | const char* fname = _catalog[i].catalog.c_str(); | ||
177 | |||
178 | s_catalog_fd = catopen(fname, flag); | ||
179 | if (s_catalog_fd == INVALID_CATALOG) { | ||
180 | continue; | ||
181 | } | ||
182 | |||
183 | i18n.m_locale = _catalog[i].locale; | ||
184 | if (FbStringUtil::haveUTF8()) { | ||
185 | if (_catalog[i].utf8) { | ||
186 | i18n.m_utf8_translate = true; | ||
187 | } else { | ||
188 | size_t n = _catalog[i].catalog.rfind(UTF8_SUFFIX); | ||
189 | if (n != std::string::npos && (n + UTF8_SUFFIX_LEN) == _catalog[i].catalog.size()) { | ||
190 | i18n.m_utf8_translate = true; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | break; | ||
195 | } | ||
119 | 196 | ||
120 | if (s_catalog_fd == INVALID_CATALOG) { | 197 | if (s_catalog_fd == INVALID_CATALOG) { |
121 | cerr<<"Warning: Failed to open file("<<filename<<")"<<endl | 198 | cerr<<"Warning: Failed to open file("<< catalog <<")"<<endl |
122 | <<"for translation, using default messages."<<endl; | 199 | <<"for translation, using default messages."<<endl; |
123 | } | 200 | } |
124 | #endif // HAVE_CATOPEN | 201 | #endif // HAVE_CATOPEN |
125 | } | 202 | } |
126 | 203 | ||
127 | I18n::I18n():m_multibyte(false), m_utf8_translate(false) { | 204 | I18n::I18n() : m_multibyte(false), m_utf8_translate(false) { |
128 | #if defined(HAVE_SETLOCALE) && defined(NLS) | 205 | #if defined(HAVE_SETLOCALE) && defined(NLS) |
129 | //make sure we don't get 0 to m_locale string | 206 | //make sure we don't get 0 to m_locale string |
130 | char *temp = setlocale(LC_MESSAGES, ""); | 207 | char *temp = setlocale(LC_MESSAGES, ""); |
@@ -146,14 +223,13 @@ I18n::I18n():m_multibyte(false), m_utf8_translate(false) { | |||
146 | 223 | ||
147 | // truncate any encoding off the end of the locale | 224 | // truncate any encoding off the end of the locale |
148 | 225 | ||
149 | // remove everything after @ | ||
150 | string::size_type index = m_locale.find('@'); | 226 | string::size_type index = m_locale.find('@'); |
151 | if (index != string::npos) | 227 | if (index != string::npos) |
152 | m_locale.erase(index); //erase all characters starting at index | 228 | m_locale.erase(index); |
153 | // remove everything before = | 229 | |
154 | index = m_locale.find('='); | 230 | index = m_locale.find('='); |
155 | if (index != string::npos) | 231 | if (index != string::npos) |
156 | m_locale.erase(0,index+1); //erase all characters starting up to index | 232 | m_locale.erase(0, index+1); |
157 | } | 233 | } |
158 | #endif // defined(HAVE_SETLOCALE) && defined(NLS) | 234 | #endif // defined(HAVE_SETLOCALE) && defined(NLS) |
159 | } | 235 | } |
@@ -162,7 +238,7 @@ I18n::I18n():m_multibyte(false), m_utf8_translate(false) { | |||
162 | I18n::~I18n() { | 238 | I18n::~I18n() { |
163 | 239 | ||
164 | #if defined(NLS) && defined(HAVE_CATCLOSE) | 240 | #if defined(NLS) && defined(HAVE_CATCLOSE) |
165 | if (s_catalog_fd != (nl_catd)-1) | 241 | if (s_catalog_fd != INVALID_CATALOG) |
166 | catclose(s_catalog_fd); | 242 | catclose(s_catalog_fd); |
167 | #endif // HAVE_CATCLOSE | 243 | #endif // HAVE_CATCLOSE |
168 | } | 244 | } |
@@ -178,27 +254,28 @@ I18n& I18n::instance() { | |||
178 | FbString I18n::getMessage(int set_number, int message_number, | 254 | FbString I18n::getMessage(int set_number, int message_number, |
179 | const char *default_message, bool translate_fb) const { | 255 | const char *default_message, bool translate_fb) const { |
180 | 256 | ||
257 | FbString msg(default_message); | ||
258 | |||
181 | #if defined(NLS) && defined(HAVE_CATGETS) | 259 | #if defined(NLS) && defined(HAVE_CATGETS) |
182 | if (s_catalog_fd != INVALID_CATALOG) { | 260 | if (s_catalog_fd != INVALID_CATALOG) { |
183 | const char *ret = catgets(s_catalog_fd, set_number, message_number, default_message); | 261 | const char *ret = catgets(s_catalog_fd, set_number, message_number, default_message); |
184 | // can't translate, leave it in raw ascii (utf-8 compatible) | ||
185 | if (ret == default_message || ret == NULL) | ||
186 | return default_message; | ||
187 | 262 | ||
188 | if (!m_utf8_translate && translate_fb) | 263 | if (ret == default_message || ret == NULL) { |
264 | // can't translate, leave it in raw ascii (utf-8 compatible) | ||
265 | } else if (!m_utf8_translate && translate_fb) | ||
189 | // Local input, UTF-8 output | 266 | // Local input, UTF-8 output |
190 | return FbStringUtil::LocaleStrToFb(ret); | 267 | msg = FbStringUtil::LocaleStrToFb(ret); |
191 | else if (m_utf8_translate && !translate_fb) | 268 | else if (m_utf8_translate && !translate_fb) |
192 | // UTF-8 input, local output | 269 | // UTF-8 input, local output |
193 | return FbStringUtil::FbStrToLocale(ret); | 270 | msg = FbStringUtil::FbStrToLocale(ret); |
194 | else | 271 | else |
195 | // UTF-8 input, UTF-8 output OR | 272 | // UTF-8 input, UTF-8 output OR |
196 | // local input, local output | 273 | // local input, local output |
197 | return ret; | 274 | msg = ret; |
198 | } | 275 | } |
199 | else | 276 | |
200 | #endif // NLS && HAVE_CATGETS | 277 | #endif // NLS && HAVE_CATGETS |
201 | return default_message; | 278 | return msg; |
202 | } | 279 | } |
203 | 280 | ||
204 | } // end namespace FbTk | 281 | } // end namespace FbTk |