From 3c0c3b3f6e3e70d763f8b7d05d98e894eeba1402 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 12 Nov 2026 09:28:56 +0100 Subject: [PATCH] fix(native): a store account with a running TREK Cloud subscription buys no second one One subscription per Apple ID or Google account. Choosing another plan in the app changed the running subscription on the App Store, and the redeem then failed with 'We could not set up your TREK'. The app now asks the store first and shows a screen of its own: the account already has TREK Cloud, a new one can be taken out once it has ended, with Open my TREK and the store's page to manage it. The native purchase refuses as well; a paid one that was never set up is still redeemed. On the address screens the link 'What is a TREK server?' is gone, and the small print under a purchase is set in the system text face at regular weight. --- .../com/liketrek/trek/TrekShellPlugin.java | 6 ++ .../com/liketrek/trek/billing/TrekBilling.kt | 62 ++++++++++++----- client/ios/App/App/TrekShellPlugin.swift | 43 ++++++++++-- client/native-shell/main.ts | 68 +++++++++++++++++-- client/native-shell/shell.css | 12 +++- client/src/native/iap.test.ts | 27 ++++++++ client/src/native/iap.ts | 37 +++++++++- client/src/native/links.ts | 6 +- client/src/native/trekShell.ts | 8 ++- shared/src/i18n/ar/native.ts | 8 ++- shared/src/i18n/az/native.ts | 8 ++- shared/src/i18n/br/native.ts | 8 ++- shared/src/i18n/ca/native.ts | 8 ++- shared/src/i18n/cs/native.ts | 8 ++- shared/src/i18n/de/native.ts | 8 ++- shared/src/i18n/en/native.ts | 8 ++- shared/src/i18n/es/native.ts | 8 ++- shared/src/i18n/et/native.ts | 8 ++- shared/src/i18n/fr/native.ts | 8 ++- shared/src/i18n/gr/native.ts | 8 ++- shared/src/i18n/he/native.ts | 8 ++- shared/src/i18n/hu/native.ts | 8 ++- shared/src/i18n/id/native.ts | 8 ++- shared/src/i18n/it/native.ts | 8 ++- shared/src/i18n/ja/native.ts | 8 ++- shared/src/i18n/ko/native.ts | 8 ++- shared/src/i18n/nl/native.ts | 8 ++- shared/src/i18n/pl/native.ts | 8 ++- shared/src/i18n/ru/native.ts | 8 ++- shared/src/i18n/sk/native.ts | 8 ++- shared/src/i18n/sv/native.ts | 8 ++- shared/src/i18n/th/native.ts | 8 ++- shared/src/i18n/tr/native.ts | 8 ++- shared/src/i18n/uk/native.ts | 8 ++- shared/src/i18n/vi/native.ts | 8 ++- shared/src/i18n/zh-TW/native.ts | 8 ++- shared/src/i18n/zh/native.ts | 8 ++- 37 files changed, 429 insertions(+), 64 deletions(-) diff --git a/client/android/app/src/main/java/com/liketrek/trek/TrekShellPlugin.java b/client/android/app/src/main/java/com/liketrek/trek/TrekShellPlugin.java index 04d2b65bf..be9262cc1 100644 --- a/client/android/app/src/main/java/com/liketrek/trek/TrekShellPlugin.java +++ b/client/android/app/src/main/java/com/liketrek/trek/TrekShellPlugin.java @@ -731,6 +731,12 @@ public class TrekShellPlugin extends Plugin { com.liketrek.trek.billing.TrekBilling.INSTANCE.restore(getContext(), call); } + /** Whether this Google account already holds a delivered cloud subscription. */ + @PluginMethod + public void storeHeld(PluginCall call) { + com.liketrek.trek.billing.TrekBilling.INSTANCE.held(getContext(), call); + } + /** A paid subscription never delivered (it cleared while the app was closed), for the shell to redeem. */ @PluginMethod public void storeUnfinished(PluginCall call) { diff --git a/client/android/app/src/main/java/com/liketrek/trek/billing/TrekBilling.kt b/client/android/app/src/main/java/com/liketrek/trek/billing/TrekBilling.kt index ed35e018d..4b2276139 100644 --- a/client/android/app/src/main/java/com/liketrek/trek/billing/TrekBilling.kt +++ b/client/android/app/src/main/java/com/liketrek/trek/billing/TrekBilling.kt @@ -119,23 +119,38 @@ object TrekBilling { val id = call.getString("productId") ?: return call.reject("productId is required") ready(activity) { ok -> if (!ok) return@ready call.resolve(JSObject().put("kind", "failed")) - details(activity, listOf(id)) { found -> - val product = found.firstOrNull() - val offer = product?.let(::baseOffer) - if (product == null || offer == null) return@details call.resolve(JSObject().put("kind", "failed")) - pendingPurchase?.resolve(JSObject().put("kind", "cancelled")) - pendingPurchase = call - pendingProduct = id - val params = BillingFlowParams.newBuilder() - .setProductDetailsParamsList( - listOf(BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(product).setOfferToken(offer.offerToken).build()), - ) - .build() - activity.runOnUiThread { - val launch = client(activity).launchBillingFlow(activity, params) - if (launch.responseCode != BillingClient.BillingResponseCode.OK) { - settle(if (launch.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) "cancelled" else "failed", null) - } + // One subscription per Google account: a second plan would run beside the first. + // A delivered one stops the purchase here; one that was paid but never set up is + // handed back as bought, so its instance is set up now. + val params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build() + client(activity).queryPurchasesAsync(params) { result, purchases -> + val held = if (result.responseCode == BillingClient.BillingResponseCode.OK) newest(purchases, PREFIX) else null + when { + held == null -> launchPurchase(activity, call, id) + held.isAcknowledged -> call.resolve(JSObject().put("kind", "subscribed")) + else -> call.resolve(receipt(held).put("kind", "bought")) + } + } + } + } + + private fun launchPurchase(activity: Activity, call: PluginCall, id: String) { + details(activity, listOf(id)) { found -> + val product = found.firstOrNull() + val offer = product?.let(::baseOffer) + if (product == null || offer == null) return@details call.resolve(JSObject().put("kind", "failed")) + pendingPurchase?.resolve(JSObject().put("kind", "cancelled")) + pendingPurchase = call + pendingProduct = id + val params = BillingFlowParams.newBuilder() + .setProductDetailsParamsList( + listOf(BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(product).setOfferToken(offer.offerToken).build()), + ) + .build() + activity.runOnUiThread { + val launch = client(activity).launchBillingFlow(activity, params) + if (launch.responseCode != BillingClient.BillingResponseCode.OK) { + settle(if (launch.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) "cancelled" else "failed", null) } } } @@ -208,6 +223,19 @@ object TrekBilling { } } + /** Whether this Google account holds a delivered subscription under `prefix`; while one runs, the shell offers no purchase. */ + fun held(context: Context, call: PluginCall) { + val prefix = call.getString("prefix") ?: PREFIX + ready(context) { ok -> + if (!ok) return@ready call.resolve(JSObject().put("held", false)) + val params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build() + client(context).queryPurchasesAsync(params) { result, purchases -> + val found = if (result.responseCode == BillingClient.BillingResponseCode.OK) newest(purchases, prefix) else null + call.resolve(JSObject().put("held", found?.isAcknowledged == true)) + } + } + } + /** The newest active subscription under `prefix` on this Google account, if any. */ fun restore(context: Context, call: PluginCall) { val prefix = call.getString("prefix") ?: "cloud." diff --git a/client/ios/App/App/TrekShellPlugin.swift b/client/ios/App/App/TrekShellPlugin.swift index 435261af0..c00b02ce8 100644 --- a/client/ios/App/App/TrekShellPlugin.swift +++ b/client/ios/App/App/TrekShellPlugin.swift @@ -46,6 +46,7 @@ public class TrekShellPlugin: CAPPlugin, CAPBridgedPlugin, ASWebAuthenticationPr CAPPluginMethod(name: "storePurchase", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "storeFinish", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "storeRestore", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "storeHeld", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "addToWallet", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "setWatchSnapshot", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "takeWatchActions", returnType: CAPPluginReturnPromise), @@ -679,6 +680,17 @@ extension TrekShellPlugin { return } Task { + // One subscription per Apple ID: another plan would change it, not add one. + // A held one that was delivered stops the purchase here. One that was paid + // but never set up is handed back as bought, so its instance is set up now. + if let held = await TrekStore.currentEntitlement(prefix: "cloud.") { + if await TrekStore.isUnfinished(held.id) { + call.resolve(["kind": "bought", "jws": held.jws, "transactionId": String(held.id), "productId": held.productId]) + } else { + call.resolve(["kind": "subscribed"]) + } + return + } do { guard let product = try await Product.products(for: [id]).first else { call.resolve(["kind": "failed"]) @@ -735,6 +747,21 @@ extension TrekShellPlugin { call.resolve(["jws": found.jws, "transactionId": String(found.id)]) } } + + /// Feature storeKit: whether this Apple ID holds a delivered subscription under + /// `prefix`. Read from the entitlements on the device, so no password is asked; + /// while one runs, the shell offers no purchase. + @objc func storeHeld(_ call: CAPPluginCall) { + let prefix = call.getString("prefix") ?? "cloud." + Task { + guard let held = await TrekStore.currentEntitlement(prefix: prefix) else { + call.resolve(["held": false]) + return + } + let unfinished = await TrekStore.isUnfinished(held.id) + call.resolve(["held": !unfinished]) + } + } } enum TrekStore { @@ -765,17 +792,25 @@ enum TrekStore { } } - static func currentEntitlement(prefix: String) async -> (jws: String, id: UInt64)? { - var newest: (date: Date, jws: String, id: UInt64)? + static func currentEntitlement(prefix: String) async -> (jws: String, id: UInt64, productId: String)? { + var newest: (date: Date, jws: String, id: UInt64, productId: String)? for await result in Transaction.currentEntitlements { guard case .verified(let transaction) = result, transaction.productID.hasPrefix(prefix), transaction.revocationDate == nil else { continue } if newest == nil || transaction.purchaseDate > newest!.date { - newest = (transaction.purchaseDate, result.jwsRepresentation, transaction.id) + newest = (transaction.purchaseDate, result.jwsRepresentation, transaction.id, transaction.productID) } } - return newest.map { ($0.jws, $0.id) } + return newest.map { (jws: $0.jws, id: $0.id, productId: $0.productId) } + } + + /// Paid but not delivered yet: the shell finishes a transaction once its instance exists. + static func isUnfinished(_ id: UInt64) async -> Bool { + for await result in Transaction.unfinished { + if case .verified(let transaction) = result, transaction.id == id { return true } + } + return false } } diff --git a/client/native-shell/main.ts b/client/native-shell/main.ts index 543b53d7b..f00e23e36 100644 --- a/client/native-shell/main.ts +++ b/client/native-shell/main.ts @@ -15,8 +15,9 @@ import { CLOUD_TERMS_URL, CLOUD_URL, PRIVACY_URL, - SERVER_DOCS_URL, STORE_TERMS_URL, + APP_STORE_SUBSCRIPTIONS_URL, + PLAY_SUBSCRIPTIONS_URL, } from '../src/native/links'; import { certificateTargetFor, @@ -268,7 +269,7 @@ function showWelcome(opts: { back?: boolean } = {}): void { el('h1', { className: 'title brand-title' }, t('native.welcome.headline')), el('p', { className: 'sub' }, t('native.welcome.sub')), ], - [cloud, connect, demo, footLinks(externalLink(t('native.connect.whatIsServer'), SERVER_DOCS_URL))] + [cloud, connect, demo, footLinks()] ) ), opts @@ -382,7 +383,7 @@ function showConnect(prefill = '', opts: { back?: boolean; recheck?: boolean } = el('h1', { className: 'title-sm' }, t('native.connect.title')), el('p', { className: 'sub' }, t(opts.recheck ? 'native.connect.recheckHint' : 'native.connect.hint')), ], - [form, addCert, footLinks(externalLink(t('native.connect.whatIsServer'), SERVER_DOCS_URL))] + [form, addCert, footLinks()] ) ), opts @@ -660,10 +661,16 @@ function planCard(plan: CloudPlan, interval: 'month' | 'year', offer: Offer): HT const featOff = (text: string) => el('span', { className: 'off' }, icon('M5 12h14', 16), text); let sub: HTMLElement | null = null; if (buyable) { - sub = el('button', { type: 'button', className: 'btn' }, t('native.plans.subscribe')); - sub.addEventListener('click', () => { + const button = el('button', { type: 'button', className: 'btn' }, t('native.plans.subscribe')); + sub = button; + button.addEventListener('click', async () => { void tap(ImpactStyle.Medium); - showClaim(plan, interval, `${label} ${per}`); + // A store account with a running subscription buys nothing more: say so before the form. + button.disabled = true; + const held = await iap.held(); + button.disabled = false; + if (held) showSubscribed(); + else showClaim(plan, interval, `${label} ${per}`); }); } return el( @@ -1157,6 +1164,10 @@ function showClaim( error.textContent = t('native.claim.failed'); return; } + if (outcome.kind === 'subscribed') { + showSubscribed(); + return; + } bought = outcome.purchase; } @@ -1206,6 +1217,51 @@ function showClaim( requestAnimationFrame(() => slugInput.focus()); } +/** + * The store account already holds a TREK Cloud subscription: one per Apple ID or + * Google account. Another plan would change it on the App Store and run beside + * it on Google Play, so the app buys nothing and says why. Offered instead: the + * TREK the subscription belongs to, and the store's own page to manage or end + * it. Once it has ended, a new one can be taken out, at a new address too. + */ +function showSubscribed(): void { + void notify(NotificationType.Warning); + const status = el('p', { className: 'hint', role: 'status' }); + const open = el('button', { type: 'button', className: 'btn' }, t('native.subscribed.open')); + open.addEventListener('click', async () => { + void tap(ImpactStyle.Medium); + open.disabled = true; + status.className = 'hint'; + status.textContent = t('native.plans.restoring'); + const purchase = await iap.restore(); + const redeemed = purchase ? await redeemPurchase('', '', purchase) : null; + if (purchase && redeemed?.ok && redeemed.instanceUrl) { + await iap.finish(purchase); + showProvisioning(redeemed.instanceUrl); + return; + } + void notify(NotificationType.Error); + open.disabled = false; + status.className = 'hint bad'; + status.textContent = t('native.plans.restoreFailed'); + }); + const manage = externalLink(t('native.subscribed.manage'), onPlay ? PLAY_SUBSCRIPTIONS_URL : APP_STORE_SUBSCRIPTIONS_URL); + show( + el( + 'div', + {}, + ...columns( + [ + topbar(() => showPlans({ back: true })), + el('h1', { className: 'title-sm' }, t('native.subscribed.title')), + el('p', { className: 'sub' }, t(onPlay ? 'native.subscribed.textAndroid' : 'native.subscribed.text')), + ], + [open, status, el('div', { className: 'foot-links' }, manage)] + ) + ) + ); +} + /** The build runs on the server; the app waits on the new address and loads it the moment it answers. */ function showProvisioning(instanceUrl: string, welcome?: string): void { const host = (() => { diff --git a/client/native-shell/shell.css b/client/native-shell/shell.css index 55268e497..18b2e2750 100644 --- a/client/native-shell/shell.css +++ b/client/native-shell/shell.css @@ -1058,12 +1058,20 @@ a.linkbtn { border-color: var(--edge-strong); border-top-color: var(--ink); } +/* Small print (the terms a purchase is under, how it renews): in the system's + own text face at its regular weight. Poppins ships from 500 up only, which + made a paragraph of legal text read as heavy as a heading. */ .note { text-align: center; color: var(--faint); - font-size: 0.84rem; + font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', Roboto, system-ui, sans-serif; + font-weight: 400; + font-size: 0.76rem; margin: 2px 0 0; - line-height: 1.45; + line-height: 1.5; +} +.note a { + color: var(--muted); } /* Under the plans: restore, the renewal terms, the legal links. */ .plans-foot { diff --git a/client/src/native/iap.test.ts b/client/src/native/iap.test.ts index 4b78d5494..183371f35 100644 --- a/client/src/native/iap.test.ts +++ b/client/src/native/iap.test.ts @@ -8,6 +8,7 @@ const shell = vi.hoisted(() => ({ storeFinish: vi.fn(), storeRestore: vi.fn(), storeUnfinished: vi.fn(), + storeHeld: vi.fn(), addListener: vi.fn(), })); @@ -34,6 +35,17 @@ describe('in-app purchase client', () => { expect(productIdFor('pro', 'year')).toBe('cloud.pro.yearly'); }); + it('the fake client can play a store account that already holds a subscription', async () => { + localStorage.setItem('trek-iap-fake-held', '1'); + try { + expect(await fakeIapClient.held()).toBe(true); + expect(await fakeIapClient.purchase('cloud.plus.monthly')).toEqual({ kind: 'subscribed' }); + } finally { + localStorage.removeItem('trek-iap-fake-held'); + } + expect(await fakeIapClient.held()).toBe(false); + }); + it('the fake client yields a receipt for the product asked for', async () => { expect(await fakeIapClient.isAvailable()).toBe(true); const outcome = await fakeIapClient.purchase('cloud.plus.monthly'); @@ -102,6 +114,21 @@ describe('native client', () => { expect(await nativeIapClient.purchase('cloud.plus.monthly')).toEqual({ kind: 'failed' }); }); + it('says when the store account already holds a subscription, and buys nothing then', async () => { + shell.storePurchase.mockResolvedValue({ kind: 'subscribed' }); + expect(await nativeIapClient.purchase('cloud.plus.monthly')).toEqual({ kind: 'subscribed' }); + shell.storeHeld.mockResolvedValue({ held: true }); + expect(await nativeIapClient.held()).toBe(true); + expect(shell.storeHeld).toHaveBeenCalledWith({ prefix: 'cloud.' }); + shell.storeHeld.mockResolvedValue({ held: false }); + expect(await nativeIapClient.held()).toBe(false); + }); + + it('a build without storeHeld counts as holding nothing; the purchase still guards', async () => { + shell.storeHeld.mockRejectedValue(new Error('not implemented')); + expect(await nativeIapClient.held()).toBe(false); + }); + it('finishes by transaction id and swallows a failure', async () => { const purchase = { platform: 'apple' as const, productId: 'cloud.plus.monthly', receipt: 'x', transactionId: '7' }; shell.storeFinish.mockResolvedValue(undefined); diff --git a/client/src/native/iap.ts b/client/src/native/iap.ts index e28c3a5f8..294edb62b 100644 --- a/client/src/native/iap.ts +++ b/client/src/native/iap.ts @@ -29,10 +29,16 @@ export interface Purchase { /** * What a purchase attempt came to. `cancelled` is the customer backing out, not * an error; `pending` is a purchase waiting on someone else (Ask to Buy, a bank), - * which a restore picks up once it goes through. + * which a restore picks up once it goes through. `subscribed` means the store + * account already holds a subscription: one per Apple ID or Google account, and + * a new one only once it has ended, so nothing was bought. */ type PurchaseOutcome = - { kind: 'bought'; purchase: Purchase } | { kind: 'cancelled' } | { kind: 'pending' } | { kind: 'failed' }; + | { kind: 'bought'; purchase: Purchase } + | { kind: 'cancelled' } + | { kind: 'pending' } + | { kind: 'failed' } + | { kind: 'subscribed' }; export interface IapClient { /** Whether this build can take a payment. */ @@ -45,6 +51,12 @@ export interface IapClient { prices(productIds: string[]): Promise>; /** A test build (TestFlight, App Review), whose purchases cost nothing and may go ahead before the opening. */ isSandbox(): Promise; + /** + * Whether the store account already holds a delivered subscription. While it + * does, nothing can be bought: on the App Store another plan would change that + * subscription, on Google Play it would run beside it. + */ + held(): Promise; /** Runs the platform's purchase sheet for a product and resolves with what became of it. */ purchase(productId: string): Promise; /** Tells the store a purchase was delivered, once its instance exists. */ @@ -88,7 +100,16 @@ export const fakeIapClient: IapClient = { async isSandbox() { return true; }, + async held() { + // `localStorage['trek-iap-fake-held'] = '1'` shows what a store account with a running subscription sees. + try { + return localStorage.getItem('trek-iap-fake-held') === '1'; + } catch { + return false; + } + }, async purchase(productId) { + if (await this.held()) return { kind: 'subscribed' }; await new Promise((resolve) => setTimeout(resolve, 900)); const nonce = String(Date.now()); return { @@ -160,12 +181,22 @@ export const nativeIapClient: IapClient = { }, }; } - if (result.kind === 'cancelled' || result.kind === 'pending') return { kind: result.kind }; + if (result.kind === 'cancelled' || result.kind === 'pending' || result.kind === 'subscribed') { + return { kind: result.kind }; + } return { kind: 'failed' }; } catch { return { kind: 'failed' }; } }, + async held() { + try { + return (await TrekShell.storeHeld({ prefix: PRODUCT_PREFIX })).held === true; + } catch { + // A build without storeHeld: the purchase itself still refuses a second subscription. + return false; + } + }, async finish(purchase) { try { await TrekShell.storeFinish({ transactionId: purchase.transactionId }); diff --git a/client/src/native/links.ts b/client/src/native/links.ts index 71e2009c9..8838351e5 100644 --- a/client/src/native/links.ts +++ b/client/src/native/links.ts @@ -6,9 +6,6 @@ /** The privacy policy the store listings name too. */ export const PRIVACY_URL = 'https://liketrek.com/privacy?app=1'; -/** What a TREK server is and how to run one, for someone who has none yet. */ -export const SERVER_DOCS_URL = 'https://github.com/liketrek/TREK#readme'; - /** Running the app with a sign-in proxy (Cloudflare Access, Pangolin and the like) in front of TREK. */ export const AUTH_PROXY_DOCS_URL = 'https://github.com/liketrek/TREK/wiki/Native-Apps#behind-a-sign-in-proxy'; @@ -27,5 +24,8 @@ export const CLOUD_URL = 'https://liketrek.com'; * store rules ask for it next to the purchase, together with the privacy policy. */ export const STORE_TERMS_URL = 'https://www.apple.com/legal/internet-services/itunes/dev/stdeula/'; +/** Where the App Store and Google Play let someone manage or end a subscription. */ +export const APP_STORE_SUBSCRIPTIONS_URL = 'https://apps.apple.com/account/subscriptions'; +export const PLAY_SUBSCRIPTIONS_URL = 'https://play.google.com/store/account/subscriptions?package=com.liketrek.trek'; /** Our terms for TREK Cloud (§ 5a covers a purchase in the app), as the app opens them: without the site's sales header. */ export const CLOUD_TERMS_URL = 'https://liketrek.com/terms?app=1'; diff --git a/client/src/native/trekShell.ts b/client/src/native/trekShell.ts index b7234d4a8..c5b82d866 100644 --- a/client/src/native/trekShell.ts +++ b/client/src/native/trekShell.ts @@ -112,7 +112,8 @@ export interface TrekShellPlugin { * Android `purchaseToken`, which the control plane verifies with Google Play. */ storePurchase(options: { productId: string }): Promise<{ - kind: 'bought' | 'cancelled' | 'pending' | 'failed'; + /** `subscribed`: this store account already holds a delivered subscription, so nothing was bought. */ + kind: 'bought' | 'cancelled' | 'pending' | 'failed' | 'subscribed'; jws?: string; purchaseToken?: string; productId?: string; @@ -134,6 +135,11 @@ export interface TrekShellPlugin { }): Promise<{ result: 'shown' | 'unsupported' }>; /** iOS, feature storeKit: the newest active subscription under `prefix` on this Apple ID, if any. */ storeRestore(options: { prefix: string }): Promise<{ jws?: string; transactionId?: string }>; + /** + * Whether this Apple ID or Google account holds a delivered subscription under + * `prefix`, read without asking for a password. Not in builds before 5.1.4. + */ + storeHeld(options: { prefix: string }): Promise<{ held: boolean }>; /** Feature watch: what the Apple Watch app shows (native/watch.ts), as JSON, sent on through WatchConnectivity. */ setWatchSnapshot(options: { json: string }): Promise; /** Feature watch: the ticks the watch sent since the last call, oldest first (parsed by parseWatchActions). */ diff --git a/shared/src/i18n/ar/native.ts b/shared/src/i18n/ar/native.ts index 3cabb241f..122cd820f 100644 --- a/shared/src/i18n/ar/native.ts +++ b/shared/src/i18n/ar/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'اتصال', 'native.connect.checking': 'جارٍ التحقق…', 'native.connect.tryDemo': 'جرّب النسخة التجريبية', - 'native.connect.whatIsServer': 'ما هو خادم TREK؟', 'native.connect.errorInvalid': 'لا يبدو هذا عنوان ويب.', 'native.connect.errorUnreachable': 'لا يستجيب أي خادم على هذا العنوان. تحقق من العنوان ومن اتصالك.', 'native.connect.errorNotTrek': 'الخادم على هذا العنوان ليس TREK.', @@ -88,6 +87,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'يُخصم المبلغ من حساب Google الخاص بك عند التأكيد. يتجدد الاشتراك تلقائيًا ما لم تلغِه قبل نهاية الفترة. يمكنك إدارته أو إلغاؤه في Google Play من الملف الشخصي، الدفعات والاشتراكات، الاشتراكات.', 'native.plans.restoreNoneAndroid': 'لم يُعثر على اشتراك نشط في حساب Google هذا.', + 'native.subscribed.title': 'لديك TREK Cloud بالفعل', + 'native.subscribed.text': + 'يوجد بالفعل اشتراك نشط في TREK Cloud على معرّف Apple هذا. يمكنك الاشتراك من جديد، وبعنوان جديد أيضًا، بعد انتهائه.', + 'native.subscribed.textAndroid': + 'يوجد بالفعل اشتراك نشط في TREK Cloud على حساب Google هذا. يمكنك الاشتراك من جديد، وبعنوان جديد أيضًا، بعد انتهائه.', + 'native.subscribed.open': 'افتح TREK الخاص بي', + 'native.subscribed.manage': 'إدارة الاشتراك', 'native.claim.agree': 'بالاشتراك تسري شروط TREK Cloud على توفير نسختك (المزوّد: Maurice Bötger، روستوك). يتولى المتجر الشراء والدفع والاسترداد.', 'native.claim.consentTitle': 'اختلافات TREK Cloud عن TREK المستضاف ذاتيًا (بالألمانية، ملزمة قانونيًا):', diff --git a/shared/src/i18n/az/native.ts b/shared/src/i18n/az/native.ts index 784cc38c0..1d0d2b8af 100644 --- a/shared/src/i18n/az/native.ts +++ b/shared/src/i18n/az/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Qoşul', 'native.connect.checking': 'Yoxlanılır…', 'native.connect.tryDemo': 'Demonu sınayın', - 'native.connect.whatIsServer': 'TREK serveri nədir?', 'native.connect.errorInvalid': 'Bu, veb ünvana bənzəmir.', 'native.connect.errorUnreachable': 'Bu ünvanda heç bir server cavab vermədi. Ünvanı və bağlantınızı yoxlayın.', 'native.connect.errorNotTrek': 'Bu ünvandakı server TREK deyil.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Ödəniş təsdiq etdikdə Google hesabınızdan tutulur. Abunəlik dövr bitməzdən əvvəl ləğv etməsəniz avtomatik yenilənir. Onu Google Play-də Profil, Ödənişlər və abunəliklər, Abunəliklər bölməsində idarə edə və ya ləğv edə bilərsiniz.', 'native.plans.restoreNoneAndroid': 'Bu Google hesabında aktiv abunəlik tapılmadı.', + 'native.subscribed.title': 'Artıq TREK Cloud-unuz var', + 'native.subscribed.text': + 'Bu Apple ID-də artıq aktiv TREK Cloud abunəliyi var. O bitdikdən sonra yenisini, həm də yeni ünvanla, ala bilərsiniz.', + 'native.subscribed.textAndroid': + 'Bu Google hesabında artıq aktiv TREK Cloud abunəliyi var. O bitdikdən sonra yenisini, həm də yeni ünvanla, ala bilərsiniz.', + 'native.subscribed.open': 'TREK-imi aç', + 'native.subscribed.manage': 'Abunəliyi idarə et', 'native.claim.agree': 'Abunə olmaqla nümunənizin təqdim edilməsinə TREK Cloud şərtləri tətbiq olunur (təchizatçı: Maurice Bötger, Rostok). Alış, ödəniş və geri qaytarmanı mağaza həyata keçirir.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/br/native.ts b/shared/src/i18n/br/native.ts index 882a2e83c..d40145a75 100644 --- a/shared/src/i18n/br/native.ts +++ b/shared/src/i18n/br/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Conectar', 'native.connect.checking': 'Verificando…', 'native.connect.tryDemo': 'Experimentar a demonstração', - 'native.connect.whatIsServer': 'O que é um servidor TREK?', 'native.connect.errorInvalid': 'Isso não parece um endereço da web.', 'native.connect.errorUnreachable': 'Nenhum servidor respondeu neste endereço. Verifique o endereço e sua conexão.', 'native.connect.errorNotTrek': 'O servidor neste endereço não é o TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'O pagamento é cobrado na sua conta Google ao confirmar. A assinatura é renovada automaticamente, a menos que você a cancele antes do fim do período. Gerencie ou cancele no Google Play em Perfil, Pagamentos e assinaturas, Assinaturas.', 'native.plans.restoreNoneAndroid': 'Nenhuma assinatura ativa encontrada nesta conta Google.', + 'native.subscribed.title': 'Você já tem o TREK Cloud', + 'native.subscribed.text': + 'Este ID Apple já tem uma assinatura ativa do TREK Cloud. Você pode fazer uma nova, inclusive com um novo endereço, quando ela terminar.', + 'native.subscribed.textAndroid': + 'Esta conta Google já tem uma assinatura ativa do TREK Cloud. Você pode fazer uma nova, inclusive com um novo endereço, quando ela terminar.', + 'native.subscribed.open': 'Abrir meu TREK', + 'native.subscribed.manage': 'Gerenciar assinatura', 'native.claim.agree': 'Ao assinar, os termos do TREK Cloud se aplicam ao fornecimento da sua instância (fornecedor: Maurice Bötger, Rostock). A loja cuida da compra, do pagamento e dos reembolsos.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/ca/native.ts b/shared/src/i18n/ca/native.ts index f39d30668..7d33cb522 100644 --- a/shared/src/i18n/ca/native.ts +++ b/shared/src/i18n/ca/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Connecta', 'native.connect.checking': 'S’està comprovant…', 'native.connect.tryDemo': 'Prova la demostració', - 'native.connect.whatIsServer': 'Què és un servidor TREK?', 'native.connect.errorInvalid': 'Això no sembla una adreça web.', 'native.connect.errorUnreachable': 'Cap servidor respon en aquesta adreça. Comprova l’adreça i la connexió.', 'native.connect.errorNotTrek': 'El servidor d’aquesta adreça no és TREK.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'El pagament es carrega al teu compte de Google en confirmar. La subscripció es renova automàticament si no la cancel·les abans que acabi el període. Gestiona-la o cancel·la-la a Google Play, a Perfil, Pagaments i subscripcions, Subscripcions.', 'native.plans.restoreNoneAndroid': 'No s’ha trobat cap subscripció activa en aquest compte de Google.', + 'native.subscribed.title': 'Ja tens TREK Cloud', + 'native.subscribed.text': + 'Aquest ID d’Apple ja té una subscripció activa a TREK Cloud. En pots contractar una de nova, també amb una adreça nova, quan s’hagi acabat.', + 'native.subscribed.textAndroid': + 'Aquest compte de Google ja té una subscripció activa a TREK Cloud. En pots contractar una de nova, també amb una adreça nova, quan s’hagi acabat.', + 'native.subscribed.open': 'Obre el meu TREK', + 'native.subscribed.manage': 'Gestiona la subscripció', 'native.claim.agree': 'En subscriure’t, s’apliquen les condicions de TREK Cloud a la provisió de la teva instància (proveïdor: Maurice Bötger, Rostock). La botiga gestiona la compra, el pagament i els reemborsaments.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/cs/native.ts b/shared/src/i18n/cs/native.ts index 19161f8a9..e70312327 100644 --- a/shared/src/i18n/cs/native.ts +++ b/shared/src/i18n/cs/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Připojit', 'native.connect.checking': 'Ověřování…', 'native.connect.tryDemo': 'Vyzkoušet demo', - 'native.connect.whatIsServer': 'Co je server TREK?', 'native.connect.errorInvalid': 'To nevypadá jako webová adresa.', 'native.connect.errorUnreachable': 'Na této adrese neodpovídá žádný server. Zkontrolujte adresu a připojení.', 'native.connect.errorNotTrek': 'Server na této adrese není TREK.', @@ -89,6 +88,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Platba se při potvrzení strhne z vašeho účtu Google. Předplatné se automaticky obnovuje, pokud je nezrušíte před koncem období. Spravovat nebo zrušit ho můžete v Google Play v části Profil, Platby a odběry, Odběry.', 'native.plans.restoreNoneAndroid': 'Pro tento účet Google nebylo nalezeno žádné aktivní předplatné.', + 'native.subscribed.title': 'TREK Cloud už máte', + 'native.subscribed.text': + 'Toto Apple ID už má aktivní předplatné TREK Cloud. Nové, i s novou adresou, si můžete sjednat, až skončí.', + 'native.subscribed.textAndroid': + 'Tento účet Google už má aktivní předplatné TREK Cloud. Nové, i s novou adresou, si můžete sjednat, až skončí.', + 'native.subscribed.open': 'Otevřít můj TREK', + 'native.subscribed.manage': 'Spravovat předplatné', 'native.claim.agree': 'Předplacením se na poskytování vaší instance vztahují podmínky TREK Cloud (poskytovatel: Maurice Bötger, Rostock). Nákup, platbu a vrácení peněz vyřizuje obchod.', 'native.claim.consentTitle': 'Odlišnosti TREK Cloud od vlastního TREK (v němčině, právně závazné):', diff --git a/shared/src/i18n/de/native.ts b/shared/src/i18n/de/native.ts index 54a38398e..de7c0a809 100644 --- a/shared/src/i18n/de/native.ts +++ b/shared/src/i18n/de/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Verbinden', 'native.connect.checking': 'Wird geprüft…', 'native.connect.tryDemo': 'Demo ausprobieren', - 'native.connect.whatIsServer': 'Was ist ein TREK-Server?', 'native.connect.errorInvalid': 'Das sieht nicht nach einer Webadresse aus.', 'native.connect.errorUnreachable': 'Unter dieser Adresse antwortet kein Server. Prüfe die Adresse und deine Verbindung.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Die Zahlung wird bei Bestätigung über dein Google-Konto abgerechnet. Das Abo verlängert sich automatisch, wenn du es nicht vor Ablauf des Zeitraums kündigst. Verwalten und kündigen kannst du es in Google Play unter Profil, Zahlungen und Abos, Abos.', 'native.plans.restoreNoneAndroid': 'Für dieses Google-Konto wurde kein aktives Abo gefunden.', + 'native.subscribed.title': 'Du hast schon TREK Cloud', + 'native.subscribed.text': + 'Über diese Apple-ID läuft bereits ein TREK-Cloud-Abo. Ein neues kannst du abschließen, auch mit neuer Adresse, sobald es beendet ist.', + 'native.subscribed.textAndroid': + 'Über dieses Google-Konto läuft bereits ein TREK-Cloud-Abo. Ein neues kannst du abschließen, auch mit neuer Adresse, sobald es beendet ist.', + 'native.subscribed.open': 'Mein TREK öffnen', + 'native.subscribed.manage': 'Abo verwalten', 'native.claim.agree': 'Mit dem Abonnieren gelten für die Bereitstellung deiner Instanz die AGB von TREK Cloud (Anbieter: Maurice Bötger, Rostock). Kauf, Zahlung und Erstattung wickelt der Store ab.', 'native.claim.consentTitle': 'Abweichungen von einem selbst betriebenen TREK (verbindlich auf Deutsch):', diff --git a/shared/src/i18n/en/native.ts b/shared/src/i18n/en/native.ts index 5fe0497b9..0a0646e75 100644 --- a/shared/src/i18n/en/native.ts +++ b/shared/src/i18n/en/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Connect', 'native.connect.checking': 'Checking…', 'native.connect.tryDemo': 'Try the demo', - 'native.connect.whatIsServer': 'What is a TREK server?', 'native.connect.errorInvalid': 'That does not look like a web address.', 'native.connect.errorUnreachable': 'No server answered at this address. Check the address and your connection.', 'native.connect.errorNotTrek': 'The server at this address is not TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Payment is charged to your Google account when you confirm. The subscription renews automatically unless you cancel it before the period ends. Manage or cancel it in Google Play under Profile, Payments and subscriptions, Subscriptions.', 'native.plans.restoreNoneAndroid': 'No active subscription found on this Google account.', + 'native.subscribed.title': 'You already have TREK Cloud', + 'native.subscribed.text': + 'This Apple ID already has an active TREK Cloud subscription. You can take out a new one, at a new address too, once it has ended.', + 'native.subscribed.textAndroid': + 'This Google account already has an active TREK Cloud subscription. You can take out a new one, at a new address too, once it has ended.', + 'native.subscribed.open': 'Open my TREK', + 'native.subscribed.manage': 'Manage subscription', 'native.claim.agree': 'By subscribing, the TREK Cloud terms apply to providing your instance (provider: Maurice Bötger, Rostock). The store handles the purchase, payment and refunds.', 'native.claim.consentTitle': 'How TREK Cloud differs from TREK on your own server (German, legally binding):', diff --git a/shared/src/i18n/es/native.ts b/shared/src/i18n/es/native.ts index 7f70d3aab..2b69a5144 100644 --- a/shared/src/i18n/es/native.ts +++ b/shared/src/i18n/es/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Conectar', 'native.connect.checking': 'Comprobando…', 'native.connect.tryDemo': 'Prueba la demo', - 'native.connect.whatIsServer': '¿Qué es un servidor TREK?', 'native.connect.errorInvalid': 'Eso no parece una dirección web.', 'native.connect.errorUnreachable': 'Ningún servidor responde en esta dirección. Revisa la dirección y tu conexión.', 'native.connect.errorNotTrek': 'El servidor de esta dirección no es TREK.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'El pago se carga a tu cuenta de Google al confirmar. La suscripción se renueva automáticamente salvo que la canceles antes de que termine el periodo. Gestiónala o cancélala en Google Play, en Perfil, Pagos y suscripciones, Suscripciones.', 'native.plans.restoreNoneAndroid': 'No se encontró ninguna suscripción activa en esta cuenta de Google.', + 'native.subscribed.title': 'Ya tienes TREK Cloud', + 'native.subscribed.text': + 'Este ID de Apple ya tiene una suscripción activa a TREK Cloud. Podrás contratar una nueva, también con una dirección nueva, cuando haya terminado.', + 'native.subscribed.textAndroid': + 'Esta cuenta de Google ya tiene una suscripción activa a TREK Cloud. Podrás contratar una nueva, también con una dirección nueva, cuando haya terminado.', + 'native.subscribed.open': 'Abrir mi TREK', + 'native.subscribed.manage': 'Gestionar suscripción', 'native.claim.agree': 'Al suscribirte, se aplican las condiciones de TREK Cloud a la provisión de tu instancia (proveedor: Maurice Bötger, Rostock). La tienda gestiona la compra, el pago y los reembolsos.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/et/native.ts b/shared/src/i18n/et/native.ts index cd24b1bda..af9188c51 100644 --- a/shared/src/i18n/et/native.ts +++ b/shared/src/i18n/et/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Ühenda', 'native.connect.checking': 'Kontrollin…', 'native.connect.tryDemo': 'Proovi demot', - 'native.connect.whatIsServer': 'Mis on TREKi server?', 'native.connect.errorInvalid': 'See ei näe välja nagu veebiaadress.', 'native.connect.errorUnreachable': 'Sellel aadressil ei vastanud ükski server. Kontrolli aadressi ja oma ühendust.', 'native.connect.errorNotTrek': 'Sellel aadressil olev server ei ole TREK.', @@ -90,6 +89,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': "Makse võetakse kinnitamisel sinu Google'i kontolt. Tellimus uueneb automaatselt, kui sa ei tühista seda enne perioodi lõppu. Halda või tühista seda Google Plays: Profiil, Maksed ja tellimused, Tellimused.", 'native.plans.restoreNoneAndroid': "Selle Google'i kontoga ei leitud aktiivset tellimust.", + 'native.subscribed.title': 'Sul on juba TREK Cloud', + 'native.subscribed.text': + 'Sellel Apple ID-l on juba aktiivne TREK Cloudi tellimus. Uue, ka uue aadressiga, saad võtta pärast selle lõppemist.', + 'native.subscribed.textAndroid': + "Sellel Google'i kontol on juba aktiivne TREK Cloudi tellimus. Uue, ka uue aadressiga, saad võtta pärast selle lõppemist.", + 'native.subscribed.open': 'Ava minu TREK', + 'native.subscribed.manage': 'Halda tellimust', 'native.claim.agree': 'Tellides kehtivad sinu eksemplari pakkumisele TREK Cloudi tingimused (pakkuja: Maurice Bötger, Rostock). Ostu, makset ja tagasimakseid haldab pood.', 'native.claim.consentTitle': 'TREK Cloudi erinevused isehostitud TREKist (saksa keeles, õiguslikult siduv):', diff --git a/shared/src/i18n/fr/native.ts b/shared/src/i18n/fr/native.ts index 63ce5a1ae..ba7dd0a69 100644 --- a/shared/src/i18n/fr/native.ts +++ b/shared/src/i18n/fr/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Se connecter', 'native.connect.checking': 'Vérification…', 'native.connect.tryDemo': 'Essayer la démo', - 'native.connect.whatIsServer': 'Qu’est-ce qu’un serveur TREK ?', 'native.connect.errorInvalid': 'Cela ne ressemble pas à une adresse web.', 'native.connect.errorUnreachable': 'Aucun serveur ne répond à cette adresse. Vérifiez l’adresse et votre connexion.', 'native.connect.errorNotTrek': 'Le serveur à cette adresse n’est pas TREK.', @@ -93,6 +92,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Le paiement est débité de votre compte Google lors de la confirmation. L’abonnement se renouvelle automatiquement, sauf si vous le résiliez avant la fin de la période. Gérez-le ou résiliez-le dans Google Play sous Profil, Paiements et abonnements, Abonnements.', 'native.plans.restoreNoneAndroid': 'Aucun abonnement actif trouvé pour ce compte Google.', + 'native.subscribed.title': 'Vous avez déjà TREK Cloud', + 'native.subscribed.text': + 'Cet identifiant Apple a déjà un abonnement TREK Cloud actif. Vous pourrez en souscrire un nouveau, avec une nouvelle adresse aussi, une fois celui-ci terminé.', + 'native.subscribed.textAndroid': + 'Ce compte Google a déjà un abonnement TREK Cloud actif. Vous pourrez en souscrire un nouveau, avec une nouvelle adresse aussi, une fois celui-ci terminé.', + 'native.subscribed.open': 'Ouvrir mon TREK', + 'native.subscribed.manage': 'Gérer l’abonnement', 'native.claim.agree': 'En vous abonnant, les conditions de TREK Cloud s’appliquent à la mise à disposition de votre instance (prestataire : Maurice Bötger, Rostock). La boutique gère l’achat, le paiement et les remboursements.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/gr/native.ts b/shared/src/i18n/gr/native.ts index 3ad280ce3..bfad16a9c 100644 --- a/shared/src/i18n/gr/native.ts +++ b/shared/src/i18n/gr/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Σύνδεση', 'native.connect.checking': 'Έλεγχος…', 'native.connect.tryDemo': 'Δοκιμάστε την επίδειξη', - 'native.connect.whatIsServer': 'Τι είναι ένας διακομιστής TREK;', 'native.connect.errorInvalid': 'Αυτό δεν μοιάζει με διεύθυνση ιστού.', 'native.connect.errorUnreachable': 'Κανένας διακομιστής δεν απαντά σε αυτή τη διεύθυνση. Ελέγξτε τη διεύθυνση και τη σύνδεσή σας.', @@ -93,6 +92,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Η πληρωμή χρεώνεται στον λογαριασμό σας Google κατά την επιβεβαίωση. Η συνδρομή ανανεώνεται αυτόματα, εκτός αν την ακυρώσετε πριν λήξει η περίοδος. Διαχειριστείτε ή ακυρώστε τη στο Google Play, στο Προφίλ, Πληρωμές και συνδρομές, Συνδρομές.', 'native.plans.restoreNoneAndroid': 'Δεν βρέθηκε ενεργή συνδρομή σε αυτόν τον λογαριασμό Google.', + 'native.subscribed.title': 'Έχετε ήδη TREK Cloud', + 'native.subscribed.text': + 'Αυτό το Apple ID έχει ήδη ενεργή συνδρομή στο TREK Cloud. Μπορείτε να κάνετε νέα, και με νέα διεύθυνση, όταν λήξει.', + 'native.subscribed.textAndroid': + 'Αυτός ο λογαριασμός Google έχει ήδη ενεργή συνδρομή στο TREK Cloud. Μπορείτε να κάνετε νέα, και με νέα διεύθυνση, όταν λήξει.', + 'native.subscribed.open': 'Άνοιγμα του TREK μου', + 'native.subscribed.manage': 'Διαχείριση συνδρομής', 'native.claim.agree': 'Με την εγγραφή, για την παροχή της instance σας ισχύουν οι όροι του TREK Cloud (πάροχος: Maurice Bötger, Ρόστοκ). Την αγορά, την πληρωμή και τις επιστροφές χειρίζεται το κατάστημα.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/he/native.ts b/shared/src/i18n/he/native.ts index 258ec6bed..0945ac404 100644 --- a/shared/src/i18n/he/native.ts +++ b/shared/src/i18n/he/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'התחברות', 'native.connect.checking': 'בודק…', 'native.connect.tryDemo': 'נסו את הדמו', - 'native.connect.whatIsServer': 'מהו שרת TREK?', 'native.connect.errorInvalid': 'זה לא נראה ככתובת אינטרנט.', 'native.connect.errorUnreachable': 'אף שרת לא ענה בכתובת הזו. בדקו את הכתובת ואת החיבור.', 'native.connect.errorNotTrek': 'השרת בכתובת הזו אינו TREK.', @@ -88,6 +87,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'התשלום יחויב בחשבון Google שלכם עם האישור. המינוי מתחדש אוטומטית אלא אם תבטלו אותו לפני סוף התקופה. אפשר לנהל או לבטל אותו ב-Google Play תחת פרופיל, תשלומים ומינויים, מינויים.', 'native.plans.restoreNoneAndroid': 'לא נמצא מינוי פעיל בחשבון Google הזה.', + 'native.subscribed.title': 'כבר יש לך TREK Cloud', + 'native.subscribed.text': + 'ל-Apple ID הזה כבר יש מינוי פעיל ל-TREK Cloud. אפשר להירשם למינוי חדש, גם בכתובת חדשה, אחרי שהוא יסתיים.', + 'native.subscribed.textAndroid': + 'לחשבון Google הזה כבר יש מינוי פעיל ל-TREK Cloud. אפשר להירשם למינוי חדש, גם בכתובת חדשה, אחרי שהוא יסתיים.', + 'native.subscribed.open': 'פתיחת ה-TREK שלי', + 'native.subscribed.manage': 'ניהול המינוי', 'native.claim.agree': 'בהרשמה חלים על אספקת המופע שלכם התנאים של TREK Cloud (ספק: Maurice Bötger, רוסטוק). החנות מטפלת ברכישה, בתשלום ובהחזרים.', 'native.claim.consentTitle': 'ההבדלים בין TREK Cloud לבין TREK באירוח עצמי (בגרמנית, מחייב משפטית):', diff --git a/shared/src/i18n/hu/native.ts b/shared/src/i18n/hu/native.ts index 1a6c3f2bb..2d1c881b9 100644 --- a/shared/src/i18n/hu/native.ts +++ b/shared/src/i18n/hu/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Csatlakozás', 'native.connect.checking': 'Ellenőrzés…', 'native.connect.tryDemo': 'Próbáld ki a demót', - 'native.connect.whatIsServer': 'Mi az a TREK-szerver?', 'native.connect.errorInvalid': 'Ez nem úgy néz ki, mint egy webcím.', 'native.connect.errorUnreachable': 'Ezen a címen nem válaszol szerver. Ellenőrizd a címet és a kapcsolatot.', 'native.connect.errorNotTrek': 'Az ezen a címen futó szerver nem TREK.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'A díjat a megerősítéskor a Google-fiókodra terheljük. Az előfizetés automatikusan megújul, ha nem mondod le az időszak vége előtt. Kezelni vagy lemondani a Google Playben tudod: Profil, Fizetések és előfizetések, Előfizetések.', 'native.plans.restoreNoneAndroid': 'Ehhez a Google-fiókhoz nem található aktív előfizetés.', + 'native.subscribed.title': 'Már van TREK Cloud-előfizetésed', + 'native.subscribed.text': + 'Ehhez az Apple ID-hoz már tartozik aktív TREK Cloud-előfizetés. Újat, akár új címmel is, akkor köthetsz, ha ez lejárt.', + 'native.subscribed.textAndroid': + 'Ehhez a Google-fiókhoz már tartozik aktív TREK Cloud-előfizetés. Újat, akár új címmel is, akkor köthetsz, ha ez lejárt.', + 'native.subscribed.open': 'TREK megnyitása', + 'native.subscribed.manage': 'Előfizetés kezelése', 'native.claim.agree': 'Előfizetéssel a példányod biztosítására a TREK Cloud feltételei érvényesek (szolgáltató: Maurice Bötger, Rostock). A vásárlást, a fizetést és a visszatérítést az áruház intézi.', 'native.claim.consentTitle': 'A TREK Cloud eltérései a saját üzemeltetésű TREK-től (németül, jogilag kötelező):', diff --git a/shared/src/i18n/id/native.ts b/shared/src/i18n/id/native.ts index 9594627d0..03437fc73 100644 --- a/shared/src/i18n/id/native.ts +++ b/shared/src/i18n/id/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Hubungkan', 'native.connect.checking': 'Memeriksa…', 'native.connect.tryDemo': 'Coba demonya', - 'native.connect.whatIsServer': 'Apa itu server TREK?', 'native.connect.errorInvalid': 'Itu tidak terlihat seperti alamat web.', 'native.connect.errorUnreachable': 'Tidak ada server yang merespons di alamat ini. Periksa alamat dan koneksimu.', 'native.connect.errorNotTrek': 'Server di alamat ini bukan TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Pembayaran ditagihkan ke akun Google Anda saat konfirmasi. Langganan diperpanjang otomatis kecuali Anda membatalkannya sebelum periode berakhir. Kelola atau batalkan di Google Play pada Profil, Pembayaran & langganan, Langganan.', 'native.plans.restoreNoneAndroid': 'Tidak ditemukan langganan aktif di akun Google ini.', + 'native.subscribed.title': 'Kamu sudah punya TREK Cloud', + 'native.subscribed.text': + 'Apple ID ini sudah memiliki langganan TREK Cloud yang aktif. Kamu bisa berlangganan lagi, juga dengan alamat baru, setelah langganan ini berakhir.', + 'native.subscribed.textAndroid': + 'Akun Google ini sudah memiliki langganan TREK Cloud yang aktif. Kamu bisa berlangganan lagi, juga dengan alamat baru, setelah langganan ini berakhir.', + 'native.subscribed.open': 'Buka TREK saya', + 'native.subscribed.manage': 'Kelola langganan', 'native.claim.agree': 'Dengan berlangganan, ketentuan TREK Cloud berlaku untuk penyediaan instans Anda (penyedia: Maurice Bötger, Rostock). Pembelian, pembayaran, dan pengembalian dana ditangani oleh toko.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/it/native.ts b/shared/src/i18n/it/native.ts index e2d45f479..0d00fb65d 100644 --- a/shared/src/i18n/it/native.ts +++ b/shared/src/i18n/it/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Connetti', 'native.connect.checking': 'Verifica in corso…', 'native.connect.tryDemo': 'Prova la demo', - 'native.connect.whatIsServer': 'Che cos’è un server TREK?', 'native.connect.errorInvalid': 'Non sembra un indirizzo web.', 'native.connect.errorUnreachable': 'Nessun server risponde a questo indirizzo. Controlla l’indirizzo e la connessione.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Il pagamento viene addebitato sul tuo account Google alla conferma. L’abbonamento si rinnova automaticamente se non lo annulli prima della fine del periodo. Gestiscilo o annullalo in Google Play da Profilo, Pagamenti e abbonamenti, Abbonamenti.', 'native.plans.restoreNoneAndroid': 'Nessun abbonamento attivo trovato per questo account Google.', + 'native.subscribed.title': 'Hai già TREK Cloud', + 'native.subscribed.text': + 'Questo ID Apple ha già un abbonamento TREK Cloud attivo. Potrai sottoscriverne uno nuovo, anche con un nuovo indirizzo, quando sarà terminato.', + 'native.subscribed.textAndroid': + 'Questo account Google ha già un abbonamento TREK Cloud attivo. Potrai sottoscriverne uno nuovo, anche con un nuovo indirizzo, quando sarà terminato.', + 'native.subscribed.open': 'Apri il mio TREK', + 'native.subscribed.manage': 'Gestisci abbonamento', 'native.claim.agree': 'Abbonandoti, alla fornitura della tua istanza si applicano le condizioni di TREK Cloud (fornitore: Maurice Bötger, Rostock). Lo store gestisce acquisto, pagamento e rimborsi.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/ja/native.ts b/shared/src/i18n/ja/native.ts index 01857d04d..8080abd44 100644 --- a/shared/src/i18n/ja/native.ts +++ b/shared/src/i18n/ja/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': '接続', 'native.connect.checking': '確認中…', 'native.connect.tryDemo': 'デモを試す', - 'native.connect.whatIsServer': 'TREK サーバーとは?', 'native.connect.errorInvalid': 'Web アドレスではないようです。', 'native.connect.errorUnreachable': 'このアドレスで応答するサーバーがありません。アドレスと接続を確認してください。', 'native.connect.errorNotTrek': 'このアドレスのサーバーは TREK ではありません。', @@ -90,6 +89,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': '確認時に Google アカウントに請求されます。期間終了前に解約しない限り、サブスクリプションは自動更新されます。Google Play の[プロフィール][お支払いと定期購入][定期購入]で管理または解約できます。', 'native.plans.restoreNoneAndroid': 'この Google アカウントには有効なサブスクリプションがありません。', + 'native.subscribed.title': 'TREK Cloud はすでにご利用中です', + 'native.subscribed.text': + 'この Apple ID にはすでに有効な TREK Cloud のサブスクリプションがあります。終了後に、新しいアドレスでも新たに申し込めます。', + 'native.subscribed.textAndroid': + 'この Google アカウントにはすでに有効な TREK Cloud のサブスクリプションがあります。終了後に、新しいアドレスでも新たに申し込めます。', + 'native.subscribed.open': '自分の TREK を開く', + 'native.subscribed.manage': 'サブスクリプションを管理', 'native.claim.agree': '登録すると、インスタンスの提供には TREK Cloud 利用規約が適用されます(提供者: Maurice Bötger、ロストック)。購入、支払い、返金はストアが行います。', 'native.claim.consentTitle': 'TREK Cloud とセルフホスト版 TREK の違い(ドイツ語、法的拘束力あり):', diff --git a/shared/src/i18n/ko/native.ts b/shared/src/i18n/ko/native.ts index beea3916f..0acf466a7 100644 --- a/shared/src/i18n/ko/native.ts +++ b/shared/src/i18n/ko/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': '연결', 'native.connect.checking': '확인 중…', 'native.connect.tryDemo': '데모 체험하기', - 'native.connect.whatIsServer': 'TREK 서버란?', 'native.connect.errorInvalid': '웹 주소가 아닌 것 같습니다.', 'native.connect.errorUnreachable': '이 주소에서 응답하는 서버가 없습니다. 주소와 연결 상태를 확인하세요.', 'native.connect.errorNotTrek': '이 주소의 서버는 TREK이 아닙니다.', @@ -87,6 +86,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': '확인 시 Google 계정으로 결제됩니다. 기간이 끝나기 전에 취소하지 않으면 구독이 자동으로 갱신됩니다. Google Play의 프로필, 결제 및 정기 결제, 정기 결제에서 관리하거나 취소할 수 있습니다.', 'native.plans.restoreNoneAndroid': '이 Google 계정에서 활성 구독을 찾을 수 없습니다.', + 'native.subscribed.title': '이미 TREK Cloud를 이용 중입니다', + 'native.subscribed.text': + '이 Apple ID에는 이미 활성 TREK Cloud 구독이 있습니다. 구독이 끝나면 새 주소로도 새로 구독할 수 있습니다.', + 'native.subscribed.textAndroid': + '이 Google 계정에는 이미 활성 TREK Cloud 구독이 있습니다. 구독이 끝나면 새 주소로도 새로 구독할 수 있습니다.', + 'native.subscribed.open': '내 TREK 열기', + 'native.subscribed.manage': '구독 관리', 'native.claim.agree': '구독하면 인스턴스 제공에 TREK Cloud 약관이 적용됩니다(제공자: Maurice Bötger, 로스토크). 구매, 결제, 환불은 스토어가 처리합니다.', 'native.claim.consentTitle': 'TREK Cloud와 직접 호스팅한 TREK의 차이점(독일어, 법적 구속력 있음):', diff --git a/shared/src/i18n/nl/native.ts b/shared/src/i18n/nl/native.ts index bdf64d073..6fd436949 100644 --- a/shared/src/i18n/nl/native.ts +++ b/shared/src/i18n/nl/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Verbinden', 'native.connect.checking': 'Controleren…', 'native.connect.tryDemo': 'Probeer de demo', - 'native.connect.whatIsServer': 'Wat is een TREK-server?', 'native.connect.errorInvalid': 'Dat lijkt geen webadres.', 'native.connect.errorUnreachable': 'Er reageert geen server op dit adres. Controleer het adres en je verbinding.', 'native.connect.errorNotTrek': 'De server op dit adres is geen TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'De betaling wordt bij bevestiging via je Google-account in rekening gebracht. Het abonnement wordt automatisch verlengd, tenzij je het vóór het einde van de periode opzegt. Beheer of zeg het op in Google Play onder Profiel, Betalingen en abonnementen, Abonnementen.', 'native.plans.restoreNoneAndroid': 'Geen actief abonnement gevonden voor dit Google-account.', + 'native.subscribed.title': 'Je hebt al TREK Cloud', + 'native.subscribed.text': + 'Deze Apple ID heeft al een actief TREK Cloud-abonnement. Je kunt een nieuw afsluiten, ook met een nieuw adres, zodra het is afgelopen.', + 'native.subscribed.textAndroid': + 'Dit Google-account heeft al een actief TREK Cloud-abonnement. Je kunt een nieuw afsluiten, ook met een nieuw adres, zodra het is afgelopen.', + 'native.subscribed.open': 'Mijn TREK openen', + 'native.subscribed.manage': 'Abonnement beheren', 'native.claim.agree': 'Door je te abonneren gelden voor het leveren van je instantie de voorwaarden van TREK Cloud (aanbieder: Maurice Bötger, Rostock). De store regelt aankoop, betaling en terugbetaling.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/pl/native.ts b/shared/src/i18n/pl/native.ts index 1c6cee672..e8772d877 100644 --- a/shared/src/i18n/pl/native.ts +++ b/shared/src/i18n/pl/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Połącz', 'native.connect.checking': 'Sprawdzanie…', 'native.connect.tryDemo': 'Wypróbuj demo', - 'native.connect.whatIsServer': 'Czym jest serwer TREK?', 'native.connect.errorInvalid': 'To nie wygląda na adres internetowy.', 'native.connect.errorUnreachable': 'Pod tym adresem nie odpowiada żaden serwer. Sprawdź adres i połączenie.', 'native.connect.errorNotTrek': 'Serwer pod tym adresem to nie TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Płatność zostanie pobrana z Twojego konta Google po potwierdzeniu. Subskrypcja odnawia się automatycznie, jeśli nie anulujesz jej przed końcem okresu. Zarządzaj nią lub ją anuluj w Google Play w sekcji Profil, Płatności i subskrypcje, Subskrypcje.', 'native.plans.restoreNoneAndroid': 'Nie znaleziono aktywnej subskrypcji na tym koncie Google.', + 'native.subscribed.title': 'Masz już TREK Cloud', + 'native.subscribed.text': + 'To Apple ID ma już aktywną subskrypcję TREK Cloud. Nową, także z nowym adresem, możesz wykupić, gdy ta się zakończy.', + 'native.subscribed.textAndroid': + 'To konto Google ma już aktywną subskrypcję TREK Cloud. Nową, także z nowym adresem, możesz wykupić, gdy ta się zakończy.', + 'native.subscribed.open': 'Otwórz mój TREK', + 'native.subscribed.manage': 'Zarządzaj subskrypcją', 'native.claim.agree': 'Subskrybując, do udostępnienia Twojej instancji stosuje się warunki TREK Cloud (dostawca: Maurice Bötger, Rostock). Zakup, płatność i zwroty obsługuje sklep.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/ru/native.ts b/shared/src/i18n/ru/native.ts index b8b76df06..20ab6595f 100644 --- a/shared/src/i18n/ru/native.ts +++ b/shared/src/i18n/ru/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Подключиться', 'native.connect.checking': 'Проверка…', 'native.connect.tryDemo': 'Попробовать демо', - 'native.connect.whatIsServer': 'Что такое сервер TREK?', 'native.connect.errorInvalid': 'Это не похоже на веб-адрес.', 'native.connect.errorUnreachable': 'По этому адресу не отвечает ни один сервер. Проверьте адрес и подключение.', 'native.connect.errorNotTrek': 'Сервер по этому адресу не является TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Оплата списывается с вашего аккаунта Google при подтверждении. Подписка продлевается автоматически, если вы не отмените её до конца периода. Управлять ею или отменить можно в Google Play: Профиль, Платежи и подписки, Подписки.', 'native.plans.restoreNoneAndroid': 'Для этого аккаунта Google активная подписка не найдена.', + 'native.subscribed.title': 'У вас уже есть TREK Cloud', + 'native.subscribed.text': + 'На этом Apple ID уже есть активная подписка TREK Cloud. Оформить новую, в том числе с новым адресом, можно после её окончания.', + 'native.subscribed.textAndroid': + 'В этом аккаунте Google уже есть активная подписка TREK Cloud. Оформить новую, в том числе с новым адресом, можно после её окончания.', + 'native.subscribed.open': 'Открыть мой TREK', + 'native.subscribed.manage': 'Управлять подпиской', 'native.claim.agree': 'Оформляя подписку, вы соглашаетесь, что к предоставлению вашего экземпляра применяются условия TREK Cloud (поставщик: Maurice Bötger, Росток). Покупку, оплату и возвраты обрабатывает магазин.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/sk/native.ts b/shared/src/i18n/sk/native.ts index d2dbfdbd4..4ee179053 100644 --- a/shared/src/i18n/sk/native.ts +++ b/shared/src/i18n/sk/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Pripojiť', 'native.connect.checking': 'Overuje sa…', 'native.connect.tryDemo': 'Vyskúšať demo', - 'native.connect.whatIsServer': 'Čo je server TREK?', 'native.connect.errorInvalid': 'Toto nevyzerá ako webová adresa.', 'native.connect.errorUnreachable': 'Na tejto adrese neodpovedal žiadny server. Skontrolujte adresu a pripojenie.', 'native.connect.errorNotTrek': 'Server na tejto adrese nie je TREK.', @@ -90,6 +89,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Platba sa pri potvrdení strhne z vášho účtu Google. Predplatné sa automaticky obnovuje, ak ho nezrušíte pred koncom obdobia. Spravovať alebo zrušiť ho môžete v Google Play v časti Profil, Platby a odbery, Odbery.', 'native.plans.restoreNoneAndroid': 'Pre tento účet Google sa nenašlo žiadne aktívne predplatné.', + 'native.subscribed.title': 'TREK Cloud už máte', + 'native.subscribed.text': + 'Toto Apple ID už má aktívne predplatné TREK Cloud. Nové, aj s novou adresou, si môžete objednať, keď skončí.', + 'native.subscribed.textAndroid': + 'Tento účet Google už má aktívne predplatné TREK Cloud. Nové, aj s novou adresou, si môžete objednať, keď skončí.', + 'native.subscribed.open': 'Otvoriť môj TREK', + 'native.subscribed.manage': 'Spravovať predplatné', 'native.claim.agree': 'Predplatením sa na poskytovanie vašej inštancie vzťahujú podmienky TREK Cloud (poskytovateľ: Maurice Bötger, Rostock). Nákup, platbu a vrátenie peňazí vybavuje obchod.', 'native.claim.consentTitle': 'Odlišnosti TREK Cloud od vlastného TREK (v nemčine, právne záväzné):', diff --git a/shared/src/i18n/sv/native.ts b/shared/src/i18n/sv/native.ts index 0707a827e..f6ed7a98d 100644 --- a/shared/src/i18n/sv/native.ts +++ b/shared/src/i18n/sv/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Anslut', 'native.connect.checking': 'Kontrollerar…', 'native.connect.tryDemo': 'Testa demon', - 'native.connect.whatIsServer': 'Vad är en TREK-server?', 'native.connect.errorInvalid': 'Det ser inte ut som en webbadress.', 'native.connect.errorUnreachable': 'Ingen server svarar på den här adressen. Kontrollera adressen och din anslutning.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Betalningen debiteras ditt Google-konto när du bekräftar. Prenumerationen förnyas automatiskt om du inte säger upp den innan perioden tar slut. Hantera eller säg upp den i Google Play under Profil, Betalningar och prenumerationer, Prenumerationer.', 'native.plans.restoreNoneAndroid': 'Ingen aktiv prenumeration hittades för det här Google-kontot.', + 'native.subscribed.title': 'Du har redan TREK Cloud', + 'native.subscribed.text': + 'Det här Apple-ID:t har redan en aktiv TREK Cloud-prenumeration. Du kan teckna en ny, även med en ny adress, när den har upphört.', + 'native.subscribed.textAndroid': + 'Det här Google-kontot har redan en aktiv TREK Cloud-prenumeration. Du kan teckna en ny, även med en ny adress, när den har upphört.', + 'native.subscribed.open': 'Öppna mitt TREK', + 'native.subscribed.manage': 'Hantera prenumeration', 'native.claim.agree': 'När du prenumererar gäller villkoren för TREK Cloud för tillhandahållandet av din instans (leverantör: Maurice Bötger, Rostock). Butiken sköter köp, betalning och återbetalning.', 'native.claim.consentTitle': 'Skillnader mellan TREK Cloud och ett egenhostat TREK (på tyska, juridiskt bindande):', diff --git a/shared/src/i18n/th/native.ts b/shared/src/i18n/th/native.ts index 70bef7d39..bc1bc5a1b 100644 --- a/shared/src/i18n/th/native.ts +++ b/shared/src/i18n/th/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'เชื่อมต่อ', 'native.connect.checking': 'กำลังตรวจสอบ…', 'native.connect.tryDemo': 'ลองใช้เดโม', - 'native.connect.whatIsServer': 'เซิร์ฟเวอร์ TREK คืออะไร', 'native.connect.errorInvalid': 'ดูเหมือนว่านี่ไม่ใช่ที่อยู่เว็บ', 'native.connect.errorUnreachable': 'ไม่มีเซิร์ฟเวอร์ตอบกลับที่ที่อยู่นี้ โปรดตรวจสอบที่อยู่และการเชื่อมต่อของคุณ', 'native.connect.errorNotTrek': 'เซิร์ฟเวอร์ที่ที่อยู่นี้ไม่ใช่ TREK', @@ -88,6 +87,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'ระบบจะเรียกเก็บเงินจากบัญชี Google ของคุณเมื่อยืนยัน การสมัครสมาชิกจะต่ออายุอัตโนมัติ เว้นแต่คุณจะยกเลิกก่อนสิ้นสุดรอบ จัดการหรือยกเลิกได้ใน Google Play ที่ โปรไฟล์ การชำระเงินและการสมัครใช้บริการ การสมัครใช้บริการ', 'native.plans.restoreNoneAndroid': 'ไม่พบการสมัครสมาชิกที่ใช้งานอยู่ในบัญชี Google นี้', + 'native.subscribed.title': 'คุณมี TREK Cloud อยู่แล้ว', + 'native.subscribed.text': + 'Apple ID นี้มีการสมัครสมาชิก TREK Cloud ที่ใช้งานอยู่แล้ว คุณสมัครใหม่ได้ รวมถึงใช้ที่อยู่ใหม่ หลังจากการสมัครนี้สิ้นสุดลง', + 'native.subscribed.textAndroid': + 'บัญชี Google นี้มีการสมัครสมาชิก TREK Cloud ที่ใช้งานอยู่แล้ว คุณสมัครใหม่ได้ รวมถึงใช้ที่อยู่ใหม่ หลังจากการสมัครนี้สิ้นสุดลง', + 'native.subscribed.open': 'เปิด TREK ของฉัน', + 'native.subscribed.manage': 'จัดการการสมัครสมาชิก', 'native.claim.agree': 'เมื่อสมัครสมาชิก การให้บริการอินสแตนซ์ของคุณจะเป็นไปตามข้อกำหนดของ TREK Cloud (ผู้ให้บริการ: Maurice Bötger, รอสต็อก) ร้านค้าจะดูแลการซื้อ การชำระเงิน และการคืนเงิน', 'native.claim.consentTitle': 'ความแตกต่างของ TREK Cloud จาก TREK ที่โฮสต์เอง (ภาษาเยอรมัน มีผลผูกพันทางกฎหมาย):', diff --git a/shared/src/i18n/tr/native.ts b/shared/src/i18n/tr/native.ts index 37ad2b3a9..5fed95828 100644 --- a/shared/src/i18n/tr/native.ts +++ b/shared/src/i18n/tr/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Bağlan', 'native.connect.checking': 'Kontrol ediliyor…', 'native.connect.tryDemo': 'Demoyu dene', - 'native.connect.whatIsServer': 'TREK sunucusu nedir?', 'native.connect.errorInvalid': 'Bu bir web adresine benzemiyor.', 'native.connect.errorUnreachable': 'Bu adreste yanıt veren bir sunucu yok. Adresi ve bağlantını kontrol et.', 'native.connect.errorNotTrek': 'Bu adresteki sunucu TREK değil.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': "Ödeme, onayladığınızda Google hesabınızdan tahsil edilir. Abonelik, dönem bitmeden iptal etmezseniz otomatik olarak yenilenir. Google Play'de Profil, Ödemeler ve abonelikler, Abonelikler bölümünden yönetebilir veya iptal edebilirsiniz.", 'native.plans.restoreNoneAndroid': 'Bu Google hesabında etkin abonelik bulunamadı.', + 'native.subscribed.title': "Zaten TREK Cloud'unuz var", + 'native.subscribed.text': + 'Bu Apple Kimliğinde zaten etkin bir TREK Cloud aboneliği var. Sona erdikten sonra yeni bir abonelik, yeni bir adresle de, başlatabilirsiniz.', + 'native.subscribed.textAndroid': + 'Bu Google hesabında zaten etkin bir TREK Cloud aboneliği var. Sona erdikten sonra yeni bir abonelik, yeni bir adresle de, başlatabilirsiniz.', + 'native.subscribed.open': "TREK'imi aç", + 'native.subscribed.manage': 'Aboneliği yönet', 'native.claim.agree': 'Abone olduğunuzda örneğinizin sağlanmasına TREK Cloud koşulları uygulanır (sağlayıcı: Maurice Bötger, Rostock). Satın alma, ödeme ve iadeleri mağaza yürütür.', 'native.claim.consentTitle': 'TREK Cloud’un kendi barındırdığın TREK’ten farkları (Almanca, hukuken bağlayıcı):', diff --git a/shared/src/i18n/uk/native.ts b/shared/src/i18n/uk/native.ts index eccfef076..7d9cb486b 100644 --- a/shared/src/i18n/uk/native.ts +++ b/shared/src/i18n/uk/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Підключитися', 'native.connect.checking': 'Перевірка…', 'native.connect.tryDemo': 'Спробувати демо', - 'native.connect.whatIsServer': 'Що таке сервер TREK?', 'native.connect.errorInvalid': 'Це не схоже на вебадресу.', 'native.connect.errorUnreachable': 'За цією адресою не відповідає жоден сервер. Перевірте адресу та з’єднання.', 'native.connect.errorNotTrek': 'Сервер за цією адресою не є TREK.', @@ -91,6 +90,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Оплата списується з вашого облікового запису Google під час підтвердження. Підписка подовжується автоматично, якщо ви не скасуєте її до кінця періоду. Керувати нею або скасувати можна в Google Play: Профіль, Платежі й підписки, Підписки.', 'native.plans.restoreNoneAndroid': 'Для цього облікового запису Google активної підписки не знайдено.', + 'native.subscribed.title': 'У вас уже є TREK Cloud', + 'native.subscribed.text': + 'На цьому Apple ID уже є активна підписка TREK Cloud. Оформити нову, зокрема з новою адресою, можна після її завершення.', + 'native.subscribed.textAndroid': + 'У цьому акаунті Google уже є активна підписка TREK Cloud. Оформити нову, зокрема з новою адресою, можна після її завершення.', + 'native.subscribed.open': 'Відкрити мій TREK', + 'native.subscribed.manage': 'Керувати підпискою', 'native.claim.agree': 'Оформлюючи підписку, ви погоджуєтеся, що до надання вашого екземпляра застосовуються умови TREK Cloud (постачальник: Maurice Bötger, Росток). Купівлю, оплату й повернення коштів обробляє магазин.', 'native.claim.consentTitle': diff --git a/shared/src/i18n/vi/native.ts b/shared/src/i18n/vi/native.ts index c6d0f537f..2b9da0abe 100644 --- a/shared/src/i18n/vi/native.ts +++ b/shared/src/i18n/vi/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': 'Kết nối', 'native.connect.checking': 'Đang kiểm tra…', 'native.connect.tryDemo': 'Dùng thử bản demo', - 'native.connect.whatIsServer': 'Máy chủ TREK là gì?', 'native.connect.errorInvalid': 'Đây có vẻ không phải là địa chỉ web.', 'native.connect.errorUnreachable': 'Không có máy chủ nào phản hồi tại địa chỉ này. Hãy kiểm tra địa chỉ và kết nối của bạn.', @@ -92,6 +91,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': 'Khoản thanh toán được tính vào tài khoản Google của bạn khi xác nhận. Gói đăng ký tự động gia hạn trừ khi bạn hủy trước khi hết kỳ. Quản lý hoặc hủy trong Google Play tại Hồ sơ, Thanh toán và gói thuê bao, Gói thuê bao.', 'native.plans.restoreNoneAndroid': 'Không tìm thấy gói đăng ký đang hoạt động trên tài khoản Google này.', + 'native.subscribed.title': 'Bạn đã có TREK Cloud', + 'native.subscribed.text': + 'Apple ID này đã có gói đăng ký TREK Cloud đang hoạt động. Bạn có thể đăng ký gói mới, kể cả với địa chỉ mới, sau khi gói này kết thúc.', + 'native.subscribed.textAndroid': + 'Tài khoản Google này đã có gói đăng ký TREK Cloud đang hoạt động. Bạn có thể đăng ký gói mới, kể cả với địa chỉ mới, sau khi gói này kết thúc.', + 'native.subscribed.open': 'Mở TREK của tôi', + 'native.subscribed.manage': 'Quản lý gói đăng ký', 'native.claim.agree': 'Khi đăng ký, việc cung cấp phiên bản của bạn tuân theo điều khoản TREK Cloud (nhà cung cấp: Maurice Bötger, Rostock). Cửa hàng xử lý việc mua, thanh toán và hoàn tiền.', 'native.claim.consentTitle': 'Khác biệt của TREK Cloud so với TREK tự lưu trữ (bằng tiếng Đức, có giá trị pháp lý):', diff --git a/shared/src/i18n/zh-TW/native.ts b/shared/src/i18n/zh-TW/native.ts index 35054dfcb..e10e8700e 100644 --- a/shared/src/i18n/zh-TW/native.ts +++ b/shared/src/i18n/zh-TW/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': '連線', 'native.connect.checking': '正在檢查…', 'native.connect.tryDemo': '試試示範版', - 'native.connect.whatIsServer': '什麼是 TREK 伺服器?', 'native.connect.errorInvalid': '這看起來不像網址。', 'native.connect.errorUnreachable': '此網址沒有伺服器回應。請檢查網址與網路連線。', 'native.connect.errorNotTrek': '此網址上的伺服器不是 TREK。', @@ -85,6 +84,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': '確認後將從你的 Google 帳號扣款。除非你在期滿前取消,訂閱會自動續訂。可在 Google Play 的「個人資料」「付款和訂閱」「訂閱」中管理或取消。', 'native.plans.restoreNoneAndroid': '此 Google 帳號沒有有效的訂閱。', + 'native.subscribed.title': '你已經訂閱 TREK Cloud', + 'native.subscribed.text': + '此 Apple ID 已有一個有效的 TREK Cloud 訂閱。訂閱結束後,你可以重新訂閱,也可以使用新網址。', + 'native.subscribed.textAndroid': + '此 Google 帳號已有一個有效的 TREK Cloud 訂閱。訂閱結束後,你可以重新訂閱,也可以使用新網址。', + 'native.subscribed.open': '開啟我的 TREK', + 'native.subscribed.manage': '管理訂閱', 'native.claim.agree': '訂閱後,你的執行個體的提供適用 TREK Cloud 條款(提供者:Maurice Bötger,羅斯托克)。購買、付款和退款由商店處理。', 'native.claim.consentTitle': 'TREK Cloud 與自行架設 TREK 的差異(德文,具法律效力):', diff --git a/shared/src/i18n/zh/native.ts b/shared/src/i18n/zh/native.ts index 11394b059..02ea969f5 100644 --- a/shared/src/i18n/zh/native.ts +++ b/shared/src/i18n/zh/native.ts @@ -7,7 +7,6 @@ const native: TranslationStrings = { 'native.connect.submit': '连接', 'native.connect.checking': '正在检查…', 'native.connect.tryDemo': '试试演示版', - 'native.connect.whatIsServer': '什么是 TREK 服务器?', 'native.connect.errorInvalid': '这看起来不像网址。', 'native.connect.errorUnreachable': '此地址没有服务器响应。请检查地址和网络连接。', 'native.connect.errorNotTrek': '此地址上的服务器不是 TREK。', @@ -84,6 +83,13 @@ const native: TranslationStrings = { 'native.plans.legalAndroid': '确认后将从你的 Google 账号扣款。除非你在期满前取消,订阅会自动续订。可在 Google Play 的“个人资料”“付款和订阅”“订阅”中管理或取消。', 'native.plans.restoreNoneAndroid': '此 Google 账号没有有效订阅。', + 'native.subscribed.title': '你已经订阅了 TREK Cloud', + 'native.subscribed.text': + '此 Apple ID 已有一个有效的 TREK Cloud 订阅。订阅结束后,你可以重新订阅,也可以使用新地址。', + 'native.subscribed.textAndroid': + '此 Google 账号已有一个有效的 TREK Cloud 订阅。订阅结束后,你可以重新订阅,也可以使用新地址。', + 'native.subscribed.open': '打开我的 TREK', + 'native.subscribed.manage': '管理订阅', 'native.claim.agree': '订阅后,你的实例的提供适用 TREK Cloud 条款(提供方:Maurice Bötger,罗斯托克)。购买、付款和退款由商店处理。', 'native.claim.consentTitle': 'TREK Cloud 与自托管 TREK 的区别(德语,具有法律约束力):',