// // aegis - project change supervisor // Copyright (C) 1995, 2002-2006, 2008 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #include #include #include #include #include #include #include #ifdef DEBUG enum state_ty { state_uninitialized, state_C, state_human }; static state_ty state; #endif // DEBUG static bool setlocale_is_working; static int message_catalog_set; // // This is the lost of locale names to try if the default "" setlocale fails. // static const char *const trial_locales[] = { "en_US", "en", "en_US.UTF-8", "en_US.utf8", "en_US.ISO8859-1", "en_US.iso8859-1", }; #if defined(HAVE_SETLOCALE) && defined(HAVE_GETTEXT) // // NAME // setlocale_wrapper - common setlocale processing // // DESCRIPTION // The setlocale_wrapper function is used to call the setlocale // function, with defualt arguments of // // setlocale(LC_ALL, "") // // The function return true (non-zero) if setlocale succeeds, // and false (zero) if setlocale fails. // // When setlocale returns "C" or "POSIX" this is considered a // failure, because it will result in the short form of the error // messages being used. The return value will be 0 in these // cases, too. // static bool setlocale_wrapper(void) { // // At this time (Oct-2004) Cygwin only partially implements // localisation. Returning a hard coded "yes" here at least results // in long error messages for now. // #ifndef __CYGWIN__ const char *cp = setlocale(LC_ALL, ""); if (!cp) return false; if (0 == strcmp("C", cp) || 0 == strcmp("POSIX", cp)) return false; #endif // !defined(__CYGWIN__) return true; } #endif // // NAME // language_init - initialize language functions // // DESCRIPTION // The language_init function must be called at the start of the // program, to set the various locale features. // // This function must be called after the setuid initialization. // If you forget to call me, all bets are off. // void language_init(void) { const char *lib; #if HAVE_SETLOCALE && HAVE_GETTEXT static const char package[] = "aegis"; #endif // // Protect against multiple invokation. // #ifdef DEBUG if (state != state_uninitialized) fatal_raw("language_init() called more than once (bug)"); state = state_C; #endif // // Set the locale to the default (as defined by the environment // variables) and set the message domain information. // lib = getenv("AEGIS_MESSAGE_LIBRARY"); if (!lib || !*lib) lib = configured_nlsdir(); else message_catalog_set = 1; setlocale_is_working = false; #ifdef HAVE_SETLOCALE #ifdef HAVE_GETTEXT setlocale_is_working = setlocale_wrapper(); if (!setlocale_is_working) { char *lc_all; size_t j; // // Remember the LC_ALL value in case we have to reset it. // lc_all = getenv("LC_ALL"); if (lc_all) lc_all = mem_copy_string(lc_all); // // Try the list of alternatives for the English messages. // // We set the LC_ALL environment variable, because it trumps // the LC_xxx and LANG environment variables. // for (j = 0; j < SIZEOF(trial_locales); ++j) { env_set("LC_ALL", trial_locales[j]); setlocale_is_working = setlocale_wrapper(); if (setlocale_is_working) break; } // // If we didn't find a working locale, restore the LC_ALL setting. // if (!setlocale_is_working && lc_all) { env_set("LC_ALL", lc_all); mem_free(lc_all); } else env_unset("LC_ALL"); } bindtextdomain(package, lib); textdomain(package); #endif // HAVE_GETTEXT // // set the main body of the program use use the C locale // setlocale(LC_ALL, "C"); #endif // HAVE_SETLOCALE } // // NAME // language_human - set for human conversation // // DESCRIPTION // The language_human function must be called to change the general // mode over to the default locale (usually dictated by the LANG // environment variable, et al). // // The language_human and language_C functions MUST bracket human // interactions, otherwise the mostly-english C locale will be // used. The default locale through-out the program is otherwise // assumed to be C. // void language_human(void) { if (!setlocale_is_working) return; #ifdef DEBUG switch (state) { case state_uninitialized: fatal_raw("you must call language_init() in main (bug)"); case state_human: fatal_raw("unbalanced language_human() call (bug)"); case state_C: break; } state = state_human; #endif #ifdef HAVE_SETLOCALE #ifdef HAVE_GETTEXT // // only need to flap the locale about like this // if we are using the gettext function // setlocale(LC_ALL, ""); #endif // HAVE_GETTEXT #endif // HAVE_SETLOCALE } // // NAME // language_C - set for program conversation // // DESCRIPTION // The language_C function must be called to restore the locale to // C, so that all the non-human stuff will work. // // The language_human and language_C functions MUST bracket human // interactions, otherwise the mostly-english C locale will be // used. The default locale through-out the program is otherwise // assumed to be C. // void language_C(void) { if (!setlocale_is_working) return; #ifdef DEBUG switch (state) { case state_uninitialized: fatal_raw("you must call language_init() in main (bug)"); case state_C: fatal_raw("unbalanced language_C() call (bug)"); case state_human: break; } state = state_C; #endif #ifdef HAVE_SETLOCALE #ifdef HAVE_GETTEXT // // only need to flap the locale about like this // if we are using the gettext function // setlocale(LC_ALL, "C"); #endif // HAVE_GETTEXT #endif // HAVE_SETLOCALE } #if HAVE_GETTEXT static int lang_set(void) { const char *cp; cp = getenv("LC_ALL"); if (cp && *cp) return 1; cp = getenv("LC_MESSAGES"); if (cp && *cp) return 1; cp = getenv("LANG"); if (cp && *cp) return 1; return 0; } #endif void language_check_translations() { #ifndef SOURCE_FORGE_HACK #if HAVE_GETTEXT static int done; if (!done) { done = 1; if (!message_catalog_set) { // // Only whinge about this stuff if they *haven't* messed // with the AEGIS_MESSAGE_LIBRARY environment varaible. // if (setlocale_is_working) { char *cp; language_human(); cp = gettext(""); if (!cp || !*cp) { if (lang_set()) { error_raw ( "Warning: You are seeing the short form " "of the error messages. The message " "catalogues may not have been installed " "correctly, or you may need to check " "the settings of your LC_ALL and LANG " "environment variables." ); } else { error_raw ( "Warning: You are seeing the short form " "of the error messages. Longer and " "more informative error messages are " "available using the English message " "catalogue available via the GNU Gettext " "facilities; use the command \"LANG=en_US; " "export LANG\" to enable them. The " "message catalogues (including the English " "catalogue) may not have been installed " "correctly. A number of alternate message " "catalogues in other languages are also " "available." ); } } language_C(); } else { error_raw ( "Warning: The setlocale() function failed. " "This results in you seeing the short form of the " "error messages. You may need to check the settings " "of your LC_ALL and LANG environment variables." #ifdef HAVE_LOCALE_PROG " Use the \"locale -a\" command to obtain a list " "of valid locales." #ifndef HAVE_LOCALE_GEN_PROG " If the list is very short, you may have a glibc " "install problem." #endif #endif #ifdef HAVE_LOCALE_GEN_PROG " See the locale-gen(8) man page for how to create " "additional locales." #endif ); } } } #endif // HAVE_GETTEXT #endif // !SOURCE_FORGE_HACK }