From 6f50f9282a22d7a0fe902b037c6428ce9b0adf13 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Mon, 16 Apr 2001 14:34:19 +0000
Subject: [PATCH] dev-version:
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- STRINGS
  strings.txt für deutsch und englisch um einen Haufen fehlender Einträge
  erweitert.language.c schreibt jetzt auf Wunsch ein logfile aller fehlender
  strings, was extrem hilfreich beim ergänzen ist.

- LOKALISIERUNG
  Man kann jetzt Befehle komplett in einer anderen Sprache geben. Der NR macht
  Talente, Zugvorlage und Gegenstände in der eigenen Sprache.

- monster.h
  zu monster.c nach gamecode verschoben

- locale_string(key, NULL)
  NULL-locale liefert jetzt den key selbst zurück.

- CR:
  1. Anzeige der hashes statt der lokalisierten strings
  2. TRANSLATION Block

- Messages:
  make_message heisst jetzt msg_message
  msg_error() ist eine neue funktion für fehlermeldungen

- strings.txt, messages.xml
  Einen Haufen neuer Einträge gemacht.
---
 src/askalon/main.c                        |   4 +-
 src/common/gamecode/creport.c             | 128 +++++++-
 src/common/gamecode/economy.c             |  81 ++---
 src/common/gamecode/laws.c                | 129 ++++----
 src/common/gamecode/monster.c             |  68 ++--
 src/common/{kernel => gamecode}/monster.h |   2 +-
 src/common/gamecode/randenc.c             |   7 +-
 src/common/gamecode/report.c              |  80 +++--
 src/common/gamecode/spy.c                 |  12 +-
 src/common/gamecode/study.c               |  44 +--
 src/common/kernel/battle.c                |   4 +-
 src/common/kernel/build.c                 |  24 +-
 src/common/kernel/building.c              |  20 +-
 src/common/kernel/combatspells.c          |  15 +-
 src/common/kernel/curse.c                 |  22 +-
 src/common/kernel/eressea.c               | 303 +++++++++++++----
 src/common/kernel/eressea.h               |  41 +--
 src/common/kernel/item.c                  |  27 +-
 src/common/kernel/karma.c                 |  18 +-
 src/common/kernel/magic.c                 |  22 +-
 src/common/kernel/message.c               |  56 +++-
 src/common/kernel/message.h               |   8 +-
 src/common/kernel/movement.c              |  92 +++---
 src/common/kernel/pool.c                  |   2 +-
 src/common/kernel/race.c                  |   8 +-
 src/common/kernel/race.h                  |   9 +-
 src/common/kernel/region.c                |   5 +-
 src/common/kernel/reports.c               |  17 +-
 src/common/kernel/reports.h               |   2 +-
 src/common/kernel/save.c                  | 204 ++----------
 src/common/kernel/save.h                  |   2 +-
 src/common/kernel/skill.c                 |  66 ++--
 src/common/kernel/skill.h                 |   2 +
 src/common/kernel/spell.c                 |  40 +--
 src/common/kernel/terrain.c               |   3 +-
 src/common/modules/gmcmd.c                |  14 +-
 src/common/spells/spells.c                |   6 +
 src/common/util/crmessage.c               |  10 +-
 src/common/util/language.c                |  55 +++-
 src/common/util/language.h                |  13 +-
 src/common/util/message.c                 |  14 +-
 src/common/util/umlaut.c                  |   6 +-
 src/common/util/umlaut.h                  |   4 +-
 src/common/util/util-6.dsp                |  22 +-
 src/eressea/attributes.c                  |   2 +
 src/eressea/eressea-6.dsp                 | 119 +++++--
 src/eressea/korrektur.c                   |  22 +-
 src/eressea/main.c                        |  17 +-
 src/eressea/old/order.c                   |   2 +-
 src/mapper/map_units.c                    |   6 +-
 src/res/de/messages.xml                   |  50 ++-
 src/res/de/strings.txt                    | 246 +++++++++++++-
 src/res/en/messages.xml                   |  22 +-
 src/res/en/strings.txt                    | 379 ++++++++++++++++++++--
 src/tools/prototype-advance/Graph.pyc     | Bin 3635 -> 3389 bytes
 src/tools/prototype-advance/Stack.pyc     | Bin 790 -> 259 bytes
 src/tools/translator.c                    |   2 +-
 57 files changed, 1760 insertions(+), 818 deletions(-)
 rename src/common/{kernel => gamecode}/monster.h (99%)

diff --git a/src/askalon/main.c b/src/askalon/main.c
index ea0f3abc4..51e3a2bd3 100644
--- a/src/askalon/main.c
+++ b/src/askalon/main.c
@@ -397,7 +397,7 @@ main(int argc, char *argv[])
 		sprintf(buf, "fopen(%s): ", "res/spells");
 		perror(buf);
 	}
-
+/*
 	F = fopen("res/bonus", "wt");
 	if (F) {
 		race_t r;
@@ -422,7 +422,7 @@ main(int argc, char *argv[])
 		sprintf(buf, "fopen(%s): ", "res/spells");
 		perror(buf);
 	}
-
+*/
 	debug = 0;
 	quickleave = 0;
 
diff --git a/src/common/gamecode/creport.c b/src/common/gamecode/creport.c
index 129adec76..b22317bfe 100644
--- a/src/common/gamecode/creport.c
+++ b/src/common/gamecode/creport.c
@@ -74,6 +74,68 @@ extern int quiet;
 /* globals */
 #define C_REPORT_VERSION 57
 
+/*
+ * translation table
+ */
+typedef struct translation {
+	struct translation * next;
+	const char * key;
+	const char * value;
+} translation;
+
+#define TRANSMAXHASH 255
+static translation * translation_table[TRANSMAXHASH];
+static translation * junkyard;
+
+static const char *
+add_translation(const char * key, const char * value)
+{
+	int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH;
+	translation * t = translation_table[kk];
+	while (t && strcmp(t->key, key)!=0) t=t->next;
+	if (!t) {
+		if (junkyard) {
+			t = junkyard;
+			junkyard = junkyard->next;
+		} else t = malloc(sizeof(translation));
+		t->key = key;
+		t->value = value;
+		t->next = translation_table[kk];
+		translation_table[kk] = t;
+	}
+	return key;
+}
+
+static void
+write_translations(FILE * F)
+{
+	int i;
+	fputs("TRANSLATION\n", F);
+	for (i=0;i!=TRANSMAXHASH;++i) {
+		translation * t = translation_table[i];
+		while (t) {
+			fprintf(F, "\"%s\";%s\n", t->value, t->key);
+			t = t->next;
+		}
+	}
+}
+
+static void
+reset_translations(void)
+{
+	int i;
+	for (i=0;i!=TRANSMAXHASH;++i) {
+		translation * t = translation_table[i];
+		while (t) {
+			translation * c = t->next;
+			t->next = junkyard;
+			junkyard = t;
+			t = c;
+		}
+		translation_table[i] = 0;
+	}
+}
+
 /* implementation */
 void
 cr_output_str_list(FILE * F, const char *title, const strlist * S, faction * f)
@@ -114,11 +176,12 @@ print_curses(FILE * F, void * obj, typ_t typ, attrib *a, int self)
 			}
 		} else if (a->type==&at_effect && self) {
 			effect_data * data = (effect_data *)a->data.v;
+			const char * key = resourcename(data->type->itype->rtype, 0);
 			if (!header) {
 				header = 1;
 				fputs("EFFECTS\n", F);
 			}
-			fprintf(F, "\"%d %s\"\n", data->value, locale_string(NULL, resourcename(data->type->itype->rtype, 0)));
+			fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(NULL, key)));
 		}
 		a = a->next;
 	}
@@ -185,22 +248,37 @@ cr_resource(const void * v, char * buffer, const void * userdata)
 	const faction * report = (const faction*)userdata;
 	const resource_type * r = (const resource_type *)v;
 	if (r) {
-		sprintf(buffer, "\"%s\"", locale_string(report->locale, resourcename(r, 0)));
+		const char * key = resourcename(r, 0);
+		sprintf(buffer, "\"%s\"", 
+			add_translation(key, locale_string(report->locale, key)));
 		return 0;
 	}
 	return -1;
 }
 
+static int
+cr_race(const void * v, char * buffer, const void * userdata)
+{
+	const faction * report = (const faction*)userdata;
+	int rc = (int)v;
+	const char * key = race[rc].name[0];
+	sprintf(buffer, "\"%s\"", 
+		add_translation(key, locale_string(report->locale, key)));
+	return 0;
+}
+
 static int
 cr_skill(const void * v, char * buffer, const void * userdata)
 {
 	const faction * report = (const faction*)userdata;
 	skill_t sk = (skill_t)v;
-	if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", locale_string(report->locale, skillnames[sk]));
+	if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", 
+		add_translation(skillname(sk, NULL), skillname(sk, report->locale)));
 	else strcpy(buffer, "\"\"");
 	return 0;
 }
 
+
 void 
 creport_init(void)
 {
@@ -214,11 +292,19 @@ creport_init(void)
 	tsf_register("building", &cr_building);
 	tsf_register("skill", &cr_skill);
 	tsf_register("resource", &cr_resource);
+	tsf_register("race", &cr_race);
+	tsf_register("direction", &cr_int);
 }
 
 void
 creport_cleanup(void)
 {
+	while (junkyard) {
+		translation * t = junkyard;
+		junkyard = junkyard->next;
+		free(t);
+	}
+	junkyard = 0;
 }
 
 static int msgno;
@@ -315,7 +401,7 @@ cr_output_buildings(FILE * F, building * b, unit * u, int fno, faction *f)
 		const attrib * a = a_find(b->attribs, &at_icastle);
 		if (a) type = ((icastle_data*)a->data.v)->type;
 	}
-	fprintf(F, "\"%s\";Typ\n", buildingtype(b, b->size, f->locale));
+	fprintf(F, "\"%s\";Typ\n", add_translation(b->type->_name, locale_string(f->locale, b->type->_name)));
 	fprintf(F, "\"%s\";Name\n", b->name);
 	if (strlen(b->display))
 		fprintf(F, "\"%s\";Beschr\n", b->display);
@@ -352,7 +438,7 @@ cr_output_ship(FILE * F, ship * s, unit * u, int fcaptain, faction * f, region *
 	fprintf(F, "\"%s\";Name\n", s->name);
 	if (strlen(s->display))
 		fprintf(F, "\"%s\";Beschr\n", s->display);
-	fprintf(F, "\"%s\";Typ\n", s->type->name[0]);
+	fprintf(F, "\"%s\";Typ\n", add_translation(s->type->name[0], locale_string(f->locale, s->type->name[0])));
 	fprintf(F, "%d;Groesse\n", s->size);
 	if (s->damage) {
 		int percent = s->damage*100/(s->size*DAMAGE_SCALE);
@@ -444,10 +530,12 @@ cr_output_unit(FILE * F, region * r,
 
 
 	pzTmp = get_racename(u->attribs);
-	if (pzTmp==NULL) fprintf(F, "\"%s\";Typ\n", race[u->irace].name[1]);
+	if (pzTmp==NULL) fprintf(F, "\"%s\";Typ\n", 
+		add_translation(race[u->irace].name[1], locale_string(f->locale, race[u->irace].name[1])));
 	else fprintf(F, "\"%s\";Typ\n", pzTmp);
 	if ((pzTmp || u->irace != u->race) && u->faction==f) {
-		fprintf(F, "\"%s\";wahrerTyp\n", race[u->race].name[1]);
+		fprintf(F, "\"%s\";wahrerTyp\n", 
+			add_translation(race[u->race].name[1], locale_string(f->locale, race[u->race].name[1])));
 	}
 
 	if (u->building)
@@ -502,7 +590,7 @@ cr_output_unit(FILE * F, region * r,
 		fprintf(F, "COMMANDS\n");
 		if(u->lastorder[0]) fprintf(F, "\"%s\"\n", u->lastorder);
 		for (S = u->orders; S; S = S->next) {
-			if(is_persistent(S->s)) {
+			if(is_persistent(S->s, u->faction->locale)) {
 				fprintf(F, "\"%s\"\n", S->s);
 			}
 		}
@@ -519,7 +607,8 @@ cr_output_unit(FILE * F, region * r,
 				/* 0 ist nur der Kompatibilit�t wegen drin, rausnehmen */
 				fprintf(F, "0 %d;%s\n", eff_skill(u, sk, r), skillnames[sk]);
 #else
-				fprintf(F, "%d %d;%s\n", get_skill(u, sk), eff_skill(u, sk, r), skillnames[sk]);
+				fprintf(F, "%d %d;%s\n", get_skill(u, sk), eff_skill(u, sk, r), 
+					add_translation(skillname(sk, NULL), skillname(sk, f->locale)));
 #endif
 			}
 		/* spells */
@@ -733,6 +822,7 @@ report_computer(FILE * F, faction * f)
 	else printf(" - schreibe Computerreport\n");
 
 	fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
+	fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
 	fprintf(F, "\"%s\";Spiel\n", global.gamename);
 	fprintf(F, "\"%s\";Konfiguration\n", "Standard");
 	fprintf(F, "\"%s\";Koordinaten\n", "Hex");
@@ -748,7 +838,7 @@ report_computer(FILE * F, faction * f)
 		fprintf(F, "%d;Punkte\n", f->score);
 		fprintf(F, "%d;Punktedurchschnitt\n", average_score_of_age(f->age, f->age / 24 + 1));
 	}
-	fprintf(F, "\"%s\";Typ\n", race[f->race].name[1]);
+	fprintf(F, "\"%s\";Typ\n", add_translation(race[f->race].name[1], locale_string(f->locale, race[f->race].name[1])));
 	fprintf(F, "%d;Rekrutierungskosten\n", race[f->race].rekrutieren);
 	fprintf(F, "%d;Anzahl Personen\n", count_all(f));
 	fprintf(F, "\"%s\";Magiegebiet\n", neue_gebiete[f->magiegebiet]);
@@ -800,13 +890,14 @@ report_computer(FILE * F, faction * f)
 		m = ptype->itype->construction->materials;
 		ch = resourcename(ptype->itype->rtype, 0);
 		fprintf(F, "TRANK %d\n", hashstring(ch));
-		fprintf(F, "\"%s\";Name\n", locale_string(f->locale, ch));
+		fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch)));
 		fprintf(F, "%d;Stufe\n", ptype->level);
 		fprintf(F, "\"%s\";Beschr\n", ptype->text);
 		fprintf(F, "ZUTATEN\n");
 
 		while (m->number) {
-			fprintf(F, "\"%s\"\n", locale_string(f->locale, resourcename(oldresourcetype[m->type], 0)));
+			ch = resourcename(oldresourcetype[m->type], 0);
+			fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch)));
 			m++;
 		}
 	}
@@ -836,7 +927,7 @@ report_computer(FILE * F, faction * f)
 			else tname = terrain[rterrain(r)].name;
 		}
 
-		fprintf(F, "\"%s\";Terrain\n", locale_string(f->locale, tname));
+		fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname)));
 		if (sd->mode != see_neighbour)
 		{
 			int g = 0;
@@ -879,10 +970,11 @@ report_computer(FILE * F, faction * f)
 					if(rpeasants(r)/TRADE_FRACTION > 0) {
 						fputs("PREISE\n", F);
 						while (dmd) {
-								fprintf(F, "%d;%s\n", (dmd->value
-										  ? dmd->value*dmd->type->price
-										  : -dmd->type->price),
-										  locale_string(f->locale, resourcename(dmd->type->itype->rtype, 0)));
+							const char * ch = resourcename(dmd->type->itype->rtype, 0);
+							fprintf(F, "%d;%s\n", (dmd->value
+									  ? dmd->value*dmd->type->price
+									  : -dmd->type->price),
+									  add_translation(ch, locale_string(f->locale, ch)));
 							dmd=dmd->next;
 						}
 					}
@@ -1009,4 +1101,6 @@ report_computer(FILE * F, faction * f)
 		}			/* region traversal */
 	}
 	report_crtypes(F, f->locale);
+	write_translations(F);
+	reset_translations();
 }
diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c
index 4102da5ca..59ef54ad1 100644
--- a/src/common/gamecode/economy.c
+++ b/src/common/gamecode/economy.c
@@ -733,7 +733,7 @@ giveunit(region * r, unit * u, unit * u2, strlist * S)
 	 * HELFE, PASSWORT, STIRB (Katja) */
 
 	for (S = u->orders; S; S = S->next) {
-		switch (igetkeyword(S->s)) {
+		switch (igetkeyword(S->s, u->faction->locale)) {
 		case K_BIETE:
 		case K_RESEARCH:
 		case K_BUY:
@@ -791,7 +791,7 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 
 	s = getstrtoken();
 
-	if (findparam(s) == P_CONTROL) {
+	if (findparam(s, u->faction->locale) == P_CONTROL) {
 		if (!u2) {
 			cmistake(u, S->s, notfound_error, MSG_EVENT);
 			return;
@@ -849,7 +849,7 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 	}
 
 	/* �bergabe aller Kr�uter */
-	if (findparam(s) == P_HERBS) {
+	if (findparam(s, u->faction->locale) == P_HERBS) {
 		if (!(race[u->race].ec_flags & GIVEITEM)) {
 			sprintf(buf, "%s geben nichts weg", race[u->race].name[1]);
 			mistake(u, S->s, buf, MSG_COMMERCE);
@@ -876,12 +876,12 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 		if (!n) cmistake(u, S->s, 38, MSG_COMMERCE);
 		return;
 	}
-	if (findparam(s) == P_ZAUBER) { /* Uebergebe alle Spr�che */
+	if (findparam(s, u->faction->locale) == P_ZAUBER) { /* Uebergebe alle Spr�che */
 		cmistake(u, S->s, 7, MSG_COMMERCE);
 		/* geht nimmer */
 		return;
 	}
-	if (findparam(s) == P_UNIT) {	/* Einheiten uebergeben */
+	if (findparam(s, u->faction->locale) == P_UNIT) {	/* Einheiten uebergeben */
 		if (!(race[u->race].ec_flags & GIVEUNIT)) {
 			cmistake(u, S->s, 167, MSG_COMMERCE);
 			return;
@@ -894,7 +894,7 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 		giveunit(r, u, u2, S);
 		return;
 	}
-	if (findparam(s) == P_ANY) { /* Alle Gegenst�nde �bergeben */
+	if (findparam(s, u->faction->locale) == P_ANY) { /* Alle Gegenst�nde �bergeben */
 		char * s = getstrtoken();
 		const resource_type * rtype = findresourcetype(s, u->faction->locale);
 		if (rtype!=NULL) {
@@ -923,7 +923,7 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 			}
 			return;
 		}
-		i = findparam(s);
+		i = findparam(s, u->faction->locale);
 		if (i == P_PERSON) {
 			if (!(race[u->race].ec_flags & GIVEPERSON)) {
 				sprintf(buf, "%s k�nnen nicht neu gruppiert werden.", unitname(u));
@@ -934,16 +934,6 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 			givemen(n, u, u2, S);
 			return;
 		}
-		if (i == P_SILVER) {
-			if ((race[u->race].ec_flags & HOARDMONEY)) {
-				sprintf(buf, "%s geben kein Silber weg.", race[u->race].name[1]);
-				mistake(u, S->s, buf, MSG_COMMERCE);
-				return;
-			}
-			n = get_resource(u, R_SILVER) - get_resvalue(u, R_SILVER);
-			givesilver(n, u, r, u2, S);
-			return;
-		}
 
 		if (!(race[u->race].ec_flags & GIVEITEM)) {
 			sprintf(buf, "%s geben nichts weg.", race[u->race].name[1]);
@@ -977,7 +967,7 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 			return;
 		}
 	}
-	i = findparam(s);
+	i = findparam(s, u->faction->locale);
 	if (i == P_PERSON) {
 		if (!(race[u->race].ec_flags & GIVEPERSON)) {
 			sprintf(buf, "%s k�nnen nicht neu gruppiert werden.", unitname(u));
@@ -987,15 +977,6 @@ dogive(region * r, unit * u, strlist * S, boolean liefere)
 		givemen(n, u, u2, S);
 		return;
 	}
-	if (i == P_SILVER) {
-		if ((race[u->race].ec_flags & HOARDMONEY)) {
-			sprintf(buf, "%s geben kein Silber weg.", race[u->race].name[1]);
-			mistake(u, S->s, buf, MSG_COMMERCE);
-			return;
-		}
-		givesilver(n, u, r, u2, S);
-		return;
-	}
 
 	if (!(race[u->race].ec_flags & GIVEITEM)) {
 		sprintf(buf, "%s geben nichts weg.", race[u->race].name[1]);
@@ -1018,9 +999,9 @@ forgetskill(unit * u)
 
 	s = getstrtoken();
 
-	if ((talent = findskill(s)) != NOSKILL) {
+	if ((talent = findskill(s, u->faction->locale)) != NOSKILL) {
 		set_skill(u, talent, 0);
-/*		sprintf(buf, "%s vergi�t das Talent %s.", unitname(u), skillnames[talent]); */
+/*		sprintf(buf, "%s vergi�t das Talent %s.", u, talent); */
 		add_message(&u->faction->msgs, new_message(u->faction,
 			"forget%u:unit%t:skill", u, talent));
 	}
@@ -1259,7 +1240,7 @@ economics(void)
 
 		for (u = r->units; u; u = u->next) {
 			for (S = u->orders; S; S = S->next) {
-				switch (igetkeyword(S->s)) {
+				switch (igetkeyword(S->s, u->faction->locale)) {
 
 				case K_DESTROY:
 					destroy(r, u, S->s);
@@ -1285,7 +1266,7 @@ economics(void)
 
 		for (u = r->units; u; u = u->next) {
 			for (S = u->orders; S; S = S->next) {
-				if (igetkeyword(S->s) == K_RECRUIT) {
+				if (igetkeyword(S->s, u->faction->locale) == K_RECRUIT) {
 					recruit(r, u, S, &recruitorders);
 					break;
 				}
@@ -1323,14 +1304,13 @@ manufacture(unit * u, const item_type * itype, int want)
 	n = build(u, itype->construction, 0, want);
 	switch (n) {
 	case ENEEDSKILL:
-		sprintf(buf, "dazu braucht man das Talent %s", skillnames[sk]);
-		mistake(u, u->thisorder, buf, MSG_PRODUCE);
+		add_message(&u->faction->msgs, 
+			msg_error(u, u->thisorder, "skill_needed", "skill", sk));
 		return;
 	case ELOWSKILL:
-		sprintf(buf, "man ben�tigt mindestens %s %d, um %s zu machen",
-			skillnames[sk],
-			minskill, locale_string(u->faction->locale, resourcename(itype->rtype, 1)));
-		mistake(u, u->thisorder, buf, MSG_PRODUCE);
+		add_message(&u->faction->msgs,
+			msg_error(u, u->thisorder, "manufacture_skills", "skill minskill product", 
+			sk, minskill, itype->rtype, 1));
 		return;
 	case ENOMATERIALS:
 		/* something missing from the list of materials */
@@ -1457,17 +1437,16 @@ allocate_resource(unit * u, const resource_type * rtype, int want)
 	assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it");
 	skill = eff_skill(u, itype->construction->skill, u->region);
 	if (skill == 0) {
-		sprintf(buf, "dazu braucht man das Talent %s",
-				skillnames[itype->construction->skill]);
-		mistake(u, u->thisorder, buf, MSG_PRODUCE);
+		skill_t sk = itype->construction->skill;
+		add_message(&u->faction->msgs, 
+			msg_error(u, u->thisorder, "skill_needed", "skill", sk));
 		return;
 	}
 	if (skill < itype->construction->minskill) {
-		const char * iname = locale_string(u->faction->locale, resourcename(itype->rtype, 1));
-		sprintf(buf, "man ben�tigt mindestens %s %d, um %s zu machen",
-			skillnames[itype->construction->skill],
-			itype->construction->minskill, iname);
-		mistake(u, u->thisorder, buf, MSG_PRODUCE);
+		skill_t sk = itype->construction->skill;
+		add_message(&u->faction->msgs,
+			msg_error(u, u->thisorder, "manufacture_skills", "skill minskill product", 
+			sk, itype->construction->minskill, itype->rtype));
 		return;
 	} else {
 		struct building * b = inside_building(u);
@@ -1683,7 +1662,7 @@ make(region * r, unit * u)
 		m = INT_MAX;
 	}
 
-	p = findparam(s);
+	p = findparam(s, u->faction->locale);
 
 	/* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in
 	 * thisorder abgespeichert werden - und auf den ist getstrtoken() beim
@@ -2142,7 +2121,7 @@ sell(region * r, unit * u, request ** sellorders, const char * cmd)
 	 * (das geld der region) aufgebraucht wird. */
 
 	s = getstrtoken();
-	if (findparam(s) == P_ANY) {
+	if (findparam(s, u->faction->locale) == P_ANY) {
 		n = (rpeasants(r) - rpeasants(r) / RECRUITFRACTION) / TRADE_FRACTION;
 		if (rterrain(r) == T_DESERT && buildingtype_exists(r, &bt_caravan))
 			n *= 2;
@@ -2348,7 +2327,7 @@ zuechte(region *r, unit *u)
 	int n, c;
 	int gezuechtet = 0;
 
-	if (getparam() == P_HERBS) {
+	if (getparam(u->faction->locale) == P_HERBS) {
 		plant(r, u);
 		return;
 	} else {
@@ -2404,7 +2383,7 @@ research(region *r, unit *u)
 
 	s = getstrtoken();
 
-	if (findparam(s) == P_HERBS) {
+	if (findparam(s, u->faction->locale) == P_HERBS) {
 
 		if (eff_skill(u, SK_HERBALISM, r) < 7) {
 			cmistake(u, u->thisorder, 227, MSG_EVENT);
@@ -2839,7 +2818,7 @@ produce(void)
 			}
 
 			for (s=u->orders;s;s=s->next) {
-				todo = igetkeyword(s->s);
+				todo = igetkeyword(s->s, u->faction->locale);
 				switch (todo) {
 				case K_BUY:
 					buy(r, u, &buyorders, s->s);
@@ -2859,7 +2838,7 @@ produce(void)
 				continue;
 			}
 
-			todo = igetkeyword(u->thisorder);
+			todo = igetkeyword(u->thisorder, u->faction->locale);
 			if (todo == NOKEYWORD) continue;
 
 			if (rterrain(r) == T_OCEAN && u->race != RC_AQUARIAN &&
diff --git a/src/common/gamecode/laws.c b/src/common/gamecode/laws.c
index f63558954..323072c9c 100644
--- a/src/common/gamecode/laws.c
+++ b/src/common/gamecode/laws.c
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
@@ -29,6 +29,13 @@
 # include "old/trigger.h"
 #endif
 
+/* gamecode includes */
+#include "creation.h"
+#include "economy.h"
+#include "monster.h"
+#include "randenc.h"
+#include "study.h"
+
 /* kernel includes */
 #include <alchemy.h>
 #include <border.h>
@@ -40,7 +47,6 @@
 #include <ship.h>
 #include <skill.h>
 #include <movement.h>
-#include <monster.h>
 #include <spy.h>
 #include <race.h>
 #include <battle.h>
@@ -52,12 +58,6 @@
 #include <building.h>
 #include <group.h>
 
-/* gamecode includes */
-#include "study.h"
-#include "economy.h"
-#include "creation.h"
-#include "randenc.h"
-
 /* attributes includes */
 #include <attributes/racename.h>
 
@@ -898,7 +898,7 @@ quit(void)
 	for (r = regions; r; r = r->next)
 		for (u = r->units; u; u = u->next)
 			for (S = u->orders; S; S = S->next)
-				if (igetkeyword(S->s) == K_QUIT) {
+				if (igetkeyword(S->s, u->faction->locale) == K_QUIT) {
 					if (strcmp(getstrtoken(), u->faction->passw) == 0) {
 						destroyfaction(u->faction);
 					} else {
@@ -906,7 +906,7 @@ quit(void)
 						printf("	Warnung: STIRB mit falschem Passwort f�r Partei %s: %s\n",
 							   factionid(u->faction), S->s);
 					}
-				} else if(igetkeyword(S->s) == K_RESTART && u->number > 0) {
+				} else if(igetkeyword(S->s, u->faction->locale) == K_RESTART && u->number > 0) {
 					if (!landregion(rterrain(r))) {
 						cmistake(u, S->s, 242, MSG_EVENT);
 						continue;
@@ -996,7 +996,7 @@ set_ally(unit * u, strlist * S)
 	if (!s[0])
 		keyword = P_ANY;
 	else
-		keyword = findparam(s);
+		keyword = findparam(s, u->faction->locale);
 
 	sfp = &u->faction->allies;
 #ifdef GROUPS
@@ -1009,7 +1009,7 @@ set_ally(unit * u, strlist * S)
 		if (sf->faction == f)
 			break;	/* Gleich die passende raussuchen, wenn vorhanden */
 
-	not_kw = getparam();		/* HELFE partei [modus] NICHT */
+	not_kw = getparam(u->faction->locale);		/* HELFE partei [modus] NICHT */
 
 	if (!sf) {
 		if (keyword == P_NOT || not_kw == P_NOT) {
@@ -1024,7 +1024,6 @@ set_ally(unit * u, strlist * S)
 	}
 	switch (keyword) {
 	case P_NOT:
-	case P_NEUTRAL:
 		sf->status = 0;
 		break;
 
@@ -1032,7 +1031,6 @@ set_ally(unit * u, strlist * S)
 		cmistake(u, S->s, 137, MSG_EVENT);
 		return;
 
-	case P_FRIEND:
 	case P_ANY:
 		if (not_kw == P_NOT)
 			sf->status = 0;
@@ -1091,7 +1089,7 @@ set_display(region * r, unit * u, strlist * S)
 
 	s = 0;
 
-	switch (getparam()) {
+	switch (getparam(u->faction->locale)) {
 	case P_BUILDING:
 	case P_GEBAEUDE:
 		if (!u->building) {
@@ -1191,11 +1189,11 @@ set_name(region * r, unit * u, strlist * S)
 
 	s = 0;
 
-	p = getparam();
+	p = getparam(u->faction->locale);
 
 	if(p == P_FOREIGN) {
 		foreign = true;
-		p = getparam();
+		p = getparam(u->faction->locale);
 	}
 
 	switch (p) {
@@ -1456,7 +1454,7 @@ distributeMail(region * r, unit * u, strlist * S)
 	if(strcasecmp(s, "an") == 0)
 		s = getstrtoken();
 
-	switch (findparam(s)) {
+	switch (findparam(s, u->faction->locale)) {
 
 	case P_REGION:				/* k�nnen alle Einheiten in der Region sehen */
 		s = getstrtoken();
@@ -1514,7 +1512,7 @@ distributeMail(region * r, unit * u, strlist * S)
 			}
 
 			if(see == false) {
-				cmistake(u, S->s, 63, MSG_MESSAGE);
+				cmistake(u, S->s, 64, MSG_MESSAGE);
 				return;
 			}
 
@@ -1602,7 +1600,7 @@ mail(void)
 	for (r = regions; r; r = r->next)
 		for (u = r->units; u; u = u->next)
 			for (S = u->orders; S; S = S->next)
-				if (igetkeyword(S->s) == K_MAIL)
+				if (igetkeyword(S->s, u->faction->locale) == K_MAIL)
 					distributeMail(r, u, S);
 }
 /* ------------------------------------------------------------- */
@@ -1641,7 +1639,7 @@ set_passw(void)
 	for (r = regions; r; r = r->next)
 		for (u = r->units; u; u = u->next)
 			for (S = u->orders; S; S = S->next) {
-				switch (igetkeyword(S->s)) {
+				switch (igetkeyword(S->s, u->faction->locale)) {
 				case NOKEYWORD:
 					cmistake(u, S->s, 22, MSG_EVENT);
 					break;
@@ -1716,23 +1714,6 @@ set_passw(void)
 					}
 					break;
 
-				case K_LOCALE:
-					s = getstrtoken();
-#define LOCALES
-#ifdef LOCALES
-					if (find_locale(s)) {
-						u->faction->locale = find_locale(s);
-					} else {
-						cmistake(u, S->s, 257, MSG_EVENT);
-					}
-#else
-					if(strcmp(s, "de") == 0) {
-						u->faction->locale = find_locale(s);
-					} else {
-						cmistake(u, S->s, 257, MSG_EVENT);
-					}
-#endif
-					break;
 				case K_SEND:
 					s = getstrtoken();
 					o = findoption(s);
@@ -1763,7 +1744,7 @@ set_passw(void)
 						cmistake(u, S->s, 135, MSG_EVENT);
 					} else {
 						i = (int) pow(2, o);
-						if (getparam() == P_NOT) {
+						if (getparam(u->faction->locale) == P_NOT) {
 							u->faction->options = u->faction->options & ~i;
 						} else {
 							u->faction->options = u->faction->options | i;
@@ -1814,14 +1795,20 @@ display_item(faction *f, unit *u, const item_type * itype)
 	const char *name;
 
 	if (u && *i_find(&u->items, itype) == NULL) return false;
-	name = locale_string(NULL, resourcename(itype->rtype, 0));
+	name = resourcename(itype->rtype, 0);
 	sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(f->locale), name);
 	fp = fopen(filename, "r");
 	if (!fp) {
-		sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(NULL), name);
+		name = locale_string(f->locale, resourcename(itype->rtype, 0));		
+		sprintf(filename, "%s/%s/items/%s", resourcepath(), locale_name(f->locale), name);
 		fp = fopen(filename, "r");
-		if (!fp) return false;
 	}
+	if (!fp) {
+		name = resourcename(itype->rtype, 0);
+		sprintf(filename, "%s/items/%s", resourcepath(), name);
+		fp = fopen(filename, "r");
+	}
+	if (!fp) return false;
 
 	sprintf(buf, "%s: ", name);
 
@@ -1937,14 +1924,14 @@ instant_orders(void)
 #ifdef GROUPS
 			for (S = u->orders; S; S = S->next)
 			{
-				if (igetkeyword(S->s)==K_GROUP) {
+				if (igetkeyword(S->s, u->faction->locale)==K_GROUP) {
 					set_group(u);
 				}
 			}
 #endif
 			for (S = u->orders; S; S = S->next)
 
-				switch (igetkeyword(S->s)) {
+				switch (igetkeyword(S->s, u->faction->locale)) {
 				case K_URSPRUNG:
 					{
 						int px, py;
@@ -1966,7 +1953,7 @@ instant_orders(void)
 
 				case K_STATUS:
 					param = getstrtoken();
-					switch (findparam(param)) {
+					switch (findparam(param, u->faction->locale)) {
 					case P_NOT:
 						u->status = ST_AVOID;
 						break;
@@ -1993,7 +1980,7 @@ instant_orders(void)
 #ifdef NOAID
 					case P_HELP:
 						param = getstrtoken();
-						if(findparam(param) == P_NOT) {
+						if(findparam(param, u->faction->locale) == P_NOT) {
 							fset(u, FL_NOAID);
 						} else {
 							fset(u, FL_NOAID);
@@ -2017,13 +2004,13 @@ instant_orders(void)
 					s = getstrtoken();
 
 					/* KAMPFZAUBER [NICHT] l�scht alle gesetzten Kampfzauber */
-					if (!s || *s == 0 || findparam(s) == P_NOT) {
+					if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) {
 						unset_combatspell(u, 0);
 						break;
 					}
 
 					/* Optional: STUFE n */
-					if (findparam(s) == P_LEVEL) {
+					if (findparam(s, u->faction->locale) == P_LEVEL) {
 						/* Merken, setzen kommt erst sp�ter */
 						s = getstrtoken();
 						level = atoi(s);
@@ -2041,7 +2028,7 @@ instant_orders(void)
 					/* KAMPFZAUBER "<Spruchname>" NICHT  l�scht diesen speziellen
 					 * Kampfzauber */
 					s = getstrtoken();
-					if(findparam(s) == P_NOT){
+					if(findparam(s, u->faction->locale) == P_NOT){
 						unset_combatspell(u,spell);
 						break;
 					}
@@ -2062,15 +2049,15 @@ instant_orders(void)
 						cmistake(u, S->s, 223, MSG_EVENT);
 						break;
 					}
-					if (getparam() == P_NOT)
+					if (getparam(u->faction->locale) == P_NOT)
 						setguard(u, GUARD_NONE);
 					break;
 
 				case K_RESHOW:
 					s = getstrtoken();
 
-					if(findparam(s) == P_ANY) {
-						param_t p = getparam();
+					if(findparam(s, u->faction->locale) == P_ANY) {
+						param_t p = getparam(u->faction->locale);
 
 						if(p == P_ZAUBER) {
 							a_removeall(&u->faction->attribs, &at_seenspell);
@@ -2152,7 +2139,7 @@ bewache_an(void)
 		for (u = r->units; u; u = u->next)
 			if (!fval(u, FL_MOVED)) {
 				for (S = u->orders; S; S = S->next) {
-					if (igetkeyword(S->s) == K_GUARD && getparam() != P_NOT) {
+					if (igetkeyword(S->s, u->faction->locale) == K_GUARD && getparam(u->faction->locale) != P_NOT) {
 						if (rterrain(r) != T_OCEAN) {
 							if (!illusionary(u) && u->race != RC_SPELL) {
 #ifdef WACH_WAFF
@@ -2297,9 +2284,9 @@ reorder(void)
 			if (!fval(u, FL_MARK)) {
 				strlist * o;
 				for (o=u->orders;o;o=o->next) {
-					if (igetkeyword(o->s)==K_SORT) {
+					if (igetkeyword(o->s, u->faction->locale)==K_SORT) {
 						const char * s = getstrtoken();
-						param_t p = findparam(s);
+						param_t p = findparam(s, u->faction->locale);
 						int id = getid();
 						unit **vp, *v = findunit(id);
 						if (v==NULL || v->faction!=u->faction || v->region!=r) {
@@ -2354,9 +2341,9 @@ renumber(void)
 	for (r=regions;r;r=r->next) {
 		for (u=r->units;u;u=u->next) {
 			faction * f = u->faction;
-			for (S = u->orders; S; S = S->next) if (igetkeyword(S->s)==K_NUMBER) {
+			for (S = u->orders; S; S = S->next) if (igetkeyword(S->s, u->faction->locale)==K_NUMBER) {
 				s = getstrtoken();
-				switch(findparam(s)) {
+				switch(findparam(s, u->faction->locale)) {
 
 				case P_FACTION:
 					s = getstrtoken();
@@ -2549,7 +2536,7 @@ new_units (void)
 	for (r = regions; r; r = r->next)
 		for (u = r->units; u; u = u->next)
 			for (S = u->orders; S;) {
-				if ((igetkeyword(S->s) == K_MAKE) && (getparam() == P_TEMP)) {
+				if ((igetkeyword(S->s, u->faction->locale) == K_MAKE) && (getparam(u->faction->locale) == P_TEMP)) {
 					const attrib * a;
 					int g;
 					char * name;
@@ -2563,7 +2550,7 @@ new_units (void)
 						S = S->next;
 
 						while (S) {
-							if (igetkeyword(S->s) == K_END)
+							if (igetkeyword(S->s, u->faction->locale) == K_END)
 								break;
 							S2 = S->next;
 							removelist(&u->orders, S);
@@ -2604,7 +2591,7 @@ new_units (void)
 					S = S->next;
 
 					while (S) {
-						if (igetkeyword(S->s) == K_END)
+						if (igetkeyword(S->s, u->faction->locale) == K_END)
 							break;
 						S2 = S->next;
 						translist(&u->orders, &u2->orders, S);
@@ -2635,7 +2622,7 @@ setdefaults (void)
 
 			set_string(&u->thisorder, u->lastorder);
 			for(S = u->orders; S; S = S->next) {
-				keyword_t keyword = igetkeyword(S->s);
+				keyword_t keyword = igetkeyword(S->s, u->faction->locale);
 
 				switch (keyword) {
 
@@ -2656,7 +2643,7 @@ setdefaults (void)
 					 * abgespeichert). */
 
 				case K_MAKE:
-					if (getparam() == P_TEMP) break;
+					if (getparam(u->faction->locale) == P_TEMP) break;
 				case K_BESIEGE:
 				case K_ENTERTAIN:
 				case K_RESEARCH:
@@ -2670,7 +2657,7 @@ setdefaults (void)
 				case K_BIETE:
 				case K_PIRACY:
 					if (idle (u->faction)) {
-						set_string (&u->thisorder, keywords[K_WORK]);
+						set_string (&u->thisorder, locale_string(u->faction->locale, keywords[K_WORK]));
 						break;
 					}
 					/* Ab hier Befehle, die auch eine idle
@@ -2683,7 +2670,7 @@ setdefaults (void)
 				case K_DRIVE:
 				case K_MOVE:
 					if(fval(u, FL_HUNGER)) {
-						set_string(&u->thisorder, keywords[K_WORK]);
+						set_string(&u->thisorder, locale_string(u->faction->locale, keywords[K_WORK]));
 					} else {
 						set_string(&u->thisorder, S->s);
 					}
@@ -2711,7 +2698,7 @@ setdefaults (void)
 			 * die Einheitsnummer ungueltig). Auch Attackiere sollte nie in
 			 * den Default �bernommen werden */
 
-			switch (igetkeyword (u->thisorder)) {
+			switch (igetkeyword (u->thisorder, u->faction->locale)) {
 				case K_MOVE:
 				case K_BIETE:
 				case K_ATTACK:
@@ -2721,8 +2708,8 @@ setdefaults (void)
 				set_string(&u->lastorder, u->thisorder);
 			}
 			/* Attackiere sollte niemals Default werden */
-			if (igetkeyword(u->lastorder) == K_ATTACK)
-				set_string(&u->lastorder, keywords[K_WORK]);
+			if (igetkeyword(u->lastorder, u->faction->locale) == K_ATTACK)
+				set_string(&u->lastorder, locale_string(u->faction->locale, keywords[K_WORK]));
 
 		}
 	}
@@ -2838,7 +2825,7 @@ defaultorders (void)
 	list_foreach(region, regions, r) {
 		list_foreach(unit, r->units, u) {
 			list_foreach(strlist, u->orders, s) {
-				switch (igetkeyword(s->s)) {
+				switch (igetkeyword(s->s, u->faction->locale)) {
 				case K_DEFAULT:
 					c = getstrtoken();
 					i = atoi(c);
@@ -2849,11 +2836,11 @@ defaultorders (void)
 						s->s[0]=0;
 						break;
 					case 1 :
-						sprintf(buf, "%s \"%s\"", keywords[K_DEFAULT], getstrtoken());
+						sprintf(buf, "%s \"%s\"", locale_string(u->faction->locale, keywords[K_DEFAULT]), getstrtoken());
 						set_string(&s->s, buf);
 						break;
 					default :
-						sprintf(buf, "%s %d \"%s\"", keywords[K_DEFAULT], i-1, getstrtoken());
+						sprintf(buf, "%s %d \"%s\"", locale_string(u->faction->locale, keywords[K_DEFAULT]), i-1, getstrtoken());
 						set_string(&s->s, buf);
 						break;
 					}
@@ -2925,7 +2912,7 @@ processorders (void)
 	for (r = regions; r; r = r->next) {
 		for (u = r->units; u; u = u->next) {
 			for (S = u->orders; S; S = S->next) {
-				if (igetkeyword(S->s) == K_USE) {
+				if (igetkeyword(S->s, u->faction->locale) == K_USE) {
 					char * t = getstrtoken();
 					const item_type * itype = finditemtype(t, u->faction->locale);
 
diff --git a/src/common/gamecode/monster.c b/src/common/gamecode/monster.c
index a71574e88..c861b1cea 100644
--- a/src/common/gamecode/monster.c
+++ b/src/common/gamecode/monster.c
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
@@ -21,22 +21,25 @@
 
 #include <config.h>
 #include "eressea.h"
-#include "item.h"
-
 #include "monster.h"
-#include "reports.h"
-#include "message.h"
-#include "region.h"
+
 #include "economy.h"
-#include "faction.h"
-#include "movement.h"
-#include "race.h"
-#include "magic.h"
-#include "build.h"
-#include "pool.h"
-#include "names.h"
-#include "unit.h"
-#include "pathfinder.h"
+
+/* kernel includes */
+#include <item.h>
+#include <reports.h>
+#include <message.h>
+#include <region.h>
+#include <faction.h>
+#include <movement.h>
+#include <race.h>
+#include <magic.h>
+#include <skill.h>
+#include <build.h>
+#include <pool.h>
+#include <names.h>
+#include <unit.h>
+#include <pathfinder.h>
 
 /* util includes */
 #include <attrib.h>
@@ -95,7 +98,7 @@ monster_attack(unit * u, const unit * target)
 	if (is_waiting(u)) return false;
 
 	sprintf(zText, "%s %s",
-		keywords[K_ATTACK], unitid(target));
+		locale_string(u->faction->locale, keywords[K_ATTACK]), unitid(target));
 	S = makestrlist(zText);
 	addlist(&u->orders, S);
 	return true;
@@ -106,7 +109,7 @@ taxed_by_monster(unit * u)
 {
 	strlist *S;
 
-	S = makestrlist(keywords[K_TAX]);
+	S = makestrlist(locale_string(u->faction->locale, keywords[K_TAX]));
 	addlist(&u->orders, S);
 }
 
@@ -348,7 +351,7 @@ move_monster(region * r, unit * u)
 	if (d == NODIRECTION)
 		return;
 
-	sprintf(buf, "%s %s", keywords[K_MOVE], directions[d]);
+	sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), locale_string(u->faction->locale, directions[d]));
 
 	S = makestrlist(buf);
 	S->next = u->orders;
@@ -438,7 +441,7 @@ set_movement_order(unit * u, const region * target, int moves, boolean (*allowed
 		return false;
 	}
 
-	strcpy(buf, keywords[K_MOVE]);
+	strcpy(buf, locale_string(u->faction->locale, keywords[K_MOVE]));
 	c = buf + strlen(buf);
 
 	while (position!=moves && plan[position+1]) {
@@ -447,7 +450,7 @@ set_movement_order(unit * u, const region * target, int moves, boolean (*allowed
 		direction_t dir = reldirection(prev, next);
 		assert(dir!=NODIRECTION);
 		*c++ = ' ';
-		strcpy(c, directions[dir]);
+		strcpy(c, locale_string(u->faction->locale, directions[dir]));
 		c += strlen(c);
 	}
 
@@ -530,7 +533,7 @@ monster_seeks_target(region *r, unit *u)
 
 	if( d == NODIRECTION )
 		return;
-	sprintf(buf, "%s %s", keywords[K_MOVE], directions[d]);
+	sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), locale_string(u->faction->locale, directions[d]));
 	SP = &u->orders;
 	S = makestrlist(buf);
 	addlist2(SP, S);
@@ -605,14 +608,14 @@ random_attack_by_monster(const region * r, unit * u)
 		    && target != u
 		    && humanoid(target)
 			&& !illusionary(target)
-		    && target->number <= max) 
+		    && target->number <= max)
 		{
 			if (monster_attack(u, target)) {
 				unit * u2;
 				success = true;
 				for (u2 = r->units; u2; u2 = u2->next) {
-					if (u2->faction->no == MONSTER_FACTION 
-						&& rand() % 100 < 75) 
+					if (u2->faction->no == MONSTER_FACTION
+						&& rand() % 100 < 75)
 					{
 						monster_attack(u2, target);
 					}
@@ -867,7 +870,8 @@ learn_monster(unit *u)
 		if(get_skill(u, sk) > 0) {
 			c++;
 			if(c == n) {
-				sprintf(buf, "%s %s", keywords[K_STUDY], skillnames[sk]);
+				sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_STUDY]), 
+					skillname(sk, u->faction->locale));
 				set_string(&u->thisorder, buf);
 				break;
 			}
@@ -943,7 +947,7 @@ plan_monsters(void)
 			if (ta && strncmp(u->lastorder, "WARTEN", 6) != 0) {
 				unit * tu = (unit *)ta->data.v;
 				if (tu && tu->region==r) {
-					sprintf(buf, "%s %s", keywords[K_ATTACK], itoa36(tu->no));
+					sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_ATTACK]), itoa36(tu->no));
 					S = makestrlist(buf);
 					addlist(&u->orders, S);
 				} else if (tu) {
@@ -964,7 +968,7 @@ plan_monsters(void)
 
 			if (!(fval(u, FL_ISNEW)) && r->terrain != T_OCEAN) { /* Monster bewachen immer */
 				strlist *S;
-				S = makestrlist(keywords[K_GUARD]);
+				S = makestrlist(locale_string(u->faction->locale, keywords[K_GUARD]));
 				addlist(&u->orders, S);
 			}
 
@@ -977,15 +981,15 @@ plan_monsters(void)
 			} else {
 				boolean done = false;
 				if((race[u->race].flags & RCF_ATTACKRANDOM)
-					&& rand()%100<MONSTERATTACK 
-					&& is_moving == false) 
+					&& rand()%100<MONSTERATTACK
+					&& is_moving == false)
 				{
 					done = random_attack_by_monster(r, u);
-				} 
+				}
 				if (!done) {
 					if(u->race == RC_SEASERPENT) {
-						set_string(&u->thisorder, keywords[K_PIRACY]);
-						set_string(&u->lastorder, keywords[K_PIRACY]);
+						set_string(&u->thisorder, locale_string(u->faction->locale, keywords[K_PIRACY]));
+						set_string(&u->lastorder, locale_string(u->faction->locale, keywords[K_PIRACY]));
 					} else if(race[u->race].flags & RCF_LEARN) {
 						learn_monster(u);
 					}
diff --git a/src/common/kernel/monster.h b/src/common/gamecode/monster.h
similarity index 99%
rename from src/common/kernel/monster.h
rename to src/common/gamecode/monster.h
index 1624502bf..fa1aa92b5 100644
--- a/src/common/kernel/monster.h
+++ b/src/common/gamecode/monster.h
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
diff --git a/src/common/gamecode/randenc.c b/src/common/gamecode/randenc.c
index 1356eeba6..1fe6c3841 100644
--- a/src/common/gamecode/randenc.c
+++ b/src/common/gamecode/randenc.c
@@ -1025,8 +1025,8 @@ randomevents(void)
 
 					u->hp += unit_max_hp(u) * increase;
 					add_message(&u->faction->msgs, new_message(u->faction,
-						"orcgrowth%u:unit%i:amount%s:race",
-						u, increase, increase == 1 ? race[u->race].name[0] : race[u->race].name[1]));
+						"orcgrowth%u:unit%i:amount%i:race",
+						u, increase, u->race));
 				}
 			}
 		}
@@ -1095,7 +1095,8 @@ randomevents(void)
 #if 0
 /* ist kaputt. wei� nicht, wieso. */
 							if (r==s) {
-								sprintf(buf, "Durch Konzentrationsmangel vergi�t %s das Talent %s vollst�ndig", unitname(u), skillnames[sk]);
+								sprintf(buf, "Durch Konzentrationsmangel vergi�t %s das Talent %s vollst�ndig", 
+									unitname(u), skillname(u->faction->local, sk));
 								addmessage(0, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
 							}
 #endif
diff --git a/src/common/gamecode/report.c b/src/common/gamecode/report.c
index ded6dc898..851c4b4f6 100644
--- a/src/common/gamecode/report.c
+++ b/src/common/gamecode/report.c
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
@@ -649,9 +649,9 @@ print_curses(FILE *F, const void * obj, typ_t typ, const attrib *a, int self, in
 			}
 		} else if (a->type==&at_effect && self) {
 			effect_data * data = (effect_data *)a->data.v;
-			sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", 
+			sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.",
 					(data->value==1 ? "t" : "en"),
-					data->value, 
+					data->value,
 					(data->value==1 ? "" : "en"),
 					locale_string(NULL, resourcename(data->type->itype->rtype, 0)));
 			rnl(F);
@@ -795,16 +795,10 @@ f_regionid(const region * r, const faction * f)
 	else {
 		pl = getplane(r);
 		if(pl && fval(pl,PFL_NOCOORDS)) {
-			if (rterrain(r) == T_OCEAN)
-				sprintf(buf, "Ozean");
-			else
-				sprintf(buf, "%s", rname(r, f->locale));
+			sprintf(buf, "%s", rname(r, f->locale));
 		} else {
-			if (rterrain(r) == T_OCEAN)
-				sprintf(buf, "Ozean (%d,%d%s%s)", region_x(r,f), region_y(r,f), pl?",":"", pl?pl->name:"");
-			else
-		     sprintf(buf, "%s (%d,%d%s%s)", rname(r, f->locale), region_x(r,f), region_y(r,f), pl?",":"", pl?pl->name:"");
-			}
+			sprintf(buf, "%s (%d,%d%s%s)", rname(r, f->locale), region_x(r,f), region_y(r,f), pl?",":"", pl?pl->name:"");
+		}
 	}
 
 	return buf;
@@ -1038,13 +1032,13 @@ describe(FILE * F, region * r, int partial, faction * f)
 			scat((char *)a_do->data.v);
 		} else {
 			int nrd = 0;
-			
+
 			/* Nachbarregionen, die gesehen werden, ermitteln */
 			for (d = 0; d != MAXDIRECTIONS; d++)
 				if (see[d] && rconnect(r, d)) nrd++;
-			
+
 			/* Richtungen aufz�hlen */
-			
+
 			dh = false;
 			for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) {
 				region * r2 = rconnect(r, d);
@@ -1055,7 +1049,7 @@ describe(FILE * F, region * r, int partial, faction * f)
 					else scat(", im ");
 				}
 				else scat(" Im ");
-				scat(directions[d]);
+				scat(locale_string(f->locale, directions[d]));
 				scat(" ");
 				if (!dh) scat("der Region liegt ");
 				sprintf(dbuf, trailinto(r2, f->locale),
@@ -1128,7 +1122,7 @@ describe(FILE * F, region * r, int partial, faction * f)
 				if (e->lastd==d) strcat(buf, " und im ");
 				else strcat(buf, ", im ");
 			}
-			strcat(buf, directions[d]);
+			strcat(buf, locale_string(f->locale, directions[d]));
 			first = false;
 		}
 		if (!e->transparent) strcat(buf, " versperrt ");
@@ -1299,7 +1293,7 @@ order_template(FILE * F, faction * f)
 	rps_nowrap(F, "");
 	rnl(F);
 
-	sprintf(buf, "%s %s \"hier_passwort_eintragen\"", parameters[P_FACTION], factionid(f));
+	sprintf(buf, "%s %s \"hier_passwort_eintragen\"", locale_string(f->locale, parameters[P_FACTION]), factionid(f));
 	rps_nowrap(F, buf);
 	rnl(F);
 
@@ -1322,12 +1316,12 @@ order_template(FILE * F, faction * f)
 					rnl(F);
 					pl = getplane(r);
 					if (pl && fval(pl, PFL_NOCOORDS)) {
-						sprintf(buf, "REGION; %s", rname(r, f->locale));
+						sprintf(buf, "%s; %s", locale_string(f->locale, parameters[P_REGION]), rname(r, f->locale));
 					} else if (pl && pl->id != 0) {
-						sprintf(buf, "REGION %d,%d,%d ; %s", region_x(r,f),
+						sprintf(buf, "%s %d,%d,%d ; %s", locale_string(f->locale, parameters[P_REGION]), region_x(r,f),
 								region_y(r,f), pl->id, rname(r, f->locale));
 					} else {
-						sprintf(buf, "REGION %d,%d ; %s", region_x(r,f),
+						sprintf(buf, "%s %d,%d ; %s", locale_string(f->locale, parameters[P_REGION]), region_x(r,f),
 								region_y(r,f), rname(r, f->locale));
 					}
 					rps_nowrap(F, buf);
@@ -1340,7 +1334,7 @@ order_template(FILE * F, faction * f)
 				}
 				dh = 1;
 
-				sprintf(buf, "%s %s;		%s [%d,%d$", parameters[P_UNIT],
+				sprintf(buf, "%s %s;		%s [%d,%d$", locale_string(u->faction->locale, parameters[P_UNIT]),
 						unitid(u), u->name, u->number, get_money(u));
 				if (u->building != NULL && fval(u, FL_OWNER)) {
 					building * b = u->building;
@@ -1370,7 +1364,7 @@ order_template(FILE * F, faction * f)
 				rnl(F);
 
 				for (S2 = u->orders; S2; S2 = S2->next) {
-					if(is_persistent(S2->s)) {
+					if(is_persistent(S2->s, u->faction->locale)) {
 						sprintf(buf, "   %s", S2->s);
 						rps_nowrap(F, buf);
 						rnl(F);
@@ -1388,7 +1382,7 @@ order_template(FILE * F, faction * f)
 	}
 	rps_nowrap(F, "");
 	rnl(F);
-	sprintf(buf, parameters[P_NEXT]);
+	sprintf(buf, locale_string(f->locale, parameters[P_NEXT]));
 	rps_nowrap(F, buf);
 	rnl(F);
 }
@@ -1690,7 +1684,7 @@ report(FILE *F, faction * f)
 
 	centre(F, gamedate(), true);
 	rnl(F);
-	sprintf(buf, "%s, %s/%s (%s)", factionname(f), race[f->race].name[1],
+	sprintf(buf, "%s, %s/%s (%s)", factionname(f), locale_string(f->locale, race[f->race].name[1]),
 			neue_gebiete[f->magiegebiet], f->email);
 	centre(F, buf, true);
 
@@ -2040,11 +2034,12 @@ report(FILE *F, faction * f)
 				}
 				sprintf(buf, "%s, %s, (%d/%d)",
 					shipname(sh),
-					sh->type->name[0],
+					locale_string(f->locale, sh->type->name[0]),
 					(w + 99) / 100,	/* +99 weil sonst die Nachkommastellen ignoriert w�rden */
 					shipcapacity(sh) / 100);
 			} else {
-				sprintf(buf, "%s, %s", shipname(sh), sh->type->name[0]);
+				sprintf(buf, "%s, %s", shipname(sh), 
+					locale_string(f->locale, sh->type->name[0]));
 			}
 
 			assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */
@@ -2379,7 +2374,7 @@ seen_region * last;
 #define MAXSEEHASH 4095
 seen_region * seehash[MAXSEEHASH];
 
-static void 
+static void
 seen_done(void)
 {
 	while (seen) {
@@ -2395,7 +2390,7 @@ seen_done(void)
 }
 
 #if FAST_SEEN
-static void 
+static void
 init_intervals()
 {
 	region * r;
@@ -3386,17 +3381,38 @@ eval_resource(struct opstack ** stack, const void * userdata)
 	const faction * report = (const faction*)userdata;
 	int j = opop(stack, int);
 	struct resource_type * res = opop(stack, struct resource_type *);
-	
+
 	const char * c = locale_string(report->locale, resourcename(res, j!=1));
 	opush(stack, strcpy(balloc(strlen(c)+1), c));
 }
 
+static void
+eval_race(struct opstack ** stack, const void * userdata)
+{
+	const faction * report = (const faction*)userdata;
+	int j = opop(stack, int);
+	int r = opop(stack, int);
+
+	const char * c = locale_string(report->locale, race[r].name[j!=1]);
+	opush(stack, strcpy(balloc(strlen(c)+1), c));
+}
+
+static void
+eval_direction(struct opstack ** stack, const void * userdata)
+{
+	const faction * report = (const faction*)userdata;
+	int i = opop(stack, int);
+
+	const char * c = locale_string(report->locale, directions[i]);
+	opush(stack, strcpy(balloc(strlen(c)+1), c));
+}
+
 static void
 eval_skill(struct opstack ** stack, const void * userdata)
 {
 	const faction * report = (const faction*)userdata;
 	int sk = opop(stack, int);
-	const char * c = locale_string(report->locale, skillnames[sk]);
+	const char * c = skillname(sk, report->locale);
 	opush(stack, strcpy(balloc(strlen(c)+1), c));
 	unused(userdata);
 }
@@ -3406,9 +3422,11 @@ report_init(void)
 {
 	add_function("region", &eval_region);
 	add_function("resource", &eval_resource);
+	add_function("race", &eval_race);
 	add_function("faction", &eval_faction);
 	add_function("ship", &eval_ship);
 	add_function("unit", &eval_unit);
 	add_function("building", &eval_building);
 	add_function("skill", &eval_skill);
+	add_function("direction", &eval_direction);
 }
diff --git a/src/common/gamecode/spy.c b/src/common/gamecode/spy.c
index f8032c7c4..16cf02e3f 100644
--- a/src/common/gamecode/spy.c
+++ b/src/common/gamecode/spy.c
@@ -137,15 +137,15 @@ setstealth(unit * u, strlist * S)
 		return;
 	}
 
-	switch(findparam(s)) {
+	switch(findparam(s, u->faction->locale)) {
 	case P_FACTION:
 		/* TARNE PARTEI [NICHT|NUMMER abcd] */
 		s = getstrtoken();
 		if(!s || *s == 0) {
 			fset(u, FL_PARTEITARNUNG);
-		} else if (findparam(s) == P_NOT) {
+		} else if (findparam(s, u->faction->locale) == P_NOT) {
 			freset(u, FL_PARTEITARNUNG);
-		} else if (findkeyword(s) == K_NUMBER) {
+		} else if (findkeyword(s, u->faction->locale) == K_NUMBER) {
 			char *s2 = getstrtoken();
 			int nr;
 			if(!s2 || *s2 == 0 || (nr = atoi36(s2)) == u->faction->no) {
@@ -176,7 +176,7 @@ setstealth(unit * u, strlist * S)
 			return;
 		}
 		s = getstrtoken();
-		if (findparam(s) == P_NOT) {
+		if (findparam(s, u->faction->locale) == P_NOT) {
 			a = a_find(u->attribs, &at_fshidden);
 			if(a) a->data.ca[0] = 0;
 			if(a->data.i == 0) a_remove(&u->attribs, a);
@@ -192,7 +192,7 @@ setstealth(unit * u, strlist * S)
 			cmistake(u, S->s, 277, MSG_EVENT);
 			return;
 		}
-		if (findparam(s) == P_NOT) {
+		if (findparam(s, u->faction->locale) == P_NOT) {
 			a = a_find(u->attribs, &at_fshidden);
 			if(a) a->data.ca[1] = 0;
 			if(a->data.i == 0) a_remove(&u->attribs, a);
@@ -427,7 +427,7 @@ sabotage(region * r, unit * u)
 
 	s = getstrtoken();
 
-	i = findparam(s);
+	i = findparam(s, u->faction->locale);
 
 	switch (i) {
 	case P_SHIP:
diff --git a/src/common/gamecode/study.c b/src/common/gamecode/study.c
index e018e448e..387212087 100644
--- a/src/common/gamecode/study.c
+++ b/src/common/gamecode/study.c
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
@@ -55,9 +55,9 @@
 
 /* ------------------------------------------------------------- */
 static skill_t
-getskill(void)
+getskill(const struct locale * lang)
 {
-	return findskill(getstrtoken());
+	return findskill(getstrtoken(), lang);
 }
 
 static magic_t
@@ -185,7 +185,7 @@ teach_unit(unit * teacher, unit * student, int teaching, skill_t sk, boolean rep
 		 * Deswegen darf C D nie lehren d�rfen.
 		 *
 		 * -> Das ist wirr. wer hat das entworfen?
-		 * Besser w�re, man macht erst vorab alle zuordnungen, und dann 
+		 * Besser w�re, man macht erst vorab alle zuordnungen, und dann
 		 * die Talent�nderung (enno).
 		 */
 
@@ -236,24 +236,24 @@ teach(region * r, unit * u)
 	if (teaching == 0)
 		return;
 
-	strcpy(order, keywords[K_TEACH]);
+	strcpy(order, locale_string(u->faction->locale, keywords[K_TEACH]));
 
 	u2 = 0;
 	count = 0;
 #if TEACH_ALL
-	if (getparam()==P_ANY) {
+	if (getparam(u->faction->locale)==P_ANY) {
 		unit * student = r->units;
 		skill_t teachskill[MAXSKILLS];
 		int i = 0;
 		do {
-			sk = getskill();
+			sk = getskill(u->faction->locale);
 			teachskill[i++]=sk;
 		} while (sk!=NOSKILL);
 		while (teaching && student) {
 			if (student->faction == u->faction) {
-				if (igetkeyword(student->thisorder) == K_STUDY) {
+				if (igetkeyword(student->thisorder, student->faction->locale) == K_STUDY) {
 					/* Input ist nun von student->thisorder !! */
-					sk = getskill();
+					sk = getskill(student->faction->locale);
 					if (sk!=NOSKILL && teachskill[0]!=NOSKILL) {
 						for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break;
 						sk = teachskill[i];
@@ -268,9 +268,9 @@ teach(region * r, unit * u)
 #if TEACH_FRIENDS
 		while (teaching && student) {
 			if (student->faction != u->faction && allied(u, student->faction, HELP_GUARD)) {
-				if (igetkeyword(student->thisorder) == K_STUDY) {
+				if (igetkeyword(student->thisorder, student->faction->locale) == K_STUDY) {
 					/* Input ist nun von student->thisorder !! */
-					sk = getskill();
+					sk = getskill(student->faction->locale);
 					if (sk != NOSKILL && eff_skill(u, sk, r) > eff_skill(student, sk, r)) {
 						teaching -= teach_unit(u, student, teaching, sk, true);
 					}
@@ -279,7 +279,7 @@ teach(region * r, unit * u)
 			student = student->next;
 		}
 #endif
-	} 
+	}
 	else
 #endif
 	for (;;) {
@@ -292,7 +292,7 @@ teach(region * r, unit * u)
 		 * LEHRE und 101 wird gelesen (und ignoriert), und dann wird
 		 * getunit die einheit 102 zur�ck liefern. */
 
-		igetkeyword(u->thisorder);
+		igetkeyword(u->thisorder, u->faction->locale);
 		for (j = count; j; j--)
 			getstrtoken();
 
@@ -305,7 +305,7 @@ teach(region * r, unit * u)
 
 			/* Finde den string, der den Fehler verursacht hat */
 
-			igetkeyword(u->thisorder);
+			igetkeyword(u->thisorder, u->faction->locale);
 			for (j = count; j; j--)
 				getstrtoken();
 
@@ -320,7 +320,7 @@ teach(region * r, unit * u)
 
 			strcpy(buf, "Die Einheit '");
 
-			if (findparam(s) == P_TEMP) {
+			if (findparam(s, u->faction->locale) == P_TEMP) {
 				/* F�r: "Die Einheit 'TEMP ZET' wurde nicht gefunden" oder "Die Einheit
 				 * 'TEMP' wurde nicht gefunden" */
 
@@ -360,11 +360,11 @@ teach(region * r, unit * u)
 			mistake(u, u->thisorder, buf, MSG_EVENT);
 			continue;
 		}
-		i = igetkeyword(u2->thisorder);
+		i = igetkeyword(u2->thisorder, u2->faction->locale);
 
 		/* Input ist nun von u2->thisorder !! */
 
-		if (i != K_STUDY || ((sk = getskill()) == NOSKILL)) {
+		if (i != K_STUDY || ((sk = getskill(u2->faction->locale)) == NOSKILL)) {
 			sprintf(buf, "%s lernt nicht", unitname(u2));
 			mistake(u, u->thisorder, buf, MSG_EVENT);
 			continue;
@@ -412,7 +412,7 @@ learn(void)
 	for (r = regions; r; r = r->next)
 		for (u = r->units; u; u = u->next)
 			if (rterrain(r) != T_OCEAN || u->race == RC_AQUARIAN)
-				if (igetkeyword(u->thisorder) == K_STUDY) {
+				if (igetkeyword(u->thisorder, u->faction->locale) == K_STUDY) {
 					double multi = 1.0;
 					attrib * a = NULL;
 					int money = 0;
@@ -426,7 +426,7 @@ learn(void)
 						continue;
 					}
 
-					i = getskill();
+					i = getskill(u->faction->locale);
 
 					if (i < 0) {
 						cmistake(u, findorder(u, u->thisorder), 77, MSG_EVENT);
@@ -447,7 +447,7 @@ learn(void)
 
 						p = studycost = study_cost(u,i);
 						a = a_find(u->attribs, &at_learning);
-						
+
 						if (btype == &bt_academy) {
 							studycost = max(50, studycost * 2);
 						}
@@ -601,7 +601,7 @@ learn(void)
 #ifdef SKILLFIX_SAVE
 					if (a && a->data.i) {
 						int skill = get_skill(u, (skill_t)i);
-						skillfix(u, (skill_t)i, skill, 
+						skillfix(u, (skill_t)i, skill,
 								 (int)(u->number * 30 * multi), a->data.i);
 					}
 #endif
@@ -666,7 +666,7 @@ teaching(void)
 					&& !is_cursed(u->attribs, C_KAELTESCHUTZ,0))
 				continue;
 
-			switch (igetkeyword(u->thisorder)) {
+			switch (igetkeyword(u->thisorder, u->faction->locale)) {
 
 			case K_TEACH:
 				if (attacked(u)){
diff --git a/src/common/kernel/battle.c b/src/common/kernel/battle.c
index d1917602f..b498e4d7c 100644
--- a/src/common/kernel/battle.c
+++ b/src/common/kernel/battle.c
@@ -3364,7 +3364,7 @@ do_battle(void)
 				strlist *sl;
 
 				list_foreach(strlist, u->orders, sl) {
-					if (igetkeyword(sl->s) == K_ATTACK) {
+					if (igetkeyword(sl->s, u->faction->locale) == K_ATTACK) {
 						unit *u2;
 						fighter *c1, *c2;
 
@@ -3379,7 +3379,7 @@ do_battle(void)
 #ifdef DELAYED_OFFENSE
 						if (get_moved(&u->attribs) && !guarded_by(r, u->faction)) {
 							add_message(&u->faction->msgs, 
-								make_message("no_attack_after_advance", "unit region command", u, u->region, sl->s));
+								msg_message("no_attack_after_advance", "unit region command", u, u->region, sl->s));
 						}
 #endif
 						if (fval(u, FL_HUNGER)) {
diff --git a/src/common/kernel/build.c b/src/common/kernel/build.c
index 7a58dd77b..a25fecc04 100644
--- a/src/common/kernel/build.c
+++ b/src/common/kernel/build.c
@@ -267,7 +267,7 @@ do_siege(void)
 			unit *u;
 
 			for (u = r->units; u; u = u->next) {
-				if (igetkeyword(u->thisorder) == K_BESIEGE)
+				if (igetkeyword(u->thisorder, u->faction->locale) == K_BESIEGE)
 					siege(r, u);
 			}
 		}
@@ -327,7 +327,7 @@ destroy(region * r, unit * u, const char * cmd)
 
 	s = getstrtoken();
 
-	if (findparam(s)==P_ROAD) {
+	if (findparam(s, u->faction->locale)==P_ROAD) {
 		destroy_road(u, INT_MAX, cmd);
 		return;
 	}
@@ -345,11 +345,11 @@ destroy(region * r, unit * u, const char * cmd)
 		}
 	}
 
-	if(getparam() == P_ROAD) {
+	if(getparam(u->faction->locale) == P_ROAD) {
 		destroy_road(u, n, cmd);
 		return;
 	}
-	 
+
 	if (u->building) {
 		building *b = u->building;
 #if 0
@@ -834,11 +834,11 @@ build_building(unit * u, const building_type * btype, int want)
 	}
 
 	if( want == INT_MAX )
-		sprintf(buffer, "%s %s %s", keywords[K_MAKE], string2, buildingid(b));
+		sprintf(buffer, "%s %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), string2, buildingid(b));
 	else if( want-built <= 0 )
-		strcpy(buffer, keywords[K_WORK]);
+		strcpy(buffer, locale_string(u->faction->locale, keywords[K_WORK]));
 	else
-		sprintf(buffer, "%s %d %s %s", keywords[K_MAKE], want-built, string2, buildingid(b));
+		sprintf(buffer, "%s %d %s %s", locale_string(u->faction->locale, keywords[K_MAKE]), want-built, string2, buildingid(b));
 	set_string(&u->lastorder, buffer);
 
 	b->size += built;
@@ -926,7 +926,7 @@ create_ship(region * r, unit * u, const struct ship_type * newtype, int want)
 	u->ship = sh;
 	fset(u, FL_OWNER);
 	sprintf(buffer, "%s %s %s",
-			keywords[K_MAKE], parameters[P_SHIP], shipid(sh));
+			locale_string(u->faction->locale, keywords[K_MAKE]), locale_string(u->faction->locale, parameters[P_SHIP]), shipid(sh));
 	u->lastorder = set_string(&u->lastorder, buffer);
 
 	build_ship(u, sh, want);
@@ -1031,7 +1031,7 @@ do_leave(void)
 	for (r = regions; r; r = r->next) {
 		for (u = r->units; u; u = u->next) {
 			for (S = u->orders; S; S = S->next) {
-				if(igetkeyword(S->s) == K_LEAVE) {
+				if(igetkeyword(S->s, u->faction->locale) == K_LEAVE) {
 					if (r->terrain == T_OCEAN && u->ship) {
 						if(!(race[u->race].flags & RCF_SWIM)) {
 							cmistake(u, S->s, 11, MSG_MOVE);
@@ -1070,7 +1070,7 @@ do_misc(char try)
 
 		for (u = r->units; u; u = u->next) {
 			for (S = u->orders; S; S = S->next) {
-				switch (igetkeyword(S->s)) {
+				switch (igetkeyword(S->s, u->faction->locale)) {
 				case K_CONTACT:
 					set_contact(r, u, try);
 					break;
@@ -1082,10 +1082,10 @@ do_misc(char try)
 			for (S = u->orders; S;) {
 				Snext = S->next;
 
-				switch (igetkeyword(S->s)) {
+				switch (igetkeyword(S->s, u->faction->locale)) {
 				case K_ENTER:
 
-					switch (getparam()) {
+					switch (getparam(u->faction->locale)) {
 					case P_BUILDING:
 					case P_GEBAEUDE:
 
diff --git a/src/common/kernel/building.c b/src/common/kernel/building.c
index 9c781272d..67336599f 100644
--- a/src/common/kernel/building.c
+++ b/src/common/kernel/building.c
@@ -44,6 +44,22 @@ const building_type *
 bt_find(const char* name)
 {
 	const struct building_typelist * btl = buildingtypes;
+
+	if (global.data_version < RELEASE_VERSION) {
+		const char * translation[3][2] = { 
+			{ "illusion", "illusioncastle" }, 
+			{ "generic", "genericbuilding" }, 
+			{ NULL, NULL } 
+		};
+		int i;
+		for (i=0;translation[i][0];++i) {
+			/* calling a building "illusion" was a bad idea" */
+			if (strcmp(translation[i][0], name)==0) {
+				name = translation[i][1];
+				break;
+			}
+		}
+	}
 	while (btl && strcasecmp(btl->type->_name, name)) btl = btl->next;
 	if (!btl) {
 		btl = buildingtypes;
@@ -656,7 +672,7 @@ building_type bt_blessedstonecircle = {
 
 /** Building: illusion */
 building_type bt_illusion = {
-	"illusion",     /* _name */
+	"illusioncastle",     /* _name */
 	BTF_NOBUILD,     /* flags */
 	0, 0, 0,    /* capac/size, maxcapac, maxsize */
 	NULL,  /* maintenance */
@@ -666,7 +682,7 @@ building_type bt_illusion = {
 
 /** Building: Generisches Geb�ude */
 building_type bt_generic = {
-	"generic",					/* _name */
+	"genericbuilding",					/* _name */
 	BTF_NOBUILD,  			/* flags */
 	-1, -1, 1,  				/* capac/size, maxcapac, maxsize */
 	NULL,								/* maintenance */
diff --git a/src/common/kernel/combatspells.c b/src/common/kernel/combatspells.c
index d6a3cd430..4bfc7c5dd 100644
--- a/src/common/kernel/combatspells.c
+++ b/src/common/kernel/combatspells.c
@@ -3,14 +3,15 @@
 #include "eressea.h"
 
 /* kernel includes */
-#include "magic.h"
-#include "unit.h"
-#include "region.h"
-#include "item.h"
+#include "battle.h"
 #include "build.h"
 #include "building.h"
+#include "faction.h"
+#include "item.h"
+#include "magic.h"
+#include "region.h"
+#include "unit.h"
 #include "movement.h"
-#include "battle.h"
 #include "spell.h"
 #include "race.h"
 
@@ -1173,8 +1174,8 @@ sp_denyattack(fighter * fi, int level, int power, spell * sp)
 	fset(fi, FIG_ATTACKED);
 
 	/* Hat der Magier ein NACH, wird die angegebene Richtung bevorzugt */
-	if (igetkeyword(mage->thisorder) == K_MOVE
-				|| igetkeyword(mage->thisorder) == K_ROUTE)
+	if (igetkeyword(mage->thisorder, mage->faction->locale) == K_MOVE
+				|| igetkeyword(mage->thisorder, mage->faction->locale) == K_ROUTE)
 	{
 		fi->run.region = movewhere(r, mage);
 		if (!fi->run.region) {
diff --git a/src/common/kernel/curse.c b/src/common/kernel/curse.c
index a76c22a73..abb5e3ce6 100644
--- a/src/common/kernel/curse.c
+++ b/src/common/kernel/curse.c
@@ -25,6 +25,7 @@
 
 /* kernel includes */
 #include "magic.h"
+#include "skill.h"
 #include "unit.h"
 #include "region.h"
 #include "race.h"
@@ -139,7 +140,6 @@ cfindhash(int i)
 /* Spruch identifizieren */
 
 #include "umlaut.h"
-extern struct tnode cursenames;
 
 typedef struct cursetype_list {
 	struct cursetype_list * next;
@@ -165,19 +165,15 @@ const curse_type *
 ct_find(const char *c)
 {
 /* TODO: findet nur curse_types, die auch in curse_data sind.
- * da fehlt noch ene registrierung wie f�r attrib_type
+ * da fehlt noch eine registrierung wie f�r attrib_type
  */
-	int i;
-	if (findtoken(&cursenames, c, (void**)&i)==E_TOK_NOMATCH) return NULL;
-	if (i == -1 || cursedaten[i].name[0] == 0) {
-		cursetype_list * ctl = cursetypes;
-		while (ctl) {
-			int k = min(strlen(c), strlen(ctl->type->name));
-			if (!strncasecmp(c, ctl->type->name, k)) return ctl->type;
-			ctl = ctl->next;
-		}
+	cursetype_list * ctl = cursetypes;
+	while (ctl) {
+		int k = min(strlen(c), strlen(ctl->type->name));
+		if (!strncasecmp(c, ctl->type->name, k)) return ctl->type;
+		ctl = ctl->next;
 	}
-	return &cursedaten[i];
+	return NULL;
 }
 
 /* ------------------------------------------------------------- */
@@ -1203,7 +1199,7 @@ cinfo_skill(void * obj, typ_t typ, curse *c, int self)
 
 	if (self){
 		sprintf(buf, "%s ist in %s ungew�hnlich ungeschickt. (%s)", u->name,
-				skillnames[ck->skill], curseid(c));
+				skillname(ck->skill, u->faction->locale), curseid(c));
 		return 1;
 	}
 	return 0;
diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c
index 5ba52ebdd..58403de3d 100644
--- a/src/common/kernel/eressea.c
+++ b/src/common/kernel/eressea.c
@@ -39,7 +39,6 @@
 #include "magic.h"
 #include "building.h"
 #include "battle.h"
-#include "monster.h"
 #include "race.h"
 #include "pool.h"
 #include "region.h"
@@ -76,14 +75,14 @@ FILE    *logfile;
 
 const char *directions[MAXDIRECTIONS+2] =
 {
-	"Nordwesten",
-	"Nordosten",
-	"Osten",
-	"S�dosten",
-	"S�dwesten",
-	"Westen",
+	"northwest",
+	"northeast",
+	"east",
+	"southeast",
+	"southwest",
+	"west",
 	"",
-	"Pause"
+	"pause"
 };
 
 const char *gr_prefix[3] = {
@@ -94,6 +93,7 @@ const char *gr_prefix[3] = {
 
 const char *parameters[MAXPARAMS] =
 {
+	"LOCALE",
 	"ALLES",
 	"BAUERN",
 	"BURG",
@@ -111,13 +111,9 @@ const char *parameters[MAXPARAMS] =
 	"SILBER",
 	"STRA�EN",
 	"TEMPOR�RE",
-	"FEIND",
-	"FREUND",
-	"NEUTRAL",
 	"FLIEHE",
 	"GEB�UDE",
 	"GIB",			/* F�r HELFE */
-	"WAHRNEHMUNG",
 	"K�MPFE",
 	"BEWACHE",
 	"ZAUBERBUCH",
@@ -198,7 +194,6 @@ const char *keywords[MAXKEYWORDS] =
 	"MEINUNG",
 	"MAGIEGEBIET",
 	"PIRATERIE",
-	"LOCALE",
 	"NEUSTART",
 #ifdef GROUPS
 	"GRUPPE",
@@ -714,7 +709,7 @@ isallied(const plane * pl, const faction * f, const faction * f2, int mode)
 		if (p==pl) return mode;
 		a=a->next;
 	}
-	
+
 	if (pl && pl->flags & PFL_FRIENDLY) return mode;
 	if (mode != HELP_GIVE && pl && (pl->flags & PFL_NOALLIANCES)) return 0;
 	for (sf = f->allies; sf; sf = sf->next)
@@ -1118,57 +1113,82 @@ enum {
 	UT_NONE,
 	UT_PARAM,
 	UT_ITEM,
-	UT_SKILL,
-	UT_KEYWORD,
 	UT_BUILDING,
 	UT_HERB,
 	UT_POTION,
 	UT_MAX
 };
 
-struct tnode tokens[UT_MAX];
-struct tnode spellnames;
-struct tnode cursenames;
+static struct lstr {
+	const struct locale * lang;
+	struct tnode tokens[UT_MAX];
+	struct tnode skillnames;
+	struct tnode keywords;
+	struct lstr * next;
+} * lstrs;
+
+static struct lstr *
+get_lnames(const struct locale * lang)
+{
+	static struct lstr * lnames = NULL;
+	static const struct locale * lastlang = NULL;
+
+	if (lastlang!=lang || lnames==NULL) {
+		lnames = lstrs;
+		while (lnames && lnames->lang!=lang) lnames = lnames->next;
+		if (lnames==NULL) {
+			lnames = calloc(sizeof(struct lstr), 1);
+			lnames->lang = lang;
+			lnames->next = lstrs;
+			lstrs = lnames;
+		}
+	}
+	return lnames;
+}
 
 skill_t
-findskill(const char *s)
+findskill(const char *s, const struct locale * lang)
 {
+	struct lstr * lnames = get_lnames(lang);
 	int i;
-	if (findtoken(&tokens[UT_SKILL], s, (void**)&i)==E_TOK_NOMATCH) return NOSKILL;
+
+	if (findtoken(&lnames->skillnames, s, (void**)&i)==E_TOK_NOMATCH) return NOSKILL;
 	return (skill_t)i;
 }
 
 keyword_t
-findkeyword(const char *s)
+findkeyword(const char *s, const struct locale * lang)
 {
+	struct lstr * lnames = get_lnames(lang);
 	int i;
 #ifdef AT_PERSISTENT
 	if(*s == '@') s++;
 #endif
-	if (findtoken(&tokens[UT_KEYWORD], s, (void**)&i)==E_TOK_NOMATCH) return NOKEYWORD;
+	if (findtoken(&lnames->keywords, s, (void**)&i)==E_TOK_NOMATCH) return NOKEYWORD;
 	return (keyword_t) i;
 }
 
 keyword_t
-igetkeyword (const char *s)
+igetkeyword (const char *s, const struct locale * lang)
 {
-	return findkeyword (igetstrtoken (s));
+	return findkeyword (igetstrtoken (s), lang);
 }
 
 keyword_t
-getkeyword (void)
+getkeyword (const struct locale * lang)
 {
-	return findkeyword (getstrtoken ());
+	return findkeyword (getstrtoken (), lang);
 }
 
 param_t
-findparam(const char *s)
+findparam(const char *s, const struct locale * lang)
 {
+	struct lstr * lnames = get_lnames(lang);
 	const building_type * btype;
 
 	int i;
-	if (findtoken(&tokens[UT_PARAM], s, (void**)&i)==E_TOK_NOMATCH) {
-		btype = findbuildingtype(s, NULL);
+	if (findtoken(&lnames->tokens[UT_PARAM], s, (void**)&i)==E_TOK_NOMATCH) {
+		btype = findbuildingtype(s, lang);
 		if (btype!=NULL) return (param_t) P_BUILDING;
 		return NOPARAM;
 	}
@@ -1176,14 +1196,14 @@ findparam(const char *s)
 }
 
 param_t
-igetparam (const char *s)
+igetparam (const char *s, const struct locale *lang)
 {
-	return findparam (igetstrtoken (s));
+	return findparam (igetstrtoken (s), lang);
 }
 param_t
-getparam (void)
+getparam (const struct locale * lang)
 {
-	return findparam (getstrtoken ());
+	return findparam (getstrtoken (), lang);
 }
 
 #ifdef FUZZY_BASE36
@@ -1307,7 +1327,7 @@ read_unitid (faction * f, region * r)
 	 * paramliste. machen wir das nicht, dann wird getnewunit in s nach der
 	 * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */
 
-	switch (findparam (s)) {
+	switch (findparam (s, f->locale)) {
 	case P_TEMP:
 		return read_newunitid(f, r);
 	}
@@ -1556,7 +1576,7 @@ createunitid(region * r1, faction * f, int number, race_t race, int id, const ch
 	assert(f->alive);
 	u_setfaction(u, f);
 	set_string(&u->thisorder, "");
-	set_string(&u->lastorder, keywords[K_WORK]);
+	set_string(&u->lastorder, locale_string(u->faction->locale, keywords[K_WORK]));
 	u_seteffstealth(u, -1);
 	u->race = race;
 	u->irace = race;
@@ -1789,6 +1809,7 @@ typedef struct t_umlaut {
  * WICHTIG: "setenv LANG en_US" sonst ist � != �
  */
 
+#if 0
 static const t_umlaut umlaut[] = {
 /* Parameter */
 	{ "Stra�en", P_ROAD, UT_PARAM },
@@ -1825,28 +1846,27 @@ static const t_umlaut umlaut[] = {
 	{ "Flinkfingerring", I_RING_OF_NIMBLEFINGER, UT_ITEM },
 	{ NULL, 0, 0 }
 };
+#endif
 
 static void
-init_tokens(void)
+init_tokens(const struct locale * lang)
 {
+	struct lstr * lnames = get_lnames(lang);
 	int i;
 	for (i=0;i!=MAXPARAMS;++i)
-		addtoken(&tokens[UT_PARAM], parameters[i], (void*)i);
+		addtoken(&lnames->tokens[UT_PARAM], locale_string(lang, parameters[i]), (void*)i);
 	for (i=0;i!=MAXSKILLS;++i)
-		addtoken(&tokens[UT_SKILL], skillnames[i], (void*)i);
+		addtoken(&lnames->skillnames, skillname(i, lang), (void*)i);
 	for (i=0;i!=MAXKEYWORDS;++i)
-		addtoken(&tokens[UT_KEYWORD], keywords[i], (void*)i);
+		addtoken(&lnames->keywords, locale_string(lang, keywords[i]), (void*)i);
+#if 0
 	for (i=0;umlaut[i].txt;++i)
-		addtoken(&tokens[umlaut[i].typ], umlaut[i].txt, (void*)umlaut[i].id);
-	for (i=0; spelldaten[i].id != SPL_NOSPELL; i++)
-		addtoken(&spellnames, spelldaten[i].name, (void*)i);
-	for (i=0; i!=MAXCURSE; i++){
-		addtoken(&cursenames, cursedaten[i].name, (void*)i);
-	}
+		addtoken(&lnames->tokens[umlaut[i].typ], umlaut[i].txt, (void*)umlaut[i].id);
+#endif
 }
 
 void
-kernel_done(void) 
+kernel_done(void)
 {
 	/* calling this function releases memory assigned to static variables, etc.
 	 * calling it is optional, e.g. a release server will most likely not do it.
@@ -1856,9 +1876,7 @@ kernel_done(void)
 	gc_done();
 }
 
-extern void attrib_init(void);
-
-void
+static void
 read_strings(FILE * F)
 {
 	char rbuf[8192];
@@ -1867,6 +1885,7 @@ read_strings(FILE * F)
 		locale * lang;
 		char * key = b;
 		char * language;
+		const char * k;
 
 		if (rbuf[0]=='#') continue;
 		rbuf[strlen(rbuf)-1] = 0; /* \n weg */
@@ -1878,14 +1897,181 @@ read_strings(FILE * F)
 		*b++ = 0;
 		lang = find_locale(language);
 		if (!lang) lang = make_locale(language);
-		locale_setstring(lang, key, b);
+		k = locale_getstring(lang, key);
+		if (k) {
+			log_warning(("Trying to register %s[%s]=\"%s\", already have \"%s\"\n", key, language, k, b));
+		} else locale_setstring(lang, key, b);
 	}
 }
 
+const char * messages[] = {
+	"%s/%s/messages.xml",
+	NULL
+};
+
+const char * strings[] = {
+	"%s/%s/strings.txt",
+	NULL
+};
+
+const char * locales[] = {
+	"de", "en",
+	NULL
+};
+
+void
+init_locales(void)
+{
+	FILE * F;
+	int l;
+	for (l=0;locales[l];++l) {
+		char zText[MAX_PATH];
+		int i;
+		for (i=0;strings[i];++i) {
+			sprintf(zText, strings[i], resourcepath(), locales[l]);
+			F = fopen(zText, "r+");
+			if (F) {
+				read_strings(F);
+				fclose(F);
+			} else {
+				sprintf(buf, "fopen(%s): ", zText);
+				perror(buf);
+			}
+		}
+		for (i=0;messages[i];++i) {
+			sprintf(zText, messages[i], resourcepath(), locales[l]);
+			F = fopen(zText, "r+");
+			if (F) {
+				read_messages(F, NULL);
+				fclose(F);
+			} else {
+				sprintf(buf, "fopen(%s): ", zText);
+				perror(buf);
+			}
+		}
+	}
+	for (l=0;locales[l];++l) {
+		const struct locale * lang = find_locale(locales[l]);
+		if (lang) init_tokens(lang);
+	}
+}
+
+/* TODO: soll hier weg */
+extern building_type bt_caldera;
+extern attrib_type at_traveldir_new;
+
+void
+attrib_init(void)
+{
+	/* Geb�udetypen registrieren */
+	init_buildings();
+	bt_register(&bt_castle);
+	bt_register(&bt_lighthouse);
+	bt_register(&bt_mine);
+	bt_register(&bt_quarry);
+	bt_register(&bt_harbour);
+	bt_register(&bt_academy);
+	bt_register(&bt_magictower);
+	bt_register(&bt_smithy);
+	bt_register(&bt_sawmill);
+	bt_register(&bt_stables);
+	bt_register(&bt_monument);
+	bt_register(&bt_dam);
+	bt_register(&bt_caravan);
+	bt_register(&bt_tunnel);
+	bt_register(&bt_inn);
+	bt_register(&bt_stonecircle);
+	bt_register(&bt_blessedstonecircle);
+	bt_register(&bt_illusion);
+	bt_register(&bt_generic);
+	bt_register(&bt_caldera);
+
+	/* Schiffstypen registrieren: */
+	st_register(&st_boat);
+	st_register(&st_longboat);
+	st_register(&st_dragonship);
+	st_register(&st_caravelle);
+	st_register(&st_trireme);
+
+	/* disable: st_register(&st_transport); */
+
+	/* Alle speicherbaren Attribute m�ssen hier registriert werden */
+	at_register(&at_unitdissolve);
+	at_register(&at_traveldir_new);
+	at_register(&at_familiar);
+	at_register(&at_familiarmage);
+	at_register(&at_eventhandler);
+	at_register(&at_stealth);
+	at_register(&at_mage);
+	at_register(&at_bauernblut);
+	at_register(&at_countdown);
+	at_register(&at_showitem);
+	at_register(&at_curse);
+	at_register(&at_cursewall);
+
+	at_register(&at_seenspell);
+	at_register(&at_reportspell);
+	at_register(&at_deathcloud);
+
+	/* neue REGION-Attribute */
+	at_register(&at_direction);
+	at_register(&at_moveblock);
+#if AT_SALARY
+	at_register(&at_salary);
+#endif
+	at_register(&at_horseluck);
+	at_register(&at_peasantluck);
+	at_register(&at_deathcount);
+	at_register(&at_chaoscount);
+	at_register(&at_woodcount);
+	at_register(&at_laen);
+	at_register(&at_road);
+
+	/* neue UNIT-Attribute */
+	at_register(&at_alias);
+	at_register(&at_siege);
+	at_register(&at_target);
+	at_register(&at_potion);
+	at_register(&at_potionuser);
+	at_register(&at_contact);
+	at_register(&at_effect);
+	at_register(&at_private);
+
+#if defined(OLD_TRIGGER)
+	at_register(&at_pointer_tag);
+	at_register(&at_relation);
+	at_register(&at_relbackref);
+	at_register(&at_trigger);
+	at_register(&at_action);
+#endif
+	at_register(&at_icastle);
+	at_register(&at_guard);
+	at_register(&at_lighthouse);
+	at_register(&at_group);
+	at_register(&at_faction_special);
+	at_register(&at_prayer_timeout);
+	at_register(&at_prayer_effect);
+	at_register(&at_wyrm);
+	at_register(&at_building_generic_type);
+
+/* border-typen */
+	register_bordertype(&bt_noway);
+	register_bordertype(&bt_fogwall);
+	register_bordertype(&bt_wall);
+	register_bordertype(&bt_illusionwall);
+	register_bordertype(&bt_firewall);
+	register_bordertype(&bt_wisps);
+	register_bordertype(&bt_road);
+
+#if USE_EVENTS
+	at_register(&at_events);
+#endif
+	at_register(&at_jihad);
+}
+
 void
 kernel_init(void)
 {
-	init_tokens();
 	skill_init();
 	attrib_init();
 	translation_init();
@@ -2054,7 +2240,7 @@ register_faction_id(int id)
 
 boolean
 faction_id_is_unused(int id)
-{  
+{
     if(used_faction_ids==NULL)
 		return(true);
 	return (boolean)(bsearch(&id, used_faction_ids, no_used_faction_ids,
@@ -2147,7 +2333,7 @@ resolve2(void)
 
 #endif
 
-static void 
+static void
 init_directions(tnode * root)
 {
 	/* mit dieser routine kann man mehrere namen f�r eine direction geben,
@@ -2488,9 +2674,8 @@ movewhere(region * r, const unit *u)
 			   "(%d,%d) noch nicht generiert!\n", r->x, r->y,
 			   r->x + delta_x[d], r->y + delta_y[d]);
 #else
-		sprintf(buf, "%s entdeckt, da� es keinen Weg nach %s gibt.",
-						unitname(u), directions[d]);
-		addmessage(r, u->faction, buf, MSG_MOVE, ML_WARN);
+		add_message(&u->faction->msgs, 
+			msg_message("moveblocked", "unit direction", u, d));
 		return NULL;
 #endif
 	}
@@ -2504,8 +2689,8 @@ movewhere(region * r, const unit *u)
 	}
 
 	if (move_blocked(u, r, d) == true) {
-		add_message(&u->faction->msgs,
-			new_message(u->faction, "moveblocked%u:unit%i:direction", u, d));
+		add_message(&u->faction->msgs, 
+			msg_message("moveblocked", "unit direction", u, d));
 		return NULL;
 	}
 
diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h
index 18f17d67d..31259dc8c 100644
--- a/src/common/kernel/eressea.h
+++ b/src/common/kernel/eressea.h
@@ -138,6 +138,7 @@ struct building_type;
 #define BASE36IDS_VERSION 197
 #define NEWSOURCE_VERSION 197
 #define NEWSTATUS_VERSION 198
+#define NEWNAMES_VERSION 199
 #define LOCALE_VERSION 300 /* TODO */
 
 /* globale settings des Spieles */
@@ -148,7 +149,7 @@ typedef struct settings {
 } settings;
 extern settings global;
 
-#define RELEASE_VERSION NEWSTATUS_VERSION
+#define RELEASE_VERSION NEWNAMES_VERSION
 #define ECHECK_VERSION "3.11"
 
 /* changes from->to: 72->73: struct unit::lock entfernt.
@@ -401,7 +402,6 @@ enum {
 	K_VOTE,
 	K_MAGIEGEBIET,
 	K_PIRACY,
-	K_LOCALE,
 	K_RESTART,
 #ifdef GROUPS
 	K_GROUP,
@@ -433,6 +433,7 @@ enum {
 
 typedef int param_t;
 enum {
+	P_LOCALE,
 	P_ANY,
 	P_PEASANT,
 	P_BUILDING,
@@ -450,13 +451,9 @@ enum {
 	P_SILVER,
 	P_ROAD,
 	P_TEMP,
-	P_ENEMY,
-	P_FRIEND,
-	P_NEUTRAL,
 	P_FLEE,
 	P_GEBAEUDE,
 	P_GIB,
-	P_OBSERVE,
 	P_KAEMPFE,
 	P_GUARD,
 	P_ZAUBER,
@@ -569,8 +566,6 @@ enum {
 	NOSKILL = (skill_t) -1
 };
 
-extern const char *skillnames[MAXSKILLS];
-
 /* ------------- Typ von Einheiten ----------------------------- */
 
 enum {
@@ -910,15 +905,23 @@ int armedmen(const struct unit * u);
 void scat(const char *s);
 void icat(int n);
 
-int findstr(const char **v, const char *s, unsigned char n);
-
-skill_t findskill(const char *s);
 int atoip(const char *s);
 int geti(void);
-keyword_t igetkeyword(const char *s);
-keyword_t getkeyword(void);
-keyword_t findkeyword(const char *s);
-char *igetstrtoken(const char *s);
+
+extern int findstr(const char **v, const char *s, unsigned char n);
+
+extern char *igetstrtoken(const char *s);
+extern char *getstrtoken(void);
+
+extern skill_t findskill(const char *s, const struct locale * lang);
+
+extern keyword_t findkeyword(const char *s, const struct locale * lang);
+extern keyword_t igetkeyword(const char *s, const struct locale * lang);
+extern keyword_t getkeyword(const struct locale * lang);
+
+extern param_t findparam(const char *s, const struct locale * lang);
+extern param_t igetparam(const char *s, const struct locale * lang);
+extern param_t getparam(const struct locale * lang);
 
 #define BASE36_VERSION 93
 extern int atoi36(const char * s);
@@ -947,12 +950,6 @@ int newunitid(void);
 int forbiddenid(int id);
 int newcontainerid(void);
 
-char *getstrtoken(void);
-char *igetstrtoken(const char *s);
-param_t findparam(const char *s);
-param_t igetparam(const char *s);
-param_t getparam(void);
-
 extern struct unit *createunit(struct region * r, struct faction * f, int number, race_t race);
 extern struct unit *createunitid(struct region * r1, struct faction * f, int number, race_t race, int id, const char * dname);
 extern boolean getunitpeasants;
@@ -1010,8 +1007,6 @@ void freestrlist(strlist * s);
 
 int change_hitpoints(struct unit *u, int value);
 
-skill_t findskill(const char *s);
-
 int weight(const struct unit * u);
 void changeblockchaos(void);
 
diff --git a/src/common/kernel/item.c b/src/common/kernel/item.c
index 57872cf36..0b46d69d3 100644
--- a/src/common/kernel/item.c
+++ b/src/common/kernel/item.c
@@ -1299,6 +1299,9 @@ init_olditems(void)
 	item_t i;
 	resource_type * rtype;
 
+	const struct locale * lang = find_locale("de");
+	assert(lang);
+
 	for (i=0; i!=MAXITEMS; ++i) {
 		int iflags = ITF_NONE;
 		int rflags = RTF_ITEM|RTF_POOLED;
@@ -1354,10 +1357,10 @@ init_olditems(void)
 			}
 		}
 		if (name[0]==NULL) {
-			name[0] = reverse_lookup(NULL, itemdata[i].name[0]);
-			name[1] = reverse_lookup(NULL, itemdata[i].name[1]);
-			appearance[0] = reverse_lookup(NULL, itemdata[i].name[2]);
-			appearance[1] = reverse_lookup(NULL, itemdata[i].name[3]);
+			name[0] = reverse_lookup(lang, itemdata[i].name[0]);
+			name[1] = reverse_lookup(lang, itemdata[i].name[1]);
+			appearance[0] = reverse_lookup(lang, itemdata[i].name[2]);
+			appearance[1] = reverse_lookup(lang, itemdata[i].name[3]);
 		}
 		rtype = new_resourcetype(name, appearance, rflags);
 		itype = new_itemtype(rtype, iflags, weight, capacity, minskill, skill);
@@ -1490,6 +1493,10 @@ init_oldherbs(void)
 	herb_t h;
 	const char * names[2];
 	const char * appearance[2] = { "herbbag", "herbbag" };
+
+	const struct locale * lang = find_locale("de");
+	assert(lang);
+
 	for (h=0;h!=MAXHERBS;++h) {
 		item_type * itype;
 		terrain_t t;
@@ -1506,8 +1513,8 @@ init_oldherbs(void)
 			}
 		}
 		if (!names[0]) {
-			names[0] = reverse_lookup(NULL, herbdata[0][h]);
-			names[1] = reverse_lookup(NULL, herbdata[1][h]);
+			names[0] = reverse_lookup(lang, herbdata[0][h]);
+			names[1] = reverse_lookup(lang, herbdata[1][h]);
 		}
 
 		rtype = new_resourcetype(names, appearance, RTF_ITEM|RTF_POOLED);
@@ -1852,6 +1859,10 @@ init_oldpotions(void)
 	potion_t p;
 	const char * names[2];
 	const char * appearance[2] = { "vial", "vials" };
+
+	const struct locale * lang = find_locale("de");
+	assert(lang);
+
 	for (p=0;p!=MAXPOTIONS;++p) {
 		item_type * itype;
 		resource_type * rtype;
@@ -1906,8 +1917,8 @@ init_oldpotions(void)
 			}
 		}
 		if (!names[0]) {
-			names[0] = reverse_lookup(NULL, potionnames[0][p]);
-			names[1] = reverse_lookup(NULL, potionnames[1][p]);
+			names[0] = reverse_lookup(lang, potionnames[0][p]);
+			names[1] = reverse_lookup(lang, potionnames[1][p]);
 		}
 
 		rtype = new_resourcetype(names, appearance, RTF_ITEM|RTF_POOLED);
diff --git a/src/common/kernel/karma.c b/src/common/kernel/karma.c
index 4ff8ef1e3..eee8f2c8e 100644
--- a/src/common/kernel/karma.c
+++ b/src/common/kernel/karma.c
@@ -326,7 +326,7 @@ sacrificings(void)
 
 	for(r=regions; r; r=r->next) {
 		for(u=r->units; u; u=u->next) {
-			if(igetkeyword(u->thisorder) == K_SACRIFICE) {
+			if(igetkeyword(u->thisorder, u->faction->locale) == K_SACRIFICE) {
 				int   n = 1, karma;
 				char *s = getstrtoken();
 
@@ -338,7 +338,7 @@ sacrificings(void)
 
 				s = getstrtoken();
 
-				switch(findparam(s)) {
+				switch(findparam(s, u->faction->locale)) {
 
 				case P_SILVER:
 					n = use_pooled(u, r, R_SILVER, n);
@@ -386,7 +386,7 @@ prayers(void)
 
 	for(r=regions; r; r=r->next) {
 		for(u=r->units; u; u=u->next) {
-			for(S = u->orders; S; S = S->next) if(igetkeyword(S->s) == K_PRAY) {
+			for(S = u->orders; S; S = S->next) if(igetkeyword(S->s, u->faction->locale) == K_PRAY) {
 				attrib *a, *a2;
 				unit *u2;
 				int karma_cost;
@@ -394,9 +394,9 @@ prayers(void)
 				param_t p;
 				char *s = getstrtoken();
 
-				if(findparam(s) == P_FOR) s = getstrtoken();
+				if(findparam(s, u->faction->locale) == P_FOR) s = getstrtoken();
 
-				p = findparam(s);
+				p = findparam(s, u->faction->locale);
 				switch(p) {
 				case P_AURA:
 					if(!is_mage) {
@@ -462,7 +462,7 @@ set_jihad(void)
 
 	for(r=regions; r; r=r->next) {
 		for(u=r->units; u; u=u->next) {
-			for(S = u->orders; S; S=S->next) if(igetkeyword(S->s) == K_SETJIHAD) {
+			for(S = u->orders; S; S=S->next) if(igetkeyword(S->s, u->faction->locale) == K_SETJIHAD) {
 				faction *f = u->faction;
 				int can = fspecial(f, FS_JIHAD);
 				int has = 0;
@@ -491,7 +491,7 @@ set_jihad(void)
 					cmistake(u, S->s, 282, MSG_EVENT);
 					continue;
 				}
-				
+
 				for(a = a_find(f->attribs, &at_jihad); a; a = a->nexttype) {
 					if(a->data.sa[0] == jrace) break;
 				}
@@ -532,7 +532,7 @@ jihad_attacks(void)
 	strlist *S;
 	attrib *a;
 	ally *sf, **sfp;
-	
+
 	for(f=factions; f; f=f->next) if(fspecial(f, FS_JIHAD)) {
 		for(r=f->first; r != f->last; r = r->next) if(rand()%1000 <= 1) {
 			boolean doit = false;
@@ -559,7 +559,7 @@ jihad_attacks(void)
 
 					if(sf) sf->status = sf->status & (HELP_ALL - HELP_FIGHT);
 
-					sprintf(buf, "%s %s", keywords[K_ATTACK], unitid(u));
+					sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_ATTACK]), unitid(u));
 					S = makestrlist(buf);
 					addlist(&u2->orders, S);
 				}
diff --git a/src/common/kernel/magic.c b/src/common/kernel/magic.c
index 617fe2563..cb6ac701c 100644
--- a/src/common/kernel/magic.c
+++ b/src/common/kernel/magic.c
@@ -557,7 +557,6 @@ getspell(const unit *u, spellid_t spellid)
 /* Spruch identifizieren */
 
 #include "umlaut.h"
-extern struct tnode spellnames;
 
 spell *
 find_spellbyname(unit *u, char *s)
@@ -565,7 +564,6 @@ find_spellbyname(unit *u, char *s)
 	sc_mage *m;
 	spell_ptr *spt;
 	spell *sp;
-	int i;
 
 	m = get_mage(u);
 	if (!m) {
@@ -578,9 +576,9 @@ find_spellbyname(unit *u, char *s)
 			return sp;
 		}
 	}
-
+#if 0 /* enno: geht vorerst nicht mit locales */
 	if (findtoken(&spellnames, s, (void**)&i)==0 && getspell(u, spelldaten[i].id)) return &spelldaten[i];
-
+#endif
 	return (spell *) NULL;
 }
 
@@ -1940,7 +1938,7 @@ add_spellparameter(region *target_r, unit *u, const char *syntax,
 					 * Einheitennummer kommt dahinter. In beiden F�llen wird der
 					 * Befehl um ein token weiter eingelesen und es mu� gepr�ft
 					 * werden, ob der Befehlsstring �berhaupt lang genug w�re. */
-					switch (findparam(token)) {
+					switch (findparam(token, u->faction->locale)) {
 						case P_TEMP:
 							i++;
 							if (par->length < i - skip) {
@@ -2086,7 +2084,7 @@ add_spellparameter(region *target_r, unit *u, const char *syntax,
 				{ /* keyword, dieses Element beschreibt was f�r ein Typ nachfolgt */
 					c++; /* das n�chste Zeichen ist immer ein c f�r einen
 									variablen Stringparameter */
-					switch (findparam(token)) {
+					switch (findparam(token, u->faction->locale)) {
 						case P_REGION:
 						{
 							spobj->typ = SPP_REGION;
@@ -2109,7 +2107,7 @@ add_spellparameter(region *target_r, unit *u, const char *syntax,
 								return 0;
 							}
 							token = strtok(NULL, " ");
-							if (findparam(token) == P_TEMP) {
+							if (findparam(token, u->faction->locale) == P_TEMP) {
 								i++;
 								if (par->length < i - skip) {
 									/* Fehler: Ziel vergessen */
@@ -2611,7 +2609,7 @@ is_moving_ship(const region * r, const ship *sh)
 	int todo;
 
 	u = shipowner(r, sh);
-	todo = igetkeyword(u->thisorder);
+	todo = igetkeyword(u->thisorder, u->faction->locale);
 	if (todo == K_ROUTE || todo == K_MOVE || todo == K_FOLLOW){
 		return true;
 	}
@@ -2657,7 +2655,7 @@ magic(void)
 			}
 
 			for (so = u->orders; so; so = so->next) {
-				if (igetkeyword(so->s) == K_CAST) {
+				if (igetkeyword(so->s, u->faction->locale) == K_CAST) {
 					if (fval(u, FL_HUNGER)) {
 						cmistake(u, so->s, 224, MSG_MAGIC);
 						continue;
@@ -2674,7 +2672,7 @@ magic(void)
 					skiptokens = 1;
 					s = getstrtoken();
 					/* f�r Syntax ' STUFE x REGION y z ' */
-					if (findparam(s) == P_LEVEL) {
+					if (findparam(s, u->faction->locale) == P_LEVEL) {
 						s = getstrtoken();
 						level = min(atoip(s), level);
 						s = getstrtoken();
@@ -2685,7 +2683,7 @@ magic(void)
 							continue;
 						}
 					}
-					if (findparam(s) == P_REGION) {
+					if (findparam(s, u->faction->locale) == P_REGION) {
 						t_x = atoi(getstrtoken());
 						t_x = rel_to_abs(getplane(u->region),u->faction,t_x,0);
 						t_y = atoi(getstrtoken());
@@ -2701,7 +2699,7 @@ magic(void)
 					}
 					/* f�r Syntax ' REGION x y STUFE z '
 					 * hier nach REGION nochmal auf STUFE pr�fen */
-					if (findparam(s) == P_LEVEL) {
+					if (findparam(s, u->faction->locale) == P_LEVEL) {
 						s = getstrtoken();
 						level = min(atoip(s), level);
 						s = getstrtoken();
diff --git a/src/common/kernel/message.c b/src/common/kernel/message.c
index 09d3515e4..cb1296fc4 100644
--- a/src/common/kernel/message.c
+++ b/src/common/kernel/message.c
@@ -245,11 +245,54 @@ read_messages(FILE * F, const locale * lang)
 	unused(lang);
 }
 
-message * 
-make_message(const char * name, const char* sig, ...)
-	/* make_message("oops_error", "unit region command", u, r, cmd) */
+static void
+arg_set(void * args[], const message_type * mtype, char * buffer, void * v)
 {
 	int i;
+	for (i=0;i!=mtype->nparameters;++i) {
+		if (!strcmp(buffer, mtype->pnames[i])) break;
+	}
+	if (i!=mtype->nparameters) args[i] = v;
+}
+
+struct message * 
+msg_error(const struct unit * u, const char * cmd, const char * name, const char* sig, ...)
+{
+	va_list marker;
+	const message_type * mtype = mt_find(name);
+	char buffer[64], *oc = buffer;
+	const char *ic = sig;
+	void * args[16];
+	memset(args, 0, sizeof(args));
+	if (cmd==NULL) cmd = u->thisorder;
+
+	if (!mtype) {
+		fprintf(stderr, "trying to create message of unknown type \"%s\"\n", name);
+		return NULL;
+	}
+
+	arg_set(args, mtype, "unit", (void*)u);
+	arg_set(args, mtype, "region", (void*)u->region);
+	arg_set(args, mtype, "command", (void*)cmd);
+
+	va_start(marker, sig);
+	while (*ic && !isalnum(*ic)) ic++;
+	while (*ic) {
+		void * v = va_arg(marker, void *);
+		while (isalnum(*ic)) *oc++ = *ic++;
+		*oc = '\0';
+		arg_set(args, mtype, buffer, v);
+		while (*ic && !isalnum(*ic)) ic++;
+	}
+	va_end(marker);
+
+	return msg_create(mtype, (void**)args);
+}
+
+message * 
+msg_message(const char * name, const char* sig, ...)
+	/* msg_message("oops_error", "unit region command", u, r, cmd) */
+{
 	va_list marker;
 	const message_type * mtype = mt_find(name);
 	char buffer[64], *oc = buffer;
@@ -268,10 +311,7 @@ make_message(const char * name, const char* sig, ...)
 		void * v = va_arg(marker, void *);
 		while (isalnum(*ic)) *oc++ = *ic++;
 		*oc = '\0';
-		for (i=0;i!=mtype->nparameters;++i) {
-			if (!strcmp(buffer, mtype->pnames[i])) break;
-		}
-		if (i!=mtype->nparameters) args[i] = v;
+		arg_set(args, mtype, buffer, v);
 		while (*ic && !isalnum(*ic)) ic++;
 	}
 	va_end(marker);
@@ -369,7 +409,7 @@ new_message(struct faction * receiver, const char* sig, ...)
 				args[i] = (void*)va_arg(marker, skill_t);
 				break;
 			case 'd':
-				args[i] = (void*)directions[i];
+				args[i] = (void*)i;
 				break;
 			case 'S':
 			default:
diff --git a/src/common/kernel/message.h b/src/common/kernel/message.h
index 74a602318..5585b4aa8 100644
--- a/src/common/kernel/message.h
+++ b/src/common/kernel/message.h
@@ -49,8 +49,9 @@ void write_msglevels(struct warning * warnings, FILE * F);
 void read_msglevels(struct warning ** w, FILE * F);
 void set_msglevel(struct warning ** warnings, const char * type, int level);
 
-extern struct message * make_message(const char * name, const char* sig, ...);
-extern struct message * new_message(struct faction * receiver, const char * signature, ...);
+extern struct message * msg_message(const char * name, const char* sig, ...);
+extern struct message * msg_error(const struct unit *, const char *, 
+											 const char * name, const char* sig, ...);
 extern struct message * add_message(struct message_list** pm, struct message * m);
 extern void free_messages(struct message_list * m);
 extern void read_messages(FILE * F, const struct locale * lang);
@@ -60,4 +61,7 @@ extern struct messageclass * msgclasses;
 extern const struct messageclass * mc_add(const char * name);
 extern const struct messageclass * mc_find(const char * name);
 
+/* convenience, deprecated */
+extern struct message * new_message(struct faction * receiver, const char * signature, ...);
+
 #endif
diff --git a/src/common/kernel/movement.c b/src/common/kernel/movement.c
index 965ec26d9..c23a02357 100644
--- a/src/common/kernel/movement.c
+++ b/src/common/kernel/movement.c
@@ -575,7 +575,7 @@ coords_or_direction(region *r, faction *f, int dir)
 	plane *pl = getplane(r);
 
 	if(fval(pl, PFL_NOCOORDS)) {
-		strcpy(lbuf, directions[dir]);
+		strcpy(lbuf, locale_string(f->locale, directions[dir]));
 	} else {
 		sprintf(lbuf, "(%d,%d)",region_x(r,f), region_y(r,f));
 	}
@@ -703,16 +703,14 @@ is_guarded(region * r, unit * u, unsigned int mask)
 	return NULL;
 }
 
-const char *shortdirections[MAXDIRECTIONS+2] =
+const char *shortdirections[MAXDIRECTIONS] =
 {
-	"NW",
-	"NO",
-	"Ost",
-	"SO",
-	"SW",
-	"West",
-	"",
-	"Pause"
+	"dir_NW",
+	"dir_NO",
+	"dir_Ost",
+	"dir_SO",
+	"dir_SW",
+	"dir_West"
 };
 
 void
@@ -726,10 +724,10 @@ cycle_route(unit *u, int gereist)
 	boolean paused = false;
 	boolean pause;
 
-	if (igetkeyword(u->thisorder) != K_ROUTE) return;
+	if (igetkeyword(u->thisorder, u->faction->locale) != K_ROUTE) return;
 	tail[0] = '\0';
 
-	strcpy(neworder, keywords[K_ROUTE]);
+	strcpy(neworder, locale_string(u->faction->locale, keywords[K_ROUTE]));
 
 	for (cm=0;;++cm) {
 		pause = false;
@@ -742,19 +740,19 @@ cycle_route(unit *u, int gereist)
 		}
 		if (cm<gereist) {
 			/* hier sollte keine PAUSE auftreten */
-			if (!pause) strcat(strcat(tail, " "), shortdirections[d]);
+			if (!pause) strcat(strcat(tail, " "), locale_string(u->faction->locale, shortdirections[d]));
 		}
 		else if (cm==gereist && !paused && pause){
-			strcat(strcat(tail, " "), parameters[P_PAUSE]);
+			strcat(strcat(tail, " "), locale_string(u->faction->locale, parameters[P_PAUSE]));
 			paused=true;
 		}
 		/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
 		 * hier keine normale direction), muss jede PAUSE einzeln
 		 * herausgefiltert und explizit gesetzt werden */
 		else if (pause) {
-			strcat(strcat(neworder, " "), parameters[P_PAUSE]);
+			strcat(strcat(neworder, " "), locale_string(u->faction->locale, parameters[P_PAUSE]));
 		} else
-			strcat(strcat(neworder, " "), shortdirections[d]);
+			strcat(strcat(neworder, " "), locale_string(u->faction->locale, shortdirections[d]));
 	}
 
 	strcat(neworder, tail);
@@ -775,14 +773,14 @@ init_drive(void)
 		 * doesn't seem to be an easy way to speed this up. */
 
 		for(u=r->units; u; u=u->next) {
-			if(igetkeyword(u->thisorder) == K_DRIVE && !fval(u, FL_LONGACTION)) {
+			if(igetkeyword(u->thisorder, u->faction->locale) == K_DRIVE && !fval(u, FL_LONGACTION)) {
 				boolean found = false;
 				ut = getunit(r, u);
 				if(!ut) {
 					cmistake(u, findorder(u, u->thisorder), 64, MSG_MOVE);
 					continue;
 				}
-				for (S = ut->orders; S; S = S->next) if (igetkeyword(S->s) == K_TRANSPORT) {
+				for (S = ut->orders; S; S = S->next) if (igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
 					if(getunit(r, ut) == u) {
 						found = true;
 						break;
@@ -805,11 +803,11 @@ init_drive(void)
 		for (u=r->units; u; u=u->next) {
 			w = 0;
 
-			for (S = u->orders; S; S = S->next) if(igetkeyword(S->s) == K_TRANSPORT) {
+			for (S = u->orders; S; S = S->next) if(igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
 				ut = getunit(r, u);
 				if(!ut) continue;
 
-				if (igetkeyword(ut->thisorder) == K_DRIVE && !fval(ut, FL_LONGACTION)) {
+				if (igetkeyword(ut->thisorder, u->faction->locale) == K_DRIVE && !fval(ut, FL_LONGACTION)) {
 					u2 = getunit(r, u);
 					if(u2 == u) {
 						w += weight(ut);
@@ -845,7 +843,7 @@ cantravel(const unit *u, const region *from, const region * to, boolean (*allowe
 		} else if (get_item(u, I_HORSE) > 0) {
 			return ETRAVEL_NORIDE|ETRAVEL_NOSWIM;
 		}
-	} 
+	}
 	if (!u->ship && leftship(u) && is_guarded(from, u, GUARD_LANDING)) {
 		/* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */
 		return ETRAVEL_LEFTSHIP;
@@ -896,8 +894,8 @@ travel(region * first, unit * u, region * next, int flucht)
 	 * Normalerweise verliert man 3 BP pro Region, bei Stra�en nur 2 BP.
 	 * Au�erdem: Wenn Einheit transportiert, nur halbe BP */
 
-	if (rterrain(current)==T_OCEAN 
-			&& !(race[u->race].flags&(RCF_FLY) && rterrain(next)!=T_OCEAN)) 
+	if (rterrain(current)==T_OCEAN
+			&& !(race[u->race].flags&(RCF_FLY) && rterrain(next)!=T_OCEAN))
 	{ /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */
 		if (u->race != RC_AQUARIAN)
 		{
@@ -963,7 +961,7 @@ travel(region * first, unit * u, region * next, int flucht)
 			/* faction special */
 			if(fspecial(u->faction, FS_QUICK))
 				mp = BP_RIDING;
-			
+
 			/* Siebenmeilentee */
 			if (get_effect(u, oldpotiontype[P_FAST]) >= u->number)
 				mp *= 2;
@@ -1149,11 +1147,11 @@ travel(region * first, unit * u, region * next, int flucht)
 		/* und jetzt noch die transportierten Einheiten verschieben */
 
 		for (S = u->orders; S; S = S->next) {
-			if (igetkeyword(S->s) == K_TRANSPORT) {
+			if (igetkeyword(S->s, u->faction->locale) == K_TRANSPORT) {
 				ut = getunit(first, u);
 				if (ut) {
 					boolean found = false;
-					if (igetkeyword(ut->thisorder) == K_DRIVE 
+					if (igetkeyword(ut->thisorder, u->faction->locale) == K_DRIVE
 							&& !fval(ut, FL_LONGACTION)) {
 						u2 = getunit(first, ut);
 						if(u2 == u) {
@@ -1316,7 +1314,7 @@ check_takeoff(ship *sh, region *from, region *to)
 	return true;
 }
 
-boolean 
+boolean
 ship_allowed(const struct ship_type * type, region * r)
 {
 	int c = 0;
@@ -1377,7 +1375,7 @@ sail(region * starting_point, unit * u, region * next_point, boolean move_on_lan
 				plane *pl = getplane(next_point);
 				if(pl && fval(pl, PFL_NOCOORDS)) {
 					sprintf(buf, "Die %s entdeckt, da� im %s Festland ist.",
-						shipname(u->ship), directions[dir]);
+						shipname(u->ship), locale_string(u->faction->locale, directions[dir]));
 				} else {
 					sprintf(buf, "Die %s entdeckt, da� (%d,%d) Festland ist.",
 						 	shipname(u->ship), region_x(next_point,u->faction),
@@ -1680,7 +1678,7 @@ move(region * r, unit * u, boolean move_on_land)
 			region * rc = rconnect(r2,d);
 			if (rc) {
 				sprintf(buf, "Im %s ist eine ungeheure magische Pr�senz zu versp�ren.",
-						directions[back[d]]);
+						locale_string(u->faction->locale, directions[back[d]]));
 				addmessage(rc, NULL, buf, MSG_EVENT, ML_IMPORTANT);
 			}
 		}
@@ -1697,11 +1695,11 @@ move(region * r, unit * u, boolean move_on_land)
 				if (a && a->data.v==u) {
 					/* wir basteln ihm ein NACH */
 					int k, i = 0;
-					strcpy(buf, keywords[K_MOVE]);
+					strcpy(buf, locale_string(u->faction->locale, keywords[K_MOVE]));
 					while (route[i]!=NODIRECTION)
-						strcat(strcat(buf, " "), directions[route[i++]]);
+						strcat(strcat(buf, " "), locale_string(u->faction->locale, directions[route[i++]]));
 					set_string(&uf->thisorder, buf);
-					k = igetkeyword(uf->thisorder);
+					k = igetkeyword(uf->thisorder, u->faction->locale);
 					assert(k==K_MOVE);
 					move(r, uf, true);
 				}
@@ -1820,11 +1818,12 @@ piracy(unit *u)
 		"piratesawvictim%h:ship%r:region%d:dir", sh, r, target_dir));
 
 	/* Befehl konstruieren */
-	sprintf(buf, "%s %s", keywords[K_MOVE], directions[target_dir]);
+	sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), 
+		locale_string(u->faction->locale, directions[target_dir]));
 	set_string(&u->thisorder, buf);
 
 	/* Bewegung ausf�hren */
-	igetkeyword(u->thisorder);	/* NACH ignorieren */
+	igetkeyword(u->thisorder, u->faction->locale);	/* NACH ignorieren */
 	move(r, u, true);
 }
 
@@ -1895,21 +1894,22 @@ hunt(unit *u)
 		return false;
 	}
 
-	sprintf(command, "%s %s", keywords[K_MOVE], directions[dir]);
+	sprintf(command, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), 
+		locale_string(u->faction->locale, directions[dir]));
 	moves = 1;
 
 	rc = rconnect(rc, dir);
 	while(moves < shipspeed(u->ship, u)
 			&& (dir = hunted_dir(rc->attribs, id)) != NODIRECTION) {
 		strcat(command, " ");
-		strcat(command, directions[dir]);
+		strcat(command, locale_string(u->faction->locale, directions[dir]));
 		moves++;
 		rc = rconnect(rc, dir);
 	}
 
 	/* In command steht jetzt das NACH-Kommando. */
 
-	igetkeyword(command);		/* NACH ignorieren und Parsing initialisieren. */
+	igetkeyword(command, u->faction->locale);		/* NACH ignorieren und Parsing initialisieren. */
 	move(u->region, u, false);							/* NACH ausf�hren */
 	return true;						/* true -> Einheitenliste von vorne durchgehen */
 }
@@ -2018,7 +2018,7 @@ movement(void)
 				up = &u;
 				if (u==NULL) break;
 			}
-			kword = igetkeyword(u->thisorder);
+			kword = igetkeyword(u->thisorder, u->faction->locale);
 			switch (kword) {
 			case K_ROUTE:
 			case K_MOVE:
@@ -2053,7 +2053,7 @@ movement(void)
 			param_t p;
 
 			for (o=u->orders;o;o=o->next) {
-				if(igetkeyword(o->s) == K_FOLLOW) {
+				if(igetkeyword(o->s, u->faction->locale) == K_FOLLOW) {
 					if(attacked(u)) {
 						cmistake(u, o->s, 52, MSG_MOVE);
 						u = u2; break;
@@ -2062,7 +2062,7 @@ movement(void)
 						u = u2; break;
 					}
 
-					p = getparam();
+					p = getparam(u->faction->locale);
 					if(p != P_SHIP) {
 						if(p != P_UNIT) {
 							cmistake(u, o->s, 240, MSG_MOVE);
@@ -2087,8 +2087,8 @@ movement(void)
 		for (u = r->units; u;) {
 			unit * u2 = u->next;
 			if (utarget(u)
-				&& (igetkeyword(u->thisorder) == K_MOVE
-				|| igetkeyword(u->thisorder) == K_ROUTE)) {
+				&& (igetkeyword(u->thisorder, u->faction->locale) == K_MOVE
+				|| igetkeyword(u->thisorder, u->faction->locale) == K_ROUTE)) {
 					if (attacked(u)) {
 						cmistake(u, findorder(u, u->thisorder), 52, MSG_PRODUCE);
 					} else if (race[u->race].flags & RCF_CANNOTMOVE) {
@@ -2110,7 +2110,7 @@ movement(void)
 		unit * u;
 		for(u = r->units; u;) {
 			unit *un = u->next;
-			if(igetkeyword(u->thisorder) == K_PIRACY) piracy(u);
+			if(igetkeyword(u->thisorder, u->faction->locale) == K_PIRACY) piracy(u);
 			u = un;
 		}
 		a_removeall(&r->attribs, &at_piracy_direction);
@@ -2130,8 +2130,8 @@ follow(void)
 			if (fval(u, FL_LONGACTION)) continue;
 			a = a_find(u->attribs, &at_follow);
 			for (o=u->orders;o;o=o->next) {
-				if (igetkeyword(o->s) == K_FOLLOW
-						&& getparam() == P_UNIT) {
+				if (igetkeyword(o->s, u->faction->locale) == K_FOLLOW
+						&& getparam(u->faction->locale) == P_UNIT) {
 					int id = read_unitid(u->faction, r);
 					if (id>0) {
 						unit * uf = findunit(id);
@@ -2151,7 +2151,7 @@ follow(void)
 				if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0))
 					continue;
 				for (o=u2->orders;o;o=o->next) {
-					switch (igetkeyword(o->s)) {
+					switch (igetkeyword(o->s, u2->faction->locale)) {
 					case K_MOVE:
 					case K_ROUTE:
 					case K_PIRACY:
diff --git a/src/common/kernel/pool.c b/src/common/kernel/pool.c
index cae3e7f38..81487b768 100644
--- a/src/common/kernel/pool.c
+++ b/src/common/kernel/pool.c
@@ -378,7 +378,7 @@ init_pool(void)
 			strlist *s;
 
 			list_foreach(strlist, u->orders, s) {
-				if (u->number > 0 && igetkeyword(s->s) == K_RESERVE
+				if (u->number > 0 && igetkeyword(s->s, u->faction->locale) == K_RESERVE
 						&& (urace(u)->ec_flags & GETITEM)) {
 					int count = geti();
 					int use;
diff --git a/src/common/kernel/race.c b/src/common/kernel/race.c
index ce42cd7c2..4e6bb92e8 100644
--- a/src/common/kernel/race.c
+++ b/src/common/kernel/race.c
@@ -400,7 +400,7 @@ struct racedata race[MAXRACES] =
 		true,
 		RCF_KILLPEASANTS|RCF_SCAREPEASANTS|RCF_ATTACKRANDOM|RCF_LEARN|RCF_FLY|RCF_WALK|RCF_NOTEACH,
 		BF_MAGIC_EQUIPMENT,
-		GETITEM | HOARDMONEY | CANGUARD,
+		GETITEM | CANGUARD,
 		{NORACE,NORACE,NORACE,NORACE,NORACE,NORACE},
 		&drachen_name, &age_firedragon, &allowed_dragon
 	},
@@ -421,7 +421,7 @@ struct racedata race[MAXRACES] =
 		true,
 		( RCF_KILLPEASANTS|RCF_SCAREPEASANTS|RCF_ATTACKRANDOM|RCF_LEARN|RCF_FLY|RCF_WALK|RCF_NOTEACH ),
 		( BF_MAGIC_EQUIPMENT ),
-		GETITEM | HOARDMONEY | CANGUARD,
+		GETITEM | CANGUARD,
 		{NORACE,NORACE,NORACE,NORACE,NORACE,NORACE},
 		&drachen_name, &age_dragon, &allowed_dragon
 	},
@@ -442,7 +442,7 @@ struct racedata race[MAXRACES] =
 		true,
 		( RCF_KILLPEASANTS|RCF_SCAREPEASANTS|RCF_ATTACKRANDOM|RCF_LEARN|RCF_FLY|RCF_WALK|RCF_NOTEACH ),
 		( BF_MAGIC_EQUIPMENT ),
-		GETITEM | HOARDMONEY | CANGUARD,
+		GETITEM | CANGUARD,
 		{NORACE,NORACE,NORACE,NORACE,NORACE,NORACE},
 		&drachen_name, NULL, &allowed_dragon
 	},
@@ -1060,7 +1060,7 @@ struct racedata race[MAXRACES] =
 		true,
 		RCF_KILLPEASANTS|RCF_SCAREPEASANTS|RCF_ATTACKRANDOM|RCF_LEARN|RCF_NOTEACH|RCF_SWIM|RCF_MOVERANDOM,
 		(0),
-		GETITEM | HOARDMONEY | CANGUARD,
+		GETITEM | CANGUARD,
 		{NORACE,NORACE,NORACE,NORACE,NORACE,NORACE},
 		&drachen_name, NULL, &allowed_swim
 	},
diff --git a/src/common/kernel/race.h b/src/common/kernel/race.h
index 05388e696..df4ea1a2f 100644
--- a/src/common/kernel/race.h
+++ b/src/common/kernel/race.h
@@ -105,11 +105,10 @@ typedef struct race_type {
 #define GIVEPERSON     (1<<2)   /* �bergibt Personen */
 #define GIVEUNIT       (1<<3)   /* Einheiten an andere Partei �bergeben */
 #define GETITEM        (1<<4)   /* nimmt Gegenst�nde an */
-#define HOARDMONEY     (1<<5)   /* geben niemals Silber weg */
-#define CANGUARD       (1<<6)   /* bewachen auch ohne Waffen */
-#define ECF_REC_HORSES     (1<<7)   /* Rekrutiert aus Pferden */
-#define ECF_REC_ETHEREAL   (1<<8)   /* Rekrutiert aus dem Nichts */
-#define ECF_REC_UNLIMITED  (1<<9)   /* Rekrutiert ohne Limit */
+#define CANGUARD       (1<<5)   /* bewachen auch ohne Waffen */
+#define ECF_REC_HORSES     (1<<6)   /* Rekrutiert aus Pferden */
+#define ECF_REC_ETHEREAL   (1<<7)   /* Rekrutiert aus dem Nichts */
+#define ECF_REC_UNLIMITED  (1<<8)   /* Rekrutiert ohne Limit */
 
 /* Battle-Flags */
 #define BF_EQUIPMENT				(1<<0)
diff --git a/src/common/kernel/region.c b/src/common/kernel/region.c
index da58bca96..03d10e767 100644
--- a/src/common/kernel/region.c
+++ b/src/common/kernel/region.c
@@ -42,7 +42,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-static int g_maxluxuries;
+static int g_maxluxuries = 0;
 
 const int delta_x[MAXDIRECTIONS] =
 {
@@ -730,6 +730,7 @@ setluxuries(region * r, const luxury_type * sale)
 void
 terraform(region * r, terrain_t t)
 {
+	const struct locale * locale_de = find_locale("de");
 	/* defaults: */
 
 	rsetterrain(r, t);
@@ -816,7 +817,7 @@ terraform(region * r, terrain_t t)
 		if (terrain[r->terrain].herbs) name = terrain[r->terrain].herbs[rand()%3];
 
 		if (name != NULL) {
-			const item_type * itype = finditemtype(name, NULL);
+			const item_type * itype = finditemtype(name, locale_de);
 			const herb_type * htype = resource2herb(itype->rtype);
 			rsetherbtype(r, htype);
 			rsetherbs(r, (short)(50+rand()%31));
diff --git a/src/common/kernel/reports.c b/src/common/kernel/reports.c
index f3da6a5e0..0311185b2 100644
--- a/src/common/kernel/reports.c
+++ b/src/common/kernel/reports.c
@@ -182,7 +182,6 @@ bufunit(const faction * f, const unit * u, int indent,
 	skill_t sk;
 	int getarnt = fval(u, FL_PARTEITARNUNG);
 	attrib *a_otherfaction = NULL;
-	const char *c;
 	const char *pzTmp;
 	spell *sp;
 	building * b;
@@ -239,14 +238,14 @@ bufunit(const faction * f, const unit * u, int indent,
 	pzTmp = get_racename(u->attribs);
 	if (pzTmp || u->irace != u->race) {
 		if (pzTmp) scat(pzTmp);
-		else scat(race[u->irace].name[u->number != 1]);
+		else scat(locale_string(f->locale, race[u->irace].name[u->number != 1]));
 		if (u->faction == f) {
 			scat(" (");
-			scat(race[u->race].name[u->number != 1]);
+			scat(locale_string(f->locale, race[u->race].name[u->number != 1]));
 			scat(")");
 		}
 	} else {
-		scat(race[u->race].name[u->number != 1]);
+		scat(locale_string(f->locale, race[u->race].name[u->number != 1]));
 	}
 
 	/* status */
@@ -286,7 +285,7 @@ bufunit(const faction * f, const unit * u, int indent,
 	dh = 0;
 	if (u->faction == f || telepath_see) {
 		for (sk = 0; sk != MAXSKILLS; sk++) {
-			spskill(u, sk, &dh, 1);
+			spskill(f->locale, u, sk, &dh, 1);
 		}
 	}
 
@@ -436,7 +435,7 @@ bufunit(const faction * f, const unit * u, int indent,
 }
 
 void
-spskill(const struct unit * u, skill_t sk, int *dh, int days)
+spskill(const struct locale * lang, const struct unit * u, skill_t sk, int *dh, int days)
 {
 	int i, d;
 	if (!u->number)
@@ -452,7 +451,7 @@ spskill(const struct unit * u, skill_t sk, int *dh, int days)
 		scat("Talente: ");
 		*dh = 1;
 	}
-	scat(skillnames[sk]);
+	scat(skillname(sk, lang));
 	scat(" ");
 
 	if (sk == SK_MAGIC){
@@ -543,7 +542,7 @@ spy_message(int spy, unit *u, unit *target)
 					} else {
 						scat(", ");
 					}
-					scat(skillnames[sk]);
+					scat(skillname(sk, u->faction->locale));
 				}
 			}
 			if (found == 0) {
@@ -578,7 +577,7 @@ spy_message(int spy, unit *u, unit *target)
 					} else {
 						scat(", ");
 					}
-					scat(skillnames[sk]);
+					scat(skillname(sk, u->faction->locale));
 					scat(" ");
 					icat(eff_skill(target, sk, target->region));
 				}
diff --git a/src/common/kernel/reports.h b/src/common/kernel/reports.h
index 37f2a3fa6..2a6b61855 100644
--- a/src/common/kernel/reports.h
+++ b/src/common/kernel/reports.h
@@ -39,7 +39,7 @@ extern int read_datenames(const char *filename);
 void sparagraph(struct strlist ** SP, const char *s, int indent, char mark);
 void lparagraph(struct strlist ** SP, char *s, int indent, char mark);
 const char *hp_status(const struct unit * u);
-extern void spskill(const struct unit * u, skill_t sk, int *dh, int days); /* mapper */
+extern void spskill(const struct locale * lang, const struct unit * u, skill_t sk, int *dh, int days); /* mapper */
 extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode);
 
 void reports(void);
diff --git a/src/common/kernel/save.c b/src/common/kernel/save.c
index c8e7d2924..cce423488 100644
--- a/src/common/kernel/save.c
+++ b/src/common/kernel/save.c
@@ -37,7 +37,6 @@
 #include "unit.h"
 #include "skill.h"
 #include "message.h"
-#include "monster.h"
 #include "objtypes.h"
 #include "border.h"
 #include "karma.h"
@@ -377,8 +376,8 @@ readunit(FILE * F, struct faction * f)
 			if (!getbuf(F))
 				break;
 
-			if (igetkeyword(buf) == NOKEYWORD) {
-				p = igetparam(buf);
+			if (igetkeyword(buf, u->faction->locale) == NOKEYWORD) {
+				p = igetparam(buf, u->faction->locale);
 				if (p == P_UNIT || p == P_FACTION || p == P_NEXT)
 					break;
 			}
@@ -473,9 +472,6 @@ version(void)
 }
 /* ------------------------------------------------------------- */
 
-/* TODO: soll hier weg */
-extern building_type bt_caldera;
-
 int
 readorders(const char *filename)
 {
@@ -495,12 +491,31 @@ readorders(const char *filename)
 	 * Partei */
 
 	while (b) {
+		const struct locale * lang = f?f->locale:NULL;
 		int p;
+		const char * s;
 
-		switch (igetparam(b)) {
+		switch (igetparam(b, lang)) {
+		case P_LOCALE:
+			s = getstrtoken();
+#define LOCALES
+#ifdef LOCALES
+			if (f && find_locale(s)) {
+				f->locale = find_locale(s);
+			}
+#else
+			if(strcmp(s, "de") == 0) {
+				f->locale = find_locale(s);
+			}
+#endif
+
+			b = getbuf(F);
+			break;
 		case P_FACTION:
 			f = readfaction();
-			if (f) ++nfactions;
+			if (f) {
+				++nfactions;
+			}
 
 			b = getbuf(F);
 
@@ -515,7 +530,7 @@ readorders(const char *filename)
 			if (!f || !readunit(F, f)) do {
 				b = getbuf(F);
 				if (!b) break;
-				p = igetparam(b);
+				p = igetparam(b, lang);
 			} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT);
 			break;
 
@@ -527,7 +542,7 @@ readorders(const char *filename)
 			 * einer Zeile steht, und nun die n�chste gelesen werden mu�. */
 
 		case P_NEXT:
-			f = 0;
+			f = NULL;
 		default:
 			b = getbuf(F);
 		}
@@ -583,12 +598,12 @@ typus2race(unsigned char typus)
 }
 
 boolean
-is_persistent(const char *s) 
+is_persistent(const char *s, const struct locale *lang) 
 {
 #ifdef AT_PERSISTENT                                                          
 	if(*s == '@') return true;                                                  
 #endif      /* Nur kurze Befehle! */
-	switch(igetkeyword(s)) {
+	switch(igetkeyword(s, lang)) {
 		case K_BUY:
 		case K_SELL:
 		case K_KOMMENTAR:
@@ -1862,7 +1877,7 @@ writegame(char *path, char quiet)
 			wi(F, getguard(u));
 #endif
 			for(S=u->orders; S; S=S->next) {
-				if (is_persistent(S->s)) {
+				if (is_persistent(S->s, u->faction->locale)) {
 					wspace(F);
 					ws(F, S->s);
 				}
@@ -2052,169 +2067,6 @@ struct fjord { int size; faction * f; } fjord[3];
 
 /* ------------------------------------------------------------- */
 
-extern attrib_type at_traveldir_new;
-void
-attrib_init(void)
-{
-	/* Geb�udetypen registrieren */
-	init_buildings();
-	bt_register(&bt_castle);
-	bt_register(&bt_lighthouse);
-	bt_register(&bt_mine);
-	bt_register(&bt_quarry);
-	bt_register(&bt_harbour);
-	bt_register(&bt_academy);
-	bt_register(&bt_magictower);
-	bt_register(&bt_smithy);
-	bt_register(&bt_sawmill);
-	bt_register(&bt_stables);
-	bt_register(&bt_monument);
-	bt_register(&bt_dam);
-	bt_register(&bt_caravan);
-	bt_register(&bt_tunnel);
-	bt_register(&bt_inn);
-	bt_register(&bt_stonecircle);
-	bt_register(&bt_blessedstonecircle);
-	bt_register(&bt_illusion);
-	bt_register(&bt_generic);
-	bt_register(&bt_caldera);
-
-	/* Schiffstypen registrieren: */
-	st_register(&st_boat);
-	st_register(&st_longboat);
-	st_register(&st_dragonship);
-	st_register(&st_caravelle);
-	st_register(&st_trireme);
-
-	/* disable: st_register(&st_transport); */
-
-	/* Alle speicherbaren Attribute m�ssen hier registriert werden */
-	at_register(&at_unitdissolve);
-	at_register(&at_traveldir_new);
-	at_register(&at_familiar);
-	at_register(&at_familiarmage);
-	at_register(&at_eventhandler);
-	at_register(&at_stealth);
-	at_register(&at_mage);
-	at_register(&at_bauernblut);
-	at_register(&at_countdown);
-	at_register(&at_showitem);
-	at_register(&at_curse);
-	at_register(&at_cursewall);
-
-	at_register(&at_seenspell);
-	at_register(&at_reportspell);
-	at_register(&at_deathcloud);
-
-	/* neue REGION-Attribute */
-	at_register(&at_direction);
-	at_register(&at_moveblock);
-#if AT_SALARY
-	at_register(&at_salary);
-#endif
-	at_register(&at_horseluck);
-	at_register(&at_peasantluck);
-	at_register(&at_deathcount);
-	at_register(&at_chaoscount);
-	at_register(&at_woodcount);
-	at_register(&at_laen);
-	at_register(&at_road);
-
-	/* neue UNIT-Attribute */
-	at_register(&at_alias);
-	at_register(&at_siege);
-	at_register(&at_target);
-	at_register(&at_potion);
-	at_register(&at_potionuser);
-	at_register(&at_contact);
-	at_register(&at_effect);
-	at_register(&at_private);
-
-#if defined(OLD_TRIGGER)
-	at_register(&at_pointer_tag);
-	at_register(&at_relation);
-	at_register(&at_relbackref);
-	at_register(&at_trigger);
-	at_register(&at_action);
-#endif
-	at_register(&at_icastle);
-	at_register(&at_guard);
-	at_register(&at_lighthouse);
-	at_register(&at_group);
-	at_register(&at_faction_special);
-	at_register(&at_prayer_timeout);
-	at_register(&at_prayer_effect);
-	at_register(&at_wyrm);
-	at_register(&at_building_generic_type);
-
-/* border-typen */
-	register_bordertype(&bt_noway);
-	register_bordertype(&bt_fogwall);
-	register_bordertype(&bt_wall);
-	register_bordertype(&bt_illusionwall);
-	register_bordertype(&bt_firewall);
-	register_bordertype(&bt_wisps);
-	register_bordertype(&bt_road);
-
-#if USE_EVENTS
-	at_register(&at_events);
-#endif
-	at_register(&at_jihad);
-}
-
-extern void inittokens(void);
-extern void create_teleport_plane(void);
-
-void read_strings(FILE * F);
-
-const char * messages[] = {
-	"%s/%s/messages.xml",
-	NULL
-};
-
-const char * strings[] = {
-	"%s/%s/strings.txt",
-	NULL
-};
-
-const char * locales[] = {
-	"de", "en",
-	NULL
-};
-
-void
-init_locales(void)
-{
-	FILE * F;
-	int l;
-	for (l=0;locales[l];++l) {
-		char zText[MAX_PATH];
-		int i;
-		for (i=0;strings[i];++i) {
-			sprintf(zText, strings[i], resourcepath(), locales[l]);
-			F = fopen(zText, "r+");
-			if (F) {
-				read_strings(F);
-				fclose(F);
-			} else {
-				sprintf(buf, "fopen(%s): ", zText);
-				perror(buf);
-			}
-		}
-		for (i=0;messages[i];++i) {
-			sprintf(zText, messages[i], resourcepath(), locales[l]);
-			F = fopen(zText, "r+");
-			if (F) {
-				read_messages(F, NULL);
-				fclose(F);
-			} else {
-				sprintf(buf, "fopen(%s): ", zText);
-				perror(buf);
-			}
-		}
-	}
-}
-
 int
 lastturn(void)
 {
diff --git a/src/common/kernel/save.h b/src/common/kernel/save.h
index cdda69b0f..5481c5bbd 100644
--- a/src/common/kernel/save.h
+++ b/src/common/kernel/save.h
@@ -38,7 +38,7 @@ void writegame(char *path, char quiet);
 
 extern void rsf(FILE * F, char *s, size_t len);
 
-extern boolean is_persistent(const char *s);
+extern boolean is_persistent(const char *s, const struct locale * lang);
 
 /* Versions�nderungen: */
 #define HEX_VERSION 81
diff --git a/src/common/kernel/skill.c b/src/common/kernel/skill.c
index d423e3662..fe5eb3b36 100644
--- a/src/common/kernel/skill.c
+++ b/src/common/kernel/skill.c
@@ -36,39 +36,45 @@
 #include <stdlib.h>
 
 /* Umlaute hier drin, weil die in den Report kommen */
-const char *skillnames[MAXSKILLS] =
+static const char *skillnames[MAXSKILLS] =
 {
-	"Alchemie",
-	"Armbrustschie�en",
-	"Bergbau",
-	"Bogenschie�en",
-	"Burgenbau",
-	"Handeln",
-	"Holzf�llen",
-	"Katapultbedienung",
-	"Kr�uterkunde",
-	"Magie",
-	"Pferdedressur",
-	"Reiten",
-	"R�stungsbau",
-	"Schiffbau",
-	"Hiebwaffen",
-	"Segeln",
-	"Stangenwaffen",
-	"Spionage",
-	"Steinbau",
-	"Stra�enbau",
-	"Taktik",
-	"Tarnung",
-	"Unterhaltung",
-	"Waffenbau",
-	"Wagenbau",
-	"Wahrnehmung",
-	"Steuereintreiben",
-	"Ausdauer",
-	"Waffenloser Kampf"
+	"sk_alchemy",
+	"sk_crossbow",
+	"sk_mining",
+	"sk_bow",
+	"sk_building",
+	"sk_trade",
+	"sk_forestry",
+	"sk_catapult",
+	"sk_herbalism",
+	"sk_magic",
+	"sk_training",
+	"sk_riding",
+	"sk_armorer",
+	"sk_shipcraft",
+	"sk_melee",
+	"sk_sailing",
+	"sk_polearm",
+	"sk_espionage",
+	"sk_quarrying",
+	"sk_roadwork",
+	"sk_tactics",
+	"sk_stealth",
+	"sk_entertainment",
+	"sk_weaponsmithing",
+	"sk_cartmaking",
+	"sk_perception",
+	"sk_taxation",
+	"sk_stamina",
+	"sk_unarmed"
 };
 
+const char * 
+skillname(skill_t sk, const struct locale * lang)
+{
+	return locale_string(lang, skillnames[sk]);
+}
+
 /** skillmod attribut **/
 static void
 init_skillmod(attrib * a) {
diff --git a/src/common/kernel/skill.h b/src/common/kernel/skill.h
index 6563741c0..2df7800be 100644
--- a/src/common/kernel/skill.h
+++ b/src/common/kernel/skill.h
@@ -47,6 +47,8 @@ extern void skill_init(void);
 extern void skill_done(void);
 extern struct attrib * make_skillmod(skill_t skill, unsigned int flags, int(*special)(const struct unit*, const struct region*, skill_t, int), double multiplier, int bonus);
 
+extern const char * skillname(skill_t, const struct locale *);
+
 int level_days(int level);
 void remove_zero_skills(void);
 
diff --git a/src/common/kernel/spell.c b/src/common/kernel/spell.c
index dc217beb5..b0986072b 100644
--- a/src/common/kernel/spell.c
+++ b/src/common/kernel/spell.c
@@ -1,6 +1,6 @@
 /* vi: set ts=2:
  *
- *	
+ *
  *	Eressea PB(E)M host Copyright (C) 1998-2000
  *      Christian Schlittchen (corwin@amber.kn-bremen.de)
  *      Katja Zedel (katze@felidae.kn-bremen.de)
@@ -87,11 +87,12 @@ attrib_type at_unitdissolve = {
 
 /* ----------------------------------------------------------------------- */
 
-const char *
-spellcmd(const strarray * sa) {
+#ifdef TODO
+static const char *
+spellcmd(const strarray * sa, const struct locale * lang) {
 	int i;
 	char * p = buf;
-	strcpy(p, keywords[K_CAST]);
+	strcpy(p, locale_string(lang, keywords[K_CAST]));
 	p += strlen(p);
 	for (i=0;i!=sa->length;++i) {
 		*p++ = ' ';
@@ -101,11 +102,10 @@ spellcmd(const strarray * sa) {
 	return buf;
 }
 
-#ifdef TODO
 void
 report_failure(unit * mage, const strarray * sa) {
 	/* Fehler: "Der Zauber schl�gt fehl" */
-	cmistake(mage, strdup(spellcmd(sa)), 180, MSG_MAGIC);
+	cmistake(mage, strdup(spellcmd(sa, mage->faction->locale)), 180, MSG_MAGIC);
 }
 #else
 void
@@ -723,7 +723,7 @@ sp_summon_familiar(castorder *co)
 					scat(", ");
 				}
 			}
-			scat(skillnames[sk]);
+			scat(skillname(sk, mage->faction->locale));
 		}
 	}
 	scat(" lernen.");
@@ -2031,7 +2031,7 @@ sp_homestone(castorder *co)
 	unit *mage = (unit *)co->magician;
 	int cast_level = co->level;
 	int force = co->force;
-	
+
 	if(!mage->building || mage->building->type != &bt_castle){
 		cmistake(mage, strdup(co->order), 197, MSG_MAGIC);
 		return 0;
@@ -2435,7 +2435,7 @@ patzer_peasantmob(castorder *co)
 	attrib *a;
 	region *r;
 	unit *mage = (unit *)co->magician;
-	
+
 	if (mage->region->land){
 		r = mage->region;
 	} else {
@@ -3541,7 +3541,7 @@ sp_bloodsacrifice(castorder *co)
 		report_failure(mage, co->order);
 		return 0;
 	}
-	
+
 	damage = min(hp, dice_rand("4d12"));
 
 	if (eff_skill(mage, SK_MAGIC, mage->region) > 8){
@@ -3549,7 +3549,7 @@ sp_bloodsacrifice(castorder *co)
 	} else {
 		aura = damage / 4;
 	}
-	
+
 	if (aura <= 0){
 		report_failure(mage, co->order);
 		return 0;
@@ -4381,7 +4381,7 @@ sp_recruit(castorder *co)
 		u->ship = mage->ship;
 	}
 	set_string(&u->name, n == 1 ? "Bauer" : "Bauern");
-	set_string(&u->thisorder, keywords[K_WORK]);
+	set_string(&u->thisorder, locale_string(u->faction->locale, keywords[K_WORK]));
 	u->status = mage->status;
 
 	/* Parteitarnung */
@@ -4786,7 +4786,7 @@ sp_puttorest(castorder *co)
 	laid_to_rest = max(laid_to_rest, deathcount(r));
 
 	deathcounts(r, -laid_to_rest);
-	
+
 	/* melden, 1x pro partei */
 	for (u = r->units; u; u = u->next) freset(u->faction, FL_DH);
 
@@ -6271,7 +6271,7 @@ sp_movecastle(castorder *co)
 		sprintf(buf, "%s in %s: 'ZAUBER \"%s\"': Der Erdelementar "
 				"weigert sich, nach %s zu gehen.",
 			unitname(mage), regionid(mage->region), sp->name,
-			directions[dir]);
+			locale_string(mage->faction->locale, directions[dir]));
 		addmessage(0, mage->faction, buf, MSG_MAGIC, ML_MISTAKE);
 		return cast_level;
 	}
@@ -6294,7 +6294,7 @@ sp_movecastle(castorder *co)
 
 	sprintf(buf, "Ein Beben ersch�ttert %s. Viele kleine Pseudopodien "
 		"erheben das Geb�ude und tragen es in Richtung %s.",
-		buildingname(b), directions[dir]);
+		buildingname(b), locale_string(mage->faction->locale, directions[dir]));
 
 	if((b->type==&bt_caravan || b->type==&bt_dam || b->type==&bt_tunnel)) {
 		boolean damage = false;
@@ -6743,7 +6743,7 @@ sp_becomewyrm(castorder *co)
  * Wirkung:		 der Magier verdient $50 pro Spruchstufe
  * Kosten:		 1 SP pro Stufe
  */
-#include "../gamecode/economy.h" 
+#include "../gamecode/economy.h"
 /* TODO: das ist scheisse, aber spells geh�ren eh nicht in den kernel */
 int
 sp_earn_silver(castorder *co)
@@ -7513,7 +7513,7 @@ spell spelldaten[] =
 		 {0, 0, 0}},
 		(spell_f)sp_treewalkexit, patzer
 	},
-	
+
 	{SPL_HOLYGROUND, "Heiliger Boden",
 		"Dieses Ritual beschw�rt verschiedene Naturgeister in den Boden der "
 		"Region, welche diese fortan bewachen. In einer so gesegneten Region "
@@ -7820,7 +7820,7 @@ spell spelldaten[] =
 		"sein kann.",
 		NULL,
 		NULL,
-		M_CHAOS, (SPELLLEVEL | FARCASTING | ONSHIPCAST), 
+		M_CHAOS, (SPELLLEVEL | FARCASTING | ONSHIPCAST),
 		5, 6,
 		{
 			{R_AURA, 5, SPC_LEVEL},
@@ -8075,7 +8075,7 @@ spell spelldaten[] =
 			{0, 0, 0}},
 		(spell_f)sp_destroy_magic, patzer
 	},
-	
+
 	{SPL_UNHOLYPOWER, "Unheilige Kraft",
 		"Nur gefl�stert wird dieses Ritual an den dunklen Akademien an die "
 		"Adepten weitergegeben, geh�rt es doch zu den finstersten, die je "
@@ -8601,7 +8601,7 @@ spell spelldaten[] =
 		"es einige Wochen sp�ter...",
 		NULL,
 		"u+",
-		M_TRAUM, 
+		M_TRAUM,
 		(UNITSPELL | TESTRESISTANCE | TESTCANSEE | SPELLLEVEL), 5, 12,
 		{
 			{R_AURA, 5, SPC_LEVEL},
diff --git a/src/common/kernel/terrain.c b/src/common/kernel/terrain.c
index 48faecf41..48ade210c 100644
--- a/src/common/kernel/terrain.c
+++ b/src/common/kernel/terrain.c
@@ -59,8 +59,7 @@ trailinto(const region * r, const locale * lang)
 		}
 		else s = locale_string(lang, terrain[t].trailname(r));
 		if (s && *s) {
-			assert(strstr(s, "%s"));
-			return s;
+			if (strstr(s, "%s"))	return s;
 		}
 	}
 	return "%s";
diff --git a/src/common/modules/gmcmd.c b/src/common/modules/gmcmd.c
index f626466f6..77ca42d87 100644
--- a/src/common/modules/gmcmd.c
+++ b/src/common/modules/gmcmd.c
@@ -196,7 +196,7 @@ gm_give(const char * str, struct unit * u)
 
 	if (to==NULL || rplane(to->region) != rplane(u->region)) {
 		/* unknown or in another plane */
-		mistake(u, str, "Die Einheit wurde nicht gefunden.\n", 0);
+		cmistake(u, str, 64, MSG_COMMERCE);
 	} else if (itype==NULL || i_get(u->items, itype)==0) {
 		/* unknown or not enough */
 		mistake(u, str, "So einen Gegenstand hat die Einheit nicht.\n", 0);
@@ -230,7 +230,7 @@ gm_take(const char * str, struct unit * u)
 
 	if (to==NULL || rplane(to->region) != rplane(u->region)) {
 		/* unknown or in another plane */
-		mistake(u, str, "Die Einheit wurde nicht gefunden.\n", 0);
+		cmistake(u, str, 64, MSG_COMMERCE);
 	} else if (itype==NULL || i_get(to->items, itype)==0) {
 		/* unknown or not enough */
 		mistake(u, str, "So einen Gegenstand hat die Einheit nicht.\n", 0);
@@ -259,15 +259,15 @@ static void
 gm_skill(const char * str, struct unit * u)
 {
 	unit * to = findunit(atoi36(igetstrtoken(str)));
-	skill_t skill = findskill(getstrtoken());
+	skill_t skill = findskill(getstrtoken(), u->faction->locale);
 	int num = atoi(getstrtoken());
 	
 	if (to==NULL || rplane(to->region) != rplane(u->region)) {
 		/* unknown or in another plane */
-		mistake(u, str, "Die Einheit wurde nicht gefunden.\n", 0);
+		cmistake(u, str, 64, MSG_COMMERCE);
 	} else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) {
 		/* unknown or not enough */
-		mistake(u, str, "Dieses Talent ist unbekannt, oder kann nciht erh�ht werden.\n", 0);
+		mistake(u, str, "Dieses Talent ist unbekannt, oder kann nicht erh�ht werden.\n", 0);
 	} else if (num<0 || num>5000) {
 		/* sanity check failed */
 		mistake(u, str, "Der gew�hlte Wert ist nicht zugelassen.\n", 0);
@@ -297,7 +297,7 @@ gm_command(const char * cmd, struct unit * u)
 	i = min(16, c-cmd);
 	strncpy(zText, cmd, i);
 	zText[i]=0;
-	if (findtoken(&g_keys, zText, (void**)&cm) && cm->perform) cm->perform(++c, u);
+	if (findtoken(&g_keys, zText, (void**)&cm)==E_TOK_SUCCESS && cm->perform) cm->perform(++c, u);
 }
 
 void
@@ -329,7 +329,7 @@ gmcommands(void)
 			unit * u = *up;
 			strlist * order;
 			for (order = u->orders; order; order = order->next)
-				if (igetkeyword(order->s) == K_GM) {
+				if (igetkeyword(order->s, u->faction->locale) == K_GM) {
 					gm_command(order->s, u);
 				}			
 			if (u==*up) up = &u->next;
diff --git a/src/common/spells/spells.c b/src/common/spells/spells.c
index b6e95118b..32713e68f 100644
--- a/src/common/spells/spells.c
+++ b/src/common/spells/spells.c
@@ -24,12 +24,18 @@
 struct curse_type;
 extern const struct curse_type ct_firewall;
 extern void ct_register(const struct curse_type * ct);
+extern curse_type cursedaten[MAXCURSE];
 
 void
 init_spells(void)
 {
+	int i;
 	/* sp_summon_alp */
 	init_alp();
 	/* init_firewall(); */
 	ct_register(&ct_firewall);
+
+	for (i=0;i!=MAXCURSE;++i) {
+		ct_register(&cursedaten[i]);
+	}
 }
diff --git a/src/common/util/crmessage.c b/src/common/util/crmessage.c
index 93575dd43..ec13c5d42 100644
--- a/src/common/util/crmessage.c
+++ b/src/common/util/crmessage.c
@@ -6,9 +6,9 @@
  |                   |  Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
  +-------------------+  Stefan Reich <reich@halbling.de>
 
- This program may not be used, modified or distributed 
+ This program may not be used, modified or distributed
  without prior permission by the authors of Eressea.
- 
+
 */
 
 #include <config.h>
@@ -68,7 +68,7 @@ typedef struct crmessage_type {
 
 static crmessage_type * messagetypes;
 
-static crmessage_type * 
+static crmessage_type *
 crt_find(const struct message_type * mtype)
 {
 	crmessage_type * found = NULL;
@@ -112,9 +112,9 @@ cr_render(const message * msg, char * buffer, const void * userdata)
 	if (crt==NULL) return -1;
 	for (i=0;i!=msg->type->nparameters;++i) {
 		if (crt->renderers[i]==NULL) {
-			log_error(("No renderer for argument %s:%s of \"%s\"\n", 
+			log_error(("No renderer for argument %s:%s of \"%s\"\n",
 				msg->type->pnames[i], msg->type->types[i], msg->type->name));
-			continue; /* strcpy(c, (const char*)msg->parameters[i]); */
+			continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */
 		} else {
 			if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue;
 		}
diff --git a/src/common/util/language.c b/src/common/util/language.c
index 2006e1c8f..948bbc504 100644
--- a/src/common/util/language.c
+++ b/src/common/util/language.c
@@ -44,7 +44,7 @@ static locale * default_locale;
 unsigned int
 locale_hashkey(const locale * lang)
 {
-	if (lang==NULL) lang = default_locale;
+	assert(lang);
 	return lang->hashkey;
 }
 
@@ -75,6 +75,31 @@ make_locale(const char * name)
 	return l;
 }
 
+static FILE * s_debug = NULL;
+
+void 
+debug_language(const char * log)
+{
+	s_debug = fopen(log, "w+");
+}
+
+const char *
+locale_getstring(const locale * lang, const char * key)
+{
+	unsigned int hkey = hashstring(key);
+	unsigned int id = hkey % SMAXHASH;
+	struct locale_string * find;
+
+	assert(lang);
+	if (key==NULL || *key==0) return NULL;
+	find = lang->strings[id];
+	while (find) {
+		if (find->hashkey == hkey && !strcmp(key, find->key)) return find->str;
+		find = find->nexthash;
+	}
+	return NULL;
+}
+
 const char *
 locale_string(const locale * lang, const char * key)
 {
@@ -82,22 +107,28 @@ locale_string(const locale * lang, const char * key)
 	unsigned int id = hkey % SMAXHASH;
 	struct locale_string * find;
 
-	if (key==NULL || *key==0) return NULL;
-	if (lang==NULL) lang = default_locale;
+	if (key == NULL || *key==0) return NULL;
+	if (lang == NULL) return key;
 	find = lang->strings[id];
 	while (find) {
 		if (find->hashkey == hkey && !strcmp(key, find->key)) break;
 		find = find->nexthash;
 	}
 	if (!find) {
-		if (lang==default_locale) {
-			log_warning(("missing translation for \"%s\"\n", key));
-			return key;
+		const char * s = key;
+		if (lang!=default_locale) {
+			log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name));
+			s = locale_string(default_locale, key);
+			if (s_debug) {
+				fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s);
+				locale_setstring((struct locale*)lang, key, s);
+			}
 		}
-		log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name));
-		return locale_string(default_locale, key);
+		return s;
+	}
+	else {
+		return find->str;
 	}
-	return find->str;
 }
 
 void
@@ -108,7 +139,7 @@ locale_setstring(locale * lang, const char * key, const char * value)
 	unsigned int id = hkey % SMAXHASH;
 	struct locale_string * find;
 
-	if (lang==NULL) lang = default_locale;
+	assert(lang);
 	find = lang->strings[id];
 	while (find) {
 		if (find->hashkey==hkey && !strcmp(key, find->key)) break;
@@ -128,7 +159,7 @@ locale_setstring(locale * lang, const char * key, const char * value)
 const char *
 locale_name(const locale * lang)
 {
-	if (lang==NULL) lang = default_locale;
+	assert(lang);
 	return lang->name;
 }
 
@@ -136,7 +167,7 @@ const char *
 reverse_lookup(const locale * lang, const char * str)
 {
 	int i;
-	if (lang==NULL) lang = default_locale;
+	assert(lang);
 	if (lang!=NULL) {
 		for (i=0;i!=SMAXHASH;++i) {
 			struct locale_string * ls;
diff --git a/src/common/util/language.h b/src/common/util/language.h
index 98807293f..bc53bff07 100644
--- a/src/common/util/language.h
+++ b/src/common/util/language.h
@@ -21,10 +21,13 @@ extern locale * find_locale(const char * name);
 extern locale * make_locale(const char * key);
 
 /** operations on locales: **/
-extern const char * locale_string(const locale * lang, const char * key);
-extern void locale_setstring(locale * lang, const char * key, const char * value);
-extern unsigned int locale_hashkey(const locale * lang);
-extern const char * locale_name(const locale * lang);
+extern void locale_setstring(struct locale * lang, const char * key, const char * value);
+extern const char * locale_getstring(const struct locale * lang, const char * key);
+extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */
+extern unsigned int locale_hashkey(const struct locale * lang);
+extern const char * locale_name(const struct locale * lang);
 
-extern const char * reverse_lookup(const locale * lang, const char * str);
+extern const char * reverse_lookup(const struct locale * lang, const char * str);
+
+extern void debug_language(const char * log);
 #endif
diff --git a/src/common/util/message.c b/src/common/util/message.c
index bc59ef9d0..c70bf4958 100644
--- a/src/common/util/message.c
+++ b/src/common/util/message.c
@@ -6,9 +6,9 @@
  |                   |  Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
  +-------------------+  Stefan Reich <reich@halbling.de>
 
- This program may not be used, modified or distributed 
+ This program may not be used, modified or distributed
  without prior permission by the authors of Eressea.
- 
+
 */
 
 #include <config.h>
@@ -20,13 +20,13 @@
 #include <string.h>
 #include <stdarg.h>
 
-const char * 
+const char *
 mt_name(const message_type* mtype)
 {
 	return mtype->name;
 }
 
-message_type * 
+message_type *
 mt_new(const char * name, const char * args[])
 {
 	int i, nparameters;
@@ -55,7 +55,7 @@ mt_new(const char * name, const char * args[])
 	return mtype;
 }
 
-message_type * 
+message_type *
 mt_new_va(const char * name, ...)
 {
 	const char * args[16];
@@ -107,7 +107,7 @@ typedef struct messagetype_list {
 
 static messagetype_list * messagetypes;
 
-const message_type * 
+const message_type *
 mt_register(const message_type * type)
 {
 	messagetype_list * mtl = messagetypes;
@@ -121,7 +121,7 @@ mt_register(const message_type * type)
 	return type;
 }
 
-const message_type * 
+const message_type *
 mt_find(const char * name)
 {
 	messagetype_list * mtl = messagetypes;
diff --git a/src/common/util/umlaut.c b/src/common/util/umlaut.c
index aa271fa73..f825ca2a4 100644
--- a/src/common/util/umlaut.c
+++ b/src/common/util/umlaut.c
@@ -61,7 +61,7 @@ addtoken(tnode * root, const char* str, void * id)
 		int index, i = 0;
 		char c = *str;
 		if (c<'a' || c>'z') c = (char)tolower((unsigned char)c);
-		index = ((unsigned char)c) % 32;
+		index = ((unsigned char)c) % NODEHASHSIZE;
 		next = root->next[index];
 		if (!(root->flags & LEAF)) root->id = id;
 		while (next && next->c != c) next = next->nexthash;
@@ -77,7 +77,7 @@ addtoken(tnode * root, const char* str, void * id)
 			root->next[index] = ref;
 			
 			if (u!=c) {
-				index = ((unsigned char)u) % 32;
+				index = ((unsigned char)u) % NODEHASHSIZE;
 				ref = malloc(sizeof(tref));
 				ref->c = u;
 				ref->node = node;
@@ -113,7 +113,7 @@ findtoken(tnode * tk, const char * str, void **result)
 
 /*		if (c<'a' || c>'z') c = (char)tolower((unsigned char)c); */
 
-		index = ((unsigned char)c) % 32;
+		index = ((unsigned char)c) % NODEHASHSIZE;
 		ref = tk->next[index];
 		while (ref && ref->c!=c) ref = ref->nexthash;
 		++str;
diff --git a/src/common/util/umlaut.h b/src/common/util/umlaut.h
index 53d54221b..9ded54d03 100644
--- a/src/common/util/umlaut.h
+++ b/src/common/util/umlaut.h
@@ -17,11 +17,11 @@
 
 #define E_TOK_NOMATCH (-1)
 #define E_TOK_SUCCESS 0
-
+#define NODEHASHSIZE 7
 struct tref;
 
 typedef struct tnode {
-	struct tref * next[32];
+	struct tref * next[NODEHASHSIZE];
 	unsigned char flags;
 	void * id;
 } tnode;
diff --git a/src/common/util/util-6.dsp b/src/common/util/util-6.dsp
index 550adf865..8b1d39995 100644
--- a/src/common/util/util-6.dsp
+++ b/src/common/util/util-6.dsp
@@ -7,21 +7,21 @@
 CFG=util - Win32 Conversion
 !MESSAGE This is not a valid makefile. To build this project using NMAKE,
 !MESSAGE use the Export Makefile command and run
-!MESSAGE
+!MESSAGE 
 !MESSAGE NMAKE /f "util-6.mak".
-!MESSAGE
+!MESSAGE 
 !MESSAGE You can specify a configuration when running NMAKE
 !MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
+!MESSAGE 
 !MESSAGE NMAKE /f "util-6.mak" CFG="util - Win32 Conversion"
-!MESSAGE
+!MESSAGE 
 !MESSAGE Possible choices for configuration are:
-!MESSAGE
+!MESSAGE 
 !MESSAGE "util - Win32 Release" (based on "Win32 (x86) Static Library")
 !MESSAGE "util - Win32 Debug" (based on "Win32 (x86) Static Library")
 !MESSAGE "util - Win32 Conversion" (based on "Win32 (x86) Static Library")
 !MESSAGE "util - Win32 Profile" (based on "Win32 (x86) Static Library")
-!MESSAGE
+!MESSAGE 
 
 # Begin Project
 # PROP AllowPerConfigDependencies 0
@@ -122,7 +122,7 @@ LIB32=link.exe -lib
 # ADD BASE LIB32 /nologo
 # ADD LIB32 /nologo
 
-!ENDIF
+!ENDIF 
 
 # Begin Target
 
@@ -209,6 +209,10 @@ SOURCE=.\vset.h
 
 SOURCE=.\windir.h
 # End Source File
+# Begin Source File
+
+SOURCE=.\xml.h
+# End Source File
 # End Group
 # Begin Source File
 
@@ -290,5 +294,9 @@ SOURCE=.\vset.c
 
 SOURCE=.\windir.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\xml.c
+# End Source File
 # End Target
 # End Project
diff --git a/src/eressea/attributes.c b/src/eressea/attributes.c
index 8144c58f1..5458d0065 100644
--- a/src/eressea/attributes.c
+++ b/src/eressea/attributes.c
@@ -26,6 +26,7 @@
 #include <attributes/hate.h>
 #include <attributes/overrideroads.h>
 #include <attributes/racename.h>
+#include <attributes/otherfaction.h>
 #ifdef AT_OPTION
 # include <attributes/option.h>
 #endif
@@ -49,6 +50,7 @@ init_attributes(void)
 	init_hate();
 	init_reduceproduction();
 	init_racename();
+	init_otherfaction();
 #ifdef AT_MOVED
 	init_moved();
 #endif
diff --git a/src/eressea/eressea-6.dsp b/src/eressea/eressea-6.dsp
index 294b524ce..66221d4db 100644
--- a/src/eressea/eressea-6.dsp
+++ b/src/eressea/eressea-6.dsp
@@ -748,7 +748,7 @@ SOURCE=..\common\attributes\follow.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -772,7 +772,7 @@ SOURCE=..\common\attributes\follow.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -796,7 +796,7 @@ SOURCE=..\common\attributes\giveitem.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -820,7 +820,7 @@ SOURCE=..\common\attributes\giveitem.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -837,6 +837,19 @@ SOURCE=..\common\attributes\giveitem.h
 # Begin Source File
 
 SOURCE=..\common\attributes\gm.c
+
+!IF  "$(CFG)" == "eressea - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
+
+# PROP Intermediate_Dir "../common/attributes/Debug"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Profile"
+
+!ENDIF 
+
 # End Source File
 # Begin Source File
 
@@ -848,7 +861,7 @@ SOURCE=..\common\attributes\hate.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -872,7 +885,7 @@ SOURCE=..\common\attributes\hate.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -896,7 +909,7 @@ SOURCE=..\common\attributes\iceberg.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -920,7 +933,7 @@ SOURCE=..\common\attributes\iceberg.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -944,7 +957,7 @@ SOURCE=..\common\attributes\key.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -968,7 +981,7 @@ SOURCE=..\common\attributes\key.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -992,7 +1005,7 @@ SOURCE=..\common\attributes\matmod.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1016,7 +1029,7 @@ SOURCE=..\common\attributes\matmod.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1032,6 +1045,40 @@ SOURCE=..\common\attributes\matmod.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\common\attributes\moved.c
+
+!IF  "$(CFG)" == "eressea - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
+
+# PROP Intermediate_Dir "../common/attributes/Debug"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Profile"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\attributes\option.c
+
+!IF  "$(CFG)" == "eressea - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
+
+# PROP Intermediate_Dir "../common/attributes/Debug"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Profile"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
 SOURCE=..\common\attributes\orcification.c
 
 !IF  "$(CFG)" == "eressea - Win32 Release"
@@ -1040,7 +1087,7 @@ SOURCE=..\common\attributes\orcification.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1056,6 +1103,23 @@ SOURCE=..\common\attributes\orcification.c
 # End Source File
 # Begin Source File
 
+SOURCE=..\common\attributes\otherfaction.c
+
+!IF  "$(CFG)" == "eressea - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
+
+# PROP Intermediate_Dir "../common/attributes/Debug"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Profile"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
 SOURCE=..\common\attributes\overrideroads.c
 
 !IF  "$(CFG)" == "eressea - Win32 Release"
@@ -1064,7 +1128,7 @@ SOURCE=..\common\attributes\overrideroads.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1087,7 +1151,7 @@ SOURCE=..\common\attributes\overrideroads.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1102,6 +1166,23 @@ SOURCE=..\common\attributes\overrideroads.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\common\attributes\racename.c
+
+!IF  "$(CFG)" == "eressea - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
+
+# PROP Intermediate_Dir "../common/attributes/Debug"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
+
+!ELSEIF  "$(CFG)" == "eressea - Win32 Profile"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
 SOURCE=..\common\attributes\reduceproduction.c
 
 !IF  "$(CFG)" == "eressea - Win32 Release"
@@ -1110,7 +1191,7 @@ SOURCE=..\common\attributes\reduceproduction.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1134,7 +1215,7 @@ SOURCE=..\common\attributes\reduceproduction.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1158,7 +1239,7 @@ SOURCE=..\common\attributes\targetregion.c
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
@@ -1182,7 +1263,7 @@ SOURCE=..\common\attributes\targetregion.h
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Debug"
 
-# PROP Intermediate_Dir "..\common\attributes\Debug"
+# PROP Intermediate_Dir "../common/attributes/Debug"
 
 !ELSEIF  "$(CFG)" == "eressea - Win32 Conversion"
 
diff --git a/src/eressea/korrektur.c b/src/eressea/korrektur.c
index 16da11bf3..0b20a9a89 100644
--- a/src/eressea/korrektur.c
+++ b/src/eressea/korrektur.c
@@ -662,7 +662,7 @@ fix_migrants(void) {
 		unit * u;
 		for (u=r->units;u;u=u->next) {
 			if (u->race==RC_HUMAN) u->irace=RC_HUMAN;
-			if (u->irace!=u->race && u->race!=RC_ILLUSION && u->race!=RC_DAEMON) {
+			if (u->irace!=u->race && (race[u->race].flags & RCF_SHAPESHIFT)==0) {
 				log_warning(("[fix_migrants] %s ist ein %s, als %s getarnt\n", unitname(u), race[u->race].name[0], race[u->irace].name[0]));
 			}
 		}
@@ -2142,17 +2142,33 @@ test_gmquest(void)
 
 }
 
+#define TEST_LOCALES 0
+#if TEST_LOCALES
+static void
+setup_locales(void) 
+{
+	locale * lang = find_locale("en");
+	faction * f = factions;
+	while (f) {
+		f->locale = lang;
+		f = f->next;
+	}
+}
+#endif
+
 void
 korrektur(void)
 {
+#if TEST_LOCALES
+	setup_locales();
+#endif
+
 #ifdef TEST_GM_COMMANDS
 	setup_gm_faction();
 #endif
 	make_gms();
 	/* Wieder entfernen! */
-#ifdef BROKEN_OWNERS
 	verify_owners(false);
-#endif
 	/* fix_herbtypes(); */
 #ifdef CONVERT_TRIGGER
 	convert_triggers();
diff --git a/src/eressea/main.c b/src/eressea/main.c
index da9178041..5de729514 100644
--- a/src/eressea/main.c
+++ b/src/eressea/main.c
@@ -132,6 +132,7 @@ game_init(void)
 	report_init();
 	creport_init();
 
+	debug_language("locales.log");
 	init_locales();
 
 	init_races();
@@ -162,20 +163,6 @@ game_init(void)
 	}
 }
 
-static void
-create_game(void)
-{
-	assert(regions==NULL || !"game is initialized");
-	printf("Keine Spieldaten gefunden, erzeuge neues Spiel in %s...\n", datapath());
-	makedir(datapath(), 0700);
-	/* erste Insel generieren */
-	new_region(0, 0);
-	/* Monsterpartei anlegen */
-	createmonsters();
-	/* Teleportebene anlegen */
-	create_teleport_plane();
-}
-
 static void
 getgarbage(void)
 {
@@ -384,7 +371,7 @@ write_stats(void)
 						i = 0;
 						fputs("\n\t", F);
 					}
-					fprintf(F, "{ SK_%s, %d }, ", skillnames[sk], race[r].bonus[sk]);
+					fprintf(F, "{ SK_%s, %d }, ", skillname(sk, NULL), race[r].bonus[sk]);
 					++i;
 				}
 			}
diff --git a/src/eressea/old/order.c b/src/eressea/old/order.c
index 13b3ed945..5943c2223 100644
--- a/src/eressea/old/order.c
+++ b/src/eressea/old/order.c
@@ -73,7 +73,7 @@ order_string(const order * o, char * buf, size_t len)
 		len=4096;
 	}
 	c = buf;
-	strncpy(c, keywords[o->type], len);
+	strncpy(c, locale_string(u->faction->locale, keywords[o->type]), len);
 	slen = strlen(c);
 	len -= slen;
 	c += slen;
diff --git a/src/mapper/map_units.c b/src/mapper/map_units.c
index c6f8e76a9..f97c02fcf 100644
--- a/src/mapper/map_units.c
+++ b/src/mapper/map_units.c
@@ -322,7 +322,7 @@ modify_talente(unit * u, region * r)
 	waddnstr(wn, "< Talente >", -1);
 	for (i = 0; i < MAXSKILLS; i++) {
 		q = get_skill(u, i);
-		sprintf(buf, "%s %d [%d]", skillnames[i], eff_skill(u, i, r), q / u->number);
+		sprintf(buf, "%s %d [%d]", skillname(i, NULL), eff_skill(u, i, r), q / u->number);
 		TL[i] = strdup(buf);
 		if (L > 10) {
 			wmove(wn, i + 1, 4);
@@ -395,7 +395,7 @@ modify_talente(unit * u, region * r)
 					wrefresh(mywin);	/* altes Fenster �berb�geln */
 				}
 				set_skill(u, x, q * u->number);
-				sprintf(buf, "%s %d [%d]", skillnames[x], eff_skill(u, x, r), q);
+				sprintf(buf, "%s %d [%d]", skillname(x, NULL), eff_skill(u, x, r), q);
 				free(TL[x]);
 				modif = 1;
 				TL[x] = strdup(buf);
@@ -467,7 +467,7 @@ modify_unit(region * r, unit * modunit)
 					Addstr(", ");
 					q += 2;
 				}
-				sprintf(buf, "%s %d [%d]", skillnames[sk], eff_skill(u, sk, r), a / u->number);
+				sprintf(buf, "%s %d [%d]", skillname(sk, NULL), eff_skill(u, sk, r), a / u->number);
 				q += strlen(buf);
 				if (q > SX - 8) {
 					q = strlen(buf);
diff --git a/src/res/de/messages.xml b/src/res/de/messages.xml
index fe9c5ad5a..cea6e79af 100644
--- a/src/res/de/messages.xml
+++ b/src/res/de/messages.xml
@@ -10,6 +10,36 @@
 	</locale>
 </message>
 
+<message name="manufacture_skills">
+	<type>
+		<arg name="unit" type="unit"></arg>
+		<arg name="region" type="region"></arg>
+		<arg name="command" type="string"></arg>
+		<arg name="skill" type="skill"></arg>
+		<arg name="minskill" type="int"></arg>
+		<arg name="product" type="resource"></arg>
+	</type>
+	<locale name="de">
+		<nr section="production">
+			<text>"$unit($unit) in $region($region): '$command' - Man ben�tigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren."</text>
+		</nr>
+	</locale>
+</message>
+
+<message name="skill_needed">
+	<type>
+		<arg name="unit" type="unit"></arg>
+		<arg name="region" type="region"></arg>
+		<arg name="command" type="string"></arg>
+		<arg name="skill" type="skill"></arg>
+	</type>
+	<locale name="de">
+		<nr section="production">
+			<text>"$unit($unit) in $region($region): '$command' - Dazu braucht man das Talent $skill"</text>
+		</nr>
+	</locale>
+</message>
+
 <message name="no_attack_after_advance">
 	<type>
 		<arg name="unit" type="unit"></arg>
@@ -4519,7 +4549,12 @@
 	</type>
 	<locale name="de">
 		<nr section="events">
-			<text>"$unit($unit) vermehrt sich um $int($amount) $race($race)."</text>
+			<text>"$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)."</text>
+		</nr>
+	</locale>
+	<locale name="en">
+		<nr section="events">
+			<text>"$unit($unit) breeds $int($amount) new $race($race,$amount)."</text>
 		</nr>
 	</locale>
 </message>
@@ -4580,6 +4615,11 @@
 			<text>"$unit($unit) entdeckt, da� es keinen Weg nach $direction($direction) gibt."</text>
 		</nr>
 	</locale>
+	<locale name="en">
+		<nr section="movement">
+			<text>"$unit($unit) discovers that there is no route going $direction($direction)."</text>
+		</nr>
+	</locale>
 </message>
 
 <message name="followfail">
@@ -5818,12 +5858,12 @@
 
 <message name="growtree_effect">
 	<type>
-		<arg name="mage" type="unit"></arg>
+		<arg name="unit" type="unit"></arg>
 		<arg name="amount" type="int"></arg>
 	</type>
 	<locale name="de">
 		<nr section="magic">
-			<text>"$unit($mage) erschuf einen heiligen Hain von $int($amount) B�umen."</text>
+			<text>"$unit($unit) erschuf einen heiligen Hain von $int($amount) B�umen."</text>
 		</nr>
 	</locale>
 </message>
@@ -6129,7 +6169,7 @@
 	</type>
 	<locale name="de">
 		<nr section="magic">
-			<text>"$unit($mage) verwandelt $int($amount) $race($race) aus $unit($target)."</text>
+			<text>"$unit($mage) verwandelt $int($amount) $race($race,$amount) aus $unit($target)."</text>
 		</nr>
 	</locale>
 </message>
@@ -6239,7 +6279,7 @@
 	</type>
 	<locale name="de">
 		<nr section="events">
-			<text>"Wir erkl�ren allen $race($race) den heiligen Krieg."</text>
+			<text>"Wir erkl�ren allen $race($race,0) den heiligen Krieg."</text>
 		</nr>
 	</locale>
 </message>
diff --git a/src/res/de/strings.txt b/src/res/de/strings.txt
index 2ecaee792..084fb8b1f 100644
--- a/src/res/de/strings.txt
+++ b/src/res/de/strings.txt
@@ -1,3 +1,9 @@
+Karavelle;de;Karavelle
+Boot;de;Boot
+Langboot;de;Langboot
+Drachenschiff;de;Drachenschiff
+Trireme;de;Trireme
+
 # Terraintypen
 maelstrom;de;Mahlstrom
 ocean;de;Ozean
@@ -52,6 +58,13 @@ east;de;Osten
 southwest;de;S�dwesten
 southeast;de;S�dosten
 
+dir_NW;de;NW
+dir_NO;de;NO
+dir_Ost;de;Ost
+dir_SO;de;SO
+dir_SW;de;SW
+dir_West;de;West
+
 # Verschiedenes
 unknownunit;de;eine unbekannte Einheit
 
@@ -64,6 +77,7 @@ section_magic;de;Magie und Artefakte
 section_movement;de;Reisen und Bewegung
 section_study;de;Lehren und Lernen
 section_battle;de;K�mpfe
+section_none;de;Verschiedenes
 
 # Geb�udetypen
 fortress_generic;de;Burg
@@ -83,8 +97,8 @@ tunnel;de;Tunnel
 inn;de;Taverne
 stonecircle;de;Steinkreis
 blessedstonecircle;de;Gesegneter Steinkreis
-illusion;de;Traumschl��chen
-generic;de;Struktur
+illusioncastle;de;Traumschl��chen
+genericbuilding;de;Struktur
 
 #Testgeb�ude
 temple;de;Tempel
@@ -126,6 +140,8 @@ person;de;Person
 persons;de;Personen
 
 #items
+runesword;de;Runenschwert
+runeswords;de;Runenschwerter
 iron;de;Eisen
 irons;de;Eisen
 log;de;Holz
@@ -358,3 +374,229 @@ p14s;de;Heiltr
 # Spezialitems
 lmsreward;de;G�rtel der Heldentaten
 lmsrewards;de;G�rtel der Heldentaten
+
+# Parameter
+ALLES;de;ALLES
+BAUERN;de;BAUERN
+BURG;de;BURG
+EINHEIT;de;EINHEIT
+PRIVAT;de;PRIVAT
+HINTEN;de;HINTEN
+KOMMANDO;de;KOMMANDO
+KR�UTER;de;KR�UTER
+NICHT;de;NICHT
+N�CHSTER;de;N�CHSTER
+PARTEI;de;PARTEI
+PERSONEN;de;PERSONEN
+REGION;de;REGION
+SCHIFF;de;SCHIFF
+SILBER;de;SILBER
+STRA�EN;de;STRA�EN
+TEMPOR�RE;de;TEMPOR�RE
+FEIND;de;FEIND
+FLIEHE;de;FLIEHE
+GEB�UDE;de;GEB�UDE
+GIB;de;GIB
+K�MPFE;de;K�MPFE
+BEWACHE;de;BEWACHE
+ZAUBERBUCH;de;ZAUBERBUCH
+PAUSE;de;PAUSE
+VORNE;de;VORNE
+AGGRESSIV;de;AGGRESSIV
+DEFENSIV;de;DEFENSIV
+STUFE;de;STUFE
+HELFE;de;HELFE
+FREMDES;de;FREMDES
+AURA;de;AURA
+UM;de;UM
+BEISTAND;de;BEISTAND
+GNADE;de;GNADE
+HINTER;de;HINTER
+VOR;de;VOR
+ANZAHL;de;ANZAHL
+GEGENST�NDE;de;GEGENST�NDE
+TR�NKE;de;TR�NKE
+
+#;Talente:
+sk_alchemy;de;Alchemie
+sk_crossbow;de;Armbrustschie�en
+sk_stamina;de;Ausdauer
+sk_mining;de;Bergbau
+sk_bow;de;Bogenschie�en
+sk_building;de;Burgenbau
+sk_trade;de;Handeln
+sk_melee;de;Hiebwaffen
+sk_forestry;de;Holzf�llen
+sk_catapult;de;Katapultbedienung
+sk_herbalism;de;Kr�uterkunde
+sk_magic;de;Magie
+sk_training;de;Pferdedressur
+sk_riding;de;Reiten
+sk_armorer;de;R�stungsbau
+sk_shipcraft;de;Schiffbau
+sk_sailing;de;Segeln
+sk_espionage;de;Spionage
+sk_polearm;de;Stangenwaffen
+sk_quarrying;de;Steinbau
+sk_taxation;de;Steuereintreiben
+sk_roadwork;de;Stra�enbau
+sk_tactics;de;Taktik
+sk_stealth;de;Tarnung
+sk_entertainment;de;Unterhaltung
+sk_weaponsmithing;de;Waffenbau
+sk_unarmed;de;Waffenloser Kampf
+sk_cartmaking;de;Wagenbau
+sk_perception;de;Wahrnehmung
+
+# Befehle
+//;de;//
+BANNER;de;BANNER
+ARBEITEN;de;ARBEITEN
+ATTACKIEREN;de;ATTACKIEREN
+BIETEN;de;BIETEN
+BEKLAUEN;de;BEKLAUEN
+BELAGERE;de;BELAGERE
+BENENNEN;de;BENENNEN
+BENUTZEN;de;BENUTZEN
+BESCHREIBE;de;BESCHREIBE
+BETRETEN;de;BETRETEN
+BEWACHEN;de;BEWACHEN
+BOTSCHAFT;de;BOTSCHAFT
+ENDE;de;ENDE
+FAHREN;de;FAHREN
+NUMMER;de;NUMMER
+FOLGEN;de;FOLGEN
+FORSCHEN;de;FORSCHEN
+HELFEN;de;HELFEN
+K�MPFEN;de;K�MPFEN
+KAMPFZAUBER;de;KAMPFZAUBER
+KAUFEN;de;KAUFEN
+KONTAKTIERE;de;KONTAKTIERE
+LEHREN;de;LEHREN
+LERNEN;de;LERNEN
+LIEFERE;de;LIEFERE
+MACHEN;de;MACHEN
+NACH;de;NACH
+PASSWORT;de;PASSWORT
+REKRUTIEREN;de;REKRUTIEREN
+RESERVIEREN;de;RESERVIEREN
+ROUTE;de;ROUTE
+SABOTIEREN;de;SABOTIEREN
+OPTION;de;OPTION
+SPIONIEREN;de;SPIONIEREN
+STIRB;de;STIRB
+TARNEN;de;TARNEN
+TRANSPORTIEREN;de;TRANSPORTIEREN
+TREIBEN;de;TREIBEN
+UNTERHALTEN;de;UNTERHALTEN
+VERKAUFE;de;VERKAUFE
+VERLASSE;de;VERLASSE
+VERGESSE;de;VERGESSE
+ZAUBERE;de;ZAUBERE
+ZEIGEN;de;ZEIGEN
+ZERST�REN;de;ZERST�REN
+Z�CHTEN;de;Z�CHTEN
+DEFAULT;de;DEFAULT
+REPORT;de;REPORT
+URSPRUNG;de;URSPRUNG
+EMAIL;de;EMAIL
+MEINUNG;de;MEINUNG
+MAGIEGEBIET;de;MAGIEGEBIET
+PIRATERIE;de;PIRATERIE
+LOCALE;de;LOCALE
+NEUSTART;de;NEUSTART
+GRUPPE;de;GRUPPE
+OPFERE;de;OPFERE
+BETEN;de;BETEN
+SORTIEREN;de;SORTIEREN
+JIHAD;de;JIHAD
+GM;de;GM
+
+
+Adler;de;Adler
+Drache;de;Drache
+Drachen;de;Drachen
+D�mon;de;D�mon
+D�monen;de;D�monen
+Einhorn;de;Einhorn
+Einh�rner;de;Einh�rner
+Elf;de;Elf
+Elfen;de;Elfen
+Eule;de;Eule
+Eulen;de;Eulen
+Geist;de;Geist
+Geister;de;Geister
+Goblin;de;Goblin
+Goblins;de;Goblins
+Halbling;de;Halbling
+Halblinge;de;Halblinge
+Hirnt�ter;de;Hirnt�ter
+Insekt;de;Insekt
+Insekten;de;Insekten
+Jungdrache;de;Jungdrache
+Jungdrachen;de;Jungdrachen
+Katze;de;Katze
+Katzen;de;Katzen
+Luchs;de;Luchs
+Luchse;de;Luchse
+Meermensch;de;Meermensch
+Meermenschen;de;Meermenschen
+Mensch;de;Mensch
+Menschen;de;Menschen
+Ork;de;Ork
+Orks;de;Orks
+Riesenschildkr�te;de;Riesenschildkr�te
+Riesenschildkr�ten;de;Riesenschildkr�ten
+Schablone;de;Schablone
+Schablonen;de;Schablonen
+Schattenritter;de;Schattenritter
+Seeschlange;de;Seeschlange
+Troll;de;Troll
+Trolle;de;Trolle
+Untote;de;Untote
+Untoter;de;Untoter
+Warg;de;Warg
+Warge;de;Warge
+Zombie;de;Zombie
+Zombies;de;Zombies
+Zwerg;de;Zwerg
+Zwerge;de;Zwerge
+
+# races, future use:
+rc_lynx;de;Luchse
+rc_unicorns;de;Einh�rner
+rc_wolves;de;Warge
+rc_dragons;de;Drachen
+rc_catdragons;de;Katzendrachen
+rc_ghosts;de;Geister
+rc_cats;de;Katzen
+rc_humans;de;Menschen
+rc_cat;de;Katze
+rc_elf;de;Elf
+rc_human;de;Mensch
+rc_elves;de;Elfen
+rc_aquarian;de;Meermensch
+rc_dwarves;de;Zwerge
+rc_lynxs;de;Luchs
+rc_unicorn;de;Einhorn
+rc_wolf;de;Warg
+rc_dragon;de;Drache
+rc_catdragon;de;Katzendrache
+rc_dwarf;de;Zwerg
+rc_aquarians;de;Meermenschen
+rc_insects;de;Insekten
+rc_insect;de;Insekt
+rc_ghost;de;Geist
+rc_halfling;de;Halbling
+rc_halflings;de;Halblinge
+rc_trolls;de;Trolle
+rc_troll;de;Troll
+rc_undead;de;Untote
+rc_undeads;de;Untoter
+rc_owl;de;Eule
+rc_giantturtle;de;Riesenschildkr�te
+rc_orcs;de;Orks
+rc_orc;de;Ork
+rc_zombie;de;Zombie
+rc_zombies;de;Zombies
+rc_shadowknight;de;Schattenritter
diff --git a/src/res/en/messages.xml b/src/res/en/messages.xml
index 721d563d9..751145cfe 100644
--- a/src/res/en/messages.xml
+++ b/src/res/en/messages.xml
@@ -241,7 +241,7 @@
 	</type>
 	<locale name="en">
 		<nr section="errors">
-			<text>"$unit($unit) in $region($region): '$command' - Order was unrecognizable."</text>
+			<text>"$unit($unit) in $region($region): '$command' - Unknown command."</text>
 		</nr>
 	</locale>
 </message>
@@ -733,7 +733,7 @@
 		<arg name="region" type="region"></arg>
 		<arg name="command" type="string"></arg>
 	</type>
-	<locale name="de">
+	<locale name="en">
 		<nr section="errors">
 			<text>"$unit($unit) in $region($region): '$command' - The unit could not be found."</text>
 		</nr>
@@ -2869,7 +2869,7 @@
 	</type>
 	<locale name="en">
 		<nr section="none">
-			<text>"$unit($unit) hands $int($amount) $resource($resource,$amount) to $unit($target)."</text>
+			<text>"$unit($unit) gave $int($amount) $resource($resource,$amount) to $unit($target)."</text>
 		</nr>
 	</locale>
 </message>
@@ -2906,7 +2906,7 @@
 	</type>
 	<locale name="en">
 		<nr section="none">
-			<text>"$unit($unit) hands command over to $unit($receipient)."</text>
+			<text>"$unit($unit) gave control to $unit($receipient)."</text>
 		</nr>
 	</locale>
 </message>
@@ -3280,7 +3280,7 @@
 	</type>
 	<locale name="en">
 		<nr section="none">
-			<text>"$unit($unit) looses $int($dead) people due to starvation in $region($region)."</text>
+			<text>"$unit($unit) loses $int($dead) people due to starvation in $region($region)."</text>
 		</nr>
 	</locale>
 </message>
@@ -3524,7 +3524,7 @@
 		<arg name="direction" type="direction"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>"$unit($unit) refuses to travel to the$direction($direction)."</text>
 		</nr>
 	</locale>
@@ -3536,7 +3536,7 @@
 		<arg name="region" type="region"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>"The crew of the $ship($ship) refuses to travel to $region($region)."</text>
 		</nr>
 	</locale>
@@ -3548,7 +3548,7 @@
 		<arg name="direction" type="direction"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>" The crew of the $ship($ship) refuses to travel to the$direction($direction)."</text>
 		</nr>
 	</locale>
@@ -3571,7 +3571,7 @@
 		<arg name="ship" type="ship"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>"In the very last moment, the crew of the $ship($ship) saved the ship from grounding."</text>
 		</nr>
 	</locale>
@@ -3583,7 +3583,7 @@
 		<arg name="region" type="region"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>"$unit($unit) discovered that $region($region) is Ocean."</text>
 		</nr>
 	</locale>
@@ -3595,7 +3595,7 @@
 		<arg name="direction" type="direction"></arg>
 	</type>
 	<locale name="en">
-		<nr section="none">
+		<nr section="movement">
 			<text>"$unit($unit) discovered that an Ocean lies in the $direction($direction)."</text>
 		</nr>
 	</locale>
diff --git a/src/res/en/strings.txt b/src/res/en/strings.txt
index 98baee9c4..12f52a67b 100644
--- a/src/res/en/strings.txt
+++ b/src/res/en/strings.txt
@@ -1,10 +1,25 @@
-west;en;West
-northwest;en;Northwest
-northeast;en;Northeast
-east;en;East
-southwest;en;Southwest
-southeast;en;Southeast
+Karavelle;en;caravelle
+Boot;en;boat
+Langboot;en;longboat
+Drachenschiff;en;dragonboat
+Trireme;en;trireme
+
+west;en;west
+northwest;en;northwest
+northeast;en;northeast
+east;en;east
+southwest;en;southwest
+southeast;en;southeast
+
+dir_NW;en;NW
+dir_NO;en;NE
+dir_Ost;en;East
+dir_SO;en;SE
+dir_SW;en;SW
+dir_West;en;West
+
 unknownunit;en;an unknown unit
+
 section_events;en;Messages and Events
 section_errors;en;Warnings and Errors
 section_economy;en;Economy and Trade
@@ -15,6 +30,26 @@ section_study;en;Learning and Teaching
 section_battle;en;Battles
 section_none;en;Miscellaneous
 
+# Building Types
+genericbuilding;en;structure
+illusioncastle;en;fairy castle
+blessedstonecircle;en;blessed stonecircle
+stonecircle;en;stonecircle
+inn;en;inn
+tunnel;en;tunnel
+caravan;en;caravanserei
+dam;en;dam
+monument;en;monument
+stables;en;stables
+sawmill;en;sawmill
+smithy;en;smithy
+magictower;en;magic tower
+academy;en;academy
+harbour;en;harbour
+quarry;en;quarry
+mine;en;mine
+lighthouse;en;lighthouse
+
 # Burgausbaustufen
 site;en;site
 fortification;en;fortification
@@ -25,13 +60,12 @@ citadel;en;citadel
 
 # Items
 herb;en;herb
-herbbag;en;herbbag
 vial;en;vial
 vials;en;vials
 
 # Resourcen
-money;en;money
-moneys;en;moneys
+money;en;silver
+moneys;en;silver
 hp;en;hp
 hps;en;hps
 aura;en;aura
@@ -65,16 +99,8 @@ chainmail;en;chainmail
 chainmails;en;chainmails
 plate;en;plate
 plates;en;plates
-balm;en;balm
-spice;en;spice
-jewel;en;jewel
-jewels;en;jewels
-myrrh;en;myrrh
-oil;en;oil
-silk;en;silk
-incense;en;incense
-firesword;en;firesword
-fireswords;en;fireswords
+firesword;en;flaming sword
+fireswords;en;flaming swords
 shieldstone;en;shieldstone
 shieldstones;en;shieldstones
 greatsword;en;great sword
@@ -161,9 +187,58 @@ aurafocuses;en;aurafocuses
 presspass;en;presspass
 presspasses;en;presspasses
 trollbelt;en;trollbelt
+person;en;man
+persons;en;men
+unit;en;unit
+units;en;units
+ao_chastity;en;amulet of chastity
+ao_chastitys;en;amulets of chastity
+laens;en;laen
+pegasus;en;pegasus
+pegasi;en;pegasi
+elvenhorse;en;elven horse
+elvenhorses;en;elven horses
+dolphin;en;dolphin
+dolphins;en;dolphins
+runesword;en;runesword
+runeswords;en;runeswords
+magicherbbag;en;bag of conservation
+mallornspear;en;mallorn spear
+mallornspears;en;mallorn spear
+mallornlance;en;mallorn lance
+mallornlances;en;mallorn lances
+mallornbow;en;mallorn bow
+mallornbows;en;mallorn bows
+mallorncrossbow;en;mallorn crossbow
+mallorncrossbows;en;mallorn crossbows
+ao_daemon;en;eye of the Demon
+ao_daemons;en;eye of the Demon
+museumticket;en;ticket to the grand museum
+museumtickets;en;tickets to the grand museum
+museumexitticket;en;returnticket for the grand museum
+museumexittickets;en;returntickets for the grand museum
+griphonwing;en;wing of the gryphon
+griphonwings;en;wings of the gryphon
+
+# luxury goods
+balm;en;balm
+spice;en;spice
+jewel;en;jewel
+jewels;en;jewels
+myrrh;en;myrrh
+oil;en;oil
+silk;en;silk
+incense;en;incense
+balms;en;balm
+spices;en;spice
+myrrhs;en;myrrh
+oils;en;oil
+silks;en;silk
+incenses;en;incense
 
 # Spezialitems
 lmsreward;en;Belt of Heroic Legends
+lmsrewards;en;Belts of Heroic Legends
 
 # Terraintypen
 maelstrom;en;maelstrom
@@ -187,7 +262,7 @@ hall1;en;hallway
 corridor1;en;corridor
 
 maelstrom_trail;en;a %s
-ocean_trail;en;an %s
+ocean_trail;en;the %s
 plain_trail;en;the plain of %s
 forest_trail;en;the forests of %s
 swamp_trail;en;the swamps of %s
@@ -208,3 +283,267 @@ corridor1_trail;en;a %s
 
 caldera;en;caldera
 xmas_exit;en;portal
+
+viele;en;many
+sehr viele;en;a great many
+
+# intranslatables:
+h0;en;Flachwurz
+h0s;en;Flachwurz
+h1;en;W�rziger Wagemut
+h1s;en;W�rzige Wagemut
+h2;en;Eulenauge
+h2s;en;Eulenaugen
+h3;en;Gr�ner Spinnerich
+h3s;en;Gr�ne Spinneriche
+h4;en;Blauer Baumringel
+h4s;en;Blaue Baumringel
+h5;en;Elfenlieb
+h5s;en;Elfenlieb
+h6;en;Gurgelkraut
+h6s;en;Gurgelkr�uter
+h7;en;Knotiger Saugwurz
+h7s;en;Knotige Saugwurze
+h8;en;Blasenmorchel
+h8s;en;Blasenmorcheln
+h9;en;Wasserfinder
+h9s;en;Wasserfinder
+h10;en;Kakteenschwitz
+h10s;en;Kakteenschwitze
+h11;en;Sandf�ule
+h11s;en;Sandf�ulen
+h12;en;Windbeutel
+h12s;en;Windbeutel
+h13;en;Fjordwuchs
+h13s;en;Fjordwuchse
+h14;en;Alraune
+h14s;en;Alraunen
+h15;en;Steinbei�er
+h15s;en;Steinbei�er
+h16;en;Spaltwachs
+h16s;en;Spaltwachse
+h17;en;H�hlenglimm
+h17s;en;H�hlenglimme
+h18;en;Eisblume
+h18s;en;Eisblumen
+h19;en;Wei�er W�terich
+h19s;en;Wei�e W�teriche
+h20;en;Schneekristall
+h20s;en;Schneekristalle
+p0;en;Siebenmeilentee
+p0s;en;Siebenmeilentees
+p1;en;Goliathwasser
+p1s;en;Goliathwasser
+p2;en;Wasser des Lebens
+p2s;en;Wasser des Lebens
+p3;en;Schaffenstrunk
+p3s;en;Schaffenstr�nke
+p4;en;Wundsalbe
+p4s;en;Wundsalben
+p5;en;Bauernblut
+p5s;en;Bauernblut
+p6;en;Gehirnschmalz
+p6s;en;Gehirnschmalz
+p7;en;Dumpfbackenbrot
+p7s;en;Dumpfbackenbrote
+p8;en;Nestw�rme
+p8s;en;Nestw�rme
+p9;en;Pferdegl�ck
+p9s;en;Pferdegl�ck
+p10;en;Berserkerblut
+p10s;en;Berserkerblut
+p11;en;Bauernlieb
+p11s;en;Bauernlieb
+p12;en;Trank der Wahrheit
+p12s;en;Tr�nke der Wahrheit
+p13;en;Elixier der Macht
+p13s;en;Elixiere der Macht
+p14;en;Heiltrank
+p14s;en;Heiltr�nke
+
+# Parameters
+ALLES;en;ALL
+BAUERN;en;PEASANTS
+BURG;en;FORTIFICATION
+EINHEIT;en;UNIT
+PRIVAT;en;PRIVATE
+HINTEN;en;BACK
+KOMMANDO;en;CONTROL
+KR�UTER;en;HERBS
+NICHT;en;NOT
+N�CHSTER;en;NEXT
+PARTEI;en;PARTEI
+PERSONEN;en;MEN
+REGION;en;REGION
+SCHIFF;en;SHIP
+STRA�EN;en;ROADS
+TEMPOR�RE;en;TEMPORARY
+FLIEHE;en;FLEE
+GEB�UDE;en;BUILDING
+GIB;en;GIVE
+K�MPFE;en;COMBAT
+BEWACHE;en;GUARD
+ZAUBERBUCH;en;SPELLBOOK
+PAUSE;en;PAUSE
+VORNE;en;FRONT
+AGGRESSIV;en;AGGRESSIVE
+DEFENSIV;en;DEFENSIVE
+STUFE;en;LEVEL
+HELFE;en;HELP
+FREMDES;en;ALIEN
+AURA;en;AURA
+UM;en;FOR
+BEISTAND;en;AID
+GNADE;en;MERCY
+HINTER;en;AFTER
+VOR;en;BEFORE
+ANZAHL;en;NUMBER
+GEGENST�NDE;en;ITEMS
+TR�NKE;en;POTIONS
+SILBER;en;MONEY
+
+# Skills
+sk_alchemy;en;alchemy
+sk_crossbow;en;crossbow
+sk_stamina;en;stamina
+sk_mining;en;mining
+sk_bow;en;bow
+sk_building;en;building
+sk_trade;en;trade
+sk_melee;en;melee
+sk_forestry;en;forestry
+sk_catapult;en;catapult
+sk_herbalism;en;herbalism
+sk_magic;en;magic
+sk_training;en;training
+sk_riding;en;riding
+sk_armorer;en;armorer
+sk_shipcraft;en;shipcraft
+sk_sailing;en;sailing
+sk_espionage;en;espionage
+sk_polearm;en;polearm
+sk_quarrying;en;quarrying
+sk_taxation;en;taxation
+sk_roadwork;en;roadwork
+sk_tactics;en;tactics
+sk_stealth;en;stealth
+sk_entertainment;en;entertainment
+sk_weaponsmithing;en;weaponsmithing
+sk_unarmed;en;unarmed combat
+sk_cartmaking;en;cartmaking
+sk_perception;en;perception
+
+# Keywords
+//;en;//
+BANNER;en;BANNER
+ARBEITEN;en;WORK
+ATTACKIEREN;en;ATTACK
+BIETEN;en;BIDD
+BEKLAUEN;en;STEAL
+BELAGERE;en;BESIEGE
+BENENNEN;en;NAME
+BENUTZEN;en;USE
+BESCHREIBE;en;DESCRIBE
+BETRETEN;en;ENTER
+BEWACHEN;en;GUARD
+BOTSCHAFT;en;MESSAGE
+ENDE;en;END
+FAHREN;en;HITCH
+NUMMER;en;NUMBER
+FOLGEN;en;FOLLOW
+FORSCHEN;en;RESEARCH
+HELFEN;en;HELP
+K�MPFEN;en;COMBAT
+KAMPFZAUBER;en;COMBATSPELL
+KAUFEN;en;BUY
+KONTAKTIERE;en;CONTACT
+LEHREN;en;TEACH
+LERNEN;en;LEARN
+LIEFERE;en;SUPPLY
+MACHEN;en;MAKE
+NACH;en;MOVE
+PASSWORT;en;PASSWORD
+REKRUTIEREN;en;RECRUIT
+RESERVIEREN;en;RESERVE
+ROUTE;en;ROUTE
+SABOTIEREN;en;SABOTAGE
+OPTION;en;OPTION
+SPIONIEREN;en;SPY
+STIRB;en;QUIT
+TARNEN;en;TARN
+TRANSPORTIEREN;en;TRANSPORT
+TREIBEN;en;TAX
+UNTERHALTEN;en;ENTERTAIN
+VERKAUFE;en;SELL
+VERLASSE;en;LEAVE
+VERGESSE;en;FORGET
+ZAUBERE;en;CAST
+ZEIGEN;en;SHOW
+ZERST�REN;en;DESTROY
+Z�CHTEN;en;BREED
+DEFAULT;en;DEFAULT
+REPORT;en;REPORT
+URSPRUNG;en;ORIGIN
+EMAIL;en;EMAIL
+MEINUNG;en;OPINION
+MAGIEGEBIET;en;CIRCLE
+PIRATERIE;en;PIRACY
+LOCALE;en;LOCALE
+NEUSTART;en;RESTART
+GRUPPE;en;GROUP
+OPFERE;en;SACRIFICE
+BETEN;en;PRAY
+SORTIEREN;en;SORT
+JIHAD;en;JIHAD
+GM;en;GM
+
+Luchse;en;lynx
+Einh�rner;en;unicorns
+Warge;en;wolves
+Drachen;en;dragons
+Katzendrachen;en;catdragons
+Geister;en;ghosts
+Katzen;en;cats
+Menschen;en;humans
+Katze;en;cat
+Elf;en;elf
+Mensch;en;human
+Elfen;en;elves
+Meermensch;en;aquarian
+Zwerge;en;dwarves
+Luchs;en;lynx
+Einhorn;en;unicorn
+Warg;en;wolf
+Drache;en;dragon
+Katzendrache;en;catdragon
+Zwerg;en;dwarf
+Meermenschen;en;aquarians
+Insekten;en;insects
+Insekt;en;insect
+Geist;en;ghost
+Halbling;en;halfling
+Halblinge;en;halflings
+Trolle;en;trolls
+Troll;en;troll
+Untote;en;undead
+Untoter;en;undead
+Eule;en;owl
+Riesenschildkr�te;en;giant turtle
+Orks;en;orc
+Zombie;en;zombie
+Zombies;en;zombies
+Schattenritter;en;shadow knight
+Adler;en;eagle
+Hirnt�ter;en;braineater
+Jungdrachen;en;young dragons
+Jungdrache;en;young dragons
+Seeschlange;en;sea serpent
+Eulen;en;owls
+Riesenschildkr�ten;en;giant turtles
+D�mon;en;Demon
+Ork;en;orc
+D�monen;en;Demons
+Schablonen;en;templates
+Goblin;en;goblin
+Schablone;en;template
+Goblins;en;goblins
diff --git a/src/tools/prototype-advance/Graph.pyc b/src/tools/prototype-advance/Graph.pyc
index b0f59b51eb6a1d2ec69d43871233ec88aecc126a..44a9cad16a33c370e4d00ad53909d55f1a6f8d98 100644
GIT binary patch
delta 7
OcmdlivsY?^EiV8JL;|4z

delta 255
zcmZXOyAFat5Ji`lC@xY-fqnoLeu1&HqcO4FAdEl=kL=*9@|R4k{WoW!u&|ljGr4!}
ze1iA-wRN9?w$hh+XfwueN<)aUDSIJsP9ULfuOON>1Dp|`%O)GiA!?w^i&J}%h<q?3
z^rB8=1rpW03?Y$eG3s0<U4bF38LDu!*{jVh>K<qj59BdikT!H~@(H)OL(_{xQ-zf2
i&?jky3S;%sgv1eK5BJ}RzXnyHk#T3RA>iu1<y&8(-#I4$

diff --git a/src/tools/prototype-advance/Stack.pyc b/src/tools/prototype-advance/Stack.pyc
index 929d842a0384055ce432fa8df1565a2cbb36f494..1655429e13b06982845a4f16e4318679c923e453 100644
GIT binary patch
delta 7
OcmbQn*37hlnGpa8^8wZX

literal 790
zcmaJ<%TB^T6g|@^LW-yf3lkIfT^M#QbmJeeuq)X#m4X%(noM1gkjw%T|HM!6yS(QL
z<)H!SWTtb^J&()hcXZSHx*bA3RvvdLi<h584vc}^-~(6!4+A*_NMbE(NLf;4!xu#w
z1aQ|xTKI5<k$T@GMDPOxA0fB858yk<L)}~4Co!A#hX!n8;ks-T!Z+{)EP&KdOA;HF
z#eu9Y<T834>n6{tOfNUDTXL`Rdga{lkfz17sM0iqV*_i3fsiTPg`7pGZ;`7oC;}`D
zmLg}1RSEyFx+B46WjUJWj<L)hCwux<Z&gDrh<(a;_uQ<-(7U1cbBc-J+Z!=Uv9hIv
z9XCeVivE?poRx=iAW}-A9afFtimV;@lNGDvJ_#^u!}wE9GntA!f2Q+SDQwl3tRygb
zuxENL>W~=DeDqdU^A0pcYr3XwVnTNYrdAo&+M%nFF{yWxt^bx1CC6^fvE{e_E2X~v
L2TC({0%Ox3e$9ia

diff --git a/src/tools/translator.c b/src/tools/translator.c
index cc268ba51..43ee34bbe 100644
--- a/src/tools/translator.c
+++ b/src/tools/translator.c
@@ -139,7 +139,7 @@ new_message(struct faction * receiver, const char* sig, ...)
 				args[i] = resourcename(oldresourcetype[(resource_t)va_arg(marker, resource_t)], 0);
 				break;
 			case 't':
-				args[i] = skillnames[va_arg(marker, skill_t)];
+				args[i] = skillname(va_arg(marker, skill_t), NULL);
 				break;
 			case 'd':
 				args[i] = directions[i];