Java ResourceBundle
最后修改于 2024 年 1 月 27 日
在本 Java ResourceBundle 教程中,我们将展示如何在 Java 中使用 ResourceBundle。
硬编码特定于区域设置的数据不是一个好方法。诸如消息或标签之类的值应放置在单独的文件中。这样,我们就可以处理多个区域设置,而无需为每个区域设置编写不同的代码。这对于翻译人员来说也很方便,因为他们只处理可翻译的文本,而不查看编程代码。
Java ResourceBundle
资源包是一个 Java 属性文件,其中包含特定于区域设置的数据。它是一种通过使代码与区域设置无关来国际化 Java 应用程序的方式。
资源包被组织成具有公共基本名称的系列。例如,如果我们有一个 words 基本名称,words_sk 匹配斯洛伐克语的区域设置。如果不支持特定的区域设置,则使用默认资源包。
资源包还支持方言;例如,words_es_AR 用于阿根廷使用的西班牙语,而 words_es_BO 用于玻利维亚。
ResourceBundle 是一个抽象类,它有两个子类:PropertyResourceBundle 和 ListResourceBundle。PropertyResourceBundle 从属性文件加载数据。属性文件是一个纯文本文件,其中包含可翻译的文本。属性文件不是 Java 源代码的一部分,它们只能包含 String 值。ListResourceBundle 使用方便的列表管理资源;它从类文件获取数据。我们可以将任何特定于区域设置的对象存储在 ListResourceBundle 中。
要获取适当的 ResourceBundle,我们调用 ResourceBundle.getBundle 方法。这是一个工厂方法,它查找 ListResourceBundle,如果找不到,则查找 PropertyResourceBundle。如果找不到资源包,则抛出 MissingResourceException。
Java PropertyResourceBundle 示例
在第一个应用程序中,我们创建一个简单的 Java 应用程序,它使用三个资源包:默认的英语、德语和斯洛伐克语。
我们创建三个属性文件并将它们放在 resources 目录中。
w1 = Earth w2 = ocean
这是默认的属性文件;它通常使用英语。我们在文件中包含两个单词。
w1 = Erde w2 = ozean
words_de.properties 文件包含德语单词。
w1 = Zem w2 = oceán
words_sk.properties 文件包含斯洛伐克语单词。
package com.zetcode;
import java.util.Locale;
import java.util.ResourceBundle;
public class ResourceBundleEx {
static public void main(String[] args) {
Locale[] locales = {
Locale.GERMAN,
new Locale("sk", "SK"),
Locale.ENGLISH
};
System.out.println("w1:");
for (Locale locale : locales) {
getWord(locale, "w1");
}
System.out.println("w2:");
for (Locale locale : locales) {
getWord(locale, "w2");
}
}
static void getWord(Locale curLoc, String key) {
ResourceBundle words
= ResourceBundle.getBundle("resources/words", curLoc);
String value = words.getString(key);
System.out.printf("Locale: %s, Value: %s %n", curLoc.toString(), value);
}
}
在代码示例中,我们打印三个资源包中使用的所有单词。
Locale[] locales = {
Locale.GERMAN,
new Locale("sk", "SK"),
Locale.ENGLISH
};
我们在示例中有三个区域设置:德语、斯洛伐克语和英语。
for (Locale locale : locales) {
getWord(locale, "w1");
}
我们遍历这些区域设置并打印用 w1 键标记的单词。
ResourceBundle words
= ResourceBundle.getBundle("resources/words", curLoc);
使用 ResourceBundle.getBundle 方法,我们获得当前使用区域设置的包。由于我们没有创建 ListResourceBundle,因此该方法使用 PropertyResourceBundle,它从属性文件加载数据。
String value = words.getString(key);
System.out.printf("Locale: %s, Value: %s %n", curLoc.toString(), value);
我们获取该值并打印区域设置名称、键和值。
w1: Locale: de, Value: Erde Locale: sk_SK, Value: Zem Locale: en, Value: Earth w2: Locale: de, Value: ozean Locale: sk_SK, Value: oceán Locale: en, Value: ocean
Java ListResourceBundle 示例
在以下应用程序中,我们使用 ListResourceBundle。
我们为斯洛伐克语和捷克语创建区域设置资源。
package com.zetcode.myres;
import java.util.ListResourceBundle;
public class MyResources_sk extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return resources;
}
private final Object[][] resources = {
{ "Capital", "Bratislava" },
{ "Area", 49035 },
{ "Currency", "EUR" },
};
}
这里我们有一个 ListResourceBundle 的斯洛伐克语实现。我们必须覆盖 getContents 方法。该方法返回键/值对的数组。
package com.zetcode.myres;
import java.util.ListResourceBundle;
public class MyResources_cs_CZ extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return resources;
}
private final Object[][] resources = {
{ "Capital", "Praha" },
{ "Area", 78866 },
{ "Currency", "CZK" },
};
}
这是捷克语的实现。
package com.zetcode;
import java.util.Locale;
import java.util.ResourceBundle;
public class ResourceBundleEx2 {
public static void main(String[] args) {
Locale sk_loc = new Locale("sk", "SK");
ResourceBundle bundle =
ResourceBundle.getBundle("com.zetcode.myres.MyResources", sk_loc);
System.out.println("Capital: " + bundle.getObject("Capital"));
System.out.println("Area: " + bundle.getObject("Area"));
System.out.println("Currency: " + bundle.getObject("Currency"));
System.out.println();
Locale cz_loc = new Locale("cs", "CZ");
ResourceBundle bundle2 =
ResourceBundle.getBundle("com.zetcode.myres.MyResources", cz_loc);
System.out.println("Capital: " + bundle2.getObject("Capital"));
System.out.println("Area: " + bundle2.getObject("Area"));
System.out.println("Currency: " + bundle2.getObject("Currency"));
}
}
该示例打印斯洛伐克和捷克共和国的一些地理数据。
Locale sk_loc = new Locale("sk", "SK");
ResourceBundle bundle =
ResourceBundle.getBundle("com.zetcode.myres.MyResources", sk_loc);
使用 ResourceBundle.getBundle 方法,我们从 com.zetcode.myres.MyResources_sk.class 创建一个资源包。
Capital: Bratislava Area: 49035 Currency: EUR Capital: Praha Area: 78866 Currency: CZK
Swing 应用程序
在第三个示例中,我们使用 Java Swing 创建一个简单的 GUI 应用程序。该示例可以动态更改 UI 的语言。 该示例使用 ListResourceBundle 类。
源代码和图像可在作者的 Github 存储库中找到。
package com.zetcode.myres;
import java.util.ListResourceBundle;
import javax.swing.ImageIcon;
public class MyResources_sk extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return resources;
}
private final Object[][] resources = {
{"name", "Slovensko"},
{"lang_menu", "Jazyk"},
{"lang_sk", "Slovenčina"},
{"lang_hu", "Maďarčina"},
{"flag", new ImageIcon("src/resources/slovakia.png")},
{"description", "Slovensko je vnútrozemský štát v strednej Európe."}
};
}
这些是斯洛伐克语的资源。我们有五个字符串和一个 ImageIcon。
package com.zetcode.myres;
import java.util.ListResourceBundle;
import javax.swing.ImageIcon;
public class MyResources_hu extends ListResourceBundle {
@Override
protected Object[][] getContents() {
return resources;
}
private final Object[][] resources = {
{"name", "Magyarország"},
{"lang_menu", "Nyelv"},
{"lang_sk", "Szlovák"},
{"lang_hu", "Magyar"},
{"flag", new ImageIcon("src/resources/hungary.png")},
{"description", "Magyarország közép-európai ország "
+ "a Kárpát-medencében."}
};
}
这些是匈牙利语的资源。
package com.zetcode;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.LayoutStyle;
/*
* Java ResourceBundle tutorial
*
* This program uses a ResourceBundle in a
* Java Swing application.
*
* Author: Jan Bodnar
* Website: zetcode.com
* Last modified: October 2022
*/
public class ResourceBundleEx3 extends JFrame {
private ResourceBundle bundle;
private JLabel flag;
private JLabel lbl;
private JMenu langMenu;
private JRadioButtonMenuItem skMenuItem;
private JRadioButtonMenuItem huMenuItem;
public ResourceBundleEx3() {
initUI();
}
private void initUI() {
createMenuBar();
flag = new JLabel();
lbl = new JLabel();
updateLanguage(new Locale("sk", "SK"));
createLayout(lbl, flag);
pack();
setTitle(bundle.getString("name"));
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void updateLanguage(Locale locale) {
bundle = ResourceBundle.getBundle("com.zetcode.myres.MyResources", locale);
langMenu.setText(bundle.getString("lang_menu"));
skMenuItem.setText(bundle.getString("lang_sk"));
huMenuItem.setText(bundle.getString("lang_hu"));
flag.setIcon((Icon) bundle.getObject("flag"));
lbl.setText(bundle.getString("description"));
setTitle(bundle.getString("name"));
pack();
}
private void createMenuBar() {
JMenuBar menubar = new JMenuBar();
langMenu = new JMenu();
langMenu.setMnemonic(KeyEvent.VK_F);
ButtonGroup btnGroup = new ButtonGroup();
skMenuItem = new JRadioButtonMenuItem("Slovak", true);
btnGroup.add(skMenuItem);
skMenuItem.addActionListener((ActionEvent e) -> {
updateLanguage(new Locale("sk", "SK"));
});
langMenu.add(skMenuItem);
huMenuItem = new JRadioButtonMenuItem("Hungarian");
btnGroup.add(huMenuItem);
huMenuItem.addActionListener((ActionEvent e) -> {
updateLanguage(new Locale("hu", "HU"));
});
langMenu.add(huMenuItem);
menubar.add(langMenu);
setJMenuBar(menubar);
}
private void createLayout(JComponent... arg) {
Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(arg[1])
);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
ResourceBundleEx3 ex = new ResourceBundleEx3();
ex.setVisible(true);
});
}
}
我们有一个菜单栏,其中包含一个菜单,该菜单包含两个单选按钮菜单项。 选择一个单选按钮菜单项会更改应用程序用户界面的语言。
private void updateLanguage(Locale locale) {
bundle = ResourceBundle.getBundle("com.zetcode.myres.MyResources", locale);
langMenu.setText(bundle.getString("lang_menu"));
skMenuItem.setText(bundle.getString("lang_sk"));
huMenuItem.setText(bundle.getString("lang_hu"));
flag.setIcon((Icon) bundle.getObject("flag"));
lbl.setText(bundle.getString("description"));
setTitle(bundle.getString("name"));
pack();
}
当我们选择一个单选按钮菜单项时,将调用 updateLanguage 方法。 它基于给定的区域设置创建一个新的 ResourceBundle,并更新菜单、单选菜单项、图像图标、描述和框架标题。
skMenuItem.addActionListener((ActionEvent e) -> {
updateLanguage(new Locale("sk", "SK"));
});
选择一个斯洛伐克单选按钮菜单项,我们调用 updateLanguage 方法并传递一个斯洛伐克区域设置为参数。
Spring Boot 应用程序
在下一个示例中,我们在 Spring Boot 应用程序中使用资源包。Spring 是一个流行的 Java 应用程序框架。Spring Boot 是一种新的解决方案,可以用最少的精力创建独立的、生产级的基于 Spring 的应用程序。
同样,我们创建三个属性文件并将它们放在 src/main/resources/messages 目录中。
w1 = Earth w2 = ocean
这是默认的属性文件。
w1 = Erde w2 = ozean
words_de.properties 文件包含德语单词。
w1 = Zem w2 = oceán
words_sk.properties 文件包含斯洛伐克语单词。
plugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.zetcode'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}
这是 Gradle 构建文件。
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ResourceBundleMessageSource;
@SpringBootApplication
public class Application {
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("messages/words");
source.setUseCodeAsDefaultMessage(true);
return source;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application 是主应用程序类。我们设置 Spring Boot 程序。
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("messages/words");
source.setUseCodeAsDefaultMessage(true);
return source;
}
使用 @Bean 注解,我们生成一个 ResourceBundleMessageSource bean,它由 Spring 容器管理。ResourceBundleMessageSource 是一个 MessageSource 实现,它使用指定的基本名称访问资源包。此类依赖于底层 JDK 的 ResourceBundle 实现。
package com.zetcode;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import java.util.Locale;
@Component
public class MyRunner implements CommandLineRunner {
private MessageSource messageSource;
public MyRunner(MessageSource messageSource) {
this.messageSource = messageSource;
}
@Override
public void run(String... args) throws Exception {
System.out.println(messageSource.getMessage("w1",
null, Locale.GERMAN));
System.out.println(messageSource.getMessage("w1",
null, Locale.ENGLISH));
System.out.println(messageSource.getMessage("w2",
null, new Locale("sk", "SK")));
}
}
MyRunner 是 Spring Boot 应用程序的命令行运行器。
private MessageSource messageSource;
public MyRunner(MessageSource messageSource) {
this.messageSource = messageSource;
}
我们将 MessageSource 注入到该字段中。
System.out.println(messageSource.getMessage("w1",
null, Locale.GERMAN));
我们使用 getMessage 方法获取德语区域设置中的单词 w1。
... Erde Earth oceán ...
来源
在本文中,我们介绍了 Java ResourceBundle。我们创建了两个 Java 控制台应用程序、一个 Swing 应用程序和一个 Spring Boot 应用程序。
作者
列出所有Java教程。