summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c251
1 files changed, 131 insertions, 120 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 685bafd6..6ce53e44 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -824,9 +824,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
824 iString *key = collectNew_String(); 824 iString *key = collectNew_String();
825 toString_Sym(SDLK_s, KMOD_PRIMARY, key); 825 toString_Sym(SDLK_s, KMOD_PRIMARY, key);
826 appendFormat_String(src, 826 appendFormat_String(src,
827 "\n```\n%s\n```\n" 827 cstr_Lang("error.unsupported.suggestsave"),
828 "You can save it as a file to your Downloads folder, though. "
829 "Press %s or select \"%s\" from the menu.",
830 cstr_String(meta), 828 cstr_String(meta),
831 cstr_String(key), 829 cstr_String(key),
832 saveToDownloads_Label); 830 saveToDownloads_Label);
@@ -1045,7 +1043,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
1045 updateTrust_DocumentWidget_(d, resp); 1043 updateTrust_DocumentWidget_(d, resp);
1046 d->sourceTime = resp->when; 1044 d->sourceTime = resp->when;
1047 d->sourceStatus = success_GmStatusCode; 1045 d->sourceStatus = success_GmStatusCode;
1048 format_String(&d->sourceHeader, "(cached content)"); 1046 format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached"));
1049 updateTimestampBuf_DocumentWidget_(d); 1047 updateTimestampBuf_DocumentWidget_(d);
1050 set_Block(&d->sourceContent, &resp->body); 1048 set_Block(&d->sourceContent, &resp->body);
1051 updateDocument_DocumentWidget_(d, resp, iTrue); 1049 updateDocument_DocumentWidget_(d, resp, iTrue);
@@ -1220,9 +1218,9 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
1220 NULL, 1218 NULL,
1221 format_CStr(uiHeading_ColorEscape "%s", cstr_Rangecc(parts.host)), 1219 format_CStr(uiHeading_ColorEscape "%s", cstr_Rangecc(parts.host)),
1222 isEmpty_String(&resp->meta) 1220 isEmpty_String(&resp->meta)
1223 ? format_CStr("Please enter input for %s:", cstr_Rangecc(parts.path)) 1221 ? format_CStr(cstr_Lang("dlg.input.prompt"), cstr_Rangecc(parts.path))
1224 : cstr_String(&resp->meta), 1222 : cstr_String(&resp->meta),
1225 uiTextCaution_ColorEscape "Send \u21d2", 1223 uiTextCaution_ColorEscape "${dlg.input.send} \u21d2",
1226 format_CStr("!document.input.submit doc:%p", d)); 1224 format_CStr("!document.input.submit doc:%p", d));
1227 setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"), 1225 setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"),
1228 statusCode == sensitiveInput_GmStatusCode); 1226 statusCode == sensitiveInput_GmStatusCode);
@@ -1469,14 +1467,14 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo
1469#if defined (iPlatformAppleMobile) 1467#if defined (iPlatformAppleMobile)
1470 exportDownloadedFile_iOS(savePath); 1468 exportDownloadedFile_iOS(savePath);
1471#else 1469#else
1472 makeMessage_Widget(uiHeading_ColorEscape "FILE SAVED", 1470 makeMessage_Widget(uiHeading_ColorEscape "${heading.save}",
1473 format_CStr("%s\nSize: %.3f %s", cstr_String(path_File(f)), 1471 format_CStr("%s\n${dlg.save.size} %.3f %s", cstr_String(path_File(f)),
1474 isMega ? size / 1.0e6f : (size / 1.0e3f), 1472 isMega ? size / 1.0e6f : (size / 1.0e3f),
1475 isMega ? "MB" : "KB")); 1473 isMega ? "${mb}" : "${kb}"));
1476#endif 1474#endif
1477 } 1475 }
1478 else { 1476 else {
1479 makeMessage_Widget(uiTextCaution_ColorEscape "ERROR SAVING FILE", 1477 makeMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}",
1480 strerror(errno)); 1478 strerror(errno));
1481 } 1479 }
1482 iRelease(f); 1480 iRelease(f);
@@ -1625,57 +1623,62 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1625 } 1623 }
1626 iString *msg = collectNew_String(); 1624 iString *msg = collectNew_String();
1627 if (isEmpty_String(&d->sourceHeader)) { 1625 if (isEmpty_String(&d->sourceHeader)) {
1628 appendFormat_String(msg, "%s\n%zu bytes\n", cstr_String(meta), size_Block(&d->sourceContent)); 1626 appendFormat_String(msg, "%s\n%zu ${bytes}\n", cstr_String(meta), size_Block(&d->sourceContent));
1629 } 1627 }
1630 else { 1628 else {
1631 appendFormat_String(msg, "%s\n", cstr_String(&d->sourceHeader)); 1629 appendFormat_String(msg, "%s\n", cstr_String(&d->sourceHeader));
1632 if (size_Block(&d->sourceContent)) { 1630 if (size_Block(&d->sourceContent)) {
1633 appendFormat_String(msg, "%zu bytes\n", size_Block(&d->sourceContent)); 1631 appendFormat_String(msg, "%zu ${bytes}\n", size_Block(&d->sourceContent));
1634 } 1632 }
1635 } 1633 }
1636 appendFormat_String(msg, 1634 appendFormat_String(
1637 "\n%sCertificate Status:\n" 1635 msg,
1638 "%s%s %s by CA\n" 1636 "\n%s${pageinfo.cert.status}\n"
1639 "%s%s Domain name %s%s\n" 1637 "%s%s %s\n"
1640 "%s%s %s (%04d-%02d-%02d %02d:%02d:%02d)\n" 1638 "%s%s %s%s\n"
1641 "%s%s %s", 1639 "%s%s %s (%04d-%02d-%02d %02d:%02d:%02d)\n"
1642 uiHeading_ColorEscape, 1640 "%s%s %s",
1643 d->certFlags & authorityVerified_GmCertFlag ? 1641 uiHeading_ColorEscape,
1644 checked : uiTextAction_ColorEscape "\u2610", 1642 d->certFlags & authorityVerified_GmCertFlag ? checked
1645 uiText_ColorEscape, 1643 : uiTextAction_ColorEscape "\u2610",
1646 d->certFlags & authorityVerified_GmCertFlag ? "Verified" : "Not verified", 1644 uiText_ColorEscape,
1647 d->certFlags & domainVerified_GmCertFlag ? checked : unchecked, 1645 d->certFlags & authorityVerified_GmCertFlag ? "${pageinfo.cert.ca.verified}"
1648 uiText_ColorEscape, 1646 : "${pageinfo.cert.ca.unverified}",
1649 d->certFlags & domainVerified_GmCertFlag ? "matches" : "mismatch", 1647 d->certFlags & domainVerified_GmCertFlag ? checked : unchecked,
1650 ~d->certFlags & domainVerified_GmCertFlag 1648 uiText_ColorEscape,
1651 ? format_CStr(" (%s)", cstr_String(d->certSubject)) 1649 d->certFlags & domainVerified_GmCertFlag ? "${pageinfo.domain.match}"
1652 : "", 1650 : "${pageinfo.domain.mismatch}",
1653 d->certFlags & timeVerified_GmCertFlag ? checked : unchecked, 1651 ~d->certFlags & domainVerified_GmCertFlag
1654 uiText_ColorEscape, 1652 ? format_CStr(" (%s)", cstr_String(d->certSubject))
1655 d->certFlags & timeVerified_GmCertFlag ? "Not expired" : "Expired", 1653 : "",
1656 d->certExpiry.year, 1654 d->certFlags & timeVerified_GmCertFlag ? checked : unchecked,
1657 d->certExpiry.month, 1655 uiText_ColorEscape,
1658 d->certExpiry.day, 1656 d->certFlags & timeVerified_GmCertFlag ? "${pageinfo.cert.notexpired}"
1659 d->certExpiry.hour, 1657 : "${pageinfo.cert.expired}",
1660 d->certExpiry.minute, 1658 d->certExpiry.year,
1661 d->certExpiry.second, 1659 d->certExpiry.month,
1662 d->certFlags & trusted_GmCertFlag ? checked : unchecked, 1660 d->certExpiry.day,
1663 uiText_ColorEscape, 1661 d->certExpiry.hour,
1664 d->certFlags & trusted_GmCertFlag ? "Trusted" : "Not trusted"); 1662 d->certExpiry.minute,
1663 d->certExpiry.second,
1664 d->certFlags & trusted_GmCertFlag ? checked : unchecked,
1665 uiText_ColorEscape,
1666 d->certFlags & trusted_GmCertFlag ? "${pageinfo.cert.trusted}"
1667 : "${pageinfo.cert.untrusted}");
1665 setFocus_Widget(NULL); 1668 setFocus_Widget(NULL);
1666 iArray *items = new_Array(sizeof(iMenuItem)); 1669 iArray *items = new_Array(sizeof(iMenuItem));
1667 if (canTrust) { 1670 if (canTrust) {
1668 pushBack_Array( 1671 pushBack_Array(
1669 items, &(iMenuItem){ uiTextCaution_ColorEscape "Trust", 0, 0, "server.trustcert" }); 1672 items, &(iMenuItem){ uiTextCaution_ColorEscape "${dlg.cert.trust}", 0, 0, "server.trustcert" });
1670 } 1673 }
1671 if (haveFingerprint) { 1674 if (haveFingerprint) {
1672 pushBack_Array(items, &(iMenuItem){ "Copy Fingerprint", 0, 0, "server.copycert" }); 1675 pushBack_Array(items, &(iMenuItem){ "${dlg.cert.fingerprint}", 0, 0, "server.copycert" });
1673 } 1676 }
1674 if (!isEmpty_Array(items)) { 1677 if (!isEmpty_Array(items)) {
1675 pushBack_Array(items, &(iMenuItem){ "---", 0, 0, 0 }); 1678 pushBack_Array(items, &(iMenuItem){ "---", 0, 0, 0 });
1676 } 1679 }
1677 pushBack_Array(items, &(iMenuItem){ "Dismiss", 0, 0, "message.ok" }); 1680 pushBack_Array(items, &(iMenuItem){ "${dismiss}", 0, 0, "message.ok" });
1678 iWidget *dlg = makeQuestion_Widget(uiHeading_ColorEscape "PAGE INFORMATION", 1681 iWidget *dlg = makeQuestion_Widget(uiHeading_ColorEscape "${heading.pageinfo}",
1679 cstr_String(msg), 1682 cstr_String(msg),
1680 data_Array(items), 1683 data_Array(items),
1681 size_Array(items)); 1684 size_Array(items));
@@ -1871,8 +1874,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1871 } 1874 }
1872 else if (equal_Command(cmd, "document.save") && document_App() == d) { 1875 else if (equal_Command(cmd, "document.save") && document_App() == d) {
1873 if (d->request) { 1876 if (d->request) {
1874 makeMessage_Widget(uiTextCaution_ColorEscape "PAGE INCOMPLETE", 1877 makeMessage_Widget(uiTextCaution_ColorEscape "${heading.save.incomplete}",
1875 "The page contents are still being downloaded."); 1878 "${dlg.save.incomplete}");
1876 } 1879 }
1877 else if (!isEmpty_Block(&d->sourceContent)) { 1880 else if (!isEmpty_Block(&d->sourceContent)) {
1878 saveToDownloads_(d->mod.url, &d->sourceMime, &d->sourceContent); 1881 saveToDownloads_(d->mod.url, &d->sourceMime, &d->sourceContent);
@@ -2077,14 +2080,20 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2077 } 2080 }
2078 if (!isEmpty_PtrArray(links)) { 2081 if (!isEmpty_PtrArray(links)) {
2079 if (argLabel_Command(cmd, "confirm")) { 2082 if (argLabel_Command(cmd, "confirm")) {
2080 const char *plural = size_PtrArray(links) != 1 ? "s" : ""; 2083 //const char *plural = size_PtrArray(links) != 1 ? "s" : "";
2084 const iBool isPlural = size_PtrArray(links) != 1;
2081 makeQuestion_Widget( 2085 makeQuestion_Widget(
2082 uiHeading_ColorEscape "IMPORT BOOKMARKS", 2086 uiHeading_ColorEscape "${heading.import.bookmarks}",
2083 format_CStr("Found %d new link%s on the page.", size_PtrArray(links), plural), 2087 format_CStr(cstr_Lang(isPlural ? "dlg.import.found.many" : "dlg.import.found"),
2084 (iMenuItem[]){ { "Cancel", 0, 0, NULL }, 2088 size_PtrArray(links)),
2085 { format_CStr(uiTextAction_ColorEscape "Add %d Bookmark%s", 2089 (iMenuItem[]){
2086 size_PtrArray(links), 2090 { "${cancel}", 0, 0, NULL },
2087 plural), 0, 0, "bookmark.links" } }, 2091 { format_CStr(isPlural ? "dlg.import.add.many" : "dlg.import.add",
2092 uiTextAction_ColorEscape,
2093 size_PtrArray(links)),
2094 0,
2095 0,
2096 "bookmark.links" } },
2088 2); 2097 2);
2089 } 2098 }
2090 else { 2099 else {
@@ -2100,8 +2109,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2100 } 2109 }
2101 } 2110 }
2102 else { 2111 else {
2103 makeMessage_Widget(uiHeading_ColorEscape "IMPORT BOOKMARKS", 2112 makeMessage_Widget(uiHeading_ColorEscape "${heading.import.bookmarks}",
2104 "All links on this page are already bookmarked."); 2113 "${dlg.import.notnew}");
2105 } 2114 }
2106 return iTrue; 2115 return iTrue;
2107 } 2116 }
@@ -2117,9 +2126,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2117 } 2126 }
2118 } 2127 }
2119 else if (equal_Command(cmd, "document.autoreload.menu") && document_App() == d) { 2128 else if (equal_Command(cmd, "document.autoreload.menu") && document_App() == d) {
2120 iWidget *dlg = makeQuestion_Widget(uiTextAction_ColorEscape "AUTO-RELOAD", 2129 iWidget *dlg = makeQuestion_Widget(uiTextAction_ColorEscape "${heading.autoreload}",
2121 "Select the auto-reload interval for this tab.", 2130 "${dlg.autoreload}",
2122 (iMenuItem[]){ { "Cancel", 0, 0, NULL } }, 2131 (iMenuItem[]){ { "${cancel}", 0, 0, NULL } },
2123 1); 2132 1);
2124 for (int i = 0; i < max_ReloadInterval; ++i) { 2133 for (int i = 0; i < max_ReloadInterval; ++i) {
2125 insertChildAfterFlags_Widget( 2134 insertChildAfterFlags_Widget(
@@ -2454,7 +2463,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2454 init_Array(&items, sizeof(iMenuItem)); 2463 init_Array(&items, sizeof(iMenuItem));
2455 if (d->contextLink) { 2464 if (d->contextLink) {
2456 const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); 2465 const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId);
2457 const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); 2466// const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId);
2458 const iRangecc scheme = urlScheme_String(linkUrl); 2467 const iRangecc scheme = urlScheme_String(linkUrl);
2459 const iBool isGemini = equalCase_Rangecc(scheme, "gemini"); 2468 const iBool isGemini = equalCase_Rangecc(scheme, "gemini");
2460 iBool isNative = iFalse; 2469 iBool isNative = iFalse;
@@ -2466,11 +2475,11 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2466 pushBackN_Array( 2475 pushBackN_Array(
2467 &items, 2476 &items,
2468 (iMenuItem[]){ 2477 (iMenuItem[]){
2469 { openTab_Icon " Open Link in New Tab", 2478 { openTab_Icon " ${link.newtab}",
2470 0, 2479 0,
2471 0, 2480 0,
2472 format_CStr("!open newtab:1 url:%s", cstr_String(linkUrl)) }, 2481 format_CStr("!open newtab:1 url:%s", cstr_String(linkUrl)) },
2473 { openTabBg_Icon " Open Link in Background Tab", 2482 { openTabBg_Icon " ${link.newtab.background}",
2474 0, 2483 0,
2475 0, 2484 0,
2476 format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) } }, 2485 format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) } },
@@ -2479,7 +2488,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2479 else if (!willUseProxy_App(scheme)) { 2488 else if (!willUseProxy_App(scheme)) {
2480 pushBack_Array( 2489 pushBack_Array(
2481 &items, 2490 &items,
2482 &(iMenuItem){ openExt_Icon " Open Link in Default Browser", 2491 &(iMenuItem){ openExt_Icon " ${link.browser}",
2483 0, 2492 0,
2484 0, 2493 0,
2485 format_CStr("!open default:1 url:%s", cstr_String(linkUrl)) }); 2494 format_CStr("!open default:1 url:%s", cstr_String(linkUrl)) });
@@ -2489,7 +2498,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2489 &items, 2498 &items,
2490 (iMenuItem[]){ 2499 (iMenuItem[]){
2491 { "---", 0, 0, NULL }, 2500 { "---", 0, 0, NULL },
2492 { isGemini ? "Open without Proxy" : openExt_Icon " Open Link in Default Browser", 2501 { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}",
2493 0, 2502 0,
2494 0, 2503 0,
2495 format_CStr("!open noproxy:1 url:%s", cstr_String(linkUrl)) } }, 2504 format_CStr("!open noproxy:1 url:%s", cstr_String(linkUrl)) } },
@@ -2500,8 +2509,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2500 urlEncodeSpaces_String(linkLabel); 2509 urlEncodeSpaces_String(linkLabel);
2501 pushBackN_Array(&items, 2510 pushBackN_Array(&items,
2502 (iMenuItem[]){ { "---", 0, 0, NULL }, 2511 (iMenuItem[]){ { "---", 0, 0, NULL },
2503 { "Copy Link", 0, 0, "document.copylink" }, 2512 { "${link.copy}", 0, 0, "document.copylink" },
2504 { pin_Icon " Bookmark Link...", 2513 { pin_Icon " ${link.bookmark}",
2505 0, 2514 0,
2506 0, 2515 0,
2507 format_CStr("!bookmark.add title:%s url:%s", 2516 format_CStr("!bookmark.add title:%s url:%s",
@@ -2512,7 +2521,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2512 if (isNative && d->contextLink->mediaType != download_GmRunMediaType) { 2521 if (isNative && d->contextLink->mediaType != download_GmRunMediaType) {
2513 pushBackN_Array(&items, (iMenuItem[]){ 2522 pushBackN_Array(&items, (iMenuItem[]){
2514 { "---", 0, 0, NULL }, 2523 { "---", 0, 0, NULL },
2515 { download_Icon " Download Linked File", 0, 0, "document.downloadlink" }, 2524 { download_Icon " ${link.download}", 0, 0, "document.downloadlink" },
2516 }, 2); 2525 }, 2);
2517 } 2526 }
2518 iMediaRequest *mediaReq; 2527 iMediaRequest *mediaReq;
@@ -2532,39 +2541,39 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2532 if (!isEmpty_Range(&d->selectMark)) { 2541 if (!isEmpty_Range(&d->selectMark)) {
2533 pushBackN_Array( 2542 pushBackN_Array(
2534 &items, 2543 &items,
2535 (iMenuItem[]){ { "Copy", 0, 0, "copy" }, { "---", 0, 0, NULL } }, 2544 (iMenuItem[]){ { "${menu.copy}", 0, 0, "copy" }, { "---", 0, 0, NULL } },
2536 2); 2545 2);
2537 } 2546 }
2538 if (deviceType_App() == desktop_AppDeviceType) { 2547 if (deviceType_App() == desktop_AppDeviceType) {
2539 pushBackN_Array( 2548 pushBackN_Array(
2540 &items, 2549 &items,
2541 (iMenuItem[]){ 2550 (iMenuItem[]){
2542 { "Go Back", navigateBack_KeyShortcut, "navigate.back" }, 2551 { "${menu.back}", navigateBack_KeyShortcut, "navigate.back" },
2543 { "Go Forward", navigateForward_KeyShortcut, "navigate.forward" } }, 2552 { "${menu.forward}", navigateForward_KeyShortcut, "navigate.forward" } },
2544 2); 2553 2);
2545 } 2554 }
2546 pushBackN_Array( 2555 pushBackN_Array(
2547 &items, 2556 &items,
2548 (iMenuItem[]){ 2557 (iMenuItem[]){
2549 { upArrow_Icon " Go to Parent", navigateParent_KeyShortcut, "navigate.parent" }, 2558 { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },
2550 { upArrowBar_Icon " Go to Root", navigateRoot_KeyShortcut, "navigate.root" }, 2559 { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },
2551 { "---", 0, 0, NULL }, 2560 { "---", 0, 0, NULL },
2552 { reload_Icon " Reload Page", reload_KeyShortcut, "navigate.reload" }, 2561 { reload_Icon " ${menu.reload}", reload_KeyShortcut, "navigate.reload" },
2553 { timer_Icon " Set Auto-Reload...", 0, 0, "document.autoreload.menu" }, 2562 { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" },
2554 { "---", 0, 0, NULL }, 2563 { "---", 0, 0, NULL },
2555 { pin_Icon " Bookmark Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, 2564 { pin_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
2556 { star_Icon " Subscribe to Page...", subscribeToPage_KeyModifier, "feeds.subscribe" }, 2565 { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" },
2557 { "---", 0, 0, NULL }, 2566 { "---", 0, 0, NULL },
2558 { book_Icon " Import Links as Bookmarks...", 0, 0, "bookmark.links confirm:1" }, 2567 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },
2559 { globe_Icon " Translate...", 0, 0, "document.translate" }, 2568 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },
2560 { "---", 0, 0, NULL }, 2569 { "---", 0, 0, NULL },
2561 { "Copy Page URL", 0, 0, "document.copylink" } }, 2570 { "${menu.page.copyurl}", 0, 0, "document.copylink" } },
2562 12); 2571 12);
2563 if (isEmpty_Range(&d->selectMark)) { 2572 if (isEmpty_Range(&d->selectMark)) {
2564 pushBackN_Array( 2573 pushBackN_Array(
2565 &items, 2574 &items,
2566 (iMenuItem[]){ 2575 (iMenuItem[]){
2567 { "Copy Page Source", 'c', KMOD_PRIMARY, "copy" }, 2576 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },
2568 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, 2577 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },
2569 2); 2578 2);
2570 } 2579 }
@@ -2692,14 +2701,14 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2692 const iString *url = absoluteUrl_String( 2701 const iString *url = absoluteUrl_String(
2693 d->mod.url, linkUrl_GmDocument(d->doc, linkId)); 2702 d->mod.url, linkUrl_GmDocument(d->doc, linkId));
2694 makeQuestion_Widget( 2703 makeQuestion_Widget(
2695 uiTextCaution_ColorEscape "OPEN LINK", 2704 uiTextCaution_ColorEscape "${heading.openlink}",
2696 format_CStr( 2705 format_CStr(
2697 "Open this link in the default browser?\n" uiTextAction_ColorEscape 2706 cstr_Lang("dlg.openlink.confirm"),
2698 "%s", 2707 uiTextAction_ColorEscape,
2699 cstr_String(url)), 2708 cstr_String(url)),
2700 (iMenuItem[]){ 2709 (iMenuItem[]){
2701 { "Cancel", 0, 0, NULL }, 2710 { "${cancel}", 0, 0, NULL },
2702 { uiTextCaution_ColorEscape "Open Link", 2711 { uiTextCaution_ColorEscape "${dlg.openlink}",
2703 0, 0, format_CStr("!open default:1 url:%s", cstr_String(url)) } }, 2712 0, 0, format_CStr("!open default:1 url:%s", cstr_String(url)) } },
2704 2); 2713 2);
2705 } 2714 }
@@ -2823,7 +2832,7 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2
2823 const int domainHeight = lineHeight_Text(banner_FontId) * 2; 2832 const int domainHeight = lineHeight_Text(banner_FontId) * 2;
2824 iRect rect = { add_I2(visPos, init_I2(0, domainHeight)), 2833 iRect rect = { add_I2(visPos, init_I2(0, domainHeight)),
2825 addY_I2(run->visBounds.size, -domainHeight - lineHeight_Text(uiContent_FontId)) }; 2834 addY_I2(run->visBounds.size, -domainHeight - lineHeight_Text(uiContent_FontId)) };
2826 format_String(&str, "UNTRUSTED CERTIFICATE"); 2835 format_String(&str, "${heading.certwarn}");
2827 const int certFlags = d->widget->certFlags; 2836 const int certFlags = d->widget->certFlags;
2828 if (certFlags & timeVerified_GmCertFlag && certFlags & domainVerified_GmCertFlag) { 2837 if (certFlags & timeVerified_GmCertFlag && certFlags & domainVerified_GmCertFlag) {
2829 iUrl parts; 2838 iUrl parts;
@@ -2834,32 +2843,30 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2
2834 iTime now; 2843 iTime now;
2835 initCurrent_Time(&now); 2844 initCurrent_Time(&now);
2836 const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24; 2845 const int days = secondsSince_Time(&oldUntil, &now) / 3600 / 24;
2846 appendCStr_String(&str, "\n");
2837 if (days <= 30) { 2847 if (days <= 30) {
2838 appendFormat_String(&str, 2848 appendFormat_String(&str,
2839 "\nThe received certificate may have been recently renewed " 2849 cstr_Lang("dlg.certwarn.mayberenewed"),
2840 "\u2014 it is for the correct domain and has not expired. "
2841 "The currently trusted certificate will expire on %s, "
2842 "in %d days.",
2843 cstrCollect_String(format_Date(&exp, "%Y-%m-%d")), 2850 cstrCollect_String(format_Date(&exp, "%Y-%m-%d")),
2844 days); 2851 days);
2845 } 2852 }
2846 else { 2853 else {
2847 appendFormat_String(&str, "\nThe received certificate is valid but different than " 2854 appendCStr_String(&str, cstr_Lang("dlg.certwarn.different"));
2848 "the one we trust.");
2849 } 2855 }
2850 } 2856 }
2851 else if (certFlags & domainVerified_GmCertFlag) { 2857 else if (certFlags & domainVerified_GmCertFlag) {
2852 appendFormat_String(&str, "\nThe received certificate has expired on %s.", 2858 appendCStr_String(&str, "\n");
2859 appendFormat_String(&str, cstr_Lang("dlg.certwarn.expired"),
2853 cstrCollect_String(format_Date(&d->widget->certExpiry, "%Y-%m-%d"))); 2860 cstrCollect_String(format_Date(&d->widget->certExpiry, "%Y-%m-%d")));
2854 } 2861 }
2855 else if (certFlags & timeVerified_GmCertFlag) { 2862 else if (certFlags & timeVerified_GmCertFlag) {
2856 appendFormat_String(&str, "\nThe received certificate is for the wrong domain (%s). " 2863 appendCStr_String(&str, "\n");
2857 "This may be a server configuration problem.", 2864 appendFormat_String(&str, cstr_Lang("dlg.certwarn.domain"),
2858 cstr_String(d->widget->certSubject)); 2865 cstr_String(d->widget->certSubject));
2859 } 2866 }
2860 else { 2867 else {
2861 appendFormat_String(&str, "\nThe received certificate is expired AND for the " 2868 appendCStr_String(&str, "\n");
2862 "wrong domain."); 2869 appendCStr_String(&str, cstr_Lang("dlg.certwarn.domain.expired"));
2863 } 2870 }
2864 const iInt2 dims = advanceWrapRange_Text( 2871 const iInt2 dims = advanceWrapRange_Text(
2865 uiContent_FontId, width_Rect(rect) - 16 * gap_UI, range_String(&str)); 2872 uiContent_FontId, width_Rect(rect) - 16 * gap_UI, range_String(&str));
@@ -2880,6 +2887,7 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2
2880 bpos = topLeft_Rect(rect); 2887 bpos = topLeft_Rect(rect);
2881 draw_Text(uiLabelLarge_FontId, bpos, fg, "\u26a0"); 2888 draw_Text(uiLabelLarge_FontId, bpos, fg, "\u26a0");
2882 adjustEdges_Rect(&rect, 0, -8 * gap_UI, 0, 8 * gap_UI); 2889 adjustEdges_Rect(&rect, 0, -8 * gap_UI, 0, 8 * gap_UI);
2890 translate_Lang(&str);
2883 drawWrapRange_Text(uiContent_FontId, 2891 drawWrapRange_Text(uiContent_FontId,
2884 addY_I2(topLeft_Rect(rect), yOff), 2892 addY_I2(topLeft_Rect(rect), yOff),
2885 width_Rect(rect), 2893 width_Rect(rect),
@@ -2990,8 +2998,9 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
2990 iGmMediaInfo info; 2998 iGmMediaInfo info;
2991 imageInfo_Media(constMedia_GmDocument(doc), imageId, &info); 2999 imageInfo_Media(constMedia_GmDocument(doc), imageId, &info);
2992 const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), imageId); 3000 const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), imageId);
2993 format_String(&text, "%s \u2014 %d x %d \u2014 %.1fMB", 3001 format_String(&text, "%s \u2014 %d x %d \u2014 %.1f%s",
2994 info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f); 3002 info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f,
3003 cstr_Lang("mb"));
2995 } 3004 }
2996 else if (audioId) { 3005 else if (audioId) {
2997 iGmMediaInfo info; 3006 iGmMediaInfo info;
@@ -3047,24 +3056,26 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
3047 if (run->flags & endOfLine_GmRunFlag && 3056 if (run->flags & endOfLine_GmRunFlag &&
3048 (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) || 3057 (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) ||
3049 showHost)) { 3058 showHost)) {
3050 format_String(&str, 3059 format_String(
3051 " \u2014%s%s%s\r%c%s", 3060 &str,
3052 showHost ? " " : "", 3061 " \u2014%s%s%s\r%c%s",
3053 showHost ? (flags & mailto_GmLinkFlag 3062 showHost ? " " : "",
3054 ? cstr_String(url) 3063 showHost
3055 : ~flags & gemini_GmLinkFlag 3064 ? (flags & mailto_GmLinkFlag ? cstr_String(url)
3056 ? format_CStr("%s://%s", 3065 : ~flags & gemini_GmLinkFlag ? format_CStr("%s://%s",
3057 cstr_Rangecc(parts.scheme), 3066 cstr_Rangecc(parts.scheme),
3058 cstr_Rangecc(parts.host)) 3067 cstr_Rangecc(parts.host))
3059 : cstr_Rangecc(parts.host)) 3068 : cstr_Rangecc(parts.host))
3060 : "", 3069 : "",
3061 showHost && (showImage || showAudio) ? " \u2014" : "", 3070 showHost && (showImage || showAudio) ? " \u2014" : "",
3062 showImage || showAudio 3071 showImage || showAudio
3063 ? asciiBase_ColorEscape + fg 3072 ? asciiBase_ColorEscape + fg
3064 : (asciiBase_ColorEscape + 3073 : (asciiBase_ColorEscape +
3065 linkColor_GmDocument(doc, run->linkId, domain_GmLinkPart)), 3074 linkColor_GmDocument(doc, run->linkId, domain_GmLinkPart)),
3066 showImage ? " View Image \U0001f5bb" 3075 showImage || showAudio
3067 : showAudio ? " Play Audio \U0001f3b5" : ""); 3076 ? format_CStr(showImage ? " %s \U0001f5bb" : " %s \U0001f3b5",
3077 cstr_Lang(showImage ? "link.hint.image" : "link.hint.audio"))
3078 : "");
3068 } 3079 }
3069 if (run->flags & endOfLine_GmRunFlag && flags & visited_GmLinkFlag) { 3080 if (run->flags & endOfLine_GmRunFlag && flags & visited_GmLinkFlag) {
3070 iDate date; 3081 iDate date;
@@ -3398,7 +3409,7 @@ const iString *bookmarkTitle_DocumentWidget(const iDocumentWidget *d) {
3398 } 3409 }
3399 } 3410 }
3400 if (isEmpty_StringArray(title)) { 3411 if (isEmpty_StringArray(title)) {
3401 pushBackCStr_StringArray(title, "Blank Page"); 3412 pushBackCStr_StringArray(title, cstr_Lang("bookmark.title.blank"));
3402 } 3413 }
3403 return collect_String(joinCStr_StringArray(title, " \u2014 ")); 3414 return collect_String(joinCStr_StringArray(title, " \u2014 "));
3404} 3415}