From bbb563e83a1979eb14c47027e5e2fc1178dccc87 Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Thu, 29 Oct 2026 03:07:42 -0700 Subject: [PATCH] fix(i18n): translate source control remote operation error toasts (#35893) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- src/renderer/src/i18n/locales/de.json | 73 +++++ src/renderer/src/i18n/locales/en.json | 73 +++++ src/renderer/src/i18n/locales/es.json | 73 +++++ src/renderer/src/i18n/locales/fr.json | 73 +++++ src/renderer/src/i18n/locales/ja.json | 73 +++++ src/renderer/src/i18n/locales/ko.json | 73 +++++ src/renderer/src/i18n/locales/pt.json | 73 +++++ src/renderer/src/i18n/locales/ru.json | 73 +++++ src/renderer/src/i18n/locales/tr.json | 73 +++++ src/renderer/src/i18n/locales/zh-Hant.json | 73 +++++ src/renderer/src/i18n/locales/zh.json | 73 +++++ .../lib/source-control-remote-error-copy.ts | 306 ++++++++++++++++++ .../lib/source-control-remote-error.test.ts | 27 +- .../src/lib/source-control-remote-error.ts | 198 ++++++------ src/shared/git-remote-error.ts | 42 ++- src/shared/source-control-push-failure.ts | 4 +- 16 files changed, 1270 insertions(+), 110 deletions(-) create mode 100644 src/renderer/src/lib/source-control-remote-error-copy.ts diff --git a/src/renderer/src/i18n/locales/de.json b/src/renderer/src/i18n/locales/de.json index 52024a80072..3268d5e6ba9 100644 --- a/src/renderer/src/i18n/locales/de.json +++ b/src/renderer/src/i18n/locales/de.json @@ -20347,6 +20347,79 @@ }, "enableSourceControlAi": "KI für die Quellcodeverwaltung unter Einstellungen -> Git aktivieren.", "chooseBaseBranch": "Vor dem Generieren einen Basis-Branch auswählen." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "Submodul „{{name}}“ hat Änderungen im Remote. Im Submodul pullen und erneut versuchen.", + "remoteChanged": "Ein Submodul hat Änderungen im Remote. Im Submodul pullen und erneut versuchen.", + "namedPushFailed": "Submodul „{{name}}“ konnte nicht gepusht werden. Den Push-Fehler des Submoduls beheben und erneut versuchen.", + "pushFailed": "Ein Submodul konnte nicht gepusht werden. Den Push-Fehler des Submoduls beheben und erneut versuchen." + }, + "failedWithDetail": { + "publish": "Veröffentlichen des Branches fehlgeschlagen. {{detail}}", + "sync": "Synchronisierung fehlgeschlagen. {{detail}}", + "forcePush": "Erzwungener Push fehlgeschlagen. {{detail}}", + "push": "Push fehlgeschlagen. {{detail}}", + "fetch": "Fetch fehlgeschlagen. {{detail}}", + "fastForward": "Fast-Forward fehlgeschlagen. {{detail}}", + "rebase": "Rebase fehlgeschlagen. {{detail}}", + "pull": "Pull fehlgeschlagen. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Veröffentlichen des Branches blockiert — lint beim Push fehlgeschlagen.", + "sync": "Synchronisierung blockiert — lint beim Push fehlgeschlagen.", + "forcePush": "Erzwungener Push blockiert — lint beim Push fehlgeschlagen.", + "push": "Push blockiert — lint beim Push fehlgeschlagen." + }, + "prePush": { + "publish": "Veröffentlichen des Branches blockiert — pre-push-Hook fehlgeschlagen.", + "sync": "Synchronisierung blockiert — pre-push-Hook fehlgeschlagen.", + "forcePush": "Erzwungener Push blockiert — pre-push-Hook fehlgeschlagen.", + "push": "Push blockiert — pre-push-Hook fehlgeschlagen." + }, + "detail": { + "publish": "Veröffentlichen des Branches blockiert — {{detail}}", + "sync": "Synchronisierung blockiert — {{detail}}", + "forcePush": "Erzwungener Push blockiert — {{detail}}", + "push": "Push blockiert — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "Veröffentlichen des Branches fehlgeschlagen. {{detail}}. Den Zugriff auf das Remote prüfen und erneut versuchen.", + "sync": "Synchronisierung fehlgeschlagen. {{detail}}. Den Zugriff auf das Remote prüfen und erneut versuchen.", + "forcePush": "Erzwungener Push fehlgeschlagen. {{detail}}. Den Zugriff auf das Remote prüfen und erneut versuchen.", + "push": "Push fehlgeschlagen. {{detail}}. Den Zugriff auf das Remote prüfen und erneut versuchen." + }, + "publishFailed": "Veröffentlichen des Branches fehlgeschlagen. Den Zugriff auf das Remote prüfen und erneut versuchen.", + "syncFailed": "Synchronisierung fehlgeschlagen. Die Verbindung prüfen und erneut versuchen.", + "forcePushFailed": "Erzwungener Push fehlgeschlagen. Die Verbindung prüfen und erneut versuchen.", + "pushFailed": "Push fehlgeschlagen. Die Verbindung prüfen und erneut versuchen.", + "localChangesBlocked": { + "rebase": "Rebase blockiert — lokale Änderungen zuerst committen oder stashen.", + "fastForward": "Fast-Forward blockiert — lokale Änderungen zuerst committen oder stashen.", + "pull": "Pull blockiert — lokale Änderungen zuerst committen oder stashen." + }, + "operationFailed": "Remote-Operation fehlgeschlagen", + "unconcludedMerge": { + "rebase": "Rebase blockiert — zuerst bestehende Konflikte beheben.", + "sync": "Synchronisierung blockiert — zuerst bestehende Merge-Konflikte beheben.", + "pull": "Pull blockiert — zuerst bestehende Merge-Konflikte beheben." + }, + "mergeConflicts": { + "rebase": "Rebase wegen Konflikten angehalten. Diese in der Quellcodeverwaltung beheben und dann den Rebase fortsetzen.", + "sync": "Synchronisierung wegen Merge-Konflikten angehalten. Diese in der Quellcodeverwaltung beheben und dann den Merge committen.", + "pull": "Pull wegen Merge-Konflikten angehalten. Diese in der Quellcodeverwaltung beheben und dann den Merge committen." + }, + "syncRemoteMoved": "Synchronisierung fehlgeschlagen — das Remote hat sich während der Synchronisierung geändert. Erneut versuchen.", + "forcePushRejected": "Erzwungener Push abgelehnt — das Remote hat sich seit dem letzten Fetch geändert. Zuerst fetchen und erneut versuchen.", + "pushRejected": "Push abgelehnt — das Remote enthält Änderungen. Zuerst pullen und erneut versuchen.", + "untrackedFilesBlocked": { + "rebase": "Rebase blockiert — nicht versionierte Dateien zuerst verschieben, entfernen oder hinzufügen.", + "fastForward": "Fast-Forward blockiert — nicht versionierte Dateien zuerst verschieben, entfernen oder hinzufügen.", + "pull": "Pull blockiert — nicht versionierte Dateien zuerst verschieben, entfernen oder hinzufügen." + }, + "authenticationFailed": "Authentifizierung fehlgeschlagen. Die Zugangsdaten für das Remote prüfen." } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index e3af7f5212f..165a8d20336 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -20773,6 +20773,79 @@ }, "enableSourceControlAi": "Enable Source Control AI in Settings -> Git.", "chooseBaseBranch": "Choose a base branch before generating." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "Submodule '{{name}}' has remote changes. Pull inside the submodule, then try again.", + "remoteChanged": "A submodule has remote changes. Pull inside the submodule, then try again.", + "namedPushFailed": "Submodule '{{name}}' could not be pushed. Resolve the submodule push error, then try again.", + "pushFailed": "A submodule could not be pushed. Resolve the submodule push error, then try again." + }, + "failedWithDetail": { + "publish": "Publish Branch failed. {{detail}}", + "sync": "Sync failed. {{detail}}", + "forcePush": "Force Push failed. {{detail}}", + "push": "Push failed. {{detail}}", + "fetch": "Fetch failed. {{detail}}", + "fastForward": "Fast-forward failed. {{detail}}", + "rebase": "Rebase failed. {{detail}}", + "pull": "Pull failed. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Publish Branch blocked — lint failed during push.", + "sync": "Sync blocked — lint failed during push.", + "forcePush": "Force Push blocked — lint failed during push.", + "push": "Push blocked — lint failed during push." + }, + "prePush": { + "publish": "Publish Branch blocked — pre-push hook failed.", + "sync": "Sync blocked — pre-push hook failed.", + "forcePush": "Force Push blocked — pre-push hook failed.", + "push": "Push blocked — pre-push hook failed." + }, + "detail": { + "publish": "Publish Branch blocked — {{detail}}", + "sync": "Sync blocked — {{detail}}", + "forcePush": "Force Push blocked — {{detail}}", + "push": "Push blocked — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "Publish Branch failed. {{detail}}. Check your remote access and try again.", + "sync": "Sync failed. {{detail}}. Check your remote access and try again.", + "forcePush": "Force Push failed. {{detail}}. Check your remote access and try again.", + "push": "Push failed. {{detail}}. Check your remote access and try again." + }, + "publishFailed": "Publish Branch failed. Check your remote access and try again.", + "syncFailed": "Sync failed. Check your connection and try again.", + "forcePushFailed": "Force Push failed. Check your connection and try again.", + "pushFailed": "Push failed. Check your connection and try again.", + "localChangesBlocked": { + "rebase": "Rebase blocked — commit or stash your local changes first.", + "fastForward": "Fast-forward blocked — commit or stash your local changes first.", + "pull": "Pull blocked — commit or stash your local changes first." + }, + "operationFailed": "Remote operation failed", + "unconcludedMerge": { + "rebase": "Rebase blocked — resolve existing conflicts first.", + "sync": "Sync blocked — resolve existing merge conflicts first.", + "pull": "Pull blocked — resolve existing merge conflicts first." + }, + "mergeConflicts": { + "rebase": "Rebase stopped with conflicts. Resolve them in Source Control, then continue the rebase.", + "sync": "Sync stopped with merge conflicts. Resolve them in Source Control, then commit the merge.", + "pull": "Pull stopped with merge conflicts. Resolve them in Source Control, then commit the merge." + }, + "syncRemoteMoved": "Sync failed — remote moved while syncing. Try again.", + "forcePushRejected": "Force push rejected — remote changed since last fetch. Fetch first, then try again.", + "pushRejected": "Push rejected — remote has changes. Pull first, then try again.", + "untrackedFilesBlocked": { + "rebase": "Rebase blocked — move, remove, or add untracked files first.", + "fastForward": "Fast-forward blocked — move, remove, or add untracked files first.", + "pull": "Pull blocked — move, remove, or add untracked files first." + }, + "authenticationFailed": "Authentication failed. Check your remote credentials." } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 758ad450ab4..485ef9f482d 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -21364,6 +21364,79 @@ }, "enableSourceControlAi": "Activa Source Control AI en Ajustes -> Git.", "chooseBaseBranch": "Elige una rama base antes de generar." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "El submódulo '{{name}}' tiene cambios en el remoto. Haz pull dentro del submódulo y vuelve a intentarlo.", + "remoteChanged": "Un submódulo tiene cambios en el remoto. Haz pull dentro del submódulo y vuelve a intentarlo.", + "namedPushFailed": "No se pudo hacer push del submódulo '{{name}}'. Resuelve el error de push del submódulo y vuelve a intentarlo.", + "pushFailed": "No se pudo hacer push de un submódulo. Resuelve el error de push del submódulo y vuelve a intentarlo." + }, + "failedWithDetail": { + "publish": "No se pudo publicar la rama. {{detail}}", + "sync": "La sincronización falló. {{detail}}", + "forcePush": "El force push falló. {{detail}}", + "push": "El push falló. {{detail}}", + "fetch": "El fetch falló. {{detail}}", + "fastForward": "El fast-forward falló. {{detail}}", + "rebase": "El rebase falló. {{detail}}", + "pull": "El pull falló. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Publicación de rama bloqueada — el lint falló durante el push.", + "sync": "Sincronización bloqueada — el lint falló durante el push.", + "forcePush": "Force push bloqueado — el lint falló durante el push.", + "push": "Push bloqueado — el lint falló durante el push." + }, + "prePush": { + "publish": "Publicación de rama bloqueada — el hook pre-push falló.", + "sync": "Sincronización bloqueada — el hook pre-push falló.", + "forcePush": "Force push bloqueado — el hook pre-push falló.", + "push": "Push bloqueado — el hook pre-push falló." + }, + "detail": { + "publish": "Publicación de rama bloqueada — {{detail}}", + "sync": "Sincronización bloqueada — {{detail}}", + "forcePush": "Force push bloqueado — {{detail}}", + "push": "Push bloqueado — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "No se pudo publicar la rama. {{detail}}. Comprueba tu acceso al remoto y vuelve a intentarlo.", + "sync": "La sincronización falló. {{detail}}. Comprueba tu acceso al remoto y vuelve a intentarlo.", + "forcePush": "El force push falló. {{detail}}. Comprueba tu acceso al remoto y vuelve a intentarlo.", + "push": "El push falló. {{detail}}. Comprueba tu acceso al remoto y vuelve a intentarlo." + }, + "publishFailed": "No se pudo publicar la rama. Comprueba tu acceso al remoto y vuelve a intentarlo.", + "syncFailed": "La sincronización falló. Comprueba tu conexión y vuelve a intentarlo.", + "forcePushFailed": "El force push falló. Comprueba tu conexión y vuelve a intentarlo.", + "pushFailed": "El push falló. Comprueba tu conexión y vuelve a intentarlo.", + "localChangesBlocked": { + "rebase": "Rebase bloqueado — primero haz commit o stash de tus cambios locales.", + "fastForward": "Fast-forward bloqueado — primero haz commit o stash de tus cambios locales.", + "pull": "Pull bloqueado — primero haz commit o stash de tus cambios locales." + }, + "operationFailed": "La operación remota falló", + "unconcludedMerge": { + "rebase": "Rebase bloqueado — resuelve primero los conflictos existentes.", + "sync": "Sincronización bloqueada — resuelve primero los conflictos de merge existentes.", + "pull": "Pull bloqueado — resuelve primero los conflictos de merge existentes." + }, + "mergeConflicts": { + "rebase": "El rebase se detuvo por conflictos. Resuélvelos en Control de código fuente y luego continúa el rebase.", + "sync": "La sincronización se detuvo por conflictos de merge. Resuélvelos en Control de código fuente y luego haz commit del merge.", + "pull": "El pull se detuvo por conflictos de merge. Resuélvelos en Control de código fuente y luego haz commit del merge." + }, + "syncRemoteMoved": "La sincronización falló — el remoto cambió durante la sincronización. Vuelve a intentarlo.", + "forcePushRejected": "Force push rechazado — el remoto cambió desde el último fetch. Haz fetch primero y vuelve a intentarlo.", + "pushRejected": "Push rechazado — hay cambios en el remoto. Haz pull primero y vuelve a intentarlo.", + "untrackedFilesBlocked": { + "rebase": "Rebase bloqueado — mueve, elimina o añade primero los archivos sin seguimiento.", + "fastForward": "Fast-forward bloqueado — mueve, elimina o añade primero los archivos sin seguimiento.", + "pull": "Pull bloqueado — mueve, elimina o añade primero los archivos sin seguimiento." + }, + "authenticationFailed": "Falló la autenticación. Comprueba tus credenciales del remoto." } }, "aiVault": { diff --git a/src/renderer/src/i18n/locales/fr.json b/src/renderer/src/i18n/locales/fr.json index cacf805f8dd..f91c40ac26d 100644 --- a/src/renderer/src/i18n/locales/fr.json +++ b/src/renderer/src/i18n/locales/fr.json @@ -20917,6 +20917,79 @@ }, "enableSourceControlAi": "Activez l’IA du contrôle de code source dans Paramètres -> Git.", "chooseBaseBranch": "Choisissez une branche de base avant de générer." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "Le sous-module « {{name}} » a des modifications distantes. Faites un pull dans le sous-module, puis réessayez.", + "remoteChanged": "Un sous-module a des modifications distantes. Faites un pull dans le sous-module, puis réessayez.", + "namedPushFailed": "Le sous-module « {{name}} » n'a pas pu être poussé. Résolvez l'erreur de push du sous-module, puis réessayez.", + "pushFailed": "Un sous-module n'a pas pu être poussé. Résolvez l'erreur de push du sous-module, puis réessayez." + }, + "failedWithDetail": { + "publish": "La publication de la branche a échoué. {{detail}}", + "sync": "La synchronisation a échoué. {{detail}}", + "forcePush": "Le force push a échoué. {{detail}}", + "push": "Le push a échoué. {{detail}}", + "fetch": "Le fetch a échoué. {{detail}}", + "fastForward": "Le fast-forward a échoué. {{detail}}", + "rebase": "Le rebase a échoué. {{detail}}", + "pull": "Le pull a échoué. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Publication de la branche bloquée — le lint a échoué pendant le push.", + "sync": "Synchronisation bloquée — le lint a échoué pendant le push.", + "forcePush": "Force push bloqué — le lint a échoué pendant le push.", + "push": "Push bloqué — le lint a échoué pendant le push." + }, + "prePush": { + "publish": "Publication de la branche bloquée — le hook pre-push a échoué.", + "sync": "Synchronisation bloquée — le hook pre-push a échoué.", + "forcePush": "Force push bloqué — le hook pre-push a échoué.", + "push": "Push bloqué — le hook pre-push a échoué." + }, + "detail": { + "publish": "Publication de la branche bloquée — {{detail}}", + "sync": "Synchronisation bloquée — {{detail}}", + "forcePush": "Force push bloqué — {{detail}}", + "push": "Push bloqué — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "La publication de la branche a échoué. {{detail}}. Vérifiez votre accès au dépôt distant et réessayez.", + "sync": "La synchronisation a échoué. {{detail}}. Vérifiez votre accès au dépôt distant et réessayez.", + "forcePush": "Le force push a échoué. {{detail}}. Vérifiez votre accès au dépôt distant et réessayez.", + "push": "Le push a échoué. {{detail}}. Vérifiez votre accès au dépôt distant et réessayez." + }, + "publishFailed": "La publication de la branche a échoué. Vérifiez votre accès au dépôt distant et réessayez.", + "syncFailed": "La synchronisation a échoué. Vérifiez votre connexion et réessayez.", + "forcePushFailed": "Le force push a échoué. Vérifiez votre connexion et réessayez.", + "pushFailed": "Le push a échoué. Vérifiez votre connexion et réessayez.", + "localChangesBlocked": { + "rebase": "Rebase bloqué — commitez ou stashez d'abord vos modifications locales.", + "fastForward": "Fast-forward bloqué — commitez ou stashez d'abord vos modifications locales.", + "pull": "Pull bloqué — commitez ou stashez d'abord vos modifications locales." + }, + "operationFailed": "Échec de l'opération distante", + "unconcludedMerge": { + "rebase": "Rebase bloqué — résolvez d'abord les conflits existants.", + "sync": "Synchronisation bloquée — résolvez d'abord les conflits de fusion existants.", + "pull": "Pull bloqué — résolvez d'abord les conflits de fusion existants." + }, + "mergeConflicts": { + "rebase": "Le rebase s'est arrêté sur des conflits. Résolvez-les dans Contrôle de code source, puis poursuivez le rebase.", + "sync": "La synchronisation s'est arrêtée sur des conflits de fusion. Résolvez-les dans Contrôle de code source, puis commitez la fusion.", + "pull": "Le pull s'est arrêté sur des conflits de fusion. Résolvez-les dans Contrôle de code source, puis commitez la fusion." + }, + "syncRemoteMoved": "La synchronisation a échoué — le dépôt distant a changé pendant la synchronisation. Réessayez.", + "forcePushRejected": "Force push rejeté — le dépôt distant a changé depuis le dernier fetch. Faites d'abord un fetch, puis réessayez.", + "pushRejected": "Push rejeté — le dépôt distant a des modifications. Faites d'abord un pull, puis réessayez.", + "untrackedFilesBlocked": { + "rebase": "Rebase bloqué — déplacez, supprimez ou ajoutez d'abord les fichiers non suivis.", + "fastForward": "Fast-forward bloqué — déplacez, supprimez ou ajoutez d'abord les fichiers non suivis.", + "pull": "Pull bloqué — déplacez, supprimez ou ajoutez d'abord les fichiers non suivis." + }, + "authenticationFailed": "Échec de l'authentification. Vérifiez vos identifiants d'accès au dépôt distant." } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index 82a7cb07507..89eb4f12bc7 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -20343,6 +20343,79 @@ }, "enableSourceControlAi": "設定 -> Git でソース管理 AI を有効にしてください。", "chooseBaseBranch": "生成する前にベースブランチを選択してください。" + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "サブモジュール「{{name}}」にリモートの変更があります。サブモジュール内でプルしてから、もう一度お試しください。", + "remoteChanged": "サブモジュールにリモートの変更があります。サブモジュール内でプルしてから、もう一度お試しください。", + "namedPushFailed": "サブモジュール「{{name}}」をプッシュできませんでした。サブモジュールのプッシュエラーを解決してから、もう一度お試しください。", + "pushFailed": "サブモジュールをプッシュできませんでした。サブモジュールのプッシュエラーを解決してから、もう一度お試しください。" + }, + "failedWithDetail": { + "publish": "ブランチの公開に失敗しました。{{detail}}", + "sync": "同期に失敗しました。{{detail}}", + "forcePush": "フォースプッシュに失敗しました。{{detail}}", + "push": "プッシュに失敗しました。{{detail}}", + "fetch": "フェッチに失敗しました。{{detail}}", + "fastForward": "Fast-forward に失敗しました。{{detail}}", + "rebase": "リベースに失敗しました。{{detail}}", + "pull": "プルに失敗しました。{{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "ブランチの公開がブロックされました — プッシュ中に lint が失敗しました。", + "sync": "同期がブロックされました — プッシュ中に lint が失敗しました。", + "forcePush": "フォースプッシュがブロックされました — プッシュ中に lint が失敗しました。", + "push": "プッシュがブロックされました — プッシュ中に lint が失敗しました。" + }, + "prePush": { + "publish": "ブランチの公開がブロックされました — pre-push フックが失敗しました。", + "sync": "同期がブロックされました — pre-push フックが失敗しました。", + "forcePush": "フォースプッシュがブロックされました — pre-push フックが失敗しました。", + "push": "プッシュがブロックされました — pre-push フックが失敗しました。" + }, + "detail": { + "publish": "ブランチの公開がブロックされました — {{detail}}", + "sync": "同期がブロックされました — {{detail}}", + "forcePush": "フォースプッシュがブロックされました — {{detail}}", + "push": "プッシュがブロックされました — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "ブランチの公開に失敗しました。{{detail}}。リモートへのアクセスを確認して、もう一度お試しください。", + "sync": "同期に失敗しました。{{detail}}。リモートへのアクセスを確認して、もう一度お試しください。", + "forcePush": "フォースプッシュに失敗しました。{{detail}}。リモートへのアクセスを確認して、もう一度お試しください。", + "push": "プッシュに失敗しました。{{detail}}。リモートへのアクセスを確認して、もう一度お試しください。" + }, + "publishFailed": "ブランチの公開に失敗しました。リモートへのアクセスを確認して、もう一度お試しください。", + "syncFailed": "同期に失敗しました。接続を確認して、もう一度お試しください。", + "forcePushFailed": "フォースプッシュに失敗しました。接続を確認して、もう一度お試しください。", + "pushFailed": "プッシュに失敗しました。接続を確認して、もう一度お試しください。", + "localChangesBlocked": { + "rebase": "リベースがブロックされました — 先にローカルの変更をコミットまたはスタッシュしてください。", + "fastForward": "Fast-forward がブロックされました — 先にローカルの変更をコミットまたはスタッシュしてください。", + "pull": "プルがブロックされました — 先にローカルの変更をコミットまたはスタッシュしてください。" + }, + "operationFailed": "リモート操作に失敗しました", + "unconcludedMerge": { + "rebase": "リベースがブロックされました — 先に既存の競合を解決してください。", + "sync": "同期がブロックされました — 先に既存のマージ競合を解決してください。", + "pull": "プルがブロックされました — 先に既存のマージ競合を解決してください。" + }, + "mergeConflicts": { + "rebase": "リベースが競合で停止しました。ソース管理で解決してから、リベースを続行してください。", + "sync": "同期がマージ競合で停止しました。ソース管理で解決してから、マージをコミットしてください。", + "pull": "プルがマージ競合で停止しました。ソース管理で解決してから、マージをコミットしてください。" + }, + "syncRemoteMoved": "同期に失敗しました — 同期中にリモートが変更されました。もう一度お試しください。", + "forcePushRejected": "フォースプッシュが拒否されました — 最後のフェッチ以降にリモートが変更されました。先にフェッチしてから、もう一度お試しください。", + "pushRejected": "プッシュが拒否されました — リモートに変更があります。先にプルしてから、もう一度お試しください。", + "untrackedFilesBlocked": { + "rebase": "リベースがブロックされました — 先に未追跡ファイルを移動、削除、または追加してください。", + "fastForward": "Fast-forward がブロックされました — 先に未追跡ファイルを移動、削除、または追加してください。", + "pull": "プルがブロックされました — 先に未追跡ファイルを移動、削除、または追加してください。" + }, + "authenticationFailed": "認証に失敗しました。リモートの認証情報を確認してください。" } }, "rendererRecovery": { diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index f47349594f2..f15b1f0e8cb 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -20343,6 +20343,79 @@ }, "enableSourceControlAi": "설정 -> Git에서 소스 제어 AI를 활성화하세요.", "chooseBaseBranch": "생성하기 전에 기준 브랜치를 선택하세요." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "'{{name}}' 하위 모듈에 원격 변경 사항이 있습니다. 하위 모듈 내에서 풀한 후 다시 시도하세요.", + "remoteChanged": "하위 모듈에 원격 변경 사항이 있습니다. 하위 모듈 내에서 풀한 후 다시 시도하세요.", + "namedPushFailed": "'{{name}}' 하위 모듈을 푸시하지 못했습니다. 하위 모듈의 푸시 오류를 해결한 후 다시 시도하세요.", + "pushFailed": "하위 모듈을 푸시하지 못했습니다. 하위 모듈의 푸시 오류를 해결한 후 다시 시도하세요." + }, + "failedWithDetail": { + "publish": "브랜치 게시에 실패했습니다. {{detail}}", + "sync": "동기화에 실패했습니다. {{detail}}", + "forcePush": "강제 푸시에 실패했습니다. {{detail}}", + "push": "푸시에 실패했습니다. {{detail}}", + "fetch": "가져오기에 실패했습니다. {{detail}}", + "fastForward": "Fast-forward에 실패했습니다. {{detail}}", + "rebase": "리베이스에 실패했습니다. {{detail}}", + "pull": "풀에 실패했습니다. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "브랜치 게시 차단됨 — 푸시 중 lint가 실패했습니다.", + "sync": "동기화 차단됨 — 푸시 중 lint가 실패했습니다.", + "forcePush": "강제 푸시 차단됨 — 푸시 중 lint가 실패했습니다.", + "push": "푸시 차단됨 — 푸시 중 lint가 실패했습니다." + }, + "prePush": { + "publish": "브랜치 게시 차단됨 — pre-push 훅이 실패했습니다.", + "sync": "동기화 차단됨 — pre-push 훅이 실패했습니다.", + "forcePush": "강제 푸시 차단됨 — pre-push 훅이 실패했습니다.", + "push": "푸시 차단됨 — pre-push 훅이 실패했습니다." + }, + "detail": { + "publish": "브랜치 게시 차단됨 — {{detail}}", + "sync": "동기화 차단됨 — {{detail}}", + "forcePush": "강제 푸시 차단됨 — {{detail}}", + "push": "푸시 차단됨 — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "브랜치 게시에 실패했습니다. {{detail}}. 원격 저장소 접근 권한을 확인하고 다시 시도하세요.", + "sync": "동기화에 실패했습니다. {{detail}}. 원격 저장소 접근 권한을 확인하고 다시 시도하세요.", + "forcePush": "강제 푸시에 실패했습니다. {{detail}}. 원격 저장소 접근 권한을 확인하고 다시 시도하세요.", + "push": "푸시에 실패했습니다. {{detail}}. 원격 저장소 접근 권한을 확인하고 다시 시도하세요." + }, + "publishFailed": "브랜치 게시에 실패했습니다. 원격 저장소 접근 권한을 확인하고 다시 시도하세요.", + "syncFailed": "동기화에 실패했습니다. 연결을 확인하고 다시 시도하세요.", + "forcePushFailed": "강제 푸시에 실패했습니다. 연결을 확인하고 다시 시도하세요.", + "pushFailed": "푸시에 실패했습니다. 연결을 확인하고 다시 시도하세요.", + "localChangesBlocked": { + "rebase": "리베이스 차단됨 — 먼저 로컬 변경 사항을 커밋하거나 스태시하세요.", + "fastForward": "Fast-forward 차단됨 — 먼저 로컬 변경 사항을 커밋하거나 스태시하세요.", + "pull": "풀 차단됨 — 먼저 로컬 변경 사항을 커밋하거나 스태시하세요." + }, + "operationFailed": "원격 작업 실패", + "unconcludedMerge": { + "rebase": "리베이스 차단됨 — 먼저 기존 충돌을 해결하세요.", + "sync": "동기화 차단됨 — 먼저 기존 병합 충돌을 해결하세요.", + "pull": "풀 차단됨 — 먼저 기존 병합 충돌을 해결하세요." + }, + "mergeConflicts": { + "rebase": "리베이스가 충돌로 중단되었습니다. 소스 제어에서 충돌을 해결한 후 리베이스를 계속하세요.", + "sync": "동기화가 병합 충돌로 중단되었습니다. 소스 제어에서 충돌을 해결한 후 병합을 커밋하세요.", + "pull": "풀이 병합 충돌로 중단되었습니다. 소스 제어에서 충돌을 해결한 후 병합을 커밋하세요." + }, + "syncRemoteMoved": "동기화에 실패했습니다 — 동기화 중 원격 저장소가 변경되었습니다. 다시 시도하세요.", + "forcePushRejected": "강제 푸시가 거부되었습니다 — 마지막으로 가져온 이후 원격 저장소가 변경되었습니다. 먼저 가져온 후 다시 시도하세요.", + "pushRejected": "푸시가 거부되었습니다 — 원격 저장소에 변경 사항이 있습니다. 먼저 풀한 후 다시 시도하세요.", + "untrackedFilesBlocked": { + "rebase": "리베이스 차단됨 — 먼저 추적되지 않은 파일을 이동, 제거 또는 추가하세요.", + "fastForward": "Fast-forward 차단됨 — 먼저 추적되지 않은 파일을 이동, 제거 또는 추가하세요.", + "pull": "풀 차단됨 — 먼저 추적되지 않은 파일을 이동, 제거 또는 추가하세요." + }, + "authenticationFailed": "인증에 실패했습니다. 원격 인증 정보를 확인하세요." } }, "rendererRecovery": { diff --git a/src/renderer/src/i18n/locales/pt.json b/src/renderer/src/i18n/locales/pt.json index fcbf8754143..0041892035e 100644 --- a/src/renderer/src/i18n/locales/pt.json +++ b/src/renderer/src/i18n/locales/pt.json @@ -201,6 +201,79 @@ }, "enableSourceControlAi": "Ative a IA de Controle de Versão em Configurações -> Git.", "chooseBaseBranch": "Escolha uma branch base antes de gerar." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "O submódulo '{{name}}' tem alterações no remoto. Faça pull dentro do submódulo e tente novamente.", + "remoteChanged": "Um submódulo tem alterações no remoto. Faça pull dentro do submódulo e tente novamente.", + "namedPushFailed": "Não foi possível fazer push do submódulo '{{name}}'. Resolva o erro de push do submódulo e tente novamente.", + "pushFailed": "Não foi possível fazer push de um submódulo. Resolva o erro de push do submódulo e tente novamente." + }, + "failedWithDetail": { + "publish": "A publicação da branch falhou. {{detail}}", + "sync": "A sincronização falhou. {{detail}}", + "forcePush": "O force push falhou. {{detail}}", + "push": "O push falhou. {{detail}}", + "fetch": "O fetch falhou. {{detail}}", + "fastForward": "O fast-forward falhou. {{detail}}", + "rebase": "O rebase falhou. {{detail}}", + "pull": "O pull falhou. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Publicação da branch bloqueada — o lint falhou durante o push.", + "sync": "Sincronização bloqueada — o lint falhou durante o push.", + "forcePush": "Force push bloqueado — o lint falhou durante o push.", + "push": "Push bloqueado — o lint falhou durante o push." + }, + "prePush": { + "publish": "Publicação da branch bloqueada — o hook pre-push falhou.", + "sync": "Sincronização bloqueada — o hook pre-push falhou.", + "forcePush": "Force push bloqueado — o hook pre-push falhou.", + "push": "Push bloqueado — o hook pre-push falhou." + }, + "detail": { + "publish": "Publicação da branch bloqueada — {{detail}}", + "sync": "Sincronização bloqueada — {{detail}}", + "forcePush": "Force push bloqueado — {{detail}}", + "push": "Push bloqueado — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "A publicação da branch falhou. {{detail}}. Verifique seu acesso ao remoto e tente novamente.", + "sync": "A sincronização falhou. {{detail}}. Verifique seu acesso ao remoto e tente novamente.", + "forcePush": "O force push falhou. {{detail}}. Verifique seu acesso ao remoto e tente novamente.", + "push": "O push falhou. {{detail}}. Verifique seu acesso ao remoto e tente novamente." + }, + "publishFailed": "A publicação da branch falhou. Verifique seu acesso ao remoto e tente novamente.", + "syncFailed": "A sincronização falhou. Verifique sua conexão e tente novamente.", + "forcePushFailed": "O force push falhou. Verifique sua conexão e tente novamente.", + "pushFailed": "O push falhou. Verifique sua conexão e tente novamente.", + "localChangesBlocked": { + "rebase": "Rebase bloqueado — faça commit ou stash das alterações locais primeiro.", + "fastForward": "Fast-forward bloqueado — faça commit ou stash das alterações locais primeiro.", + "pull": "Pull bloqueado — faça commit ou stash das alterações locais primeiro." + }, + "operationFailed": "Falha na operação remota", + "unconcludedMerge": { + "rebase": "Rebase bloqueado — resolva os conflitos existentes primeiro.", + "sync": "Sincronização bloqueada — resolva os conflitos de merge existentes primeiro.", + "pull": "Pull bloqueado — resolva os conflitos de merge existentes primeiro." + }, + "mergeConflicts": { + "rebase": "O rebase foi interrompido por conflitos. Resolva-os no Controle de versão e depois continue o rebase.", + "sync": "A sincronização foi interrompida por conflitos de merge. Resolva-os no Controle de versão e depois faça commit do merge.", + "pull": "O pull foi interrompido por conflitos de merge. Resolva-os no Controle de versão e depois faça commit do merge." + }, + "syncRemoteMoved": "A sincronização falhou — o remoto mudou durante a sincronização. Tente novamente.", + "forcePushRejected": "Force push rejeitado — o remoto mudou desde o último fetch. Faça fetch primeiro e tente novamente.", + "pushRejected": "Push rejeitado — o remoto tem alterações. Faça pull primeiro e tente novamente.", + "untrackedFilesBlocked": { + "rebase": "Rebase bloqueado — mova, remova ou adicione os arquivos não rastreados primeiro.", + "fastForward": "Fast-forward bloqueado — mova, remova ou adicione os arquivos não rastreados primeiro.", + "pull": "Pull bloqueado — mova, remova ou adicione os arquivos não rastreados primeiro." + }, + "authenticationFailed": "Falha na autenticação. Verifique suas credenciais de acesso ao remoto." } }, "githubChecks": { diff --git a/src/renderer/src/i18n/locales/ru.json b/src/renderer/src/i18n/locales/ru.json index 64b93056e6a..a7cd994c422 100644 --- a/src/renderer/src/i18n/locales/ru.json +++ b/src/renderer/src/i18n/locales/ru.json @@ -20974,6 +20974,79 @@ }, "enableSourceControlAi": "Включите ИИ для управления версиями в разделе «Настройки -> Git».", "chooseBaseBranch": "Перед генерацией выберите базовую ветку." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "В подмодуле «{{name}}» есть изменения в удалённом репозитории. Получите и слейте изменения внутри подмодуля, затем повторите попытку.", + "remoteChanged": "В одном из подмодулей есть изменения в удалённом репозитории. Получите и слейте изменения внутри подмодуля, затем повторите попытку.", + "namedPushFailed": "Не удалось отправить подмодуль «{{name}}». Устраните ошибку отправки подмодуля, затем повторите попытку.", + "pushFailed": "Не удалось отправить один из подмодулей. Устраните ошибку отправки подмодуля, затем повторите попытку." + }, + "failedWithDetail": { + "publish": "Не удалось опубликовать ветку. {{detail}}", + "sync": "Не удалось выполнить синхронизацию. {{detail}}", + "forcePush": "Не удалось выполнить принудительную отправку. {{detail}}", + "push": "Не удалось отправить изменения. {{detail}}", + "fetch": "Не удалось получить изменения. {{detail}}", + "fastForward": "Не удалось выполнить перемотку вперёд. {{detail}}", + "rebase": "Не удалось выполнить перебазирование. {{detail}}", + "pull": "Не удалось получить и слить изменения. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Публикация ветки заблокирована — при отправке не пройдена проверка lint.", + "sync": "Синхронизация заблокирована — при отправке не пройдена проверка lint.", + "forcePush": "Принудительная отправка заблокирована — при отправке не пройдена проверка lint.", + "push": "Отправка заблокирована — при отправке не пройдена проверка lint." + }, + "prePush": { + "publish": "Публикация ветки заблокирована — хук pre-push завершился с ошибкой.", + "sync": "Синхронизация заблокирована — хук pre-push завершился с ошибкой.", + "forcePush": "Принудительная отправка заблокирована — хук pre-push завершился с ошибкой.", + "push": "Отправка заблокирована — хук pre-push завершился с ошибкой." + }, + "detail": { + "publish": "Публикация ветки заблокирована — {{detail}}", + "sync": "Синхронизация заблокирована — {{detail}}", + "forcePush": "Принудительная отправка заблокирована — {{detail}}", + "push": "Отправка заблокирована — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "Не удалось опубликовать ветку. {{detail}}. Проверьте доступ к удалённому репозиторию и повторите попытку.", + "sync": "Не удалось выполнить синхронизацию. {{detail}}. Проверьте доступ к удалённому репозиторию и повторите попытку.", + "forcePush": "Не удалось выполнить принудительную отправку. {{detail}}. Проверьте доступ к удалённому репозиторию и повторите попытку.", + "push": "Не удалось отправить изменения. {{detail}}. Проверьте доступ к удалённому репозиторию и повторите попытку." + }, + "publishFailed": "Не удалось опубликовать ветку. Проверьте доступ к удалённому репозиторию и повторите попытку.", + "syncFailed": "Не удалось выполнить синхронизацию. Проверьте соединение и повторите попытку.", + "forcePushFailed": "Не удалось выполнить принудительную отправку. Проверьте соединение и повторите попытку.", + "pushFailed": "Не удалось отправить изменения. Проверьте соединение и повторите попытку.", + "localChangesBlocked": { + "rebase": "Перебазирование заблокировано — сначала создайте коммит с локальными изменениями или уберите их в stash.", + "fastForward": "Перемотка вперёд заблокирована — сначала создайте коммит с локальными изменениями или уберите их в stash.", + "pull": "Получение и слияние заблокированы — сначала создайте коммит с локальными изменениями или уберите их в stash." + }, + "operationFailed": "Ошибка удалённой операции", + "unconcludedMerge": { + "rebase": "Перебазирование заблокировано — сначала разрешите существующие конфликты.", + "sync": "Синхронизация заблокирована — сначала разрешите существующие конфликты слияния.", + "pull": "Получение и слияние заблокированы — сначала разрешите существующие конфликты слияния." + }, + "mergeConflicts": { + "rebase": "Перебазирование остановлено из-за конфликтов. Разрешите их в разделе «Управление версиями», затем продолжите перебазирование.", + "sync": "Синхронизация остановлена из-за конфликтов слияния. Разрешите их в разделе «Управление версиями», затем создайте коммит слияния.", + "pull": "Получение и слияние остановлены из-за конфликтов слияния. Разрешите их в разделе «Управление версиями», затем создайте коммит слияния." + }, + "syncRemoteMoved": "Синхронизация не удалась — во время неё удалённый репозиторий изменился. Повторите попытку.", + "forcePushRejected": "Принудительная отправка отклонена — удалённый репозиторий изменился с момента последнего получения изменений. Сначала получите изменения, затем повторите попытку.", + "pushRejected": "Отправка отклонена — в удалённом репозитории есть изменения. Сначала получите и слейте их, затем повторите попытку.", + "untrackedFilesBlocked": { + "rebase": "Перебазирование заблокировано — сначала переместите, удалите или добавьте неотслеживаемые файлы.", + "fastForward": "Перемотка вперёд заблокирована — сначала переместите, удалите или добавьте неотслеживаемые файлы.", + "pull": "Получение и слияние заблокированы — сначала переместите, удалите или добавьте неотслеживаемые файлы." + }, + "authenticationFailed": "Ошибка аутентификации. Проверьте учётные данные для удалённого репозитория." } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/tr.json b/src/renderer/src/i18n/locales/tr.json index f83b1a345f7..3a850b3cefa 100644 --- a/src/renderer/src/i18n/locales/tr.json +++ b/src/renderer/src/i18n/locales/tr.json @@ -20330,6 +20330,79 @@ }, "enableSourceControlAi": "Ayarlar -> Git bölümünde Kaynak Kontrolü AI özelliğini etkinleştirin.", "chooseBaseBranch": "Oluşturmadan önce bir temel branch seçin." + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "Alt modül '{{name}}' için remote'da değişiklikler var. Alt modülün içinde pull yapın, ardından tekrar deneyin.", + "remoteChanged": "Bir alt modül için remote'da değişiklikler var. Alt modülün içinde pull yapın, ardından tekrar deneyin.", + "namedPushFailed": "Alt modül '{{name}}' gönderilemedi. Alt modülün gönderme hatasını giderip tekrar deneyin.", + "pushFailed": "Bir alt modül gönderilemedi. Alt modülün gönderme hatasını giderip tekrar deneyin." + }, + "failedWithDetail": { + "publish": "Branch yayınlanamadı. {{detail}}", + "sync": "Senkronizasyon yapılamadı. {{detail}}", + "forcePush": "Force push yapılamadı. {{detail}}", + "push": "Gönderme işlemi yapılamadı. {{detail}}", + "fetch": "Fetch yapılamadı. {{detail}}", + "fastForward": "Fast-forward yapılamadı. {{detail}}", + "rebase": "Rebase yapılamadı. {{detail}}", + "pull": "Pull yapılamadı. {{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "Branch yayını engellendi — push sırasında lint kontrolü geçilemedi.", + "sync": "Senkronizasyon engellendi — push sırasında lint kontrolü geçilemedi.", + "forcePush": "Force push engellendi — push sırasında lint kontrolü geçilemedi.", + "push": "Gönderme engellendi — push sırasında lint kontrolü geçilemedi." + }, + "prePush": { + "publish": "Branch yayını engellendi — pre-push hook'u tamamlanamadı.", + "sync": "Senkronizasyon engellendi — pre-push hook'u tamamlanamadı.", + "forcePush": "Force push engellendi — pre-push hook'u tamamlanamadı.", + "push": "Gönderme engellendi — pre-push hook'u tamamlanamadı." + }, + "detail": { + "publish": "Branch yayını engellendi — {{detail}}", + "sync": "Senkronizasyon engellendi — {{detail}}", + "forcePush": "Force push engellendi — {{detail}}", + "push": "Gönderme engellendi — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "Branch yayınlanamadı. {{detail}}. Remote erişiminizi kontrol edip tekrar deneyin.", + "sync": "Senkronizasyon yapılamadı. {{detail}}. Remote erişiminizi kontrol edip tekrar deneyin.", + "forcePush": "Force push yapılamadı. {{detail}}. Remote erişiminizi kontrol edip tekrar deneyin.", + "push": "Gönderme işlemi yapılamadı. {{detail}}. Remote erişiminizi kontrol edip tekrar deneyin." + }, + "publishFailed": "Branch yayınlanamadı. Remote erişiminizi kontrol edip tekrar deneyin.", + "syncFailed": "Senkronizasyon yapılamadı. Bağlantınızı kontrol edip tekrar deneyin.", + "forcePushFailed": "Force push yapılamadı. Bağlantınızı kontrol edip tekrar deneyin.", + "pushFailed": "Gönderme işlemi yapılamadı. Bağlantınızı kontrol edip tekrar deneyin.", + "localChangesBlocked": { + "rebase": "Rebase engellendi — önce yerel değişikliklerinizi commit'leyin veya stash'leyin.", + "fastForward": "Fast-forward engellendi — önce yerel değişikliklerinizi commit'leyin veya stash'leyin.", + "pull": "Pull engellendi — önce yerel değişikliklerinizi commit'leyin veya stash'leyin." + }, + "operationFailed": "Remote işlemi yapılamadı", + "unconcludedMerge": { + "rebase": "Rebase engellendi — önce mevcut çakışmaları çözün.", + "sync": "Senkronizasyon engellendi — önce mevcut merge çakışmalarını çözün.", + "pull": "Pull engellendi — önce mevcut merge çakışmalarını çözün." + }, + "mergeConflicts": { + "rebase": "Rebase çakışmalar nedeniyle durdu. Kaynak Kontrolü bölümünde çakışmaları çözün, ardından rebase'e devam edin.", + "sync": "Senkronizasyon merge çakışmaları nedeniyle durdu. Kaynak Kontrolü bölümünde çakışmaları çözün, ardından merge işlemini commit'leyin.", + "pull": "Pull merge çakışmaları nedeniyle durdu. Kaynak Kontrolü bölümünde çakışmaları çözün, ardından merge işlemini commit'leyin." + }, + "syncRemoteMoved": "Senkronizasyon yapılamadı — senkronizasyon sırasında remote değişti. Tekrar deneyin.", + "forcePushRejected": "Force push reddedildi — son fetch'ten bu yana remote değişti. Önce fetch yapıp tekrar deneyin.", + "pushRejected": "Push reddedildi — remote'da değişiklikler var. Önce pull yapıp tekrar deneyin.", + "untrackedFilesBlocked": { + "rebase": "Rebase engellendi — önce izlenmeyen dosyaları taşıyın, kaldırın veya ekleyin.", + "fastForward": "Fast-forward engellendi — önce izlenmeyen dosyaları taşıyın, kaldırın veya ekleyin.", + "pull": "Pull engellendi — önce izlenmeyen dosyaları taşıyın, kaldırın veya ekleyin." + }, + "authenticationFailed": "Kimlik doğrulanamadı. Remote kimlik bilgilerinizi kontrol edin." } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/zh-Hant.json b/src/renderer/src/i18n/locales/zh-Hant.json index 0285482033d..fbe024e0382 100644 --- a/src/renderer/src/i18n/locales/zh-Hant.json +++ b/src/renderer/src/i18n/locales/zh-Hant.json @@ -20062,6 +20062,79 @@ }, "enableSourceControlAi": "請在「設定 -> Git」中啟用原始碼控制 AI。", "chooseBaseBranch": "產生前請先選擇基礎分支。" + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "子模組「{{name}}」有遠端變更。請在子模組內拉取後再試一次。", + "remoteChanged": "某個子模組有遠端變更。請在子模組內拉取後再試一次。", + "namedPushFailed": "無法推送子模組「{{name}}」。請解決子模組的推送錯誤後再試一次。", + "pushFailed": "無法推送某個子模組。請解決子模組的推送錯誤後再試一次。" + }, + "failedWithDetail": { + "publish": "發布分支失敗。{{detail}}", + "sync": "同步失敗。{{detail}}", + "forcePush": "強制推送失敗。{{detail}}", + "push": "推送失敗。{{detail}}", + "fetch": "擷取失敗。{{detail}}", + "fastForward": "快轉失敗。{{detail}}", + "rebase": "變基失敗。{{detail}}", + "pull": "拉取失敗。{{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "分支發布遭阻擋 — 推送期間 lint 失敗。", + "sync": "同步遭阻擋 — 推送期間 lint 失敗。", + "forcePush": "強制推送遭阻擋 — 推送期間 lint 失敗。", + "push": "推送遭阻擋 — 推送期間 lint 失敗。" + }, + "prePush": { + "publish": "分支發布遭阻擋 — pre-push 鉤子失敗。", + "sync": "同步遭阻擋 — pre-push 鉤子失敗。", + "forcePush": "強制推送遭阻擋 — pre-push 鉤子失敗。", + "push": "推送遭阻擋 — pre-push 鉤子失敗。" + }, + "detail": { + "publish": "分支發布遭阻擋 — {{detail}}", + "sync": "同步遭阻擋 — {{detail}}", + "forcePush": "強制推送遭阻擋 — {{detail}}", + "push": "推送遭阻擋 — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "發布分支失敗。{{detail}}。請檢查遠端存取權限後再試一次。", + "sync": "同步失敗。{{detail}}。請檢查遠端存取權限後再試一次。", + "forcePush": "強制推送失敗。{{detail}}。請檢查遠端存取權限後再試一次。", + "push": "推送失敗。{{detail}}。請檢查遠端存取權限後再試一次。" + }, + "publishFailed": "發布分支失敗。請檢查遠端存取權限後再試一次。", + "syncFailed": "同步失敗。請檢查連線後再試一次。", + "forcePushFailed": "強制推送失敗。請檢查連線後再試一次。", + "pushFailed": "推送失敗。請檢查連線後再試一次。", + "localChangesBlocked": { + "rebase": "變基遭阻擋 — 請先提交或儲藏本機變更。", + "fastForward": "快轉遭阻擋 — 請先提交或儲藏本機變更。", + "pull": "拉取遭阻擋 — 請先提交或儲藏本機變更。" + }, + "operationFailed": "遠端操作失敗", + "unconcludedMerge": { + "rebase": "變基遭阻擋 — 請先解決現有衝突。", + "sync": "同步遭阻擋 — 請先解決現有合併衝突。", + "pull": "拉取遭阻擋 — 請先解決現有合併衝突。" + }, + "mergeConflicts": { + "rebase": "變基因衝突而停止。請在原始碼控制中解決衝突,再繼續變基。", + "sync": "同步因合併衝突而停止。請在原始碼控制中解決衝突,再提交合併。", + "pull": "拉取因合併衝突而停止。請在原始碼控制中解決衝突,再提交合併。" + }, + "syncRemoteMoved": "同步失敗 — 同步期間遠端已變更。請再試一次。", + "forcePushRejected": "強制推送遭拒 — 自上次擷取以來,遠端已有變更。請先擷取後再試一次。", + "pushRejected": "推送遭拒 — 遠端有變更。請先拉取後再試一次。", + "untrackedFilesBlocked": { + "rebase": "變基遭阻擋 — 請先移動、移除或新增未追蹤的檔案。", + "fastForward": "快轉遭阻擋 — 請先移動、移除或新增未追蹤的檔案。", + "pull": "拉取遭阻擋 — 請先移動、移除或新增未追蹤的檔案。" + }, + "authenticationFailed": "身分驗證失敗。請檢查遠端憑證。" } }, "agentsSidebarIntro": { diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index 895183cdacb..4a498473c6f 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -20344,6 +20344,79 @@ }, "enableSourceControlAi": "请在设置 -> Git 中启用源代码控制 AI。", "chooseBaseBranch": "请先选择基础分支,再生成。" + }, + "remoteError": { + "submodule": { + "namedRemoteChanged": "子模块“{{name}}”有远程更改。请在子模块内拉取后重试。", + "remoteChanged": "某个子模块有远程更改。请在子模块内拉取后重试。", + "namedPushFailed": "无法推送子模块“{{name}}”。请解决子模块的推送错误后重试。", + "pushFailed": "无法推送某个子模块。请解决子模块的推送错误后重试。" + }, + "failedWithDetail": { + "publish": "发布分支失败。{{detail}}", + "sync": "同步失败。{{detail}}", + "forcePush": "强制推送失败。{{detail}}", + "push": "推送失败。{{detail}}", + "fetch": "获取失败。{{detail}}", + "fastForward": "快进失败。{{detail}}", + "rebase": "变基失败。{{detail}}", + "pull": "拉取失败。{{detail}}" + }, + "hookBlocked": { + "lint": { + "publish": "发布分支被阻止 — 推送时 lint 失败。", + "sync": "同步被阻止 — 推送时 lint 失败。", + "forcePush": "强制推送被阻止 — 推送时 lint 失败。", + "push": "推送被阻止 — 推送时 lint 失败。" + }, + "prePush": { + "publish": "发布分支被阻止 — pre-push 钩子失败。", + "sync": "同步被阻止 — pre-push 钩子失败。", + "forcePush": "强制推送被阻止 — pre-push 钩子失败。", + "push": "推送被阻止 — pre-push 钩子失败。" + }, + "detail": { + "publish": "发布分支被阻止 — {{detail}}", + "sync": "同步被阻止 — {{detail}}", + "forcePush": "强制推送被阻止 — {{detail}}", + "push": "推送被阻止 — {{detail}}" + } + }, + "remoteAccessWithDetail": { + "publish": "发布分支失败。{{detail}}。请检查远程访问权限后重试。", + "sync": "同步失败。{{detail}}。请检查远程访问权限后重试。", + "forcePush": "强制推送失败。{{detail}}。请检查远程访问权限后重试。", + "push": "推送失败。{{detail}}。请检查远程访问权限后重试。" + }, + "publishFailed": "发布分支失败。请检查远程访问权限后重试。", + "syncFailed": "同步失败。请检查连接后重试。", + "forcePushFailed": "强制推送失败。请检查连接后重试。", + "pushFailed": "推送失败。请检查连接后重试。", + "localChangesBlocked": { + "rebase": "变基被阻止 — 请先提交本地更改或将其存入 stash。", + "fastForward": "快进被阻止 — 请先提交本地更改或将其存入 stash。", + "pull": "拉取被阻止 — 请先提交本地更改或将其存入 stash。" + }, + "operationFailed": "远程操作失败", + "unconcludedMerge": { + "rebase": "变基被阻止 — 请先解决现有冲突。", + "sync": "同步被阻止 — 请先解决现有合并冲突。", + "pull": "拉取被阻止 — 请先解决现有合并冲突。" + }, + "mergeConflicts": { + "rebase": "变基因冲突而停止。请在源代码控制中解决冲突,然后继续变基。", + "sync": "同步因合并冲突而停止。请在源代码控制中解决冲突,然后提交合并。", + "pull": "拉取因合并冲突而停止。请在源代码控制中解决冲突,然后提交合并。" + }, + "syncRemoteMoved": "同步失败 — 同步期间远程发生了更改。请重试。", + "forcePushRejected": "强制推送被拒绝 — 远程在上次获取后发生了更改。请先获取,再重试。", + "pushRejected": "推送被拒绝 — 远程有更改。请先拉取,再重试。", + "untrackedFilesBlocked": { + "rebase": "变基被阻止 — 请先移动、移除或添加未跟踪文件。", + "fastForward": "快进被阻止 — 请先移动、移除或添加未跟踪文件。", + "pull": "拉取被阻止 — 请先移动、移除或添加未跟踪文件。" + }, + "authenticationFailed": "身份验证失败。请检查远程凭据。" } }, "rendererRecovery": { diff --git a/src/renderer/src/lib/source-control-remote-error-copy.ts b/src/renderer/src/lib/source-control-remote-error-copy.ts new file mode 100644 index 00000000000..a50055793ee --- /dev/null +++ b/src/renderer/src/lib/source-control-remote-error-copy.ts @@ -0,0 +1,306 @@ +import { translate } from '@/i18n/i18n' +import { + classifySubmodulePushFailure, + formatSubmodulePushFailureSentence +} from '../../../shared/git-remote-error' +import { + LINT_PUSH_FAILURE_SUMMARY, + PRE_PUSH_FAILURE_SUMMARY +} from '../../../shared/source-control-push-failure' + +export type PushLikeOperation = 'publish' | 'sync' | 'forcePush' | 'push' +export type RemoteOperation = PushLikeOperation | 'fetch' | 'fastForward' | 'rebase' | 'pull' +// Sync shares pull wording for merge refusals; fast-forward only differs for overwrite refusals. +export type PullLikeOperation = 'rebase' | 'sync' | 'fastForward' | 'pull' + +export function translateSubmodulePushFailureDetail(message: string): string | null { + const failure = classifySubmodulePushFailure(message) + if (!failure) { + return null + } + // Case-variant normalized text is not Orca's sentence; show it verbatim. + if ( + failure.detail !== + formatSubmodulePushFailureSentence(failure.submoduleName, failure.remoteChanged) + ) { + return failure.detail + } + const name = failure.submoduleName + if (failure.remoteChanged) { + return name + ? translate( + 'sourceControl.remoteError.submodule.namedRemoteChanged', + "Submodule '{{name}}' has remote changes. Pull inside the submodule, then try again.", + { name } + ) + : translate( + 'sourceControl.remoteError.submodule.remoteChanged', + 'A submodule has remote changes. Pull inside the submodule, then try again.' + ) + } + return name + ? translate( + 'sourceControl.remoteError.submodule.namedPushFailed', + "Submodule '{{name}}' could not be pushed. Resolve the submodule push error, then try again.", + { name } + ) + : translate( + 'sourceControl.remoteError.submodule.pushFailed', + 'A submodule could not be pushed. Resolve the submodule push error, then try again.' + ) +} + +// Detail is a whole sentence (translated Orca copy or verbatim git output). +export function operationFailedWithDetail(operation: RemoteOperation, detail: string): string { + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.failedWithDetail.publish', + 'Publish Branch failed. {{detail}}', + { detail } + ) + case 'sync': + return translate( + 'sourceControl.remoteError.failedWithDetail.sync', + 'Sync failed. {{detail}}', + { + detail + } + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.failedWithDetail.forcePush', + 'Force Push failed. {{detail}}', + { detail } + ) + case 'push': + return translate( + 'sourceControl.remoteError.failedWithDetail.push', + 'Push failed. {{detail}}', + { + detail + } + ) + case 'fetch': + return translate( + 'sourceControl.remoteError.failedWithDetail.fetch', + 'Fetch failed. {{detail}}', + { detail } + ) + case 'fastForward': + return translate( + 'sourceControl.remoteError.failedWithDetail.fastForward', + 'Fast-forward failed. {{detail}}', + { detail } + ) + case 'rebase': + return translate( + 'sourceControl.remoteError.failedWithDetail.rebase', + 'Rebase failed. {{detail}}', + { detail } + ) + case 'pull': + return translate( + 'sourceControl.remoteError.failedWithDetail.pull', + 'Pull failed. {{detail}}', + { + detail + } + ) + } +} + +export function pushHookBlockedMessage(operation: PushLikeOperation, summary: string): string { + if (summary === LINT_PUSH_FAILURE_SUMMARY) { + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.hookBlocked.lint.publish', + 'Publish Branch blocked — lint failed during push.' + ) + case 'sync': + return translate( + 'sourceControl.remoteError.hookBlocked.lint.sync', + 'Sync blocked — lint failed during push.' + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.hookBlocked.lint.forcePush', + 'Force Push blocked — lint failed during push.' + ) + case 'push': + return translate( + 'sourceControl.remoteError.hookBlocked.lint.push', + 'Push blocked — lint failed during push.' + ) + } + } + if (summary === PRE_PUSH_FAILURE_SUMMARY) { + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.hookBlocked.prePush.publish', + 'Publish Branch blocked — pre-push hook failed.' + ) + case 'sync': + return translate( + 'sourceControl.remoteError.hookBlocked.prePush.sync', + 'Sync blocked — pre-push hook failed.' + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.hookBlocked.prePush.forcePush', + 'Force Push blocked — pre-push hook failed.' + ) + case 'push': + return translate( + 'sourceControl.remoteError.hookBlocked.prePush.push', + 'Push blocked — pre-push hook failed.' + ) + } + } + // Raw hook output line; lowercase its first letter to read as a clause after the dash. + const detail = `${summary.charAt(0).toLowerCase()}${summary.slice(1)}` + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.hookBlocked.detail.publish', + 'Publish Branch blocked — {{detail}}', + { detail } + ) + case 'sync': + return translate( + 'sourceControl.remoteError.hookBlocked.detail.sync', + 'Sync blocked — {{detail}}', + { + detail + } + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.hookBlocked.detail.forcePush', + 'Force Push blocked — {{detail}}', + { detail } + ) + case 'push': + return translate( + 'sourceControl.remoteError.hookBlocked.detail.push', + 'Push blocked — {{detail}}', + { + detail + } + ) + } +} + +export function remoteAccessFailedMessage( + operation: PushLikeOperation, + detail: string | null +): string { + if (detail) { + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.remoteAccessWithDetail.publish', + 'Publish Branch failed. {{detail}}. Check your remote access and try again.', + { detail } + ) + case 'sync': + return translate( + 'sourceControl.remoteError.remoteAccessWithDetail.sync', + 'Sync failed. {{detail}}. Check your remote access and try again.', + { detail } + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.remoteAccessWithDetail.forcePush', + 'Force Push failed. {{detail}}. Check your remote access and try again.', + { detail } + ) + case 'push': + return translate( + 'sourceControl.remoteError.remoteAccessWithDetail.push', + 'Push failed. {{detail}}. Check your remote access and try again.', + { detail } + ) + } + } + switch (operation) { + case 'publish': + return translate( + 'sourceControl.remoteError.publishFailed', + 'Publish Branch failed. Check your remote access and try again.' + ) + case 'sync': + return translate( + 'sourceControl.remoteError.syncFailed', + 'Sync failed. Check your connection and try again.' + ) + case 'forcePush': + return translate( + 'sourceControl.remoteError.forcePushFailed', + 'Force Push failed. Check your connection and try again.' + ) + case 'push': + return translate( + 'sourceControl.remoteError.pushFailed', + 'Push failed. Check your connection and try again.' + ) + } +} + +export function localChangesBlockedMessage(operation: PullLikeOperation): string { + if (operation === 'rebase') { + return translate( + 'sourceControl.remoteError.localChangesBlocked.rebase', + 'Rebase blocked — commit or stash your local changes first.' + ) + } + if (operation === 'fastForward') { + return translate( + 'sourceControl.remoteError.localChangesBlocked.fastForward', + 'Fast-forward blocked — commit or stash your local changes first.' + ) + } + return translate( + 'sourceControl.remoteError.localChangesBlocked.pull', + 'Pull blocked — commit or stash your local changes first.' + ) +} + +export function untrackedFilesBlockedMessage(operation: PullLikeOperation): string { + if (operation === 'rebase') { + return translate( + 'sourceControl.remoteError.untrackedFilesBlocked.rebase', + 'Rebase blocked — move, remove, or add untracked files first.' + ) + } + if (operation === 'fastForward') { + return translate( + 'sourceControl.remoteError.untrackedFilesBlocked.fastForward', + 'Fast-forward blocked — move, remove, or add untracked files first.' + ) + } + return translate( + 'sourceControl.remoteError.untrackedFilesBlocked.pull', + 'Pull blocked — move, remove, or add untracked files first.' + ) +} + +export function mergeConflictsMessage(operation: PullLikeOperation): string { + if (operation === 'rebase') { + return translate( + 'sourceControl.remoteError.mergeConflicts.rebase', + 'Rebase stopped with conflicts. Resolve them in Source Control, then continue the rebase.' + ) + } + return operation === 'sync' + ? translate( + 'sourceControl.remoteError.mergeConflicts.sync', + 'Sync stopped with merge conflicts. Resolve them in Source Control, then commit the merge.' + ) + : translate( + 'sourceControl.remoteError.mergeConflicts.pull', + 'Pull stopped with merge conflicts. Resolve them in Source Control, then commit the merge.' + ) +} diff --git a/src/renderer/src/lib/source-control-remote-error.test.ts b/src/renderer/src/lib/source-control-remote-error.test.ts index 57db857e539..d363ef3697f 100644 --- a/src/renderer/src/lib/source-control-remote-error.test.ts +++ b/src/renderer/src/lib/source-control-remote-error.test.ts @@ -1,7 +1,15 @@ -import { describe, expect, it } from 'vitest' +import { afterEach, describe, expect, it } from 'vitest' +import { i18n } from '@/i18n/i18n' +import es from '@/i18n/locales/es.json' import { resolveRemoteOperationErrorMessage } from './source-control-remote-error' +const originalLanguage = i18n.language + +afterEach(async () => { + await i18n.changeLanguage(originalLanguage) +}) + describe('source-control remote error formatting', () => { it('prefers fatal detail over an earlier remote detail for publish failures', () => { const error = new Error('remote: protected branch\r\nfatal: Authentication failed\r\n') @@ -64,4 +72,21 @@ describe('source-control remote error formatting', () => { "Push failed. Submodule 'deps/lib' could not be pushed. Resolve the submodule push error, then try again." ) }) + it('translates classified sentences and passes unclassified errors through verbatim', async () => { + i18n.addResourceBundle('es', 'translation', es) + await i18n.changeLanguage('es') + const submoduleError = new Error( + "Command failed: git push\nUnable to push submodule 'deps/lib'\nfatal: failed to push all needed submodules" + ) + + expect(resolveRemoteOperationErrorMessage(submoduleError, { isPush: true })).toBe( + es.sourceControl.remoteError.failedWithDetail.push.replace( + '{{detail}}', + es.sourceControl.remoteError.submodule.namedPushFailed.replace('{{name}}', 'deps/lib') + ) + ) + expect(resolveRemoteOperationErrorMessage(new Error('some new git failure'))).toBe( + 'some new git failure' + ) + }) }) diff --git a/src/renderer/src/lib/source-control-remote-error.ts b/src/renderer/src/lib/source-control-remote-error.ts index fe388b972a5..7f75daa2f8d 100644 --- a/src/renderer/src/lib/source-control-remote-error.ts +++ b/src/renderer/src/lib/source-control-remote-error.ts @@ -1,3 +1,4 @@ +import { translate } from '@/i18n/i18n' import { GIT_AUTHENTICATION_FAILED_MESSAGE, formatSubmodulePushFailureDetail, @@ -7,8 +8,19 @@ import { isPushHookFailure, summarizePushFailure } from '../../../shared/source-control-push-failure' +import { + type PullLikeOperation, + type PushLikeOperation, + type RemoteOperation, + localChangesBlockedMessage, + mergeConflictsMessage, + operationFailedWithDetail, + pushHookBlockedMessage, + remoteAccessFailedMessage, + translateSubmodulePushFailureDetail, + untrackedFilesBlockedMessage +} from './source-control-remote-error-copy' -const REMOTE_OPERATION_FAILED_MESSAGE = 'Remote operation failed' const REMOTE_OPERATION_DETAIL_MAX_LENGTH = 200 const SYNC_PUSH_STAGE_ERROR = Symbol('source-control-sync-push-stage-error') type SyncPushStageMarkedError = Error & { [SYNC_PUSH_STAGE_ERROR]?: true } @@ -65,10 +77,10 @@ function* iterateRemoteErrorLines(message: string): Generator { function resolveSubmodulePushFailureMessage( message: string, - operationLabel: string + operation: PushLikeOperation ): string | null { - const detail = formatSubmodulePushFailureDetail(message) - return detail ? `${operationLabel} failed. ${truncateDetail(detail)}` : null + const detail = translateSubmodulePushFailureDetail(message) + return detail ? operationFailedWithDetail(operation, truncateDetail(detail)) : null } function isNonFastForwardRemoteError(error: unknown): boolean { @@ -108,6 +120,24 @@ export function isSyncPushStageError(error: unknown): boolean { ) } +function unconcludedMergeMessage(operation: PullLikeOperation): string { + if (operation === 'rebase') { + return translate( + 'sourceControl.remoteError.unconcludedMerge.rebase', + 'Rebase blocked — resolve existing conflicts first.' + ) + } + return operation === 'sync' + ? translate( + 'sourceControl.remoteError.unconcludedMerge.sync', + 'Sync blocked — resolve existing merge conflicts first.' + ) + : translate( + 'sourceControl.remoteError.unconcludedMerge.pull', + 'Pull blocked — resolve existing merge conflicts first.' + ) +} + // Share merge-error patterns so unconcluded/fresh-conflict wording stays consistent. const UNCONCLUDED_MERGE_ERROR_PATTERN = /unmerged files|needs merge|you have not concluded your merge/i @@ -118,50 +148,48 @@ export function resolveRemoteOperationErrorMessage( options?: RemoteOperationErrorOptions ): string { if (!(error instanceof Error)) { - return REMOTE_OPERATION_FAILED_MESSAGE + return translate('sourceControl.remoteError.operationFailed', 'Remote operation failed') } + const pullLikeOperation: PullLikeOperation = options?.isRebase + ? 'rebase' + : options?.isSync + ? 'sync' + : options?.isFastForward + ? 'fastForward' + : 'pull' + if (UNCONCLUDED_MERGE_ERROR_PATTERN.test(error.message)) { - if (options?.isRebase) { - return 'Rebase blocked — resolve existing conflicts first.' - } - return options?.isSync - ? 'Sync blocked — resolve existing merge conflicts first.' - : 'Pull blocked — resolve existing merge conflicts first.' + return unconcludedMergeMessage(pullLikeOperation) } if (FRESH_MERGE_CONFLICT_ERROR_PATTERN.test(error.message)) { - if (options?.isRebase) { - return 'Rebase stopped with conflicts. Resolve them in Source Control, then continue the rebase.' - } - return options?.isSync - ? 'Sync stopped with merge conflicts. Resolve them in Source Control, then commit the merge.' - : 'Pull stopped with merge conflicts. Resolve them in Source Control, then commit the merge.' + return mergeConflictsMessage(pullLikeOperation) } if (options?.publish) { - const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'Publish Branch') + const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'publish') if (submoduleMessage) { return submoduleMessage } } if (options?.isSync) { - const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'Sync') + const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'sync') if (submoduleMessage) { return submoduleMessage } } if (options?.isForcePush) { - const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'Force Push') + const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'forcePush') if (submoduleMessage) { return submoduleMessage } } if (options?.isPush) { - const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'Push') + const submoduleMessage = resolveSubmodulePushFailureMessage(error.message, 'push') if (submoduleMessage) { return submoduleMessage } @@ -170,15 +198,14 @@ export function resolveRemoteOperationErrorMessage( const isPushLikeOperation = options?.isPush || options?.isForcePush || options?.publish || options?.isSyncPushStage if (isPushLikeOperation && isPushHookFailure(error.message)) { - const summary = summarizePushFailure(error.message) - const operationLabel = options?.publish - ? 'Publish Branch' + const operation: PushLikeOperation = options?.publish + ? 'publish' : options?.isSyncPushStage - ? 'Sync' + ? 'sync' : options?.isForcePush - ? 'Force Push' - : 'Push' - return `${operationLabel} blocked — ${summary.charAt(0).toLowerCase()}${summary.slice(1)}` + ? 'forcePush' + : 'push' + return pushHookBlockedMessage(operation, summarizePushFailure(error.message)) } // Sync already pulled; NFF means the remote raced before its inner push. Choose sync wording before the shared push path, never misleading Pull first advice. @@ -186,7 +213,10 @@ export function resolveRemoteOperationErrorMessage( options?.isSync && /non-fast-forward|fetch first|updates were rejected/i.test(error.message) ) { - return 'Sync failed — remote moved while syncing. Try again.' + return translate( + 'sourceControl.remoteError.syncRemoteMoved', + 'Sync failed — remote moved while syncing. Try again.' + ) } // Lease rejection means remote changed since our snapshot; Pull first could reintroduce commits the explicit force-push meant to replace. @@ -194,12 +224,18 @@ export function resolveRemoteOperationErrorMessage( options?.isForcePush && /non-fast-forward|fetch first|updates were rejected|stale info/i.test(error.message) ) { - return 'Force push rejected — remote changed since last fetch. Fetch first, then try again.' + return translate( + 'sourceControl.remoteError.forcePushRejected', + 'Force push rejected — remote changed since last fetch. Fetch first, then try again.' + ) } // Share rejected/NFF handling across publish and push for consistent actions. if (/non-fast-forward|fetch first|updates were rejected/i.test(error.message)) { - return 'Push rejected — remote has changes. Pull first, then try again.' + return translate( + 'sourceControl.remoteError.pushRejected', + 'Push rejected — remote has changes. Pull first, then try again.' + ) } // Collapse overwritten-worktree refusal to one line instead of listing every affected path in the toast. @@ -208,110 +244,74 @@ export function resolveRemoteOperationErrorMessage( error.message ) ) { - if (options?.isRebase) { - return 'Rebase blocked — commit or stash your local changes first.' - } - if (options?.isFastForward) { - return 'Fast-forward blocked — commit or stash your local changes first.' - } - return 'Pull blocked — commit or stash your local changes first.' + return localChangesBlockedMessage(pullLikeOperation) } if (/Pull would overwrite local changes/i.test(error.message)) { - if (options?.isRebase) { - return 'Rebase blocked — commit or stash your local changes first.' - } - if (options?.isFastForward) { - return 'Fast-forward blocked — commit or stash your local changes first.' - } - return 'Pull blocked — commit or stash your local changes first.' + return localChangesBlockedMessage(pullLikeOperation) } if (/Pull would overwrite untracked files/i.test(error.message)) { - if (options?.isRebase) { - return 'Rebase blocked — move, remove, or add untracked files first.' - } - if (options?.isFastForward) { - return 'Fast-forward blocked — move, remove, or add untracked files first.' - } - return 'Pull blocked — move, remove, or add untracked files first.' + return untrackedFilesBlockedMessage(pullLikeOperation) } // Why: the normalized auth message has no `fatal:` line and usually arrives IPC/RPC-wrapped. if (error.message.includes(GIT_AUTHENTICATION_FAILED_MESSAGE)) { - const operationLabel = options?.publish - ? 'Publish Branch' + const operation: RemoteOperation = options?.publish + ? 'publish' : options?.isSync - ? 'Sync' + ? 'sync' : options?.isForcePush - ? 'Force Push' + ? 'forcePush' : options?.isPush - ? 'Push' + ? 'push' : options?.isFetch - ? 'Fetch' + ? 'fetch' : options?.isFastForward - ? 'Fast-forward' + ? 'fastForward' : options?.isRebase - ? 'Rebase' - : 'Pull' - return `${operationLabel} failed. ${GIT_AUTHENTICATION_FAILED_MESSAGE}` + ? 'rebase' + : 'pull' + return operationFailedWithDetail( + operation, + translate( + 'sourceControl.remoteError.authenticationFailed', + 'Authentication failed. Check your remote credentials.' + ) + ) } if (options?.publish) { // Unwrap publish git/IPC errors while preserving actionable fatal reasons. - const detail = extractPublishFailureDetail(error.message) - if (detail) { - return `Publish Branch failed. ${detail}. Check your remote access and try again.` - } - - return 'Publish Branch failed. Check your remote access and try again.' + return remoteAccessFailedMessage('publish', extractPublishFailureDetail(error.message)) } if (options?.isSync) { // Sync reports its own failure, retaining push detail extraction for auth/protected-branch guidance. - const detail = extractPublishFailureDetail(error.message) - if (detail) { - return `Sync failed. ${detail}. Check your remote access and try again.` - } - return 'Sync failed. Check your connection and try again.' + return remoteAccessFailedMessage('sync', extractPublishFailureDetail(error.message)) } if (options?.isForcePush) { - const detail = extractPublishFailureDetail(error.message) - if (detail) { - return `Force Push failed. ${detail}. Check your remote access and try again.` - } - return 'Force Push failed. Check your connection and try again.' + return remoteAccessFailedMessage('forcePush', extractPublishFailureDetail(error.message)) } if (options?.isPush) { // Prefer git fatal/remote detail over generic connection messages for auth/protected-branch failures. - const detail = extractPublishFailureDetail(error.message) - if (detail) { - return `Push failed. ${detail}. Check your remote access and try again.` - } - return 'Push failed. Check your connection and try again.' + return remoteAccessFailedMessage('push', extractPublishFailureDetail(error.message)) } - if (options?.isFetch) { + const verbatimOperation: RemoteOperation | null = options?.isFetch + ? 'fetch' + : options?.isFastForward + ? 'fastForward' + : options?.isRebase + ? 'rebase' + : null + if (verbatimOperation) { const detail = extractPublishFailureDetail(error.message) ?? truncateDetail(stripCredentialsFromMessage(error.message)) - return `Fetch failed. ${detail}` - } - - if (options?.isFastForward) { - const detail = - extractPublishFailureDetail(error.message) ?? - truncateDetail(stripCredentialsFromMessage(error.message)) - return `Fast-forward failed. ${detail}` - } - - if (options?.isRebase) { - const detail = - extractPublishFailureDetail(error.message) ?? - truncateDetail(stripCredentialsFromMessage(error.message)) - return `Rebase failed. ${detail}` + return operationFailedWithDetail(verbatimOperation, detail) } return error.message diff --git a/src/shared/git-remote-error.ts b/src/shared/git-remote-error.ts index b8bb5efd2a9..c14facd6d7c 100644 --- a/src/shared/git-remote-error.ts +++ b/src/shared/git-remote-error.ts @@ -9,7 +9,7 @@ const SUBMODULE_PUSH_FAILURE_SENTINEL_PATTERN = const SUBMODULE_REMOTE_CHANGED_PATTERN = /non-fast-forward|fetch first|updates were rejected|remote contains work that you do not have/i const NORMALIZED_SUBMODULE_PUSH_FAILURE_PATTERN = - /(?:^|:\s)((?:Submodule '[^'\n]+'|A submodule) (?:has remote changes\. Pull inside the submodule, then try again\.|could not be pushed\. Resolve the submodule push error, then try again\.))(?:$|\s)/i + /(?:^|:\s)((?:Submodule '([^'\n]+)'|A submodule) (?:(has remote changes)\. Pull inside the submodule, then try again\.|could not be pushed\. Resolve the submodule push error, then try again\.))(?:$|\s)/i const DIVERGENT_PULL_RECONCILIATION_PATTERN = /Need to specify how to reconcile divergent branches|divergent branches and need to specify how to reconcile them/i // Why: these args already pin a reconcile strategy; the merge fallback must not override an explicit choice like --ff-only. @@ -22,24 +22,50 @@ export function stripCredentialsFromMessage(message: string): string { return message.replace(USERPASS_URL_PATTERN, '$1').replace(HTTPS_TOKEN_URL_PATTERN, '$1') } -export function formatSubmodulePushFailureDetail(message: string): string | null { +export type SubmodulePushFailure = { + submoduleName: string | null + remoteChanged: boolean + detail: string +} + +// Why: the renderer rebuilds this classification as translated copy; detail stays English for main/CLI. +export function classifySubmodulePushFailure(message: string): SubmodulePushFailure | null { const raw = stripCredentialsFromMessage(message) const trimmed = raw.trim() const normalizedMatch = trimmed.match(NORMALIZED_SUBMODULE_PUSH_FAILURE_PATTERN) if (normalizedMatch) { - return normalizedMatch[1] + return { + submoduleName: normalizedMatch[2] ?? null, + remoteChanged: normalizedMatch[3] !== undefined, + detail: normalizedMatch[1] + } } if (!SUBMODULE_PUSH_FAILURE_SENTINEL_PATTERN.test(trimmed)) { return null } // Why: recursive push hides the actionable nested rejection behind a top-level "failed to push all needed submodules" line. - const submoduleName = trimmed.match(SUBMODULE_PUSH_FAILURE_PATTERN)?.[1]?.trim() - const subject = submoduleName ? `Submodule '${submoduleName}'` : 'A submodule' - if (SUBMODULE_REMOTE_CHANGED_PATTERN.test(trimmed)) { - return `${subject} has remote changes. Pull inside the submodule, then try again.` + const submoduleName = trimmed.match(SUBMODULE_PUSH_FAILURE_PATTERN)?.[1]?.trim() || null + const remoteChanged = SUBMODULE_REMOTE_CHANGED_PATTERN.test(trimmed) + return { + submoduleName, + remoteChanged, + detail: formatSubmodulePushFailureSentence(submoduleName, remoteChanged) } - return `${subject} could not be pushed. Resolve the submodule push error, then try again.` +} + +export function formatSubmodulePushFailureSentence( + submoduleName: string | null, + remoteChanged: boolean +): string { + const subject = submoduleName ? `Submodule '${submoduleName}'` : 'A submodule' + return remoteChanged + ? `${subject} has remote changes. Pull inside the submodule, then try again.` + : `${subject} could not be pushed. Resolve the submodule push error, then try again.` +} + +export function formatSubmodulePushFailureDetail(message: string): string | null { + return classifySubmodulePushFailure(message)?.detail ?? null } function extractTailLine(message: string): string { diff --git a/src/shared/source-control-push-failure.ts b/src/shared/source-control-push-failure.ts index 49db6401065..0f0694516b3 100644 --- a/src/shared/source-control-push-failure.ts +++ b/src/shared/source-control-push-failure.ts @@ -5,8 +5,8 @@ import { import type { GitStatusEntry } from './git-status-types' const FALLBACK_PUSH_FAILURE_SUMMARY = 'Push failed.' -const LINT_PUSH_FAILURE_SUMMARY = 'Lint failed during push.' -const PRE_PUSH_FAILURE_SUMMARY = 'Pre-push hook failed.' +export const LINT_PUSH_FAILURE_SUMMARY = 'Lint failed during push.' +export const PRE_PUSH_FAILURE_SUMMARY = 'Pre-push hook failed.' export const PUSH_FAILURE_SUMMARY_SCAN_CODE_UNITS = 64 * 1024 const PUSH_FAILURE_PROMPT_OUTPUT_LIMIT = 12_000