2009-07-21 4 views
10

Giả sử bạn đang tạo một phần mềm blog và muốn hiển thị số lượng nhận xét mà mục nhập nhận được. Bạn có thể làm theo cách này:Cách thanh lịch nhất để đối phó với người độc thân/số nhiều?

[Entry title] 
[Content........] 
[ <?php print($numComments;) ?> Comments] 

nào có thể dẫn đến:

[Entry title] 
[Content........] 
5 Comments 

Nhưng nếu một mục chỉ có 1 bình luận, tôi muốn dòng để nói 'Comment' chứ không phải 'Nhận xét'. Và trong dòng if/else s là xấu xí và lặp đi lặp lại.

Cách tốt nhất để giải quyết vấn đề này là gì?

+4

+1 Dành cho tên người dùng của bạn, vì nó cho tôi biết. Đó là một thông minh và tôi muốn được quan tâm đến việc biết bao nhiêu upvotes bạn đã cho rằng một mình. :) – Dusty

+1

Tôi bị cám dỗ một nửa chỉ để chống lại tác động của những người upvote –

Trả lời

13

Vui lòng sử dụng các chức năng ngettext cho những thứ như thế này. Nó cho phép bạn xử lý chính xác với số nhiều bằng tiếng Anh và các ngôn ngữ khác , một lần và cho tất cả. Bạn sử dụng nó như thế này:

printf(ngettext("%d Comment", "%d Comments", $numComments), $numComments); 

Chức năng ngettext sẽ trả về chuỗi định dạng đầu tiên ("%d Comment") nếu có chỉ là một bình luận duy nhất và thứ hai định dạng string ("%d Comments") nếu có nhiều. Hàm printf sẽ sau đó đặt số vào chuỗi.

này có vẻ như rất nhiều công việc, nhưng nó là rất mạnh mẽ: nó hoạt động với các ngôn ngữ có nhiều hơn một hình thức số nhiều - họ thực sự tồn tại (!). Hướng dẫn sử dụng PHP đưa ra một ví dụ cho từ "cửa sổ" trở thành "1 okno", "2 okna" và "5 oken" trong một số ngôn ngữ kỳ lạ mà tôi không nhận ra ...

Nếu bạn là hậu quả về việc sử dụng ngettext thì người dùng tương lai của bạn từ các nước xa xôi sẽ rất biết ơn bạn :-)

Edit: Như đã đề cập trong các ý kiến, có một chức năng duy nhất để làm các việc trên:

function pluralize($num, $singleWord, $pluralWord) { 
    return printf(ngettext($singleWord, $pluralWord, $num), $num); 
} 

Theo mặc định, xgettext sẽ không nhận ra chức năng mới này, nhưng bạn có thể thêm nó với --keyword cờ. Cho một tập tin test.php với

echo ngettext("foo", "foos", 1); 
echo pluralize(2, "bar", "bars"); 

bạn có thể trích xuất các chuỗi với

xgettext --keyword=pluralize:2,3 test.php 

Các kết quả messages.po tập tin có mục như thế này:

#: test.php:7 
msgid "foo" 
msgid_plural "foos" 
msgstr[0] "" 
msgstr[1] "" 

#: test.php:8 
msgid "bar" 
msgid_plural "bars" 
msgstr[0] "" 
msgstr[1] "" 

Các dịch sẽ điền vào mỗi hình thức số nhiều và với dòng chính xác là hình thành "Dạng số nhiều" trong tiêu đề danh mục thư, bạn sẽ là khả năng để hỗ trợ tất cả các ngôn ngữ.

+0

nó sẽ được lặp đi lặp lại để sử dụng điều này với một printf tất cả các thời gian, nhưng có lẽ một hàm wrapper có thể được viết mà không printf và% d. Có lẽ bạn có thể viết nội dung của hàm này và cập nhật câu trả lời của bạn? 'function pluralize ($ num, $ singleWord, $ pluralWord = '')' –

+0

@Click Upvote: ý tưởng hay. Tôi đã thực hiện hàm với ba đối số bắt buộc - chuỗi số nhiều là cần thiết để xgettext có thể nhận ra hàm gọi và xử lý nó một cách chính xác. –

+0

Đó sẽ là tiếng Slovak. –

3

Tạo hàm có số và từ và trả về một chuỗi chứa cả hai. Nó sẽ thêm một "s" (hoặc tham khảo một từ điển mà bạn xây dựng) khi số lớn hơn 1.

+1

Tôi sẽ làm cho chức năng thêm các s nếu số không phải là 1, do đó 0 được dạng số nhiều là tốt. –

+0

Bạn sẽ gọi một chức năng như thế nào? –

+0

Pluralize có vẻ giống như tên phù hợp nhất. – Brandon

2

Không phải là thanh lịch nhất, nhưng dễ nhất để xuất ra "Chú thích".

[Entry title] 
[Content........] 
1 Comment(s) 
+0

Dễ dàng, nhưng không hoạt động tốt trong mọi tình huống –

+2

Như bạn lưu ý, điều này không phải rất thanh lịch ... Khi tôi xem đầu ra như vậy, tôi luôn luôn tự hỏi tại sao máy tính không dành thêm mili giây để tìm ra nếu "s" nên có hay không :-) –

+0

+1 Haha. Đã đồng ý. – Dusty

4

Tại sao không dành thời gian để nhân đạo thứ thậm chí nhiều hơn ....

switch ($numComments) 
{ 
    case 0: 
     echo "Be the first to write a comment"; 
     break; 
    case 1: 
     echo "Just one comment so far"; 
     break; 
    default: 
     echo "There are $numComments comments"; 

} 
+0

+1 Phương pháp này sẽ tránh được hầu hết các vấn đề nội địa hoá. – fishlips

+0

@fishlips: ngoại trừ khi một ngôn ngữ có ba hoặc nhiều dạng số nhiều. Như được giải thích dưới đây, hàm ngettext là giải pháp tổng quát hơn. Nó cho phép một dịch giả bao gồm tất cả các dạng số nhiều của nó trong tập tin ".po" và một trình dịch đúng sẽ được chọn khi chạy. –

3

Nó làm tôi ngạc nhiên mà không ai cho rằng chưa, nhưng những gì tôi thường làm là sử dụng các nhà điều hành có điều kiện:

string commentWord = numComments != 1 ? "Comments" : "Comment"; 

Lưu ý: chuỗi nên dĩ nhiên không được mã hóa cứng như thế này, mà được tải từ kho lưu trữ tài nguyên, nơi lưu trữ với trình giữ chỗ định dạng cho số, để bạn có thể xử lý ngôn ngữ mà số sẽ xuất hiện cuối cùng (hoặc ở giữa):

// should load "{0} Comments" or "{0} Comment" if we run in an English locale 
string comments = string.Format(
     numComments != 1 ? GetResource("Comments") : GetResource("Comment"), 
     numComments); 
+4

Đây không phải là cách thực hiện quốc tế. Ngôn ngữ khác ngoài tiếng Anh có quy tắc riêng cho các dạng số nhiều; ví dụ. Tiếng Lithuania có ba dạng khác nhau: "1 komentaras", "2 komentarai", "10 komentarų". Khuôn khổ GNU gettext phổ biến trong các chương trình C có một giải pháp cho điều này (hàm ngettext). Tôi không quen thuộc với Java/C#/PHP vì vậy tôi không thể nói giải pháp chính xác chính xác ở đó là gì. –

+0

@Marius: cảm ơn thông tin đó. Tôi không biết những quy tắc của Lithuania. Tôi đã thực hiện một chút phần mềm quốc tế (sự kiện đã làm một phần mềm dịch thuật của văn bản giao diện người dùng cho một khách hàng lớn) nhưng chưa bao giờ gặp những yêu cầu như vậy. Rất thú vị! Mặc dù vậy, tôi sẽ không đi sâu vào chi tiết ở đây, tôi chỉ muốn giới thiệu khái niệm chọn các văn bản từ một kho lưu trữ tài nguyên, thay vì chỉ mã hóa chúng. –

+0

@ Fredrik: Tôi cũng bị đánh giá cao lần đầu tiên tôi nghe nói về các ngôn ngữ có nhiều hơn hai dạng số nhiều ... Tôi là người Đan Mạch và chỉ sử dụng hai dạng :-) May mắn thay, chức năng ngettext có thể xử lý nó, vui lòng xem trả lời ở một nơi khác trên trang này. –

0

Khám phá Rails inflector module. Điều này cung cấp một giải pháp tốt đẹp, tập trung và cấu hình cho vấn đề này.

2

Trong C/C++, bạn có thể làm như sau. Bạn có thể làm điều gì đó tương tự trong PHP.

printf("%d %s\n", numComments, numComments == 1 ? "Comment" : "Comments"); 

Sau đây cũng làm việc, nhưng bạn có thể chạy vào các vấn đề với \b (backspace) được xử lý không đúng cách trong việc triển khai khác nhau.

printf("%d Comment%s\n", numComments, numComments == 1 ? " \b" : "s"); 

Sử dụng \0 (ký tự rỗng) để in không có gì, thay vào đó, in không gian trong quá trình triển khai của tôi.