internat.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: internat.cpp
  3. // Purpose: Demonstrates internationalisation (i18n) support
  4. // Author: Vadim Zeitlin/Julian Smart
  5. // Modified by:
  6. // Created: 04/01/98
  7. // Copyright: (c) Julian Smart
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // NOTE: don't miss the "readme.txt" file which comes with this sample!
  11. // ============================================================================
  12. // declarations
  13. // ============================================================================
  14. // ----------------------------------------------------------------------------
  15. // headers
  16. // ----------------------------------------------------------------------------
  17. // For compilers that support precompilation, includes "wx/wx.h".
  18. #include "wx/wxprec.h"
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22. #ifndef WX_PRECOMP
  23. #include "wx/wx.h"
  24. #endif
  25. #include "wx/intl.h"
  26. #include "wx/file.h"
  27. #include "wx/log.h"
  28. #include "wx/cmdline.h"
  29. #ifndef wxHAS_IMAGES_IN_RESOURCES
  30. #include "../sample.xpm"
  31. #endif
  32. // ----------------------------------------------------------------------------
  33. // private classes
  34. // ----------------------------------------------------------------------------
  35. // Define a new application type
  36. class MyApp: public wxApp
  37. {
  38. public:
  39. MyApp() { m_lang = wxLANGUAGE_UNKNOWN; }
  40. virtual void OnInitCmdLine(wxCmdLineParser& parser);
  41. virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
  42. virtual bool OnInit();
  43. protected:
  44. wxLanguage m_lang; // language specified by user
  45. wxLocale m_locale; // locale we'll be using
  46. };
  47. // Define a new frame type
  48. class MyFrame: public wxFrame
  49. {
  50. public:
  51. MyFrame(wxLocale& m_locale);
  52. public:
  53. void OnTestLocaleAvail(wxCommandEvent& event);
  54. void OnAbout(wxCommandEvent& event);
  55. void OnQuit(wxCommandEvent& event);
  56. void OnPlay(wxCommandEvent& event);
  57. void OnOpen(wxCommandEvent& event);
  58. void OnTest1(wxCommandEvent& event);
  59. void OnTest2(wxCommandEvent& event);
  60. void OnTest3(wxCommandEvent& event);
  61. void OnTestMsgBox(wxCommandEvent& event);
  62. wxDECLARE_EVENT_TABLE();
  63. wxLocale& m_locale;
  64. };
  65. // ----------------------------------------------------------------------------
  66. // constants
  67. // ----------------------------------------------------------------------------
  68. // ID for the menu commands
  69. enum
  70. {
  71. INTERNAT_TEST = wxID_HIGHEST + 1,
  72. INTERNAT_PLAY,
  73. INTERNAT_TEST_1,
  74. INTERNAT_TEST_2,
  75. INTERNAT_TEST_3,
  76. INTERNAT_TEST_MSGBOX
  77. };
  78. // language data
  79. static const wxLanguage langIds[] =
  80. {
  81. wxLANGUAGE_DEFAULT,
  82. wxLANGUAGE_FRENCH,
  83. wxLANGUAGE_ITALIAN,
  84. wxLANGUAGE_GERMAN,
  85. wxLANGUAGE_RUSSIAN,
  86. wxLANGUAGE_BULGARIAN,
  87. wxLANGUAGE_CZECH,
  88. wxLANGUAGE_POLISH,
  89. wxLANGUAGE_SWEDISH,
  90. #if wxUSE_UNICODE || defined(__WXMOTIF__)
  91. wxLANGUAGE_JAPANESE,
  92. #endif
  93. #if wxUSE_UNICODE
  94. wxLANGUAGE_GEORGIAN,
  95. wxLANGUAGE_ENGLISH,
  96. wxLANGUAGE_ENGLISH_US,
  97. wxLANGUAGE_ARABIC,
  98. wxLANGUAGE_ARABIC_EGYPT
  99. #endif
  100. };
  101. // note that it makes no sense to translate these strings, they are
  102. // shown before we set the locale anyhow
  103. const wxString langNames[] =
  104. {
  105. "System default",
  106. "French",
  107. "Italian",
  108. "German",
  109. "Russian",
  110. "Bulgarian",
  111. "Czech",
  112. "Polish",
  113. "Swedish",
  114. #if wxUSE_UNICODE || defined(__WXMOTIF__)
  115. "Japanese",
  116. #endif
  117. #if wxUSE_UNICODE
  118. "Georgian",
  119. "English",
  120. "English (U.S.)",
  121. "Arabic",
  122. "Arabic (Egypt)"
  123. #endif
  124. };
  125. // the arrays must be in sync
  126. wxCOMPILE_TIME_ASSERT( WXSIZEOF(langNames) == WXSIZEOF(langIds),
  127. LangArraysMismatch );
  128. // ----------------------------------------------------------------------------
  129. // wxWidgets macros
  130. // ----------------------------------------------------------------------------
  131. wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
  132. EVT_MENU(INTERNAT_TEST, MyFrame::OnTestLocaleAvail)
  133. EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
  134. EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
  135. EVT_MENU(INTERNAT_PLAY, MyFrame::OnPlay)
  136. EVT_MENU(wxID_OPEN, MyFrame::OnOpen)
  137. EVT_MENU(INTERNAT_TEST_1, MyFrame::OnTest1)
  138. EVT_MENU(INTERNAT_TEST_2, MyFrame::OnTest2)
  139. EVT_MENU(INTERNAT_TEST_3, MyFrame::OnTest3)
  140. EVT_MENU(INTERNAT_TEST_MSGBOX, MyFrame::OnTestMsgBox)
  141. wxEND_EVENT_TABLE()
  142. IMPLEMENT_APP(MyApp)
  143. // ============================================================================
  144. // implementation
  145. // ============================================================================
  146. // ----------------------------------------------------------------------------
  147. // MyApp
  148. // ----------------------------------------------------------------------------
  149. // command line arguments handling
  150. void MyApp::OnInitCmdLine(wxCmdLineParser& parser)
  151. {
  152. parser.AddParam(_("locale"),
  153. wxCMD_LINE_VAL_STRING,
  154. wxCMD_LINE_PARAM_OPTIONAL);
  155. wxApp::OnInitCmdLine(parser);
  156. }
  157. bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser)
  158. {
  159. if ( !wxApp::OnCmdLineParsed(parser) )
  160. return false;
  161. if ( parser.GetParamCount() )
  162. {
  163. const wxString loc = parser.GetParam();
  164. const wxLanguageInfo * const lang = wxLocale::FindLanguageInfo(loc);
  165. if ( !lang )
  166. {
  167. wxLogError(_("Locale \"%s\" is unknown."), loc);
  168. return false;
  169. }
  170. m_lang = static_cast<wxLanguage>(lang->Language);
  171. }
  172. return true;
  173. }
  174. // `Main program' equivalent, creating windows and returning main app frame
  175. bool MyApp::OnInit()
  176. {
  177. if ( !wxApp::OnInit() )
  178. return false;
  179. if ( m_lang == wxLANGUAGE_UNKNOWN )
  180. {
  181. int lng = wxGetSingleChoiceIndex
  182. (
  183. _("Please choose language:"),
  184. _("Language"),
  185. WXSIZEOF(langNames),
  186. langNames
  187. );
  188. m_lang = lng == -1 ? wxLANGUAGE_DEFAULT : langIds[lng];
  189. }
  190. // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return
  191. // false just because it failed to load wxstd catalog
  192. if ( !m_locale.Init(m_lang, wxLOCALE_DONT_LOAD_DEFAULT) )
  193. {
  194. wxLogWarning(_("This language is not supported by the system."));
  195. // continue nevertheless
  196. }
  197. // normally this wouldn't be necessary as the catalog files would be found
  198. // in the default locations, but when the program is not installed the
  199. // catalogs are in the build directory where we wouldn't find them by
  200. // default
  201. wxLocale::AddCatalogLookupPathPrefix(".");
  202. // Initialize the catalogs we'll be using
  203. const wxLanguageInfo* pInfo = wxLocale::GetLanguageInfo(m_lang);
  204. if (!m_locale.AddCatalog("internat"))
  205. {
  206. wxLogError(_("Couldn't find/load the 'internat' catalog for locale '%s'."),
  207. pInfo ? pInfo->GetLocaleName() : _("unknown"));
  208. }
  209. // Now try to add wxstd.mo so that loading "NOTEXIST.ING" file will produce
  210. // a localized error message:
  211. m_locale.AddCatalog("wxstd");
  212. // NOTE: it's not an error if we couldn't find it!
  213. // this catalog is installed in standard location on Linux systems and
  214. // shows that you may make use of the standard message catalogs as well
  215. //
  216. // if it's not installed on your system, it is just silently ignored
  217. #ifdef __LINUX__
  218. {
  219. wxLogNull noLog;
  220. m_locale.AddCatalog("fileutils");
  221. }
  222. #endif
  223. // Create the main frame window
  224. MyFrame *frame = new MyFrame(m_locale);
  225. // Show the frame
  226. frame->Show(true);
  227. return true;
  228. }
  229. // ----------------------------------------------------------------------------
  230. // MyFrame
  231. // ----------------------------------------------------------------------------
  232. // main frame constructor
  233. MyFrame::MyFrame(wxLocale& locale)
  234. : wxFrame(NULL,
  235. wxID_ANY,
  236. _("International wxWidgets App")),
  237. m_locale(locale)
  238. {
  239. SetIcon(wxICON(sample));
  240. // Make a menubar
  241. wxMenu *file_menu = new wxMenu;
  242. file_menu->Append(INTERNAT_TEST, _("&Test locale availability...\tCtrl-T"));
  243. file_menu->AppendSeparator();
  244. // since wxID_ABOUT and wxID_EXIT are stock IDs they will automatically get
  245. // translated help strings; nice isn't it?
  246. file_menu->Append(wxID_ABOUT, _("&About"));
  247. file_menu->AppendSeparator();
  248. file_menu->Append(wxID_EXIT, _("E&xit"));
  249. wxMenu *test_menu = new wxMenu;
  250. test_menu->Append(wxID_OPEN, _("&Open bogus file"), _("Shows a wxWidgets localized error message"));
  251. test_menu->Append(INTERNAT_PLAY, _("&Play a game"), _("A little game; hint: 17 is a lucky number for many"));
  252. test_menu->AppendSeparator();
  253. test_menu->Append(INTERNAT_TEST_1, _("&1 _() (gettext)"), _("Tests the _() macro"));
  254. test_menu->Append(INTERNAT_TEST_2, _("&2 _N() (ngettext)"), _("Tests the _N() macro"));
  255. test_menu->Append(INTERNAT_TEST_3, _("&3 wxTRANSLATE() (gettext_noop)"), _("Tests the wxTRANSLATE() macro"));
  256. test_menu->Append(INTERNAT_TEST_MSGBOX, _("&Message box test"),
  257. _("Tests message box buttons labels translation"));
  258. wxMenuBar *menu_bar = new wxMenuBar;
  259. menu_bar->Append(file_menu, _("&File"));
  260. menu_bar->Append(test_menu, _("&Test"));
  261. SetMenuBar(menu_bar);
  262. // this demonstrates RTL support in wxStatusBar:
  263. CreateStatusBar(1);
  264. // this demonstrates RTL layout mirroring for Arabic locales
  265. wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
  266. sizer->Add(new wxStaticText(this, wxID_ANY, _("First")),
  267. wxSizerFlags().Border());
  268. sizer->Add(new wxStaticText(this, wxID_ANY, _("Second")),
  269. wxSizerFlags().Border());
  270. SetSizer(sizer);
  271. }
  272. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
  273. {
  274. Close(true);
  275. }
  276. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  277. {
  278. wxString localeInfo;
  279. wxString locale = m_locale.GetLocale();
  280. wxString sysname = m_locale.GetSysName();
  281. wxString canname = m_locale.GetCanonicalName();
  282. localeInfo.Printf(_("Language: %s\nSystem locale name: %s\nCanonical locale name: %s\n"),
  283. locale.c_str(), sysname.c_str(), canname.c_str() );
  284. wxMessageDialog dlg(
  285. this,
  286. wxString(_("I18n sample\n(c) 1998, 1999 Vadim Zeitlin and Julian Smart"))
  287. + "\n\n"
  288. + localeInfo,
  289. _("About Internat"),
  290. wxOK | wxICON_INFORMATION
  291. );
  292. dlg.ShowModal();
  293. }
  294. void MyFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
  295. {
  296. wxString str = wxGetTextFromUser
  297. (
  298. _("Enter your number:"),
  299. _("Try to guess my number!"),
  300. wxEmptyString,
  301. this
  302. );
  303. if ( str.empty() )
  304. {
  305. // cancelled
  306. return;
  307. }
  308. long num;
  309. if ( !str.ToLong(&num) || num < 0 )
  310. {
  311. str = _("You've probably entered an invalid number.");
  312. }
  313. else if ( num == 9 )
  314. {
  315. // this message is not translated (not in catalog) because we used wxT()
  316. // and not _() around it
  317. str = wxT("You've found a bug in this program!");
  318. }
  319. else if ( num == 17 )
  320. {
  321. str.clear();
  322. // string must be split in two -- otherwise the translation would't be
  323. // found
  324. str << _("Congratulations! you've won. Here is the magic phrase:")
  325. << _("cannot create fifo `%s'");
  326. }
  327. else
  328. {
  329. // this is a more implicit way to write _() but note that if you use it
  330. // you must ensure that the strings get extracted in the message
  331. // catalog as by default xgettext won't do it; it only knows of _(),
  332. // not of wxTRANSLATE(). As internat's readme.txt says you should thus
  333. // call xgettext with -kwxTRANSLATE.
  334. str = wxGetTranslation(wxTRANSLATE("Bad luck! try again..."));
  335. // note also that if we want 'str' to contain a localized string
  336. // we need to use wxGetTranslation explicitly as wxTRANSLATE just
  337. // tells xgettext to extract the string but has no effect on the
  338. // runtime of the program!
  339. }
  340. wxMessageBox(str, _("Result"), wxOK | wxICON_INFORMATION);
  341. }
  342. void MyFrame::OnTestLocaleAvail(wxCommandEvent& WXUNUSED(event))
  343. {
  344. static wxString s_locale;
  345. wxString locale = wxGetTextFromUser
  346. (
  347. _("Enter the locale to test"),
  348. wxGetTextFromUserPromptStr,
  349. s_locale,
  350. this
  351. );
  352. if ( locale.empty() )
  353. return;
  354. s_locale = locale;
  355. const wxLanguageInfo * const info = wxLocale::FindLanguageInfo(s_locale);
  356. if ( !info )
  357. {
  358. wxLogError(_("Locale \"%s\" is unknown."), s_locale.c_str());
  359. return;
  360. }
  361. if ( wxLocale::IsAvailable(info->Language) )
  362. {
  363. wxLogMessage(_("Locale \"%s\" is available."), s_locale.c_str());
  364. }
  365. else
  366. {
  367. wxLogWarning(_("Locale \"%s\" is not available."), s_locale.c_str());
  368. }
  369. }
  370. void MyFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
  371. {
  372. // open a bogus file -- the error message should be also translated if
  373. // you've got wxstd.mo somewhere in the search path (see MyApp::OnInit)
  374. wxFile file("NOTEXIST.ING");
  375. }
  376. void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event))
  377. {
  378. const wxString& title = _("Testing _() (gettext)");
  379. // NOTE: using the wxTRANSLATE() macro here we won't show a localized
  380. // string in the text entry dialog; we'll simply show the un-translated
  381. // string; however if the user press "ok" without altering the text,
  382. // since the "default value" string has been extracted by xgettext
  383. // the wxGetTranslation call later will manage to return a localized
  384. // string
  385. wxTextEntryDialog d(this, _("Please enter text to translate"),
  386. title, wxTRANSLATE("default value"));
  387. if (d.ShowModal() == wxID_OK)
  388. {
  389. wxString v = d.GetValue();
  390. wxString s(title);
  391. s << "\n" << v << " -> "
  392. << wxGetTranslation(v.c_str()) << "\n";
  393. wxMessageBox(s);
  394. }
  395. }
  396. void MyFrame::OnTest2(wxCommandEvent& WXUNUSED(event))
  397. {
  398. const wxString& title = _("Testing _N() (ngettext)");
  399. wxTextEntryDialog d(this,
  400. _("Please enter range for plural forms of \"n files deleted\" phrase"),
  401. title, "0-10");
  402. if (d.ShowModal() == wxID_OK)
  403. {
  404. int first, last;
  405. wxSscanf(d.GetValue(), "%d-%d", &first, &last);
  406. wxString s(title);
  407. s << "\n";
  408. for (int n = first; n <= last; ++n)
  409. {
  410. s << n << " " <<
  411. wxPLURAL("file deleted", "files deleted", n) <<
  412. "\n";
  413. }
  414. wxMessageBox(s);
  415. }
  416. }
  417. void MyFrame::OnTest3(wxCommandEvent& WXUNUSED(event))
  418. {
  419. const char* lines[] =
  420. {
  421. wxTRANSLATE("line 1"),
  422. wxTRANSLATE("line 2"),
  423. wxTRANSLATE("line 3"),
  424. };
  425. wxString s(_("Testing wxTRANSLATE() (gettext_noop)"));
  426. s << "\n";
  427. for (size_t i = 0; i < WXSIZEOF(lines); ++i)
  428. {
  429. s << lines[i] << " -> " << wxGetTranslation(lines[i]) << "\n";
  430. }
  431. wxMessageBox(s);
  432. }
  433. void MyFrame::OnTestMsgBox(wxCommandEvent& WXUNUSED(event))
  434. {
  435. if ( wxMessageBox
  436. (
  437. _("Are the labels of the buttons in this message box "
  438. "translated into the current locale language?"),
  439. _("wxWidgets i18n sample"),
  440. wxYES_NO,
  441. this
  442. ) != wxYES )
  443. {
  444. wxMessageBox(_("Please report the details of your platform to us."));
  445. }
  446. }