compiler/i18n: Added i18n strings to libec/ecc/ecp/ecs
[sdk] / ecere / src / sys / i18n.ec
1 #ifndef ECERE_COM_MODULE
2 import "File"
3 #endif
4 import "Map"
5
6 #if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
7 #define dllexport
8 #if !defined(ECERE_BOOTSTRAP)
9 #define stdcall
10 #endif
11 #endif
12
13 #ifndef ECERE_BOOTSTRAP
14 #define FileOpen FileOpenBuffered
15 #endif
16
17 static Map<String, Map<String, String>> moduleMaps { };
18
19 #define SWAP_DWORD(dword) ((((unsigned int)(dword) & 0x000000ff) << 24) \
20                          | (((unsigned int)(dword) & 0x0000ff00) <<  8) \
21                          | (((unsigned int)(dword) & 0x00ff0000) >>  8) \
22                          | (((unsigned int)(dword) & 0xff000000) >> 24))
23
24 public dllexport void LoadTranslatedStrings(Module module, char * name)
25 {
26 #ifndef ECERE_COM_MODULE
27    File f;
28    char fileName[MAX_LOCATION];
29
30    char lcAll[256];
31    char language[256];
32    char lang[256];
33    char lcMessages[256];
34    char * locale = null;
35
36    if(GetEnvironment("LANGUAGE", language, sizeof(language)))
37       locale = language;
38    else if(GetEnvironment("LC_ALL", lcAll, sizeof(lcAll)))
39       locale = lcAll;
40    else if(GetEnvironment("LC_MESSAGES", lcMessages, sizeof(lcMessages)))
41       locale = lcMessages;
42    else if(GetEnvironment("LANG", lang, sizeof(lang)))
43       locale = lang;
44
45    if(locale)
46    {
47       char * dot;
48       strcpy(language, locale);
49       dot = strstr(language, ".");
50       if(dot) *dot = 0;
51       locale = language;
52    }
53
54    if(module.name)
55       sprintf(fileName, "<:%s>locale/%s/LC_MESSAGES/%s.mo", module.name, locale, name);
56    else
57       sprintf(fileName, ":locale/%s/LC_MESSAGES/%s.mo", locale, name);
58    f = FileOpen(fileName, read);
59    if(!f)
60    {
61       sprintf(fileName, "locale/%s/LC_MESSAGES/%s.mo", locale, name);
62       f = FileOpen(fileName, read);
63    }
64    if(!f)
65    {
66       sprintf(fileName, "/usr/share/locale/%s/LC_MESSAGES/%s.mo", locale, name);
67       f = FileOpen(fileName, read);
68    }
69    if(f)
70    {
71       uint magic = 0;
72       f.Read(&magic, sizeof(uint), 1);
73       if(magic == 0x950412de || magic == 0xde120495)
74       {
75          Map<String, String> textMap;
76          bool swap = magic != 0x950412de;
77          uint revision = 0;
78          uint numStrings = 0;
79          uint origStrings = 0, transStrings = 0;
80          uint hashingSize = 0, hashingOffset = 0;
81          int c;
82          f.Read(&revision, sizeof(uint), 1);       if(swap) SWAP_DWORD(revision);
83          f.Read(&numStrings, sizeof(uint), 1);     if(swap) SWAP_DWORD(numStrings);
84          f.Read(&origStrings, sizeof(uint), 1);    if(swap) SWAP_DWORD(origStrings);
85          f.Read(&transStrings, sizeof(uint), 1);   if(swap) SWAP_DWORD(transStrings);
86          f.Read(&hashingSize, sizeof(uint), 1);    if(swap) SWAP_DWORD(hashingSize);
87          f.Read(&hashingOffset, sizeof(uint), 1);  if(swap) SWAP_DWORD(hashingOffset);
88          
89          if(!moduleMaps)
90             moduleMaps = { };
91          {
92             MapIterator<String, Map<String, String>> it { map = moduleMaps };
93             if(it.Index(module.name, false))
94                delete it.data;
95             // TOFIX: delete moduleMaps[module];
96          }
97          moduleMaps[module.name] = textMap = { };
98          for(c = 0; c < numStrings; c++)
99          {
100             uint len = 0, offset = 0;
101             char * original = null, * translated = null;
102
103             f.Seek(origStrings + c*2*sizeof(uint), start);
104             f.Read(&len, sizeof(uint), 1);      if(swap)SWAP_DWORD(len);
105             f.Read(&offset, sizeof(uint), 1);   if(swap)SWAP_DWORD(offset);
106             f.Seek(offset, start);
107
108             original = new byte[len + 1];
109             f.Read(original, 1, len + 1);
110
111             f.Seek(transStrings + c*2*sizeof(uint), start);
112             f.Read(&len, sizeof(uint), 1);      if(swap)SWAP_DWORD(len);
113             f.Read(&offset, sizeof(uint), 1);   if(swap)SWAP_DWORD(offset);
114             f.Seek(offset, start);
115
116             translated = new byte[len + 1];
117             f.Read(translated, 1, len + 1);
118
119             if(len)
120             {
121                MapIterator<String, String> it { map = textMap };
122                // TOFIX: Memory leak if the add fails
123                if(it.Index(original, false))
124                   delete translated;
125                else
126                   textMap[original] = translated;
127             }
128             else
129                delete translated;
130             delete original;
131          }
132       }
133       else
134       {
135          // Failure
136          printf("Invalid format while loading %s\n", fileName);
137       }
138       delete f;
139    }
140 #endif
141 }
142
143 public dllexport void UnloadTranslatedStrings(Module module)
144 {
145    MapIterator<String, Map<String, String>> it { map = moduleMaps };
146    if(it.Index(module.name, false))
147    {
148       it.data.Free();
149       moduleMaps.Delete(it.pointer);
150    }
151 }
152
153 public dllexport char * GetTranslatedString(Module module, char * string, char * stringAndContext)
154 {
155    Map<String, String> textMap = moduleMaps ? moduleMaps[module.name] : null;
156    char * result = textMap ? textMap[stringAndContext ? stringAndContext : string] : string;
157    return (result && result[0]) ? result : string;
158 }