storebound/apps/desktop/src/i18n/en.ts

1726 lines
92 KiB
TypeScript

// 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': 'Studios & 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.exitNoMessage': 'The command stopped without an error message (exit {code}); the log has the details',
'gerr.apiDisabled': '{what} needs the {service} turned on in Google Cloud project {project}.',
'gerr.what.reporting': 'Crash and ANR data',
'gerr.what.publisher': 'Reading the app on Google Play',
'gerr.what.storage': 'Play statistics',
'gerr.what.other': 'This read',
'gerr.projectUnknown': '(the service account\'s project)',
'gerr.turnOn': 'Turn it on in Google Cloud',
'gerr.checkAgain': 'Check again',
'gerr.noAccess': 'The service account has no access to {app} in Play Console: add it under Users and permissions.',
'gerr.thisApp': 'this app',
'gerr.openUsers': 'Open Users and permissions',
'gerr.revoked': 'Google refused the service account key: it was revoked, deleted or has expired. Add a new JSON key in Accounts.',
'gerr.quota': 'The Google API quota is used up for now. Try again later.',
'gerr.details': 'Details',
'gerr.openFailed': 'Could not open the page',
'gerr.portfolio': '{count} Google Cloud projects need an API turned on: affects {apps}',
'gerr.portfolio_one': '1 Google Cloud project needs an API turned on: affects {apps}',
'gerr.portfolioProject': 'Project {project}: {service}',
'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.sent': 'In review',
'phase.released': "Couldn't check the store page",
'phase.releasedUnknown': "Couldn't check the store page",
'phase.pageUnknown': "Couldn't check the store page",
'phase.pageStale': "couldn't check the store page, as of {when}",
'phase.reviewLive': 'In review (live: {version})',
'phase.reviewManaged': 'In review / ready to publish (managed publishing)',
'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.released': 'Released',
'tl.store': 'Store',
'tl.created': 'Created {date}',
'tl.notOnStore': 'Not on this store',
'tl.unknown': 'Unknown',
'tl.unreadable': "Couldn't read {store}: state unknown",
'tl.otherVersion': '{now} · {phase} ({version} not submitted)',
'tl.notThisVersion': 'Not this version',
'tl.current': 'Current',
'tl.bothVersions': 'Play {play} · App Store {ios}',
'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.storeStale': "Couldn't refresh {store}: showing the read from {when}. {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}',
'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.',
'checks.scan': 'Rejection risks',
'checks.scanSub': 'Offline scan of the project files: guideline, evidence, fix',
'checks.scanAgain': 'Scan again',
'checks.scanClean': 'No rejection risks found',
'checks.scanCleanText': 'Nothing in the project files, config or listings matches a known App Store rejection or Google Play policy issue.',
'checks.scanSdks': 'SDKs: {list}',
'checks.scanAsk': '{count} declaration answers only you can give',
'checks.scanAsk_one': '1 declaration answer only you can give',
'checks.scanWrite': 'Detected Data safety / App Privacy answers differ from the config: storebound scan --write adds them',
'checks.accepted': 'Accepted: {reason}',
'checks.sev.blocker': 'Blocker',
'checks.sev.high': 'High',
'checks.sev.medium': 'Medium',
'checks.sev.accepted': 'Accepted',
'checks.sev.low': 'Low',
'folders.lead': 'One folder per app with its storebound.config.ts (iOS and Android in one config). This list is the machine\'s (~/.storebound/projects.json): `storebound desktop` or `storebound apps add` in a terminal adds to it too. Pick the store accounts each app uses.',
'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 accounts live once per machine in ~/.storebound, shared with the storebound CLI (`storebound accounts`): one credential profile per account, key files readable only by you. 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 and profile names only: the keys are in ~/.storebound',
'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}; its key file moves to a .removed folder in ~/.storebound',
'accounts.saved': '"{label}" saved',
'accounts.savedDetail': 'The key is in a credential profile in ~/.storebound (the CLI uses it too).',
'acct.profile': 'profile {name}',
'acct.noProfile': 'key not moved from the keychain yet',
'app.pinNotice': 'This project uses storebound {pin} (package.json), the app runs {app}. The app works with its own copy; update the project with `bun add -d storebound@{app}` (or npm i -D) to keep both the same.',
'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 into ~/.storebound (readable only by you). 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. Six 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 ~/.storebound, shared with the storebound CLI. 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 3).',
'wz.skip': 'Skip for now',
'wz.back': 'Back',
'wz.next': 'Next',
'wz.finish': 'Finish',
'nav.ignored': 'Ignored',
'nav.studios': 'Studios',
'nav.studiosLabel': 'Studios',
'palette.studio': 'Studio',
'action.importApps': 'Import apps',
'action.importAppsHint': 'Read-only: every app each store account can see, from App Store Connect and Google Play',
'apps.storeOnly': 'Store only',
'apps.storeOnlyHint': 'On a store account, no local project (no app folder on this machine): store data only (read-only)',
'common.save': 'Save',
'studio.studio': 'Studio',
'studio.none': 'No studio',
'studio.noneSub': 'Accounts not in a studio yet',
'studio.new': 'New studio',
'studio.newSub': 'A studio groups store accounts, and with them their apps',
'studio.name': 'Name',
'studio.namePlaceholder': 'Example Games',
'studio.color': 'Colour',
'studio.add': 'Add a studio',
'studio.added': 'Studio {name} added',
'studio.edit': 'Edit',
'studio.logo': 'Logo',
'studio.logoClear': 'Remove logo',
'studio.remove': 'Remove',
'studio.removeHint': 'Removes the studio only: its accounts and apps stay, without a studio',
'studio.counts': '{count} accounts · {apps} apps · {store} store only',
'studio.noAccounts': 'No store account in this studio yet: add one below and pick this studio.',
'studio.allAssigned': 'Every account is in a studio.',
'color.indigo': 'Indigo',
'color.violet': 'Violet',
'color.rose': 'Rose',
'color.amber': 'Amber',
'color.emerald': 'Emerald',
'color.teal': 'Teal',
'color.sky': 'Sky',
'color.slate': 'Slate',
'accounts.leadStudios': 'Studios group your store accounts: Google Play service accounts and App Store Connect team keys. Keys live in ~/.storebound, shared with the CLI; apps come in with Import apps.',
'accounts.emptyTextStudios': 'Add a studio, then its Google Play service account and App Store Connect keys. Import apps then lists every app those keys can see.',
'accounts.playSubMany': 'Service account JSON key. One service account can be invited to several Play developer accounts: it sees all their apps.',
'accounts.appleSubMany': 'One API key per team (company or individual): key id, issuer id and the .p8 file.',
'accounts.safetyStudios': 'Keys are read once from the file you pick, stored in ~/.storebound (readable only by you, shared with the storebound CLI) and never shown again. storebound gets one account\'s key in memory for one call. Studio names, labels and app lists stay on this computer.',
'acct.ok': 'Works',
'acct.noApps': 'No apps',
'acct.permission': 'Permission missing',
'acct.revoked': 'Key revoked',
'acct.apiDisabled': 'API off',
'acct.error': 'Not reachable',
'acct.notTested': 'Not tested',
'acct.kindPlay': 'Google Play service account',
'acct.kindApple': 'App Store Connect team key',
'acct.appsRead': '{count} apps, read {when}',
'acct.appsRead_one': '1 app, read {when}',
'acct.notImported': 'apps not imported yet',
'acct.folders': 'used by {count} folders',
'acct.folders_one': 'used by 1 folder',
'acct.test': 'Test',
'acct.testAll': 'Test all accounts',
'acct.import': 'Import apps',
'acct.edit': 'Rename or move to a studio',
'acct.editAria': 'Edit {label}',
'acct.ignore': 'Ignore this account',
'acct.ignoreHint': 'Ignore: leave this account\'s apps out of the portfolio and store reads',
'acct.unignore': 'Show this account again',
'acct.ignored': 'Ignored',
'acct.openFix': 'Open',
'ignored.lead': 'Apps and accounts left out of the portfolio, the sidebar and store reads. Nothing on the stores changes.',
'ignored.restoreAll': 'Restore all',
'ignored.restore': 'Restore',
'ignored.emptyTitle': 'Nothing is ignored',
'ignored.emptyText': 'Ignore an app from its page (or a whole account in Studios & accounts) to keep test apps and old titles out of the way.',
'ignored.apps': 'Apps',
'ignored.appsSub': '{count} ignored',
'ignored.accounts': 'Accounts',
'ignored.accountsSub': 'Every app of these accounts is left out',
'ignored.accountApps': '{count} apps',
'ignored.accountApps_one': '1 app',
'ignored.noApps': 'No ignored app.',
'ignored.noAccounts': 'No ignored account.',
'ignored.howTo': 'Pairing and single-store apps:',
'ignored.toPairing': 'Settings > App pairing',
'pair.folder': 'From its app folder',
'pair.manual': 'Paired by hand',
'pair.id': 'Paired: same bundle id and package name',
'pair.close': 'Paired: close ids',
'pair.name': 'Paired: same name',
'pair.single': 'One store only',
'app.moveStudio': 'Move to a studio',
'app.pairWith': 'Pair with',
'app.pairWithName': 'Pair {name} with',
'app.pick': 'Pick an app',
'app.unpair': 'Unpair',
'app.ignore': 'Ignore',
'app.ignoreHint': 'Leave this app out of the portfolio and store reads (Ignored lists it to restore)',
'app.studioHint': 'Open the studio',
'app.storeOnlyTitle': 'Store only.',
'app.storeOnlyText': 'This app is on your store accounts but has no app folder: releases, reviews, health and TestFlight are shown read-only. Link its folder, or start one, to manage listings, products and checks.',
'app.linkFolder': 'Link a folder',
'app.initHere': 'Start an app folder here',
'app.linked': '{name} is linked',
'app.linkFailed': 'Could not link the folder',
'portfolio.subStudios': '{count} apps · {stores} store listings · {studios} studios',
'portfolio.emptyAccounts': 'Add a studio and its accounts',
'portfolio.notImported': 'Apps of {count} accounts are not imported yet: Import apps lists everything those keys can see.',
'portfolio.notImported_one': 'Apps of 1 account are not imported yet: Import apps lists everything its key can see.',
'portfolio.toolbar': 'Filter and sort the apps',
'portfolio.search': 'Search apps, bundle ids, packages',
'portfolio.studioFilter': 'Studio',
'portfolio.allStudios': 'All studios',
'portfolio.sort': 'Sort',
'portfolio.sortAttention': 'Needs attention',
'portfolio.sortRecent': 'Recently updated',
'portfolio.sortName': 'Name',
'portfolio.group': 'Group by studio',
'portfolio.groupCount': '{count} apps',
'portfolio.noConfig': 'No config',
'portfolio.storeOnlyCheck': 'Store only',
'portfolio.noMatch': 'No app matches',
'portfolio.noMatchText': 'Clear the search or pick another studio.',
'portfolio.studiosN': '{count} studios',
'portfolio.studiosN_one': '1 studio',
'portfolio.folders': 'App folders',
'portfolio.foldersN': '{count} folders · {store} store only',
'portfolio.ignoredN': '{count} apps',
'portfolio.ignoredN_one': '1 app',
'kpi.appsSubStore': 'iOS {ios} · Android {android} · {store} store only',
'toast.importing': 'Importing apps',
'toast.importingDetail': 'Every app each account can see (read-only)',
'toast.importDone': '{count} apps on your accounts',
'toast.importDone_one': '1 app on your accounts',
'toast.importDoneDetail': 'from {count} accounts',
'toast.importDoneDetail_one': 'from 1 account',
'toast.importPartial': '{count} accounts could not be read',
'toast.importPartial_one': '1 account could not be read',
'toast.saveFailed': 'Not saved',
'notify.releaseTitle': '{name}: store state changed',
'notify.releaseBody': '{store} {version}: {phase}',
'notify.lowTitle': '{name}: {count} new low ratings',
'notify.lowTitle_one': '{name}: a new low rating',
'notify.crashTitle': '{name}: over the Play threshold',
'set.lead': 'Studios, accounts, store reads, the offline cache, language, theme, notifications and more. Everything stays on this computer.',
'set.sections': 'Settings sections',
'set.studios': 'Studios & accounts',
'set.studiosSub': 'Which accounts belong to which studio',
'set.studioLine': 'Play {play} · App Store {apple} · {apps} apps',
'set.noStudios': 'No studio yet. Studios group accounts and their apps in the portfolio and the sidebar.',
'set.manage': 'Manage',
'set.pairing': 'App pairing & ignore list',
'set.pairingSub': 'An iOS and an Android app become one card when their ids or names match; pair or split them by hand here',
'set.pairedHow': 'Pairing',
'set.noCandidates': 'Nothing to pair with',
'set.noStoreOnly': 'Every app has its folder: pairing comes from the configs.',
'set.ignoredLine': 'Ignored: {count} apps, {accounts} accounts.',
'set.openIgnored': 'Open the list',
'set.refresh': 'Store reads',
'set.refreshSub': 'Reads use each account\'s API quota: they run when you ask, or on the schedule here',
'set.autoRefresh': 'Read the stores automatically',
'set.autoHint': 'While the app is open. Off by default.',
'health.likelyCause': 'Likely cause:',
'health.suggestedFix': 'Fix:',
'health.copied': "Copied for AI: paste it into your agent",
'health.copyFailed': "Could not copy to the clipboard",
'health.issueType': "Type",
'health.issueWhere': "Location",
'health.issueShare': "Share of reports",
'health.issueVersions': "versionCode",
'health.issueBuild': "Build",
'health.issueOs': "Android API",
'health.issueLastSeen': "Last report",
'health.sample': "Sample stack trace",
'health.noSample': "No sample report in the last 28 days.",
'health.copyForAi': "Copy for AI",
'health.openConsole': "Open in Play Console",
'health.issuesUnread': "Top issues not read: {error}",
'set.autoRead': "Read everything automatically",
'set.autoReadHint': "Status, releases, catalog, prices, listings, TestFlight, health, reviews and checks of every app, in the background, inside the stores' limits",
'set.everyMinutes': "While the app is open, read again every",
'set.onlyOnStart': "Only on start",
'set.everyHint': "Only reads past their age limit run (status 5 min, reviews 15 min, catalog and prices 30 min, health and analytics 6 h). Paused while the window is hidden.",
'action.refreshAll': "Refresh all",
'action.refreshAllHint': "Read everything of every app again now (read-only, inside the stores' limits)",
'read.ago': "read {when}",
'read.refreshing': "Refreshing…",
'read.couldNotRefresh': "couldn't refresh: {reason}",
'read.refresh': "Refresh",
'read.waiting': "Reading…",
'reader.progress': "Reading {done} of {total}",
'reader.upToDate': "Everything read",
'reader.off': "Auto-read is off",
'reader.appleQuota': "App Store limit {left}/{limit} left this hour",
'reader.backoff': "The store asked to slow down: waiting",
'set.off': 'Off',
'set.min': '{n} min',
'set.hour': '{n} h',
'set.onLaunch': 'Read when the app starts',
'set.onLaunchHint': 'Imports the apps of every account, then reads every app\'s store status',
'set.icons': 'Store icons on import',
'set.iconsHint': 'One extra request per app; folders use their own icon',
'set.parallel': 'Apps read at the same time',
'set.parallelHint': 'Fewer is gentler on rate limits',
'set.cache': 'Offline cache',
'set.cacheSub': 'The last store reads, shown with their time when you are offline',
'set.cacheSize': 'On disk',
'set.cacheRows': '{count} saved reads',
'set.cacheRows_one': '1 saved read',
'set.cacheOldest': 'Oldest',
'set.keep': 'Keep saved reads',
'set.days': '{n} days',
'set.year': '1 year',
'set.always': 'Always',
'set.notifications': 'Notifications',
'set.notificationsSub': 'After a read, when something changed since the previous one',
'set.nReview': 'Review and release state changes',
'set.nReviewHint': 'In review, approved, rejected, live, halted',
'set.nLow': 'New 1 or 2 star reviews',
'set.nLowHint': 'When the Reviews tab reads new ones',
'set.nCrash': 'Crash or ANR rate over the threshold',
'set.nCrashHint': 'Google Play bad behavior thresholds',
'set.testNotify': 'Send a test notification',
'set.testTitle': 'storebound',
'set.testBody': 'Notifications work.',
'set.appCopy': 'app copy',
'set.depsText': 'Store work needs no local tool. Screenshots, previews and icons use ffmpeg and Chrome: one click on the Dependencies screen.',
'set.cli': 'CLI sidecar',
'set.protocol': 'Protocol',
'set.state': 'State',
'set.running': 'Running',
'set.writes': 'Writes',
'set.writesText': 'Dry run first, then your Apply in a system dialog. Submit, release and publish stay in the consoles.',
'set.privacy': 'Privacy',
'set.p1': 'No telemetry, no analytics, no crash reports: the app talks only to the stores, with your keys, when you ask.',
'set.p2': 'Store keys live in ~/.storebound and the app folder list in ~/.storebound/projects.json, shared with the CLI; the app data folder holds labels, settings and saved reads, never keys.',
'set.p3': 'Nothing is written into your app folders unless you confirm it in a system dialog.',
'set.p4': 'Tester emails stay masked; review drafts stay in each app folder\'s .storebound/ (gitignored).',
'set.reveal': 'Show the data folder',
'set.scQuit': 'Quit',
'set.updates': 'Updates',
'set.channel': 'Channel',
'set.stable': 'Stable',
'set.beta': 'Beta',
'set.updatesText': 'Updates come from storebound.dev and are signed; the app checks the signature before it replaces anything, and installs only when you press Install. Nothing is checked in the background.',
'set.updateCheck': 'Check for updates',
'set.updateChecking': 'Checking…',
'set.updateNone': 'storebound {version} is the newest version on the {channel} channel.',
'set.updateAvailable': 'storebound {version} is available.',
'set.updateInstall': 'Install {version}…',
'set.updateInstalling': 'Downloading the update… {done}',
'set.reset': 'Reset',
'set.resetText': 'Forgets {studios} studios, the labels of {accounts} accounts, pairing, the ignore list, settings and saved reads. The accounts in ~/.storebound and the {folders} app folders stay: the CLI uses them too. A system dialog asks first.',
'set.resetButton': 'Reset the app',
'set.resetDone': 'storebound desktop was reset',
'set.footer': '{n} apps known to this computer',
'studio.counts_one': '1 account · {apps} apps · {store} store only',
'portfolio.groupCount_one': '1 app',
'portfolio.groupAccounts': '{count} accounts',
'portfolio.groupAccounts_one': '1 account',
'write.dryRunning': 'Dry run first: nothing changes yet',
'write.notApplied': 'Not applied',
'write.notAppliedDetail': 'You chose Cancel in the dialog: nothing changed.',
'act.storeTitle': 'Push to the stores',
'act.storeSub': 'Listing text, screenshots and previews from this folder, and the local renders',
'act.playListing': 'Listing text',
'act.playListingDone': 'Play listing updated',
'act.playImages': 'Graphics and screenshots',
'act.version': 'Version',
'act.appleListing': 'Version {version} and its text',
'act.appleListingDone': 'App Store version and text updated',
'act.appleShots': 'Screenshots',
'act.applePreviews': 'App previews',
'act.uploaded': 'Uploaded',
'act.slowHint': 'Can take minutes: progress shows in the toast, Cancel stops it',
'act.render': 'Render (local)',
'act.renderLang': 'Language to render',
'act.allLangs': 'All languages',
'act.renderShots': 'Render screenshots',
'act.renderVideo': 'Cut app previews',
'act.icons': 'Generate icons',
'act.gallery': 'Review gallery',
'act.galleryDone': 'Gallery written next to the renders',
'act.rendered': 'Done',
'act.localHint': 'Local files only; needs ffmpeg and Chrome (Dependencies)',
'act.note': 'Each action runs a dry run and shows it in a system dialog before anything changes. Nothing here submits for review or publishes: that stays in the consoles.',
'act.catalogTitle': 'Sync the catalog',
'act.catalogSub': 'Create and update products and subscriptions with their regional prices from the config',
'act.playProducts': 'One-time products',
'act.playSubs': 'Subscriptions',
'act.appleIap': 'In-app purchases',
'act.appleSubs': 'Subscriptions',
'act.synced': 'Catalog updated',
'act.prices': 'Prices',
'act.pricesExport': 'Export prices (CSV)',
'act.pricesExported': 'Prices exported into the folder',
'act.pricesImport': 'Changing live prices from a sheet stays a terminal step:',
'act.catalogNote': 'Never submits: new items wait in the consoles until you send them with a version.',
'roll.playNow': 'Rollout {pct} %',
'roll.share': 'New user share',
'roll.toShare': 'Raise to {pct} %',
'roll.halt': 'Halt',
'roll.haltHint': 'Stops new installs of the update; not a rollback',
'roll.halted': 'Rollout halted',
'roll.resume': 'Resume',
'roll.complete': 'Everyone (100 %)',
'roll.completeHint': 'Completes the staged rollout: every user gets the update',
'roll.done': 'Rollout updated',
'roll.iosNow': 'Phased release, day {day} of 7',
'roll.pause': 'Pause',
'roll.pauseHint': 'Holds the automatic updates (up to 30 days); not a rollback',
'roll.paused': 'Phased release paused',
'roll.everyone': 'Release to everyone',
'roll.everyoneHint': 'Ends the phased release: every user with automatic updates gets it now',
'roll.phasedOn': 'Turn on phased release',
'roll.phasedOnHint': 'When this version goes live, it reaches users with automatic updates over 7 days',
'roll.phasedOnDone': 'Phased release is on',
'tf.what': 'What to Test',
'tf.groupsBtn': 'Internal groups',
'tf.whatToTest': 'What to Test for build {build}',
'tf.whatPlaceholder': 'What changed and what to look at (every App Store locale gets this text)',
'tf.whatSave': 'Set this text',
'tf.whatFromFile': 'From the listing file',
'tf.whatFromFileHint': 'Each locale\'s whatToTest (or What\'s New) from the App Store listing file',
'tf.whatSaved': 'What to Test updated',
'tf.toInternal': 'Give build {build} to internal groups',
'tf.noInternal': 'No internal group: create one in App Store Connect or with apple.testflight.groups.',
'tf.distribute': 'Give to these groups',
'tf.distributed': 'Build added to the groups',
'tf.externalNote': 'External groups and Beta App Review stay in App Store Connect.',
'tf.testersTitle': 'Testers',
'tf.testersSub': 'From the testers CSV in this folder (.storebound/testers.csv, never committed)',
'tf.testersGroup': 'Group',
'tf.testersAll': 'Every group in the CSV',
'tf.testersAdd': 'Add new testers',
'tf.testersHint': 'Apple emails each new tester an invitation once the group has a build',
'tf.testersDone': 'Testers added',
'tf.testersNote': 'Emails stay masked in every line and dialog. Removing testers stays a terminal step.',
'reviews.replyEditor': 'Reply',
'reviews.replyPlaceholder': 'Plain text, in the reviewer\'s language. No incentives, no personal data.',
'reviews.unsaved': 'Not saved',
'reviews.save': 'Save draft',
'reviews.saved': 'Draft saved (approve it again)',
'reviews.send': 'Send reply',
'reviews.sendHint': 'Public: the reviewer is notified. A system dialog shows the reply first.',
'reviews.sent': 'Reply sent',
'reviews.incentive': 'Offers something for a rating or asks for stars: not allowed',
'reviews.tooLong': 'Longer than the store allows ({limit} characters)',
'reviews.sendNoteD3': 'Replies are public. Save, approve, then Send: each step shows a system dialog first.',
// ---- every CLI area in the window: prices, store art, growth, app info, exports, onboarding ----
'tab.prices': 'Prices',
'tab.art': 'Store art',
'tab.growth': 'Growth',
'tab.appinfo': 'App info',
'col.date': 'Date',
'common.yes': 'Yes',
'common.no': 'No',
'export.button': 'Export',
'export.hint': 'Save what this screen shows as a file (CSV or Markdown)',
'export.saved': 'Saved',
'export.failed': 'Export failed',
'export.readFirst': 'Read it first',
'export.personal': 'personal data',
'export.prices': 'Prices (CSV, price sheet format)',
'export.reviews': 'Reviews (CSV)',
'export.health': 'Health report (Markdown)',
'export.validate': 'Store readiness report (Markdown)',
'export.catalog': 'Catalog parity (Markdown)',
'export.listings': 'Listings (Markdown)',
'export.noListings': 'No listing files in this app folder',
'export.portfolio': 'Portfolio (CSV)',
'export.noApps': 'No apps yet',
'export.declarations': 'Store declarations (Markdown)',
'export.dataSafety': 'Data safety (Play CSV)',
'export.noDataSafety': 'The config has no Data safety answers',
'export.analytics': 'Analytics, daily (CSV)',
'palette.gExport': 'Export',
'palette.export': 'Export: {what}',
'palette.prices': '{name} · Prices and price sheet',
'palette.art': '{name} · Store art gallery',
'hint.keys': 'Map a store account to this app in App folders, or add the key in Studios & accounts.',
'hint.permission': 'The key works but lacks a permission: Studios & accounts > Test shows the fix.',
'hint.config': 'Set that value in storebound.config.ts (the Checks tab lists what is missing).',
'hint.renders': 'Render the screenshots first: Store art > Render.',
'hint.ffmpeg': 'Download ffmpeg on the Dependencies screen (one click, checked by hash).',
'hint.chrome': 'Download Chrome for Testing on the Dependencies screen.',
'hint.snapshot': 'Take a snapshot first: Growth > Take a snapshot.',
'hint.bucket': 'Set play.reportsBucket in the config (Play Console > Download reports > Statistics > Copy Cloud Storage URI).',
'hint.analyticsSetup': 'Start the App Store reports once: Growth > Start App Store reports (Admin key); data comes 1-2 days later.',
'hint.version': 'Create the version first: Listings > Push App Store version and text.',
'hint.fastlane': 'Pick the folder that contains fastlane/ (or ios/fastlane, android/fastlane).',
'hint.priceSheet': 'Write the sheet first: Prices > Write store/prices.csv, or pick a CSV.',
'hint.pricePoint': 'App Store prices must be one of Apple\'s price points: export with equalized prices to see them.',
'hint.network': 'Check the internet connection and try again.',
'hint.confirm': 'This step needs your confirmation in the dialog; run it again and press the button.',
'hint.git': 'The app folder must be a git repository with history (analytics compare reads git log).',
'prices.readTitle': 'Prices',
'prices.sheetTitle': 'Price sheet',
'prices.sheetSub': 'Every product x store x region in one CSV: export it, edit it, compare it, apply it',
'prices.exportCsv': 'Export prices CSV',
'prices.getSheet': 'Get the sheet',
'prices.readFirst': 'Read prices first',
'prices.writeProject': 'Write store/prices.csv',
'prices.writeHint': 'Writes the current prices into the app folder for `storebound prices import` (dry run first)',
'prices.compareHead': 'Compare and apply',
'prices.pickSheet': 'Compare a sheet…',
'prices.pickFailed': 'Could not open the sheet',
'prices.compareProject': 'Compare store/prices.csv',
'prices.showSheet': 'Show the sheet in the folder',
'prices.noSheetYet': 'No price sheet yet',
'prices.sheetNote': 'Reading changes nothing. Applying a sheet is your decision: storebound shows the dry run in a system dialog and writes only after you press its button. An App Store price increase cannot be undone once it starts.',
'prices.compareTitle': 'Compare the price sheet',
'prices.diffTitle': 'Sheet {file} against the stores',
'prices.diffSub': 'What would change on each store',
'prices.compareAgain': 'Compare again',
'prices.apply': 'Apply {count} changes',
'prices.apply_one': 'Apply 1 change',
'prices.applied': 'Prices written',
'prices.applyNote': 'Owner action: the stores apply new prices within hours, users see them then. Play regions without a price get Play\'s conversion of the US price.',
'prices.upToDate': 'Prices match the sheet',
'prices.upToDateText': 'Nothing to apply. Edit the sheet, then compare again.',
'prices.dChanged': '{count} changed',
'prices.dNew': '{count} new',
'prices.dUp': '{count} up',
'prices.dDown': '{count} down',
'prices.dProducts': 'Products: {list}',
'prices.colStarts': 'Starts',
'prices.colNow': 'Now',
'prices.colNew': 'New',
'prices.colKind': 'Set by',
'prices.now': 'now',
'prices.new': 'New',
'prices.more': '{count} more rows in the sheet',
'prices.emptyTitle': 'No in-app products in the config',
'prices.emptyText': 'Prices are read for the products of storebound.config.ts. Add them there (store-iap-setup skill), then create them on the stores from the Catalog tab.',
'prices.emptyHint': 'in storebound.config.ts',
'prices.notReadTitle': 'Prices not read yet',
'prices.notReadText': 'One read-only pass over App Store Connect and Google Play lists every product\'s price in every territory. It uses the accounts\' API quota.',
'prices.readNow': 'Read prices',
'prices.kProducts': 'Products',
'prices.kProductsSub': '{count} prices read',
'prices.kRegions': 'Territories',
'prices.kRegionsAuto': 'App Store equalized prices included',
'prices.kRegionsManual': 'App Store manual prices only',
'prices.kGaps': 'Price gaps',
'prices.kGapsSub': '≥ {pct} % apart in the same currency',
'prices.kMissing': 'Not on a store',
'prices.kMissingNone': 'Every product is on its stores',
'prices.overview': 'Products x key territories',
'prices.withAuto': 'App Store equalized prices',
'prices.auto': 'Equalized',
'prices.manual': 'Manual',
'prices.autoLegend': 'grey: App Store equalized from the base territory',
'prices.gapLegend': 'Δ: gap between the stores ≥ {pct} %',
'prices.perRegion': '{product} in every territory',
'prices.perRegionSub': '{count} territories',
'prices.searchRegion': 'Territory or currency',
'prices.otherCurrency': 'other currency',
'prices.scheduled': 'from {date}: {price}',
'prices.missingNote': 'Not on the store yet: {list}. Create them from the Catalog tab, then read again.',
'cat.openPrices': 'Open prices',
'cat.pricesHere': 'Prices per territory, the price sheet and applying it are on the Prices tab.',
'art.title': 'Store art',
'art.images': 'Images',
'art.imagesSub': '{count} languages',
'art.imagesSub_one': '1 language',
'art.videos': 'App previews',
'art.videosSub': 'App Store and promo videos',
'art.errors': 'Store errors',
'art.errorsSub': 'Size, alpha, format, count',
'art.warnings': 'Warnings',
'art.rendered': 'Scanned {when}',
'art.variant': 'Variant',
'art.base': 'Base',
'art.onlyIssues': 'Only issues',
'art.openFolder': 'Open folder',
'art.openPage': 'Open review page',
'art.openPageHint': 'Opens the gallery page (index.html) in your browser',
'art.writePage': 'Write review page',
'art.render': 'Render {lang}',
'art.notThere': 'Not there yet',
'art.count': '{count} files',
'art.count_one': '1 file',
'art.open': 'Open {name}',
'art.tooBig': 'too big to preview',
'art.prev': 'Previous',
'art.next': 'Next',
'art.emptyTitle': 'No renders yet',
'art.emptyText': 'Render the store screenshots from the frames and the copy file: press Render. It runs locally (ffmpeg and Chrome) and uploads nothing.',
'art.noIssues': 'No issues here',
'art.noIssuesText': 'Every file of this language passes the local store checks.',
'art.foot': 'Local files only, read {when}. Uploading is on the Listings tab.',
'gr.analytics': 'Store analytics',
'gr.analyticsSub': '{count} snapshots since {since}',
'gr.analyticsSubNone': 'Snapshots in .storebound/analytics, next to the listing changes in git',
'gr.setup': 'Start App Store reports',
'gr.setupDone': 'Report request created',
'gr.setupHint': 'Creates the ongoing App Store analytics report request once (Admin key). Changes nothing public.',
'gr.snapshot': 'Take a snapshot',
'gr.snapshotDone': 'Snapshot saved',
'gr.snapshotHint': 'Reads impressions, page views, downloads (App Store) and visitors, installs (Play) into .storebound/analytics',
'gr.noneTitle': 'No analytics snapshots yet',
'gr.noneText': 'A snapshot keeps 28 days of store traffic in the app folder (.storebound/analytics). With a few of them, this tab shows each listing change from git next to the conversion before and after it.',
'gr.noBucket': 'For Google Play, set play.reportsBucket in the config first.',
'gr.impressions': 'Impressions',
'gr.downloads': 'Downloads',
'gr.visitors': 'Listing visitors',
'gr.acquisitions': 'Acquisitions',
'gr.conversion': 'Conversion',
'gr.conversionSub': 'Installs per reach, whole window',
'gr.days': '{count} days',
'gr.days_one': '1 day',
'gr.daysN': '{count} days',
'gr.daysN_one': '1 day',
'gr.chartAria': 'Daily store traffic on {store} with listing changes',
'gr.changes': '{count} listing changes',
'gr.changes_one': '1 listing change',
'gr.indexLabel': 'Index: 100 = each line\'s own average over these days. Hover for the real numbers.',
'gr.noDataTitle': 'No {store} days in the snapshots yet',
'gr.noDataText': 'The snapshots read no daily numbers for this store yet. Take a new snapshot once the store has data.',
'gr.oneDay': 'One day of data so far: the chart starts with the second day.',
'gr.change': 'Listing change (git)',
'gr.before': 'Before',
'gr.after': 'After',
'gr.reading': 'A change needs several days on both sides and enough traffic; seasonality, featuring and ads move these numbers too.',
'gr.aso': 'ASO',
'gr.asoSub': 'aso audit, offline, {date}',
'gr.asoSubNone': 'Keyword field, rank trend and next steps from the app folder (aso audit, offline)',
'gr.asoField': 'Keyword field',
'gr.asoFieldSub': 'check --aso over store/appstore.md',
'gr.asoErrors': '{count} errors',
'gr.asoErrors_one': '1 error',
'gr.asoWarnings': '{count} warnings',
'gr.asoWarnings_one': '1 warning',
'gr.asoDrafts': 'Draft keywords to review: {locales}',
'gr.asoRanked': 'Keywords ranked',
'gr.asoLatest': 'In the first 200 results · {date}',
'gr.asoNoRanks': 'No rank snapshot yet: storebound aso rank',
'gr.asoGaps': 'Coverage gaps',
'gr.asoGapsSub': 'Words in top apps\' names you do not cover · {date}',
'gr.asoNoCompetitors': 'No competitor snapshot yet: storebound aso competitors',
'gr.asoChartAria': 'Keyword ranks over the rank snapshots, rank 1 at the top',
'gr.asoNotRanked': 'not ranked',
'gr.asoKeyword': 'Keyword',
'gr.asoRank': 'Rank',
'gr.asoBest': 'Best',
'gr.asoNext': 'Next 3 actions',
'gr.asoReading': 'Ranks follow the public iTunes Search API order, which is close to, not equal to, App Store search: read them as a trend. Popularity comes only from Apple Ads (aso suggest with an Apple Ads API key), never estimated.',
'gr.ppo': 'Product Page Optimization',
'gr.ppoSub': 'App Store A/B tests of the screenshots',
'gr.ppoRead': 'Read tests',
'gr.ppoNotRead': 'Tests not read yet',
'gr.ppoNotReadText': 'Read-only: the tests, their state, traffic share and treatments. Results per treatment are only in App Store Connect.',
'gr.ppoNone': 'No tests yet',
'gr.ppoNoneText': 'Create a test from a screenshot variant below, upload its screenshots, then start it.',
'gr.ppoNoVariants': 'Add a screenshot variant to shots.variants in the config (store-screenshots skill) and render it; each variant becomes one treatment.',
'gr.results': 'Results in App Store Connect',
'gr.test': 'Test',
'gr.state': 'State',
'gr.traffic': 'Traffic',
'gr.dates': 'Running',
'gr.treatments': 'Treatments',
'gr.owner': 'Owner action',
'gr.running': 'running',
'gr.notStarted': 'not started',
'gr.treatment': '{name} ({count} locales)',
'gr.treatment_one': '{name} (1 locale)',
'gr.startBtn': 'Start',
'gr.stopBtn': 'Stop',
'gr.start': 'Start the test "{name}"',
'gr.stop': 'Stop the test "{name}"',
'gr.started': 'Test start requested',
'gr.stopped': 'Test stop requested',
'gr.create': 'New test',
'gr.variant': 'Variant {id}',
'gr.createBtn': 'Create test',
'gr.createTitle': 'Create a Product Page Optimization test',
'gr.created': 'Test created (not started)',
'gr.upload': 'Treatment screenshots',
'gr.uploadBtn': 'Upload screenshots',
'gr.uploadTitle': 'Upload the screenshots of variant {id}',
'gr.uploadInto': 'Into the editable test "{name}"',
'gr.uploadNoTest': 'Create a test first: uploads go into the editable test.',
'gr.ppoNote': 'Create and upload change nothing visitors see. Start and stop are your decision: each shows a system dialog that names the action; a stopped test cannot be restarted.',
'gr.ppoStoreOnly': 'Read-only for a store-only app: link an app folder to create and run tests.',
'gr.playExp': 'Store listing experiments',
'gr.playExpSub': 'Google Play: no API',
'gr.playExpText': 'Google Play has no API for store listing experiments: create and run them in Play Console > Grow > Store listing experiments, with the variant screenshots storebound renders.',
'gr.seeVariants': 'See the variant renders',
'ai.askTitle': '{count} questions only you can answer',
'ai.askTitle_one': '1 question only you can answer',
'ai.askSub': 'The config does not prove these answers. storebound never guesses a compliance answer: decide, then set it in the config.',
'ai.allAnswered': 'Every declaration this tab shows comes from the config. The answers are still yours: review them before each submission.',
'ai.aDataSafety': 'Data safety',
'ai.aAppPrivacy': 'App Privacy',
'ai.aAppInfo': 'App info',
'ai.aEncryption': 'Export compliance',
'ai.aReview': 'App Review',
'ai.askedHere': '{count} open questions about this form above',
'ai.askedHere_one': '1 open question about this form above',
'ai.dsTitle': 'Data safety',
'ai.dsSub': 'Google Play, from dataSafety in the config',
'ai.dsUpload': 'Upload Data safety',
'ai.dsUploadHint': 'Replaces the whole Play Data safety form (dry run and system dialog first)',
'ai.dsUploaded': 'Data safety uploaded',
'ai.dsNoneTitle': 'No Data safety answers',
'ai.dsNoneText': 'Add dataSafety to storebound.config.ts (store-declarations skill): what the app and every SDK collect, why, and whether it is shared.',
'ai.dsCollects': 'Collects or shares data',
'ai.dsEncrypted': 'Encrypted in transit',
'ai.dsDeletion': 'Data deletion without deleting the account',
'ai.dsAuto90': 'No, deleted automatically within 90 days',
'ai.dsAccounts': 'Account creation',
'ai.dsNever': 'Play cannot read this form back. Once you upload from here, this tab shows what changed since.',
'ai.dsSame': 'Same as the last upload ({when}).',
'ai.dsChanged': '{count} answers changed since the last upload ({when}): upload again to bring Play up to date.',
'ai.dsChanged_one': '1 answer changed since the last upload ({when}): upload again to bring Play up to date.',
'ai.show': 'Show',
'ai.hide': 'Hide',
'ai.colType': 'Data type',
'ai.colCollected': 'Collected for',
'ai.colShared': 'Shared for',
'ai.notShared': 'not shared',
'ai.optional': 'optional',
'ai.ephemeral': 'ephemeral',
'ai.dsFoot': 'The upload sends {rows} CSV rows (Play\'s import format) and replaces every earlier answer.',
'ai.apTitle': 'App Privacy',
'ai.apSub': 'App Store, suggested from the Data safety answers',
'ai.apOpen': 'Open App Privacy',
'ai.apNote': 'App Privacy has no API: enter these answers in App Store Connect > App Privacy. Apple also asks per type whether it is linked to the user and used for tracking.',
'ai.apNoneTitle': 'No data collected',
'ai.apNoneText': 'The Data safety answers list no data types: in App Store Connect answer "Data Not Collected", if that is true for every SDK.',
'ai.apUnknownTitle': 'Nothing to suggest yet',
'ai.apUnknownText': 'Answer the data collection once in dataSafety; the App Privacy answers follow from it.',
'ai.colAppleType': 'Data type',
'ai.colPurposes': 'Purposes',
'ai.colLinked': 'Linked to user',
'ai.colTracking': 'Tracking',
'ai.ask': 'Your answer',
'ai.askLikely': 'Check: shared',
'ai.noPlay': 'Not on Google Play',
'ai.noPlayText': 'The config has no play section.',
'ai.noApple': 'Not on the App Store',
'ai.noAppleText': 'The config has no apple section.',
'ai.infoTitle': 'App info',
'ai.infoSub': 'Categories, age rating, content rights',
'ai.infoPush': 'Push the App Store app info',
'ai.push': 'Push',
'ai.pushed': 'Pushed to App Store Connect',
'ai.category': 'Category',
'ai.age': 'Age rating',
'ai.ageAllNone': 'Every question "none": confirm',
'ai.rights': 'Content rights',
'ai.rightsOwn': 'No third-party content',
'ai.rightsThird': 'Third-party content, rights held',
'ai.price': 'Price',
'ai.free': 'Free, every territory',
'ai.paid': 'Paid (set in App Store Connect)',
'ai.notSet': 'Not set',
'ai.notAnswered': 'Not answered',
'ai.encTitle': 'Export compliance',
'ai.encSub': 'Encryption answer for every build',
'ai.encAnswer': 'Answer builds',
'ai.encPush': 'Answer export compliance for the builds',
'ai.encYes': 'Uses non-exempt encryption',
'ai.encNo': 'Only exempt encryption',
'ai.encYesText': 'Builds are linked to the approved encryption declaration in App Store Connect.',
'ai.encNoText': 'Builds without an answer get usesNonExemptEncryption = false. Better: ITSAppUsesNonExemptEncryption = NO in Info.plist.',
'ai.encUnset': 'apple.usesNonExemptEncryption is not set. Decide it with the export-compliance skill; storebound never guesses it.',
'ai.encUnsetHint': 'Answer apple.usesNonExemptEncryption in the config first',
'ai.reviewTitle': 'App Review details',
'ai.reviewSub': 'Contact, demo account, notes',
'ai.reviewPush': 'Push the App Review details',
'ai.signIn': 'Sign-in needed',
'ai.contact': 'Contact',
'ai.demo': 'Demo account',
'ai.demoNone': 'none needed',
'ai.missing': 'Missing',
'ai.notes': 'Notes for the reviewer',
'ai.notesBytes': '{n} / {max} bytes',
'ai.notesNone': 'No notes (apple.info.reviewNotes, reviewAccess.instructions).',
'ai.reviewSafe': 'Contact and demo account stay in the app folder\'s .storebound/ (gitignored); shown masked, never the password.',
'ai.foot': 'From the config and .storebound/, read {when}. Nothing here was sent anywhere.',
'ds.functionality': 'App functionality',
'ds.analytics': 'Analytics',
'ds.communications': 'Developer communications',
'ds.fraud': 'Fraud prevention, security',
'ds.advertising': 'Advertising or marketing',
'ds.personalization': 'Personalization',
'ds.account': 'Account management',
'folders.fastlane': 'Import from fastlane',
'folders.fastlaneHint': 'Pick a folder with a fastlane setup: storebound shows the import plan in a system dialog, then writes its files next to fastlane (never overwrites)',
'folders.imported': '{name} imported from fastlane',
'folders.importedDetail': 'Config, listing files and screenshot frames written. Next: replace the placeholders, then Checks.',
'folders.startShort': 'Start an app folder',
'folders.newNote': 'Both ask for a folder in a system dialog, show what they would write, and write only after you press Apply. Existing files are kept.',
'folders.open': 'Open',
'folders.openApp': 'Open this app',
'folders.reveal': 'Show in the file manager',
'wz.s0': 'Your studio',
'wz.studioTitle': 'Which studio are these apps from?',
'wz.studioLead': 'A studio groups store accounts and their apps (a company, a client, a side project). Pick one or create it; the keys of the next steps go into it. You can move things later.',
'wz.studioPick': 'Studio',
'wz.studioAccounts': '{count} store accounts',
'wz.studioAccounts_one': '1 store account',
'wz.studioPicked': 'Selected',
'wz.studioNoneHint': 'Keep accounts without a studio',
'wz.studioNew': 'Create your studio',
'wz.studioAnother': 'Or create another studio',
'wz.studioNewText': 'A name and a colour; a logo can come later in Studios & accounts.',
'wz.studioPlaceholder': 'For example: Example Games',
'wz.studioCreate': 'Create studio',
'wz.fastlaneTitle': 'Import from fastlane',
'wz.fastlaneText': 'The folder has a fastlane setup (deliver, supply). storebound turns it into its config and listing files and leaves fastlane untouched.',
'wz.fastlaneGo': 'Choose the folder and import',
'wz.fastlaneNote': 'You see the import plan and what it does not map before anything is written.',
'wz.keysInto': 'New keys go into {name}.',
'wz.keysNoStudio': 'New keys stay without a studio.',
'wz.change': 'Change',
'crash.titleApp': 'storebound hit an error',
'crash.titleScreen': 'This screen hit an error',
'crash.leadApp': 'The window could not be shown. Your app folders, store keys and saved data are untouched. Reload usually fixes it; if it keeps happening, copy the details into a bug report.',
'crash.leadScreen': 'The rest of the app still works. Try again, reload the window, or copy the details into a bug report.',
'crash.details': 'Details',
'crash.copy': 'Copy details',
'crash.copied': 'Details copied.',
'crash.copyFailed': 'Could not copy: select the details and copy them by hand.',
'crash.retry': 'Try again',
'crash.reload': 'Reload',
'crash.reset': 'Reset saved state (keeps a backup)',
'crash.resetHint': 'Starts again from the machine\'s accounts and app folders. The saved state is kept as a backup file, store keys stay in ~/.storebound, app folders are not touched.',
'crash.resetDone': 'Saved state reset. Backup: {path}. Reloading…',
'crash.logNote': 'Also written to logs/webview.log in the app data folder (home folder shown as ~, no keys).',
'folder.missing': 'Folder not found.',
'folder.missingText': 'storebound cannot find this app folder at {path}. It may have been moved, renamed or deleted. Locate it to keep its accounts and saved reads, or remove it from the list (no files are touched).',
'folder.missingShort': 'Folder not found',
'folder.locate': 'Locate…',
'folder.locateHint': 'Pick the folder that now holds this app\'s storebound.config.ts',
'folder.located': '{name} found',
'folder.locateFailed': 'Could not use that folder',
'folder.remove': 'Remove from list',
'folder.removed': '{name} removed from the list',
'cf.button': 'Fill in console',
'cf.hint': 'Fill in {form} in the console from your config: you review every field and press Save yourself',
'cf.appleAppRecord': 'App Store app record',
'cf.appleAgeRating': 'App Store age rating',
'cf.appleAppPrivacy': 'App Privacy',
'cf.playContentRating': 'Play content rating',
'cf.playTargetAudience': 'Play target audience and content',
'cf.playAppRecord': 'Play app (Create app)',
'cf.dryFailed': 'Could not prepare {form}',
'cf.panelTitle': 'Fill in console: {form}',
'cf.disclaimer': 'Console pages change. This is AI-assisted: review every field in the browser and press the final button (Publish, Submit, Save or Create) yourself. storebound moves through the pages for you and never submits or publishes; App Privacy answers stay a draft until you press Publish.',
'cf.notOpened': 'You chose Cancel in the dialog: no browser was opened.',
'cf.runningText': 'The browser is open with storebound\'s own profile (the first time, sign in there yourself; it is kept for the next runs). storebound opens the form, fills the fields and marks the ones you answer. Review every field, press Save yourself, then close the browser.',
'cf.doneText': 'Browser closed. Filled: {filled}, marked for you: {highlighted}. Check in the console that your answers are saved.',
'cf.closed': 'Browser closed.',
'cf.cancelled': 'Stopped: the browser was closed.',
'cf.failed': 'The browser run stopped',
'cf.fallback': 'The page did not look as expected, so storebound only marked the fields. Enter the answers yourself.',
'cf.answers': '{count} answers from your config',
'cf.answers_one': '1 answer from your config',
'cf.uncertain': '{count} for you',
'cf.noAnswers': 'The config has no answers for this form: every field is yours.',
'cf.youAnswer': 'You answer this',
'cf.foot': 'A native dialog asks once more before the browser opens.',
'cf.cancelRun': 'Cancel: close the browser',
'cf.open': 'Open the browser',
'cf.waiting': 'Waiting until you close the browser',
'cf.playContentRatingText': 'The IARC questionnaire that gives the app its age ratings.',
'cf.playTargetAudienceText': 'Target age groups and whether the app appeals to children.',
'cf.playAppRecordText': 'The Play Developer API cannot create apps: storebound fills Create app (name, package name, language, app or game, free or paid). You tick the declarations and press Create app, then add the app to the service account.',
'cf.noRecordTitle': 'No App Store app record yet',
'cf.noRecordText': 'App Store Connect has no API to create the app record. storebound fills the New App form from your config; you press Create yourself, then put the Apple ID into apple.appId.',
// send for review, console plans, owner actions (desktop parity)
'write.declined': 'Waiting for your decision',
'toast.log': 'Log ({count} lines)',
'releases.ownerNote': 'Submitting, resubmitting and the production release are your decision: each shows its plan first, then a system dialog, and runs only after you press its button there. Releasing an approved App Store version (manual release) stays in App Store Connect.',
'oa.planFailed': 'Could not prepare: {what}',
'oa.notSent': 'You chose Cancel in the dialog: nothing was sent.',
'oa.dryChanged': 'The dry run did not pass this time (the store changed in between?): nothing was sent. Check the plan below.',
'oa.cancelled': 'Stopped. What the store already took stays; read the state again before you go on.',
'oa.dryBad': 'The dry run stopped',
'oa.plan': 'Plan (dry run, nothing sent yet)',
'oa.noOutput': '(the dry run printed nothing)',
'oa.running': 'Running. Apple can answer "not ready yet" for a few minutes after a build is attached; storebound retries with a heartbeat line, up to 10 minutes.',
'oa.progress': 'Progress',
'oa.foot': 'Next: a system dialog shows this plan again. Nothing is sent before you press its button.',
'oa.fixFirst': 'Fix what the plan names first, then read the state again.',
'oa.stop': 'Stop',
'oa.continue': 'Continue: {what}',
'oa.working': 'Working',
'cp.title': 'Console steps without an API',
'cp.sub': 'Each form as a plan your AI agent (or you) follows in the console, then a check of the result. The final button stays yours.',
'cp.button': 'Plan',
'cp.hint': 'The steps, answers and buttons for {form}, and a check of the result',
'cp.failed': 'Could not make the plan for {form}',
'cp.agentFirst': 'Agent-first: your AI agent drives the page with this plan; storebound never clicks the final button',
'cp.openPage': 'Open the page',
'cp.openFailed': 'Could not open the page',
'cp.steps': '{count} steps',
'cp.steps_one': '1 step',
'cp.answers': '{count} answers from your config',
'cp.answers_one': '1 answer from your config',
'cp.sCertain': 'From the config',
'cp.sAsk': 'You answer',
'cp.sCheck': 'You check',
'cp.sAgreement': 'Agreement: yours',
'cp.final': 'The final button ({button}) is yours. Never pressed by anyone else:',
'cp.verify': 'Check the result',
'cp.verifyApi': 'storebound reads the result from the App Store Connect API (read-only).',
'cp.verifyText': 'Paste the page text (or the capture JSON the plan names) after the form is saved; storebound compares it with the config (read-only).',
'cp.pasteLabel': 'Page text of the finished form',
'cp.pastePlaceholder': 'Paste the page text here',
'cp.verified': '{matched} match, {mismatches} differ',
'cp.vMatch': 'Match',
'cp.vMismatch': 'Differs',
'cp.vNotFound': 'Not found',
'cp.foot': 'Copy plan hands the whole plan (JSON) to your AI agent.',
'cp.copy': 'Copy plan',
'cp.copied': 'Plan copied',
'cp.verifyRun': 'Check',
'cp.appleAppRecordText': 'App Store Connect has no API to create the app record: the New App form, Create is yours.',
'cp.appleAgeRatingText': 'The age rating has an API (apple appinfo): the plan only shows where to look and how to check it.',
'cp.appleAppPrivacyText': 'No API: every data type with its purposes, linked and tracking answers; Publish is yours.',
'cp.playStoreSettings': 'Play store settings (App category)',
'cp.playStoreSettingsText': 'The Play API cannot set the App category: Edit > App or game > Category > Save.',
'cp.playAppContent': 'Play App content (every card)',
'cp.playAppContentText': 'Every App content card in order with its page, and the owner questions in one batch.',
'cp.playPrivacyPolicy': 'Play App content: privacy policy',
'cp.playAds': 'Play App content: ads',
'cp.playSignIn': 'Play App content: sign-in details',
'cp.playSignInText': 'The demo account for Google\'s reviewers: you type it (storebound never prints it).',
'cp.playAdId': 'Play App content: advertising ID',
'cp.playGovernment': 'Play App content: government apps',
'cp.playFinancial': 'Play App content: financial features',
'cp.playHealth': 'Play App content: health apps',
'cp.cardText': 'One App content card: its page, the answer from your config and the final Save.',
'cp.playCountries': 'Production countries',
'cp.playCountriesText': 'The API cannot set production countries (countryAvailability is read-only): pick them in the console.',
'cp.playProductionRelease': 'Play: send the production release for review',
'cp.playProductionReleaseText': 'Edit release > Next > Save, then Publishing overview. "Send changes for review" has no API: that click is yours.',
'sub.section': 'Send for review',
'sub.appleTitle': 'App Store: submit for review',
'sub.appleSub': 'Not read yet: read the submission state',
'sub.appleRead': 'App Store submission state',
'sub.read': 'Read state',
'sub.notRead': 'Submission state not read yet',
'sub.notReadText': 'Read the review submissions and the uploaded builds from App Store Connect (read-only) before you submit.',
'sub.submissions': 'Review submissions',
'sub.kWaiting': 'Waiting for review',
'sub.kInReview': 'In review',
'sub.kUnresolved': 'Back from App Review (unresolved issues)',
'sub.kDraft': 'Draft submission',
'sub.kEmptyDraft': 'Empty draft',
'sub.kDone': 'Done',
'sub.kOther': 'Submission',
'sub.harmless': 'harmless: App Store Connect keeps it and cannot cancel it; a later run reuses it',
'sub.markVersion': 'marked resolved when you resubmit with a new build',
'sub.markIap': 'marked resolved only with the box below, after you fixed what App Review asked for',
'sub.noOpen': 'No open review submission: a submit makes one.',
'sub.busy': 'A submission is {state}: nothing can be sent next to it until App Review is done.',
'sub.build': 'Build (by number)',
'sub.pickBuild': 'Pick the build you uploaded',
'sub.attachedTo': 'attached to {version}',
'sub.version': 'Version',
'sub.noVersion': 'No editable version',
'sub.buildHint': 'Only VALID builds can go in. Pick the number you uploaded: storebound never takes "the latest".',
'sub.noBuilds': 'No builds on App Store Connect yet: upload one first (storebound apple upload).',
'sub.unresolvedText': 'App Review sent this submission back. Fix what it asked for, upload a fixed build, pick it here and resubmit: the rejected version item is marked resolved and the same submission goes back.',
'sub.resolveIaps': 'Also mark rejected in-app purchase items resolved',
'sub.resolveIapsNeeded': '(an in-app purchase item is rejected: Apple takes no resubmit until it is resolved)',
'sub.resubmit': 'Resubmit',
'sub.resubmitted': 'Resubmitted to App Review',
'sub.resubmitLead': 'Attaches the build you picked, reuses the submission back from App Review (no second draft), marks the rejected items resolved and resubmits it.',
'sub.submit': 'Submit for review',
'sub.submitted': 'Sent to App Review',
'sub.submitLead': 'Attaches the build you picked to the version, reuses the open submission (a new draft only when none is open), adds the in-app purchases that are ready and sends it to App Review.',
'sub.pickFirst': 'Pick a build first',
'sub.iapTitle': 'In-app purchases ({count} in the config)',
'sub.iapTitle_one': 'In-app purchases (1 in the config)',
'sub.iapText': 'Sends the products and subscriptions that are ready to App Review. The first of a type needs the app version in the same submission.',
'sub.withVersion': 'With the editable app version (submits the app too)',
'sub.iapSubmit': 'Submit in-app purchases',
'sub.iapLead': 'Puts the ready products and subscriptions into the open review submission (reused, never a second draft) and submits it.',
'sub.playTitle': 'Google Play: production release',
'sub.playSub': 'Not read yet: read the tracks',
'sub.playRead': 'Google Play tracks',
'sub.playNotReadText': 'Read the tracks and their versionCodes from Google Play (read-only) before you send one to production.',
'sub.managedOff': 'Managed publishing is off: once Google approves the release it goes live by itself. To choose the moment, turn on Publishing overview > Managed publishing first.',
'sub.managedUnset': 'Managed publishing is off by default (play.managedPublishing is not set): once Google approves the release it goes live by itself.',
'sub.managedOn': 'Managed publishing is on: after approval you publish the release in Publishing overview.',
'sub.prodNow': 'Production now',
'sub.versionCode': 'versionCode (by number)',
'sub.pickCode': 'Pick the versionCode',
'sub.inProduction': 'in production',
'sub.as': 'Send as',
'sub.sCompleted': 'Everyone',
'sub.sStaged': 'Staged rollout',
'sub.sDraft': 'Draft',
'sub.codeHint': 'Only versionCodes already on Play (a testing track). Pick the one you uploaded: storebound never takes "the latest".',
'sub.noCodes': 'No versionCode on Play yet: upload the bundle to a testing track first.',
'sub.playSend': 'Send to production',
'sub.playDraft': 'Prepare a production draft',
'sub.pickCodeFirst': 'Pick a versionCode first',
'sub.playSent': 'Production release sent',
'sub.playDrafted': 'Production draft saved',
'sub.playLead': 'Puts the versionCode on the production track with the What\'s new of every language. Google reviews it; with managed publishing off it then goes live by itself.',
'sub.playDraftLead': 'A never-published app: Play takes only a draft through the API. The rest (countries, Send changes for review) is in the console steps below.',
'sub.sendChanges': 'Send changes for review',
'sub.consoleStepTitle': 'No API for these Play steps',
'sub.consoleStepText': 'Production countries ({countries}) and Publishing overview > "Send changes for review" have no API. Each has a plan: open the page, follow the steps, and press the final button yourself.',
'sub.countriesAll': 'config: all countries / regions',
'sub.countriesN': 'config: {count} countries',
'sub.countriesN_one': 'config: 1 country',
'tf.groupsSync': 'Create missing groups',
'tf.groupsSynced': 'TestFlight groups created',
'tf.groupsSyncHint': 'Creates the groups of apple.testflight.groups that are missing (existing ones are never changed); the dry run lists them first',
'act.priceProducts': 'Price changes (products)',
'act.priceSubs': 'Price changes (subscriptions)',
'act.priceDone': 'Price changes applied',
'act.priceLead': 'A normal sync never changes the price of a live product: it holds those back for you. This runs the same sync with the price changes, after the plan and your OK in the system dialog.',
'act.priceHint': 'Price changes of existing products are your decision: plan first, then a system dialog',
'deps.sdkTitle': 'Android SDK',
'deps.sdkSub': 'Where play build finds it: ANDROID_HOME, ANDROID_SDK_ROOT, sdk.dir in local.properties, then the Android Studio folder',
'deps.sdkPath': 'Folder',
'deps.sdkFrom': 'Found through',
'deps.sdkNone': 'Not found. play build needs it (install Android Studio, or set ANDROID_HOME). Checked:',
'ai.dsFrom': 'from {source}',
'ed.countAria': '{n} of {limit} characters',
'ed.unsavedField': 'Unsaved change',
'ed.was': 'Saved:',
'ed.empty': '(empty)',
'ed.removed': '(removed)',
'ed.reset': 'Reset',
'ed.notSet': 'Not set',
'ed.none': 'none',
'ed.notNumber': 'Not a number',
'ed.notJson': 'Not valid JSON: {error}',
'ed.noGit': 'Not a git folder',
'ed.gitClean': 'No uncommitted changes in these files',
'ed.gitDirty': 'Uncommitted in git: {files}. storebound never commits.',
'ed.also': 'the same section also serves {codes}',
'ed.newFile': 'new file',
'ed.masked': 'Personal data: not shown.',
'ed.unsaved': '{count} unsaved changes',
'ed.unsaved_one': '1 unsaved change',
'ed.noChanges': 'No unsaved changes',
'ed.undo': 'Undo',
'ed.redo': 'Redo',
'ed.discard': 'Discard',
'ed.review': 'Review and save',
'ed.close': 'Close',
'ed.fixFirst': 'Fix the errors first',
'ed.save': 'Save to the app folder',
'ed.saved': 'Saved to the app folder',
'ed.nothingToApply': 'Nothing to change on the store.',
'ed.applyNow': 'Apply to the store',
'ed.saveFirst': 'Save your edits first: the store gets what the files hold.',
'ed.statusDraft': 'Machine draft, not reviewed',
'ed.statusTranslate': 'Not translated yet',
'ed.alsoServes': 'also {codes}',
'ed.newSection': '{lang} has no section in the listing file yet. Fill in the required fields; saving adds the section.',
'ed.keywordsHint': 'Comma separated, no spaces after commas; do not repeat words from the name or subtitle.',
'ed.whatsNewApple': 'Not allowed on the first version.',
'ed.nameHint': 'Empty: the app name from the config.',
'ed.supportUrl': 'Support URL',
'ed.marketingUrl': 'Marketing URL',
'ed.privacyUrl': 'Privacy policy URL',
'ed.termsUrl': 'Terms of Use URL',
'ed.termsHint': 'Needed with subscriptions (Apple 3.1.2).',
'ed.website': 'Website',
'ed.websiteHint': 'Google Play: the domain that serves app-ads.txt.',
'ed.contactEmail': 'Contact email',
'ed.copyright': 'Copyright',
'ed.video': 'Promo video (YouTube URL)',
'ed.videoHint': 'Public or unlisted, ads off, embeddable. Play takes no video upload.',
'ed.listingTitle': 'Edit the listing',
'ed.listingSub': 'Per language, both stores side by side. Counters use the store limits; the checks of check and scan run as you type.',
'ed.pullPlay': 'Pull from Google Play',
'ed.pullApple': 'Pull from the App Store',
'ed.pulled': 'The listing file now matches the store',
'ed.pullHint': 'Reads the live texts and shows the diff before anything in the files changes.',
'ed.pullDirty': 'You have unsaved edits: they stay pending on top of the pulled text.',
'ed.pullNote': 'Pulling rewrites the listing files after a diff; your unsaved edits stay pending on top.',
'ed.playCode': 'Play language',
'ed.rtl': 'Right-to-left language.',
'ed.noStoreForLang': '{lang} is on neither store in the config.',
'ed.detailsTitle': 'Store details',
'ed.detailsSub': 'URLs, contact and copyright, shared by both stores (storebound.config.ts).',
'ed.applyTitle': 'Apply to the stores',
'ed.applySub': 'Each store: the dry run (old to new per language) in the window, then the confirm dialog, then the real run.',
'ed.applyPlay': 'Google Play listing: preview',
'ed.applyApple': 'App Store {version}: preview',
'ed.applyNote': 'Nothing goes to review: the texts wait in the store until you send the version or changes for review.',
'ed.appleInfoTitle': 'App Store app information',
'ed.appleInfoSub': 'Categories, content rights, price, export compliance and the App Store name.',
'ed.catPrimary': 'Primary category',
'ed.catSub1': 'Game subcategory 1',
'ed.catSub2': 'Game subcategory 2',
'ed.catSecondary': 'Secondary category',
'ed.free': 'Price',
'ed.freeHint': 'Free: available in every territory and new ones.',
'ed.encHint': 'Only you can answer this: export compliance skill.',
'ed.appleName': 'App Store name',
'ed.appleNameHint': 'When the app name is taken on the App Store.',
'ed.ageTitle': 'Age rating',
'ed.ageSub': 'Every question of the App Store declaration. Not set: the "nothing" answer.',
'ed.ageDefault': 'Default: {value}',
'ed.reviewSub': 'Sign-in, notes and contact for App Review. The demo account password is never shown.',
'ed.notesHint': 'App Store Connect takes at most {max} bytes.',
'ed.signInSteps': 'Sign-in steps for reviewers',
'ed.contact_firstName': 'Contact first name',
'ed.contact_lastName': 'Contact last name',
'ed.contact_phone': 'Contact phone',
'ed.contact_email': 'Contact email',
'ed.contactHint': 'Personal data: kept in the private .storebound/ folder (gitignored), shown masked. Type to replace.',
'ed.demoHint': 'The demo account lives only in the private .storebound/ folder; the window never reads the password.',
'ed.game': 'Game',
'ed.app': 'App',
'ed.playSettingsTitle': 'Google Play store settings',
'ed.playSettingsSub': 'Category, countries, managed publishing, target audience, delete-account page.',
'ed.playCategory': 'App category',
'ed.noApiHint': 'No API: the console plan step uses this value.',
'ed.managed': 'Managed publishing',
'ed.countries': 'Production countries',
'ed.countriesHint': 'Two-letter codes (US, GB, TR). Empty: all countries.',
'ed.targetAges': 'Target age groups',
'ed.targetAgesHint': 'Of {groups}.',
'ed.deletionUrl': 'Delete-account page',
'ed.declTitle': 'Data safety and App Privacy answers',
'ed.declSub': 'The answers both forms are filled from. Only you know them: change what the app and its SDKs really do.',
'ed.dsTypes': 'Data types (Play)',
'ed.dsTypesHint': 'Play data type id to usage: { "PSL_EMAIL": { "shared": false, "collect": ["account"] } }. Not listed: not collected.',
'ed.apAnswers': 'App Privacy (App Store)',
'ed.apHint': 'Checked with the whole config when you save; App Privacy has no API (console fill).',
'ed.promoTitle': 'App Store promotion',
'ed.promoSub': 'Promoted purchases, custom product pages and in-app events.',
'ed.promoted': 'Promoted in-app purchases',
'ed.promotedHint': 'Turning them on stays a terminal step (apple promoted --enable).',
'ed.cpp': 'Custom product pages',
'ed.cppHint': 'Submitting a page and making it visible stay terminal steps.',
'ed.events': 'In-app events',
'ed.eventsHint': 'Name 30, short 50, long 120 characters per locale. Sending to review stays a terminal step.',
'ed.applyCpp': 'Custom product pages: preview',
'ed.applyEvents': 'In-app events: preview',
'ed.applyInfoSub': 'App information, App Review, export compliance, Data safety and the Play app details.',
'ed.applyPlayDetails': 'Play contact email and website: preview',
'ed.playConsoleOnly': 'Category, countries and managed publishing have no API: App info > Console steps.',
'ed.itemName': 'Name',
'ed.itemDescription': 'Description',
'ed.benefits': 'Benefits (Play)',
'ed.benefitsHint': 'Comma separated, up to 4, 40 characters each.',
'ed.usd': 'Base price (USD)',
'ed.usdHint': 'A live product\'s new price waits for your decision (Apply the price changes).',
'ed.refName': 'Reference name',
'ed.reviewNote': 'Review note',
'ed.reviewShot': 'Review screenshot',
'ed.family': 'Family Sharing',
'ed.offerCodes': 'Offer codes',
'ed.offerCodesHint': 'Creating codes stays a terminal step (they work like vouchers).',
'ed.level': 'Level in the group',
'ed.levelHint': '1 = highest level of service.',
'ed.period': 'Period',
'ed.periodHint': 'Cannot change after the subscription is approved.',
'ed.intro': 'Introductory offer',
'ed.introHint': 'For example { "type": "free", "duration": "P1W" }.',
'ed.offers': 'Promotional offers',
'ed.winBack': 'Win-back offers',
'ed.winBackHint': 'Creating one stays a terminal step: it goes live by itself on its start date.',
'ed.catalogTitle': 'Edit the catalog',
'ed.catalogEmpty': 'No products or subscriptions in the config',
'ed.catalogEmptyText': 'Add them with the store-iap-setup or store-subscriptions skill.',
'ed.productsTitle': 'In-app products',
'ed.productsSub': 'Names, descriptions per language, price and review details.',
'ed.groupTitle': 'Subscription group {name}',
'ed.groupSub': 'Group display name per language and each subscription.',
'ed.groupName': 'Group display name',
'ed.applyCatalogSub': 'Each store: the dry run per product in the window, then the confirm dialog.',
'ed.applyPlayProducts': 'Play products: preview',
'ed.applyPlaySubs': 'Play subscriptions: preview',
'ed.applyAppleIap': 'App Store in-app purchases: preview',
'ed.applyAppleSubs': 'App Store subscriptions: preview',
'ed.applyIapReview': 'Review screenshots: preview',
'ed.priceGate': 'Price changes of live products are never applied here: they wait for your decision in the owner action.',
'ed.tfTitle': 'Edit TestFlight information',
'ed.tfSub': 'What to Test per locale, the beta description, notes for Beta App Review and the groups.',
'ed.whatToTest': 'What to Test',
'ed.whatToTestHint': 'Empty: the What\'s new text is used.',
'ed.betaDescription': 'Beta App Description',
'ed.betaDescriptionAll': 'Beta App Description (every locale)',
'ed.betaNotes': 'Notes for Beta App Review',
'ed.tfGroups': 'Beta groups',
'ed.tfGroupsHint': '[{ "name": "Studio team", "internal": true }]. Existing groups are never changed or deleted.',
'ed.applyTfSub': 'Test information and the missing groups. External testing and Beta App Review stay terminal steps.',
'ed.applyTfInfo': 'Test information: preview',
'ed.artTitle': 'Screenshot order and frames',
'ed.artSub': 'The stores show the screenshots in this order. Point a scene at another frame to replace its screenshot.',
'ed.artEmpty': 'No screenshot scenes in the config',
'ed.artEmptyText': 'Set up shots with the store-screenshots skill.',
'ed.frame': 'Frame',
'ed.up': 'Up',
'ed.down': 'Down',
'ed.moveUp': 'Move {id} up',
'ed.moveDown': 'Move {id} down',
'ed.applyArtSub': 'Render, then upload: an upload replaces the store\'s screenshot set (dry run first).',
'ed.loadFailed': 'Could not read the app folder\'s files: {error}',
} as const;