Arsip: Meng-Indonesia-kan Message Dlg


by deLogic in Sistem more 16 years ago 4167
Artikel ini memaparkan bagaimana mengubah bahasa standar (Inggris) pada judul dan tombol MessageDlg menjadi Bahasa Indonesia.
Jangan percaya judul di atas. Yang dibahas di sini sesungguhnya hanyalah membuat antarmuka GUI untuk software WAV/MP3 Encoder\Decoder - Lame. Lame sudah lama negtop di dunia encoding & decoding suara antarformat MP3 & WAV. Namun yang akan saya ulas di bawah hanya pada fitur mengompres file MP3 hingga ukurannya menjadi lebih kecil. Yang selanjutnya, MP3 dengan ukuran kecil jauh lebih efisien digunakan pada handphone, PDA, MP3 player dan sejenisnya. Kualitas MP3 tergantung pada beberapa hal, seperti bitrate, jumlah channel, dan beberapa hal lain yang spesifik dengan digital music.

Secara standar, bahasa yang digunakan oleh Delphi untuk menampilkan pesan pada kotak dialog pada MessageDlg adalah bahasa Inggris.

MessageDlg('Professional SKU', mtInformation, [mbOK], 0);

Kode diatas akan menampilkan kotak dialog seperti gambar berikut:
MessagDlg Standard

Nah lalu bagaimanakah kode yang dibuat untuk menampilkan kotak dialog seperti gambar berikut?
MessagDlg ala Indonesia

Built From Scratch ?
Alternatif pertama adalah dengan membuat sendiri pustaka untuk menampilkan kotak dialog dengan bahasa Indonesia. Disini, diperlukan form dan konstanta tombol berbahasa Indonesia, membuat rutin yang berkaitan dengan User Interface, membuat event handler yang dibutuhkan dan sebagainya. Ah.. sudah terbayang betapa merepotkannya!

Modify The Source ?
Alternatif kedua, memodifikasi bahasa / teks yang digunakan oleh rutin MessageDlg yang disimpan pada unit Consts. Namun opsi ini menuntut Anda untuk mengkompilasi ulang source unit Delphi, sangat banyak dan beresiko terutama jika terdapat unit yang Anda tidak memiliki source-code nya.

Facade Pattern CreateMessageDialog
Alternatif yang lebih elegan adalah dengan membuat facade pattern dari fungsi CreateMessageDialog yang boleh jadi merupakan inti dari pembuatan kotak dialog. Kotak dialog dapat lebih variatif, seperti yang ditunjukkan oleh rekan Wisnu Widiarta pada tulisannya: classIndonesianDialog.


Nah.. menurut Anda saya menggunakan teknik yang mana? hmm tidak satupun, saya menggunakan teknik dan pendekatan yang berbeda, yaitu mengubah teks yang digunakan oleh MessageDlg di memori pada saat runtime.

Mengapa Modifikasi Memori ?
Tentu saja alasan saya modifikasi memori adalah saya tidak perlu susah payah membangun dari awal (built from scratch), memodifikasi source dan mengkompilasi ulang dan saya tidak perlu membuat facade pattern dari CreateMessageDlg. Saya cukup sekali saja mengganti teks yang digunakan oleh MessageDlg pada saat runtime, hasil modifikasi akan terus berlaku sampai aplikasi ditutup dan tentu saja tetap dengan memanggil fungsi MessageDlg. Dan hasilnya cukup efektif.

Langkah Pertama

Langkah pertama meng-Indonesia-kan MessageDlg adalah dengan menentukan dan mendeklarasikan pesan teks baru yang akan digunakan pada MessageDlg. Selengkapnya mengenai konstanta teks yang digunakan dapat disimak pada unit consts.pas. Sebagai petunjuk, konstanta yang terkait dengan MessageDlg adalah konstanta yang mengandung awalan (prefix) SMsgDlg. Berikut pendeklarasian konstanta yang baru:

const
_NewSMsgDlgWarning = 'Peringatan';
_NewSMsgDlgError = 'Kesalahan';
_NewSMsgDlgInformation = 'Informasi';
_NewSMsgDlgConfirm = 'Konfirmasi';
_NewSMsgDlgYes = '&Ya';
_NewSMsgDlgNo = '&Tidak';
_NewSMsgDlgOK = 'OK';
_NewSMsgDlgCancel = 'Batal';
_NewSMsgDlgHelp = '&Panduan';
_NewSMsgDlgHelpNone = 'Panduan tidak tersedia';
_NewSMsgDlgHelpHelp = 'Panduan';
_NewSMsgDlgAbort = '&Batal';
_NewSMsgDlgRetry = '&Ulang';
_NewSMsgDlgIgnore = 'A&cuh';
_NewSMsgDlgAll = '&Semua';
_NewSMsgDlgNoToAll = 'T&idak untuk Semua';
_NewSMsgDlgYesToAll = 'Ya untuk S&emua';

Yang Kedua
Nah, disinilah bagian yang paling menarik, yaitu pembuatan kode untuk memanipulasi isi memori, terutama yang berkaitan dengan teks pada MessageDlg.

1| procedure ReplaceResourceString(RStringRec: PResStringRec; AString: PChar);
2| var
3|   OldProtect: Cardinal;
4| begin
5|   if RStringRec = nil then Exit;
6|   if VirtualProtect(RStringRec, SizeOf(RStringRec^), PAGE_EXECUTE_READWRITE, OldProtect) then
7|   begin
8|     RStringRec^.Identifier := Integer(AString);
9|     VirtualProtect(RStringRec, SizeOf(RStringRec^), OldProtect, @OldProtect);
10|   end;
11| end;

Prosedur ReplaceResourceString memiliki 2 parameter. Parameter 1 bertipe PResStringRec, yaitu pointer untuk resource-string teks standar yang digunakan oleh MessageDlg. Sedangkan parameter 2 bertipe PChar, berisi teks yang akan digunakan untuk memodifikasi MessageDlg.


Pada baris 6 dan 9 terdapat rutin WindowsAPI VirtualProtect. API ini digunakan untuk mengubah proteksi akses suatu blok memori, apakah hanya baca saja, tulis saja, baca-tulis dan sebagainya. Berikut kutipan dari dokumentasi VirtualProtect.


The VirtualProtect function changes the access protection on a region of committed pages in the virtual address space of the calling process.

BOOL VirtualProtect(
LPVOID lpAddress,	// address of region of committed pages
DWORD dwSize, // size of the region
DWORD flNewProtect, // desired access protection
PDWORD lpflOldProtect // address of variable to get old protection
);

Return Values

If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.


Penggunaan VirtualProtect pada baris 6 bertujuan untuk mengubah proteksi akses blok memori menjadi baca-tulis pada alamat yang ditunjuk, dalam hal ini alamat resource-string tertentu. Hal ini dilakukan untuk memastikan bahwa blok memori tersebut dapat dimodifikasi. Baris 8 digunakan untuk mengubah teks pesan pada resource-string yang ditunjuk. Sedangkan pada baris 9 digunakan untuk mengembalikan proteksi akses blok memori sebelum modifikasi.

Terapkan Modifikasi
Tentu saja prosedur ReplaceResourceString tidak hanya sebatas dideklarasikan, namun harus digunakan. Agar efek modifikasi teks dapat langsung diterapkan, maka pemanggilan prosedur dilakukan pada bagian initialization unit.

initialization
ReplaceResourceString(@SMsgDlgWarning, _NewSMsgDlgWarning);
ReplaceResourceString(@SMsgDlgError, _NewSMsgDlgError);
ReplaceResourceString(@SMsgDlgInformation, _NewSMsgDlgInformation);
ReplaceResourceString(@SMsgDlgConfirm, _NewSMsgDlgConfirm);
ReplaceResourceString(@SMsgDlgYes, _NewSMsgDlgYes);
ReplaceResourceString(@SMsgDlgNo, _NewSMsgDlgNo);
ReplaceResourceString(@SMsgDlgOK, _NewSMsgDlgOK);
ReplaceResourceString(@SMsgDlgCancel, _NewSMsgDlgCancel);
ReplaceResourceString(@SMsgDlgHelp, _NewSMsgDlgHelp);
ReplaceResourceString(@SMsgDlgHelpNone, _NewSMsgDlgHelpNone);
ReplaceResourceString(@SMsgDlgHelpHelp, _NewSMsgDlgHelpHelp);
ReplaceResourceString(@SMsgDlgAbort, _NewSMsgDlgAbort);
ReplaceResourceString(@SMsgDlgRetry, _NewSMsgDlgRetry);
ReplaceResourceString(@SMsgDlgIgnore, _NewSMsgDlgIgnore);
ReplaceResourceString(@SMsgDlgAll, _NewSMsgDlgAll);
ReplaceResourceString(@SMsgDlgNoToAll, _NewSMsgDlgNoToAll);
ReplaceResourceString(@SMsgDlgYesToAll, _NewSMsgDlgYesToAll);

Sediakan Demo
Selanjutnya, persiapkan demo MessageDlg generator untuk menguji apakah modifikasi yang dilakukan berjalan dengan baik.

procedure TfrmDialogIndonesia.btnTampilClick(Sender: TObject);
var
JenisDialog   : TMsgDlgType;
PilihanTombol : set of TMsgDlgBtn;
I             : Integer;
begin
JenisDialog := TMsgDlgType(rgJenisDialog.ItemIndex);
PilihanTombol := [];
for I := 0 to chklbPilihanTombol.Count - 1 do
if chklbPilihanTombol.Checked[I] then Include(PilihanTombol, TMsgDlgBtn(I));
MessageDlg(mmoPesan.Text, JenisDialog, PilihanTombol, 0);
end;

Full .pas Code
Berikut kode kustomisasi MessageDlg selengkapnya:

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: DialogIndonesia.pas, released on 2007-10-18
The Initial Developer of the Original Code is Bayu Prasetio
Portions created by Bayu Prasetio are Copyright (C) 2007 Bayu Prasetio.
All Rights Reserved.
-----------------------------------------------------------------------------}
unit DialogIndonesia;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, CheckLst;
type
TfrmDialogIndonesia = class(TForm)
StatusBar1: TStatusBar;
rgJenisDialog: TRadioGroup;
gbPilihanTombol: TGroupBox;
chklbPilihanTombol: TCheckListBox;
GroupBox2: TGroupBox;
mmoPesan: TMemo;
bvTombol: TBevel;
btnTampil: TButton;
btnKeluar: TButton;
procedure btnTampilClick(Sender: TObject);
procedure btnKeluarClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmDialogIndonesia: TfrmDialogIndonesia;
implementation
{$R *.dfm}
uses
Consts;
procedure TfrmDialogIndonesia.btnKeluarClick(Sender: TObject);
begin
Close;
end;
procedure TfrmDialogIndonesia.btnTampilClick(Sender: TObject);
var
JenisDialog   : TMsgDlgType;
PilihanTombol : set of TMsgDlgBtn;
I             : Integer;
begin
JenisDialog := TMsgDlgType(rgJenisDialog.ItemIndex);
PilihanTombol := [];
for I := 0 to chklbPilihanTombol.Count - 1 do
if chklbPilihanTombol.Checked[I] then Include(PilihanTombol, TMsgDlgBtn(I));
MessageDlg(mmoPesan.Text, JenisDialog, PilihanTombol, 0);
end;
//------------------------------------------------------------------------------
const
_NewSMsgDlgWarning = 'Peringatan';
_NewSMsgDlgError = 'Kesalahan';
_NewSMsgDlgInformation = 'Informasi';
_NewSMsgDlgConfirm = 'Konfirmasi';
_NewSMsgDlgYes = '&Ya';
_NewSMsgDlgNo = '&Tidak';
_NewSMsgDlgOK = 'OK';
_NewSMsgDlgCancel = 'Batal';
_NewSMsgDlgHelp = '&Panduan';
_NewSMsgDlgHelpNone = 'Panduan tidak tersedia';
_NewSMsgDlgHelpHelp = 'Panduan';
_NewSMsgDlgAbort = '&Batal';
_NewSMsgDlgRetry = '&Ulang';
_NewSMsgDlgIgnore = 'A&cuh';
_NewSMsgDlgAll = '&Semua';
_NewSMsgDlgNoToAll = 'T&idak untuk Semua';
_NewSMsgDlgYesToAll = 'Ya untuk S&emua';
{-- taken from bpCodeReplacement.pas by Bayu Prasetio}
procedure ReplaceResourceString(RStringRec: PResStringRec; AString: PChar);
var
OldProtect: Cardinal;
begin
if RStringRec = nil then Exit;
if VirtualProtect(RStringRec, SizeOf(RStringRec^), PAGE_EXECUTE_READWRITE, OldProtect) then
begin
RStringRec^.Identifier := Integer(AString);
VirtualProtect(RStringRec, SizeOf(RStringRec^), OldProtect, @OldProtect);
end;
end;
initialization
ReplaceResourceString(@SMsgDlgWarning, _NewSMsgDlgWarning);
ReplaceResourceString(@SMsgDlgError, _NewSMsgDlgError);
ReplaceResourceString(@SMsgDlgInformation, _NewSMsgDlgInformation);
ReplaceResourceString(@SMsgDlgConfirm, _NewSMsgDlgConfirm);
ReplaceResourceString(@SMsgDlgYes, _NewSMsgDlgYes);
ReplaceResourceString(@SMsgDlgNo, _NewSMsgDlgNo);
ReplaceResourceString(@SMsgDlgOK, _NewSMsgDlgOK);
ReplaceResourceString(@SMsgDlgCancel, _NewSMsgDlgCancel);
ReplaceResourceString(@SMsgDlgHelp, _NewSMsgDlgHelp);
ReplaceResourceString(@SMsgDlgHelpNone, _NewSMsgDlgHelpNone);
ReplaceResourceString(@SMsgDlgHelpHelp, _NewSMsgDlgHelpHelp);
ReplaceResourceString(@SMsgDlgAbort, _NewSMsgDlgAbort);
ReplaceResourceString(@SMsgDlgRetry, _NewSMsgDlgRetry);
ReplaceResourceString(@SMsgDlgIgnore, _NewSMsgDlgIgnore);
ReplaceResourceString(@SMsgDlgAll, _NewSMsgDlgAll);
ReplaceResourceString(@SMsgDlgNoToAll, _NewSMsgDlgNoToAll);
ReplaceResourceString(@SMsgDlgYesToAll, _NewSMsgDlgYesToAll);
end.

Dan berikut salah satu aksi dari kode di atas.
MessagDlg ala Indonesia



Selengkapnya di http://blog.bprasetio.or.id/2007/10/22/meng-indonesia-kan-messagedlg/

Semoga bermanfaat.

Local Business Directory, Search Engine Submission & SEO Tools FreeWebSubmission.com SonicRun.com