#1 2011-09-13 06:32:00

proto
Member
From: Russia, Kostroma
Registered: 2011-09-12
Posts: 31

Sample i18n

thanks for buatiful framework!
may be any write simple sample for using SQLite3i18n language file?

Offline

#2 2011-09-14 07:49:53

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Sample i18n

The SQLite3i18n.pas unit is able to handle both Internationalization (i18n) and Localization (L10n).

The TLanguageFile class is able to retrieve a custom list of text, and use it for all resourcestring and screen captions. The global _() function, or the Translate method of the TLanguageFile class can be used to translate any English text into the corresponding language.

The generic string type is used when some text is to be displayed on screen. Dedicated U2S and S2U functions, or even better the UTF8ToString and StringToUTF8 methods of a TLanguageFile instance can be used for proper conversion.

Localization is performed via some dedicated methods of the TLanguageFile class, like DateToText, DateTimeToText, TimeToText.

I'll update the main sample file about using this i18n feature, write associated documentation and post some additional information here soon.

Offline

#3 2011-09-14 16:27:09

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Sample i18n

Extracted from the updated documentation:

Application i18n and L10n

In computing, internationalization and localization (also spelled internationalization and localization) are means of adapting computer software to different languages, regional differences and technical requirements of a target market:
- Internationalization (i18n)is the process of designing a software application so that it can be adapted to various languages;
- Localization (L10n) is the process of adapting internationalized software for a specific region or language by adding locale-specific components and translating text, e.g. for dates display.

Our framework handle both features, via the !LibSQLite3i18n.pas unit. We just saw above how resourcestring defined in the source code are retrieved from the executable and can be translated on the fly. The unit extends this to visual forms, and even captions generated from RTTI - see 5.

The unit expects all textual content (both resourcestring and RTTI derived captions) to be correct English text. A list of all used textual elements will be retrieved then hashed into an unique numerical value. When a specific locale is set for the application, the unit will search for a .msg text file in the executable folder matching the expected locale definition. For instance, it will search for FR.msg for translation into French.

In order to translate all the user interface, a corresponding .msg file is to be supplied in the executable folder. Neither the source code, nor the executable is to be rebuild to add a new language. And since this file is indeed a plain textual file, even a non developer (e.g. an end-user) is able to add a new language, starting from another .msg.


Creating the reference file

In order to begin a translation task, the SQlite3i18n.pas unit is able to extract all textual resource from the executable, and create a reference text file, containing all English sentences and words to be translated, associated with their numerical hash value.

It will in fact:
- Extract all resourcestring text;
- Extract all captions generated from RTTI (e.g. from enumerations or class properties names);
- Extract all embedded dfm resources, and create per-form sections, allowing a custom translation of displayed captions or hints.

This creation step needs a compilation of the executable with the EXTRACTALLRESOURCES conditional defined, globally to the whole application (a full rebuild is necessary after having added or suppressed this conditional from the Project / Options / Folders-Conditionals IDE field).

Then the ExtractAllResources global procedure is to be called somewhere in the code.

For instance, here is how this is implemented in FileMain.pas, for the framework main demo:

procedure TMainForm.FormShow(Sender: TObject);
begin
{$ifdef EXTRACTALLRESOURCES}
  ExtractAllResources(
    // first, all enumerations to be translated
    [TypeInfo(TFileEvent),TypeInfo(TFileAction),TypeInfo(TPreviewAction)],
    // then some class instances (including the TSQLModel will handle all TSQLRecord)
    [Client.Model],
    // some custom classes or captions
    [],[]);
  Close;
{$else}
  //i18nLanguageToRegistry(lngFrench);
{$endif}
  Ribbon.ToolBar.ActivePageIndex := 1;
end;

The TFileEvent and TFileAction enumerations RTTI information is supplied, together with the current TSQLModel instance. All TSQLRecord classes (and therefore properties) will be scanned, and all needed English caption text will be extracted.

The Close method is then called, since we don't want to use the application itself, but only extract all resources from the executable.

Running once the executable will create a SynFile.messages text file in the SynFile.exe folder, containing all English text:

[TEditForm]
Name.EditLabel.Caption=_2817614158   Name
KeyWords.EditLabel.Caption=_3731019706   KeyWords


[TLoginForm]
Label1.Caption=_1741937413   &User name:
Label2.Caption=_4235002365   &Password:


[TMainForm]
Caption=_16479868    Synopse SQLite3 Framework demo - SynFile


[Messages]
2784453965=Memo
2751226180=Data
744738530=Safe memo
895337940=Safe data
2817614158=Name
1741937413=&User name:
4235002365=&Password:
16479868= Synopse SQLite3 Framework demo - SynFile
940170664=Content
3153227598=None
3708724895=Page %d / %d
2767358349=Size: %s
4281038646=Content Type: %s
2584741026=This memo is password protected.|Please click on the "Edit" button to show its content.
3011148197=Please click on the "Extract" button to get its content.
388288630=Signed,By %s on %s
(...)

The main section of this text file is named [Messages]. In fact, it contains all English extracted texts, as NumericalKey=EnglishText pairs. Note this will reflect the exact content of resourcestring or RTTI captions, including formating characters (like %d), and replacing line feeds (#13) by the special  character (a line feed is not expected on a one-line-per-pair file layout). Some other text lines are separated by a comma. This is usual for instance for hint values, as expected by the code.

As requested, each application form has its own section (e.g. [TEditForm], [TMainForm]), proposing some default translation, specified by a numerical key (for instance Label1.Caption will use the text identified by 1741937413 in the [Messages] section). The underline character before the numerical key is used to refers to this value. Note that if no _NumericalKey is specified, a plain text can be specified, in order to reflect a specific use of the generic text on the screen.


Adding a new language

In order to translate the whole application into French, the following SynFile.FR file could be made available in the SynFile.exe folder:

[Messages]
2784453965=Texte
2751226180=Données
744738530=Texte sécurisé
895337940=Données sécurisées
2817614158=Nom
1741937413=&Nom utilisateur:
4235002365=&Mot de passe:
16479868= Synopse mORMot Framework demo - SynFile
940170664=Contenu
3153227598=Vide
3708724895=Page %d / %d
2767358349=Taille: %s
4281038646=Type de contenu: %s
2584741026=Le contenu de ce memo est protégé par un mot de passe.|Choisissez "Editer" pour le visualiser.
3011148197=Choisissez "Extraire" pour enregistrer le contenu.
388288630=Signé,Par %s le %s
(....)

Since no form-level custom captions have been defined in this SynFile.FR file, the default numerical values will be used. In our case, Name.EditLabel.Caption will be displayed using the text specified by 2817614158, i.e. 'Nom'.

Note that the special characters %s %d , markup was preserved: only the plain English text has been translated to the corresponding French.


Language selection

User Interface language can be specified at execution.

By default, it will use the registry to set the language. It will need an application restart, but it will also allow easier translation of all forms, using a low-level hook of the TForm.Create constructor.

For instance, if you set in FileMain.pas, for the framework main demo:

procedure TMainForm.FormShow(Sender: TObject);
begin
  (...)
  i18nLanguageToRegistry(lngFrench);
  Ribbon.ToolBar.ActivePageIndex := 1;
end;

It will set the main application language as French. At next startup, the content of a supplied SynFileFR.msg file will be used to translate all screen layout, including all RTTI-generated captions.

See i18nAddLanguageItems, i18nAddLanguageMenu and i18nAddLanguageCombo functions and procedures to create your own language selection dialog, using a menu or a combo box, for instance.


Localization

Take a look at the TLanguageFile class. After the main language has been set, you can use the global Language instance in order to localize your application layout.

The SQlite3i18n unit will register itself to some methods of SQlite3Commons.pas, in order to translate the RTTI-level text into the current selected language. See for instance i18nDateText.

Offline

#4 2011-09-21 10:52:34

proto
Member
From: Russia, Kostroma
Registered: 2011-09-12
Posts: 31

Re: Sample i18n

issue if i add in uses section SQLite3UI (SQLite3i18n include in SQLite3UI)
my standart system LCID 1049 - ru
but if i only add in uses section SQLite3i18n all my setting get english format.

SetCurrentLanguage(LCIDToLanguage(SysLocale.DefaultLCID));

in my pc this function set always lngEnglish, but get russian local parameters SysLocale.DefaultLCID = 1049

  if CurrentLanguage.Index=aLanguage then
    exit;

{$ifdef USEFORMCREATEHOOK}
  if CurrentLanguage.Index<>LANGUAGE_NONE then
    raise Exception.Create('lang unit: language must be set only once');
{$endif USEFORMCREATEHOOK}

  // 2. file must exists if not English
  if aLanguage<>lngEnglish then
    if not FileExists(TLanguageFile.FileName(aLanguage)) then
      if CurrentLanguage.Index=lngEnglish then
        exit else
        aLanguage := lngEnglish; // if .msg not available -> force english  <<<<<<< always english, but why not default system language? <<<<<<<

Offline

#5 2011-09-21 11:35:58

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Sample i18n

Take a look at the documentation, and call i18nLanguageToRegistry() to change the application language at startup.

Offline

#6 2012-04-28 04:13:12

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Re: Sample i18n

What if after we call ExtractAllResources, and we've made a translation in the file *. Msg, and later we need to add or change the strings on the project we also need to be translate?
whether we should call ExtractAllResources again, then add and translate to the file *. msg?
I think this way is arduous.
is possible in the future will be made such a small program like kdlscan.exe?

Thank you.

Offline

#7 2012-04-28 07:01:59

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Sample i18n

The easiest (and what we are doing) is to use a textual difference program (like WinDiff of TotalCommander).
It will show the difference between the old and new files.
Then you'll be able to change the translations.

A dedicated tool may be available.
But it is not our high priority now.
You are free to contribute!

Offline

#8 2012-04-28 09:52:57

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Re: Sample i18n

ok. thank you. maybe I'll use Notepad + +

I'd love to contribute, but frankly, I do not feel confident.

Offline

#9 2012-04-28 09:58:38

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Re: Sample i18n

ok. thank you. maybe I'll use Notepad + +

I'd love to contribute, but frankly, I do not feel confident.

Offline

#10 2013-07-30 07:40:56

general-e
Member
From: Germany
Registered: 2013-04-11
Posts: 7

Re: Sample i18n

Hi, I think I found a small bug.
I've activated the i18nLanguageToRegistry(lngGerman); line of code in your Maindemo.
But the value in registry is only "d" not "de".
So next start doesn't load the DE.msg.

Offline

#11 2013-07-30 08:49:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Sample i18n

You are right.
I've fixed an Unicode issue in function i18nLanguageToRegistry().
See http://synopse.info/fossil/info/ab7db454be

Should be working as expected by now.
Thanks for the report.

Offline

Board footer

Powered by FluxBB