From fff0abad765714d967614cfa871e37efca956194 Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Sat, 31 Jan 2015 21:37:44 +0100 Subject: [PATCH] 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. --- src/FbTk/I18n.cc | 177 +++++++++++++++++++++++---------- src/cli_info.cc | 13 ++- src/cli_options.cc | 18 +--- src/main.cc | 2 +- util/fbsetroot.cc | 2 +- util/fluxbox-update_configs.cc | 2 +- 6 files changed, 140 insertions(+), 74 deletions(-) diff --git a/src/FbTk/I18n.cc b/src/FbTk/I18n.cc index f53e5edc..18eb67ca 100644 --- a/src/FbTk/I18n.cc +++ b/src/FbTk/I18n.cc @@ -37,6 +37,7 @@ #include #include +#include #include #ifdef HAVE_LOCALE_H @@ -65,15 +66,54 @@ using std::string; namespace { -const nl_catd INVALID_CATALOG = ((nl_catd)(-1)); -nl_catd s_catalog_fd = INVALID_CATALOG; +const char UTF8_SUFFIX[] = "-UTF-8.cat"; +const size_t UTF8_SUFFIX_LEN = sizeof(UTF8_SUFFIX)-1; // without \0 +const char DEFAULT_CATFILE[] = "fluxbox.cat"; +const char ENV_CATFILE[] = "FLUXBOX_CATFILE"; +const char ENV_CATDIR[] = "FLUXBOX_CATDIR"; + +const nl_catd INVALID_CATALOG = (nl_catd)(-1); +nl_catd s_catalog_fd = INVALID_CATALOG; + + +const char* getCatalogDir() { + const char* cat_dir = getenv(ENV_CATDIR); + if (cat_dir) { + return cat_dir; + } + return LOCALEPATH; +} + + +std::string join_str(size_t n, ...) { + std::string s; + va_list args; + va_start(args, n); + for (; n > 0; n--) { + s.append(va_arg(args, const char*)); + } + return s; +} } namespace FbTk { + +// initialize the i18n-system be opening the catalog-file +// named by 'catalog'. per default we expect 'catalog' to +// be 0/NULL, the code picks a sane default then: +// +// - environment variable FLUXBOX_CATFILE is set? use it +// - DEFAULT_CATFILE ("fluxbox.cat") +// - the utf8 encoded translation for the current locale +// +// handling things this was allows us to test catalog files +// without putting them into the install path +// $PREFIX/share/fluxbox/nls/XYZ/ void I18n::init(const char* catalog) { + static bool init = false; if (init) { return; @@ -81,50 +121,87 @@ void I18n::init(const char* catalog) { #if defined(NLS) && defined(HAVE_CATOPEN) - FbStringUtil::init(); - - I18n& i18n = I18n::instance(); - - string filename = LOCALEPATH; - filename += '/'; - filename += i18n.m_locale; - filename += '/'; - filename += catalog; - - if (!FileUtil::isRegularFile(filename.c_str()) && i18n.m_locale != "C" && FbStringUtil::haveUTF8()) { - // try the UTF-8 catalog, this also picks up situations where - // the codeset somehow isn't specified - - // remove everything after @ - string::size_type index = i18n.m_locale.find('.'); - // erase all characters starting at index - if (index != string::npos) - i18n.m_locale.erase(index); - - i18n.m_locale.append(".UTF-8"); - i18n.m_utf8_translate = true; - - filename = LOCALEPATH; - filename += '/'; - filename += i18n.m_locale; - filename += '/'; - filename += catalog; + if (!catalog) { + const char* c = getenv(ENV_CATFILE); + if (!c) { + c = DEFAULT_CATFILE; + } + catalog = c; } + FbStringUtil::init(); + + int flag; + + I18n& i18n = I18n::instance(); + const string dir = getCatalogDir(); + const string locale = i18n.m_locale; + string clean_locale = locale; + size_t i; + + // clean the locale, we have to append something later on + i = clean_locale.find('.'); + if (i != string::npos) + clean_locale.erase(i); + #ifdef MCLoadBySet - s_catalog_fd = catopen(filename.c_str(), MCLoadBySet); -#else // !MCLoadBySet - s_catalog_fd = catopen(filename.c_str(), NL_CAT_LOCALE); -#endif // MCLoadBySet + flag = MCLoadBySet; +#else + flag = NL_CAT_LOCALE; +#endif + + struct { std::string catalog; std::string locale; bool utf8; } _catalog[] = { + + // first try pure 'catalog'. catopen() will use NLSPATH if it's + // set and replaces '%N' by 'catalog'. eg: with catalog="fluxbox.cat" + // "/usr/share/fluxbox/nls/C/%N" becomes "/usr/share/fluxbox/nls/C/fluxbox.cat" + { string(catalog), locale, false }, + + // try full-path to 'catalog' + { join_str(5, dir.c_str(), "/", locale.c_str(), "/", catalog), locale, false }, + + // try the UTF-8 catalog, this also picks up situations where + // the codeset somehow isn't specified + { join_str(5, dir.c_str(), "/", clean_locale.c_str(), ".UTF-8/", catalog), + join_str(2, clean_locale.c_str(), ".UTF8"), true}, + + }; + + for (i = 0; i < sizeof(_catalog)/sizeof(_catalog[0]); i++) { + + if (_catalog[i].utf8 && locale == "C") { + continue; + } + + const char* fname = _catalog[i].catalog.c_str(); + + s_catalog_fd = catopen(fname, flag); + if (s_catalog_fd == INVALID_CATALOG) { + continue; + } + + i18n.m_locale = _catalog[i].locale; + if (FbStringUtil::haveUTF8()) { + if (_catalog[i].utf8) { + i18n.m_utf8_translate = true; + } else { + size_t n = _catalog[i].catalog.rfind(UTF8_SUFFIX); + if (n != std::string::npos && (n + UTF8_SUFFIX_LEN) == _catalog[i].catalog.size()) { + i18n.m_utf8_translate = true; + } + } + } + break; + } if (s_catalog_fd == INVALID_CATALOG) { - cerr<<"Warning: Failed to open file("< -#else - #include -#endif - -#ifdef HAVE_CSTRING - #include -#else - #include -#endif - +#include +#include #include using std::cerr; diff --git a/src/main.cc b/src/main.cc index d1b30465..3cc728da 100644 --- a/src/main.cc +++ b/src/main.cc @@ -158,7 +158,7 @@ void setupSignalHandling() { int main(int argc, char **argv) { - FbTk::I18n::init("fluxbox.cat"); + FbTk::I18n::init(0); FluxboxCli::Options opts; int exitcode = opts.parse(argc, argv); diff --git a/util/fbsetroot.cc b/util/fbsetroot.cc index 28ad26ec..07f6b685 100644 --- a/util/fbsetroot.cc +++ b/util/fbsetroot.cc @@ -370,7 +370,7 @@ int main(int argc, char **argv) { char *display_name = (char *) 0; int i = 1; - FbTk::I18n::init("fluxbox.cat"); + FbTk::I18n::init(0); for (; i < argc; i++) { if (!strcmp(argv[i], "-display") || !strcmp(argv[i], "--display")) { diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc index a7d3d4a8..4065f976 100644 --- a/util/fluxbox-update_configs.cc +++ b/util/fluxbox-update_configs.cc @@ -565,7 +565,7 @@ int main(int argc, char **argv) { bool check = 0; pid_t fb_pid = 0; - FbTk::I18n::init("fluxbox.cat"); + FbTk::I18n::init(0); _FB_USES_NLS; for (; i < argc; i++) {