Merge pull request #46 from badgerman/master

German keywords in the imperative.
This commit is contained in:
Enno Rehling 2014-10-29 20:38:26 +01:00
commit fe5ea49506
22 changed files with 292 additions and 255 deletions

5
conf/e2/config.json Normal file
View File

@ -0,0 +1,5 @@
{
"include": [
"keywords.json"
]
}

5
conf/e3/config.json Normal file
View File

@ -0,0 +1,5 @@
{
"include": [
"keywords.json"
]
}

5
conf/e4/config.json Normal file
View File

@ -0,0 +1,5 @@
{
"include": [
"keywords.json"
]
}

65
conf/keywords.json Normal file
View File

@ -0,0 +1,65 @@
{
"keywords": {
"de": {
"//" : "//",
"banner": "BANNER",
"work": [ "ARBEITE", "ARBEITEN" ],
"attack": ["ATTACKIERE", "ATTACKIEREN"],
"steal": [ "BEKLAUE", "BEKLAUEN" ],
"besiege": ["BELAGERE", "BELAGERN" ],
"name": [ "BENENNE", "BENENNEN" ],
"use": [ "BENUTZE", "BENUTZEN" ],
"describe": [ "BESCHREIBE", "BESCHREIBEN" ],
"enter": ["BETRETE", "BETRETEN"],
"guard": ["BEWACHE", "BEWACHEN"],
"message": "BOTSCHAFT",
"end": "ENDE",
"ride": ["REITE", "REITEN"],
"number": "NUMMER",
"follow": ["FOLGE","FOLGEN"],
"research": ["FORSCHE", "FORSCHEN"],
"give": "GIB",
"help": [ "HELFE", "HELFEN" ],
"combat": [ "KÄMPFE", "KÄMPFEN" ],
"ready" : "KAMPFZAUBER",
"buy" : [ "KAUFE", "KAUFEN"],
"contact": [ "KONTAKT", "KONTAKTIEREN"],
"teach": ["LEHRE", "LEHREN"],
"study": ["LERNE", "LERNEN"],
"make": ["MACHE", "MACHEN"],
"maketemp": ["MACHE TEMP", "MACHETEMP"],
"move" : "NACH",
"password" : "PASSWORD",
"recruit": ["REKRUTIERE", "REKRUTIEREN"],
"reserve": ["RESERVIERE", "RESERVIEREN"],
"route": "ROUTE",
"sabotage": ["SABOTIERE", "SABOTIEREN"],
"option": "OPTION",
"spy": ["SPIONIERE", "SPIONIEREN"],
"quit": "STIRB",
"hide": ["TARNE", "TARNEN"],
"carry": ["TRANSPORTIERE", "TRANSPORTIEREN"],
"tax": ["TREIBE", "TREIBEN", "STEUERN"],
"entertain": ["UNTERHALTE", "UNTERHALTEN"],
"sell": ["VERKAUFE", "VERKAUFEN"],
"leave": ["VERLASSE", "VERLASSEN"],
"forget": ["VERGISS", "VERGESSEN"],
"cast": ["ZAUBERE", "ZAUBERN"],
"show": ["ZEIGE", "ZEIGEN"],
"destroy": ["ZERSTÖRE", "ZERSTÖREN"],
"grow": ["ZÜCHTE", "ZÜCHTEN"],
"default": "DEFAULT",
"origin": "URSPRUNG",
"email": "EMAIL",
"piracy": "PIRATERIE",
"group": "GRUPPE",
"sort": ["SORTIERE", "SORTIEREN"],
"prefix": "PRÄFIX",
"plant": ["PFLANZE", "PFLANZEN"],
"alliance": "ALLIANZ",
"claim": ["BEANSPRUCHE", "BEANSPRUCHEN"],
"promote": ["BEFÖRDERE", "BEFÖRDERUNG"],
"pay": ["BEZAHLE", "BEZAHLEN"]
}
}
}

View File

@ -2111,199 +2111,6 @@
</string>
</namespace>
<namespace name="keyword">
<!--Befehle -->
<string name="//">
<text locale="de">//</text>
</string>
<string name="banner">
<text locale="de">BANNER</text>
</string>
<string name="work">
<text locale="de">ARBEITEN</text>
</string>
<string name="attack">
<text locale="de">ATTACKIEREN</text>
</string>
<string name="claim">
<text locale="de">BEANSPRUCHEN</text>
</string>
<string name="steal">
<text locale="de">BEKLAUEN</text>
</string>
<string name="besiege">
<text locale="de">BELAGERE</text>
</string>
<string name="name">
<text locale="de">BENENNEN</text>
</string>
<string name="use">
<text locale="de">BENUTZEN</text>
</string>
<string name="describe">
<text locale="de">BESCHREIBEN</text>
</string>
<string name="enter">
<text locale="de">BETRETEN</text>
</string>
<string name="give">
<text locale="de">GIB</text>
</string>
<string name="guard">
<text locale="de">BEWACHEN</text>
</string>
<string name="message">
<text locale="de">BOTSCHAFT</text>
</string>
<string name="end">
<text locale="de">ENDE</text>
</string>
<string name="ride">
<text locale="de">FAHREN</text>
</string>
<string name="number">
<text locale="de">NUMMER</text>
</string>
<string name="follow">
<text locale="de">FOLGEN</text>
</string>
<string name="research">
<text locale="de">FORSCHEN</text>
</string>
<string name="help">
<text locale="de">HELFEN</text>
</string>
<string name="combat">
<text locale="de">KÄMPFEN</text>
</string>
<string name="ready">
<text locale="de">KAMPFZAUBER</text>
</string>
<string name="buy">
<text locale="de">KAUFEN</text>
</string>
<string name="contact">
<text locale="de">KONTAKTIEREN</text>
</string>
<string name="teach">
<text locale="de">LEHREN</text>
</string>
<string name="study">
<text locale="de">LERNEN</text>
</string>
<string name="locale">
<text locale="de">LOCALE</text>
</string>
<string name="make">
<text locale="de">MACHEN</text>
</string>
<string name="maketemp">
<text locale="de">MACHETEMP</text>
</string>
<string name="move">
<text locale="de">NACH</text>
</string>
<string name="alliance">
<text locale="de">ALLIANZ</text>
</string>
<string name="promote">
<text locale="de">BEFÖRDERUNG</text>
</string>
<string name="pay">
<text locale="de">BEZAHLEN</text>
</string>
<string name="plant">
<text locale="de">PFLANZEN</text>
</string>
<string name="prefix">
<text locale="de">PRÄFIX</text>
</string>
<string name="info">
<text locale="de">INFO</text>
</string>
<string name="password">
<text locale="de">PASSWORT</text>
</string>
<string name="recruit">
<text locale="de">REKRUTIEREN</text>
</string>
<string name="reserve">
<text locale="de">RESERVIEREN</text>
</string>
<string name="route">
<text locale="de">ROUTE</text>
</string>
<string name="sabotage">
<text locale="de">SABOTIEREN</text>
</string>
<string name="option">
<text locale="de">OPTION</text>
</string>
<string name="spy">
<text locale="de">SPIONIEREN</text>
</string>
<string name="quit">
<text locale="de">STIRB</text>
</string>
<string name="hide">
<text locale="de">TARNEN</text>
</string>
<string name="carry">
<text locale="de">TRANSPORTIEREN</text>
</string>
<string name="tax">
<text locale="de">TREIBEN</text>
</string>
<string name="entertain">
<text locale="de">UNTERHALTEN</text>
</string>
<string name="sell">
<text locale="de">VERKAUFEN</text>
</string>
<string name="leave">
<text locale="de">VERLASSEN</text>
</string>
<string name="forget">
<text locale="de">VERGESSEN</text>
</string>
<string name="cast">
<text locale="de">ZAUBERE</text>
</string>
<string name="show">
<text locale="de">ZEIGEN</text>
</string>
<string name="destroy">
<text locale="de">ZERSTÖREN</text>
</string>
<string name="grow">
<text locale="de">ZÜCHTEN</text>
</string>
<string name="default">
<text locale="de">DEFAULT</text>
</string>
<string name="report">
<text locale="de">REPORT</text>
</string>
<string name="origin">
<text locale="de">URSPRUNG</text>
</string>
<string name="email">
<text locale="de">EMAIL</text>
</string>
<string name="piracy">
<text locale="de">PIRATERIE</text>
</string>
<string name="locale">
<text locale="de">LOCALE</text>
</string>
<string name="group">
<text locale="de">GRUPPE</text>
</string>
<string name="sort">
<text locale="de">SORTIEREN</text>
</string>
</namespace>
<!--NR generieren -->
<string name="nr_options">
<text locale="de">Optionen</text>

View File

@ -1,8 +1,10 @@
local confdir = 'conf/'
if config.rules then
confdir = confdir .. config.rules .. '/'
end
if config.install then
confdir = config.install .. '/' .. confdir
end
read_xml(confdir .. 'config.xml', confdir .. 'catalog.xml')
rules=''
if config.rules then
rules = config.rules .. '/'
end
read_xml(confdir .. rules .. 'config.xml', confdir .. rules .. 'catalog.xml')
eressea.config.read(rules .. 'config.json', confdir)

View File

@ -7,6 +7,8 @@
#include <util/language.h>
#include <cJSON.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "kernel/building.h"
#include "kernel/race.h"
@ -48,8 +50,34 @@ int config_parse(const char *json)
return 1;
}
int config_read(const char *filename)
int config_read(const char *filename, const char * relpath)
{
char name[MAX_PATH];
FILE *F;
json_relpath = relpath;
if (relpath) {
_snprintf(name, sizeof(name), "%s/%s", relpath, filename);
F = fopen(name, "rt");
}
else {
F = fopen(filename, "rt");
}
if (F) {
int result;
char *data;
size_t sz;
fseek(F, 0, SEEK_END);
sz = ftell(F);
rewind(F);
data = malloc(sz);
fread(data, 1, sz, F);
fclose(F);
result = config_parse(data);
free(data);
return result;
}
return 1;
}

View File

@ -6,7 +6,7 @@ extern "C" {
void config_reset(void);
int config_parse(const char *json);
int config_read(const char *filename);
int config_read(const char *filename, const char * relpath);
#ifdef __cplusplus
}

View File

@ -5,7 +5,7 @@ $#include "bind_config.h"
module eressea {
module config {
void config_reset @ reset(void);
int config_read @ read(const char *filename);
int config_read @ read(const char *filename, const char *relpath);
int config_parse @ parse(const char *json);
}
}

View File

@ -57,16 +57,18 @@ static int tolua_config_eressea_config_read00(lua_State* tolua_S)
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isstring(tolua_S,1,0,&tolua_err) ||
!tolua_isnoobj(tolua_S,2,&tolua_err)
!tolua_isstring(tolua_S, 1, 0, &tolua_err) ||
!tolua_isstring(tolua_S, 2, 0, &tolua_err) ||
!tolua_isnoobj(tolua_S,3,&tolua_err)
)
goto tolua_lerror;
else
#endif
{
const char* filename = ((const char*) tolua_tostring(tolua_S,1,0));
const char* filename = ((const char*)tolua_tostring(tolua_S, 1, 0));
const char* relpath = ((const char*)tolua_tostring(tolua_S, 2, 0));
{
int tolua_ret = (int) config_read(filename);
int tolua_ret = (int) config_read(filename, relpath);
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
}
}

View File

@ -1961,20 +1961,6 @@ void kernel_done(void)
gc_done();
}
const char *localenames[] = {
"de", "en",
NULL
};
void init_locales(void)
{
int l;
for (l = 0; localenames[l]; ++l) {
struct locale *lang = get_or_create_locale(localenames[l]);
init_locale(lang);
}
}
/* TODO: soll hier weg */
extern struct attrib_type at_shiptrail;

View File

@ -101,7 +101,6 @@ extern "C" {
/* ------------------------------------------------------------- */
void add_translation(struct critbit_tree **cb, const char *str, int i);
void init_translations(const struct locale *lang, int ut, const char * (*string_cb)(int i), int maxstrings);
void init_locales(void);
int shipspeed(const struct ship *sh, const struct unit *u);
#define i2b(i) ((bool)((i)?(true):(false)))
@ -171,7 +170,6 @@ extern "C" {
/* returns a value between [0..xpct_2], generated with two dice */
int distribute(int old, int new_value, int n);
void init_locales(void);
void init_locale(struct locale *lang);
int newunitid(void);

View File

@ -627,29 +627,69 @@ static void json_keywords(cJSON *json) {
static void json_races(cJSON *json) {
cJSON *child;
if (json->type!=cJSON_Object) {
if (json->type != cJSON_Object) {
log_error("races is not a json object: %d", json->type);
return;
}
for (child=json->child;child;child=child->next) {
for (child = json->child; child; child = child->next) {
json_race(child, rc_get_or_create(child->string));
}
}
const char * json_relpath;
static void json_include(cJSON *json) {
cJSON *child;
if (json->type != cJSON_Array) {
log_error("config is not a json array: %d", json->type);
return;
}
for (child = json->child; child; child = child->next) {
FILE *F;
if (json_relpath) {
char name[MAX_PATH];
_snprintf(name, sizeof(name), "%s/%s", json_relpath, child->valuestring);
F = fopen(name, "rt");
}
else {
F = fopen(child->valuestring, "rt");
}
if (F) {
cJSON *config;
char *data;
size_t sz;
fseek(F, 0, SEEK_END);
sz = ftell(F);
rewind(F);
data = malloc(sz);
fread(data, 1, sz, F);
fclose(F);
config = cJSON_Parse(data);
free(data);
json_config(config);
cJSON_Delete(config);
}
}
}
void json_config(cJSON *json) {
cJSON *child;
if (json->type!=cJSON_Object) {
log_error("config is not a json object: %d", json->type);
return;
}
reset_locales();
for (child=json->child;child;child=child->next) {
if (strcmp(child->string, "races")==0) {
json_races(child);
}
else if (strcmp(child->string, "items")==0) {
else if (strcmp(child->string, "items") == 0) {
json_items(child);
}
else if (strcmp(child->string, "ships")==0) {
else if (strcmp(child->string, "include") == 0) {
json_include(child);
}
else if (strcmp(child->string, "ships") == 0) {
json_ships(child);
}
else if (strcmp(child->string, "strings")==0) {
@ -676,6 +716,5 @@ void json_config(cJSON *json) {
log_error("config contains unknown attribute %s", child->string);
}
}
init_locales();
}

View File

@ -18,6 +18,7 @@ extern "C" {
struct cJSON;
void json_config(struct cJSON *str);
extern const char * json_relpath;
#ifdef __cplusplus
}

View File

@ -10,11 +10,13 @@
#include "race.h"
#include "ship.h"
#include "spell.h"
#include "order.h"
#include "terrain.h"
#include "util/language.h"
#include <CuTest.h>
#include <cJSON.h>
#include <tests.h>
#include <string.h>
#include <stdio.h>
static const struct race * race_with_flag(const char * name) {
@ -101,7 +103,7 @@ static void test_races(CuTest * tc)
static void test_findrace(CuTest *tc) {
const char * data = "{\"races\": { \"dwarf\": {} }, \"strings\": { \"de\" : { \"race::dwarf\" : \"Zwerg\" } } }";
cJSON *json = cJSON_Parse(data);
const struct locale *lang;
struct locale *lang;
const race *rc;
CuAssertPtrNotNull(tc, json);
@ -110,6 +112,7 @@ static void test_findrace(CuTest *tc) {
CuAssertPtrEquals(tc, 0, (void *)findrace("Zwerg", lang));
json_config(json);
init_locale(lang);
rc = findrace("Zwerg", lang);
CuAssertPtrNotNull(tc, rc);
CuAssertStrEquals(tc, "dwarf", rc->_name);
@ -228,29 +231,29 @@ static void test_spells(CuTest * tc)
CuAssertPtrEquals(tc, 0, find_spell("fireball"));
}
static const char * building_data = "{\"buildings\": { "
"\"house\" : { "
"\"maintenance\" : "
"{ \"type\" : \"iron\", \"amount\" : 1, \"flags\" : [ \"required\", \"variable\" ] }"
","
"\"construction\" : {"
"\"maxsize\" : 20,"
"\"reqsize\" : 10,"
"\"minskill\" : 1,"
"\"materials\" : {"
"\"stone\" : 2,"
"\"iron\" : 1"
"}}},"
"\"shed\" : {"
"\"maintenance\" : ["
"{ \"type\" : \"iron\", \"amount\" : 1 },"
"{ \"type\" : \"stone\", \"amount\" : 2 }"
"]}"
"}}";
static void test_buildings(CuTest * tc)
{
const char * data = "{\"buildings\": { "
"\"house\" : { "
"\"maintenance\" : "
"{ \"type\" : \"iron\", \"amount\" : 1, \"flags\" : [ \"required\", \"variable\" ] }"
","
"\"construction\" : {"
"\"maxsize\" : 20,"
"\"reqsize\" : 10,"
"\"minskill\" : 1,"
"\"materials\" : {"
"\"stone\" : 2,"
"\"iron\" : 1"
"}}},"
"\"shed\" : {"
"\"maintenance\" : ["
"{ \"type\" : \"iron\", \"amount\" : 1 },"
"{ \"type\" : \"stone\", \"amount\" : 2 }"
"]}"
"}}";
cJSON *json = cJSON_Parse(data);
cJSON *json = cJSON_Parse(building_data);
const building_type *bt;
test_cleanup();
@ -292,6 +295,25 @@ static void test_buildings(CuTest * tc)
test_cleanup();
}
static void test_configs(CuTest * tc)
{
const char * data = "{\"include\": [ \"test.json\" ] }";
FILE *F;
cJSON *json = cJSON_Parse(data);
test_cleanup();
F = fopen("test.json", "wt");
fwrite(building_data, 1, strlen(building_data), F);
fclose(F);
CuAssertPtrNotNull(tc, json);
CuAssertPtrEquals(tc, 0, buildingtypes);
json_config(json);
CuAssertPtrNotNull(tc, buildingtypes);
unlink("test.json");
test_cleanup();
}
static void test_terrains(CuTest * tc)
{
const char * data = "{\"terrains\": { \"plain\" : { \"flags\" : [ \"land\", \"fly\", \"walk\" ] } }}";
@ -374,6 +396,7 @@ static void test_keywords(CuTest * tc)
CuAssertIntEquals(tc, K_MOVE, get_keyword("nach", lang));
CuAssertStrEquals(tc, "LERNEN", locale_string(lang, "keyword::study"));
CuAssertStrEquals(tc, "NACH", locale_string(lang, "keyword::move"));
test_cleanup();
}
@ -395,6 +418,26 @@ static void test_strings(CuTest * tc)
CuAssertStrEquals(tc, "LERNEN", locale_string(lang, "study"));
}
static void test_infinitive_from_config(CuTest *tc) {
char buffer[32];
struct locale *lang;
struct order *ord;
const char * data = "{\"keywords\": { \"de\" : { \"study\" : [ \"LERNE\", \"LERNEN\" ] }}}";
cJSON *json = cJSON_Parse(data);
CuAssertPtrNotNull(tc, json);
json_config(json);
lang = get_or_create_locale("de");
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERN", lang));
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNE", lang));
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang));
ord = create_order(K_STUDY, lang, "");
CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer)));
test_cleanup();
}
CuSuite *get_jsonconf_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -404,6 +447,7 @@ CuSuite *get_jsonconf_suite(void)
SUITE_ADD_TEST(suite, test_items);
SUITE_ADD_TEST(suite, test_ships);
SUITE_ADD_TEST(suite, test_buildings);
SUITE_ADD_TEST(suite, test_configs);
SUITE_ADD_TEST(suite, test_castles);
SUITE_ADD_TEST(suite, test_terrains);
SUITE_ADD_TEST(suite, test_races);
@ -411,6 +455,7 @@ CuSuite *get_jsonconf_suite(void)
SUITE_ADD_TEST(suite, test_strings);
SUITE_ADD_TEST(suite, test_spells);
SUITE_ADD_TEST(suite, test_flags);
SUITE_ADD_TEST(suite, test_infinitive_from_config);
return suite;
}

View File

@ -32,6 +32,7 @@ static void test_parse_order(CuTest *tc) {
struct locale * lang = get_or_create_locale("en");
locale_setstring(lang, "keyword::move", "MOVE");
init_keyword(lang, K_MOVE, "MOVE");
ord = parse_order("MOVE NORTH", lang);
CuAssertPtrNotNull(tc, ord);
CuAssertIntEquals(tc, K_MOVE, getkeyword(ord));

View File

@ -1460,6 +1460,7 @@ int readgame(const char *filename, int backup)
storage store;
FILE *F;
init_locales();
log_printf(stdout, "- reading game data from %s\n", filename);
sprintf(path, "%s/%s", datapath(), filename);

View File

@ -1,6 +1,7 @@
#include <platform.h>
#include "kernel/types.h"
#include "kernel/config.h"
#include "kernel/order.h"
#include "keyword.h"
#include "util/language.h"
#include "tests.h"
@ -19,6 +20,25 @@ static void test_init_keywords(CuTest *tc) {
test_cleanup();
}
static void test_infinitive(CuTest *tc) {
char buffer[32];
struct locale *lang;
struct order *ord;
test_cleanup();
lang = get_or_create_locale("de");
locale_setstring(lang, "keyword::study", "LERNE");
init_keyword(lang, K_STUDY, "LERNE");
init_keyword(lang, K_STUDY, "LERNEN");
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERN", lang));
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNE", lang));
CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang));
ord = create_order(K_STUDY, lang, "");
CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer)));
test_cleanup();
}
static void test_init_keyword(CuTest *tc) {
struct locale *lang;
test_cleanup();
@ -76,6 +96,7 @@ static void test_get_shortest_match(CuTest *tc) {
CuSuite *get_keyword_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_infinitive);
SUITE_ADD_TEST(suite, test_init_keyword);
SUITE_ADD_TEST(suite, test_init_keywords);
SUITE_ADD_TEST(suite, test_findkeyword);
@ -83,4 +104,3 @@ CuSuite *get_keyword_suite(void)
SUITE_DISABLE_TEST(suite, test_get_keyword_default);
return suite;
}

View File

@ -4562,10 +4562,10 @@ int init_data(const char *filename, const char *catalog)
{
int l;
l = read_xml(filename, catalog);
reset_locales();
if (l) {
return l;
}
init_locales();
if (turn < 0) {
turn = first_turn;
}

View File

@ -11,8 +11,8 @@ static void test_init_skills(CuTest *tc) {
test_cleanup();
lang = get_or_create_locale("de");
locale_setstring(lang, "alchemy", "Alchemie");
init_skills(lang);
// locale_setstring(lang, "alchemy", "Alchemie");
init_skill(lang, SK_ALCHEMY, "Alchemie");
CuAssertIntEquals(tc, SK_ALCHEMY, get_skill("alchemie", lang));
test_cleanup();
}

View File

@ -243,8 +243,32 @@ void *get_translation(const struct locale *lang, const char *str, int index) {
return NULL;
}
void free_locales(void)
const char *localenames[] = {
"de", "en",
NULL
};
extern void init_locale(struct locale *lang);
static int locale_init = 0;
void init_locales(void)
{
int l;
if (locale_init) return;
for (l = 0; localenames[l]; ++l) {
struct locale *lang = get_or_create_locale(localenames[l]);
init_locale(lang);
}
locale_init = 1;
}
void reset_locales(void) {
locale_init = 0;
}
void free_locales(void) {
locale_init = 0;
while (locales) {
int i;
locale * next = locales->next;
@ -261,4 +285,5 @@ void free_locales(void)
free(locales);
locales = next;
}
memset(lstrs, 0, sizeof(lstrs)); // TODO: does this data need to be free'd?
}

View File

@ -29,7 +29,9 @@ extern "C" {
/** managing multiple locales: **/
extern struct locale *get_locale(const char *name);
extern struct locale *get_or_create_locale(const char *key);
extern void free_locales(void);
void init_locales(void);
void free_locales(void);
void reset_locales(void);
/** operations on locales: **/
extern void locale_setstring(struct locale *lang, const char *key,