From e8c65a9cc9aee8f49df01e0452516adb1eb7f289 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 25 Mar 2021 08:48:51 +0200 Subject: Lang: Plural strings IssueID #192 --- src/lang.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-- src/lang.h | 4 ++++ src/ui/documentwidget.c | 29 +++++++++++------------- src/ui/sidebarwidget.c | 8 +++---- 4 files changed, 79 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/lang.c b/src/lang.c index be8ad9d1..983ae3c5 100644 --- a/src/lang.c +++ b/src/lang.c @@ -19,12 +19,32 @@ int cmp_MsgStr_(const void *e1, const void *e2) { /*----------------------------------------------------------------------------------------------*/ +enum iPluralType { + none_PluralType, + notEqualToOne_PluralType, + slavic_PluralType, +}; + struct Impl_Lang { iSortedArray *messages; + enum iPluralType pluralType; }; static iLang lang_; +static size_t pluralIndex_Lang_(const iLang *d, int n) { + switch (d->pluralType) { + case notEqualToOne_PluralType: + return n != 1; + case slavic_PluralType: + return n % 10 == 1 && n % 100 != 11 ? 0 + : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 + : 2; + default: + return 0; + } +} + static void clear_Lang_(iLang *d) { clear_SortedArray(d->messages); } @@ -36,6 +56,15 @@ static void load_Lang_(iLang *d, const char *id) { : equal_CStr(id, "ru") ? &blobRu_Embedded : equal_CStr(id, "de") ? &blobDe_Embedded : &blobEn_Embedded; + if (data == &blobRu_Embedded) { + d->pluralType = slavic_PluralType; + } +// else if (data == &blobZhHans_Embedded) { +// d->pluralType = none_PluralType; +// } + else { + d->pluralType = notEqualToOne_PluralType; + } iMsgStr msg; for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { msg.id.start = ptr; @@ -45,6 +74,7 @@ static void load_Lang_(iLang *d, const char *id) { while (*++ptr) {} msg.str.end = ptr; /* Allocate the string. The data has already been sorted. */ + printf("ID:%s\n", msg.id.start); pushBack_Array(&d->messages->values, &msg); } } @@ -87,12 +117,30 @@ iRangecc range_Lang(iRangecc msgId) { return str; } +const iString *string_Lang(const char *msgId) { + return collectNewRange_String(range_Lang(range_CStr(msgId))); +} + const char *cstr_Lang(const char *msgId) { return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */ } -const iString *string_Lang(const char *msgId) { - return collectNewRange_String(range_Lang(range_CStr(msgId))); +static char *pluralId_Lang_(const iLang *d, const char *msgId, int count) { + const size_t len = strlen(msgId); + char *pluralId = strdup(msgId); + pluralId[len - 1] = '0' + pluralIndex_Lang_(d, count); + return pluralId; +} + +const char *cstrCount_Lang(const char *msgId, int count) { + iAssert(endsWith_Rangecc(range_CStr(msgId), ".n")); /* by convention */ + char *pluralId = pluralId_Lang_(&lang_, msgId, count); + const char *str = cstr_Lang(pluralId); + if (str == pluralId) { + str = msgId; /* not found */ + } + free(pluralId); + return str; } void translate_Lang(iString *textWithIds) { @@ -129,3 +177,11 @@ const char *translateCStr_Lang(const char *textWithIds) { translate_Lang(text); return cstr_String(text); } + +const char *formatCStr_Lang(const char *formatMsgId, int count) { + return format_CStr(cstrCount_Lang(formatMsgId, count), count); +} + +const char *formatCStrs_Lang(const char *formatMsgId, size_t count) { + return format_CStr(cstrCount_Lang(formatMsgId, (int) count), count); +} diff --git a/src/lang.h b/src/lang.h index ea71e531..bf4c16d1 100644 --- a/src/lang.h +++ b/src/lang.h @@ -13,3 +13,7 @@ const iString * string_Lang (const char *msgId); void translate_Lang (iString *textWithIds); const char * translateCStr_Lang (const char *textWithIds); + +const char * cstrCount_Lang (const char *msgId, int count); +const char * formatCStr_Lang (const char *formatMsgId, int count); +const char * formatCStrs_Lang (const char *formatMsgId, size_t count); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 3d8d4f12..88016b1c 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -2081,20 +2081,17 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) } if (!isEmpty_PtrArray(links)) { if (argLabel_Command(cmd, "confirm")) { - //const char *plural = size_PtrArray(links) != 1 ? "s" : ""; - const iBool isPlural = size_PtrArray(links) != 1; + const size_t count = size_PtrArray(links); makeQuestion_Widget( uiHeading_ColorEscape "${heading.import.bookmarks}", - format_CStr(cstr_Lang(isPlural ? "dlg.import.found.many" : "dlg.import.found"), - size_PtrArray(links)), - (iMenuItem[]){ - { "${cancel}", 0, 0, NULL }, - { format_CStr(cstr_Lang(isPlural ? "dlg.import.add.many" : "dlg.import.add"), - uiTextAction_ColorEscape, - size_PtrArray(links)), - 0, - 0, - "bookmark.links" } }, + formatCStrs_Lang("dlg.import.found.n", count), + (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, + { format_CStr(cstrCount_Lang("dlg.import.add.n", count), + uiTextAction_ColorEscape, + count), + 0, + 0, + "bookmark.links" } }, 2); } else { @@ -2846,10 +2843,10 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24; appendCStr_String(&str, "\n"); if (days <= 30) { - appendFormat_String(&str, - cstr_Lang("dlg.certwarn.mayberenewed"), - cstrCollect_String(format_Date(&exp, "%Y-%m-%d")), - days); + appendCStr_String(&str, + format_CStr(cstrCount_Lang("dlg.certwarn.mayberenewed.n", days), + cstrCollect_String(format_Date(&exp, "%Y-%m-%d")), + days)); } else { appendCStr_String(&str, cstr_Lang("dlg.certwarn.different")); diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 5ff585a5..29b3646a 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c @@ -352,7 +352,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { "%s", isActive ? cstr_Lang("ident.using") : isUsed_GmIdentity(ident) - ? format_CStr(cstr_Lang("ident.usedonurls"), size_StringSet(ident->useUrls)) + ? formatCStrs_Lang("ident.usedonurls.n", size_StringSet(ident->useUrls)) : cstr_Lang("ident.notused")); const char *expiry = ident->flags & temporary_GmIdentityFlag @@ -705,12 +705,12 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { if (i == feeds_SidebarMode && d->numUnreadEntries) { updateText_LabelWidget( button, - collectNewFormat_String("%s " uiTextAction_ColorEscape "%zu%s", + collectNewFormat_String("%s " uiTextAction_ColorEscape "%zu%s%s", tightModeLabels_[i], d->numUnreadEntries, + !isTight ? " " : "", !isTight - ? (d->numUnreadEntries == 1 ? " ${sidebar.unread}" - : " ${sidebar.unread.many}") + ? formatCStrs_Lang("sidebar.unread.n", d->numUnreadEntries) : "")); } else { -- cgit v1.2.3