feat(docs): update Reticulum documentation links to use dynamic URLs based on locale

This commit is contained in:
Ivan
2026-04-22 12:03:47 -05:00
parent 3a9a8b8aeb
commit 616a014a3c
5 changed files with 46 additions and 14 deletions
+2 -2
View File
@@ -11687,9 +11687,9 @@ class ReticulumMeshChat:
dm = self.current_context.docs_manager
async def reticulum_docs_handler(request):
path = request.match_info.get("filename", "index.html")
path = request.match_info.get("filename", "manual/index.html")
if not path:
path = "index.html"
path = "manual/index.html"
if path.endswith("/"):
path += "index.html"
@@ -511,7 +511,7 @@
{{ $t("tutorial.meshchatx_docs") }}
</a>
<a
href="/reticulum-docs/index.html"
:href="reticulumBundledDocsUrl"
target="_blank"
class="px-3 py-1 text-[10px] rounded-xl border border-gray-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-gray-700 dark:text-zinc-300 font-semibold shadow-sm transition-all hover:bg-gray-50 dark:hover:bg-zinc-700 hover:border-blue-400 dark:hover:border-blue-500 inline-block"
>
@@ -1180,7 +1180,7 @@
{{ $t("tutorial.read_meshchatx_docs") }}
</a>
<a
href="/reticulum-docs/index.html"
:href="reticulumBundledDocsUrl"
target="_blank"
class="h-12 rounded-xl border border-gray-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-gray-700 dark:text-zinc-300 font-semibold shadow-sm transition-all hover:bg-gray-50 dark:hover:bg-zinc-700 hover:border-blue-400 dark:hover:border-blue-500 inline-flex items-center justify-center px-6"
>
@@ -1358,6 +1358,7 @@ import logoUrl from "../assets/images/logo.png";
import ToastUtils from "../js/ToastUtils";
import DialogUtils from "../js/DialogUtils";
import GlobalState from "../js/GlobalState";
import { bundledReticulumDocsUrl } from "../js/reticulumDocsEntryUrl.js";
import LanguageSelector from "./LanguageSelector.vue";
import MaterialDesignIcon from "./MaterialDesignIcon.vue";
@@ -1420,6 +1421,9 @@ export default {
selectedBootstrapCount() {
return this.selectedBootstrapKeys.length;
},
reticulumBundledDocsUrl() {
return bundledReticulumDocsUrl(this.$i18n.locale);
},
},
beforeUnmount() {
if (this.onWindowResize) {
@@ -488,6 +488,7 @@
<!-- Reticulum Docs View -->
<iframe
v-if="activeTab === 'reticulum' && status.has_docs && !searchQuery"
:key="localDocsUrl"
ref="docsFrame"
:src="localDocsUrl"
class="w-full h-full border-none opacity-0 transition-opacity duration-1000"
@@ -522,6 +523,8 @@
<script>
import MaterialDesignIcon from "../MaterialDesignIcon.vue";
import ToastUtils from "../../js/ToastUtils";
import GlobalState from "../../js/GlobalState";
import { bundledReticulumDocsUrl } from "../../js/reticulumDocsEntryUrl.js";
export default {
components: {
@@ -572,12 +575,7 @@ export default {
if (this.selectedReticulumPath) {
return `/reticulum-docs/${this.selectedReticulumPath}`;
}
const lang = this.currentLang;
if (lang === "en") return "/reticulum-docs/index.html";
if (Object.keys(this.languages).includes(lang)) {
return `/reticulum-docs/index_${lang}.html`;
}
return "/reticulum-docs/index.html";
return bundledReticulumDocsUrl(this.currentLang);
},
allLanguages() {
return Object.entries(this.languages).map(([code, name]) => ({
@@ -723,7 +721,8 @@ export default {
await window.api.patch("/api/v1/config", {
language: langCode,
});
// The app will update automatically via websocket config sync
this.$i18n.locale = langCode;
GlobalState.config.language = langCode;
} catch (error) {
console.error("Failed to update language:", error);
}
@@ -0,0 +1,29 @@
/**
* Locales that ship a localized root index (index_<locale>.html) in the
* Reticulum website bundle. The Sphinx manual itself is English-only under
* manual/; other locales use these pages like the public site.
*/
const BUNDLED_RETICULUM_SITE_INDEX_LOCALES = new Set(["de", "es", "jp", "nl", "pl", "pt-br", "tr", "uk", "zh-cn"]);
/**
* @param {string | undefined} locale
* @returns {string} path relative to /reticulum-docs/ (no leading slash)
*/
export function bundledReticulumDocsEntryPath(locale) {
const lang = (locale || "en").toLowerCase();
if (lang === "en") {
return "manual/index.html";
}
if (BUNDLED_RETICULUM_SITE_INDEX_LOCALES.has(lang)) {
return `index_${lang}.html`;
}
return "manual/index.html";
}
/**
* @param {string | undefined} locale
* @returns {string} absolute app path for the default bundled Reticulum docs view
*/
export function bundledReticulumDocsUrl(locale) {
return `/reticulum-docs/${bundledReticulumDocsEntryPath(locale)}`;
}
+3 -3
View File
@@ -95,7 +95,7 @@ describe("DocsPage.vue", () => {
await nextTick();
expect(wrapper.find("iframe").exists()).toBe(true);
expect(wrapper.find("iframe").attributes("src")).toBe("/reticulum-docs/index.html");
expect(wrapper.find("iframe").attributes("src")).toBe("/reticulum-docs/manual/index.html");
});
it("shows progress bar while extracting an upload", async () => {
@@ -197,7 +197,7 @@ describe("DocsPage.vue", () => {
expect(wrapper.vm.status.last_error).toBeNull();
});
it("changes localDocsUrl based on locale", async () => {
it("opens the Sphinx manual for English and localized site index for other locales", async () => {
const wrapper = mountDocsPage();
await nextTick();
@@ -207,7 +207,7 @@ describe("DocsPage.vue", () => {
i18nMock.locale = "en";
await nextTick();
expect(wrapper.vm.localDocsUrl).toBe("/reticulum-docs/index.html");
expect(wrapper.vm.localDocsUrl).toBe("/reticulum-docs/manual/index.html");
});
it("handles extremely long error messages in the UI", async () => {