Index: boost/locale/gnu_gettext.hpp =================================================================== --- boost/locale/gnu_gettext.hpp (revision 82148) +++ boost/locale/gnu_gettext.hpp (working copy) @@ -24,13 +24,228 @@ namespace gnu_gettext { /// + /// The callback for custom file system support. This callback should read the file named \a file_name + /// encoded in \a encoding character set into std::vector and return it. + /// + /// - If the file does not exist, it should return an empty vector. + /// - If a error occurs during file read it should throw a error. + /// + /// \note The user should support only the encodings the locales are created for. So if the user + /// uses only one encoding or the file system is encoding agnostic, he may ignore the \a encoding parameter. + /// + typedef function< + std::vector( + std::string const &file_name, + std::string const &encoding + ) + > callback_type; + + /// + /// \brief This type represents GNU Gettext domain name for the messages. + /// + /// It consists of two parameters: + /// + /// - name - the name of the domain - used for opening the file name + /// - encoding - the encoding of the keys in the sources, default - UTF-8 + /// + class BOOST_LOCALE_DECL domain { + public: + /// + /// Create a domain object from the name that can hold an encoding after symbol "/" + /// such that if n is "hello/cp1255" then the name would be "hello" and "encoding" would + /// be "cp1255" and if n is "hello" then the name would be the same but encoding would be + /// "UTF-8" + /// + domain(std::string const &n); + /// + /// Create a domain object from the name and encoding + /// + domain(std::string const &name,std::string const &encodings); + + domain(); + domain(domain const &other); + domain const &operator=(domain const &); + ~domain(); + + std::string name() const; + std::string encoding() const; + + /// + /// Check whether two objects are equivalent, only names are compared, encoding is ignored + /// + bool operator==(domain const &other) const; + /// + /// Check whether two objects aren't equivalent, only names are compared, encoding is ignored + /// + bool operator!=(domain const &other) const; + private: + struct data; + data *d; + std::string name_,encoding_; + }; + + + /// /// \brief This structure holds all information required for creating gnu-gettext message catalogs, /// /// The user is expected to set its parameters to load these catalogs correctly. This structure /// also allows providing functions for charset conversion. Note, you need to provide them, /// so this structure is not useful for wide characters without subclassing and it will also /// ignore gettext catalogs that use a charset different from \a encoding. + /// + class BOOST_LOCALE_DECL catalog_info { + public: + + /// + /// Initializes default catalog for "C" locale: + /// + /// - language: "C" + /// - country: empty + /// - variant: empty + /// - encoding: empty + /// - locale_category: "LC_MESSAGES" + /// - path_formats: ( "{1}/{2}/{3}/{4}.mo" ) + /// + /// + /// The user is expected to define at least: language, paths (at least one), domains (at least one) + /// and encoding for narrow character catalogs + /// + catalog_info(); + catalog_info(catalog_info const &); + catalog_info const &operator=(catalog_info const &); + ~catalog_info(); + + /// + /// Get the language we load the catalog for, like "ru", "en", "de" + /// + std::string language() const; + /// + /// Set the language we load the catalog for, like "ru", "en", "de" + /// + void language(std::string const &); + /// + /// Get the country we load the catalog for, like "US", "IL" + /// + std::string country() const; + /// + /// Set the country we load the catalog for, like "US", "IL" + /// + void country(std::string const &); + /// + /// Get language variant, like "euro" so it would look for catalog like de_DE\@euro + /// + std::string variant() const; + /// + /// Set language variant, like "euro" so it would look for catalog like de_DE\@euro + /// + void variant(std::string const &); + /// + /// Get the required target charset encoding. Ignored for wide characters. + /// For narrow, should specify the correct encoding required for this catalog + /// + std::string encoding() const; + /// + /// Set the required target charset encoding. Ignored for wide characters. + /// For narrow, should specify the correct encoding required for this catalog + /// + void encoding(std::string const &); + + /// + /// Get the locale category, is set by default to LC_MESSAGES, but may be changed + /// + std::string locale_category() const; + /// + /// Set the locale category, is set by default to LC_MESSAGES, but may be changed + /// + void locale_category(std::string const &); + + /// + /// Get the callback for handling custom file systems, if it is empty, the real OS file-system + /// is being used. + /// + callback_type callback() const; + /// + /// Set the callback for handling custom file systems, if it is empty, the real OS file-system + /// is being used. + /// + void callback(callback_type const &); + + /// + /// Type that defines a list of domains that are loaded + /// The first one is the default one + /// + typedef std::vector domains_type; + + /// + /// Get message domains - application name, like my_app. So files named my_app.mo would be loaded + /// + domains_type domains() const; + /// + /// Add message domain - application name, like my_app. So files named my_app.mo would be loaded + /// + void add_domain(domain const &); + + /// + /// Paths to search files in. Under MS Windows it uses encoding + /// parameter to convert them to wide OS specific paths. + /// + std::vector paths() const; + + /// + /// Add a path to search in + /// + void add_path(std::string const &); + + /// + /// Optional formats to search the file in. + /// + /// Formats are the same syntax as the Boost format functions, but + /// use the following variables: + /// + /// \li {1} A path to search for catalogs in. + /// \li {2} The locale's name. + /// \li {3} The locale's category. + /// \li {4} The Gettext domain. + /// + /// For example, \c {1}/{2}/{3}/{4}.mo is the standard Gettext layout. + /// Using something like \c {1}/{2}.mo would compact the folder hierarchy, for an + /// application that uses a single domain + /// + std::vector path_formats() const; + + /// + /// Add new path format, see \ref path_formats() + /// + void add_path_format(std::string const &); + + private: + struct data; + data *d; + }; + + /// + /// Create a message_format facet using GNU Gettext catalogs. It uses \a info structure to get + /// information about where to read them from and uses it for character set conversion (if needed) + /// + template + message_format *create_messages_facet(catalog_info const &info); + + + // ---- deprecated stuff goes there --- // + + + + /// + /// \brief This structure holds all information required for creating gnu-gettext message catalogs, + /// + /// The user is expected to set its parameters to load these catalogs correctly. This structure + /// also allows providing functions for charset conversion. Note, you need to provide them, + /// so this structure is not useful for wide characters without subclassing and it will also + /// ignore gettext catalogs that use a charset different from \a encoding. + /// + /// \deprecated Use catalog_info instead + /// struct messages_info { messages_info() : language("C"), @@ -124,19 +339,70 @@ /// callback_type callback; + /// + /// Convert to non-deprecated format + /// + catalog_info to_catalog() const + { + catalog_info r; + + r.language(language); + + if(!country.empty()) + r.country(country); + if(!variant.empty()) + r.variant(variant); + if(!encoding.empty()) + r.encoding(encoding); + r.locale_category(locale_category); + if(!callback.empty()) + r.callback(callback); + for(size_t i=0;i message_format *create_messages_facet(messages_info const &info); + /// \cond INTERNAL + + template<> + BOOST_LOCALE_DECL message_format *create_messages_facet(catalog_info const &info); template<> + BOOST_LOCALE_DECL message_format *create_messages_facet(catalog_info const &info); + + #ifdef BOOST_HAS_CHAR16_T + template<> + BOOST_LOCALE_DECL message_format *create_messages_facet(catalog_info const &info); + #endif + + #ifdef BOOST_HAS_CHAR32_T + template<> + BOOST_LOCALE_DECL message_format *create_messages_facet(catalog_info const &info); + #endif + + + // deprecated internal stuff + + template<> BOOST_LOCALE_DECL message_format *create_messages_facet(messages_info const &info); template<> Index: libs/locale/src/shared/message.cpp =================================================================== --- libs/locale/src/shared/message.cpp (revision 82148) +++ libs/locale/src/shared/message.cpp (working copy) @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #ifdef BOOST_MSVC @@ -533,16 +534,18 @@ return p->second; } - mo_message(messages_info const &inf) + mo_message(catalog_info const &inf) { - std::string language = inf.language; - std::string variant = inf.variant; - std::string country = inf.country; - std::string encoding = inf.encoding; - std::string lc_cat = inf.locale_category; - std::vector const &domains = inf.domains; - std::vector const &search_paths = inf.paths; + std::vector formats = inf.path_formats(); + std::string language = inf.language(); + std::string variant = inf.variant(); + std::string country = inf.country(); + std::string encoding = inf.encoding(); + std::string lc_cat = inf.locale_category(); + std::vector domains = inf.domains(); + std::vector search_paths = inf.paths(); + // // List of fallbacks: en_US@euro, en@euro, en_US, en. // @@ -566,16 +569,18 @@ for(unsigned id=0;id - message_format *create_messages_facet(messages_info const &info) + message_format *create_messages_facet(catalog_info const &data) { - return new mo_message(info); + return new mo_message(data); } template<> - message_format *create_messages_facet(messages_info const &info) + message_format *create_messages_facet(catalog_info const &data) { - return new mo_message(info); + return new mo_message(data); } #ifdef BOOST_HAS_CHAR16_T template<> - message_format *create_messages_facet(messages_info const &info) + message_format *create_messages_facet(catalog_info const &data) { - return new mo_message(info); + return new mo_message(data); } #endif #ifdef BOOST_HAS_CHAR32_T template<> - message_format *create_messages_facet(messages_info const &info) + message_format *create_messages_facet(catalog_info const &data) { - return new mo_message(info); + return new mo_message(data); } #endif + template<> + message_format *create_messages_facet(messages_info const &data) + { + return new mo_message(data.to_catalog()); + } + template<> + message_format *create_messages_facet(messages_info const &data) + { + return new mo_message(data.to_catalog()); + } + + #ifdef BOOST_HAS_CHAR16_T + + template<> + message_format *create_messages_facet(messages_info const &data) + { + return new mo_message(data.to_catalog()); + } + #endif + + #ifdef BOOST_HAS_CHAR32_T + + template<> + message_format *create_messages_facet(messages_info const &data) + { + return new mo_message(data.to_catalog()); + } + #endif + + struct domain::data {}; + domain::domain() : d(0) {} + domain::~domain() {} + domain::domain(domain const &other) : + d(0), + name_(other.name_), + encoding_(other.encoding_) + { + } + domain const &domain::operator=(domain const &other) + { + if(this!=&other) { + name_ = other.name_; + encoding_ = other.encoding_; + } + return *this; + } + std::string domain::name() const { return name_; } + std::string domain::encoding() const { return encoding_; } + domain::domain(std::string const &n,std::string const &e) :d(0),name_(n),encoding_(e) {} + domain::domain(std::string const &n) : d(0) + { + size_t pos = n.find("/"); + if(pos==std::string::npos) { + name_ = n; + encoding_ = "UTF-8"; + } + else { + name_ = n.substr(0,pos); + encoding_ = n.substr(pos+1); + } + } + bool domain::operator==(domain const &other) const + { + return name_ == other.name_; + } + bool domain::operator!=(domain const &other) const + { + return !(*this == other); + } + + struct catalog_info::data { + data() : language("C"), locale_category("LC_MESSAGES") {} + std::string language; + std::string country; + std::string variant; + std::string encoding; + std::string locale_category; + std::vector domains; + std::vector paths; + callback_type callback; + std::vector path_formats; + }; + + catalog_info::catalog_info() : d(new catalog_info::data()) + { + } + catalog_info::~catalog_info() { delete d; } + // d is never 0 + catalog_info::catalog_info(catalog_info const &other) : d(new catalog_info::data(*other.d)) + { + } + + catalog_info const &catalog_info::operator=(catalog_info const &other) + { + if(this != &other) { + // d is never 0 + catalog_info::data *p = new catalog_info::data(*other.d); + delete d; + d=p; + } + return *this; + } + + + std::string catalog_info::language() const { return d->language; } + void catalog_info::language(std::string const &v) { d->language=v; } + + std::string catalog_info::country() const { return d->country; } + void catalog_info::country(std::string const &v) { d->country=v; } + + std::string catalog_info::variant() const { return d->variant; } + void catalog_info::variant(std::string const &v) { d->variant=v; } + + std::string catalog_info::encoding() const { return d->encoding; } + void catalog_info::encoding(std::string const &v) { d->encoding=v; } + + std::string catalog_info::locale_category() const { return d->locale_category; } + void catalog_info::locale_category(std::string const &v) { d->locale_category=v; } + + callback_type catalog_info::callback() const { return d->callback; } + void catalog_info::callback(callback_type const &v) { d->callback=v; } + + catalog_info::domains_type catalog_info::domains() const { return d->domains; } + void catalog_info::add_domain(domain const &v) { d->domains.push_back(v); } + + std::vector catalog_info::paths() const { return d->paths; } + void catalog_info::add_path(std::string const &v) { d->paths.push_back(v); } + + std::vector catalog_info::path_formats() const + { + if(d->path_formats.empty()) { + std::vector r; + r.push_back("{1}/{2}/{3}/{4}.mo"); + return r; + } + return d->path_formats; + } + void catalog_info::add_path_format(std::string const &v) { d->path_formats.push_back(v); } + + + + + + } /// gnu_gettext } // locale