Crossfire Server  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 }
One available language.
Definition: languages.cpp:25
Error, serious thing.
Definition: logger.h:11
#define dirent
Definition: global.h:215
void bufferreader_destroy(BufferReader *br)
Destroy a BufferReader.
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
void i18n_init(void)
Initializes the i18n subsystem.
Definition: languages.cpp:131
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
void * language_t
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:69
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
sstring name
Language&#39;s name, in its native version.
Definition: languages.cpp:27
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
static void convert_newline(char *line)
Replaces &#39; &#39; by a newline char.
Definition: languages.cpp:114
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.cpp:250
DIR * opendir(const char *)
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
Global type definitions and header inclusions.
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
std::map< sstring, sstring > messages
Available messages for this language.
Definition: languages.cpp:28
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
BufferReader * bufferreader_init_from_file(BufferReader *br, const char *filepath, const char *failureMessage, LogLevel failureLevel)
Initialize or create a BufferReader from a file path.
language_t i18n_get_language_by_code(const char *code)
Find the identifier of a language from its code.
Definition: languages.cpp:74
language_t language
The language the player wishes to use.
Definition: player.h:222
struct Settings settings
Global settings.
Definition: init.cpp:139
void i18n_list_languages(object *who)
List all languages for who.
Definition: languages.cpp:96
sstring code
Language code, "message." extension.
Definition: languages.cpp:26
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
const char * datadir
Read only data files.
Definition: global.h:249
Only for debugging purposes.
Definition: logger.h:13
struct dirent * readdir(DIR *)
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
int closedir(DIR *)
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
#define MSG_SUBTYPE_NONE
Definition: newclient.h:439
static i18n_file * i18n_default
"English" language.
Definition: languages.cpp:34
StringBuffer * buf
Definition: readable.cpp:1563
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
const char * sstring
Definition: sstring.h:2
static std::vector< i18n_file * > i18n_files
Defined languages.
Definition: languages.cpp:32
sstring i18n_get_language_code(language_t language)
Return the code of a specified language.
Definition: languages.cpp:86
void i18n_free(void)
Clears all i18n-related data.
Definition: languages.cpp:210