Desktop D2 UI: design system, portfolio, release timeline, catalog parity, listings, health, reviews, TestFlight, checks, command palette, toasts, first-run guide, en + tr with i18n check, 7:1 theme check, dev fixture mode and screenshot harness

This commit is contained in:
CRTkafa 2026-10-11 03:34:47 +08:00
parent 95b7cf7ced
commit 2ef0769730
44 changed files with 5475 additions and 742 deletions

560
apps/desktop/src/i18n/en.ts Normal file
View file

@ -0,0 +1,560 @@
// English UI strings (the source catalog). Placeholders: {name}. Plural: a "<key>_one" entry for a count of 1.
export const en = {
'a11y.skip': 'Skip to content',
'a11y.breadcrumbs': 'You are here',
'nav.sections': 'Sections',
'nav.portfolio': 'Portfolio',
'nav.appsLabel': 'Apps',
'nav.workspace': 'Workspace',
'nav.apps': 'App folders',
'nav.accounts': 'Accounts',
'nav.dependencies': 'Dependencies',
'nav.settings': 'Settings',
'nav.noApps': 'No apps yet',
'nav.problems': '{count} problems',
'nav.problems_one': '1 problem',
'tab.releases': 'Releases',
'tab.catalog': 'Catalog',
'tab.listings': 'Listings',
'tab.health': 'Health',
'tab.reviews': 'Reviews',
'tab.testflight': 'TestFlight',
'tab.checks': 'Checks',
'profile.app': 'App',
'profile.game': 'Game',
'profile.subscription-app': 'Subscription app',
'foot.cli': 'CLI {version} running',
'foot.cliDown': 'CLI not running',
'foot.cliStarting': 'Starting the CLI',
'foot.lastRead': 'Stores read {when}',
'foot.neverRead': 'Stores not read yet',
'top.storesRead': 'Stores read {when}',
'top.storesNotRead': 'Stores not read',
'dev.fixtures': 'DEV FIXTURES',
'dev.fixturesHint': 'Development build on fixture data: nothing here comes from a store. Release builds have no fixture mode.',
'action.readStores': 'Read the stores',
'action.reading': 'Reading',
'action.readStoresHint': 'Read-only: App Store Connect and Google Play status of every app, with each app\'s own accounts',
'action.checkConfigs': 'Check configs',
'action.addFolder': 'Add app folder',
'action.addAccount': 'Add a store account',
'action.toggleTheme': 'Switch light / dark',
'action.welcome': 'Open the welcome guide',
'action.refresh': 'Refresh',
'palette.title': 'Command palette',
'palette.button': 'Search or jump to',
'palette.placeholder': 'Jump to an app, a tab or a screen, or run an action',
'palette.results': 'Results',
'palette.none': 'Nothing matches "{q}"',
'palette.move': 'move',
'palette.open': 'open',
'palette.toggle': 'open / close',
'palette.gApps': 'Apps',
'palette.gGo': 'Go to',
'palette.gTabs': 'App tabs',
'palette.gActions': 'Actions',
'palette.openApp': 'Open',
'common.loading': 'Loading',
'common.unknown': 'Unknown',
'common.cancel': 'Cancel',
'common.close': 'Close',
'common.exit': 'Exit code {code}',
'common.cachedFrom': 'Last read {when} (saved copy)',
'common.readWhen': 'Read {when}',
'common.readFailedKeep': 'The last read failed, so this shows the previous one: {error}',
'time.justNow': 'just now',
'time.never': 'never',
'toast.readingStores': 'Reading the stores',
'toast.readingStoresDetail': 'App Store Connect and Google Play, read-only',
'toast.readDone': 'Stores read',
'toast.readDoneDetail': '{count} apps up to date',
'toast.readDoneDetail_one': '1 app up to date',
'toast.readDonePartial': 'Stores read, with gaps',
'toast.readDonePartialDetail': '{count} apps could not be read on a store; they show as unknown',
'toast.readDonePartialDetail_one': '1 app could not be read on a store; it shows as unknown',
'toast.readFailed': 'Reading the stores failed',
'toast.cancelled': 'Cancelled',
'toast.reading': 'Reading',
'toast.readingDetail': 'Read-only',
'toast.readOk': '{what} read',
'toast.readFailedWhat': 'Reading {what} failed',
'write.dryFailed': 'The dry run failed, nothing was written',
'write.failed': 'Not applied',
'phase.none': 'Not on this store',
'phase.live': 'Live',
'phase.rollout': 'Rollout',
'phase.phased': 'Phased',
'phase.halted': 'Halted',
'phase.paused': 'Paused',
'phase.approved': 'Approved',
'phase.review': 'In review',
'phase.rejected': 'Rejected',
'phase.testing': 'Testing',
'phase.draft': 'Draft',
'phase.other': 'Other',
'stage.build': 'Build',
'stage.testing': 'Testing',
'stage.review': 'Review',
'stage.live': 'Live',
'stage.rollout': 'Rollout',
'check.notChecked': 'Not checked',
'check.notLoaded': 'Config not loaded',
'check.problems': '{count} problems',
'check.problems_one': '1 problem',
'check.warnings': '{count} warnings',
'check.warnings_one': '1 warning',
'check.ok': 'Config OK',
'app.notSetUp': 'not set up',
'app.notOnStore': 'Not on this store',
'app.sections': '{name} sections',
'app.consoleHint': 'Submit, release and publish happen in the store console',
'portfolio.lead': 'Every app in this workspace on the App Store and Google Play.',
'portfolio.sub': '{count} apps · {stores} store listings',
'portfolio.sub_one': '1 app · {stores} store listings',
'portfolio.emptyTitle': 'Add your first app',
'portfolio.emptyText': 'storebound works on app folders: one storebound.config.ts per app, for iOS and Android. Add a folder that has one, or start a new one from the templates.',
'portfolio.notReadNotice': 'Releases, rollouts and catalog parity need one read of the stores. It is read-only and uses each app\'s own accounts.',
'portfolio.apps': 'Apps',
'portfolio.appsSub': 'Release state from the stores, read {when}',
'portfolio.appsSubOffline': 'Config only: read the stores for releases',
'portfolio.unreadable': 'Unreadable',
'portfolio.noVersion': 'No version yet',
'portfolio.noNext': 'Nothing in flight',
'portfolio.thenNext': 'next {version} · {phase}',
'portfolio.products': '{count} products',
'portfolio.products_one': '1 product',
'portfolio.subs': '{count} subs',
'portfolio.subs_one': '1 sub',
'portfolio.inParity': 'In parity',
'portfolio.differs': '{count} differ',
'portfolio.differs_one': '1 differs',
'portfolio.configOnly': 'Not compared yet',
'portfolio.attention': 'Needs attention',
'portfolio.attentionSub': 'Problems first, then warnings',
'portfolio.allClear': 'Nothing needs attention',
'portfolio.allClearText': 'Configs check out and no store reported a problem in the last read.',
'portfolio.workspace': 'Workspace',
'portfolio.healthNotRead': 'Not read',
'portfolio.healthNoPlay': 'iOS only',
'portfolio.healthTitle': 'Last 14 days, user-perceived, read {when}',
'portfolio.accounts': '{play} Google Play · {apple} App Store Connect',
'portfolio.storesRead': 'Stores read',
'portfolio.tools': 'Local tools',
'portfolio.toolsFound': '{found} of {total} found',
'kpi.apps': 'Apps',
'kpi.appsSub': '{ios} on iOS · {android} on Android',
'kpi.live': 'Live versions',
'kpi.liveSub': 'across {count} store listings',
'kpi.rolling': 'Rolling out',
'kpi.review': 'In review',
'kpi.attention': 'Needs attention',
'kpi.blockers': '{count} blockers',
'kpi.blockers_one': '1 blocker',
'kpi.noBlockers': 'No blockers',
'kpi.none': 'None',
'kpi.notRead': 'Read the stores to see this',
'legend.done': 'done',
'legend.stages': 'Build · Testing · Review · Live · Rollout',
'col.app': 'App',
'col.next': 'Next version',
'col.catalog': 'Catalog',
'col.crash': 'Crash rate',
'col.config': 'Config',
'col.version': 'Version',
'col.build': 'Build',
'col.versionCode': 'Version code',
'col.track': 'Track',
'col.item': 'Item',
'col.type': 'Type',
'col.priceGap': 'Price gap',
'col.region': 'Region',
'col.diff': 'Difference',
'col.language': 'Language',
'col.issue': 'Issue',
'col.reports': 'Reports',
'col.users': 'Users',
'col.metric': 'Metric',
'col.value': 'Value',
'col.goal': 'Goal',
'col.name': 'Name',
'col.store': 'Store',
'col.usedBy': 'Used by',
'col.added': 'Added',
'col.actions': 'Actions',
'att.storeError': '{store} could not be read: {error}',
'att.rejected': '{store} {version} was rejected',
'att.halted': '{store} {version}: rollout halted',
'att.catalog': '{count} catalog items differ between the stores',
'att.catalog_one': '1 catalog item differs between the stores',
'att.crash': 'Crash rate near or over the Google Play threshold',
'att.anr': 'ANR rate near or over the Google Play threshold',
'tl.next': 'Next',
'tl.live': 'Live',
'tl.store': 'Store',
'tl.created': 'Created {date}',
'tl.notOnStore': 'Not on this store',
'tl.noVersion': '{version} is not on {store} yet',
'tl.everyone': 'Everyone',
'tl.day': 'day {day} of 7',
'tl.rolloutAria': 'Share of users with this version',
'releases.notReadTitle': 'Release state is not read yet',
'releases.notReadText': 'The timeline shows each version on both stores: build, TestFlight or internal testing, review, live and the rollout share. Read the stores once to fill it.',
'releases.noAccounts': 'Tip: map store accounts to this app in App folders first.',
'releases.storeUnreadable': '{store} could not be read, so its lane shows as unknown: {error}',
'releases.noVersions': 'No versions on the stores yet',
'releases.noVersionsText': 'When the first build is uploaded it shows here.',
'releases.history': 'Versions on the stores',
'releases.historySub': 'Read {when}',
'releases.consoleNote': 'storebound never submits for review, releases or completes a rollout. Do those in the store console.',
'cat.products': 'One-time products',
'cat.productsSub': 'In the config',
'cat.subscriptions': 'Subscriptions',
'cat.subsSub': 'All groups',
'cat.parity': 'In parity',
'cat.parityRead': 'Compared {when}',
'cat.gaps': 'Price gaps',
'cat.gapsSub': 'Same currency, over 10 %',
'cat.matrix': 'Parity matrix',
'cat.configOnly': 'From the config only: compare with both stores to fill the store columns',
'cat.compare': 'Compare with the stores',
'cat.ok': 'Matches',
'cat.warn': 'Differs',
'cat.error': 'Missing or wrong',
'cat.na': 'Not sold here',
'cat.unknown': 'Not compared',
'cat.extra': 'Store only',
'cat.sub': 'Subscription',
'cat.product': 'Product',
'cat.notInConfig': 'Not in the config',
'cat.noGap': 'None',
'cat.gapsTitle': 'Price gaps between the stores',
'cat.gapsTitleSub': 'Stores round to their own price tiers, so small gaps are normal',
'cat.emptyTitle': 'No in-app products or subscriptions',
'cat.emptyText': 'Products and subscriptions are defined once in storebound.config.ts and created on both stores. This app has none in its config.',
'lst.languages': 'Languages',
'lst.completeKpi': 'Complete',
'lst.completeSub': 'Required fields, both stores',
'lst.toFix': 'To fix',
'lst.toFixSub': 'Missing or over the limit',
'lst.screenshots': 'Screenshots',
'lst.screenshotsSub': 'Rendered, all languages',
'lst.noRenders': 'No renders folder yet',
'lst.playSub': 'store/listing.md',
'lst.appleSub': 'store/appstore.md',
'lst.complete': 'Complete',
'lst.completeAria': '{pct} % complete',
'lst.missing': 'Missing',
'lst.optional': 'Optional',
'lst.over': '{n} over',
'lst.title': 'Title',
'lst.short': 'Short',
'lst.full': 'Full',
'lst.whatsNew': 'What\'s new',
'lst.name': 'Name',
'lst.subtitle': 'Subtitle',
'lst.promo': 'Promo text',
'lst.keywords': 'Keywords',
'lst.description': 'Description',
'lst.noFilesTitle': 'No listing files yet',
'lst.noFilesText': 'Listing text lives in store/listing.md (Google Play) and store/appstore.md (App Store) in the app folder, one section per language.',
'lst.noFilesHint': 'writes both templates into the app folder',
'lst.foot': 'From the app folder\'s files, read {when}. Nothing is uploaded from here.',
'health.read': 'Read health',
'health.emptyTitle': 'Health is not read yet',
'health.emptyText': 'Crash and ANR rates against the Google Play thresholds, worst devices and top issues, plus App Store diagnostics. Read-only.',
'health.crash': 'User-perceived crash rate',
'health.anr': 'User-perceived ANR rate',
'health.window': '{from} to {to}',
'health.over': 'Over threshold',
'health.near': 'Near threshold',
'health.under': 'Under threshold',
'health.current28': '28-day average, as Google Play counts it',
'health.daily': 'Daily',
'health.threshold': 'Bad behavior threshold {value}',
'health.chartAria': '{metric}: {value}',
'health.devices': 'Worst devices',
'health.devicesSub': 'Per-device threshold {value}',
'health.noDevices': 'No device has enough users to compare.',
'health.issues': 'Top issues',
'health.issuesSub': 'Most reports first',
'health.noIssues': 'No issues reported',
'health.crashShort': 'Crash',
'health.appleMetrics': 'Performance metrics',
'health.appleMetricsSub': 'Latest values per metric',
'health.noMetrics': 'No metrics yet',
'health.signatures': 'Diagnostic signatures',
'health.signaturesSub': 'Heaviest first, latest builds',
'health.noSignatures': 'No diagnostic signatures',
'health.betaCrashes': 'TestFlight crashes',
'health.noBetaCrashes': 'No TestFlight crash reports in the window.',
'health.build': 'build {build}',
'health.noPlay': 'This app is not on Google Play.',
'health.noApple': 'This app is not on the App Store.',
'health.unreadable': '{store} could not be read, shown as unknown: {error}',
'reviews.read': 'Read reviews',
'reviews.emptyTitle': 'Reviews are not read yet',
'reviews.emptyText': 'The last 30 days on the App Store, the last 7 on Google Play (its API keeps no more), with your local reply drafts. Read-only.',
'reviews.ratings': 'Ratings',
'reviews.count': '{count} reviews',
'reviews.count_one': '1 review',
'reviews.unansweredN': '{count} without a reply',
'reviews.unansweredN_one': '1 without a reply',
'reviews.filter': 'Filter',
'reviews.store': 'Store',
'reviews.all': 'All',
'reviews.onlyUnanswered': 'Only without a reply',
'reviews.search': 'Search reviews',
'reviews.inbox': 'Inbox',
'reviews.shown': '{count} shown',
'reviews.noMatch': 'No review matches the filter',
'reviews.pick': 'Pick a review',
'reviews.answered': 'Answered',
'reviews.drafted': 'Draft',
'reviews.approved': 'Approved',
'reviews.notApproved': 'Not approved',
'reviews.noTitle': 'No title',
'reviews.noText': 'No text',
'reviews.version': 'version {v}',
'reviews.currentReply': 'Reply on the store',
'reviews.draft': 'Your reply draft',
'reviews.noDraft': 'No draft for this review. "Make drafts" writes one file per unanswered review into .storebound/replies.',
'reviews.emptyDraft': 'The draft {file} has no reply yet: write it under "## Reply".',
'reviews.chars': '{n} of {limit} characters',
'reviews.approve': 'Approve',
'reviews.unapprove': 'Remove approval',
'reviews.approveHint': 'Marks the draft approved (local file, confirmed in a dialog). Nothing is sent.',
'reviews.fixFirst': 'Fix the errors first',
'reviews.sentOn': 'Sent {date}',
'reviews.sendNote': 'Replies are public, so they go out from a terminal:',
'reviews.makeDrafts': 'Make drafts',
'reviews.makeDraftsHint': 'One local draft per unanswered review (dry run first, then a confirmation)',
'reviews.draftsMade': 'Reply drafts written',
'reviews.approvedToast': 'Draft approved',
'reviews.unapproved': 'Approval removed',
'reviews.starsAria': '{count} of 5 stars',
'reviews.starsAria_one': '1 of 5 stars',
'tf.read': 'Read TestFlight',
'tf.emptyTitle': 'TestFlight is not read yet',
'tf.emptyText': 'Beta groups, testers and recent builds with their processing and beta review states. Read-only.',
'tf.noIos': 'This app is not on iOS',
'tf.noIosText': 'TestFlight is for apps with an App Store record. Add the apple section to the config to use it.',
'tf.internal': 'Internal',
'tf.external': 'External',
'tf.testers': 'testers',
'tf.builds': 'builds',
'tf.all': 'All',
'tf.publicOn': 'Public link on',
'tf.publicOff': 'Invite only',
'tf.noGroups': 'No beta groups',
'tf.buildsTitle': 'Recent builds',
'tf.buildsSub': 'Newest first',
'tf.processing': 'Processing',
'tf.internalTesting': 'Internal testing',
'tf.externalTesting': 'External testing',
'tf.uploaded': 'Uploaded',
'tf.noBuilds': 'No builds uploaded yet',
'tf.missingGroups': 'In the config but not on App Store Connect: {groups}',
'checks.offline': 'Config check',
'checks.offlineSub': 'Offline: config, listing files, copy, declarations, products',
'checks.again': 'Check again',
'checks.clean': 'The config checks out',
'checks.cleanText': 'No problems or warnings in the app folder.',
'checks.problem': 'Problem',
'checks.warning': 'Warning',
'checks.validate': 'Store readiness',
'checks.validateSub': 'Read-only report from both stores, blockers in order',
'checks.run': 'Run the report',
'checks.validateEmpty': 'Readiness not checked yet',
'checks.validateEmptyText': 'What is still missing on the App Store and Google Play before a submission, in the order to fix it.',
'checks.ready': 'No blockers',
'checks.readyText': 'Both stores have what a submission needs.',
'folders.lead': 'One folder per app with its storebound.config.ts (iOS and Android in one config). Pick the store accounts each app uses; the keys stay in the keychain.',
'folders.list': 'App folders',
'folders.listSub': '{count} folders',
'folders.listSub_one': '1 folder',
'folders.emptyTitle': 'No app folders yet',
'folders.emptyText': 'Add a folder that has a storebound.config.ts, or start a new one below.',
'folders.added': '{name} added',
'folders.started': '{name} started',
'folders.startedDetail': 'Templates written. Edit storebound.config.ts and the store files next.',
'folders.playFor': 'Google Play account for {name}',
'folders.appleFor': 'App Store Connect account for {name}',
'folders.noPlay': 'No Google Play account',
'folders.noApple': 'No App Store account',
'folders.check': 'Check',
'folders.gallery': 'Gallery',
'folders.galleryHint': 'Writes the local screenshot review page (dry run first, then a confirmation)',
'folders.remove': 'Remove {name} from the list (the folder stays)',
'folders.checkTitle': 'Config check',
'folders.galleryTitle': 'Screenshot review page',
'folders.newTitle': 'Start a new app folder',
'folders.newSub': 'storebound init: config, listing, screenshot copy, declarations and privacy policy templates',
'folders.profile': 'Profile',
'folders.profileHint.app': 'Utility or productivity app: optional account and analytics, no ads.',
'folders.profileHint.game': 'Free-to-play game with ads and in-app purchases.',
'folders.profileHint.subscription-app': 'App with accounts and auto-renewable subscriptions.',
'folders.chooseAndStart': 'Choose a folder and start',
'run.failed': 'Failed',
'run.running': 'Running',
'run.applied': 'Applied after your confirmation',
'run.cancelled': 'Cancelled in the dialog: nothing was written',
'run.dryFailed': 'The dry run failed: nothing was written',
'run.done': 'Done',
'accounts.lead': 'Store API keys live in the system keychain (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux). They are never shown again, never written to your app folders, and reach storebound in memory for one call.',
'accounts.list': 'Store accounts',
'accounts.listSub': 'Labels only: the keys are in the keychain',
'accounts.emptyTitle': 'No store accounts yet',
'accounts.emptyText': 'Add a Google Play service account or an App Store Connect API key below. Store reads need them; app folders work without.',
'accounts.unused': 'Not used',
'accounts.remove': 'Remove',
'accounts.removeAria': 'Remove {label} and delete its key from the keychain',
'accounts.saved': '"{label}" saved',
'accounts.savedDetail': 'The key is in the system keychain.',
'accounts.playSub': 'Service account JSON key',
'accounts.appleSub': 'Team API key (.p8) from Users and Access, Integrations',
'accounts.label': 'Name',
'accounts.playPlaceholder': 'Studio Play account',
'accounts.applePlaceholder': 'Studio App Store key',
'accounts.playHow': 'A service account with access to your apps in Play Console (Users and permissions).',
'accounts.keyId': 'Key ID',
'accounts.issuerId': 'Issuer ID',
'accounts.choosePlay': 'Choose the JSON key',
'accounts.chooseApple': 'Choose the .p8 key',
'accounts.safety': 'Keys are picked in the system file dialog and go straight to the keychain. The window never sees them.',
'deps.lead': 'Local tools for screenshots, app previews, icons and simulator or emulator captures. Store work (listings, products, releases, reviews) needs none of them.',
'deps.checkAgain': 'Check again',
'deps.tools': 'Tools on this computer',
'deps.found': '{found} of {total} found',
'deps.missing': 'Missing',
'deps.appCopy': 'App copy',
'deps.installed': 'Installed',
'deps.download': 'Download',
'deps.remove': 'Remove',
'deps.getIt': 'Get it',
'deps.unavailable': 'Not for this platform',
'deps.downloading': 'Downloading {tool}',
'deps.installedToast': '{tool} installed',
'deps.failed': 'Download failed',
'deps.cancelledDetail': 'The partial download was deleted.',
'deps.removed': 'Removed from the app data folder',
'deps.inAppData': 'In the app data folder ({folder})',
'deps.notDownloaded': 'Not downloaded',
'deps.source': 'Source',
'deps.license': 'License',
'deps.verify': 'Verified by',
'deps.verifyFfmpeg': 'SHA-256 of the exact archive, pinned in this app version',
'deps.verifyChrome': 'Google\'s code signature (macOS, Windows) or the version banner (Linux)',
'deps.licenseLink': 'License and source',
'deps.terminal': 'From a terminal',
'deps.terminalSub': 'The same check, and the usual install commands',
'deps.copy': 'Copy "{cmd}"',
'deps.copied': 'Copied',
'dl.resolve': 'Finding the download',
'dl.download': 'Downloading',
'dl.verify': 'Verifying',
'dl.unpack': 'Unpacking',
'dl.install': 'Installing',
'dl.done': 'Done',
'dl.error': 'Failed',
'dl.cancelled': 'Cancelled',
'settings.lead': 'Appearance, language, shortcuts and what this app runs on.',
'settings.appearance': 'Appearance',
'settings.theme': 'Theme',
'settings.system': 'System',
'settings.light': 'Light',
'settings.dark': 'Dark',
'settings.motion': 'Motion',
'settings.followSystem': 'Follow the system',
'settings.reduce': 'Reduce',
'settings.language': 'Language',
'settings.shortcuts': 'Keyboard shortcuts',
'settings.scPalette': 'Command palette',
'settings.scWorkspace': 'App folders, Accounts, Dependencies, Settings',
'settings.scTabs': 'Previous / next app tab',
'settings.scTabArrows': 'Move between tabs (tab list focused)',
'settings.scClose': 'Close a dialog',
'settings.data': 'Saved reads',
'settings.dataText': 'The last store reads are kept in the app data folder so screens open with them offline, always marked with their time. No keys are kept there.',
'settings.clearCache': 'Clear saved reads',
'settings.cacheCleared': 'Saved reads cleared',
'settings.about': 'About',
'settings.app': 'App',
'settings.debug': 'debug build',
'settings.methods': '{count} methods',
'settings.tools': 'Local tools',
'settings.telemetry': 'Telemetry',
'settings.telemetryNone': 'None. The app only talks to the store APIs through storebound, with your keys.',
'wz.s1': 'Welcome',
'wz.s2': 'Your apps',
'wz.s3': 'Store keys',
'wz.s4': 'Local tools',
'wz.s5': 'First read',
'wz.footer': 'You can open this guide again from Settings or the command palette.',
'wz.footerSafe': 'Nothing is submitted or released from here.',
'wz.welcomeTitle': 'Every app, both stores, one window',
'wz.welcomeLead': 'storebound desktop shows where each of your apps stands on the App Store and Google Play, and runs the storebound CLI for you. Five short steps get you there.',
'wz.p1t': 'One portfolio',
'wz.p1s': 'Releases, rollouts, catalog parity, health and reviews of every app.',
'wz.p2t': 'Safe by design',
'wz.p2s': 'Reads are read-only. Every change shows a dry run and a native confirmation first.',
'wz.p3t': 'Your keys stay yours',
'wz.p3s': 'Store keys live in the system keychain. No account, no telemetry.',
'wz.appsTitle': 'Add your apps',
'wz.appsLead': 'Each app is a folder with a storebound.config.ts that describes it on both stores.',
'wz.addTitle': 'Add an existing folder',
'wz.addText': 'The folder already has a storebound.config.ts (from storebound init or the CLI).',
'wz.initTitle': 'Start a new app folder',
'wz.initText': 'Writes the templates for a profile into a folder you choose. Existing files are kept.',
'wz.added': 'Added',
'wz.ready': 'Ready',
'wz.keysTitle': 'Add your store keys',
'wz.keysLead': 'Store reads need an API key per store. You can skip this and add them later in Accounts.',
'wz.mapHint': 'Which accounts this app uses',
'wz.toolsTitle': 'Check the local tools',
'wz.toolsLead': 'Screenshots, previews and icons use ffmpeg and Chrome. The app can download its own copies; store work needs none of them.',
'wz.toolsNote': 'The same check in a terminal:',
'wz.readTitle': 'Read the stores',
'wz.readLead': 'One read-only pass over App Store Connect and Google Play fills the portfolio: versions, review state, rollouts and catalog parity.',
'wz.readNow': 'Read the stores now',
'wz.readDone': '{count} apps read {when}',
'wz.needApp': 'Add an app folder first (step 2).',
'wz.skip': 'Skip for now',
'wz.back': 'Back',
'wz.next': 'Next',
'wz.finish': 'Finish',
} as const;