summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/en.po35
-rw-r--r--res/lang/en.binbin2131 -> 2275 bytes
-rw-r--r--src/lang.c53
-rw-r--r--src/lang.h7
-rw-r--r--src/macos.m4
-rw-r--r--src/ui/labelwidget.c24
-rw-r--r--src/ui/window.c12
7 files changed, 87 insertions, 48 deletions
diff --git a/po/en.po b/po/en.po
index 44b6ee11..cb203ca8 100644
--- a/po/en.po
+++ b/po/en.po
@@ -10,6 +10,24 @@ msgstr "Version"
10msgid "about.powered" 10msgid "about.powered"
11msgstr "Powered by SDL 2, OpenSSL, and ☕️" 11msgstr "Powered by SDL 2, OpenSSL, and ☕️"
12 12
13msgid "menu.title.file"
14msgstr "File"
15
16msgid "menu.title.edit"
17msgstr "Edit"
18
19msgid "menu.title.view"
20msgstr "View"
21
22msgid "menu.title.bookmarks"
23msgstr "Bookmarks"
24
25msgid "menu.title.identity"
26msgstr "Identity"
27
28msgid "menu.title.help"
29msgstr "Help"
30
13msgid "menu.newtab" 31msgid "menu.newtab"
14msgstr "New Tab" 32msgstr "New Tab"
15 33
@@ -29,7 +47,7 @@ msgid "menu.duptab"
29msgstr "Duplicate Tab" 47msgstr "Duplicate Tab"
30 48
31msgid "menu.openlocation" 49msgid "menu.openlocation"
32msgstr "Open Location..." 50msgstr "Open Location"
33 51
34msgid "menu.find" 52msgid "menu.find"
35msgstr "Find on Page" 53msgstr "Find on Page"
@@ -86,7 +104,7 @@ msgid "menu.feeds.entrylist"
86msgstr "Show Feed Entries" 104msgstr "Show Feed Entries"
87 105
88msgid "menu.preferences" 106msgid "menu.preferences"
89msgstr "Preferences..." 107msgstr "Preferences"
90 108
91msgid "menu.help" 109msgid "menu.help"
92msgstr "Help" 110msgstr "Help"
@@ -146,13 +164,13 @@ msgid "menu.debug"
146msgstr "Debug Information" 164msgstr "Debug Information"
147 165
148msgid "menu.bookmark.page" 166msgid "menu.bookmark.page"
149msgstr "Bookmark This Page..." 167msgstr "Bookmark This Page"
150 168
151msgid "menu.subscribe.page" 169msgid "menu.subscribe.page"
152msgstr "Subscribe to This Page..." 170msgstr "Subscribe to This Page"
153 171
154msgid "menu.import.links" 172msgid "menu.import.links"
155msgstr "Import All Links on Page..." 173msgstr "Import All Links on Page"
156 174
157msgid "menu.bookmarks.refresh" 175msgid "menu.bookmarks.refresh"
158msgstr "Refresh Remote Bookmarks" 176msgstr "Refresh Remote Bookmarks"
@@ -161,10 +179,10 @@ msgid "menu.feeds.refresh"
161msgstr "Refresh Feeds" 179msgstr "Refresh Feeds"
162 180
163msgid "menu.identity.new" 181msgid "menu.identity.new"
164msgstr "New Identity..." 182msgstr "New Identity"
165 183
166msgid "menu.identity.import" 184msgid "menu.identity.import"
167msgstr "Import..." 185msgstr "Import"
168 186
169msgid "menu.identity.notactive" 187msgid "menu.identity.notactive"
170msgstr "No Active Identity" 188msgstr "No Active Identity"
@@ -193,10 +211,11 @@ msgstr "Search Query"
193msgid "status.feeds" 211msgid "status.feeds"
194msgstr "Updating Feeds" 212msgstr "Updating Feeds"
195 213
214# megabytes, used as the unit after a number
196msgid "mb" 215msgid "mb"
197msgstr "MB" 216msgstr "MB"
198 217
199# strftime() formatted, split on two lines 218# strftime() formatted, split on two lines
200#, c-format 219#, c-format
201msgid "page.timestamp" 220msgid "page.timestamp"
202msgstr "Received at %I:%M %p\non %b %d, %Y" 221msgstr "Received at %I:%M %p\non %b %d, %Y"
diff --git a/res/lang/en.bin b/res/lang/en.bin
index d02a2f3d..0603e6ad 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/src/lang.c b/src/lang.c
index d0120798..81afb0d2 100644
--- a/src/lang.c
+++ b/src/lang.c
@@ -8,13 +8,13 @@ iDeclareType(Lang)
8iDeclareType(MsgStr) 8iDeclareType(MsgStr)
9 9
10struct Impl_MsgStr { 10struct Impl_MsgStr {
11 const char *id; /* these point to null-terminated strings in embedded data */ 11 iRangecc id; /* these point to null-terminated strings in embedded data */
12 const char *str; 12 iRangecc str;
13}; 13};
14 14
15int cmp_MsgStr_(const void *e1, const void *e2) { 15int cmp_MsgStr_(const void *e1, const void *e2) {
16 const iMsgStr *a = e1, *b = e2; 16 const iMsgStr *a = e1, *b = e2;
17 return iCmpStr(a->id, b->id); 17 return cmpCStrNSc_Rangecc(a->id, b->id.start, size_Range(&b->id), &iCaseSensitive);
18} 18}
19 19
20/*----------------------------------------------------------------------------------------------*/ 20/*----------------------------------------------------------------------------------------------*/
@@ -35,10 +35,12 @@ static void load_Lang_(iLang *d, const char *id) {
35 const iBlock *data = &blobEn_Embedded; 35 const iBlock *data = &blobEn_Embedded;
36 iMsgStr msg; 36 iMsgStr msg;
37 for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { 37 for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) {
38 msg.id = ptr; 38 msg.id.start = ptr;
39 while (*++ptr) {} 39 while (*++ptr) {}
40 msg.str = ++ptr; 40 msg.id.end = ptr;
41 msg.str.start = ++ptr;
41 while (*++ptr) {} 42 while (*++ptr) {}
43 msg.str.end = ptr;
42 /* Allocate the string. The data has already been sorted. */ 44 /* Allocate the string. The data has already been sorted. */
43 pushBack_Array(&d->messages->values, &msg); 45 pushBack_Array(&d->messages->values, &msg);
44 } 46 }
@@ -62,18 +64,51 @@ void setCurrent_Lang(const char *language) {
62 load_Lang_(d, language); 64 load_Lang_(d, language);
63} 65}
64 66
65const char *cstr_Lang(const char *msgId) { 67iRangecc range_Lang(iRangecc msgId) {
66 const iLang *d = &lang_; 68 const iLang *d = &lang_;
67 size_t pos; 69 size_t pos;
68 const iMsgStr key = { .id = iConstCast(char *, msgId) }; 70 const iMsgStr key = { .id = msgId };
69 if (locate_SortedArray(d->messages, &key, &pos)) { 71 if (locate_SortedArray(d->messages, &key, &pos)) {
70 return ((const iMsgStr *) at_SortedArray(d->messages, pos))->str; 72 return ((const iMsgStr *) at_SortedArray(d->messages, pos))->str;
71 } 73 }
72 fprintf(stderr, "[Lang] missing: %s\n", msgId); fflush(stderr); 74 fprintf(stderr, "[Lang] missing: %s\n", cstr_Rangecc(msgId)); fflush(stderr);
73 iAssert(iFalse); 75 iAssert(iFalse);
74 return msgId; 76 return msgId;
75} 77}
76 78
79const char *cstr_Lang(const char *msgId) {
80 return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */
81}
82
77const iString *string_Lang(const char *msgId) { 83const iString *string_Lang(const char *msgId) {
78 return collectNewCStr_String(cstr_Lang(msgId)); 84 return collectNewRange_String(range_Lang(range_CStr(msgId)));
85}
86
87void translate_Lang(iString *textWithIds) {
88 for (const char *pos = cstr_String(textWithIds); *pos; ) {
89 iRangecc id;
90 id.start = strstr(pos, "${");
91 if (!id.start) {
92 break;
93 }
94 id.start += 2;
95 id.end = strchr(id.start, '}');
96 iAssert(id.end != NULL);
97 const size_t idLen = size_Range(&id);
98 const iRangecc replacement = range_Lang(id);
99 const size_t startPos = id.start - cstr_String(textWithIds) - 2;
100 /* Replace it. */
101 remove_Block(&textWithIds->chars, startPos, idLen + 3);
102 insertData_Block(&textWithIds->chars, startPos, replacement.start, size_Range(&replacement));
103 pos = cstr_String(textWithIds) + startPos + size_Range(&replacement);
104 }
105}
106
107const char *translateCStr_Lang(const char *textWithIds) {
108 if (strstr(textWithIds, "${") == NULL) {
109 return textWithIds; /* nothing to replace */
110 }
111 iString *text = collectNewCStr_String(textWithIds);
112 translate_Lang(text);
113 return cstr_String(text);
79} 114}
diff --git a/src/lang.h b/src/lang.h
index 3e9291f2..ea71e531 100644
--- a/src/lang.h
+++ b/src/lang.h
@@ -6,5 +6,10 @@ void init_Lang (void);
6void deinit_Lang (void); 6void deinit_Lang (void);
7 7
8void setCurrent_Lang (const char *language); 8void setCurrent_Lang (const char *language);
9const iString * string_Lang (const char *msgId); 9iRangecc range_Lang (iRangecc msgId);
10
10const char * cstr_Lang (const char *msgId); 11const char * cstr_Lang (const char *msgId);
12const iString * string_Lang (const char *msgId);
13
14void translate_Lang (iString *textWithIds);
15const char * translateCStr_Lang (const char *textWithIds);
diff --git a/src/macos.m b/src/macos.m
index c6c30fa5..12575dd5 100644
--- a/src/macos.m
+++ b/src/macos.m
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#include "macos.h" 23#include "macos.h"
24#include "app.h" 24#include "app.h"
25#include "lang.h"
25#include "ui/color.h" 26#include "ui/color.h"
26#include "ui/command.h" 27#include "ui/command.h"
27#include "ui/keys.h" 28#include "ui/keys.h"
@@ -462,6 +463,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem *
462 NSApplication *app = [NSApplication sharedApplication]; 463 NSApplication *app = [NSApplication sharedApplication];
463 MyDelegate *myDel = (MyDelegate *) app.delegate; 464 MyDelegate *myDel = (MyDelegate *) app.delegate;
464 NSMenu *appMenu = [app mainMenu]; 465 NSMenu *appMenu = [app mainMenu];
466 menuLabel = translateCStr_Lang(menuLabel);
465 NSMenuItem *mainItem = [appMenu insertItemWithTitle:[NSString stringWithUTF8String:menuLabel] 467 NSMenuItem *mainItem = [appMenu insertItemWithTitle:[NSString stringWithUTF8String:menuLabel]
466 action:nil 468 action:nil
467 keyEquivalent:@"" 469 keyEquivalent:@""
@@ -469,7 +471,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem *
469 NSMenu *menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:menuLabel]]; 471 NSMenu *menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:menuLabel]];
470 [menu setAutoenablesItems:NO]; 472 [menu setAutoenablesItems:NO];
471 for (size_t i = 0; i < count; ++i) { 473 for (size_t i = 0; i < count; ++i) {
472 const char *label = items[i].label; 474 const char *label = translateCStr_Lang(items[i].label);
473 if (label[0] == '\r') { 475 if (label[0] == '\r') {
474 /* Skip the formatting escape. */ 476 /* Skip the formatting escape. */
475 label += 2; 477 label += 2;
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c
index c3bc4392..0becd419 100644
--- a/src/ui/labelwidget.c
+++ b/src/ui/labelwidget.c
@@ -359,29 +359,7 @@ void updateSize_LabelWidget(iLabelWidget *d) {
359} 359}
360 360
361static void replaceVariables_LabelWidget_(iLabelWidget *d) { 361static void replaceVariables_LabelWidget_(iLabelWidget *d) {
362 for (const char *label = cstr_String(&d->label); *label; ) { 362 translate_Lang(&d->label);
363 iRangecc id;
364 id.start = strstr(label, "${");
365 if (!id.start) {
366 break;
367 }
368 id.start += 2;
369 id.end = strchr(id.start, '}');
370 iAssert(id.end != NULL);
371 /* TODO: Add a lookup that doesn't allocate anything; Lang can handle it. */
372 const size_t len = size_Range(&id);
373 char *key = malloc(len + 1);
374 memcpy(key, id.start, len);
375 key[len] = 0;
376 const char *text = cstr_Lang(key);
377 const size_t textLen = strlen(text);
378 free(key);
379 /* Replace it. */
380 size_t startPos = id.start - cstr_String(&d->label) - 2;
381 remove_Block(&d->label.chars, startPos, len + 3);
382 insertData_Block(&d->label.chars, startPos, text, textLen);
383 label = cstr_String(&d->label) + startPos + textLen;
384 }
385} 363}
386 364
387void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { 365void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) {
diff --git a/src/ui/window.c b/src/ui/window.c
index 2d1deb72..d27d252b 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -1055,12 +1055,12 @@ static void setupUserInterface_Window(iWindow *d) {
1055 setAlignVisually_LabelWidget(navMenu, iTrue); 1055 setAlignVisually_LabelWidget(navMenu, iTrue);
1056 setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); 1056 setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu");
1057#else 1057#else
1058 insertMenuItems_MacOS("File", 1, fileMenuItems_, iElemCount(fileMenuItems_)); 1058 insertMenuItems_MacOS("${menu.title.file}", 1, fileMenuItems_, iElemCount(fileMenuItems_));
1059 insertMenuItems_MacOS("Edit", 2, editMenuItems_, iElemCount(editMenuItems_)); 1059 insertMenuItems_MacOS("${menu.title.edit}", 2, editMenuItems_, iElemCount(editMenuItems_));
1060 insertMenuItems_MacOS("View", 3, viewMenuItems_, iElemCount(viewMenuItems_)); 1060 insertMenuItems_MacOS("${menu.title.view}", 3, viewMenuItems_, iElemCount(viewMenuItems_));
1061 insertMenuItems_MacOS("Bookmarks", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_)); 1061 insertMenuItems_MacOS("${menu.title.bookmarks}", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_));
1062 insertMenuItems_MacOS("Identity", 5, identityMenuItems_, iElemCount(identityMenuItems_)); 1062 insertMenuItems_MacOS("${menu.title.identity}", 5, identityMenuItems_, iElemCount(identityMenuItems_));
1063 insertMenuItems_MacOS("Help", 7, helpMenuItems_, iElemCount(helpMenuItems_)); 1063 insertMenuItems_MacOS("${menu.title.help}", 7, helpMenuItems_, iElemCount(helpMenuItems_));
1064#endif 1064#endif
1065 } 1065 }
1066 /* Tab bar. */ { 1066 /* Tab bar. */ {