Commit f44390aa authored by Vivien Kraus's avatar Vivien Kraus

Merge branch '51-full-internationalization' into 'develop'

Resolve "Full internationalization"

Closes #51

See merge request gugurumbe/tarot!45
parents 75392cd1 e1d388ba
Pipeline #108955 passed with stages
in 5 minutes and 16 seconds
......@@ -15,6 +15,8 @@
#+texinfo_printed_title: Tarot
#+PROPERTY: header-args :exports both
#+texinfo: @documentencoding UTF-8
This manual is for Tarot (version {{{version}}}, {{{updated}}}).
* Gender-neutral pronouns :noexport:
......@@ -625,6 +627,45 @@ self-contained library. The library is divided into modules. The
entire API is accessible by including =tarot.h=. To compile and link
the program, use the =tarot= module in =pkg-config=.
** Library initialization
In order to use the library, you need to initialize and quit it. For
instance, a useless program would be:
#+BEGIN_SRC C :eval no
#include <tarot.h>
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char *argv[])
{
tarot_set_localedir ("/usr/share/locale");
if (tarot_init () != 0)
{
fprintf (stderr, "Could not load libtarot.\n");
return EXIT_ERROR;
}
fprintf (stderr, "You are running libtarot %s\n",
tarot_libtarot_version ());
tarot_quit ();
return EXIT_SUCCESS;
}
#+END_SRC
#+attr_texinfo: :options {void} tarot_set_localedir (const char *@var{localedir})
#+begin_deftypefun
Define the locale directory, prior to initializing the library.
#+end_deftypefun
#+attr_texinfo: :options {int} tarot_init (void)
#+begin_deftypefun
Perform the library initialization.
#+end_deftypefun
#+attr_texinfo: :options {void} tarot_quit (void)
#+begin_deftypefun
Release all resources for libtarot.
#+end_deftypefun
** Working with cards
#+attr_texinfo: :options {typedef unsigned int} TarotCard
#+begin_deftp
......@@ -664,7 +705,7 @@ success, or anything else if there is an error, such as /c/ is the
excuse, or not a valid card.
#+end_deftypefun
#+attr_texinfo: :options {TarotCard} tarot_string_to_card (const char *@var{text})
#+attr_texinfo: :options {TarotCard} tarot_string_to_card_c (const char *@var{text})
#+begin_deftypefun
If you want to exchange cards, you should not use their IDs because it
is not easily understandable. The library provides a card parser and
......@@ -683,6 +724,12 @@ This function converts /text/ to a card. If the parsing failed,
return the value -1 as coerced to a =TarotCard=.
#+end_deftypefun
#+attr_texinfo: :options {TarotCard} tarot_string_to_card (const char *@var{text})
#+begin_deftypefun
Same as =tarot_string_to_card_c=, but use an internationalized version
of the card names.
#+end_deftypefun
#+attr_texinfo: :options {TarotCard} tarot_card_parse (const char *@var{text}, char **@var{end})
#+begin_deftypefun
If you are writing a full parser, then you may want an interface that
......@@ -695,6 +742,12 @@ The return value is meaningless if /end/ is set to the same address as
/text/.
#+end_deftypefun
#+attr_texinfo: :options {TarotCard} tarot_card_parse_c (const char *@var{text}, char **@var{end})
#+begin_deftypefun
Same as =tarot_card_parse=, but use the locale-independent card
representation.
#+end_deftypefun
#+attr_texinfo: :options {size_t} tarot_card_to_string (TarotCard @var{c}, size_t @var{max}, char *@var{dest})
#+begin_deftypefun
As the reverse operation, this function will print /c/ to /dest/ (it
......@@ -704,12 +757,24 @@ NUL. So you should call this function again with at least the return
value plus one bytes in /dest/ / /max/.
#+end_deftypefun
#+attr_texinfo: :options {size_t} tarot_card_to_string_c (TarotCard @var{c}, size_t @var{max}, char *@var{dest})
#+begin_deftypefun
Same as =tarot_card_to_string=, but use the locale-independent card
representation.
#+end_deftypefun
#+attr_texinfo: :options {char *} tarot_card_to_string_alloc (TarotCard @var{c})
#+begin_deftypefun
If the previous procedure is too complex, you can convert /c/ to a
string directly, but you have to release the return value.
#+end_deftypefun
#+attr_texinfo: :options {char *} tarot_card_to_string_c_alloc (TarotCard @var{c})
#+begin_deftypefun
Same as =tarot_card_to_string_alloc=, but use the locale-independent card
representation.
#+end_deftypefun
#+attr_texinfo: :options {struct} TarotCardArray
#+begin_deftypefun
When dealing with multiple cards, you can use this wrapper of an array
......@@ -769,13 +834,19 @@ In some API functions, a player ID greater than or equal to the number
of players means the dog.
#+end_deftp
#+attr_texinfo: :options {TarotPlayer} tarot_string_to_player (const char *@var{text})
#+attr_texinfo: :options {TarotPlayer} tarot_string_to_player_c (const char *@var{text})
#+begin_deftypefun
To exchange player IDs, you may want to use their text representation.
This is simply a capital unicode letter 'P' followed by the ID, plus
one.
#+end_deftypefun
#+attr_texinfo: :options {TarotPlayer} tarot_string_to_player (const char *@var{text})
#+begin_deftypefun
Same as =tarot_string_to_player_c=, but use an internationalized
player name.
#+end_deftypefun
#+attr_texinfo: :options {TarotPlayer} tarot_player_parse (const char *@var{text}, char **@var{end})
#+begin_deftypefun
Convert /text/ to a player, and set /end/ to the first character that
......@@ -783,18 +854,36 @@ is not part of the player number. If it is exactly /text/, then the
parser failed and the return value is meaningless.
#+end_deftypefun
#+attr_texinfo: :options {TarotPlayer} tarot_player_parse_c (const char *@var{text}, char **@var{end})
#+begin_deftypefun
Same as =tarot_player_parse=, but use a locale-independent player
representation.
#+end_deftypefun
#+attr_texinfo: :options {size_t} tarot_player_to_string (TarotPlayer @var{p}, size_t @var{max}, char *@var{dest})
#+begin_deftypefun
Same as =tarot_card_to_string=, but represent a player /p/ instead of
a card.
#+end_deftypefun
#+attr_texinfo: :options {size_t} tarot_player_to_string_c (TarotPlayer @var{p}, size_t @var{max}, char *@var{dest})
#+begin_deftypefun
Same as =tarot_player_to_string=, but use a locale-independent player
representation.
#+end_deftypefun
#+attr_texinfo: :options {char *} tarot_player_to_string_alloc (TarotPlayer @var{p})
#+begin_deftypefun
Same as =tarot_card_to_string_alloc=, but with a player /p/ instead of
a card.
#+end_deftypefun
#+attr_texinfo: :options {char *} tarot_player_to_string_c_alloc (TarotPlayer @var{p})
#+begin_deftypefun
Same as =tarot_player_to_string_alloc=, but use a locale-independent player
representation.
#+end_deftypefun
#+attr_texinfo: :options {struct} TarotPlayerArray
#+begin_deftp
A resizeable array of players.
......
......@@ -34,7 +34,7 @@ if ENABLE_RENDERER
if WITH_GOBJECT
if WITH_CAIRO
$(srcdir)/%reldir%/example.xml.png: %reldir%/example.xml src/tarot
$(render_verbose) src/tarot --render -i $(srcdir)/%reldir%/example.xml -o $(srcdir)/%reldir%/example.xml.png
$(render_verbose) ./pre-inst-env tarot --render -i $(srcdir)/%reldir%/example.xml -o $(srcdir)/%reldir%/example.xml.png
else # not WITH_CAIRO
$(srcdir)/%reldir%/example.xml.png: %reldir%/example.xml
@echo "A game needs to be re-rendered. You need to enable the cairo bindings."
......
......@@ -4,4 +4,6 @@ src/engine/application.vala
src/engine/pretty_status.vala
src/engine/solo.vala
src/tarot-opts.h
src/tarot-opts.c
\ No newline at end of file
src/tarot-opts.c
src/cards/tarot/cards_private_impl.h
src/core/player/tarot/player_private_impl.h
\ No newline at end of file
This diff is collapsed.
......@@ -7,6 +7,7 @@ export LD_LIBRARY_PATH="$abs_top_builddir/src/.libs:$LD_LIBRARY_PATH"
export GUILE_AUTO_COMPILE=1
export GUILE_LOAD_PATH="$abs_top_srcdir/src/scm:$abs_top_builddir/src/scm:$GUILE_LOAD_PATH"
export GUILE_COMPILED_LOAD_PATH="$abs_top_builddir/src/scm:$GUILE_COMPILED_LOAD_PATH"
export LANG=C
exec "$@"
# Local Variables:
......
......@@ -47,18 +47,42 @@ tarot_string_to_card (const char *text)
return (TarotCard) (-1);
}
TarotCard
tarot_string_to_card_c (const char *text)
{
char *end = NULL;
TarotCard ret = card_parse_c (text, &end);
if (end != text && *end == '\0')
{
return ret;
}
return (TarotCard) (-1);
}
TarotCard
tarot_card_parse (const char *text, char **end)
{
return card_parse (text, end);
}
TarotCard
tarot_card_parse_c (const char *text, char **end)
{
return card_parse_c (text, end);
}
size_t
tarot_card_to_string (TarotCard c, size_t max, char *dest)
{
return card_to_string (c, max, dest);
}
size_t
tarot_card_to_string_c (TarotCard c, size_t max, char *dest)
{
return card_to_string_c (c, max, dest);
}
char *
tarot_card_to_string_alloc (TarotCard c)
{
......@@ -73,6 +97,20 @@ tarot_card_to_string_alloc (TarotCard c)
return ret;
}
char *
tarot_card_to_string_c_alloc (TarotCard c)
{
char *ret = malloc (4);
if (ret != NULL)
{
if (card_to_string_c (c, 4, ret) >= 4)
{
assert (0);
}
}
return ret;
}
TarotCardArray *
tarot_card_array_alloc ()
{
......
......@@ -110,18 +110,27 @@ extern "C"
/* Return ((TarotCard) (-1)) if not found */
TarotCard tarot_string_to_card (const char *text);
/* Use the C locale */
TarotCard tarot_string_to_card_c (const char *text);
TarotCard tarot_card_parse (const char *text, char **end);
TarotCard tarot_card_parse_c (const char *text, char **end);
/**
* tarot_card_to_string: (skip):
*/
size_t tarot_card_to_string (TarotCard c, size_t max, char *dest);
size_t tarot_card_to_string_c (TarotCard c, size_t max, char *dest);
/**
* tarot_card_to_string_alloc: (method):
*/
char *tarot_card_to_string_alloc (TarotCard c);
char *tarot_card_to_string_c_alloc (TarotCard c);
struct TarotCardArray;
typedef struct TarotCardArray TarotCardArray;
......
......@@ -46,7 +46,9 @@ extern "C"
static int of (TarotNumber n, TarotSuit s, TarotCard * c);
static int decompose (TarotCard c, TarotNumber * n, TarotSuit * s);
static TarotCard card_parse (const char *text, char **end);
static TarotCard card_parse_c (const char *text, char **end);
static size_t card_to_string (TarotCard c, size_t max, char *dest);
static size_t card_to_string_c (TarotCard c, size_t max, char *dest);
struct TarotCardArray
{
......
......@@ -26,6 +26,8 @@
#include <tarot/cards_private.h>
#include <string.h>
#include <assert.h>
#include <gettext.h>
#define _(String) dgettext (PACKAGE, String)
static inline int
of (TarotNumber n, TarotSuit s, TarotCard * c)
......@@ -62,6 +64,41 @@ decompose (TarotCard c, TarotNumber * n, TarotSuit * s)
static inline TarotCard
card_parse (const char *text, char **end)
{
size_t len = 0;
len = strlen (text);
/* *INDENT-OFF* */
[+ FOR card +]
if (len >= strlen (_ ("[+ short +]"))
&& strncmp (text, _ ("[+ short +]"), strlen (_ ("[+ short +]"))) == 0)
{
if (end != NULL)
{
*end = (char *) text + strlen (_ ("[+ short +]"));
}
return [+ id +];
}
else if (len < strlen (_ ("[+ short +]"))
&& strncmp (text, _ ("[+ short +]"), len) == 0)
{
if (end != NULL)
{
*end = (char *) text + len;
assert (**end == '\0');
}
return (TarotCard) (-1);
}
[+ ENDFOR card +]
/* *INDENT-ON* */
if (end != NULL)
{
*end = (char *) text;
}
return (TarotCard) (-1);
}
static inline TarotCard
card_parse_c (const char *text, char **end)
{
size_t len = 0;
len = strlen (text);
......@@ -96,7 +133,7 @@ card_parse (const char *text, char **end)
}
static inline size_t
card_to_string (TarotCard c, size_t max, char *dest)
card_to_string_c (TarotCard c, size_t max, char *dest)
{
/* *INDENT-OFF* */
[+ FOR card +]
......@@ -124,6 +161,35 @@ card_to_string (TarotCard c, size_t max, char *dest)
return 0;
}
static inline size_t
card_to_string (TarotCard c, size_t max, char *dest)
{
/* *INDENT-OFF* */
[+ FOR card +]
if (c == [+ id +])
{
size_t required = strlen (_ ("[+ short +]"));
if (max > required)
{
strncpy (dest, _ ("[+ short +]"), required);
dest[required] = '\0';
}
else if (max != 0)
{
strncpy (dest, _ ("[+ short +]"), max - 1);
dest[max - 1] = '\0';
}
return required;
}
[+ ENDFOR card +]
/* *INDENT-ON* */
if (max != 0)
{
*dest = '\0';
}
return 0;
}
static inline TarotCardArray *
card_array_alloc ()
{
......
......@@ -41,12 +41,24 @@ tarot_player_parse (const char *text, char **end)
return player_parse (text, end);
}
TarotPlayer
tarot_player_parse_c (const char *text, char **end)
{
return player_parse_c (text, end);
}
size_t
tarot_player_to_string (TarotPlayer p, size_t max, char *dest)
{
return player_to_string (p, max, dest);
}
size_t
tarot_player_to_string_c (TarotPlayer p, size_t max, char *dest)
{
return player_to_string_c (p, max, dest);
}
char *
tarot_player_to_string_alloc (TarotPlayer p)
{
......@@ -59,6 +71,18 @@ tarot_player_to_string_alloc (TarotPlayer p)
return ret;
}
char *
tarot_player_to_string_c_alloc (TarotPlayer p)
{
size_t alloc_length = 1 + player_to_string_c (p, 0, NULL);
char *ret = malloc (alloc_length);
if (ret != NULL)
{
player_to_string_c (p, alloc_length, ret);
}
return ret;
}
TarotPlayerArray *
tarot_player_array_alloc ()
{
......
......@@ -42,16 +42,32 @@ extern "C"
*/
TarotPlayer tarot_player_parse (const char *text, char **end);
/**
* tarot_player_parse_c:
* end: (transfer none):
*/
TarotPlayer tarot_player_parse_c (const char *text, char **end);
/**
* tarot_player_to_string: (skip):
*/
size_t tarot_player_to_string (TarotPlayer p, size_t max, char *dest);
/**
* tarot_player_to_string_c: (skip):
*/
size_t tarot_player_to_string_c (TarotPlayer p, size_t max, char *dest);
/**
* tarot_player_to_string_alloc: (method):
*/
char *tarot_player_to_string_alloc (TarotPlayer p);
/**
* tarot_player_to_string_c_alloc: (method):
*/
char *tarot_player_to_string_c_alloc (TarotPlayer p);
struct TarotPlayerArray;
typedef struct TarotPlayerArray TarotPlayerArray;
......
......@@ -32,6 +32,9 @@ extern "C"
static TarotPlayer player_parse (const char *text, char **end);
static size_t player_to_string (TarotPlayer p, size_t max, char *dest);
static TarotPlayer player_parse_c (const char *text, char **end);
static size_t player_to_string_c (TarotPlayer p, size_t max, char *dest);
struct TarotPlayerArray
{
size_t n;
......
......@@ -20,58 +20,128 @@
*/
#include <tarot/player_private.h>
#include "gettext.h"
#define _(String) dgettext (PACKAGE, String)
#define N_(String) (String)
static const char *names[6] =
{
N_ ("P1"),
N_ ("P2"),
N_ ("P3"),
N_ ("P4"),
N_ ("P5"),
N_ ("P6")
};
static inline TarotPlayer
player_parse (const char *text, char **end)
{
TarotPlayer ret = (TarotPlayer) - 1;
if (text[0] == 'P')
size_t i;
TarotPlayer ret = ((TarotPlayer) (-1));
for (i = 0; i < 6; i++)
{
if (text[1] >= '1' && text[1] <= '9')
{
ret = text[1] - '1';
if (end)
{
*end = (char *) text + 2;
}
}
const char *candidate = gettext (names[i]);
if (strncmp (text, candidate, strlen (candidate)) == 0)
{
ret = (TarotPlayer) i;
if (end)
{
*end = (char *) text + strlen (candidate);
}
}
}
else if (end)
if (ret == ((TarotPlayer) (-1)))
{
*end = (char *) text;
}
return ret;
}
static inline size_t
player_to_string (TarotPlayer p, size_t max, char *dest)
static inline TarotPlayer
player_parse_c (const char *text, char **end)
{
if (max != 0)
size_t i;
TarotPlayer ret = ((TarotPlayer) (-1));
for (i = 0; i < 6; i++)
{
dest[0] = '\0';
const char *candidate = names[i];
if (strncmp (text, candidate, strlen (candidate)) == 0)
{
ret = (TarotPlayer) i;
if (end)
{
*end = (char *) text + strlen (candidate);
}
}
}
if (p >= 9)
if (ret == ((TarotPlayer) (-1)))
{
*end = (char *) text;
}
return ret;
}
static inline size_t
player_to_string (TarotPlayer p, size_t max, char *dest)
{
if (p >= 6)
{
if (max >= 1)
{
*dest = '\0';
}
return 0;
}
switch (max)
{
const char *source = gettext (names[p]);
if (max == 0)
{
return strlen (source);
}
else if (max > strlen (source))
{
strcpy (dest, source);
return strlen (source);
}
else
{
strncpy (dest, source, max);
dest[max - 1] = '\0';
return strlen (source);
}
}
}
static inline size_t
player_to_string_c (TarotPlayer p, size_t max, char *dest)
{
if (p >= 6)
{
case 0:
break;
case 1:
dest[0] = '\0';
break;
case 2:
dest[0] = 'P';
dest[1] = '\0';
break;
default:
dest[0] = 'P';
dest[1] = '1' + p;
dest[2] = '\0';
break;
if (max >= 1)
{
*dest = '\0';
}
return 0;
}
return 2;
{
const char *source = names[p];
if (max == 0)
{
return strlen (source);
}
else if (max > strlen (source))
{
strcpy (dest, source);
return strlen (source);
}
else
{
strncpy (dest, source, max);
dest[max - 1] = '\0';
return strlen (source);
}
}
}
static inline TarotPlayerArray *
......
......@@ -38,6 +38,11 @@ extern "C"
{
#endif /* __cplusplus */
void tarot_set_localedir (const char *localedir);
int tarot_init (void);
void tarot_quit (void);
/**
* tarot_libtarot_version:
*/
......
......@@ -22,6 +22,42 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "gettext.h"
static int libtarot_initialized = 0;
static char *tarot_localedir = NULL;
void
tarot_set_localedir (const char *localedir)
{
assert (libtarot_initialized == 0);
tarot_localedir = malloc (strlen (localedir) + 1);
if (tarot_localedir == NULL)
{
abort ();
}
strcpy (tarot_localedir, localedir);
}
int
tarot_init (void)
{
assert (libtarot_initialized == 0);
if (tarot_localedir != NULL)
{
bindtextdomain (PACKAGE, tarot_localedir);
}
libtarot_initialized = 1;
return 0;
}
void
tarot_quit (void)
{
free (tarot_localedir);
tarot_localedir = NULL;
}
const char *
tarot_libtarot_version ()
......
......@@ -83,19 +83,19 @@ namespace Tarot {
if (suit != Tarot.Suit.TRUMPS) {
switch (number) {
case 1:
s_number = " A";
s_number = _ (" A");
break;
case 11:
s_number = " J";
s_number = _ (" J");
break;
case 12:
s_number = " C";
s_number = _ (" C");
break;
case 13:
s_number = " Q";
s_number = _ (" Q");
break;
case 14:
s_number = " K";
s_number = _ (" K");
break;
}
}
......
......@@ -44,12 +44,13 @@ include = "int tarot_run_render (char *input, int w, int h, char **output, int *
include = "int tarot_run_interactive (size_t n_players, int call, const char *seed, size_t n_iterations, size_t retry, char **output);";
include = "void tarot_setup_environment (const char *runtime_prefix_env, const char *sysconfdir, const char *localedir);";
include = "int opts_main (int argc, char **argv);";
include = "int main (int argc, char **argv) { tarot_setup_environment (RUNTIME_PREFIX_ENV, SYSCONFDIR, LOCALEDIR); setlocale (LC_ALL, \"\"); bindtextdomain (PACKAGE, getenv (\"LOCALEDIR\")); textdomain (PACKAGE); return opts_main (argc, argv); }";
include = "int main (int argc, char **argv) { tarot_setup_environment (RUNTIME_PREFIX_ENV, SYSCONFDIR, LOCALEDIR); setlocale (LC_ALL, \"\"); bindtextdomain (PACKAGE, getenv (\"LOCALEDIR\")); textdomain (PACKAGE); OPT_XLAT_OPT_NAMES; OPT_XLAT_CFG_NAMES; return opts_main (argc, argv); }";
include = "static char *read_input ();";
include = "static void write_output (char *output, size_t len);";
include = "#define main opts_main";
include = <<- END
static char *
read_input ()
{
......@@ -250,6 +251,11 @@ main = {
int decl;