default.po
with all the texts to be translated. Because it has no translations in it, it is named a “translation template”. You should download poEdit and use this program to translate the messages in the po file.locale
folder: Put the default.mo
file in C:\my\program\path\locale\##\LC_MESSAGES\default.mo
(assuming the application is located in C:\my\program\path\myprogram.exe
). In this path, represents the two-letter language code that you can find in the Section called ISO 639 language codes in the appendix called Standards.UseLanguage()
. For example: UseLanguage('es'); // es = Spanish
This line is added earlier in the project, for example:
program Project1; uses gnugettext in 'gnugettext.pas', Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin // Add extra domain for runtime library translations AddDomainForResourceString ('delphi'); // Force program to use Danish instead of the current Windows settings UseLanguage ('da'); // Put ignores on the properties that cannot be translated TP_GlobalIgnoreClassProperty (TMyComponent1,'property1'); TP_GlobalIgnoreClassProperty (TMyComponent2,'property2'); TP_GlobalIgnoreClassProperty (TMyComponent3,'property3'); TP_GlobalIgnoreClassProperty (TMyComponent4,'property4'); Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.
// Localization: force to use Locale System Default so all text is displayed correctly // to fix Delphi7 bug (see Bug Report 2460: http://qc.borland.com/wc/qcmain.aspx?d=2460) // Not so much an issue with Latin characters, but with Cyrillic (Russian) characters. // For full list of locales, open registry HKEY_CLASSES_ROOT\MIME\DataBase\Rfc1766 //ShowMessage(format('GetThreadLocale = %d, GetSystemDefaultLCID = %d, GetUserDefaultLCID = %d', // [GetThreadLocale, GetSystemDefaultLCID, GetUserDefaultLCID])); SetThreadLocale(LOCALE_SYSTEM_DEFAULT); // same as SetThreadLocale($0419);
program UTF8Test; {%File 'MissingMethods-incomplete.txt'} // used by UTF8 {%File 'MissingWindowMessages-incomplete.txt'} // used by UTF8 uses ShareMem, UTF8VCLMessages in 'UTF8VCLMessages.pas', UTF8VCL in 'UTF8VCL.pas', UTF8VCLUtils in 'UTF8VCLUtils.pas', UTF8VCLControls in 'UTF8VCLControls.pas', Forms, TestForm in 'TestForm.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.
Then add the following to the form needing UTF8 support:
uses UTF8VCL;
OnFormCreate
event in every form in the project: TranslateComponent (self);
TranslatedComponent(self)
function. Comment out the classes or properties not used in the current form or unit: //-------------------------------------- // VCL, important ones //-------------------------------------- TP_GlobalIgnoreClassProperty(TAction,'Category'); TP_GlobalIgnoreClassProperty(TControl,'HelpKeyword'); TP_GlobalIgnoreClassProperty(TNotebook,'Pages'); //-------------------------------------- // VCL, not so important //-------------------------------------- // These are normally not needed. TP_GlobalIgnoreClassProperty(TControl,'ImeName'); TP_GlobalIgnoreClass(TFont); //-------------------------------------- // Database (DB unit) //-------------------------------------- // Field names and table names often tend to have names that are also used // for other purposes elsewhere in the program. Therefore, it is very wise // to add this somewhere in your program if you are using databases. TP_GlobalIgnoreClassProperty(TField,'DefaultExpression'); TP_GlobalIgnoreClassProperty(TField,'FieldName'); TP_GlobalIgnoreClassProperty(TField,'KeyFields'); TP_GlobalIgnoreClassProperty(TField,'DisplayName'); TP_GlobalIgnoreClassProperty(TField,'LookupKeyFields'); TP_GlobalIgnoreClassProperty(TField,'LookupResultField'); TP_GlobalIgnoreClassProperty(TField,'Origin'); TP_GlobalIgnoreClass(TParam); TP_GlobalIgnoreClassProperty(TFieldDef,'Name'); //-------------------------------------- // MIDAS/Datasnap //-------------------------------------- TP_GlobalIgnoreClassProperty(TClientDataset,'CommandText'); TP_GlobalIgnoreClassProperty(TClientDataset,'Filename'); TP_GlobalIgnoreClassProperty(TClientDataset,'Filter'); TP_GlobalIgnoreClassProperty(TClientDataset,'IndexFieldnames'); TP_GlobalIgnoreClassProperty(TClientDataset,'IndexName'); TP_GlobalIgnoreClassProperty(TClientDataset,'MasterFields'); TP_GlobalIgnoreClassProperty(TClientDataset,'Params'); TP_GlobalIgnoreClassProperty(TClientDataset,'ProviderName'); //-------------------------------------- // Database controls //-------------------------------------- TP_GlobalIgnoreClassProperty(TDBComboBox,'DataField'); TP_GlobalIgnoreClassProperty(TDBCheckBox,'DataField'); TP_GlobalIgnoreClassProperty(TDBEdit,'DataField'); TP_GlobalIgnoreClassProperty(TDBImage,'DataField'); TP_GlobalIgnoreClassProperty(TDBListBox,'DataField'); TP_GlobalIgnoreClassProperty(TDBLookupControl,'DataField'); TP_GlobalIgnoreClassProperty(TDBLookupControl,'KeyField'); TP_GlobalIgnoreClassProperty(TDBLookupControl,'ListField'); TP_GlobalIgnoreClassProperty(TDBMemo,'DataField'); TP_GlobalIgnoreClassProperty(TDBRadioGroup,'DataField'); TP_GlobalIgnoreClassProperty(TDBRichEdit,'DataField'); TP_GlobalIgnoreClassProperty(TDBText,'DataField'); //-------------------------------------- // Interbase Express (IBX) //-------------------------------------- TP_GlobalIgnoreClass(TIBDatabase); TP_GlobalIgnoreClass(TIBDatabase); TP_GlobalIgnoreClass(TIBTransaction); TP_GlobalIgnoreClassProperty(TIBSQL,'UniqueRelationName'); //-------------------------------------- // Borland Database Engine //-------------------------------------- TP_GlobalIgnoreClass(TSession); TP_GlobalIgnoreClass(TDatabase); //-------------------------------------- // ADO components //-------------------------------------- TP_GlobalIgnoreClass (TADOConnection); TP_GlobalIgnoreClassProperty(TADOQuery,'CommandText'); TP_GlobalIgnoreClassProperty(TADOQuery,'ConnectionString'); TP_GlobalIgnoreClassProperty(TADOQuery,'DatasetField'); TP_GlobalIgnoreClassProperty(TADOQuery,'Filter'); TP_GlobalIgnoreClassProperty(TADOQuery,'IndexFieldNames'); TP_GlobalIgnoreClassProperty(TADOQuery,'IndexName'); TP_GlobalIgnoreClassProperty(TADOQuery,'MasterFields'); TP_GlobalIgnoreClassProperty(TADOTable,'IndexFieldNames'); TP_GlobalIgnoreClassProperty(TADOTable,'IndexName'); TP_GlobalIgnoreClassProperty(TADOTable,'MasterFields'); TP_GlobalIgnoreClassProperty(TADOTable,'TableName'); TP_GlobalIgnoreClassProperty(TADODataset,'CommandText'); TP_GlobalIgnoreClassProperty(TADODataset,'ConnectionString'); TP_GlobalIgnoreClassProperty(TADODataset,'DatasetField'); TP_GlobalIgnoreClassProperty(TADODataset,'Filter'); TP_GlobalIgnoreClassProperty(TADODataset,'IndexFieldNames'); TP_GlobalIgnoreClassProperty(TADODataset,'IndexName'); TP_GlobalIgnoreClassProperty(TADODataset,'MasterFields'); //-------------------------------------- // ActiveX stuff //-------------------------------------- TP_GlobalIgnoreClass (TWebBrowser); //-------------------------------------- // Other //-------------------------------------- TP_GlobalIgnoreClassProperty(TwwKeyCombo,'Text'); TP_GlobalIgnoreClassProperty(TdxBarManager, 'Categories'); // TdxBarManager prop generates memory leak TP_GlobalIgnoreClassProperty(TdxBarManager, 'IniFileName'); // TdxBarManager prop generates memory leak TP_GlobalIgnoreClassProperty(TdxBarManager, 'RegistryPath'); // TdxBarManager prop generates memory leak
Perform the following steps to automate the build process of localization. These steps assume the existence of translation files translation-default.po
and translation-ignore.po
:
default.po
file. C:\> msg
msgid
entries in default.po
. C:\> msguniq -o output.po default.po
msguniq
utility, by using poStripAllCR.exe
(custom application). poStripAllCR.exe
will strip unnecessary carriage returns (CR) characters that break '#: filename:line
' lines.C:\> msgmerge -o output.po def.po ref.pot
locale
directory.msgmergePOT
tool to create an English→YourLanguage translation file.C:\> msgmergePOT english.po russian.po english-russian.po
Now you have an English language program with a translation to the language that your program used before.
msgen
, a program that creates an English translation file, where all translations are a copy of the original, but marked as fuzzy. A translator can then run through all messages and correct any typing errors or improve any words, if needed. 4)C:\> msgen english-empty-translation.po -o english-fuzzy-translation.po -s
msgid
and msgstr
. Text in the msgstr must be formatted in UTF-8. NOTE: It does not support multiline msgstr
values.msgstr
is not empty in any row (to avoid “Error: No tabulator in line” message).C:\> msgimport textfile.txt -o output.po
To distinguish fields that need translation from the ones that do not, follow these guidelines: