test_message.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. //
  2. // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. #include <boost/locale/generator.hpp>
  9. #include <boost/locale/localization_backend.hpp>
  10. #include <boost/locale/message.hpp>
  11. #include <boost/locale/gnu_gettext.hpp>
  12. #include <boost/locale/encoding.hpp>
  13. #include "test_locale.hpp"
  14. #include "test_locale_tools.hpp"
  15. #include <fstream>
  16. namespace bl = boost::locale;
  17. std::string backend;
  18. bool file_loader_is_actually_called = false;
  19. struct file_loader {
  20. std::vector<char> operator()(std::string const &name,std::string const &/*encoding*/) const
  21. {
  22. std::vector<char> buffer;
  23. std::ifstream f(name.c_str(),std::ifstream::binary);
  24. if(!f)
  25. return buffer;
  26. f.seekg(0,std::ifstream::end);
  27. size_t len = f.tellg();
  28. if(len == 0)
  29. return buffer;
  30. f.seekg(0);
  31. buffer.resize(len,'\0');
  32. f.read(&buffer[0],len);
  33. file_loader_is_actually_called = true;
  34. return buffer;
  35. }
  36. };
  37. std::string same_s(std::string s)
  38. {
  39. return s;
  40. }
  41. std::wstring same_w(std::wstring s)
  42. {
  43. return s;
  44. }
  45. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  46. std::u16string same_u16(std::u16string s)
  47. {
  48. return s;
  49. }
  50. #endif
  51. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  52. std::u32string same_u32(std::u32string s)
  53. {
  54. return s;
  55. }
  56. #endif
  57. template<typename Char>
  58. void strings_equal(std::string n_c,std::string n_s,std::string n_p,int n,std::string iexpected,std::locale const &l,std::string domain)
  59. {
  60. typedef std::basic_string<Char> string_type;
  61. string_type expected=to_correct_string<Char>(iexpected,l);
  62. string_type c = to<Char>(n_c.c_str());
  63. string_type s = to<Char>(n_s.c_str());
  64. string_type p = to<Char>(n_p.c_str());
  65. if(domain=="default") {
  66. TEST(bl::translate(c,s,p,n).str(l)==expected);
  67. Char const *c_c_str = c.c_str(),*s_c_str=s.c_str(), *p_c_str=p.c_str(); // workaround gcc-3.4 bug
  68. TEST(bl::translate(c_c_str,s_c_str,p_c_str,n).str(l)==expected);
  69. std::locale tmp_locale=std::locale();
  70. std::locale::global(l);
  71. string_type tmp=bl::translate(c,s,p,n);
  72. TEST(tmp==expected);
  73. tmp=bl::translate(c,s,p,n).str();
  74. TEST(tmp==expected);
  75. std::locale::global(tmp_locale);
  76. std::basic_ostringstream<Char> ss;
  77. ss.imbue(l);
  78. ss << bl::translate(c,s,p,n);
  79. TEST(ss.str()==expected);
  80. }
  81. TEST( bl::translate(c,s,p,n).str(l,domain)==expected );
  82. std::locale tmp_locale=std::locale();
  83. std::locale::global(l);
  84. TEST(bl::translate(c,s,p,n).str(domain)==expected);
  85. std::locale::global(tmp_locale);
  86. {
  87. std::basic_ostringstream<Char> ss;
  88. ss.imbue(l);
  89. ss << bl::as::domain(domain) << bl::translate(c,s,p,n);
  90. TEST(ss.str()==expected);
  91. }
  92. {
  93. std::basic_ostringstream<Char> ss;
  94. ss.imbue(l);
  95. ss << bl::as::domain(domain) << bl::translate(c.c_str(),s.c_str(),p.c_str(),n);
  96. TEST(ss.str()==expected);
  97. }
  98. }
  99. template<typename Char>
  100. void strings_equal(std::string n_s,std::string n_p,int n,std::string iexpected,std::locale const &l,std::string domain)
  101. {
  102. typedef std::basic_string<Char> string_type;
  103. string_type expected=to_correct_string<Char>(iexpected,l);
  104. string_type s = to<Char>(n_s.c_str());
  105. string_type p = to<Char>(n_p.c_str());
  106. if(domain=="default") {
  107. TEST(bl::translate(s,p,n).str(l)==expected);
  108. Char const *s_c_str=s.c_str(), *p_c_str=p.c_str(); // workaround gcc-3.4 bug
  109. TEST(bl::translate(s_c_str,p_c_str,n).str(l)==expected);
  110. std::locale tmp_locale=std::locale();
  111. std::locale::global(l);
  112. string_type tmp=bl::translate(s,p,n);
  113. TEST(tmp==expected);
  114. tmp=bl::translate(s,p,n).str();
  115. TEST(tmp==expected);
  116. std::locale::global(tmp_locale);
  117. std::basic_ostringstream<Char> ss;
  118. ss.imbue(l);
  119. ss << bl::translate(s,p,n);
  120. TEST(ss.str()==expected);
  121. }
  122. TEST(bl::translate(s,p,n).str(l,domain)==expected);
  123. std::locale tmp_locale=std::locale();
  124. std::locale::global(l);
  125. TEST(bl::translate(s,p,n).str(domain)==expected);
  126. std::locale::global(tmp_locale);
  127. {
  128. std::basic_ostringstream<Char> ss;
  129. ss.imbue(l);
  130. ss << bl::as::domain(domain) << bl::translate(s,p,n);
  131. TEST(ss.str()==expected);
  132. }
  133. {
  134. std::basic_ostringstream<Char> ss;
  135. ss.imbue(l);
  136. ss << bl::as::domain(domain) << bl::translate(s.c_str(),p.c_str(),n);
  137. TEST(ss.str()==expected);
  138. }
  139. }
  140. template<typename Char>
  141. void strings_equal(std::string n_c,std::string n_original,std::string iexpected,std::locale const &l,std::string domain)
  142. {
  143. typedef std::basic_string<Char> string_type;
  144. string_type expected=to_correct_string<Char>(iexpected,l);
  145. string_type original = to<Char>(n_original.c_str());
  146. string_type c = to<Char>(n_c.c_str());
  147. if(domain=="default") {
  148. TEST(bl::translate(c,original).str(l)==expected);
  149. Char const *original_c_str=original.c_str(); // workaround gcc-3.4 bug
  150. Char const *context_c_str = c.c_str();
  151. TEST(bl::translate(context_c_str,original_c_str).str(l)==expected);
  152. std::locale tmp_locale=std::locale();
  153. std::locale::global(l);
  154. string_type tmp=bl::translate(c,original);
  155. TEST(tmp==expected);
  156. tmp=bl::translate(c,original).str();
  157. TEST(tmp==expected);
  158. std::locale::global(tmp_locale);
  159. std::basic_ostringstream<Char> ss;
  160. ss.imbue(l);
  161. ss << bl::translate(c,original);
  162. TEST(ss.str()==expected);
  163. }
  164. TEST(bl::translate(c,original).str(l,domain)==expected);
  165. std::locale tmp_locale=std::locale();
  166. std::locale::global(l);
  167. TEST(bl::translate(c,original).str(domain)==expected);
  168. std::locale::global(tmp_locale);
  169. {
  170. std::basic_ostringstream<Char> ss;
  171. ss.imbue(l);
  172. ss << bl::as::domain(domain) << bl::translate(c,original);
  173. TEST(ss.str()==expected);
  174. }
  175. {
  176. std::basic_ostringstream<Char> ss;
  177. ss.imbue(l);
  178. ss << bl::as::domain(domain) << bl::translate(c.c_str(),original.c_str());
  179. TEST(ss.str()==expected);
  180. }
  181. }
  182. template<typename Char>
  183. void strings_equal(std::string n_original,std::string iexpected,std::locale const &l,std::string domain)
  184. {
  185. typedef std::basic_string<Char> string_type;
  186. string_type expected=to_correct_string<Char>(iexpected,l);
  187. string_type original = to<Char>(n_original.c_str());
  188. if(domain=="default") {
  189. TEST(bl::translate(original).str(l)==expected);
  190. Char const *original_c_str=original.c_str(); // workaround gcc-3.4 bug
  191. TEST(bl::translate(original_c_str).str(l)==expected);
  192. std::locale tmp_locale=std::locale();
  193. std::locale::global(l);
  194. string_type tmp=bl::translate(original);
  195. TEST(tmp==expected);
  196. tmp=bl::translate(original).str();
  197. TEST(tmp==expected);
  198. std::locale::global(tmp_locale);
  199. std::basic_ostringstream<Char> ss;
  200. ss.imbue(l);
  201. ss << bl::translate(original);
  202. TEST(ss.str()==expected);
  203. }
  204. TEST(bl::translate(original).str(l,domain)==expected);
  205. std::locale tmp_locale=std::locale();
  206. std::locale::global(l);
  207. TEST(bl::translate(original).str(domain)==expected);
  208. std::locale::global(tmp_locale);
  209. {
  210. std::basic_ostringstream<Char> ss;
  211. ss.imbue(l);
  212. ss << bl::as::domain(domain) << bl::translate(original);
  213. TEST(ss.str()==expected);
  214. }
  215. {
  216. std::basic_ostringstream<Char> ss;
  217. ss.imbue(l);
  218. ss << bl::as::domain(domain) << bl::translate(original.c_str());
  219. TEST(ss.str()==expected);
  220. }
  221. }
  222. void test_cntranslate(std::string c,std::string s,std::string p,int n,std::string expected,std::locale const &l,std::string domain)
  223. {
  224. strings_equal<char>(c,s,p,n,expected,l,domain);
  225. strings_equal<wchar_t>(c,s,p,n,expected,l,domain);
  226. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  227. if(backend=="icu" || backend=="std")
  228. strings_equal<char16_t>(c,s,p,n,expected,l,domain);
  229. #endif
  230. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  231. if(backend=="icu" || backend=="std")
  232. strings_equal<char32_t>(c,s,p,n,expected,l,domain);
  233. #endif
  234. }
  235. void test_ntranslate(std::string s,std::string p,int n,std::string expected,std::locale const &l,std::string domain)
  236. {
  237. strings_equal<char>(s,p,n,expected,l,domain);
  238. strings_equal<wchar_t>(s,p,n,expected,l,domain);
  239. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  240. if(backend=="icu" || backend=="std")
  241. strings_equal<char16_t>(s,p,n,expected,l,domain);
  242. #endif
  243. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  244. if(backend=="icu" || backend=="std")
  245. strings_equal<char32_t>(s,p,n,expected,l,domain);
  246. #endif
  247. }
  248. void test_ctranslate(std::string c,std::string original,std::string expected,std::locale const &l,std::string domain)
  249. {
  250. strings_equal<char>(c,original,expected,l,domain);
  251. strings_equal<wchar_t>(c,original,expected,l,domain);
  252. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  253. if(backend=="icu" || backend=="std")
  254. strings_equal<char16_t>(c,original,expected,l,domain);
  255. #endif
  256. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  257. if(backend=="icu" || backend=="std")
  258. strings_equal<char32_t>(c,original,expected,l,domain);
  259. #endif
  260. }
  261. void test_translate(std::string original,std::string expected,std::locale const &l,std::string domain)
  262. {
  263. strings_equal<char>(original,expected,l,domain);
  264. strings_equal<wchar_t>(original,expected,l,domain);
  265. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  266. if(backend=="icu" || backend=="std")
  267. strings_equal<char16_t>(original,expected,l,domain);
  268. #endif
  269. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  270. if(backend=="icu" || backend=="std")
  271. strings_equal<char32_t>(original,expected,l,domain);
  272. #endif
  273. }
  274. bool iso_8859_8_not_supported = false;
  275. int main(int argc,char **argv)
  276. {
  277. try {
  278. std::string def[] = {
  279. #ifdef BOOST_LOCALE_WITH_ICU
  280. "icu" ,
  281. #endif
  282. #ifndef BOOST_LOCALE_NO_STD_BACKEND
  283. "std" ,
  284. #endif
  285. #ifndef BOOST_LOCALE_NO_POSIX_BACKEND
  286. "posix",
  287. #endif
  288. #ifndef BOOST_LOCALE_NO_WINAPI_BACKEND
  289. "winapi",
  290. #endif
  291. };
  292. for(int type = 0 ; type < int(sizeof(def)/sizeof(def[0])) ; type ++ ) {
  293. boost::locale::localization_backend_manager tmp_backend = boost::locale::localization_backend_manager::global();
  294. tmp_backend.select(def[type]);
  295. boost::locale::localization_backend_manager::global(tmp_backend);
  296. backend = def[type];
  297. std::cout << "Testing for backend --------- " << def[type] << std::endl;
  298. boost::locale::generator g;
  299. g.add_messages_domain("simple");
  300. g.add_messages_domain("full");
  301. g.add_messages_domain("fall");
  302. if(argc==2)
  303. g.add_messages_path(argv[1]);
  304. else
  305. g.add_messages_path("./");
  306. g.set_default_messages_domain("default");
  307. std::string locales[] = { "he_IL.UTF-8", "he_IL.ISO8859-8" };
  308. for(unsigned i=0;i<sizeof(locales)/sizeof(locales[0]);i++){
  309. std::locale l;
  310. if(i==1) {
  311. try {
  312. l = g(locales[i]);
  313. }
  314. catch(boost::locale::conv::invalid_charset_error const &e) {
  315. std::cout << "Looks like ISO-8859-8 is not supported! skipping" << std::endl;
  316. iso_8859_8_not_supported = true;
  317. continue;
  318. }
  319. }
  320. else {
  321. l = g(locales[i]);
  322. }
  323. std::cout << " Testing "<<locales[i]<<std::endl;
  324. std::cout << " single forms" << std::endl;
  325. test_translate("hello","שלום",l,"default");
  326. test_translate("hello","היי",l,"simple");
  327. test_translate("hello","hello",l,"undefined");
  328. test_translate("untranslated","untranslated",l,"default");
  329. // Check removal of old "context" information
  330. test_translate("#untranslated","#untranslated",l,"default");
  331. test_translate("##untranslated","##untranslated",l,"default");
  332. test_ctranslate("context","hello","שלום בהקשר אחר",l,"default");
  333. test_translate("#hello","#שלום",l,"default");
  334. std::cout << " plural forms" << std::endl;
  335. {
  336. test_ntranslate("x day","x days",0,"x ימים",l,"default");
  337. test_ntranslate("x day","x days",1,"יום x",l,"default");
  338. test_ntranslate("x day","x days",2,"יומיים",l,"default");
  339. test_ntranslate("x day","x days",3,"x ימים",l,"default");
  340. test_ntranslate("x day","x days",20,"x יום",l,"default");
  341. test_ntranslate("x day","x days",0,"x days",l,"undefined");
  342. test_ntranslate("x day","x days",1,"x day",l,"undefined");
  343. test_ntranslate("x day","x days",2,"x days",l,"undefined");
  344. test_ntranslate("x day","x days",20,"x days",l,"undefined");
  345. }
  346. std::cout << " plural forms with context" << std::endl;
  347. {
  348. std::string inp = "context";
  349. std::string out = "בהקשר ";
  350. test_cntranslate(inp,"x day","x days",0,out+"x ימים",l,"default");
  351. test_cntranslate(inp,"x day","x days",1,out+"יום x",l,"default");
  352. test_cntranslate(inp,"x day","x days",2,out+"יומיים",l,"default");
  353. test_cntranslate(inp,"x day","x days",3,out+"x ימים",l,"default");
  354. test_cntranslate(inp,"x day","x days",20,out+"x יום",l,"default");
  355. test_cntranslate(inp,"x day","x days",0,"x days",l,"undefined");
  356. test_cntranslate(inp,"x day","x days",1,"x day",l,"undefined");
  357. test_cntranslate(inp,"x day","x days",2,"x days",l,"undefined");
  358. test_cntranslate(inp,"x day","x days",20,"x days",l,"undefined");
  359. }
  360. }
  361. std::cout << " Testing fallbacks" <<std::endl;
  362. test_translate("test","he_IL",g("he_IL.UTF-8"),"full");
  363. test_translate("test","he",g("he_IL.UTF-8"),"fall");
  364. std::cout << " Testing automatic conversions " << std::endl;
  365. std::locale::global(g("he_IL.UTF-8"));
  366. TEST(same_s(bl::translate("hello"))=="שלום");
  367. TEST(same_w(bl::translate(to<wchar_t>("hello")))==to<wchar_t>("שלום"));
  368. #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
  369. if(backend=="icu" || backend=="std")
  370. TEST(same_u16(bl::translate(to<char16_t>("hello")))==to<char16_t>("שלום"));
  371. #endif
  372. #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
  373. if(backend=="icu" || backend=="std")
  374. TEST(same_u32(bl::translate(to<char32_t>("hello")))==to<char32_t>("שלום"));
  375. #endif
  376. }
  377. std::cout << "Testing custom file system support" << std::endl;
  378. {
  379. boost::locale::gnu_gettext::messages_info info;
  380. info.language = "he";
  381. info.country = "IL";
  382. info.encoding="UTF-8";
  383. if(argc==2)
  384. info.paths.push_back(argv[1]);
  385. else
  386. info.paths.push_back("./");
  387. info.domains.push_back(bl::gnu_gettext::messages_info::domain("default"));
  388. info.callback = file_loader();
  389. std::locale l(std::locale::classic(),boost::locale::gnu_gettext::create_messages_facet<char>(info));
  390. TEST(file_loader_is_actually_called);
  391. TEST(bl::translate("hello").str(l)=="שלום");
  392. }
  393. if(iso_8859_8_not_supported)
  394. {
  395. std::cout << "ISO 8859-8 not supported so skipping non-US-ASCII keys" << std::endl;
  396. }
  397. else
  398. {
  399. std::cout << "Testing non-US-ASCII keys" << std::endl;
  400. std::cout << " UTF-8 keys" << std::endl;
  401. {
  402. boost::locale::generator g;
  403. g.add_messages_domain("default");
  404. if(argc==2)
  405. g.add_messages_path(argv[1]);
  406. else
  407. g.add_messages_path("./");
  408. std::locale l = g("he_IL.UTF-8");
  409. // narrow
  410. TEST(bl::gettext("בדיקה",l)=="test");
  411. TEST(bl::gettext("לא קיים",l)=="לא קיים");
  412. // wide
  413. std::wstring wtest = bl::conv::to_utf<wchar_t>("בדיקה","UTF-8");
  414. std::wstring wmiss = bl::conv::to_utf<wchar_t>("לא קיים","UTF-8");
  415. TEST(bl::gettext(wtest.c_str(),l)==L"test");
  416. TEST(bl::gettext(wmiss.c_str(),l)==wmiss);
  417. l=g("he_IL.ISO-8859-8");
  418. // conversion with substitution
  419. TEST(bl::gettext("test-あにま-בדיקה",l)==bl::conv::from_utf("test--בדיקה","ISO-8859-8"));
  420. }
  421. std::cout << " `ANSI' keys" << std::endl;
  422. {
  423. boost::locale::generator g;
  424. g.add_messages_domain("default/ISO-8859-8");
  425. if(argc==2)
  426. g.add_messages_path(argv[1]);
  427. else
  428. g.add_messages_path("./");
  429. std::locale l = g("he_IL.UTF-8");
  430. // narrow non-UTF-8 keys
  431. // match
  432. TEST(bl::gettext(bl::conv::from_utf("בדיקה","ISO-8859-8").c_str(),l)=="test");
  433. // conversion
  434. TEST(bl::gettext(bl::conv::from_utf("לא קיים","ISO-8859-8").c_str(),l)=="לא קיים");
  435. }
  436. }
  437. // Test compiles
  438. {
  439. bl::gettext("");
  440. bl::gettext(L"");
  441. bl::dgettext("","");
  442. bl::dgettext("",L"");
  443. bl::pgettext("","");
  444. bl::pgettext(L"",L"");
  445. bl::dpgettext("","","");
  446. bl::dpgettext("",L"",L"");
  447. bl::ngettext("","",1);
  448. bl::ngettext(L"",L"",1);
  449. bl::dngettext("","","",1);
  450. bl::dngettext("",L"",L"",1);
  451. bl::npgettext("","","",1);
  452. bl::npgettext(L"",L"",L"",1);
  453. bl::dnpgettext("","","","",1);
  454. bl::dnpgettext("",L"",L"",L"",1);
  455. }
  456. }
  457. catch(std::exception const &e) {
  458. std::cerr << "Failed " << e.what() << std::endl;
  459. return EXIT_FAILURE;
  460. }
  461. FINALIZE();
  462. }
  463. // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
  464. // boostinspect:noascii