summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-25 08:48:51 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-25 08:49:04 +0200
commite8c65a9cc9aee8f49df01e0452516adb1eb7f289 (patch)
tree0a02ae01c34561c950c71cdf4e116d90bb7b9577 /src
parent9b2f3176145af506071fee1e0a174de9e209b69f (diff)
Lang: Plural strings
IssueID #192
Diffstat (limited to 'src')
-rw-r--r--src/lang.c60
-rw-r--r--src/lang.h4
-rw-r--r--src/ui/documentwidget.c29
-rw-r--r--src/ui/sidebarwidget.c8
4 files changed, 79 insertions, 22 deletions
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) {
19 19
20/*----------------------------------------------------------------------------------------------*/ 20/*----------------------------------------------------------------------------------------------*/
21 21
22enum iPluralType {
23 none_PluralType,
24 notEqualToOne_PluralType,
25 slavic_PluralType,
26};
27
22struct Impl_Lang { 28struct Impl_Lang {
23 iSortedArray *messages; 29 iSortedArray *messages;
30 enum iPluralType pluralType;
24}; 31};
25 32
26static iLang lang_; 33static iLang lang_;
27 34
35static 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
28static void clear_Lang_(iLang *d) { 48static 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
120const iString *string_Lang(const char *msgId) {
121 return collectNewRange_String(range_Lang(range_CStr(msgId)));
122}
123
90const char *cstr_Lang(const char *msgId) { 124const 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
94const iString *string_Lang(const char *msgId) { 128static 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
135const 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
98void translate_Lang(iString *textWithIds) { 146void 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
181const char *formatCStr_Lang(const char *formatMsgId, int count) {
182 return format_CStr(cstrCount_Lang(formatMsgId, count), count);
183}
184
185const char *formatCStrs_Lang(const char *formatMsgId, size_t count) {
186 return format_CStr(cstrCount_Lang(formatMsgId, (int) count), count);
187}
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);
13 13
14void translate_Lang (iString *textWithIds); 14void translate_Lang (iString *textWithIds);
15const char * translateCStr_Lang (const char *textWithIds); 15const char * translateCStr_Lang (const char *textWithIds);
16
17const char * cstrCount_Lang (const char *msgId, int count);
18const char * formatCStr_Lang (const char *formatMsgId, int count);
19const 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 {