Multilanguage with Firemonkey (Delphi) - delphi

I'm looking for a solution to change the language at runtime. (Firemonkey / Delphi)
TLang works, but I get weird strings in an empty project. (e.g. Samsung Galaxy Nexus and other mobile stuff) And I prefer another solution and not string-replace like TLang.
Unfortunately, resourcestring doesn't work. I tried to translate the resourcestrings with "resource dll expert" (IDE RAD Studio XE5). And the example application "RichEdit" also doesn't work.
Any idea?

Okay I found the problem, why it isn't running. The tool have some bugs. The path to the Project.exe can not contain spaces.
Another solution is Stringtable like this:
// default.rc file
#define firstString 1
#define secondString 2
STRINGTABLE
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
BEGIN
firstString , "Neutral String 1"
secondString , "Neutral String 2"
END
// english.rc file
#define firstString 1
#define secondString 2
STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
BEGIN
firstString , "First String"
secondString , "Second String"
END
And than {$R default.res default.rc} {$R english.res english.rc} into the *.pas file. To use the transalation: LoadStr(2)
With an resource-editor, I can see the two languages. But how I can change the default/neutral to another language at runtime. Is there a kind of "SetLanguage" function in Delphi?

For simple projects TLang works fine, but the included "Language Designer" (doubleclick on the TLang component) is not much fun.If you want to translate and handle your strings extern you only can import external languages files one by one and have to import all again, if some texts change.
I wrote a small tool to handle texts extern in a spreadsheet and convert this texts to the LNG format:
See TLang converter
For large projects you may also check out some commercial products for translating/localization of Delphi FMX projects like:
http://www.sisulizer.de
http://www.tsilang.com
http://www.regulace.org

Related

Delphi Version number central but other info decentral

Background
Upto RS10.3 I used to use Andreas Hausladen DDevExtensions to set my version number in my project sources to be the same for all modules (bpl's/exe), but unfortunately Andreas has stopped updating his tool for RS10.4 and later.
So I am looking for more comfortable ways to set a version number in my app modules than applying multi-file changes to all dproj files with NotePad++.
But... On the other side I do want to keep specific information (like file description etc) specific to the module file.
What I also would like but isnt really a requirement is to have my (c) notice, and other shared info to be centralized in a single file (preferably .rc) as well.
It is not a problem to drop the version info from the dproj files (which are a pain to maintain anyway) and have a specific .rc file for each module instead.
Another advantage would be that having one central version number and (c) file is also a lot better in svn change management since I don't have to commit each and every .dproj file because of the version/build number change.
Investigation
(To be updated as we go along)
I Checked out
How to include Subversion revision number into Delphi project
Incrementing Delphi XE project version number from command line
But those solutions are not really what I am looking for; I am not looking for scripts but a source file/project file way to accomplish my task.
So here's the Q
How can I have one single .rc file containing my version number and use it in other .rc files containing specific version info
Ah I didn't expect it to be this simple...
I Created two .rc files, one with the shared info as #defines SharedVersionDefs.rc:
#define VER_MAJ 1
#define VER_MIN 2
#define VER_SUB 3
#define VER_BUILD 8
#define VER_FILEVERSION VER_MAJ,VER_MIN,VER_SUB,VER_BUILD
#define VER_FILEVERSION_STR ""VER_MAJ,VER_MIN,VER_SUB,VER_BUILD"\0"
// in my app file and product version are the same
#define VER_PRODUCTVERSION VER_MAJ,VER_MIN,VER_SUB,VER_BUILD
#define VER_PRODUCTVERSION_STR ""VER_MAJ,VER_MIN,VER_SUB,VER_BUILD"\0"
#define VER_COMPANYNAME_STR "MyCompany\0"
#define VER_LEGALCOPYRIGHT_STR "(c) 2020 "VER_COMPANYNAME_STR"\0"
And one specific file (which would re-appear for each module with different names and contents) SpecificVersion.rc:
/* Use the shared version info from a central file */
#include "SharedVersionDefs.rc"
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", VER_COMPANYNAME_STR
VALUE "FileDescription", "Specific file description"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "Specific internal name"
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
VALUE "ProductName", "LCCAMQM"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
Just had to create these 2 files, set version info in the delphi dproj file to OFF, and then add the specific .rc file to the module's dproj where I want it to appear, in this case a minor delphi project:
program VersionInfoTest;
{$R 'SpecificVersion.res' 'SpecificVersion.rc'}
uses
Vcl.Forms,
uMain in 'uMain.pas' {frmMain},
uVerinfo in 'uVerinfo.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
And I verified this worked.
ATTENTION: Due to RSP-13486 you are required to add the .rc file to the .dproj file as well. Just drag-and-drop in in there using the IDE.
More info regarding the .rc files and examples can be found on MSDN

Delphi 7 cyrillic characters not showing correctly

i recently asked (and paid) for translation of my Delphi app to support Macedonian (Cyrillic font) support.
I posted text to translate to my contracted translator, she sent me back translated strings. The text was extracted from all my .dfm and .pas files
when i replaced the original text with cyrillic translation, i can open .dfm fies also .pas files in my favourite Notepad++ (or notepad) , and i see translated characters correctly.
When i open these files in Delphi (as dpr file) , i see something like this:
Please someone tell me how to convert/display these strings in Delphi correctly.
I am using Macedonian regional settings, but it not helped me with this problem.
PS: Yes I am still using Delphi 7 because i love it / purchased this version.
UPDATE
Original text in Delphi:
original: ПОДГОТВИ КУТИИ ЗРДРУГИТЕ ЦЕÐТРÐЛИ
Correct text:
ПОДГОТВИ КУТИИ ЗА ДРУГИТЕ ЦЕНТРАЛИ
I noticed, when i change ParentFont property to false and font set to Verdana and Cyrillic (RUSSIAN_CHARSET) , then i copy/paste cyrillic text, it shows normally in Delphi
OK so i SOLVED that!
The solution is multi step one, and Notepad++ is needed:
1st step: Replace all fonts in .dfm with (for example) Verdana , or some font that allows Cyrillic support
2nd step: Replace all ParentFont = False to ParentFont = True
3rd step: In notepad++ Choose: Encoding -> Convert to ANSI
that's all, do this for all .dfm and .pas file (only 3rd step)
i am happy to not Listened David Heffernan and not gave up!
Your text file was UTF-8 encoded, whereas Delphi7 requires WinAnsi encoding, with codepage 1251 for Cyrillic characters.
You have the UTF8Decode() function in System.pas to make the conversion programmatically, if you prefer.

Auto rename compiled file in Delphi XE2

I use Delphi XE2 and I have a project called PGetBase. In this project, there is a module with a constant declaration. For example:
const
   FragH = 5;
   FragW = 4;
...
After compiling, the file is called PGetBase.exe. Is it possible to make the name of the build file dependent on the constants declared in the module, e.g. PGetBase_5_4.exe, by making use of a Post-Build event?
Add a project to the projectgroup which creates an executable that uses the same unit and changes the filename. Build and run that executable in the Post-Build event.
Microsoft Build knows nothing about the Pascal language and cannot parse the sources.
However you may extract "5" and "4" into some external text files.
const
FragH =
{$I Frag_h.txt}
;
FragW =
{$I Frag_W.txt}
;
Then make a simple program (or script: WSH, PowerShell, etc), that would be launched from post-build events.
You program would read those file and rename the Delphi-made PGetBase.exe to anything you wish.
PS. Of course one can parse the source unit to regain those constants, rather than offloading them into external storage. Comments hold the discussion pro et con.
PPS. NGLN came wit ha neat idea. Rather than parsing the file, you can just include that unit as part of your renamer project. Then you can add a pre-build event, that would compile(make) renamer and in post-buid the renamer would have those constants within itself. While calling make/dcc32 would probably be slower than just parsing the sources from inside the version-neutral pre-compiled renamer.exe, that NGLN's approach is elegant and self-contained in its own way.

Export C functions for LabView with c++builder

I have a DLL that I have ported from VC2008 to C++ Builder XE2. The DLL is used in LabVIEW's TestStand.
TestStand, when importing the VC2008 DLL, can see the function names and their arguments. When using the C++ Builder DLL, all its sees are the function names and not the arguments. All exports are C functions and use extern "C" declspec( dllexport ).
Is there a way to get the exports correct?
I have read that adding a TLB file will do the job, if this is true, how do I create a TLB that exports only C functions?
TestStand can read a .c/.cpp file and derive parameters from that file. You still load the DLL and select the function you want to call. You then 'verify' the parameters and select the .c/.cpp file in the dialog. TestStand will find the function with the same name and insert the parameters itself.
The function must be very specific, I had to create a dummy .c file that contained the prototypes as TestStand could not handle the #defines for dllexport and dllimport. It likes a very specific format. For the function:
TESTAPI bool StartTest( long inNumber ) {}
where TESTAPIis either extern "C" __declspec( dllexport ) or extern "C" __declspec( dllimport I had to write the line below in my dummy file:
bool __declspec( dllexport ) StartTest( long inNumber ) {}
That does it.
DLL function parameters cannot be determined from exports alone, unless they are being decorated by the calling convention (which is unusual to do in a DLL). If a TLB (aka a Type Library) solves the problem, then the VC2008 DLL is likely an In-Process ActiveX/COM object rather than a flat C DLL. If so, then in C+Builder you can use the IDE wizards on the "File | New" menu to create an "ActiveX Library" project, then a "COM Object" to add to the library. Then you will have a TLB that you can define your object with, and the IDE will generate stub code that you can fill in with your object's implementation.
If that is not what LabViews is expecting, then I suggest you contact them and ask. If all it needs is a TLB with flat C functions (which is very unusual, because TLB's are object-oriented), then you can omit the "COM Object" portion and just create an "ActiveX Library" project to get a bare-bones TLB, then add your definitions to it as needed, an then add your exports to the project.
From the reference here:
Avoid using the extern "C" syntax to export symbols. The extern "C" syntax prevents the C/C++ DLL Adapter from obtaining type information for function and method parameters."
A little late to the game, but your problem may be that C++ Builder is decorating the exported function with a leading underscore. The TLIB command line utility should help prove this (assuming tlib still ships with C++Builder)
TLIB mydll.lib, mydll.lst
Look at the resulting lst file and see if it contains StartTest or _StartTest. LabView is probably expecting to find a function without the underscore.
You can add a DEF file to your C++Builder project that will suppress the leading underscore. Try this:
Use the __cdecl calling convention instead of __stdcall.
Export plain "C" functions. No C++ classes or member functions.
Make sure you have an extern "C" {} around your function prototypes.
Create a DEF file that aliases the exported functions to a Microsoft
compatible name. Alias the names so they don't contain a leading
underscore. The DEF file will look like this:
EXPORTS
; MSVC name = C++Builder name
StartTest = _StartTest
Foo = _Foo
Bar = _Bar
5- Add the DEF file to your BCB DLL project and rebuild it.
Check out these ancient articles for more details:
http://bcbjournal.org/articles/vol4/0012/Using_Visual_C_DLLs_with_CBuilder.htm
The reverse article (creating C++Builder DLLs that get called from VC++ created applications) is buried in this archive:
http://www.frasersoft.net/program/bcbdev.zip : /articles/bcbdll.htm. It describes the DEF file trick in more detail, plus some other options.
Note that my answer is based on the way thing were in 1998 or so. They may have changed since then. If they have, then the C++Builder command line tools impdef, tlib, tdump, plus the Microsoft equivalents of those tools, should be able to show you exactly what is in your DLL vs the MSVC one.
H^2
I suggest to use ActiveX object: you can create an automation object in C++Builder and in Labview / TestStand you can import this object. If you use automation, in Lavbiew you will have the correct parameter definition. Make sure you are using a set of compatible type variables with Labview / TestStand.
For example, this fragment of code is the implementation of an array passed from Labview to C++:
STDMETHODIMP TCanLibraryImpl::DataDownload(VARIANT Data, long* RV)
{
_precondition_cmodule();
*RV = 0;
TSafeArrayLong1 mySafeArray(Data.parray);
int dLen =mySafeArray.BoundsLength[0];
...
}
In Labview you will pass to this function an array of I64

any functions to create zip file of directory/file on vista with delphi 2009

I am looking for a simple method of zipping and compressing with delphi. I have already looked at the components at torry delphi:http://www.torry.net/pages.php?s=99. They all seem as though they would accomplish what I want however a few disadvantages to using them is that none of them run in delphi 2009 and are very complex which makes it difficult for me to port them to delphi 2009. And besides, the documentation on them is scarce, well at least to me. I need basic zipping functionality without the overhead of using a bunch of DLLs. My quest lead me to FSCTL_SET_COMPRESSION which I thought would have settled the issue but unfortunately this too did not work. CREATEFILE looked promising, until I tried it yielded the same result as FSCTL_SET... I know that there are some limited native zipping capability on windows. For instance if one right clicks a file or folder and selects -> sendTo ->zipped folder, a zipped archive is smartly created. I think if I was able to access that capability from delphi it will be a solution. On a side issue, does linux have its own native zipping functions that can be used similar to this?
TurboPower's excellent Abbrevia can be downloaded for D2009 here, D2010 support is underway and already available in svn according to their forum.
Abbrevia used to be a commercial (for $$$) product, which means that the documentation is quite complete.
I use Zipforge. Why are there problems porting these to D2009? Is it because of the 64bit??
Here is some sample code
procedure ZipIt;
var
Archiver: TZipForge;
FileName: String;
begin
try
Archiver:= TZipForge.create(self);
with Archiver do begin
FileName := 'c:\temp\myzip.zip';
// Create a new archive file
OpenArchive(fmCreate);
// Set path to folder with some text files to BaseDir
BaseDir := 'c:\temp\';
// Add all files and directories from 'C:\SOURCE_FOLDER' to the archive
AddFiles('myfiletozip.txt');
// Close the archive
CloseArchive;
end;
finally
Archiver.Free;
end;
end;
If you can "do" COM from Delphi, then you can take advantage of the built-in zip capability of the Windows shell. It gives you good basic capability.
In VBScript it looks like this:
Sub CreateZip(pathToZipFile, dirToZip)
WScript.Echo "Creating zip (" & pathToZipFile & ") from folder (" & dirToZip & ")"
Dim fso
Set fso= Wscript.CreateObject("Scripting.FileSystemObject")
If fso.FileExists(pathToZipFile) Then
WScript.Echo "That zip file already exists - deleting it."
fso.DeleteFile pathToZipFile
End If
If Not fso.FolderExists(dirToZip) Then
WScript.Echo "The directory to zip does not exist."
Exit Sub
End If
NewZip pathToZipFile
dim sa
set sa = CreateObject("Shell.Application")
Dim zip
Set zip = sa.NameSpace(pathToZipFile)
WScript.Echo "opening dir (" & dirToZip & ")"
Dim d
Set d = sa.NameSpace(dirToZip)
For Each s In d.items
WScript.Echo s
Next
' http://msdn.microsoft.com/en-us/library/bb787866(VS.85).aspx
' ===============================================================
' 4 = do not display a progress box
' 16 = Respond with "Yes to All" for any dialog box that is displayed.
' 128 = Perform the operation on files only if a wildcard file name (*.*) is specified.
' 256 = Display a progress dialog box but do not show the file names.
' 2048 = Version 4.71. Do not copy the security attributes of the file.
' 4096 = Only operate in the local directory. Don't operate recursively into subdirectories.
WScript.Echo "copying files..."
zip.CopyHere d.items, 4
' wait until finished
sLoop = 0
Do Until d.Items.Count <= zip.Items.Count
Wscript.Sleep(1000)
Loop
End Sub
COM also allws you to use DotNetZip, which is a free download, that does password-encrypted zips, zip64, Self-extracting archives, unicode, spanned zips, and other things.
Personally I use VCL Zip which runs with D2009 and D2010 perfectly fine. it does cost $120 at the time of this post but is very simple, flexible and most of all FAST.
Have a look at VCLZIP and download the trail if your interested
code wise:
VCLZip1.ZipName := ‘myfiles.zip’;
VCLZip1.FilesList.add(‘c:\mydirectory\*.*’);
VCLZip1.Zip;
is all you need for a basic zip, you can of course set compression levels, directory structures, zip streams, unzip streams and much more.
Hope this is of some assistance.
RE
Take a look at this OpenSource SynZip unit. It's even faster for decompression than the default unit shipped with Delphi, and it will generate a smaller exe (crc tables are created at startup).
No external dll is needed. Works from Delphi 6 up to XE. No problem with Unicode version of Delphi. All in a single unit.
I just made some changes to handle Unicode file names inside Zip content, not only Win-Ansi charset but any Unicode chars. Feedback is welcome.

Resources