IT

사용자 메시지의 복수

lottoking 2020. 8. 9. 09:14
반응형

사용자 메시지의 복수


사용자에게 표시하는 것을 생성 할 때 많은 시간, 메시지의 번호가 뭔가를 내가 고객에게 메시지 할 것입니다.

예를 들어 보겠습니다. 고객이 1 개 이상에서 여러 항목을 선택하고 삭제를 클릭했습니다. 이제 고객에게 확인 메시지를 전달하고 싶은데, 선택한 항목 수를 중데하여 여러 항목을 선택하고 실수로 할 가능성을 최소화하고 싶습니다. 그들.

한 가지 방법은 다음과 같은 일반 메시지를 만드는 것입니다.

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

은 "문제는"여기의 경우 noofitemselected1, 우리는 쓰기 에이 항목 대신 항목그들 .

내 해결책은 다음과 가변적입니다.

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

코드 내부에 여러 숫자에 대한 참조가 많고 실제 메시지를 읽기가 어려워지면 매우 길고 매우 끔찍해입니다.

그래서 제 질문은 간단합니다. 이와 같은 메시지를 생성하는 더 좋은 방법이 있습니까?

편집하다

메시지 상자 안에를 표시해야 할 말하고 메시지 상자 사용을 아예 피하는 방법에 대한 대답 만 메시지 때 많은 사람들이 매우 있습니다. .

그러나 복수화 문제는 메시지 상자 외에 프로그램의 다른 위치에도 많은 점을 기억하십시오. 예를 들어, 그리드에서 선택한 줄 수를 표시하는 그리드 옆에있는 레이블은 복수화와 관련하여 갖습니다.

이렇게하면 기본적으로 프로그램에서 어떤 방식 으로든 더 이상 텍스트에 적용되는 출력 솔루션은 더 이상 텍스트를 출력하지 않도록 프로그램을 변경하는 것입니다. :)


아무리 작게 번역이 앱을 다른 언어로 번역 할 가능성이 있다면 둘 다 문제입니다. 수행하는 올바른 방법은 다음과이를 사용합니다.

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

이것은 다른 언어가 복수를 다르게 처리하기 때문입니다. 말레이어와 같은 일부는 구문 상 복수형도 매장이 일반적으로 동일합니다. 두 공유를 분리하면 나중에 다른 언어를 더 쉽게 지원할 수 있습니다.

대중이 사용하고 사용자가 일반 대중이 사용하고 사용자라면 두 번째 방법이 있습니다. 죄송하지만이 작업을 수행하는 더 짧은 방법을 모르겠습니다.

이 앱이 회사 내부적으로 만 사용하는 경우 바로 가기를 수행하십시오 "item(s)". 진취적인 코드를 사용할 때 누구에게도 깊은 인상을 줄 필요는 없습니다. 그러나 이것은 프로그래머가 게으르다는 인상을 주 앱의 품질에 대한 의견을 낮추기 때문에 공개적으로 말하는 앱에 대해 작업을 수행하지 않는 것이 좋습니다. 저를 믿으세요, 이런 작은 일들.


메시지없이 항목을 삭제하고 사용자에게 정말 좋은 실행 취소 기능을 제공하고 복잡한 복수를 피할 수 있습니다. 사용자는 아무것도 읽지 않습니다 . 당신은 좋은 취소 설비를 구축해야한다 어쨌든 프로그램의 일환으로.

가능성이있는 실행 취소 기능을 만들면 실제로 두 가지 이점이 있습니다. 첫 번째 이점은 사용자가 실수를 되돌리고 읽기를 최소화 할 수 있기 때문에 사용자의 삶을 더 쉽게 만듭니다. 두 번째 이점은 앱이 실수로 아니라 사소하지 않은 워크 플로의 반전을 허용하여 실제를 반영하는 것입니다.

한 번은 단일 대화 상자 나 확인 메시지를 사용하지 않고 앱을 작성했습니다. 심각한 생각이 필요하다는 확인 유형 메시지를 사용하는 것보다 구현하기 훨씬 더 어려웠습니다. 그러나 최종 결과는 최종 사용자에 따라 다소 좋았습니다.


그냥 어때 :

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

이렇게하면 번호 동의 문제를 제거하고 사용자에게 더 짧고 정확한 오류 메시지가 추가로 표시됩니다. 우리 모두는 사용자가 어쨌든 오류 메시지를 읽지 않는다는 것을 알고 있습니다. 길이가 짧을수록 텍스트를 한 가능성이 짧습니다 .

또는 사용자가 오류 메시지를 읽지 않는다는 지식으로 무장하면 다른 방식으로 접근 할 수 있습니다. 확인 메시지를 모두 건너 뛰고 뛰고 삭제 된 항목에 관계없이 Just Works라는 실행 취소 기능을 제공하십시오. 대부분의 사용자는 이미 원하는 작업이 아니라는 것을 알았을 때 작업을 실행 취소하는 데 익숙하며, 다른 성가신 팝업을 처리하는 것 보다이 동작이 더 자연 스럽습니다.


Java가 수년 동안 가지고있는 것은 무엇입니까 : java.text.MessageFormat 및 ChoiceFormat? 자세한 내용은 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.

귀하의 경우에는 좀 더 간단한 것을 원합니다.

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

이 접근 방식의 장점은 복수 또는 단수 단어 개념이없는 언어 (예 : 일본어)에 대해 분명하게 번역을 제공합니다.


메시지를 하드 코딩하지 않고 별도의 리소스 파일에 두 개의 메시지를 제공합니다. 처럼

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

그런 다음 String.Format에 다음과 같이 공급합니다.

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

string message = String.Format(messageTemplate, noofitemsselected)

이 접근 방식은 현지화 및 유지 관리가 더 많은 것을 생각합니다. 모든 UI 메시지는 단일 위치에 있습니다.


메시지를 다르게 표현하여 문제를 해결할 수 있습니다.

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

내가 제안하고 싶은 첫번째 것은 : use string.Format. 이렇게하면 다음과 같이 할 수 있습니다.

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

또한 WPF 앱에서 리소스 패키지가 파이프로 구분되어 단수 및 복수 메시지 (또는 0 / 다수의 다수 메시지)를 포함하는 시스템을 보았습니다. 그런 다음 다음 사용자 지정 변환기를 사용 하여이 리소스를 구문 분석하고 관련 (서식이 지정된 언어를 사용할 수 있으므로 Xaml은 다음과 사용할 수 있습니다.

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

영어의 경우 위에 많은 답변이 있습니다. 다른 언어의 경우 복수형은 명사의 성별과 어미에 따라 달라지기 때문에 더 어렵습니다. 프랑스어로 된 몇 가지 예 :

일반 남성 :

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

일반 여성

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

광대 한 남성 ( 's'로 끝남)

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

동일한 문제가 대부분의 라틴어에 존재하며 독일어 또는 러시아어에서 3 개의 성별 (남성 성, 여성 성 및 중성)이있는 경우 더욱 악화됩니다.

당신의 목표가 영어 이상의 것을 다루는 것이라면주의가 필요합니다.


복수형 메시지를 가질 수있는 먼저 번호와 메시지 사이에 간접적 인 레이어를 만드는 것이 현명이라고 생각합니다.

예를 들어 어떤 종류의 상수를 사용하여 표시 할 메시지를 지정합니다. 구현 세부 정보를 숨기는 일부 기능을 사용하여 메시지를 가져옵니다.

get_message(DELETE_WARNING, quantity)

다음으로 가능한 메시지와 변형을 보유하는 사전을 만들고 변형이 언제 사용되어야 할 것인지 알 수 있습니다.

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

이제에 해당하는 키를 찾고 해당 메시지로 quantity의 값을 보간 할 수 quantity있습니다.

이 너무하고 단순 순진한 예제이지만,이 작업을 수행하는 다른 방법은 L10N 및 I18N에 대한 좋은 지원을 제공 할 수 없습니다.


아래 함수를 VBA에서 C #으로 변환해야하지만 사용법은 다음과 같이 변경됩니다.

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

나는 MS Access에서 사용하는 VBA 기능을 사용하여 당신이 말하는 것을 정확하게 수행합니다. 나는 VBA를 게시하기 위해 해킹 당할 수 있습니다. 알고리즘은 주석에서 분명해야합니다.

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

위의 코드 주석에서 사용법이 약간 잘 렸지만 반복하겠습니다.

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

예,이 솔루션은 영어가 아닌 언어를 무시합니다. 그것이 중요한지 여부는 요구 사항에 따라 달라집니다.


복수형을 자동으로 생성 할 수 있습니다. 복수 생성기 .

복수 생성 규칙은 wikipedia를 참조하십시오.

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

좀 더 일반적인 방법은 어떻습니까? 두 번째 문장에서 복수형을 사용하지 마십시오.

삭제할 선택된 항목 수 : 선택된 항목 없음.
확실해?

이 방법을 사용하면 줄 끝에 숫자가 표시되어 쉽게 알아볼 수 있습니다. 이 솔루션은 모든 언어에서 동일한 논리로 작동합니다.


내 일반적인 접근 방식은 다음과 같이 "단일 / 복수 함수"를 작성하는 것입니다.

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

그런 다음 메시지 본문에서이 함수를 호출합니다.

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

이것은 훨씬 더 좋지는 않지만 적어도 (a) 결정을 함수에 넣고 코드를 약간 정리하고 (b) 불규칙한 복수형을 처리 할 수있을만큼 유연합니다. 즉, 명사 (n, "child", "children") 등을 쉽게 말할 수 있습니다.

물론 이것은 영어에서만 작동하지만 개념은 더 복잡한 어미를 가진 언어로 쉽게 확장 할 수 있습니다.

쉬운 경우 마지막 매개 변수를 선택 사항으로 만들 수 있습니다.

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

국제화

국제화 지원을 원한다고 가정합니다.이 경우 다른 언어는 복수형에 대해 서로 다른 패턴을 가지고 있습니다 (예 : 2 개에 대한 특수 복수형 또는 폴란드어와 같은 더 복잡한 언어). 문자열에 간단한 패턴을 적용하는 데 의존 할 수 없습니다. 그것을 해결하기 위해.

GNU Gettext의 ngettext기능을 사용하고 소스 코드에 두 개의 영어 메시지를 제공 할 수 있습니다 . Gettext는 다른 언어로 번역 될 때 다른 (잠재적으로 더 많은) 메시지에서 선택할 수있는 인프라를 제공합니다. GNU gettext의 복수 지원에 대한 전체 설명은 http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html참조 하십시오 .

GNU Gettext는 LGPL에 속합니다. Gettext의 C # 포트에 ngettext이름이 지정 GettextResourceManager.GetPluralString됩니다.

(현지화 지원이 필요하지 않고 Gettext를 즉시 사용하고 싶지 않다면 영어로이 작업을 수행하는 자체 함수를 작성하고 두 개의 전체 메시지전달 합니다. 나중에 l10n이 필요한 경우 이렇게하면됩니다. 단일 함수를 다시 작성하여 추가하십시오.)


같은 함수를 작성하는 방법

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

.. 필요할 때마다 사용 하시겠습니까?

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

첫 번째 문제는 Pluralize를 의미 합니다 . Inflector 를 사용할 수 있습니다 .

그리고 두 번째로 ToPronounString과 같은 이름으로 문자열 표현 확장을 사용할 수 있습니다.


어제 우리 팀원이 저에게 똑같은 질문을 던졌습니다.

여기 StackOverflow에 다시 올라온 이후로 나는 우주가 괜찮은 솔루션을 생산하는 데 bash가 있다고 말하고 있다고 생각했습니다.

나는 빠르게 무언가를 모았고 결코 완벽하지는 않지만 유용하거나 토론 / 개발을 촉발시킬 수 있습니다.

이 코드는 3 개의 메시지가있을 수 있다는 생각을 기반으로합니다. 다음 구조를 따르는 0 개 항목에 대해 하나, 하나의 항목에 대해 하나 및 둘 이상의 항목에 대해 하나 :

singlePropertyName
singlePropertyName_Zero
singlePropertyName_Plural

리소스 클래스를 모방하기 위해 테스트 할 내부 클래스를 만들었습니다. 아직 실제 리소스 파일을 사용하여 테스트하지 않았으므로 아직 전체 결과를 보지 못했습니다.

여기에 코드가 있습니다 (현재 저는 세 번째 매개 변수를 Type으로 간단히 지정할 수 있고 두 번째 매개 변수도 문자열이라는 것을 알고있는 몇 가지 제네릭을 포함 시켰습니다.이 두 매개 변수를 더 나은 것으로 결합하는 방법이 있다고 생각합니다. 여유 시간이있을 때 다시 돌아 올게요.

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

테스트 리소스 클래스 :

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

내 빠른 실행 방법

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

내 관점에서 첫 번째 솔루션이 가장 적합한 솔루션입니다. 즉, 여러 언어를 지원하는 응용 프로그램이 필요한 경우 두 번째 옵션이 어려울 수 있습니다. 첫 번째 접근 방식을 사용하면 많은 노력없이 텍스트를 쉽게 현지화 할 수 있습니다.


'선택한 항목을 삭제 하시겠습니까?'와 같은보다 일반적인 메시지로 이동할 수 있습니다.


얼마나 좋은 메시지를 받고 싶은지에 달려 있습니다. 가장 쉬운 것부터 가장 어려운 것까지 :

  1. 복수형을 피하기 위해 오류 메시지를 다시 작성하십시오. 사용자에게는 좋지 않지만 더 빠릅니다.

  2. 더 일반적인 언어를 사용하되 여전히 숫자를 포함합니다.

  3. Rails에서 "복수화"와 inflector 시스템을 사용 pluralize(5,'bunch')하면 5 bunches. Rails는 이에 대한 좋은 패턴을 가지고 있습니다.

  4. 국제화를 위해서는 Java가 제공하는 것을 살펴 봐야합니다. 이는 2 개 또는 3 개의 항목이있는 서로 다른 형태의 형용사를 포함하는 다양한 언어를 지원합니다. "s"솔루션은 영어 중심입니다.

사용하는 옵션은 제품 목표에 따라 다릅니다. -ndp


사용자가 실제로 이해할 수있는 메시지를 제시하고 싶은 이유는 무엇입니까? 40 년의 프로그래밍 역사에 어긋납니다. Nooooo, 우리는 좋은 일이 있습니다. 이해할 수있는 메시지로 그것을 망치지 마십시오 .


(j / k)


월드 오브 워크래프트에서하는 것처럼하세요 :

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

조금 더 짧아집니다.

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

내가 언급하지 않은 접근 방식 중 하나는 대체 / 선택 태그를 사용하는 것입니다 (예 : "You are about to squash {0} [? i ({0} = 1) : / cactus / cacti /]"). (즉, 정수로 간주되는 인수 0이 1과 같은지 여부에 따라 대체를 지정하는 형식과 같은식이 있습니다.) .net 이전에 사용 된 태그를 본 적이 있습니다. .net의 표준이 아니며 형식을 지정하는 가장 좋은 방법도 모릅니다.


나는 잠시 동안 상자를 벗어난 것으로 생각할 것입니다. 여기에 제시된 모든 제안은 복수화를 수행하거나 (1 개 이상의 복수화, 성별 등에 대해 걱정) 전혀 사용하지 않고 멋진 실행 취소를 제공하는 것입니다.

나는 비언어적 방식으로 가서 시각적 대기열을 사용합니다. 예를 들어 손가락을 닦아서 항목을 선택하는 Iphone 앱을 상상해보십시오. 마스터 삭제 버튼을 사용하여 삭제하기 전에 선택한 항목을 "흔들고"V (확인) 또는 X (취소) 버튼이있는 상자 제목의 물음표를 표시합니다.

또는 Kinekt / Move / Wii의 3D 세계에서 파일을 선택하고 손을 삭제 버튼으로 이동 한 다음 확인을 위해 손을 머리 위로 이동하라는 지시를받는 것을 상상해보십시오 (앞에서 언급 한 것과 동일한 시각적 기호 사용). 3 개의 파일을 삭제하라는 메시지가 표시되면 반투명 빨간색 X가있는 3 개의 파일이 표시되고 확인 작업을 수행하라는 메시지가 표시됩니다.

참고 URL : https://stackoverflow.com/questions/4254088/plurality-in-user-messages

반응형