1 | // |
2 | // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. |
5 | // https://www.boost.org/LICENSE_1_0.txt |
6 | |
7 | #ifndef BOOST_LOCLAE_GNU_GETTEXT_HPP |
8 | #define BOOST_LOCLAE_GNU_GETTEXT_HPP |
9 | |
10 | #include <boost/locale/detail/is_supported_char.hpp> |
11 | #include <boost/locale/message.hpp> |
12 | #include <functional> |
13 | #include <stdexcept> |
14 | #include <type_traits> |
15 | #include <vector> |
16 | |
17 | #ifdef BOOST_MSVC |
18 | # pragma warning(push) |
19 | # pragma warning(disable : 4251) // "identifier" : class "type" needs to have dll-interface... |
20 | #endif |
21 | |
22 | namespace boost { namespace locale { |
23 | /// \addtogroup message |
24 | /// @{ |
25 | |
26 | /// \brief This namespace holds classes that provide GNU Gettext message catalogs support. |
27 | namespace gnu_gettext { |
28 | |
29 | /// \brief This structure holds all information required for creating gnu-gettext message catalogs, |
30 | /// |
31 | /// The user is expected to set its parameters to load these catalogs correctly. This structure |
32 | /// also allows providing functions for charset conversion. Note, you need to provide them, |
33 | /// so this structure is not useful for wide characters without subclassing and it will also |
34 | /// ignore gettext catalogs that use a charset different from \a encoding. |
35 | struct BOOST_LOCALE_DECL messages_info { |
36 | messages_info() : language("C" ), locale_category("LC_MESSAGES" ) {} |
37 | |
38 | std::string language; ///< The language we load the catalog for, like "ru", "en", "de" |
39 | std::string country; ///< The country we load the catalog for, like "US", "IL" |
40 | std::string variant; ///< Language variant, like "euro" so it would look for catalog like de_DE\@euro |
41 | std::string encoding; ///< Required target charset encoding. Ignored for wide characters. |
42 | ///< For narrow, should specify the correct encoding required for this catalog |
43 | std::string locale_category; ///< Locale category, is set by default to LC_MESSAGES, but may be changed |
44 | /// |
45 | /// \brief This type represents GNU Gettext domain name for the messages. |
46 | /// |
47 | /// It consists of two parameters: |
48 | /// |
49 | /// - name - the name of the domain - used for opening the file name |
50 | /// - encoding - the encoding of the keys in the sources, default - UTF-8 |
51 | /// |
52 | struct domain { |
53 | std::string name; ///< The name of the domain |
54 | std::string encoding; ///< The character encoding for the domain |
55 | domain() = default; |
56 | |
57 | /// Create a domain object from the name that can hold an encoding after symbol "/" |
58 | /// such that if n is "hello/cp1255" then the name would be "hello" and "encoding" would |
59 | /// be "cp1255" and if n is "hello" then the name would be the same but encoding would be |
60 | /// "UTF-8" |
61 | domain(const std::string& n) |
62 | { |
63 | const size_t pos = n.find(c: '/'); |
64 | if(pos == std::string::npos) { |
65 | name = n; |
66 | encoding = "UTF-8" ; |
67 | } else { |
68 | name = n.substr(pos: 0, n: pos); |
69 | encoding = n.substr(pos: pos + 1); |
70 | } |
71 | } |
72 | |
73 | /// Check whether two objects are equivalent, only names are compared, encoding is ignored |
74 | bool operator==(const domain& other) const { return name == other.name; } |
75 | /// Check whether two objects are distinct, only names are compared, encoding is ignored |
76 | bool operator!=(const domain& other) const { return !(*this == other); } |
77 | }; |
78 | |
79 | typedef std::vector<domain> domains_type; ///< Type that defines a list of domains that are loaded |
80 | ///< The first one is the default one |
81 | domains_type domains; ///< Message domains - application name, like my_app. So files named my_app.mo |
82 | ///< would be loaded |
83 | std::vector<std::string> paths; ///< Paths to search files in. Under MS Windows it uses encoding |
84 | ///< parameter to convert them to wide OS specific paths. |
85 | |
86 | /// The callback for custom file system support. This callback should read the file named \a file_name |
87 | /// encoded in \a encoding character set into std::vector<char> and return it. |
88 | /// |
89 | /// - If the file does not exist, it should return an empty vector. |
90 | /// - If an error occurs during file read it should throw an exception. |
91 | /// |
92 | /// \note The user should support only the encodings the locales are created for. So if the user |
93 | /// uses only one encoding or the file system is encoding agnostic, he may ignore the \a encoding parameter. |
94 | typedef std::function<std::vector<char>(const std::string& file_name, const std::string& encoding)> |
95 | callback_type; |
96 | |
97 | /// The callback for handling custom file systems, if it is empty, the real OS file-system |
98 | /// is being used. |
99 | callback_type callback; |
100 | |
101 | /// Get paths to folders which may contain catalog files |
102 | std::vector<std::string> get_catalog_paths() const; |
103 | |
104 | private: |
105 | /// Get a list of folder names for the language, country and variant |
106 | std::vector<std::string> get_lang_folders() const; |
107 | }; |
108 | |
109 | /// Create a message_format facet using GNU Gettext catalogs. It uses \a info structure to get |
110 | /// information about where to read them from and uses it for character set conversion (if needed) |
111 | template<typename CharType, class = boost::locale::detail::enable_if_is_supported_char<CharType>> |
112 | BOOST_LOCALE_DECL message_format<CharType>* create_messages_facet(const messages_info& info); |
113 | |
114 | } // namespace gnu_gettext |
115 | |
116 | /// @} |
117 | |
118 | }} // namespace boost::locale |
119 | |
120 | #ifdef BOOST_MSVC |
121 | # pragma warning(pop) |
122 | #endif |
123 | |
124 | #endif |
125 | |