summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--po/en.po203
-rw-r--r--res/about/lagrange.gmi8
-rw-r--r--src/app.c2
-rw-r--r--src/defs.h6
-rw-r--r--src/gmrequest.c4
-rw-r--r--src/lang.c56
-rw-r--r--src/lang.h10
-rw-r--r--src/ui/documentwidget.c4
-rw-r--r--src/ui/window.c202
10 files changed, 388 insertions, 109 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d692025b..2166acc5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -107,6 +107,8 @@ set (SOURCES
107 src/history.h 107 src/history.h
108 src/ipc.c 108 src/ipc.c
109 src/ipc.h 109 src/ipc.h
110 src/lang.c
111 src/lang.h
110 src/lookup.c 112 src/lookup.c
111 src/lookup.h 113 src/lookup.h
112 src/media.c 114 src/media.c
diff --git a/po/en.po b/po/en.po
new file mode 100644
index 00000000..44b6ee11
--- /dev/null
+++ b/po/en.po
@@ -0,0 +1,203 @@
1msgid "about.logo"
2msgstr "ASCII art: the word \"Lagrange\" using a large font"
3
4msgid "about.tagline"
5msgstr "A Beautiful Gemini Client"
6
7msgid "about.version"
8msgstr "Version"
9
10msgid "about.powered"
11msgstr "Powered by SDL 2, OpenSSL, and ☕️"
12
13msgid "menu.newtab"
14msgstr "New Tab"
15
16msgid "menu.closetab"
17msgstr "Close Tab"
18
19msgid "menu.closetab.other"
20msgstr "Close Other Tabs"
21
22msgid "menu.closetab.left"
23msgstr "Close Tabs To Left"
24
25msgid "menu.closetab.right"
26msgstr "Close Tabs To Right"
27
28msgid "menu.duptab"
29msgstr "Duplicate Tab"
30
31msgid "menu.openlocation"
32msgstr "Open Location..."
33
34msgid "menu.find"
35msgstr "Find on Page"
36
37msgid "macos.menu.find"
38msgstr "Find"
39
40msgid "menu.save.files"
41msgstr "Save to Files"
42
43msgid "menu.save.downloads"
44msgstr "Save to Downloads"
45
46msgid "menu.copy.source"
47msgstr "Copy Source Text"
48
49msgid "menu.sidebar"
50msgstr "Toggle Sidebar"
51
52msgid "menu.sidebar.left"
53msgstr "Toggle Left Sidebar"
54
55msgid "menu.sidebar.right"
56msgstr "Toggle Right Sidebar"
57
58msgid "menu.zoom.in"
59msgstr "Zoom In"
60
61msgid "menu.zoom.out"
62msgstr "Zoom Out"
63
64msgid "menu.zoom.reset"
65msgstr "Reset Zoom"
66
67msgid "menu.bookmarks.list"
68msgstr "List All Bookmarks"
69
70msgid "macos.menu.bookmarks.list"
71msgstr "List All"
72
73msgid "menu.bookmarks.bytag"
74msgstr "List Bookmarks by Tag"
75
76msgid "macos.menu.bookmarks.bytag"
77msgstr "List by Tag"
78
79msgid "menu.bookmarks.bytime"
80msgstr "List Bookmarks by Creation Time"
81
82msgid "macos.menu.bookmarks.bytime"
83msgstr "List by Creation Time"
84
85msgid "menu.feeds.entrylist"
86msgstr "Show Feed Entries"
87
88msgid "menu.preferences"
89msgstr "Preferences..."
90
91msgid "menu.help"
92msgstr "Help"
93
94msgid "menu.releasenotes"
95msgstr "Release Notes"
96
97msgid "menu.quit"
98msgstr "Quit Lagrange"
99
100msgid "menu.cut"
101msgstr "Cut"
102
103msgid "menu.copy"
104msgstr "Copy"
105
106msgid "menu.paste"
107msgstr "Paste"
108
109msgid "menu.copy.pagelink"
110msgstr "Copy Link to Page"
111
112msgid "menu.show.bookmarks"
113msgstr "Show Bookmarks"
114
115msgid "menu.show.feeds"
116msgstr "Show Feeds"
117
118msgid "menu.show.history"
119msgstr "Show History"
120
121msgid "menu.show.identities"
122msgstr "Show Identities"
123
124msgid "menu.show.outline"
125msgstr "Show Page Outline"
126
127msgid "menu.back"
128msgstr "Go Back"
129
130msgid "menu.forward"
131msgstr "Go Forward"
132
133msgid "menu.parent"
134msgstr "Go to Parent"
135
136msgid "menu.root"
137msgstr "Go to Root"
138
139msgid "menu.reload"
140msgstr "Reload Page"
141
142msgid "menu.aboutpages"
143msgstr "About Pages"
144
145msgid "menu.debug"
146msgstr "Debug Information"
147
148msgid "menu.bookmark.page"
149msgstr "Bookmark This Page..."
150
151msgid "menu.subscribe.page"
152msgstr "Subscribe to This Page..."
153
154msgid "menu.import.links"
155msgstr "Import All Links on Page..."
156
157msgid "menu.bookmarks.refresh"
158msgstr "Refresh Remote Bookmarks"
159
160msgid "menu.feeds.refresh"
161msgstr "Refresh Feeds"
162
163msgid "menu.identity.new"
164msgstr "New Identity..."
165
166msgid "menu.identity.import"
167msgstr "Import..."
168
169msgid "menu.identity.notactive"
170msgstr "No Active Identity"
171
172msgid "sidebar.bookmarks"
173msgstr "Bookmarks"
174
175msgid "sidebar.feeds"
176msgstr "Feeds"
177
178msgid "sidebar.history"
179msgstr "History"
180
181msgid "sidebar.identities"
182msgstr "Identities"
183
184msgid "sidebar.outline"
185msgstr "Page Outline"
186
187msgid "hint.findtext"
188msgstr "Find text on page"
189
190msgid "status.query"
191msgstr "Search Query"
192
193msgid "status.feeds"
194msgstr "Updating Feeds"
195
196msgid "mb"
197msgstr "MB"
198
199# strftime() formatted, split on two lines
200#, c-format
201msgid "page.timestamp"
202msgstr "Received at %I:%M %p\non %b %d, %Y"
203
diff --git a/res/about/lagrange.gmi b/res/about/lagrange.gmi
index eb70374c..c043d26b 100644
--- a/res/about/lagrange.gmi
+++ b/res/about/lagrange.gmi
@@ -1,4 +1,4 @@
1``` ASCII art: the word "Lagrange" using a large font 1``` ${about.logo}
2ooooo 2ooooo
3`888' 3`888'
4 888 .oooo. .oooooooo oooo d8b .oooo. ooo. .oo. .oooooooo .ooooo. 4 888 .oooo. .oooooooo oooo d8b .oooo. ooo. .oo. .oooooooo .ooooo.
@@ -9,7 +9,7 @@ o888ooooood8 `Y888""8o `8oooooo. d888b `Y888""8o o888o o888o `8oooooo. `Y8b
9 d" YD d" YD 9 d" YD d" YD
10 "Y88888P' "Y88888P' 10 "Y88888P' "Y88888P'
11``` 11```
12# A Beautiful Gemini Client 12# ${about.tagline}
13## Version ${APP_VERSION} 13## ${version} ${APP_VERSION}
14=> https://skyjake.fi/@jk by @jk@skyjake.fi 14=> https://skyjake.fi/@jk by @jk@skyjake.fi
15Powered by SDL 2, OpenSSL, and ☕️ 15${about.powered}
diff --git a/src/app.c b/src/app.c
index 2bf2ad4a..4789c62b 100644
--- a/src/app.c
+++ b/src/app.c
@@ -507,6 +507,7 @@ static void communicateWithRunningInstance_App_(iApp *d, iProcessId instance,
507 507
508static void init_App_(iApp *d, int argc, char **argv) { 508static void init_App_(iApp *d, int argc, char **argv) {
509 init_CommandLine(&d->args, argc, argv); 509 init_CommandLine(&d->args, argc, argv);
510 init_Lang();
510 /* Where was the app started from? We ask SDL first because the command line alone is 511 /* Where was the app started from? We ask SDL first because the command line alone is
511 not a reliable source of this information, particularly when it comes to different 512 not a reliable source of this information, particularly when it comes to different
512 operating systems. */ { 513 operating systems. */ {
@@ -715,6 +716,7 @@ static void deinit_App(iApp *d) {
715 deinit_Ipc(); 716 deinit_Ipc();
716 deinit_SortedArray(&d->tickers); 717 deinit_SortedArray(&d->tickers);
717 deinit_Periodic(&d->periodic); 718 deinit_Periodic(&d->periodic);
719 deinit_Lang();
718 iRecycle(); 720 iRecycle();
719} 721}
720 722
diff --git a/src/defs.h b/src/defs.h
index 27eacd3b..6b76ed71 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -22,6 +22,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include "lang.h"
26
25enum iFileVersion { 27enum iFileVersion {
26 initial_FileVersion = 0, 28 initial_FileVersion = 0,
27 addedResponseTimestamps_FileVersion = 1, 29 addedResponseTimestamps_FileVersion = 1,
@@ -86,7 +88,7 @@ enum iFileVersion {
86/* UI labels that depend on the platform */ 88/* UI labels that depend on the platform */
87 89
88#if defined (iPlatformMobile) 90#if defined (iPlatformMobile)
89# define saveToDownloads_Label "Save to Files" 91# define saveToDownloads_Label "${menu.save.files}"
90#else 92#else
91# define saveToDownloads_Label "Save to Downloads" 93# define saveToDownloads_Label "${menu.save.downloads}"
92#endif 94#endif
diff --git a/src/gmrequest.c b/src/gmrequest.c
index 4631640e..f065f935 100644
--- a/src/gmrequest.c
+++ b/src/gmrequest.c
@@ -395,6 +395,10 @@ static const iBlock *replaceVariables_(const iBlock *block) {
395 repl = range_CStr("Shift+"); 395 repl = range_CStr("Shift+");
396#endif 396#endif
397 } 397 }
398 else {
399 /* Translated string. */
400 repl = range_String(string_Lang(cstr_Rangecc(name)));
401 }
398 remove_Block(replaced, span.start, size_Range(&span)); 402 remove_Block(replaced, span.start, size_Range(&span));
399 insertData_Block(replaced, span.start, repl.start, size_Range(&repl)); 403 insertData_Block(replaced, span.start, repl.start, size_Range(&repl));
400 iZap(m); 404 iZap(m);
diff --git a/src/lang.c b/src/lang.c
new file mode 100644
index 00000000..b5f80fd1
--- /dev/null
+++ b/src/lang.c
@@ -0,0 +1,56 @@
1#include "lang.h"
2
3#include <the_Foundation/sortedarray.h>
4#include <the_Foundation/string.h>
5
6iDeclareType(Lang)
7iDeclareType(MsgStr)
8
9struct Impl_MsgStr {
10 const char *id;
11 iString str;
12};
13
14int cmp_MsgStr_(const void *e1, const void *e2) {
15 const iMsgStr *a = e1, *b = e2;
16 return iCmpStr(a->id, b->id);
17}
18
19/*----------------------------------------------------------------------------------------------*/
20
21struct Impl_Lang {
22 iSortedArray *messages;
23};
24
25static iLang lang_;
26
27void init_Lang(void) {
28 iLang *d = &lang_;
29 d->messages = new_SortedArray(sizeof(iMsgStr), cmp_MsgStr_);
30 setCurrent_Lang("en");
31}
32
33void deinit_Lang(void) {
34 iLang *d = &lang_;
35 delete_SortedArray(d->messages);
36}
37
38void setCurrent_Lang(const char *language) {
39 /* TODO: Load compiled language strings from an embedded blob. */
40}
41
42const iString *string_Lang(const char *msgId) {
43 const iLang *d = &lang_;
44 size_t pos;
45 const iMsgStr key = { .id = msgId };
46 if (locate_SortedArray(d->messages, &key, &pos)) {
47 return &((const iMsgStr *) at_SortedArray(d->messages, pos))->str;
48 }
49 //iAssert(iFalse);
50 fprintf(stderr, "[Lang] missing: %s\n", msgId);
51 return collectNewCStr_String(msgId);
52}
53
54const char *cstr_Lang(const char *msgId) {
55 return cstr_String(string_Lang(msgId));
56}
diff --git a/src/lang.h b/src/lang.h
new file mode 100644
index 00000000..3e9291f2
--- /dev/null
+++ b/src/lang.h
@@ -0,0 +1,10 @@
1#pragma once
2
3#include <the_Foundation/string.h>
4
5void init_Lang (void);
6void deinit_Lang (void);
7
8void setCurrent_Lang (const char *language);
9const iString * string_Lang (const char *msgId);
10const char * cstr_Lang (const char *msgId);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 0b9757d4..685bafd6 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -744,7 +744,7 @@ static void updateTimestampBuf_DocumentWidget_(iDocumentWidget *d) {
744 d->timestampBuf = new_TextBuf( 744 d->timestampBuf = new_TextBuf(
745 uiLabel_FontId, 745 uiLabel_FontId,
746 white_ColorId, 746 white_ColorId,
747 cstrCollect_String(format_Time(&d->sourceTime, "Received at %I:%M %p\non %b %d, %Y"))); 747 cstrCollect_String(format_Time(&d->sourceTime, cstr_Lang("page.timestamp"))));
748 } 748 }
749} 749}
750 750
@@ -856,7 +856,7 @@ static void updateFetchProgress_DocumentWidget_(iDocumentWidget *d) {
856 showCollapsed_Widget(as_Widget(prog), dlSize >= 250000); 856 showCollapsed_Widget(as_Widget(prog), dlSize >= 250000);
857 if (isVisible_Widget(prog)) { 857 if (isVisible_Widget(prog)) {
858 updateText_LabelWidget(prog, 858 updateText_LabelWidget(prog,
859 collectNewFormat_String("%s%.3f MB", 859 collectNewFormat_String("%s%.3f ${mb}",
860 isFinished_GmRequest(d->request) 860 isFinished_GmRequest(d->request)
861 ? uiHeading_ColorEscape 861 ? uiHeading_ColorEscape
862 : uiTextCaution_ColorEscape, 862 : uiTextCaution_ColorEscape,
diff --git a/src/ui/window.c b/src/ui/window.c
index bd2b1493..b8b2853e 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -188,65 +188,65 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) {
188#if !defined (iPlatformAppleMobile) 188#if !defined (iPlatformAppleMobile)
189/* TODO: Submenus wouldn't hurt here. */ 189/* TODO: Submenus wouldn't hurt here. */
190static const iMenuItem navMenuItems_[] = { 190static const iMenuItem navMenuItems_[] = {
191 { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, 191 { add_Icon " ${menu.nav.newtab}", 't', KMOD_PRIMARY, "tabs.new" },
192 { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, 192 { "${menu.nav.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },
193 { "---", 0, 0, NULL }, 193 { "---", 0, 0, NULL },
194 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" }, 194 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },
195 { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" }, 195 { "${menu.copy.source}", SDLK_c, KMOD_PRIMARY, "copy" },
196 { "---", 0, 0, NULL }, 196 { "---", 0, 0, NULL },
197 { leftHalf_Icon " Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 197 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
198 { rightHalf_Icon " Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, 198 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
199 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 199 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
200 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 200 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
201 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 201 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
202 { "---", 0, 0, NULL }, 202 { "---", 0, 0, NULL },
203 { book_Icon " List All Bookmarks", 0, 0, "!open url:about:bookmarks" }, 203 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
204 { "List Bookmarks by Tag", 0, 0, "!open url:about:bookmarks?tags" }, 204 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },
205 { "List Bookmarks by Creation Time", 0, 0, "!open url:about:bookmarks?created" }, 205 { "${menu.bookmarks.bytime}", 0, 0, "!open url:about:bookmarks?created" },
206 { "---", 0, 0, NULL }, 206 { "---", 0, 0, NULL },
207 { "Show Feed Entries", 0, 0, "!open url:about:feeds" }, 207 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },
208 { "---", 0, 0, NULL }, 208 { "---", 0, 0, NULL },
209 { gear_Icon " Preferences...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 209 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
210 { "Help", SDLK_F1, 0, "!open url:about:help" }, 210 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },
211 { "Release Notes", 0, 0, "!open url:about:version" }, 211 { "${menu.releasenotes}", 0, 0, "!open url:about:version" },
212 { "---", 0, 0, NULL }, 212 { "---", 0, 0, NULL },
213 { "Quit Lagrange", 'q', KMOD_PRIMARY, "quit" } 213 { "${menu.quit}", 'q', KMOD_PRIMARY, "quit" }
214}; 214};
215#else 215#else
216/* Tablet menu. */ 216/* Tablet menu. */
217static const iMenuItem tabletNavMenuItems_[] = { 217static const iMenuItem tabletNavMenuItems_[] = {
218 { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, 218 { add_Icon " ${menu.opentab}", 't', KMOD_PRIMARY, "tabs.new" },
219 { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, 219 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },
220 { "---", 0, 0, NULL }, 220 { "---", 0, 0, NULL },
221 { magnifyingGlass_Icon " Find on page", 0, 0, "focus.set id:find.input" }, 221 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },
222 { leftHalf_Icon " Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 222 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
223 { rightHalf_Icon " Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, 223 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
224 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 224 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
225 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 225 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
226 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 226 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
227 { "---", 0, 0, NULL }, 227 { "---", 0, 0, NULL },
228 { book_Icon " List All Bookmarks", 0, 0, "!open url:about:bookmarks" }, 228 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
229 { "List Bookmarks by Tag", 0, 0, "!open url:about:bookmarks?tags" }, 229 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },
230 { "List Feed Entries", 0, 0, "!open url:about:feeds" }, 230 { "${menu.bookmarks.bydate}", 0, 0, "!open url:about:feeds" },
231 { "---", 0, 0, NULL }, 231 { "---", 0, 0, NULL },
232 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 232 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
233 { "Help", SDLK_F1, 0, "!open url:about:help" }, 233 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },
234 { "Release Notes", 0, 0, "!open url:about:version" }, 234 { "${menu.releasenotes}", 0, 0, "!open url:about:version" },
235}; 235};
236 236
237/* Phone menu. */ 237/* Phone menu. */
238static const iMenuItem phoneNavMenuItems_[] = { 238static const iMenuItem phoneNavMenuItems_[] = {
239 { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, 239 { add_Icon " ${menu.opentab}", 't', KMOD_PRIMARY, "tabs.new" },
240 { close_Icon " Close Tab", 'w', KMOD_PRIMARY, "tabs.close" }, 240 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },
241 { "---", 0, 0, NULL }, 241 { "---", 0, 0, NULL },
242 { magnifyingGlass_Icon " Find on page", 0, 0, "focus.set id:find.input" }, 242 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },
243 { leftHalf_Icon " Toggle Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 243 { leftHalf_Icon " ${menu.sidebar}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
244 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 244 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
245 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 245 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
246 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 246 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
247 { "---", 0, 0, NULL }, 247 { "---", 0, 0, NULL },
248 { book_Icon " List All Bookmarks", 0, 0, "!open url:about:bookmarks" }, 248 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
249 { "List Feed Entries", 0, 0, "!open url:about:feeds" }, 249 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },
250 { "---", 0, 0, NULL }, 250 { "---", 0, 0, NULL },
251 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 251 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
252}; 252};
@@ -256,69 +256,69 @@ static const iMenuItem phoneNavMenuItems_[] = {
256#if defined (iHaveNativeMenus) 256#if defined (iHaveNativeMenus)
257/* Using native menus. */ 257/* Using native menus. */
258static const iMenuItem fileMenuItems_[] = { 258static const iMenuItem fileMenuItems_[] = {
259 { "New Tab", SDLK_t, KMOD_PRIMARY, "tabs.new" }, 259 { "${menu.newtab}", SDLK_t, KMOD_PRIMARY, "tabs.new" },
260 { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, 260 { "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },
261 { "---", 0, 0, NULL }, 261 { "---", 0, 0, NULL },
262 { saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" }, 262 { saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },
263}; 263};
264 264
265static const iMenuItem editMenuItems_[] = { 265static const iMenuItem editMenuItems_[] = {
266 { "Cut", SDLK_x, KMOD_PRIMARY, "input.copy cut:1" }, 266 { "${menu.cut}", SDLK_x, KMOD_PRIMARY, "input.copy cut:1" },
267 { "Copy", SDLK_c, KMOD_PRIMARY, "copy" }, 267 { "${menu.copy}", SDLK_c, KMOD_PRIMARY, "copy" },
268 { "Paste", SDLK_v, KMOD_PRIMARY, "input.paste" }, 268 { "${menu.paste}", SDLK_v, KMOD_PRIMARY, "input.paste" },
269 { "---", 0, 0, NULL }, 269 { "---", 0, 0, NULL },
270 { "Copy Link to Page", SDLK_c, KMOD_PRIMARY | KMOD_SHIFT, "document.copylink" }, 270 { "${menu.copy.pagelink}", SDLK_c, KMOD_PRIMARY | KMOD_SHIFT, "document.copylink" },
271 { "---", 0, 0, NULL }, 271 { "---", 0, 0, NULL },
272 { "Find", SDLK_f, KMOD_PRIMARY, "focus.set id:find.input" }, 272 { "${macos.menu.find}", SDLK_f, KMOD_PRIMARY, "focus.set id:find.input" },
273}; 273};
274 274
275static const iMenuItem viewMenuItems_[] = { 275static const iMenuItem viewMenuItems_[] = {
276 { "Show Bookmarks", '1', KMOD_PRIMARY, "sidebar.mode arg:0 toggle:1" }, 276 { "${menu.show.bookmarks}", '1', KMOD_PRIMARY, "sidebar.mode arg:0 toggle:1" },
277 { "Show Feeds", '2', KMOD_PRIMARY, "sidebar.mode arg:1 toggle:1" }, 277 { "${menu.show.feeds}", '2', KMOD_PRIMARY, "sidebar.mode arg:1 toggle:1" },
278 { "Show History", '3', KMOD_PRIMARY, "sidebar.mode arg:2 toggle:1" }, 278 { "${menu.show.history}", '3', KMOD_PRIMARY, "sidebar.mode arg:2 toggle:1" },
279 { "Show Identities", '4', KMOD_PRIMARY, "sidebar.mode arg:3 toggle:1" }, 279 { "${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 toggle:1" },
280 { "Show Page Outline", '5', KMOD_PRIMARY, "sidebar.mode arg:4 toggle:1" }, 280 { "${menu.show.outline}", '5', KMOD_PRIMARY, "sidebar.mode arg:4 toggle:1" },
281 { "Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 281 { "${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
282 { "Toggle Right Sidebar", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, 282 { "${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
283 { "---", 0, 0, NULL }, 283 { "---", 0, 0, NULL },
284 { "Go Back", SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" }, 284 { "${menu.back}", SDLK_LEFTBRACKET, KMOD_PRIMARY, "navigate.back" },
285 { "Go Forward", SDLK_RIGHTBRACKET, KMOD_PRIMARY, "navigate.forward" }, 285 { "${menu.forward}", SDLK_RIGHTBRACKET, KMOD_PRIMARY, "navigate.forward" },
286 { "Go to Parent", navigateParent_KeyShortcut, "navigate.parent" }, 286 { "${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },
287 { "Go to Root", navigateRoot_KeyShortcut, "navigate.root" }, 287 { "${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },
288 { "Reload Page", reload_KeyShortcut, "navigate.reload" }, 288 { "${menu.reload}", reload_KeyShortcut, "navigate.reload" },
289 { "---", 0, 0, NULL }, 289 { "---", 0, 0, NULL },
290 { "Zoom In", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 290 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
291 { "Zoom Out", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 291 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
292 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 292 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
293}; 293};
294 294
295static iMenuItem bookmarksMenuItems_[] = { 295static iMenuItem bookmarksMenuItems_[] = {
296 { "Bookmark This Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, 296 { "${menu.bookmark.page}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
297 { "Subscribe to This Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, 297 { "${menu.subscribe.page}", subscribeToPage_KeyModifier, "feeds.subscribe" },
298 { "---", 0, 0, NULL }, 298 { "---", 0, 0, NULL },
299 { "Import All Links on Page...", 0, 0, "bookmark.links confirm:1" }, 299 { "${menu.import.links}", 0, 0, "bookmark.links confirm:1" },
300 { "---", 0, 0, NULL }, 300 { "---", 0, 0, NULL },
301 { "List All", 0, 0, "open url:about:bookmarks" }, 301 { "${macos.menu.bookmarks.list}", 0, 0, "open url:about:bookmarks" },
302 { "List by Tag", 0, 0, "open url:about:bookmarks?tags" }, 302 { "${macos.menu.bookmarks.bytag}", 0, 0, "open url:about:bookmarks?tags" },
303 { "List by Creation Time", 0, 0, "open url:about:bookmarks?created" }, 303 { "${macos.menu.bookmarks.bytime}", 0, 0, "open url:about:bookmarks?created" },
304 { "Show Feed Entries", 0, 0, "open url:about:feeds" }, 304 { "${menu.feeds.entrylist}", 0, 0, "open url:about:feeds" },
305 { "---", 0, 0, NULL }, 305 { "---", 0, 0, NULL },
306 { "Refresh Remote Bookmarks", 0, 0, "bookmarks.reload.remote" }, 306 { "${menu.bookmarks.refresh}", 0, 0, "bookmarks.reload.remote" },
307 { "Refresh Feeds", SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh" }, 307 { "${menu.feeds.refresh}", SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh" },
308}; 308};
309 309
310static const iMenuItem identityMenuItems_[] = { 310static const iMenuItem identityMenuItems_[] = {
311 { "New Identity...", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" }, 311 { "${menu.identity.new}", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" },
312 { "---", 0, 0, NULL }, 312 { "---", 0, 0, NULL },
313 { "Import...", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, 313 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },
314}; 314};
315 315
316static const iMenuItem helpMenuItems_[] = { 316static const iMenuItem helpMenuItems_[] = {
317 { "Help", 0, 0, "!open url:about:help" }, 317 { "${menu.help}", 0, 0, "!open url:about:help" },
318 { "Release Notes", 0, 0, "!open url:about:version" }, 318 { "${menu.releasenotes}", 0, 0, "!open url:about:version" },
319 { "---", 0, 0, NULL }, 319 { "---", 0, 0, NULL },
320 { "About Pages", 0, 0, "!open url:about:about" }, 320 { "${menu.aboutpages}", 0, 0, "!open url:about:about" },
321 { "Debug Information", 0, 0, "!open url:about:debug" }, 321 { "${menu.debug}", 0, 0, "!open url:about:debug" },
322}; 322};
323#endif 323#endif
324 324
@@ -333,17 +333,17 @@ static const iMenuItem identityButtonMenuItems_[] = {
333}; 333};
334#else /* desktop */ 334#else /* desktop */
335static const iMenuItem identityButtonMenuItems_[] = { 335static const iMenuItem identityButtonMenuItems_[] = {
336 { "No Active Identity", 0, 0, "ident.showactive" }, 336 { "${menu.identity.notactive}", 0, 0, "ident.showactive" },
337 { "---", 0, 0, NULL }, 337 { "---", 0, 0, NULL },
338# if !defined (iHaveNativeMenus) 338# if !defined (iHaveNativeMenus)
339 { add_Icon " New Identity...", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" }, 339 { add_Icon " ${menu.identity.new}", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" },
340 { "Import...", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, 340 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },
341 { "---", 0, 0, NULL }, 341 { "---", 0, 0, NULL },
342 { person_Icon " Show Identities", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" }, 342 { person_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" },
343# else 343# else
344 { add_Icon " New Identity...", 0, 0, "ident.new" }, 344 { add_Icon " ${menu.identity.new}", 0, 0, "ident.new" },
345 { "---", 0, 0, NULL }, 345 { "---", 0, 0, NULL },
346 { person_Icon " Show Identities", 0, 0, "sidebar.mode arg:3 show:1" }, 346 { person_Icon " ${menu.show.identities}", 0, 0, "sidebar.mode arg:3 show:1" },
347#endif 347#endif
348}; 348};
349#endif 349#endif
@@ -443,7 +443,7 @@ static void updateNavBarIdentity_(iWidget *navBar) {
443 idItem, 443 idItem,
444 ident ? format_CStr(uiTextAction_ColorEscape "%s", 444 ident ? format_CStr(uiTextAction_ColorEscape "%s",
445 cstrCollect_String(subject_TlsCertificate(ident->cert))) 445 cstrCollect_String(subject_TlsCertificate(ident->cert)))
446 : "No Active Identity"); 446 : "${menu.identity.notactive}");
447 setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident); 447 setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident);
448} 448}
449 449
@@ -998,7 +998,7 @@ static void setupUserInterface_Window(iWindow *d) {
998 moveToParentRightEdge_WidgetFlag); 998 moveToParentRightEdge_WidgetFlag);
999 /* Feeds refresh indicator is inside the input field. */ { 999 /* Feeds refresh indicator is inside the input field. */ {
1000 iLabelWidget *queryInd = 1000 iLabelWidget *queryInd =
1001 new_LabelWidget(uiTextAction_ColorEscape "\u21d2 Search Query", NULL); 1001 new_LabelWidget(uiTextAction_ColorEscape "\u21d2 ${status.query}", NULL);
1002 setId_Widget(as_Widget(queryInd), "input.indicator.search"); 1002 setId_Widget(as_Widget(queryInd), "input.indicator.search");
1003 setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); 1003 setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId);
1004 setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); 1004 setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId);
@@ -1009,7 +1009,7 @@ static void setupUserInterface_Window(iWindow *d) {
1009 } 1009 }
1010 /* Feeds refresh indicator is inside the input field. */ { 1010 /* Feeds refresh indicator is inside the input field. */ {
1011 iLabelWidget *fprog = new_LabelWidget(uiTextCaution_ColorEscape 1011 iLabelWidget *fprog = new_LabelWidget(uiTextCaution_ColorEscape
1012 "\u2605 Updating Feeds", NULL); 1012 "\u2605 ${status.feeds}", NULL);
1013 setId_Widget(as_Widget(fprog), "feeds.progress"); 1013 setId_Widget(as_Widget(fprog), "feeds.progress");
1014 setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId); 1014 setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId);
1015 setAlignVisually_LabelWidget(fprog, iTrue); 1015 setAlignVisually_LabelWidget(fprog, iTrue);
@@ -1018,7 +1018,7 @@ static void setupUserInterface_Window(iWindow *d) {
1018 collapse_WidgetFlag | hidden_WidgetFlag); 1018 collapse_WidgetFlag | hidden_WidgetFlag);
1019 } 1019 }
1020 /* Download progress indicator is also inside the input field, but hidden normally. */ { 1020 /* Download progress indicator is also inside the input field, but hidden normally. */ {
1021 iLabelWidget *progress = new_LabelWidget(uiTextCaution_ColorEscape "00.000 MB", NULL); 1021 iLabelWidget *progress = new_LabelWidget(uiTextCaution_ColorEscape "00.000 ${mb}", NULL);
1022 setId_Widget(as_Widget(progress), "document.progress"); 1022 setId_Widget(as_Widget(progress), "document.progress");
1023 setBackgroundColor_Widget(as_Widget(progress), uiBackground_ColorId); 1023 setBackgroundColor_Widget(as_Widget(progress), uiBackground_ColorId);
1024 setAlignVisually_LabelWidget(progress, iTrue); 1024 setAlignVisually_LabelWidget(progress, iTrue);
@@ -1122,7 +1122,7 @@ static void setupUserInterface_Window(iWindow *d) {
1122 addChildFlags_Widget( 1122 addChildFlags_Widget(
1123 searchBar, iClob(new_LabelWidget(magnifyingGlass_Icon, NULL)), frameless_WidgetFlag); 1123 searchBar, iClob(new_LabelWidget(magnifyingGlass_Icon, NULL)), frameless_WidgetFlag);
1124 iInputWidget *input = new_InputWidget(0); 1124 iInputWidget *input = new_InputWidget(0);
1125 setHint_InputWidget(input, "Find text on page"); 1125 setHint_InputWidget(input, "${hint.findtext}");
1126 setSelectAllOnFocus_InputWidget(input, iTrue); 1126 setSelectAllOnFocus_InputWidget(input, iTrue);
1127 setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ 1127 setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */
1128 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), 1128 setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag),
@@ -1159,10 +1159,10 @@ static void setupUserInterface_Window(iWindow *d) {
1159// setBackgroundColor_Widget(i.object, tmBannerSideTitle_ColorId); 1159// setBackgroundColor_Widget(i.object, tmBannerSideTitle_ColorId);
1160 } 1160 }
1161 const iMenuItem items[] = { 1161 const iMenuItem items[] = {
1162 { pin_Icon " Bookmarks", 0, 0, "toolbar.showview arg:0" }, 1162 { pin_Icon " ${sidebar.bookmarks}", 0, 0, "toolbar.showview arg:0" },
1163 { star_Icon " Feeds", 0, 0, "toolbar.showview arg:1" }, 1163 { star_Icon " ${sidebar.feeds}", 0, 0, "toolbar.showview arg:1" },
1164 { clock_Icon " History", 0, 0, "toolbar.showview arg:2" }, 1164 { clock_Icon " ${sidebar.history}", 0, 0, "toolbar.showview arg:2" },
1165 { page_Icon " Page Outline", 0, 0, "toolbar.showview arg:4" }, 1165 { page_Icon " ${sidebar.outline}", 0, 0, "toolbar.showview arg:4" },
1166 }; 1166 };
1167 iWidget *menu = makeMenu_Widget(findChild_Widget(toolBar, "toolbar.view"), 1167 iWidget *menu = makeMenu_Widget(findChild_Widget(toolBar, "toolbar.view"),
1168 items, iElemCount(items)); 1168 items, iElemCount(items));
@@ -1174,27 +1174,27 @@ static void setupUserInterface_Window(iWindow *d) {
1174 iWidget *tabsMenu = makeMenu_Widget( 1174 iWidget *tabsMenu = makeMenu_Widget(
1175 d->root, 1175 d->root,
1176 (iMenuItem[]){ 1176 (iMenuItem[]){
1177 { close_Icon " Close Tab", 0, 0, "tabs.close" }, 1177 { close_Icon " ${menu.closetab}", 0, 0, "tabs.close" },
1178 { copy_Icon " Duplicate Tab", 0, 0, "tabs.new duplicate:1" }, 1178 { copy_Icon " ${menu.duptab}", 0, 0, "tabs.new duplicate:1" },
1179 { "---", 0, 0, NULL }, 1179 { "---", 0, 0, NULL },
1180 { "Close Other Tabs", 0, 0, "tabs.close toleft:1 toright:1" }, 1180 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" },
1181 { barLeftArrow_Icon " Close Tabs To Left", 0, 0, "tabs.close toleft:1" }, 1181 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" },
1182 { barRightArrow_Icon " Close Tabs To Right", 0, 0, "tabs.close toright:1" }, 1182 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" },
1183 }, 1183 },
1184 6); 1184 6);
1185 iWidget *barMenu = 1185 iWidget *barMenu =
1186 makeMenu_Widget(d->root, 1186 makeMenu_Widget(d->root,
1187 (iMenuItem[]){ 1187 (iMenuItem[]){
1188 { leftHalf_Icon " Toggle Left Sidebar", 0, 0, "sidebar.toggle" }, 1188 { leftHalf_Icon " ${menu.sidebar.left}", 0, 0, "sidebar.toggle" },
1189 { rightHalf_Icon " Toggle Right Sidebar", 0, 0, "sidebar2.toggle" }, 1189 { rightHalf_Icon " ${menu.sidebar.right}", 0, 0, "sidebar2.toggle" },
1190 }, 1190 },
1191 deviceType_App() == phone_AppDeviceType ? 1 : 2); 1191 deviceType_App() == phone_AppDeviceType ? 1 : 2);
1192 iWidget *clipMenu = makeMenu_Widget(d->root, 1192 iWidget *clipMenu = makeMenu_Widget(d->root,
1193 (iMenuItem[]){ 1193 (iMenuItem[]){
1194 { scissor_Icon " Cut", 0, 0, "input.copy cut:1" }, 1194 { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },
1195 { clipCopy_Icon " Copy", 0, 0, "input.copy" }, 1195 { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },
1196 { "---", 0, 0, NULL }, 1196 { "---", 0, 0, NULL },
1197 { clipboard_Icon " Paste", 0, 0, "input.paste" }, 1197 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },
1198 }, 1198 },
1199 4); 1199 4);
1200 setId_Widget(tabsMenu, "doctabs.menu"); 1200 setId_Widget(tabsMenu, "doctabs.menu");