fix(i18n): translate updater failure messages shown in the renderer (#35833)

* fix(i18n): translate updater failure messages shown in the renderer

* fix(i18n): localize the dev-channel platform list and paired-server updater errors

* fix(i18n): sync runtime catalog and coded updater status expectations

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-29 02:00:52 -07:00
committed by GitHub
co-authored by OrcaWin
parent f06cc6e554
commit f8cf31797e
42 changed files with 827 additions and 119 deletions
+4 -12
View File
@@ -6,22 +6,14 @@ import {
} from './linux-package-update-recovery'
import { getLinuxPackageType } from './linux-update-package-type'
import type { LinuxPackageArtifact } from './linux-package-update-recovery'
export const LINUX_PACKAGE_MARKER_UNUSABLE_MESSAGE =
'Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.'
export const LINUX_PACKAGE_EXTERNALLY_MANAGED_MESSAGE =
'This copy of Orca is managed by your system package manager, so Orca cannot install updates itself. Update Orca through your distribution instead.'
export const LINUX_PACKAGE_MANUAL_INSTALL_MESSAGE =
'Quit Orca before running the system package install command.'
const PACKAGE_METADATA_UNUSABLE_MESSAGE =
'The downloaded package metadata could not be verified. Quit Orca before downloading and installing the update from the official release page.'
import { updaterCodedMessage } from '../shared/updater-failure-copy'
export function createLinuxPackageManualInstallStatus(
artifact: Pick<LinuxPackageArtifact, 'packageType' | 'version'>
): UpdateStatus {
return {
state: 'error',
message: LINUX_PACKAGE_MANUAL_INSTALL_MESSAGE,
...updaterCodedMessage('linuxPackageManualInstall'),
recovery: {
kind: 'linux-package-install',
packageType: artifact.packageType,
@@ -70,7 +62,7 @@ export function resolveLinuxPackageDownloadedStatus(info: {
clearTrackedLinuxPackageArtifact()
return {
state: 'error',
message: LINUX_PACKAGE_MARKER_UNUSABLE_MESSAGE,
...updaterCodedMessage('linuxPackageMarkerUnusable'),
version: info.version,
retryable: false
}
@@ -79,7 +71,7 @@ export function resolveLinuxPackageDownloadedStatus(info: {
if (!artifact) {
return {
state: 'error',
message: PACKAGE_METADATA_UNUSABLE_MESSAGE,
...updaterCodedMessage('linuxPackageMetadataUnusable'),
version: info.version,
retryable: false
}
+7
View File
@@ -198,6 +198,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
expect(context.sendStatus).toHaveBeenLastCalledWith({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType,
@@ -220,6 +221,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
state: 'error',
message:
'The downloaded package metadata could not be verified. Quit Orca before downloading and installing the update from the official release page.',
messageCode: 'linuxPackageMetadataUnusable',
version: '1.0.61',
retryable: false
}
@@ -261,6 +263,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
state: 'error',
message:
'Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.',
messageCode: 'linuxPackageMarkerUnusable',
version: '1.0.61',
retryable: false
})
@@ -292,6 +295,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
expect(context.sendStatus).toHaveBeenLastCalledWith({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType: 'deb',
@@ -314,6 +318,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
expect(context.sendStatus).toHaveBeenLastCalledWith({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType: 'deb',
@@ -391,6 +396,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
expect(context.sendStatus).toHaveBeenLastCalledWith({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType: 'deb',
@@ -446,6 +452,7 @@ describe('registerAutoUpdaterHandlers linux package artifact tracking', () => {
expect(context.sendStatus).toHaveBeenLastCalledWith({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType: 'deb',
@@ -108,6 +108,7 @@ const ARTIFACT = {
const MANUAL_INSTALL_STATUS = {
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType: 'deb',
+9 -21
View File
@@ -22,7 +22,7 @@ vi.mock('./git/gh-rate-limit-breaker', () => ({
recordGhPrimaryRateLimit: (...args: unknown[]) => recordRateLimitMock(...args)
}))
const { describeRateLimitReset, listReleaseBuilds, rateLimitResetAtMs, resolveTargetBuild } =
const { listReleaseBuilds, rateLimitResetAtMs, resolveTargetBuild } =
await import('./updater-release-builds')
function jsonResponse(
@@ -396,9 +396,13 @@ describe('listReleaseBuilds', () => {
})
)
await expect(listReleaseBuilds('hourly', 'darwin')).rejects.toThrow(
const failure = listReleaseBuilds('hourly', 'darwin')
await expect(failure).rejects.toThrow(
"GitHub rate limit reached. Try again in about 28 minutes, or run `gh auth login` so Orca can use your account's higher limit."
)
await expect(failure).rejects.toMatchObject({
coded: { messageCode: 'rateLimitedInMinutesSignedOut', messageParams: { count: 28 } }
})
})
it('omits the sign-in hint when the rate-limited request was authenticated', async () => {
@@ -407,9 +411,9 @@ describe('listReleaseBuilds', () => {
jsonResponse(null, { ok: false, status: 403, headers: { 'x-ratelimit-remaining': '0' } })
)
const failure = listReleaseBuilds('hourly', 'darwin')
await expect(failure).rejects.toThrow(/rate limit reached/)
await expect(failure).rejects.not.toThrow(/gh auth login/)
await expect(listReleaseBuilds('hourly', 'darwin')).rejects.toThrow(
/^GitHub rate limit reached\. Try again in a few minutes\.$/
)
})
it('treats 429 as a rate limit', async () => {
@@ -464,22 +468,6 @@ describe('rateLimitResetAtMs', () => {
})
})
describe('describeRateLimitReset', () => {
const nowMs = 1_800_000_000_000
it('falls back to a vague wait when the reset is unknown', () => {
expect(describeRateLimitReset(null, nowMs)).toBe('in a few minutes')
})
it('rounds a sub-minute reset up to a minute', () => {
expect(describeRateLimitReset(nowMs + 20_000, nowMs)).toBe('in about a minute')
})
it('rounds a partial minute up', () => {
expect(describeRateLimitReset(nowMs + 9 * 60_000 + 1, nowMs)).toBe('in about 10 minutes')
})
})
describe('resolveTargetBuild', () => {
it('pins an hourly tag at the hourly repo download path', () => {
expect(resolveTargetBuild('hourly', 'v1.4.160-hourly.202607281400')).toEqual({
+15 -13
View File
@@ -13,6 +13,7 @@ import { parseRetryAfterHeaderMs } from '../shared/retry-after-header'
import { getGhRateLimitBlockedUntilMs, recordGhPrimaryRateLimit } from './git/gh-rate-limit-breaker'
import { isValidVersion } from './updater-fallback'
import { rejectReleaseApiToken, resolveReleaseApiToken } from './updater-release-api-token'
import { UpdaterCodedError } from './updater/updater-coded-error'
const FETCH_TIMEOUT_MS = 8000
const MAX_LISTED_BUILDS = 100
@@ -60,12 +61,18 @@ export function rateLimitResetAtMs(headers: Headers, nowMs: number): number | nu
return resetEpochSeconds > 0 ? resetEpochSeconds * 1000 : null
}
export function describeRateLimitReset(resetAtMs: number | null, nowMs: number): string {
function rateLimitError(resetAtMs: number | null, nowMs: number, signedIn: boolean): Error {
if (resetAtMs === null) {
return 'in a few minutes'
return new UpdaterCodedError(signedIn ? 'rateLimitedSoon' : 'rateLimitedSoonSignedOut')
}
const minutes = Math.ceil((resetAtMs - nowMs) / 60_000)
return minutes <= 1 ? 'in about a minute' : `in about ${minutes} minutes`
if (minutes <= 1) {
return new UpdaterCodedError(signedIn ? 'rateLimitedInMinute' : 'rateLimitedInMinuteSignedOut')
}
return new UpdaterCodedError(
signedIn ? 'rateLimitedInMinutes' : 'rateLimitedInMinutesSignedOut',
{ count: minutes }
)
}
function releaseListError(
@@ -75,18 +82,13 @@ function releaseListError(
signedIn: boolean
): Error {
if (res.status === 404) {
return new Error(`No releases repository found at ${repo}.`)
return new UpdaterCodedError('releaseRepoNotFound', { repo })
}
if (isRateLimited(res)) {
const nowMs = Date.now()
const retry = describeRateLimitReset(rateLimitResetAtMs(res.headers, nowMs), nowMs)
return new Error(
signedIn
? `GitHub rate limit reached. Try again ${retry}.`
: `GitHub rate limit reached. Try again ${retry}, or run \`gh auth login\` so Orca can use your account's higher limit.`
)
return rateLimitError(rateLimitResetAtMs(res.headers, nowMs), nowMs, signedIn)
}
return new Error(`Could not list ${channel} builds (HTTP ${res.status}).`)
return new UpdaterCodedError('releaseListFailed', { channel, status: res.status })
}
export function getReleaseDownloadUrlForRepo(repo: string, tag: string): string {
@@ -180,7 +182,7 @@ export async function listReleaseBuilds(
}
const payload: unknown = await res.json()
if (!Array.isArray(payload)) {
throw new Error(`Could not read the ${channel} release list.`)
throw new UpdaterCodedError('releaseListUnreadable', { channel })
}
const builds = payload
.map((entry) => parseReleaseEntry(entry as GitHubReleaseEntry, repo, platform))
@@ -198,7 +200,7 @@ export type ResolvedTargetBuild = {
export function resolveTargetBuild(channel: ReleaseChannel, tag: string): ResolvedTargetBuild {
const version = normalizeTagToVersion(tag)
if (!isValidVersion(version)) {
throw new Error(`"${tag}" is not a valid release tag.`)
throw new UpdaterCodedError('invalidReleaseTag', { tag })
}
const repo = getReleaseRepoForChannel(channel)
return { tag, version, feedUrl: getReleaseDownloadUrlForRepo(repo, tag) }
@@ -67,6 +67,8 @@ describe('updater', () => {
expect(send).toHaveBeenCalledWith('updater:status', {
state: 'error',
message,
messageCode: 'channelUnsupportedPlatform',
messageParams: { channel: expect.any(String) },
userInitiated: true
})
expect(autoUpdaterMock.checkForUpdates).not.toHaveBeenCalled()
@@ -92,6 +94,8 @@ describe('updater', () => {
expect(send).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: expect.stringContaining('Download the installer from the release page'),
messageCode: 'unsignedDevChannel',
messageParams: { channel: 'Adhoc' },
userInitiated: true
})
expect(autoUpdaterMock.checkForUpdates).not.toHaveBeenCalled()
@@ -118,11 +122,13 @@ describe('updater', () => {
checkForUpdatesFromMenu({ channel, targetTag })
expect(send).not.toHaveBeenCalledWith('updater:status', {
state: 'error',
message: expect.stringContaining('Download the installer'),
userInitiated: true
})
expect(send).not.toHaveBeenCalledWith(
'updater:status',
expect.objectContaining({
state: 'error',
message: expect.stringContaining('Download the installer')
})
)
expect(autoUpdaterMock.allowDowngrade).toBe(true)
} finally {
platformSpy.mockRestore()
@@ -553,6 +559,7 @@ describe('updater', () => {
expect(sendMock).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -586,6 +593,7 @@ describe('updater', () => {
expect(sendMock).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
+1
View File
@@ -288,6 +288,7 @@ describe('updater check failure handling', () => {
expect(sendMock).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: RELEASE_NOT_READY_MESSAGE,
messageCode: 'releaseNotReady',
userInitiated: true
})
})
@@ -99,6 +99,7 @@ describe('updater externally managed Linux installs', () => {
expect(lastStatus(send)).toEqual({
state: 'error',
message: EXTERNALLY_MANAGED_MESSAGE,
messageCode: 'linuxPackageExternallyManaged',
version: '1.0.61',
retryable: false
})
@@ -114,6 +114,7 @@ describe('updater Linux root packages', () => {
expect(lastStatus(send)).toEqual({
state: 'error',
message: 'Quit Orca before running the system package install command.',
messageCode: 'linuxPackageManualInstall',
recovery: {
kind: 'linux-package-install',
packageType,
@@ -229,6 +230,7 @@ describe('updater Linux root packages', () => {
state: 'error',
message:
'Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.',
messageCode: 'linuxPackageMarkerUnusable',
version: '1.0.61',
retryable: false
})
@@ -105,6 +105,7 @@ describe('updater', () => {
expect(statuses).toContainEqual({
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -196,6 +197,7 @@ describe('updater', () => {
expect(statuses).toContainEqual({
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -347,6 +349,7 @@ describe('updater', () => {
expect(statuses.at(-1)).toEqual({
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -447,6 +450,7 @@ describe('updater', () => {
expect(statuses).toContainEqual({
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -661,6 +665,7 @@ describe('updater', () => {
expect(statuses).toContainEqual({
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -127,6 +127,7 @@ describe('updater', () => {
expect(sendMock).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
@@ -182,6 +183,7 @@ describe('updater', () => {
expect(sendMock).toHaveBeenCalledWith('updater:status', {
state: 'error',
message: "Couldn't reach the update server. Try again in a few minutes.",
messageCode: 'updateServerUnreachable',
userInitiated: true
})
})
+7 -4
View File
@@ -1,6 +1,5 @@
import { app } from 'electron'
import {
DEV_CHANNEL_PLATFORM_LABEL,
getVersionChannel,
hasDedicatedReleaseRepo,
isChannelSupportedOnPlatform,
@@ -14,6 +13,8 @@ import { profileStateBuildCompatibilityError } from '../../shared/profile-state-
import { listReleaseBuilds, resolveTargetBuild } from '../updater-release-builds'
import { ReleaseBuildListCache, type ReleaseBuildListOptions } from '../updater-release-build-cache'
import { UpdaterMenuChecks } from './updater-menu-checks'
import { updaterCodedMessage } from '../../shared/updater-failure-copy'
import { updaterErrorMessage } from './updater-coded-error'
export abstract class UpdaterBuildSelection extends UpdaterMenuChecks {
private readonly releaseBuildCache = new ReleaseBuildListCache((channel) =>
@@ -96,7 +97,9 @@ export abstract class UpdaterBuildSelection extends UpdaterMenuChecks {
if (!isChannelSupportedOnPlatform(channel, process.platform)) {
this.sendStatus({
state: 'error',
message: `${RELEASE_CHANNEL_LABELS[channel]} builds are produced only for ${DEV_CHANNEL_PLATFORM_LABEL}.`,
...updaterCodedMessage('channelUnsupportedPlatform', {
channel: RELEASE_CHANNEL_LABELS[channel]
}),
userInitiated: true
})
return
@@ -111,7 +114,7 @@ export abstract class UpdaterBuildSelection extends UpdaterMenuChecks {
) {
this.sendStatus({
state: 'error',
message: `${RELEASE_CHANNEL_LABELS[channel]} builds are unsigned, and this signed build only installs updates signed by Orca's publisher. Download the installer from the release page and run it once — updates work normally from there, including back to Stable.`,
...updaterCodedMessage('unsignedDevChannel', { channel: RELEASE_CHANNEL_LABELS[channel] }),
userInitiated: true
})
return
@@ -164,7 +167,7 @@ export abstract class UpdaterBuildSelection extends UpdaterMenuChecks {
this.restoreReleaseUpdateSource()
this.sendSettledCheckStatus({
state: 'error',
message: String((error as Error)?.message ?? error),
...updaterErrorMessage(error),
userInitiated: true
})
} finally {
+6 -3
View File
@@ -2,6 +2,7 @@ import { isBenignCheckFailure } from '../updater-fallback'
import { ReleaseFeedPreflightError } from './updater-state'
import type { CheckFailureSource } from './updater-state'
import { UpdaterReleaseFeed } from './updater-release-feed'
import { updaterCodedMessage } from '../../shared/updater-failure-copy'
export abstract class UpdaterCheckFailure extends UpdaterReleaseFeed {
protected isRetryableReleaseFeedPreflightFailure(sourceError: unknown): boolean {
@@ -81,9 +82,11 @@ export abstract class UpdaterCheckFailure extends UpdaterReleaseFeed {
// User clicks need visible feedback distinguishing incomplete releases from transport failure.
this.sendSettledCheckStatus({
state: 'error',
message: this.isStableReleaseNotReadyFailure(sourceError)
? "A newer release isn't available for this device yet. Check again later."
: "Couldn't reach the update server. Try again in a few minutes.",
...updaterCodedMessage(
this.isStableReleaseNotReadyFailure(sourceError)
? 'releaseNotReady'
: 'updateServerUnreachable'
),
userInitiated: true
})
} else {
+14 -3
View File
@@ -5,6 +5,7 @@ import { getRetainedLinuxPackageManualInstallStatus } from '../linux-package-dow
import type { UpdateCheckOptions, UpdateStatus } from '../../shared/update-status-types'
import type { UpdateCheckVariant } from './updater-types'
import { UpdaterStatus } from './updater-status'
import type { UpdaterCodedMessage } from '../../shared/updater-failure-copy'
import {
AUTO_UPDATE_CHECK_INTERVAL_MS,
AUTO_UPDATE_RETRY_INTERVAL_MS,
@@ -265,7 +266,9 @@ export abstract class UpdaterCheckState extends UpdaterStatus {
)
}
protected sendErrorStatus(message: string, userInitiated?: boolean): void {
protected sendErrorStatus(failure: string | UpdaterCodedMessage, userInitiated?: boolean): void {
const coded = typeof failure === 'string' ? { message: failure } : failure
const { message } = coded
if (
this.currentStatus.state === 'error' &&
this.currentStatus.message === message &&
@@ -280,7 +283,7 @@ export abstract class UpdaterCheckState extends UpdaterStatus {
message: 'Windows update signature check could not run'
})
}
this.sendStatus({ state: 'error', message, userInitiated })
this.sendStatus({ state: 'error', ...coded, userInitiated })
}
/** Retain the distro-package manual-install card when settling a check; ordinary status would erase it. */
@@ -289,7 +292,15 @@ export abstract class UpdaterCheckState extends UpdaterStatus {
if (retainedStatus) {
this.sendStatus(retainedStatus)
} else if (status.state === 'error') {
this.sendErrorStatus(status.message, status.userInitiated)
const { message, messageCode, messageParams } = status
this.sendErrorStatus(
{
message,
...(messageCode === undefined ? {} : { messageCode }),
...(messageParams === undefined ? {} : { messageParams })
},
status.userInitiated
)
} else {
this.sendStatus(status)
}
+22
View File
@@ -0,0 +1,22 @@
import {
updaterCodedMessage,
type UpdaterCodedMessage,
type UpdaterFailureCode,
type UpdaterFailureParams
} from '../../shared/updater-failure-copy'
import { errorMessage } from '../../shared/error-message'
/** Thrown inside main only; handlers copy its code onto the status or IPC result. */
export class UpdaterCodedError extends Error {
readonly coded: UpdaterCodedMessage
constructor(code: UpdaterFailureCode, params?: UpdaterFailureParams) {
const coded = updaterCodedMessage(code, params)
super(coded.message)
this.coded = coded
}
}
export function updaterErrorMessage(error: unknown): UpdaterCodedMessage {
return error instanceof UpdaterCodedError ? error.coded : { message: errorMessage(error) }
}
+2 -2
View File
@@ -6,7 +6,7 @@ import {
} from '../updater-mac-install'
import { recordUpdaterLifecycle } from '../updater-lifecycle-diagnostics'
import { isExternallyManagedLinuxInstall } from '../linux-update-package-type'
import { LINUX_PACKAGE_EXTERNALLY_MANAGED_MESSAGE } from '../linux-package-downloaded-status'
import { updaterCodedMessage } from '../../shared/updater-failure-copy'
import { QUIT_AND_INSTALL_DELAY_MS } from './updater-state'
import { UpdaterRemoteStatus } from './updater-remote-status'
import { prepareThisProcessShipItStaging } from './shipit-leftover-recovery'
@@ -83,7 +83,7 @@ export abstract class UpdaterDownloadInstall extends UpdaterRemoteStatus {
this.restoreReleaseUpdateSource()
this.sendStatus({
state: 'error',
message: LINUX_PACKAGE_EXTERNALLY_MANAGED_MESSAGE,
...updaterCodedMessage('linuxPackageExternallyManaged'),
version,
retryable: false
})
@@ -10,7 +10,7 @@ import { getMacUpdateRunningInstances } from '../macos-update-running-instances'
import { commitServeSupervisorPark } from './serve-supervisor-install-park'
import { armUpdateInstallExitWatchdog } from '../update-install-exit-watchdog'
import { getLinuxPackageType } from '../linux-update-package-type'
import { LINUX_PACKAGE_MARKER_UNUSABLE_MESSAGE } from '../linux-package-downloaded-status'
import { updaterCodedMessage } from '../../shared/updater-failure-copy'
import { recordUpdaterLifecycle } from '../updater-lifecycle-diagnostics'
import { requestServeUpdateHandoff, failServeUpdateHandoff } from '../serve-update-handoff'
import { UpdaterMacInstallPreflight } from './updater-mac-install-preflight'
@@ -54,7 +54,7 @@ export abstract class UpdaterInstallExecution extends UpdaterMacInstallPreflight
this.sendToMainWindow('updater:quitAndInstallAborted')
this.sendInstallFailureStatus({
state: 'error',
message: LINUX_PACKAGE_MARKER_UNUSABLE_MESSAGE,
...updaterCodedMessage('linuxPackageMarkerUnusable'),
...(pendingVersion ? { version: pendingVersion } : {})
})
return
+20 -19
View File
@@ -13,24 +13,25 @@ import type {
LinuxPackageInstallRecovery
} from '../../shared/update-status-types'
import { UpdaterInstallSupport } from './updater-install-support'
import {
updaterCodedMessage,
updaterFailureText,
type UpdaterFailureCode
} from '../../shared/updater-failure-copy'
const LINUX_PACKAGE_RECOVERY_MESSAGES: Record<LinuxPackageRecoveryUnavailableReason, string> = {
missing:
'The downloaded package is no longer in the update cache. Download the update again, or get it from the official release page.',
const LINUX_PACKAGE_RECOVERY_CODES: Record<
LinuxPackageRecoveryUnavailableReason,
UpdaterFailureCode
> = {
missing: 'linuxPackageMissing',
// Also covers traversal/symlink escape from cache; do not claim only file type changed.
'not-regular':
'The downloaded package is no longer a valid file in the update cache. Download the update again, or get it from the official release page.',
'hash-mismatch':
'The downloaded package no longer matches the verified release, so Orca will not hand it to a package manager. Download the update again, or get it from the official release page.',
'read-failed':
'Orca could not read the downloaded package. Download the update again, or get it from the official release page.',
'no-sudo':
'No sudo command was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.',
'no-package-manager':
'No supported package manager was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.',
'not-regular': 'linuxPackageNotRegular',
'hash-mismatch': 'linuxPackageHashMismatch',
'read-failed': 'linuxPackageReadFailed',
'no-sudo': 'linuxPackageNoSudo',
'no-package-manager': 'linuxPackageNoPackageManager',
// Capture tracks absolute cache paths; invalid paths indicate a bug.
'invalid-package-path':
'The downloaded package is not at a usable path, so Orca cannot build a safe install command. Show the package and install it with your package manager.'
'invalid-package-path': 'linuxPackageInvalidPath'
}
// Clear status recovery with the artifact or renderer actions stay enabled.
@@ -88,12 +89,12 @@ export abstract class UpdaterPackageRecovery extends UpdaterInstallSupport {
): never {
this.assertCurrentLinuxPackageRecovery(recovery, artifact)
this.recordLinuxPackageRecoveryUnavailable(recovery, reason)
const message = LINUX_PACKAGE_RECOVERY_MESSAGES[reason]
const coded = updaterCodedMessage(LINUX_PACKAGE_RECOVERY_CODES[reason])
if (RECOVERY_CLEARING_REASONS.includes(reason)) {
clearTrackedLinuxPackageArtifact()
this.sendStatus({ state: 'error', message, version: recovery.version })
this.sendStatus({ state: 'error', ...coded, version: recovery.version })
}
throw new Error(message)
throw new Error(coded.message)
}
protected async getLinuxPackageInstallInstructions(): Promise<LinuxPackageInstallInstructions> {
@@ -116,7 +117,7 @@ export abstract class UpdaterPackageRecovery extends UpdaterInstallSupport {
return {
ok: false,
reason: result.reason,
message: LINUX_PACKAGE_RECOVERY_MESSAGES[result.reason]
message: updaterFailureText(LINUX_PACKAGE_RECOVERY_CODES[result.reason])
}
}
this.failLinuxPackageRecovery(recovery, artifact, result.reason)
+4 -2
View File
@@ -6,6 +6,8 @@ import { isTrustedUIRenderer } from '../ipc/ui'
import type { Store } from '../persistence'
import { logStartupMilestone } from '../startup/startup-diagnostics'
import { applyProxyToElectronUpdaterSession } from '../updater/electron-updater-proxy-session'
import { updaterErrorMessage } from '../updater/updater-coded-error'
import { updaterCodedMessage } from '../../shared/updater-failure-copy'
import {
checkForUpdatesFromMenu,
dismissAvailableUpdate,
@@ -174,7 +176,7 @@ export function registerUpdaterHandlers(_store: Store): void {
options?: { force?: boolean }
): Promise<ReleaseBuildListResult> => {
if (!RELEASE_CHANNELS.includes(channel)) {
return { ok: false, channel, message: `Unknown release channel "${channel}".` }
return { ok: false, channel, ...updaterCodedMessage('unknownReleaseChannel', { channel }) }
}
try {
return {
@@ -184,7 +186,7 @@ export function registerUpdaterHandlers(_store: Store): void {
}
} catch (error) {
// Return expected network/rate-limit failures as data for the build picker.
return { ok: false, channel, message: String((error as Error)?.message ?? error) }
return { ok: false, channel, ...updaterErrorMessage(error) }
}
}
)
@@ -8,6 +8,7 @@ const { toastSuccess } = vi.hoisted(() => ({ toastSuccess: vi.fn() }))
vi.mock('sonner', () => ({ toast: { success: toastSuccess } }))
import { LinuxPackageInstallRecoveryCard } from './LinuxPackageInstallRecoveryCard'
import { UPDATER_FAILURE_COPY } from '../../../shared/updater-failure-copy'
const RELEASE_URL = 'https://github.com/stablyai/orca/releases/tag/v1.4.200'
const DIAGNOSTIC = 'pkexec: no polkit authentication agent found'
@@ -516,7 +517,7 @@ describe('LinuxPackageInstallRecoveryCard without a usable command', () => {
expect(screen.queryByRole('button', { name: 'Copy Install Command' })).toBeNull()
expect(button('Show Package').dataset.variant).toBe('default')
expect(footnoteText()).toBe(NO_PACKAGE_MANAGER.message)
expect(footnoteText()).toBe(UPDATER_FAILURE_COPY.linuxPackageNoPackageManager)
expect(screen.getByText(/Quit Orca before finishing the update/)).toBeTruthy()
fireEvent.click(button('Download Manually'))
@@ -534,7 +535,7 @@ describe('LinuxPackageInstallRecoveryCard without a usable command', () => {
fireEvent.click(button('Copy Install Command'))
await flushActions()
expect(footnoteText()).toBe('No sudo binary is available on this machine.')
expect(footnoteText()).toBe(UPDATER_FAILURE_COPY.linuxPackageNoSudo)
expect(button('Show Package').dataset.variant).toBe('default')
expect(button('Download Manually')).toBeTruthy()
})
@@ -6,6 +6,7 @@ import type {
} from '../../../shared/update-status-types'
import { UpdateErrorCardContent } from './UpdateErrorCardContent'
import { translate } from '@/i18n/i18n'
import { linuxPackageCommandUnavailableText } from '@/lib/updater-message-copy'
import { useMountedRef } from '@/hooks/useMountedRef'
function copiedNote(packageFileName: string): string {
@@ -91,7 +92,7 @@ export function LinuxPackageInstallRecoveryCard({
if (!instructions.ok) {
if (isCurrentRecovery()) {
setCommandUnavailable(true)
setActionError(instructions.message)
setActionError(linuxPackageCommandUnavailableText(instructions))
}
return
}
+2 -1
View File
@@ -6,6 +6,7 @@ import { useAppStore } from '../store'
import { Card } from './ui/card'
import { Button } from './ui/button'
import { translate } from '@/i18n/i18n'
import { updaterMessageText } from '@/lib/updater-message-copy'
import { UpdateCardStateContent } from './maintenance/update-card/UpdateCardStateContent'
import { buildUpdateCardErrorModel } from './maintenance/update-card/update-card-error-model'
import {
@@ -168,7 +169,7 @@ export function UpdateCard(): React.JSX.Element | null {
})
const linuxPackageRecovery =
status.state === 'error' && status.recovery?.kind === 'linux-package-install'
? { recovery: status.recovery, diagnostic: status.message }
? { recovery: status.recovery, diagnostic: updaterMessageText(status) }
: null
const handleDismissWithAnimation = (): void => {
if (prefersReducedMotion) {
@@ -7,6 +7,7 @@ import {
} from '../../../../../shared/updater-windows-signature-check'
import { getReleaseNotesUrlForVersion } from '../../../../../shared/release-channel'
import { translate } from '@/i18n/i18n'
import { updaterMessageText } from '@/lib/updater-message-copy'
import { isHttp2ProtocolError } from './update-card-visibility'
export function buildUpdateCardErrorModel({
@@ -51,12 +52,14 @@ export function buildUpdateCardErrorModel({
}
: null
}
// Raw checks below match the host's English; display text translates known codes.
const message = updaterMessageText(status)
if (status.installBlock && status.retryAction === 'install' && status.retryable !== false) {
return {
variant: 'waiting',
...getUpdateInstallBlockGuidance(status.installBlock),
blockers: status.installBlock.instances,
detail: status.message,
detail: message,
deferLabel: translate('updates.installBlock.later', 'Later'),
footnote: {
text: translate(
@@ -73,8 +76,8 @@ export function buildUpdateCardErrorModel({
if (status.retryAction === 'install' && status.retryable !== false) {
return {
title: translate('auto.components.UpdateCard.4cf109845a', 'Update Error'),
summary: status.message,
detail: status.message,
summary: message,
detail: message,
releaseUrl: getReleaseNotesUrlForVersion(cachedVersion),
primaryAction: {
label: translate('auto.components.UpdateCard.2c2d3e03ca', 'Try Again'),
@@ -96,7 +99,7 @@ export function buildUpdateCardErrorModel({
'auto.components.UpdateCard.d29740d175',
'The selected build could not be used.'
),
detail: status.message,
detail: message,
primaryAction: {
label: translate('auto.components.UpdateCard.37d45c9ec1', 'Choose Another Build'),
onClick: onChooseLocalBuild
@@ -115,7 +118,7 @@ export function buildUpdateCardErrorModel({
'auto.components.UpdateCard.90559b14e3',
'This turns on a process-wide Electron networking switch after restart. Use it for corporate VPNs or proxies that reject HTTP/2 update downloads.'
),
detail: compatibilitySetupError ?? status.message,
detail: compatibilitySetupError ?? message,
releaseUrl: getReleaseNotesUrlForVersion(cachedVersion),
primaryAction: {
label: translate('auto.components.UpdateCard.933c6fdf5b', 'Enable & Restart'),
@@ -133,7 +136,7 @@ export function buildUpdateCardErrorModel({
'auto.components.UpdateCard.092f09fc14',
"The installer's publisher doesn't match Orca, so we stopped the update. Don't install this download; check official releases for a corrected version."
),
detail: status.message,
detail: message,
releaseUrl: getReleaseNotesUrlForVersion(null),
manualLabel: translate('auto.components.UpdateCard.c9ff9b9ec2', 'Check official releases')
}
@@ -145,7 +148,7 @@ export function buildUpdateCardErrorModel({
'auto.components.UpdateCard.a05992a26b',
"The signature check couldn't run — usually because antivirus software blocked it. Retry the download, or get the installer from our official releases."
),
detail: status.message,
detail: message,
releaseUrl: getReleaseNotesUrlForVersion(cachedVersion),
primaryAction: {
label: translate('auto.components.UpdateCard.48565a32bc', 'Retry Download'),
@@ -159,14 +162,14 @@ export function buildUpdateCardErrorModel({
: translate('auto.components.UpdateCard.updateCheckFailed', 'Update Check Failed'),
summary:
cachedVersion && status.retryable === false
? status.message
? message
: cachedVersion
? translate(
'auto.components.UpdateCard.updateIncomplete',
'Could not complete the update.'
)
: translate('auto.components.UpdateCard.checkFailed', 'Could not check for updates.'),
detail: status.message,
detail: message,
releaseUrl: getReleaseNotesUrlForVersion(cachedVersion),
primaryAction:
cachedVersion && status.retryable !== false
@@ -8,6 +8,7 @@ import { Button } from '../ui/button'
import { SearchableSetting } from './SearchableSetting'
import { SettingsSubsectionHeader } from './SettingsFormControls'
import { translate } from '@/i18n/i18n'
import { updaterMessageText } from '@/lib/updater-message-copy'
import { getUpdateCheckClickOptions, getUpdateCheckHint } from '@/lib/update-check-click-options'
import { GeneralRemoteServerUpdates } from './GeneralRemoteServerUpdates'
import { ReleaseChannelSection } from './ReleaseChannelSection'
@@ -243,17 +244,17 @@ export function GeneralUpdateSettingsSection(): React.JSX.Element {
(updateStatus.installBlock
? getUpdateInstallBlockGuidance(updateStatus.installBlock).explainer
: updateStatus.recovery?.kind === 'linux-package-install'
? updateStatus.message
? updaterMessageText(updateStatus)
: updateVersionRef.current
? translate(
'auto.components.settings.GeneralUpdateSettingsSection.b9ad70c30d',
'Update error. {{value0}}',
{ value0: updateStatus.message }
{ value0: updaterMessageText(updateStatus) }
)
: translate(
'auto.components.settings.GeneralUpdateSettingsSection.bd79d412f0',
'Update check failed. {{value0}}',
{ value0: updateStatus.message }
{ value0: updaterMessageText(updateStatus) }
))}
</p>
</SearchableSetting>
@@ -8,6 +8,9 @@ import { ReleaseBuildPicker } from './ReleaseBuildPicker'
import { SettingsSegmentedControl, SettingsSubsectionHeader } from './SettingsFormControls'
import { Badge } from '../ui/badge'
import { translate } from '@/i18n/i18n'
import { updaterMessageText } from '@/lib/updater-message-copy'
import { errorMessage } from '../../../../shared/error-message'
import type { UpdaterCodedMessage } from '../../../../shared/updater-failure-copy'
import { getShortcutPlatform } from '@/lib/shortcut-platform'
import {
DEV_CHANNEL_PLATFORM_LABEL,
@@ -57,7 +60,7 @@ export function ReleaseChannelSection(): React.JSX.Element {
const [appVersion, setAppVersion] = useState<string | null>(null)
const [builds, setBuilds] = useState<ReleaseBuild[] | null>(null)
const [loadError, setLoadError] = useState<string | null>(null)
const [loadError, setLoadError] = useState<UpdaterCodedMessage | null>(null)
const [loading, setLoading] = useState(false)
const [selectedTag, setSelectedTag] = useState<string | null>(null)
@@ -102,14 +105,14 @@ export function ReleaseChannelSection(): React.JSX.Element {
setSelectedTag(result.builds[0]?.tag ?? null)
} else {
setBuilds(null)
setLoadError(result.message)
setLoadError(result)
}
} catch (error) {
if (isStale()) {
return
}
setBuilds(null)
setLoadError(String((error as Error)?.message ?? error))
setLoadError({ message: errorMessage(error) })
} finally {
// Only the newest request may clear loading; old completions must not flash No builds.
if (!isStale()) {
@@ -312,7 +315,7 @@ export function ReleaseChannelSection(): React.JSX.Element {
</p>
{loadError ? (
<p className="text-xs text-destructive">{loadError}</p>
<p className="text-xs text-destructive">{updaterMessageText(loadError)}</p>
) : needsManualInstall && selectedBuild ? (
<p className="text-xs text-muted-foreground">
{translate(
+32
View File
@@ -2346,6 +2346,38 @@
"count_other": "{{count}} running terminals"
}
},
"updates": {
"failure": {
"channelUnsupportedPlatform": "{{channel}} builds are produced only for macOS and Windows.",
"invalidReleaseTag": "\"{{tag}}\" is not a valid release tag.",
"linuxPackageExternallyManaged": "This copy of Orca is managed by your system package manager, so Orca cannot install updates itself. Update Orca through your distribution instead.",
"linuxPackageHashMismatch": "The downloaded package no longer matches the verified release, so Orca will not hand it to a package manager. Download the update again, or get it from the official release page.",
"linuxPackageInvalidPath": "The downloaded package is not at a usable path, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageManualInstall": "Quit Orca before running the system package install command.",
"linuxPackageMarkerUnusable": "Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.",
"linuxPackageMetadataUnusable": "The downloaded package metadata could not be verified. Quit Orca before downloading and installing the update from the official release page.",
"linuxPackageMissing": "The downloaded package is no longer in the update cache. Download the update again, or get it from the official release page.",
"linuxPackageNoPackageManager": "No supported package manager was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageNoSudo": "No sudo command was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageNotRegular": "The downloaded package is no longer a valid file in the update cache. Download the update again, or get it from the official release page.",
"linuxPackageReadFailed": "Orca could not read the downloaded package. Download the update again, or get it from the official release page.",
"rateLimitedInMinute": "GitHub rate limit reached. Try again in about a minute.",
"rateLimitedInMinuteSignedOut": "GitHub rate limit reached. Try again in about a minute, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinutesSignedOut_one": "GitHub rate limit reached. Try again in about {{count}} minute, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinutesSignedOut_other": "GitHub rate limit reached. Try again in about {{count}} minutes, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinutes_one": "GitHub rate limit reached. Try again in about {{count}} minute.",
"rateLimitedInMinutes_other": "GitHub rate limit reached. Try again in about {{count}} minutes.",
"rateLimitedSoon": "GitHub rate limit reached. Try again in a few minutes.",
"rateLimitedSoonSignedOut": "GitHub rate limit reached. Try again in a few minutes, or run `gh auth login` so Orca can use your account's higher limit.",
"releaseListFailed": "Could not list {{channel}} builds (HTTP {{status}}).",
"releaseListUnreadable": "Could not read the {{channel}} release list.",
"releaseNotReady": "A newer release isn't available for this device yet. Check again later.",
"releaseRepoNotFound": "No releases repository found at {{repo}}.",
"unknownReleaseChannel": "Unknown release channel \"{{channel}}\".",
"unsignedDevChannel": "{{channel}} builds are unsigned, and this signed build only installs updates signed by Orca's publisher. Download the installer from the release page and run it once — updates work normally from there, including back to Stable.",
"updateServerUnreachable": "Couldn't reach the update server. Try again in a few minutes."
}
},
"workspace": {
"links": {
"linkedCount_one": "{{count}} linked",
+31 -1
View File
@@ -21142,7 +21142,37 @@
"preparingAriaLabel": "Das Update wird vorbereitet. Zum Aufklappen klicken."
},
"wslMoveInstallHeld": "Ein Projekt wird auf seinen WSL-Host verschoben. Das Update nach Abschluss des Verschiebens installieren.",
"wslMoveUndoInstallHeld": "Ein Projekt wird von seinem WSL-Host zurückgeholt. Das Update danach installieren."
"wslMoveUndoInstallHeld": "Ein Projekt wird von seinem WSL-Host zurückgeholt. Das Update danach installieren.",
"failure": {
"releaseNotReady": "Für dieses Gerät ist noch keine neuere Version verfügbar. Später erneut prüfen.",
"updateServerUnreachable": "Der Update-Server konnte nicht erreicht werden. In einigen Minuten erneut versuchen.",
"channelUnsupportedPlatform": "{{channel}}-Builds werden nur für macOS und Windows erstellt.",
"unsignedDevChannel": "{{channel}}-Builds sind nicht signiert. Dieser signierte Build installiert nur Updates, die vom Herausgeber von Orca signiert wurden. Das Installationsprogramm von der Release-Seite herunterladen und einmal ausführen – danach funktionieren Updates wie gewohnt, auch zurück zu Stable.",
"linuxPackageMissing": "Das heruntergeladene Paket ist nicht mehr im Update-Cache vorhanden. Das Update erneut herunterladen oder von der offiziellen Release-Seite beziehen.",
"linuxPackageNotRegular": "Das heruntergeladene Paket ist im Update-Cache keine gültige Datei mehr. Das Update erneut herunterladen oder von der offiziellen Release-Seite beziehen.",
"linuxPackageHashMismatch": "Das heruntergeladene Paket stimmt nicht mehr mit der überprüften Version überein. Orca übergibt es daher nicht an eine Paketverwaltung. Das Update erneut herunterladen oder von der offiziellen Release-Seite beziehen.",
"linuxPackageReadFailed": "Orca konnte das heruntergeladene Paket nicht lesen. Das Update erneut herunterladen oder von der offiziellen Release-Seite beziehen.",
"linuxPackageNoSudo": "In den Systemverzeichnissen wurde kein sudo-Befehl gefunden. Orca kann daher keinen sicheren Installationsbefehl erstellen. Das Paket anzeigen und über die Paketverwaltung installieren.",
"linuxPackageNoPackageManager": "In den Systemverzeichnissen wurde keine unterstützte Paketverwaltung gefunden. Orca kann daher keinen sicheren Installationsbefehl erstellen. Das Paket anzeigen und über die Paketverwaltung installieren.",
"linuxPackageInvalidPath": "Das heruntergeladene Paket liegt nicht unter einem verwendbaren Pfad. Orca kann daher keinen sicheren Installationsbefehl erstellen. Das Paket anzeigen und über die Paketverwaltung installieren.",
"linuxPackageMarkerUnusable": "Orca konnte das Format des installierten Linux-Pakets nicht überprüfen und installiert dieses Update daher nicht automatisch. Das Update von der offiziellen Release-Seite herunterladen und manuell installieren.",
"linuxPackageExternallyManaged": "Diese Orca-Installation wird von der Paketverwaltung des Systems verwaltet. Orca kann Updates daher nicht selbst installieren. Orca stattdessen über die Distribution aktualisieren.",
"linuxPackageManualInstall": "Orca beenden, bevor der Systembefehl zur Paketinstallation ausgeführt wird.",
"linuxPackageMetadataUnusable": "Die Metadaten des heruntergeladenen Pakets konnten nicht überprüft werden. Orca beenden, bevor das Update von der offiziellen Release-Seite heruntergeladen und installiert wird.",
"unknownReleaseChannel": "Unbekannter Veröffentlichungskanal „{{channel}}“.",
"invalidReleaseTag": "„{{tag}}“ ist kein gültiges Release-Tag.",
"releaseRepoNotFound": "Unter {{repo}} wurde kein Release-Repository gefunden.",
"releaseListFailed": "{{channel}}-Builds konnten nicht aufgelistet werden (HTTP {{status}}).",
"releaseListUnreadable": "Die Release-Liste für {{channel}} konnte nicht gelesen werden.",
"rateLimitedSoon": "GitHub-Ratenlimit erreicht. In einigen Minuten erneut versuchen.",
"rateLimitedSoonSignedOut": "GitHub-Ratenlimit erreicht. In einigen Minuten erneut versuchen oder `gh auth login` ausführen, damit Orca das höhere Limit deines Kontos nutzen kann.",
"rateLimitedInMinute": "GitHub-Ratenlimit erreicht. In etwa einer Minute erneut versuchen.",
"rateLimitedInMinuteSignedOut": "GitHub-Ratenlimit erreicht. In etwa einer Minute erneut versuchen oder `gh auth login` ausführen, damit Orca das höhere Limit deines Kontos nutzen kann.",
"rateLimitedInMinutes_one": "GitHub-Ratenlimit erreicht. In etwa {{count}} Minute erneut versuchen.",
"rateLimitedInMinutes_other": "GitHub-Ratenlimit erreicht. In etwa {{count}} Minuten erneut versuchen.",
"rateLimitedInMinutesSignedOut_one": "GitHub-Ratenlimit erreicht. In etwa {{count}} Minute erneut versuchen oder `gh auth login` ausführen, damit Orca das höhere Limit deines Kontos nutzen kann.",
"rateLimitedInMinutesSignedOut_other": "GitHub-Ratenlimit erreicht. In etwa {{count}} Minuten erneut versuchen oder `gh auth login` ausführen, damit Orca das höhere Limit deines Kontos nutzen kann."
}
},
"jira": {
"connect": {
+31 -1
View File
@@ -21563,7 +21563,37 @@
"preparingAriaLabel": "Preparing update. Click to expand."
},
"wslMoveInstallHeld": "A project is moving to its WSL host. Install the update once the move finishes.",
"wslMoveUndoInstallHeld": "A project is coming back from its WSL host. Install the update once that finishes."
"wslMoveUndoInstallHeld": "A project is coming back from its WSL host. Install the update once that finishes.",
"failure": {
"releaseNotReady": "A newer release isn't available for this device yet. Check again later.",
"updateServerUnreachable": "Couldn't reach the update server. Try again in a few minutes.",
"channelUnsupportedPlatform": "{{channel}} builds are produced only for macOS and Windows.",
"unsignedDevChannel": "{{channel}} builds are unsigned, and this signed build only installs updates signed by Orca's publisher. Download the installer from the release page and run it once — updates work normally from there, including back to Stable.",
"linuxPackageMissing": "The downloaded package is no longer in the update cache. Download the update again, or get it from the official release page.",
"linuxPackageNotRegular": "The downloaded package is no longer a valid file in the update cache. Download the update again, or get it from the official release page.",
"linuxPackageHashMismatch": "The downloaded package no longer matches the verified release, so Orca will not hand it to a package manager. Download the update again, or get it from the official release page.",
"linuxPackageReadFailed": "Orca could not read the downloaded package. Download the update again, or get it from the official release page.",
"linuxPackageNoSudo": "No sudo command was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageNoPackageManager": "No supported package manager was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageInvalidPath": "The downloaded package is not at a usable path, so Orca cannot build a safe install command. Show the package and install it with your package manager.",
"linuxPackageMarkerUnusable": "Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.",
"linuxPackageExternallyManaged": "This copy of Orca is managed by your system package manager, so Orca cannot install updates itself. Update Orca through your distribution instead.",
"linuxPackageManualInstall": "Quit Orca before running the system package install command.",
"linuxPackageMetadataUnusable": "The downloaded package metadata could not be verified. Quit Orca before downloading and installing the update from the official release page.",
"unknownReleaseChannel": "Unknown release channel \"{{channel}}\".",
"invalidReleaseTag": "\"{{tag}}\" is not a valid release tag.",
"releaseRepoNotFound": "No releases repository found at {{repo}}.",
"releaseListFailed": "Could not list {{channel}} builds (HTTP {{status}}).",
"releaseListUnreadable": "Could not read the {{channel}} release list.",
"rateLimitedSoon": "GitHub rate limit reached. Try again in a few minutes.",
"rateLimitedSoonSignedOut": "GitHub rate limit reached. Try again in a few minutes, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinute": "GitHub rate limit reached. Try again in about a minute.",
"rateLimitedInMinuteSignedOut": "GitHub rate limit reached. Try again in about a minute, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinutes_one": "GitHub rate limit reached. Try again in about {{count}} minute.",
"rateLimitedInMinutes_other": "GitHub rate limit reached. Try again in about {{count}} minutes.",
"rateLimitedInMinutesSignedOut_one": "GitHub rate limit reached. Try again in about {{count}} minute, or run `gh auth login` so Orca can use your account's higher limit.",
"rateLimitedInMinutesSignedOut_other": "GitHub rate limit reached. Try again in about {{count}} minutes, or run `gh auth login` so Orca can use your account's higher limit."
}
},
"jira": {
"connect": {
+33 -1
View File
@@ -21805,7 +21805,39 @@
"browserGuidance": "Finaliza el proceso que aparece abajo y vuelve a intentarlo: su servidor seguirá funcionando sin navegador. Si otro equipo usa este Mac como host SSH, actualiza Orca en ese equipo para que el navegador pueda pausarse automáticamente durante las actualizaciones."
},
"wslMoveInstallHeld": "Un proyecto se está moviendo a su host WSL. Instala la actualización cuando termine el movimiento.",
"wslMoveUndoInstallHeld": "Un proyecto está volviendo desde su host WSL. Instala la actualización cuando termine."
"wslMoveUndoInstallHeld": "Un proyecto está volviendo desde su host WSL. Instala la actualización cuando termine.",
"failure": {
"releaseNotReady": "Aún no hay una versión más reciente disponible para este dispositivo. Vuelve a comprobarlo más tarde.",
"updateServerUnreachable": "No se pudo contactar con el servidor de actualizaciones. Vuelve a intentarlo en unos minutos.",
"channelUnsupportedPlatform": "Las versiones de {{channel}} se generan solo para macOS y Windows.",
"unsignedDevChannel": "Las versiones de {{channel}} no están firmadas y esta versión firmada solo instala actualizaciones firmadas por el editor de Orca. Descarga el instalador desde la página de versiones y ejecútalo una vez; después, las actualizaciones funcionarán con normalidad, incluso para volver a Stable.",
"linuxPackageMissing": "El paquete descargado ya no está en la caché de actualizaciones. Descarga la actualización de nuevo u obtenla en la página oficial de versiones.",
"linuxPackageNotRegular": "El paquete descargado ya no es un archivo válido en la caché de actualizaciones. Descarga la actualización de nuevo u obtenla en la página oficial de versiones.",
"linuxPackageHashMismatch": "El paquete descargado ya no coincide con la versión verificada, por lo que Orca no lo entregará a un gestor de paquetes. Descarga la actualización de nuevo u obtenla en la página oficial de versiones.",
"linuxPackageReadFailed": "Orca no pudo leer el paquete descargado. Descarga la actualización de nuevo u obtenla en la página oficial de versiones.",
"linuxPackageNoSudo": "No se encontró el comando sudo en los directorios del sistema, por lo que Orca no puede generar un comando de instalación seguro. Muestra el paquete e instálalo con tu gestor de paquetes.",
"linuxPackageNoPackageManager": "No se encontró ningún gestor de paquetes compatible en los directorios del sistema, por lo que Orca no puede generar un comando de instalación seguro. Muestra el paquete e instálalo con tu gestor de paquetes.",
"linuxPackageInvalidPath": "El paquete descargado no está en una ruta utilizable, por lo que Orca no puede generar un comando de instalación seguro. Muestra el paquete e instálalo con tu gestor de paquetes.",
"linuxPackageMarkerUnusable": "Orca no pudo verificar el formato del paquete de Linux instalado, por lo que no instalará esta actualización automáticamente. Descarga la actualización desde la página oficial de versiones e instálala manualmente.",
"linuxPackageExternallyManaged": "El gestor de paquetes del sistema administra esta copia de Orca, por lo que Orca no puede instalar actualizaciones por sí mismo. Actualiza Orca a través de tu distribución.",
"linuxPackageManualInstall": "Sal de Orca antes de ejecutar el comando de instalación de paquetes del sistema.",
"linuxPackageMetadataUnusable": "No se pudieron verificar los metadatos del paquete descargado. Sal de Orca antes de descargar e instalar la actualización desde la página oficial de versiones.",
"unknownReleaseChannel": "Canal de lanzamiento desconocido «{{channel}}».",
"invalidReleaseTag": "«{{tag}}» no es una etiqueta de versión válida.",
"releaseRepoNotFound": "No se encontró ningún repositorio de versiones en {{repo}}.",
"releaseListFailed": "No se pudieron listar las versiones de {{channel}} (HTTP {{status}}).",
"releaseListUnreadable": "No se pudo leer la lista de versiones de {{channel}}.",
"rateLimitedSoon": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en unos minutos.",
"rateLimitedSoonSignedOut": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en unos minutos o ejecuta `gh auth login` para que Orca pueda usar el límite más alto de tu cuenta.",
"rateLimitedInMinute": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente un minuto.",
"rateLimitedInMinuteSignedOut": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente un minuto o ejecuta `gh auth login` para que Orca pueda usar el límite más alto de tu cuenta.",
"rateLimitedInMinutes_one": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minuto.",
"rateLimitedInMinutes_other": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minutos.",
"rateLimitedInMinutes_many": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minutos.",
"rateLimitedInMinutesSignedOut_one": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minuto o ejecuta `gh auth login` para que Orca pueda usar el límite más alto de tu cuenta.",
"rateLimitedInMinutesSignedOut_other": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minutos o ejecuta `gh auth login` para que Orca pueda usar el límite más alto de tu cuenta.",
"rateLimitedInMinutesSignedOut_many": "Se alcanzó el límite de velocidad de GitHub. Inténtalo de nuevo en aproximadamente {{count}} minutos o ejecuta `gh auth login` para que Orca pueda usar el límite más alto de tu cuenta."
}
},
"jira": {
"savedFilters": {
+33 -1
View File
@@ -21899,7 +21899,39 @@
"browserGuidance": "Terminez le processus ci-dessous, puis réessayez : son serveur continue de fonctionner sans navigateur. Si un autre ordinateur utilise ce Mac comme hôte SSH, la mise à jour d’Orca sur cet ordinateur permet au navigateur de se mettre automatiquement en pause lors des mises à jour."
},
"wslMoveInstallHeld": "Un projet est en cours de déplacement vers son hôte WSL. Installez la mise à jour une fois le déplacement terminé.",
"wslMoveUndoInstallHeld": "Un projet est en train de revenir de son hôte WSL. Installez la mise à jour une fois l'opération terminée."
"wslMoveUndoInstallHeld": "Un projet est en train de revenir de son hôte WSL. Installez la mise à jour une fois l'opération terminée.",
"failure": {
"releaseNotReady": "Aucune version plus récente n'est encore disponible pour cet appareil. Vérifiez à nouveau plus tard.",
"updateServerUnreachable": "Impossible de joindre le serveur de mise à jour. Réessayez dans quelques minutes.",
"channelUnsupportedPlatform": "Les versions {{channel}} sont produites uniquement pour macOS et Windows.",
"unsignedDevChannel": "Les versions {{channel}} ne sont pas signées, et cette version signée n'installe que les mises à jour signées par l'éditeur d'Orca. Téléchargez le programme d'installation depuis la page des versions et exécutez-le une fois. Les mises à jour fonctionneront ensuite normalement, y compris pour revenir à Stable.",
"linuxPackageMissing": "Le package téléchargé n'est plus dans le cache des mises à jour. Téléchargez à nouveau la mise à jour ou récupérez-la sur la page officielle des versions.",
"linuxPackageNotRegular": "Le package téléchargé n'est plus un fichier valide dans le cache des mises à jour. Téléchargez à nouveau la mise à jour ou récupérez-la sur la page officielle des versions.",
"linuxPackageHashMismatch": "Le package téléchargé ne correspond plus à la version vérifiée. Orca ne le transmettra donc pas à un gestionnaire de packages. Téléchargez à nouveau la mise à jour ou récupérez-la sur la page officielle des versions.",
"linuxPackageReadFailed": "Orca n'a pas pu lire le package téléchargé. Téléchargez à nouveau la mise à jour ou récupérez-la sur la page officielle des versions.",
"linuxPackageNoSudo": "La commande sudo est introuvable dans les répertoires système. Orca ne peut donc pas générer de commande d'installation sûre. Affichez le package et installez-le avec votre gestionnaire de packages.",
"linuxPackageNoPackageManager": "Aucun gestionnaire de packages pris en charge n'a été trouvé dans les répertoires système. Orca ne peut donc pas générer de commande d'installation sûre. Affichez le package et installez-le avec votre gestionnaire de packages.",
"linuxPackageInvalidPath": "Le chemin du package téléchargé n'est pas utilisable. Orca ne peut donc pas générer de commande d'installation sûre. Affichez le package et installez-le avec votre gestionnaire de packages.",
"linuxPackageMarkerUnusable": "Orca n'a pas pu vérifier le format du package Linux installé et n'installera donc pas cette mise à jour automatiquement. Téléchargez la mise à jour depuis la page officielle des versions et installez-la manuellement.",
"linuxPackageExternallyManaged": "Cette copie d'Orca est gérée par votre gestionnaire de packages système. Orca ne peut donc pas installer les mises à jour lui-même. Mettez plutôt Orca à jour via votre distribution.",
"linuxPackageManualInstall": "Quittez Orca avant d'exécuter la commande système d'installation de packages.",
"linuxPackageMetadataUnusable": "Les métadonnées du package téléchargé n'ont pas pu être vérifiées. Quittez Orca avant de télécharger et d'installer la mise à jour depuis la page officielle des versions.",
"unknownReleaseChannel": "Canal de publication inconnu « {{channel}} ».",
"invalidReleaseTag": "« {{tag}} » n'est pas un tag de version valide.",
"releaseRepoNotFound": "Aucun dépôt de versions trouvé à l'adresse {{repo}}.",
"releaseListFailed": "Impossible de lister les versions {{channel}} (HTTP {{status}}).",
"releaseListUnreadable": "Impossible de lire la liste des versions {{channel}}.",
"rateLimitedSoon": "Limite de débit GitHub atteinte. Réessayez dans quelques minutes.",
"rateLimitedSoonSignedOut": "Limite de débit GitHub atteinte. Réessayez dans quelques minutes ou exécutez `gh auth login` pour qu'Orca puisse utiliser la limite plus élevée de votre compte.",
"rateLimitedInMinute": "Limite de débit GitHub atteinte. Réessayez dans environ une minute.",
"rateLimitedInMinuteSignedOut": "Limite de débit GitHub atteinte. Réessayez dans environ une minute ou exécutez `gh auth login` pour qu'Orca puisse utiliser la limite plus élevée de votre compte.",
"rateLimitedInMinutes_one": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minute.",
"rateLimitedInMinutes_other": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minutes.",
"rateLimitedInMinutes_many": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minutes.",
"rateLimitedInMinutesSignedOut_one": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minute ou exécutez `gh auth login` pour qu'Orca puisse utiliser la limite plus élevée de votre compte.",
"rateLimitedInMinutesSignedOut_other": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minutes ou exécutez `gh auth login` pour qu'Orca puisse utiliser la limite plus élevée de votre compte.",
"rateLimitedInMinutesSignedOut_many": "Limite de débit GitHub atteinte. Réessayez dans environ {{count}} minutes ou exécutez `gh auth login` pour qu'Orca puisse utiliser la limite plus élevée de votre compte."
}
},
"onboarding": {
"language": {
+29 -1
View File
@@ -21233,7 +21233,35 @@
"browserSummary": "バックグラウンド Orca サーバーのブラウザはまだこのアプリを使用しています。"
},
"wslMoveInstallHeld": "プロジェクトを WSL ホストへ移動しています。移動が完了してからアップデートをインストールしてください。",
"wslMoveUndoInstallHeld": "プロジェクトを WSL ホストから戻しています。完了してからアップデートをインストールしてください。"
"wslMoveUndoInstallHeld": "プロジェクトを WSL ホストから戻しています。完了してからアップデートをインストールしてください。",
"failure": {
"releaseNotReady": "このデバイス向けの新しいリリースはまだ利用できません。後でもう一度確認してください。",
"updateServerUnreachable": "更新サーバーに接続できませんでした。数分後にもう一度お試しください。",
"channelUnsupportedPlatform": "{{channel}} ビルドは macOS と Windows 向けにのみ提供されます。",
"unsignedDevChannel": "{{channel}} ビルドは未署名で、この署名済みビルドでは Orca の発行元が署名した更新のみをインストールできます。リリースページからインストーラーをダウンロードして一度実行してください。その後は Stable に戻す場合も含め、通常どおり更新できます。",
"linuxPackageMissing": "ダウンロードしたパッケージが更新キャッシュにありません。更新を再ダウンロードするか、公式リリースページから入手してください。",
"linuxPackageNotRegular": "更新キャッシュ内のダウンロード済みパッケージが有効なファイルではなくなっています。更新を再ダウンロードするか、公式リリースページから入手してください。",
"linuxPackageHashMismatch": "ダウンロードしたパッケージが検証済みリリースと一致しなくなったため、Orca はパッケージマネージャーに渡しません。更新を再ダウンロードするか、公式リリースページから入手してください。",
"linuxPackageReadFailed": "Orca はダウンロードしたパッケージを読み取れませんでした。更新を再ダウンロードするか、公式リリースページから入手してください。",
"linuxPackageNoSudo": "システムディレクトリに sudo コマンドが見つからないため、Orca は安全なインストールコマンドを生成できません。パッケージを表示し、パッケージマネージャーでインストールしてください。",
"linuxPackageNoPackageManager": "システムディレクトリに対応するパッケージマネージャーが見つからないため、Orca は安全なインストールコマンドを生成できません。パッケージを表示し、パッケージマネージャーでインストールしてください。",
"linuxPackageInvalidPath": "ダウンロードしたパッケージのパスを使用できないため、Orca は安全なインストールコマンドを生成できません。パッケージを表示し、パッケージマネージャーでインストールしてください。",
"linuxPackageMarkerUnusable": "Orca はインストール済み Linux パッケージの形式を確認できなかったため、この更新を自動インストールしません。公式リリースページから更新をダウンロードし、手動でインストールしてください。",
"linuxPackageExternallyManaged": "この Orca はシステムのパッケージマネージャーで管理されているため、Orca 自体では更新をインストールできません。ディストリビューションの仕組みで Orca を更新してください。",
"linuxPackageManualInstall": "システムのパッケージインストールコマンドを実行する前に Orca を終了してください。",
"linuxPackageMetadataUnusable": "ダウンロードしたパッケージのメタデータを検証できませんでした。Orca を終了してから、公式リリースページから更新をダウンロードしてインストールしてください。",
"unknownReleaseChannel": "不明なリリースチャンネル「{{channel}}」。",
"invalidReleaseTag": "「{{tag}}」は有効なリリースタグではありません。",
"releaseRepoNotFound": "{{repo}} にリリース用リポジトリが見つかりません。",
"releaseListFailed": "{{channel}} ビルドの一覧を取得できませんでした(HTTP {{status}})。",
"releaseListUnreadable": "{{channel}} のリリース一覧を読み取れませんでした。",
"rateLimitedSoon": "GitHub のレート制限に達しました。数分後にもう一度お試しください。",
"rateLimitedSoonSignedOut": "GitHub のレート制限に達しました。数分後にもう一度試すか、`gh auth login` を実行して Orca がアカウントのより高い上限を利用できるようにしてください。",
"rateLimitedInMinute": "GitHub のレート制限に達しました。約 1 分後にもう一度お試しください。",
"rateLimitedInMinuteSignedOut": "GitHub のレート制限に達しました。約 1 分後にもう一度試すか、`gh auth login` を実行して Orca がアカウントのより高い上限を利用できるようにしてください。",
"rateLimitedInMinutes_other": "GitHub のレート制限に達しました。約 {{count}} 分後にもう一度お試しください。",
"rateLimitedInMinutesSignedOut_other": "GitHub のレート制限に達しました。約 {{count}} 分後にもう一度試すか、`gh auth login` を実行して Orca がアカウントのより高い上限を利用できるようにしてください。"
}
},
"onboarding": {
"language": {
+29 -1
View File
@@ -21233,7 +21233,35 @@
"browserGuidance": "아래 프로세스를 종료한 후 다시 시도하세요. 서버는 브라우저 없이 계속 실행됩니다. 다른 컴퓨터가 이 Mac을 SSH 호스트로 사용하는 경우 해당 컴퓨터의 Orca를 업데이트하면 업데이트 시 브라우저가 자동으로 일시 중지됩니다."
},
"wslMoveInstallHeld": "프로젝트를 WSL 호스트로 옮기는 중입니다. 이동이 끝난 후 업데이트를 설치하세요.",
"wslMoveUndoInstallHeld": "프로젝트를 WSL 호스트에서 다시 가져오는 중입니다. 완료된 후 업데이트를 설치하세요."
"wslMoveUndoInstallHeld": "프로젝트를 WSL 호스트에서 다시 가져오는 중입니다. 완료된 후 업데이트를 설치하세요.",
"failure": {
"releaseNotReady": "이 기기에서는 아직 새 릴리스를 사용할 수 없습니다. 나중에 다시 확인하세요.",
"updateServerUnreachable": "업데이트 서버에 연결할 수 없습니다. 몇 분 후 다시 시도하세요.",
"channelUnsupportedPlatform": "{{channel}} 빌드는 macOS 및 Windows용으로만 제공됩니다.",
"unsignedDevChannel": "{{channel}} 빌드는 서명되지 않았으며, 현재 서명된 빌드는 Orca 게시자가 서명한 업데이트만 설치합니다. 릴리스 페이지에서 설치 프로그램을 다운로드하여 한 번 실행하세요. 이후에는 Stable로 돌아가는 경우를 포함해 업데이트가 정상적으로 작동합니다.",
"linuxPackageMissing": "다운로드한 패키지가 업데이트 캐시에 더 이상 없습니다. 업데이트를 다시 다운로드하거나 공식 릴리스 페이지에서 받으세요.",
"linuxPackageNotRegular": "다운로드한 패키지가 업데이트 캐시에서 더 이상 유효한 파일이 아닙니다. 업데이트를 다시 다운로드하거나 공식 릴리스 페이지에서 받으세요.",
"linuxPackageHashMismatch": "다운로드한 패키지가 검증된 릴리스와 더 이상 일치하지 않아 Orca가 패키지 관리자에 전달하지 않습니다. 업데이트를 다시 다운로드하거나 공식 릴리스 페이지에서 받으세요.",
"linuxPackageReadFailed": "Orca가 다운로드한 패키지를 읽지 못했습니다. 업데이트를 다시 다운로드하거나 공식 릴리스 페이지에서 받으세요.",
"linuxPackageNoSudo": "시스템 디렉터리에서 sudo 명령을 찾지 못해 Orca가 안전한 설치 명령을 생성할 수 없습니다. 패키지를 표시하고 패키지 관리자로 설치하세요.",
"linuxPackageNoPackageManager": "시스템 디렉터리에서 지원되는 패키지 관리자를 찾지 못해 Orca가 안전한 설치 명령을 생성할 수 없습니다. 패키지를 표시하고 패키지 관리자로 설치하세요.",
"linuxPackageInvalidPath": "다운로드한 패키지가 사용 가능한 경로에 있지 않아 Orca가 안전한 설치 명령을 생성할 수 없습니다. 패키지를 표시하고 패키지 관리자로 설치하세요.",
"linuxPackageMarkerUnusable": "Orca가 설치된 Linux 패키지 형식을 확인하지 못해 이 업데이트를 자동으로 설치하지 않습니다. 공식 릴리스 페이지에서 업데이트를 다운로드하고 수동으로 설치하세요.",
"linuxPackageExternallyManaged": "이 Orca는 시스템 패키지 관리자가 관리하므로 Orca가 직접 업데이트를 설치할 수 없습니다. 배포판을 통해 Orca를 업데이트하세요.",
"linuxPackageManualInstall": "시스템 패키지 설치 명령을 실행하기 전에 Orca를 종료하세요.",
"linuxPackageMetadataUnusable": "다운로드한 패키지의 메타데이터를 검증할 수 없습니다. Orca를 종료한 후 공식 릴리스 페이지에서 업데이트를 다운로드하고 설치하세요.",
"unknownReleaseChannel": "알 수 없는 출시 채널 \"{{channel}}\"입니다.",
"invalidReleaseTag": "\"{{tag}}\"은(는) 유효한 릴리스 태그가 아닙니다.",
"releaseRepoNotFound": "{{repo}}에서 릴리스 저장소를 찾을 수 없습니다.",
"releaseListFailed": "{{channel}} 빌드 목록을 가져올 수 없습니다(HTTP {{status}}).",
"releaseListUnreadable": "{{channel}} 릴리스 목록을 읽을 수 없습니다.",
"rateLimitedSoon": "GitHub 속도 제한에 도달했습니다. 몇 분 후 다시 시도하세요.",
"rateLimitedSoonSignedOut": "GitHub 속도 제한에 도달했습니다. 몇 분 후 다시 시도하거나 `gh auth login`을 실행하여 Orca가 계정의 더 높은 한도를 사용할 수 있도록 하세요.",
"rateLimitedInMinute": "GitHub 속도 제한에 도달했습니다. 약 1분 후 다시 시도하세요.",
"rateLimitedInMinuteSignedOut": "GitHub 속도 제한에 도달했습니다. 약 1분 후 다시 시도하거나 `gh auth login`을 실행하여 Orca가 계정의 더 높은 한도를 사용할 수 있도록 하세요.",
"rateLimitedInMinutes_other": "GitHub 속도 제한에 도달했습니다. 약 {{count}}분 후 다시 시도하세요.",
"rateLimitedInMinutesSignedOut_other": "GitHub 속도 제한에 도달했습니다. 약 {{count}}분 후 다시 시도하거나 `gh auth login`을 실행하여 Orca가 계정의 더 높은 한도를 사용할 수 있도록 하세요."
}
},
"onboarding": {
"language": {
+33 -1
View File
@@ -21559,7 +21559,39 @@
"preparingAriaLabel": "Preparando atualização. Clique para expandir."
},
"wslMoveInstallHeld": "Um projeto está sendo movido para o host WSL dele. Instale a atualização quando a movimentação terminar.",
"wslMoveUndoInstallHeld": "Um projeto está voltando do host WSL dele. Instale a atualização quando isso terminar."
"wslMoveUndoInstallHeld": "Um projeto está voltando do host WSL dele. Instale a atualização quando isso terminar.",
"failure": {
"releaseNotReady": "Uma versão mais recente ainda não está disponível para este dispositivo. Verifique novamente mais tarde.",
"updateServerUnreachable": "Não foi possível acessar o servidor de atualização. Tente novamente em alguns minutos.",
"channelUnsupportedPlatform": "As builds {{channel}} são produzidas apenas para macOS e Windows.",
"unsignedDevChannel": "As builds {{channel}} não são assinadas, e esta build assinada só instala atualizações assinadas pelo publicador do Orca. Baixe o instalador na página de releases e execute-o uma vez — depois disso, as atualizações funcionam normalmente, inclusive para voltar ao Stable.",
"linuxPackageMissing": "O pacote baixado não está mais no cache de atualizações. Baixe a atualização novamente ou obtenha-a na página oficial de releases.",
"linuxPackageNotRegular": "O pacote baixado não é mais um arquivo válido no cache de atualizações. Baixe a atualização novamente ou obtenha-a na página oficial de releases.",
"linuxPackageHashMismatch": "O pacote baixado não corresponde mais ao release verificado, por isso o Orca não o encaminhará a um gerenciador de pacotes. Baixe a atualização novamente ou obtenha-a na página oficial de releases.",
"linuxPackageReadFailed": "O Orca não conseguiu ler o pacote baixado. Baixe a atualização novamente ou obtenha-a na página oficial de releases.",
"linuxPackageNoSudo": "O comando sudo não foi encontrado nos diretórios do sistema, por isso o Orca não pode gerar um comando de instalação seguro. Exiba o pacote e instale-o com seu gerenciador de pacotes.",
"linuxPackageNoPackageManager": "Nenhum gerenciador de pacotes compatível foi encontrado nos diretórios do sistema, por isso o Orca não pode gerar um comando de instalação seguro. Exiba o pacote e instale-o com seu gerenciador de pacotes.",
"linuxPackageInvalidPath": "O pacote baixado não está em um caminho utilizável, por isso o Orca não pode gerar um comando de instalação seguro. Exiba o pacote e instale-o com seu gerenciador de pacotes.",
"linuxPackageMarkerUnusable": "O Orca não conseguiu verificar o formato do pacote Linux instalado, por isso não instalará esta atualização automaticamente. Baixe a atualização na página oficial de releases e instale-a manualmente.",
"linuxPackageExternallyManaged": "Esta cópia do Orca é gerenciada pelo gerenciador de pacotes do sistema, por isso o Orca não pode instalar atualizações por conta própria. Atualize o Orca pela sua distribuição.",
"linuxPackageManualInstall": "Encerre o Orca antes de executar o comando de instalação de pacotes do sistema.",
"linuxPackageMetadataUnusable": "Não foi possível verificar os metadados do pacote baixado. Encerre o Orca antes de baixar e instalar a atualização pela página oficial de releases.",
"unknownReleaseChannel": "Canal de versão desconhecido \"{{channel}}\".",
"invalidReleaseTag": "\"{{tag}}\" não é uma tag de release válida.",
"releaseRepoNotFound": "Nenhum repositório de releases encontrado em {{repo}}.",
"releaseListFailed": "Não foi possível listar as builds {{channel}} (HTTP {{status}}).",
"releaseListUnreadable": "Não foi possível ler a lista de releases de {{channel}}.",
"rateLimitedSoon": "Limite de taxa do GitHub atingido. Tente novamente em alguns minutos.",
"rateLimitedSoonSignedOut": "Limite de taxa do GitHub atingido. Tente novamente em alguns minutos ou execute `gh auth login` para que o Orca possa usar o limite maior da sua conta.",
"rateLimitedInMinute": "Limite de taxa do GitHub atingido. Tente novamente em cerca de um minuto.",
"rateLimitedInMinuteSignedOut": "Limite de taxa do GitHub atingido. Tente novamente em cerca de um minuto ou execute `gh auth login` para que o Orca possa usar o limite maior da sua conta.",
"rateLimitedInMinutes_one": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minuto.",
"rateLimitedInMinutes_other": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minutos.",
"rateLimitedInMinutes_many": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minutos.",
"rateLimitedInMinutesSignedOut_one": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minuto ou execute `gh auth login` para que o Orca possa usar o limite maior da sua conta.",
"rateLimitedInMinutesSignedOut_other": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minutos ou execute `gh auth login` para que o Orca possa usar o limite maior da sua conta.",
"rateLimitedInMinutesSignedOut_many": "Limite de taxa do GitHub atingido. Tente novamente em cerca de {{count}} minutos ou execute `gh auth login` para que o Orca possa usar o limite maior da sua conta."
}
},
"jira": {
"connect": {
+35 -1
View File
@@ -21795,7 +21795,41 @@
"preparingAriaLabel": "Подготовка обновления. Нажмите, чтобы развернуть."
},
"wslMoveInstallHeld": "Проект переносится на свой хост WSL. Установите обновление, когда перенос завершится.",
"wslMoveUndoInstallHeld": "Проект возвращается со своего хоста WSL. Установите обновление, когда это завершится."
"wslMoveUndoInstallHeld": "Проект возвращается со своего хоста WSL. Установите обновление, когда это завершится.",
"failure": {
"releaseNotReady": "Более новый выпуск пока недоступен для этого устройства. Проверьте позже.",
"updateServerUnreachable": "Не удалось связаться с сервером обновлений. Повторите попытку через несколько минут.",
"channelUnsupportedPlatform": "Сборки {{channel}} выпускаются только для macOS и Windows.",
"unsignedDevChannel": "Сборки {{channel}} не подписаны, а эта подписанная сборка устанавливает только обновления с подписью издателя Orca. Скачайте установщик со страницы выпусков и запустите его один раз — после этого обновления будут работать как обычно, включая возврат на Stable.",
"linuxPackageMissing": "Загруженного пакета больше нет в кэше обновлений. Загрузите обновление ещё раз или получите его на официальной странице выпусков.",
"linuxPackageNotRegular": "Загруженный пакет больше не является допустимым файлом в кэше обновлений. Загрузите обновление ещё раз или получите его на официальной странице выпусков.",
"linuxPackageHashMismatch": "Загруженный пакет больше не соответствует проверенному выпуску, поэтому Orca не передаст его менеджеру пакетов. Загрузите обновление ещё раз или получите его на официальной странице выпусков.",
"linuxPackageReadFailed": "Orca не удалось прочитать загруженный пакет. Загрузите обновление ещё раз или получите его на официальной странице выпусков.",
"linuxPackageNoSudo": "Команда sudo не найдена в системных каталогах, поэтому Orca не может сформировать безопасную команду установки. Покажите пакет и установите его через менеджер пакетов.",
"linuxPackageNoPackageManager": "В системных каталогах не найден поддерживаемый менеджер пакетов, поэтому Orca не может сформировать безопасную команду установки. Покажите пакет и установите его через менеджер пакетов.",
"linuxPackageInvalidPath": "Путь к загруженному пакету непригоден для использования, поэтому Orca не может сформировать безопасную команду установки. Покажите пакет и установите его через менеджер пакетов.",
"linuxPackageMarkerUnusable": "Orca не удалось проверить формат установленного пакета Linux, поэтому это обновление не будет установлено автоматически. Загрузите обновление с официальной страницы выпусков и установите его вручную.",
"linuxPackageExternallyManaged": "Эта копия Orca управляется системным менеджером пакетов, поэтому Orca не может устанавливать обновления самостоятельно. Обновите Orca средствами вашего дистрибутива.",
"linuxPackageManualInstall": "Завершите работу Orca перед выполнением системной команды установки пакета.",
"linuxPackageMetadataUnusable": "Не удалось проверить метаданные загруженного пакета. Завершите работу Orca перед загрузкой и установкой обновления с официальной страницы выпусков.",
"unknownReleaseChannel": "Неизвестный канал выпусков «{{channel}}».",
"invalidReleaseTag": "«{{tag}}» не является допустимым тегом выпуска.",
"releaseRepoNotFound": "Репозиторий выпусков по адресу {{repo}} не найден.",
"releaseListFailed": "Не удалось получить список сборок {{channel}} (HTTP {{status}}).",
"releaseListUnreadable": "Не удалось прочитать список выпусков {{channel}}.",
"rateLimitedSoon": "Достигнут лимит запросов GitHub. Повторите попытку через несколько минут.",
"rateLimitedSoonSignedOut": "Достигнут лимит запросов GitHub. Повторите попытку через несколько минут или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи.",
"rateLimitedInMinute": "Достигнут лимит запросов GitHub. Повторите попытку примерно через минуту.",
"rateLimitedInMinuteSignedOut": "Достигнут лимит запросов GitHub. Повторите попытку примерно через минуту или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи.",
"rateLimitedInMinutes_one": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуту.",
"rateLimitedInMinutes_other": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуты.",
"rateLimitedInMinutesSignedOut_one": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуту или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи.",
"rateLimitedInMinutesSignedOut_other": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуты или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи.",
"rateLimitedInMinutes_few": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуты.",
"rateLimitedInMinutes_many": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минут.",
"rateLimitedInMinutesSignedOut_few": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минуты или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи.",
"rateLimitedInMinutesSignedOut_many": "Достигнут лимит запросов GitHub. Повторите попытку примерно через {{count}} минут или выполните `gh auth login`, чтобы Orca могла использовать более высокий лимит вашей учётной записи."
}
},
"jira": {
"connect": {
+31 -1
View File
@@ -21123,7 +21123,37 @@
"preparingAriaLabel": "Güncelleme hazırlanıyor. Genişletmek için tıklayın."
},
"wslMoveInstallHeld": "Bir proje WSL ana makinesine taşınıyor. Taşıma bittiğinde güncellemeyi yükleyin.",
"wslMoveUndoInstallHeld": "Bir proje WSL ana makinesinden geri getiriliyor. Bu bittiğinde güncellemeyi yükleyin."
"wslMoveUndoInstallHeld": "Bir proje WSL ana makinesinden geri getiriliyor. Bu bittiğinde güncellemeyi yükleyin.",
"failure": {
"releaseNotReady": "Bu cihaz için daha yeni bir sürüm henüz kullanıma sunulmadı. Daha sonra tekrar kontrol edin.",
"updateServerUnreachable": "Güncelleme sunucusuna ulaşılamadı. Birkaç dakika sonra tekrar deneyin.",
"channelUnsupportedPlatform": "{{channel}} sürümleri yalnızca macOS ve Windows için üretilir.",
"unsignedDevChannel": "{{channel}} sürümleri imzasızdır ve bu imzalı sürüm yalnızca Orca'nın yayımcısının imzaladığı güncellemeleri yükler. Yükleyiciyi sürüm sayfasından indirip bir kez çalıştırın; bundan sonra Kararlı kanalına dönüş dahil güncellemeler normal şekilde çalışır.",
"linuxPackageMissing": "İndirilen paket artık güncelleme önbelleğinde değil. Güncellemeyi yeniden indirin veya resmi sürüm sayfasından edinin.",
"linuxPackageNotRegular": "İndirilen paket artık güncelleme önbelleğinde geçerli bir dosya değil. Güncellemeyi yeniden indirin veya resmi sürüm sayfasından edinin.",
"linuxPackageHashMismatch": "İndirilen paket artık doğrulanmış sürümle eşleşmediğinden Orca paketi bir paket yöneticisine aktarmayacak. Güncellemeyi yeniden indirin veya resmi sürüm sayfasından edinin.",
"linuxPackageReadFailed": "Orca indirilen paketi okuyamadı. Güncellemeyi yeniden indirin veya resmi sürüm sayfasından edinin.",
"linuxPackageNoSudo": "Sistem dizinlerinde sudo komutu bulunamadığından Orca güvenli bir kurulum komutu oluşturamıyor. Paketi gösterin ve paket yöneticinizle yükleyin.",
"linuxPackageNoPackageManager": "Sistem dizinlerinde desteklenen bir paket yöneticisi bulunamadığından Orca güvenli bir kurulum komutu oluşturamıyor. Paketi gösterin ve paket yöneticinizle yükleyin.",
"linuxPackageInvalidPath": "İndirilen paket kullanılabilir bir yolda olmadığından Orca güvenli bir kurulum komutu oluşturamıyor. Paketi gösterin ve paket yöneticinizle yükleyin.",
"linuxPackageMarkerUnusable": "Orca kurulu Linux paketinin biçimini doğrulayamadığından bu güncellemeyi otomatik yüklemeyecek. Güncellemeyi resmi sürüm sayfasından indirin ve elle yükleyin.",
"linuxPackageExternallyManaged": "Bu Orca kopyası sistem paket yöneticiniz tarafından yönetildiğinden Orca güncellemeleri kendisi yükleyemez. Orca'yı dağıtımınız üzerinden güncelleyin.",
"linuxPackageManualInstall": "Sistemin paket yükleme komutunu çalıştırmadan önce Orca'dan çıkın.",
"linuxPackageMetadataUnusable": "İndirilen paketin meta verileri doğrulanamadı. Güncellemeyi resmi sürüm sayfasından indirip yüklemeden önce Orca'dan çıkın.",
"unknownReleaseChannel": "Bilinmeyen yayın kanalı \"{{channel}}\".",
"invalidReleaseTag": "\"{{tag}}\" geçerli bir sürüm etiketi değil.",
"releaseRepoNotFound": "{{repo}} adresinde sürümlerin yayımlandığı bir repo bulunamadı.",
"releaseListFailed": "{{channel}} sürümleri listelenemedi (HTTP {{status}}).",
"releaseListUnreadable": "{{channel}} sürüm listesi okunamadı.",
"rateLimitedSoon": "GitHub istek sınırına ulaşıldı. Birkaç dakika sonra tekrar deneyin.",
"rateLimitedSoonSignedOut": "GitHub istek sınırına ulaşıldı. Birkaç dakika sonra tekrar deneyin veya Orca'nın hesabınızdaki daha yüksek sınırı kullanabilmesi için `gh auth login` komutunu çalıştırın.",
"rateLimitedInMinute": "GitHub istek sınırına ulaşıldı. Yaklaşık bir dakika sonra tekrar deneyin.",
"rateLimitedInMinuteSignedOut": "GitHub istek sınırına ulaşıldı. Yaklaşık bir dakika sonra tekrar deneyin veya Orca'nın hesabınızdaki daha yüksek sınırı kullanabilmesi için `gh auth login` komutunu çalıştırın.",
"rateLimitedInMinutes_one": "GitHub istek sınırına ulaşıldı. Yaklaşık {{count}} dakika sonra tekrar deneyin.",
"rateLimitedInMinutes_other": "GitHub istek sınırına ulaşıldı. Yaklaşık {{count}} dakika sonra tekrar deneyin.",
"rateLimitedInMinutesSignedOut_one": "GitHub istek sınırına ulaşıldı. Yaklaşık {{count}} dakika sonra tekrar deneyin veya Orca'nın hesabınızdaki daha yüksek sınırı kullanabilmesi için `gh auth login` komutunu çalıştırın.",
"rateLimitedInMinutesSignedOut_other": "GitHub istek sınırına ulaşıldı. Yaklaşık {{count}} dakika sonra tekrar deneyin veya Orca'nın hesabınızdaki daha yüksek sınırı kullanabilmesi için `gh auth login` komutunu çalıştırın."
}
},
"jira": {
"connect": {
+29 -1
View File
@@ -20845,7 +20845,35 @@
"preparingAriaLabel": "正在準備更新。點選展開。"
},
"wslMoveInstallHeld": "專案正在移到其 WSL 主機。移動完成後再安裝更新。",
"wslMoveUndoInstallHeld": "專案正在從其 WSL 主機移回。完成後再安裝更新。"
"wslMoveUndoInstallHeld": "專案正在從其 WSL 主機移回。完成後再安裝更新。",
"failure": {
"releaseNotReady": "此裝置尚無可用的較新版本。請稍後再檢查。",
"updateServerUnreachable": "無法連線至更新伺服器。請稍候幾分鐘再試。",
"channelUnsupportedPlatform": "{{channel}} 建置版本僅針對 macOS 和 Windows 提供。",
"unsignedDevChannel": "{{channel}} 建置版本未經簽署,而目前已簽署的建置版本只會安裝由 Orca 發行者簽署的更新。請從發行版本頁面下載安裝程式並執行一次,之後更新即可正常運作,包括切回穩定版。",
"linuxPackageMissing": "下載的套件已不在更新快取中。請重新下載更新,或從官方發行版本頁面取得。",
"linuxPackageNotRegular": "更新快取中下載的套件已不再是有效檔案。請重新下載更新,或從官方發行版本頁面取得。",
"linuxPackageHashMismatch": "下載的套件已不再符合驗證過的發行版本,因此 Orca 不會將其交給套件管理員。請重新下載更新,或從官方發行版本頁面取得。",
"linuxPackageReadFailed": "Orca 無法讀取下載的套件。請重新下載更新,或從官方發行版本頁面取得。",
"linuxPackageNoSudo": "系統目錄中找不到 sudo 指令,因此 Orca 無法產生安全的安裝指令。請顯示套件,並使用套件管理員安裝。",
"linuxPackageNoPackageManager": "系統目錄中找不到支援的套件管理員,因此 Orca 無法產生安全的安裝指令。請顯示套件,並使用套件管理員安裝。",
"linuxPackageInvalidPath": "下載的套件不在可用的路徑中,因此 Orca 無法產生安全的安裝指令。請顯示套件,並使用套件管理員安裝。",
"linuxPackageMarkerUnusable": "Orca 無法驗證已安裝的 Linux 套件格式,因此不會自動安裝此更新。請從官方發行版本頁面下載更新並手動安裝。",
"linuxPackageExternallyManaged": "此 Orca 由系統套件管理員管理,因此 Orca 無法自行安裝更新。請透過您使用的發行版更新 Orca。",
"linuxPackageManualInstall": "執行系統套件安裝指令前,請先結束 Orca。",
"linuxPackageMetadataUnusable": "無法驗證下載套件的後設資料。請先結束 Orca,再從官方發行版本頁面下載並安裝更新。",
"unknownReleaseChannel": "未知的發布頻道「{{channel}}」。",
"invalidReleaseTag": "「{{tag}}」不是有效的發行版本標籤。",
"releaseRepoNotFound": "在 {{repo}} 找不到發行版本存放庫。",
"releaseListFailed": "無法列出 {{channel}} 建置版本(HTTP {{status}})。",
"releaseListUnreadable": "無法讀取 {{channel}} 的發行版本清單。",
"rateLimitedSoon": "已達 GitHub 速率限制。請稍候幾分鐘再試。",
"rateLimitedSoonSignedOut": "已達 GitHub 速率限制。請稍候幾分鐘再試,或執行 `gh auth login`,讓 Orca 使用您帳戶的較高額度。",
"rateLimitedInMinute": "已達 GitHub 速率限制。請約一分鐘後再試。",
"rateLimitedInMinuteSignedOut": "已達 GitHub 速率限制。請約一分鐘後再試,或執行 `gh auth login`,讓 Orca 使用您帳戶的較高額度。",
"rateLimitedInMinutes_other": "已達 GitHub 速率限制。請約 {{count}} 分鐘後再試。",
"rateLimitedInMinutesSignedOut_other": "已達 GitHub 速率限制。請約 {{count}} 分鐘後再試,或執行 `gh auth login`,讓 Orca 使用您帳戶的較高額度。"
}
},
"jira": {
"connect": {
+29 -1
View File
@@ -21234,7 +21234,35 @@
"browserSummary": "后台 Orca 服务器的浏览器仍在使用此应用程序。"
},
"wslMoveInstallHeld": "项目正在移到其 WSL 主机。移动完成后再安装更新。",
"wslMoveUndoInstallHeld": "项目正在从其 WSL 主机移回。完成后再安装更新。"
"wslMoveUndoInstallHeld": "项目正在从其 WSL 主机移回。完成后再安装更新。",
"failure": {
"releaseNotReady": "此设备暂时还无法获取更新的版本。请稍后再检查。",
"updateServerUnreachable": "无法连接更新服务器。请几分钟后重试。",
"channelUnsupportedPlatform": "{{channel}} 构建仅针对 macOS 和 Windows 提供。",
"unsignedDevChannel": "{{channel}} 构建未签名,而当前已签名的构建仅安装由 Orca 发布者签名的更新。请从版本发布页面下载安装程序并运行一次,之后更新即可正常进行,包括切回稳定版。",
"linuxPackageMissing": "下载的安装包已不在更新缓存中。请重新下载更新,或从官方版本发布页面获取。",
"linuxPackageNotRegular": "更新缓存中下载的安装包已不再是有效文件。请重新下载更新,或从官方版本发布页面获取。",
"linuxPackageHashMismatch": "下载的安装包与已验证的版本不再匹配,因此 Orca 不会将其交给包管理器。请重新下载更新,或从官方版本发布页面获取。",
"linuxPackageReadFailed": "Orca 无法读取下载的安装包。请重新下载更新,或从官方版本发布页面获取。",
"linuxPackageNoSudo": "系统目录中未找到 sudo 命令,因此 Orca 无法生成安全的安装命令。请显示安装包并使用包管理器安装。",
"linuxPackageNoPackageManager": "系统目录中未找到受支持的包管理器,因此 Orca 无法生成安全的安装命令。请显示安装包并使用包管理器安装。",
"linuxPackageInvalidPath": "下载的安装包不在可用路径中,因此 Orca 无法生成安全的安装命令。请显示安装包并使用包管理器安装。",
"linuxPackageMarkerUnusable": "Orca 无法验证已安装的 Linux 软件包格式,因此不会自动安装此更新。请从官方版本发布页面下载更新并手动安装。",
"linuxPackageExternallyManaged": "此 Orca 由系统包管理器管理,因此 Orca 无法自行安装更新。请通过所用的发行版更新 Orca。",
"linuxPackageManualInstall": "运行系统软件包安装命令前,请先退出 Orca。",
"linuxPackageMetadataUnusable": "无法验证下载的安装包元数据。请先退出 Orca,再从官方版本发布页面下载并安装更新。",
"unknownReleaseChannel": "未知的发布渠道“{{channel}}”。",
"invalidReleaseTag": "“{{tag}}”不是有效的发布标签。",
"releaseRepoNotFound": "在 {{repo}} 未找到发布版本的仓库。",
"releaseListFailed": "无法列出 {{channel}} 构建(HTTP {{status}})。",
"releaseListUnreadable": "无法读取 {{channel}} 的版本发布列表。",
"rateLimitedSoon": "已达到 GitHub 速率限制。请几分钟后重试。",
"rateLimitedSoonSignedOut": "已达到 GitHub 速率限制。请几分钟后重试,或运行 `gh auth login`,以便 Orca 使用你账户的更高限额。",
"rateLimitedInMinute": "已达到 GitHub 速率限制。请约一分钟后重试。",
"rateLimitedInMinuteSignedOut": "已达到 GitHub 速率限制。请约一分钟后重试,或运行 `gh auth login`,以便 Orca 使用你账户的更高限额。",
"rateLimitedInMinutes_other": "已达到 GitHub 速率限制。请约 {{count}} 分钟后重试。",
"rateLimitedInMinutesSignedOut_other": "已达到 GitHub 速率限制。请约 {{count}} 分钟后重试,或运行 `gh auth login`,以便 Orca 使用你账户的更高限额。"
}
},
"onboarding": {
"language": {
@@ -0,0 +1,39 @@
import { afterEach, describe, expect, it } from 'vitest'
import { i18n } from '@/i18n/i18n'
import es from '@/i18n/locales/es.json'
import { updaterCodedMessage } from '../../../shared/updater-failure-copy'
import { updaterMessageText } from './updater-message-copy'
const originalLanguage = i18n.language
afterEach(async () => {
await i18n.changeLanguage(originalLanguage)
})
describe('updater message copy', () => {
it('translates coded updater messages and keeps channel names verbatim', async () => {
i18n.addResourceBundle('es', 'translation', es)
await i18n.changeLanguage('es')
expect(updaterMessageText(updaterCodedMessage('updateServerUnreachable'))).toBe(
es.updates.failure.updateServerUnreachable
)
expect(
updaterMessageText(updaterCodedMessage('unsignedDevChannel', { channel: 'Hourly' }))
).toBe(es.updates.failure.unsignedDevChannel.replace('{{channel}}', 'Hourly'))
})
it('keeps the English message for older hosts, unknown codes and missing params', async () => {
i18n.addResourceBundle('es', 'translation', es)
await i18n.changeLanguage('es')
expect(updaterMessageText({ message: 'Older host text' })).toBe('Older host text')
expect(updaterMessageText({ message: 'Newer host text', messageCode: 'futureCode' })).toBe(
'Newer host text'
)
expect(
updaterMessageText({
message: 'Hourly builds are unsigned…',
messageCode: 'unsignedDevChannel'
})
).toBe('Hourly builds are unsigned…')
})
})
@@ -0,0 +1,158 @@
import { translate } from '@/i18n/i18n'
import type { LinuxPackageCommandUnavailableReason } from '../../../shared/update-status-types'
import {
UPDATER_FAILURE_COPY as EN,
type UpdaterFailureCode
} from '../../../shared/updater-failure-copy'
type Param = (name: string) => string | null
type CountParam = (name: string) => number | null
// null = required params missing; caller shows the host's English message.
const COPY: Record<UpdaterFailureCode, (param: Param, count: CountParam) => string | null> = {
releaseNotReady: () => translate('updates.failure.releaseNotReady', EN.releaseNotReady),
updateServerUnreachable: () =>
translate('updates.failure.updateServerUnreachable', EN.updateServerUnreachable),
channelUnsupportedPlatform: (param) => {
const channel = param('channel')
return channel === null
? null
: translate('updates.failure.channelUnsupportedPlatform', EN.channelUnsupportedPlatform, {
channel
})
},
unsignedDevChannel: (param) => {
const channel = param('channel')
return channel === null
? null
: translate('updates.failure.unsignedDevChannel', EN.unsignedDevChannel, { channel })
},
linuxPackageMissing: () =>
translate('updates.failure.linuxPackageMissing', EN.linuxPackageMissing),
linuxPackageNotRegular: () =>
translate('updates.failure.linuxPackageNotRegular', EN.linuxPackageNotRegular),
linuxPackageHashMismatch: () =>
translate('updates.failure.linuxPackageHashMismatch', EN.linuxPackageHashMismatch),
linuxPackageReadFailed: () =>
translate('updates.failure.linuxPackageReadFailed', EN.linuxPackageReadFailed),
linuxPackageNoSudo: () => translate('updates.failure.linuxPackageNoSudo', EN.linuxPackageNoSudo),
linuxPackageNoPackageManager: () =>
translate('updates.failure.linuxPackageNoPackageManager', EN.linuxPackageNoPackageManager),
linuxPackageInvalidPath: () =>
translate('updates.failure.linuxPackageInvalidPath', EN.linuxPackageInvalidPath),
linuxPackageMarkerUnusable: () =>
translate('updates.failure.linuxPackageMarkerUnusable', EN.linuxPackageMarkerUnusable),
linuxPackageExternallyManaged: () =>
translate('updates.failure.linuxPackageExternallyManaged', EN.linuxPackageExternallyManaged),
linuxPackageManualInstall: () =>
translate('updates.failure.linuxPackageManualInstall', EN.linuxPackageManualInstall),
linuxPackageMetadataUnusable: () =>
translate('updates.failure.linuxPackageMetadataUnusable', EN.linuxPackageMetadataUnusable),
unknownReleaseChannel: (param) => {
const channel = param('channel')
return channel === null
? null
: translate('updates.failure.unknownReleaseChannel', EN.unknownReleaseChannel, { channel })
},
invalidReleaseTag: (param) => {
const tag = param('tag')
return tag === null
? null
: translate('updates.failure.invalidReleaseTag', EN.invalidReleaseTag, { tag })
},
releaseRepoNotFound: (param) => {
const repo = param('repo')
return repo === null
? null
: translate('updates.failure.releaseRepoNotFound', EN.releaseRepoNotFound, { repo })
},
releaseListFailed: (param, count) => {
const channel = param('channel')
const status = count('status')
return channel === null || status === null
? null
: translate('updates.failure.releaseListFailed', EN.releaseListFailed, { channel, status })
},
releaseListUnreadable: (param) => {
const channel = param('channel')
return channel === null
? null
: translate('updates.failure.releaseListUnreadable', EN.releaseListUnreadable, { channel })
},
rateLimitedSoon: () => translate('updates.failure.rateLimitedSoon', EN.rateLimitedSoon),
rateLimitedSoonSignedOut: () =>
translate('updates.failure.rateLimitedSoonSignedOut', EN.rateLimitedSoonSignedOut),
rateLimitedInMinute: () =>
translate('updates.failure.rateLimitedInMinute', EN.rateLimitedInMinute),
rateLimitedInMinuteSignedOut: () =>
translate('updates.failure.rateLimitedInMinuteSignedOut', EN.rateLimitedInMinuteSignedOut),
rateLimitedInMinutes: (_param, count) => {
const minutes = count('count')
return minutes === null
? null
: translate('updates.failure.rateLimitedInMinutes', EN.rateLimitedInMinutes, {
count: minutes,
defaultValue_one: 'GitHub rate limit reached. Try again in about {{count}} minute.'
})
},
rateLimitedInMinutesSignedOut: (_param, count) => {
const minutes = count('count')
return minutes === null
? null
: translate(
'updates.failure.rateLimitedInMinutesSignedOut',
EN.rateLimitedInMinutesSignedOut,
{
count: minutes,
defaultValue_one:
"GitHub rate limit reached. Try again in about {{count}} minute, or run `gh auth login` so Orca can use your account's higher limit."
}
)
}
}
const COMMAND_UNAVAILABLE_CODES: Record<LinuxPackageCommandUnavailableReason, UpdaterFailureCode> =
{
'no-sudo': 'linuxPackageNoSudo',
'no-package-manager': 'linuxPackageNoPackageManager'
}
function isUpdaterFailureCode(code: unknown): code is UpdaterFailureCode {
return typeof code === 'string' && Object.hasOwn(COPY, code)
}
function codedText(code: unknown, params: unknown): string | null {
if (!isUpdaterFailureCode(code)) {
return null
}
const values: Record<string, unknown> =
typeof params === 'object' && params !== null ? Object.fromEntries(Object.entries(params)) : {}
return COPY[code](
(name) => (typeof values[name] === 'string' ? values[name] : null),
(name) => (typeof values[name] === 'number' ? values[name] : null)
)
}
/** Updater message text: known codes translate; unknown codes and older hosts keep the English message. */
export function updaterMessageText(source: {
message: string
messageCode?: unknown
messageParams?: unknown
}): string {
return codedText(source.messageCode, source.messageParams) ?? source.message
}
/** The install-instructions result already names its reason; unknown reasons keep main's English. */
export function linuxPackageCommandUnavailableText(instructions: {
reason: LinuxPackageCommandUnavailableReason
message: string
}): string {
return (
codedText(
Object.hasOwn(COMMAND_UNAVAILABLE_CODES, instructions.reason)
? COMMAND_UNAVAILABLE_CODES[instructions.reason]
: undefined,
undefined
) ?? instructions.message
)
}
@@ -1,4 +1,5 @@
import type { RemoteServerUpdaterSnapshot } from '../../../shared/remote-server-update'
import { updaterMessageText } from '@/lib/updater-message-copy'
type PollingTransport = {
getUpdaterStatus: (environmentId: string) => Promise<RemoteServerUpdaterSnapshot>
@@ -23,7 +24,7 @@ export async function pollRemoteServerUpdater(
while (now() < deadline) {
const snapshot = await transport.getUpdaterStatus(environmentId)
if (snapshot.status.state === 'error') {
throw new Error(snapshot.status.message)
throw new Error(updaterMessageText(snapshot.status))
}
onSnapshot(snapshot)
if (accept(snapshot)) {
+10 -1
View File
@@ -90,6 +90,9 @@ export type UpdateStatus = (
| {
state: 'error'
message: string
/** Translation code for `message`; older hosts omit it and newer ones may send unknown codes. */
messageCode?: string
messageParams?: Record<string, string | number>
/** Known download/install target; absent for check-time failures and older hosts. */
version?: string
/** Omitted by older hosts and for failures whose retryability is unknown. */
@@ -106,4 +109,10 @@ export type UpdateStatus = (
export type ReleaseBuildListResult =
| { ok: true; channel: ReleaseChannel; builds: ReleaseBuild[] }
| { ok: false; channel: ReleaseChannel; message: string }
| {
ok: false
channel: ReleaseChannel
message: string
messageCode?: string
messageParams?: Record<string, string | number>
}
+76
View File
@@ -0,0 +1,76 @@
// One English table for updater failures: main builds the English `message`, the renderer translates by code.
export const UPDATER_FAILURE_COPY = {
releaseNotReady: "A newer release isn't available for this device yet. Check again later.",
updateServerUnreachable: "Couldn't reach the update server. Try again in a few minutes.",
channelUnsupportedPlatform: '{{channel}} builds are produced only for macOS and Windows.',
unsignedDevChannel:
"{{channel}} builds are unsigned, and this signed build only installs updates signed by Orca's publisher. Download the installer from the release page and run it once — updates work normally from there, including back to Stable.",
linuxPackageMissing:
'The downloaded package is no longer in the update cache. Download the update again, or get it from the official release page.',
linuxPackageNotRegular:
'The downloaded package is no longer a valid file in the update cache. Download the update again, or get it from the official release page.',
linuxPackageHashMismatch:
'The downloaded package no longer matches the verified release, so Orca will not hand it to a package manager. Download the update again, or get it from the official release page.',
linuxPackageReadFailed:
'Orca could not read the downloaded package. Download the update again, or get it from the official release page.',
linuxPackageNoSudo:
'No sudo command was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.',
linuxPackageNoPackageManager:
'No supported package manager was found in the system directories, so Orca cannot build a safe install command. Show the package and install it with your package manager.',
linuxPackageInvalidPath:
'The downloaded package is not at a usable path, so Orca cannot build a safe install command. Show the package and install it with your package manager.',
linuxPackageMarkerUnusable:
'Orca could not verify the installed Linux package format, so it will not install this update automatically. Download the update from the official release page and install it manually.',
linuxPackageExternallyManaged:
'This copy of Orca is managed by your system package manager, so Orca cannot install updates itself. Update Orca through your distribution instead.',
linuxPackageManualInstall: 'Quit Orca before running the system package install command.',
linuxPackageMetadataUnusable:
'The downloaded package metadata could not be verified. Quit Orca before downloading and installing the update from the official release page.',
unknownReleaseChannel: 'Unknown release channel "{{channel}}".',
invalidReleaseTag: '"{{tag}}" is not a valid release tag.',
releaseRepoNotFound: 'No releases repository found at {{repo}}.',
releaseListFailed: 'Could not list {{channel}} builds (HTTP {{status}}).',
releaseListUnreadable: 'Could not read the {{channel}} release list.',
rateLimitedSoon: 'GitHub rate limit reached. Try again in a few minutes.',
rateLimitedSoonSignedOut:
"GitHub rate limit reached. Try again in a few minutes, or run `gh auth login` so Orca can use your account's higher limit.",
rateLimitedInMinute: 'GitHub rate limit reached. Try again in about a minute.',
rateLimitedInMinuteSignedOut:
"GitHub rate limit reached. Try again in about a minute, or run `gh auth login` so Orca can use your account's higher limit.",
// Only for two or more minutes; one minute uses rateLimitedInMinute.
rateLimitedInMinutes: 'GitHub rate limit reached. Try again in about {{count}} minutes.',
rateLimitedInMinutesSignedOut:
"GitHub rate limit reached. Try again in about {{count}} minutes, or run `gh auth login` so Orca can use your account's higher limit."
} as const
export type UpdaterFailureCode = keyof typeof UPDATER_FAILURE_COPY
export type UpdaterFailureParams = Record<string, string | number>
/** Wire shape: `message` stays English for older readers; code and params let the renderer translate it. */
export type UpdaterCodedMessage = {
message: string
messageCode?: string
messageParams?: UpdaterFailureParams
}
// One pass, so a value containing "{{status}}" stays verbatim.
export function updaterFailureText(
code: UpdaterFailureCode,
params: UpdaterFailureParams = {}
): string {
return UPDATER_FAILURE_COPY[code].replace(/\{\{(\w+)\}\}/g, (slot, name: string) =>
Object.hasOwn(params, name) ? String(params[name]) : slot
)
}
export function updaterCodedMessage(
code: UpdaterFailureCode,
params?: UpdaterFailureParams
): UpdaterCodedMessage {
return {
message: updaterFailureText(code, params),
messageCode: code,
...(params ? { messageParams: params } : {})
}
}