2010-09-05 37 views
9

Tôi đang sử dụng jsf-ri 2.0.3, nơi cần hỗ trợ tiếng Hebrew và tiếng Nga. Vấn đề là tôi thấy vô nghĩa trên màn hình thay vì văn bản chính xác.i18n với các tệp thuộc tính được mã hóa UTF-8 trong ứng dụng JSF 2.0

Trước hết, tôi đã xác định các gói (* _locale.properties) cho từng ngôn ngữ. Các tập tin được mã hóa UTF-8. Thứ hai, tôi đã xác định các mặc định và hỗ trợ miền địa phương trong faces-config.xml

<locale-config> 
    <default-locale>iw</default-locale> 
    <supported-locale>en</supported-locale> 
    <supported-locale>ru</supported-locale> 
</locale-config> 

Thần I đã thêm một bộ lọc tùy chỉnh mà sẽ thiết lập mã hóa đáp ứng charcter sang UTF-8.

<filter> 
    <filter-name>encodingFilter</filter-name> 
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
    <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
    </init-param> 
    <init-param> 
     <param-name>forceEncoding</param-name> 
     <param-value>true</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>encodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Và cuối cùng khi tôi tạo một xhtml đơn giản để gỡ lỗi đầu ra tôi nhìn thấy một kết quả rất lạ

<f:loadBundle basename="i18n.frontend.homepage" var="msg"/> 
<strong>i18n: </strong><h:outputText value="#{msg.language}"/> 
<br/> 
<strong>Locale: </strong> 
<h:outputText value="#{facesContext.externalContext.response.locale}"/> 
<br/> 
<strong>Encoding: </strong> 
<h:outputText value="#{facesContext.externalContext.response.characterEncoding}"/> 

Kết quả là:

i18n: ×¢×ר×ת 
Locale: en_US 
Encoding: UTF-8 

Điều gì là sai với cấu hình của tôi?

Trả lời

22

Đúng vậy, bạn có thể tạo tùy chỉnh ResourceBundle hoặc sử dụng bộ chuyển đổi native2ascii (nếu cần thiết với các plugin Maven 2 để thực hiện việc chuyển đổi minh bạch hơn). Vì câu trả lời khác chỉ đi theo cách tiếp cận cuối cùng một cách chi tiết, đây là câu trả lời khác về cách bạn có thể tạo một tệp tùy chỉnh ResourceBundle để tải các tệp thuộc tính dưới dạng UTF-8 trong một ứng dụng JSF 2.x trên môi trường Java SE 1.6.

faces-config.xml

<application> 
    <resource-bundle> 
     <base-name>com.example.i18n.Text</base-name> 
     <var>text</var> 
    </resource-bundle> 
</application> 

com.example.i18n.Text

package com.example.i18n; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.URL; 
import java.net.URLConnection; 
import java.util.Enumeration; 
import java.util.Locale; 
import java.util.PropertyResourceBundle; 
import java.util.ResourceBundle; 

import javax.faces.context.FacesContext; 

public class Text extends ResourceBundle { 

    protected static final String BUNDLE_NAME = "com.example.i18n.text"; 
    protected static final String BUNDLE_EXTENSION = "properties"; 
    protected static final String CHARSET = "UTF-8"; 
    protected static final Control UTF8_CONTROL = new UTF8Control(); 

    public Text() { 
     setParent(ResourceBundle.getBundle(BUNDLE_NAME, 
      FacesContext.getCurrentInstance().getViewRoot().getLocale(), UTF8_CONTROL)); 
    } 

    @Override 
    protected Object handleGetObject(String key) { 
     return parent.getObject(key); 
    } 

    @Override 
    public Enumeration<String> getKeys() { 
     return parent.getKeys(); 
    } 

    protected static class UTF8Control extends Control { 
     public ResourceBundle newBundle 
      (String baseName, Locale locale, String format, ClassLoader loader, boolean reload) 
       throws IllegalAccessException, InstantiationException, IOException 
     { 
      // The below code is copied from default Control#newBundle() implementation. 
      // Only the PropertyResourceBundle line is changed to read the file as UTF-8. 
      String bundleName = toBundleName(baseName, locale); 
      String resourceName = toResourceName(bundleName, BUNDLE_EXTENSION); 
      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 { 
        bundle = new PropertyResourceBundle(new InputStreamReader(stream, CHARSET)); 
       } finally { 
        stream.close(); 
       } 
      } 
      return bundle; 
     } 
    } 
} 

này hy vọng UTF-8 mã hóa các thuộc tính tập tin như text.properties, text_en.properties, vv trong com.example.i18n gói. Không cần native2ascii.

Nhân tiện, với kiểu JSF 2.0 kiểu mới <resource-bundle> khai báo trong faces-config.xml, bạn không cần <f:loadBundle> trong các chế độ xem nữa. Tất cả văn bản sẽ có sẵn trực tiếp bởi #{text} trong tất cả các chế độ xem.

+0

Đây là một công cụ tuyệt vời. Nó sẽ được thêm vào OmniFaces một ngày nào đó? – Med

+1

@Med: Tôi đã xem xét điều này, nhưng tôi đã quyết định rằng điều này là trên cạnh với "Hacky". Thay vào đó, hãy sử dụng các trình soạn thảo thích hợp và các công cụ xây dựng như Eclipse và/hoặc Maven/Ant. Ví dụ, khi sử dụng trình soạn thảo tệp thuộc tính dựng sẵn của Eclipse, UTF-8 sẽ được lưu trong suốt theo ISO-8859-1 với các điểm mã hóa unicode khi cần thiết. – BalusC

+0

Ok, tôi hiểu rõ vấn đề của bạn! Cảm ơn. – Med

3

Vâng, sau khi điều tra sâu, tôi đã tìm thấy giải pháp.

Trước đó để java 1.6 PropertyResourceBundle chỉ có một hàm tạo có tài liệu sau The property file read with this constructor must be encoded in ISO-8859-1. Điều này có nghĩa là chỉ có thể sử dụng văn bản tiếng Anh trong gói tài nguyên.

Có hai giải pháp cho vấn đề này:

Người đầu tiên được viết một phần Mà tùy chỉnh loadBundle sẽ sử dụng đúng phương pháp ResourceBundle instantiation.

Loại thứ hai (lựa chọn của tôi) đang sử dụng bộ chuyển đổi Native-to-ASCII có thể được sử dụng với maven bằng cách sử dụng Native2Ascii maven plugin.

Dưới đây là ví dụ cấu hình:

<plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>native2ascii-maven-plugin</artifactId> 
    <executions> 
     <execution> 
      <goals> 
       <goal>native2ascii</goal> 
      </goals> 
      <configuration> 
       <src>${basedir}/src/main/resources</src>     
       <dest>${project.build.directory}/native2ascii</dest> 
       <encoding>UTF8</encoding> 
       <includes>**/*.properties</includes> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 
0

Tôi gặp vấn đề tương tự với ứng dụng SWT độc lập. Đây là trình tải tài nguyên đã được sửa đổi được tạo bởi WindowBuilder. Ý tưởng cơ bản - Lớp thông điệp chỉ chứa các tài nguyên trong các trường chuỗi. Vì vậy, tôi chuyển đổi chúng sang UTF8 (nếu có thể) sau khi tải ISO-8859-1 thô.

import java.lang.reflect.Field; 

import org.eclipse.osgi.util.NLS; 

public class Messages extends NLS { 
private static final String BUNDLE_NAME = "org.digimead.tabuddy.desktop.res.messages"; //$NON-NLS-1$ 
public static String MainWindow_newShell_text; 
public static String MainWindow_actionOpenFile_text; 
public static String MainWindow_actionCloseFile_text; 

// ////////////////////////////////////////////////////////////////////////// 
// 
// Constructor 
// 
// ////////////////////////////////////////////////////////////////////////// 
private Messages() { 
    // do not instantiate 
} 

// ////////////////////////////////////////////////////////////////////////// 
// 
// Class initialization 
// 
// ////////////////////////////////////////////////////////////////////////// 
static { 
    // load message values from bundle file 
    NLS.initializeMessages(BUNDLE_NAME, Messages.class); 
    final Field[] fieldArray = Messages.class.getDeclaredFields(); 
    final int len = fieldArray.length; 
    for (int i = 0; i < len; i++) { 
     final Field field = (Field) fieldArray[i]; 
     if (field.getType() == java.lang.String.class) { 
      if (!field.isAccessible()) 
       field.setAccessible(true); 
      try { 
       final String rawValue = (String) field.get(null); 
       field.set(null, new String(rawValue.getBytes("ISO-8859-1"), 
         "UTF-8")); 
      } catch (Exception e) { 
       // skip field modification 
      } 
     } 
    } 
} 

}

Các vấn đề liên quan