2010-04-09 33 views
14

Chúng tôi có rất nhiều chuỗi chứa cùng một chuỗi con, từ các câu về kiểm tra nhật ký hoặc cách liên hệ với bộ phận hỗ trợ, đến các chuỗi giống như thương hiệu có chứa tên công ty hoặc sản phẩm. Sự lặp lại đã gây ra một vài vấn đề cho chính mình (chủ yếu là lỗi chính tả hoặc sao chép/dán lỗi) nhưng nó cũng gây ra các vấn đề ở chỗ nó làm tăng số lượng văn bản dịch giả của chúng tôi phải dịch.Làm thế nào để tránh lặp lại trong chuỗi Java ResourceBundle?

Các giải pháp tôi đã đưa ra đi một cái gì đó như thế này:

public class ExpandingResourceBundleControl extends ResourceBundle.Control { 
    public static final ResourceBundle.Control EXPANDING = 
    new ExpandingResourceBundleControl(); 

    private ExpandingResourceBundleControl() { } 

    @Override 
    public ResourceBundle newBundle(String baseName, Locale locale, String format, 
            ClassLoader loader, boolean reload) 
    throws IllegalAccessException, InstantiationException, IOException { 

     ResourceBundle inner = super.newBundle(baseName, locale, format, loader, reload); 
     return inner == null ? null : new ExpandingResourceBundle(inner, loader); 
    } 
} 

ExpandingResourceBundle đại biểu đến bó tài nguyên thật nhưng thực hiện chuyển đổi của {{this.kind.of.thing}} để tìm kiếm chìa khóa trong các nguồn tài nguyên.

Mỗi khi bạn muốn để có được một trong số này, bạn phải đi:

ResourceBundle.getBundle("com/acme/app/Bundle", EXPANDING); 

Và điều này hoạt động tốt - một thời gian.

Điều cuối cùng xảy ra là một số mã mới (trong trường hợp mã được tạo tự động của chúng tôi được nhổ ra khỏi Matisse) tra cứu cùng một gói tài nguyên mà không chỉ định điều khiển tùy chỉnh. Điều này dường như không thể tái sản xuất nếu bạn viết một bài kiểm tra đơn vị đơn giản gọi nó với và sau đó không có, nhưng nó xảy ra khi ứng dụng được chạy cho thực. Bằng cách nào đó bộ nhớ cache bên trong ResourceBundle đẩy giá trị tốt và thay thế nó bằng giá trị bị hỏng. Tôi chưa tìm ra lý do tại sao và các tập tin jar của Sun được biên dịch mà không cần thông tin gỡ lỗi để gỡ lỗi nó là một việc vặt.

Câu hỏi của tôi:

  1. Có một số cách để thiết lập trên toàn cầu các ResourceBundle.Control mặc định rằng tôi có thể không biết? Điều đó sẽ giải quyết mọi thứ khá thanh lịch.

  2. Có cách nào khác để xử lý loại điều này một cách thanh lịch, có lẽ không làm xáo trộn các lớp ResourceBundle?

+0

Đó là thứ có thể dễ dàng được xử lý bằng cách sử dụng lập trình meta, nếu Java có. –

Trả lời

6

Tôi nghĩ đây là một lỗ hổng cơ bản trong cách ResourceBundles được thiết kế để hoạt động: các khóa tham chiếu các khóa khác tự động vi phạm nguyên tắc DRY (không lặp lại). Cách tôi nhận được xung quanh điều này tương tự như phương thức của bạn: tạo một lớp ReflectiveResourceBundle cho phép bạn chỉ định các khóa Tài nguyên trong các thông báo sử dụng ký hiệu EL.

một cách sai lầm:

my.name.first=Bob 
my.name.last=Smith 
my.name.full=Bob Smith 

đúng cách:

my.name.first=Bob 
my.name.last=Smith 
my.name.full=${my.name.first} ${my.name.last} 

Tôi đã uploaded the code to GitHub vì vậy bạn hay bất cứ ai khác có thể tải về nó. Ngoài ra, tôi đã thêm một số mã mẫu cho bất kỳ ai sử dụng Stripes Framework (http://www.stripesframework.org/) để giúp bạn nhanh chóng hoạt động.

Bí quyết để làm việc này với thẻ tag tiêu chuẩn JSTL fmt là thiết lập bộ chặn chặn thay thế tài nguyên của HttpServletRequest bằng tài nguyên của riêng chúng tôi. Mã trông giống như sau:

ResourceBundle bundle = MyStaticResourceHoldingTheBundle.getBundle(); 
Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale)); 

Hãy xem gói sọc.interceptor trong liên kết ở trên để biết thêm chi tiết.

+0

Bạn nói đúng, điều này rất giống với giải pháp của chúng tôi, và nó có cùng một nhược điểm là mã được tạo ra bằng cách sử dụng ResourceBundle.getBundle() sẽ không nhận được giải pháp thay thế. Sự khác biệt chính là trong trường hợp của chúng tôi, chúng tôi sử dụng bộ nhớ cache ResourceBundle hiện có trong khi trong trường hợp bạn giữ bộ nhớ cache riêng biệt, có lẽ là để làm việc xung quanh bộ nhớ cache của Sun đôi khi clobbering các gói được lưu trữ. – Trejkaz

+0

Bởi vì tôi chỉ tình cờ gặp phải vấn đề tương tự: Tôi về cơ bản muốn sử dụng lại tất cả các tính năng của ResourceBundle, nhưng thêm mở rộng khóa. Vì vậy, tôi có nguồn gốc từ PropertyResourceBundle và overrode handleGetObject() cho phù hợp (như có thể được nhìn thấy trong các nguồn Matt Brocks). Sau đó tôi bắt nguồn từ ResourceBundle.Control, overrode newBundle() để trả về PropertyResourceBundle tùy chỉnh của tôi (chỉ cần sửa đổi nguồn gốc cho phương thức này) và chuyển nó thành ResourceBundle.getBundle(). Điều này làm cho nó có thể tái sử dụng tất cả các tính năng của ResourceBundle + thêm mở rộng khóa. – quaylar

+0

@Matt Brock, có vẻ như liên kết bị hỏng. Bạn có thể chia sẻ trang không? –

0

Nếu lặp lại chuỗi được khoanh vùng theo nghĩa là bạn biết một chuỗi nhất định sẽ được lặp lại nhưng chỉ trong cùng một dự án như vậy mà bó chia sẻ tài nguyên không phải là một cơn ác mộng thiết kế, sau đó bạn có thể cân nhắc phá vỡ chuỗi xuống vào nhiều phần khóa-giá trị. Tách các bộ phận lặp lại với những phần không sử dụng lại và tái sử dụng các phần lặp lại. Ví dụ, cho phép nói rằng bạn có hai chuỗi sau đây bạn cần phải hiển thị: "Các Robin Red mũ là một nhỏ có nguồn gốc bộ Sẻ chim đến Úc"

  1. "The Robin Red trắng được tìm thấy trong khu vực máy sấy trên khắp lục địa. "

Gói tài nguyên có thể là như sau:

robin.name=The Red-capped Robin 
robin.native=is a small passerine bird native to Australia. 
robin.region=is found in dryer regions across much of the continent. 

và sau đó kết hợp các phần cần thiết khi cần bundle.getString("robin.name")+bundle.getString(robin.native).

Một điều bạn cần phải cẩn thận về dù là các quy tắc ngữ pháp như chủ đề thứ tự vị từ, v.v. có thể không giống nhau trong tất cả các ngôn ngữ. Vì vậy, bạn sẽ cần phải được một chút cẩn thận khi chia tách câu.

+5

Thực ra đó cũng là một ý tưởng tồi đối với các ngữ cảnh khác nhau (ví dụ: trên menu hoặc trong thanh trạng thái), giới tính của chủ thể và đa số (1, 2, 27, v.v), vì chúng cũng thay đổi tùy theo văn hóa. – devstuff

+0

Đây thực sự là lý do chính xác chúng tôi đã đi với phương pháp làm tất cả các chèn từ phía ResourceBundle. Với cách tiếp cận hiện tại của chúng ta, ví dụ sẽ được thực hiện bằng cách đặt {{robin.name}} vào vị trí thích hợp trong các giá trị bên dưới nó. Nếu ai đó gặp phải một ngôn ngữ mà nó không hoạt động, họ có khả năng loại bỏ hoàn toàn biến đó. Nhưng ... giải pháp của chúng tôi là tất nhiên khó khăn để làm cho công việc một cách chính xác. – Trejkaz

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