Cơ sở dữ liệu được hỗ trợ i18n cho java web-app


6

Tôi muốn sử dụng cơ sở dữ liệu để lưu trữ cặp khóa/giá trị i18n để chúng tôi có thể sửa đổi/tải lại dữ liệu i18n khi chạy. Có ai đã làm điều này không? Hay có ai có ý tưởng về cách thực hiện điều này không? Tôi đã đọc một số chủ đề về điều này, nhưng tôi đã không nhìn thấy một giải pháp khả thi.

Tôi đặc biệt đề cập đến cái gì đó sẽ làm việc với các thẻ JSTL như

<fmt:setlocale> 
<fmt:bundle> 
<fmt:setBundle> 
<fmt:message> 

Tôi nghĩ rằng đây sẽ bao gồm việc mở rộng ResourceBundle, nhưng khi tôi đã cố gắng này, tôi chạy vào vấn đề mà đã phải làm với cách các thẻ jstl nhận được gói tài nguyên.

2

Bạn chỉ hỏi cách lưu trữ UTF-8/16 ký tự trong DB? trong mysql nó chỉ là vấn đề đảm bảo bạn xây dựng với sự hỗ trợ UTF8 và thiết lập đó là mặc định, hoặc chỉ định nó ở cấp độ cột hoặc bảng. Tôi đã làm điều này trong oracle và mysql trước đây. Tạo một bảng và cắt và dán một số dữ liệu i18n vào đó và xem điều gì xảy ra ... bạn có thể đã được đặt ..

hoặc tôi hoàn toàn mất điểm của bạn?

chỉnh sửa:

rõ ràng hơn ... Tôi thường thực hiện một ba bảng cột ... ngôn ngữ, quan trọng, giá trị ... nơi "giá trị" có chứa những từ có khả năng ngoại ngữ hoặc cụm từ ... " ngôn ngữ "chứa một số khóa ngôn ngữ và" khóa "là một khóa tiếng Anh (tức là login.error.password.dup) ... ngôn ngữ và khóa được lập chỉ mục ...

Tôi đã xây dựng các giao diện trên cấu trúc như thế này hiển thị mỗi khóa với tất cả các bản dịch (giá trị) ... nó có thể trở nên lạ mắt và bao gồm các đánh dấu và đánh dấu "bẩn" và tất cả những thứ khác bạn cần để cho phép người dịch và nhập dữ liệu dân gian sử dụng ..

Chỉnh sửa 2:

Bây giờ bạn thêm các thông tin về các thẻ JSTL, tôi hiểu thêm một chút ... Tôi chưa bao giờ làm điều đó bản thân mình .. nhưng tôi tìm thấy thông tin cũ này trên theserverside ...

HttpSession session = .. [get hold of the session] 
ResourceBundle bundle = new PropertyResourceBundle(toInputStream(myOwnProperties)) [toInputStream just stores the properties into an inputstream] 
Locale locale = .. [get hold of the locale] 
javax.servlet.jsp.jstl.core.Config.set(session, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle ,locale)); 

1

Chúng tôi có bảng cơ sở dữ liệu với khóa/ngôn ngữ/thuật ngữ trong đó khóa là số nguyên và là khóa chính kết hợp cùng với ngôn ngữ.

Chúng tôi đang sử dụng Struts, vì vậy chúng tôi đã kết thúc việc thực hiện PropertyMessageResources thực hiện riêng cho phép chúng tôi thực hiện điều gì đó như <bean:message key="impressum.text" />.

Nó hoạt động rất tốt và mang lại cho chúng tôi sự linh hoạt để tự động chuyển đổi ngôn ngữ trong giao diện người dùng cũng như cập nhật bản dịch khi đang di chuyển.


13

Cuối cùng tôi đã làm việc này với trợ giúp của danb ở trên.

Đây là lớp gói tài nguyên và lớp kiểm soát gói tài nguyên của tôi.

Tôi đã sử dụng mã này từ @ [danb].

ResourceBundle bundle = ResourceBundle.getBundle("AwesomeBundle", locale, DbResourceBundle.getMyControl()); 
javax.servlet.jsp.jstl.core.Config.set(actionBeanContext.getRequest(), Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale)); 

và đã viết lớp này.

public class DbResourceBundle extends ResourceBundle 
{ 
    private Properties properties; 

    public DbResourceBundle(Properties inProperties) 
    { 
     properties = inProperties; 
    } 

    @Override 
    @SuppressWarnings(value = { "unchecked" }) 
    public Enumeration<String> getKeys() 
    { 
     return properties != null ? ((Enumeration<String>) properties.propertyNames()) : null; 
    } 

    @Override 
    protected Object handleGetObject(String key) 
    { 
     return properties.getProperty(key); 
    } 

    public static ResourceBundle.Control getMyControl() 
    { 
     return new ResourceBundle.Control() 
     { 

      @Override 
      public List<String> getFormats(String baseName) 
      { 
       if (baseName == null) 
       { 
        throw new NullPointerException(); 
       } 
       return Arrays.asList("db"); 
      } 

      @Override 
      public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, 
        InstantiationException, IOException 
      { 
       if ((baseName == null) || (locale == null) || (format == null) || (loader == null)) 
        throw new NullPointerException(); 
       ResourceBundle bundle = null; 
       if (format.equals("db")) 
       { 
        Properties p = new Properties(); 
        DataSource ds = (DataSource) ContextFactory.getApplicationContext().getBean("clinicalDataSource"); 
        Connection con = null; 
        Statement s = null; 
        ResultSet rs = null; 
        try 
        { 
         con = ds.getConnection(); 
         StringBuilder query = new StringBuilder(); 
         query.append("select label, value from i18n where bundle='" + StringEscapeUtils.escapeSql(baseName) + "' "); 

         if (locale != null) 
         { 
          if (StringUtils.isNotBlank(locale.getCountry())) 
          { 
           query.append("and country='" + escapeSql(locale.getCountry()) + "' "); 

          } 
          if (StringUtils.isNotBlank(locale.getLanguage())) 
          { 
           query.append("and language='" + escapeSql(locale.getLanguage()) + "' "); 

          } 
          if (StringUtils.isNotBlank(locale.getVariant())) 
          { 
           query.append("and variant='" + escapeSql(locale.getVariant()) + "' "); 

          } 
         } 
         s = con.createStatement(); 
         rs = s.executeQuery(query.toString()); 
         while (rs.next()) 
         { 
          p.setProperty(rs.getString(1), rs.getString(2)); 
         } 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
         throw new RuntimeException("Can not build properties: " + e); 
        } 
        finally 
        { 
         DbUtils.closeQuietly(con, s, rs); 
        } 
        bundle = new DbResourceBundle(p); 
       } 
       return bundle; 
      } 

      @Override 
      public long getTimeToLive(String baseName, Locale locale) 
      { 
       return 1000 * 60 * 30; 
      } 

      @Override 
      public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) 
      { 
       return true; 
      } 

     }; 
    } 

0

Thực sự những gì ScArcher2 cần là phản hồi không được đánh dấu là chính xác hoặc hữu ích.

Giải pháp ScArcher2 chọn sử dụng là imo khủng khiếp mestake :) Tải TẤT CẢ các bản dịch cùng một lúc ... trong bất kỳ ứng dụng lớn hơn của nó sẽ giết nó. Đang tải các bản dịch của mỗi yêu cầu ...

Phương pháp của david thường được sử dụng trong môi trường sản xuất thực tế. Đôi khi để hạn chế các cuộc gọi db, mà là với mọi thông báo được dịch, bạn có thể tạo các nhóm bản dịch theo chủ đề, chức năng, vv để tải trước chúng. Nhưng điều này phức tạp hơn một chút và có thể được thay thế bằng hệ thống bộ nhớ cache tốt.

  0

Tôi đồng ý rằng việc tải tất cả bản dịch trong các ứng dụng lớn hơn có thể gây ra sự cố. Trong trường hợp của chúng tôi nó không phải là một vấn đề ở tất cả và nó đã đáp ứng nhu cầu của chúng tôi. Mã của tôi có thể được sửa đổi để sử dụng một cơ chế lưu bộ nhớ đệm mà chỉ duy trì một tập con của các bản dịch trong bộ nhớ tại bất kỳ thời điểm nào. Mã chỉ là một ví dụ về những gì đã làm việc, không phải là điều tốt nhất trong mọi tình huống. 05 sep. 122012-09-05 15:01:31