ResourceBundleのリソースプロパティでUTF-8を使用する方法


259

Javaを使用してリソースプロパティでUTF-8を使用する必要がありますResourceBundle。プロパティファイルに直接テキストを入力すると、mojibakeと表示されます。

私のアプリはGoogle App Engineで実行されます。

誰かが私に例を挙げることができますか?私はこの仕事を得ることができません。


1
Java 1.6リーダーで渡すことができるようにこれを修正しました。以下のダウン@Chinaxing解答方法を参照してください
ウィル

1
@Will:質問は経由でそれらを読んについて主にjava.util.ResourceBundleありません、java.util.Properties
BalusC 2014

1
この答えた質問をチェックしてください,,,それはあなたを助け願っています[ stackoverflow.com/questions/863838/... [1]:stackoverflow.com/questions/863838/...
MajdyプログラマBBOY

6
JDK9は参照、ネイティブでUTF-8をサポートする必要がありますJEP 226
パオロFulgoni

回答:


375

ファイルが指定されResourceBundle#getBundle()ているPropertyResourceBundle場合の裏側の使用.properties。これにより、デフォルトでProperties#load(InputStream)これらのプロパティファイルがロードされます。あたりとしてのjavadoc、彼らはISO-8859-1として、デフォルトの読み取りです。

public void load(InputStream inStream) throws IOException

入力バイトストリームからプロパティリスト(キーと要素のペア)を読み取ります。入力ストリームは、load(Reader)で指定されている単純な行指向の形式であり、ISO 8859-1文字エンコードを使用すると想定されています。つまり、各バイトは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;
    }
}

これは次のように使用できます。

ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", new UTF8Control());

以下も参照してください。


ありがとう。ところで、FORMAT_PROPERTIESを返すようにgetFormatsをオーバーライドするのは良い考えのようです。
フラビオエトルスコ

getFormats()をオーバーライドするためのこの提案について詳しく説明してもらえますか?
Mark Roper

1
@ imgx64:通知ありがとうございます。回答が修正されました。
BalusC 2015

10
StandardCharsets.UTF_8Java 7以降を使用している場合は、遠慮なく使用してください
Niks

1
@Nyerguds:プログラムで変更する理由がある場合(私は人生では想像できませんが)、自由に変更してください。私が投稿するすべてのコードスニペットは、結局のところキックオフの例にすぎません。
BalusC 2016

131

ResourceBundleのインスタンスがあり、次のようにしてStringを取得できるとします。

String val = bundle.getString(key); 

日本語の表示の問題を次の方法で解決しました:

return new String(val.getBytes("ISO-8859-1"), "UTF-8");

37
ここのすべての素朴な賛成者/コメンターへ:これは解決策ではありませんが、回避策です。本当の根本的な問題はまだ解決されておらず、解決する必要があります。
BalusC、2014

2
これは私の状況を修正しました。解決策は、リソースバンドルとプロパティファイルでJavaがネイティブにUTF-8の処理を開始することです。それが発生するまで、回避策を使用します。
JohnRDOrazio 2015

@BalusC; このアプローチの欠点は何ですか?(追加の文字列を作成する以外?)
Paaske 2015年

8
@Paaske:これは回避策であり、解決策ではありません。コードベース全体のすべての文字列変数のすべての場所に回避策を再適用する必要があります。これはまったくナンセンスです。文字列変数に適切な値がすぐに含まれるように、適切な場所で1か所で修正します。クライアントを変更する必要はまったくないはずです。
BalusC 2015年

3
はい、もちろんアプリケーション全体を変更する必要がある場合、これは悪いことです。ただし、ResourceBundleをシングルトンとしてすでに使用している場合は、一度修正するだけで済みます。シングルトンアプローチがResourceBundleの最も一般的な使用方法であるという印象を受けました。
Paaske、2015年

51

これを見てください:http : //docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)

プロパティは、Readerオブジェクトを引数として受け取ります。これは、InputStreamから作成できます。

作成時に、リーダーのエンコーディングを指定できます。

InputStreamReader isr = new InputStreamReader(stream, "UTF-8");

次に、このReaderをloadメソッドに適用します。

prop.load(isr);

ところで:.propertiesファイルからストリームを取得します:

 InputStream stream = this.class.getClassLoader().getResourceAsStream("a.properties");

ところで:からリソースバンドルを取得しますInputStreamReader

ResourceBundle rb = new PropertyResourceBundle(isr);

これがあなたに役立つことを願っています!


3
ResourceBundleただし、ここでの実際の質問はについてです。
Nyerguds

1
確かに、あなたが使用していてPropertiesUTF-8文字列を取得したい場合、これは受け入れられるべき答えであり、これは魅力のように機能します。ただし、ResourceBundle言語リソースなどの場合、受け入れられる答えはエレガントです。それでも賛成票を投じた。
–IlgıtYıldırım2016

ResourceBundle rb = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"))
dedek

23

ResourceBundle.Control たとえば、プロパティファイルでcp1251文字セットが使用されている場合、UTF-8と新しいStringメソッドは機能しません。

だから私は一般的な方法を使用することをお勧めしました:ユニコード記号で書く。このため:

IDEA-特別なトランスペアレントネイティブからASCIIへの変換オプション(設定>ファイルエンコーディング)があります。

Eclipse-プラグインプロパティエディター」があります。個別のアプリケーションとして機能します。


4
IntelliJ IDEA 14では、これは[設定]-> [エディター]-> [ファイルエンコーディング]にあります。また、既存のプロパティファイルを削除し、このオプションを有効にするために再作成する必要がありました。
2015年

IDEは答えに特に関係ありませんが、UTF-8文字セットでコンテンツを保存しないという根本的な問題に実際に対処しないツールだけです。変換やプロパティの記述のようなハッカーなしで問題をすぐに解決します。異なる文字セットで定義されたファイル内のUnicodeシンボル。
ダレルティーグ

21

この問題は最終的に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のファイルを自動的に再読み取りします。


19

リソースをUTF-8で含むresources.utf8ファイルを作成し、以下を実行するルールを設定します。

native2ascii -encoding utf8 resources.utf8 resources.properties

どこnative2asciiから来るの?私はちょうどでしたfind / -name native2ascii*私はそれが... JDKのほんの一部ではないと仮定して、そして何の結果を得ていない
ArtOfWarfare

うーん。これはIBM JDKの一部ではありませんが、Oracle JDKのに含まれているようjdk1.*.0_*/binです。
ArtOfWarfare 2015年

少なくともJDK 6で、IBM JDKの一部であるように見えるん
エリック・フィン

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);  
            }  
        }  
    }  
}  

1
私はこのソリューションが好きで、Gist gist.github.com/enginer/3168dd4a374994718f0e
Sllouyssgort

これは非常にうまく機能します。UTF8で中国語の翻訳プロパティファイルを追加しただけで、問題なくロードされます。
tresf 2018

9

注意:JavaプロパティファイルはISO 8859-1でエンコードする必要があります。

ISO 8859-1文字エンコード。このエンコーディングで直接表現できない文字は、Unicodeエスケープを使用して記述できます。エスケープシーケンスでは1つの「u」文字のみが許可されます。

@seeプロパティJavaドキュメント

それでも本当にこれを実行したい場合: EclipseでのJavaプロパティUTF-8エンコーディング -いくつかのコードサンプルがあります


1
Java!= Eclipse ...後者はIDEです。詳細データ!= Java。Javaは、国際化(結局のところResourceBundlesに関する質問です)のための文字セットの膨大な配列を使用したスト​​リーム処理をサポートします...最も単純な答えとしてUTF-8を使用することで解決します。ターゲット言語でサポートされていない文字セットでプロパティファイルを書き込むと、問題が不必要に複雑になります。
ダレルティーグ

@Darell Teague:ResouceBundleに対して読み込まれたプロパティファイルがISO 8859-1である必要がある「ヒント」は、javaステートメント です:docs.oracle.com/javase/8/docs/api/java/util/… .. 。私の答えの2番目の部分は、帽子の問題に対処するための「ヒント」にすぎません。
Ralph


3

Guavaの優れたサポートライブラリとtry-with-resourcesコンストラクトを使用するJava 7ソリューションを次に示します。最もシンプルなエクスペリエンスを実現するために、UTF-8を使用してプロパティファイルを読み書きします。

プロパティファイルをUTF-8として読み取るには:

File file =  new File("/path/to/example.properties");

// Create an empty set of properties
Properties properties = new Properties();

if (file.exists()) {

  // Use a UTF-8 reader from Guava
  try (Reader reader = Files.newReader(file, Charsets.UTF_8)) {
    properties.load(reader);
  } catch (IOException e) {
    // Do something
  }
}

プロパティファイルをUTF-8として書き込むには:

File file =  new File("/path/to/example.properties");

// Use a UTF-8 writer from Guava
try (Writer writer = Files.newWriter(file, Charsets.UTF_8)) {
  properties.store(writer, "Your title here");
  writer.flush();
} catch (IOException e) {
  // Do something
}

この答えは役に立ちます。ここでさまざまな答えがある中心的な問題は、データと文字セットに関する誤解のようです。Javaは、上記のように格納されている文字セットを指定するだけで、データを(正しく)読み取ることができます。UTF-8は地球上のほとんどすべての言語をサポートするために一般的に使用されているため、ResourceBundleベースのプロパティに非常に適用できます。
ダレルティーグ

@DarrellTeague:まあ、「UTF-8は一般的にサポートに使用されています...」-「Unicodeは一般的にサポートに使用されています...」:) があるはずです:) UTF-8はUnicodeの文字エンコーディング(en .wikipedia.org / wiki / UTF-8)。
Honza Zidek 2017年

実際には、UTF-8は特に「文字セット」と呼ばれることを意図していた(「Unicode文字セット」を参照するだけではなく)。このコンテキスト(データ)でのUTF-8は、いくつかの手段によってインターネットでの使用を支配しているため67%。参照:stackoverflow.com/questions/8509339/…–
Darrell Teague

3

1つ示唆されたように、リソースバンドルの実装を行いましたが、それは役に立ちませんでした。バンドルは常にen_USロケールで呼び出されたためです...デフォルトのロケールを別の言語に設定しようとしましたが、まだリソースバンドルの実装を試みましたen_USでコントロールが呼び出されました...ログメッセージを出力してデバッグのステップを実行し、xhtmlおよびJSF呼び出しを介して実行時にロケールを変更した後に別のローカル呼び出しが行われているかどうかを確認しようとしました...発生しませんでした...次に、サーバー(tomcatサーバー)でファイルを読み取るためにシステムをデフォルトでutf8に設定しようとしましたが、すべてのクラスライブラリがutf8でコンパイルされておらず、tomcatがutf8形式で読み取っていたため、問題が発生しましたそしてサーバーが適切に実行されていなかった...その後、私は私のhtmlコントローラーにxhtmlファイルから呼び出されるメソッドを実装することになりました。その方法で私は次のことをしました:

        public String message(String key, boolean toUTF8) throws Throwable{
            String result = "";
            try{
                FacesContext context = FacesContext.getCurrentInstance();
                String message = context.getApplication().getResourceBundle(context, "messages").getString(key);

                result = message==null ? "" : toUTF8 ? new String(message.getBytes("iso8859-1"), "utf-8") : message;
            }catch(Throwable t){}
            return result;
        }

これは私のアプリケーションのパフォーマンスを低下させる可能性があるので、特に緊張しました...しかし、これを実装した後、私のアプリケーションは今より高速であるかのように見えます。 JSFはプロパティへのアクセス方法を解析します...一部のプロパティは変換されず、utf8形式である必要がないことがわかっているため、この呼び出しでブール引数を具体的に渡します...

プロパティファイルをUTF8形式で保存しましたが、アプリケーションの各ユーザーが参照ロケール設定を持っているため、問題なく機能しています。


2
Properties prop = new Properties();
String fileName = "./src/test/resources/predefined.properties";
FileInputStream inputStream = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(inputStream,"UTF-8");

1

私の問題の価値があるのは、ファイル自体が間違ったエンコーディングであったことです。iconvを使用するとうまくいきました

iconv -f ISO-8859-15 -t UTF-8  messages_nl.properties > messages_nl.properties.new

言及のための1 iconv。私は前にそれを聞いたことがないが、私は、コンソールにそれを入力し、驚くなかれ、それが存在することだ(とにかく、CentOSの6で。)
ArtOfWarfare

でも実際に使ってみたのですが、うまくいきませんでした。ISO-8559-1に変換できない最初の文字をスローしました。
ArtOfWarfare 2015年

1

Rodが提供するアプローチを使用しようとしましたが、すべてのアプリケーションで同じ回避策を繰り返さないというBalusCの懸念を考慮して、このクラスが付属していました。

import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;

public class MyResourceBundle {

    // feature variables
    private ResourceBundle bundle;
    private String fileEncoding;

    public MyResourceBundle(Locale locale, String fileEncoding){
        this.bundle = ResourceBundle.getBundle("com.app.Bundle", locale);
        this.fileEncoding = fileEncoding;
    }

    public MyResourceBundle(Locale locale){
        this(locale, "UTF-8");
    }

    public String getString(String key){
        String value = bundle.getString(key); 
        try {
            return new String(value.getBytes("ISO-8859-1"), fileEncoding);
        } catch (UnsupportedEncodingException e) {
            return value;
        }
    }
}

これを使用する方法は、通常のResourceBundleの使用方法と非常に似ています。

private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
String label = labels.getString(key)

または、デフォルトでUTF-8を使用する代替コンストラクタを使用できます。

private MyResourceBundle labels = new MyResourceBundle("es");

0

「設定/設定」ダイアログ(Ctrl+ Alt+ S)を開き、「エディターとファイルのエンコーディング」をクリックします。

表示されているウィンドウのスクリーンショット

次に、下部で、プロパティファイルのデフォルトのエンコーディングを指定します。エンコーディングタイプを選択します。

または、リソースバンドルでテキストの代わりにUnicode記号を使用することもできます(たとえば、"ів"equals \u0456\u0432


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.