From ad7c0c48a4bb85a46b68b46c4c24152a65ab4bbd Mon Sep 17 00:00:00 2001 From: Tatsuzo Araki Date: Sat, 21 Mar 2026 01:26:09 +0900 Subject: [PATCH 01/14] Add localized SEO metadata foundation Introduce a shared metadata helper for canonical URLs, hreflang, Open Graph, and Twitter tags on the current locale routes. Move locale-specific SEO copy into the message catalogs for en, ja, zh-Hans, and zh-Hant so existing pages can read from one localized content source instead of duplicating route strings. Also improve the root fallback and language-selector metadata to use search-oriented descriptions that match BitRemote's downloader and NAS positioning without changing the UI layout. --- src/app/[locale]/layout.tsx | 27 ++++---------- src/app/[locale]/privacy/page.tsx | 15 ++++---- src/app/[locale]/support/page.tsx | 15 ++++---- src/app/[locale]/terms/page.tsx | 15 ++++---- src/app/layout.tsx | 20 +++++++++- src/app/page.tsx | 27 ++++++++++++++ src/messages/en.json | 54 +++++++++++++++++++++++++++ src/messages/ja.json | 54 +++++++++++++++++++++++++++ src/messages/zh-hans.json | 54 +++++++++++++++++++++++++++ src/messages/zh-hant.json | 54 +++++++++++++++++++++++++++ src/seo/metadata.ts | 61 +++++++++++++++++++++++++++++++ 11 files changed, 354 insertions(+), 42 deletions(-) create mode 100644 src/seo/metadata.ts diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index a6a1855..3abd093 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -3,7 +3,8 @@ import type { Metadata } from 'next'; import { TextTabsNav } from '@/components/TextTabsNav'; import { defaultLocale, isLocale, localeLang, locales, type Locale } from '@/i18n/locales'; import { getMessages } from '@/i18n/messages'; -import { absoluteUrl, localePath } from '@/i18n/urls'; +import { localePath } from '@/i18n/urls'; +import { buildMetadataForCurrentLocalePage } from '@/seo/metadata'; export const dynamicParams = false; @@ -20,24 +21,12 @@ export async function generateMetadata({ const locale: Locale = isLocale(rawLocale) ? rawLocale : defaultLocale; const messages = getMessages(locale); - const siteName = messages.site.name; - - return { - title: { - default: siteName, - template: `%s | ${siteName}`, - }, - description: messages.site.description, - alternates: { - canonical: absoluteUrl(localePath(locale, '/')), - languages: { - en: absoluteUrl(localePath('en', '/')), - ja: absoluteUrl(localePath('ja', '/')), - 'zh-Hans': absoluteUrl(localePath('zh-hans', '/')), - 'zh-Hant': absoluteUrl(localePath('zh-hant', '/')), - }, - }, - }; + return buildMetadataForCurrentLocalePage({ + locale, + pathname: '/', + messages, + page: 'home', + }); } export default async function LocaleLayout({ diff --git a/src/app/[locale]/privacy/page.tsx b/src/app/[locale]/privacy/page.tsx index 2a0b260..b5851bc 100644 --- a/src/app/[locale]/privacy/page.tsx +++ b/src/app/[locale]/privacy/page.tsx @@ -5,7 +5,8 @@ import { TextFrame } from '@/components/TextFrame'; import { privacyPolicyUrl } from '@/i18n/links'; import { defaultLocale, isLocale, type Locale } from '@/i18n/locales'; import { getMessages } from '@/i18n/messages'; -import { absoluteUrl, localePath } from '@/i18n/urls'; +import { localePath } from '@/i18n/urls'; +import { buildMetadataForCurrentLocalePage } from '@/seo/metadata'; export async function generateMetadata({ params, @@ -16,12 +17,12 @@ export async function generateMetadata({ const locale: Locale = isLocale(rawLocale) ? rawLocale : defaultLocale; const messages = getMessages(locale); - return { - title: messages.pages.privacy.title, - alternates: { - canonical: absoluteUrl(localePath(locale, '/privacy/')), - }, - }; + return buildMetadataForCurrentLocalePage({ + locale, + pathname: '/privacy/', + messages, + page: 'privacy', + }); } export default async function PrivacyPage({ diff --git a/src/app/[locale]/support/page.tsx b/src/app/[locale]/support/page.tsx index b8c2276..24e8068 100644 --- a/src/app/[locale]/support/page.tsx +++ b/src/app/[locale]/support/page.tsx @@ -5,7 +5,8 @@ import { TextFrame } from '@/components/TextFrame'; import { LINKS } from '@/i18n/links'; import { defaultLocale, isLocale, type Locale } from '@/i18n/locales'; import { getMessages } from '@/i18n/messages'; -import { absoluteUrl, localePath } from '@/i18n/urls'; +import { localePath } from '@/i18n/urls'; +import { buildMetadataForCurrentLocalePage } from '@/seo/metadata'; export async function generateMetadata({ params, @@ -16,12 +17,12 @@ export async function generateMetadata({ const locale: Locale = isLocale(rawLocale) ? rawLocale : defaultLocale; const messages = getMessages(locale); - return { - title: messages.pages.support.title, - alternates: { - canonical: absoluteUrl(localePath(locale, '/support/')), - }, - }; + return buildMetadataForCurrentLocalePage({ + locale, + pathname: '/support/', + messages, + page: 'support', + }); } export default async function SupportPage({ diff --git a/src/app/[locale]/terms/page.tsx b/src/app/[locale]/terms/page.tsx index 8afe8a8..531dbea 100644 --- a/src/app/[locale]/terms/page.tsx +++ b/src/app/[locale]/terms/page.tsx @@ -5,7 +5,8 @@ import { TextFrame } from '@/components/TextFrame'; import { eulaUrl } from '@/i18n/links'; import { defaultLocale, isLocale, type Locale } from '@/i18n/locales'; import { getMessages } from '@/i18n/messages'; -import { absoluteUrl, localePath } from '@/i18n/urls'; +import { localePath } from '@/i18n/urls'; +import { buildMetadataForCurrentLocalePage } from '@/seo/metadata'; export async function generateMetadata({ params, @@ -16,12 +17,12 @@ export async function generateMetadata({ const locale: Locale = isLocale(rawLocale) ? rawLocale : defaultLocale; const messages = getMessages(locale); - return { - title: messages.pages.terms.title, - alternates: { - canonical: absoluteUrl(localePath(locale, '/terms/')), - }, - }; + return buildMetadataForCurrentLocalePage({ + locale, + pathname: '/terms/', + messages, + page: 'terms', + }); } export default async function TermsPage({ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cae321e..eb60313 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,8 +4,9 @@ import './globals.css'; export const metadata: Metadata = { metadataBase: new URL('https://bitremote.app'), - title: 'BitRemote', - description: 'An Apple platforms app to control your downloaders remotely.', + title: 'BitRemote | Remote Download Manager App', + description: + 'Remote download manager app for NAS, seedbox, and home server workflows on iPhone, iPad, and Mac.', manifest: '/site.webmanifest', icons: { icon: [ @@ -16,6 +17,21 @@ export const metadata: Metadata = { shortcut: ['/favicon.ico'], apple: [{ url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }], }, + openGraph: { + type: 'website', + url: 'https://bitremote.app/', + title: 'BitRemote | Remote Download Manager App', + description: + 'Remote download manager app for NAS, seedbox, and home server workflows on iPhone, iPad, and Mac.', + siteName: 'BitRemote', + locale: 'en_US', + }, + twitter: { + card: 'summary', + title: 'BitRemote | Remote Download Manager App', + description: + 'Remote download manager app for NAS, seedbox, and home server workflows on iPhone, iPad, and Mac.', + }, }; export default function RootLayout({ diff --git a/src/app/page.tsx b/src/app/page.tsx index ac8fbe2..458b402 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,36 @@ +import type { Metadata } from 'next'; + import { BitRemoteWordmark } from '@/components/BitRemoteWordmark'; import { TextButton } from '@/components/TextButton'; import { LINKS } from '@/i18n/links'; import { localeLabels, locales } from '@/i18n/locales'; import { localeRoot } from '@/i18n/urls'; +export const metadata: Metadata = { + title: 'BitRemote | Remote Download Manager App', + description: + 'Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on Apple devices.', + keywords: ['bitremote', 'remote download manager app', 'nas download app'], + alternates: { + canonical: 'https://bitremote.app/', + }, + openGraph: { + type: 'website', + url: 'https://bitremote.app/', + title: 'BitRemote | Remote Download Manager App', + description: + 'Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on Apple devices.', + siteName: 'BitRemote', + locale: 'en_US', + }, + twitter: { + card: 'summary', + title: 'BitRemote | Remote Download Manager App', + description: + 'Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on Apple devices.', + }, +}; + export default function RootPage() { return (
diff --git a/src/messages/en.json b/src/messages/en.json index e3912a7..893112b 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -116,5 +116,59 @@ "github": "Bug reports and feature requests:", "githubButton": "GitHub Repository" } + }, + "seo": { + "home": { + "title": "BitRemote | Remote Download Manager for NAS and Home Server Tasks", + "description": "Remote download manager for iPhone, iPad, and Mac. Control aria2, qBittorrent, Transmission, Synology Download Station, and QNAP Download Station from anywhere.", + "keywords": [ + "remote download manager", + "nas downloads app", + "home server download manager", + "aria2 remote", + "qbittorrent remote", + "transmission remote", + "synology download station remote", + "qnap download station remote" + ] + }, + "support": { + "title": "BitRemote Support | Help, Community, and GitHub", + "description": "Get BitRemote support, report bugs, request features, and join the community for the remote download manager app for iPhone, iPad, and Mac.", + "keywords": [ + "bitremote support", + "download manager support", + "bitremote github", + "report bitremote bug", + "bitremote community" + ] + }, + "privacy": { + "title": "BitRemote Privacy Policy | Ark Studios", + "description": "Read the official BitRemote privacy policy from Ark Studios for the remote download manager app used with NAS and downloader clients.", + "keywords": [ + "bitremote privacy policy", + "ark studios privacy", + "download manager privacy" + ] + }, + "terms": { + "title": "BitRemote EULA | Ark Studios", + "description": "Read the BitRemote end user license agreement from Ark Studios for the remote downloader management app on Apple platforms.", + "keywords": [ + "bitremote eula", + "bitremote terms", + "ark studios eula" + ] + }, + "languageSelector": { + "title": "BitRemote | Remote Download Manager App", + "description": "Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on Apple devices.", + "keywords": [ + "bitremote", + "remote download manager app", + "nas download app" + ] + } } } diff --git a/src/messages/ja.json b/src/messages/ja.json index 9db2c03..1a137d2 100644 --- a/src/messages/ja.json +++ b/src/messages/ja.json @@ -98,5 +98,59 @@ "github": "不具合報告・機能リクエスト:", "githubButton": "GitHub リポジトリ" } + }, + "seo": { + "home": { + "title": "BitRemote | NAS とホームサーバー向けリモートダウンロード管理", + "description": "iPhone、iPad、Mac で使えるリモートダウンロード管理アプリ。aria2、qBittorrent、Transmission、Synology Download Station、QNAP Download Station を外出先から操作できます。", + "keywords": [ + "リモート ダウンロード 管理", + "NAS ダウンロード アプリ", + "ホームサーバー ダウンロード 管理", + "aria2 リモート", + "qBittorrent リモート", + "Transmission リモート", + "Synology Download Station リモート", + "QNAP Download Station リモート" + ] + }, + "support": { + "title": "BitRemote サポート | ヘルプ、コミュニティ、GitHub", + "description": "BitRemote のサポート情報、バグ報告、機能要望、コミュニティ参加先をまとめています。iPhone、iPad、Mac 向けリモートダウンロード管理アプリの案内ページです。", + "keywords": [ + "BitRemote サポート", + "ダウンロード管理 サポート", + "BitRemote GitHub", + "BitRemote バグ報告", + "BitRemote コミュニティ" + ] + }, + "privacy": { + "title": "BitRemote 個人情報保護方針 | Ark Studios", + "description": "NAS や各種ダウンロードクライアントを操作する BitRemote の公式プライバシーポリシーを Ark Studios の案内先から確認できます。", + "keywords": [ + "BitRemote 個人情報保護方針", + "Ark Studios 個人情報保護方針", + "ダウンロード管理 プライバシー" + ] + }, + "terms": { + "title": "BitRemote EULA | Ark Studios", + "description": "Apple プラットフォーム向けリモートダウンロード管理アプリ BitRemote の EULA を Ark Studios の案内先から確認できます。", + "keywords": [ + "BitRemote EULA", + "BitRemote 利用規約", + "Ark Studios EULA" + ] + }, + "languageSelector": { + "title": "BitRemote | リモートダウンロード管理アプリ", + "description": "BitRemote の紹介を読む言語を選択してください。NAS、seedbox、ホームサーバーのダウンロードタスクを Apple デバイスから管理できます。", + "keywords": [ + "BitRemote", + "リモートダウンロード管理アプリ", + "NAS ダウンロード アプリ" + ] + } } } diff --git a/src/messages/zh-hans.json b/src/messages/zh-hans.json index 9e0bd63..b4e2d9c 100644 --- a/src/messages/zh-hans.json +++ b/src/messages/zh-hans.json @@ -98,5 +98,59 @@ "github": "Bug 报告与功能请求:", "githubButton": "GitHub 仓库" } + }, + "seo": { + "home": { + "title": "BitRemote | 面向 NAS 与家庭服务器的远程下载管理", + "description": "适用于 iPhone、iPad 和 Mac 的远程下载管理应用。可从任何地方控制 aria2、qBittorrent、Transmission、Synology Download Station 和 QNAP Download Station。", + "keywords": [ + "远程下载管理", + "NAS 下载应用", + "家庭服务器 下载管理", + "aria2 远程", + "qBittorrent 远程", + "Transmission 远程", + "Synology Download Station 远程", + "QNAP Download Station 远程" + ] + }, + "support": { + "title": "BitRemote 支持 | 帮助、社区与 GitHub", + "description": "获取 BitRemote 支持、提交问题、提出功能需求,并加入社区。这是面向 iPhone、iPad、Mac 的远程下载管理应用支持入口。", + "keywords": [ + "BitRemote 支持", + "下载管理 支持", + "BitRemote GitHub", + "BitRemote 问题反馈", + "BitRemote 社区" + ] + }, + "privacy": { + "title": "BitRemote 隐私权政策 | Ark Studios", + "description": "查看 Ark Studios 提供的 BitRemote 官方隐私政策,了解这款 NAS 与下载工具远程控制应用的数据处理方式。", + "keywords": [ + "BitRemote 隐私政策", + "Ark Studios 隐私政策", + "下载管理 隐私" + ] + }, + "terms": { + "title": "BitRemote EULA | Ark Studios", + "description": "查看 Ark Studios 提供的 BitRemote EULA。BitRemote 是一款适用于 Apple 设备的远程下载管理应用。", + "keywords": [ + "BitRemote EULA", + "BitRemote 条款", + "Ark Studios EULA" + ] + }, + "languageSelector": { + "title": "BitRemote | 远程下载管理应用", + "description": "选择你的语言以了解 BitRemote。这款应用可让你在 Apple 设备上管理 NAS、seedbox 与家庭服务器的下载任务。", + "keywords": [ + "BitRemote", + "远程下载管理应用", + "NAS 下载应用" + ] + } } } diff --git a/src/messages/zh-hant.json b/src/messages/zh-hant.json index 09481aa..2df3cad 100644 --- a/src/messages/zh-hant.json +++ b/src/messages/zh-hant.json @@ -98,5 +98,59 @@ "github": "Bug 回報與功能請求:", "githubButton": "GitHub 儲存庫" } + }, + "seo": { + "home": { + "title": "BitRemote | NAS 與家用伺服器的遠端下載管理", + "description": "適用於 iPhone、iPad 與 Mac 的遠端下載管理 App。可從任何地方控制 aria2、qBittorrent、Transmission、Synology Download Station 與 QNAP Download Station。", + "keywords": [ + "遠端下載管理", + "NAS 下載 App", + "家用伺服器 下載管理", + "aria2 遠端", + "qBittorrent 遠端", + "Transmission 遠端", + "Synology Download Station 遠端", + "QNAP Download Station 遠端" + ] + }, + "support": { + "title": "BitRemote 支援 | 說明、社群與 GitHub", + "description": "取得 BitRemote 支援、回報問題、提出功能需求,並加入社群。這是 iPhone、iPad、Mac 遠端下載管理 App 的支援入口。", + "keywords": [ + "BitRemote 支援", + "下載管理 支援", + "BitRemote GitHub", + "BitRemote 問題回報", + "BitRemote 社群" + ] + }, + "privacy": { + "title": "BitRemote 隱私權政策 | Ark Studios", + "description": "查看 Ark Studios 提供的 BitRemote 官方隱私權政策,了解這款 NAS 與下載工具遠端控制 App 的資料處理方式。", + "keywords": [ + "BitRemote 隱私權政策", + "Ark Studios 隱私權政策", + "下載管理 隱私" + ] + }, + "terms": { + "title": "BitRemote EULA | Ark Studios", + "description": "查看 Ark Studios 提供的 BitRemote EULA。BitRemote 是用於 Apple 裝置的遠端下載管理 App。", + "keywords": [ + "BitRemote EULA", + "BitRemote 條款", + "Ark Studios EULA" + ] + }, + "languageSelector": { + "title": "BitRemote | 遠端下載管理 App", + "description": "選擇你的語言以了解 BitRemote。這款 App 可讓你在 Apple 裝置上管理 NAS、seedbox 與家用伺服器的下載任務。", + "keywords": [ + "BitRemote", + "遠端下載管理 App", + "NAS 下載 App" + ] + } } } diff --git a/src/seo/metadata.ts b/src/seo/metadata.ts new file mode 100644 index 0000000..950d01d --- /dev/null +++ b/src/seo/metadata.ts @@ -0,0 +1,61 @@ +import type { Metadata } from 'next'; + +import type { Messages } from '@/i18n/messages'; +import { localeLang, locales, type Locale } from '@/i18n/locales'; +import { absoluteUrl, localePath } from '@/i18n/urls'; + +type SeoPage = keyof Messages['seo']; + +const openGraphLocaleByLocale: Record = { + en: 'en_US', + ja: 'ja_JP', + 'zh-hans': 'zh_CN', + 'zh-hant': 'zh_TW', +}; + +function buildLanguageAlternates(pathname: string): Record { + return Object.fromEntries( + locales.map((locale) => [localeLang[locale], absoluteUrl(localePath(locale, pathname))]), + ); +} + +export function buildMetadataForCurrentLocalePage({ + locale, + pathname, + messages, + page, +}: { + locale: Locale; + pathname: string; + messages: Messages; + page: SeoPage; +}): Metadata { + const seo = messages.seo[page]; + const canonical = absoluteUrl(localePath(locale, pathname)); + + return { + title: seo.title, + description: seo.description, + keywords: seo.keywords, + alternates: { + canonical, + languages: buildLanguageAlternates(pathname), + }, + openGraph: { + type: 'website', + url: canonical, + siteName: messages.site.name, + locale: openGraphLocaleByLocale[locale], + alternateLocale: locales + .filter((candidate) => candidate !== locale) + .map((candidate) => openGraphLocaleByLocale[candidate]), + title: seo.title, + description: seo.description, + }, + twitter: { + card: 'summary', + title: seo.title, + description: seo.description, + }, + }; +} From fa5778892ea6c575a7fb80d7b8c24cdbdd6c57da Mon Sep 17 00:00:00 2001 From: Tatsuzo Araki Date: Sat, 21 Mar 2026 01:42:11 +0900 Subject: [PATCH 02/14] Generate robots and sitemap metadata routes Replace the hand-maintained public robots.txt and sitemap.xml with App Router metadata routes so crawl directives and sitemap output come from code instead of drifting static files. Centralize the current locale route list in a shared SEO route helper and generate all existing localized URLs from that source. The sitemap now includes localized alternates for the current homepage, privacy, terms, and support routes while keeping the existing trailing-slash URL shape and export-friendly behavior. --- public/robots.txt | 4 ---- public/sitemap.xml | 24 ------------------------ src/app/robots.ts | 11 +++++++++++ src/app/sitemap.ts | 24 ++++++++++++++++++++++++ src/seo/routes.ts | 18 ++++++++++++++++++ 5 files changed, 53 insertions(+), 28 deletions(-) delete mode 100644 public/robots.txt delete mode 100644 public/sitemap.xml create mode 100644 src/app/robots.ts create mode 100644 src/app/sitemap.ts create mode 100644 src/seo/routes.ts diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index 0ed4efb..0000000 --- a/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Allow: / - -Sitemap: https://bitremote.app/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index 76865a8..0000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - https://bitremote.app/ - - https://bitremote.app/en/ - https://bitremote.app/en/privacy/ - https://bitremote.app/en/terms/ - https://bitremote.app/en/support/ - - https://bitremote.app/ja/ - https://bitremote.app/ja/privacy/ - https://bitremote.app/ja/terms/ - https://bitremote.app/ja/support/ - - https://bitremote.app/zh-hans/ - https://bitremote.app/zh-hans/privacy/ - https://bitremote.app/zh-hans/terms/ - https://bitremote.app/zh-hans/support/ - - https://bitremote.app/zh-hant/ - https://bitremote.app/zh-hant/privacy/ - https://bitremote.app/zh-hant/terms/ - https://bitremote.app/zh-hant/support/ - diff --git a/src/app/robots.ts b/src/app/robots.ts new file mode 100644 index 0000000..c8d950a --- /dev/null +++ b/src/app/robots.ts @@ -0,0 +1,11 @@ +import type { MetadataRoute } from 'next'; + +export default function robots(): MetadataRoute.Robots { + return { + rules: { + userAgent: '*', + allow: '/', + }, + sitemap: 'https://bitremote.app/sitemap.xml', + }; +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts new file mode 100644 index 0000000..a10f569 --- /dev/null +++ b/src/app/sitemap.ts @@ -0,0 +1,24 @@ +import type { MetadataRoute } from 'next'; + +import { localeLang, locales } from '@/i18n/locales'; +import { absoluteUrl, localePath } from '@/i18n/urls'; +import { getLocalizedRouteEntries } from '@/seo/routes'; + +export default function sitemap(): MetadataRoute.Sitemap { + return [ + { + url: absoluteUrl('/'), + }, + ...getLocalizedRouteEntries().map(({ locale, pathname, url }) => ({ + url, + alternates: { + languages: Object.fromEntries( + locales.map((candidateLocale) => [ + localeLang[candidateLocale], + absoluteUrl(localePath(candidateLocale, pathname)), + ]), + ), + }, + })), + ]; +} diff --git a/src/seo/routes.ts b/src/seo/routes.ts new file mode 100644 index 0000000..71cd364 --- /dev/null +++ b/src/seo/routes.ts @@ -0,0 +1,18 @@ +import { locales, type Locale } from '@/i18n/locales'; +import { absoluteUrl, localePath } from '@/i18n/urls'; + +export const localeStaticPaths = ['/', '/privacy/', '/terms/', '/support/'] as const; + +export function getLocalizedRouteEntries(): Array<{ + locale: Locale; + pathname: (typeof localeStaticPaths)[number]; + url: string; +}> { + return locales.flatMap((locale) => + localeStaticPaths.map((pathname) => ({ + locale, + pathname, + url: absoluteUrl(localePath(locale, pathname)), + })), + ); +} From fe09ac51df79563116ed36c4a046c364239bda11 Mon Sep 17 00:00:00 2001 From: Tatsuzo Araki Date: Sat, 21 Mar 2026 01:46:48 +0900 Subject: [PATCH 03/14] Refine homepage copy for search intent Update the visible homepage messaging across en, ja, zh-Hans, and zh-Hant to explain BitRemote more clearly as a remote download manager for NAS, seedbox, and home server workflows. Keep the existing layout and components unchanged while improving the hero, benefit frames, quickstart steps, pricing lead-in, FAQ answers, and App Store CTA wording for clarity and stronger search alignment. --- src/messages/en.json | 54 +++++++++++++++++++-------------------- src/messages/ja.json | 52 ++++++++++++++++++------------------- src/messages/zh-hans.json | 52 ++++++++++++++++++------------------- src/messages/zh-hant.json | 52 ++++++++++++++++++------------------- 4 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/messages/en.json b/src/messages/en.json index 893112b..b7bed96 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1,8 +1,8 @@ { "site": { "name": "BitRemote", - "tagline": "Control your downloaders remotely.", - "description": "An Apple platforms app to control your downloaders remotely." + "tagline": "Remote download manager for NAS and home server tasks.", + "description": "An Apple platforms app to remotely manage downloader clients on NAS, seedbox, and home server setups." }, "nav": { "home": "Home", @@ -13,65 +13,65 @@ "faq": "FAQ" }, "cta": { - "appStore": "Download on the App Store", - "supportedDownloaders": "Supported downloaders" + "appStore": "Download BitRemote on the App Store", + "supportedDownloaders": "Supported download clients" }, "hero": { - "subhead": "Built for iPhone, iPad, and Mac. Manage download tasks and monitor activity — wherever you are." + "subhead": "Built for iPhone, iPad, and Mac. Connect to aria2, qBittorrent, Transmission, Synology Download Station, and QNAP Download Station to monitor activity and control download tasks from anywhere." }, "sections": { "benefits": { - "title": "What you can do", + "title": "Manage downloads from anywhere", "items": [ { "id": "diverseClientSupport", - "title": "Diverse Client Support", - "subtitle": "Seamlessly integrate with popular download tools including {clients}." + "title": "Works with popular download clients", + "subtitle": "Connect BitRemote to {clients} and manage downloader tasks from one Apple app." }, { "id": "comprehensiveTaskManagement", - "title": "Comprehensive Task Management", - "subtitle": "Easily control your downloads with options to pause, resume, delete tasks, and add new ones on the fly." + "title": "Control remote download tasks", + "subtitle": "Pause, resume, remove, and add tasks without going back to your NAS, seedbox, or home server dashboard." }, { "id": "smartFilteringSorting", - "title": "Smart Filtering & Sorting", - "subtitle": "Organize downloads by status, category, or tag, and sort by various criteria for efficiency." + "title": "Filter and sort large queues", + "subtitle": "Review tasks by status, category, and tag so you can find active, paused, or completed downloads faster." }, { "id": "activityMonitor", - "title": "Activity Monitor", - "subtitle": "Monitor real-time statistics and transfer history happening on your client." + "title": "Monitor transfer activity", + "subtitle": "Track real-time speeds, statistics, and transfer history from your downloader client on iPhone, iPad, or Mac." }, { "id": "clientsBackupRestore", - "title": "Clients Backup & Restore", - "subtitle": "Export and import clients with a unified JSON format, ensuring seamless transfers across app versions." + "title": "Back up client connections", + "subtitle": "Export and import saved client setups in a unified JSON format when you move devices or reinstall the app." }, { "id": "optionalCertificateEvaluation", - "title": "Optional Certificate Evaluation", - "subtitle": "Option to bypass certificate evaluation for client hosts, enabling connections to servers with self-signed certificates." + "title": "Connect to self-hosted environments", + "subtitle": "Optional certificate evaluation bypass helps when your downloader host uses a self-signed certificate." } ] }, "downloaders": { - "title": "Supported downloaders" + "title": "Supported download clients" }, "quickstart": { - "title": "How it works", + "title": "Get started in minutes", "steps": [ { "title": "Install", - "body": "Get BitRemote on the App Store." + "body": "Download BitRemote from the App Store on iPhone, iPad, or Mac." }, { "title": "Connect", - "body": "Add your downloader client (host + credentials)." + "body": "Add your downloader client with its host address and credentials." }, { - "title": "Control", - "body": "Monitor and manage tasks from your Apple devices." + "title": "Manage", + "body": "Monitor activity, review queues, and control download tasks from your Apple devices." } ], "requirements": "Requires iOS / iPadOS / macOS 26.0 or later." @@ -79,7 +79,7 @@ "plus": { "title": "Pricing", "frameTitle": "BitRemote+", - "subtitle": "Choose the plan that fits your setup.", + "subtitle": "Start with the core app, then unlock advanced features for heavier downloader setups.", "items": ["Remove Ads", "Unlimited Clients", "Task Insight Panel", "Exclusive Client Types"], "note": "$1.99 per month, $9.99 per year, or $49.99 for a one-time purchase plan." }, @@ -88,11 +88,11 @@ "items": [ { "q": "Do I need to be on the same network?", - "a": "It depends on your setup. Many users connect over LAN, VPN, or a secure remote access method provided by their environment." + "a": "Not always. BitRemote works with the network access your setup allows, including LAN, VPN, or another secure remote access method." }, { "q": "Does BitRemote download files on my device?", - "a": "No. BitRemote controls and monitors your existing downloader clients." + "a": "No. BitRemote is a remote controller for your existing downloader client. The downloads stay on your NAS, seedbox, or server." }, { "q": "Is my data safe?", diff --git a/src/messages/ja.json b/src/messages/ja.json index 1a137d2..8b4dc11 100644 --- a/src/messages/ja.json +++ b/src/messages/ja.json @@ -1,8 +1,8 @@ { "site": { "name": "BitRemote", - "tagline": "ダウンロードツールをリモートで操作", - "description": "ダウンロードツールをリモートで操作できる Apple プラットフォーム向けアプリ。" + "tagline": "NAS とホームサーバー向けのリモートダウンロード管理", + "description": "NAS、seedbox、ホームサーバー上のダウンロードクライアントをリモート管理できる Apple プラットフォーム向けアプリ。" }, "nav": { "home": "ホーム", @@ -13,72 +13,72 @@ "faq": "FAQ" }, "cta": { - "appStore": "App Store でダウンロード", - "supportedDownloaders": "対応ダウンロードツール" + "appStore": "BitRemote を App Store でダウンロード", + "supportedDownloaders": "対応ダウンロードクライアント" }, "hero": { - "subhead": "iPhone / iPad / Mac に対応。外出先からでもタスク管理とアクティビティ確認。" + "subhead": "iPhone / iPad / Mac に対応。aria2、qBittorrent、Transmission、Synology Download Station、QNAP Download Station に接続して、どこからでもダウンロードタスクを管理できます。" }, "sections": { "benefits": { - "title": "機能", + "title": "どこからでもダウンロード管理", "items": [ { "id": "diverseClientSupport", - "title": "多様なクライアントサポート", - "subtitle": "{clients} など、人気ダウンロードツールとシームレスに連携。" + "title": "主要なダウンロードクライアントに対応", + "subtitle": "{clients} に接続し、1つの Apple アプリからダウンロードタスクを確認・操作できます。" }, { "id": "comprehensiveTaskManagement", - "title": "包括的なタスク管理", - "subtitle": "ダウンロードタスクの一時停止、再開、削除、新規追加など、簡単に制御できます。" + "title": "リモートでタスク操作", + "subtitle": "NAS やホームサーバーの管理画面に戻らなくても、タスクの追加、一時停止、再開、削除が行えます。" }, { "id": "smartFilteringSorting", - "title": "スマートなフィルタリングと並べ替え", - "subtitle": "ステータス、カテゴリ、タグでダウンロードタスクを整理し、多様な条件で効率的に並べ替えができます。" + "title": "キューを素早く整理", + "subtitle": "ステータス、カテゴリ、タグでタスクを絞り込み、大量のダウンロードキューから目的の項目をすぐに見つけられます。" }, { "id": "activityMonitor", - "title": "アクティビティモニタ", - "subtitle": "クライアントの統計情報と転送履歴をリアルタイムで確認できます。" + "title": "転送状況を確認", + "subtitle": "ダウンロードクライアントの速度、統計情報、転送履歴をリアルタイムで確認できます。" }, { "id": "clientsBackupRestore", - "title": "クライアントのバックアップと復元", - "subtitle": "統一された JSON フォーマットでクライアントをバックアップ・復元し、アプリのバージョン間で円滑に転送できます。" + "title": "接続設定をバックアップ", + "subtitle": "保存したクライアント設定を JSON 形式で書き出し・読み込みできるため、端末移行や再設定が簡単です。" }, { "id": "optionalCertificateEvaluation", - "title": "選択的証明書認証", - "subtitle": "クライアントホストの証明書認証をスキップするオプションにより、自己署名証明書を使用するサーバーへの接続が可能になります。" + "title": "セルフホスト環境にも対応", + "subtitle": "自己署名証明書を使うホスト向けに、証明書評価をスキップするオプションを利用できます。" } ] }, "downloaders": { - "title": "対応ダウンロードツール" + "title": "対応ダウンロードクライアント" }, "quickstart": { - "title": "使い方", + "title": "すぐに始める", "steps": [ - { "title": "インストール", "body": "App Store から BitRemote を入手。" }, - { "title": "接続", "body": "クライアント(ホストと認証情報)を追加。" }, - { "title": "操作", "body": "Apple デバイスからタスクを管理・監視。" } + { "title": "インストール", "body": "iPhone、iPad、または Mac に BitRemote を App Store からインストール。" }, + { "title": "接続", "body": "ダウンロードクライアントのホスト情報と認証情報を追加。" }, + { "title": "管理", "body": "Apple デバイスからアクティビティ確認とタスク操作を開始。" } ], "requirements": "iOS / iPadOS / macOS 26.0 以降が必要です。" }, "plus": { "title": "料金", "frameTitle": "BitRemote+", - "subtitle": "使い方に合ったプランを選べます。", + "subtitle": "基本機能から始めて、より多くのクライアントや詳細機能が必要になったらアップグレードできます。", "items": ["広告非表示", "クライアント数制限なし", "タスクの詳細情報パネル", "専用クライアントタイプ"], "note": "月額 US$1.99、年額 US$9.99、または一度購入プラン US$49.99。" }, "faq": { "title": "FAQ", "items": [ - { "q": "同じネットワーク内で使う必要がありますか?", "a": "構成によります。LAN / VPN / セキュアなリモートアクセス等をご利用ください。" }, - { "q": "端末にファイルをダウンロードしますか?", "a": "いいえ。BitRemote は既存のダウンロードツールのクライアントを操作・監視します。" }, + { "q": "同じネットワーク内で使う必要がありますか?", "a": "必ずしもそうではありません。LAN、VPN、または安全なリモートアクセス手段など、環境が許可する接続方法を利用できます。" }, + { "q": "端末にファイルをダウンロードしますか?", "a": "いいえ。BitRemote は既存のダウンロードクライアントを遠隔操作するアプリであり、ダウンロード先は NAS やサーバー側です。" }, { "q": "データは安全ですか?", "a": "クライアント認証情報は当社サーバーにアップロードされないため、当社がアクセスすることはありません。ただし、認証情報は端末内で暗号化されません。脱獄デバイスで BitRemote を使用すると、認証情報が漏えいする可能性があります。" } ] } diff --git a/src/messages/zh-hans.json b/src/messages/zh-hans.json index b4e2d9c..d88cd59 100644 --- a/src/messages/zh-hans.json +++ b/src/messages/zh-hans.json @@ -1,8 +1,8 @@ { "site": { "name": "BitRemote", - "tagline": "远程控制你的下载工具", - "description": "一款可在 Apple 设备上远程控制下载工具的应用。" + "tagline": "适用于 NAS 与家庭服务器的远程下载管理", + "description": "可在 Apple 设备上远程管理 NAS、seedbox 与家庭服务器下载客户端的应用。" }, "nav": { "home": "主页", @@ -13,72 +13,72 @@ "faq": "常见问题" }, "cta": { - "appStore": "前往 App Store 下载", - "supportedDownloaders": "支持的下载工具" + "appStore": "前往 App Store 下载 BitRemote", + "supportedDownloaders": "支持的下载客户端" }, "hero": { - "subhead": "适用于 iPhone / iPad / Mac。随时随地管理任务、查看活动情况。" + "subhead": "适用于 iPhone / iPad / Mac。连接 aria2、qBittorrent、Transmission、Synology Download Station 与 QNAP Download Station,随时随地管理下载任务。" }, "sections": { "benefits": { - "title": "功能", + "title": "随时随地管理下载", "items": [ { "id": "diverseClientSupport", - "title": "多元客户端支持", - "subtitle": "无缝整合常用的下载工具,包括 {clients}。" + "title": "支持主流下载客户端", + "subtitle": "将 BitRemote 连接到 {clients},在同一个 Apple 应用中管理下载任务。" }, { "id": "comprehensiveTaskManagement", - "title": "全面的任务管理", - "subtitle": "轻松控制您的下载任务,可随时暂停、恢复、删除任务,并添加新任务。" + "title": "远程控制下载任务", + "subtitle": "不用回到 NAS、seedbox 或家庭服务器后台,也能新增、暂停、恢复或删除任务。" }, { "id": "smartFilteringSorting", - "title": "智能过滤和排序", - "subtitle": "按状态、类别或标签整理下载任务,并按各种条件排序提高管理效率。" + "title": "快速整理下载队列", + "subtitle": "按状态、类别或标签筛选与排序任务,更快找到进行中、暂停中或已完成的下载。" }, { "id": "activityMonitor", - "title": "活动监视器", - "subtitle": "实时掌握客户端的统计数据与传输记录。" + "title": "查看传输活动", + "subtitle": "在 iPhone、iPad 或 Mac 上实时查看速度、统计数据与传输记录。" }, { "id": "clientsBackupRestore", - "title": "客户端数据备份与恢复", - "subtitle": "使用统一的 JSON 格式导出和导入客户端,确保在不同版本间无缝转移。" + "title": "备份连接设置", + "subtitle": "以统一的 JSON 格式导出与导入已保存的客户端设置,方便换机或重新安装。" }, { "id": "optionalCertificateEvaluation", - "title": "可选的证书验证", - "subtitle": "可选择跳过客户端主机的证书验证,允许连接到使用自签证书的服务器。" + "title": "适合自托管环境", + "subtitle": "如果你的主机使用自签证书,可选择跳过证书验证。" } ] }, "downloaders": { - "title": "支持的下载工具" + "title": "支持的下载客户端" }, "quickstart": { - "title": "使用方式", + "title": "快速开始", "steps": [ - { "title": "安装", "body": "在 App Store 获取 BitRemote。" }, - { "title": "连接", "body": "添加你的客户端(主机与凭据)。" }, - { "title": "控制", "body": "在 Apple 设备上监控并管理任务。" } + { "title": "安装", "body": "在 iPhone、iPad 或 Mac 上从 App Store 获取 BitRemote。" }, + { "title": "连接", "body": "添加下载客户端的主机地址与登录凭据。" }, + { "title": "管理", "body": "在 Apple 设备上监控活动并控制下载任务。" } ], "requirements": "需要 iOS / iPadOS / macOS 26.0 或更高版本。" }, "plus": { "title": "价格", "frameTitle": "BitRemote+", - "subtitle": "选择适合你使用方式的方案。", + "subtitle": "可先使用核心功能,等需要更多客户端与高级功能时再升级。", "items": ["移除广告", "不限客户端数", "任务详情面板", "专属客户端类型"], "note": "每月 US$1.99、每年 US$9.99,或单次购买方案 US$49.99。" }, "faq": { "title": "常见问题", "items": [ - { "q": "必须在同一网络下使用吗?", "a": "取决于你的网络环境。你可以通过局域网、VPN 或其他安全方式连接。" }, - { "q": "BitRemote 会在设备上下载文件吗?", "a": "不会。BitRemote 用于控制和监控现有的下载工具客户端。" }, + { "q": "必须在同一网络下使用吗?", "a": "不一定。BitRemote 可以根据你的环境,通过局域网、VPN 或其他安全的远程访问方式连接。" }, + { "q": "BitRemote 会在设备上下载文件吗?", "a": "不会。BitRemote 是现有下载客户端的远程控制器,文件仍会下载到 NAS、seedbox 或服务器端。" }, { "q": "我的数据安全吗?", "a": "你的客户端凭据不会上传到我们的服务器,因此我们无法访问这些凭据。但这些凭据不会在设备上加密。如果你在越狱设备上使用 BitRemote,客户端凭据可能会被泄露。" } ] } diff --git a/src/messages/zh-hant.json b/src/messages/zh-hant.json index 2df3cad..733b90a 100644 --- a/src/messages/zh-hant.json +++ b/src/messages/zh-hant.json @@ -1,8 +1,8 @@ { "site": { "name": "BitRemote", - "tagline": "遠端控制你的下載工具", - "description": "一款可在 Apple 裝置上遠端控制下載工具的 App。" + "tagline": "適用於 NAS 與家用伺服器的遠端下載管理", + "description": "可在 Apple 裝置上遠端管理 NAS、seedbox 與家用伺服器下載用戶端的 App。" }, "nav": { "home": "主頁", @@ -13,72 +13,72 @@ "faq": "常見問題" }, "cta": { - "appStore": "前往 App Store 下載", - "supportedDownloaders": "支援的下載工具" + "appStore": "前往 App Store 下載 BitRemote", + "supportedDownloaders": "支援的下載用戶端" }, "hero": { - "subhead": "適用於 iPhone / iPad / Mac。隨時隨地管理任務、查看活動狀態。" + "subhead": "適用於 iPhone / iPad / Mac。連接 aria2、qBittorrent、Transmission、Synology Download Station 與 QNAP Download Station,隨時隨地管理下載任務。" }, "sections": { "benefits": { - "title": "功能", + "title": "隨時隨地管理下載", "items": [ { "id": "diverseClientSupport", - "title": "多元用戶端支援", - "subtitle": "無縫整合常用的下載工具,包括 {clients}。" + "title": "支援主流下載用戶端", + "subtitle": "將 BitRemote 連接到 {clients},在同一個 Apple App 中管理下載任務。" }, { "id": "comprehensiveTaskManagement", - "title": "全面的任務管理", - "subtitle": "輕鬆控制您的下載任務,可隨時暫停、恢復、刪除任務,並添加新任務。" + "title": "遠端控制下載任務", + "subtitle": "不用回到 NAS、seedbox 或家用伺服器後台,也能新增、暫停、恢復或刪除任務。" }, { "id": "smartFilteringSorting", - "title": "智慧過濾和排序", - "subtitle": "按狀態、類別或標籤整理下載任務,並按各種條件排序提高管理效率。" + "title": "快速整理下載佇列", + "subtitle": "依狀態、類別或標籤篩選與排序任務,更快找到進行中、暫停中或已完成的下載。" }, { "id": "activityMonitor", - "title": "活動監視器", - "subtitle": "實時掌握用戶端的統計資料與傳輸紀錄。" + "title": "查看傳輸活動", + "subtitle": "在 iPhone、iPad 或 Mac 上即時查看速度、統計資料與傳輸紀錄。" }, { "id": "clientsBackupRestore", - "title": "用戶端資料備份與回復", - "subtitle": "使用統一的 JSON 格式匯出和匯入用戶端,確保在不同版本間無縫轉移。" + "title": "備份連線設定", + "subtitle": "以統一的 JSON 格式匯出與匯入已儲存的用戶端設定,方便換機或重新安裝。" }, { "id": "optionalCertificateEvaluation", - "title": "可選的憑證驗證", - "subtitle": "可選擇跳過用戶端主機的憑證驗證,允許連接到使用自簽憑證的伺服器。" + "title": "適合自架環境", + "subtitle": "若你的主機使用自簽憑證,可選擇略過憑證驗證。" } ] }, "downloaders": { - "title": "支援的下載工具" + "title": "支援的下載用戶端" }, "quickstart": { - "title": "使用方式", + "title": "快速開始", "steps": [ - { "title": "安裝", "body": "在 App Store 取得 BitRemote。" }, - { "title": "連線", "body": "新增你的用戶端(主機與憑證)。" }, - { "title": "控制", "body": "在 Apple 裝置上監控並管理任務。" } + { "title": "安裝", "body": "在 iPhone、iPad 或 Mac 上從 App Store 取得 BitRemote。" }, + { "title": "連線", "body": "新增下載用戶端的主機位址與登入憑證。" }, + { "title": "管理", "body": "在 Apple 裝置上監控活動並控制下載任務。" } ], "requirements": "需要 iOS / iPadOS / macOS 26.0 或以上版本。" }, "plus": { "title": "價格", "frameTitle": "BitRemote+", - "subtitle": "選擇適合你使用方式的方案。", + "subtitle": "可先使用核心功能,當需要更多用戶端與進階功能時再升級。", "items": ["移除廣告", "不限用戶端數", "任務明細面板", "專屬用戶端類型"], "note": "每月 US$1.99、每年 US$9.99,或單次購買方案 US$49.99。" }, "faq": { "title": "常見問題", "items": [ - { "q": "必須在同一網路下使用嗎?", "a": "取決於你的網路環境。你可以透過區域網路、VPN 或其他安全方式連線。" }, - { "q": "BitRemote 會在裝置上下載檔案嗎?", "a": "不會。BitRemote 用於控制與監控現有的下載工具用戶端。" }, + { "q": "必須在同一網路下使用嗎?", "a": "不一定。BitRemote 可依你的環境,透過區域網路、VPN 或其他安全的遠端存取方式連線。" }, + { "q": "BitRemote 會在裝置上下載檔案嗎?", "a": "不會。BitRemote 是現有下載用戶端的遠端控制器,檔案仍會下載到 NAS、seedbox 或伺服器端。" }, { "q": "我的資料安全嗎?", "a": "你的用戶端憑證不會上傳到我們的伺服器,因此我們無法存取這些憑證。不過,這些憑證不會在裝置上加密。若你在越獄裝置上使用 BitRemote,用戶端憑證可能會被洩露。" } ] } From 093bdf503406e65e5d8e835b6b3911f7b04261a6 Mon Sep 17 00:00:00 2001 From: Tatsuzo Araki Date: Sat, 21 Mar 2026 01:49:43 +0900 Subject: [PATCH 04/14] Add structured data for current routes Introduce reusable JSON-LD helpers for SoftwareApplication, FAQPage, and BreadcrumbList schema so the current locale routes can emit structured data from the same localized content source. Add SoftwareApplication and FAQPage schema to the localized homepage, and breadcrumb schema to the support, privacy, and terms pages without changing the existing UI layout. --- src/app/[locale]/page.tsx | 30 ++++++++---- src/app/[locale]/privacy/page.tsx | 13 +++++ src/app/[locale]/support/page.tsx | 13 +++++ src/app/[locale]/terms/page.tsx | 13 +++++ src/domain/clients.ts | 8 +++ src/seo/schema.ts | 81 +++++++++++++++++++++++++++++++ 6 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 src/seo/schema.ts diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index c26daec..1182263 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -4,18 +4,15 @@ import { FaqAccordion } from '@/components/FaqAccordion'; import { TextButton } from '@/components/TextButton'; import { TextFrame } from '@/components/TextFrame'; import { TextSeparator } from '@/components/TextSeparator'; -import { Client } from '@/domain/clients'; +import { supportedClients } from '@/domain/clients'; import { LINKS } from '@/i18n/links'; import { defaultLocale, isLocale, type Locale } from '@/i18n/locales'; import { getMessages } from '@/i18n/messages'; - -const supportedClients: readonly Client[] = [ - Client.aria2, - Client.qBittorrent, - Client.Transmission, - Client.SynologyDownloadStation, - Client.QNAPDownloadStation, -]; +import { + buildFaqPageSchema, + buildSoftwareApplicationSchema, + serializeJsonLd, +} from '@/seo/schema'; function formatSupportedClients(locale: Locale): string { if (supportedClients.length === 0) { @@ -60,9 +57,24 @@ export default async function LocaleHomePage({ const benefits = messages.sections.benefits.items; const supportedClientsText = formatSupportedClients(locale); + const softwareApplicationSchema = buildSoftwareApplicationSchema({ + locale, + messages, + supportedClients, + }); + const faqPageSchema = buildFaqPageSchema(messages); return (
+