2011-08-09 17 views
10

Khi thực hiện quốc tế hóa trong Java, bạn gán một khóa chuỗi cho mỗi thư. Thực hành tốt nhất là gì, nơi đặt các khóa chuỗi đó. Mục tiêu là cho phép tái cấu trúc dễ dàng (ví dụ: thay đổi tên khóa), mã sạch và dễ đọc, tách mối quan tâm nhưng vẫn không sao chép khóa/tin nhắn ngay cả khi được gọi từ các phần khác nhau của mã.Nơi đặt các chuỗi khóa i18n trong Java

//bad way, strings directly in code 
messages.getString("hello_key"); 

-

// better way, use String constants 
public static final String HELLO_KEY = "hello_key"; 
... 
messages.getString(HELLO_KEY); 

-

// other (better?) way, put all keys in one huge central class 
public class AllMessageKeys { 
    public static final String HELLO_KEY = "hello_key"; 
    ... 
} 

public class Foo { 
    ... 
    messages.getString(AllMessageKeys.HELLO_KEY); 
} 

-

// other (better?) way, put all keys in neighbor class 
public class FooMessageKeys { 
    public static final String HELLO_KEY = "hello_key"; 
} 

public class Foo { 
    ... 
    messages.getString(FooMessageKeys.HELLO_KEY); 
} 

Bất kỳ đề xuất khác? Tốt nhất? Tôi đang sử dụng IDE Eclipse, nếu điều đó làm cho phần tái cấu trúc trở nên rõ ràng hơn.

Làm rõ: trong ví dụ trên "thông báo" thuộc loại ResourceBundle.

+0

Đừng downvote câu trả lời nếu bạn muốn mọi người bận tâm để trả lời câu hỏi của bạn. Tôi sẽ sửa đổi câu trả lời của tôi, nhưng tôi không nghĩ rằng nó là giá trị nỗ lực nữa. –

+2

@Stephen C: Là đối số phản đối: hãy bỏ phiếu xuống bình chọn câu trả lời nghèo nàn. Đó là toàn bộ điểm của hệ thống bầu cử. Đó là ở đây để dễ dàng phân biệt giữa những người được rõ ràng, đủ cho một số người và những người mà không ai hiểu. Ngoài ra nó sẽ phục vụ như một số liệu chính xác (mặc dù nó thường không). –

Trả lời

1

tôi luôn sử dụng cho các công cụ như một giao diện mà chìa khóa của tôi được liệt kê. Tên của Interace chủ yếu là DESC = Vấn đề/mô tả/chủ đề ngắn và các giá trị khóa. Bằng cách này, bạn có thể tạo một số Giao diện đẹp và một số Giao diện chung, ví dụ: cho các phím OK hoặc Abort.

// other (better?) way, put all keys in neighbor class 
public interface DESCMessage { 
    public static final String HELLO_KEY = "hello_key"; 
} 

public class Foo { 
    ... 
    messages.getString(DESCMessage.HELLO_KEY); 
} 
+3

Nhận xét của tôi về điều này là nó chạy ngược với "giao diện mô tả loại" 'thực hành tốt nhất' (Checkstyle, Bloch). –

+0

Đồng ý với @AlistairIsrael. Đây là một ví dụ kinh điển về kiểu chống "giao diện liên tục" như được mô tả bởi Bloch. Xin đừng dùng cái này. – Mike

+0

Đồng ý với aisrael và Mike.Nếu bạn muốn một cách tiếp cận tương tự, một Enum sẽ là tốt nhất cho điều này (như đã được chỉ ra bởi Arne Burmeister), nếu bạn không thích phím bổ sung() gọi bạn chỉ đơn giản là có thể đi với hằng số tĩnh cuối cùng. – JavierJ

-1

IMHO Nơi tốt nhất để xác định các phím này, và chuỗi liên quan của họ, là NLS files.n Và bạn phải lưu chúng vào file ResourceBundle

2

Tôi cũng nghĩ điều đầu tiên là lựa chọn tồi tệ nhất. Trong hầu hết các trường hợp (khóa chỉ được sử dụng bởi một lớp), tôi thích giải pháp thứ hai với các hằng số String.

Nếu khóa được tham chiếu từ nhiều lớp, lớp lân cận là cách tốt hơn (sử dụng giao diện như @moohkooh được đề cập).

Giải pháp với một lớp trung tâm tạo ra một nam châm phụ thuộc là thiết kế xấu theo ý kiến ​​của tôi. Các giao diện hàng xóm với các hằng số cho mỗi gói sẽ tốt hơn.

Nếu bạn không muốn có một giao diện để giữ hằng, bạn có thể sử dụng một enum làm giàu:

public enum DESCMessage { 

    HELLO("hello_key"), 
    OTHER("other_key"); 

    private final String key; 

    private DESCMessage(String key) { 
    this.key = key; 
    } 

    public String key() { 
    return key; 
    } 
} 

này có thể được sử dụng như:

messages.getString(DESCMessage.HELLO.key()); 
+0

Bằng cách nào đó tôi đã có thể bỏ qua câu trả lời của bạn khi tôi đọc câu hỏi này ... Thật không may. Tôi mạnh mẽ đồng ý với việc sử dụng enums :) –

1

hằng chuỗi là con đường để đi . Nơi bạn xác định chúng, nó thực sự phụ thuộc vào cấu trúc mã của bạn và cách sử dụng các khóa. Ví dụ:

  • Nếu bạn chỉ sử dụng các khóa trong một lớp, tốt nhất bạn nên đặt chúng ở đó.
  • Nếu bạn tái sử dụng các phím tương tự trên mã của bạn, cách tốt nhất là đặt chúng trong một lớp helper (một lớp cho mỗi gói toàn cầu hoặc tùy thuộc vào cách sử dụng chìa khóa và số lượng phím)

Từ quan điểm refactoring xem nó phức tạp hơn một chút (đòi hỏi nhiều thay đổi hơn) để di chuyển các hằng số từ một lớp này sang lớp khác hơn là đổi tên chúng hoặc thay đổi giá trị của chúng.

Khi thay đổi giá trị của chúng, bạn không có cách nào tự động thay đổi tài nguyên được xác định.

0

IMHO ResourceBundle tạo điều kiện cho việc sử dụng các tệp thuộc tính cụ thể của miền địa phương. Để sử dụng ResourceBundle, các file thuộc tính nên được đặt tên theo quy ước sau đây: -

BaseName_langCode.properties 

HOẶC

BaseName_langCode_countryCode.properties 

Bạn có thể sử dụng các tập tin thuộc tính.

+3

Những gì địa ngục có tên của các tập tin tài nguyên để làm với việc đặt các phím trong mã? –

7

Về cơ bản, có vẻ như tất cả chúng ta đều đồng ý rằng một số loại hằng số là cần thiết. Khi nói đến hằng số, tôi rất thích Enums. Java Enums rất mạnh mẽ và chắc chắn không được sử dụng:

String title = Messages.getString(RunDialogMessages.TITLE); 

OK nhưng những gì tôi phải làm để làm cho nó trông như thế này? Một giao diện đơn giản, một enum và sửa đổi nhỏ để thói quen truy cập thông điệp tiêu chuẩn. Hãy bắt đầu với giao diện:

public interface MessageKeyProvider { 
    String getKey(); 
} 

Các enum:

public enum RunDialogMessages implements MessageKeyProvider { 
    TITLE("RunDialog.Title"), 
    PROMPT("RunDialog.Prompt.Label"), 
    RUN("RunDialog.Run.Button"), 
    CANCEL("RunDialog.Cancel.Button"); 


    private RunDialogMessages(String key) { 
     this.key = key; 
    } 

    private String key; 

    @Override 
    public String getKey() { 
     return key; 
    } 
} 

Và sửa đổi getString() phương pháp:

public static String getString(MessageKeyProvider provider) { 
    String key = provider.getKey(); 
    try { 
     return RESOURCE_BUNDLE.getString(key); 
    } catch (MissingResourceException e) { 
     return '!' + key + '!'; 
    } 
} 

Chỉ cần để hoàn thành bức tranh, chúng ta hãy xem RunDialog.properties (Tôi sẽ hãy nêu một chút về nó sớm):

RunDialog.Title=Run 
RunDialog.Prompt.Label=Enter the name of the program to run: 
RunDialog.Run.Button=Run 
RunDialog.Cancel.Button=Cancel 

Rõ ràng, bạn có thể sử dụng Enum để đọc từ tệp thuộc tính (bằng cách nhúng ResourceBundle), tuy nhiên nó có thể vi phạm Nguyên tắc duy nhất về trách nhiệm (cũng như không lặp lại chính mình, vì mã truy cập sẽ cần được lặp lại).

Quay lại tệp thuộc tính, tôi có cảm giác (tôi có thể sai ở đây), rằng một trong các mục tiêu của bạn là tránh sao chép bản dịch. Đó là lý do tại sao tôi đặt hai Runs ở ví dụ trên. Bạn thấy đấy, từ này sẽ được dịch theo một cách khác tùy thuộc vào ngữ cảnh (thực tế là khá phổ biến). Trong ví dụ này, nếu tôi được dịch đó để Ba Lan nó sẽ trông như thế này:

RunDialog.Title=Uruchamianie 
RunDialog.Prompt.Label=Wpisz nazwę programu do uruchomienia: 
RunDialog.Run.Button=Uruchom 
RunDialog.Cancel.Button=Anuluj 

Đó là vấn đề đáng tiếc của một số ngôn ngữ lạ mà có một khái niệm về chia ...

1

Một trong những tốt cách thực hiện điều này được giải thích ở đây: Short article on a new approach using NLS với một số ưu điểm hơn phương pháp tiếp cận ResourceBundle.

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