diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index cae321e..85743d9 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -5,7 +5,6 @@ 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.',
manifest: '/site.webmanifest',
icons: {
icon: [
diff --git a/src/app/llms-full.txt/route.ts b/src/app/llms-full.txt/route.ts
new file mode 100644
index 0000000..b759d9c
--- /dev/null
+++ b/src/app/llms-full.txt/route.ts
@@ -0,0 +1,96 @@
+import { downloaderSlugByDownloader, getDownloaderLandingContent } from '@/domain/downloader-landings';
+import { supportedDownloaders } from '@/domain/downloaders';
+import { LINKS } from '@/i18n/links';
+import { getMessages } from '@/i18n/messages';
+import { absoluteUrl } from '@/i18n/urls';
+
+export const dynamic = 'force-static';
+
+export function GET() {
+ const messages = getMessages('en');
+ const sections: string[] = [];
+
+ // Header
+ sections.push(`# BitRemote`);
+ sections.push(`\n> ${messages.site.description}`);
+
+ // About
+ sections.push(`\n## About\n`);
+ sections.push(messages.seo.home.description);
+ sections.push(`\n- Website: ${absoluteUrl('/en/')}`);
+ sections.push(`- App Store: ${LINKS.appStore}`);
+ sections.push(`- GitHub: ${LINKS.github}`);
+ sections.push(`- Discord: ${LINKS.discord}`);
+ sections.push(`- Telegram: ${LINKS.telegram}`);
+
+ // Features
+ sections.push(`\n## Features\n`);
+ for (const item of messages.sections.benefits.items) {
+ sections.push(`### ${item.title}\n`);
+ sections.push(item.subtitle);
+ sections.push('');
+ }
+
+ // Supported Downloaders
+ sections.push(`## Supported Downloaders\n`);
+ for (const d of supportedDownloaders) {
+ const slug = downloaderSlugByDownloader[d];
+ sections.push(`- [${d}](${absoluteUrl(`/en/downloaders/${slug}/`)})`);
+ }
+
+ // Quickstart
+ sections.push(`\n## Quickstart\n`);
+ for (const step of messages.sections.quickstart.steps) {
+ sections.push(`### ${step.title}\n`);
+ sections.push(step.body);
+ sections.push('');
+ }
+ sections.push(messages.sections.quickstart.requirements);
+
+ // Pricing
+ sections.push(`\n## Pricing\n`);
+ sections.push(messages.sections.plus.subtitle);
+ sections.push(`\nBitRemote+ includes:`);
+ for (const item of messages.sections.plus.items) {
+ sections.push(`- ${item}`);
+ }
+ sections.push(`\n${messages.sections.plus.note}`);
+
+ // FAQ
+ sections.push(`\n## FAQ\n`);
+ for (const item of messages.sections.faq.items) {
+ sections.push(`### ${item.q}\n`);
+ sections.push(item.a);
+ sections.push('');
+ }
+
+ // Downloader Landing Pages
+ sections.push(`## Downloader Details\n`);
+ for (const d of supportedDownloaders) {
+ const slug = downloaderSlugByDownloader[d];
+ const content = getDownloaderLandingContent('en', slug);
+ if (!content) continue;
+
+ sections.push(`### ${d}\n`);
+ sections.push(content.heroBody);
+ sections.push(`\n#### ${content.overviewTitle}\n`);
+ sections.push(content.overviewBody);
+ sections.push(`\n#### ${content.capabilityTitle}\n`);
+ for (const item of content.capabilityItems) {
+ sections.push(`- ${item}`);
+ }
+ sections.push(`\n#### ${content.useCaseTitle}\n`);
+ for (const item of content.useCaseItems) {
+ sections.push(`- ${item}`);
+ }
+ sections.push('');
+ }
+
+ const body = sections.join('\n');
+
+ return new Response(body, {
+ headers: {
+ 'Content-Type': 'text/plain; charset=utf-8',
+ },
+ });
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index ac8fbe2..eee1d1a 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,8 +1,41 @@
+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';
+import { localeLabels, localeLang, locales } from '@/i18n/locales';
+import { absoluteUrl, localePath, localeRoot } from '@/i18n/urls';
+
+const description =
+ 'Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on Apple devices.';
+
+export const metadata: Metadata = {
+ title: 'BitRemote',
+ description,
+ keywords: ['bitremote', 'remote download manager app', 'nas download app'],
+ alternates: {
+ canonical: 'https://bitremote.app/',
+ languages: {
+ ...Object.fromEntries(
+ locales.map((locale) => [localeLang[locale], absoluteUrl(localePath(locale, '/'))]),
+ ),
+ 'x-default': 'https://bitremote.app/',
+ },
+ },
+ openGraph: {
+ type: 'website',
+ url: 'https://bitremote.app/',
+ title: 'BitRemote',
+ description,
+ siteName: 'BitRemote',
+ locale: 'en_US',
+ },
+ twitter: {
+ card: 'summary',
+ title: 'BitRemote',
+ description,
+ },
+};
export default function RootPage() {
return (
diff --git a/src/app/robots.ts b/src/app/robots.ts
new file mode 100644
index 0000000..1521598
--- /dev/null
+++ b/src/app/robots.ts
@@ -0,0 +1,13 @@
+import type { MetadataRoute } from 'next';
+
+export const dynamic = 'force-static';
+
+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..0b08680
--- /dev/null
+++ b/src/app/sitemap.ts
@@ -0,0 +1,54 @@
+import type { MetadataRoute } from 'next';
+
+import {
+ getAvailableDownloaderLandingLocales,
+ getDownloaderLandingEntries,
+} from '@/domain/downloader-landings';
+import { localeLang, locales } from '@/i18n/locales';
+import { absoluteUrl, localePath } from '@/i18n/urls';
+import { getLocalizedRouteEntries } from '@/seo/routes';
+
+export const dynamic = 'force-static';
+
+export default function sitemap(): MetadataRoute.Sitemap {
+ const lastModified = new Date();
+
+ return [
+ {
+ url: absoluteUrl('/'),
+ lastModified,
+ },
+ {
+ url: absoluteUrl('/llms.txt'),
+ lastModified,
+ },
+ {
+ url: absoluteUrl('/llms-full.txt'),
+ lastModified,
+ },
+ ...getLocalizedRouteEntries().map(({ locale, pathname, url }) => ({
+ url,
+ lastModified,
+ alternates: {
+ languages: Object.fromEntries(
+ locales.map((candidateLocale) => [
+ localeLang[candidateLocale],
+ absoluteUrl(localePath(candidateLocale, pathname)),
+ ]),
+ ),
+ },
+ })),
+ ...getDownloaderLandingEntries().map(({ locale, content }) => ({
+ url: absoluteUrl(`/${locale}/downloaders/${content.slug}/`),
+ lastModified,
+ alternates: {
+ languages: Object.fromEntries(
+ getAvailableDownloaderLandingLocales(content.slug).map((candidateLocale) => [
+ localeLang[candidateLocale],
+ absoluteUrl(`/${candidateLocale}/downloaders/${content.slug}/`),
+ ]),
+ ),
+ },
+ })),
+ ];
+}
diff --git a/src/ascii-panel/pages/HomePage.tsx b/src/ascii-panel/pages/HomePage.tsx
index e69eda2..00abacd 100644
--- a/src/ascii-panel/pages/HomePage.tsx
+++ b/src/ascii-panel/pages/HomePage.tsx
@@ -2,101 +2,101 @@
import { useEffect, useState } from 'react';
-import { Client } from '@/domain/clients';
+import { Downloader } from '@/domain/downloaders';
-type ClientSpeed = { client: Client; up: string; down: string };
+type ClientSpeed = { client: Downloader; up: string; down: string };
type ClientSpeedFrame = readonly [ClientSpeed, ClientSpeed, ClientSpeed, ClientSpeed, ClientSpeed];
const clientsDataset: readonly ClientSpeedFrame[] = [
[
- { client: Client.aria2, up: '2 MB/s', down: '3 MB/s' },
- { client: Client.qBittorrent, up: '150 KB/s', down: '80 MB/s' },
- { client: Client.Transmission, up: '22 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '14 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
+ { client: Downloader.aria2, up: '2 MB/s', down: '3 MB/s' },
+ { client: Downloader.qBittorrent, up: '150 KB/s', down: '80 MB/s' },
+ { client: Downloader.Transmission, up: '22 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '14 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
],
[
- { client: Client.aria2, up: '3 MB/s', down: '4 MB/s' },
- { client: Client.qBittorrent, up: '168 KB/s', down: '92 MB/s' },
- { client: Client.Transmission, up: '24 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '16 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
+ { client: Downloader.aria2, up: '3 MB/s', down: '4 MB/s' },
+ { client: Downloader.qBittorrent, up: '168 KB/s', down: '92 MB/s' },
+ { client: Downloader.Transmission, up: '24 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '16 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
],
[
- { client: Client.aria2, up: '3 MB/s', down: '5 MB/s' },
- { client: Client.qBittorrent, up: '192 KB/s', down: '88 MB/s' },
- { client: Client.Transmission, up: '26 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '18 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '5 KB/s' },
+ { client: Downloader.aria2, up: '3 MB/s', down: '5 MB/s' },
+ { client: Downloader.qBittorrent, up: '192 KB/s', down: '88 MB/s' },
+ { client: Downloader.Transmission, up: '26 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '18 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '5 KB/s' },
],
[
- { client: Client.aria2, up: '2 MB/s', down: '4 MB/s' },
- { client: Client.qBittorrent, up: '180 KB/s', down: '82 MB/s' },
- { client: Client.Transmission, up: '25 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '17 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
+ { client: Downloader.aria2, up: '2 MB/s', down: '4 MB/s' },
+ { client: Downloader.qBittorrent, up: '180 KB/s', down: '82 MB/s' },
+ { client: Downloader.Transmission, up: '25 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '17 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
],
[
- { client: Client.aria2, up: '2 MB/s', down: '3 MB/s' },
- { client: Client.qBittorrent, up: '160 KB/s', down: '75 MB/s' },
- { client: Client.Transmission, up: '23 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '15 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
+ { client: Downloader.aria2, up: '2 MB/s', down: '3 MB/s' },
+ { client: Downloader.qBittorrent, up: '160 KB/s', down: '75 MB/s' },
+ { client: Downloader.Transmission, up: '23 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '15 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
],
[
- { client: Client.aria2, up: '4 MB/s', down: '2 MB/s' },
- { client: Client.qBittorrent, up: '142 KB/s', down: '72 MB/s' },
- { client: Client.Transmission, up: '21 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '13 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
+ { client: Downloader.aria2, up: '4 MB/s', down: '2 MB/s' },
+ { client: Downloader.qBittorrent, up: '142 KB/s', down: '72 MB/s' },
+ { client: Downloader.Transmission, up: '21 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '13 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
],
[
- { client: Client.aria2, up: '3 MB/s', down: '3 MB/s' },
- { client: Client.qBittorrent, up: '130 KB/s', down: '78 MB/s' },
- { client: Client.Transmission, up: '22 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '12 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
+ { client: Downloader.aria2, up: '3 MB/s', down: '3 MB/s' },
+ { client: Downloader.qBittorrent, up: '130 KB/s', down: '78 MB/s' },
+ { client: Downloader.Transmission, up: '22 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '12 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
],
[
- { client: Client.aria2, up: '2 MB/s', down: '4 MB/s' },
- { client: Client.qBittorrent, up: '145 KB/s', down: '86 MB/s' },
- { client: Client.Transmission, up: '24 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '13 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
+ { client: Downloader.aria2, up: '2 MB/s', down: '4 MB/s' },
+ { client: Downloader.qBittorrent, up: '145 KB/s', down: '86 MB/s' },
+ { client: Downloader.Transmission, up: '24 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '13 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '4 KB/s' },
],
[
- { client: Client.aria2, up: '1 MB/s', down: '5 MB/s' },
- { client: Client.qBittorrent, up: '158 KB/s', down: '84 MB/s' },
- { client: Client.Transmission, up: '23 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '15 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
+ { client: Downloader.aria2, up: '1 MB/s', down: '5 MB/s' },
+ { client: Downloader.qBittorrent, up: '158 KB/s', down: '84 MB/s' },
+ { client: Downloader.Transmission, up: '23 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '15 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '3 KB/s' },
],
[
- { client: Client.aria2, up: '2 MB/s', down: '3 MB/s' },
- { client: Client.qBittorrent, up: '154 KB/s', down: '79 MB/s' },
- { client: Client.Transmission, up: '22 MB/s', down: '0 KB/s' },
- { client: Client.SynologyDownloadStation, up: '14 KB/s', down: '0 KB/s' },
- { client: Client.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
+ { client: Downloader.aria2, up: '2 MB/s', down: '3 MB/s' },
+ { client: Downloader.qBittorrent, up: '154 KB/s', down: '79 MB/s' },
+ { client: Downloader.Transmission, up: '22 MB/s', down: '0 KB/s' },
+ { client: Downloader.SynologyDownloadStation, up: '14 KB/s', down: '0 KB/s' },
+ { client: Downloader.QNAPDownloadStation, up: '0 KB/s', down: '2 KB/s' },
],
] as const;
const FRAME_INTERVAL_MS = 2000;
const clientBadges = {
- [Client.aria2]: 'A',
- [Client.qBittorrent]: 'Q',
- [Client.Transmission]: 'T',
- [Client.SynologyDownloadStation]: 'S',
- [Client.QNAPDownloadStation]: 'Q',
-} as const satisfies Record
;
+ [Downloader.aria2]: 'A',
+ [Downloader.qBittorrent]: 'Q',
+ [Downloader.Transmission]: 'T',
+ [Downloader.SynologyDownloadStation]: 'S',
+ [Downloader.QNAPDownloadStation]: 'Q',
+} as const satisfies Record;
type Direction = 'up' | 'down' | 'none';
-function clientSkeletonName(client: Client): string {
+function clientSkeletonName(client: Downloader): string {
switch (client) {
- case Client.SynologyDownloadStation:
+ case Downloader.SynologyDownloadStation:
return 'Synology DS';
- case Client.QNAPDownloadStation:
+ case Downloader.QNAPDownloadStation:
return 'QNAP DS';
default:
return client;
diff --git a/src/components/DownloaderLandingPage.tsx b/src/components/DownloaderLandingPage.tsx
new file mode 100644
index 0000000..a2d32e0
--- /dev/null
+++ b/src/components/DownloaderLandingPage.tsx
@@ -0,0 +1,69 @@
+import { TextButton } from '@/components/TextButton';
+import { TextFrame } from '@/components/TextFrame';
+import { TextSeparator } from '@/components/TextSeparator';
+import type { DownloaderLandingContent } from '@/domain/downloader-landings';
+import { LINKS } from '@/i18n/links';
+import type { Messages } from '@/i18n/messages';
+import type { Locale } from '@/i18n/locales';
+import { localePath } from '@/i18n/urls';
+
+export function DownloaderLandingPage({
+ locale,
+ messages,
+ content,
+}: {
+ locale: Locale;
+ messages: Messages;
+ content: DownloaderLandingContent;
+}) {
+ return (
+
+
+
+ [{content.downloader}]
+
+
+ {content.heroTitle}
+
+ {content.heroBody}
+
+
+
+ {messages.cta.appStore}
+
+
+ {messages.nav.home}
+
+
+
+
+
+
+
+
+ {content.overviewBody}
+
+
+
+
+
+
+
+
+ {content.capabilityItems.map((item) => (
+ - {item}
+ ))}
+
+
+
+
+
+ {content.useCaseItems.map((item) => (
+ - {item}
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/domain/clients.ts b/src/domain/clients.ts
deleted file mode 100644
index f88a01d..0000000
--- a/src/domain/clients.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export enum Client {
- aria2 = 'aria2',
- qBittorrent = 'qBittorrent',
- Transmission = 'Transmission',
- SynologyDownloadStation = 'Synology Download Station',
- QNAPDownloadStation = 'QNAP Download Station',
-}
diff --git a/src/domain/downloader-landings.ts b/src/domain/downloader-landings.ts
new file mode 100644
index 0000000..ed2c059
--- /dev/null
+++ b/src/domain/downloader-landings.ts
@@ -0,0 +1,557 @@
+import type { Locale } from '@/i18n/locales';
+import { Downloader } from '@/domain/downloaders';
+
+export const downloaderSlugByDownloader = {
+ [Downloader.aria2]: 'aria2',
+ [Downloader.qBittorrent]: 'qbittorrent',
+ [Downloader.Transmission]: 'transmission',
+ [Downloader.SynologyDownloadStation]: 'synology-download-station',
+ [Downloader.QNAPDownloadStation]: 'qnap-download-station',
+} as const satisfies Record;
+
+export type DownloaderLandingSlug = (typeof downloaderSlugByDownloader)[Downloader];
+
+export const downloaderLandingSlugs = Object.values(downloaderSlugByDownloader);
+
+/* ------------------------------------------------------------------ */
+/* Types */
+/* ------------------------------------------------------------------ */
+
+/** Fields that are unique per downloader (stored in the dictionary). */
+type DownloaderLandingEntry = {
+ seoDescription: string;
+ heroTitle: string;
+ heroBody: string;
+ overviewBody: string;
+ capabilityItems: string[];
+ useCaseItems: string[];
+};
+
+/** Factory that produces an entry from a downloader display name. */
+type DownloaderLandingEntryFactory = (d: Downloader) => DownloaderLandingEntry;
+
+/** Full content returned to consumers (entry + generated fields). */
+export type DownloaderLandingContent = DownloaderLandingEntry & {
+ slug: DownloaderLandingSlug;
+ downloader: Downloader;
+ primaryKeyword: string;
+ seoTitle: string;
+ overviewTitle: string;
+ capabilityTitle: string;
+ useCaseTitle: string;
+};
+
+/* ------------------------------------------------------------------ */
+/* Slug ↔ Downloader mapping */
+/* ------------------------------------------------------------------ */
+
+const downloaderBySlug = Object.fromEntries(
+ Object.entries(downloaderSlugByDownloader).map(([d, s]) => [s, d as Downloader]),
+) as Record;
+
+/* ------------------------------------------------------------------ */
+/* Per-locale templates for shared fields */
+/* ------------------------------------------------------------------ */
+
+type LocaleTemplates = {
+ primaryKeyword: (d: Downloader) => string;
+ seoTitle: (d: Downloader) => string;
+ overviewTitle: (d: Downloader) => string;
+ capabilityTitle: string;
+ useCaseTitle: string;
+};
+
+const hasCompactSeoTitle = (d: Downloader) =>
+ d === Downloader.SynologyDownloadStation || d === Downloader.QNAPDownloadStation;
+
+const localeTemplates: Record = {
+ en: {
+ primaryKeyword: (d) => `${d.toLowerCase()} remote control app`,
+ seoTitle: (d) =>
+ hasCompactSeoTitle(d)
+ ? `BitRemote for ${d} | Remote Control App`
+ : `BitRemote for ${d} | ${d} Remote Control App`,
+ overviewTitle: (d) => `Why use BitRemote with ${d}`,
+ capabilityTitle: 'What you can do',
+ useCaseTitle: 'How BitRemote helps with your workflow',
+ },
+ 'zh-hant': {
+ primaryKeyword: (d) => `${d} 遠端控制工具`,
+ seoTitle: (d) =>
+ hasCompactSeoTitle(d)
+ ? `BitRemote for ${d} | 遠端控制工具`
+ : `BitRemote for ${d} | ${d} 遠端控制工具`,
+ overviewTitle: (d) => `為什麼搭配 ${d} 使用 BitRemote`,
+ capabilityTitle: '主要功能',
+ useCaseTitle: 'BitRemote 如何幫助你最佳化工作流程',
+ },
+ 'zh-hans': {
+ primaryKeyword: (d) => `${d} 远程管理工具`,
+ seoTitle: (d) =>
+ hasCompactSeoTitle(d)
+ ? `BitRemote for ${d} | 远程管理工具`
+ : `BitRemote for ${d} | ${d} 远程管理工具`,
+ overviewTitle: (d) => `为什么搭配 ${d} 使用 BitRemote`,
+ capabilityTitle: '主要功能',
+ useCaseTitle: 'BitRemote 如何帮助你优化工作流',
+ },
+ ja: {
+ primaryKeyword: (d) => `${d} 遠隔操作アプリ`,
+ seoTitle: (d) =>
+ hasCompactSeoTitle(d)
+ ? `BitRemote for ${d} | 遠隔操作アプリ`
+ : `BitRemote for ${d} | ${d} 遠隔操作アプリ`,
+ overviewTitle: (d) => `${d} に BitRemote を使う理由`,
+ capabilityTitle: '主な機能',
+ useCaseTitle: 'BitRemote でワークフローを改善する方法',
+ },
+};
+
+/* ------------------------------------------------------------------ */
+/* Dictionary — entry factories keyed by Downloader enum */
+/* ------------------------------------------------------------------ */
+
+type DownloaderLandingDictionary = Partial<
+ Record>>
+>;
+
+const downloaderLandingDictionary: DownloaderLandingDictionary = {
+ en: {
+ [Downloader.aria2]: (d) => ({
+ seoDescription:
+ `Use BitRemote as an ${d} remote control app on iPhone, iPad, and Mac. Monitor queues, add tasks, and manage ${d} downloads from anywhere.`,
+ heroTitle: `Control ${d} downloads from iPhone, iPad, and Mac.`,
+ heroBody:
+ `BitRemote gives you a focused way to monitor ${d} activity, review queues, and manage remote download tasks without going back to your server dashboard.`,
+ overviewBody:
+ `If you already run ${d} on a NAS, VPS, seedbox, or home server, BitRemote gives you a native interface on iPhone, iPad, and Mac for checking progress and controlling download tasks while you are away from your main machine.`,
+ capabilityItems: [
+ `Review active, waiting, stopped, and completed ${d} tasks.`,
+ 'Pause, resume, remove, and add download tasks remotely.',
+ 'Check transfer activity and queue status from iPhone, iPad, and Mac.',
+ ],
+ useCaseItems: [
+ 'Monitor remote download jobs while away from your desk.',
+ `Manage self-hosted ${d} setups on a NAS or home server.`,
+ 'Keep track of large download queues from a simpler mobile UI.',
+ ],
+ }),
+ [Downloader.qBittorrent]: (d) => ({
+ seoDescription:
+ `Manage ${d} remotely with BitRemote on iPhone, iPad, and Mac. Review queues, monitor activity, and control ${d} tasks from anywhere.`,
+ heroTitle: `Use BitRemote as a ${d} remote control app.`,
+ heroBody:
+ `BitRemote helps you stay on top of ${d} queues from iPhone, iPad, and Mac, with a cleaner mobile-friendly view of remote download activity and task controls.`,
+ overviewBody:
+ `${d} is powerful, but the desktop web workflow is not always ideal on mobile devices. BitRemote gives you a dedicated interface on iPhone, iPad, and Mac for remote task management and status checks.`,
+ capabilityItems: [
+ `Monitor ${d} queues and transfer activity remotely.`,
+ `Pause, resume, remove, and add ${d} tasks from iPhone, iPad, and Mac.`,
+ 'Filter and inspect tasks without relying on a desktop browser session.',
+ ],
+ useCaseItems: [
+ 'Check home server download progress while away from home.',
+ 'Manage remote queues without opening the full web UI.',
+ `Access your ${d} server from iPhone, iPad, and Mac with one app.`,
+ ],
+ }),
+ [Downloader.Transmission]: (d) => ({
+ seoDescription:
+ `Control ${d} remotely with BitRemote on iPhone, iPad, and Mac. Monitor transfer activity, manage queues, and update remote tasks from anywhere.`,
+ heroTitle: `Manage ${d} from iPhone, iPad, and Mac.`,
+ heroBody:
+ `BitRemote gives ${d} users a focused remote control app for queue management, transfer monitoring, and fast status checks from iPhone, iPad, and Mac.`,
+ overviewBody:
+ `When your ${d} client runs on a NAS, server, or home setup, BitRemote makes it easier to check activity and control tasks without navigating a desktop-style interface.`,
+ capabilityItems: [
+ `Review ${d} task status and transfer activity remotely.`,
+ 'Pause, resume, remove, and add tasks from a native app for iPhone, iPad, and Mac.',
+ 'Use a simpler interface for frequent queue checks and quick actions.',
+ ],
+ useCaseItems: [
+ `Check ${d} activity while away from your server.`,
+ 'Manage home server downloads from iPhone or iPad.',
+ 'Use a cleaner Mac interface for quick queue updates.',
+ ],
+ }),
+ [Downloader.SynologyDownloadStation]: (d) => ({
+ seoDescription:
+ `Use BitRemote to manage ${d} remotely on iPhone, iPad, and Mac. Monitor tasks, review queues, and control downloads from anywhere.`,
+ heroTitle: `Remote control for ${d}.`,
+ heroBody:
+ `BitRemote gives Synology users a native app for iPhone, iPad, and Mac to monitor Download Station activity and manage remote download tasks without opening DSM every time.`,
+ overviewBody:
+ `If your downloads run through Download Station on a Synology NAS, BitRemote gives you a simpler experience on iPhone, iPad, and Mac for checking activity and controlling queues.`,
+ capabilityItems: [
+ `Review ${d} task status and queue activity.`,
+ 'Pause, resume, remove, and add download tasks remotely.',
+ 'Keep track of NAS download progress from iPhone, iPad, or Mac.',
+ ],
+ useCaseItems: [
+ 'Check NAS downloads without logging in to DSM.',
+ 'Manage download tasks while away from home or the office.',
+ 'Use a native app for iPhone, iPad, and Mac instead of a browser-based workflow.',
+ ],
+ }),
+ [Downloader.QNAPDownloadStation]: (d) => ({
+ seoDescription:
+ `Control ${d} remotely with BitRemote on iPhone, iPad, and Mac. Monitor queue activity and manage remote download tasks from anywhere.`,
+ heroTitle: `Remote download management for ${d}.`,
+ heroBody:
+ `BitRemote helps QNAP users monitor Download Station activity and control remote queues from a native app for iPhone, iPad, and Mac, built for quick task management.`,
+ overviewBody:
+ `When your downloads run on a QNAP NAS, BitRemote gives you a simpler way to check progress and manage tasks from iPhone, iPad, and Mac without relying on the full NAS interface.`,
+ capabilityItems: [
+ `Monitor ${d} task status and remote activity.`,
+ 'Pause, resume, remove, and add tasks from iPhone, iPad, and Mac.',
+ 'Use a cleaner interface for regular queue reviews and quick changes.',
+ ],
+ useCaseItems: [
+ 'Track NAS download progress while away from your desk.',
+ 'Manage QNAP queues from iPhone or iPad without opening the full web UI.',
+ 'Use Mac for faster remote queue checks and task cleanup.',
+ ],
+ }),
+ },
+ 'zh-hant': {
+ [Downloader.aria2]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 與 Mac 上使用 BitRemote 遠端管理 ${d}。隨時查看佇列、新增任務並管理 ${d} 下載。`,
+ heroTitle: `在 iPhone、iPad 與 Mac 上控制 ${d} 下載`,
+ heroBody:
+ `BitRemote 讓你不用回到伺服器後台,也能查看 ${d} 活動、檢查佇列並管理遠端下載任務。`,
+ overviewBody:
+ `如果你的 ${d} 執行在 NAS、VPS、seedbox 或家用伺服器上,BitRemote 能在 iPhone、iPad 與 Mac 上提供更適合日常管理的遠端介面。`,
+ capabilityItems: [
+ `查看 ${d} 進行中、等待中、停止中與已完成的任務`,
+ '遠端暫停、恢復、刪除與新增下載任務',
+ '在 iPhone、iPad 與 Mac 上檢查傳輸活動與佇列狀態',
+ ],
+ useCaseItems: [
+ '離開座位時查看遠端下載工作',
+ `管理 NAS 或家用伺服器上的自架 ${d}`,
+ '用更適合手機的介面追蹤大型下載佇列',
+ ],
+ }),
+ [Downloader.qBittorrent]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 與 Mac 上用 BitRemote 遠端管理 ${d}。隨時查看佇列、監控活動並控制 ${d} 任務。`,
+ heroTitle: `把 BitRemote 當成你的 ${d} 遠端控制工具`,
+ heroBody:
+ `BitRemote 幫助你在 iPhone、iPad 與 Mac 上更輕鬆查看 ${d} 佇列、掌握活動狀態,並快速執行任務操作。`,
+ overviewBody:
+ `${d} 功能很完整,但在行動裝置上不一定好操作。BitRemote 提供更專注的 iPhone、iPad 與 Mac 介面來處理遠端任務管理。`,
+ capabilityItems: [
+ `遠端監控 ${d} 佇列與傳輸活動`,
+ `從 iPhone、iPad 與 Mac 暫停、恢復、刪除與新增 ${d} 任務`,
+ '不用依賴桌面瀏覽器也能篩選與檢查任務',
+ ],
+ useCaseItems: [
+ '離家時檢查家中伺服器的下載進度',
+ '不開完整 Web UI 也能管理遠端佇列',
+ `用同一個 App 在 iPhone、iPad 與 Mac 上存取你的 ${d} 伺服器`,
+ ],
+ }),
+ [Downloader.Transmission]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 與 Mac 上用 BitRemote 遠端控制 ${d}。隨時監控傳輸活動、管理佇列並更新遠端任務。`,
+ heroTitle: `用 iPhone、iPad 與 Mac 管理 ${d}`,
+ heroBody:
+ `BitRemote 為 ${d} 使用者提供專注的遠端控制工具,方便在 iPhone、iPad 與 Mac 上查看佇列與傳輸狀態。`,
+ overviewBody:
+ `當 ${d} 執行在 NAS、伺服器或家用環境上時,BitRemote 讓你不用面對桌面式介面,也能快速檢查活動與控制任務。`,
+ capabilityItems: [
+ `遠端查看 ${d} 任務狀態與傳輸活動`,
+ '透過 iPhone、iPad 與 Mac 上的原生 App 暫停、恢復、刪除與新增任務',
+ '用更簡潔的介面完成常見佇列檢查與操作',
+ ],
+ useCaseItems: [
+ `離開伺服器時查看 ${d} 活動`,
+ '在 iPhone 或 iPad 上管理家用伺服器下載',
+ '用 Mac 更快速地清理與更新佇列',
+ ],
+ }),
+ [Downloader.SynologyDownloadStation]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 與 Mac 上用 BitRemote 遠端管理 ${d}。隨時查看任務、佇列與下載活動。`,
+ heroTitle: `${d} 的遠端控制工具`,
+ heroBody:
+ `BitRemote 為 Synology 使用者提供 iPhone、iPad 與 Mac 上的原生 App,可查看 Download Station 活動並管理遠端下載任務,不必每次都打開 DSM。`,
+ overviewBody:
+ `如果你的下載任務跑在 Synology NAS 的 Download Station 上,BitRemote 能在行動裝置與 Mac 上提供更簡單的管理體驗。`,
+ capabilityItems: [
+ `查看 ${d} 任務狀態與佇列活動`,
+ '遠端暫停、恢復、刪除與新增下載任務',
+ '在 iPhone、iPad 或 Mac 上追蹤 NAS 下載進度',
+ ],
+ useCaseItems: [
+ '不登入 DSM 也能查看 NAS 下載狀態',
+ '外出時管理家中或辦公室的下載任務',
+ '用 iPhone、iPad 與 Mac 上的原生 App 取代瀏覽器操作流程',
+ ],
+ }),
+ [Downloader.QNAPDownloadStation]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 與 Mac 上用 BitRemote 遠端控制 ${d}。隨時監控佇列活動並管理遠端下載任務。`,
+ heroTitle: `${d} 的遠端下載管理`,
+ heroBody:
+ `BitRemote 幫助 QNAP 使用者用 iPhone、iPad 與 Mac 上的原生 App 監看 Download Station 活動,並更快速地處理遠端佇列。`,
+ overviewBody:
+ `當你的下載任務跑在 QNAP NAS 上時,BitRemote 能在 iPhone、iPad 與 Mac 上提供更簡單的查看與管理方式。`,
+ capabilityItems: [
+ `監控 ${d} 任務狀態與遠端活動`,
+ '從 iPhone、iPad 與 Mac 暫停、恢復、刪除與新增任務',
+ '用更乾淨的介面進行例行佇列檢查與調整',
+ ],
+ useCaseItems: [
+ '離開座位時追蹤 NAS 下載進度',
+ '在 iPhone 或 iPad 上管理 QNAP 佇列而不打開完整 Web UI',
+ '用 Mac 更快完成遠端佇列檢查與整理',
+ ],
+ }),
+ },
+ 'zh-hans': {
+ [Downloader.aria2]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 和 Mac 上使用 BitRemote 远程管理 ${d}。随时查看队列、新增任务并管理 ${d} 下载。`,
+ heroTitle: `在 iPhone、iPad 和 Mac 上控制 ${d} 下载`,
+ heroBody:
+ `BitRemote 让你不用回到服务器后台,也能查看 ${d} 活动、检查队列并管理远程下载任务。`,
+ overviewBody:
+ `如果你的 ${d} 运行在 NAS、VPS、seedbox 或家庭服务器上,BitRemote 能在 iPhone、iPad 和 Mac 上提供更适合日常使用的远程管理界面。`,
+ capabilityItems: [
+ `查看 ${d} 进行中、等待中、停止中与已完成的任务`,
+ '远程暂停、恢复、删除与新增下载任务',
+ '在 iPhone、iPad 和 Mac 上检查传输活动与队列状态',
+ ],
+ useCaseItems: [
+ '离开座位时查看远程下载任务',
+ `管理 NAS 或家庭服务器上的自托管 ${d}`,
+ '用更适合手机的界面追踪大型下载队列',
+ ],
+ }),
+ [Downloader.qBittorrent]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 和 Mac 上用 BitRemote 远程管理 ${d}。随时查看队列、监控活动并控制 ${d} 任务。`,
+ heroTitle: `把 BitRemote 当作你的 ${d} 远程管理工具`,
+ heroBody:
+ `BitRemote 帮助你在 iPhone、iPad 和 Mac 上更轻松地查看 ${d} 队列、掌握活动状态,并快速执行任务操作。`,
+ overviewBody:
+ `${d} 功能强大,但在移动设备上不一定好操作。BitRemote 提供更专注的 iPhone、iPad 和 Mac 界面来处理远程任务管理。`,
+ capabilityItems: [
+ `远程监控 ${d} 队列与传输活动`,
+ `从 iPhone、iPad 和 Mac 暂停、恢复、删除与新增 ${d} 任务`,
+ '不用依赖桌面浏览器也能筛选与检查任务',
+ ],
+ useCaseItems: [
+ '离家时检查家庭服务器的下载进度',
+ '不开完整 Web UI 也能管理远程队列',
+ `用同一个 App 在 iPhone、iPad 和 Mac 上访问你的 ${d} 服务器`,
+ ],
+ }),
+ [Downloader.Transmission]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 和 Mac 上用 BitRemote 远程控制 ${d}。随时监控传输活动、管理队列并更新远程任务。`,
+ heroTitle: `用 iPhone、iPad 和 Mac 管理 ${d}`,
+ heroBody:
+ `BitRemote 为 ${d} 用户提供专注的远程管理工具,方便在 iPhone、iPad 和 Mac 上查看队列与传输状态。`,
+ overviewBody:
+ `当 ${d} 运行在 NAS、服务器或家庭环境上时,BitRemote 让你不用面对桌面式界面,也能快速检查活动与控制任务。`,
+ capabilityItems: [
+ `远程查看 ${d} 任务状态与传输活动`,
+ '通过 iPhone、iPad 和 Mac 上的原生 App 暂停、恢复、删除与新增任务',
+ '用更简洁的界面完成常见队列检查与操作',
+ ],
+ useCaseItems: [
+ `离开服务器时查看 ${d} 活动`,
+ '在 iPhone 或 iPad 上管理家庭服务器下载',
+ '用 Mac 更快清理与更新队列',
+ ],
+ }),
+ [Downloader.SynologyDownloadStation]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 和 Mac 上用 BitRemote 远程管理 ${d}。随时查看任务、队列与下载活动。`,
+ heroTitle: `${d} 的远程管理工具`,
+ heroBody:
+ `BitRemote 为 Synology 用户提供 iPhone、iPad 和 Mac 上的原生 App,可查看 Download Station 活动并管理远程下载任务,不必每次都打开 DSM。`,
+ overviewBody:
+ `如果你的下载任务运行在 Synology NAS 的 Download Station 上,BitRemote 能在移动设备与 Mac 上提供更简单的管理体验。`,
+ capabilityItems: [
+ `查看 ${d} 任务状态与队列活动`,
+ '远程暂停、恢复、删除与新增下载任务',
+ '在 iPhone、iPad 或 Mac 上追踪 NAS 下载进度',
+ ],
+ useCaseItems: [
+ '不登录 DSM 也能查看 NAS 下载状态',
+ '外出时管理家里或办公室的下载任务',
+ '用 iPhone、iPad 和 Mac 上的原生 App 替代浏览器操作流程',
+ ],
+ }),
+ [Downloader.QNAPDownloadStation]: (d) => ({
+ seoDescription:
+ `在 iPhone、iPad 和 Mac 上用 BitRemote 远程控制 ${d}。随时监控队列活动并管理远程下载任务。`,
+ heroTitle: `${d} 的远程下载管理`,
+ heroBody:
+ `BitRemote 帮助 QNAP 用户用 iPhone、iPad 和 Mac 上的原生 App 监看 Download Station 活动,并更快处理远程队列。`,
+ overviewBody:
+ `当你的下载任务运行在 QNAP NAS 上时,BitRemote 能在 iPhone、iPad 和 Mac 上提供更简单的查看与管理方式。`,
+ capabilityItems: [
+ `监控 ${d} 任务状态与远程活动`,
+ '从 iPhone、iPad 和 Mac 暂停、恢复、删除与新增任务',
+ '用更干净的界面完成日常队列检查与调整',
+ ],
+ useCaseItems: [
+ '离开座位时追踪 NAS 下载进度',
+ '在 iPhone 或 iPad 上管理 QNAP 队列而不打开完整 Web UI',
+ '用 Mac 更快完成远程队列检查与整理',
+ ],
+ }),
+ },
+ ja: {
+ [Downloader.aria2]: (d) => ({
+ seoDescription:
+ `iPhone、iPad、Mac で BitRemote を使って ${d} をリモート管理。キュー確認、新規追加、ダウンロード操作をどこからでも行えます。`,
+ heroTitle: `iPhone、iPad、Mac から ${d} を操作`,
+ heroBody:
+ `BitRemote を使えば、サーバー画面に戻らなくても ${d} の状態確認、キュー管理、遠隔操作ができます。`,
+ overviewBody:
+ `${d} を NAS、VPS、seedbox、ホームサーバーで運用しているなら、BitRemote が iPhone、iPad、Mac 向けの扱いやすい管理インターフェースになります。`,
+ capabilityItems: [
+ `${d} の進行中、待機中、停止中、完了済みタスクを確認`,
+ 'ダウンロードタスクの追加、一時停止、再開、削除を遠隔操作',
+ 'iPhone、iPad、Mac から転送状況とキュー状態を確認',
+ ],
+ useCaseItems: [
+ '席を離れている間に遠隔ダウンロード状況を確認',
+ `NAS やホームサーバー上のセルフホスト ${d} を管理`,
+ '大きなダウンロードキューを使いやすい UI で追跡',
+ ],
+ }),
+ [Downloader.qBittorrent]: (d) => ({
+ seoDescription:
+ `iPhone、iPad、Mac で BitRemote を使って ${d} をリモート管理。キュー確認、アクティビティ監視、タスク操作をどこからでも行えます。`,
+ heroTitle: `${d} 用の遠隔操作アプリとして使う`,
+ heroBody:
+ `BitRemote は iPhone、iPad、Mac で ${d} のキュー確認、状態把握、タスク操作を行いやすくする専用アプリです。`,
+ overviewBody:
+ `${d} は高機能ですが、モバイルでは操作しづらいことがあります。BitRemote は iPhone、iPad、Mac 向けのリモート管理に集中した UI を提供します。`,
+ capabilityItems: [
+ `${d} のキューと転送状況を遠隔監視`,
+ 'iPhone、iPad、Mac からタスクの追加、一時停止、再開、削除を実行',
+ 'デスクトップブラウザに頼らずタスクを絞り込み・確認',
+ ],
+ useCaseItems: [
+ '外出中にホームサーバーの進捗を確認',
+ 'Web UI を開かずに遠隔キューを管理',
+ `iPhone、iPad、Mac のどれからでも一つのアプリで ${d} サーバーにアクセス`,
+ ],
+ }),
+ [Downloader.Transmission]: (d) => ({
+ seoDescription:
+ `iPhone、iPad、Mac で BitRemote を使って ${d} をリモート操作。転送状況の監視、キュー管理、遠隔タスク更新が可能です。`,
+ heroTitle: `iPhone、iPad、Mac から ${d} を管理`,
+ heroBody:
+ `BitRemote は iPhone、iPad、Mac から ${d} のキューや転送状況をすばやく確認できるリモート管理アプリです。`,
+ overviewBody:
+ `${d} が NAS やサーバーで動いている場合でも、BitRemote ならデスクトップ向け画面に頼らず日常的な確認と操作ができます。`,
+ capabilityItems: [
+ `${d} のタスク状況と転送状況を遠隔確認`,
+ 'iPhone、iPad、Mac 向けの専用アプリからタスクの追加、一時停止、再開、削除を実行',
+ 'よくあるキュー確認をよりシンプルな UI で処理',
+ ],
+ useCaseItems: [
+ `サーバーから離れていても ${d} の状態を確認`,
+ 'iPhone や iPad からホームサーバーのダウンロードを管理',
+ 'Mac で素早くキューを見直して整理',
+ ],
+ }),
+ [Downloader.SynologyDownloadStation]: (d) => ({
+ seoDescription:
+ `iPhone、iPad、Mac で BitRemote を使って ${d} をリモート管理。タスク、キュー、ダウンロード状況をどこからでも確認できます。`,
+ heroTitle: `${d} 用の遠隔操作アプリ`,
+ heroBody:
+ 'BitRemote は Download Station の状況確認と遠隔操作を iPhone、iPad、Mac から行える専用アプリで、毎回 DSM を開く必要がありません。',
+ overviewBody:
+ 'Synology NAS の Download Station でダウンロードを回しているなら、BitRemote がモバイルや Mac での管理をより簡単にします。',
+ capabilityItems: [
+ `${d} のタスク状況とキュー活動を確認`,
+ 'ダウンロードタスクの追加、一時停止、再開、削除を遠隔実行',
+ 'iPhone、iPad、Mac から NAS の進捗を追跡',
+ ],
+ useCaseItems: [
+ 'DSM にログインせず NAS の状態を確認',
+ '外出中に自宅や職場のダウンロードタスクを管理',
+ 'ブラウザ中心の操作を iPhone、iPad、Mac の専用アプリに置き換え',
+ ],
+ }),
+ [Downloader.QNAPDownloadStation]: (d) => ({
+ seoDescription:
+ `iPhone、iPad、Mac で BitRemote を使って ${d} をリモート操作。キュー状況を監視し、遠隔ダウンロードタスクを管理できます。`,
+ heroTitle: `${d} の遠隔操作アプリ`,
+ heroBody:
+ `BitRemote は QNAP ユーザー向けに、Download Station の状況確認とキュー操作を素早く行える iPhone、iPad、Mac アプリを提供します。`,
+ overviewBody:
+ 'QNAP NAS でダウンロードを運用している場合、BitRemote は iPhone、iPad、Mac からの確認と管理をよりシンプルにします。',
+ capabilityItems: [
+ `${d} のタスク状況と遠隔活動を監視`,
+ 'iPhone、iPad、Mac からタスクの追加、一時停止、再開、削除を実行',
+ '日常的なキュー確認と調整をより見やすい UI で実施',
+ ],
+ useCaseItems: [
+ '席を離れている間に NAS の進捗を確認',
+ 'iPhone や iPad から Web UI を開かずに QNAP キューを管理',
+ 'Mac で遠隔キューの整理や確認をすばやく実施',
+ ],
+ }),
+ },
+};
+
+/* ------------------------------------------------------------------ */
+/* Public getters */
+/* ------------------------------------------------------------------ */
+
+function buildContent(
+ locale: Locale,
+ downloader: Downloader,
+ factory: DownloaderLandingEntryFactory,
+): DownloaderLandingContent {
+ const slug = downloaderSlugByDownloader[downloader];
+ const templates = localeTemplates[locale];
+ const entry = factory(downloader);
+ return {
+ ...entry,
+ slug,
+ downloader,
+ primaryKeyword: templates.primaryKeyword(downloader),
+ seoTitle: templates.seoTitle(downloader),
+ overviewTitle: templates.overviewTitle(downloader),
+ capabilityTitle: templates.capabilityTitle,
+ useCaseTitle: templates.useCaseTitle,
+ };
+}
+
+export function getDownloaderLandingContent(
+ locale: Locale,
+ slug: DownloaderLandingSlug,
+): DownloaderLandingContent | undefined {
+ const downloader = downloaderBySlug[slug];
+ const factory = downloaderLandingDictionary[locale]?.[downloader];
+ if (!factory) return undefined;
+ return buildContent(locale, downloader, factory);
+}
+
+export function getDownloaderLandingEntries() {
+ return Object.entries(downloaderLandingDictionary).flatMap(([locale, entries]) =>
+ Object.entries(entries ?? {}).map(([downloader, factory]) => ({
+ locale: locale as Locale,
+ content: buildContent(locale as Locale, downloader as Downloader, factory),
+ })),
+ );
+}
+
+export function getAvailableDownloaderLandingLocales(slug: DownloaderLandingSlug): Locale[] {
+ const downloader = downloaderBySlug[slug];
+ return (Object.keys(downloaderLandingDictionary) as Locale[]).filter(
+ (locale) => downloaderLandingDictionary[locale]?.[downloader],
+ );
+}
diff --git a/src/domain/downloaders.ts b/src/domain/downloaders.ts
new file mode 100644
index 0000000..191bf61
--- /dev/null
+++ b/src/domain/downloaders.ts
@@ -0,0 +1,15 @@
+export enum Downloader {
+ aria2 = 'aria2',
+ qBittorrent = 'qBittorrent',
+ Transmission = 'Transmission',
+ SynologyDownloadStation = 'Synology Download Station',
+ QNAPDownloadStation = 'QNAP Download Station',
+}
+
+export const supportedDownloaders: readonly Downloader[] = [
+ Downloader.aria2,
+ Downloader.qBittorrent,
+ Downloader.Transmission,
+ Downloader.SynologyDownloadStation,
+ Downloader.QNAPDownloadStation,
+];
diff --git a/src/messages/en.json b/src/messages/en.json
index e3912a7..7a5649c 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 app for iPhone, iPad, and Mac to remotely manage downloaders on NAS, seedbox, and home server setups."
},
"nav": {
"home": "Home",
@@ -13,45 +13,45 @@
"faq": "FAQ"
},
"cta": {
- "appStore": "Download on the App Store",
+ "appStore": "Download BitRemote on the App Store",
"supportedDownloaders": "Supported downloaders"
},
"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 your downloaders 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}."
+ "id": "accessibilitySupport",
+ "title": "Rich accessibility support",
+ "subtitle": "Supports VoiceOver, Voice Control, Larger Text, Dark Interface, Sufficient Contrast, Differentiate Without Color, and Reduced Motion."
},
{
"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 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 downloader connections",
+ "subtitle": "Export and import saved downloader 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."
}
]
},
@@ -59,19 +59,19 @@
"title": "Supported downloaders"
},
"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 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 iPhone, iPad, or Mac."
}
],
"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,15 +88,15 @@
"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. The downloads stay on your NAS, seedbox, or server."
},
{
"q": "Is my data safe?",
- "a": "Your client credentials are never uploaded to our servers, so we cannot access them. However, credentials are not encrypted on-device. If you use BitRemote on a jailbroken device, your client credentials may be compromised."
+ "a": "Your downloader credentials are never uploaded to our servers, so we cannot access them. However, credentials are not encrypted on-device. If you use BitRemote on a jailbroken device, your downloader credentials may be compromised."
}
]
}
@@ -116,5 +116,59 @@
"github": "Bug reports and feature requests:",
"githubButton": "GitHub Repository"
}
+ },
+ "seo": {
+ "home": {
+ "title": "BitRemote",
+ "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",
+ "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",
+ "description": "Read the official BitRemote privacy policy from Ark Studios for the remote download manager app used with NAS and downloaders.",
+ "keywords": [
+ "bitremote privacy policy",
+ "ark studios privacy",
+ "download manager privacy"
+ ]
+ },
+ "terms": {
+ "title": "BitRemote | EULA",
+ "description": "Read the BitRemote end user license agreement from Ark Studios for the remote download manager app for iPhone, iPad, and Mac.",
+ "keywords": [
+ "bitremote eula",
+ "bitremote terms",
+ "ark studios eula"
+ ]
+ },
+ "languageSelector": {
+ "title": "BitRemote",
+ "description": "Choose your language to learn about BitRemote, the remote download manager app for NAS, seedbox, and home server workflows on iPhone, iPad, and Mac.",
+ "keywords": [
+ "bitremote",
+ "remote download manager app",
+ "nas download app"
+ ]
+ }
}
}
diff --git a/src/messages/ja.json b/src/messages/ja.json
index 9db2c03..e0543c2 100644
--- a/src/messages/ja.json
+++ b/src/messages/ja.json
@@ -1,57 +1,57 @@
{
"site": {
"name": "BitRemote",
- "tagline": "ダウンロードツールをリモートで操作",
- "description": "ダウンロードツールをリモートで操作できる Apple プラットフォーム向けアプリ。"
+ "tagline": "NAS とホームサーバー向けのリモートダウンロード管理ツール",
+ "description": "NAS、seedbox、ホームサーバー上のダウンロードツールをリモート管理できる iPhone、iPad、Mac 向けアプリ。"
},
"nav": {
"home": "ホーム",
"features": "機能",
- "downloaders": "対応クライアント",
- "quickstart": "使い方",
+ "downloaders": "対応ダウンロードツール",
+ "quickstart": "はじめ方",
"subscription": "料金",
"faq": "FAQ"
},
"cta": {
- "appStore": "App Store でダウンロード",
+ "appStore": "BitRemote を App Store でダウンロード",
"supportedDownloaders": "対応ダウンロードツール"
},
"hero": {
- "subhead": "iPhone / iPad / Mac に対応。外出先からでもタスク管理とアクティビティ確認。"
+ "subhead": "iPhone / iPad / Mac に対応。ダウンロードツールに接続して、どこからでもアクティビティの確認とダウンロードタスクの管理ができます。"
},
"sections": {
"benefits": {
- "title": "機能",
+ "title": "どこからでもダウンロード管理",
"items": [
{
- "id": "diverseClientSupport",
- "title": "多様なクライアントサポート",
- "subtitle": "{clients} など、人気ダウンロードツールとシームレスに連携。"
+ "id": "accessibilitySupport",
+ "title": "充実したアクセシビリティ対応",
+ "subtitle": "「VoiceOver」「音声コントロール」「さらに大きな文字」「ダークインターフェース」「十分なコントラスト」「色を使わずに区別」「視差効果を減らす」に対応しています。"
},
{
"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": "自己署名証明書を使うサーバー向けに、証明書評価をスキップするオプションを利用できます。"
}
]
},
@@ -59,27 +59,27 @@
"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": "iPhone、iPad、Mac からアクティビティ確認とタスク操作を開始。" }
],
"requirements": "iOS / iPadOS / macOS 26.0 以降が必要です。"
},
"plus": {
"title": "料金",
"frameTitle": "BitRemote+",
- "subtitle": "使い方に合ったプランを選べます。",
- "items": ["広告非表示", "クライアント数制限なし", "タスクの詳細情報パネル", "専用クライアントタイプ"],
+ "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": "クライアント認証情報は当社サーバーにアップロードされないため、当社がアクセスすることはありません。ただし、認証情報は端末内で暗号化されません。脱獄デバイスで BitRemote を使用すると、認証情報が漏えいする可能性があります。" }
+ { "q": "同じネットワーク内で使う必要がありますか?", "a": "必ずしもそうではありません。LAN、VPN、または安全なリモートアクセス手段など、環境が許可する接続方法を利用できます。" },
+ { "q": "端末にファイルをダウンロードしますか?", "a": "いいえ。BitRemote は既存のダウンロードツールを遠隔操作するアプリであり、ダウンロード先は NAS やサーバー側です。" },
+ { "q": "データは安全ですか?", "a": "ダウンロードツール認証情報は当社サーバーにアップロードされないため、当社がアクセスすることはありません。ただし、認証情報は端末内で暗号化されません。脱獄デバイスで BitRemote を使用すると、認証情報が漏えいする可能性があります。" }
]
}
},
@@ -98,5 +98,59 @@
"github": "不具合報告・機能リクエスト:",
"githubButton": "GitHub リポジトリ"
}
+ },
+ "seo": {
+ "home": {
+ "title": "BitRemote",
+ "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 | サポート",
+ "description": "BitRemote のサポート情報、バグ報告、機能要望、コミュニティ参加先をまとめています。iPhone、iPad、Mac 向けリモートダウンロード管理アプリの案内ページです。",
+ "keywords": [
+ "BitRemote サポート",
+ "ダウンロード管理 サポート",
+ "BitRemote GitHub",
+ "BitRemote バグ報告",
+ "BitRemote コミュニティ"
+ ]
+ },
+ "privacy": {
+ "title": "BitRemote | 個人情報保護方針",
+ "description": "NAS や各種ダウンロードツールを操作する BitRemote の公式プライバシーポリシーを Ark Studios の案内先から確認できます。",
+ "keywords": [
+ "BitRemote 個人情報保護方針",
+ "Ark Studios 個人情報保護方針",
+ "ダウンロード管理 プライバシー"
+ ]
+ },
+ "terms": {
+ "title": "BitRemote | EULA",
+ "description": "iPhone、iPad、Mac 向けリモートダウンロード管理アプリ BitRemote の EULA を Ark Studios の案内先から確認できます。",
+ "keywords": [
+ "BitRemote EULA",
+ "BitRemote 利用規約",
+ "Ark Studios EULA"
+ ]
+ },
+ "languageSelector": {
+ "title": "BitRemote | リモートダウンロード管理アプリ",
+ "description": "BitRemote の紹介を読む言語を選択してください。NAS、seedbox、ホームサーバーのダウンロードタスクを iPhone、iPad、Mac から管理できます。",
+ "keywords": [
+ "BitRemote",
+ "リモートダウンロード管理アプリ",
+ "NAS ダウンロード アプリ"
+ ]
+ }
}
}
diff --git a/src/messages/zh-hans.json b/src/messages/zh-hans.json
index 9e0bd63..31649d5 100644
--- a/src/messages/zh-hans.json
+++ b/src/messages/zh-hans.json
@@ -1,57 +1,57 @@
{
"site": {
"name": "BitRemote",
- "tagline": "远程控制你的下载工具",
- "description": "一款可在 Apple 设备上远程控制下载工具的应用。"
+ "tagline": "适用于 NAS 与家庭服务器的远程下载管理工具",
+ "description": "可在 iPhone、iPad 和 Mac 上远程管理 NAS、seedbox 与家庭服务器下载工具的应用。"
},
"nav": {
"home": "主页",
"features": "功能",
"downloaders": "支持的下载工具",
- "quickstart": "使用方法",
+ "quickstart": "开始使用",
"subscription": "价格",
"faq": "常见问题"
},
"cta": {
- "appStore": "前往 App Store 下载",
+ "appStore": "前往 App Store 下载 BitRemote",
"supportedDownloaders": "支持的下载工具"
},
"hero": {
- "subhead": "适用于 iPhone / iPad / Mac。随时随地管理任务、查看活动情况。"
+ "subhead": "适用于 iPhone / iPad / Mac。连接你的下载工具,随时随地管理下载任务。"
},
"sections": {
"benefits": {
- "title": "功能",
+ "title": "随时随地管理下载",
"items": [
{
- "id": "diverseClientSupport",
- "title": "多元客户端支持",
- "subtitle": "无缝整合常用的下载工具,包括 {clients}。"
+ "id": "accessibilitySupport",
+ "title": "丰富的辅助功能支持",
+ "subtitle": "支持「旁白」、「语音控制」、「放大文字」、「深色界面」、「足够的对比度」、「不单靠颜色区分」和「减少动态效果」。"
},
{
"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": "如果你的主机使用自签证书,可选择跳过证书验证。"
}
]
},
@@ -59,26 +59,26 @@
"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": "在 iPhone、iPad 和 Mac 上监控活动并控制下载任务。" }
],
"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,客户端凭据可能会被泄露。" }
]
}
@@ -98,5 +98,59 @@
"github": "Bug 报告与功能请求:",
"githubButton": "GitHub 仓库"
}
+ },
+ "seo": {
+ "home": {
+ "title": "BitRemote",
+ "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 | 支持",
+ "description": "获取 BitRemote 支持、提交问题、提出功能需求,并加入社区。这是面向 iPhone、iPad、Mac 的远程下载管理应用支持入口。",
+ "keywords": [
+ "BitRemote 支持",
+ "下载管理 支持",
+ "BitRemote GitHub",
+ "BitRemote 问题反馈",
+ "BitRemote 社区"
+ ]
+ },
+ "privacy": {
+ "title": "BitRemote | 隐私权政策",
+ "description": "查看 Ark Studios 提供的 BitRemote 官方隐私政策,了解这款 NAS 与下载工具远程控制应用的数据处理方式。",
+ "keywords": [
+ "BitRemote 隐私政策",
+ "Ark Studios 隐私政策",
+ "下载管理 隐私"
+ ]
+ },
+ "terms": {
+ "title": "BitRemote | EULA",
+ "description": "查看 Ark Studios 提供的 BitRemote EULA。BitRemote 是一款适用于 iPhone、iPad 和 Mac 的远程下载管理应用。",
+ "keywords": [
+ "BitRemote EULA",
+ "BitRemote 条款",
+ "Ark Studios EULA"
+ ]
+ },
+ "languageSelector": {
+ "title": "BitRemote | 远程下载管理应用",
+ "description": "选择你的语言以了解 BitRemote。这款应用可让你在 iPhone、iPad 和 Mac 上管理 NAS、seedbox 与家庭服务器的下载任务。",
+ "keywords": [
+ "BitRemote",
+ "远程下载管理应用",
+ "NAS 下载应用"
+ ]
+ }
}
}
diff --git a/src/messages/zh-hant.json b/src/messages/zh-hant.json
index 09481aa..c481b51 100644
--- a/src/messages/zh-hant.json
+++ b/src/messages/zh-hant.json
@@ -1,57 +1,57 @@
{
"site": {
"name": "BitRemote",
- "tagline": "遠端控制你的下載工具",
- "description": "一款可在 Apple 裝置上遠端控制下載工具的 App。"
+ "tagline": "適用於 NAS 與家用伺服器的遠端下載管理工具",
+ "description": "可在 iPhone、iPad 與 Mac 上遠端管理 NAS、seedbox 與家用伺服器下載工具的 App。"
},
"nav": {
"home": "主頁",
"features": "功能",
"downloaders": "支援的下載工具",
- "quickstart": "使用方法",
+ "quickstart": "開始使用",
"subscription": "價格",
"faq": "常見問題"
},
"cta": {
- "appStore": "前往 App Store 下載",
+ "appStore": "前往 App Store 下載 BitRemote",
"supportedDownloaders": "支援的下載工具"
},
"hero": {
- "subhead": "適用於 iPhone / iPad / Mac。隨時隨地管理任務、查看活動狀態。"
+ "subhead": "適用於 iPhone / iPad / Mac。連接你的下載工具,隨時隨地管理下載任務。"
},
"sections": {
"benefits": {
- "title": "功能",
+ "title": "隨時隨地管理下載",
"items": [
{
- "id": "diverseClientSupport",
- "title": "多元用戶端支援",
- "subtitle": "無縫整合常用的下載工具,包括 {clients}。"
+ "id": "accessibilitySupport",
+ "title": "豐富的輔助使用支援",
+ "subtitle": "支援「旁白」、「語音控制」、「放大文字」、「深色介面」、「足夠的對比」、「不單靠顏色區分」與「減少動態效果」。"
},
{
"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": "若你的主機使用自簽憑證,可選擇略過憑證驗證。"
}
]
},
@@ -59,26 +59,26 @@
"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": "在 iPhone、iPad 與 Mac 上監控活動並控制下載任務。" }
],
"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,用戶端憑證可能會被洩露。" }
]
}
@@ -98,5 +98,59 @@
"github": "Bug 回報與功能請求:",
"githubButton": "GitHub 儲存庫"
}
+ },
+ "seo": {
+ "home": {
+ "title": "BitRemote",
+ "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 | 支援",
+ "description": "取得 BitRemote 支援、回報問題、提出功能需求,並加入社群。這是 iPhone、iPad、Mac 遠端下載管理 App 的支援入口。",
+ "keywords": [
+ "BitRemote 支援",
+ "下載管理 支援",
+ "BitRemote GitHub",
+ "BitRemote 問題回報",
+ "BitRemote 社群"
+ ]
+ },
+ "privacy": {
+ "title": "BitRemote | 隱私權政策",
+ "description": "查看 Ark Studios 提供的 BitRemote 官方隱私權政策,了解這款 NAS 與下載工具遠端控制 App 的資料處理方式。",
+ "keywords": [
+ "BitRemote 隱私權政策",
+ "Ark Studios 隱私權政策",
+ "下載管理 隱私"
+ ]
+ },
+ "terms": {
+ "title": "BitRemote | EULA",
+ "description": "查看 Ark Studios 提供的 BitRemote EULA。BitRemote 是用於 iPhone、iPad 與 Mac 的遠端下載管理 App。",
+ "keywords": [
+ "BitRemote EULA",
+ "BitRemote 條款",
+ "Ark Studios EULA"
+ ]
+ },
+ "languageSelector": {
+ "title": "BitRemote | 遠端下載管理 App",
+ "description": "選擇你的語言以了解 BitRemote。這款 App 可讓你在 iPhone、iPad 與 Mac 上管理 NAS、seedbox 與家用伺服器的下載任務。",
+ "keywords": [
+ "BitRemote",
+ "遠端下載管理 App",
+ "NAS 下載 App"
+ ]
+ }
}
}
diff --git a/src/seo/downloader-metadata.ts b/src/seo/downloader-metadata.ts
new file mode 100644
index 0000000..81e64b3
--- /dev/null
+++ b/src/seo/downloader-metadata.ts
@@ -0,0 +1,68 @@
+import type { Metadata } from 'next';
+
+import type { Downloader } from '@/domain/downloaders';
+import {
+ getAvailableDownloaderLandingLocales,
+ type DownloaderLandingContent,
+ type DownloaderLandingSlug,
+} from '@/domain/downloader-landings';
+import { localeLang, type Locale } from '@/i18n/locales';
+import { absoluteUrl } from '@/i18n/urls';
+
+const platforms = ['iPhone', 'iPad', 'Mac', 'iOS', 'iPadOS', 'macOS'] as const;
+
+function buildDownloaderKeywords(downloader: Downloader, primaryKeyword: string): string[] {
+ return [
+ primaryKeyword,
+ downloader,
+ 'BitRemote',
+ ...platforms.map((platform) => `${downloader} ${platform}`),
+ ];
+}
+
+function landingPath(locale: Locale, slug: DownloaderLandingSlug): string {
+ return `/${locale}/downloaders/${slug}/`;
+}
+
+export function buildDownloaderLandingMetadata({
+ locale,
+ slug,
+ content,
+}: {
+ locale: Locale;
+ slug: DownloaderLandingSlug;
+ content: DownloaderLandingContent;
+}): Metadata {
+ const canonical = absoluteUrl(landingPath(locale, slug));
+ const availableLocales = getAvailableDownloaderLandingLocales(slug);
+
+ return {
+ title: content.seoTitle,
+ description: content.seoDescription,
+ keywords: buildDownloaderKeywords(content.downloader, content.primaryKeyword),
+ alternates: {
+ canonical,
+ languages: {
+ ...Object.fromEntries(
+ availableLocales.map((candidateLocale) => [
+ localeLang[candidateLocale],
+ absoluteUrl(landingPath(candidateLocale, slug)),
+ ]),
+ ),
+ 'x-default': absoluteUrl(landingPath('en', slug)),
+ },
+ },
+ openGraph: {
+ type: 'website',
+ url: canonical,
+ title: content.seoTitle,
+ description: content.seoDescription,
+ siteName: 'BitRemote',
+ },
+ twitter: {
+ card: 'summary',
+ title: content.seoTitle,
+ description: content.seoDescription,
+ },
+ };
+}
diff --git a/src/seo/metadata.ts b/src/seo/metadata.ts
new file mode 100644
index 0000000..29f9872
--- /dev/null
+++ b/src/seo/metadata.ts
@@ -0,0 +1,73 @@
+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))]),
+ ),
+ 'x-default': absoluteUrl('/'),
+ };
+}
+
+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,
+ images: [
+ {
+ url: absoluteUrl('/opengraph.jpg'),
+ width: 3544,
+ height: 1772,
+ alt: messages.site.name,
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: seo.title,
+ description: seo.description,
+ images: [absoluteUrl('/opengraph.jpg')],
+ },
+ };
+}
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)),
+ })),
+ );
+}
diff --git a/src/seo/schema.ts b/src/seo/schema.ts
new file mode 100644
index 0000000..c591368
--- /dev/null
+++ b/src/seo/schema.ts
@@ -0,0 +1,81 @@
+import type { Messages } from '@/i18n/messages';
+import { LINKS } from '@/i18n/links';
+import { localeLang, type Locale } from '@/i18n/locales';
+import { absoluteUrl, localePath } from '@/i18n/urls';
+
+type BreadcrumbItem = {
+ name: string;
+ path: string;
+};
+
+export function serializeJsonLd(schema: object): { __html: string } {
+ return {
+ __html: JSON.stringify(schema).replace(/ item.title),
+ ...supportedDownloaders,
+ ],
+ sameAs: [LINKS.appStore, LINKS.github],
+ };
+}
+
+export function buildFaqPageSchema(messages: Messages) {
+ return {
+ '@context': 'https://schema.org',
+ '@type': 'FAQPage',
+ mainEntity: messages.sections.faq.items.map((item) => ({
+ '@type': 'Question',
+ name: item.q,
+ acceptedAnswer: {
+ '@type': 'Answer',
+ text: item.a,
+ },
+ })),
+ };
+}
+
+export function buildBreadcrumbSchema({
+ locale,
+ items,
+}: {
+ locale: Locale;
+ items: BreadcrumbItem[];
+}) {
+ return {
+ '@context': 'https://schema.org',
+ '@type': 'BreadcrumbList',
+ itemListElement: items.map((item, index) => ({
+ '@type': 'ListItem',
+ position: index + 1,
+ name: item.name,
+ item: absoluteUrl(localePath(locale, item.path)),
+ })),
+ };
+}