aboutsummaryrefslogblamecommitdiffstats
path: root/unicode/src/base/ULanguage.pas
blob: a89ded2d8955a12991974a589be0b1cc8acc8100 (plain) (tree)




































                                                                        

                                                  


                        
                                                      

      

                                                
                   
           

                                     





                                                                     
                         








                                                                                           








                          



           

       


                                                             
























                                                                        
                                  













                                                                                   


                                                






                                                

                                                       






                                                

                              


                      



                                                               

























                                                                




                                                                                               
   
                 
     























                                                                              
                 




                        

             





                                      
 





                                     


                                                        





                                      

    



                                                                                 





                                         



                                                                              












                               



                                                                          




                     
                               












                                       
{* UltraStar Deluxe - Karaoke Game
 *
 * UltraStar Deluxe is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *}

unit ULanguage;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}

type
  TLanguageEntry = record
    ID:     AnsiString;  //**< identifier (ASCII)
    Text:   UTF8String;  //**< translation (UTF-8)
  end;

  TLanguageList = record
    Name:     AnsiString;  //**< language name (ASCII)
  end;

  TLanguageEntryArray = array of TLanguageEntry;

  TLanguage = class
    private
      List:   array of TLanguageList;

      Entry:  TLanguageEntryArray; //**< Entrys of Chosen Language
      SEntry: TLanguageEntryArray; //**< Entrys of Standard Language
      CEntry: TLanguageEntryArray; //**< Constant Entrys e.g. Version

      Implode_Glue1, Implode_Glue2: UTF8String;

      procedure LoadList;
      function FindID(const ID: AnsiString; const EntryList: TLanguageEntryArray): integer;

    public
      constructor Create;
      function Translate(const Text: UTF8String): UTF8String;
      procedure ChangeLanguage(const Language: AnsiString);
      procedure AddConst(const ID: AnsiString; const Text: UTF8String);
      procedure ChangeConst(const ID: AnsiString; const Text: UTF8String);
      function Implode(const Pieces: array of UTF8String): UTF8String;
  end;

var
  Language:     TLanguage;

implementation

uses
  UMain,
  UIni,
  IniFiles,
  Classes,
  SysUtils,
  ULog;

{**
 * LoadList, set default language, set standard implode glues
 *}
constructor TLanguage.Create;
var
  I, J: Integer;
begin
  inherited;

  LoadList;

  //Set Implode Glues for Backward Compatibility
  Implode_Glue1 := ', ';
  Implode_Glue2 := ' and ';

  if (Length(List) = 0) then //No Language Files Loaded -> Abort Loading
    Log.CriticalError('Could not load any Language File');

  //Standard Language (If a Language File is Incomplete)
  //Then use English Language
  for I := 0 to high(List) do //Search for English Language
  begin
    //English Language Found -> Load
    if Uppercase(List[I].Name) = 'ENGLISH' then
    begin
      ChangeLanguage('English');

      SetLength(SEntry, Length(Entry));
      for J := 0 to high(Entry) do
        SEntry[J] := Entry[J];

      SetLength(Entry, 0);
      
      Break;
    end;

    if (I = high(List)) then
      Log.LogError('English Languagefile missing! No standard Translation loaded');
  end;
  //Standard Language END
  
end;

{**
 * Parse the Language Dir searching Translations
 *}
procedure TLanguage.LoadList;
var
  SR:     TSearchRec;   // for parsing directory
begin
  SetLength(List, 0);
  SetLength(ILanguage, 0);

  if FindFirst(LanguagesPath + '*.ini', 0, SR) = 0 then
  begin
    repeat
      SetLength(List, Length(List)+1);
      SetLength(ILanguage, Length(ILanguage)+1);
      SR.Name := ChangeFileExt(SR.Name, '');

      List[High(List)].Name := SR.Name;
      ILanguage[High(ILanguage)] := SR.Name;
    until (FindNext(SR) <> 0);
    SysUtils.FindClose(SR);
  end; // if FindFirst
end;

{**
 * Load the specified LanguageFile
 *}
procedure TLanguage.ChangeLanguage(const Language: AnsiString);
var
  IniFile:    TIniFile;
  E:          integer; // entry
  S:          TStringList;
begin
  SetLength(Entry, 0);
  IniFile := TIniFile.Create(LanguagesPath + Language + '.ini');
  S := TStringList.Create;

  IniFile.ReadSectionValues('Text', S);
  SetLength(Entry, S.Count);
  for E := 0 to high(Entry) do
  begin
    if S.Names[E] = 'IMPLODE_GLUE1' then
      Implode_Glue1 := S.ValueFromIndex[E]+ ' '
    else if S.Names[E] = 'IMPLODE_GLUE2' then
      Implode_Glue2 := ' ' + S.ValueFromIndex[E] + ' ';

    Entry[E].ID := S.Names[E];
    Entry[E].Text := S.ValueFromIndex[E];
  end;

  S.Free;
  IniFile.Free;
end;

{**
 * Find the index of ID an array of language entries.
 * @returns the index on success, -1 otherwise.
 *}
function TLanguage.FindID(const ID: AnsiString; const EntryList: TLanguageEntryArray): integer;
var
  Index: integer;
begin
  for Index := 0 to High(EntryList) do
  begin
    if ID = EntryList[Index].ID then
    begin
      Result := Index;
      Exit;
    end;
  end;
  Result := -1;
end;

{**
 * Translate the Text.
 * If Text is an ID, text will be translated according to the current language
 * setting. If Text is not a known ID, it will be returned as is. 
 * @param Text either an ID or an UTF-8 encoded string 
 *}
function TLanguage.Translate(const Text: UTF8String): UTF8String;
var
  E:  integer; // entry
  ID: AnsiString;
  EntryIndex: integer;
begin
  // fallback result in case Text is not a known ID
  Result := Text;

  // normalize ID case
  ID := UpperCase(Text);

  // Check if ID exists

  //Const Mod
  EntryIndex := FindID(ID, CEntry);
  if (EntryIndex >= 0) then
  begin
    Result := CEntry[EntryIndex].Text;
    Exit;
  end;

  EntryIndex := FindID(ID, Entry);
  if (EntryIndex >= 0) then
  begin
    Result := Entry[EntryIndex].Text;
    Exit;
  end;

  //Standard Language (If a Language File is Incomplete)
  //Then use Standard Language
  EntryIndex := FindID(ID, SEntry);
  if (EntryIndex >= 0) then
  begin
    Result := SEntry[EntryIndex].Text;
    Exit;
  end;
end;

{**
 * Add a Constant ID that will be Translated but not Loaded from the LanguageFile
 *}
procedure TLanguage.AddConst(const ID: AnsiString; const Text: UTF8String);
begin
  SetLength (CEntry, Length(CEntry) + 1);
  CEntry[high(CEntry)].ID := ID;
  CEntry[high(CEntry)].Text := Text;
end;

{**
 * Change a Constant Value by ID
 *}
procedure TLanguage.ChangeConst(const ID: AnsiString; const Text: UTF8String);
var
  I: Integer;
begin
  for I := 0 to high(CEntry) do
  begin
    if CEntry[I].ID = ID then
    begin
     CEntry[I].Text := Text;
     Break;
    end;
  end;
end;

{**
 * Connect an array of strings with ' and ' or ', ' to one string
 *}
function TLanguage.Implode(const Pieces: array of UTF8String): UTF8String;
var
  I: Integer;
begin
  Result := '';
  //Go through Pieces
  for I := 0 to high(Pieces) do
  begin
    //Add Value
    Result := Result + Pieces[I];

    //Add Glue
    if (I < high(Pieces) - 1) then
      Result := Result + Implode_Glue1
    else if (I < high(Pieces)) then
      Result := Result + Implode_Glue2;
  end;
end;

end.