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教程。