Vielzahl in Benutzernachrichten


106

Viele Male, wenn Nachrichten an den Benutzer zu zeigen , zu erzeugen, werden die Nachricht eine Reihe von enthalten etwas , dass ich über die Kunden informieren will.

Ich gebe ein Beispiel: Der Kunde hat eine Anzahl von Artikeln ab 1 ausgewählt und auf Löschen geklickt. Jetzt möchte ich dem Kunden eine Bestätigungsnachricht geben und die Anzahl der von ihm ausgewählten Artikel erwähnen, um die Wahrscheinlichkeit eines Fehlers zu minimieren, indem er eine Reihe von Artikeln auswählt und auf Löschen klickt, wenn er nur einen löschen möchte Sie.

Eine Möglichkeit besteht darin, die generische Nachricht folgendermaßen zu erstellen:

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

Das "Problem" hier ist der Fall, wo noofitemselected1 ist, und wir müssen Artikel und es anstelle von Artikeln und ihnen schreiben .

Meine normale Lösung wird so etwas sein

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

Dies wird ziemlich schnell und ziemlich schnell sehr böse, wenn es viele Verweise auf die Zahlenvielfalt im Code gibt und die eigentliche Nachricht schwer zu lesen ist.

Meine Fragen sind also einfach. Gibt es bessere Möglichkeiten, solche Nachrichten zu generieren?

BEARBEITEN

Ich sehe, dass viele Personen in dem Fall, dass ich erwähnte, dass die Nachricht in einem Nachrichtenfeld angezeigt werden soll, sehr aufgehängt sind und einfach eine Antwort gegeben haben, wie man die Verwendung des Nachrichtenfelds überhaupt vermeiden kann, und das ist alles gut .

Denken Sie jedoch daran, dass das Problem der Pluralisierung neben Meldungsfeldern auch für Texte an anderen Stellen im Programm gilt. Beispielsweise hat eine Beschriftung neben einem Raster, die die Anzahl der im Raster ausgewählten Linien anzeigt, das gleiche Problem hinsichtlich der Pluralisierung.

Dies gilt also grundsätzlich für die meisten Texte, die auf irgendeine Weise aus Programmen ausgegeben werden, und dann ist die Lösung nicht so einfach, das Programm so zu ändern, dass kein Text mehr ausgegeben wird :)


5
@ 0xA3: Ich weiß nicht wirklich, ob jede Sprache eine Pluralisierung hat, die so leicht ausgedrückt werden kann wie "Artikel".
Jens

5
Sie sollten wahrscheinlich auch über Lokalisierung nachdenken. Dieses Problem kann noch viel schlimmer werden.
Alex Brown

4
@Jens: Normalerweise nicht, zumindest auf bequeme Weise möglich. Einige Sprachen haben zB unterschiedliche Pluralisierungen für 2-4 als für 5-unendlich, alles abhängig vom Geschlecht. "Natürliche Sprachen: Lokalisierungswahnsinn! Bald an einen Computer in Ihrer Nähe!"
Piskvor verließ das Gebäude

29
IMO, nichts lässt Programmierer für Benutzer fauler aussehen als schlechte Pluralität.
Greg

4
@ Øyvind: +1 für deine Bearbeitung. Es scheint, dass viele der "Antwortenden" hier eher darauf bedacht sind, zu beweisen, dass Ihre Frage falsch ist, als eine Lösung anzubieten, die richtig ist. Anti-Lösungen, wenn Sie so wollen.
mwolfe02

Antworten:


53

Wenn es jemals eine noch so kleine Chance gibt, dass diese App in andere Sprachen übersetzt werden muss, sind beide falsch. Der richtige Weg, dies zu tun, ist:

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?"
);

Dies liegt daran, dass verschiedene Sprachen mit Pluralität unterschiedlich umgehen. Einige wie Malaiisch haben nicht einmal syntaktische Pluralformen, daher wären die Zeichenfolgen im Allgemeinen identisch. Das Trennen der beiden Zeichenfolgen erleichtert später die Unterstützung anderer Sprachen.

Andernfalls ist die zweite Methode vorzuziehen, wenn diese App von der Öffentlichkeit genutzt werden soll und benutzerfreundlich sein soll. Entschuldigung, aber ich kenne keinen kürzeren Weg, dies zu tun.

Wenn diese App nur intern von Ihrem Unternehmen verwendet werden soll, führen Sie die Verknüpfung aus "item(s)". Sie müssen niemanden wirklich beeindrucken, wenn Sie Enterprisy-Code schreiben. Ich würde jedoch davon abraten, dies für öffentlich konsumierte Apps zu tun, da dies den Eindruck erweckt, dass der Programmierer faul ist und somit seine Meinung über die Qualität der App verringert. Vertrauen Sie mir, kleine Dinge wie diese Angelegenheit.


34
Obwohl ich der Prämisse zustimme, ignorieren Sie Sprachen mit mehr als zwei Pluralitätsgraden. (Nehmen Sie zum Beispiel Russisch. Drei verschiedene Arten zu sagen, je nachdem, ob es 1, <5 oder> = 5 ist, und selbst das hängt davon ab, wovon Sie genau sprechen.) Grundsätzlich sage ich, dass Sie eine stärkere bedingte Anweisung und nicht nur einen ternären Operator benötigen.
krass

4
Sie können das noofitemsselectedin diesem Beispiel sogar für die erste Option optimieren . da Sie wissen, dass es 1. ist
Standard

15
Während wir gerade dabei sind, kann Hebräisch verschiedene Pluralitäten für 1, 2, 3-10 und 11+ haben.
Joel Spolsky

3
@ Joel, Hebräisch kann so viele verschiedene Pluralitäten haben? לא ידעתי (ich wusste es nicht)! Modernes Hebräisch ist wie Englisch, was Pluralformen angeht (obwohl altes Hebräisch auch eine doppelte Form hatte)
Ken Bloom

3
Im Englischen wird Null wie ein Plural behandelt (0 Elemente, 2 Elemente). Was passiert mit Null auf Hebräisch, Russisch, Rumänisch? Gibt es eine einfache Möglichkeit, die Bereiche zu identifizieren? Ich vermute, dass die Informationen pro Sprache ermittelt werden müssen, sodass jedes System, das auf Nachrichtendateien basiert, mit unterschiedlichen Mengen an Pluralität in einer Reihe von Nachrichten umgehen muss. Autsch! Das Einrichten der Übersetzungen wäre ebenfalls schwierig - für verschiedene Sprachen werden unterschiedliche Anzahlen von Nachrichten benötigt.
Jonathan Leffler

94

Sie können all diese unordentliche Vielzahl vermeiden, indem Sie einfach die Elemente ohne Nachricht löschen und dem Benutzer eine wirklich gute Rückgängig-Funktion geben. Benutzer lesen nie etwas . Sie sollten ohnehin eine gute Rückgängig-Funktion als Teil Ihres Programms erstellen.

Sie erhalten tatsächlich zwei Vorteile, wenn Sie eine umfassende Rückgängig-Funktion erstellen. Der erste Vorteil erleichtert dem Benutzer das Leben, indem er Fehler rückgängig machen und das Lesen minimieren kann. Der zweite Vorteil ist, dass Ihre App das wirkliche Leben widerspiegelt, indem sie die Umkehrung des nicht trivialen Workflows ermöglicht (nicht nur Fehler).

Ich habe einmal eine App geschrieben, ohne einen einzigen Dialog oder eine Bestätigungsnachricht zu verwenden. Es erforderte einige ernsthafte Überlegungen und war erheblich schwieriger zu implementieren als die Verwendung von Bestätigungsnachrichten. Aber das Endergebnis war laut den Endbenutzern ziemlich gut zu verwenden.


12
Aus irgendeinem Grund habe ich wirklich das Gefühl, dass ich damit einverstanden bin und es unterstützen sollte.
Cody Gray

4
@ Øyvind, Hier ist der Grund: Nachrichten, in denen der Benutzer um Überprüfung gebeten wird, sind für den Benutzer teuer, insbesondere wenn sie in Form eines modalen Dialogfelds angezeigt werden, in dem alles angehalten wird, bis der Benutzer den Dialog beantwortet. Dies ärgert viele Benutzer bis zu dem Punkt, an dem sie auf eine beliebige Schaltfläche klicken, um über das Dialogfeld zu gelangen (wie viele Installationsprogramme haben Sie gerade auf Weiter , Weiter, Weiter geklickt ? ). Folglich ist es sicherer und es gibt viel weniger Benutzerreibung, wenn Sie nur einen weichen Löschvorgang durchführen und eine Rückgängig-Funktion bereitstellen. Google Mail verwendet diese Technik mit großer Wirkung.
Robert Harvey

5
Umstritten, aber in jedem Fall tritt das gleiche Problem in anderen Fällen als einer Bestätigungsnachricht beim Löschen auf, sodass diese Antwort die Frage wirklich tangential berührt.
Jay

50
Ich habe dies positiv bewertet, ohne es zu lesen. Ich kann es später immer wieder rückgängig machen
Steven A. Lowe

6
@ Robert Harvey: Wahrscheinlich apokryphisch, aber vor vielen Jahren habe ich gelesen, dass Lotus 40.000 Einheiten Lotus Notes für den Mac ausgeliefert hat und 60.000 zurückgegeben wurden. Die Schnittstelle war so schlecht, dass sogar die Leute, die sie raubkopiert hatten, sie zurückschickten.
Duncan

39

Wie wäre es einfach:

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

Auf diese Weise beseitigen Sie die Schwierigkeiten bei der Nummernvereinbarung und erhalten als Bonus eine noch kürzere, präzisere Fehlermeldung für den Benutzer. Wir alle wissen, dass Benutzer ohnehin keine Fehlermeldungen lesen . Je kürzer sie sind, desto wahrscheinlicher ist es, dass sie zumindest einen Blick darauf werfen auf den Text werfen.

Mit dem Wissen, dass Benutzer keine Fehlermeldungen lesen, können Sie dies auch anders angehen. Überspringen Sie die Bestätigungsmeldung vollständig und stellen Sie einfach eine Funktion zum Rückgängigmachen bereit, die funktioniert, unabhängig davon, was gelöscht wurde. Die meisten Benutzer sind bereits daran gewöhnt, einen Vorgang rückgängig zu machen, wenn sie feststellen, dass er nicht ihren Wünschen entspricht, und finden dieses Verhalten wahrscheinlich natürlicher, als sich mit einem anderen nervigen Popup befassen zu müssen.


1
Gute Antwort. In diesem Fall wurde der Kunde jedoch gebeten, in vielen Fällen Fehlermeldungen bereitzustellen, da er der Ansicht war, dass dies der beste Ansatz sei. Das Ändern des Textes kann das Problem jedoch zumindest minimieren und weniger chaotisch machen.
Øyvind Bråthen

@ Øyvind: Fair genug. Da Sie dem Kunden folgen müssen, würde ich entweder den ersten von mir vorgeschlagenen Ansatz wählen oder eine Ressourcendatei mit einer Handlerfunktion verwenden. Ich dachte nur, es lohnt sich, auf eine Alternative hinzuweisen, weil sie so leicht vergessen wird. Heck, ich habe erst daran gedacht, nachdem ich meine erste Antwort eingereicht hatte.
Cody Gray

Alternativen sind herzlich willkommen. Deshalb habe ich es auch +1 gegeben :)
Øyvind Bråthen

1
+1 für den Versuch, ein unlösbares Problem nicht zu lösen. Und denken Sie an Steve Krugs Gesetz: Entfernen Sie die Hälfte der Wörter. Dann mach es nochmal. Ich benutze: "{x} item (s) löschen?"
Serge Wautier

20

Was ist mit dem, was Java seit Jahren hat: java.text.MessageFormat und ChoiceFormat? Weitere Informationen finden Sie unter 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.

In Ihrem Fall möchten Sie etwas Einfacheres:

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

Der Vorteil dieses Ansatzes besteht darin, dass er gut mit den i18n-Bundles zusammenarbeitet und Sie Übersetzungen für Sprachen (wie Japanisch) bereitstellen können, die kein Konzept für mehrere oder einzelne Wörter haben.


1
Dieser Ansatz eignet sich gut für den Umgang mit Pluralität, aber leider nicht für das Geschlecht. Sie benötigen für jede Art von Dingen, die gelöscht werden können, eine andere Zeichenfolge.
Mr. Shiny und New

Wenn Sie das Substantiv kennen, können Sie die Sätze so gestalten, dass sie mit dem richtigen Adjektiv funktionieren. Aber ja, nachdem Sie klassisches Griechisch studiert haben, haben Sie eine andere Form des Wortes, die auf männlichen, weiblichen oder neutralen Substantiven basiert (das Adjektiv nimmt die Form des Substantivs an, das es modifiziert), und die Form unterscheidet sich aufgrund seiner Funktion im Satz ( Subjekt, Objekt usw.). Wir können uns immer Fälle einfallen lassen, in denen eine Lösung funktioniert und eine andere nicht. Auf diese Weise versuchten die Java-Leute, das Problem zu lösen. Sie müssen immer noch vorsichtig sein, wie Sie die Nachrichtenformate bilden.
Berin Loritsch

Sie können der Java-Lösung immer zwei Ganzzahlen geben, wobei die zweite das Geschlecht angibt. (In Wirklichkeit ist die Übereinstimmung der Geschlechter in der Regel weniger wichtig, nur weil der Anwendungsfall des Einfügens verschiedener Objekte in eine Nachricht weniger häufig ist als das Anpassen unterschiedlicher Nummern desselben Objekts in eine Nachricht.)
Ken Bloom

12

Ich würde die Nachricht nicht fest codieren, sondern zwei Nachrichten in einer separaten Ressourcendatei bereitstellen. Mögen

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?";

und dann füttere sie in String.Format wie

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

string message = String.Format(messageTemplate, noofitemsselected)

Ich denke, dass dieser Ansatz einfacher zu lokalisieren und zu pflegen ist. Alle UI-Nachrichten befinden sich an einem einzigen Ort.


+1, ich mag diesen Ansatz. Sie müssten jedoch die Entsprechungen der Ressourcennamen verfolgen.
Standard

11

Sie können das Problem vollständig umgehen, indem Sie die Nachricht anders formulieren.

string message = "The number of selected items is " + noofitemsselected + ". Are you sure you want to delete everything in this selection?";

10

Das erste, was ich vorschlagen würde, ist: verwenden string.Format. Damit können Sie so etwas tun:

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

Außerdem habe ich in WPF-Apps Systeme gesehen, bei denen eine Ressourcenzeichenfolge durch zwei Nachrichten getrennt ist: eine Singular- und eine Pluralnachricht (oder sogar eine Null / Einzel / Viele-Nachricht). Ein benutzerdefinierter Konverter könnte dann verwendet werden, um diese Ressource zu analysieren und die relevante (formatierte) Zeichenfolge zu verwenden. Ihre Xaml sieht also ungefähr so ​​aus:

<TextBlock Text="{Binding numOfItems, Converter={StaticResource c:NumericMessageFormatter}, ConverterParameter={StaticResource s:SuitableMessageTemplate}}" />

7

Für Englisch viele Antworten oben. Für andere Sprachen ist es schwieriger, da Pluralformen vom Geschlecht des Substantivs und der Wortendung abhängen. Einige Beispiele auf Französisch:

Regelmäßig männlich:

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

Regelmäßig weiblich

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

Unregelmäßig männlich (endet mit 's')

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

Das gleiche Problem besteht in den meisten lateinischen Sprachen und verschlimmert sich in Deutsch oder Russisch, wo es drei Geschlechter gibt (makulin, weiblich und neutral).

Sie müssen aufpassen, wenn Ihr Ziel darin besteht, mehr als nur Englisch zu beherrschen.


Zumindest in meinem Fall ist dies kein wirkliches Problem. Für jeden Text, in den ich die Zahl einfügen möchte, weiß ich, wie das Substantiv beim Generieren der Zeichenfolge lautet. Aber um eine allgemeinere Lösung zu finden, stimme ich Ihnen zu, dass es eine sehr schwierige, wenn nicht unmögliche Aufgabe sein könnte, sie für "alle" Sprachen zum Laufen zu bringen.
Øyvind Bråthen

1
Oder nehmen Sie Polnisch, wo die Pluralform des verwendeten Substantivs je nach Anzahl unterschiedlich ist! : /
UpTheCreek

5

Um pluralisierte Nachrichten zu haben, die richtig lokalisiert werden können, ist es meiner Meinung nach ratsam, zuerst eine Indirektionsebene zwischen der Nummer und einer Nachricht zu erstellen.

Verwenden Sie beispielsweise eine Konstante, um anzugeben, welche Nachricht angezeigt werden soll. Rufen Sie die Nachricht mit einer Funktion ab, mit der die Implementierungsdetails ausgeblendet werden.

get_message(DELETE_WARNING, quantity)

Erstellen Sie als Nächstes ein Wörterbuch, das die möglichen Nachrichten und Variationen enthält, und teilen Sie Variationen mit, wann sie verwendet werden sollten.

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?'
}

Jetzt können Sie einfach den Schlüssel finden, der dem entspricht, quantityund den Wert von quantitymit dieser Nachricht interpolieren .

Dieses vereinfachte und naive Beispiel, aber ich sehe keinen anderen vernünftigen Weg, dies zu tun und in der Lage zu sein, L10N und I18N gut zu unterstützen.


5

Sie müssen die folgende Funktion von VBA nach C # übersetzen, aber Ihre Verwendung würde sich ändern zu:

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

Ich habe eine VBA-Funktion, die ich in MS Access verwende, um genau das zu tun, wovon Sie sprechen. Ich weiß, dass ich für das Posten von VBA in Stücke gehackt werde, aber hier geht es trotzdem. Der Algorithmus sollte aus den Kommentaren ersichtlich sein:

'---------------------------------------------------------------------------------------'
' 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

Die Verwendung wurde in den obigen Codekommentaren etwas eingeschränkt, daher werde ich sie hier wiederholen:

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."

Ja, diese Lösung ignoriert Sprachen, die nicht Englisch sind. Ob das wichtig ist, hängt von Ihren Anforderungen ab.


4

Sie können den Plural automatisch generieren, siehe z. Plural Generator .

Für Pluralerzeugungsregeln siehe Wikipedia

string msg = "Do you want to delete " + numItems + GetPlural(" item", numItems) + "?";

Ich verwende diese Methode gerne, wenn die Anwendung nicht internationalisiert ist. Das Puralisieren führt zu einer polierteren Anwendung.
Cspolton

1
Es ist wirklich schwer, dies zu internationalisieren, und es schlägt oft auf Englisch fehl, z. B. "Sie haben Befehle + numMice + GetPlural (" mouse ", numMice)"
James Anderson

@ James Anderson: Nun, das ist grammatikalisch gesehen nicht das beste Beispiel ;-) Fallen Sie nicht in die Falle, wenn Sie glauben, dass die Verwendung einer GetPural-Methode die einzige Methode ist, die Sie verwenden dürfen.
Cspolton

In Verbindung mit ein paar weiteren Funktionen für ein paar weitere Eckfälle halte ich dies für eine sehr gute Lösung, die jedoch nicht kürzer ist.
Lalli

4

Wie wäre es mit einem allgemeineren Weg. Vermeiden Sie die Pluralisierung im zweiten Satz:

Anzahl der ausgewählten Elemente, die gelöscht werden sollen: noofitemsselected.
Bist du sicher?

Ich finde heraus, dass auf diese Weise die Zahl am Ende der Zeile steht, was wirklich leicht zu erkennen ist. Diese Lösung würde in jeder Sprache mit derselben Logik funktionieren.


"Ausgewählte zu löschende Elemente:" klingt nicht richtig, der Satz zeigt eine Liste von Namen an, aber eine Nummer wird gedruckt. Selbst wenn in "Anzahl der zu löschenden Elemente:" geändert wird, ist "Elemente" immer noch umständlich.
Lalli

@lalli: Ja, der Wortlaut ist nicht perfekt und keine der angebotenen Lösungen klingt perfekt. Ich schlage nur vor, es in eine Form wie Label und Wert zu bringen. Sie haben Recht mit dem Hinzufügen Number(ich antwortete, während ich mein Baby in den Schlaf wiegte).
Danosaure

4

Mein allgemeiner Ansatz besteht darin, eine "Einzel- / Pluralfunktion" wie folgt zu schreiben:

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

Dann rufe ich im Hauptteil der Nachricht diese Funktion auf:

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

Dies ist nicht viel besser, aber zumindest (a) setzt die Entscheidung in eine Funktion und macht den Code ein wenig unübersichtlich, und (b) ist flexibel genug, um mit unregelmäßigen Pluralformen umzugehen. dh es ist leicht genug, Substantiv (n, "Kind", "Kinder") und dergleichen zu sagen.

Natürlich funktioniert dies nur für Englisch, aber das Konzept ist leicht auf Sprachen mit komplexeren Endungen erweiterbar.

Mir fällt ein, dass Sie den letzten Parameter für den einfachen Fall optional machen könnten:

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;
}

1
Ich mag Ihren letzten Teil, in dem Sie einen Standardwert verwenden, um den Code im Falle der Standardoperation des Hinzufügens eines s zum Pluralisieren des Substantivs "übersichtlich" zu machen.
Øyvind Bråthen

4

Internationalisierung

Ich gehe davon aus, dass Sie Unterstützung bei der Internationalisierung wünschen. In diesem Fall haben verschiedene Sprachen unterschiedliche Muster für Pluralformen (z. B. eine spezielle Pluralform für 2 von etwas oder kompliziertere Sprachen wie Polnisch), und Sie können sich nicht darauf verlassen, ein einfaches Muster auf Ihre Zeichenfolge anzuwenden etwas reparieren.

Sie können die ngettextFunktion von GNU Gettext verwenden und zwei englische Nachrichten in Ihrem Quellcode bereitstellen. Gettext bietet die Infrastruktur, um bei der Übersetzung in andere Sprachen aus anderen (möglicherweise mehr) Nachrichten auszuwählen. Eine vollständige Beschreibung der Pluralunterstützung von GNU gettext finden Sie unter http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html .

GNU Gettext steht unter der LGPL. ngettextwird GettextResourceManager.GetPluralStringim C # -Port von Gettext benannt.

(Wenn Sie keine Lokalisierungsunterstützung benötigen und Gettext nicht sofort verwenden möchten, schreiben Sie Ihre eigene Funktion, die dies für Englisch ausführt, und übergeben Sie zwei vollständige Nachrichten. Wenn Sie später 1010 benötigen, können Sie dies tun Hinzufügen durch Umschreiben einer einzelnen Funktion.)


3

Wie wäre es, Funktion wie zu schreiben

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

.. und verwenden Sie es, wann immer Sie brauchen?

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

3
du hast nicht darüber nachgedacht, oder lol, du hast eine Funktion, um Multiplikationen zu sortieren oder nicht für den Satz, dann gehst du und setzt "es / sie" am Ende lol
Barkermn01

Sie sollten dieser Funktion nur zwei Nachrichten für den gesamten Satz übergeben.
Ken Bloom

Es war nur ein Beispiel. Mir ist klar, dass die Variante, ganze Sätze zu senden, korrekter ist.
Pavel Morshenyuk

3

Für das erste Problem, ich meine Pluralize, können Sie Inflector verwenden .

Und für die zweite können Sie eine Zeichenfolgendarstellungserweiterung mit einem Namen wie ToPronounString verwenden.


3

Genau diese Frage wurde mir gestern von einem Mitglied unseres Teams gestellt.

Da es hier auf StackOverflow wieder auftauchte, dachte ich, das Universum sagte mir, ich solle versuchen, eine anständige Lösung zu finden.

Ich habe schnell etwas zusammengestellt und es ist keineswegs perfekt, aber es könnte von Nutzen sein oder eine Diskussion / Entwicklung auslösen.

Dieser Code basiert auf der Idee, dass es 3 Nachrichten geben kann. Eine für null Artikel, eine für einen Artikel und eine für mehr als einen Artikel, die der folgenden Struktur folgen:

singlePropertyName
singlePropertyName_Zero
singlePropertyName_Plural

Ich habe eine interne Klasse zum Testen erstellt, um die Ressourcenklasse nachzuahmen. Ich habe dies noch nicht mit einer tatsächlichen Ressourcendatei getestet, daher muss ich noch das vollständige Ergebnis sehen.

Hier ist der Code (derzeit habe ich einige Generika eingefügt, bei denen ich weiß, dass ich den dritten Parameter einfach als Typ angeben könnte, und auch der zweite Parameter ist eine Zeichenfolge. Ich denke, es gibt eine Möglichkeit, diese beiden Parameter zu etwas Besserem zu kombinieren, aber ich ' Ich werde darauf zurückkommen, wenn ich einen freien Moment habe.

    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();
}

Ressourcenklasse testen:

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";}}
}

und meine schnelle Ausführungsmethode

void Main()
{
    var message = GetMessage(56, "Tester",typeof(TestMessenger));
    message.Dump();
}

Wenn Sie möchten, dass dies wirklich vollständig ist, sollten Sie auch eine Nachricht hinzufügen singlePropertyName_All, um dies noch deutlicher zu machen.
Danosaure

2

Aus meiner Sicht ist Ihre erste Lösung die am besten geeignete. Wenn Sie die Anwendung zur Unterstützung mehrerer Sprachen benötigen, kann die zweite Option mühsam sein. Mit dem Faustansatz ist es einfach, den Text ohne großen Aufwand zu lokalisieren.


2

Sie könnten eine allgemeinere Nachricht wie "Sind Sie sicher, dass Sie die ausgewählten Elemente löschen möchten" auswählen.


3
Dies funktioniert sicherlich, aber ich denke, die Idee des Fragestellers, die Anzahl der zu löschenden Elemente auf einen Blick anzuzeigen, ist gut. Mehr als einmal habe ich versucht, eine Datei von meinem Desktop zu löschen, und versehentlich mehr als diese eine Datei gelöscht.
Cody Gray

2

Ich komme darauf an, wie schön eine Nachricht sein soll. Vom einfachsten zum schwierigsten:

  1. Schreiben Sie Ihre Fehlermeldung erneut, um eine Pluralisierung zu vermeiden. Nicht so schön für Ihren Benutzer, aber schneller.

  2. Verwenden Sie eine allgemeinere Sprache, geben Sie jedoch die Nummer (n) an.

  3. Verwenden Sie ein "Pluralisierungs" - und Inflektorsystem ala Rails, damit Sie sagen pluralize(5,'bunch')und erhalten können 5 bunches. Rails hat dafür ein gutes Muster.

  4. Für die Internationalisierung müssen Sie sich ansehen, was Java bietet. Dies unterstützt eine Vielzahl von Sprachen, einschließlich solcher, die unterschiedliche Formen von Adjektiven mit 2 oder 3 Elementen haben. Die "s" -Lösung ist sehr englisch zentriert.

Welche Option Sie wählen, hängt von Ihren Produktzielen ab. - ndp


2

Warum möchten Sie eine Nachricht präsentieren, die die Benutzer tatsächlich verstehen können? Es widerspricht 40 Jahren Programmiergeschichte. Nein, wir haben eine gute Sache vor uns, verderben Sie sie nicht mit verständlichen Botschaften.


(j / k)


+1: auch hier etwas Humor zu sehen. Aber selbst wenn Sie Spaß machen, verstehe ich Ihren zugrunde liegenden Punkt. Viele, viele Programme, die im Laufe der Jahre erstellt wurden, haben extrem schlechte Nachrichten. Normalerweise, weil sie für einen normalen Benutzer sowieso zu technisch sind, um sie zu verstehen.
Øyvind Bråthen

Guter Punkt. Ich liebe es immer, wenn ich eine Nachricht wie "Fehler 494-B bei Benutzereingaben" erhalte - es fügt das zusätzliche kleine Rätsel hinzu, was falsch ist, was das Leben so viel interessanter macht. Ich habe kürzlich einen Fehler beim Erstellen eines Kennworts erhalten, das einfach besagt: "Kennwort entspricht nicht den Sicherheitsanforderungen". Kein Hinweis darauf, welche Anforderung ich nicht erfüllte. Mein Passwort enthielt sowohl Groß- als auch Kleinbuchstaben und mehrere Ziffern. Ich habe versucht, einen sekundären Charakter hinzuzufügen. Immer noch nein. Es verging schließlich, als ich einen Charakter löschte. Ich denke, sie hatten die Regel, dass man nicht zweimal hintereinander denselben Charakter haben kann.
Jay

2

Mach es wie in World of Warcraft:

BILLING_NAG_WARNING = "Your play time expires in %d |4minute:minutes;";

0

Mit wird es etwas kürzer

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

0

Ein Ansatz, den ich nicht erwähnt habe, wäre die Verwendung eines Substitutions- / Auswahl-Tags (z. B. "Sie sind dabei, {0} [? I ({0} = 1): / cactus / cacti /] zu quetschen"). (Mit anderen Worten, lassen Sie einen formatähnlichen Ausdruck die Ersetzung angeben, basierend darauf, ob das als Ganzzahl verwendete Argument Null gleich 1 ist.) Ich habe solche Tags in den Tagen vor .net gesehen; mir sind keine bekannt Standard für sie in .net, noch weiß ich nicht, wie ich sie am besten formatieren kann.


0

Ich würde für eine Minute über den Tellerrand hinaus denken. Alle Vorschläge hier sind entweder die Pluralisierung (und die Sorge um mehr als eine Pluralisierungsstufe, das Geschlecht usw.) oder sie werden überhaupt nicht verwendet und bieten ein schönes Rückgängigmachen.

Ich würde den nicht-lingualen Weg gehen und dafür visuelle Warteschlangen verwenden. Stellen Sie sich beispielsweise eine iPhone-App vor, bei der Sie Elemente auswählen, indem Sie sich den Finger abwischen. Bevor Sie sie mit der Master-Löschtaste löschen, werden die ausgewählten Elemente "geschüttelt" und ein Fragezeichen mit dem Titel "V" (OK) oder "X" (Abbrechen) angezeigt.

Oder stellen Sie sich in der 3D-Welt von Kinekt / Move / Wii vor, Sie wählen die Dateien aus, bewegen Ihre Hand zur Löschtaste und werden aufgefordert, Ihre Hand zur Bestätigung über Ihren Kopf zu bewegen (unter Verwendung der gleichen visuellen Symbole wie zuvor erwähnt, z. B. stattdessen Wenn Sie aufgefordert werden, 3 Dateien zu löschen, werden 3 Dateien mit einem schwebenden halbtransparenten roten X angezeigt, und Sie werden aufgefordert, etwas zu tun, um dies zu bestätigen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.