gettext.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* Copyright 2004,2006,2018
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include <locale.h>
  19. #include "dynwind.h"
  20. #include "feature.h"
  21. #include "gsubr.h"
  22. #include "libgettext.h"
  23. #include "numbers.h"
  24. #include "strings.h"
  25. #include "gettext.h"
  26. int
  27. scm_i_to_lc_category (SCM category, int allow_lc_all)
  28. {
  29. int c_category = scm_to_int (category);
  30. switch (c_category)
  31. {
  32. #ifdef LC_CTYPE
  33. case LC_CTYPE:
  34. #endif
  35. #ifdef LC_NUMERIC
  36. case LC_NUMERIC:
  37. #endif
  38. #ifdef LC_COLLATE
  39. case LC_COLLATE:
  40. #endif
  41. #ifdef LC_TIME
  42. case LC_TIME:
  43. #endif
  44. #ifdef LC_MONETARY
  45. case LC_MONETARY:
  46. #endif
  47. #ifdef LC_MESSAGES
  48. case LC_MESSAGES:
  49. #endif
  50. #ifdef LC_PAPER
  51. case LC_PAPER:
  52. #endif
  53. #ifdef LC_NAME
  54. case LC_NAME:
  55. #endif
  56. #ifdef LC_ADDRESS
  57. case LC_ADDRESS:
  58. #endif
  59. #ifdef LC_TELEPHONE
  60. case LC_TELEPHONE:
  61. #endif
  62. #ifdef LC_MEASUREMENT
  63. case LC_MEASUREMENT:
  64. #endif
  65. #ifdef LC_IDENTIFICATION
  66. case LC_IDENTIFICATION:
  67. #endif
  68. return c_category;
  69. #ifdef LC_ALL
  70. case LC_ALL:
  71. if (allow_lc_all)
  72. return c_category;
  73. #endif
  74. }
  75. scm_wrong_type_arg (0, 0, category);
  76. }
  77. SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0,
  78. (SCM msgid, SCM domain, SCM category),
  79. "Return the translation of @var{msgid} in the message domain "
  80. "@var{domain}. @var{domain} is optional and defaults to the "
  81. "domain set through (textdomain). @var{category} is optional "
  82. "and defaults to LC_MESSAGES.")
  83. #define FUNC_NAME s_scm_gettext
  84. {
  85. char *c_msgid;
  86. char const *c_result;
  87. SCM result;
  88. scm_dynwind_begin (0);
  89. c_msgid = scm_to_locale_string (msgid);
  90. scm_dynwind_free (c_msgid);
  91. if (SCM_UNBNDP (domain))
  92. {
  93. /* 1 argument case. */
  94. c_result = gettext (c_msgid);
  95. }
  96. else
  97. {
  98. char *c_domain;
  99. c_domain = scm_to_locale_string (domain);
  100. scm_dynwind_free (c_domain);
  101. if (SCM_UNBNDP (category))
  102. {
  103. /* 2 argument case. */
  104. c_result = dgettext (c_domain, c_msgid);
  105. }
  106. else
  107. {
  108. /* 3 argument case. */
  109. int c_category;
  110. c_category = scm_i_to_lc_category (category, 0);
  111. c_result = dcgettext (c_domain, c_msgid, c_category);
  112. }
  113. }
  114. if (c_result == c_msgid)
  115. result = msgid;
  116. else
  117. result = scm_from_locale_string (c_result);
  118. scm_dynwind_end ();
  119. return result;
  120. }
  121. #undef FUNC_NAME
  122. SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0,
  123. (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category),
  124. "Return the translation of @var{msgid}/@var{msgid_plural} in the "
  125. "message domain @var{domain}, with the plural form being chosen "
  126. "appropriately for the number @var{n}. @var{domain} is optional "
  127. "and defaults to the domain set through (textdomain). "
  128. "@var{category} is optional and defaults to LC_MESSAGES.")
  129. #define FUNC_NAME s_scm_ngettext
  130. {
  131. char *c_msgid;
  132. char *c_msgid_plural;
  133. unsigned long c_n;
  134. const char *c_result;
  135. SCM result;
  136. scm_dynwind_begin (0);
  137. c_msgid = scm_to_locale_string (msgid);
  138. scm_dynwind_free (c_msgid);
  139. c_msgid_plural = scm_to_locale_string (msgid_plural);
  140. scm_dynwind_free (c_msgid_plural);
  141. c_n = scm_to_ulong (n);
  142. if (SCM_UNBNDP (domain))
  143. {
  144. /* 3 argument case. */
  145. c_result = ngettext (c_msgid, c_msgid_plural, c_n);
  146. }
  147. else
  148. {
  149. char *c_domain;
  150. c_domain = scm_to_locale_string (domain);
  151. scm_dynwind_free (c_domain);
  152. if (SCM_UNBNDP (category))
  153. {
  154. /* 4 argument case. */
  155. c_result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n);
  156. }
  157. else
  158. {
  159. /* 5 argument case. */
  160. int c_category;
  161. c_category = scm_i_to_lc_category (category, 0);
  162. c_result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n,
  163. c_category);
  164. }
  165. }
  166. if (c_result == c_msgid)
  167. result = msgid;
  168. else if (c_result == c_msgid_plural)
  169. result = msgid_plural;
  170. else
  171. result = scm_from_locale_string (c_result);
  172. scm_dynwind_end ();
  173. return result;
  174. }
  175. #undef FUNC_NAME
  176. SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0,
  177. (SCM domainname),
  178. "If optional parameter @var{domainname} is supplied, "
  179. "set the textdomain. "
  180. "Return the textdomain.")
  181. #define FUNC_NAME s_scm_textdomain
  182. {
  183. char const *c_result;
  184. char *c_domain;
  185. SCM result = SCM_BOOL_F;
  186. scm_dynwind_begin (0);
  187. if (SCM_UNBNDP (domainname))
  188. c_domain = NULL;
  189. else
  190. {
  191. c_domain = scm_to_locale_string (domainname);
  192. scm_dynwind_free (c_domain);
  193. }
  194. c_result = textdomain (c_domain);
  195. if (c_result != NULL)
  196. result = scm_from_locale_string (c_result);
  197. else if (!SCM_UNBNDP (domainname))
  198. SCM_SYSERROR;
  199. scm_dynwind_end ();
  200. return result;
  201. }
  202. #undef FUNC_NAME
  203. SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0,
  204. (SCM domainname, SCM directory),
  205. "If optional parameter @var{directory} is supplied, "
  206. "set message catalogs to directory @var{directory}. "
  207. "Return the directory bound to @var{domainname}.")
  208. #define FUNC_NAME s_scm_bindtextdomain
  209. {
  210. char *c_domain;
  211. char *c_directory;
  212. char const *c_result;
  213. SCM result;
  214. scm_dynwind_begin (0);
  215. if (SCM_UNBNDP (directory))
  216. c_directory = NULL;
  217. else
  218. {
  219. c_directory = scm_to_locale_string (directory);
  220. scm_dynwind_free (c_directory);
  221. }
  222. c_domain = scm_to_locale_string (domainname);
  223. scm_dynwind_free (c_domain);
  224. c_result = bindtextdomain (c_domain, c_directory);
  225. if (c_result != NULL)
  226. result = scm_from_locale_string (c_result);
  227. else if (!SCM_UNBNDP (directory))
  228. SCM_SYSERROR;
  229. else
  230. result = SCM_BOOL_F;
  231. scm_dynwind_end ();
  232. return result;
  233. }
  234. #undef FUNC_NAME
  235. SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0,
  236. (SCM domainname, SCM encoding),
  237. "If optional parameter @var{encoding} is supplied, "
  238. "set encoding for message catalogs of @var{domainname}. "
  239. "Return the encoding of @var{domainname}.")
  240. #define FUNC_NAME s_scm_bind_textdomain_codeset
  241. {
  242. char *c_domain;
  243. char *c_encoding;
  244. char const *c_result;
  245. SCM result;
  246. scm_dynwind_begin (0);
  247. if (SCM_UNBNDP (encoding))
  248. c_encoding = NULL;
  249. else
  250. {
  251. c_encoding = scm_to_locale_string (encoding);
  252. scm_dynwind_free (c_encoding);
  253. }
  254. c_domain = scm_to_locale_string (domainname);
  255. scm_dynwind_free (c_domain);
  256. c_result = bind_textdomain_codeset (c_domain, c_encoding);
  257. if (c_result != NULL)
  258. result = scm_from_locale_string (c_result);
  259. else if (!SCM_UNBNDP (encoding))
  260. SCM_SYSERROR;
  261. else
  262. result = SCM_BOOL_F;
  263. scm_dynwind_end ();
  264. return result;
  265. }
  266. #undef FUNC_NAME
  267. void
  268. scm_init_gettext ()
  269. {
  270. /* When gettext support was first added (in 1.8.0), it provided feature
  271. `i18n'. We keep this as is although the name is a bit misleading
  272. now. */
  273. scm_add_feature ("i18n");
  274. #include "gettext.x"
  275. }