diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-25 08:48:51 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-25 08:49:04 +0200 |
commit | e8c65a9cc9aee8f49df01e0452516adb1eb7f289 (patch) | |
tree | 0a02ae01c34561c950c71cdf4e116d90bb7b9577 /src | |
parent | 9b2f3176145af506071fee1e0a174de9e209b69f (diff) |
Lang: Plural strings
IssueID #192
Diffstat (limited to 'src')
-rw-r--r-- | src/lang.c | 60 | ||||
-rw-r--r-- | src/lang.h | 4 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 29 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 8 |
4 files changed, 79 insertions, 22 deletions
@@ -19,12 +19,32 @@ int cmp_MsgStr_(const void *e1, const void *e2) { | |||
19 | 19 | ||
20 | /*----------------------------------------------------------------------------------------------*/ | 20 | /*----------------------------------------------------------------------------------------------*/ |
21 | 21 | ||
22 | enum iPluralType { | ||
23 | none_PluralType, | ||
24 | notEqualToOne_PluralType, | ||
25 | slavic_PluralType, | ||
26 | }; | ||
27 | |||
22 | struct Impl_Lang { | 28 | struct Impl_Lang { |
23 | iSortedArray *messages; | 29 | iSortedArray *messages; |
30 | enum iPluralType pluralType; | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | static iLang lang_; | 33 | static iLang lang_; |
27 | 34 | ||
35 | static size_t pluralIndex_Lang_(const iLang *d, int n) { | ||
36 | switch (d->pluralType) { | ||
37 | case notEqualToOne_PluralType: | ||
38 | return n != 1; | ||
39 | case slavic_PluralType: | ||
40 | return n % 10 == 1 && n % 100 != 11 ? 0 | ||
41 | : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 | ||
42 | : 2; | ||
43 | default: | ||
44 | return 0; | ||
45 | } | ||
46 | } | ||
47 | |||
28 | static void clear_Lang_(iLang *d) { | 48 | static void clear_Lang_(iLang *d) { |
29 | clear_SortedArray(d->messages); | 49 | clear_SortedArray(d->messages); |
30 | } | 50 | } |
@@ -36,6 +56,15 @@ static void load_Lang_(iLang *d, const char *id) { | |||
36 | : equal_CStr(id, "ru") ? &blobRu_Embedded | 56 | : equal_CStr(id, "ru") ? &blobRu_Embedded |
37 | : equal_CStr(id, "de") ? &blobDe_Embedded | 57 | : equal_CStr(id, "de") ? &blobDe_Embedded |
38 | : &blobEn_Embedded; | 58 | : &blobEn_Embedded; |
59 | if (data == &blobRu_Embedded) { | ||
60 | d->pluralType = slavic_PluralType; | ||
61 | } | ||
62 | // else if (data == &blobZhHans_Embedded) { | ||
63 | // d->pluralType = none_PluralType; | ||
64 | // } | ||
65 | else { | ||
66 | d->pluralType = notEqualToOne_PluralType; | ||
67 | } | ||
39 | iMsgStr msg; | 68 | iMsgStr msg; |
40 | for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { | 69 | for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { |
41 | msg.id.start = ptr; | 70 | msg.id.start = ptr; |
@@ -45,6 +74,7 @@ static void load_Lang_(iLang *d, const char *id) { | |||
45 | while (*++ptr) {} | 74 | while (*++ptr) {} |
46 | msg.str.end = ptr; | 75 | msg.str.end = ptr; |
47 | /* Allocate the string. The data has already been sorted. */ | 76 | /* Allocate the string. The data has already been sorted. */ |
77 | printf("ID:%s\n", msg.id.start); | ||
48 | pushBack_Array(&d->messages->values, &msg); | 78 | pushBack_Array(&d->messages->values, &msg); |
49 | } | 79 | } |
50 | } | 80 | } |
@@ -87,12 +117,30 @@ iRangecc range_Lang(iRangecc msgId) { | |||
87 | return str; | 117 | return str; |
88 | } | 118 | } |
89 | 119 | ||
120 | const iString *string_Lang(const char *msgId) { | ||
121 | return collectNewRange_String(range_Lang(range_CStr(msgId))); | ||
122 | } | ||
123 | |||
90 | const char *cstr_Lang(const char *msgId) { | 124 | const char *cstr_Lang(const char *msgId) { |
91 | return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */ | 125 | return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */ |
92 | } | 126 | } |
93 | 127 | ||
94 | const iString *string_Lang(const char *msgId) { | 128 | static char *pluralId_Lang_(const iLang *d, const char *msgId, int count) { |
95 | return collectNewRange_String(range_Lang(range_CStr(msgId))); | 129 | const size_t len = strlen(msgId); |
130 | char *pluralId = strdup(msgId); | ||
131 | pluralId[len - 1] = '0' + pluralIndex_Lang_(d, count); | ||
132 | return pluralId; | ||
133 | } | ||
134 | |||
135 | const char *cstrCount_Lang(const char *msgId, int count) { | ||
136 | iAssert(endsWith_Rangecc(range_CStr(msgId), ".n")); /* by convention */ | ||
137 | char *pluralId = pluralId_Lang_(&lang_, msgId, count); | ||
138 | const char *str = cstr_Lang(pluralId); | ||
139 | if (str == pluralId) { | ||
140 | str = msgId; /* not found */ | ||
141 | } | ||
142 | free(pluralId); | ||
143 | return str; | ||
96 | } | 144 | } |
97 | 145 | ||
98 | void translate_Lang(iString *textWithIds) { | 146 | void translate_Lang(iString *textWithIds) { |
@@ -129,3 +177,11 @@ const char *translateCStr_Lang(const char *textWithIds) { | |||
129 | translate_Lang(text); | 177 | translate_Lang(text); |
130 | return cstr_String(text); | 178 | return cstr_String(text); |
131 | } | 179 | } |
180 | |||
181 | const char *formatCStr_Lang(const char *formatMsgId, int count) { | ||
182 | return format_CStr(cstrCount_Lang(formatMsgId, count), count); | ||
183 | } | ||
184 | |||
185 | const char *formatCStrs_Lang(const char *formatMsgId, size_t count) { | ||
186 | return format_CStr(cstrCount_Lang(formatMsgId, (int) count), count); | ||
187 | } | ||
@@ -13,3 +13,7 @@ const iString * string_Lang (const char *msgId); | |||
13 | 13 | ||
14 | void translate_Lang (iString *textWithIds); | 14 | void translate_Lang (iString *textWithIds); |
15 | const char * translateCStr_Lang (const char *textWithIds); | 15 | const char * translateCStr_Lang (const char *textWithIds); |
16 | |||
17 | const char * cstrCount_Lang (const char *msgId, int count); | ||
18 | const char * formatCStr_Lang (const char *formatMsgId, int count); | ||
19 | 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) | |||
2081 | } | 2081 | } |
2082 | if (!isEmpty_PtrArray(links)) { | 2082 | if (!isEmpty_PtrArray(links)) { |
2083 | if (argLabel_Command(cmd, "confirm")) { | 2083 | if (argLabel_Command(cmd, "confirm")) { |
2084 | //const char *plural = size_PtrArray(links) != 1 ? "s" : ""; | 2084 | const size_t count = size_PtrArray(links); |
2085 | const iBool isPlural = size_PtrArray(links) != 1; | ||
2086 | makeQuestion_Widget( | 2085 | makeQuestion_Widget( |
2087 | uiHeading_ColorEscape "${heading.import.bookmarks}", | 2086 | uiHeading_ColorEscape "${heading.import.bookmarks}", |
2088 | format_CStr(cstr_Lang(isPlural ? "dlg.import.found.many" : "dlg.import.found"), | 2087 | formatCStrs_Lang("dlg.import.found.n", count), |
2089 | size_PtrArray(links)), | 2088 | (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, |
2090 | (iMenuItem[]){ | 2089 | { format_CStr(cstrCount_Lang("dlg.import.add.n", count), |
2091 | { "${cancel}", 0, 0, NULL }, | 2090 | uiTextAction_ColorEscape, |
2092 | { format_CStr(cstr_Lang(isPlural ? "dlg.import.add.many" : "dlg.import.add"), | 2091 | count), |
2093 | uiTextAction_ColorEscape, | 2092 | 0, |
2094 | size_PtrArray(links)), | 2093 | 0, |
2095 | 0, | 2094 | "bookmark.links" } }, |
2096 | 0, | ||
2097 | "bookmark.links" } }, | ||
2098 | 2); | 2095 | 2); |
2099 | } | 2096 | } |
2100 | else { | 2097 | else { |
@@ -2846,10 +2843,10 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 | |||
2846 | const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24; | 2843 | const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24; |
2847 | appendCStr_String(&str, "\n"); | 2844 | appendCStr_String(&str, "\n"); |
2848 | if (days <= 30) { | 2845 | if (days <= 30) { |
2849 | appendFormat_String(&str, | 2846 | appendCStr_String(&str, |
2850 | cstr_Lang("dlg.certwarn.mayberenewed"), | 2847 | format_CStr(cstrCount_Lang("dlg.certwarn.mayberenewed.n", days), |
2851 | cstrCollect_String(format_Date(&exp, "%Y-%m-%d")), | 2848 | cstrCollect_String(format_Date(&exp, "%Y-%m-%d")), |
2852 | days); | 2849 | days)); |
2853 | } | 2850 | } |
2854 | else { | 2851 | else { |
2855 | appendCStr_String(&str, cstr_Lang("dlg.certwarn.different")); | 2852 | 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) { | |||
352 | "%s", | 352 | "%s", |
353 | isActive ? cstr_Lang("ident.using") | 353 | isActive ? cstr_Lang("ident.using") |
354 | : isUsed_GmIdentity(ident) | 354 | : isUsed_GmIdentity(ident) |
355 | ? format_CStr(cstr_Lang("ident.usedonurls"), size_StringSet(ident->useUrls)) | 355 | ? formatCStrs_Lang("ident.usedonurls.n", size_StringSet(ident->useUrls)) |
356 | : cstr_Lang("ident.notused")); | 356 | : cstr_Lang("ident.notused")); |
357 | const char *expiry = | 357 | const char *expiry = |
358 | ident->flags & temporary_GmIdentityFlag | 358 | ident->flags & temporary_GmIdentityFlag |
@@ -705,12 +705,12 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
705 | if (i == feeds_SidebarMode && d->numUnreadEntries) { | 705 | if (i == feeds_SidebarMode && d->numUnreadEntries) { |
706 | updateText_LabelWidget( | 706 | updateText_LabelWidget( |
707 | button, | 707 | button, |
708 | collectNewFormat_String("%s " uiTextAction_ColorEscape "%zu%s", | 708 | collectNewFormat_String("%s " uiTextAction_ColorEscape "%zu%s%s", |
709 | tightModeLabels_[i], | 709 | tightModeLabels_[i], |
710 | d->numUnreadEntries, | 710 | d->numUnreadEntries, |
711 | !isTight ? " " : "", | ||
711 | !isTight | 712 | !isTight |
712 | ? (d->numUnreadEntries == 1 ? " ${sidebar.unread}" | 713 | ? formatCStrs_Lang("sidebar.unread.n", d->numUnreadEntries) |
713 | : " ${sidebar.unread.many}") | ||
714 | : "")); | 714 | : "")); |
715 | } | 715 | } |
716 | else { | 716 | else { |