BẢN ĐỊA HÓA CÁC GIAO DIỆN ĐỒ HỌA

Ở trên chúng ta đã đề cập đến những vấn đề chính của công việc bản địa hoá phần mềm. Phần này, chúng ta giải thích cách địa phương hoá các yêu cầu để thay đổi các mã lệnh mà bạn đã viết. Chúng ta xét phương thức lập trình sau:

public class MyApplet extends JApplet implements ActionLístenerl

public void init(){

JButton cancelButton = new JButton(“Cancel”); cancelButton.addActionListener(this);

}

public void actionPerformed(ActionEvent evt){ String arg = evt.getActioncommand(); if(arg.equals(“Cancel”)) doCancel (); else …

}

}

Dễ nhận thấy, tên gọi của nút nhấn “Cancel” sử dụng tốt cho những người biết tiếng Anh, nhưng khi chương trình sử dụng cho người Việt thl phải dịch thành “Hủy bỏ“. Do vậy, các tên gọi, thông báo phải được cập nhật tự động cả ở phương thức init () và actionPerformed (). Nhưng nếu vl một lý do nào đấy mà ta quên không cập nhật một trong các hàm đỏ thì những nút này sẽ không thực hiện được như mong muốn. Để khắc phục vấn đề nêu trên, ta có thể thực hiện theo các chiến lược:

  1. Sử dụng các lớp bên trong thay vì sử dụng các phương thức riêng actionPerformed().
  1. Xác định các thành phần thông qua các tham chiếu của chúng chứ không phải bằng các tên cùa các nhãn.
  2. Sử dụng thuộc tính name của lớp Component để xác định các thành phần.

Chúng ta lần lượt xét các cách nêu trên.

1. Sử dụng lớp bên trong

Thay vì tạo ra một bộ xử lý để xử lý cho nhiều hành động, ta có thể định nghĩa một bộ xử lý riêng cho mỗi thành phần. Ví dụ, đoạn chương trinh trên được viết thành:

public class MỵApplet extends JApplet implements ActionListener{ public void init(){

JButton cancelButton = new JButton(“Cancel”); cancelButton.addActionListener( new ActionListener(){

public void actionPerformed(ActionEvent evt){ doCancel() ;

}

}) ;

}

}

Chương trình tạo ra một lớp bèn trong để lắng nghe sự kiện khi nút nhấn Cancel. Do vậy, chí có một chỗ xuất hiện tên của thảnh phần cần được dịch sang tiếng bản địa.

2. Xác định các thành phần thông qua các tham chiếu

Nhiều khi ta không muốn sử dụng những lớp bên trong một lớp khác, bởi vì như thế có thể dẫn đến sự nhập nhằng trong một số thao tác, như đọc dữ liệu chẳng hạn. Chúng ta có cách thực hiện khác là đặt các thành phần vào các biển thể hiện và so sánh chung với câu lệnh tương ứng để xử lý các sự kiện.

public class MyApplet extends JApplet implements ActionListener{ JButton cancelButton;

public void init(){ cancelButton = new JButton(“Cancel”); cancelButton.addActionListener(this);

public void actionPerformed(ActìonEvent evt){

Object source = evt.getSource(); if(source == cancelButton) doCancel(); else …

}

}

3. Sử dụng thuộc tính name của lớp Component để xác định các thành phần

Các thành phần mà chúng ta xây dựng đều là lớp con cùa Component, vì thế có thể sử dụng thuộc tính name thông qua hàm get Name () để xác định thành phần tuông ứng. Đặc trưng tên gọi cùa thành phần là bất biến đối với mọi sự thay đổi tên (nhãn) của chúng khi cần bản địa hoá chương trình. Ví dụ, nếu ta gắn cho nút “Huý bò” với tèn gọi là “Cancell” thòng qua name bằng cách sử dụng setName (“Cancel 1”) trong chương trình thì nó không phải là nhãn được hiển thị của nút đó, mà là xâu tương ứng.

public class MyApplet extends JApplet implements ActionListener{ public void init(){

JButton cancelButton = new JButton(“Cancel”); cancelButton.setName(“Cancell”); cancelButton.addActionListener(this);

}

publíc void actionPeríormed(ActionEvent evt){

Component source – evt.getSource(); if(source.getName().equals(“Cancell”) doCancel(); else …

}

}

Như vậy, nếu nhãn cùa nút huý bò được hiển thị là “Cancel” (trong tiếng Anh), và khi cần được dịch sang một ngôn ngữ khác, ví dụ được dịch sang tiếng Việt Nam là “Huỳ bò” thì tên đặt trong chương trình cùa nút đó vẫn không bị thay đổi, nó vẫn là “Cancel 1”.

Ví dụ 8.6, Chương trình applet tính toán và hiển thị biểu đồ số tiền tiết kiệm và khả năng thu nhập khi nghỉ hưu (nghỉ làm việc) ờ nhiều nước khác nhau như hình 8.7, 8.8.

Người sử dụng có thể chọn khu vực (English, China, Germany) và nhập vào:

  • Số tiền tiết kiệm được từ trước (Prior Savings),
  • Số tiền tiết kiệm hàng năm (Annual Contribution),
  • Thu nhập khi nghỉ việc (Retirement Income),
  • Tuổi hiện nay (Current Age),
  • Tuồi nghi hưu (Retirement Age),
  • Dự kiến tuổi thọ (Life Expectancy),
  • Tỳ lệ lạm phát (Inf lation),
  • Tỷ lệ tăng trường (Investment Return).

Sau khi nhập các sổ liệu nêu trên, nhấn nút “Compute” để tính và vẽ lại biểu đồ về thu nhập theo các độ tuổi về hưu.

Vùng văn bản hiển thị số tiền dư hàng năm từ năm hiện thời cho đến tuổi thọ dự kiến và tưcmg ứng là biểu đồ mô tả ờ vùng bên trái.

Chương trình tính toán tiền tiết kiệm và khả năng thu nhập khi nghi làm việc chạy thử cho ba nước: Anh, Đức và Việt Nam. Sau đây là một số điểm cần chú ý trong chương trình.

  • Các nhãn, tên nút và các thông báo được dịch sang tiếng Đức, tiếng Việt tương ứng có thể tìm thấy trong các lóp: RetireResources, RetireResources_de, RetireResources_zh.
  • Các trường vãn bản xử lý các dữ liệu số, tiền tệ và tỳ lệ % theo khuôn dạng cùa từng vùng bản địa.
  • Trường tính toán sử dụng Mes sage Format.
  • Ta có thể chọn màu khác nhau để hiển thị biểu đồ cho từng nước theo yêu cầu của người sử dụng.

// Retire, java import java.io.*; import javax.swing.*; import java.awt.*; import java.awt.event. *; import java.text.*; import java.util.*; import java.applet.*;

public class Retire extends JAppleti

private JTextField savingsField = new JTextField(10); private JTextField contribField = new JTextField(10); private JTextField incomeField = new JTextField(10); private JTextField currentAgeField = new JTextField (4) ; private JTextField retireAgeField = new JTextField (4) ; private JTextField deathAgeField = new JTextField(4); private JTextField inflationPercentField = new JTextField(6); private JTextField investPercentField = new JTextField(6); private JTextArea retireText = new JTextArea (10, 25); private RetireCanvas retireCanvas = new RetireCanvas(); private JButton computeButton = new JButton(); private JLabel langLabel = new JLabel(); private JLabel saviLabel = new JLabel (); private JLabel contLabel = new JLabelO; private JLabel incoLabel = new JLabelO;

JLabel currLabel = new JLabel(); JLabel retiLabel = new JLabel(); JLabel deadLabel = new JLabel(); JLabel inflLabel = new JLabel(); JLabel inveLabel = new JLabel();

private Retirelnfo info = new Retirelnfo ();

Locale[] locales;

Locale currentLocale ;

JComboBox comboBox = new JComboBox(); ResourceBundle res;

NumberFormat currencyFmt;

NumberFormat numberFmt;

NumberFormat percentFmt;

public void init(){

GridBagLayout gbl = new GridBagLayout(); getContentPane().setLayout(gbl);

GridBagConstraints gbc = new GridBagConstraints(); gbc.weightx = 100; gbc.weighty = 0;

gbc.f111= GridBagConstraints.NONE; gbc.anchor = GridBagConstraints.EAST;

add(inflationPercentField, gbc, 1, 3, 1, 1); add(investPercentField, gbc, 3, 3, 1, 1);

computeButton.setName(“computeButton”); computeButton.addActionListener( new ActionListener() {

public void actionPerformed(ActionEvent evt){ getlnfo(); updateData(); updateGraph();

}

}) ;

add(computeButton, gbc, 5, 3, 1, 1); gbc.weighty = 100;

gbc.fill= GridBagConstraints.BOTH; add(retireCanvas, gbc, 0, 4, 4, 1); add(new JScrollPane (retireText), gbc, 4, 4, 2, 1); retireText.setEditable(false);

retireText.setFont(new Font(“Monospaced”, Font.PLAIN, 10));

info.setSavings(0); info.setContrib(9000); info.setIncome(60000); info.setCurrentAge(35);

info.setRetìreAge(65) ;

info.setDeathAge(85) ;

info.setInvestPercent(0.1) ;

info.setInflationPercent(0.05) ;

comboBox.addActionListener( new ActionListener(){

public void actionPerformed(ActionEvent evt){

setCurrentLocale(comboBox.getSelectedlndex());

}

)) ;

locales = new Locale[]

{Locale.US, Locale.CHINA, Locale.GERMAN);

int locale Index = 0; //Mặc định là US for(int i = 0; i < locales.length; i + +)

if(getLocale 0.equals(locales[i])) localelndex = i;

setCurrentLocale(localelndex);

}

public void add(Component c, GridBagConstraints gbc, int X, int y, int w, int h){ gbc.gridx = x; gbc.gridy = y; gbc.gridheight = h; gbc.gridwidth = w; getContentPane().add(c, gbc);

}

public void setCurrentLocale(int localelndex){ currentlocale = locales(localelndex];

comboBox.removeAlIIterns() ;

String language;

for(int i = 0; i < locales.length; Ì++){

language = locales[i].getDìsplayLanguage(currentLocale); comboBox.addltem(language) ;

}

comboBox.setSelectedlndex(localelndex);

res = ResouraèBundle.getBundle(“Pet±ceResouraes”, currentLocale);

currencỵRnt = NumberFormat.getCurrencylnstanae(currentlocale); numberRnt = NumberFormat.getNưmberlnstance(currentlocale); percentRnt = NumberFormat.getPercentInstance(currentLocale);

updateDisplay() ; updatelnfo(); updatèData(); updateGraph();

)

public void updatePisplay(){

langLabel.setText(res.getstring(“language”)); saviLabel.setText(res.getstring(“savings”)); contLabel.setText(res.getstring(“contrib”)); incoLabel.setText(res.getstring(“income”)); currLabel.setText(res.getstring(“currentAge”)); retiLabel.setText(res,getString(“retireAge”)); deadLabel.setText(res.getstring(“deathAge”)); inflLabel.setText(res,getString(“inflationPercent”));

inveLabel.setText (res.getstring(“investPercent”)); computeButton.setText(res.getstring(“computeButton”));

validate();

}

public void updatelnfo() {

savingsField.setText(currencyEmt.format(info.getSavings())); contribField.setText(currencyFmt.format(info.getcontrib 0));

inccmeField. setText (currencyFbt. format (info.getlncome ()) ) ; currentAgeField. setText (numberEbt. format (info. getCurrentAge ())); retireAgeField.setText(numberEbt.format(info.getRetireAge())); deathAgeField.setText(numberEbt.format(info.getDeathAge())); inflatiaitermritFiekLsetfed: (percaTtffrt.fcmat (infc.getlfflatirTibrml: ())); inyestterteritField. setText (peraentFMt. format (info, get L-rvestEfercent ()));

}

public void updateData(){ retireText.setText(“”);

MessageFormat retireMsg = new MessageFormat (“”);

retireMsg.setLocale(currentLocale);

retireMsg.applyPattern(res.getString(“retire”));

for(int i = info.getCurrentSge(); i <= info.getDeathAge (); i++) { Gbject[] args = {new Integer (i), new Double (info. getBalance(i))); retireText.append(retird^sg.format(args) + “\n”) ;

}

}

public void updateGraph(){

retireCanvas. setColorGain ((Color) res.getObject (“oolorGain”)); retireCanvas.setColorPre((Color) res.getObject (“colorPre”)); retireCanvas. setCblorLoss ((Color) res. getObject (“colorloss”));

retireCanvas.setlnfo(info) ; repaint();

)

public void getInfo(){ try {

info.setSavings(currencyFmt.parse(

savingsField.getText()).doubleValue()); info.setContrib (currencyFmt.parse (

contribField.getText()).doubleValue());

info . setlncome (currencyFmt .parse (

incomeField.getText()).doubleValue()); info.setCurrentAge(numberFmt.parse(

currentAgeField.getText()).intValue()); info.setRetireAge{numberFmt.parse(

retireAgeField.getText()) .intValue ()); info.setDeathAge(numberFmt.parse(

deathAgeField.getText()).intValue() ) ; info.setlnvestPercent(percentFmt.parse{‘

investPercentField.getText()).doubleValue()); info.setlnflationPercent(percentFmt.parse(

inflationPercentField.getText()).doubleValue());

}catch(ParseException e){

}

}

}

class Retìreĩnfo{

public double getBalance(int year){ if(year < currentAge) return 0; else if(year == currentAge){ age = year; balance = savings; return balance;

}else if(year == age) return balance; else if(year != age + 1) getBalance(year – 1); age = year; if (age < retireAge) balance += contrib; else

balance -= income;

balance “ balance * (1 + (investPercent – inflationPercent));

return balance;

}

public double getSavings(){ return savings;

}

public double getContrib(){ return contrib;

}

public int getCurrentAge() { return currentAge;

}

public int getRetireAge(){ return retireAge;

}

public double getIncome(){ return income;

}

public int getDeathAge(){

.return deathAge;

}

public double getlnflationPercent(){ return inflationPercent;

}

public double getInvestPercent(){ return investPercent;

}

public void setSavings{double x) { savings = x;

}

public void setContrib(double x){ contrib = x;

}

« <

public void setlncome(double x){

income = x;

}

public void setCurrentAge(int x){ currentAge = x;

}

public void setRetireAge(int x){ retireAge = x;

}

public void setDeathAge(int x) { deathAge = x;

}

public void setlnflationPercent(double x){ inflationPercent = x;

}

public void setlnvestPercent(double x){ investPercent = x;

}

private double savings; private double contrib; private double income; private double inflationPercent; private double investPercent; private int currentAge; private int retireAge; private int deathAge;

private int age-; private double balance;

}

class RetireCanvas extends JPanel{ public RetireCanvas(){ setSize(300, 300);

}

public void setlnfo(Retirelnfo newlnfo){ info = newlnfo;

}

public void paint(Graphics g){ if(info == null) return; double minValue = 0; double maxValue = 0; int i ;

for(i = info.getCurrentAge(); i <= info.getDeathAge(); i++){ double v = info.getBalance(i); if(minValue > v) minValue = v; if(maxValue < v) maxValue = v;

}

if(maxValue == minValue) return;

int harW = getWidfhO / (infb.getDaathAgeO – info.getQjrrantAgeO + 1);

double scale – getHeight() I (maxValue – minValue);

for(i = info.getCurrentAge (); i <= info.getDeathAge (); i++) {

int xl = (i – info.getCurrentAge()) * barW + 1; int yl;

double v = info.getBalance ( i); int h;

int y = (int) (maxValue * scale); if(v >= 0){

yl = (int)((maxValue – v) * scale); h = y – yl;

} else{

yl = y;

h = (int) (-v * scale);

}

if(i < info.getRetireAge()) g.setColor (colorPre);

else if( V >= 0)

g.setColor(colorGain);

else

g.setColor(colorLoss); g.fillRect(xl, yl, barW -2, h); g.fillRect(xl, yl, barW -2, h) ;

}

}

public void setColorPre(Color c) { colorPre = c;

}

public void setColorGain(Color c) { colorGaìn = c;

}

public void setColorLoss(Color c) { colorLoss = c;

}

private Retirelnfo info = null; private Color colorPre; private Color colorGain; private Color colorLoss;

}

// RetireResources java: Lóp hiển thị tiếng Anh

import j ava.util.*; import java.awt.*;

public class RetireResources extends ListResourceBundle{ public Object[][] getContents(){ return contents;

}

static final Object[][] contents -{

{“language”, “Language”},

{“computeButton”, “Compute”},

{“savings”, “Prior Savings”},

{“contrib”, “Annual Contribution”},

{“income”, “Retirement Income”},

{“currentAge”, “Current Age”},

{“retireAge”, “Retirement Age”},

{“deathAge”, “Life Expectancy”},

{“inflationPercent”, “Inflation”},

{“investPercent”, “Investment Return”},

{“retire”, “Age: {0, number} Balance: {1, number, currency}” },

{“colorPre”, Color.blue},

{“colorGain”, Color.white},

{“colorLoss”, Color.red}

};

}

// RetireResources_de.java: Lớp hiển thị tiếng Đức import java.util.*; import java.awt.*;

public class RetireResources_de extends ListResourceBundle{

public Object [][ 3 getContents() { return contents;

}

static final Object[][] contents ={

{“language”, “Sprache”},

{“computeButton”, “Rechnen”},

{“savings”, “Prior Savings”},

{“contrib”,  “J%hrliche Einzahlung”},

{“income”, “Einkommen nach Ruhestand”},

{“currentAge”, “Jetziges Alter”},

{“retireAge”, “Ruhestandsalter”},

{“deathAge”, “Lebenserwartung”},

{“inflationPercent”, “Inflation”},

{“ìnvestPercent”, “Investitionsgewinn”},

{“retire”, “Alter: {0, number} Guhaben: {1, number, currency}”}, {“colorPre”, Color.yellow},

{“colorGain”, Color.black},

{“colorLoss”, Color.red}

} ;

}

// RetireResources zh.java. Lớp hiển thị tiếng Việt import java.util.*; import j ava.awt.*;

public class RetireResources_zh extends ListResourceBundle{

public Object [][] getContents () { return contents;

}

static final Objectnu contents ={

{“language”, “Ngon ngu”},

{“computeButton”, “Tình”},

{“savings”, “Tich luy tu truoc”},

{“contrib”, “Thu nhap hang nam”},

(“income”, “Thu nhap khi nghi huu”},

{“currentAge”, “Tuoi hien nay”},

{“retíreAge”, “Tuoi nghi huu”},

{“deathAge”, “Du kien tuoi tho”},

{“inflationPercent”, “Ty le lam phat”},

{ “investPercent”, “Ty l,e tang truong”},

{“retire”, “Tuoi: {0, nunber} So du: {1, nurrber, currency}”},

{“colorPre”, Color.yellow},

{“colorGain”, Color.black},

{“colorLoss”, Color.red}