Ticket #7266: gettext_paths.patch
File gettext_paths.patch, 21.0 KB (added by , 10 years ago) |
---|
-
boost/locale/gnu_gettext.hpp
24 24 namespace gnu_gettext { 25 25 26 26 /// 27 /// The callback for custom file system support. This callback should read the file named \a file_name 28 /// encoded in \a encoding character set into std::vector<char> and return it. 29 /// 30 /// - If the file does not exist, it should return an empty vector. 31 /// - If a error occurs during file read it should throw a error. 32 /// 33 /// \note The user should support only the encodings the locales are created for. So if the user 34 /// uses only one encoding or the file system is encoding agnostic, he may ignore the \a encoding parameter. 35 /// 36 typedef function< 37 std::vector<char>( 38 std::string const &file_name, 39 std::string const &encoding 40 ) 41 > callback_type; 42 43 /// 44 /// \brief This type represents GNU Gettext domain name for the messages. 45 /// 46 /// It consists of two parameters: 47 /// 48 /// - name - the name of the domain - used for opening the file name 49 /// - encoding - the encoding of the keys in the sources, default - UTF-8 50 /// 51 class BOOST_LOCALE_DECL domain { 52 public: 53 /// 54 /// Create a domain object from the name that can hold an encoding after symbol "/" 55 /// such that if n is "hello/cp1255" then the name would be "hello" and "encoding" would 56 /// be "cp1255" and if n is "hello" then the name would be the same but encoding would be 57 /// "UTF-8" 58 /// 59 domain(std::string const &n); 60 /// 61 /// Create a domain object from the name and encoding 62 /// 63 domain(std::string const &name,std::string const &encodings); 64 65 domain(); 66 domain(domain const &other); 67 domain const &operator=(domain const &); 68 ~domain(); 69 70 std::string name() const; 71 std::string encoding() const; 72 73 /// 74 /// Check whether two objects are equivalent, only names are compared, encoding is ignored 75 /// 76 bool operator==(domain const &other) const; 77 /// 78 /// Check whether two objects aren't equivalent, only names are compared, encoding is ignored 79 /// 80 bool operator!=(domain const &other) const; 81 private: 82 struct data; 83 data *d; 84 std::string name_,encoding_; 85 }; 86 87 88 /// 27 89 /// \brief This structure holds all information required for creating gnu-gettext message catalogs, 28 90 /// 29 91 /// The user is expected to set its parameters to load these catalogs correctly. This structure 30 92 /// also allows providing functions for charset conversion. Note, you need to provide them, 31 93 /// so this structure is not useful for wide characters without subclassing and it will also 32 94 /// ignore gettext catalogs that use a charset different from \a encoding. 95 /// 96 class BOOST_LOCALE_DECL catalog_info { 97 public: 98 99 /// 100 /// Initializes default catalog for "C" locale: 101 /// 102 /// - language: "C" 103 /// - country: empty 104 /// - variant: empty 105 /// - encoding: empty 106 /// - locale_category: "LC_MESSAGES" 107 /// - path_formats: ( "{1}/{2}/{3}/{4}.mo" ) 108 /// 109 /// 110 /// The user is expected to define at least: language, paths (at least one), domains (at least one) 111 /// and encoding for narrow character catalogs 112 /// 113 catalog_info(); 114 catalog_info(catalog_info const &); 115 catalog_info const &operator=(catalog_info const &); 116 ~catalog_info(); 117 118 /// 119 /// Get the language we load the catalog for, like "ru", "en", "de" 120 /// 121 std::string language() const; 122 /// 123 /// Set the language we load the catalog for, like "ru", "en", "de" 124 /// 125 void language(std::string const &); 126 /// 127 /// Get the country we load the catalog for, like "US", "IL" 128 /// 129 std::string country() const; 130 /// 131 /// Set the country we load the catalog for, like "US", "IL" 132 /// 133 void country(std::string const &); 134 /// 135 /// Get language variant, like "euro" so it would look for catalog like de_DE\@euro 136 /// 137 std::string variant() const; 138 /// 139 /// Set language variant, like "euro" so it would look for catalog like de_DE\@euro 140 /// 141 void variant(std::string const &); 142 /// 143 /// Get the required target charset encoding. Ignored for wide characters. 144 /// For narrow, should specify the correct encoding required for this catalog 145 /// 146 std::string encoding() const; 147 /// 148 /// Set the required target charset encoding. Ignored for wide characters. 149 /// For narrow, should specify the correct encoding required for this catalog 150 /// 151 void encoding(std::string const &); 152 153 /// 154 /// Get the locale category, is set by default to LC_MESSAGES, but may be changed 155 /// 156 std::string locale_category() const; 157 /// 158 /// Set the locale category, is set by default to LC_MESSAGES, but may be changed 159 /// 160 void locale_category(std::string const &); 161 162 /// 163 /// Get the callback for handling custom file systems, if it is empty, the real OS file-system 164 /// is being used. 165 /// 166 callback_type callback() const; 167 /// 168 /// Set the callback for handling custom file systems, if it is empty, the real OS file-system 169 /// is being used. 170 /// 171 void callback(callback_type const &); 172 173 /// 174 /// Type that defines a list of domains that are loaded 175 /// The first one is the default one 176 /// 177 typedef std::vector<domain> domains_type; 178 179 /// 180 /// Get message domains - application name, like my_app. So files named my_app.mo would be loaded 181 /// 182 domains_type domains() const; 183 /// 184 /// Add message domain - application name, like my_app. So files named my_app.mo would be loaded 185 /// 186 void add_domain(domain const &); 187 188 /// 189 /// Paths to search files in. Under MS Windows it uses encoding 190 /// parameter to convert them to wide OS specific paths. 191 /// 192 std::vector<std::string> paths() const; 193 194 /// 195 /// Add a path to search in 196 /// 197 void add_path(std::string const &); 198 199 /// 200 /// Optional formats to search the file in. 201 /// 202 /// Formats are the same syntax as the Boost format functions, but 203 /// use the following variables: 204 /// 205 /// \li {1} A path to search for catalogs in. 206 /// \li {2} The locale's name. 207 /// \li {3} The locale's category. 208 /// \li {4} The Gettext domain. 209 /// 210 /// For example, \c {1}/{2}/{3}/{4}.mo is the standard Gettext layout. 211 /// Using something like \c {1}/{2}.mo would compact the folder hierarchy, for an 212 /// application that uses a single domain 213 /// 214 std::vector<std::string> path_formats() const; 215 216 /// 217 /// Add new path format, see \ref path_formats() 218 /// 219 void add_path_format(std::string const &); 220 221 private: 222 struct data; 223 data *d; 224 }; 225 226 33 227 /// 228 /// Create a message_format facet using GNU Gettext catalogs. It uses \a info structure to get 229 /// information about where to read them from and uses it for character set conversion (if needed) 230 /// 231 template<typename CharType> 232 message_format<CharType> *create_messages_facet(catalog_info const &info); 233 234 235 // ---- deprecated stuff goes there --- // 236 237 238 239 /// 240 /// \brief This structure holds all information required for creating gnu-gettext message catalogs, 241 /// 242 /// The user is expected to set its parameters to load these catalogs correctly. This structure 243 /// also allows providing functions for charset conversion. Note, you need to provide them, 244 /// so this structure is not useful for wide characters without subclassing and it will also 245 /// ignore gettext catalogs that use a charset different from \a encoding. 246 /// 247 /// \deprecated Use catalog_info instead 248 /// 34 249 struct messages_info { 35 250 messages_info() : 36 251 language("C"), … … 124 339 /// 125 340 callback_type callback; 126 341 342 /// 343 /// Convert to non-deprecated format 344 /// 345 catalog_info to_catalog() const 346 { 347 catalog_info r; 348 349 r.language(language); 350 351 if(!country.empty()) 352 r.country(country); 353 if(!variant.empty()) 354 r.variant(variant); 355 if(!encoding.empty()) 356 r.encoding(encoding); 357 r.locale_category(locale_category); 358 if(!callback.empty()) 359 r.callback(callback); 360 for(size_t i=0;i<paths.size();i++) 361 r.add_path(paths[i]); 362 for(size_t i=0;i<domains.size();i++) { 363 if(domains[i].encoding.empty()) 364 r.add_domain(domains[i].name); 365 else 366 r.add_domain(boost::locale::gnu_gettext::domain(domains[i].name,domains[i].encoding)); 367 } 368 return r; 369 } 370 127 371 }; 128 372 129 373 /// 130 374 /// Create a message_format facet using GNU Gettext catalogs. It uses \a info structure to get 131 375 /// information about where to read them from and uses it for character set conversion (if needed) 132 376 /// 377 /// \deprecated use create_messages_facet(catalog_info const &info) 378 /// 133 379 134 380 template<typename CharType> 135 381 message_format<CharType> *create_messages_facet(messages_info const &info); 382 136 383 137 384 /// \cond INTERNAL 385 386 template<> 387 BOOST_LOCALE_DECL message_format<char> *create_messages_facet(catalog_info const &info); 138 388 139 389 template<> 390 BOOST_LOCALE_DECL message_format<wchar_t> *create_messages_facet(catalog_info const &info); 391 392 #ifdef BOOST_HAS_CHAR16_T 393 template<> 394 BOOST_LOCALE_DECL message_format<char16_t> *create_messages_facet(catalog_info const &info); 395 #endif 396 397 #ifdef BOOST_HAS_CHAR32_T 398 template<> 399 BOOST_LOCALE_DECL message_format<char32_t> *create_messages_facet(catalog_info const &info); 400 #endif 401 402 403 // deprecated internal stuff 404 405 template<> 140 406 BOOST_LOCALE_DECL message_format<char> *create_messages_facet(messages_info const &info); 141 407 142 408 template<> -
libs/locale/src/shared/message.cpp
9 9 #include <boost/config.hpp> 10 10 #include <boost/locale/message.hpp> 11 11 #include <boost/locale/gnu_gettext.hpp> 12 #include <boost/locale/format.hpp> 12 13 #include <boost/shared_ptr.hpp> 13 14 #include <boost/locale/encoding.hpp> 14 15 #ifdef BOOST_MSVC … … 533 534 return p->second; 534 535 } 535 536 536 mo_message( messages_info const &inf)537 mo_message(catalog_info const &inf) 537 538 { 538 std::string language = inf.language; 539 std::string variant = inf.variant; 540 std::string country = inf.country; 541 std::string encoding = inf.encoding; 542 std::string lc_cat = inf.locale_category; 543 std::vector<messages_info::domain> const &domains = inf.domains; 544 std::vector<std::string> const &search_paths = inf.paths; 539 std::vector<std::string> formats = inf.path_formats(); 545 540 541 std::string language = inf.language(); 542 std::string variant = inf.variant(); 543 std::string country = inf.country(); 544 std::string encoding = inf.encoding(); 545 std::string lc_cat = inf.locale_category(); 546 std::vector<boost::locale::gnu_gettext::domain> domains = inf.domains(); 547 std::vector<std::string> search_paths = inf.paths(); 548 546 549 // 547 550 // List of fallbacks: en_US@euro, en@euro, en_US, en. 548 551 // … … 566 569 567 570 568 571 for(unsigned id=0;id<domains.size();id++) { 569 std::string domain=domains[id].name ;570 std::string key_encoding = domains[id].encoding ;572 std::string domain=domains[id].name(); 573 std::string key_encoding = domains[id].encoding(); 571 574 domains_[domain]=id; 572 575 573 576 574 577 bool found=false; 575 578 for(unsigned j=0;!found && j<paths.size();j++) { 576 579 for(unsigned i=0;!found && i<search_paths.size();i++) { 577 std::string full_path = search_paths[i]+"/"+paths[j]+"/" + lc_cat + "/"+domain+".mo"; 578 found = load_file(full_path,encoding,key_encoding,id,inf.callback); 580 for(unsigned k=0;!found && k<formats.size();k++) { 581 std::string full_path = (format(formats[k]) % search_paths[i] % paths[j] % lc_cat % domain).str(std::locale::classic()); 582 found = load_file(full_path,encoding,key_encoding,id,inf.callback()); 583 } 579 584 } 580 585 } 581 586 } … … 743 748 bool key_conversion_required_; 744 749 }; 745 750 751 746 752 template<> 747 message_format<char> *create_messages_facet( messages_info const &info)753 message_format<char> *create_messages_facet(catalog_info const &data) 748 754 { 749 return new mo_message<char>( info);755 return new mo_message<char>(data); 750 756 } 751 757 752 758 template<> 753 message_format<wchar_t> *create_messages_facet( messages_info const &info)759 message_format<wchar_t> *create_messages_facet(catalog_info const &data) 754 760 { 755 return new mo_message<wchar_t>( info);761 return new mo_message<wchar_t>(data); 756 762 } 757 763 758 764 #ifdef BOOST_HAS_CHAR16_T 759 765 760 766 template<> 761 message_format<char16_t> *create_messages_facet( messages_info const &info)767 message_format<char16_t> *create_messages_facet(catalog_info const &data) 762 768 { 763 return new mo_message<char16_t>( info);769 return new mo_message<char16_t>(data); 764 770 } 765 771 #endif 766 772 767 773 #ifdef BOOST_HAS_CHAR32_T 768 774 769 775 template<> 770 message_format<char32_t> *create_messages_facet( messages_info const &info)776 message_format<char32_t> *create_messages_facet(catalog_info const &data) 771 777 { 772 return new mo_message<char32_t>( info);778 return new mo_message<char32_t>(data); 773 779 } 774 780 #endif 775 781 782 template<> 783 message_format<char> *create_messages_facet(messages_info const &data) 784 { 785 return new mo_message<char>(data.to_catalog()); 786 } 776 787 788 template<> 789 message_format<wchar_t> *create_messages_facet(messages_info const &data) 790 { 791 return new mo_message<wchar_t>(data.to_catalog()); 792 } 793 794 #ifdef BOOST_HAS_CHAR16_T 795 796 template<> 797 message_format<char16_t> *create_messages_facet(messages_info const &data) 798 { 799 return new mo_message<char16_t>(data.to_catalog()); 800 } 801 #endif 802 803 #ifdef BOOST_HAS_CHAR32_T 804 805 template<> 806 message_format<char32_t> *create_messages_facet(messages_info const &data) 807 { 808 return new mo_message<char32_t>(data.to_catalog()); 809 } 810 #endif 811 812 struct domain::data {}; 813 domain::domain() : d(0) {} 814 domain::~domain() {} 815 domain::domain(domain const &other) : 816 d(0), 817 name_(other.name_), 818 encoding_(other.encoding_) 819 { 820 } 821 domain const &domain::operator=(domain const &other) 822 { 823 if(this!=&other) { 824 name_ = other.name_; 825 encoding_ = other.encoding_; 826 } 827 return *this; 828 } 829 std::string domain::name() const { return name_; } 830 std::string domain::encoding() const { return encoding_; } 831 domain::domain(std::string const &n,std::string const &e) :d(0),name_(n),encoding_(e) {} 832 domain::domain(std::string const &n) : d(0) 833 { 834 size_t pos = n.find("/"); 835 if(pos==std::string::npos) { 836 name_ = n; 837 encoding_ = "UTF-8"; 838 } 839 else { 840 name_ = n.substr(0,pos); 841 encoding_ = n.substr(pos+1); 842 } 843 } 844 bool domain::operator==(domain const &other) const 845 { 846 return name_ == other.name_; 847 } 848 bool domain::operator!=(domain const &other) const 849 { 850 return !(*this == other); 851 } 852 853 struct catalog_info::data { 854 data() : language("C"), locale_category("LC_MESSAGES") {} 855 std::string language; 856 std::string country; 857 std::string variant; 858 std::string encoding; 859 std::string locale_category; 860 std::vector<domain> domains; 861 std::vector<std::string> paths; 862 callback_type callback; 863 std::vector<std::string> path_formats; 864 }; 865 866 catalog_info::catalog_info() : d(new catalog_info::data()) 867 { 868 } 869 catalog_info::~catalog_info() { delete d; } 870 // d is never 0 871 catalog_info::catalog_info(catalog_info const &other) : d(new catalog_info::data(*other.d)) 872 { 873 } 874 875 catalog_info const &catalog_info::operator=(catalog_info const &other) 876 { 877 if(this != &other) { 878 // d is never 0 879 catalog_info::data *p = new catalog_info::data(*other.d); 880 delete d; 881 d=p; 882 } 883 return *this; 884 } 885 886 887 std::string catalog_info::language() const { return d->language; } 888 void catalog_info::language(std::string const &v) { d->language=v; } 889 890 std::string catalog_info::country() const { return d->country; } 891 void catalog_info::country(std::string const &v) { d->country=v; } 892 893 std::string catalog_info::variant() const { return d->variant; } 894 void catalog_info::variant(std::string const &v) { d->variant=v; } 895 896 std::string catalog_info::encoding() const { return d->encoding; } 897 void catalog_info::encoding(std::string const &v) { d->encoding=v; } 898 899 std::string catalog_info::locale_category() const { return d->locale_category; } 900 void catalog_info::locale_category(std::string const &v) { d->locale_category=v; } 901 902 callback_type catalog_info::callback() const { return d->callback; } 903 void catalog_info::callback(callback_type const &v) { d->callback=v; } 904 905 catalog_info::domains_type catalog_info::domains() const { return d->domains; } 906 void catalog_info::add_domain(domain const &v) { d->domains.push_back(v); } 907 908 std::vector<std::string> catalog_info::paths() const { return d->paths; } 909 void catalog_info::add_path(std::string const &v) { d->paths.push_back(v); } 910 911 std::vector<std::string> catalog_info::path_formats() const 912 { 913 if(d->path_formats.empty()) { 914 std::vector<std::string> r; 915 r.push_back("{1}/{2}/{3}/{4}.mo"); 916 return r; 917 } 918 return d->path_formats; 919 } 920 void catalog_info::add_path_format(std::string const &v) { d->path_formats.push_back(v); } 921 922 923 924 925 926 777 927 } /// gnu_gettext 778 928 779 929 } // locale