aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk')
-rw-r--r--src/FbTk/I18n.cc165
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
66namespace { 67namespace {
67 68
68const nl_catd INVALID_CATALOG = ((nl_catd)(-1)); 69const char UTF8_SUFFIX[] = "-UTF-8.cat";
69nl_catd s_catalog_fd = INVALID_CATALOG; 70const size_t UTF8_SUFFIX_LEN = sizeof(UTF8_SUFFIX)-1; // without \0
71const char DEFAULT_CATFILE[] = "fluxbox.cat";
72const char ENV_CATFILE[] = "FLUXBOX_CATFILE";
73const char ENV_CATDIR[] = "FLUXBOX_CATDIR";
74
75const nl_catd INVALID_CATALOG = (nl_catd)(-1);
76nl_catd s_catalog_fd = INVALID_CATALOG;
77
78
79const 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
88std::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
74namespace FbTk { 101namespace 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/
76void I18n::init(const char* catalog) { 115void 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
127I18n::I18n():m_multibyte(false), m_utf8_translate(false) { 204I18n::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) {
162I18n::~I18n() { 238I18n::~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() {
178FbString I18n::getMessage(int set_number, int message_number, 254FbString 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