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