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 p <> 0 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.