Remove preview link from mobile setup (#35619)

* Revert incorrect mobile download destination

* Remove mobile preview install option
This commit is contained in:
Jinjing
2026-10-28 20:02:24 -07:00
committed by GitHub
parent bfa0dc01ba
commit 79ba74dc38
19 changed files with 62 additions and 248 deletions
@@ -76,8 +76,7 @@ describe('HeroFlow height', () => {
platform="ios"
onPlatformChange={vi.fn()}
installQrUrl={null}
iosChannel="preview"
onIosChannelChange={vi.fn()}
installCopy={{ ctaLabel: 'Open TestFlight', url: 'https://example.com' }}
onOpenAndroidInstallGuide={vi.fn()}
onOpenInstallUrl={vi.fn()}
onCopyInstallUrl={vi.fn()}
@@ -123,8 +122,7 @@ describe('HeroFlow height', () => {
platform="ios"
onPlatformChange={vi.fn()}
installQrUrl={null}
iosChannel="preview"
onIosChannelChange={vi.fn()}
installCopy={{ ctaLabel: 'Open TestFlight', url: 'https://example.com' }}
onOpenAndroidInstallGuide={vi.fn()}
onOpenInstallUrl={vi.fn()}
onCopyInstallUrl={vi.fn()}
@@ -165,6 +163,7 @@ describe('HeroFlow height', () => {
const onOpenAndroidInstallGuide = vi.fn()
renderFlow(0, {
platform: 'android',
installCopy: { ctaLabel: 'Download APK', url: 'https://example.com/app-release.apk' },
onOpenAndroidInstallGuide
})
@@ -3,7 +3,7 @@ import { ArrowLeft, ArrowRight, Copy } from 'lucide-react'
import { cn } from '../../lib/utils'
import type { MobileNetworkInterface } from '../settings/mobile-network-interface-selection'
import { AndroidLogo, IosBrandIcon } from './MobileBrandIcons'
import { getChannelTagline, type IosChannel } from './mobile-platform-copy'
import type { InstallCopy } from './mobile-platform-copy'
import type { MobilePairingConnectionMode } from '../../../../shared/mobile-pairing-connection-mode'
import type { MobileRelayMintFailure } from '../../../../shared/mobile-relay-mint-failure'
import { MobileHeroPairingStep } from './MobileHeroPairingStep'
@@ -20,8 +20,7 @@ type HeroFlowProps = {
platform: Platform
onPlatformChange: (next: Platform) => void
installQrUrl: string | null
iosChannel: IosChannel
onIosChannelChange: (next: IosChannel) => void
installCopy: InstallCopy
onOpenAndroidInstallGuide: () => void
onOpenInstallUrl: () => void
onCopyInstallUrl: () => void
@@ -59,8 +58,7 @@ export function HeroFlow({
platform,
onPlatformChange,
installQrUrl,
iosChannel,
onIosChannelChange,
installCopy,
onOpenAndroidInstallGuide,
onOpenInstallUrl,
onCopyInstallUrl,
@@ -164,39 +162,9 @@ export function HeroFlow({
{translate('auto.components.mobile.MobileHero.ac1eb64952', 'Android')}
</button>
</div>
{platform === 'ios' ? (
<div
className="mp-channel-toggle"
role="radiogroup"
aria-label={translate(
'auto.components.mobile.MobileHero.channel.group',
'Release channel'
)}
>
<button
type="button"
role="radio"
aria-checked={iosChannel === 'preview'}
className={cn(iosChannel === 'preview' && 'is-active')}
onClick={() => onIosChannelChange('preview')}
>
{translate('auto.components.mobile.MobileHero.channel.preview', 'Preview')}
</button>
<button
type="button"
role="radio"
aria-checked={iosChannel === 'stable'}
className={cn(iosChannel === 'stable' && 'is-active')}
onClick={() => onIosChannelChange('stable')}
>
{translate('auto.components.mobile.MobileHero.channel.stable', 'Stable')}
</button>
<span className="mp-channel-tagline">{getChannelTagline(iosChannel)}</span>
</div>
) : null}
<div className="mp-inline-actions">
<button type="button" className="mp-ghost-action" onClick={onOpenInstallUrl}>
{translate('auto.components.mobile.MobileHero.downloadApp', 'Download app')}
{installCopy.ctaLabel}
</button>
<button type="button" className="mp-text-link" onClick={onCopyInstallUrl}>
<Copy className="size-3.5" />
@@ -3,7 +3,6 @@ import { toast } from 'sonner'
import { useMountedRef } from '@/hooks/useMountedRef'
import { useAppStore } from '@/store'
import type { Platform, StepIndex } from './MobileHero'
import type { IosChannel } from './mobile-platform-copy'
import type { MobileNetworkInterface } from '../settings/mobile-network-interface-selection'
import { translate } from '@/i18n/i18n'
import { useMobilePageEscape } from './use-mobile-page-escape'
@@ -28,8 +27,6 @@ export default function MobilePage(): React.JSX.Element {
const [stepIdx, setStepIdx] = useState<StepIndex>(0)
const [platform, setPlatform] = useState<Platform>('ios')
// Default to the daily iOS preview unless the user chooses the public release.
const [iosChannel, setIosChannel] = useState<IosChannel>('preview')
const [pairQrDataUrl, setPairQrDataUrl] = useState<string | null>(null)
const [pairQrSize, setPairQrSize] = useState<number | null>(null)
@@ -80,11 +77,9 @@ export default function MobilePage(): React.JSX.Element {
showPairedDevices,
stage
} = useMobilePagePairedDevices({ stepIdx, setStepIdx })
const installQrUrl = useMobileInstallQr(stage, platform, iosChannel)
const { copyInstallUrl, openAndroidInstallGuide, openInstallUrl } = useMobileInstallActions(
platform,
iosChannel
)
const installQrUrl = useMobileInstallQr(stage, platform)
const { copyInstallUrl, openAndroidInstallGuide, openInstallUrl } =
useMobileInstallActions(platform)
const { generatePairing } = useMobilePairingGeneration({
connectionMode,
@@ -339,8 +334,6 @@ export default function MobilePage(): React.JSX.Element {
handleBack={handleBack}
handleContinue={handleContinue}
installQrUrl={installQrUrl}
iosChannel={iosChannel}
setIosChannel={setIosChannel}
loadNetworkInterfaces={() => void loadNetworkInterfaces()}
networkInterfaces={networkInterfaces}
openAndroidInstallGuide={openAndroidInstallGuide}
@@ -8,7 +8,7 @@ import {
type Platform,
type StepIndex
} from './MobileHero'
import type { IosChannel } from './mobile-platform-copy'
import { getInstallCopy } from './mobile-platform-copy'
import type { MobilePageStage } from './mobile-page-stage'
import { MobilePageToolbar } from './MobilePageToolbar'
import { PhoneCarousel } from './PhoneCarousel'
@@ -32,8 +32,6 @@ type MobilePageContentProps = {
handleBack: () => void
handleContinue: () => void
installQrUrl: string | null
iosChannel: IosChannel
setIosChannel: (channel: IosChannel) => void
loadNetworkInterfaces: () => void
networkInterfaces: MobileNetworkInterface[]
openAndroidInstallGuide: () => void
@@ -80,8 +78,6 @@ export function MobilePageContent({
handleBack,
handleContinue,
installQrUrl,
iosChannel,
setIosChannel,
loadNetworkInterfaces,
networkInterfaces,
openAndroidInstallGuide,
@@ -134,8 +130,7 @@ export function MobilePageContent({
platform={platform}
onPlatformChange={setPlatform}
installQrUrl={installQrUrl}
iosChannel={iosChannel}
onIosChannelChange={setIosChannel}
installCopy={getInstallCopy(platform)}
onOpenAndroidInstallGuide={openAndroidInstallGuide}
onOpenInstallUrl={openInstallUrl}
onCopyInstallUrl={copyInstallUrl}
@@ -1,30 +1,24 @@
import type { Platform } from './MobileHero'
import { translate } from '@/i18n/i18n'
// iOS offers App Store and TestFlight tracks; Android has a single APK track.
export type IosChannel = 'stable' | 'preview'
export type InstallCopy = { ctaLabel: string; url: string }
export const ANDROID_INSTALL_GUIDE_URL = 'https://www.onorca.dev/docs/android-apk'
const IOS_CHANNEL_URLS: Record<IosChannel, string> = {
stable: 'https://apps.apple.com/app/orca-ide/id6766130217',
preview: 'https://testflight.apple.com/join/YjeGMQBA'
}
const ANDROID_INSTALL_URL = 'https://www.onorca.dev/download/android'
export function getInstallCopy(platform: Platform, iosChannel: IosChannel): { url: string } {
return { url: platform === 'ios' ? IOS_CHANNEL_URLS[iosChannel] : ANDROID_INSTALL_URL }
}
export function getChannelTagline(iosChannel: IosChannel): string {
return iosChannel === 'preview'
? translate(
'auto.components.mobile.mobile.platform.copy.preview.tagline',
'Newest features, updated daily.'
)
: translate(
'auto.components.mobile.mobile.platform.copy.stable.tagline',
'The public release, updated weekly.'
)
export function getInstallCopy(platform: Platform): InstallCopy {
return platform === 'ios'
? {
ctaLabel: translate(
'auto.components.mobile.mobile.platform.copy.openAppStore',
'Open App Store'
),
url: 'https://apps.apple.com/app/orca-ide/id6766130217'
}
: {
ctaLabel: translate(
'auto.components.mobile.mobile.platform.copy.downloadApk',
'Download APK'
),
url: 'https://www.onorca.dev/download/android'
}
}
@@ -1,21 +0,0 @@
// @vitest-environment happy-dom
import { cleanup, renderHook } from '@testing-library/react'
import { afterEach, expect, it, vi } from 'vitest'
import { useMobileInstallActions } from './use-mobile-install-actions'
afterEach(cleanup)
it.each([
['ios', 'preview'],
['ios', 'stable'],
['android', 'stable']
] as const)('opens the download page for %s and %s', (platform, channel) => {
const openUrl = vi.fn()
Object.defineProperty(window, 'api', { configurable: true, value: { shell: { openUrl } } })
const { result } = renderHook(() => useMobileInstallActions(platform, channel))
result.current.openInstallUrl()
expect(openUrl).toHaveBeenCalledWith('https://onorca.dev/download')
})
@@ -3,12 +3,9 @@ import { toast } from 'sonner'
import { useMountedRef } from '@/hooks/useMountedRef'
import { translate } from '@/i18n/i18n'
import type { Platform } from './MobileHero'
import { ANDROID_INSTALL_GUIDE_URL, getInstallCopy, type IosChannel } from './mobile-platform-copy'
import { ANDROID_INSTALL_GUIDE_URL, getInstallCopy } from './mobile-platform-copy'
export function useMobileInstallActions(
platform: Platform,
iosChannel: IosChannel
): {
export function useMobileInstallActions(platform: Platform): {
copyInstallUrl: () => Promise<void>
openAndroidInstallGuide: () => void
openInstallUrl: () => void
@@ -16,8 +13,8 @@ export function useMobileInstallActions(
const mountedRef = useMountedRef()
const openInstallUrl = useCallback((): void => {
void window.api.shell.openUrl('https://onorca.dev/download')
}, [])
void window.api.shell.openUrl(getInstallCopy(platform).url)
}, [platform])
const openAndroidInstallGuide = useCallback((): void => {
void window.api.shell.openUrl(ANDROID_INSTALL_GUIDE_URL)
@@ -25,7 +22,7 @@ export function useMobileInstallActions(
const copyInstallUrl = useCallback(async (): Promise<void> => {
try {
await window.api.ui.writeClipboardText(getInstallCopy(platform, iosChannel).url)
await window.api.ui.writeClipboardText(getInstallCopy(platform).url)
if (mountedRef.current) {
toast.success(
translate('auto.components.mobile.MobilePage.fad833de8d', 'Install link copied')
@@ -39,7 +36,7 @@ export function useMobileInstallActions(
)
}
}
}, [iosChannel, mountedRef, platform])
}, [mountedRef, platform])
return { copyInstallUrl, openAndroidInstallGuide, openInstallUrl }
}
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'
import QRCodeBrowser from 'qrcode/lib/browser'
import type { Platform } from './MobileHero'
import { getInstallCopy, type IosChannel } from './mobile-platform-copy'
import { getInstallCopy } from './mobile-platform-copy'
import type { MobilePageStage } from './mobile-page-stage'
async function renderQrDataUrl(text: string): Promise<string> {
@@ -14,8 +14,7 @@ async function renderQrDataUrl(text: string): Promise<string> {
export function useMobileInstallQr(
stage: MobilePageStage | null,
platform: Platform,
iosChannel: IosChannel
platform: Platform
): string | null {
const [installQrUrl, setInstallQrUrl] = useState<string | null>(null)
@@ -28,7 +27,7 @@ export function useMobileInstallQr(
let cancelled = false
void (async () => {
try {
const dataUrl = await renderQrDataUrl(getInstallCopy(platform, iosChannel).url)
const dataUrl = await renderQrDataUrl(getInstallCopy(platform).url)
if (!cancelled) {
setInstallQrUrl(dataUrl)
}
@@ -41,7 +40,7 @@ export function useMobileInstallQr(
return () => {
cancelled = true
}
}, [platform, iosChannel, stage])
}, [platform, stage])
return installQrUrl
}
+2 -12
View File
@@ -14665,7 +14665,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "App herunterladen",
"a8fb43cf1c": "Fortfahren",
"3f90dbd274": "Abschließen",
"b622eba64d": "Zurück",
@@ -14698,11 +14697,6 @@
"e59a252eca": "Code erneut generieren",
"d0b52871ce": "Die Smartphones sind gekoppelt.",
"051978a785": "Das Smartphone ist gekoppelt.",
"channel": {
"group": "Veröffentlichungskanal",
"preview": "Vorschau",
"stable": "Stabil"
},
"pairingQrError": "Dieser Kopplungscode konnte nicht als QR-Code dargestellt werden. Stattdessen in Orca Mobile kopieren.",
"noRelayCode": "Kein Kopplungscode verfügbar",
"noPairingCode": "Kein Kopplungscode verfügbar",
@@ -14749,12 +14743,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Neueste Funktionen, täglich aktualisiert."
},
"stable": {
"tagline": "Die öffentliche Version, wöchentlich aktualisiert."
}
"downloadApk": "APK herunterladen",
"openAppStore": "App Store öffnen"
}
}
},
+3 -13
View File
@@ -14733,11 +14733,6 @@
"e59a252eca": "Regenerate code",
"d0b52871ce": "Your phones are paired.",
"051978a785": "Your phone is paired.",
"channel": {
"group": "Release channel",
"preview": "Preview",
"stable": "Stable"
},
"pairingQrError": "This pairing code couldn’t be rendered as a QR code. Copy it into Orca Mobile instead.",
"noRelayCode": "No pairing code available",
"noPairingCode": "No pairing code available",
@@ -14753,8 +14748,7 @@
"androidHelp": {
"guide": "Install guide"
},
"openAppAndScan": "Open Orca Mobile, tap <strong>Pair Desktop</strong>, and scan the code.",
"downloadApp": "Download app"
"openAppAndScan": "Open Orca Mobile, tap <strong>Pair Desktop</strong>, and scan the code."
},
"MobilePage": {
"e17393c6a3": "Phone preview",
@@ -14785,12 +14779,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Newest features, updated daily."
},
"stable": {
"tagline": "The public release, updated weekly."
}
"downloadApk": "Download APK",
"openAppStore": "Open App Store"
}
}
},
+2 -12
View File
@@ -14531,7 +14531,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "Descargar la aplicación",
"a8fb43cf1c": "Continuar",
"3f90dbd274": "Hecho",
"b622eba64d": "Atrás",
@@ -14564,11 +14563,6 @@
"e59a252eca": "Regenerar código",
"d0b52871ce": "Tus teléfonos están emparejados.",
"051978a785": "Tu teléfono está emparejado.",
"channel": {
"group": "Canal de versión",
"preview": "Vista previa",
"stable": "Estable"
},
"pairingQrError": "Este código de emparejamiento no se pudo representar como código QR. Cópialo en Orca Mobile.",
"directAddressDisclosure": "También usar una ruta local más rápida",
"directAddressHint": "Opcional. Elige la dirección Wi‑Fi o Tailscale que el teléfono usará cuando esté cerca — suele ser más rápido que Relay. Relay sigue funcionando cuando estás fuera.",
@@ -14615,12 +14609,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Las funciones más recientes, actualizadas a diario."
},
"stable": {
"tagline": "La versión pública, actualizada semanalmente."
}
"downloadApk": "Descargar APK",
"openAppStore": "Abrir App Store"
}
}
},
+2 -12
View File
@@ -14717,7 +14717,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "Télécharger l’application",
"a8fb43cf1c": "Continuer",
"3f90dbd274": "Terminé",
"b622eba64d": "Retour",
@@ -14750,11 +14749,6 @@
"e59a252eca": "Régénérer le code",
"d0b52871ce": "Vos téléphones sont appairés.",
"051978a785": "Votre téléphone est appairé.",
"channel": {
"group": "Canal de release",
"preview": "Aperçu",
"stable": "Stable"
},
"pairingQrError": "Ce code d'appairage n'a pas pu être rendu sous forme de QR code. Copiez-le plutôt dans Orca Mobile.",
"noRelayCode": "Aucun code d'appairage disponible",
"noPairingCode": "Aucun code d'appairage disponible",
@@ -14801,12 +14795,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Fonctionnalités les plus récentes, mises à jour chaque jour."
},
"stable": {
"tagline": "La version publique, mise à jour chaque semaine."
}
"downloadApk": "Télécharger l'APK",
"openAppStore": "Ouvrir l'App Store"
}
}
},
+2 -12
View File
@@ -14167,7 +14167,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "アプリをダウンロード",
"a8fb43cf1c": "Continue",
"3f90dbd274": "完了",
"b622eba64d": "戻る",
@@ -14200,11 +14199,6 @@
"e59a252eca": "コードを再生成する",
"d0b52871ce": "スマートフォンはペアリングされています。",
"051978a785": "スマートフォンはペアリングされています。",
"channel": {
"group": "リリースチャンネル",
"preview": "プレビュー",
"stable": "安定版"
},
"pairingQrError": "このペアリングコードを QR コードとして表示できませんでした。代わりに Orca Mobile にコピーしてください。",
"directAddressDisclosure": "より速いローカル経路も使う",
"directAddressHint": "任意。近く(同じ Wi‑Fi または Tailscale)にいるときにスマホが使うアドレスを選びます。通常は Relay より高速です。外出中は引き続き Relay が使われます。",
@@ -14251,12 +14245,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "最新機能を毎日更新。"
},
"stable": {
"tagline": "一般公開版、毎週更新。"
}
"downloadApk": "APK をダウンロード",
"openAppStore": "App Store を開く"
}
}
},
+2 -12
View File
@@ -14167,7 +14167,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "앱 다운로드",
"a8fb43cf1c": "Continue",
"3f90dbd274": "완료",
"b622eba64d": "뒤로",
@@ -14200,11 +14199,6 @@
"e59a252eca": "코드 재생성",
"d0b52871ce": "휴대전화가 페어링되었습니다.",
"051978a785": "휴대전화가 페어링되었습니다.",
"channel": {
"group": "릴리스 채널",
"preview": "미리 보기",
"stable": "안정 버전"
},
"pairingQrError": "이 페어링 코드를 QR 코드로 표시할 수 없습니다. 대신 Orca Mobile에 복사하세요.",
"directAddressDisclosure": "더 빠른 로컬 경로도 사용",
"directAddressHint": "선택 사항. 근처에 있을 때(같은 Wi‑Fi 또는 Tailscale) 휴대폰이 사용할 주소를 고르세요. 보통 Relay보다 빠릅니다. 외부에 있을 때는 여전히 Relay를 사용합니다.",
@@ -14251,12 +14245,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "최신 기능, 매일 업데이트."
},
"stable": {
"tagline": "정식 출시 버전, 매주 업데이트."
}
"downloadApk": "APK 다운로드",
"openAppStore": "App Store 열기"
}
}
},
+2 -12
View File
@@ -15811,7 +15811,6 @@
}
},
"MobileHero": {
"downloadApp": "Baixar aplicativo",
"a8fb43cf1c": "Continuar",
"3f90dbd274": "Concluído",
"b622eba64d": "Voltar",
@@ -15844,11 +15843,6 @@
"e59a252eca": "Gerar novo código",
"d0b52871ce": "Seus celulares estão pareados.",
"051978a785": "Seu celular está pareado.",
"channel": {
"group": "Canal de lançamento",
"preview": "Preview",
"stable": "Estável"
},
"pairingQrError": "Este código de pareamento não pôde ser renderizado como um código QR. Copie-o no Orca Mobile em vez disso.",
"noRelayCode": "Nenhum código de pareamento disponível",
"noPairingCode": "Nenhum código de pareamento disponível",
@@ -15940,12 +15934,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Recursos mais novos, atualizados diariamente."
},
"stable": {
"tagline": "O lançamento público, atualizado semanalmente."
}
"downloadApk": "Baixar APK",
"openAppStore": "Abrir App Store"
}
}
},
+2 -12
View File
@@ -15067,7 +15067,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "Скачать приложение",
"a8fb43cf1c": "Продолжить",
"3f90dbd274": "Готово",
"b622eba64d": "Назад",
@@ -15100,11 +15099,6 @@
"e59a252eca": "Создать новый код",
"d0b52871ce": "Ваши телефоны подключены.",
"051978a785": "Ваш телефон подключён.",
"channel": {
"group": "Канал выпуска",
"preview": "Предварительный",
"stable": "Стабильный"
},
"pairingQrError": "Не удалось представить этот код сопряжения как QR-код. Вместо этого скопируйте его в Orca Mobile.",
"noRelayCode": "Код сопряжения недоступен",
"noPairingCode": "Код сопряжения недоступен",
@@ -15151,12 +15145,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "Новые возможности, обновления каждый день."
},
"stable": {
"tagline": "Общедоступный выпуск, обновления каждую неделю."
}
"downloadApk": "Скачать APK",
"openAppStore": "Открыть App Store"
}
}
},
+2 -12
View File
@@ -14651,7 +14651,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "Uygulamayı indir",
"a8fb43cf1c": "Devam Et",
"3f90dbd274": "Bitti",
"b622eba64d": "Geri",
@@ -14684,11 +14683,6 @@
"e59a252eca": "Kodu yeniden oluştur",
"d0b52871ce": "Telefonlarınız eşleştirildi.",
"051978a785": "Telefonunuz eşleştirildi.",
"channel": {
"group": "Sürüm kanalı",
"preview": "Önizleme",
"stable": "Kararlı"
},
"pairingQrError": "Bu eşleştirme kodu QR koduna dönüştürülemedi. Bunun yerine kodu Orca Mobile'a kopyalayın.",
"noRelayCode": "Kullanılabilir eşleştirme kodu yok",
"noPairingCode": "Kullanılabilir eşleştirme kodu yok",
@@ -14735,12 +14729,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "En yeni özellikler, günlük güncellenir."
},
"stable": {
"tagline": "Genel sürüm, haftalık güncellenir."
}
"downloadApk": "APK indir",
"openAppStore": "App Store'u aç"
}
}
},
+2 -12
View File
@@ -14485,7 +14485,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "下載應用程式",
"a8fb43cf1c": "繼續",
"3f90dbd274": "完成",
"b622eba64d": "返回",
@@ -14518,11 +14517,6 @@
"e59a252eca": "重新產生配對碼",
"d0b52871ce": "您的手機已配對。",
"051978a785": "您的手機已配對。",
"channel": {
"group": "發布管道",
"preview": "預覽版",
"stable": "穩定版"
},
"pairingQrError": "無法將此配對碼呈現為 QR Code。請改為將其複製到 Orca Mobile。",
"noRelayCode": "沒有可用的配對碼",
"noPairingCode": "沒有可用的配對碼",
@@ -14569,12 +14563,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "最新功能,每日更新。"
},
"stable": {
"tagline": "公開發布版,每週更新。"
}
"downloadApk": "下載 APK",
"openAppStore": "開啟 App Store"
}
}
},
+2 -12
View File
@@ -14167,7 +14167,6 @@
},
"mobile": {
"MobileHero": {
"downloadApp": "下载应用",
"a8fb43cf1c": "继续",
"3f90dbd274": "完成",
"b622eba64d": "返回",
@@ -14200,11 +14199,6 @@
"e59a252eca": "重新生成代码",
"d0b52871ce": "您的手机已配对。",
"051978a785": "您的手机已配对。",
"channel": {
"group": "发布渠道",
"preview": "预览版",
"stable": "稳定版"
},
"pairingQrError": "无法将此配对码呈现为二维码。请改为将其复制到 Orca Mobile。",
"directAddressDisclosure": "也可使用更快的本地连接",
"directAddressHint": "可选。选择手机在附近(同一 Wi‑Fi 或 Tailscale)时使用的地址,通常比 Relay 更快。外出时仍走 Relay。",
@@ -14251,12 +14245,8 @@
"mobile": {
"platform": {
"copy": {
"preview": {
"tagline": "最新功能,每日更新。"
},
"stable": {
"tagline": "公开发布版,每周更新。"
}
"downloadApk": "下载 APK",
"openAppStore": "打开 App Store"
}
}
},