java - Cómo usar UTF-8 en propiedades de recursos con ResourceBundle
google-app-engine internationalization (15)
Necesito usar UTF-8 en mis propiedades de recursos usando el ResourceBundle
de Java. Cuando ingreso el texto directamente en el archivo de propiedades, se muestra como mojibake.
Mi aplicación se ejecuta en Google App Engine.
¿Alguien puede darme un ejemplo? No puedo conseguir este trabajo.
Abra el cuadro de diálogo Configuración / Preferencias ( Ctrl + Alt + S ), luego haga clic en Editor y Codificaciones de archivos.
Luego, en la parte inferior, usted codificará las codificaciones predeterminadas para los archivos de propiedades. Elija su tipo de codificación.
Alternativamente, puede usar símbolos Unicode en lugar de texto en su paquete de recursos (por ejemplo, "ів"
es igual a /u0456/u0432
)
Aquí hay una solución Java 7 que utiliza la excelente biblioteca de soporte de Guava y la construcción try-with-resources. Lee y escribe archivos de propiedades usando UTF-8 para la experiencia general más simple.
Para leer un archivo de propiedades como 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
}
}
Para escribir un archivo de propiedades como 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
}
Atención: ¡los archivos de propiedades de Java deben codificarse en ISO 8859-1!
Codificación de caracteres ISO 8859-1. Los caracteres que no se pueden representar directamente en esta codificación se pueden escribir utilizando escapes de Unicode; solo se permite un solo carácter ''u'' en una secuencia de escape.
@ver Propiedades Java Doc
Si todavía desea hacer esto, eche un vistazo a: Propiedades de Java codificación UTF-8 en Eclipse : hay algunos ejemplos de código
Como se sugirió, pasé por la implementación del paquete de recursos ... pero eso no ayudó ... ya que siempre se llamaba al paquete en la configuración regional en_US ... intenté establecer mi configuración regional predeterminada en un idioma diferente y aún así mi implementación del paquete de recursos se estaba llamando al control con en_US ... traté de poner mensajes de registro y hacer un paso a través de la depuración y ver si se estaba realizando una llamada local diferente después de cambiar la configuración regional en el tiempo de ejecución a través de xhtml y llamadas JSF ... que no sucedió ... luego traté de hacer una configuración predeterminada del sistema en un utf8 para leer los archivos de mi servidor (servidor tomcat) ... pero eso causó que todos los archivos de mis clases no se compilaran en utf8 y tomcat comenzó a leer en formato utf8 y el servidor no se ejecutaba correctamente ... luego terminé implementando un método en mi controlador java para ser llamado desde archivos xhtml ... en ese método hice lo siguiente:
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;
}
Estaba particularmente nervioso, ya que esto podría ralentizar el rendimiento de mi aplicación ... sin embargo, después de implementar esto, parece que ahora mi aplicación es más rápida ... creo que es porque ahora accedo directamente a las propiedades en lugar de permitir que JSF analiza su camino para acceder a las propiedades ... yo paso específicamente el argumento booleano en esta llamada porque sé que algunas de las propiedades no se traducirían y no es necesario que estén en formato utf8 ...
Ahora he guardado mi archivo de propiedades en formato UTF8 y está funcionando bien ya que cada usuario en mi aplicación tiene una preferencia de configuración regional de referencia.
Creamos un archivo resources.utf8 que contiene los recursos en UTF-8 y tenemos una regla para ejecutar lo siguiente:
native2ascii -encoding utf8 resources.utf8 resources.properties
Dado que tienes una instancia de ResourceBundle y puedes obtener String por:
String val = bundle.getString(key);
Resolví mi problema de visualización japonés por:
return new String(val.getBytes("ISO-8859-1"), "UTF-8");
El ResourceBundle#getBundle()
utiliza bajo las cubiertas PropertyResourceBundle
cuando se especifica un archivo .properties
. A su vez, esto usa por defecto las Properties#load(InputStream)
para cargar esos archivos de propiedades. Según Properties#load(InputStream) , se leen por defecto como ISO-8859-1.
public void load(InputStream inStream) throws IOException
Lee una lista de propiedades (pares de clave y elemento) del flujo de bytes de entrada. El flujo de entrada está en un formato simple orientado a la línea como se especifica en la carga (Lector) y se supone que utiliza la codificación de caracteres ISO 8859-1 ; Es decir, cada byte es un carácter latino1. Los caracteres que no están en Latin1, y ciertos caracteres especiales, se representan en claves y elementos utilizando escapes de Unicode como se define en la sección 3.3 de la Especificación del lenguaje Java ™.
Por lo tanto, deberías guardarlos como ISO-8859-1. Si tiene caracteres más allá del rango ISO-8859-1 y no puede usar /uXXXX
fuera de la parte superior de la cabeza y, por lo tanto, está obligado a guardar el archivo como UTF-8, entonces deberá usar la herramienta native2ascii para convierta un archivo de propiedades guardado UTF-8 en un archivo de propiedades guardado ISO-8859-1 en el que todos los caracteres descubiertos se conviertan al formato /uXXXX
. El siguiente ejemplo convierte un archivo de propiedades codificadas en UTF-8 text_utf8.properties
en un archivo de propiedades codificadas ISO-8859-1 válido text.properties
.
native2ascii -encoding UTF-8 text_utf8.properties text.properties
Cuando se utiliza un IDE sano como Eclipse, esto ya se realiza automáticamente cuando crea un archivo .properties
en un proyecto basado en Java y utiliza el propio editor de Eclipse. Eclipse convertirá de forma transparente los caracteres más allá del rango ISO-8859-1 al formato /uXXXX
. Vea también las capturas de pantalla a continuación (observe las pestañas "Propiedades" y "Fuente" en la parte inferior, haga clic para verlas en tamaño grande):
Alternativamente, también puede crear una implementación personalizada de ResourceBundle.Control
en la que lea explícitamente los archivos de propiedades como UTF-8 utilizando InputStreamReader
, de modo que solo puede guardarlos como UTF-8 sin la necesidad de tener problemas con native2ascii
. Aquí hay un ejemplo de inicio:
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;
}
}
Esto se puede utilizar de la siguiente manera:
ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", new UTF8Control());
Ver también:
Este problema finalmente se ha solucionado en Java 9: https://docs.oracle.com/javase/9/intl/internationalization-enhancements-jdk-9
La codificación predeterminada para los archivos de propiedades ahora es UTF-8.
La mayoría de los archivos de propiedades existentes no deberían verse afectados: UTF-8 e ISO-8859-1 tienen la misma codificación para los caracteres ASCII, y la codificación ISO-8859-1 no ASCII legible por humanos no es válida en UTF-8. Si se detecta una secuencia de bytes UTF-8 no válida, el tiempo de ejecución de Java vuelve a leer automáticamente el archivo en ISO-8859-1.
Intenté utilizar el enfoque proporcionado por Rod, pero teniendo en cuenta la preocupación de Balus por no repetir la misma solución en toda la aplicación y llegué con esta clase:
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;
}
}
}
La forma de usar esto sería muy similar al uso regular de ResourceBundle:
private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
String label = labels.getString(key)
O puede usar el constructor alternativo que usa UTF-8 por defecto:
private MyResourceBundle labels = new MyResourceBundle("es");
Por lo que vale la pena mi problema fue que los archivos en sí estaban en la codificación incorrecta. Usando iconv funcionó para mí
iconv -f ISO-8859-15 -t UTF-8 messages_nl.properties > messages_nl.properties.new
mira esto: http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)
las propiedades aceptan un objeto Reader como argumentos, que puede crear desde un InputStream.
en el momento de la creación, puede especificar la codificación del Reader:
InputStreamReader isr = new InputStreamReader(stream, "UTF-8");
A continuación, aplique este lector al método de carga:
prop.load(isr);
Por cierto: obtener la secuencia de archivo .properties :
InputStream stream = this.class.getClassLoader().getResourceAsStream("a.properties");
Espero que esto le pueda ayudar !
http://sourceforge.net/projects/eclipse-rbe/
como ya se ha indicado, los archivos de propiedad deben codificarse en ISO 8859-1
Puede usar el complemento anterior para eclipse IDE para realizar la conversión Unicode para usted.
ResourceBundle.Control
con UTF-8 y los nuevos métodos de String no funcionan, si el archivo de propiedades usa el conjunto de caracteres cp1251, por ejemplo.
Así que recomendé usar un método común: escribir en símbolos Unicode . Para esto:
IDEA : tiene una opción especial de " Conversión nativa a ASCII transparente " (Configuración> Codificación de archivo).
Eclipse - tiene un complemento " Editor de propiedades " . Puede funcionar como aplicación separada.
Properties prop = new Properties();
String fileName = "./src/test/resources/predefined.properties";
FileInputStream inputStream = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(inputStream,"UTF-8");
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 <[email protected]>
*/
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);
}
}
}
}