From 949c6ce65e2e6edb765c9a237aebe0ebebe12750 Mon Sep 17 00:00:00 2001 From: shum Date: Tue, 14 Jul 2026 12:38:09 +0000 Subject: [PATCH] website: fix broken links across docs and pages Render glossary tooltips through the shared replaceLink transform so their relative links become absolute site URLs instead of 404ing when injected across pages; add the English-only routes (downloads, faq, jobs, reproduce, security, transparency) to supportedRoutes so the language switcher stops emitting href="undefined"; passthrough-copy docs/guide/images, docs/guide/diagrams and docs/themes. Fix the SIMPLEX.md p2p anchor typo and correct image paths in CLI, the v0.4 blog post and the fr/pl translation docs to point at the existing shared assets. --- blog/20210914-simplex-chat-v0.4-released.md | 4 +- docs/CLI.md | 6 +- docs/GLOSSARY.md | 2 +- docs/lang/fr/TRANSLATIONS.md | 4 +- docs/lang/pl/SERVER.md | 2 +- docs/lang/pl/TRANSLATIONS.md | 4 +- docs/lang/pl/WEBRTC.md | 6 +- website/.eleventy.js | 83 ++++++++++++--------- 8 files changed, 61 insertions(+), 50 deletions(-) diff --git a/blog/20210914-simplex-chat-v0.4-released.md b/blog/20210914-simplex-chat-v0.4-released.md index 31adf022a9..253745015b 100644 --- a/blog/20210914-simplex-chat-v0.4-released.md +++ b/blog/20210914-simplex-chat-v0.4-released.md @@ -30,13 +30,13 @@ To create a group use the `/g ` command. You can then invite contacts to **Please note:** Groups are not stored on any server; they are maintained as a list of members in the app database. Sending a message to the group sends a message to each member of the group. -![simplex-chat](../images/groups.gif) +![simplex-chat](/images/groups.gif) ### File transfer Sharing files is simple! To send a file to a contact, use the `/f @ ` command. The recipient will have to accept before the file is sent. -![simplex-chat](../images/files.gif) +![simplex-chat](/images/files.gif) ## We're always looking for help! diff --git a/docs/CLI.md b/docs/CLI.md index 628fe2a4af..dc7f85cd38 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -220,7 +220,7 @@ Use `/help` in chat to see the list of available commands. To create a group use `/g `, then add contacts to it with `/a `. You can then send messages to the group by entering `# `. Use `/help groups` for other commands. -![simplex-chat](../images/groups.gif) +![simplex-chat](/images/groups.gif) > **Please note**: the groups are not stored on any server, they are maintained as a list of members in the app database to whom the messages will be sent. @@ -228,7 +228,7 @@ To create a group use `/g `, then add contacts to it with `/a ` - the recipient will have to accept it before it is sent. Use `/help files` for other commands. -![simplex-chat](../images/files.gif) +![simplex-chat](/images/files.gif) You can send files to a group with `/f # `. @@ -242,4 +242,4 @@ User address is "long-term" in a sense that it is a multiple-use connection link Use `/help address` for other commands. -![simplex-chat](../images/user-addresses.gif) +![simplex-chat](/images/user-addresses.gif) diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md index c8fdd56bdd..5ea32c73e9 100644 --- a/docs/GLOSSARY.md +++ b/docs/GLOSSARY.md @@ -163,7 +163,7 @@ In the context of SimpleX network, these are the identifiers generated by SMP re Peer-to-peer (P2P) is the network architecture when participants have equal rights and communicate directly via a general purpose transport or overlay network. Unlike client-server architecture, all peers in a P2P network both provide and consume the resources. In the context of messaging, P2P architecture usually means that the messages are sent between peers, without user accounts or messages being stored on any servers. Examples are Tox, Briar, Cwtch and many others. -The advantage is that the participants do not depend on any servers. There are [multiple downsides](./SIMPLEX.md#comparison-with-p2p9-messaging-protocols) to that architecture, such as no asynchronous message delivery, the need for network-wide peer addresses, possibility of network-wide attacks, that are usually mitigated only by using a centralized authority. These disadvantages are avoided with [proxied P2P](#proxied-peer-to-peer) architecture. +The advantage is that the participants do not depend on any servers. There are [multiple downsides](./SIMPLEX.md#comparison-with-p2p-messaging-protocols) to that architecture, such as no asynchronous message delivery, the need for network-wide peer addresses, possibility of network-wide attacks, that are usually mitigated only by using a centralized authority. These disadvantages are avoided with [proxied P2P](#proxied-peer-to-peer) architecture. [Wikipedia](https://en.wikipedia.org/wiki/Peer-to-peer). diff --git a/docs/lang/fr/TRANSLATIONS.md b/docs/lang/fr/TRANSLATIONS.md index 1e216900e7..cb7de707ff 100644 --- a/docs/lang/fr/TRANSLATIONS.md +++ b/docs/lang/fr/TRANSLATIONS.md @@ -26,7 +26,7 @@ Ce document est créé pour accélérer ce processus, et partager quelques astuc 2. Certaines des chaînes n'ont pas besoin d'être traduites, mais elles doivent quand même être copiées - il y a un bouton dans l'interface weblate pour cela : -weblate: copy source to translation +weblate: copy source to translation 3. Weblate propose également des suggestions automatiques qui peuvent accélérer le processus. Parfois, elles peuvent être utilisées telles quelles, parfois elles nécessitent quelques retouches - cliquez pour les utiliser dans les traductions. @@ -34,7 +34,7 @@ Ce document est créé pour accélérer ce processus, et partager quelques astuc 5. Quand vous traduisez [l'app iOS](https://hosted.weblate.org/projects/simplex-chat/ios/), la plupart des chaînes de caractères sont identiques, elles peuvent être copiées en un clic dans la section Glossaire. L'indice visuel que cela est possible est que la chaîne source entière est surlignée en jaune. De nombreuses autres chaînes sont très similaires, elles ne diffèrent que par la syntaxe d'interpolation ou la façon dont la police en gras est utilisée - elles ne nécessitent qu'une édition minimale. Certaines chaînes sont propres à la plate-forme iOS. Elles doivent être traduites séparément. -weblate: automatic suggestions +weblate: automatic suggestions ## Une fois la traduction terminée diff --git a/docs/lang/pl/SERVER.md b/docs/lang/pl/SERVER.md index f4bffc1bcc..e3ffe40c16 100644 --- a/docs/lang/pl/SERVER.md +++ b/docs/lang/pl/SERVER.md @@ -482,4 +482,4 @@ Możliwe jest również udostępnienie adresu swojego serwera znajomym, pozwalaj _Uwaga_: Do obsługi haseł wymagany jest serwer SMP w wersji 4.0. Jeśli już posiadasz serwer, możesz dodać hasło do niego poprzez wpisanie hasła do pliku INI serwera. -       +       diff --git a/docs/lang/pl/TRANSLATIONS.md b/docs/lang/pl/TRANSLATIONS.md index 36daa5a148..531177dba5 100644 --- a/docs/lang/pl/TRANSLATIONS.md +++ b/docs/lang/pl/TRANSLATIONS.md @@ -39,7 +39,7 @@ Kroki są następujące: 2. Niektóre ciągi nie wymagają tłumaczenia, ale nadal trzeba je skopiować - w interfejsie użytkownika weblate znajduje się odpowiedni przycisk: -weblate: copy source to translation +weblate: copy source to translation 3. Weblate posiada również automatyczne sugestie, które mogą przyspieszyć ten proces. Czasami mogą być używane w niezmienionej formie, a czasami wymagają edycji - kliknij, aby użyć ich w tłumaczeniach. @@ -68,7 +68,7 @@ My wtedy: Serdecznie dziękujemy! To ogromny wysiłek i wielka pomoc dla rozwoju sieci SimpleX. -weblate: automatic suggestions +weblate: automatic suggestions ## Częste błędy w tłumaczeniu diff --git a/docs/lang/pl/WEBRTC.md b/docs/lang/pl/WEBRTC.md index d279491fb8..e291d887b5 100644 --- a/docs/lang/pl/WEBRTC.md +++ b/docs/lang/pl/WEBRTC.md @@ -139,7 +139,7 @@ To tyle - teraz możesz wykonywać połączenia audio i wideo za pośrednictwem 2. W sekcji **Build up ICE Server List** dodaj: - + - `STUN: stun::` kliknij `Add STUN` - `TURN: turn::`, `Username: `, `Credential: ` kliknij `Add TURN` @@ -148,11 +148,11 @@ To tyle - teraz możesz wykonywać połączenia audio i wideo za pośrednictwem 3. Powinieneś zobaczyć swoje serwery w sekcji **ICE server list**. Jeśli wszystko jest skonfigurowane poprawnie, naciśnij `Start test`: - + 4. W sekcji **Results** powinieneś zobaczyć coś takiego: - + Jeśli wyniki pokazują `srflx` i `relay`, wszystko jest skonfigurowane poprawnie! diff --git a/website/.eleventy.js b/website/.eleventy.js index e90ac373a0..a96614e4ba 100644 --- a/website/.eleventy.js +++ b/website/.eleventy.js @@ -21,10 +21,50 @@ linksData.forEach(entry => { entry.imageExists = entry.image && fs.existsSync(path.join(linkImagesDir, entry.image)) }) +// Rewrites relative markdown links to website permalinks or GitHub URLs. +// Shared by the main markdown renderer (markdownLib) and the glossary renderer +// below, so glossary tooltips injected into pages get absolute, working links. +function replaceLink(link, _env) { + let parsed = uri.parse(link) + if (parsed.scheme || parsed.host) return link + + let hostFile = path.resolve(_env.page.inputPath) + let linkFile = path.resolve(hostFile, '..', parsed.path) + if (parsed.path.startsWith('/')) { + let srcIndex = hostFile.indexOf("/src") + if (srcIndex !== -1) { + linkFile = path.join(hostFile.slice(0, srcIndex + 4), parsed.path) + } + } + + if (fs.existsSync(linkFile) && fs.statSync(linkFile).isFile()) { + // this condition works if the link is a valid website file + const fileContent = fs.readFileSync(linkFile, 'utf8') + parsed.path = (matter(fileContent).data?.permalink || parsed.path).replace(/\.md$/, ".html").toLowerCase() + } else if (!fs.existsSync(linkFile)) { + linkFile = linkFile.replace('/website/src', '') + if (fs.existsSync(linkFile)) { + // this condition works if the link is a valid project file + const githubUrl = "https://github.com/simplex-chat/simplex-chat/blob/stable" + const repoRoot = hostFile.slice(0, hostFile.indexOf('/website/src')) + const repoPath = linkFile.slice(repoRoot.length) + return `${githubUrl}${repoPath}` + } else { + // if the link is not a valid website file or project file + throw new Error(`Broken link: ${parsed.path} in ${hostFile}`) + } + } + + return uri.serialize(parsed) +} + // The implementation of Glossary feature -const md = new markdownIt() +const md = new markdownIt({ replaceLink }).use(markdownItReplaceLink) +// Resolve the glossary's relative links (e.g. ./SIMPLEX.md) as if rendered from +// its built location, so tooltips embedded on other pages get absolute URLs. +const glossaryInputPath = path.resolve(__dirname, 'src/docs/GLOSSARY.md') const glossaryMarkdownContent = fs.readFileSync(path.resolve(__dirname, '../docs/GLOSSARY.md'), 'utf8') -const glossaryHtmlContent = md.render(glossaryMarkdownContent) +const glossaryHtmlContent = md.render(glossaryMarkdownContent, { page: { inputPath: glossaryInputPath } }) const glossaryDOM = new JSDOM(glossaryHtmlContent) const glossaryDocument = glossaryDOM.window.document const glossary = require('./src/_data/glossary.json') @@ -63,7 +103,7 @@ const globalConfig = { } const translationsDirectoryPath = './langs' -const supportedRoutes = ["blog", "contact", "invitation", "messaging", "docs", "fdroid", "why", "file", ""] +const supportedRoutes = ["blog", "contact", "invitation", "messaging", "docs", "fdroid", "why", "file", "downloads", "faq", "reproduce", "transparency", "security", "jobs", ""] let supportedLangs = [] fs.readdir(translationsDirectoryPath, (err, files) => { if (err) { @@ -320,6 +360,9 @@ module.exports = function (ty) { ty.addPassthroughCopy("src/blog/images") ty.addPassthroughCopy("src/docs/*.png") ty.addPassthroughCopy("src/docs/images") + ty.addPassthroughCopy("src/docs/guide/images") + ty.addPassthroughCopy("src/docs/guide/diagrams") + ty.addPassthroughCopy("src/docs/themes") ty.addPassthroughCopy("src/docs/protocol/diagrams") ty.addPassthroughCopy("src/docs/protocol/*.json") ty.addPassthroughCopy("src/images") @@ -418,39 +461,7 @@ module.exports = function (ty) { html: true, breaks: true, linkify: true, - replaceLink: function (link, _env) { - let parsed = uri.parse(link) - if (parsed.scheme || parsed.host) return link - - let hostFile = path.resolve(_env.page.inputPath) - let linkFile = path.resolve(hostFile, '..', parsed.path) - if (parsed.path.startsWith('/')) { - let srcIndex = hostFile.indexOf("/src") - if (srcIndex !== -1) { - linkFile = path.join(hostFile.slice(0, srcIndex + 4), parsed.path) - } - } - - if (fs.existsSync(linkFile) && fs.statSync(linkFile).isFile()) { - // this condition works if the link is a valid website file - const fileContent = fs.readFileSync(linkFile, 'utf8') - parsed.path = (matter(fileContent).data?.permalink || parsed.path).replace(/\.md$/, ".html").toLowerCase() - } else if (!fs.existsSync(linkFile)) { - linkFile = linkFile.replace('/website/src', '') - if (fs.existsSync(linkFile)) { - // this condition works if the link is a valid project file - const githubUrl = "https://github.com/simplex-chat/simplex-chat/blob/stable" - const repoRoot = hostFile.slice(0, hostFile.indexOf('/website/src')) - const repoPath = linkFile.slice(repoRoot.length) - return `${githubUrl}${repoPath}` - } else { - // if the link is not a valid website file or project file - throw new Error(`Broken link: ${parsed.path} in ${hostFile}`) - } - } - - return uri.serialize(parsed) - } + replaceLink: replaceLink }).use(markdownItAnchor, { slugify: (str) => slugify(str, {