Mnogość w wiadomościach użytkownika

106

Wielokrotnie, podczas generowania wiadomości do pokazania użytkownikowi, wiadomość będzie zawierała szereg rzeczy , o których chcę poinformować klienta.

Podam przykład: klient wybrał kilka pozycji od 1 wzwyż i kliknął Usuń. Teraz chcę przekazać klientowi wiadomość potwierdzającą i chcę wspomnieć o liczbie wybranych przez niego pozycji, aby zminimalizować możliwość popełnienia błędu przez wybranie kilku pozycji i kliknięcie przycisku Usuń, gdy chce usunąć tylko jedną z im.

Jednym ze sposobów jest utworzenie ogólnej wiadomości w ten sposób:

int noofitemsselected = SomeFunction();
string message = "You have selected " + noofitemsselected + " item(s). Are you sure you want to delete it/them?";

"Problemem" jest tutaj przypadek, w którym noofitemselectedjest 1 i musimy wpisać item i to zamiast itemów i je .

Moje normalne rozwiązanie będzie takie

int noofitemsselected = SomeFunction();
string message = "You have selected " + noofitemsselected + " " + (noofitemsselected==1?"item" : "items") + ". Are you sure you want to delete " + (noofitemsselected==1?"it" : "them") + "?";

Robi się to dość długo i dość paskudnie, naprawdę szybko, jeśli w kodzie jest wiele odniesień do mnogości liczb, a rzeczywista wiadomość staje się trudna do odczytania.

Więc moje pytania są proste. Czy są jakieś lepsze sposoby generowania takich wiadomości?

EDYTOWAĆ

Widzę, że wiele osób bardzo się rozłączyło w przypadku, gdy wspomniałem, że wiadomość powinna być wyświetlana w skrzynce wiadomości i po prostu udzieliła odpowiedzi, jak w ogóle uniknąć korzystania z tej skrzynki i to wszystko jest w porządku .

Pamiętaj jednak, że problem liczby mnogiej dotyczy również tekstów innych miejsc w programie oprócz okien komunikatów. Na przykład etykieta obok siatki wyświetlającej liczbę linii wybranych w siatce będzie miała ten sam problem dotyczący liczby mnogiej.

Zasadniczo dotyczy to większości tekstu, który jest w jakiś sposób generowany przez programy, a wtedy rozwiązanie nie jest tak proste, jak po prostu zmienić program tak, aby nie wyświetlał już tekstu :)

Øyvind Bråthen
źródło
6
@ 0xA3: Naprawdę nie wiem, czy każdy język ma liczbę mnogą, którą można łatwo wyrazić jako „element (y)”.
Jens
5
Prawdopodobnie powinieneś też pomyśleć o lokalizacji. Ten problem może się znacznie pogorszyć.
Alex Brown
4
@Jens: Zwykle tego nie robią, w najmniej wygodny sposób. Niektóre języki mają np. Inną liczbę mnogą dla 2-4 niż dla 5-nieskończoności, wszystko to w zależności od płci. „Języki naturalne: szaleństwo lokalizacji! Wkrótce na Twoim komputerze!”
Piskvor opuścił budynek
29
IMO, nic nie sprawia, że ​​programiści wyglądają bardziej leniwie dla użytkowników niż zła liczba mnoga.
Greg
4
@ Øyvind: +1 za edycję. Wygląda na to, że wielu „odpowiadających” jest bardziej skupionych na udowodnieniu, że Twoje pytanie jest błędne, niż na oferowaniu właściwego rozwiązania. Anty-rozwiązania, jeśli chcesz.
mwolfe02

Odpowiedzi:

53

Jeśli kiedykolwiek będzie jakaś szansa, nieważne jak mała, że ​​ta aplikacja będzie musiała zostać przetłumaczona na inne języki, to obie są w błędzie. Prawidłowy sposób to:

string message = ( noofitemsselected==1 ?
  "You have selected " + noofitemsselected + " item. Are you sure you want to delete it?":
  "You have selected " + noofitemsselected + " items. Are you sure you want to delete them?"
);

Dzieje się tak, ponieważ różne języki różnie obsługują wiele. Niektóre, takie jak malajski, nie mają nawet składniowej liczby mnogiej, więc ciągi znaków byłyby zasadniczo identyczne. Oddzielenie dwóch ciągów ułatwia późniejszą obsługę innych języków.

W przeciwnym razie, jeśli ta aplikacja jest przeznaczona do użytku publicznego i ma być przyjazna dla użytkownika, preferowana jest druga metoda. Przepraszam, ale tak naprawdę nie znam krótszego sposobu na zrobienie tego.

Jeśli ta aplikacja ma być używana tylko wewnętrznie przez Twoją firmę, zrób to na skróty "item(s)". Nie musisz nikomu imponować, pisząc kod biznesowy. Ale odradzałbym to robić w przypadku aplikacji konsumowanej publicznie, ponieważ sprawia to wrażenie, że programista jest leniwy, a tym samym obniża jego opinię o jakości aplikacji. Zaufaj mi, takie małe rzeczy mają znaczenie.

slebetman
źródło
35
Chociaż zgadzam się z założeniem, ignorujesz języki, które mają więcej niż dwa stopnie pluralizmu. (Weźmy na przykład rosyjski. Trzy różne sposoby mówienia w zależności od tego, czy wynosi 1, <5, czy> = 5, a nawet to zależy od tego, o czym dokładnie mówisz). Zasadniczo mówię, że potrzebujesz silniejszej instrukcji warunkowej, a nie tylko operatora trójskładnikowego.
Crasic
4
Możesz nawet zoptymalizować noofitemsselectedw tym przykładzie dla pierwszej opcji; ponieważ wiesz, że jest to 1.
Domyślnie
16
Skoro już o tym mowa, hebrajski może mieć różne liczby mnogie dla 1, 2, 3-10 i 11+.
Joel Spolsky
3
@Joel, hebrajski może mieć tyle różnych liczby mnogiej? לא ידעתי (nie wiedziałem)! Współczesny hebrajski jest podobny do angielskiego, jeśli chodzi o liczbę mnogą (chociaż starożytny hebrajski miał również podwójną formę).
Ken Bloom,
3
W języku angielskim zero jest traktowane jak liczba mnoga (0 pozycji, 2 pozycje); co dzieje się z zerem w języku hebrajskim, rosyjskim, rumuńskim? Czy istnieje prosty sposób identyfikacji zakresów? Domyślam się, że informacje muszą być określone dla każdego języka, więc każdy system oparty na plikach komunikatów musi radzić sobie z różnymi ilościami mnogości w zestawie komunikatów. Auć! Ustawienie tłumaczeń również byłoby trudne - dla różnych języków potrzebne są różne liczby wiadomości.
Jonathan Leffler
94

Możesz uniknąć całej tej niechlujnej mnogości, po prostu usuwając elementy bez żadnej wiadomości i dając użytkownikowi naprawdę dobrą funkcję Cofnij. Użytkownicy nigdy niczego nie czytają . W każdym razie powinieneś stworzyć dobrą funkcję Cofnij jako część swojego programu.

W rzeczywistości uzyskujesz 2 korzyści, tworząc kompleksową funkcję cofania. Pierwsza korzyść ułatwia życie użytkownika, umożliwiając mu odwracanie błędów i minimalizację czytania. Drugą korzyścią jest to, że Twoja aplikacja odzwierciedla prawdziwe życie, umożliwiając odwrócenie nietrywialnego przepływu pracy (a nie tylko błędów).

Kiedyś napisałem aplikację bez użycia jednego okna dialogowego lub wiadomości z potwierdzeniem. Wymagało to poważnego przemyślenia i było znacznie trudniejsze do wdrożenia niż używanie wiadomości typu potwierdzenia. Ale wynik końcowy był raczej przyjemny w użyciu, według jego użytkowników końcowych.

HTTP 410
źródło
12
Z jakiegoś powodu naprawdę czuję, że się z tym zgadzam i powinienem to głosować.
Cody Gray
4
@ Øyvind, Oto dlaczego: Wiadomości proszące użytkownika o weryfikację są dla użytkownika drogie, zwłaszcza gdy są prezentowane w postaci modalnego okna dialogowego, które zatrzymuje wszystko, dopóki użytkownik nie odpowie na nie. To denerwuje wielu użytkowników do tego stopnia, że ​​zaczynają po prostu klikać dowolny przycisk, aby ominąć okno dialogowe (ile instalatorów właśnie kliknąłeś następny, następny, następny? ). W związku z tym jest to bezpieczniejsze i znacznie mniej tarcia ze strony użytkownika, jeśli wykonasz tylko nietrwałe usuwanie i zapewnisz możliwość cofnięcia. Gmail używa tej techniki z doskonałym skutkiem.
Robert Harvey
5
Dyskusyjne, ale w każdym razie ten sam problem pojawi się w przypadkach innych niż komunikat potwierdzający usunięcie, więc ta odpowiedź jest naprawdę styczna do pytania.
Jay
50
Głosowałem za tym bez czytania. zawsze mogę to cofnąć później
Steven A. Lowe
6
@Robert Harvey: Prawdopodobnie apokryf, ale wiele lat temu czytałem, że Lotus wysłał 40 000 sztuk Lotus Notes na Maca, a 60 000 zostało zwróconych. Interfejs był tak zły, że nawet ludzie, którzy go piraci, odesłali go z powrotem.
Duncan
39

Może po prostu:

string message = "Are you sure you want to delete " + noofitemsselected + " item(s)?"

W ten sposób eliminujesz trudności z umową numeryczną i jako bonus otrzymujesz jeszcze krótszy, bardziej konkretny komunikat o błędzie dla użytkownika. Wszyscy wiemy, że użytkownicy i tak nie czytają komunikatów o błędach . Im są krótsze, tym bardziej prawdopodobne jest, że przynajmniej spojrzą na tekst.

Lub mając wiedzę, że użytkownicy nie czytają komunikatów o błędach, możesz podejść do tego inaczej. Pomiń całkowicie komunikat potwierdzający i po prostu zapewnij funkcję cofania, która po prostu działa, niezależnie od tego, co zostało usunięte. Większość użytkowników jest już przyzwyczajonych do cofania operacji, gdy zauważą, że nie jest to, czego chcieli, i prawdopodobnie uznają to zachowanie za bardziej naturalne niż konieczność radzenia sobie z kolejnym irytującym wyskakującym okienkiem.

Cody Gray
źródło
1
Dobra odpowiedź. Jednak w tym przypadku klient poprosił o dostarczenie komunikatów o błędach w wielu przypadkach, ponieważ uznał, że to najlepsze podejście. Ale zmiana tekstu może przynajmniej zminimalizować problem i sprawić, że będzie mniej bałaganiarski.
Øyvind Bråthen
@ Øyvind: W porządku. Ponieważ musisz podążać za klientem, zastosowałbym pierwsze podejście, które zaproponowałem, lub użyłbym pliku zasobów z funkcją obsługi. Pomyślałem, że warto wskazać alternatywę, bo tak łatwo o niej zapomnieć. Heck, nawet o tym nie pomyślałem, dopóki nie złożyłem pierwszej odpowiedzi.
Cody Gray
Mile widziane są alternatywy. Dlatego też dałem mu +1 :)
Øyvind Bråthen
1
+1 za niepodejmowanie próby rozwiązania nierozwiązywalnego problemu. I pamiętaj o prawie Steve'a Kruga: usuń połowę słów. Następnie zrób to ponownie. Używam: „Usunąć elementy ({x})?”
Serge Wautier
20

A co z tym, co Java miała od lat: java.text.MessageFormat i ChoiceFormat? Więcej informacji można znaleźć pod adresem http://download.oracle.com/javase/1.4.2/docs/api/java/text/MessageFormat.html .

MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
form.applyPattern(
   "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");

Object[] testArgs = {new Long(12373), "MyDisk"};

System.out.println(form.format(testArgs));

// output, with different testArgs
output: The disk "MyDisk" are no files.
output: The disk "MyDisk" is one file.
output: The disk "MyDisk" are 1,273 files.

W twoim przypadku chcesz czegoś prostszego:

MessageFormat form = new MessageFormat("Are you sure you want to delete {0,choice,1#one item,1<{0,number.integer} files}?");

Zaletą tego podejścia jest to, że działa dobrze z pakietami i18n i możesz zapewnić prawidłowe tłumaczenia dla języków (takich jak japoński), które nie mają pojęcia liczby mnogiej ani liczby pojedynczej.

Berin Loritsch
źródło
1
To podejście sprawdza się dobrze w przypadku wielości, ale niestety nie dotyczy płci. Potrzebujesz innego ciągu dla każdego rodzaju rzeczy, które można usunąć.
Mr. Shiny and New 安 宇
Jeśli znasz rzeczownik, możesz tak ułożyć zdania, aby działały z odpowiednim przymiotnikiem. Ale tak, studiując klasyczną grekę, masz inną formę tego słowa opartą na rzeczownikach rodzaju męskiego, żeńskiego lub nijakiego (przymiotnik przyjmuje postać rzeczownika, który modyfikuje), a forma różni się w zależności od funkcji w zdaniu ( podmiot, przedmiot itp.). Zawsze możemy wymyślić przypadki, w których jedno rozwiązanie działa, a inne nie. W ten sposób ludzie Java próbowali rozwiązać problem. Nadal musisz uważać na sposób tworzenia formatów wiadomości.
Berin Loritsch
Zawsze możesz podać rozwiązanie Java dwie liczby całkowite, gdzie druga wskazuje płeć. (Ale w rzeczywistości zgodność płci jest zwykle mniej niepokojąca po prostu dlatego, że przypadek użycia dopasowania różnych obiektów do wiadomości jest rzadszy niż dopasowanie różnych numerów tego samego przedmiotu do wiadomości)
Ken Bloom,
12

Postanowiłbym nie zakodować wiadomości na sztywno, ale podać dwie wiadomości w osobnym pliku zasobów. Lubić

string DELETE_SINGLE = "You have selected {0} item. Are you sure you want to delete it?";
string DELETE_MULTI = "You have selected {0} items. Are you sure you want to delete them?";

a następnie umieszcza je w String.Format like

if(noofitemsselected == 1)
    messageTemplate = MessageResources.DELETE_SINGLE;
else
    messageTemplate = MessageResources.DELETE_MULTI;

string message = String.Format(messageTemplate, noofitemsselected)

Myślę, że takie podejście jest łatwiejsze do zlokalizowania i utrzymania. Wszystkie komunikaty interfejsu użytkownika znajdowałyby się w jednym miejscu.

Jens
źródło
+1, podoba mi się to podejście. Chociaż należałoby śledzić odpowiedniki nazw zasobów.
Domyślnie
11

Możesz całkowicie ominąć ten problem, używając innego sformułowania wiadomości.

string message = "The number of selected items is " + noofitemsselected + ". Are you sure you want to delete everything in this selection?";
gdejohn
źródło
10

Pierwszą rzeczą, którą zasugerowałbym, jest: użyj string.Format. To pozwala zrobić coś takiego:

int numOfItems = GetNumOfItems();
string msgTemplate;
msgTemplate = numOfItems == 1 ? "You selected only {0} item." : "Wow, you selected {0} items!";
string msg = string.Format(msgTemplate, numOfItems);

Ponadto w aplikacjach WPF widziałem systemy, w których ciąg zasobów byłby rozdzielany potokiem, aby mieć dwie wiadomości: pojedynczą i mnogą (lub nawet zero / pojedynczą / wiele wiadomości). Następnie można użyć niestandardowego konwertera do przeanalizowania tego zasobu i użycia odpowiedniego (sformatowanego) ciągu, więc Xaml wygląda mniej więcej tak:

<TextBlock Text="{Binding numOfItems, Converter={StaticResource c:NumericMessageFormatter}, ConverterParameter={StaticResource s:SuitableMessageTemplate}}" />
Dan Puzey
źródło
7

W przypadku języka angielskiego wiele odpowiedzi powyżej. W przypadku innych języków jest to trudniejsze, ponieważ liczba mnoga zależy od rodzaju rzeczownika i końcówki słowa. Kilka przykładów w języku francuskim:

Zwykły męski:

Vous avez choisi 1 compte. Voulez-vous vraiment le supprimer.
Vous avez choisi 2 comptes. Voulez-vous vraiment les supprimer.

Zwykła kobieca

Vous avez choisi 1 table. Voulez-vous vraiment la supprimer.
Vous avez choisi 2 tables. Voulez-vous vraiment les supprimer.

Nieregularny rodzaj męski (kończy się na „s”)

Vous avez choisi 1 pays. Voulez-vous vraiment le supprimer.
Vous avez choisi 2 pays. Voulez-vous vraiment les supprimer?

Ten sam problem występuje w większości języków łacińskich i nasila się w języku niemieckim lub rosyjskim, gdzie występują 3 rodzaje (maculine, żeński i nijaki).

Musisz uważać, jeśli Twoim celem jest opanowanie czegoś więcej niż tylko angielskiego.

uśmiechnięty człowiek
źródło
Przynajmniej w moim przypadku nie stanowi to problemu. Dla każdego tekstu, który chcę wstawić liczbę, będę wiedział, jaki jest rzeczownik podczas generowania ciągu. Ale żeby znaleźć bardziej ogólne rozwiązanie, zgadzam się z tobą, że sprawienie, by działało we „wszystkich” językach, może być zadaniem bardzo trudnym, jeśli nie niemożliwym.
Øyvind Bråthen
1
Albo weźmy język polski, gdzie liczba mnoga użytego rzeczownika różni się w zależności od liczby! : /
UpTheCreek
5

Aby móc mieć wiadomości w liczbie mnogiej, które będzie można poprawnie zlokalizować, uważam, że rozsądnie byłoby najpierw utworzyć warstwę pośrednią między liczbą a wiadomością.

Na przykład użyj jakiejś stałej, aby określić, którą wiadomość chcesz wyświetlić. Pobierz wiadomość, używając funkcji, która ukryje szczegóły implementacji.

get_message(DELETE_WARNING, quantity)

Następnie utwórz słownik zawierający możliwe komunikaty i odmiany, a następnie poinformuj o nich, kiedy należy ich użyć.

DELETE_WARNING = {
   1: 'Are you sure you want to delete %s item',
   >1: 'Are you sure you want to delete %s items'
   >5: 'My language has special plural above five, do you wish to delete it?'
}

Teraz możesz po prostu znaleźć klucz, który odpowiada the quantityi interpolować wartość quantityz tą wiadomością.

To zbyt uproszczony i naiwny przykład, ale tak naprawdę nie widzę innego rozsądnego sposobu, aby to zrobić i móc zapewnić dobre wsparcie dla L10N i I18N.

Davor Lucic
źródło
5

Będziesz musiał przetłumaczyć poniższą funkcję z VBA na C #, ale twoje użycie zmieniłoby się na:

int noofitemsselected = SomeFunction();
string message = Pluralize("You have selected # item[s]. Are you sure you want to delete [it/them]?", noofitemsselected);

Mam funkcję VBA, której używam w MS Access, aby robić dokładnie to, o czym mówisz. Wiem, że zostanę zhakowany na kawałki za publikowanie VBA, ale tak czy inaczej. Algorytm powinien wynikać z komentarzy:

'---------------------------------------------------------------------------------------'
' Procedure : Pluralize'
' Purpose   : Formats an English phrase to make verbs agree in number.'
' Usage     : Msg = "There [is/are] # record[s].  [It/They] consist[s/] of # part[y/ies] each."'
'             Pluralize(Msg, 1) --> "There is 1 record.  It consists of 1 party each."'
'             Pluralize(Msg, 6) --> "There are 6 records.  They consist of 6 parties each."'
'---------------------------------------------------------------------------------------'
''
Function Pluralize(Text As String, Num As Variant, Optional NumToken As String = "#")
Const OpeningBracket = "\["
Const ClosingBracket = "\]"
Const DividingSlash = "/"
Const CharGroup = "([^\]]*)"  'Group of 0 or more characters not equal to closing bracket'
Dim IsPlural As Boolean, Msg As String, Pattern As String

    On Error GoTo Err_Pluralize

    If IsNumeric(Num) Then
        IsPlural = (Num <> 1)
    End If

    Msg = Text

    'Replace the number token with the actual number'
    Msg = Replace(Msg, NumToken, Num)

    'Replace [y/ies] style references'
    Pattern = OpeningBracket & CharGroup & DividingSlash & CharGroup & ClosingBracket
    Msg = RegExReplace(Pattern, Msg, "$" & IIf(IsPlural, 2, 1))

    'Replace [s] style references'
    Pattern = OpeningBracket & CharGroup & ClosingBracket
    Msg = RegExReplace(Pattern, Msg, IIf(IsPlural, "$1", ""))

    'Return the modified message'    
    Pluralize = Msg
End Function

Function RegExReplace(SearchPattern As String, _
                      TextToSearch As String, _
                      ReplacePattern As String) As String
Dim RE As Object

    Set RE = CreateObject("vbscript.regexp")
    With RE
        .MultiLine = False
        .Global = True
        .IgnoreCase = False
        .Pattern = SearchPattern
    End With

    RegExReplace = RE.Replace(TextToSearch, ReplacePattern)
End Function

Użycie zostało nieco odcięte w komentarzach do kodu powyżej, więc powtórzę to tutaj:

Msg = "There [is/are] # record[s]. [It/They] consist[s/] of # part[y/ies] each."

Pluralize(Msg, 1) --> "There is 1 record.  It consists of 1 party each."
Pluralize(Msg, 6) --> "There are 6 records.  They consist of 6 parties each."

Tak, to rozwiązanie ignoruje języki inne niż angielski. To, czy to ma znaczenie, zależy od Twoich wymagań.

mwolfe02
źródło
4

Możesz wygenerować liczbę mnogą automatycznie, patrz np. generator liczby mnogiej .

Aby zapoznać się z regułami generowania liczby mnogiej, zobacz wikipedię

string msg = "Do you want to delete " + numItems + GetPlural(" item", numItems) + "?";
thumbmunkeys
źródło
Lubię używać tej metody, jeśli aplikacja nie jest umiędzynarodowiona. Oczyszczanie zapewnia bardziej dopracowaną aplikację.
cspolton
1
Jest to naprawdę trudne do umiędzynarodowienia i często zawodzi w języku angielskim, np. „Masz zamówienia + numMice + GetPlural (" mysz ", numMice)"
James Anderson
@James Anderson: To nie jest najlepszy przykład gramatycznie, prawda ;-) Nie wpadaj w pułapkę myślenia, że ​​użycie metody GetPural jest jedyną metodą, której możesz używać.
cspolton
w połączeniu z kilkoma dodatkowymi funkcjami do obsługi kilku dodatkowych przypadków narożnych, myślę, że jest to bardzo dobre rozwiązanie, choć nie krótsze.
lalli
4

Co powiesz na bardziej ogólny sposób. Unikaj liczby mnogiej w drugim zdaniu:

Liczba wybranych elementów do usunięcia: noofitemsselected.
Jesteś pewny?

Dowiaduję się, że robiąc to w ten sposób, numer jest umieszczany na końcu linii, co jest naprawdę łatwe do wykrycia. To rozwiązanie działałoby z tą samą logiką w dowolnym języku.

Danosaure
źródło
„Wybrane elementy do usunięcia:” nie brzmi dobrze, zdanie wskazuje listę nazwisk, ale drukowana jest liczba. Nawet jeśli zmieniono na „Liczba elementów do usunięcia:”, nadal „elementy” są niewygodne.
lalli
@lalli: Tak, sformułowanie nie jest idealne, a żadne z proponowanych rozwiązań nie brzmi idealnie. Sugeruję tylko, aby nadać mu formę taką jak etykieta i wartość. Masz rację co do dodawania Number(odpowiadałem, kołysząc moje dziecko do snu).
Danosaure
4

Moje ogólne podejście polega na napisaniu „funkcji pojedynczej / mnogiej”, na przykład:

public static string noun(int n, string single, string plural)
{
  if (n==1)
    return single;
  else
    return plural;
}

Następnie w treści wiadomości nazywam tę funkcję:

string message="Congratulations! You have won "+n+" "+noun(n, "foobar", "foobars")+"!";

Nie jest to o wiele lepsze, ale przynajmniej (a) umieszcza decyzję w funkcji, dzięki czemu trochę porządkuje kod, a (b) jest wystarczająco elastyczne, aby obsługiwać nieregularne liczby mnogie. tzn. łatwo jest powiedzieć rzeczownik (n, „dziecko”, „dzieci”) i tym podobne.

Oczywiście działa to tylko w przypadku języka angielskiego, ale koncepcję można łatwo rozszerzyć na języki z bardziej złożonymi zakończeniami.

Wydaje mi się, że ostatni parametr można ustawić jako opcjonalny dla łatwego przypadku:

public static string noun(int n, string single, string plural=null)
{
  if (n==1)
    return single;
  else if (plural==null)
    return single+"s";
  else
    return plural;
}
Sójka
źródło
1
Podoba mi się twoja ostatnia część, w której używasz domyślnej wartości do "uporządkowania" kodu w przypadku domyślnej operacji dodawania s do rzeczownika w liczbie mnogiej.
Øyvind Bråthen
4

Umiędzynarodowienie

Zakładam, że chcesz obsługiwać internacjonalizację, w którym to przypadku różne języki mają różne wzorce dla liczby mnogiej (np. Specjalna forma liczby mnogiej dla 2 czegoś lub bardziej skomplikowane języki, takie jak polski) i nie możesz polegać na zastosowaniu prostego wzoru do swojego ciągu naprawić to.

Możesz użyć funkcji GNU Gettext i umieścić ngettextw kodzie źródłowym dwie wiadomości w języku angielskim. Gettext zapewni infrastrukturę do wyboru spośród innych (potencjalnie więcej) wiadomości po przetłumaczeniu na inne języki. Zobacz http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html, aby uzyskać pełny opis obsługi liczby mnogiej GNU gettext.

GNU Gettext jest na licencji LGPL. ngettextjest nazwany GettextResourceManager.GetPluralStringw porcie C # Gettext.

(Jeśli nie potrzebujesz obsługi lokalizacji i nie chcesz od razu używać Gettext, napisz własną funkcję, która robi to dla języka angielskiego i prześlij do niej dwie pełne wiadomości , w ten sposób, jeśli będziesz potrzebować l10n później, możesz dodaj, przepisując pojedynczą funkcję).

Ken Bloom
źródło
3

Co powiesz na napisanie funkcji takiej jak

string GetOutputMessage(int count, string oneItemMsg, string multiItemMsg)
{
 return string.Format("{0} {1}", count, count > 1 ? multiItemMsg : oneItemMsg);
}

.. i używaj go kiedy tylko potrzebujesz?

string message = "You have selected " + GetOutputMessage(noofitemsselected,"item","items") + ". Are you sure you want to delete it/them?";
Pavel Morshenyuk
źródło
3
nie pomyślałeś o tym, czy nie lol, masz funkcję sortowania mnożników lub nie dla zdania, a następnie
wstawiasz
Powinieneś tylko przekazać dwie wiadomości dla całego zdania do tej funkcji.
Ken Bloom,
To był tylko przykład. Zdaję sobie sprawę, że wariant wysyłania całych zdań jest bardziej poprawny.
Pavel Morshenyuk
3

W przypadku pierwszego problemu, mam na myśli Pluralize, możesz użyć Inflectora .

Po drugie, możesz użyć rozszerzenia reprezentującego ciąg o nazwie takiej jak ToPronounString.

Yogesh
źródło
3

Dokładnie to samo pytanie zadał mi wczoraj członek naszego zespołu.

Odkąd pojawił się ponownie tutaj w StackOverflow, pomyślałem, że wszechświat mówi mi, żebym się zastanawiał nad stworzeniem przyzwoitego rozwiązania.

Szybko złożyłem coś w całość i wcale nie jest to idealne, ale może się przydać lub wywołać dyskusję / rozwój.

Ten kod opiera się na założeniu, że mogą istnieć 3 wiadomości. Jeden na zero pozycji, jeden na jeden przedmiot i jeden na więcej niż jeden przedmiot, które mają następującą strukturę:

singlePropertyName
singlePropertyName_Zero
singlePropertyName_Plural

Stworzyłem wewnętrzną klasę do testowania, aby naśladować klasę zasobów. Nie testowałem jeszcze tego przy użyciu rzeczywistego pliku zasobów, więc nie widzę jeszcze pełnego wyniku.

Oto kod (obecnie zawarłem kilka typów ogólnych, o których wiem, że mogłem określić trzeci parametr po prostu jako Typ, a także drugi parametr to ciąg znaków, myślę, że istnieje sposób na połączenie tych dwóch parametrów w coś lepszego, ale ja ' Wrócę do tego, kiedy będę miał wolną chwilę.

    public static string GetMessage<T>(int count, string resourceSingularName, T resourceType) where T : Type
{
    var resourcePluralName = resourceSingularName + "_Plural";
    var resourceZeroName = resourceSingularName + "_Zero";
    string resource = string.Empty;
    if(count == 0)
    {
        resource = resourceZeroName;
    }
    else{
        resource = (count <= 1)? resourceSingularName : resourcePluralName;
    }
    var x = resourceType.GetProperty(resource).GetValue(Activator.CreateInstance(resourceType),null);

    return x.ToString();
}

Testuj klasę zasobów:

internal class TestMessenger
{
    public string Tester{get{
    return "Hello World of one";}}
    public string Tester_Zero{get{
    return "Hello no world";}}
    public string Tester_Plural{get{
    return "Hello Worlds";}}
}

i moja metoda szybkiego wykonywania

void Main()
{
    var message = GetMessage(56, "Tester",typeof(TestMessenger));
    message.Dump();
}
Jamie Dixon
źródło
Jeśli chcesz, aby było to naprawdę kompletne, dodaj również wiadomość, singlePropertyName_Allaby była jeszcze bardziej oczywista.
Danosaure
2

Z mojego punktu widzenia Twoje pierwsze rozwiązanie jest najbardziej odpowiednie. Dlaczego tak mówię, jeśli potrzebujesz aplikacji do obsługi wielu języków, druga opcja może być żmudna. Przy pierwszym podejściu łatwo jest zlokalizować tekst bez większego wysiłku.

Illuminati
źródło
2

Możesz skorzystać z bardziej ogólnej wiadomości, np. „Czy na pewno chcesz usunąć wybrane elementy”.

Piotr
źródło
3
To z pewnością działa, ale myślę, że pomysł osoby pytającej, aby na pierwszy rzut oka pokazać liczbę elementów, które mają zostać usunięte, jest dobry. Nieraz próbowałem usunąć plik z pulpitu i przypadkowo usunąłem więcej niż jeden plik.
Cody Grey
2

Zależę od tego, jaką miłą wiadomość chcesz mieć. Od najłatwiejszego do najtrudniejszego:

  1. Napisz ponownie komunikat o błędzie, aby uniknąć liczby mnogiej. Nie tak przyjemne dla użytkownika, ale szybsze.

  2. Użyj bardziej ogólnego języka, ale nadal podawaj numery.

  3. Użyj "pluralizacji" i systemu inflector ala Rails, żebyś mógł powiedzieć pluralize(5,'bunch')i dostać 5 bunches. Rails ma na to dobry wzór.

  4. W przypadku internacjonalizacji należy sprawdzić, co zapewnia Java. Będzie to obsługiwać szeroką gamę języków, w tym te, które mają różne formy przymiotników z 2 lub 3 elementami. Rozwiązanie „s” jest bardzo angielskie.

Wybór opcji zależy od Twoich celów produktowych. - ndp

ndp
źródło
2

Dlaczego miałbyś prezentować wiadomość, którą użytkownicy naprawdę zrozumieją? Jest to sprzeczne z 40-letnią historią programowania. Nooooo, dzieje się dobrze, nie psuj tego zrozumiałymi wiadomościami.


(j / k)

John Alexiou
źródło
+1: dobrze widzieć tu też trochę humoru. Ale nawet jeśli żartujesz, rozumiem twój podstawowy punkt. Wiele programów stworzonych przez lata zawiera bardzo złe komunikaty. Zwykle dlatego, że i tak przechodzą do kwestii technicznych, aby zwykły użytkownik mógł to zrozumieć.
Øyvind Bråthen
Słuszna uwaga. Zawsze uwielbiam, gdy otrzymuję komunikat typu „Błąd 494-B przy wprowadzaniu danych przez użytkownika” - dodaje to dodatkową małą tajemnicę dotyczącą tego, co jest nie tak, co czyni życie o wiele bardziej interesującym. Niedawno wystąpił błąd podczas próby utworzenia hasła, który brzmiał po prostu: „Hasło nie spełnia wymagań bezpieczeństwa”. Brak podpowiedzi, jakiego wymagania nie spełniłem. Moje hasło zawierało duże i małe litery oraz kilka cyfr. Spróbowałem dodać świecką postać. Nadal nie. W końcu minęło, kiedy USUNIŁEM znak. Myślę, że mieli zasadę, że nie można mieć tej samej postaci dwa razy z rzędu.
Jay
2

Zrób to tak, jak w World of Warcraft:

BILLING_NAG_WARNING = "Your play time expires in %d |4minute:minutes;";
Thomas Bonini
źródło
0

Trochę się skraca z

string message = "Are you sure you want to delete " + noofitemsselected + " item" + (noofitemsselected>1 ? "s" : "") + "?";
Jonas Elfström
źródło
0

Jednym z podejść, o którym nie wspomniałem, byłoby użycie tagu substitution / select (np. Coś w rodzaju „Masz zamiar zgnieść {0} [? I ({0} = 1): / cactus / cacti /]”. (innymi słowy, użyj wyrażenia podobnego do formatu określającego podstawienie na podstawie tego, czy argument zero, traktowany jako liczba całkowita, jest równy 1). Widziałem takie tagi używane w dniach poprzedzających .net; nie znam żadnych standard dla nich w .net, ani nie znam najlepszego sposobu ich formatowania.

supercat
źródło
0

Pomyślałbym przez chwilę po wyjęciu z pudełka, wszystkie sugestie tutaj dotyczą albo wykonania liczby mnogiej (i martwienia się o więcej niż 1 poziom liczby mnogiej, płeć itp.) Lub w ogóle go nie używają i zapewniają przyjemne cofnięcie.

Pójdę drogą niejęzykową i użyję do tego wizualnych kolejek. np. wyobraź sobie aplikację Iphone, którą wybierasz, wycierając palcem. przed ich usunięciem za pomocą głównego przycisku usuwania, "potrząśnie" wybranymi elementami i wyświetli pole zatytułowane ze znakiem zapytania z przyciskami V (ok) lub X (anuluj) ...

Lub w świecie 3D Kinekt / Move / Wii - wyobraź sobie, że wybierasz pliki, przesuwasz dłonią do przycisku usuwania i każesz przesunąć dłonią nad głową w celu potwierdzenia (używając tych samych symboli wizualnych, jak wspomniałem wcześniej. Np. Zamiast tego z prośbą o usunięcie 3 plików? pokaże 3 pliki z najechanym półprzezroczystym czerwonym znakiem X i poleci zrobić coś, aby potwierdzić.

Eran Medan
źródło