By default, if no translation for a language is available, dxgettext will not do any translation but use the strings as they are in the source code. Sometimes this is not desirable. e.g.
- Your customer does not understand the source language (e.g. your source language is not English but say German)
- You are using dxgettext to convert special characters from a placeholder (e.g. “(R)” or “[deg]“) to the actual character (“®” or “°”)
In these cases you’d probably want the translation to default to a language that is actually supplied.
dxgettext doesn’t seem to have this feature (I looked quite hard) so I implemented it myself.
unit u_dzTranslator; interface // ... other stuff ... ///<summary> /// Sets the language to use </summary> procedure UseLanguage(_LanguageCode: string); ///<summary> /// gets a list of languages for which translations are available </summary> procedure GetListOfLanguages(const _Domain: string; _Codes: TStrings; _Languages: TStrings = nil); ///<summary> /// Sets the language to use if the desired language is not available, /// defaults to English </summary> procedure SetDefaultLanguage(const _LanguageCode: string); // ... other stuff ... implementation uses gnugettext; // ... other stuff ... const DEFAULT_LANGUAGE = 'en'; var gblDefaultLanguage: string = DEFAULT_LANGUAGE; procedure UseLanguage(_LanguageCode: string); var Codes: TStringList; CurLang: string; i: Integer; p: Integer; begin gnugettext.UseLanguage(_LanguageCode); CurLang := gnugettext.GetCurrentLanguage; Codes := TStringList.Create; try GetListOfLanguages('default', Codes); for i := 0 to Codes.Count - 1 do begin if SameText(CurLang, Codes[i]) then begin // There is a translation for this language and country, everything is fine Exit; //--> end; end; // no translation found, try without the country code p := Pos('_', CurLang); if p0 then begin CurLang := Copy(CurLang, 1, p - 1); for i := 0 to Codes.Count - 1 do begin if SameText(CurLang, Codes[i]) then begin // There is a translation for this language but not country, we can live with that Exit; //--> end; end; end; finally FreeAndNil(Codes); end; // we found no translation for this language, so we use the default language gnugettext.UseLanguage(gblDefaultLanguage); end; procedure SetDefaultLanguage(const _LanguageCode: string); begin if _LanguageCode = '' then gblDefaultLanguage := DEFAULT_LANGUAGE else gblDefaultLanguage := _LanguageCode; UseLanguage(gnugettext.GetCurrentLanguage); end; procedure GetListOfLanguages(const _Domain: string; _Codes: TStrings; _Languages: TStrings = nil); var i: Integer; begin _Codes.Clear; gnugettext.DefaultInstance.GetListOfLanguages(_Domain, _Codes); if Assigned(_Languages) then begin _Languages.Clear; for i := 0 to _Codes.Count - 1 do begin _Languages.Add(languagecodes.getlanguagename(_Codes[i])); end; end; end; // ... other stuff ... initialization SetDefaultLanguage(DEFAULT_LANGUAGE); end.Apart from the obvious, that is, setting a unit global variable to the desired default language, which itself defaults to English, this code changes the way UseLanguageWorks. It now does:
- Call gnugettext.UseLanguage to let gnugettext do its stuff
- Call gnugettext.GetCurrentLanguage to get the language that gnugettext uses (just in case gnugettext changes it from what was set with UseLanguage).
- Gets a list of all supported translations
- Tries to find a matching translation for the desired language and country.
- If not found, tries to find a matching translation for the desired language, ignoring the country
- If not found, changes the language to the default language.
Note that I just wrote this code, it might still contain bugs and is probably far from perfect. I will put it into the unit u_dzTranslator of my dzlib library and will fix any bugs I find in the future there.