Java国际化编程之中英文切换

本文介绍Java国际化编程的基本原理,通过具体实例演示了如何在Java应用中实现多语言支持,包括资源文件的创建与使用、语言切换功能的实现等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、国际化编程的本质及原理分析

  • 一套软件,多个语言包

Java是第一个设计成支持国际化的编程语言

  • 重点在于如下两个类;
  • java.util.ResourceBundle 用于加载一个语言_国家包
  • java.util.Locale 定义一个语言_国家
  • 语言 zh,en等,国家/地区CN,US
  • 语言文件
  • 就是一个properties文件
  • Properties 类在加载.proerties文件时使用的iso-8859-1的编码,所以由中文时必须进行native2ascii进行转义。
  • 包含键值对,形式为key=value,例如age=20;name=中国
  • 存储编码必须为ASCII编码,如果是ASCII以外的文字,则必须使用native2ascii.exe(%JAVA_HOME%/bin目录下)进行转码为Unicode,命令格式如下:
    native2ascii xxx.properties xxx_语言_国家.properties

命名规则:

  • 包名_语言_国家地区.properties (语言和国家/地区可选)
  • message.properties
  • message.zh.properties
  • message.zh_CN.properties

二、代码实践

项目文件结构如下图:
在这里插入图片描述
请先忽略其中的resource文件夹,com目录是编译Main.java时自动生成的class包目录,重点先关注Main.java文件,其中Main.java文件的内容如下:

package com.cholen;

import java.util.Locale;
import java.util.ResourceBundle;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class MainWindow extends JFrame implements ActionListener{
	private JLabel jlbAccount;
	private JLabel jlbPassword;
	private JTextField jtfAccount;
	private JTextField jtfPassword;
	private JButton btnLogin;
	private JButton btnCancel;
	private JPanel mainPanel;
	private JMenuBar jMenuBar;
	private JMenu jmLanguage;
	private JMenuItem jmiZH;
	private JMenuItem jmiEN;
	private static Locale locale;
	private static ResourceBundle bundle;
	public MainWindow(){
		mainPanel = new JPanel();
		mainPanel.setLayout(new GridLayout(3, 2, 5, 5));
		jlbAccount = new JLabel();
		jlbAccount.setHorizontalAlignment(JLabel.CENTER);
		jlbAccount.setVerticalAlignment(JLabel.CENTER);
		jlbPassword = new JLabel();
		jlbPassword.setHorizontalAlignment(JLabel.CENTER);
		jlbAccount.setVerticalAlignment(JLabel.CENTER);
		jtfAccount = new JTextField();
		jtfPassword = new JTextField();
		btnLogin = new JButton();
		btnCancel = new JButton();
		jMenuBar = new JMenuBar();
		jmLanguage = new JMenu();
		jmiZH = new JMenuItem();
		jmiEN = new JMenuItem();
		jmLanguage.add(jmiZH);
		jmLanguage.addSeparator();
		jmLanguage.add(jmiEN);
		jMenuBar.add(jmLanguage);

		mainPanel.add(jlbAccount);
		mainPanel.add(jtfAccount);
		mainPanel.add(jlbPassword);
		mainPanel.add(jtfPassword);
		mainPanel.add(btnLogin);
		mainPanel.add(btnCancel);

		setLanguage(locale);

		jmiEN.addActionListener(this);
		jmiZH.addActionListener(this);

		this.setJMenuBar(jMenuBar);
		this.getContentPane().add(mainPanel);
		this.setSize(512, 600);
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==jmiZH){
			locale = new Locale("zh", "CN");
			this.setLanguage(locale);
		}else if(e.getSource()==jmiEN){
			locale = new Locale("en", "US");
			this.setLanguage(locale);
		}
	}

	private void setLanguage(Locale locale){
		bundle = ResourceBundle.getBundle("messages", locale);
		this.setTitle(bundle.getString("mainWindowTitle"));

		jmLanguage.setText(bundle.getString("jmLanguage"));
		jmiZH.setText(bundle.getString("jmiZH"));
		jmiEN.setText(bundle.getString("jmiEN"));

		jlbAccount.setText(bundle.getString("jlbAccount"));
		jlbPassword.setText(bundle.getString("jlbPassword"));
		btnLogin.setText(bundle.getString("btnLogin"));
		btnCancel.setText(bundle.getString("btnCancel"));

	}
	static {
		// 取得系统默认的国家_语言环境
		locale = Locale.getDefault();
	}


}
public class Main{
	public static void main(String[] args){
		new MainWindow();
	}
}

进入到Main.java所在的文件夹下,执行如下编译命令即可生成上述的com目录:

javac -d . Main.java

其中messages_zh_CN.properties原始内容如下:

jmLanguage=语言
jmiZH=中文
jmiEN=英文
jlbAccount=账号
jlbPassword=密码
btnLogin=登录
btnCancel=取消
mainWindowTitle=微信
  • 请务必在保存时将该文件保存为ascii类型

进入到message_zh_CN.properties文件所在的目录,接下来用native2ascii.exe进行转码,命令如下:

native2ascii message_zh_CN.properties message_zh_CN.properties
  • native2ascii的第一个参数是src文件名,第二个参数是out文件名

这里将输出和输入定为一样的,则原来的message_zh_CN.properties会被覆盖,被覆盖后的内容如下:

jmLanguage=\u8bed\u8a00
jmiZH=\u4e2d\u6587
jmiEN=\u82f1\u6587
jlbAccount=\u8d26\u53f7
jlbPassword=\u5bc6\u7801
btnLogin=\u767b\u5f55
btnCancel=\u53d6\u6d88
mainWindowTitle=\u5fae\u4fe1

其中message_en_US.properties的内容如下:

jmLanguage=language
jmiZH=Chinese
jmiEN=English
jlbAccount=account
jlbPassword=password
btnLogin=login
btnCancel=cancel
mainWindowTitle=WeChat
  • 由于其本身就是英文,所以不需要用native2ascii进行转码,但请务必在保存时选择保存为ascii类型

直接用java命令运行生成的com.cholen.Main.class 文件,效果图如下面视频所展示:

Java国际化编程效果展示 (中英文切换)

这里视频不清晰的话,请移步到下方链接地址:

https://www.bilibili.com/video/BV1hA41177Yv/

三、实践过程中的问题

3.1 问题提出

在开始编写代码时,我并没有将MainWindow类实现ActionListener接口,而是想到的是直接在构造函数中为菜单项 “中文”、“英文”(代码中的jmiZH、jmiEN)直接addActionListener实现语言_地区的转换,而本例由于要在addActionListener中调用该类的一个成员方法setLanguage(Locale locale), 由于此时构造函数没有执行完,对象还没有生成,所以这样的做法不成功

3.2 问题解决

让MainWindow这个类去实现ActionListener接口,并重写其中的actionPerformed(ActionEvent e)方法,如下:

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==jmiZH){
			locale = new Locale("zh", "CN");
			this.setLanguage(locale);
		}else if(e.getSource()==jmiEN){
			locale = new Locale("en", "US");
			this.setLanguage(locale);
		}
	}

务必在构造函数中为菜单项 “中文”、“英文”(代码中的jmiZH、jmiEN)添加事件监听,代码如下:

	jmiEN.addActionListener(this);
	jmiZH.addActionListener(this);

四、代码实践后的思考

4.1 关于.properties文件存放的路径问题

messages_en_US.properties和messages_zh_CN.properties文件目前必须放在类的顶级目录下,

  • 能否将其放在某个包下面,此时如何找到该资源文件?
  • 能否新建一个resource目录,再在resource目录下新建一个language目录,将其放在该目录下,此时如何找到该资源文件?

4.2 解决方案

4.2.1 可以将资源文件放在某个包下面,譬如我将其放在com包目录下,如下图展示:

在这里插入图片描述

那么此时源代码中的:

	bundle = ResourceBundle.getBundle("messages", locale);

这一行应改为:

	bundle = ResourceBundle.getBundle("com.messages", locale);

也就是说带上包名

4.2.2 可以将资源文件放在\resource\language目录下,如下图展示:

在这里插入图片描述
问题的关键就在于Java对于外部资源的访问,这是一个主题,值得弄懂学习,读者可以自行学习,我这里直接给出解决方案,自己写一个流将资源文件读入(请务必关注资源的路径问题)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值