henry pushed to branch tor-browser-153.0esr-16.0-1 at The Tor Project / Applications / Tor Browser Commits: 34750d3a by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! BB 41916: Letterboxing preferences UI BB 44959: Swap about:manual link. - - - - - 1f471dc9 by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! BB 40925: Implemented the Security Level component BB 44959: Swap about:manual link. - - - - - 2064e1c8 by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! TB 11698: Incorporate Tor Browser Manual pages into Tor Browser TB 44959: Integrate the new manual. - - - - - 631c2c54 by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! TB 30237: Add v3 onion services client authentication prompt TB 44959: Swap about:manual link. - - - - - da12add2 by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection TB 44959: Swap about:manual link. - - - - - 21d6cfe7 by Henry Wilkes at 2026-07-28T13:15:52+00:00 fixup! Add TorStrings module for localization TB 44959: Swap about:manual link. - - - - - 18 changed files: - browser/components/DesktopActorRegistry.sys.mjs - browser/components/about/AboutRedirector.cpp - + browser/components/aboutmanual/AboutManualChild.sys.mjs - + browser/components/aboutmanual/AboutManualParent.sys.mjs - + browser/components/aboutmanual/content/aboutManual.js - + browser/components/aboutmanual/jar.mn - + browser/components/aboutmanual/moz.build - browser/components/moz.build - browser/components/onionservices/content/authPopup.inc.xhtml - browser/components/preferences/config/passwords-autofill.mjs - browser/components/preferences/letterboxing.inc.xhtml - browser/components/securitylevel/content/securityLevelPanel.inc.xhtml - browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml - browser/components/torpreferences/config/connection.mjs - browser/components/torpreferences/content/connectionPane.inc.xhtml - browser/components/torpreferences/content/provideBridgeDialog.xhtml - toolkit/content/aboutNetError.mjs - toolkit/modules/TorStrings.sys.mjs Changes: ===================================== browser/components/DesktopActorRegistry.sys.mjs ===================================== @@ -126,6 +126,23 @@ let JSWINDOWACTORS = { remoteTypes: ["privilegedabout"], }, + AboutManual: { + parent: { + esModuleURI: + "moz-src:///browser/components/aboutmanual/AboutManualParent.sys.mjs", + }, + child: { + esModuleURI: + "moz-src:///browser/components/aboutmanual/AboutManualChild.sys.mjs", + + events: { + ManualLocaleSelected: { wantUntrusted: true }, + }, + }, + + matches: ["about:manual"], + }, + AboutMessagePreview: { parent: { esModuleURI: "resource:///actors/AboutMessagePreviewParent.sys.mjs", ===================================== browser/components/about/AboutRedirector.cpp ===================================== @@ -212,52 +212,45 @@ static nsAutoCString GetAboutModuleName(nsIURI* aURI) { return path; } -static nsTHashSet<nsCStringHashKey> GetManualLocales() { - nsTHashSet<nsCStringHashKey> locales; - RefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::APP); - if (!zip) { - // Probably a local build started with ./mach run - return locales; - } - UniquePtr<nsZipFind> find; - const nsAutoCString prefix("chrome/browser/content/browser/manual/"); - nsAutoCString needle = prefix; - needle.Append("*.html"); - if (NS_SUCCEEDED(zip->FindInit(needle.get(), getter_Transfers(find)))) { - const char* entryName; - uint16_t entryNameLen; - while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) { - // 5 is to remove the final `.html` - const size_t length = entryNameLen - prefix.Length() - 5; - locales.Insert(nsAutoCString(entryName + prefix.Length(), length)); - } - } - return locales; -} - static nsAutoCString GetManualChromeURI() { - static nsTHashSet<nsCStringHashKey> locales = GetManualLocales(); - - nsAutoCString reqLocale; - intl::LocaleService::GetInstance()->GetAppLocaleAsBCP47(reqLocale); - // Check every time the URL is needed in case the locale has changed. - // It might help also if we start allowing to change language, e.g., with a - // get parameter (see tor-browser#42675). - if (!locales.Contains(reqLocale) && reqLocale.Length() > 2 && - reqLocale[2] == '-') { - // At the moment, codes in our manual output are either 2 letters (en) or - // 5 letters (pt-BR) - reqLocale.SetLength(2); + nsTArray<nsCString> availableLocales; + nsCString availableLocalesStr; + if (NS_SUCCEEDED(mozilla::Preferences::GetCString( + "torbrowser.manual.available-locales", availableLocalesStr)) && + availableLocalesStr.Length() > 0) { + for (const nsACString& locale : availableLocalesStr.Split(',')) { + availableLocales.AppendElement(locale); + } } - if (!locales.Contains(reqLocale)) { - reqLocale = "en"; + nsCString tryLocale; + if (!NS_SUCCEEDED(mozilla::Preferences::GetCString("torbrowser.manual.locale", + tryLocale)) || + !availableLocales.Contains(tryLocale)) { + nsTArray<nsCString> appLocales; + intl::LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales); + bool found = false; + for (size_t i = 0; i < appLocales.Length(); i++) { + tryLocale = appLocales[i]; + if (availableLocales.Contains(tryLocale)) { + found = true; + break; + } else if (tryLocale.Length() > 3 && tryLocale[2] == '-') { + // Strip the region code and see if the lang matches. + tryLocale.SetLength(2); + if (availableLocales.Contains(tryLocale)) { + found = true; + break; + } + } + } + if (!found) { + tryLocale.AssignLiteral("en"); + } } - - // %s is the language - constexpr char model[] = "chrome://browser/content/manual/%s.html"; - nsAutoCString url; - url.AppendPrintf(model, reqLocale.get()); - return url; + nsAutoCString uri; + uri.AppendPrintf("chrome://browser/content/aboutmanual/aboutManual-%s.html", + tryLocale.get()); + return uri; } NS_IMETHODIMP ===================================== browser/components/aboutmanual/AboutManualChild.sys.mjs ===================================== @@ -0,0 +1,15 @@ +/** + * Actor child class for the about:manual page. + */ +export class AboutManualChild extends JSWindowActorChild { + handleEvent(event) { + switch (event.type) { + case "ManualLocaleSelected": { + const locale = event.detail; + if (typeof locale === "string") { + this.sendAsyncMessage("AboutManual:LocaleSelected", locale); + } + } + } + } +} ===================================== browser/components/aboutmanual/AboutManualParent.sys.mjs ===================================== @@ -0,0 +1,21 @@ +/** + * Actor parent class for the about:manual page. + */ +export class AboutManualParent extends JSWindowActorParent { + receiveMessage(message) { + switch (message.name) { + case "AboutManual:LocaleSelected": { + const locale = message.data; + if ( + Services.prefs + .getStringPref("torbrowser.manual.available-locales", "") + .split(",") + .includes(locale) + ) { + Services.prefs.setStringPref("torbrowser.manual.locale", locale); + this.browsingContext.reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); + } + } + } + } +} ===================================== browser/components/aboutmanual/content/aboutManual.js ===================================== @@ -0,0 +1,67 @@ +"use strict"; + +function changePage(initialLoad) { + let page; + const hash = location.hash; + const id = hash.startsWith("#") ? hash.substr(1) : null; + let targetEl = null; + if (id) { + targetEl = document.getElementById(id); + page = targetEl?.closest(".olm-page"); + } + if (!page) { + if (!initialLoad) { + // Make no change. + return; + } + page = document.getElementById("index"); + } + const currPage = document.querySelector(".olm-page:not(.d-none)"); + if (currPage === page) { + // No change in page. + return; + } + + currPage?.classList.add("d-none"); + page.classList.remove("d-none"); + + // If we are targeting an element that is not a page element, we want to + // scroll it into view (the focus position should have already shifted to + // point to it). + // Otherwise, if we have no target or the target is a page, we want to scroll + // to the top of the document so that the header is visible. + const doScroll = () => { + const scrollEl = targetEl && targetEl !== page ? targetEl : document.body; + scrollEl.scrollIntoView({ + behavior: "instant", + block: "start", + inline: "start", + }); + }; + if (initialLoad) { + window.addEventListener("load", doScroll, { once: true }); + } else { + doScroll(); + } +} + +window.addEventListener("DOMContentLoaded", () => { + const langDropdown = document.getElementById("language-menu-dropdown"); + for (const langButton of langDropdown.querySelectorAll("button")) { + langButton.addEventListener("click", () => { + dispatchEvent( + new CustomEvent("ManualLocaleSelected", { + // The button's lang attribute is expected to match the locale's code. + detail: langButton.getAttribute("lang"), + bubbles: true, + }) + ); + }); + } + + changePage(true); +}); + +window.addEventListener("hashchange", () => { + changePage(false); +}); ===================================== browser/components/aboutmanual/jar.mn ===================================== @@ -0,0 +1,2 @@ +browser.jar: + content/browser/aboutmanual/aboutManual.js (content/aboutManual.js) ===================================== browser/components/aboutmanual/moz.build ===================================== @@ -0,0 +1,6 @@ +JAR_MANIFESTS += ["jar.mn"] + +MOZ_SRC_FILES += [ + "AboutManualChild.sys.mjs", + "AboutManualParent.sys.mjs", +] ===================================== browser/components/moz.build ===================================== @@ -26,6 +26,7 @@ with Files("controlcenter/**"): DIRS += [ "about", + "aboutmanual", "aboutlogins", "abouttor", "aboutwelcome", ===================================== browser/components/onionservices/content/authPopup.inc.xhtml ===================================== @@ -6,7 +6,7 @@ <label class="text-link popup-notification-learnmore-link" is="text-link" - href="about:manual#onion-services_onion-service-authentication" + href="about:manual#features__onion-services___onion-service-auth" useoriginprincipal="true" data-l10n-id="onion-site-authentication-prompt-learn-more" /> ===================================== browser/components/preferences/config/passwords-autofill.mjs ===================================== @@ -792,7 +792,7 @@ SettingGroupManager.registerGroups({ onionSiteAuthentication: { l10nId: "onion-site-authentication-group", headingLevel: 2, - supportPage: "tor-manual:onion-services_onion-service-authentication", + supportPage: "tor-manual:features__onion-services___onion-service-auth", items: [ { id: "onionSiteSavedKeys", ===================================== browser/components/preferences/letterboxing.inc.xhtml ===================================== @@ -10,7 +10,7 @@ <html:span data-l10n-id="letterboxing-overview"></html:span> <html:a is="moz-support-link" - support-page="tor-manual:anti-fingerprinting_letterboxing" + support-page="tor-manual:features__fingerprinting-protections___letterboxing" data-l10n-id="letterboxing-learn-more" ></html:a> </description> ===================================== browser/components/securitylevel/content/securityLevelPanel.inc.xhtml ===================================== @@ -18,7 +18,7 @@ <html:a is="moz-support-link" id="securityLevel-learnMore" - support-page="tor-manual:security-settings" + support-page="tor-manual:features__security-levels" data-l10n-id="security-level-panel-learn-more-link" ></html:a> <html:img id="securityLevel-background-image" alt="" /> ===================================== browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml ===================================== @@ -13,7 +13,7 @@ ></html:span> <html:a is="moz-support-link" - support-page="tor-manual:security-settings" + support-page="tor-manual:features__security-levels" data-l10n-id="security-level-preferences-learn-more-link" ></html:a> </description> ===================================== browser/components/torpreferences/config/connection.mjs ===================================== @@ -13,7 +13,7 @@ SettingGroupManager.registerGroups({ connectionStatus: { inProgress: true, l10nId: "tor-connection-internet-status-group", - supportPage: "tor-manual:about", + supportPage: "tor-manual:getting-started__about-tor-browser", headingLevel: 2, items: [ { ===================================== browser/components/torpreferences/content/connectionPane.inc.xhtml ===================================== @@ -18,7 +18,7 @@ <label class="learnMore text-link" is="text-link" - href="about:manual#about" + href="about:manual#getting-started__about-tor-browser" useoriginprincipal="true" data-l10n-id="tor-connection-browser-learn-more-link" /> @@ -129,7 +129,7 @@ <label class="learnMore text-link" is="text-link" - href="about:manual#bridges" + href="about:manual#circumvention__unblocking-tor" useoriginprincipal="true" data-l10n-id="tor-bridges-learn-more-link" /> ===================================== browser/components/torpreferences/content/provideBridgeDialog.xhtml ===================================== @@ -37,7 +37,7 @@ <label is="text-link" class="learnMore text-link" - href="about:manual#bridges" + href="about:manual#circumvention__unblocking-tor" useoriginprincipal="true" data-l10n-id="user-provide-bridge-dialog-learn-more" /> ===================================== toolkit/content/aboutNetError.mjs ===================================== @@ -372,7 +372,7 @@ function initOnionError() { const learnMore = document.getElementById("learnMoreContainer"); learnMore.hidden = false; const learnMoreLink = document.getElementById("learnMoreLink"); - learnMoreLink.href = "about:manual#onion-services"; + learnMoreLink.href = "about:manual#features__onion-services"; setFocus("#netErrorButtonContainer > .try-again"); ===================================== toolkit/modules/TorStrings.sys.mjs ===================================== @@ -243,7 +243,7 @@ const Loader = { ); return { ...tsb.getStrings(strings), - learnMoreURL: "about:manual#onion-services", + learnMoreURL: "about:manual#features__onion-services", // XUL popups cannot open about: URLs, but we are online when showing the notification, so just use the online version learnMoreURLNotification: `https://tb-manual.torproject.org/${getLocale()}/onion-services/`, }; View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a527ea6... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a527ea6... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
participants (1)
-
henry (@henry)