Crossfire Server, Trunk  1.75.0
languages.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
14 #include "global.h"
15 
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <map>
20 #include <memory>
21 
25 struct i18n_file {
28  std::map<sstring, sstring> messages;
29 };
30 
32 static std::vector<i18n_file *> i18n_files;
34 static i18n_file *i18n_default = nullptr;
35 
42 const char *i18n(const object *who, const char *code) {
43  if (!who || !who->contr || !who->contr->language)
44  return code;
45 
46  sstring scode = find_string(code);
47  if (!scode)
48  return code;
49  i18n_file *file = static_cast<i18n_file *>(who->contr->language);
50  auto found = file->messages.find(scode);
51 
52  return found == file->messages.end() ? code : found->second;
53 }
54 
61  for (auto language : i18n_files) {
62  if (strcmp(code, language->code) == 0)
63  return language;
64  }
65 
66  return nullptr;
67 }
68 
76  if (found)
77  return found;
78  return i18n_default;
79 }
80 
87  if (!language)
88  return i18n_default->code;
89  return static_cast<i18n_file *>(language)->code;
90 }
91 
96 void i18n_list_languages(object *who) {
97  for (auto language : i18n_files) {
99  "[fixed]%s: %s",
100  language->code,
101  language->name
102  );
103  }
104 }
105 
114 static void convert_newline(char *line) {
115  char *next;
116  char buf[MAX_BUF];
117 
118  while ((next = strstr(line, "\\n")) != NULL) {
119  *next = '\n';
120  *(next+1) = '\0';
121  snprintf(buf, MAX_BUF, "%s%s", line, next+2);
122  strcpy(line, buf);
123  }
124 }
125 
131 void i18n_init(void) {
132  char dirname[MAX_BUF], filename[MAX_BUF*2], *line;
133  BufferReader *br;
134  char *token;
135  DIR *dir;
136  struct dirent *file;
137 
138  snprintf(dirname, sizeof(dirname), "%s/i18n/", settings.datadir);
139 
140  dir = opendir(dirname);
141  if (dir == NULL) {
142  LOG(llevError, "i18n: couldn't open %s\n", dirname);
144  }
145 
146  sstring code = add_string("LN");
147 
148  while ((file = readdir(dir)) != NULL) {
149  if (strncmp(file->d_name, "messages.", 9) != 0)
150  continue;
151 
152  snprintf(filename, sizeof(filename), "%s%s", dirname, file->d_name);
153  br = bufferreader_init_from_file(NULL, filename, "i18n: couldn't open %s: %s\n", llevError);
154  if (!br) {
156  }
157  i18n_file *language = new i18n_file();
158 
159  if (!language) {
160  LOG(llevError, "i18n: couldn't allocate memory!\n");
162  }
163  language->code = add_string(file->d_name + 9);
164  i18n_files.push_back(language);
165 
166  while ((line = bufferreader_next_line(br)) != NULL) {
167  if (line[0] != '#' && line[0] != '\0') {
168 
169  token = strtok(line, "|");
170  convert_newline(token);
171  sstring scode = add_string(token), smessage;
172  token = strtok(NULL, "|");
173  if (token != NULL) {
174  convert_newline(token);
175  smessage = add_string(token);
176  } else {
177  smessage = add_refcount(scode);
178  }
179  language->messages[scode] = smessage;
180  }
181  }
183 
184  auto found = language->messages.find(code);
185  if (found == language->messages.end()) {
186  LOG(llevError, "i18n: no language set in %s\n", filename);
188  }
189 
190  language->name = found->second;
191  LOG(llevDebug, "i18n: %zu strings for %s\n",
192  language->messages.size(), language->name);
193 
194  if (strcmp(language->code, "en") == 0)
195  i18n_default = language;
196  }
197  closedir(dir);
198 
199  free_string(code);
200 
201  if (i18n_default == nullptr) {
202  LOG(llevError, "i18n: couldn't find default language (en)\n");
204  }
205 }
206 
210 void i18n_free(void) {
211  for (auto language : i18n_files) {
212  free_string(language->code); /* name is a copy of a message */
213  for (auto message : language->messages) {
214  free_string(message.first);
215  free_string(message.second);
216  }
217  delete language;
218  }
219  i18n_files.clear();
220 }
global.h
i18n_free
void i18n_free(void)
Clears all i18n-related data.
Definition: languages.cpp:210
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
i18n_files
static std::vector< i18n_file * > i18n_files
Defined languages.
Definition: languages.cpp:32
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
language_t
void * language_t
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:69
Settings::datadir
const char * datadir
Read only data files.
Definition: global.h:249
i18n_file::messages
std::map< sstring, sstring > messages
Available messages for this language.
Definition: languages.cpp:28
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
bufferreader_destroy
void bufferreader_destroy(BufferReader *br)
Destroy a BufferReader.
Definition: bufferreader.cpp:40
i18n_file::name
sstring name
Language's name, in its native version.
Definition: languages.cpp:27
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
buf
StringBuffer * buf
Definition: readable.cpp:1565
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
i18n_init
void i18n_init(void)
Initializes the i18n subsystem.
Definition: languages.cpp:131
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
bufferreader_init_from_file
BufferReader * bufferreader_init_from_file(BufferReader *br, const char *filepath, const char *failureMessage, LogLevel failureLevel)
Initialize or create a BufferReader from a file path.
Definition: bufferreader.cpp:65
opendir
DIR * opendir(const char *)
is_valid_types_gen.line
line
Definition: is_valid_types_gen.py:34
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
i18n_get_language_code
sstring i18n_get_language_code(language_t language)
Return the code of a specified language.
Definition: languages.cpp:86
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
readdir
struct dirent * readdir(DIR *)
find_string
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.cpp:236
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
i18n_file
One available language.
Definition: languages.cpp:25
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:424
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
i18n_get_language_by_code
language_t i18n_get_language_by_code(const char *code)
Find the identifier of a language from its code.
Definition: languages.cpp:74
sstring
const typedef char * sstring
Definition: sstring.h:2
i18n_list_languages
void i18n_list_languages(object *who)
List all languages for who.
Definition: languages.cpp:96
player::language
language_t language
The language the player wishes to use.
Definition: player.h:220
i18n_find_language_by_code
language_t i18n_find_language_by_code(const char *code)
Attempt to find the identifier of a language from its code.
Definition: languages.cpp:60
i18n_file::code
sstring code
Language code, "message." extension.
Definition: languages.cpp:26
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
closedir
int closedir(DIR *)
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
BufferReader
Definition: bufferreader.cpp:21
i18n_default
static i18n_file * i18n_default
"English" language.
Definition: languages.cpp:34
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
i18n
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
convert_newline
static void convert_newline(char *line)
Replaces ' ' by a newline char.
Definition: languages.cpp:114
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
Definition: bufferreader.cpp:102