Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > многоязычный интерфейс


Автор: namra 17.11.2008, 21:16
Здравствуйте у меня такая проблема есть код перевода интерфейса программы, как мне его записать в отдельный unit  и подключать к каждой форме через uses, чтобы не загромождать кодом формы.
Код перевода
Код

 procedure ChangeLang(LangSection: string);
var
  // временная числовая переменная для выборки всех компонентов
  i: Integer;
  LangIniFile: TIniFile;
  // строковая переменная для получения каталога, где находится запущенный EXE файл
  ProgramPath: string;
begin
  // если в окне больше одного компонента
  if ComponentCount <> 0 then 
  begin
    // получаем каталог, где лежит запущенный EXE файл
    ProgramPath := ExtractFileDir(Application.ExeName);
    // гарантированно устанавливаем последний символ '\' в конце строки
    if ProgramPath[Length(ProgramPath)] <> '\' then
      ProgramPath := ProgramPath + '\';
    // подготавливаем INI файл. Он должен иметь название lang.ini
    // и должен находиться в каталоге программы
    LangIniFile:=TIniFile.Create(ProgramPath+'lang.ini');
    // читаем заголовок окна
    Caption:=LangIniFile.ReadString(LangSection,name,Caption);
    // перебираем все компоненты в этом окне
    for i:=1 to ComponentCount do
    begin
      // если выбран из массива компонент Button, то изменяем текст на кнопке
      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Caption);

      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).hint := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Hint);
      // аналогично для других типов:
      if Components[i-1].ClassType = TMenuItem then
        (Components[i-1] as TMenuItem).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TMenuItem).Caption);

      if Components[i-1].ClassType = TLabel then
        (Components[i-1] as TLabel).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TLabel).Caption);
      if Components[i-1].ClassType = TEdit then
        (Components[i-1] as TEdit).Text := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TEdit).Text);
    end;
    LangIniFile.Free; // освобождаем ресурс
  end;
end;

Автор: Akella 17.11.2008, 23:19
для таких вопросов

Цитата(namra @  17.11.2008,  21:16 Найти цитируемый пост)
как мне его записать в отдельный unit


Цитата(namra @  17.11.2008,  21:16 Найти цитируемый пост)
подключать к каждой форме через uses

есть раздел Delphi для новичков

Добавлено через 2 минуты и 1 секунду
 smile О и ещё, заметил вот что. Название темы
Цитата
многоязычный интерфейс

ну никак не относиться к твое1 проблеме

Добавлено через 3 минуты и 43 секунды
namra, в IDE же есть команда: File->New, выбери там новый unit и вставишь свой код в него.

А в остальных модулях проекта просто в uses добавишь имя нового модуля.

Автор: namra 18.11.2008, 00:03
Создал Unit запихал код выдал: Очень нужно может кто опишет где это описать и что исправить

Код

unit trans;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,IniFiles, Menus;

implementation
 procedure ChangeLang(LangSection: string);
var
  // временная числовая переменная для выборки всех компонентов
  i: Integer;
  LangIniFile: TIniFile;
  // строковая переменная для получения каталога, где находится запущенный EXE файл
  ProgramPath: string;
begin
  // если в окне больше одного компонента
  if ComponentCount <> 0 then 
  begin
    // получаем каталог, где лежит запущенный EXE файл
    ProgramPath := ExtractFileDir(Application.ExeName);
    // гарантированно устанавливаем последний символ '\' в конце строки
    if ProgramPath[Length(ProgramPath)] <> '\' then
      ProgramPath := ProgramPath + '\';
    // подготавливаем INI файл. Он должен иметь название lang.ini
    // и должен находиться в каталоге программы
    LangIniFile:=TIniFile.Create(ProgramPath+'lang.ini');
    // читаем заголовок окна
    Caption:=LangIniFile.ReadString(LangSection,name,Caption);
    // перебираем все компоненты в этом окне
    for i:=1 to ComponentCount do
    begin
      // если выбран из массива компонент Button, то изменяем текст на кнопке
      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Caption);

      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).hint := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Hint);
      // аналогично для других типов:
      if Components[i-1].ClassType = TMenuItem then
        (Components[i-1] as TMenuItem).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TMenuItem).Caption);

    end;
    LangIniFile.Free; // освобождаем ресурс
  end;
end;
end.




выдал ошибки

Код

[Error] trans.pas(18): Undeclared identifier: 'ComponentCount'
[Warning] trans.pas(18): Comparing signed and unsigned types - widened both operands
[Error] trans.pas(29): Undeclared identifier: 'Caption'
[Error] trans.pas(29): Undeclared identifier: 'name'
[Error] trans.pas(34): Undeclared identifier: 'Components'
[Error] trans.pas(34): 'THEN' expected but identifier 'ClassType' found
[Error] trans.pas(38): 'THEN' expected but identifier 'ClassType' found
[Error] trans.pas(42): 'THEN' expected but identifier 'ClassType' found
[Error] trans.pas(53): Statement expected but end of file found
[Fatal Error] Unit1.pas(7): Could not compile used unit 'trans.pas'

Автор: remax 18.11.2008, 00:39
Проще использовать один Unit, а перевод осуществлять специальными средствами, например JvTranslator из библиотеки JEDI.  

Автор: Bose 18.11.2008, 02:00
замени текст на такой:
Код

unit trans;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,IniFiles, Menus;
procedure ChangeLang(LangSection: string;aForm:TForm);
implementation
 procedure ChangeLang(LangSection: string;aForm:TForm);
var
  // временная числовая переменная для выборки всех компонентов
  i: Integer;
  LangIniFile: TIniFile;
  // строковая переменная для получения каталога, где находится запущенный EXE файл
  ProgramPath: string;
begin
  // если в окне больше одного компонента
  with aForm do
  if ComponentCount <> 0 then 
  begin
    // получаем каталог, где лежит запущенный EXE файл
    ProgramPath := ExtractFileDir(Application.ExeName);
    // гарантированно устанавливаем последний символ '\' в конце строки
    if ProgramPath[Length(ProgramPath)] <> '\' then
      ProgramPath := ProgramPath + '\';
    // подготавливаем INI файл. Он должен иметь название lang.ini
    // и должен находиться в каталоге программы
    LangIniFile:=TIniFile.Create(ProgramPath+'lang.ini');
    // читаем заголовок окна
    Caption:=LangIniFile.ReadString(LangSection,name,Caption);
    // перебираем все компоненты в этом окне
    for i:=1 to ComponentCount do
    begin
      // если выбран из массива компонент Button, то изменяем текст на кнопке
      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Caption);
      if Components[i-1].ClassType = TButton then
        (Components[i-1] as TButton).hint := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TButton).Hint);
      // аналогично для других типов:
      if Components[i-1].ClassType = TMenuItem then
        (Components[i-1] as TMenuItem).Caption := LangIniFile.ReadString(LangSection,
        name+Components[i-1].name, (Components[i-1] as TMenuItem).Caption);
    end;
    LangIniFile.Free; // освобождаем ресурс
  end;
end;
end.


При вызове передавай в процедуру ещё и экземпляр формы. Например
Код

ChangeLang('Section1',Form1);


Автор: namra 18.11.2008, 22:24
Bose спасибо огромное помогло! smile   smile 

Автор: ecspertiza 19.11.2008, 12:31
Могу посоветовать прогу Delphi localization compiler специально для локализации приложений на дельфах, я сам ей интерфейс на другой язык переводил, в месте с ней обычно и демка есть посмотришь разберёсяsmile

Автор: Akella 20.11.2008, 11:47
А разве в самой IDE нет возможности реализовать многоязычный интерфейс, я когда-то читал, что можно, только не занимался этим.

Добавлено через 4 минуты и 17 секунд
namra, смотри, помоему тебе неплохой пример, тоже перевод с использованием текстовых файлов:
http://www.codenet.ru/progr/delphi/stat/multilang.php

Автор: ecspertiza 20.11.2008, 12:28
В самой IDE можно реализовать многоязычный интерфейс тока ето геморой и нечнго больше,
Зачем изобретать велосипед, кто нить скачал Delphi localization compiler и посмотрел что ето такое? Если прога состоит из 30 форм, и языков надо не 2 а 6, то пользуясь примером http://www.codenet.ru/progr/delphi/stat/multilang.php, скока будет длится загрузка да и смена интерфейса будет возможна тока при перезагрузке, говорю для локализации или интернационализации на Delphi качайте прогу Delphi localization compiler, там всё просто, есть к ней описание, и демка.

Автор: Akella 20.11.2008, 15:14
ecspertiza, я не понял, как с ним работать,  smile

Добавлено через 30 секунд
честно говоря я и не шибко вдавался в изучение сей программы

Автор: ecspertiza 20.11.2008, 15:33
Там всё просто, включаешь прогу, зате File->new, выбираешь *.exe своей программы,  она подгружает всё что может перевести, затем идёт процесс перевода(руками правда) на требуемый язык, затем Save and Compile (в папку с проектом), в программе подключаем модуль LcUnit.pas(идёт вместе с программой), потом в программе пишем
Код

function LcCallBack( iLCID : integer; pUd : pointer ) : integer; stdcall;
begin
  with TLanguages.Create
  do  begin
      TForm1( pUd ).Combobox1.Items.AddObject( NameFromLocaleID[ iLCID ],
        pointer( iLCID ) );
      Free;
      end;
  result := 1;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  iEngUsLCID : LCID;
begin
  iEngUsLCID := LANG_ENGLISH + SUBLANG_ENGLISH_US shl 10 + SORT_DEFAULT shl 16; { US English LCID }
  if LoadLcf( ChangeFileExt( ParamStr( 0 ), '.lcf' ), iEngUsLCID,
    Addr( LcCallBack ), Self ) = 1
  then  ComboBox1.ItemIndex := ComboBox1.Items.
    IndexOfObject( pointer( iEngUsLCID ) );
  TranslateComponent( Self );
end; //для загрузки языка при загрузке программы

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  LoadLcf( ChangeFileExt( ParamStr( 0 ), '.lcf' ),
    LCID( ComboBox1.Items.Objects[ ComboBox1.ItemIndex ] ), nil, nil );
  Caption := FORMCAPTION;
  TranslateComponent( Self );
end; // для загрузки я зыка при изменения Выпадающего списка


на самом деле всё просто, по ней в инете есть мануал тока поискать требо.

зрите в аттаче, сама прога, небольшой HELP, Demka и модуль smile 

Автор: Bose 20.11.2008, 17:10
ecspertiza, а она умеет дополнять существующий перевод?

И исходники закрыты. 


На самом деле решений для перевода полным полно. Вот только многие из них не умеют переводить все как надо. Некоторые не умеют переводить ресурсы, другие не умеют переводить свойства нестандартных компонент. Третьи уvt.n переводить всё, но для переключения языка приходится перезапускать программу. 
И чем их все рассматривать, проще написать своё, или модифицировать готовое опен-сорсное. Хотя бы тот же JvTranslator. Хотя JvTranslator насколько я помню тоже не умеет переводить resourcestrings.

Автор: ecspertiza 20.11.2008, 17:45
Bose , насчёт этого невкурсе, за собой перевод дополняет, а вот если он ещё как нить сделан то незнаю.

И ешё у етой проги проблема с месаджами, к ним надо придумывать что то своё.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)