source: trunk/Lucide/SOURCE/gui/intern.cpp @ 114

Last change on this file since 114 was 114, checked in by Eugene Romanenko, 15 years ago

Lucide's i18n now respects 'territory' modifier for 'LANG' env var.

File size: 9.2 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: CDDL 1.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the COMMON DEVELOPMENT AND
5 * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6 * this file except in compliance with the License. You may obtain a copy of
7 * the License at http://www.sun.com/cddl/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is
15 * Eugene Romanenko, netlabs.org.
16 * Portions created by the Initial Developer are Copyright (C) 2006
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23 * in which case the provisions of the LGPL are applicable instead of those
24 * above. If you wish to allow use of your version of this file only under the
25 * terms of the LGPL, and not to allow others to use your version of this file
26 * under the terms of the CDDL, indicate your decision by deleting the
27 * provisions above and replace them with the notice and other provisions
28 * required by the LGPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under the terms of any one of the CDDL
30 * or the LGPL.
31 *
32 * ***** END LICENSE BLOCK ***** */
33
34
35#define INCL_DOS
36#define INCL_WIN
37#include <os2.h>
38
39#include <fstream>
40#include <map>
41#include <string>
42using namespace std;
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <io.h>
48
49#include "globals.h"
50#include "wwbtn.h"
51#include "luutils.h"
52
53#define LINEBUF_LEN     4096
54
55static bool langLoaded = false;
56
57static map<string,string> *langDefault = NULL;
58static map<string,string> *langCurrent = NULL;
59
60#define NUM_ESCAPES     2
61static const char *escapes[NUM_ESCAPES][2] = { { "\\t", "\t" }, { "\\r", "\r" } };
62
63static string unescapeControls( const char *s )
64{
65    string r = s;
66    for ( int i = 0; i < NUM_ESCAPES; i++ )
67    {
68        const char *r_c = r.c_str();
69        char *p = strstr( r_c, escapes[i][0] );
70        if ( p != NULL )
71        {
72            int len = strlen( r_c ) + 1;
73            char *tmp = new char[ len ];
74            memset( tmp, 0, len );
75            memcpy( tmp, r_c, p - r_c );
76            strcat( tmp, escapes[i][1] );
77            strcat( tmp, p + strlen( escapes[i][0] ) );
78            r = tmp;
79            delete tmp;
80        }
81    }
82    return r;
83}
84
85
86static void loadLng( map<string,string> *array, const char *file, bool exitOnError )
87{
88    ifstream lngFile( file );
89    if ( !lngFile )
90    {
91        if ( exitOnError )
92        {
93            char msgbuf1[ 500 ];
94            char msgbuf2[ 100 ];
95            snprintf( msgbuf1, sizeof( msgbuf1 ),
96                      "Default language file \"%s\" not found!", file );
97            snprintf( msgbuf2, sizeof( msgbuf2 ), "%s error!", appName );
98
99            WinMessageBox( HWND_DESKTOP, HWND_DESKTOP, msgbuf1, msgbuf2,
100                           10000, MB_CANCEL | MB_ERROR | MB_ICONHAND | MB_MOVEABLE );
101
102            DosExit( EXIT_PROCESS, 1 );  // ??? exit() crashes
103        }
104        return;
105    }
106    else
107    {
108        char *line = new char[ LINEBUF_LEN ];
109
110        while ( !lngFile.eof() )
111        {
112            char ch;
113            lngFile.get( line, LINEBUF_LEN );
114            lngFile.get( ch );
115            if ( ( line[ 0 ] != '#' ) && ( line[ 0 ] != ' ' ) )
116            {
117                char *eqpos = NULL;
118                if ( ( eqpos = strchr( line, '=' ) ) != NULL )
119                {
120                    *eqpos = '\0';
121                    string key   = line;
122                    string value = unescapeControls( eqpos + 1 );
123                    (*array)[ key ] = value;
124                }
125            }
126        }
127
128        /*map<string,string>::const_iterator iter;
129        for ( iter=array->begin(); iter != array->end(); iter++ )
130        {
131            cout << "K:" << (*iter).first.c_str()
132                 << " V:" << (*iter).second.c_str() << endl;
133        }*/
134    }
135}
136
137static const char *lfilespec1 = "%sLUCIDE_%s_%s.LNG";
138static const char *lfilespec2 = "%sLUCIDE_%s.LNG";
139static const char *lfilespec3 = "%sLUCIDE.LNG";
140
141void loadLang()
142{
143    if ( langLoaded ) {
144        return;
145    }
146    langLoaded = true;
147
148    char appdir[ _MAX_PATH ];
149    char drive[ _MAX_DRIVE ];
150    char dir[ _MAX_DIR ];
151    _splitpath( __argv[0], drive, dir, NULL, NULL );
152    _makepath( appdir, drive, dir, NULL, NULL );
153
154    langDefault = new map<string,string>;
155    langCurrent = new map<string,string>;
156
157    afbuf lfile( _MAX_PATH );
158
159    snprintf( lfile.buffer, lfile.getSize(), lfilespec2, appdir, "EN" );
160    if ( access( lfile.buffer, F_OK ) == 0 ) {
161        loadLng( langDefault, lfile.buffer, true );
162    }
163    else {
164        snprintf( lfile.buffer, lfile.getSize(), lfilespec3, appdir );
165        loadLng( langDefault, lfile.buffer, true );
166    }
167
168    char *lng = getenv( "LANG" );
169    if ( lng == NULL ) {
170        return;
171    }
172
173    // Find language specifier
174    char *upos = strchr( lng, '_' );
175    if ( upos == NULL ) {
176        return;
177    }
178    int lngSpecLen = upos - lng;
179    if ( lngSpecLen > 2 ) {
180        return;
181    }
182    char lngSpec[ 4 ];
183    memset( lngSpec, 0, sizeof( lngSpec ) );
184    strncpy( lngSpec, lng, lngSpecLen );
185
186    // Find territory specifier
187    char *lrest = upos + 1;
188    char terrSpec[ 4 ];
189    memset( terrSpec, 0, sizeof( terrSpec ) );
190    if ( strlen( lrest ) >= 2 ) {
191        strncpy( terrSpec, lrest, 2 );
192    }
193
194    bool nlsLoaded = false;
195    if ( terrSpec[0] != 0 )
196    {
197        // First, search the file with territory specifier
198        snprintf( lfile.buffer, lfile.getSize(), lfilespec1, appdir, lngSpec, terrSpec );
199        if ( access( lfile.buffer, F_OK ) == 0 ) {
200            // File with territory specifier exist, load it
201            loadLng( langCurrent, lfile.buffer, false );
202            nlsLoaded = true;
203        }
204
205    }
206    if ( !nlsLoaded )
207    {
208        // File with territory specifier not found, load file without territory specifier
209        snprintf( lfile.buffer, lfile.getSize(), lfilespec2, appdir, lngSpec );
210        loadLng( langCurrent, lfile.buffer, false );
211    }
212}
213
214void localizeMenu( HWND hmenu )
215{
216    if ( hmenu == NULLHANDLE ) {
217        return;
218    }
219
220    afbuf mtext( 1024 );
221
222    SHORT id, len;
223    SHORT cnt = (SHORT)WinSendMsg( hmenu, MM_QUERYITEMCOUNT, MPVOID, MPVOID );
224    for ( SHORT i = 0; i < cnt; i++ )
225    {
226        id = (SHORT)WinSendMsg( hmenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT( i ), MPVOID );
227
228        len = (SHORT)WinSendMsg( hmenu, MM_QUERYITEMTEXT, MPFROM2SHORT( id, mtext.getSize() ),
229                                 MPFROMP( mtext.buffer ) );
230
231        if ( len > 0 )
232        {
233            string r = getLocalizedString( mtext.buffer );
234            if ( r != mtext.buffer ) {
235                WinSendMsg( hmenu, MM_SETITEMTEXT, MPFROMSHORT( id ), MPFROMP( r.c_str() ) );
236            }
237        }
238
239        MENUITEM mitem = { 0 };
240        BOOL itemQueried = (BOOL)WinSendMsg( hmenu, MM_QUERYITEM, MPFROM2SHORT( id, FALSE ),
241                                             MPFROMP( &mitem ) );
242        if ( itemQueried )
243        {
244            if ( mitem.afStyle & MIS_SUBMENU ) {
245                localizeMenu( mitem.hwndSubMenu );
246            }
247        }
248    }
249}
250
251void localizeDialog( HWND hdlg )
252{
253    if ( hdlg == NULLHANDLE ) {
254        return;
255    }
256
257    afbuf itemtext( 256 );
258
259    HWND  hwndNext;
260    LONG  lText;
261    HENUM henum = WinBeginEnumWindows( hdlg );
262
263    while ( ( hwndNext = WinGetNextWindow( henum ) ) != NULLHANDLE )
264    {
265        char clname[ 5 ];
266        WinQueryClassName( hwndNext, sizeof( clname ), clname );
267
268        if ( clname[0] == '#' )
269        {
270            lText = WinQueryWindowText( hwndNext, itemtext.getSize(), itemtext.buffer );
271            if ( lText )
272            {
273                string r = getLocalizedString( itemtext.buffer );
274                if ( r != itemtext.buffer )
275                {
276                    if ( clname[1] == '5' ) { // static
277                        if ( WinQueryWindowULong( hwndNext, QWL_STYLE ) & SS_TEXT ) {
278                            toWordWrapLabel( hwndNext );
279                        }
280                    }
281
282                    WinSetWindowText( hwndNext, r.c_str() );
283                }
284            }
285        }
286    }
287    WinEndEnumWindows( henum );
288}
289
290string getLocalizedString( const char *t )
291{
292    map<string,string>::const_iterator iter;
293
294    if ( ( iter = langCurrent->find( t ) ) == langCurrent->end() )
295    {
296        if ( ( iter = langDefault->find( t ) ) == langDefault->end() ) {
297            return t;
298        }
299    }
300
301    return (*iter).second;
302}
303
304void getLocalizedString( const char *key, LONG maxLen, char *buf )
305{
306    strncpy( buf, getLocalizedString( key ).c_str(), maxLen - 1 );
307}
308
309char *newstrdupL( const char *key )
310{
311    return newstrdup( getLocalizedString( key ).c_str() );
312}
313
Note: See TracBrowser for help on using the repository browser.