aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Gumz <akira@fluxbox.org>2015-01-31 20:37:44 (GMT)
committerMathias Gumz <akira@fluxbox.org>2015-01-31 20:37:44 (GMT)
commitfff0abad765714d967614cfa871e37efca956194 (patch)
treeb4ee31f5611dcf0ffbef0b1ccc950d9f07e4d83e
parent57f21b64ca27cf29212cd0d5184823cf2b0d694e (diff)
downloadfluxbox-fff0abad765714d967614cfa871e37efca956194.zip
fluxbox-fff0abad765714d967614cfa871e37efca956194.tar.bz2
Improve I18n support
Among the first steps to produce better i18n support is to test the created translations adhoc without running "make install". To achieve this, fluxbox now honors several environment variables: - NLSPATH: fluxbox won't create the absolute path to the catalog and thus catopen() is free to use NLSPATH as described in the manpage. Example given: "/tmp/%N" will pick "/tmp/fluxbox.cat". %N refers to FLUXBOX_CATFILE. - FLUXBOX_CATFILE: By setting FLUXBOX_CATFILE the users can make fluxbox to use a different name for the catalog file. Default: "fluxbox.cat" - FLUXBOX_CATDIR: Per default fluxbox tries to find FLUXBOX_CATFILE at several places. Setting this environment variable allows to point fluxbox to a different search path for the catalog files. Then, fluxbox tries catopen() first without changing the deduced catalog file name. After that it applies some heuristics to get a good catalog file name.
-rw-r--r--src/FbTk/I18n.cc165
-rw-r--r--src/cli_info.cc13
-rw-r--r--src/cli_options.cc18
-rw-r--r--src/main.cc2
-rw-r--r--util/fbsetroot.cc2
-rw-r--r--util/fluxbox-update_configs.cc2
6 files changed, 134 insertions, 68 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
diff --git a/src/cli_info.cc b/src/cli_info.cc
index 6156d56..dab6029 100644
--- a/src/cli_info.cc
+++ b/src/cli_info.cc
@@ -72,22 +72,25 @@ void FluxboxCli::showInfo(ostream &ostr) {
72 <<_FB_CONSOLETEXT(Common, Defaults, "Defaults", "Default values compiled in") 72 <<_FB_CONSOLETEXT(Common, Defaults, "Defaults", "Default values compiled in")
73 << ": " << endl; 73 << ": " << endl;
74 74
75 ostr <<_FB_CONSOLETEXT(Common, DefaultMenuFile, " menu", "default menu file (right aligned - make sure same width as other default values)") 75 ostr <<_FB_CONSOLETEXT(Common, DefaultMenuFile, " menu", "default menu file (right aligned - make sure same width as other default values)")
76 << ": " 76 << ": "
77 << FbTk::StringUtil::expandFilename(DEFAULTMENU) << endl; 77 << FbTk::StringUtil::expandFilename(DEFAULTMENU) << endl;
78 ostr << _FB_CONSOLETEXT(Common, DefaultStyle, " style", "default style (right aligned - make sure same width as other default values)") 78 ostr <<_FB_CONSOLETEXT(Common, DefaultWindowMenuFile, " windowmenu", "default windowmenu file (right aligned - make sure same width as other default values)")
79 << ": "
80 << FbTk::StringUtil::expandFilename(DEFAULT_WINDOWMENU) << endl;
81 ostr << _FB_CONSOLETEXT(Common, DefaultStyle, " style", "default style (right aligned - make sure same width as other default values)")
79 << ": " 82 << ": "
80 << FbTk::StringUtil::expandFilename(DEFAULTSTYLE) << endl; 83 << FbTk::StringUtil::expandFilename(DEFAULTSTYLE) << endl;
81 84
82 ostr << _FB_CONSOLETEXT(Common, DefaultKeyFile, " keys", "default key file (right aligned - make sure same width as other default values)") 85 ostr << _FB_CONSOLETEXT(Common, DefaultKeyFile, " keys", "default key file (right aligned - make sure same width as other default values)")
83 << ": " 86 << ": "
84 << FbTk::StringUtil::expandFilename(DEFAULTKEYSFILE) << endl; 87 << FbTk::StringUtil::expandFilename(DEFAULTKEYSFILE) << endl;
85 ostr << _FB_CONSOLETEXT(Common, DefaultInitFile, " init", "default init file (right aligned - make sure same width as other default values)") 88 ostr << _FB_CONSOLETEXT(Common, DefaultInitFile, " init", "default init file (right aligned - make sure same width as other default values)")
86 << ": " 89 << ": "
87 << FbTk::StringUtil::expandFilename(DEFAULT_INITFILE) << endl; 90 << FbTk::StringUtil::expandFilename(DEFAULT_INITFILE) << endl;
88 91
89#ifdef NLS 92#ifdef NLS
90 ostr << _FB_CONSOLETEXT(Common, DefaultLocalePath, " nls", "location for localization files (right aligned - make sure same width as other default values)") 93 ostr << _FB_CONSOLETEXT(Common, DefaultLocalePath, " nls", "location for localization files (right aligned - make sure same width as other default values)")
91 << ": " 94 << ": "
92 << FbTk::StringUtil::expandFilename(LOCALEPATH) << endl; 95 << FbTk::StringUtil::expandFilename(LOCALEPATH) << endl;
93#endif 96#endif
diff --git a/src/cli_options.cc b/src/cli_options.cc
index 9e30af7..4440e83 100644
--- a/src/cli_options.cc
+++ b/src/cli_options.cc
@@ -32,22 +32,8 @@
32#include "FbTk/Command.hh" 32#include "FbTk/Command.hh"
33#include "FbTk/CommandParser.hh" 33#include "FbTk/CommandParser.hh"
34 34
35#ifdef HAVE_CONFIG_H 35#include <cstdlib>
36#include "config.h" 36#include <cstring>
37#endif // HAVE_CONFIG_H
38
39#ifdef HAVE_CSTDLIB
40 #include <cstdlib>
41#else
42 #include <stdlib.h>
43#endif
44
45#ifdef HAVE_CSTRING
46 #include <cstring>
47#else
48 #include <string.h>
49#endif
50
51#include <iostream> 37#include <iostream>
52 38
53using std::cerr; 39using std::cerr;
diff --git a/src/main.cc b/src/main.cc
index d1b3046..3cc728d 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -158,7 +158,7 @@ void setupSignalHandling() {
158 158
159int main(int argc, char **argv) { 159int main(int argc, char **argv) {
160 160
161 FbTk::I18n::init("fluxbox.cat"); 161 FbTk::I18n::init(0);
162 162
163 FluxboxCli::Options opts; 163 FluxboxCli::Options opts;
164 int exitcode = opts.parse(argc, argv); 164 int exitcode = opts.parse(argc, argv);
diff --git a/util/fbsetroot.cc b/util/fbsetroot.cc
index 28ad26e..07f6b68 100644
--- a/util/fbsetroot.cc
+++ b/util/fbsetroot.cc
@@ -370,7 +370,7 @@ int main(int argc, char **argv) {
370 char *display_name = (char *) 0; 370 char *display_name = (char *) 0;
371 int i = 1; 371 int i = 1;
372 372
373 FbTk::I18n::init("fluxbox.cat"); 373 FbTk::I18n::init(0);
374 374
375 for (; i < argc; i++) { 375 for (; i < argc; i++) {
376 if (!strcmp(argv[i], "-display") || !strcmp(argv[i], "--display")) { 376 if (!strcmp(argv[i], "-display") || !strcmp(argv[i], "--display")) {
diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc
index a7d3d4a..4065f97 100644
--- a/util/fluxbox-update_configs.cc
+++ b/util/fluxbox-update_configs.cc
@@ -565,7 +565,7 @@ int main(int argc, char **argv) {
565 bool check = 0; 565 bool check = 0;
566 pid_t fb_pid = 0; 566 pid_t fb_pid = 0;
567 567
568 FbTk::I18n::init("fluxbox.cat"); 568 FbTk::I18n::init(0);
569 _FB_USES_NLS; 569 _FB_USES_NLS;
570 570
571 for (; i < argc; i++) { 571 for (; i < argc; i++) {