firemonkey - How to start mobile Keyboard in lower case letter? - delphi

At my application, there's a text field where the user will type their account e-mail.
With Java I can easily make the Android keyboard start with a lower-case letter by using
EditText text = new EditText(context);
text.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE);
How is it possible to achieve the same with Delphi 10 Seattle?

I guess there is no easy way to make accurate settings like yours currently. Delphi and java vk types mapping is implemented inside fmx.dex.jar library, embedded by default with every FMX Android project.
But for current purposes you can just set KeyboardType to EmailAddress, which will be converted to TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS combination. And this will be the best decision for Android.
Here are all the mappings.
On Android there is the following mapping between TVirtualKeyboardType values and TJFMXTextEditorProxy.JavaClass constants (see FMX.Platform.Android):
case VirtKBControl.KeyboardType of
TVirtualKeyboardType.Default:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_TEXT;
TVirtualKeyboardType.NumbersAndPunctuation:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_NUMBER_AND_PUNCTUATION;
TVirtualKeyboardType.NumberPad:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_NUMBER;
TVirtualKeyboardType.PhonePad:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_PHONE;
TVirtualKeyboardType.Alphabet:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_ALPHABET;
TVirtualKeyboardType.URL:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_URL;
TVirtualKeyboardType.NamePhonePad:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_NAME_PHONE_PAD;
TVirtualKeyboardType.EmailAddress:
KbType := TJFMXTextEditorProxy.JavaClass.INPUT_EMAIL_ADDRESS;
end;
Mapping between TJFMXTextEditorProxy.JavaClass constants and android.text.InputType is the following (it's in fmx.dex.jar):
switch (mInputType) {
case INPUT_NUMBER:
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
break;
case INPUT_NUMBER_AND_PUNCTUATION:
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
break;
case INPUT_PHONE:
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
break;
case INPUT_ALPHABET:
outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
if (!mPassword)
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
case INPUT_URL:
outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
break;
case INPUT_NAME_PHONE_PAD:
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
if (!mPassword)
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
case INPUT_EMAIL_ADDRESS:
outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
break;
case INPUT_TEXT:
default:
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
if (!mPassword)
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
}
if (mPassword)
{
if ((outAttrs.inputType & InputType.TYPE_CLASS_NUMBER) == InputType.TYPE_CLASS_NUMBER)
outAttrs.inputType |= InputType.TYPE_NUMBER_VARIATION_PASSWORD;
else
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
}

What component are you using for representing of this text field?
If you are using TEdit then you can change KeyboardType property to EmailAddress which should start virtual keyboard in lower case.
And based on the OS that your application is started on you could even get custom keyboard layout which provides additional keys for specific characters like #. That is if the target OS does support that.

Although the keyboard will show up with the upper-case key activated, if you set
procedure TForm.Edit1Typing(Sender: TObject);
begin
Edit1.Text:=AnsiLowerCase(Edit1.Text);
Edit1.GoToTextEnd;
end;
Then all typed keys will be in lower-case.

Related

Delphi 7: How to use a combination of check boxes

Am working an a small app in Delphi7 but am puzzles on how to use a combination of 3 check boxes
Example: if check.box1 and checkbox2 checked run system application with these prefs
or if checkbox1 only checked run system application with these prefs or if checkbox2 only checked run with these prefs
It sounds like you're having trouble getting started writing what you need, which is basically a series of if..then..else flow-control statements based on compound boolean expressions. You probably want a structure like the one below. I'm not going to show you the entire thing, because it's best for you to work it out for yourself, but this should give you the idea:
if (CheckBox1.Checked) and (CheckBox2.Checked) and not (CheckBox3.Checked) then
begin
// do one thing
end
else
begin
if (CheckBox1.Checked) and not (CheckBox2.Checked) and not (CheckBox3.Checked) then
begin
// do another thing
end
else
// etc
end;
If you're familiar with enumerated types, you might do better to declare one and use that to derive the selected preferences and then act upon them. The point of doing that is twofold: to increase the clarity of your code (at the expense of your code being longer, of course); and to separate the logic for calculating which preference the user has selected from the code which acts upon it.
Something like
type
TRunPreference = (rpNone, rpOne, rpTwo, rpThree, rpFour,
rpFive, rpSix, rpSeven, rpEight);
// rpOne..rpEight are for the 8 permutations of three booleans
// and the rpNone is to provide for initialising the variable
// with something which isn't one of the desired values
var
RunPreference : TRunPreference;
procedure TForm1.Button1Click(Sender: TObject);
begin
RunPreference := rpNone;
if (CheckBox1.Checked) and (CheckBox2.Checked) and not (CheckBox3.Checked) then
begin
RunPreference := rpOne;
end
else
begin
if (CheckBox1.Checked) and not (CheckBox2.Checked) and not (CheckBox3.Checked) then
begin
RunPreference := rpTwo;
end
else
; //
end;
case RunPreference of
rpNone :
; // do nothing
rpOne :
begin
// Act on rpOne
end;
rpTwo :
begin
// Act on rpTwo
end;
// etc
end; { Case of RunPreference }
end;
Inspired by MartynA's solution, and because I prefer compact code, here's how I would do it:
// For the three (sets of?) preferences, define bit values, and
// a variable to hold the combination of the selected preferences:
const
PrefA=1; PrefB=2; PrefC=4;
var
prefs: byte;
procedure TForm12.Button2Click(Sender: TObject);
begin
// whether a preference should be active or not becomes a simple `OR` function
// based on each checkbox's state
prefs := 0;
if CheckBox1.Checked then prefs := prefs or PrefA;
if CheckBox2.Checked then prefs := prefs or PrefB;
if CheckBox3.Checked then prefs := prefs or PrefC;
// then use a `case` statement to run according the preference combination
// The values like `PrefA or PrefC` can be used instead of numeric values,
// since they can be resolved at compile time.
// Whether they improve readability or not is ... (disputable)
case prefs of
0:
ShowMessage('Running without preferences');
PrefA:
ShowMessage('Running with PrefA alone');
PrefB:
ShowMessage('Running with PrefB alone');
PrefA or PrefB:
ShowMessage('Running with PrefA and PrefB');
PrefC:
ShowMessage('Running with PrefC alone');
PrefA or PrefC:
ShowMessage('Running with PrefA and PrefC');
PrefB or PrefC:
ShowMessage('Running with PrefB and PrefC');
PrefA or PrefB or PrefC:
ShowMessage('Running with PrefA and PrefB and PrefC');
end;
end;
If you need to check in your code whether a preference is active or not, you can do it like:
if (prefs and PrefB) then
// do whatever requires PrefB to be selected

Using TIBDataset how do I set a DateTime field to null

TField.Clear does not work on a DateTime field, like it does for say an integer field.
So how do I set the field to null?
I'm using Delphi 2010.
Currently I do this;
IBDataset1.FieldByName('EUL_START_DATE').Clear;
However the field does not get set to null, it still contains a date value.
I think this explains it, but i don't want to go messing with core delphi files.
http://qc.embarcadero.com/wc/qcmain.aspx?d=78920
What if i need to reinstall Rad Studio. I would have to remember all these little patches.
In the unit IBCustomDataset from line 3480 comment out the following lines;
//if TIBStringField(Field).EmptyAsNull then
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := True
//else
//begin
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataLength := 0;
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := False;
//end
and add in the following lines;
//NewCode IbCustomDataSet.pas Line 3480
begin
if (Field is TIBStringField) and
(not TIBStringField(Field).EmptyAsNull) then
begin
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataLength := 0;
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := False;
end
else
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := True;
end
//End New Code
solution found here;
http://qc.embarcadero.com/wc/qcmain.aspx?d=78920
Tested, seem to work ok.
Just remember to make a note if you need to reinstall rad studio, this patch will need to be re-applied.

Using Case Statement with String

Say i have a string
'SomeName'
and wanted the values return in a case statement. Can this bedone? Can strings be used in a case statement like so
Case 'SomeName' of
'bobby' : 2;
'tommy' :19;
'somename' :4000;
else
showmessage('Error');
end;
In Jcl library you have the StrIndex function StrIndex(Index, Array Of String) which works like this:
Case StrIndex('SomeName', ['bobby', 'tommy', 'somename']) of
0: ..code.. ;//bobby
1: ..code..;//tommy
2: ..code..;//somename
else
ShowMessage('error');
end.
The Delphi Case Statement only supports ordinal types. So you cannot use strings directly.
But exist another options like
build a function which returns a Integer (hash) based on a string
using generics and anonymous methods ( A generic case for strings)
using a function which receive an array of strings (Making a case for Strings, the sane way)
and so on.
#Daniel's answer pointed me in the right direction, but it took me a while to notice the "Jcl Library" part and the comments about the standard versions.
In [at least] XE2 and later, you can use:
Case IndexStr('somename', ['bobby', 'tommy', 'somename', 'george']) of
0: ..code..; // bobby
1: ..code..; // tommy
2: ..code..; // somename
-1: ShowMessage('Not Present'); // not present in array
else
ShowMessage('Default Option'); // present, but not handled above
end;
This version is case-sensitive, so if the first argument was 'SomeName' it would take the not present in array path. Use IndexText for case-insensitive comparison.
For older Delphi versions, use AnsiIndexStr or AnsiIndexText, respectively.
Kudos to #Daniel, #The_Fox, and #afrazier for most of the components of this answer.
Works on D7 and Delphi Seattle,
uses StrUtils (D7) system.Ansistring (Delphi Seattle)
case AnsiIndexStr(tipo, ['E','R'] ) of
0: result := 'yes';
1: result := 'no';
end;
I used AnsiStringIndex and works, but if you can convert to number without problems:
try
number := StrToInt(yourstring);
except
number := 0;
end;
try this it uses System.StrUtils
procedure TForm3.Button1Click(Sender: TObject);
const
cCaseStrings : array [0..4] of String = ('zero', 'one', 'two', 'three', 'four');
var
LCaseKey : String;
begin
LCaseKey := 'one';
case IndexStr(LCaseKey, cCaseStrings) of
0: ShowMessage('0');
1: ShowMessage('1');
2: ShowMessage('2');
else ShowMessage('-1');
end;
end;

Unicode characters on ZPL printer

I have the task of re-designing a system to print shipping labels, using a networked Zebra GK420T. I have been able to send ZPL print jobs to it perfectly fine, but I cannot seem to get it to print unicode characters, such as cyrillic letters. I have downloaded the lucida sans unicode font to the printer using the Seagull Scientific drivers and I am using the following ZPL code to test:
^XA
^LH100,150
^CI28
^FT0,0^A#N,50,50,R:LUCIDASR.FNT^CI28^FDTesting 1 2 3^FS
^FT0,50^A#N,50,50,R:LUCIDASR.FNT^CI28^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ
It will print the 'Testing 1 2 3' and the barcode, but it leaves a blank space instead of the cyrillic characters.
I also tried using the Zebra swiss unicode font and now it prints the russian characters as question marks:
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ
Am I doing something wrong like not escaping characters or something or is it a problem with the printer?
I just discovered that you need to escape characters above ASCII by first putting ^FH before any ^FD fields that could contain a utf character and you need to prefix the utf-8 hex code with an underscore
_D0_94 will print as Д. My final ZPL code is as follows:
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDTesting 1 2 3^FS
^FT0,50^FH^FD_D0_94_D0_BE _D1_81_D0_B2_D0_B8_D0_B4_D0_B0_D0_BD_D0_B8_D1_8F^FS
^FT0,100^B3^FDAAA001^FS
^XZ
I'm just going to have to make a way to generate the escape sequences, which should be much easier!
I had the same problem, you should add an ^FH(Field Hexadecimal Indicator) before any ^FD(Field Data) command that contains special characters, in my case I need spanish chars so I had to use ^CI28(Change International Font/Encoding)
UTF 8 HEX codes list
sample: to print Alvaro Jesús Pérez Peñaranda
we need to convert those special characters to UTF 8 Hex code and add an _ before each code, this is the result: Alvaro Jes_c3_bas P_c3_a9rez Pe_c3_b1aranda
^XA
^CI28
^FO60,75
^ASN,36,20^FH^FDAlvaro Jes_c3_bas P_c3_a9rez Pe_c3_b1aranda^FS
^XZ
I'm using Zebra ZM400 printer and use TT0003M_ font.
this font does not print kazakh cyrillic.
if you want to print cryillic + kazakh cyrillic + latin alphabet, use ARI000.FNT (arial font)
I'm using the following method convert char to hex code
I hope this helps
stringConverTextToHex(stringtext)
{
stringnewText="";
char[]charArray=text.ToCharArray();
foreach(charcincharArray)
{
switch(c)
{
case'й':
newText+="_D0_B9";
break;
case'Й':
newText+="_D0_99";
break;
case'ц':
newText+="_D1_86";
break;
case'Ц':
newText+="_D0_A6";
break;
case'у':
newText+="_D1_83";
break;
case'У':
newText+="_D0_A3";
break;
case'к':
newText+="_D0_BA";
break;
case'К':
newText+="_D0_9A";
break;
case'е':
newText+="_D0_B5";
break;
case'Е':
newText+="_D0_95";
break;
case'н':
newText+="_D0_BD";
break;
case'Н':
newText+="_D0_9D";
break;
case'г':
newText+="_D0_B3";
break;
case'Г':
newText+="_D0_93";
break;
case'ш':
newText+="_D1_88";
break;
case'Ш':
newText+="_D0_A8";
break;
case'щ':
newText+="_D1_89";
break;
case'Щ':
newText+="_D0_A9";
break;
case'з':
newText+="_D0_B7";
break;
case'З':
newText+="_D0_97";
break;
case'х':
newText+="_D1_85";
break;
case'Х':
newText+="_D0_A5";
break;
case'ъ':
newText+="_D1_8A";
break;
case'Ъ':
newText+="_D0_AA";
break;
case'ф':
newText+="_D1_84";
break;
case'Ф':
newText+="_D0_A4";
break;
case'ы':
newText+="_D1_8B";
break;
case'Ы':
newText+="_D0_AB";
break;
case'в':
newText+="_D0_B2";
break;
case'В':
newText+="_D0_92";
break;
case'а':
newText+="_D0_B0";
break;
case'А':
newText+="_D0_90";
break;
case'п':
newText+="_D0_BF";
break;
case'П':
newText+="_D0_9F";
break;
case'р':
newText+="_D1_80";
break;
case'Р':
newText+="_D0_A0";
break;
case'о':
newText+="_D0_BE";
break;
case'О':
newText+="_D0_9E";
break;
case'л':
newText+="_D0_BB";
break;
case'Л':
newText+="_D0_9B";
break;
case'д':
newText+="_D0_B4";
break;
case'Д':
newText+="_D0_94";
break;
case'ж':
newText+="_D0_B6";
break;
case'Ж':
newText+="_D0_96";
break;
case'э':
newText+="_D1_8D";
break;
case'Э':
newText+="_D0_AD";
break;
case'я':
newText+="_D1_8F";
break;
case'Я':
newText+="_D0_AF";
break;
case'ч':
newText+="_D1_87";
break;
case'Ч':
newText+="_D0_A7";
break;
case'с':
newText+="_D1_81";
break;
case'С':
newText+="_D0_A1";
break;
case'м':
newText+="_D0_BC";
break;
case'М':
newText+="_D0_9C";
break;
case'и':
newText+="_D0_B8";
break;
case'И':
newText+="_D0_98";
break;
case'т':
newText+="_D1_82";
break;
case'Т':
newText+="_D0_A2";
break;
case'ь':
newText+="_D1_8C";
break;
case'Ь':
newText+="_D0_AC";
break;
case'б':
newText+="_D0_B1";
break;
case'Б':
newText+="_D0_91";
break;
case'ю':
newText+="_D1_8E";
break;
case'Ю':
newText+="_D0_AE";
break;
case'ӑ':
newText+="_D3_91";
break;
case'Ӑ':
newText+="_D3_90";
break;
case'ӓ':
newText+="_D3_93";
break;
case'Ӓ':
newText+="_D3_92";
break;
case'ә':
newText+="_D3_99";
break;
case'Ә':
newText+="_D3_98";
break;
case'ӛ':
newText+="_D3_9B";
break;
case'Ӛ':
newText+="_D3_9A";
break;
case'ӕ':
newText+="_D3_95";
break;
case'Ӕ':
newText+="_D3_94";
break;
case'ґ':
newText+="_D2_91";
break;
case'Ґ':
newText+="_D2_90";
break;
case'ѓ':
newText+="_D1_93";
break;
case'Ѓ':
newText+="_D0_83";
break;
case'ғ':
newText+="_D2_93";
break;
case'Ғ':
newText+="_D2_92";
break;
case'ӷ':
newText+="_D3_B7";
break;
case'Ӷ':
newText+="_D3_B6";
break;
case'ҕ':
newText+="_D2_95";
break;
case'Ҕ':
newText+="_D2_94";
break;
case'ђ':
newText+="_D1_92";
break;
case'Ђ':
newText+="_D0_82";
break;
case'ѐ':
newText+="_D1_90";
break;
case'Ѐ':
newText+="_D0_80";
break;
case'ӗ':
newText+="_D3_97";
break;
case'Ӗ':
newText+="_D3_96";
break;
case'ҽ':
newText+="_D2_BD";
break;
case'Ҽ':
newText+="_D2_BC";
break;
case'ҿ':
newText+="_D2_BF";
break;
case'Ҿ':
newText+="_D2_BE";
break;
case'є':
newText+="_D1_94";
break;
case'Є':
newText+="_D0_84";
break;
case'ӂ':
newText+="_D3_82";
break;
case'Ӂ':
newText+="_D3_81";
break;
case'җ':
newText+="_D2_97";
break;
case'Җ':
newText+="_D2_96";
break;
case'ӝ':
newText+="_D3_9D";
break;
case'Ӝ':
newText+="_D3_9C";
break;
case'ҙ':
newText+="_D2_99";
break;
case'Ҙ':
newText+="_D2_98";
break;
case'ӟ':
newText+="_D3_9F";
break;
case'Ӟ':
newText+="_D3_9E";
break;
case'ӡ':
newText+="_D3_A1";
break;
case'Ӡ':
newText+="_D3_A0";
break;
case'ѕ':
newText+="_D1_95";
break;
case'Ѕ':
newText+="_D0_85";
break;
case'ѝ':
newText+="_D1_9D";
break;
case'Ѝ':
newText+="_D0_8D";
break;
case'ӥ':
newText+="_D3_A5";
break;
case'Ӥ':
newText+="_D3_A4";
break;
case'ӣ':
newText+="_D3_A3";
break;
case'Ӣ':
newText+="_D3_A2";
break;
case'і':
newText+="_D1_96";
break;
case'І':
newText+="_D0_86";
break;
case'ї':
newText+="_D1_97";
break;
case'Ї':
newText+="_D0_87";
break;
case'Ӏ':
newText+="_D3_80";
break;
case'ҋ':
newText+="_D2_8B";
break;
case'Ҋ':
newText+="_D2_8A";
break;
case'ј':
newText+="_D1_98";
break;
case'Ј':
newText+="_D0_88";
break;
case'қ':
newText+="_D2_9B";
break;
case'Қ':
newText+="_D2_9A";
break;
case'ҟ':
newText+="_D2_9F";
break;
case'Ҟ':
newText+="_D2_9E";
break;
case'ҡ':
newText+="_D2_A1";
break;
case'Ҡ':
newText+="_D2_A0";
break;
case'ӄ':
newText+="_D3_84";
break;
case'Ӄ':
newText+="_D3_83";
break;
case'ҝ':
newText+="_D2_9D";
break;
case'Ҝ':
newText+="_D2_9C";
break;
case'ӆ':
newText+="_D3_86";
break;
case'Ӆ':
newText+="_D3_85";
break;
case'љ':
newText+="_D1_99";
break;
case'Љ':
newText+="_D0_89";
break;
case'ӎ':
newText+="_D3_8E";
break;
case'Ӎ':
newText+="_D3_8D";
break;
case'ӊ':
newText+="_D3_8A";
break;
case'Ӊ':
newText+="_D3_89";
break;
case'ң':
newText+="_D2_A3";
break;
case'Ң':
newText+="_D2_A2";
break;
case'ӈ':
newText+="_D3_88";
break;
case'Ӈ':
newText+="_D3_87";
break;
case'ҥ':
newText+="_D2_A5";
break;
case'Ҥ':
newText+="_D2_A4";
break;
case'њ':
newText+="_D1_9A";
break;
case'Њ':
newText+="_D0_8A";
break;
case'ӧ':
newText+="_D3_A7";
break;
case'Ӧ':
newText+="_D3_A6";
break;
case'ө':
newText+="_D3_A9";
break;
case'Ө':
newText+="_D3_A8";
break;
case'ӫ':
newText+="_D3_AB";
break;
case'Ӫ':
newText+="_D3_AA";
break;
case'ҩ':
newText+="_D2_A9";
break;
case'Ҩ':
newText+="_D2_A8";
break;
case'ҧ':
newText+="_D2_A7";
break;
case'Ҧ':
newText+="_D2_A6";
break;
case'ҏ':
newText+="_D2_8F";
break;
case'Ҏ':
newText+="_D2_8E";
break;
case'ҫ':
newText+="_D2_AB";
break;
case'Ҫ':
newText+="_D2_AA";
break;
case'ҭ':
newText+="_D2_AD";
break;
case'Ҭ':
newText+="_D2_AC";
break;
case'ћ':
newText+="_D1_9B";
break;
case'Ћ':
newText+="_D0_8B";
break;
case'ќ':
newText+="_D1_9C";
break;
case'Ќ':
newText+="_D0_8C";
break;
case'ў':
newText+="_D1_9E";
break;
case'Ў':
newText+="_D0_8E";
break;
case'ӳ':
newText+="_D3_B3";
break;
case'Ӳ':
newText+="_D3_B2";
break;
case'ӱ':
newText+="_D3_B1";
break;
case'Ӱ':
newText+="_D3_B0";
break;
case'ӯ':
newText+="_D3_AF";
break;
case'Ӯ':
newText+="_D3_AE";
break;
case'ү':
newText+="_D2_AF";
break;
case'Ү':
newText+="_D2_AE";
break;
case'ұ':
newText+="_D2_B1";
break;
case'Ұ':
newText+="_D2_B0";
break;
case'ҳ':
newText+="_D2_B3";
break;
case'Ҳ':
newText+="_D2_B2";
break;
case'һ':
newText+="_D2_BB";
break;
case'Һ':
newText+="_D2_BA";
break;
case'ҵ':
newText+="_D2_B5";
break;
case'Ҵ':
newText+="_D2_B4";
break;
case'ӵ':
newText+="_D3_B5";
break;
case'Ӵ':
newText+="_D3_B4";
break;
case'ҷ':
newText+="_D2_B7";
break;
case'Ҷ':
newText+="_D2_B6";
break;
case'ӌ':
newText+="_D3_8C";
break;
case'Ӌ':
newText+="_D3_8B";
break;
case'ҹ':
newText+="_D2_B9";
break;
case'Ҹ':
newText+="_D2_B8";
break;
case'џ':
newText+="_D1_9F";
break;
case'Џ':
newText+="_D0_8F";
break;
case'ӹ':
newText+="_D3_B9";
break;
case'Ӹ':
newText+="_D3_B8";
break;
case'ҍ':
newText+="_D2_8D";
break;
case'Ҍ':
newText+="_D2_8C";
break;
case'ӭ':
newText+="_D3_AD";
break;
case'Ӭ':
newText+="_D3_AC";
break;
case'A':
newText+="_41";
break;
case'a':
newText+="_61";
break;
case'B':
newText+="_42";
break;
case'b':
newText+="_62";
break;
case'C':
newText+="_43";
break;
case'c':
newText+="_63";
break;
case'D':
newText+="_44";
break;
case'd':
newText+="_64";
break;
case'E':
newText+="_45";
break;
case'e':
newText+="_65";
break;
case'F':
newText+="_46";
break;
case'f':
newText+="_66";
break;
case'G':
newText+="_47";
break;
case'g':
newText+="_67";
break;
case'H':
newText+="_48";
break;
case'h':
newText+="_68";
break;
case'I':
newText+="_49";
break;
case'i':
newText+="_69";
break;
case'J':
newText+="_4A";
break;
case'j':
newText+="_6A";
break;
case'K':
newText+="_4B";
break;
case'k':
newText+="_6B";
break;
case'L':
newText+="_4C";
break;
case'l':
newText+="_6C";
break;
case'M':
newText+="_4D";
break;
case'm':
newText+="_6D";
break;
case'N':
newText+="_4E";
break;
case'n':
newText+="_6E";
break;
case'O':
newText+="_4F";
break;
case'o':
newText+="_6F";
break;
case'P':
newText+="_50";
break;
case'p':
newText+="_70";
break;
case'R':
newText+="_52";
break;
case'r':
newText+="_72";
break;
case'S':
newText+="_53";
break;
case's':
newText+="_73";
break;
case'T':
newText+="_54";
break;
case't':
newText+="_74";
break;
case'U':
newText+="_55";
break;
case'u':
newText+="_75";
break;
case'V':
newText+="_56";
break;
case'v':
newText+="_76";
break;
case'Y':
newText+="_59";
break;
case'y':
newText+="_79";
break;
case'Z':
newText+="_5A";
break;
case'z':
newText+="_7A";
break;
case'':
newText+="";
break;
default:
newText+=c;
break;
}
}
returnnewText;
}
this is the sample code
^SP
^XA
^PON^FS
^FPH^FO102,63,0
^A#N,60,60,E:ARIOOO_.FNT
^FH^FD_42_75_72_61_6B _D0_A8_D3_99
^FS
^XZ
Russian and many other characters can be printed using the free Zebra swiss unicode font. It is already included in most printers as TT0003M_ and supports Roman, Cyrillic, Eastern European, Turkish, Arabic, Hebrew.
For printing languages like Japanese or Chinese, which have thousands of characters, you need a printer with at least 23 MB of free memory and a TrueType font file you can upload (they call it download).
This file can be bought from Zebra (and they say you need 64 MB), but I was also very successful with a very old TTF file found on my Windows 7 system in the Fonts folder: ARIALUNI.TTF 1.01 (23.275.812 Bytes), Arial Unicode MS. It was installed by a MS Office installation and is maybe not licensed for this use.
Most likely you can also use other TTF files, but I tried only this one.
While ZPL-printing on this Zebra printer worked without any original driver (just generic text only), for the font installation the driver was needed. If anyone knows how to send the TTF file to the printer without driver, please comment.
I installed the Zebra Setup Utilities, which include a Fonts Downloader. Click new, then add the font (must be installed in the system), and ignore the message that 226 characters are included. Also ignore that if you configure a test string with Unicode characters, it will not display correctly. You are beeing asked if you want to download now and it takes a long time.
You can check the installation by listing the directory contents (Administration web page or printout). There the font appears as ARI000.TTF in my case.
To print, you need to send the ZPL text as UTF-8. You can copy this example to notepad and select UTF-8 in the save dialog:
^XA
^LH100,150
^CWT,E:ARI000.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDyour unicode characters here^FS
^XZ
Then, for testing, you can use a simple copy command to send it to the printer:
In case of USB you need to share this printer in the network first.
Then net use lpt1: \\localhost\sharename
and copy file.txt lpt1
We tested with many common Japanese and Chinese symbols and it works very well with high quality, on a ZT230 printer with 32 MB flash.
Your "До свидания" were probably in cp1251. Encode it in actual UTF-8 and try again. Blank spaces are a good indicator that you have an encoding problem.
Verified with v56.17.112 firmware and ^A#N,,,E:TT0003M_.FNT
if you want print Russian Cyrillic letters using :TT0003M_.FNT, you should save commands to file with UTF-8 encoding!
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDTesting 1 2 3^FS
^FT0,30^FH^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ
Then, using command line you can send it to printer port.
An example: copy C:\Users\xxx\Desktop\test_ru.txt com1
I hope that will help...
You can replace character that greater then one byte to UTF-8 hex string with underscore like "ћ => _D1_9B". Sample code below;
var zpl_code = "^XA" +
"^LH100,150" +
"^CWT,E:TT0003M_.FNT" +
"^CFT,30,30" +
"^CI28" +
"^FT0,0^FDTesting 1 2 3^FS" +
"^FT0,50^FDДо свидания^FS" +
"^FT0,100^B3^FDAAA001^FS" +
"^XZ";
var unicodeCharacterList = zpl_code.Distinct()
.Select(c => c.ToString())
.Select(c => new { key = c, UTF8Bytes = Encoding.UTF8.GetBytes(c) })
.Where(c => c.UTF8Bytes.Length > 1);
foreach (var character in unicodeCharacterList)
{
var characterHexCode = string.Join("", character.UTF8Bytes.Select(c => "_" + BitConverter.ToString(new byte[] { c }).ToLower()).ToArray());
zpl_code = zpl_code.Replace(character.key, characterHexCode);
}
This code set zpl_code variable to below output
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FD_d0_94_d0_be _d1_81_d0_b2_d0_b8_d0_b4_d0_b0_d0_bd_d0_b8_d1_8f^FS
^FT0,100^B3^FDAAA001^FS
^XZ
In latest firmware versions (since v x.16.x) you can use ^CI33 for codepage Windows-1251 encoded text (and other codepages) without ^FH. See manual
As others have noted, make sure to use ^CI28 (Change International Font/Encoding) and ^FH (Field Hexadecimal Indicator) and escape any non-ascii utf8 characters with an underscore and their hex value.
However another answer included code to format the utf8 string using a gigantic switch-case block. Here is the method I use for encoding to utf8, it should be able to format any valid utf8 byte array.
To get the byte array from a string use Encoding.UTF8.GetBytes(content).
// From the wikipedia page on utf8 encoding - https://en.wikipedia.org/wiki/UTF-8
private const int _Last1ByteCodePointByte1 = 0x7F;
private const int _First2ByteCodePointByte1 = 0xC0;
private const int _Last2ByteCodePointByte1 = 0xDF;
private const int _Last3ByteCodePointByte1 = 0xEF;
private const int _Last4ByteCodePointByte1 = 0xF7;
private const int _FirstMultiByteCodePointByte2 = 0x80;
private const int _LastMultiByteCodePointByte2 = 0xBF;
private const char _ZplMultiByteEscapeCharacter = '_';
/// <summary>
/// Encodes a sequence of utf8 bytes for printing with the ZPL language, this means escaping multi-byte characters with an underscore ('_') followed by the hex code
/// for each byte in the multi-byte characters.
/// </summary>
/// <param name="utf8Bytes">The bytes that make up the entire string, including bytes that need to be encoded and bytes that can be printed as-is.</param>
/// <returns>A string for printing with the ZPL language. Ie all multi-byte characters escaped with an underscore ('_') followed by the hex code for each byte.</returns>
/// <throws><see cref="ArgumentException"/> when <paramref name="utf8Bytes"/> isn't a valid utf8 encoding of a string.</throws>
/// <remarks>
/// Plan is to figure out how many bytes this character (code point) takes up, and if it's a 1 byte character, just use the character, but otherwise since it's a multi-byte
/// character then use an underscore ('_') followed by the hex encoded byte and each other byte in this code point will also be encoded. If we start the loop but have bytes
/// remaining in the current code point we know to hex encode this byte and continue.
/// </remarks>
private static string EncodeUtf8BytesForZPLIIPrinting(byte[] utf8Bytes)
{
var contentWithMultiByteCharsEscaped = new List<char>();
var multiByteCodePoint = new List<char>();
var remainingBytesInCurrentCodePoint = 0;
string errorMessage = null;
foreach (byte utf8Byte in utf8Bytes)
{
if (remainingBytesInCurrentCodePoint > 0)
{
if (utf8Byte < _FirstMultiByteCodePointByte2 || utf8Byte > _LastMultiByteCodePointByte2)
{
errorMessage = $"The byte {utf8Byte.ToString("X2")} is not a valid as the second or later byte of a multi-byte utf8 character (codepoint).";
break;
}
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint--;
continue; // continue since we've dealt with this byte and don't want to flow on.
}
if (multiByteCodePoint.Any())
{
foreach (char c in multiByteCodePoint) contentWithMultiByteCharsEscaped.Add(c);
multiByteCodePoint.Clear();
// flow on to loop to see what to do with the current byte.
}
if (utf8Byte <= _Last1ByteCodePointByte1)
{
// 1 byte - no escaping
contentWithMultiByteCharsEscaped.Add((char)utf8Byte);
}
else if (utf8Byte >= _First2ByteCodePointByte1 && utf8Byte <= _Last2ByteCodePointByte1)
{
// 2 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 1;
}
else if (utf8Byte <= _Last3ByteCodePointByte1)
{
// 3 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 2;
}
else if (utf8Byte <= _Last4ByteCodePointByte1)
{
// 4 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 3;
}
else
{
errorMessage = $"The byte {utf8Byte.ToString("X2")} is not a valid as the first byte of a utf8 character.";
break;
}
}
// if the last char was multiByte add it now.
if (multiByteCodePoint.Any())
{
foreach (var c in multiByteCodePoint) contentWithMultiByteCharsEscaped.Add(c);
multiByteCodePoint.Clear();
}
if (remainingBytesInCurrentCodePoint != 0 && errorMessage == null)
{
errorMessage = $"The last character didn't have enough bytes to finish the codepoint. It was a multi-byte character that needed {remainingBytesInCurrentCodePoint}" +
$" more byte{(remainingBytesInCurrentCodePoint == 1 ? null : "s")}.";
}
if (errorMessage != null)
{
throw new ArgumentException($"The byte array was not a valid byte array for a utf8 string: {errorMessage}", nameof(utf8Bytes));
}
return new string(contentWithMultiByteCharsEscaped.ToArray());
void AddHexValuesToListFromByte(List<char> list, byte #byte)
{
// A byte is <= 255 so will always fit in a 2-digit hex number, hence the 2 in "X2". The X means hex.
foreach (char c in #byte.ToString("X2"))
{
list.Add(c);
}
}
}
I took Dysnomin's answer and converted something over to Javascript. His answer was in C#
To run it, just take your string object and call variable.zplHexEncode() where the variable is your string. This defaults to the _ for the escape character. You will still have to prefix all you ^FD fields with the ^FH command. Personally, I use something like the doT module to create my ZPL and fill in the fields with values with escaped characters. YMMV.
const _Last1ByteCode = 0x7E;
const _First2ByteCode = 0xA0;
const _Last2ByteCode = 0xBF;
const _Last3ByteCode = 0xFF;
const _3ByteOffset = 0x40;
const _ZplEscapeCharacter = '_';
const _2BytePre = 'c2';
const _3BytePre = 'c3';
String.prototype.zplHexEncode = function(){
var hex, i, escHex;
var result = "";
for (i=0; i< this.length; i++) {
var charCode = this.charCodeAt(i);
if (charCode <= _Last1ByteCode)
result += String.fromCharCode(charCode);
else if (charCode >= _First2ByteCode && charCode <=_Last2ByteCode) {
hex = charCode.toString(16);
escHex = ("0"+hex).slice(-2);
result += _ZplEscapeCharacter+_2BytePre+_ZplEscapeCharacter+escHex;
}
else if (charCode > _Last2ByteCode && charCode <=_Last3ByteCode) {
charCode = charCode - _3ByteOffset;
hex = charCode.toString(16);
escHex = ("0"+hex).slice(-2);
result += _ZplEscapeCharacter+_3BytePre+_ZplEscapeCharacter+escHex;
}
else
result += '';
}
return result
}
var str = "This is a test with a unicode character¿";
console.log(str.zplHexEncode());
When we use CP1251 as system encoding it causes empty symbols in labels, if we write Cyrillic in ZPL code. CP1251 users could first force convert "До свидания" to UTF-8 and get:
До свидания
Replace До свидания in ZPL code with these strange symbols and get "До свидания" on the label. It works with tt0003m_.fnt with ^CI28, but IMHO it is better to use hex-codes instead.
For Cyrillic it is enough to change ^CI28 to ^CI33
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI33
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ

How to I18N PrimeFaces Editor

I cannot work out how to add internationalization to the PrimeFaces Editor (Version 3.2).
I need to translate tooltips, texts in comboboxes and change icons of the toolbar.
In an old users guide http://www.scribd.com/doc/49595285/46/Editor I found an attribute called "language" but this seems to be kind of disabled or removed for the actual version.
My project setup is JSF 2 with PrimeFaces 3.2 and GlassFish 3.1.2
I'd be very glad if you could show me how I can solve this problem.
Thanks and Kind regards,
Pedro
JMelnik is right. There is a workaround though!
You can do that by downloading the editor.js file from the primefaces subversion repository: 3_3_1/src/main/resources/META-INF/resources/primefaces/editor/editor.js and place it inside your project's META-INF/resources/primefaces/editor folder.
Now you can edit the file and change it according to you locale. I did it for some of the buttons in pt_BR:
buttons: {
// name,title,command,popupName (""=use name)
init:
"bold,Negrito,|" +
"italic,Itálico,|" +
"underline,Sublinhado,|" +
"strikethrough,Tachado,|" +
"subscript,Subscrito,|" +
"superscript,Sobrescrito,|" +
"font,Fonte,fontname,|" +
"size,Tamanho da Fonte,fontsize,|" +
"style,Estilo,formatblock,|" +
"color,Cor da fonte,forecolor,|" +
"highlight,Cor de Destaque do Texto,hilitecolor,color|" +
"removeformat,Remove Formatting,|" +
"bullets,Marcadores,insertunorderedlist|" +
"numbering,Numeração,insertorderedlist|" +
"outdent,Diminuir Recuo,|" +
"indent,Aumentar Recuo,|" +
"alignleft,Alinhar à Esquerda,justifyleft|" +
"center,Centralizar,justifycenter|" +
"alignright,Alinhar à Direita,justifyright|" +
"justify,Justificar,justifyfull|" +
"undo,,|" +
"redo,,|" +
"rule,Insert Horizontal Rule,inserthorizontalrule|" +
"image,Insert Image,insertimage,url|" +
"link,Insert Hyperlink,createlink,url|" +
"unlink,Remove Hyperlink,|" +
"cut,,|" +
"copy,,|" +
"paste,,|" +
"pastetext,Paste as Text,inserthtml,|" +
"print,,|" +
"source,Mostrar Código Fonte"
},
A i18n solution for that would be great since this approach won't support multiple locales and make you code depend on specific encoding (as it may use special characters).
Analysis
If we look at the PrimeFaces 3.2 documentation, there is no such attribute as language for Editor component and there is nothing mentioned in localization chapter.
PrimeFaces do not provide a way to localize Editor as they do provide for Calendar. And obviously they do provide it for calendar, because it is out of box feature for jQuery datePicker, which caledar is based on.
Outcome
Look for editor.js in PrimeFaces 3.2 sources. There is a section, where all editor buttons are initialized:
buttons: {
// name,title,command,popupName (""=use name)
init:
.....
"font,,fontname,|" +
"size,Font Size,fontsize,|" +
.....
}
There is provided format for separate button setup: name,title,command,popupName. The title part is the one you can make use of.
What you can do, you can build primefaces sources with your own titles provided, or override them in other way I cannot think of.
Help
If you are using maven, you can install customized primefaces in local or centralized repository of your own and use it instead of original dependency.
Lesson
You shouldn't look for old documentation, when you are using newer version. Look for the documentation of the version you are using.
Since JSF2 and Primefaces have jQuery, you can simply run this code on your page:
$(function(){
$(".ui-editor-group>.ui-editor-button").each(function(){
var title = $(this).attr("title").toLowerCase();
switch(title){
case "bold": title = "Negrito"; break;
case "italic": title = "Itálico"; break;
case "underline": title = "Sublinhado"; break;
case "align text left": title = "Alinhado à esquerda"; break;
case "center": title = "Centralizado"; break;
case "align text right": title = "Alinhado à direita"; break;
case "justify": title = "Justificado"; break;
case "insert hyperlink": title = "Inserir link"; break;
case "remove hyperlink": title = "Remover link"; break;
}
$(this).attr("title", title);
})
})
This little jQuery code can change Primefaces Editor's strings to wherever you want. I made it only for a few editor's components because I didn't used all of them.
If you need to translate the other options, simply add them inside the switch command. Don't forget that all titles inside switch command are in lowercase, due to ".toLowerCase()" method on line three. I've done this to simplify string management.
You can put it inside a function inside an external JavaScript file to get it cached, too.
This is a working example I made for Greek language (el_GR locale), all buttons:
$(".ui-editor-group>.ui-editor-button").each(function () {
var title = $(this).attr("title").toLowerCase();
switch (title) {
case "bold":
title = "Έντονα";
break;
case "italic":
title = "Πλάγια";
break;
case "underline":
title = "Υπογραμμισμένα";
break;
case "align text left":
title = "Στοίχιση αριστερά";
break;
case "center":
title = "Στοίχιση στο κέντρο";
break;
case "align text right":
title = "Στοίχiση δεξιά";
break;
case "justify":
title = "Στοίχιση";
break;
case "insert hyperlink":
title = "Εισαγωγή συνδέσμου";
break;
case "remove hyperlink":
title = "Αφαίρεση συνδέσμου";
break;
case "strikethrough":
title = "Διεγραμμένα";
break;
case "subscript":
title = "Δείκτης";
break;
case "superscript":
title = "Εκθέτης";
break;
case "font":
title = "Γραμματοσειρά";
break;
case "font size":
title = "Μέγεθος γραμματοσειράς";
break;
case "style":
title = "Στυλ";
break;
case "font color":
title = "Χρώμα γραμματοσειράς";
break;
case "text highlight color":
title = "Χρώμα επισήμανσης κειμένου";
break;
case "remove formatting":
title = "Κατάργηση μορφοποίησης";
break;
case "bullets":
title = "Λίστα με κουκκίδες";
break;
case "numbering":
title = "Αριθμητική λίστα";
break;
case "outdent":
title = "Προεξοχή";
break;
case "indent":
title = "Εσοχή";
break;
case "undo":
title = "Αναίρέση";
case "redo":
title = "Επαναφορά";
break;
case "insert horizontal rule":
title = "Eισαγωγή οριζόντιας γραμμής";
break;
case "insert image":
title = "Εισαγωγή εικόνας";
break;
case "cut":
title = "Κόψιμο";
break;
case "copy":
title = "Αντιγραφή";
break;
case "paste":
title = "Επικόλληση";
break;
case "paste as text":
title = "Επικόλληση ως απλό κείμενο";
break;
case "print":
title = "Εκτύπωση";
break;
case "show source":
title = "Εμφάνιση κώδικα";
break;
case "Show Rich Text":
title = "Εμφάνιση εύκολης επεξεργασίας άρθρου";
break;
}
$(this).attr("title", title);
});

Resources