2013-05-30 28 views
8

Tôi đang làm việc trên quốc tế hóa dữ liệu do người dùng nhập vào trong Ứng dụng khách/máy chủ khá lớn (HTTP (Hessian) được sử dụng để liên lạc) được lưu trữ trong cơ sở dữ liệu. Người dùng có thể chọn ngôn ngữ họ muốn xem và có ngôn ngữ mặc định được sử dụng khi bản dịch bằng ngôn ngữ được yêu cầu không có.Bạn có thể sử dụng ThreadLocal để lưu trữ ngôn ngữ được yêu cầu không?

Hiện nay một lớp dữ liệu có thể trông như thế này:

class MyDataClass { 
    private Long id; 
    private String someText; 
    /* getters and setters */ 
} 

Sau khi quốc tế hóa nó có thể trông như thế này:

class MyDataClass { 
    private Long id; 
    private Set<LocalizedStrings> localizedStrings; 
    /* getters and setters */ 
} 
class LocalizedStrings { 
    private Locale locale; 
    private String someText; 
    /* getters and setters */ 
} 

Tất nhiên nó có thể là thú vị để tạo ra một getter đại biểu trong MyDataClass mà mất chăm sóc nhận văn bản ở đúng ngôn ngữ:

public String getSomeText(Locale locale) { 
    for(LocalizedString localized : localizedStrings) { 
    if (localized.getLocale().equals(locale)) { 
     return localized.getSomeText(); 
    } 
    } 
} 

Trong nhóm của tôi, có một số lo ngại về sự cần thiết phải truyền địa phương vào mọi lúc cho đến khi họ đến được lớp dữ liệu. Vì tất cả các công cụ này sẽ xảy ra trên máy chủ và mọi yêu cầu đến máy chủ được xử lý trong một bài viết chuyên dụng, một số người gợi ý để lưu trữ các miền địa phương được yêu cầu trong một đối tượng ThreadLocal và tạo ra một tương thích ngược không tham số getter:

public String getSomeText() { 
    return getSomeText(myThreadLocalLocale.get()); 
} 

ThreadLocal sau đó cần phải là một biến toàn cầu (tĩnh ở đâu đó) hoặc nó cần phải được tiêm vào MyDataClass trên mọi cá thể tạo (chúng ta đang sử dụng spring, vì vậy chúng ta có thể tiêm nó nếu chúng ta làm cho các lớp dữ liệu của chúng ta được quản lý. tôi)).

Sử dụng ThreadLocal cho ngôn ngữ bằng cách nào đó cảm thấy sai với tôi. Tôi có thể mơ hồ tranh luận rằng tôi không thích ma thuật vô hình trong bộ thu thập và sự phụ thuộc vào một biến toàn cầu (trong một lớp dữ liệu!). Tuy nhiên, có một "cảm giác xấu" về điều này không thực sự là một cách tốt để tranh luận với các đồng nghiệp của tôi về nó. Để giúp tôi cần một câu trả lời với một trong các cách sau:

  1. Nói cho tôi biết cảm giác của tôi hút và giải pháp là rất tốt vì các lý do X, Y và Z.
  2. Hãy cho tôi một số lý lẽ dẫn chứng được tốt tôi có thể sử dụng để tranh luận với các đồng nghiệp của tôi và cho tôi biết làm thế nào để làm điều đó tốt hơn (chỉ cần luôn luôn vượt qua địa phương xung quanh hoặc bất kỳ ý tưởng nào khác?)
+1

Tại sao bạn sử dụng Tập hợp cho 'localizedStrings' chứ không phải Bản đồ? –

+0

Bạn đã cân nhắc sử dụng Spring [LocaleContextHolder] (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/i18n/LocaleContextHolder.html). Lò xo của nó sở hữu cách lưu trữ miền địa phương hiện tại (được lưu trữ bởi DispatcherServlet) cho một luồng. – sbk

+0

Nếu phạm vi của biến địa phương hóa của bạn là một chuỗi duy nhất thì điều này có vẻ giống như một giải pháp thông minh (và đơn giản). Nếu bạn đang mạo hiểm vào nhiều chủ đề thì rõ ràng, điều này đòi hỏi một cái gì đó nhiều hơn nữa. Nếu API của bạn có thông tin bản địa hóa trong mỗi yêu cầu thì đó là một giải pháp hoàn toàn hợp lệ. KISS, đó là đối số tốt nhất bạn có thể thực hiện. –

Trả lời

1

Cách tiếp cận này hoàn toàn hợp lệ. Ví dụ: Ví dụ, Spring làm cho Locale khả dụng bằng cách sử dụng ThreadLocal thông qua RequestContextListenerLocaleContextHolder.

Nếu bạn tạo triển khai tùy chỉnh, hãy đảm bảo bạn xử lý ThreadLocal (set/remove) đúng cách.

1

Sử dụng một mô hình địa phương như bạn mô tả là một mô hình rất phổ biến trong các ứng dụng web. Xem lớp này trong API mùa xuân là một ví dụ:

org.springframework.web.context.request.RequestContextHolder 

Sử dụng bộ lọc servlet (hoặc tương tự) cho cả hai thiết lập miền địa phương trong một thread địa phương, và sau đó CLEAR giá trị locale sau khi máy chủ đã hoàn thành mỗi yêu cầu. Thay vì tiêm nó ở mỗi nơi nó được sử dụng, sử dụng một nhà máy tĩnh/phương pháp accessor tương tự như RequestContextHolder: RequestContextHolder.getRequestAttributes().

2

Mặc dù, thông thường, tôi không thích làm bản địa hóa "sâu" trong ứng dụng.

Intead điều này:

public String getSomeText() { 
    return getSomeText(myThreadLocalLocale.get()); 
} 

Chúng tôi làm điều này:

public LocalizableText getSomeText() { 
    return new LocalizableText(resourceBundle, "someText"); 
} 

Và sau đó làm, ví dụ trong lớp JSP hoặc lớp đầu ra:

<%= localizable.getString(locale) %> 

Bản thân logic là ngôn ngữ bất khả tri. Chúng tôi có trường hợp, sau khi xử lý một số, ứng dụng sẽ gửi kết quả qua thư, ghi nhật ký và trình bày nó cho người dùng web bằng tất cả các ngôn ngữ khác nhau. Vì vậy, việc xử lý cùng với việc tạo kết quả và sau đó bản địa hóa phải được tách biệt.

0

ThreadLocal là thực hành không tốt. Đó là các biến toàn cầu và có rất nhiều bài viết về mức độ tồi tệ của ngôn ngữ đó. Thực tế là Spring sử dụng nó không biện minh cho việc sử dụng nó. Tôi thích các giải pháp cruftex đã đưa ra. Tránh truyền dữ liệu qua các biến toàn cục.

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