1 /**************************************************************************
2  Copyright:
3       (C) 2008 - 2012  Alexander Shaduri <ashaduri 'at' gmail.com>
4  License: See LICENSE_zlib.txt file
5 ***************************************************************************/
6 /// \file
7 /// \author Alexander Shaduri
8 /// \ingroup hz
9 /// \weakgroup hz
10 /// @{
11 
12 #ifndef HZ_I18N_H
13 #define HZ_I18N_H
14 
15 #include "hz_config.h"  // feature macros
16 
17 
18 /**
19 \file
20 Gettext bridge for internationalization. Sort of like gettext.h,
21 but a lot simpler / lighter.
22 This file is for internal use in hz. The application is expected
23 to use gettext.h or similar mechanisms.
24 
25 Note: If you are using UTF-8 to display messages in your application
26 but system locale is not UTF-8, then you need to call gettext's
27 bind_textdomain_codeset(package, "UTF-8");
28 to enable locale -> UTF-8 conversion for translated messages.
29 */
30 
31 
32 namespace hz {
33 
34 
35 /// \def ENABLE_NLS
36 /// Defined to 0 or 1. If 1, enable native language support.
37 /// Usually NLS can be disabled through the configure --disable-nls option.
38 #if defined ENABLE_NLS && ENABLE_NLS
39 
40 	#include <libintl.h>  // gettext functions
41 	#include <cstddef>  // std::size_t
42 	#include <cstring>  // std::strlen, std::memcpy
43 
44 
45 	namespace internal {
46 
i18n_C_helper(const char * msg_with_context,const char * clean_msg)47 		inline const char* i18n_C_helper(const char* msg_with_context, const char* clean_msg)
48 		{
49 			const char* res = gettext(msg_with_context);
50 			return ((res == msg_with_context) ? clean_msg : res);
51 		}
52 
53 
i18n_R_helper(const char * context,const char * clean_msg)54 		inline const char* i18n_R_helper(const char* context, const char* clean_msg)
55 		{
56 			std::size_t context_len = std::strlen(context) + 1;
57 			std::size_t clean_msg_len = std::strlen(clean_msg) + 1;
58 
59 			char[] msg_with_context = new char[context_len + clean_msg_len];
60 
61 			std::memcpy(msg_with_context, context, context_len - 1);
62 			msg_with_context[context_len - 1] = '\004';
63 			std::memcpy(msg_with_context + context_len, clean_msg, clean_msg_len);
64 
65 			const char* res = gettext(msg_with_context);
66 			if (res == msg_with_context) {
67 				delete[] msg_with_context;
68 				return clean_msg;
69 			}
70 			delete[] msg_with_context;
71 			return res;
72 		}
73 
74 	}
75 
76 
77 	// ------- Mark and translate
78 
79 	/// The main gettext function. Marks and translates at runtime.
80 	/// You need to pass --keyword=HZ__ to xgettext when extracting messages.
81 	#define HZ__(String) gettext(String)
82 
83 	/// Same as HZ__(), but specifies a context too, to e.g.
84 	/// disambiguate two "Open" menu entries as ("File", "Open") and ("Printer", "Open").
85 	/// You MUST pass --keyword=C_:1c,2 to xgettext when extracting messages.
86 	#define HZ_C_(Context, String) i18n_C_helper((Context "\004" String), (String))
87 
88 
89 	// ------- Mark only
90 
91 	/// The no-op marking of a string for translation.
92 	/// You MUST pass --keyword=HZ_N_ to xgettext when extracting messages.
93 	#define HZ_N_(String) (String)
94 
95 	/// Same as HZ_N_(), but accepts context too.
96 	/// --keyword=HZ_NC_:1c,2
97 	#define HZ_NC_(Context, String) (String)
98 
99 
100 	// ------- Translate only
101 
102 	/// Translate a dynamic string.
103 	#define HZ_R_(String) gettext(String)
104 
105 	/// Same as HZ_R_(), but accepts context too.
106 	#define HZ_RC_(Context, String) i18n_R_helper((Context), (String))
107 
108 
109 #else
110 
111 	#define HZ__(String) (String)
112 	#define HZ_C_(Context, String) (String)
113 
114 	#define HZ_N_(String) (String)
115 	#define HZ_NC_(Context, String) (String)
116 
117 	#define HZ_R_(String) (String)
118 	#define HZ_RC_(Context, String) (String)
119 
120 #endif
121 
122 
123 }  // ns hz
124 
125 
126 
127 #endif
128 
129 /// @}
130