如何在ResourceBundle的资源属性中使用UTF-8

nac*_*cho 248 java google-app-engine resourcebundle utf-8 internationalization

我需要在使用Java的资源属性中使用UTF-8 ResourceBundle.当我将文本直接输入属性文件时,它显示为mojibake.

我的应用在Google App Engine上运行.

谁能举个例子?我无法完成这项工作.

Bal*_*usC 365

指定文件时的ResourceBundle#getBundle()使用情况.这反过来默认使用加载这些属性文件.根据javadoc,它们默认为ISO-8859-1.PropertyResourceBundle.propertiesProperties#load(InputStream)

public void load(InputStream inStream) throws IOException

从输入字节流中读取属性列表(键和元素对).输入流采用加载(Reader)中指定的简单的面向行的格式,并假设使用ISO 8859-1字符编码 ; 即每个字节是一个Latin1字符.不是Latin1中的字符,以及某些特殊字符,使用"Java™语言规范"第3.3节中定义的Unicode转义符在键和元素中表示.

因此,您需要将它们保存为ISO-8859-1.如果您有任何超出ISO-8859-1范围的字符并且您无法使用\uXXXX头顶而且您因此被迫将文件保存为UTF-8,那么您需要使用native2ascii工具来转换UTF-8将属性文件保存到ISO-8859-1保存的属性文件中,其中所有未覆盖的字符都转换为\uXXXX格式.以下示例将UTF-8编码的属性文件text_utf8.properties转换为有效的ISO-8859-1编码属性文件text.properties.

native2ascii -encoding UTF-8 text_utf8.properties text.properties

使用Eclipse等理智的IDE时,.properties在基于Java的项目中创建文件并使用Eclipse自己的编辑器时,这已经自动完成.Eclipse将透明地将字符转换为ISO-8859-1范围以外的\uXXXX格式.另请参见下面的屏幕截图(请注意底部的"属性"和"源"选项卡,单击以查看大图):

或者,您也可以创建一个自定义ResourceBundle.Control实现,其中您使用明确地将属性文件读取为UTF-8 InputStreamReader,这样您就可以将它们保存为UTF-8而无需麻烦native2ascii.这是一个启动示例:

public class UTF8Control extends Control {
    public ResourceBundle newBundle
        (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
            throws IllegalAccessException, InstantiationException, IOException
    {
        // The below is a copy of the default implementation.
        String bundleName = toBundleName(baseName, locale);
        String resourceName = toResourceName(bundleName, "properties");
        ResourceBundle bundle = null;
        InputStream stream = null;
        if (reload) {
            URL url = loader.getResource(resourceName);
            if (url != null) {
                URLConnection connection = url.openConnection();
                if (connection != null) {
                    connection.setUseCaches(false);
                    stream = connection.getInputStream();
                }
            }
        } else {
            stream = loader.getResourceAsStream(resourceName);
        }
        if (stream != null) {
            try {
                // Only this line is changed to make it to read properties files as UTF-8.
                bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
            } finally {
                stream.close();
            }
        }
        return bundle;
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以使用如下:

ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", new UTF8Control());
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 如果你使用Java 7+,请不要犹豫使用`StandardCharsets.UTF_8` (9认同)

Rod*_*Rod 127

鉴于您有一个ResourceBundle实例,您可以通过以下方式获取String:

String val = bundle.getString(key); 
Run Code Online (Sandbox Code Playgroud)

我解决了日语显示问题:

return new String(val.getBytes("ISO-8859-1"), "UTF-8");
Run Code Online (Sandbox Code Playgroud)

  • 对于所有天真的赞助者/评论者:这不是解决方案,而是一种解决方法.真正的潜在问题仍然存在,需要解决. (32认同)
  • @Paaske:这是一种解决方法,而不是解决方案.您需要在整个代码库中的所有字符串变量上重新应用所有位置的变通方法.这纯属无稽之谈.只需将其固定在一个位置,在正确的位置,以便字符串变量立即包含正确的值.应该完全没有必要修改客户端. (8认同)
  • 这解决了我的情况。解决方案是让 Java 开始在资源包和属性文件中本地处理 UTF-8。在这种情况发生之前,我将使用一种解决方法。 (2认同)
  • @BalusC; 这种方法的缺点是什么?(除了创建一个额外的字符串?) (2认同)
  • 是的,如果您必须修改整个应用程序,那当然是不好的。但是,如果您已经将ResourceBundle作为单例使用,则只需修复一次即可。我的印象是单例方法是使用ResourceBundle的最常用方法。 (2认同)

Chi*_*ing 47

看看这个:http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)

属性接受Reader对象作为参数,您可以从InputStream创建它.

在创建时,您可以指定Reader的编码:

InputStreamReader isr = new InputStreamReader(stream, "UTF-8");
Run Code Online (Sandbox Code Playgroud)

然后将此Reader应用于加载方法:

prop.load(isr);
Run Code Online (Sandbox Code Playgroud)

BTW:从.properties文件中获取流:

 InputStream stream = this.class.getClassLoader().getResourceAsStream("a.properties");
Run Code Online (Sandbox Code Playgroud)

希望这可以帮到你 !

  • 这里的实际问题是关于`ResourceBundle`. (3认同)
  • 是的,如果您使用“属性”并且想要检索“UTF-8”字符串,那么这应该是可以接受的答案,那么这就像一个魅力。然而,对于诸如语言资源之类的“ResourceBundle”,公认的答案是优雅的。尽管如此,还是投票给了答案。 (2认同)

Kin*_*iro 21

ResourceBundle.Control 例如,如果属性文件使用cp1251 charset,则使用UTF-8和新的String方法不起作用.

所以我推荐使用一种常见的方法:用unicode符号.为了这:

IDEA - 具有特殊的" 透明原生到ASCII转换 "选项(设置>文件编码).

Eclipse - 有一个插件" 属性编辑器 ".它可以作为单独的应用程序.

  • 在IntelliJ IDEA 14中,它位于"设置" - >"编辑器" - >"文件编码"中.我还必须删除任何现有的属性文件,并重新创建它们以使此选项生效. (3认同)

mar*_*pes 19

package com.varaneckas.utils;  

import java.io.UnsupportedEncodingException;  
import java.util.Enumeration;  
import java.util.PropertyResourceBundle;  
import java.util.ResourceBundle;  

/** 
 * UTF-8 friendly ResourceBundle support 
 *  
 * Utility that allows having multi-byte characters inside java .property files. 
 * It removes the need for Sun's native2ascii application, you can simply have 
 * UTF-8 encoded editable .property files. 
 *  
 * Use:  
 * ResourceBundle bundle = Utf8ResourceBundle.getBundle("bundle_name"); 
 *  
 * @author Tomas Varaneckas <tomas.varaneckas@gmail.com> 
 */  
public abstract class Utf8ResourceBundle {  

    /** 
     * Gets the unicode friendly resource bundle 
     *  
     * @param baseName 
     * @see ResourceBundle#getBundle(String) 
     * @return Unicode friendly resource bundle 
     */  
    public static final ResourceBundle getBundle(final String baseName) {  
        return createUtf8PropertyResourceBundle(  
                ResourceBundle.getBundle(baseName));  
    }  

    /** 
     * Creates unicode friendly {@link PropertyResourceBundle} if possible. 
     *  
     * @param bundle  
     * @return Unicode friendly property resource bundle 
     */  
    private static ResourceBundle createUtf8PropertyResourceBundle(  
            final ResourceBundle bundle) {  
        if (!(bundle instanceof PropertyResourceBundle)) {  
            return bundle;  
        }  
        return new Utf8PropertyResourceBundle((PropertyResourceBundle) bundle);  
    }  

    /** 
     * Resource Bundle that does the hard work 
     */  
    private static class Utf8PropertyResourceBundle extends ResourceBundle {  

        /** 
         * Bundle with unicode data 
         */  
        private final PropertyResourceBundle bundle;  

        /** 
         * Initializing constructor 
         *  
         * @param bundle 
         */  
        private Utf8PropertyResourceBundle(final PropertyResourceBundle bundle) {  
            this.bundle = bundle;  
        }  

        @Override  
        @SuppressWarnings("unchecked")  
        public Enumeration getKeys() {  
            return bundle.getKeys();  
        }  

        @Override  
        protected Object handleGetObject(final String key) {  
            final String value = bundle.getString(key);  
            if (value == null)  
                return null;  
            try {  
                return new String(value.getBytes("ISO-8859-1"), "UTF-8");  
            } catch (final UnsupportedEncodingException e) {  
                throw new RuntimeException("Encoding not supported", e);  
            }  
        }  
    }  
}  
Run Code Online (Sandbox Code Playgroud)


ste*_*nix 19

Java 9中最终修复了这个问题:https: //docs.oracle.com/javase/9​​/intl/internationalization-enhancements-jdk-9

属性文件的默认编码现在为UTF-8.

大多数现有的属性文件应该不会受到影响:UTF-8和ISO-8859-1对ASCII字符相同的编码,与人类可读的非ASCII ISO-8859-1编码是无效的UTF-8.如果检测到无效的UTF-8字节序列,Java运行时将自动重新读取ISO-8859-1中的文件.


and*_*llr 18

我们创建一个resources.utf8文件,其中包含UTF-8中的资源,并具有运行以下内容的规则:

native2ascii -encoding utf8 resources.utf8 resources.properties
Run Code Online (Sandbox Code Playgroud)


Ral*_*lph 9

注意:java属性文件应该用ISO 8859-1编码!

ISO 8859-1字符编码.无法在此编码中直接表示的字符可以使用Unicode转义编写; 在转义序列中只允许一个'u'字符.

@see Properties Java Doc

如果您仍然真的想要这样做:看一下: Eclipse中的Java属性UTF-8编码 - 有一些代码示例


fmu*_*car 5

http://sourceforge.net/projects/eclipse-rbe/

如前所述,属性文件应在ISO 8859-1中编码

您可以使用上面的eclipse IDE插件为您进行Unicode转换.