Changeset 226 for trunk/Components/ACLLanguageUnit.pas
- Timestamp:
- Sep 9, 2007, 1:58:38 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Components/ACLLanguageUnit.pas
r220 r226 1 1 Unit ACLLanguageUnit; 2 3 // NewView - a new OS/2 Help Viewer 4 // Copyright 2003-2006 Aaron Lawrence 5 // Copyright 2006-2007 Ronald Brill (rbri at rbri dot de) 6 // This software is released under the GNU Public License - see readme.txt 7 8 // Helper functions for i18n 2 9 3 10 Interface … … 6 13 OS2Def, 7 14 Classes, 8 Forms; 15 Forms, 16 FileUtilsUnit; 17 18 19 const 20 LANGUAGE_DELIMITER = '_'; 21 LANGUAGE_FILE_EXTENSION = FILE_EXTENSION_DELIMITER + 'lng'; 22 LANGUAGE_COMMENT_CHAR = '#'; 23 LANGUAGE_ENVIRONMENT_VAR_LANG = 'LANG'; 24 LANGUAGE_ENVIRONMENT_VAR_OSDIR = 'OSDIR'; 25 LANGUAGE_ENVIRONMENT_VAR_ULSPATH = 'ULSPATH'; 26 LANGUAGE_DEFAULT_LANGUAGE = 'EN_US'; 27 LANGUAGE_DEFAULT_MARKER = '***'; 28 LANGUAGE_LABEL_DELIMITER = '.'; 29 9 30 10 31 type 11 32 TLanguageItem = record 12 pValue: pstring; 13 Used: boolean; 14 end; 15 TPLanguageItem = ^ TLanguageItem; 33 pValue: pString; 34 wasUsed: boolean; 35 isDefault: boolean; 36 end; 37 TPLanguageItem = ^TLanguageItem; 38 39 TLanguageItemList = class 40 protected 41 translationsList : TStringList; 42 procedure setValueWithFlags(const aLabel : String; const aValue : String; const aDefaultFlag : boolean); 43 public 44 constructor Create; 45 destructor Destroy; override; 46 47 function getValue(const aLabel : String; const aDefaultValue : String) : String; 48 procedure setValue(const aLabel : String; const aValue : String); 49 procedure saveTo(const aTextFile : TextFile); 50 end; 51 16 52 17 53 TLanguageFile = class 18 54 protected 19 FItems: TStringList; 20 FFilename: string; 21 FPrefix: string; 22 23 // only if saving... 24 FOutputFile: TextFile; 25 FSaving: boolean; 26 27 procedure GetValue( const Index: longint; 28 var Value: string ); 29 30 procedure LoadComponentLanguageInternal( Component: TComponent; 31 const Path: string; 32 const DoUpdates: boolean ); 33 34 procedure SaveItem( const Name: string; 35 const Value: string; 36 const Marker: string; ); 55 languageItems : TLanguageItemList; 56 fileName: string; 57 58 procedure LoadComponentLanguageInternal(const aComponent: TComponent; const aPath: string; const aDoUpdates: boolean); 37 59 38 60 public 39 constructor Create( const Filename: string);61 constructor Create(const aFileName : String); 40 62 destructor Destroy; override; 41 63 42 // if DoUpdatesis true, then the component and it's64 // if anApplyFlag is true, then the component and it's 43 65 // owned components will be updated. If false, then 44 66 // it will only be checked and missing items noted. 45 67 46 // Also sets Prefix to name of component with a dot, for convenience 47 // in loading strings manually, related to the component 48 procedure LoadComponentLanguage( Component: TComponent; 49 DoUpdates: boolean ); 50 51 // Starts saving to the file 52 procedure StartUpdate; 53 procedure EndUpdate; 54 55 // Looks for <prefix>.<name> 56 function GetString( const Name: string; 57 const Default: string ): string; 58 59 // If apply is true, then assign S the string called title 60 // Or, if not found, use Default. 61 // If apply is false, just look it up but don't assign to S 62 procedure LL( const Apply: boolean; 63 Var S: string; 64 const Title: string; 65 const Default: string ); 66 67 property Prefix: string read FPrefix write FPrefix; 68 69 end; 68 // For convenience in loading strings manually, related to the component 69 procedure LoadComponentLanguage(aComponent: TComponent; const anApplyFlag: boolean); 70 71 72 // write the current transations to a file 73 procedure writeToFile(const aFileName : String); 74 75 // If anApplyFlag is true, then assign aValue the translation 76 // for aLabel. Or, if not found, use aDefaultValue. 77 // If anApplyFlag is false, just look it up but don't assign to 78 // aValue 79 procedure LL( const anApplyFlag: boolean; 80 Var aValue: string; 81 const aLabel: string; 82 const aDefaultValue: string ); 83 84 end; 85 70 86 71 87 // callback for when language events occur … … 74 90 // saved, so you should access any strings you need, 75 91 // but not actually change anything 76 TLanguageEvent = procedure( Language: TLanguageFile; 77 Apply: boolean ) of object; 92 TLanguageEvent = procedure(aLanguage: TLanguageFile; const anApplyFlag: boolean) of object; 78 93 79 94 // non-object version 80 TLanguageProc = procedure( Language: TLanguageFile;81 Apply: boolean ); 95 TLanguageProc = procedure(aLanguage: TLanguageFile; const anApplyFlag: boolean); 96 82 97 83 98 var 84 99 g_CurrentLanguageFile: TLanguageFile; 85 100 86 // Register that you want to know when the current language changes 87 // Will immediately call you back, if there is a current language 88 procedure RegisterForLanguages( Callback: TLanguageEvent ); 89 90 // Register a procedure callback (not-object) 91 procedure RegisterProcForLanguages( Callback: TLanguageProc ); 92 93 94 // Register a procedure that will be called only when a language file 95 // is being updated (use to load forms if needed) 96 procedure RegisterUpdateProcForLanguages( Callback: TProcedure ); 97 98 99 // Change current language to given, and tell everybody who has registered 100 procedure ApplyLanguage( Language: TLanguageFile ); 101 102 // Tell everybody who has registered to access the given file, 103 // but don't apply strings from it 104 procedure UpdateLanguage( Language: TLanguageFile ); 105 106 // Load a string. 107 // If Language is nil then just assign default. 108 // If apply is true, then assign S the string called title 109 // Or, if not found, use Default. 110 // If apply is false, just look it up but don't assign to S 111 procedure LoadString( Language: TLanguageFile; 112 const Apply: boolean; 113 Var S: string; 114 const Title: string; 115 const Default: string ); 116 117 // Load and apply specified language file 118 procedure LoadLanguage( const FilePath: string ); 119 120 // load a language from the standard location. 121 // AppName is a short name for the app, e.g. 'newview' 122 // language spec is e.g. 'es' or 'es_es' 123 function LoadAutoLanguage( const AppName: string; 124 const LanguageSpec: string ): boolean; 125 126 // load default language based on LANG environment var 127 Procedure LoadDefaultLanguage( const AppName: string ); 101 // Register that you want to know when the current language changes 102 // Will immediately call you back, if there is a current language 103 procedure RegisterEventForLanguages(aCallbackEvent : TLanguageEvent); 104 105 // Register a procedure callback (not-object) 106 procedure RegisterProcForLanguages(aCallbackProc : TLanguageProc); 107 108 109 // Register a procedure that will be called only when a language file 110 // is being updated (use to load forms if needed) 111 procedure RegisterUpdateProcForLanguages(aCallbackProc: TProcedure); 112 113 114 // Change current language to given, and tell everybody who has registered 115 procedure ApplyLanguage(aLanguage: TLanguageFile); 116 117 // Tell everybody who has registered to access the given file, 118 // but don't apply strings from it 119 procedure UpdateLanguage(aLanguage: TLanguageFile); 120 121 122 // Load and apply specified language file 123 procedure LoadLanguage(const aFilePath: String); 124 125 126 // load a language from the standard location. 127 // anAppName is a short name for the app, e.g. 'newview' 128 // language spec is e.g. 'es' or 'es_es' 129 function LoadLanguageForSpec(const anAppName: string; const aLanguageSpec: string): boolean; 130 131 132 // load default language based on LANG environment var 133 procedure LoadDefaultLanguage(const anAppName: string); 134 128 135 129 136 Implementation 130 137 131 138 uses 132 Dos, SysUtils, // system139 Dos, SysUtils, 133 140 StdCtrls, 134 141 Buttons, … … 147 154 g_LanguageUpdateCallbacks: TList; 148 155 156 157 // ----------------- 158 // TLanguageItemList 159 // ----------------- 160 161 constructor TLanguageItemList.Create; 162 begin 163 // LogEvent(LogI18n, 'TLanguageItemList.Create'); 164 // setup our memory 165 translationsList := TStringList.Create; 166 translationsList.Sorted := true; // for lookup speed 167 translationsList.CaseSensitive := true; // also for speed. We manually convert to uppercase. 168 translationsList.Duplicates := dupAccept; 169 end; 170 171 172 destructor TLanguageItemList.Destroy; 173 var 174 i: longint; 175 tmpPLanguageItem: TPLanguageItem; 176 begin 177 // LogEvent(LogI18n, 'TLanguageItemList.Destroy'); 178 for i := 0 to translationsList.Count - 1 do 179 begin 180 tmpPLanguageItem := TPLanguageItem(translationsList.Objects[i]); 181 182 // free the parts of the item 183 DisposeStr(tmpPLanguageItem^.pValue); 184 Dispose(tmpPLanguageItem); 185 end; 186 187 translationsList.Destroy; 188 end; 189 190 191 function TLanguageItemList.getValue(const aLabel : String; const aDefaultValue : String) : String; 192 var 193 tmpPosition : LongInt; 194 tmpFound : Boolean; 195 tmpPLanguageItem : TPLanguageItem; 196 begin 197 tmpFound := translationsList.Find(UpperCase(aLabel), tmpPosition); 198 199 if not tmpFound then 200 begin 201 setValueWithFlags(aLabel, aDefaultValue, true); 202 result := ''; 203 204 // LogEvent(LogI18n, 'TLanguageItemList.getValue(' + aLabel + ') [' + aDefaultValue + ']->' + result); 205 exit; 206 end; 207 208 tmpPLanguageItem := TPLanguageItem(translationsList.Objects[tmpPosition]); 209 210 // mark as used 211 tmpPLanguageItem^.wasUsed := true; 212 213 if tmpPLanguageItem^.isDefault then 214 begin 215 result := ''; 216 217 // LogEvent(LogI18n, 'TLanguageItemList.getValue(' + aLabel + ')->' + result); 218 exit; 219 end; 220 221 result := tmpPLanguageItem^.pValue^; 222 // LogEvent(LogI18n, 'TLanguageItemList.getValue(' + aLabel + ')->' + result); 223 end; 224 225 226 procedure TLanguageItemList.setValue(const aLabel : String; const aValue : String); 227 begin 228 setValueWithFlags(aLabel, aValue, false); 229 end; 230 231 232 procedure TLanguageItemList.setValueWithFlags(const aLabel : String; const aValue : String; const aDefaultFlag : boolean); 233 var 234 tmpPLanguageItem: TPLanguageItem; 235 begin 236 // LogEvent(LogI18n, 'TLanguageItemList.setValueWithFlags(' + aLabel + ')->' + aValue + '[' + BoolToStr(aDefaultFlag) + ']'); 237 238 New(tmpPLanguageItem); 239 tmpPLanguageItem^.pValue := NewStr(aValue); 240 tmpPLanguageItem^.wasUsed := false; 241 tmpPLanguageItem^.isDefault := aDefaultFlag; 242 243 translationsList.AddObject(UpperCase(aLabel), TObject(tmpPLanguageItem)); 244 end; 245 246 247 procedure TLanguageItemList.saveTo(const aTextFile : TextFile); 248 var 249 i : integer; 250 tmpPLanguageItem: TPLanguageItem; 251 tmpLabel : String; 252 tmpQuotedValue : String; 253 tmpUnusedHeaderFlag : boolean; 254 begin 255 // used first 256 for i := 0 to translationsList.Count - 1 do 257 begin 258 tmpPLanguageItem := TPLanguageItem(translationsList.Objects[i]); 259 if tmpPLanguageItem^.wasUsed then 260 begin 261 tmpLabel := translationsList.Names[i]; 262 263 tmpQuotedValue := tmpPLanguageItem^.pValue^; 264 tmpQuotedValue := StrEscapeAllCharsBy(tmpQuotedValue, [], '"'); 265 tmpQuotedValue := StrInDoubleQuotes(tmpQuotedValue); 266 267 if tmpPLanguageItem^.isDefault then 268 begin 269 WriteLn(aTextFile, tmpLabel + ' ' + tmpQuotedValue + ' ' + LANGUAGE_DEFAULT_MARKER); 270 end 271 else 272 begin 273 WriteLn(aTextFile, tmpLabel + ' ' + tmpQuotedValue); 274 end; 275 end; 276 end; 277 278 279 // unused at the end 280 tmpUnusedHeaderFlag := false; 281 for i := 0 to translationsList.Count - 1 do 282 begin 283 tmpPLanguageItem := TPLanguageItem(translationsList.Objects[i]); 284 if not tmpPLanguageItem^.wasUsed then 285 begin 286 if not tmpUnusedHeaderFlag then 287 begin 288 tmpUnusedHeaderFlag := true; 289 290 Writeln(aTextFile, '# **********************************************************'); 291 Writeln(aTextFile, '# * The following items are no longer needed. *'); 292 Writeln(aTextFile, '# * You can delete them after checking they are of no use. *'); 293 Writeln(aTextFile, '# **********************************************************'); 294 end; 295 296 tmpLabel := translationsList.Names[i]; 297 298 tmpQuotedValue := tmpPLanguageItem^.pValue^; 299 tmpQuotedValue := StrEscapeAllCharsBy(tmpQuotedValue, [], '"'); 300 tmpQuotedValue := StrInDoubleQuotes(tmpQuotedValue); 301 302 if tmpPLanguageItem^.isDefault then 303 begin 304 WriteLn(aTextFile, tmpLabel + ' ' + tmpQuotedValue + ' ' + LANGUAGE_DEFAULT_MARKER); 305 end 306 else 307 begin 308 WriteLn(aTextFile, tmpLabel + ' ' + tmpQuotedValue); 309 end; 310 end; 311 end; 312 end; 313 314 315 // ----------------- 316 // TLanguageCallback 317 // ----------------- 318 149 319 Type 150 320 TLanguageCallback = class … … 155 325 end; 156 326 157 constructor TLanguageCallback.CreateMethod( CallbackMethod: TLanguageEvent ); 158 begin 159 FCallbackMethod := CallbackMethod; 160 FCallbackProc := nil; 161 end; 162 163 constructor TLanguageCallback.CreateProc( CallbackProc: TLanguageProc ); 164 begin 165 FCallbackProc := CallbackProc; 166 FCallbackMethod := nil; 167 end; 168 169 procedure AddLanguageCallback( CallbackObject: TLanguageCallback ); 170 begin 171 if g_LanguageCallbacks = nil then 172 g_LanguageCallbacks := TList.Create; 173 174 g_LanguageCallbacks.Add( CallbackObject ); 175 end; 176 177 procedure RegisterForLanguages( Callback: TLanguageEvent ); 178 begin 179 AddLanguageCallback( TLanguageCallback.CreateMethod( Callback ) ); 180 181 if g_CurrentLanguageFile <> nil then 182 Callback( g_CurrentLanguageFile, true ); 183 end; 184 185 procedure RegisterProcForLanguages( Callback: TLanguageProc ); 186 begin 187 AddLanguageCallback( TLanguageCallback.CreateProc( Callback ) ); 188 189 if g_CurrentLanguageFile <> nil then 190 Callback( g_CurrentLanguageFile, true ); 191 end; 192 193 procedure RegisterUpdateProcForLanguages( Callback: TProcedure ); 194 begin 195 if g_LanguageUpdateCallbacks = nil then 196 g_LanguageUpdateCallbacks := TList.Create; 197 198 g_LanguageUpdateCallbacks.Add( TObject( Callback ) ); 199 // since this is for when updating a language only, we don't immediately call it 200 end; 201 202 procedure ApplyLanguage( Language: TLanguageFile ); 203 var 204 i: longint; 205 Callback: TLanguageCallback; 206 begin 207 if g_CurrentLanguageFile <> nil then 208 g_CurrentLanguageFile.Destroy; 209 210 g_CurrentLanguageFile := Language; 211 212 // do language callbacks to everyone 213 for i := 0 to g_LanguageCallbacks.Count - 1 do 214 begin 215 Callback := g_LanguageCallbacks[ i ]; 216 if Assigned( Callback.FCallbackMethod ) then 217 Callback.FCallbackMethod( g_CurrentLanguageFile, true ); 218 if Assigned( Callback.FCallbackProc ) then 219 Callback.FCallbackProc( g_CurrentLanguageFile, true ); 220 end; 221 end; 222 223 procedure UpdateLanguage( Language: TLanguageFile ); 224 var 225 i: longint; 226 Callback: TLanguageCallback; 227 UpdateProc: TProcedure; 228 begin 229 if g_LanguageUpdateCallbacks <> nil then 230 begin 231 // first call all update callbacks so dynamically created 232 // things can be loaded (i.e. forms) 233 // Note: this will cause them to load their strings from 234 // the current language if any. This is fine, necessary even. 235 for i := 0 to g_LanguageUpdateCallbacks.Count - 1 do 236 begin 237 UpdateProc := TProcedure( g_LanguageUpdateCallbacks[ i ] ); 238 UpdateProc; 239 end; 240 end; 241 242 Language.StartUpdate; 243 244 if g_LanguageCallbacks <> nil then 245 begin 246 // now call the language events 327 328 constructor TLanguageCallback.CreateMethod(CallbackMethod: TLanguageEvent); 329 begin 330 FCallbackMethod := CallbackMethod; 331 FCallbackProc := nil; 332 end; 333 334 335 constructor TLanguageCallback.CreateProc(aCallbackProc: TLanguageProc); 336 begin 337 FCallbackProc := CallbackProc; 338 FCallbackMethod := nil; 339 end; 340 341 342 procedure AddLanguageCallback(aCallbackObject: TLanguageCallback); 343 begin 344 if g_LanguageCallbacks = nil then 345 begin 346 g_LanguageCallbacks := TList.Create; 347 end; 348 349 g_LanguageCallbacks.Add(aCallbackObject); 350 end; 351 352 353 procedure RegisterEventForLanguages(aCallbackEvent : TLanguageEvent); 354 begin 355 AddLanguageCallback( TLanguageCallback.CreateMethod(aCallbackEvent) ); 356 357 if g_CurrentLanguageFile <> nil then 358 begin 359 aCallbackEvent(g_CurrentLanguageFile, true); 360 end; 361 end; 362 363 364 procedure RegisterProcForLanguages(aCallbackProc : TLanguageProc); 365 begin 366 AddLanguageCallback( TLanguageCallback.CreateProc(aCallbackProc) ); 367 368 if g_CurrentLanguageFile <> nil then 369 begin 370 aCallbackProc(g_CurrentLanguageFile, true); 371 end; 372 end; 373 374 375 procedure RegisterUpdateProcForLanguages(aCallbackProc: TProcedure); 376 begin 377 if g_LanguageUpdateCallbacks = nil then 378 begin 379 g_LanguageUpdateCallbacks := TList.Create; 380 end; 381 382 g_LanguageUpdateCallbacks.Add(TObject(aCallbackProc)); 383 // since this is for when updating a language only, we don't immediately call it 384 end; 385 386 387 procedure ApplyLanguage(aLanguage: TLanguageFile); 388 var 389 i: longint; 390 tmpCallback: TLanguageCallback; 391 begin 392 if g_CurrentLanguageFile <> nil then 393 begin 394 g_CurrentLanguageFile.Destroy; 395 end; 396 397 g_CurrentLanguageFile := aLanguage; 398 399 // do language callbacks to everyone 247 400 for i := 0 to g_LanguageCallbacks.Count - 1 do 248 401 begin 249 Callback := g_LanguageCallbacks[ i ]; 250 if Assigned( Callback.FCallbackMethod ) then 251 Callback.FCallbackMethod( Language, false ); 252 if Assigned( Callback.FCallbackProc ) then 253 Callback.FCallbackProc( Language, false ); 254 end; 255 end; 256 257 Language.EndUpdate; 258 end; 259 260 constructor TLanguageFile.Create( const Filename: string ); 261 var 262 F: TextFile; 263 tmpLine: string; 264 Name: string; 265 Value: string; 266 pItem: TPLanguageItem; 267 tmpLineParts : TStringList; 268 begin 269 FSaving := false; 270 271 FFilename := Filename; 272 273 FPrefix := ''; 274 275 FItems := TStringList.Create; 276 FItems.Sorted := true; // for lookup speed 277 FItems.CaseSensitive := true; // also for speed. We manually convert to uppercase. 278 FItems.Duplicates := dupAccept; 279 280 if not FileExists( Filename ) then 281 exit; 282 283 FileMode := fmInput; 284 AssignFile( F, Filename ); 285 Reset( F ); 286 287 tmpLineParts := TStringList.Create; 288 289 while not Eof( F ) do 290 begin 291 ReadLn( F, tmpLine); 292 293 tmpLineParts.clear; 294 StrExtractStringsQuoted(tmpLineParts, tmpLine); 295 296 if tmpLineParts.count > 0 then 297 begin 298 Name := tmpLineParts[0]; 299 300 if Name[ 1 ] <> '#' then 301 begin 302 // Got a name, read the value and store. 303 value := ''; 304 if tmpLineParts.count > 0 then 402 tmpCallback := g_LanguageCallbacks[i]; 403 404 if Assigned(tmpCallback.FCallbackMethod) then 405 begin 406 tmpCallback.FCallbackMethod(g_CurrentLanguageFile, true); 407 end; 408 409 if Assigned(tmpCallback.FCallbackProc) then 410 begin 411 tmpCallback.FCallbackProc(g_CurrentLanguageFile, true); 412 end; 413 end; 414 end; 415 416 417 procedure UpdateLanguage(aLanguage: TLanguageFile); 418 var 419 i: longint; 420 tmpCallback : TLanguageCallback; 421 tmpUpdateProc : TProcedure; 422 begin 423 if g_LanguageUpdateCallbacks <> nil then 424 begin 425 // first call all update callbacks so dynamically created 426 // things can be loaded (i.e. forms) 427 // Note: this will cause them to load their strings from 428 // the current language if any. This is fine, necessary even. 429 for i := 0 to g_LanguageUpdateCallbacks.Count - 1 do 430 begin 431 tmpUpdateProc := TProcedure(g_LanguageUpdateCallbacks[i]); 432 tmpUpdateProc; 433 end; 434 end; 435 436 if g_LanguageCallbacks <> nil then 437 begin 438 // now call the language events 439 for i := 0 to g_LanguageCallbacks.Count - 1 do 440 begin 441 tmpCallback := g_LanguageCallbacks[i]; 442 if Assigned(tmpCallback.FCallbackMethod) then 305 443 begin 306 value := tmpLineParts[1];444 tmpCallback.FCallbackMethod(aLanguage, false); 307 445 end; 308 309 New( pItem ); 310 pItem ^. pValue := NewStr( Value ); 311 pItem ^. Used := false; 312 FItems.AddObject( UpperCase( Name ), 313 TObject( pItem ) ); 314 end; 315 end; 316 end; 317 318 tmpLineParts.Destroy; 319 CloseFile( F ); 320 end; 321 322 destructor TLanguageFile.Destroy; 323 var 324 i: longint; 325 pItem: TPLanguageItem; 326 begin 327 for i := 0 to FItems.Count - 1 do 328 begin 329 pItem := TPLanguageItem( FItems.Objects[ i ] ); 330 DisposeStr( pItem ^. pValue ); 331 Dispose( pItem ); 332 end; 333 FItems.Destroy; 334 end; 335 336 procedure TLanguageFile.GetValue( const Index: longint; 337 var Value: string ); 338 var 339 pItem: TPLanguageItem; 340 begin 341 pItem := TPLanguageItem( FItems.Objects[ Index ] ); 342 pItem ^. Used := true; 343 Value := pItem ^. pValue ^; 344 end; 345 346 // Magical procedure that does certain things... 347 // If Apply is true, then it looks up title 348 // and if found, assigns it's value to S 349 // If not found, then assigns Default to S 350 // If Apply is false, then does lookup only, does not assign S 351 // In either case, if the string is not found, 352 // it will be added to missing items list 353 procedure TLanguageFile.LL( const Apply: boolean; 354 Var S: string; 355 const Title: string; 356 const Default: string ); 357 begin 358 if Apply then 359 S := GetString( Title, Default ) 360 else 361 GetString( Title, Default ); 362 end; 363 364 procedure TLanguageFile.LoadComponentLanguage( Component: TComponent; 365 DoUpdates: boolean ); 366 begin 367 LoadComponentLanguageInternal( Component, '', DoUpdates ); 368 Prefix := Component.Name + '.'; 369 end; 370 371 procedure TLanguageFile.StartUpdate; 372 var 373 BackupFilename: string; 374 begin 375 BackupFilename := ChangeFileExt( FFilename, '.bak' ); 376 if FileExists( BackupFilename ) then 377 if not DeleteFile( BackupFilename ) then 378 raise Exception.Create( 'Unable to delete backup language file: ' 379 + BackupFilename ); 380 if FileExists( FFilename ) then 381 // backup 382 if not CopyFile( FFilename, BackupFilename ) then 383 raise Exception.Create( 'Unable to copy to backup language file: ' 384 + BackupFilename ); 385 386 AssignFile( FOutputFile, FFilename ); 387 388 Rewrite( FOutputFile ); 389 390 FSaving := true; 391 end; 392 393 procedure TLanguageFile.EndUpdate; 394 var 395 i: longint; 396 pItem: TPLanguageItem; 397 Notified: boolean; 398 begin 399 Notified := false; 400 401 for i := 0 to FItems.Count - 1 do 402 begin 403 pItem := TPLanguageItem( FItems.Objects[ i ] ); 404 if not pItem ^. Used then 405 begin 406 if not Notified then 407 begin 408 Writeln( FOutputFile, 409 '# *** The following items are no longer needed.' ); 410 Writeln( FOutputFile, 411 '# You can delete them after checking they are of no use.' ); 412 Notified := true; 413 end; 414 415 SaveItem( '# ' + FItems[ i ], 416 pItem ^. pValue^, 417 '' ); 418 end; 419 end; 420 421 FSaving := false; 422 CloseFile( FOutputFile ); 423 end; 424 425 procedure TLanguageFile.SaveItem( const Name: string; 426 const Value: string; 427 const Marker: string ); 428 429 var 430 tmpQuotedValue : string; 431 begin 432 tmpQuotedValue := StrEscapeAllCharsBy(Value, [], '"'); 433 tmpQuotedValue := StrInDoubleQuotes(tmpQuotedValue); 434 WriteLn( FOutputFile, Name + ' ' + tmpQuotedValue + ' ' + Marker ); 435 end; 436 437 procedure TLanguageFile.LoadComponentLanguageInternal( Component: TComponent; 438 const Path: string; 439 const DoUpdates: boolean ); 440 var 441 i : longint; 442 ComponentPath: string; 443 Value: string; 444 445 MenuItem: TMenuItem; 446 Button: TButton; 447 TheLabel: TLabel; 448 RadioGroup: TRadioGroup; 449 TabSet: TTabSet; 450 TabbedNotebook: TTabbedNotebook; 451 Form: TForm; 452 RadioButton: TRadioButton; 453 CheckBox: TCheckBox; 454 CoolBar2: TCoolBar2; 455 GroupBox: TGroupBox; 456 MultiColumnListBox: TMultiColumnListBox; 457 SystemOpenDialog: TSystemOpenDialog; 458 SystemSaveDialog: TSystemSaveDialog; 459 460 // searches for componentpath + name, sets value if found 461 function FindIt( const Name: string; 462 const Default: string ): boolean; 463 var 464 Index: longint; 465 begin 466 result := FItems.Find( UpperCase( ComponentPath + Name ), Index ); 467 468 if result then 469 begin 470 GetValue( Index, Value ); 471 if FSaving then 472 // save the specified value 473 SaveItem( ComponentPath + Name, Value, '' ); 446 if Assigned(tmpCallback.FCallbackProc) then 447 begin 448 tmpCallback.FCallbackProc(aLanguage, false); 449 end; 450 end; 451 end; 452 end; 453 454 455 constructor TLanguageFile.Create( const aFileName : String); 456 var 457 tmpTextFile : TextFile; 458 tmpLine : string; 459 tmpLabel : string; 460 tmpValue : string; 461 tmpLineParts : TStringList; 462 begin 463 filename := aFileName; 464 465 languageItems := TLanguageItemList.Create; 466 467 if not FileExists(aFileName) then 468 begin 469 exit; 470 end; 471 472 // read the file 473 FileMode := fmInput; 474 AssignFile(tmpTextFile, aFileName); 475 Reset(tmpTextFile); 476 477 tmpLineParts := TStringList.Create; 478 479 while not Eof(tmpTextFile) do 480 begin 481 ReadLn(tmpTextFile, tmpLine); 482 483 tmpLineParts.clear; 484 StrExtractStringsQuoted(tmpLineParts, tmpLine); 485 486 if tmpLineParts.count > 0 then 487 begin 488 tmpLabel := tmpLineParts[0]; 489 490 // TODO trim leading blanks 491 if tmpLabel[1] <> LANGUAGE_COMMENT_CHAR then 492 begin 493 // Got a name, read the value and store. 494 tmpValue := ''; 495 if tmpLineParts.count > 0 then 496 begin 497 tmpValue := tmpLineParts[1]; 498 end; 499 500 languageItems.setValue(UpperCase(tmpLabel), tmpValue); 501 end; 502 end; 503 end; 504 505 tmpLineParts.Destroy; 506 CloseFile(tmpTextFile); 507 end; 508 509 510 destructor TLanguageFile.Destroy; 511 begin 512 languageItems.Destroy; 513 end; 514 515 516 procedure TLanguageFile.LL( const anApplyFlag: boolean; 517 Var aValue: string; 518 const aLabel: string; 519 const aDefaultValue: string ); 520 begin 521 // LogEvent(LogI18n, 'TLanguageFile.LL(' + BoolToStr(Apply) + ')'); 522 523 if anApplyFlag then 524 begin 525 aValue := languageItems.getValue(UpperCase(aLabel), aDefaultValue) 474 526 end 475 527 else 476 528 begin 477 if FSaving then 478 // save the default. 479 SaveItem( ComponentPath + Name, Default, '***' ); 480 end; 481 482 if result then 483 // found 484 if not DoUpdates then 485 // not doing updates, so pretend we didn't, so we don't apply it 486 // (this is a local hack only) 487 result := false; 488 end; 489 490 Begin 491 ComponentPath := Path + Component.Name + '.'; 492 493 // Components sorted with most common at top, ish... 494 495 if Component is TMenuItem then 496 begin 497 MenuItem := TMenuItem( Component ); 498 if MenuItem.Caption <> '-' then 499 begin 529 languageItems.getValue(UpperCase(aLabel), aDefaultValue) 530 end 531 end; 532 533 534 procedure TLanguageFile.LoadComponentLanguage(aComponent: TComponent; const anApplyFlag: boolean); 535 begin 536 LoadComponentLanguageInternal(aComponent, '', anApplyFlag); 537 end; 538 539 540 procedure TLanguageFile.writeToFile(const aFileName : String); 541 var 542 tmpBackupFilename: string; 543 tmpFile: TextFile; 544 begin 545 tmpBackupFilename := ChangeFileExt(aFileName, '.bak' ); 546 if FileExists(tmpBackupFilename) then 547 begin 548 if not DeleteFile(tmpBackupFilename) then 549 begin 550 raise Exception.Create( 'Unable to delete backup language file: ' + tmpBackupFilename); 551 end; 552 end; 553 554 if FileExists(aFileName) then 555 begin 556 if not CopyFile(aFileName, tmpBackupFilename ) then 557 begin 558 raise Exception.Create( 'Unable to copy to backup language file: ' + tmpBackupFilename); 559 end; 560 end; 561 562 AssignFile(tmpFile, aFileName); 563 ReWrite(tmpFile); 564 565 languageItems.saveTo(tmpFile); 566 567 CloseFile(tmpFile); 568 end; 569 570 procedure TLanguageFile.LoadComponentLanguageInternal(const aComponent: TComponent; const aPath: string; const aDoUpdates: boolean); 571 var 572 i : longint; 573 tmpComponentPath: string; 574 tmpValue: string; 575 576 tmpMenuItem: TMenuItem; 577 tmpButton: TButton; 578 tmpLabel: TLabel; 579 tmpRadioGroup: TRadioGroup; 580 tmpTabSet: TTabSet; 581 tmpTabbedNotebook: TTabbedNotebook; 582 tmpForm: TForm; 583 tmpRadioButton: TRadioButton; 584 tmpCheckBox: TCheckBox; 585 tmpCoolBar2: TCoolBar2; 586 tmpGroupBox: TGroupBox; 587 tmpMultiColumnListBox: TMultiColumnListBox; 588 tmpSystemOpenDialog: TSystemOpenDialog; 589 tmpSystemSaveDialog: TSystemSaveDialog; 590 Begin 591 tmpComponentPath := aPath + aComponent.Name + LANGUAGE_LABEL_DELIMITER; 592 593 // Components sorted with most common at top, ish... 594 if aComponent is TMenuItem then 595 begin 596 tmpMenuItem := TMenuItem(aComponent); 597 500 598 // skip separators 501 if FindIt( 'Caption', MenuItem.Caption ) then 502 MenuItem.Caption := Value; 503 if FindIt( 'Hint', MenuItem.Hint ) then 504 MenuItem.Hint := Value; 505 end; 506 end 507 508 else if Component is TButton then 509 begin 510 Button := TButton( Component ); 511 if FindIt( 'Caption', Button.Caption ) then 512 Button.Caption := Value; 513 if FindIt( 'Hint', Button.Hint ) then 514 Button.Hint := Value; 515 end 516 517 else if Component is TLabel then 518 begin 519 TheLabel := TLabel( Component ); 520 if FindIt( 'Caption', TheLabel.Caption ) then 521 TheLabel.Caption := Value; 522 if FindIt( 'Hint', TheLabel.Hint ) then 523 TheLabel.Hint := Value; 524 end 525 526 else if Component is TRadioGroup then 527 begin 528 RadioGroup := TRadioGroup( Component ); 529 if FindIt( 'Caption', RadioGroup.Caption ) then 530 RadioGroup.Caption := Value; 531 for i := 0 to RadioGroup.Items.Count - 1 do 532 if FindIt( 'Item' + IntToStr( i ), 533 RadioGroup.Items[ i ] ) then 534 RadioGroup.Items[ i ] := Value; 535 end 536 537 else if Component is TTabSet then 538 begin 539 TabSet := TTabSet( Component ); 540 for i := 0 to TabSet.Tabs.Count - 1 do 541 if FindIt( 'Tab' + IntToStr( i ), 542 TabSet.Tabs[ i ] ) then 543 TabSet.Tabs[ i ] := Value; 544 end 545 546 else if Component is TTabbedNotebook then 547 begin 548 TabbedNotebook := TTabbedNotebook( Component ); 549 for i := 0 to TabbedNotebook.Pages.Count - 1 do 550 begin 551 if FindIt( 'Tab' + IntToStr( i ) + '.Caption', 552 TabbedNotebook.Pages[ i ] ) then 553 TabbedNotebook.Pages[ i ] := Value; 554 555 if FindIt( 'Tab' + IntToStr( i ) + '.Hint', 556 TabbedNotebook.Pages.Pages[ i ].Hint ) then 557 TabbedNotebook.Pages.Pages[ i ].Hint := Value; 558 end; 559 end 560 561 else if Component is TForm then 562 begin 563 Form := TForm( Component ); 564 if FindIt( 'Caption', Form.Caption ) then 565 Form.Caption := Value; 566 567 // load owned controls 568 for i := 0 to Component.ComponentCount - 1 do 569 LoadComponentLanguageInternal( Component.Components[ i ], 570 ComponentPath, 571 DoUpdates ); 572 573 end 574 575 else if Component is TRadioButton then 576 begin 577 RadioButton := TRadioButton( Component ); 578 if FindIt( 'Caption', RadioButton.Caption ) then 579 RadioButton.Caption := Value; 580 if FindIt( 'Hint', RadioButton.Hint ) then 581 RadioButton.Hint := Value; 582 end 583 584 else if Component is TCheckBox then 585 begin 586 CheckBox := TCheckBox( Component ); 587 if FindIt( 'Caption', CheckBox.Caption ) then 588 CheckBox.Caption := Value; 589 if FindIt( 'Hint', CheckBox.Hint ) then 590 CheckBox.Hint := Value; 591 end 592 593 else if Component is TCoolBar2 then 594 begin 595 CoolBar2 := TCoolBar2( Component ); 596 for i := 0 to CoolBar2.Sections.Count - 1 do 597 begin 598 if FindIt( 'Item' + IntToStr( i ), 599 CoolBar2.Sections[ i ].Text ) then 600 CoolBar2.Sections[ i ].Text := Value; 601 // if FindIt( 'Hint' + IntToStr( i ) ) then 602 // TCoolBar2( Component ).Sections[ i ].Hint := Value; 603 end; 604 end 605 606 else if Component is TGroupBox then 607 begin 608 GroupBox := TGroupBox( Component ); 609 if FindIt( 'Caption', GroupBox.Caption ) then 610 GroupBox.Caption := Value; 611 if FindIt( 'Hint', GroupBox.Hint ) then 612 GroupBox.Hint := Value; 613 end 614 else if Component is TMultiColumnListBox then 615 begin 616 MultiColumnListBox := TMultiColumnListBox( Component ); 617 for i := 0 to MultiColumnListBox.HeaderColumns.Count - 1 do 618 if FindIt( 'Column' + IntToStr( i ), 619 MultiColumnListBox.HeaderColumns[ i ].Text ) then 620 MultiColumnListBox.HeaderColumns[ i ].Text := Value; 621 end 622 else if Component is TSystemOpenDialog then 623 begin 624 SystemOpenDialog := TSystemOpenDialog( Component ); 625 if FindIt( 'OKName', SystemOpenDialog.OKName ) then 626 SystemOpenDialog.OKName := Value; 627 if FindIt( 'Title', SystemOpenDialog.Title ) then 628 SystemOpenDialog.Title := Value; 629 end 630 else if Component is TSystemSaveDialog then 631 begin 632 SystemSaveDialog := TSystemSaveDialog( Component ); 633 if FindIt( 'OKName', SystemSaveDialog.OKName ) then 634 SystemSaveDialog.OKName := Value; 635 if FindIt( 'Title', SystemSaveDialog.Title ) then 636 SystemSaveDialog.Title := Value; 637 638 end; 639 640 end; 641 642 function TLanguageFile.GetString( const Name: string; 643 const Default: string ): string; 644 var 645 Index: longint; 646 Found: boolean; 647 begin 648 Found := FItems.Find( UpperCase( Prefix + Name ), Index ); 649 650 if Found then 651 begin 652 GetValue( Index, Result ); 653 if FSaving then 654 SaveItem( Prefix + Name, Result, '' ); 655 end 656 else 657 begin 658 Result := Default; 659 if FSaving then 660 SaveItem( Prefix + Name, Default, '***' ); 661 end; 662 663 end; 664 665 procedure LoadString( Language: TLanguageFile; 666 const Apply: boolean; 667 Var S: string; 668 const Title: string; 669 const Default: string ); 670 begin 671 if Language = nil then 672 begin 673 if Apply then 674 begin 675 S := Default 676 end 677 end 678 else 679 begin 680 Language.LL( Apply, S, Title, Default ); 681 end; 682 end; 683 684 procedure LoadLanguage( const FilePath: string ); 685 var 686 NewLanguage: TLanguageFile; 687 begin 688 try 689 NewLanguage := TLanguageFile.Create( FilePath ); 690 except 691 exit; 692 end; 693 694 ApplyLanguage( NewLanguage ); 695 696 end; 697 698 function LoadAutoLanguage( const AppName: string; 699 const LanguageSpec: string ): boolean; 700 var 701 FilePath: string; 702 Filename: string; 703 OSDir: string; 704 begin 705 // Filenames loaded will be <AppName>.<Language>.lng 706 Filename := AppName 707 + '_' 708 + LanguageSpec 709 + '.lng'; 710 711 // eCS 1.1+ look in x:\ecs\lang 712 OSDir := GetEnv( 'OSDIR' ); 713 if OSDir <> '' then 714 begin 715 FilePath := AddDirectorySeparator( OSDir ) 716 + 'lang\' 717 + Filename; 718 if FileExists( FilePath ) then 719 begin 720 LoadLanguage( FilePath ); 599 if tmpMenuItem.Caption <> '-' then 600 begin 601 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpMenuItem.Caption); 602 if '' <> tmpValue then tmpMenuItem.Caption := tmpValue; 603 604 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpMenuItem.Hint); 605 if '' <> tmpValue then tmpMenuItem.Hint := tmpValue; 606 end; 607 end 608 609 else if aComponent is TButton then 610 begin 611 tmpButton := TButton(aComponent); 612 613 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpButton.Caption); 614 if '' <> tmpValue then tmpButton.Caption := tmpValue; 615 616 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpButton.Hint); 617 if '' <> tmpValue then tmpButton.Hint := tmpValue; 618 end 619 620 else if aComponent is TLabel then 621 begin 622 tmpLabel := TLabel(aComponent); 623 624 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpLabel.Caption); 625 if '' <> tmpValue then tmpLabel.Caption := tmpValue; 626 627 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpLabel.Hint); 628 if '' <> tmpValue then tmpLabel.Hint := tmpValue; 629 end 630 631 else if aComponent is TRadioGroup then 632 begin 633 tmpRadioGroup := TRadioGroup(aComponent); 634 635 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpRadioGroup.Caption); 636 if '' <> tmpValue then tmpRadioGroup.Caption := tmpValue; 637 638 for i := 0 to tmpRadioGroup.Items.Count - 1 do 639 begin 640 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Item' + IntToStr(i)), tmpRadioGroup.Items[i]); 641 if '' <> tmpValue then tmpRadioGroup.Items[i] := tmpValue; 642 end; 643 end 644 645 else if aComponent is TTabSet then 646 begin 647 tmpTabSet := TTabSet(aComponent); 648 649 for i := 0 to tmpTabSet.Tabs.Count - 1 do 650 begin 651 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Tab' + IntToStr(i)), tmpTabSet.Tabs[i]); 652 if '' <> tmpValue then tmpTabSet.Tabs[i] := tmpValue; 653 end; 654 end 655 656 else if aComponent is TTabbedNotebook then 657 begin 658 tmpTabbedNotebook := TTabbedNotebook(aComponent); 659 for i := 0 to tmpTabbedNotebook.Pages.Count - 1 do 660 begin 661 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Tab' + IntToStr(i) + '.Caption'), tmpTabbedNotebook.Pages[i]); 662 if '' <> tmpValue then tmpTabbedNotebook.Pages[i] := tmpValue; 663 664 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Tab' + IntToStr(i) + '.Hint'), tmpTabbedNotebook.Pages.Pages[i].Hint); 665 if '' <> tmpValue then tmpTabbedNotebook.Pages.Pages[i].Hint := tmpValue; 666 end; 667 end 668 669 else if aComponent is TForm then 670 begin 671 tmpForm := TForm(aComponent); 672 673 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpForm.Caption); 674 if '' <> tmpValue then tmpForm.Caption := tmpValue; 675 676 // load owned controls 677 for i := 0 to aComponent.ComponentCount - 1 do 678 begin 679 LoadComponentLanguageInternal(aComponent.Components[i], tmpComponentPath, aDoUpdates ); 680 end; 681 end 682 683 else if aComponent is TRadioButton then 684 begin 685 tmpRadioButton := TRadioButton(aComponent); 686 687 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpRadioButton.Caption); 688 if '' <> tmpValue then tmpRadioButton.Caption := tmpValue; 689 690 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpRadioButton.Hint); 691 if '' <> tmpValue then tmpRadioButton.Hint := tmpValue; 692 end 693 694 else if aComponent is TCheckBox then 695 begin 696 tmpCheckBox := TCheckBox(aComponent); 697 698 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpCheckBox.Caption); 699 if '' <> tmpValue then tmpCheckBox.Caption := tmpValue; 700 701 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpCheckBox.Hint); 702 if '' <> tmpValue then tmpCheckBox.Hint := tmpValue; 703 end 704 705 else if aComponent is TCoolBar2 then 706 begin 707 tmpCoolBar2 := TCoolBar2(aComponent); 708 for i := 0 to tmpCoolBar2.Sections.Count - 1 do 709 begin 710 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Item' + IntToStr(i)), tmpCoolBar2.Sections[i].Text); 711 if '' <> tmpValue then tmpCoolBar2.Sections[i].Text := tmpValue; 712 end; 713 end 714 715 else if aComponent is TGroupBox then 716 begin 717 tmpGroupBox := TGroupBox(aComponent); 718 719 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Caption'), tmpGroupBox.Caption); 720 if '' <> tmpValue then tmpGroupBox.Caption := tmpValue; 721 722 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Hint'), tmpGroupBox.Hint); 723 if '' <> tmpValue then tmpGroupBox.Hint := tmpValue; 724 end 725 726 else if aComponent is TMultiColumnListBox then 727 begin 728 tmpMultiColumnListBox := TMultiColumnListBox(aComponent); 729 730 for i := 0 to tmpMultiColumnListBox.HeaderColumns.Count - 1 do 731 begin 732 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Column' + IntToStr(i)), tmpMultiColumnListBox.HeaderColumns[i].Text); 733 if '' <> tmpValue then tmpMultiColumnListBox.HeaderColumns[i].Text := tmpValue; 734 end; 735 end 736 737 else if aComponent is TSystemOpenDialog then 738 begin 739 tmpSystemOpenDialog := TSystemOpenDialog(aComponent); 740 741 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'OKName'), tmpSystemOpenDialog.OKName); 742 if '' <> tmpValue then tmpSystemOpenDialog.OKName := tmpValue; 743 744 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Title'), tmpSystemOpenDialog.Title); 745 if '' <> tmpValue then tmpSystemOpenDialog.Title := tmpValue; 746 end 747 748 else if aComponent is TSystemSaveDialog then 749 begin 750 tmpSystemSaveDialog := TSystemSaveDialog(aComponent); 751 752 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'OKName'), tmpSystemSaveDialog.OKName); 753 if '' <> tmpValue then tmpSystemSaveDialog.OKName := tmpValue; 754 755 tmpValue := languageItems.getValue(UpperCase(tmpComponentPath + 'Title'), tmpSystemSaveDialog.Title); 756 if '' <> tmpValue then tmpSystemSaveDialog.Title := tmpValue; 757 end; 758 end; 759 760 761 procedure LoadLanguage(const aFilePath: String); 762 var 763 tmpNewLanguage: TLanguageFile; 764 begin 765 LogEvent(LogI18n, 'LoadLanguage(' + aFilePath + ')'); 766 try 767 tmpNewLanguage := TLanguageFile.Create(aFilePath); 768 except 769 // TODO more log output 770 exit; 771 end; 772 773 ApplyLanguage(tmpNewLanguage); 774 end; 775 776 777 function LoadLanguageForSpec(const anAppName: string; const aLanguageSpec: string) : boolean; 778 var 779 tmpFilePath: string; 780 tmpFileName: string; 781 tmpOSDir: string; 782 begin 783 // Filenames loaded will be <AppName>.<Language>.lng 784 tmpFilename := anAppName + LANGUAGE_DELIMITER + aLanguageSpec + LANGUAGE_FILE_EXTENSION; 785 786 // eCS 1.1+ look in x:\ecs\lang 787 tmpOSDir := GetEnv(LANGUAGE_ENVIRONMENT_VAR_OSDIR); 788 if tmpOSDir <> '' then 789 begin 790 tmpFilePath := AddDirectorySeparator(tmpOSDir) + 'lang\' + tmpFileName; 791 if FileExists(tmpFilePath) then 792 begin 793 LoadLanguage(tmpFilePath); 794 result := true; 795 exit; 796 end; 797 end; 798 799 // something or rather, maybe: look in %ULSPATH% 800 if SearchPath(LANGUAGE_ENVIRONMENT_VAR_ULSPATH, tmpFilename, tmpFilepath ) then 801 begin 802 LoadLanguage(tmpFilePath); 721 803 result := true; 722 804 exit; 723 805 end; 724 end; 725 726 // something or rather, maybe: look in %ULSPATH% 727 if SearchPath( 'ULSPATH', 728 Filename, 729 Filepath ) then 730 begin 731 LoadLanguage( FilePath ); 732 result := true; 733 exit; 734 end; 735 736 // Standalone/compatibility: look in own dir 737 FilePath := GetApplicationDir 738 + Filename; 739 740 if FileExists( FilePath ) then 741 begin 742 LoadLanguage( FilePath ); 743 result := true; 744 exit; 745 end; 746 747 Result := false; 748 end; 749 750 Procedure LoadDefaultLanguage( const AppName: string ); 751 var 752 LanguageVar: string; 753 MajorLanguage: string; 754 MinorLanguage: string; 755 tmpParts : TStringList; 756 757 begin 758 LanguageVar := GetEnv( 'LANG' ); 759 LogEvent(LogI18n, 'LANG=' + LanguageVar); 760 761 if LanguageVar = '' then 762 begin 763 LanguageVar := 'EN_US'; 764 end; 765 766 tmpParts := TStringList.Create; 767 StrExtractStrings(tmpParts, LanguageVar, ['_'], #0); 768 769 MajorLanguage := ''; 770 if tmpParts.count > 0 then 771 begin 772 MajorLanguage := tmpParts[0]; 773 end; 774 775 // note there might be some other stuff on the end of LANG 776 // such as ES_ES_EURO... 777 778 if tmpParts.count > 1 then 779 begin 780 MinorLanguage := tmpParts[1]; 781 782 LogEvent(LogI18n, 'try loading ' + MajorLanguage + '_' + MinorLanguage); 783 if LoadAutoLanguage(AppName, MajorLanguage + '_' + MinorLanguage) then 784 begin 785 // found a specifc language 786 LogEvent(LogI18n, ' translation for ' + MajorLanguage + '_' + MinorLanguage + ' sucessfully loaded'); 806 807 // Standalone/compatibility: look in own dir 808 tmpFilePath := GetApplicationDir + tmpFileName; 809 810 if FileExists(tmpFilePath) then 811 begin 812 LoadLanguage(tmpFilePath); 813 result := true; 814 exit; 815 end; 816 817 result := false; 818 end; 819 820 821 Procedure LoadDefaultLanguage(const anAppName: string); 822 var 823 tmpLanguageVar: string; 824 tmpMajorLanguage: string; 825 tmpMinorLanguage: string; 826 tmpParts : TStringList; 827 828 begin 829 tmpLanguageVar := GetEnv(LANGUAGE_ENVIRONMENT_VAR_LANG); 830 LogEvent(LogI18n, LANGUAGE_ENVIRONMENT_VAR_LANG + '=' + tmpLanguageVar); 831 832 if tmpLanguageVar = '' then 833 begin 834 tmpLanguageVar := DEFAULT_LANGUAGE; 835 end; 836 837 tmpParts := TStringList.Create; 838 StrExtractStrings(tmpParts, tmpLanguageVar, ['_'], #0); 839 840 tmpMajorLanguage := ''; 841 if tmpParts.count > 0 then 842 begin 843 tmpMajorLanguage := tmpParts[0]; 844 end; 845 846 // note there might be some other stuff on the end of LANG 847 // such as ES_ES_EURO... 848 849 if tmpParts.count > 1 then 850 begin 851 tmpMinorLanguage := tmpParts[1]; 852 853 LogEvent(LogI18n, 'try loading ' + tmpMajorLanguage + '_' + tmpMinorLanguage); 854 if LoadLanguageForSpec(anAppName, tmpMajorLanguage + '_' + tmpMinorLanguage) then 855 begin 856 // found a specifc language 857 LogEvent(LogI18n, ' translation for ' + tmpMajorLanguage + '_' + tmpMinorLanguage + ' sucessfully loaded'); 858 tmpParts.Destroy; 859 exit; 860 end; 861 end; 862 863 // try generic language? 864 LogEvent(LogI18n, 'try loading (major only) ' + tmpMajorLanguage); 865 if LoadLanguageForSpec(anAppName, tmpMajorLanguage) then 866 begin 867 LogEvent(LogI18n, 'translation for ''' + tmpMajorLanguage + ''' sucessfully loaded'); 787 868 tmpParts.Destroy; 788 869 exit; 789 870 end; 790 end; 791 792 // try generic language? 793 LogEvent(LogI18n, 'try loading (major only) ' + MajorLanguage); 794 if LoadAutoLanguage( AppName, MajorLanguage ) then 795 begin 796 LogEvent(LogI18n, 'translation for ' + MajorLanguage + 'sucessfully loaded'); 797 tmpParts.Destroy; 798 exit; 799 end; 800 801 LogEvent(LogI18n, 'No language found, using default ' + MajorLanguage); 802 LoadLanguage( '' ); 803 804 tmpParts.Destroy; 805 end; 806 807 808 Initialization 809 g_LanguageCallbacks := nil; 810 g_CurrentLanguageFile := nil; 811 812 Finalization 813 DestroyListAndObjects( g_LanguageCallbacks ); 814 if g_LanguageUpdateCallbacks <> nil then 815 g_LanguageUpdateCallbacks.Destroy; 871 872 LogEvent(LogI18n, 'No language found, using default ' + tmpMajorLanguage); 873 LoadLanguage(''); 874 875 tmpParts.Destroy; 876 end; 877 878 879 Initialization 880 g_LanguageCallbacks := nil; 881 g_CurrentLanguageFile := nil; 882 g_LanguageUpdateCallbacks := nil; 883 884 885 Finalization 886 DestroyListAndObjects(g_LanguageUpdateCallbacks); 887 DestroyListAndObjects(g_LanguageCallbacks); 888 if nil <> g_CurrentLanguageFile then g_CurrentLanguageFile.Destroy; 816 889 817 890 End.
Note:
See TracChangeset
for help on using the changeset viewer.