Traktowanie liczby mnogiej w systemie Android od „zero”


84

Jeśli mój plik strings.xml zawiera następujący zasób liczby mnogiej:

   <plurals name="item_shop">
        <item quantity="zero">No item</item>
        <item quantity="one">One item</item>
        <item quantity="other">%d items</item>
   </plurals>   

Wynik pokazuję użytkownikowi za pomocą:

textView.setText(getQuantityString(R.plurals.item_shop, quantity, quantity));

Działa dobrze z 1 i wyższymi, ale jeśli ilość wynosi 0, widzę „0 pozycji”. Czy wartość „zero” jest obsługiwana tylko w języku arabskim, jak wskazuje dokumentacja? A może coś mi brakuje?


21
Ten problem został zgłoszony tutaj code.google.com/p/android/issues/detail?id=8287 . Jeszcze nie naprawione: /
OcuS,

5
Nie sądzę, żeby to był błąd: Zwróć uwagę, że wybór jest dokonywany na podstawie konieczności gramatycznej. Ciąg znaków zerowy w języku angielskim zostanie zignorowany, nawet jeśli ilość wynosi 0, ponieważ 0 nie różni się gramatycznie od 2 ani żadnej innej liczby poza 1 („zero książek”, „jedna książka”, „dwie książki” itd. on)
ByteMe

1
Niestety nie wszystkie języki są identyczne z angielskim
Armand

3
Myślę, że jest to błąd w tym sensie, że pomijając gramatykę, w 99% przypadków potrzebowałem tej brakującej funkcjonalności. Więc tak, uważam, że to błąd, którego Google prawdopodobnie nigdy nie naprawi. W związku z tym potrzebne jest obejście. Widzisz, interfejsy API są po to, aby pomóc konsumentom, załatwić sprawę, a nie tylko reprezentować abstrakcyjne koncepcje ze świata rzeczywistego. Gdyby Zero był wspierany po wyjęciu z pudełka, obie grupy (ci, którzy potrzebują poprawności gramatycznej i ci, którzy jej nie potrzebują), mogłyby uciec bez konieczności używania czegoś innego.
Martin Marconcini

Odpowiedzi:


90

Metoda internacjonalizacji zasobów Androida jest dość ograniczona. Używając standardu odniosłem znacznie większy sukcesjava.text.MessageFormat .

Zasadniczo wszystko, co musisz zrobić, to użyć standardowego zasobu ciągu w następujący sposób:

<resources>
    <string name="item_shop">{0,choice,0#No items|1#One item|1&lt;{0} items}</string>
</resources>

Następnie z kodu wszystko, co musisz zrobić, to:

String fmt = getResources().getText(R.string.item_shop).toString();
textView.setText(MessageFormat.format(fmt, amount));

Możesz przeczytać więcej o ciągach formatujących w javadocs dla MessageFormat


7
Niezłe obejście. Mogę sobie teraz wyobrazić, jaki bałagan ludzie, którzy tłumaczą moje aplikacje,
wrzucą do

1
Jak utworzyć ciąg formatu dla „kilku” liczb (liczby kończące się 2, 3, 4, ale nie kończące się na 12, 13, 14)?
vokilam

4
Wow, to brzydkie. Taka logika powinna być zawarta w kodzie, a nie w tłumaczeniach. Liczba mnoga ma pomóc tylko w różnicach językowych dla liczb. Dzięki zaleceniu dla „niewielu” udało się przenieść logikę do tłumaczeń i tłumaczenia do logiki.
DennisK

2
Z pewnością nie jest to przyjemne obejście. Po prostu dodaj wcześniej ciąg dla no_items i klauzulę if. Jeśli (items.count == 0) {użyj ciągu} else {użyj liczby mnogiej} i WTEDY pozwól tłumaczom rozwiązać problem w pliku strings.xml…
Martin Marconcini

2
@ MartínMarconcini masz rację ... ponad 3 lata później :-)
GreyBeardedGeek

47

Od http://developer.android.com/guide/topics/resources/string-resource.html#Plurals :

Zwróć uwagę, że wybór jest dokonywany na podstawie konieczności gramatycznej. Ciąg znaków zerowy w języku angielskim zostanie zignorowany, nawet jeśli ilość wynosi 0, ponieważ 0 nie różni się gramatycznie od 2 ani żadnej innej liczby poza 1 („zero książek”, „jedna książka”, „dwie książki” itd. na). Nie dajcie się też zwieść faktowi, że, powiedzmy, dwa dźwięki, które mogą mieć zastosowanie tylko do wielkości 2: język może wymagać, aby 2, 12, 102 (i tak dalej) były traktowane tak samo, ale inaczej wielkie ilości. Polegaj na swoim tłumaczu, aby wiedział, na jakie rozróżnienia kładzie nacisk jego język.

Podsumowując, „zero” jest używane tylko w przypadku niektórych języków (to samo dotyczy „dwóch”, „kilku” itp.), Ponieważ inne języki nie mają specjalnej koniugacji i dlatego pole „zero” jest uważane za niepotrzebne


4
„Ciąg znaków zerowy w języku angielskim zostanie zignorowany, nawet jeśli ilość będzie równa 0, ponieważ 0 nie różni się gramatycznie od 2” ... a co powiesz na „Nie mam owoców” w porównaniu z „Mam jabłko i pomarańczę”?
Jeffrey Blattman,

4
Istnieje wiele różnych sposobów wyrazu 0 w porównaniu z 2. Ideą tych zasobów jest użycie ich z liczbą. Coś w stylu: mam 0 jabłek. Mam 1 jabłko. Mam 2 jabłka.
ByteMe

4
szkoda. nie powinni byli próbować przyjmować założeń specyficznych dla języka. wszyscy, których znam, którzy używają liczby mnogiej, są przez to zdezorientowani.
Jeffrey Blattman

2
@ miracle2k: Wiadomości nie są tłumaczone według kategorii, więc jakiekolwiek kategorie lub wiadomości w jednym języku nie mają wpływu na inny język. Więc jeśli masz komunikat klasy „zero” w języku angielskim tylko dla liczby zerowej, a inny język używa klasy „zero” dla zliczeń 10,100, to nie ma znaczenia, ponieważ nie tłumaczysz wiadomości klasy „zero”. Z drugiej strony: jeśli utworzysz oddzielny zasób wiadomości dla liczby 0 w języku angielskim, tworzysz problem z przepływem pracy dla tłumaczy, ponieważ ten przypadek jest już objęty oryginalną wiadomością klasy „zero” w ich języku.
Basel Shishani,

2
Prawdą jest, że włączenie kategorii „zero” w języku angielskim jako funkcji wygodnej byłoby możliwe, ale nie jest to „czyste” i tylko zachęca do złego zachowania. Możesz wpaść na pomysł umieszczenia tekstu zachęcającego użytkownika do dodawania elementów do ciągu „zero” - wtedy prawdopodobnie nie będzie można go przetłumaczyć. Ściśle mówiąc, przykład PO („Brak elementów”) już wykazuje ten problem, ponieważ tłumacz może chcieć wyrazić wielkość 0, używając również słów. Nie jest to problem z przepływem pracy, jeśli uznasz „element% s” za pojedynczą wersję „elementów% s”, a „Brak elementów” za coś zupełnie innego pod względem językowym.
cud2k

15

Oto obejście, którego używam, aby rozwiązać ten problem bez przełączania się na MessageFormat.

Najpierw wyodrębniam ciąg „zero” do własnego zasobu ciągu.

<string name="x_items_zero">No items.</string>
<plurals name="x_items">
    <!-- NOTE: This "zero" value is never accessed but is kept here to show the intended usage of the "zero" string -->
    <item quantity="zero">@string/x_items_zero</item>
    <item quantity="one">One item.</item>
    <item quantity="other">%d items.</item>
</plurals>

Następnie mam kilka wygodnych metod w moim własnym ResourcesUtil

public static String getQuantityStringZero(Resources resources, int resId, int zeroResId, int quantity) {
    if (quantity == 0) {
        return resources.getString(zeroResId);
    } else {
        return resources.getQuantityString(resId, quantity, quantity);
    }
}

public static String getQuantityStringZero(Resources resources, int resId, int zeroResId, int quantity, Object... formatArgs) {
    if (quantity == 0) {
        return resources.getString(zeroResId);
    } else {
        return resources.getQuantityString(resId, quantity, formatArgs);
    }
}

Teraz za każdym razem, gdy chcę użyć określonego ciągu dla ilości zerowej, wzywam:

String pluralString = ResourcesUtil.getQuantityStringZero(
     getContext().getResources(),
     R.plural.x_items,
     R.string.x_items_zero,
     quantity
);

Chciałbym, żeby było coś lepszego, ale przynajmniej załatwia to zadanie, zachowując czytelność XML zasobu ciągu.


Używając tego, czy "<item quantity =" zero ">" faktycznie nigdy nie będzie używany?
programista Androida

4
Prawidłowe „<item quantity =" zero ">” nie będzie używane. Mam to, ponieważ myślę, że pomaga to wyjaśnić zamierzone użycie tej wartości dla zera.
Justin Fiedler

Tak myślałem. Może jednak pomóc tłumaczom zrozumieć, co się dzieje.
programista Androida

13

Android używa systemu liczby mnogiej CLDR, a to po prostu nie działa (więc nie spodziewaj się, że to się zmieni).

System jest opisany tutaj:

http://cldr.unicode.org/index/cldr-spec/plural-rules

Krótko mówiąc, ważne jest, aby zrozumieć, że „jeden” nie oznacza liczby 1. Zamiast tego te słowa kluczowe są kategoriami, a konkretne liczby n, które należą do każdej kategorii, są zdefiniowane przez reguły w bazie danych CLDR:

http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html

Chociaż wydaje się, że nie ma języka, który używa „zera” dla czegokolwiek innego niż 0, są języki, które przypisują 0 do „jedynki”. Z pewnością jest wiele przypadków, w których „dwa” zawiera inne liczby niż tylko 2.

Jeśli Android umożliwi Ci robienie tego, co zamierzałeś, Twoje aplikacje nie mogą zostać poprawnie przetłumaczone na dowolną liczbę języków z bardziej złożonymi regułami liczby mnogiej.


5
Zachowaj ostrożność podczas publikowania standardowych / dosłownych odpowiedzi na wiele pytań, które są kopiowane i wklejane. Zazwyczaj są one oznaczane przez społeczność jako „spamerskie”. Jeśli to robisz, zwykle oznacza to, że pytania są duplikatami, więc zamiast tego
oznacz

3

Napisałem rozszerzenie Kotlin, aby obsłużyć wszystkie scenariusze, o których mogę pomyśleć.

mam zeroResId jako opcjonalne, więc czasami chcemy obsłużyć zero, wyświetlając „Brak pozycji” zamiast „0 pozycji”.

Angielski traktuje zero gramatycznie jako liczbę mnogą.

Wyboru używanego ciągu dokonuje się wyłącznie na podstawie konieczności gramatycznej.

W języku angielskim ciąg znaków zerowy jest ignorowany, nawet jeśli ilość wynosi 0, ponieważ 0 nie różni się gramatycznie od 2 ani żadnej innej liczby poza 1 („zero książek”, „jedna książka”, „dwie książki” itd. na).

https://developer.android.com/guide/topics/resources/string-resource.html#Plurals

fun Context.getQuantityStringZero(
    quantity: Int, 
    pluralResId: Int, 
    zeroResId: Int? = null
): String {
    return if (zeroResId != null && quantity == 0) {
        resources.getString(zeroResId)
    } else {
        resources.getQuantityString(pluralResId, quantity, quantity)
    }
}

2

Jeśli używasz powiązania danych, możesz obejść ten problem za pomocą czegoś takiego:

<TextView ... 
android:text="@{collection.size() > 0 ? @plurals/plural_str(collection.size(), collection.size()) : @string/zero_str}"/>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.