From 1ad15e22b7947fa92a5999f6f10e399c1ac7269d Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 14 Oct 2026 17:07:55 +0800 Subject: [PATCH] seo: bring meta descriptions into Bing's range, and add IndexNow Bing Webmaster Tools flags meta descriptions under roughly 90-100 characters. It counts characters, so most Chinese, Japanese and Korean pages failed even when the text read fine. - Hand-written descriptions for the key site pages in 11 languages: home, pricing, support, team, the blog index and its categories. Plus 16 docs pages whose text is too short to extend from. - scripts/fit-meta-descriptions.mjs runs after both builds (v3/build.sh, deploy.sh and the docs workflow). It brings every other description to 120-160 characters, using the page's opening sentences. - Category descriptions now resolve for the transliterated zh/ja/ko slugs. Before, those pages only ever showed the generic text. - IndexNow: the key file ships with the site from v3/public, and scripts/indexnow.mjs submits the live sitemaps. After deploying, each workflow submits its own half: the site or the docs. - Translate the bodies of the Spanish team page and the German support page, which were still in English. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/deploy-web.yml | 6 + .github/workflows/deploy.yml | 15 ++ content/client/windows/_index.ja.md | 2 +- content/client/windows/_index.pt.md | 2 +- content/client/windows/_index.ro.md | 2 +- content/client/windows/_index.zh-cn.md | 2 +- content/client/windows/_index.zh-tw.md | 2 +- content/dev/_index.ja.md | 2 +- content/dev/_index.ro.md | 2 +- content/dev/_index.zh-cn.md | 2 +- content/dev/_index.zh-tw.md | 2 +- .../rustdesk-server-oss/_index.zh-cn.md | 2 +- .../rustdesk-server-oss/_index.zh-tw.md | 2 +- .../audit-logs/_index.ja.md | 2 +- .../audit-logs/_index.zh-cn.md | 2 +- .../audit-logs/_index.zh-tw.md | 2 +- .../rustdesk-server-pro/oidc/_index.zh-cn.md | 2 +- .../rustdesk-server-pro/oidc/_index.zh-tw.md | 2 +- deploy.sh | 2 + scripts/fit-meta-descriptions.mjs | 225 ++++++++++++++++++ scripts/indexnow.mjs | 77 ++++++ v3/build.sh | 2 + .../de7a94336aa4d69a4e65220729f78691.txt | 1 + v3/src/i18n/blog.ts | 33 ++- v3/src/pages/[...blog]/[...page].astro | 2 +- .../[...blog]/[category]/[...page].astro | 172 +++++++------ v3/src/pages/ar/index.astro | 2 +- v3/src/pages/ar/pricing.astro | 2 +- v3/src/pages/ar/support.astro | 2 +- v3/src/pages/ar/team.astro | 2 +- v3/src/pages/careers.astro | 2 +- v3/src/pages/de/index.astro | 2 +- v3/src/pages/de/pricing.astro | 2 +- v3/src/pages/de/support.astro | 22 +- v3/src/pages/de/team.astro | 2 +- v3/src/pages/es/index.astro | 2 +- v3/src/pages/es/pricing.astro | 2 +- v3/src/pages/es/support.astro | 2 +- v3/src/pages/es/team.astro | 32 +-- v3/src/pages/fr/index.astro | 2 +- v3/src/pages/fr/pricing.astro | 2 +- v3/src/pages/fr/support.astro | 2 +- v3/src/pages/fr/team.astro | 2 +- v3/src/pages/index.astro | 2 +- v3/src/pages/it/index.astro | 2 +- v3/src/pages/it/pricing.astro | 2 +- v3/src/pages/it/support.astro | 2 +- v3/src/pages/it/team.astro | 2 +- v3/src/pages/ja/index.astro | 2 +- v3/src/pages/ja/pricing.astro | 2 +- v3/src/pages/ja/support.astro | 2 +- v3/src/pages/ja/team.astro | 2 +- v3/src/pages/ko/index.astro | 2 +- v3/src/pages/ko/pricing.astro | 2 +- v3/src/pages/ko/support.astro | 2 +- v3/src/pages/ko/team.astro | 2 +- v3/src/pages/open-source.astro | 2 +- v3/src/pages/pricing.astro | 2 +- v3/src/pages/privacy.md | 2 +- v3/src/pages/pt/index.astro | 2 +- v3/src/pages/pt/pricing.astro | 2 +- v3/src/pages/pt/support.astro | 2 +- v3/src/pages/pt/team.astro | 2 +- v3/src/pages/support.astro | 2 +- v3/src/pages/team.astro | 2 +- v3/src/pages/terms.md | 2 +- v3/src/pages/zh-cn/index.astro | 2 +- v3/src/pages/zh-cn/pricing.astro | 2 +- v3/src/pages/zh-cn/support.astro | 2 +- v3/src/pages/zh-cn/team.astro | 2 +- v3/src/pages/zh-tw/index.astro | 2 +- v3/src/pages/zh-tw/pricing.astro | 2 +- v3/src/pages/zh-tw/support.astro | 2 +- v3/src/pages/zh-tw/team.astro | 2 +- v3/zh/home.html | 6 +- 75 files changed, 537 insertions(+), 182 deletions(-) create mode 100644 scripts/fit-meta-descriptions.mjs create mode 100644 scripts/indexnow.mjs create mode 100644 v3/public/de7a94336aa4d69a4e65220729f78691.txt diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index f64c1d1e..df0261dd 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -38,3 +38,9 @@ jobs: ./build.sh scp x ${{ secrets.NAME }}@${{ secrets.HOST }}:/tmp/ ssh ${{ secrets.NAME }}@${{ secrets.HOST }} "sudo tar xzf /tmp/x -C /var/www/html/v3 && /bin/rm /tmp/x && sudo chown www-data:www-data /var/www/html/v3 -R" + + # Ask Bing to recrawl the site's pages now. The site is already live, so + # a failure here is reported but does not fail the deploy. + - name: IndexNow + continue-on-error: true + run: node scripts/indexnow.mjs site diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5bdbf46e..5328fca5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,6 +23,12 @@ jobs: with: hugo-version: '0.147.8' + # For scripts/fit-meta-descriptions.mjs, run after the Hugo build. + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Add SSH key to agent run: | mkdir -p ~/.ssh @@ -36,6 +42,15 @@ jobs: - name: Build run: | hugo --minify + # Bing flags meta descriptions outside ~120-160 characters; see the script. + node scripts/fit-meta-descriptions.mjs public cd public; tar czf x * scp x ${{ secrets.NAME }}@${{ secrets.HOST }}:/tmp/ ssh ${{ secrets.NAME }}@${{ secrets.HOST }} "sudo rm -rf /var/www/html/rustdesk.com/docs/* && sudo tar xzf /tmp/x -C /var/www/html/rustdesk.com/docs/ && /bin/rm /tmp/x && sudo chown www-data:www-data /var/www/html/rustdesk.com/docs/ -R" + + # Ask Bing to recrawl the docs now. The docs are already live, so a + # failure here is reported but does not fail the deploy. The key file + # ships with the site (Deploy-web), so that must have run once first. + - name: IndexNow + continue-on-error: true + run: node scripts/indexnow.mjs docs diff --git a/content/client/windows/_index.ja.md b/content/client/windows/_index.ja.md index e386ca2b..5418b8aa 100644 --- a/content/client/windows/_index.ja.md +++ b/content/client/windows/_index.ja.md @@ -1,7 +1,7 @@ --- title: Windows weight: 4 -description: "RustDesk のWindowsに関するドキュメントです。インストール、設定、展開、トラブルシューティングのガイドを参照できます。" +description: "Windows 版 RustDesk のインストールと展開ガイドです。IT 管理者向けに、クライアントの初期設定、MSI パッケージによる一括配布、サイレントインストールのオプション、ポータブル版で管理者権限を得る方法まで、社内展開に必要な手順を解説します。" keywords: ["rustdesk windows", "rustdesk windows install", "rustdesk msi", "rustdesk silent install", "rustdesk portable elevation", "rustdesk windows deployment"] --- diff --git a/content/client/windows/_index.pt.md b/content/client/windows/_index.pt.md index 7159de71..2131e0b9 100644 --- a/content/client/windows/_index.pt.md +++ b/content/client/windows/_index.pt.md @@ -1,7 +1,7 @@ --- title: Windows weight: 4 -description: "Documentação do RustDesk sobre Windows. Consulte guias de instalação, configuração, implantação e solução de problemas." +description: "Instale e implante o RustDesk no Windows: configuração do cliente, pacote MSI para distribuição em massa, instalação silenciosa e elevação na versão portátil." keywords: ["rustdesk windows", "rustdesk windows install", "rustdesk msi", "rustdesk silent install", "rustdesk portable elevation", "rustdesk windows deployment"] --- diff --git a/content/client/windows/_index.ro.md b/content/client/windows/_index.ro.md index 06c7f8ad..e3f6915e 100644 --- a/content/client/windows/_index.ro.md +++ b/content/client/windows/_index.ro.md @@ -1,7 +1,7 @@ --- title: Windows weight: 4 -description: "Documentație RustDesk pentru Windows. Găsiți ghiduri de instalare, configurare, implementare și depanare." +description: "Instalați RustDesk pe Windows: configurarea clientului, pachet MSI pentru distribuire în masă, instalare silențioasă și drepturi de admin în modul portabil." keywords: ["rustdesk windows", "rustdesk windows install", "rustdesk msi", "rustdesk silent install", "rustdesk portable elevation", "rustdesk windows deployment"] --- diff --git a/content/client/windows/_index.zh-cn.md b/content/client/windows/_index.zh-cn.md index ab7dd842..230bcdf5 100644 --- a/content/client/windows/_index.zh-cn.md +++ b/content/client/windows/_index.zh-cn.md @@ -1,7 +1,7 @@ --- title: Windows weight: 4 -description: "RustDesk 的Windows文档,提供安装、配置、部署和故障排查指南。" +description: "在 Windows 上安装和部署 RustDesk 的完整指南:客户端初始设置、使用 MSI 安装包向大量电脑批量分发、静默安装参数与常用选项,以及便携版如何获取管理员权限,帮助 IT 团队在企业内快速推广 RustDesk 远程桌面,省去逐台手动安装。" keywords: ["rustdesk windows", "rustdesk windows install", "rustdesk msi", "rustdesk silent install", "rustdesk portable elevation", "rustdesk windows deployment"] --- diff --git a/content/client/windows/_index.zh-tw.md b/content/client/windows/_index.zh-tw.md index 544db37b..94595e28 100644 --- a/content/client/windows/_index.zh-tw.md +++ b/content/client/windows/_index.zh-tw.md @@ -1,7 +1,7 @@ --- title: Windows weight: 4 -description: "RustDesk 的Windows文檔,提供安裝、設定、部署與疑難排解指南。" +description: "在 Windows 上安裝與部署 RustDesk 的完整指南:用戶端初始設定、使用 MSI 安裝套件向大量電腦派送、靜默安裝參數與常用選項,以及可攜版如何取得管理員權限,協助 IT 團隊在企業內快速推廣 RustDesk 遠端桌面,省去逐台手動安裝。" keywords: ["rustdesk windows", "rustdesk windows install", "rustdesk msi", "rustdesk silent install", "rustdesk portable elevation", "rustdesk windows deployment"] --- diff --git a/content/dev/_index.ja.md b/content/dev/_index.ja.md index 390789f1..cd3a60b8 100755 --- a/content/dev/_index.ja.md +++ b/content/dev/_index.ja.md @@ -3,7 +3,7 @@ title: 開発 weight: 8 pre: "3. " chapter: true -description: "RustDesk の開発に関するドキュメントです。インストール、設定、展開、トラブルシューティングのガイドを参照できます。" +description: "RustDesk のコントリビューター向け開発ドキュメントです。Linux、Windows、macOS でソースコードから RustDesk をビルドする手順、必要な依存関係、よくあるビルドエラーの対処法、プロジェクトへの貢献に役立つ情報をまとめています。" keywords: ["rustdesk development", "build rustdesk", "rustdesk contributor docs", "rustdesk linux build", "rustdesk windows build", "rustdesk macos build"] --- diff --git a/content/dev/_index.ro.md b/content/dev/_index.ro.md index 7509715c..0e24e9d3 100644 --- a/content/dev/_index.ro.md +++ b/content/dev/_index.ro.md @@ -3,7 +3,7 @@ title: Dezvoltare weight: 8 pre: "3. " chapter: true -description: "Documentație RustDesk pentru Dezvoltare. Găsiți ghiduri de instalare, configurare, implementare și depanare." +description: "Ghiduri pentru contributorii RustDesk: cum compilați RustDesk din sursă pe Linux, Windows și macOS, ce dependențe vă trebuie și cum rezolvați erorile de build." keywords: ["rustdesk development", "build rustdesk", "rustdesk contributor docs", "rustdesk linux build", "rustdesk windows build", "rustdesk macos build"] --- diff --git a/content/dev/_index.zh-cn.md b/content/dev/_index.zh-cn.md index f95b52dd..ad2b7252 100755 --- a/content/dev/_index.zh-cn.md +++ b/content/dev/_index.zh-cn.md @@ -3,7 +3,7 @@ title: 开发 weight: 8 pre: "3. " chapter: true -description: "RustDesk 的开发文档,提供安装、配置、部署和故障排查指南。" +description: "面向 RustDesk 贡献者的完整开发文档:介绍如何在 Linux、Windows 和 macOS 上从源码编译 RustDesk,需要准备的依赖库与工具链,常见编译问题的排查方法,以及参与这个开源远程桌面项目、提交代码和反馈问题的入门信息。" keywords: ["rustdesk development", "build rustdesk", "rustdesk contributor docs", "rustdesk linux build", "rustdesk windows build", "rustdesk macos build"] --- diff --git a/content/dev/_index.zh-tw.md b/content/dev/_index.zh-tw.md index dac509f9..518b5598 100755 --- a/content/dev/_index.zh-tw.md +++ b/content/dev/_index.zh-tw.md @@ -3,7 +3,7 @@ title: 開發 weight: 8 pre: "3. " chapter: true -description: "RustDesk 的開發文檔,提供安裝、設定、部署與疑難排解指南。" +description: "面向 RustDesk 貢獻者的開發文件:介紹如何在 Linux、Windows 與 macOS 上從原始碼編譯 RustDesk、需要準備的相依套件與工具鏈、常見編譯問題的排解方式,以及參與這個開源遠端桌面專案、提交程式碼與回報問題的入門資訊。" keywords: ["rustdesk development", "build rustdesk", "rustdesk contributor docs", "rustdesk linux build", "rustdesk windows build", "rustdesk macos build"] --- diff --git a/content/self-host/rustdesk-server-oss/_index.zh-cn.md b/content/self-host/rustdesk-server-oss/_index.zh-cn.md index 8269dced..0632c4a8 100755 --- a/content/self-host/rustdesk-server-oss/_index.zh-cn.md +++ b/content/self-host/rustdesk-server-oss/_index.zh-cn.md @@ -2,7 +2,7 @@ title: 自建服务器开源版 weight: 100 pre: "2.1. " -description: "RustDesk 的自建服务器开源版文档,提供安装、配置、部署和故障排查指南。" +description: "RustDesk Server OSS 是免费开源的自建服务器版本。本文介绍它包含哪些组件、何时选择开源版而非专业版,以及如何用 Docker 或直接在 Linux 上安装运行 ID 服务器(hbbs)与中继服务器(hbbr),搭建属于自己的远程桌面服务。" keywords: ["rustdesk server oss", "rustdesk open source server", "self-hosted rustdesk server", "rustdesk hbbs", "rustdesk hbbr", "rustdesk docker", "rustdesk server install", "rustdesk relay server", "rustdesk id server", "rustdesk community self-hosting"] --- diff --git a/content/self-host/rustdesk-server-oss/_index.zh-tw.md b/content/self-host/rustdesk-server-oss/_index.zh-tw.md index 0b260abe..46cd9826 100755 --- a/content/self-host/rustdesk-server-oss/_index.zh-tw.md +++ b/content/self-host/rustdesk-server-oss/_index.zh-tw.md @@ -2,7 +2,7 @@ title: RustDesk Server OSS weight: 100 pre: "2.1. " -description: "RustDesk 的RustDesk Server OSS文檔,提供安裝、設定、部署與疑難排解指南。" +description: "RustDesk Server OSS 是免費開源的自架伺服器版本。本文說明它包含哪些元件、何時選擇開源版而非專業版,以及如何用 Docker 或直接在 Linux 上安裝執行 ID 伺服器(hbbs)和中繼伺服器(hbbr),架設屬於自己的遠端桌面服務。" keywords: ["rustdesk server oss", "rustdesk open source server", "self-hosted rustdesk server", "rustdesk hbbs", "rustdesk hbbr", "rustdesk docker", "rustdesk server install", "rustdesk relay server", "rustdesk id server", "rustdesk community self-hosting"] --- diff --git a/content/self-host/rustdesk-server-pro/audit-logs/_index.ja.md b/content/self-host/rustdesk-server-pro/audit-logs/_index.ja.md index 6fa06a55..2699dbfd 100644 --- a/content/self-host/rustdesk-server-pro/audit-logs/_index.ja.md +++ b/content/self-host/rustdesk-server-pro/audit-logs/_index.ja.md @@ -1,7 +1,7 @@ --- title: 監査ログ weight: 19 -description: "RustDesk Server Pro の Web コンソールで監査ログを使用し、接続、ファイル転送、コンソール操作、アラームイベントを確認します。" +description: "RustDesk Server Pro の Web コンソールで監査ログを使う方法です。接続履歴、ファイル転送、コンソール操作、アラームイベントを確認し、いつ誰がどの端末にアクセスしたかを追跡して、セキュリティ監査やトラブル調査に役立てられます。" keywords: ["rustdesk audit logs", "rustdesk server pro logs", "rustdesk connection logs", "rustdesk file transfer logs", "rustdesk alarm logs", "rustdesk console audit"] --- diff --git a/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-cn.md b/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-cn.md index 1435eaf4..ea3870f3 100644 --- a/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-cn.md +++ b/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-cn.md @@ -1,7 +1,7 @@ --- title: 审计日志 weight: 19 -description: "在 RustDesk Server Pro Web 控制台中使用审计日志,查看连接、文件传输、控制台操作和风险异常报警事件。" +description: "介绍如何在 RustDesk Server Pro 的 Web 控制台中使用审计日志:按时间和设备查看连接记录、文件传输、控制台操作和风险异常报警事件,追踪谁在何时访问了哪台设备、做了哪些操作,便于企业开展安全审计、事后追溯与日常问题排查。" keywords: ["rustdesk audit logs", "rustdesk server pro logs", "rustdesk connection logs", "rustdesk file transfer logs", "rustdesk alarm logs", "rustdesk console audit"] --- diff --git a/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-tw.md b/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-tw.md index fd0a467b..84cd735d 100644 --- a/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-tw.md +++ b/content/self-host/rustdesk-server-pro/audit-logs/_index.zh-tw.md @@ -1,7 +1,7 @@ --- title: 稽核日誌 weight: 19 -description: "在 RustDesk Server Pro Web 主控台中使用稽核日誌,檢視連線、檔案傳輸、主控台操作和風險異常警報事件。" +description: "介紹如何在 RustDesk Server Pro 的 Web 主控台中使用稽核日誌:依時間與裝置檢視連線紀錄、檔案傳輸、主控台操作與風險異常警報事件,追蹤誰在何時存取了哪台裝置、做了哪些操作,方便企業進行安全稽核、事後追溯與日常問題排查。" keywords: ["rustdesk audit logs", "rustdesk server pro logs", "rustdesk connection logs", "rustdesk file transfer logs", "rustdesk alarm logs", "rustdesk console audit"] --- diff --git a/content/self-host/rustdesk-server-pro/oidc/_index.zh-cn.md b/content/self-host/rustdesk-server-pro/oidc/_index.zh-cn.md index 587ed84a..2e68bfe3 100644 --- a/content/self-host/rustdesk-server-pro/oidc/_index.zh-cn.md +++ b/content/self-host/rustdesk-server-pro/oidc/_index.zh-cn.md @@ -1,7 +1,7 @@ --- title: OIDC weight: 16 -description: "RustDesk 的OIDC文档,提供安装、配置、部署和故障排查指南。" +description: "在 RustDesk Server Pro 中配置 OpenID Connect(OIDC)单点登录,让用户使用 Google、Okta、Azure、GitHub、GitLab 等身份提供商的账号登录,并说明回调地址、客户端 ID 与密钥等关键设置。" keywords: ["rustdesk oidc", "rustdesk openid connect", "rustdesk sso", "rustdesk azure login", "rustdesk okta login", "rustdesk github login"] --- diff --git a/content/self-host/rustdesk-server-pro/oidc/_index.zh-tw.md b/content/self-host/rustdesk-server-pro/oidc/_index.zh-tw.md index f7516995..f22f2c8c 100644 --- a/content/self-host/rustdesk-server-pro/oidc/_index.zh-tw.md +++ b/content/self-host/rustdesk-server-pro/oidc/_index.zh-tw.md @@ -1,7 +1,7 @@ --- title: OIDC weight: 16 -description: "RustDesk 的OIDC文檔,提供安裝、設定、部署與疑難排解指南。" +description: "在 RustDesk Server Pro 中設定 OpenID Connect(OIDC)單一登入,讓使用者以 Google、Okta、Azure、GitHub、GitLab 等身分提供者的帳號登入,並說明回呼網址、用戶端 ID 與密鑰等關鍵設定。" keywords: ["rustdesk oidc", "rustdesk openid connect", "rustdesk sso", "rustdesk azure login", "rustdesk okta login", "rustdesk github login"] --- diff --git a/deploy.sh b/deploy.sh index 32d6f491..e68c2fdc 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash rm -rf public/* hugo --minify +# Bing flags meta descriptions outside ~120-160 characters; see the script. +node scripts/fit-meta-descriptions.mjs public cd public; tar czf x * scp x ot:/tmp/ ssh ot "sudo rm -rf /var/www/html/rustdesk.com/docs/* && sudo tar xzf /tmp/x -C /var/www/html/rustdesk.com/docs/ && /bin/rm /tmp/x && sudo chown www-data:www-data /var/www/html/rustdesk.com/docs/ -R" diff --git a/scripts/fit-meta-descriptions.mjs b/scripts/fit-meta-descriptions.mjs new file mode 100644 index 00000000..59a186d3 --- /dev/null +++ b/scripts/fit-meta-descriptions.mjs @@ -0,0 +1,225 @@ +#!/usr/bin/env node +/** + * Brings every page's meta description into 120-160 characters, after the + * site is built. Used by both builds: the Hugo docs (public/) and the Astro + * site (v3/dist/). + * + * node scripts/fit-meta-descriptions.mjs [--check] + * + * Why after the build: Bing Webmaster Tools flags descriptions that are too + * short (in practice anything under roughly 90 characters; it asks for + * 150-160) and it counts characters, so most Chinese, Japanese and Korean + * pages fail even when they read fine. Hand-written descriptions stay the + * source: this only steps in when one is out of range, so fixing the front + * matter or page metadata is always the better fix. + * + * - Too short: append the page's own opening sentences, taken from its + *
(or
), until the text reaches the range. + * - Too long: cut at the last sentence end that fits, else at a clause or + * word boundary with an ellipsis. + * + * og:description and twitter:description follow when they carried the same + * text. --check reports without writing; --diff also prints each change. + */ +import { readdir, readFile, writeFile, lstat } from "node:fs/promises"; +import path from "node:path"; + +const MIN = 120; +const MAX = 160; + +const [root, flag] = process.argv.slice(2); +if (!root) { + console.error("usage: fit-meta-descriptions.mjs [--check]"); + process.exit(2); +} +const DIFF = flag === "--diff"; +const CHECK = flag === "--check" || DIFF; + +/** Characters as Bing counts them: code points, not UTF-16 units. */ +const len = (s) => [...s].length; +const cut = (s, n) => [...s].slice(0, n).join(""); + +const CJK = /[\u3000-\u303f\u3040-\u30ff\u3400-\u9fff\uac00-\ud7af\uf900-\ufaff\uff00-\uffef]/; +// Chinese and Japanese run sentences together; Korean spaces them like English. +const UNSPACED = /[\u3000-\u303f\u3040-\u30ff\u3400-\u9fff\uf900-\ufaff\uff00-\uffef]/; +const SENTENCE_END = /[.!?。!?]$/; + +const decode = (s) => + s + .replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(+n)) + .replace(/&#x([0-9a-f]+);/gi, (_, n) => String.fromCodePoint(parseInt(n, 16))) + .replace(/"/g, '"') + .replace(/'|'/g, "'") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " ") + .replace(/&/g, "&"); + +const encode = (s) => + s.replace(/&/g, "&").replace(/"/g, """).replace(//g, ">"); + +const clean = (s) => + decode(s.replace(/<[^>]+>/g, " ")) + .replace(/\s+/g, " ") + .replace(/\s+([.,;:!?。,、;:!?))])/g, "$1") // "see SMTP." leaves "SMTP ." + .trim(); + +/** The page's own prose: paragraphs of the first
, else
. */ +function paragraphs(html) { + const body = + html.match(/][\s\S]*?<\/article>/)?.[0] ?? + html.match(/][\s\S]*?<\/main>/)?.[0] ?? + ""; + const prose = body.replace( + /<(script|style|pre|table|nav|header|footer|aside|figure|svg)[\s>][\s\S]*?<\/\1>/g, + " ", + ); + // The opening paragraphs summarise; deeper ones are steps and caveats. + return [...prose.matchAll(/][\s\S]*?<\/p>/g)] + .slice(0, 8) + .map((m) => clean(m[0])) + .filter((p) => !/['"]\s*\+|\{\{|\$\{/.test(p)) // template residue + .filter((p) => !/·/.test(p) || len(p) > 80) // "Jul 3 · RustDesk Team · 5 min read" + .filter((p) => (CJK.test(p) ? len(p) >= 15 : len(p) >= 40)); +} + +// A full stop ends a sentence only before whitespace, so "18.04" and "1.2.0" +// stay whole. +const sentences = (text) => + text + .split(/(?<=[.!?]["'”’))]?)\s+|(?<=[。!?])/) + .map((s) => s.trim()) + .filter(Boolean); + +/** Worth quoting: prose, not a command, a link or a lead-in to a list. */ +const quotable = (s) => + SENTENCE_END.test(s) && + (UNSPACED.test(s) ? len(s) >= 10 : len(s) >= 25) && + !/https?:|www\.|[`$<>{}=|\\]|\.\/|--|\b\w+\.(sh|exe|msi|yml|toml|json)\b/i.test(s) && + !/[::]$/.test(s) && + !/^\d+[.)、]/.test(s) && + !/following|below|as follows|以下|下面|下列|次の|다음|folgende|suivant|siguiente|seguinte|seguente|poniższ|următo/i.test(s); + +/** Close enough to say the same thing twice. */ +function overlaps(a, b) { + const grams = (s) => { + const t = s.toLowerCase().replace(/\s+/g, ""); + const out = new Set(); + for (let i = 0; i < t.length - 2; i++) out.add(t.slice(i, i + 3)); + return out; + }; + const A = grams(a); + const B = grams(b); + if (!A.size || !B.size) return false; + let shared = 0; + for (const g of B) if (A.has(g)) shared++; + return shared / B.size > 0.5; +} + +function shorten(text) { + if (len(text) <= MAX) return text; + const head = cut(text, MAX); + // A whole sentence that still clears the minimum reads best. + const ends = [...head.matchAll(/[.!?。!?](?=\s|$)|[。!?]/g)].map((m) => m.index + 1); + const sentenceEnd = ends.filter((i) => len(head.slice(0, i)) >= MIN).at(-1); + if (sentenceEnd) return head.slice(0, sentenceEnd).trim(); + // Otherwise a clause or a word, with an ellipsis. + const room = cut(text, MAX - 1); + const breaks = [...room.matchAll(/[,;:,、;:]|\s/g)].map((m) => m.index); + const at = breaks.filter((i) => len(room.slice(0, i)) >= MIN - 20).at(-1); + const body = (at ? room.slice(0, at) : room).replace(/[\s,;:,、;:—–-]+$/, ""); + return `${body}…`; +} + +function extend(text, paras) { + let out = text.trim(); + let overflow = null; + const join = (a, b) => { + const ended = SENTENCE_END.test(a) ? a : `${a}${UNSPACED.test(a.at(-1)) ? "。" : "."}`; + // No space after a full-width stop, or between two Chinese/Japanese sentences. + return /[。!?]$/.test(ended) || (UNSPACED.test(ended.at(-1)) && UNSPACED.test(b[0])) + ? `${ended}${b}` + : `${ended} ${b}`; + }; + // Whole sentences first, in page order. One that would overflow is skipped + // for the next, so the result ends on a full stop wherever possible. + for (const s of paras.flatMap(sentences).filter(quotable)) { + if (len(out) >= MIN) break; + if (overlaps(out, s) || overlaps(s, out)) continue; + const joined = join(out, s); + if (len(joined) <= MAX) out = joined; + else overflow ??= joined; + } + if (len(out) < MIN && overflow) out = shorten(overflow); + return out; +} + +export function fit(description, html) { + const d = description.replace(/\s+/g, " ").trim(); + if (len(d) > MAX) return shorten(d); + if (len(d) < MIN) return extend(d, paragraphs(html)); + return d; +} + +// ------------------------------------------------------------------ the walk + +const META = /]*>/gi; +const attr = (tag, name) => + tag.match(new RegExp(`\\s${name}=(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i"))?.slice(1).find((v) => v !== undefined); + +function setContent(tag, value) { + const encoded = `content="${encode(value)}"`; + return tag.replace(/\scontent=(?:"[^"]*"|'[^']*'|[^\s>]+)/i, ` ${encoded}`); +} + +async function* htmlFiles(dir) { + for (const entry of await readdir(dir)) { + const p = path.join(dir, entry); + const st = await lstat(p); + if (st.isSymbolicLink()) continue; // web client, self-host docs: not ours to rewrite + if (st.isDirectory()) yield* htmlFiles(p); + else if (entry.endsWith(".html")) yield p; + } +} + +const stats = { pages: 0, inRange: 0, extended: 0, shortened: 0, stillShort: [], missing: 0 }; + +for await (const file of htmlFiles(root)) { + const html = await readFile(file, "utf8"); + if (/http-equiv=["']?refresh/i.test(html)) continue; // redirect stubs + const tags = html.match(META) ?? []; + const main = tags.find((t) => (attr(t, "name") ?? "").toLowerCase() === "description"); + if (!main) { + stats.missing++; + continue; + } + stats.pages++; + const before = decode(attr(main, "content") ?? ""); + const after = fit(before, html); + if (after === before.replace(/\s+/g, " ").trim()) { + if (len(after) >= MIN && len(after) <= MAX) stats.inRange++; + else stats.stillShort.push(`${len(after)} ${path.relative(root, file)}`); + continue; + } + if (len(after) > len(before)) stats.extended++; + else stats.shortened++; + if (len(after) < MIN) stats.stillShort.push(`${len(after)} ${path.relative(root, file)}`); + if (DIFF) console.log(`\n${path.relative(root, file)}\n - ${len(before)} ${before}\n + ${len(after)} ${after}`); + if (CHECK) continue; + + const updated = html.replace(META, (tag) => { + const key = (attr(tag, "name") ?? attr(tag, "property") ?? "").toLowerCase(); + if (!["description", "og:description", "twitter:description"].includes(key)) return tag; + if (key !== "description" && decode(attr(tag, "content") ?? "") !== before) return tag; + return setContent(tag, after); + }); + await writeFile(file, updated); +} + +console.log( + `[meta] ${stats.pages} pages: ${stats.inRange} already ${MIN}-${MAX}, ` + + `${stats.extended} extended, ${stats.shortened} shortened, ` + + `${stats.stillShort.length} still out of range, ${stats.missing} without a description` + + (CHECK ? " (check only, nothing written)" : ""), +); +for (const line of stats.stillShort) console.log(` ${line}`); diff --git a/scripts/indexnow.mjs b/scripts/indexnow.mjs new file mode 100644 index 00000000..de131754 --- /dev/null +++ b/scripts/indexnow.mjs @@ -0,0 +1,77 @@ +#!/usr/bin/env node +/** + * Tells Bing (and the other IndexNow engines) to recrawl rustdesk.com now, + * instead of waiting for its own schedule. ChatGPT search leans on Bing's + * index, so this is how a fix reaches AI answers quickly. + * + * node scripts/indexnow.mjs # the site and the docs + * node scripts/indexnow.mjs site # rustdesk.com only (v3) + * node scripts/indexnow.mjs docs # rustdesk.com/docs only (Hugo) + * + * Run it AFTER a deploy: the engines verify the request by fetching the key + * file from the live site, and judge the pages as they are served. The URL + * list is read from the live sitemaps for the same reason. The two deploy + * workflows run it as their last step, each for its own half. + * + * The key is the name of the one file v3/public/<32 hex>.txt, published at + * https://rustdesk.com/.txt. One key covers the whole host, docs + * included. Google does not take part in IndexNow. + */ +import { readdir } from "node:fs/promises"; +import path from "node:path"; + +const ROOT = path.resolve(import.meta.dirname, ".."); +const ORIGIN = "https://rustdesk.com"; +const SITEMAPS = { + site: `${ORIGIN}/sitemap-index.xml`, + docs: `${ORIGIN}/docs/sitemap.xml`, +}; + +const which = process.argv[2] ?? "all"; +if (!["all", "site", "docs"].includes(which)) { + console.error("usage: indexnow.mjs [all|site|docs]"); + process.exit(2); +} + +const keyFile = (await readdir(path.join(ROOT, "v3/public"))).find((f) => /^[0-9a-f]{32}\.txt$/.test(f)); +if (!keyFile) { + console.error("[indexnow] no v3/public/.txt found"); + process.exit(1); +} +const key = keyFile.replace(/\.txt$/, ""); +const keyLocation = `${ORIGIN}/${keyFile}`; + +const live = await fetch(keyLocation).then((r) => (r.ok ? r.text() : null)).catch(() => null); +if (live?.trim() !== key) { + console.error(`[indexnow] ${keyLocation} is not live yet. Deploy the site first.`); + process.exit(1); +} + +/** Every under a sitemap, following sitemap indexes. */ +async function urlsOf(sitemap) { + const xml = await fetch(sitemap).then((r) => r.text()); + const locs = [...xml.matchAll(/\s*([^<\s]+)\s*<\/loc>/g)].map((m) => m[1]); + if (!/ u.startsWith(`${ORIGIN}/`)); + +// One request takes up to 10,000 URLs. +for (let i = 0; i < urlList.length; i += 10000) { + const batch = urlList.slice(i, i + 10000); + const res = await fetch("https://api.indexnow.org/indexnow", { + method: "POST", + headers: { "Content-Type": "application/json; charset=utf-8" }, + body: JSON.stringify({ host: new URL(ORIGIN).host, key, keyLocation, urlList: batch }), + }); + // 200 and 202 both mean accepted; 202 is "key validation pending". + console.log(`[indexnow] ${batch.length} URLs (${which}) submitted: HTTP ${res.status}`); + if (!res.ok) process.exit(1); +} diff --git a/v3/build.sh b/v3/build.sh index f116dcb9..4d355a20 100755 --- a/v3/build.sh +++ b/v3/build.sh @@ -14,5 +14,7 @@ ln -s ../currencies.json ln -s ../v2/web cp -rf ../zh ./ + # Bing flags meta descriptions outside ~120-160 characters; see the script. + node ../../scripts/fit-meta-descriptions.mjs . tar czf x * mv x .. diff --git a/v3/public/de7a94336aa4d69a4e65220729f78691.txt b/v3/public/de7a94336aa4d69a4e65220729f78691.txt new file mode 100644 index 00000000..49a98a01 --- /dev/null +++ b/v3/public/de7a94336aa4d69a4e65220729f78691.txt @@ -0,0 +1 @@ +de7a94336aa4d69a4e65220729f78691 \ No newline at end of file diff --git a/v3/src/i18n/blog.ts b/v3/src/i18n/blog.ts index 40cdbb69..fe889c96 100644 --- a/v3/src/i18n/blog.ts +++ b/v3/src/i18n/blog.ts @@ -3,6 +3,8 @@ import { DEFAULT_LOCALE, type Lang } from '@/i18n'; export interface BlogCopy { title: string; subtitle: string; + /** Meta description of the blog index: 120-160 characters (Bing). */ + description: string; page: string; newerPosts: string; olderPosts: string; @@ -21,66 +23,77 @@ const copy: Record = { en: { title: 'The Blog', subtitle: 'News, tutorials, resources, and product updates from RustDesk.', + description: 'The RustDesk blog: news and tutorials for the open-source remote desktop, plus comparisons, self-hosted deployment, security, pricing and troubleshooting.', page: 'Page', newerPosts: 'Newer posts', olderPosts: 'Older posts', updated: 'Updated', minRead: 'min read', backToBlog: 'Back to Blog', relatedPosts: 'Related Posts', viewAllPosts: 'View All Posts', category: 'Category', tag: 'Tag', share: 'Share', newPost: 'New', }, de: { - title: 'Der Blog', subtitle: 'Neuigkeiten, Anleitungen, Ressourcen und Produktupdates von RustDesk.', page: 'Seite', + title: 'Der Blog', subtitle: 'Neuigkeiten, Anleitungen, Ressourcen und Produktupdates von RustDesk.', + description: 'Der RustDesk-Blog: Neues und Anleitungen zum Open-Source-Remote-Desktop, Vergleiche, selbst gehostete Bereitstellung, Sicherheit, Preise und Fehlerbehebung.', page: 'Seite', newerPosts: 'Neuere Beiträge', olderPosts: 'Ältere Beiträge', updated: 'Aktualisiert', minRead: 'Min. Lesezeit', backToBlog: 'Zurück zum Blog', relatedPosts: 'Ähnliche Beiträge', viewAllPosts: 'Alle Beiträge anzeigen', category: 'Kategorie', tag: 'Tag', share: 'Teilen', newPost: 'Neu', }, es: { - title: 'El blog', subtitle: 'Noticias, tutoriales, recursos y actualizaciones de RustDesk.', page: 'Página', + title: 'El blog', subtitle: 'Noticias, tutoriales, recursos y actualizaciones de RustDesk.', + description: 'Blog de RustDesk: novedades y tutoriales del escritorio remoto de código abierto, comparativas, autoalojamiento, seguridad, precios y solución de problemas.', page: 'Página', newerPosts: 'Publicaciones más recientes', olderPosts: 'Publicaciones anteriores', updated: 'Actualizado', minRead: 'min de lectura', backToBlog: 'Volver al blog', relatedPosts: 'Publicaciones relacionadas', viewAllPosts: 'Ver todas las publicaciones', category: 'Categoría', tag: 'Etiqueta', share: 'Compartir', newPost: 'Nuevo', }, fr: { - title: 'Le blog', subtitle: 'Actualités, tutoriels, ressources et mises à jour de RustDesk.', page: 'Page', + title: 'Le blog', subtitle: 'Actualités, tutoriels, ressources et mises à jour de RustDesk.', + description: 'Le blog RustDesk : actualités et tutoriels sur le bureau à distance open source, comparatifs, déploiement auto-hébergé, sécurité, tarifs et dépannage.', page: 'Page', newerPosts: 'Articles plus récents', olderPosts: 'Articles plus anciens', updated: 'Mis à jour', minRead: 'min de lecture', backToBlog: 'Retour au blog', relatedPosts: 'Articles associés', viewAllPosts: 'Voir tous les articles', category: 'Catégorie', tag: 'Étiquette', share: 'Partager', newPost: 'Nouveau', }, it: { - title: 'Il blog', subtitle: 'Notizie, tutorial, risorse e aggiornamenti di RustDesk.', page: 'Pagina', + title: 'Il blog', subtitle: 'Notizie, tutorial, risorse e aggiornamenti di RustDesk.', + description: 'Blog di RustDesk: novità, tutorial, confronti con TeamViewer e AnyDesk, guide self-hosted, sicurezza, licenze e soluzioni per il desktop remoto open source.', page: 'Pagina', newerPosts: 'Articoli più recenti', olderPosts: 'Articoli meno recenti', updated: 'Aggiornato', minRead: 'min di lettura', backToBlog: 'Torna al blog', relatedPosts: 'Articoli correlati', viewAllPosts: 'Vedi tutti gli articoli', category: 'Categoria', tag: 'Etichetta', share: 'Condividi', newPost: 'Novità', }, ja: { - title: 'ブログ', subtitle: 'RustDesk のニュース、チュートリアル、資料、製品アップデート。', page: 'ページ', + title: 'ブログ', subtitle: 'RustDesk のニュース、チュートリアル、資料、製品アップデート。', + description: 'RustDesk公式ブログでは、製品ニュースやリリース情報、チュートリアル、TeamViewerやAnyDeskとの比較、セルフホストサーバーの導入ガイド、リモートデスクトップのセキュリティ、ライセンスと料金、トラブルシューティングの記事を掲載。オープンソースのRustDeskの選定や運用に役立ちます。', page: 'ページ', newerPosts: '新しい記事', olderPosts: '過去の記事', updated: '更新', minRead: '分で読めます', backToBlog: 'ブログに戻る', relatedPosts: '関連記事', viewAllPosts: 'すべての記事を見る', category: 'カテゴリー', tag: 'タグ', share: '共有', newPost: '新着', }, ko: { - title: '블로그', subtitle: 'RustDesk의 뉴스, 튜토리얼, 자료 및 제품 업데이트입니다.', page: '페이지', + title: '블로그', subtitle: 'RustDesk의 뉴스, 튜토리얼, 자료 및 제품 업데이트입니다.', + description: 'RustDesk 공식 블로그입니다. 새 기능과 릴리스 소식, 튜토리얼, TeamViewer 및 AnyDesk 비교, 자체 호스팅 서버 배포 가이드, 보안과 사기 예방, 라이선스와 가격, 문제 해결까지 오픈소스 원격 데스크톱 운영에 필요한 정보를 한곳에 모았습니다.', page: '페이지', newerPosts: '최신 글', olderPosts: '이전 글', updated: '업데이트', minRead: '분 소요', backToBlog: '블로그로 돌아가기', relatedPosts: '관련 글', viewAllPosts: '모든 글 보기', category: '카테고리', tag: '태그', share: '공유', newPost: '새 글', }, pt: { - title: 'O blog', subtitle: 'Notícias, tutoriais, recursos e atualizações do RustDesk.', page: 'Página', + title: 'O blog', subtitle: 'Notícias, tutoriais, recursos e atualizações do RustDesk.', + description: 'Blog do RustDesk sobre acesso remoto de código aberto: notícias, tutoriais, TeamViewer e AnyDesk comparados, auto-hospedagem, segurança, licenças e soluções.', page: 'Página', newerPosts: 'Publicações mais recentes', olderPosts: 'Publicações anteriores', updated: 'Atualizado', minRead: 'min de leitura', backToBlog: 'Voltar ao blog', relatedPosts: 'Publicações relacionadas', viewAllPosts: 'Ver todas as publicações', category: 'Categoria', tag: 'Etiqueta', share: 'Compartilhar', newPost: 'Novo', }, 'zh-cn': { - title: '博客', subtitle: 'RustDesk 新闻、教程、资源和产品更新。', page: '第', newerPosts: '较新文章', olderPosts: '较早文章', + title: '博客', subtitle: 'RustDesk 新闻、教程、资源和产品更新。', + description: 'RustDesk 官方博客,汇集产品新闻与功能发布(如 Web 客户端和 Wayland 无人值守访问)、上手教程、与 TeamViewer 和 AnyDesk 等工具的对比、自建服务器部署指南,以及远程桌面安全、许可计费和故障排除文章,帮助你全面了解这款开源软件。', page: '第', newerPosts: '较新文章', olderPosts: '较早文章', updated: '更新于', minRead: '分钟阅读', backToBlog: '返回博客', relatedPosts: '相关文章', viewAllPosts: '查看所有文章', category: '分类', tag: '标签', share: '分享', newPost: '最新', }, 'zh-tw': { - title: '部落格', subtitle: 'RustDesk 新聞、教學、資源與產品更新。', page: '第', newerPosts: '較新文章', olderPosts: '較早文章', + title: '部落格', subtitle: 'RustDesk 新聞、教學、資源與產品更新。', + description: 'RustDesk 官方部落格,收錄產品新聞與新功能發布(例如網頁用戶端、Wayland 無人值守存取)、操作教學、與 TeamViewer、AnyDesk 等工具的比較、自架伺服器部署指南,以及遠端桌面資安、授權計費與疑難排解文章,帶你全面認識這套開源軟體。', page: '第', newerPosts: '較新文章', olderPosts: '較早文章', updated: '更新於', minRead: '分鐘閱讀', backToBlog: '返回部落格', relatedPosts: '相關文章', viewAllPosts: '查看所有文章', category: '分類', tag: '標籤', share: '分享', newPost: '最新', }, ar: { - title: 'المدونة', subtitle: 'أخبار RustDesk وشروحاتها ومواردها وتحديثات منتجاتها.', page: 'الصفحة', + title: 'المدونة', subtitle: 'أخبار RustDesk وشروحاتها ومواردها وتحديثات منتجاتها.', + description: 'مدونة RustDesk: أخبار وشروحات ومقارنات مع TeamViewer وAnyDesk، وأدلة نشر الخادم ذاتي الاستضافة، والأمان والترخيص وحل مشكلات سطح المكتب البعيد مفتوح المصدر.', page: 'الصفحة', newerPosts: 'منشورات أحدث', olderPosts: 'منشورات أقدم', updated: 'حُدّث في', minRead: 'دقائق للقراءة', backToBlog: 'العودة إلى المدونة', relatedPosts: 'منشورات ذات صلة', viewAllPosts: 'عرض جميع المنشورات', category: 'الفئة', tag: 'الوسم', share: 'مشاركة', newPost: 'جديد', diff --git a/v3/src/pages/[...blog]/[...page].astro b/v3/src/pages/[...blog]/[...page].astro index 5b521fdf..268a745a 100644 --- a/v3/src/pages/[...blog]/[...page].astro +++ b/v3/src/pages/[...blog]/[...page].astro @@ -28,7 +28,7 @@ const copy = getBlogCopy(lang); const metadata = { title: `${copy.title}${currentPage > 1 ? ` — ${copy.page} ${currentPage}` : ''}`, - description: copy.subtitle, + description: copy.description, robots: { index: blogListRobots?.index && currentPage === 1, follow: blogListRobots?.follow, diff --git a/v3/src/pages/[...blog]/[category]/[...page].astro b/v3/src/pages/[...blog]/[category]/[...page].astro index 7c3078a7..10844d97 100644 --- a/v3/src/pages/[...blog]/[category]/[...page].astro +++ b/v3/src/pages/[...blog]/[category]/[...page].astro @@ -1,6 +1,6 @@ --- import type { InferGetStaticPropsType, GetStaticPaths } from 'astro'; -import { blogCategoryRobots, getStaticPathsBlogCategory } from '~/utils/blog'; +import { blogCategoryRobots, fetchPosts, getStaticPathsBlogCategory } from '~/utils/blog'; import Layout from '~/layouts/PageLayout.astro'; import BlogList from '~/components/blog/List.astro'; @@ -26,160 +26,174 @@ const categorySlug = String(category.slug ?? '').toLowerCase(); const localizedCategoryDescriptions: Record> = { en: { alternatives: - 'Evaluate self-hosted and open-source alternatives by deployment model, licensing, security, workflow fit, and migration effort.', + 'Articles on replacing TeamViewer, AnyDesk or Chrome Remote Desktop with a self-hosted, open-source remote desktop: licensing, security and migration.', comparisons: - 'Compare RustDesk with remote-access products and protocols using current requirements, explicit trade-offs, and proof-of-concept criteria.', + 'Head-to-head remote desktop comparisons of RustDesk, TeamViewer, AnyDesk, ScreenConnect, Splashtop, RDP and VNC: features, security, licensing, self-hosting.', deployment: - 'Plan and operate RustDesk deployments, from server sizing and networking to identity, access control, client rollout, and recovery.', + 'Self-hosted RustDesk in practice: large device fleets, unattended access, unknown devices in the console, and whether Server Pro can run offline or air-gapped.', guides: - 'Practical guides for evaluating, configuring, and operating RustDesk across platforms, teams, and deployment models.', + 'Practical RustDesk guides for Linux, Android and iOS, MSPs and enterprise IT, plus why teams self-host remote desktop and which free tools suit business use.', pricing: - 'Understand RustDesk licensing, users, managed devices, concurrency, purchase terms, upgrades, and evaluation options.', + 'Answers to licensing questions on self-hosted RustDesk Server Pro, such as what counts as a login user or managed device and how mid-term upgrades work.', security: - 'Assess remote-access security, data flows, scams, vulnerabilities, access controls, and deployment hardening without absolute compliance claims.', + 'Remote desktop security without the hype: how scams work, how safe AnyDesk and Chrome Remote Desktop are, and what self-hosting can and cannot do for GDPR.', troubleshooting: - 'Diagnose connection, display, configuration, and licensing symptoms with targeted checks and safe escalation paths.', + 'Fixes for common remote desktop errors, from RustDesk stuck on waiting for image to TeamViewer and AnyDesk commercial-use flags, with checks to run first.', }, de: { alternatives: - 'Bewerte selbst gehostete und Open-Source-Alternativen nach Bereitstellungsmodell, Lizenzierung, Sicherheit, Workflow-Fit und Migrationsaufwand.', + 'Alternativen zu TeamViewer, AnyDesk und Chrome Remote Desktop: was ein selbst gehosteter Open-Source-Remote-Desktop bei Lizenz, Sicherheit und Umstieg ändert.', comparisons: - 'Vergleiche RustDesk mit Remote-Access-Produkten und -Protokollen anhand aktueller Anforderungen, klarer Abwägungen und Proof-of-Concept-Kriterien.', + 'Remote-Desktop-Tools im Vergleich: RustDesk, TeamViewer, AnyDesk, ScreenConnect, Splashtop, RDP und VNC nach Funktionen, Sicherheit, Lizenz und Self-Hosting.', deployment: - 'Plane und betreibe RustDesk-Bereitstellungen, von Server-Größe und Netzwerk bis zu Identität, Zugriffskontrolle, Client-Rollout und Wiederherstellung.', + 'Selbst gehostetes RustDesk in der Praxis: große Geräteflotten, unbeaufsichtigter Zugriff, unbekannte Geräte und ob Server Pro offline oder air-gapped läuft.', guides: - 'Praktische Anleitungen zum Bewerten, Konfigurieren und Betreiben von RustDesk auf verschiedenen Plattformen, in Teams und in unterschiedlichen Bereitstellungsmodellen.', + 'Praxisanleitungen zu RustDesk unter Linux, Android und iOS, für MSPs und Unternehmens-IT, dazu Gründe fürs Self-Hosting und kostenlose Remote-Desktop-Tools.', pricing: - 'Verstehe RustDesk-Lizenzierung, Nutzer, verwaltete Geräte, Gleichzeitigkeit, Kaufbedingungen, Upgrades und Testoptionen.', + 'Lizenzfragen zu RustDesk Server Pro geklärt, etwa was als Benutzer oder verwaltetes Gerät zählt und wie Upgrades und gleichzeitige Verbindungen funktionieren.', security: - 'Beurteile Sicherheit, Datenflüsse, Betrugsversuche, Schwachstellen, Zugriffskontrollen und Härtung für Remote-Zugriffe ohne pauschale Compliance-Behauptungen.', + 'Sicherheit beim Fernzugriff ohne Schönfärberei: Betrugsmaschen erkennen, AnyDesk und Chrome Remote Desktop im Check, Self-Hosting und DSGVO nüchtern bewertet.', troubleshooting: - 'Diagnostiziere Verbindungs-, Anzeige-, Konfigurations- und Lizenzsymptome mit gezielten Prüfungen und sicheren Eskalationspfaden.', + 'Remote-Desktop-Fehler gezielt beheben, etwa wenn RustDesk bei Waiting for image hängt oder TeamViewer und AnyDesk eine kommerzielle Nutzung melden.', }, es: { alternatives: - 'Evalúa alternativas autoalojadas y de código abierto por modelo de despliegue, licencias, seguridad, ajuste al flujo de trabajo y esfuerzo de migración.', + 'Cómo sustituir TeamViewer, AnyDesk o Chrome Remote Desktop por un escritorio remoto autoalojado y de código abierto: licencias, seguridad y migración.', comparisons: - 'Compara RustDesk con productos y protocolos de acceso remoto usando requisitos actuales, compensaciones explícitas y criterios de prueba de concepto.', + 'Comparativas de escritorio remoto entre RustDesk, TeamViewer, AnyDesk, ScreenConnect, Splashtop, RDP y VNC: funciones, seguridad, licencias y autoalojamiento.', deployment: - 'Planifica y opera implementaciones de RustDesk, desde el tamaño del servidor y la red hasta la identidad, el control de acceso, el despliegue de clientes y la recuperación.', + 'Despliegue autoalojado de RustDesk: grandes flotas, acceso desatendido, equipos desconocidos y si RustDesk Server Pro puede funcionar sin conexión o aislado.', guides: - 'Guías prácticas para evaluar, configurar y operar RustDesk en distintas plataformas, equipos y modelos de despliegue.', + 'Guías de RustDesk para Linux, Android e iOS, MSP y TI corporativa, por qué autoalojar tu escritorio remoto y qué herramientas gratuitas sirven a una empresa.', pricing: - 'Entiende la licencia de RustDesk, usuarios, dispositivos gestionados, concurrencia, condiciones de compra, actualizaciones y opciones de evaluación.', + 'Licencias de RustDesk Server Pro: qué cuenta como usuario o dispositivo administrado, conexiones simultáneas y actualizaciones a mitad de suscripción.', security: - 'Evalúa la seguridad del acceso remoto, los flujos de datos, las estafas, las vulnerabilidades, los controles de acceso y el endurecimiento del despliegue sin afirmaciones absolutas de cumplimiento.', + 'Seguridad del escritorio remoto sin promesas absolutas: estafas, si AnyDesk y Chrome Remote Desktop son seguros y qué aporta autoalojar frente al RGPD.', troubleshooting: - 'Diagnostica síntomas de conexión, pantalla, configuración y licencias con comprobaciones dirigidas y rutas seguras de escalado.', + 'Errores de escritorio remoto resueltos paso a paso, como RustDesk atascado en esperando imagen o el aviso de uso comercial de TeamViewer y AnyDesk.', }, fr: { alternatives: - 'Évaluez les alternatives auto-hébergées et open source selon le modèle de déploiement, la licence, la sécurité, l’adéquation au flux de travail et l’effort de migration.', + 'Alternatives à TeamViewer, AnyDesk et Chrome Remote Desktop : ce que change un bureau à distance open source auto-hébergé en licence, sécurité et migration.', comparisons: - 'Comparez RustDesk avec des produits et protocoles d’accès à distance à l’aide d’exigences actuelles, de compromis explicites et de critères de preuve de concept.', + 'Comparatifs de bureau à distance entre RustDesk, TeamViewer, AnyDesk, ScreenConnect, Splashtop, RDP et VNC : fonctions, sécurité, licences, auto-hébergement.', deployment: - 'Planifiez et exploitez des déploiements RustDesk, du dimensionnement des serveurs et du réseau à l’identité, au contrôle d’accès, au déploiement client et à la reprise.', + 'Déploiement auto-hébergé de RustDesk : grands parcs, accès sans surveillance, appareils inconnus et Server Pro peut-il fonctionner hors ligne ou isolé ?', guides: - 'Guides pratiques pour évaluer, configurer et exploiter RustDesk sur différentes plateformes, pour diverses équipes et selon plusieurs modèles de déploiement.', + 'Guides RustDesk pour Linux, Android et iOS, les MSP et l’IT d’entreprise, plus pourquoi auto-héberger son bureau à distance et quels outils gratuits choisir.', pricing: - 'Comprenez la licence RustDesk, les utilisateurs, les appareils gérés, la concurrence, les conditions d’achat, les mises à niveau et les options d’évaluation.', + 'Licences RustDesk Server Pro expliquées, de la notion d’utilisateur et d’appareil géré aux connexions simultanées et à la mise à niveau en cours d’abonnement.', security: - 'Évaluez la sécurité de l’accès à distance, les flux de données, les arnaques, les vulnérabilités, les contrôles d’accès et le durcissement du déploiement sans affirmation de conformité absolue.', + 'Sécurité du bureau à distance, sans langue de bois : arnaques, AnyDesk et Chrome Remote Desktop au crible, ce que l’auto-hébergement règle ou non pour le RGPD.', troubleshooting: - 'Diagnostiquez les symptômes de connexion, d’affichage, de configuration et de licence avec des vérifications ciblées et des voies d’escalade sûres.', + 'Dépannage pas à pas quand RustDesk reste bloqué sur waiting for image ou que TeamViewer et AnyDesk signalent un usage commercial, avec les bons contrôles.', }, it: { alternatives: - 'Valuta alternative self-hosted e open source per modello di distribuzione, licenze, sicurezza, aderenza al flusso di lavoro e sforzo di migrazione.', + 'Alternative self-hosted e open source a TeamViewer, AnyDesk e Chrome Remote Desktop: come scegliere un desktop remoto per licenze, sicurezza e migrazione.', comparisons: - 'Confronta RustDesk con prodotti e protocolli di accesso remoto usando requisiti attuali, compromessi espliciti e criteri di prova di concetto.', + 'RustDesk a confronto con AnyDesk, TeamViewer, ScreenConnect, Splashtop, VNC e RDP: pro e contro reali del desktop remoto open source e self-hosted.', deployment: - 'Pianifica e gestisci distribuzioni RustDesk, dal dimensionamento del server e della rete fino a identità, controllo accessi, rollout dei client e ripristino.', + 'Mettere in produzione RustDesk self-hosted: accesso non presidiato, grandi flotte, dispositivi sconosciuti e se Server Pro funziona offline o air-gapped.', guides: - 'Guide pratiche per valutare, configurare e gestire RustDesk su piattaforme, team e modelli di distribuzione diversi.', + 'Guide pratiche a RustDesk su Linux, Android e iOS, per aziende con Active Directory e per MSP, e perché scegliere un desktop remoto self-hosted e open source.', pricing: - 'Comprendi la licenza RustDesk, gli utenti, i dispositivi gestiti, la concorrenza, i termini di acquisto, gli upgrade e le opzioni di valutazione.', + 'Licenze del desktop remoto self-hosted RustDesk Server Pro spiegate: dispositivi gestiti, utenti, connessioni simultanee e upgrade a metà abbonamento.', security: - 'Valuta sicurezza, flussi di dati, truffe, vulnerabilità, controlli di accesso e hardening del deployment senza affermazioni assolute di conformità.', + 'Sicurezza del desktop remoto senza promesse assolute: truffe, AnyDesk e Chrome Remote Desktop sotto esame, GDPR e sovranità dei dati con il self-hosting.', troubleshooting: - 'Diagnostica sintomi di connessione, schermo, configurazione e licenza con controlli mirati e percorsi di escalation sicuri.', + 'Soluzioni ai problemi di desktop remoto: RustDesk fermo in attesa dell\'immagine, avvisi di uso commerciale di AnyDesk e TeamViewer e quando chiedere aiuto.', }, ja: { alternatives: - 'デプロイ形態、ライセンス、セキュリティ、業務フローとの適合性、移行コストでセルフホスト型とオープンソースの代替案を評価します。', + 'TeamViewer、AnyDesk、Chrome Remote Desktopの代替を探すための記事集です。導入形態、ライセンス、セキュリティ、業務フローとの相性、移行の手間という観点で、セルフホスト型のオープンソース・リモートデスクトップを評価し、RustDeskで満たせる要件を整理します。', comparisons: - '最新の要件、明確なトレードオフ、PoC の基準を使って、RustDesk をリモートアクセス製品やプロトコルと比較します。', + '他のリモートアクセス製品やプロトコルとRustDeskを比べる記事です。TeamViewer、AnyDesk、ScreenConnect、RDP、VNCと機能、セキュリティ、ライセンスのトレードオフを整理し、セルフホスト型のオープンソース・リモートデスクトップが合うかをPoCで見極める基準も示します。', deployment: - 'サーバーの規模設計やネットワークから、ID 管理、アクセス制御、クライアント展開、復旧まで RustDesk の導入と運用を計画します。', - guides: 'RustDesk をさまざまなプラットフォーム、チーム、導入形態で評価・設定・運用するための実践ガイドです。', + 'オープンソースのリモートデスクトップRustDeskを導入・運用するための記事集です。無人アクセスの設定とクライアント展開、コンソールに見覚えのないデバイスが現れたときの調査、大規模展開の計画、セルフホストのRustDesk Server Proをオフラインやエアギャップ環境で使えるかを解説します。', + guides: '実践ガイドのカテゴリーです。LinuxでのインストールとX11、Waylandの違い、AndroidとiOSのリモート操作でできること、AD/LDAP連携、MSP向けのツール統合、無料のリモートデスクトップ選び、オープンソースのセルフホストへ移る際のコストまで、RustDeskの活用法を紹介します。', pricing: - 'RustDesk のライセンス、ユーザー数、管理デバイス、同時接続、購入条件、アップグレード、評価方法を理解します。', + '料金カテゴリーでは、オープンソースのリモートデスクトップRustDeskのセルフホスト用ライセンスと課金を解説します。管理対象デバイスの数え方、Customized V2でアドホックなデバイスが対象外になる理由、契約途中にユーザーやデバイスを追加したときの日割り計算と反映のタイミングを確認できます。', security: - 'リモートアクセスのセキュリティ、データフロー、詐欺、脆弱性、アクセス制御、導入時の強化策を、断定的な適合性主張なしで評価します。', - troubleshooting: '接続、表示、設定、ライセンスの症状を、的を絞った確認と安全なエスカレーション手順で切り分けます。', + 'リモートアクセスの安全性を検証する記事のカテゴリーです。リモートデスクトップ詐欺の見分け方と被害時の対処、AnyDeskとChrome Remote Desktopの暗号化とリスク、セルフホストでデータ主権やGDPRについて解決できることとできないこと、オープンソースのRustDeskの詐欺対策を扱います。', + troubleshooting: 'トラブル解決のための記事をまとめています。RustDeskで接続後に画面が表示されない原因をヘッドレス構成、スリープ、コーデック、ドライバーから切り分けるほか、TeamViewerやAnyDeskで商用利用と判定された際の公式手順と、オープンソースのセルフホスト型リモートデスクトップでの回避策も解説します。', }, ko: { alternatives: - '배포 방식, 라이선스, 보안, 업무 흐름 적합성, 마이그레이션 노력 기준으로 자체 호스팅 및 오픈소스 대안을 평가합니다.', + 'TeamViewer, AnyDesk, Chrome Remote Desktop을 대체할 자체 호스팅 오픈소스 원격 데스크톱을 찾고 있나요? 라이선스, 보안, 배포 방식, 업무 흐름 적합성, 마이그레이션 부담을 기준으로 RustDesk 같은 대안을 평가하는 방법을 정리했습니다.', comparisons: - '최신 요구사항, 명확한 트레이드오프, PoC 기준을 사용해 RustDesk를 원격 액세스 제품과 프로토콜과 비교합니다.', - deployment: '서버 규모와 네트워크부터 ID, 접근 제어, 클라이언트 배포, 복구까지 RustDesk 배포와 운영을 계획합니다.', - guides: '다양한 플랫폼, 팀, 배포 모델에서 RustDesk를 평가·구성·운영하는 실용 가이드입니다.', - pricing: 'RustDesk 라이선스, 사용자, 관리 장치, 동시성, 구매 조건, 업그레이드, 평가 옵션을 이해합니다.', + 'RustDesk를 AnyDesk, TeamViewer, ScreenConnect, Splashtop, VNC, RDP와 나란히 비교합니다. 자체 호스팅 오픈소스 원격 데스크톱의 장단점, NAT 통과와 코덱, 암호화 차이, PoC로 직접 검증할 기준까지 정리했습니다.', + deployment: '자체 호스팅 RustDesk를 실제 운영 환경에 배포하고 관리하는 방법을 다룹니다. 무인 원격 접속 설정, 대규모 기기 확장 계획, 콘솔의 낯선 기기 점검, RustDesk Server Pro를 오프라인이나 에어갭 환경에서 쓸 수 있는지까지 정리했습니다.', + guides: '리눅스, Android와 iOS, Active Directory를 쓰는 기업, 여러 고객사를 관리하는 MSP 환경에서 RustDesk를 활용하는 실전 가이드 모음입니다. 무료 원격 데스크톱 선택법과 오픈소스 솔루션을 자체 호스팅으로 운영해야 하는 이유도 설명합니다.', + pricing: 'RustDesk 라이선스 가이드입니다. 자체 호스팅 원격 데스크톱 RustDesk Server Pro에서 어떤 기기가 관리 기기로 계산되는지, 로그인 사용자 수와 동시 연결은 어떻게 적용되는지, 구독 도중 업그레이드할 때 요금은 어떻게 정산되는지 정리했습니다.', security: - '원격 액세스 보안, 데이터 흐름, 사기, 취약점, 접근 제어, 배포 강화 방안을 절대적인 준수 주장 없이 평가합니다.', - troubleshooting: '연결, 화면, 설정, 라이선스 증상을 집중 점검과 안전한 에스컬레이션 경로로 진단합니다.', + '과장 없는 원격 데스크톱 보안 가이드입니다. 원격 접속 사기를 알아채고 피하는 방법, RustDesk의 사기 대응, AnyDesk와 Chrome Remote Desktop의 암호화와 안전성 검토, GDPR과 데이터 주권을 위한 오픈소스 자체 호스팅까지 다룹니다.', + troubleshooting: '원격 데스크톱 연결이 막힐 때 참고할 문제 해결 가이드입니다. RustDesk가 연결 후 이미지 대기 중에 멈출 때 헤드리스, 절전, 코덱, 드라이버 등 원인별 해결법과 AnyDesk, TeamViewer 상업적 사용 감지 경고 대처법, 지원 요청 시점을 안내합니다.', }, pt: { alternatives: - 'Avalie alternativas auto-hospedadas e de código aberto por modelo de implantação, licenciamento, segurança, aderência ao fluxo de trabalho e esforço de migração.', + 'Alternativas auto-hospedadas e de código aberto ao TeamViewer, AnyDesk e Chrome Remote Desktop: licença, segurança, implantação e migração de acesso remoto.', comparisons: - 'Compare o RustDesk com produtos e protocolos de acesso remoto usando requisitos atuais, trocas explícitas e critérios de prova de conceito.', + 'RustDesk versus AnyDesk, TeamViewer, ScreenConnect, Splashtop, VNC e RDP: prós e contras da área de trabalho remota auto-hospedada e de código aberto.', deployment: - 'Planeje e opere implantações do RustDesk, do dimensionamento do servidor e da rede até identidade, controle de acesso, implantação de clientes e recuperação.', + 'Implantação do RustDesk auto-hospedado: acesso não assistido, grandes frotas, dispositivos desconhecidos no console e se o Server Pro roda offline ou isolado.', guides: - 'Guias práticos para avaliar, configurar e operar o RustDesk em diferentes plataformas, equipes e modelos de implantação.', + 'Guias de RustDesk para Linux, Android, iOS, empresas com Active Directory e MSPs, e por que usar uma área de trabalho remota auto-hospedada de código aberto.', pricing: - 'Entenda o licenciamento do RustDesk, usuários, dispositivos gerenciados, concorrência, termos de compra, upgrades e opções de avaliação.', + 'Licenciamento do RustDesk Server Pro auto-hospedado: o que conta como dispositivo gerenciado, usuários, conexões simultâneas e upgrade no meio da assinatura.', security: - 'Avalie a segurança de acesso remoto, fluxos de dados, golpes, vulnerabilidades, controles de acesso e endurecimento da implantação sem alegações absolutas de conformidade.', + 'Segurança em área de trabalho remota sem promessas absolutas: golpes de acesso remoto, análises do AnyDesk e Chrome Remote Desktop e GDPR com auto-hospedagem.', troubleshooting: - 'Diagnostique sintomas de conexão, tela, configuração e licenciamento com verificações direcionadas e caminhos seguros de escalonamento.', + 'Soluções para falhas de área de trabalho remota: RustDesk aguardando imagem, alertas de uso comercial do AnyDesk e TeamViewer e quando escalar o problema.', }, 'zh-cn': { - alternatives: '按部署模式、许可、安全性、工作流匹配度和迁移成本评估自托管与开源替代方案。', - comparisons: '使用当前需求、明确取舍和概念验证标准,将 RustDesk 与远程访问产品和协议进行比较。', - deployment: '规划和运行 RustDesk 部署,从服务器规格和网络,到身份、访问控制、客户端推广和恢复。', - guides: '用于在不同平台、团队和部署模式下评估、配置和运行 RustDesk 的实用指南。', - pricing: '了解 RustDesk 的许可、用户、受管设备、并发、购买条款、升级和评估选项。', - security: '在不做绝对合规断言的前提下,评估远程访问安全、数据流、诈骗、漏洞、访问控制和部署加固。', - troubleshooting: '通过有针对性的检查和安全的升级路径,诊断连接、显示、配置和许可问题。', + alternatives: '寻找 TeamViewer、AnyDesk 或 Chrome Remote Desktop 替代品的文章合集,帮助团队从部署方式、许可条款、安全性、日常工作流契合度和迁移成本出发,评估真正由自己掌控的开源、自建远程桌面方案,并说明 RustDesk 能满足哪些需求、又有哪些需要权衡。', + comparisons: '对比评测栏目:将 RustDesk 与 TeamViewer、AnyDesk、ScreenConnect、Splashtop 等产品,以及 RDP、VNC 等协议逐一比较,从功能、系统支持、安全性到授权模式讲清取舍,并给出概念验证阶段的评估要点,帮你判断开源、自建的远程桌面是否适合自己。', + deployment: '本分类聚焦开源远程桌面 RustDesk 的部署与运维:如何配置无人值守访问并分发预配置客户端,控制台出现陌生设备时应先排查什么,大规模设备群如何规划,以及自建的 RustDesk Server Pro 能否离线或在完全气隙隔离的环境中运行。', + guides: '实用指南栏目,帮你在不同平台和团队规模下用好 RustDesk:Linux 安装包选择与 X11、Wayland 的差异,Android 和 iOS 远程控制的真实能力,企业 AD/LDAP 集成与 MSP 工具整合,以及挑选免费商用远程桌面、转向开源自建方案前需要算清的账。', + pricing: '这里收录开源远程桌面 RustDesk 的许可与计费文章:解释受管设备如何计数、临时连接的设备在 Customized V2 套餐中为何不计入,订阅期内增加用户或设备时如何按比例计费、新额度如何生效(可在 Web 控制台刷新后立即启用),帮你在购买自建服务器许可证之前把成本算清楚。', + release: 'RustDesk 版本发布与开发动态:介绍 Wayland 下无人值守远程访问等新功能,以及我们如何让 Flutter 3.24 继续在 Windows 7 上运行,帮助你及时了解这款开源远程桌面软件及自建服务器部署的最新进展、兼容性变化与升级要点。', + security: '远程访问安全专题:教你识别远程桌面诈骗的危险信号以及中招后的应对步骤,客观评估 AnyDesk 与 Chrome Remote Desktop 的加密机制和风险,说明自建服务器在数据主权与 GDPR 方面能解决什么、不能解决什么,并介绍 RustDesk 这一开源项目的防诈措施。', + troubleshooting: '故障排除文章汇总:分析 RustDesk 连接成功却一直等待图像的常见原因,包括无头主机、休眠、编解码器和驱动程序,并给出相应的修复方法;也讲解 TeamViewer、AnyDesk 被判定为商业用途时的官方申诉流程,以及改用开源、自建远程桌面后如何从根本上避开这类问题。', }, 'zh-tw': { - alternatives: '依部署模式、授權、安全性、工作流程契合度與遷移成本,評估自架與開源替代方案。', - comparisons: '使用當前需求、明確取捨與概念驗證標準,將 RustDesk 與遠端存取產品和協定進行比較。', - deployment: '規劃並營運 RustDesk 部署,從伺服器規模與網路,到身分、存取控制、用戶端推廣與復原。', - guides: '協助在不同平台、團隊與部署模式下評估、設定與營運 RustDesk 的實用指南。', - pricing: '了解 RustDesk 的授權、使用者、受管裝置、同時連線、購買條款、升級與評估選項。', - security: '在不做絕對合規宣稱的前提下,評估遠端存取安全、資料流、詐騙、漏洞、存取控制與部署強化。', - troubleshooting: '透過有針對性的檢查與安全的升級路徑,診斷連線、顯示、設定與授權症狀。', + alternatives: '替代方案分類,專為想離開 TeamViewer、AnyDesk 或 Chrome Remote Desktop 的團隊整理:依部署方式、授權條款、安全性、工作流程契合度與遷移成本,協助你評估可自架、由自己掌控的開源遠端桌面工具,並說明 RustDesk 能滿足哪些需求、又有哪些取捨。', + comparisons: '比較評測分類:將 RustDesk 與 TeamViewer、AnyDesk、ScreenConnect、Splashtop 等產品,以及 RDP、VNC 等協定逐一對照,從功能、作業系統支援、安全性到授權模式說清取捨,並列出概念驗證的評估重點,幫你判斷自架的開源遠端桌面是否合用。', + deployment: '此分類收錄開源遠端桌面 RustDesk 的部署與維運實務:如何設定無人值守存取並派送預先設定的用戶端、主控台出現不明裝置時該先查什麼、大量裝置該怎麼規劃,以及自架的 RustDesk Server Pro 能否離線或在氣隙隔離環境中運作。', + guides: '實用指南合集,幫你在不同平台與團隊規模下用好 RustDesk:Linux 安裝套件怎麼選、X11 與 Wayland 有何差異,Android 與 iOS 遠端控制實際能做到什麼,企業 AD/LDAP 整合與 MSP 工具整併,以及挑選免費商用遠端桌面、改用開源自架方案前該算清的成本。', + pricing: '開源遠端桌面 RustDesk 的授權與計費文章:說明受管理裝置如何計算、臨時連線的裝置在 Customized V2 方案中為何不計入,訂閱期間加購使用者或裝置時如何按比例計費、新額度何時生效(在網頁主控台重新整理即可立即套用),幫你在購買自架伺服器授權前先把帳算清楚。', + release: 'RustDesk 版本發布與開發動態:介紹 Wayland 下無人值守遠端存取等新功能,以及我們如何讓 Flutter 3.24 繼續在 Windows 7 上執行,協助你即時了解這款開源遠端桌面軟體與自架伺服器部署的最新進展、相容性變化與升級重點。', + security: '遠端存取資安專區:教你辨識遠端桌面詐騙的警訊與受騙後的處理步驟,客觀檢視 AnyDesk 與 Chrome Remote Desktop 的加密機制與風險,說明自架伺服器在資料主權與 GDPR 上做得到與做不到的事,並介紹 RustDesk 這個開源專案採取的防詐措施。', + troubleshooting: '疑難排解文章彙整:分析 RustDesk 連線成功卻一直等待影像的常見原因,例如無外接螢幕的主機、休眠、編碼器與驅動程式,並提供對應的修復方法;也說明 TeamViewer、AnyDesk 被判定為商業用途時的官方申訴流程,以及改用開源自架遠端桌面後如何避開這類問題。', }, ar: { alternatives: - 'قيّم البدائل ذاتية الاستضافة ومفتوحة المصدر حسب نموذج النشر والترخيص والأمان وملاءمة سير العمل وجهد الانتقال.', + 'بدائل ذاتية الاستضافة ومفتوحة المصدر لـ TeamViewer وAnyDesk وChrome Remote Desktop، ومعايير اختيار سطح المكتب البعيد حسب الترخيص والأمان والنشر والانتقال.', comparisons: - 'قارن RustDesk بمنتجات وبروتوكولات الوصول عن بُعد باستخدام المتطلبات الحالية والمفاضلات الواضحة ومعايير إثبات المفهوم.', + 'مقارنات بين RustDesk وAnyDesk وTeamViewer وScreenConnect وSplashtop وVNC وRDP، توضح مزايا وحدود سطح المكتب البعيد مفتوح المصدر وذاتي الاستضافة ومعايير التجربة.', deployment: - 'خطّط وشغّل عمليات نشر RustDesk، من تحديد حجم الخادم والشبكة إلى الهوية والتحكم في الوصول وتوزيع العملاء والاستعادة.', - guides: 'أدلة عملية لتقييم RustDesk وتهيئته وتشغيله عبر منصات وفرق ونماذج نشر مختلفة.', - pricing: 'افهم ترخيص RustDesk والمستخدمين والأجهزة المُدارة والتزامن وشروط الشراء والترقيات وخيارات التقييم.', + 'نشر RustDesk ذاتي الاستضافة: الوصول غير المراقب، والتوسع لأعداد كبيرة من الأجهزة، وفحص الأجهزة المجهولة، وهل يمكن تشغيل RustDesk Server Pro دون اتصال بالإنترنت.', + guides: 'أدلة عملية لـ RustDesk على Linux وAndroid وiOS، وللمؤسسات مع Active Directory ومزودي الخدمات المُدارة، ولماذا تختار سطح مكتب بعيد مفتوح المصدر وذاتي الاستضافة.', + pricing: 'شرح ترخيص RustDesk Server Pro ذاتي الاستضافة: ما الذي يُحتسب جهازًا مُدارًا، وكيف يُعدّ المستخدمون والاتصالات المتزامنة، وكيف تتم الترقية في منتصف الاشتراك.', security: - 'قيّم أمان الوصول عن بُعد وتدفقات البيانات وعمليات الاحتيال والثغرات وضوابط الوصول وتقوية النشر دون ادعاءات امتثال مطلقة.', - troubleshooting: 'شخّص أعراض الاتصال والعرض والتهيئة والترخيص عبر فحوصات محددة ومسارات تصعيد آمنة.', + 'أمان سطح المكتب البعيد بلا ادعاءات مطلقة: كيف تكشف عمليات الاحتيال، ومراجعات لأمان AnyDesk وChrome Remote Desktop، وسيادة البيانات وGDPR عبر الاستضافة الذاتية.', + troubleshooting: 'حلول لمشكلات سطح المكتب البعيد: توقف RustDesk عند انتظار الصورة بعد الاتصال، وتنبيهات الاستخدام التجاري في AnyDesk وTeamViewer، ومتى تصعّد المشكلة.', }, }; +// Category slugs are transliterated per language (/zh-cn/category/an1-quan2, +// /ja/category/gaido), but the descriptions above are keyed by the English +// slug, so a direct lookup only ever matched the Latin-script languages. +// Resolve the English key through this category's posts and their English +// translations. +const englishPosts = await fetchPosts('en'); +const categoryKey = + categorySlug in localizedCategoryDescriptions.en + ? categorySlug + : (page.data + .map((post) => englishPosts.find((en) => en.translationKey === post.translationKey)?.category?.slug) + .find(Boolean) ?? categorySlug); const categoryDescription = - localizedCategoryDescriptions[lang]?.[categorySlug] ?? localizedCategoryDescriptions.en[categorySlug]; + localizedCategoryDescriptions[lang]?.[categoryKey] ?? localizedCategoryDescriptions.en[categoryKey]; const localePaths = (Object.keys(LOCALES) as Lang[]).map((targetLang) => ({ lang: targetLang, path: getBlogPermalink(targetLang), diff --git a/v3/src/pages/ar/index.astro b/v3/src/pages/ar/index.astro index cce29d2a..2ce38583 100644 --- a/v3/src/pages/ar/index.astro +++ b/v3/src/pages/ar/index.astro @@ -12,7 +12,7 @@ import Note from '~/components/widgets/Note.astro'; const metadata = { title: 'رست ديسك: سطح المكتب البعيد مفتوح المصدر مع حلول الخادم المستضاف ذاتيًا', - description: 'رست ديسك هو أفضل برنامج سطح المكتب البعيد مفتوح المصدر. بديل آمن لـ TeamViewer و AnyDesk مع خوادم مستضافة ذاتيًا. دعم متعدد المنصات لـ Windows و macOS و Linux و Android.', + description: 'RustDesk برنامج سطح مكتب بعيد مفتوح المصدر مع خادم ذاتي الاستضافة، وبديل لـ TeamViewer وAnyDesk على Windows وmacOS وLinux وAndroid، مع عميل يحمل اسمك وشعارك.', keywords: 'برنامج سطح المكتب البعيد, الوصول البعيد مفتوح المصدر, سطح المكتب البعيد المستضاف ذاتيًا, بديل TeamViewer, بديل AnyDesk, التحكم عن بعد الآمن, الوصول عن بعد متعدد المنصات, سطح المكتب البعيد المحلي, خادم rustdesk', ignoreTitleTemplate: true, }; diff --git a/v3/src/pages/ar/pricing.astro b/v3/src/pages/ar/pricing.astro index f471699b..da7b1cb9 100644 --- a/v3/src/pages/ar/pricing.astro +++ b/v3/src/pages/ar/pricing.astro @@ -9,7 +9,7 @@ import CallToAction from '~/components/widgets/CallToAction.astro'; const metadata = { title: 'تسعير رست ديسك - خطط الخادم المستضاف ذاتيًا', description: - 'اختر خطة رست ديسك المناسبة لمؤسستك. خطة مفتوحة المصدر مجانية متوفرة. خطط احترافية مع ميزات متقدمة للاستخدام التجاري.', + 'أسعار RustDesk Server Pro لسطح المكتب البعيد ذاتي الاستضافة: ترخيص سنوي على خادمك وليس اشتراك SaaS. قارن الخطة المجانية مفتوحة المصدر بخطط Pro مع 2FA وSSO.', keywords: 'تسعير رست ديسك, تسعير سطح المكتب البعيد المستضاف ذاتيًا, تكلفة خادم الوصول عن بعد, خطط سطح المكتب البعيد المتقدمة', author: 'RustDesk Team', diff --git a/v3/src/pages/ar/support.astro b/v3/src/pages/ar/support.astro index e39d1443..4995d41a 100644 --- a/v3/src/pages/ar/support.astro +++ b/v3/src/pages/ar/support.astro @@ -4,7 +4,7 @@ import Features2 from '~/components/widgets/Features2.astro'; const metadata = { title: 'دعم رست ديسك - المساعدة والتوثيق لبرنامج سطح المكتب البعيد', - description: 'احصل على المساعدة في برنامج رست ديسك لسطح المكتب البعيد. اعثر على التوثيق وأدلة استكشاف الأخطاء وموارد الدعم لحلول الوصول عن بعد المستضافة ذاتيًا.', + description: 'دعم RustDesk لسطح المكتب البعيد مفتوح المصدر: أبلغ عن الأخطاء على GitHub، واسأل المجتمع على Discord، ولمستخدمي RustDesk Server Pro ذاتي الاستضافة دعم بالبريد.', keywords: 'دعم رست ديسك, مساعدة سطح المكتب البعيد, دعم مستضاف ذاتيًا, توثيق الوصول عن بعد, استكشاف أخطاء رست ديسك', author: 'RustDesk Team', }; diff --git a/v3/src/pages/ar/team.astro b/v3/src/pages/ar/team.astro index d285d4f1..c82ff3a0 100644 --- a/v3/src/pages/ar/team.astro +++ b/v3/src/pages/ar/team.astro @@ -6,7 +6,7 @@ import Layout from '~/layouts/PageLayout.astro'; const metadata = { title: 'حول رست ديسك - فريق برنامج سطح المكتب البعيد ومعلومات الشركة', - description: 'تعرّف على فريق رست ديسك ومهمتنا في توفير أفضل برنامج سطح مكتب بعيد مفتوح المصدر. تعرّف على مطورينا ومساهمينا في حل الوصول عن بعد المستضاف ذاتيًا.', + description: 'من نحن: بدأ RustDesk عام 2020 كبديل مفتوح المصدر لـ TeamViewer. تعرّف على قصة برنامج سطح المكتب البعيد ذاتي الاستضافة وفريقه الأساسي ومكتبه في سنغافورة.', keywords: 'فريق رست ديسك, حول رست ديسك, شركة سطح مكتب بعيد, مطورو مفتوح المصدر, فريق وصول عن بعد مستضاف ذاتيًا', author: 'RustDesk Team', }; diff --git a/v3/src/pages/careers.astro b/v3/src/pages/careers.astro index 8c900088..4569ccb0 100644 --- a/v3/src/pages/careers.astro +++ b/v3/src/pages/careers.astro @@ -4,7 +4,7 @@ import Layout from '~/layouts/PageLayout.astro'; const metadata = { title: 'RustDesk Careers - Join Our Remote Desktop Software Development Team', - description: 'Join the RustDesk team and help build the future of open-source remote desktop software. Explore career opportunities in remote access technology and self-hosted solutions.', + description: 'Careers at RustDesk: no open positions right now. Check back later, or contribute to the open-source remote desktop project on GitHub in the meantime.', keywords: 'rustdesk careers, remote desktop jobs, open source software jobs, self-hosted technology careers, remote access development jobs, software engineering positions', author: 'RustDesk Team', }; diff --git a/v3/src/pages/de/index.astro b/v3/src/pages/de/index.astro index 6a78b79a..45600fcc 100644 --- a/v3/src/pages/de/index.astro +++ b/v3/src/pages/de/index.astro @@ -12,7 +12,7 @@ import Note from '~/components/widgets/Note.astro'; const metadata = { title: 'RustDesk: Open-Source-Fernzugriff mit selbst gehosteten Serverlösungen', - description: 'RustDesk ist die beste Open-Source-Fernzugriffssoftware. Sichere Alternative zu TeamViewer und AnyDesk mit selbst gehosteten Servern. Plattformübergreifende Unterstützung für Windows, macOS, Linux und Android.', + description: 'RustDesk ist Open-Source-Remote-Desktop-Software mit selbst gehostetem Server: Alternative zu TeamViewer und AnyDesk für Windows, macOS, Linux und Android.', keywords: 'fernzugriff software, open source fernzugriff, selbst gehosteter fernzugriff, TeamViewer alternative, AnyDesk alternative, sichere fernsteuerung, plattformübergreifender fernzugriff, on-premise fernzugriff, rustdesk server', ignoreTitleTemplate: true, }; diff --git a/v3/src/pages/de/pricing.astro b/v3/src/pages/de/pricing.astro index 30da534f..936832d0 100644 --- a/v3/src/pages/de/pricing.astro +++ b/v3/src/pages/de/pricing.astro @@ -9,7 +9,7 @@ import CallToAction from '~/components/widgets/CallToAction.astro'; const metadata = { title: 'RustDesk Preise - Selbst gehostete Remote-Desktop-Server-Pläne', description: - 'Wählen Sie den richtigen RustDesk Self-Hosting-Plan für Ihr Unternehmen. Kostenloser Open-Source-Plan verfügbar. Pro-Pläne mit erweiterten Funktionen für Unternehmen.', + 'RustDesk-Preise für selbst gehosteten Remote Desktop statt SaaS: kostenloser Open-Source-Plan oder Jahreslizenz für RustDesk Server Pro mit 2FA, SSO und LDAP.', keywords: 'rustdesk preise, selbst gehostete fernzugriff preise, remote desktop server kosten, open source fernzugriff preise, unternehmen fernzugriff pläne', author: 'RustDesk Team', diff --git a/v3/src/pages/de/support.astro b/v3/src/pages/de/support.astro index d90ddfc1..50e7865a 100644 --- a/v3/src/pages/de/support.astro +++ b/v3/src/pages/de/support.astro @@ -4,7 +4,7 @@ import Features2 from '~/components/widgets/Features2.astro'; const metadata = { title: 'RustDesk Support - Hilfe & Dokumentation für Remote-Desktop-Software', - description: 'Erhalten Sie Hilfe mit RustDesk Remote-Desktop-Software. Finden Sie Dokumentation, Fehlerbehebungsanleitungen und Support-Ressourcen für selbst gehostete Remote-Access-Lösungen.', + description: 'Support für RustDesk, den Open-Source-Remote-Desktop: Bugs auf GitHub melden, Community auf Discord, E-Mail-Tickets für selbst gehosteten RustDesk Server Pro.', keywords: 'rustdesk support, remote desktop hilfe, selbst gehostete unterstützung, remote access dokumentation, rustdesk fehlerbehebung, remote desktop setup hilfe', author: 'RustDesk Team', }; @@ -12,32 +12,32 @@ const metadata = { Open an issue', + description: 'Issue eröffnen', icon: 'tabler:brand-github', }, { title: 'Discord', - description: 'Join our server', + description: 'Unserem Server beitreten', icon: 'tabler:brand-discord', }, { - title: 'Email', + title: 'E-Mail', description: 'support@rustdesk.com', icon: 'tabler:mail', }, diff --git a/v3/src/pages/de/team.astro b/v3/src/pages/de/team.astro index b13cdd10..d40c5dc8 100644 --- a/v3/src/pages/de/team.astro +++ b/v3/src/pages/de/team.astro @@ -6,7 +6,7 @@ import Layout from '~/layouts/PageLayout.astro'; const metadata = { title: 'Über RustDesk - Remote-Desktop-Software-Team und Unternehmensinformationen', - description: 'Lernen Sie das RustDesk-Team und unsere Mission kennen, die beste Open-Source-Remote-Desktop-Software bereitzustellen. Treffen Sie unsere Entwickler und Mitwirkenden hinter der selbst gehosteten Remote-Access-Lösung.', + description: 'Über RustDesk: wie eine teure TeamViewer-Lizenz 2020 zu einem Open-Source-Remote-Desktop zum Selbsthosten führte, dazu unser Kernteam und Standort Singapur.', keywords: 'rustdesk team, über rustdesk, remote desktop unternehmen, open source entwickler, selbst gehostetes remote access team, rustdesk mitwirkende', author: 'RustDesk Team', }; diff --git a/v3/src/pages/es/index.astro b/v3/src/pages/es/index.astro index f0c4c948..a6389683 100644 --- a/v3/src/pages/es/index.astro +++ b/v3/src/pages/es/index.astro @@ -12,7 +12,7 @@ import Note from '~/components/widgets/Note.astro'; const metadata = { title: 'RustDesk: Escritorio remoto de código abierto con soluciones de servidor autoalojado', - description: 'RustDesk es el mejor software de escritorio remoto de código abierto. Alternativa segura a TeamViewer y AnyDesk con servidores autoalojados. Soporte multiplataforma para Windows, macOS, Linux y Android.', + description: 'RustDesk es un escritorio remoto de código abierto con servidor autoalojado, una alternativa a TeamViewer y AnyDesk para Windows, macOS, Linux y Android.', keywords: 'software escritorio remoto, acceso remoto código abierto, escritorio remoto autoalojado, alternativa TeamViewer, alternativa AnyDesk, control remoto seguro, acceso remoto multiplataforma, escritorio remoto local, servidor rustdesk', ignoreTitleTemplate: true, }; diff --git a/v3/src/pages/es/pricing.astro b/v3/src/pages/es/pricing.astro index c982b52d..3b25503a 100644 --- a/v3/src/pages/es/pricing.astro +++ b/v3/src/pages/es/pricing.astro @@ -9,7 +9,7 @@ import CallToAction from '~/components/widgets/CallToAction.astro'; const metadata = { title: 'Precios de RustDesk - Planes de Servidor de Escritorio Remoto Autoalojado', description: - 'Elija el plan de autoalojamiento de RustDesk adecuado para su organización. Plan de código abierto gratuito disponible. Planes Pro con características avanzadas para uso empresarial.', + 'Precios de RustDesk para escritorio remoto autoalojado, no SaaS: plan gratuito de código abierto o licencia anual de RustDesk Server Pro con 2FA, SSO y LDAP.', keywords: 'precios rustdesk, precios escritorio remoto autoalojado, costo servidor remoto, precios acceso remoto código abierto, planes escritorio remoto empresarial', author: 'RustDesk Team', diff --git a/v3/src/pages/es/support.astro b/v3/src/pages/es/support.astro index 2ca8afb8..77c1194d 100644 --- a/v3/src/pages/es/support.astro +++ b/v3/src/pages/es/support.astro @@ -4,7 +4,7 @@ import Features2 from '~/components/widgets/Features2.astro'; const metadata = { title: 'Soporte RustDesk - Ayuda y Documentación para Software de Escritorio Remoto', - description: 'Obtenga ayuda con el software de escritorio remoto RustDesk. Encuentre documentación, guías de solución de problemas y recursos de soporte para soluciones de acceso remoto autoalojadas.', + description: 'Ayuda para RustDesk, el escritorio remoto de código abierto: bugs en GitHub, comunidad en Discord y tickets por correo para RustDesk Server Pro autoalojado.', keywords: 'soporte rustdesk, ayuda escritorio remoto, soporte autoalojado, documentación acceso remoto, solución problemas rustdesk, ayuda configuración escritorio remoto', author: 'RustDesk Team', }; diff --git a/v3/src/pages/es/team.astro b/v3/src/pages/es/team.astro index 63c61a18..fdf48b09 100644 --- a/v3/src/pages/es/team.astro +++ b/v3/src/pages/es/team.astro @@ -6,7 +6,7 @@ import Layout from '~/layouts/PageLayout.astro'; const metadata = { title: 'Sobre RustDesk - Equipo de Software de Escritorio Remoto e Información de la Empresa', - description: 'Conoce al equipo de RustDesk y nuestra misión de proporcionar el mejor software de escritorio remoto de código abierto. Conoce a nuestros desarrolladores y contribuyentes detrás de la solución de acceso remoto autoalojada.', + description: 'Sobre RustDesk: cómo una licencia de TeamViewer muy cara en 2020 dio origen a este escritorio remoto de código abierto, el equipo y la sede en Singapur.', keywords: 'equipo rustdesk, sobre rustdesk, empresa escritorio remoto, desarrolladores código abierto, equipo acceso remoto autoalojado, colaboradores rustdesk', author: 'RustDesk Team', }; @@ -15,17 +15,17 @@ const metadata = { - - Why Are We Building This? + + ¿Por qué construimos esto?

- In the midst of the Covid-19 pandemic in mid-2020, the now lead dev / founder found themselves compelled to - procure a commercial license for TeamViewer to facilitate remote work in Singapore. However, they were taken - aback by the exorbitant cost. Following a restless night, they embarked on a mission to create an alternative - solution. Thus, RustDesk was conceived — an open-source, freely accessible remote desktop software that was - diligently crafted through numerous sleepless nights. This labor of dedication and determination culminated in - the release of RustDesk on GitHub in 2021, allowing it to be utilized by individuals worldwide. + A mediados de 2020, en plena pandemia de Covid-19, la persona que fundó RustDesk y hoy dirige su desarrollo + necesitó comprar una licencia comercial de TeamViewer para poder teletrabajar desde Singapur. El precio, + desorbitado, le dejó sin palabras. Tras una noche sin dormir, se propuso crear una alternativa. Así nació + RustDesk: un software de escritorio remoto de código abierto y gratuito, construido con esmero a lo largo de + muchas noches en vela. Ese esfuerzo culminó en 2021 con la publicación de RustDesk en GitHub, al alcance de + cualquier persona en el mundo.

@@ -33,18 +33,18 @@ const metadata = { CEO', description: - "Joseph Jacks founded OSS Capital in 2018. It is the world's first and only early stage VC dedicated exclusively to COSS (commercial open source) startups on a global basis. Previously, he helped start and run the very first Kubernetes startup (Kismatic) and also found and run KubeCon (the Kubernetes community conference) before donating it to the Linux Foundation in 2016 as the CNCF (Cloud Native Computing Foundation) was materializing.", + 'Joseph Jacks fundó OSS Capital en 2018, el primer y único fondo de capital riesgo en fase inicial del mundo dedicado exclusivamente a startups de COSS (código abierto comercial) a escala global. Antes ayudó a poner en marcha y dirigir la primera startup de Kubernetes (Kismatic), y fundó y dirigió KubeCon (la conferencia de la comunidad de Kubernetes) hasta donarla a la Linux Foundation en 2016, cuando se estaba formando la CNCF (Cloud Native Computing Foundation).', icon: 'tabler:user', }, { - title: 'Daniel Lamb
Community Assistant', + title: 'Daniel Lamb
Asistente de la comunidad', description: - "With a remarkable quarter century career in the IT industry, Daniel Lamb has actively participated in numerous open-source projects, assuming various roles and responsibilities. Additionally, he has accomplished the establishment of an IT services company based in Scotland, catering to customers worldwide. Daniel's extensive expertise encompasses support, sales, and community engagement, bringing a large amount of knowledge and experience to the project.", + 'Con una destacada trayectoria de un cuarto de siglo en el sector de TI, Daniel Lamb ha participado activamente en numerosos proyectos de código abierto, asumiendo distintos roles y responsabilidades. Además, fundó una empresa de servicios de TI con sede en Escocia que atiende a clientes de todo el mundo. Su amplia experiencia abarca el soporte, las ventas y la relación con la comunidad, y aporta al proyecto un gran caudal de conocimientos.', icon: 'tabler:user', }, ]} @@ -53,12 +53,12 @@ const metadata = { RustDesk – 开源远程桌面访问软件 - + - + - +