Difference between revisions of "automatic translation of forms/es"

From Lazarus wiki
Jump to navigationJump to search
(Intento de que aparezcan los códigos en recuadro)
(Intento de que aparezcan los códigos en recuadro)
Line 1: Line 1:
  
== '''COMO UTILIZAR LA TRADUCCION AUTOMATICA SIN TANTO DOLOR!''' ==
+
'''COMO UTILIZAR LA TRADUCCION AUTOMATICA SIN TANTO DOLOR!'''
  
  
Line 7: Line 7:
 
1) Deben agregar a su proyecto este archivo llamado Traductor.pas (o como quieran llamarlo)
 
1) Deben agregar a su proyecto este archivo llamado Traductor.pas (o como quieran llamarlo)
  
<math>
+
<nowiki>
 
unit Traductor;
 
unit Traductor;
  
Line 290: Line 290:
  
 
end.
 
end.
</math>
+
</nowiki>
  
 
2) Luego deben activar la traducción automática del Lazarus en Opciones de Proyecto -> i18n. Donde deben indicar que la carpeta donde se almacenarán las traducciones se llame "Languages". Claro que deben crear esa carpeta luego.
 
2) Luego deben activar la traducción automática del Lazarus en Opciones de Proyecto -> i18n. Donde deben indicar que la carpeta donde se almacenarán las traducciones se llame "Languages". Claro que deben crear esa carpeta luego.
Line 307: Line 307:
  
  
== '''PARA TRADUCIR CONSTANTES DE CARACTERES QUE NO SE ENCUENTRAN EN LOS FORMULARIOS''' ==
+
'''PARA TRADUCIR CONSTANTES DE CARACTERES QUE NO SE ENCUENTRAN EN LOS FORMULARIOS'''
  
  
Line 316: Line 316:
 
2) Crear dentro de la unidad una sección "resourcestrings" y colocar dentro los mensajes a utilizar. Ej.:
 
2) Crear dentro de la unidad una sección "resourcestrings" y colocar dentro los mensajes a utilizar. Ej.:
  
<math>
+
<nowiki>
 
unit Constantes;
 
unit Constantes;
  
Line 329: Line 329:
  
 
end.
 
end.
</math>
+
</nowiki>
  
 
3) Para utilizar estas constantes, sólo deben utilizarse como si fueran constantes normales. Ej.:
 
3) Para utilizar estas constantes, sólo deben utilizarse como si fueran constantes normales. Ej.:
  
<math>
+
<nowiki>
 
   MessageDlg(SSaludo, mtInformation, [mbOk], 0);
 
   MessageDlg(SSaludo, mtInformation, [mbOk], 0);
 
   MessageDlg(SDespedida, mtInformation, [mbOk], 0);
 
   MessageDlg(SDespedida, mtInformation, [mbOk], 0);
</math>
+
</nowiki>
  
 
4) Como penultimo paso deben indicar que desean traducir esta unidad, para lo cual deben agregar un código de inicialización a la unidad creada:
 
4) Como penultimo paso deben indicar que desean traducir esta unidad, para lo cual deben agregar un código de inicialización a la unidad creada:
  
<math>
+
<nowiki>
 
unit Constantes;
 
unit Constantes;
  
Line 363: Line 363:
  
 
end.
 
end.
</math>
+
</nowiki>
  
 
4) Como último paso deben agregar esta unidad "Constantes" a su archivo lpr, tomando el recaudo de colocarlo luego de la unidad "Traductor", porque de no ser así "TranslateResourceStrings" dará un "Access Violation".
 
4) Como último paso deben agregar esta unidad "Constantes" a su archivo lpr, tomando el recaudo de colocarlo luego de la unidad "Traductor", porque de no ser así "TranslateResourceStrings" dará un "Access Violation".
  
<math>
+
<nowiki>
 
   ...
 
   ...
 
   Traductor, // Tiene que estar antes que Constantes
 
   Traductor, // Tiene que estar antes que Constantes
 
   Constantes,
 
   Constantes,
 
   ...
 
   ...
</math>
+
</nowiki>
  
 
5) Ya está, disfruten.....
 
5) Ya está, disfruten.....

Revision as of 15:32, 19 December 2009

COMO UTILIZAR LA TRADUCCION AUTOMATICA SIN TANTO DOLOR!


Sigan estos sencillos pasos:

1) Deben agregar a su proyecto este archivo llamado Traductor.pas (o como quieran llamarlo)

unit Traductor; { Original of V.I.Volchenko and Lazarus Developers Team Modified by Oscar Flor (Delphino) from DefaultTranstator.pas to use po files. Enhancements will be very appreciated } {$mode objfpc}{$H+} interface uses Classes, SysUtils, LResources, Translations, Controls, typinfo, FileUtil, LCLProc; type { TDefaultTranslator } TDefaultTranslator = class(TAbstractTranslator) private FPOFile: TPOFile; public constructor Create(POFileName: string); destructor Destroy; override; procedure TranslateStringProperty(Sender: TObject; const Instance: TPersistent; PropInfo: PPropInfo; var Content: string); override; procedure TranslateUnitResourceStrings(UnitName : string); property POFile : TPOFile read FPOFile; end; implementation function FindLocaleFileName: string; var Lang, T: string; i: integer; function GetLocaleFileName(const LangID: string): string; var LangShortID: string; begin if LangID <> EmptyStr then begin //ParamStrUTF8(0) is said not to work properly in linux, but I've tested it Result := ExtractFilePath(ParamStrUTF8(0)) + LangID + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'languages' + DirectorySeparator + LangID + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + LangID + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + LangID + DirectorySeparator + 'LC_MESSAGES' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; {$IFDEF UNIX} //In unix-like systems we can try to search for global locale Result := '/usr/share/locale/' + LangID + '/LC_MESSAGES/' + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; {$ENDIF} //Let us search for reducted files LangShortID := copy(LangID, 1, 2); //At first, check all was checked Result := ExtractFilePath(ParamStrUTF8(0)) + LangShortID + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'languages' + DirectorySeparator + LangShortID + DirectorySeparator + ChangeFileExt( ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + LangShortID + DirectorySeparator + ChangeFileExt( ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + LangID + DirectorySeparator + 'LC_MESSAGES' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; //Full language in file name - this will be default for the project //We need more carefull handling, as it MAY result in incorrect filename try Result := ExtractFilePath(ParamStrUTF8(0)) + ChangeFileExt( ExtractFileName(ParamStrUTF8(0)), '.' + LangID) + '.po'; if FileExistsUTF8(Result) then Exit; //Common location (like in Lazarus) Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.' + LangID) + '.po'; if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'languages' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.' + LangID) + '.po'; if FileExistsUTF8(Result) then Exit; except Result := EmptyStr;//Or do something else (useless) end; // try {$IFDEF UNIX} Result := '/usr/share/locale/' + LangShortID + '/LC_MESSAGES/' + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.po'); if FileExistsUTF8(Result) then Exit; {$ENDIF} Result := ExtractFilePath(ParamStrUTF8(0)) + ChangeFileExt( ExtractFileName(ParamStrUTF8(0)), '.' + LangShortID) + '.po'; if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'locale' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.' + LangShortID) + '.po'; if FileExistsUTF8(Result) then Exit; Result := ExtractFilePath(ParamStrUTF8(0)) + 'languages' + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.' + LangShortID) + '.po'; if FileExistsUTF8(Result) then Exit; end; Result := EmptyStr; end; begin Result := EmptyStr; T:=EmptyStr; //Win32 user may decide to override locale with LANG variable. Lang := GetEnvironmentVariableUTF8('LANG'); if Lang = '' then begin for i := 1 to Paramcount - 1 do if (ParamStrUTF8(i) = '--LANG') or (ParamStrUTF8(i) = '-l') or (ParamStrUTF8(i) = '--lang') then Lang := ParamStrUTF8(i + 1); end; // if if Lang = EmptyStr then LCLGetLanguageIDs(Lang, T); Result := GetLocaleFileName(Lang); if Result <> EmptyStr then Exit; Result := ChangeFileExt(ParamStrUTF8(0), '.po'); if FileExistsUTF8(Result) then Exit; Result := EmptyStr; end; { TDefaultTranslator } constructor TDefaultTranslator.Create(POFileName: string); begin inherited Create; FPOFile := TPOFile.Create(UTF8ToSys(POFileName)); end; destructor TDefaultTranslator.Destroy; begin FPOFile.Free; //If someone will use this class incorrectly, it can be destroyed //before Reader destroying. It is a very bad thing, but in THIS situation //in this case is impossible. May be, in future we can overcome this difficulty inherited Destroy; end; procedure TDefaultTranslator.TranslateStringProperty(Sender: TObject; const Instance: TPersistent; PropInfo: PPropInfo; var Content: string); var s: string; Section: string; Component: TComponent; begin if not Assigned(FPOFile) then Exit; if not Assigned(PropInfo) then Exit; // do not translate at design time if Instance is TComponent then if csDesigning in (Instance as TComponent).ComponentState then Exit; if (UpperCase(PropInfo^.PropType^.Name) <> 'TTRANSLATESTRING') then Exit; s := FPOFile.Translate('', Content); if s = '' then begin Component := Instance as TComponent; if Component.Owner <> nil then Section := UpperCase(Component.Owner.Name) + '.'; Section := 'T' + Section + UpperCase(Component.Name) + '.' + UpperCase(PropInfo^.Name); s := FPOFile.Translate('', Section + #4 + Content); end; if s <> EmptyStr then Content := s; end; procedure TDefaultTranslator.TranslateUnitResourceStrings(UnitName: string); begin Translations.TranslateUnitResourceStrings(UnitName, FPOFile); end; var lcfn: string; initialization //It is safe to place code here as no form is initialized before unit //initialization made //We are to search for all try lcfn := FindLocaleFileName; except lcfn := EmptyStr; end; // try LRSTranslator := TDefaultTranslator.Create(lcfn); finalization LRSTranslator.Free; end.

2) Luego deben activar la traducción automática del Lazarus en Opciones de Proyecto -> i18n. Donde deben indicar que la carpeta donde se almacenarán las traducciones se llame "Languages". Claro que deben crear esa carpeta luego.

3) Agregen "Traductor.pas" a la lista de "uses" de su archivo ".lpr".

4) Abran todos los formularios que tengan y háganle algún cambio pequeño como para que deban ser guardados nuevamente.

5) Compilen su aplicación.

6) Esto debió haber creado un archivo en la carpeta "Languages" con el mismo nombre que su aplicación pero con extensión ".po".

7) Utilizando alguna herramienta de traducción de archivos .po (yo utilicé POEdit), deben generar los otros archivos de idiomas que deseen soportar. Ya saben "save as...". Los archivos deben tener la siguiente forma "<nombre de aplicación>.<idioma>.po". Ej.: MiAplicacion.es.po (para español), MiAplicacion.en.po (para inglés). Claro que deben ingresar en cada archivo y traducir los textos que se encuentren en los ítems llamados "msgstr" tomando como referencia lo escrito en "msgid".

8) En este lugar la próxima vez que ejecuten su aplicación ya deberían aparecer los textos traducidos, tomando como base el idioma de su sistema operativo. Si quiere probar los otros idiomas debe escribir en la línea de comando "--LANG <idioma>" indicando el idioma que desee probar. Ej.: MiAplicación.exe --LANG en (Para inglés).


PARA TRADUCIR CONSTANTES DE CARACTERES QUE NO SE ENCUENTRAN EN LOS FORMULARIOS


Esta técnica explicada sólo funciona para traducir los formularios, los mensajes escritos en los programas deben ser traducidos de otra forma, la cual sería:

1) Crear una nueva unidad que contendrá las constantes de caracteres para mensajes. Ej.: Constantes.

2) Crear dentro de la unidad una sección "resourcestrings" y colocar dentro los mensajes a utilizar. Ej.:

unit Constantes; interface resourcestrings SSaludo = 'Hola que hacés'; SDespedida = 'Un placer haber hablado contigo, saludos a la flía.'; implementation end.

3) Para utilizar estas constantes, sólo deben utilizarse como si fueran constantes normales. Ej.:

MessageDlg(SSaludo, mtInformation, [mbOk], 0); MessageDlg(SDespedida, mtInformation, [mbOk], 0);

4) Como penultimo paso deben indicar que desean traducir esta unidad, para lo cual deben agregar un código de inicialización a la unidad creada:

unit Constantes; interface resourcestrings SSaludo = 'Hola que hacés'; SDespedida = 'Un placer haber hablado contigo, saludos a la flía.'; implementation { Traduce los resourcestrings } procedure TranslateResourceStrings; begin TDefaultTranslator(LRSTranslator).TranslateUnitResourceStrings('Constantes'); end; initialization TranslateResourceStrings end.

4) Como último paso deben agregar esta unidad "Constantes" a su archivo lpr, tomando el recaudo de colocarlo luego de la unidad "Traductor", porque de no ser así "TranslateResourceStrings" dará un "Access Violation".

... Traductor, // Tiene que estar antes que Constantes Constantes, ...

5) Ya está, disfruten.....