diff --git a/src/features/repositories/hooks/useBatchStarImport.test.tsx b/src/features/repositories/hooks/useBatchStarImport.test.tsx
index e3b6ec89b..625896bdf 100644
--- a/src/features/repositories/hooks/useBatchStarImport.test.tsx
+++ b/src/features/repositories/hooks/useBatchStarImport.test.tsx
@@ -1,6 +1,7 @@
import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useBatchStarImport } from './useBatchStarImport';
+import { GitHubTokenPermissionError } from '../../../services/githubApi';
const mocks = vi.hoisted(() => ({
token: 'token',
@@ -64,6 +65,23 @@ describe('useBatchStarImport', () => {
expect(mocks.starRepository).not.toHaveBeenCalled();
});
+ it('explains a token permission failure during preview', async () => {
+ mocks.isRepositoryStarred.mockRejectedValueOnce(new GitHubTokenPermissionError());
+ const { result } = renderHook(() => useBatchStarImport());
+ await act(() => result.current.preview('https://github.com/owner/repo'));
+ expect(result.current.rows[0].status).toBe('unavailable');
+ expect(result.current.rows[0].error).toMatch(/Starring|starring/i);
+ });
+
+ it('explains a token permission failure during starring', async () => {
+ mocks.starRepository.mockRejectedValueOnce(new GitHubTokenPermissionError());
+ const { result } = renderHook(() => useBatchStarImport());
+ await act(() => result.current.preview('https://github.com/owner/repo'));
+ await act(() => result.current.starSelected());
+ expect(result.current.rows[0].status).toBe('failed');
+ expect(result.current.rows[0].error).toMatch(/Starring|starring/i);
+ });
+
it('requires selection for bare names and renamed repositories, and deduplicates canonical names', async () => {
mocks.getRepositoryDetails.mockImplementation(async (_owner, name) => detail('new-owner', name));
const { result } = renderHook(() => useBatchStarImport());
diff --git a/src/features/repositories/hooks/useBatchStarImport.ts b/src/features/repositories/hooks/useBatchStarImport.ts
index 6a9c3d2b2..de42f06a0 100644
--- a/src/features/repositories/hooks/useBatchStarImport.ts
+++ b/src/features/repositories/hooks/useBatchStarImport.ts
@@ -2,7 +2,8 @@ import { useCallback, useRef, useState } from 'react';
import { useAppStore } from '../../../store/useAppStore';
import { forceSyncToBackend } from '../../../services/autoSync';
import { translateBatch } from '../../../services/translateService';
-import type { GitHubRepoDetailRead } from '../../../services/githubApi';
+import { GitHubTokenPermissionError, type GitHubRepoDetailRead } from '../../../services/githubApi';
+import { makeT } from '../../../i18n/useT';
import { createGitHubApiService } from '../../../services/githubApiFactory';
import type { Repository } from '../../../types';
import type { ImportedRepositoryCandidate } from '../../../types/repositoryImport';
@@ -102,7 +103,9 @@ export function useBatchStarImport() {
candidate,
status: 'unavailable',
selected: false,
- error: error instanceof Error ? error.message : String(error),
+ error: error instanceof GitHubTokenPermissionError
+ ? makeT(language, 'repositories')('batchStar.token-permission-error')
+ : error instanceof Error ? error.message : String(error),
};
}
}));
@@ -122,7 +125,7 @@ export function useBatchStarImport() {
busyRef.current = false;
setIsResolving(false);
}
- }, [githubToken, resetTranslations]);
+ }, [githubToken, language, resetTranslations]);
/** Flips the selection of a starable row; other statuses cannot be toggled. */
const toggleRow = useCallback((index: number) => {
@@ -240,7 +243,9 @@ export function useBatchStarImport() {
));
} catch (error) {
setRows(current => current.map((item, itemIndex) => itemIndex === index
- ? { ...item, status: 'failed', selected: false, error: error instanceof Error ? error.message : String(error) }
+ ? { ...item, status: 'failed', selected: false, error: error instanceof GitHubTokenPermissionError
+ ? makeT(language, 'repositories')('batchStar.token-permission-error')
+ : error instanceof Error ? error.message : String(error) }
: item
));
}
@@ -256,7 +261,7 @@ export function useBatchStarImport() {
busyRef.current = false;
setIsStarring(false);
}
- }, [addRepository, githubToken, rows]);
+ }, [addRepository, githubToken, language, rows]);
return {
rows, duplicateCount, inputError, isResolving, isStarring, syncError,
diff --git a/src/locales/de/app.json b/src/locales/de/app.json
index 743639810..cfd0d759e 100644
--- a/src/locales/de/app.json
+++ b/src/locales/de/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Prüfen Sie, ob eine neue Version verfügbar ist",
"contact-information": "Kontaktinformationen",
"if-you-encounter-any-issues-or-have-suggestions": "Wenn Sie während der Nutzung auf Probleme stoßen oder Vorschläge haben, kontaktieren Sie mich bitte über die folgenden Methoden:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Angemeldet als {{login}}. Ein abgelaufenes Token lässt sich hier ohne Abmeldung erneuern.",
+ "token-hint": "Ein abgelaufenes Token lässt sich hier ohne Abmeldung erneuern.",
+ "token-permission-guide": "Token-Einrichtungshinweise"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Beziehen Sie beim Sichern/Exportieren Schlüssel mit ein",
diff --git a/src/locales/de/login.json b/src/locales/de/login.json
index 2abed9c37..16218a290 100644
--- a/src/locales/de/login.json
+++ b/src/locales/de/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub-Token-Berechtigungen",
+ "token-permissions-check": "Die Anmeldung prüft Ihre Identität, nicht alle Berechtigungen. Fehlende Rechte können erst bei der Nutzung einer Funktion auffallen.",
"please-enter-the-backend-url-and-api-key": "Bitte geben Sie die Backend-URL und den API-Schlüssel ein",
"invalid-backend-url-remote-backends-must-use-htt": "Ungültige Backend-Adresse: Das Remote-Backend erfordert HTTPS, nur localhost kann HTTP verwenden",
"unable-to-connect-to-this-backend-url": "Es kann keine Verbindung zur Backend-URL hergestellt werden",
@@ -26,12 +28,6 @@
"connect-to-github": "Stellen Sie eine Verbindung zu GitHub her",
"connect-and-restore-data": "Daten verbinden und wiederherstellen",
"save-and-continue": "Speichern und fortfahren",
- "how-to-create-a-github-token": "So erstellen Sie ein GitHub-Token:",
- "go-to-github-settings-developer-settings-persona": "Besuchen Sie GitHub-Einstellungen → Entwicklereinstellungen → Persönliche Zugriffstokens",
- "click-generate-new-token-classic": "Klicken Sie auf „Neues Token generieren (klassisch)“",
- "select-scopes": "Berechtigungsbereich auswählen:",
- "and": "Und",
- "copy-the-generated-token-and-paste-it-above": "Kopieren Sie das generierte Token und fügen Sie es oben ein",
"create-token-on-github": "Erstellen Sie ein Token auf GitHub →",
"already-have-backend-data": "Habe bereits Backend-Daten",
"sign-in-with-github-token": "Melden Sie sich mit dem GitHub-Token an",
@@ -41,6 +37,23 @@
"keep-local": "Bleiben Sie lokal",
"please-enter-a-valid-github-token": "Bitte geben Sie ein gültiges GitHub-Token ein",
"signed-in-but-failed-to-save-github-token-to-bac": "Sie haben sich angemeldet, aber das GitHub-Token konnte nicht im Backend gespeichert werden und Backend-Proxy-Funktionen wie README sind möglicherweise nicht verfügbar.",
- "failed-to-authenticate-please-check-your-token": "Die Authentifizierung ist fehlgeschlagen. Bitte überprüfen Sie Ihr Token."
+ "failed-to-authenticate-please-check-your-token": "Die Authentifizierung ist fehlgeschlagen. Bitte überprüfen Sie Ihr Token.",
+ "token-permissions-tab-finegrained": "Fein abgestuft",
+ "token-permissions-tab-classic": "Klassisch",
+ "token-permissions-feature-star": "Stars verwalten",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Star-Listen",
+ "token-permissions-feature-fork-sync": "Fork-Synchronisierung",
+ "token-permissions-feature-workflows": "Workflow-Starts",
+ "token-permissions-feature-fork-workflows": "Fork-Sync / Workflows",
+ "token-permissions-fine-star": "`Starring` Lesen/Schreiben, `Metadata` Lesen",
+ "token-permissions-fine-gists": "`Gists` Schreiben",
+ "token-permissions-fine-fork-sync": "`Contents` Schreiben",
+ "token-permissions-fine-workflows": "`Actions` Schreiben",
+ "token-permissions-classic-star": "`public_repo` (`repo` für private Repositorys)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Ihr Token wird nur auf diesem Gerät und Ihrem eigenen Backend gespeichert – niemals auf den Servern der App."
}
}
diff --git a/src/locales/de/repositories.json b/src/locales/de/repositories.json
index 1d9ccb239..f9fe1948d 100644
--- a/src/locales/de/repositories.json
+++ b/src/locales/de/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub hat dieses Token abgewiesen (403). Zum Prüfen oder Setzen von Stars braucht ein fein abgestuftes Token Starring mit Lese-/Schreibzugriff und Metadata mit Lesezugriff; ein klassisches Token benötigt public_repo (für private Repositorys repo).",
"title": "Sterne aus Links hinzufügen",
"hint": "Füge beliebigen Text mit GitHub-Links ein, prüfe die Repositorys und vergib Sterne. Links zu anderen Websites werden ignoriert.",
"history": "Einfügeverlauf",
diff --git a/src/locales/en/app.json b/src/locales/en/app.json
index 38197dff4..48416191d 100644
--- a/src/locales/en/app.json
+++ b/src/locales/en/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Check if a new version is available",
"contact-information": "Contact Information",
"if-you-encounter-any-issues-or-have-suggestions": "If you encounter any issues or have suggestions while using the app, feel free to contact me through:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Signed in as {{login}}. Update an expired token here without logging out.",
+ "token-hint": "Update an expired token here without logging out.",
+ "token-permission-guide": "Token setup guide"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Include keys in backup/export",
diff --git a/src/locales/en/login.json b/src/locales/en/login.json
index 676fbd911..e6f86bd18 100644
--- a/src/locales/en/login.json
+++ b/src/locales/en/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub token permissions",
+ "token-permissions-check": "Signing in checks your identity, not every permission. Missing permissions may only appear when you use a feature.",
"please-enter-the-backend-url-and-api-key": "Please enter the backend URL and API key",
"invalid-backend-url-remote-backends-must-use-htt": "Invalid backend URL: remote backends must use HTTPS; only localhost may use HTTP",
"unable-to-connect-to-this-backend-url": "Unable to connect to this backend URL",
@@ -26,12 +28,6 @@
"connect-to-github": "Connect to GitHub",
"connect-and-restore-data": "Connect and restore data",
"save-and-continue": "Save and continue",
- "how-to-create-a-github-token": "How to create a GitHub token:",
- "go-to-github-settings-developer-settings-persona": "Go to GitHub Settings → Developer settings → Personal access tokens",
- "click-generate-new-token-classic": "Click \"Generate new token (classic)\"",
- "select-scopes": "Select scopes:",
- "and": "and",
- "copy-the-generated-token-and-paste-it-above": "Copy the generated token and paste it above",
"create-token-on-github": "Create token on GitHub →",
"already-have-backend-data": "Already have backend data",
"sign-in-with-github-token": "Sign in with GitHub token",
@@ -41,6 +37,23 @@
"keep-local": "Keep local",
"please-enter-a-valid-github-token": "Please enter a valid GitHub token",
"signed-in-but-failed-to-save-github-token-to-bac": "Signed in, but failed to save GitHub token to backend. README and other backend proxy features may be unavailable.",
- "failed-to-authenticate-please-check-your-token": "Failed to authenticate. Please check your token."
+ "failed-to-authenticate-please-check-your-token": "Failed to authenticate. Please check your token.",
+ "token-permissions-tab-finegrained": "Fine-grained",
+ "token-permissions-tab-classic": "Classic",
+ "token-permissions-feature-star": "Managing Stars",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Star Lists",
+ "token-permissions-feature-fork-sync": "Fork sync",
+ "token-permissions-feature-workflows": "Workflow dispatch",
+ "token-permissions-feature-fork-workflows": "Fork sync / workflows",
+ "token-permissions-fine-star": "`Starring` read & write, `Metadata` read",
+ "token-permissions-fine-gists": "`Gists` write",
+ "token-permissions-fine-fork-sync": "`Contents` write",
+ "token-permissions-fine-workflows": "`Actions` write",
+ "token-permissions-classic-star": "`public_repo` (`repo` for private repositories)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Your token is stored only on this device and your own backend — never on the app's servers."
}
}
diff --git a/src/locales/en/repositories.json b/src/locales/en/repositories.json
index dc3a6f10b..e33d07c93 100644
--- a/src/locales/en/repositories.json
+++ b/src/locales/en/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub rejected this token (403). To check or add Stars, enable Starring read/write and repository Metadata read on a fine-grained token, or public_repo on a classic token (repo for private repositories).",
"title": "Star from links",
"hint": "Paste any text containing GitHub links, review the repositories, then Star them. Links to other websites are ignored.",
"history": "Paste history",
diff --git a/src/locales/es/app.json b/src/locales/es/app.json
index 2c5efc850..1807d9bf3 100644
--- a/src/locales/es/app.json
+++ b/src/locales/es/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Compruebe si hay una nueva versión disponible",
"contact-information": "Información del contacto",
"if-you-encounter-any-issues-or-have-suggestions": "Si encuentra algún problema o tiene sugerencias durante el uso, comuníquese conmigo a través de los siguientes métodos:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Sesión iniciada como {{login}}. Renueva aquí un token caducado sin cerrar la sesión.",
+ "token-hint": "Renueva aquí un token caducado sin cerrar la sesión.",
+ "token-permission-guide": "Guía de configuración del token"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Incluir claves al realizar copias de seguridad/exportar",
diff --git a/src/locales/es/login.json b/src/locales/es/login.json
index 677e75ff5..b2bca0b6a 100644
--- a/src/locales/es/login.json
+++ b/src/locales/es/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "Permisos del token de GitHub",
+ "token-permissions-check": "El inicio de sesión verifica tu identidad, no todos los permisos. La falta de permisos puede aparecer al usar una función.",
"please-enter-the-backend-url-and-api-key": "Ingrese la URL de backend y la clave API",
"invalid-backend-url-remote-backends-must-use-htt": "Dirección de backend no válida: el backend remoto requiere HTTPS, solo el host local puede usar HTTP",
"unable-to-connect-to-this-backend-url": "No se puede conectar a la URL de backend",
@@ -26,12 +28,6 @@
"connect-to-github": "Conéctate a GitHub",
"connect-and-restore-data": "Conectar y restaurar datos",
"save-and-continue": "Guardar y continuar",
- "how-to-create-a-github-token": "Cómo crear un token de GitHub:",
- "go-to-github-settings-developer-settings-persona": "Visite Configuración de GitHub → Configuración de desarrollador → Tokens de acceso personal",
- "click-generate-new-token-classic": "Haga clic en \"Generar nuevo token (clásico)\"",
- "select-scopes": "Seleccione el alcance del permiso:",
- "and": "y",
- "copy-the-generated-token-and-paste-it-above": "Copie el token generado y péguelo arriba",
"create-token-on-github": "Crea un token en GitHub →",
"already-have-backend-data": "Ya tengo datos de backend",
"sign-in-with-github-token": "Inicie sesión usando el token de GitHub",
@@ -41,6 +37,23 @@
"keep-local": "mantener local",
"please-enter-a-valid-github-token": "Ingrese un token de GitHub válido",
"signed-in-but-failed-to-save-github-token-to-bac": "Ha iniciado sesión, pero el token de GitHub no se pudo guardar en el backend y es posible que las funciones de proxy del backend, como README, no estén disponibles.",
- "failed-to-authenticate-please-check-your-token": "La autenticación falló, verifique su token."
+ "failed-to-authenticate-please-check-your-token": "La autenticación falló, verifique su token.",
+ "token-permissions-tab-finegrained": "Específico",
+ "token-permissions-tab-classic": "Clásico",
+ "token-permissions-feature-star": "Gestionar estrellas",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Listas de estrellas",
+ "token-permissions-feature-fork-sync": "Sincronizar forks",
+ "token-permissions-feature-workflows": "Ejecutar flujos",
+ "token-permissions-feature-fork-workflows": "Forks / flujos",
+ "token-permissions-fine-star": "`Starring` lectura y escritura, `Metadata` lectura",
+ "token-permissions-fine-gists": "`Gists` escritura",
+ "token-permissions-fine-fork-sync": "`Contents` escritura",
+ "token-permissions-fine-workflows": "`Actions` escritura",
+ "token-permissions-classic-star": "`public_repo` (`repo` para repositorios privados)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Tu token se guarda solo en este dispositivo y en tu propio backend; nunca en los servidores de la app."
}
}
diff --git a/src/locales/es/repositories.json b/src/locales/es/repositories.json
index 4d4a5c5a1..1911f33ca 100644
--- a/src/locales/es/repositories.json
+++ b/src/locales/es/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub rechazó este token (403). Para consultar o añadir estrellas, activa Starring de lectura/escritura y Metadata de lectura en un token de permisos específicos, o public_repo en uno clásico (repo para repositorios privados).",
"title": "Marcar desde enlaces",
"hint": "Pega cualquier texto con enlaces de GitHub, revisa los repositorios y márcalos con Star. Se ignoran los enlaces a otros sitios.",
"history": "Historial de texto",
diff --git a/src/locales/fr/app.json b/src/locales/fr/app.json
index ba7f97339..3f440ad4d 100644
--- a/src/locales/fr/app.json
+++ b/src/locales/fr/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Vérifiez si une nouvelle version est disponible",
"contact-information": "Coordonnées",
"if-you-encounter-any-issues-or-have-suggestions": "Si vous rencontrez des problèmes ou avez des suggestions lors de l'utilisation, veuillez me contacter via les méthodes suivantes :",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Connecté en tant que {{login}}. Renouvelez ici un token expiré sans vous déconnecter.",
+ "token-hint": "Renouvelez ici un token expiré sans vous déconnecter.",
+ "token-permission-guide": "Guide de configuration du token"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Inclure les clés lors de la sauvegarde/exportation",
diff --git a/src/locales/fr/login.json b/src/locales/fr/login.json
index e471acc3e..678ed9ff1 100644
--- a/src/locales/fr/login.json
+++ b/src/locales/fr/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "Autorisations du jeton GitHub",
+ "token-permissions-check": "La connexion vérifie votre identité, pas toutes les autorisations. Un manque de droits peut n'apparaître qu'à l'utilisation d'une fonction.",
"please-enter-the-backend-url-and-api-key": "Veuillez saisir l'URL du backend et la clé API",
"invalid-backend-url-remote-backends-must-use-htt": "Adresse du backend invalide : le backend distant nécessite HTTPS, seul l'hôte local peut utiliser HTTP",
"unable-to-connect-to-this-backend-url": "Impossible de se connecter à l'URL du backend",
@@ -26,12 +28,6 @@
"connect-to-github": "Connectez-vous à GitHub",
"connect-and-restore-data": "Connectez-vous et restaurez les données",
"save-and-continue": "Enregistrer et continuer",
- "how-to-create-a-github-token": "Comment créer un jeton GitHub :",
- "go-to-github-settings-developer-settings-persona": "Visitez Paramètres GitHub → Paramètres du développeur → Jetons d'accès personnels",
- "click-generate-new-token-classic": "Cliquez sur \"Générer un nouveau token (classique)\"",
- "select-scopes": "Sélectionnez la portée de l'autorisation :",
- "and": "et",
- "copy-the-generated-token-and-paste-it-above": "Copiez le jeton généré et collez-le ci-dessus",
"create-token-on-github": "Créer un jeton sur GitHub →",
"already-have-backend-data": "Vous disposez déjà de données back-end",
"sign-in-with-github-token": "Connectez-vous en utilisant le jeton GitHub",
@@ -41,6 +37,23 @@
"keep-local": "rester local",
"please-enter-a-valid-github-token": "Veuillez saisir un jeton GitHub valide",
"signed-in-but-failed-to-save-github-token-to-bac": "Vous êtes connecté, mais le jeton GitHub n'a pas pu être enregistré dans le backend et les fonctions de proxy backend telles que README peuvent ne pas être disponibles.",
- "failed-to-authenticate-please-check-your-token": "L'authentification a échoué, veuillez vérifier votre jeton."
+ "failed-to-authenticate-please-check-your-token": "L'authentification a échoué, veuillez vérifier votre jeton.",
+ "token-permissions-tab-finegrained": "Granularité fine",
+ "token-permissions-tab-classic": "Classique",
+ "token-permissions-feature-star": "Gérer les étoiles",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Listes d'étoiles",
+ "token-permissions-feature-fork-sync": "Synchronisation des forks",
+ "token-permissions-feature-workflows": "Lancement de workflows",
+ "token-permissions-feature-fork-workflows": "Forks / workflows",
+ "token-permissions-fine-star": "`Starring` lecture/écriture, `Metadata` lecture",
+ "token-permissions-fine-gists": "`Gists` écriture",
+ "token-permissions-fine-fork-sync": "`Contents` écriture",
+ "token-permissions-fine-workflows": "`Actions` écriture",
+ "token-permissions-classic-star": "`public_repo` (`repo` pour les dépôts privés)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Votre jeton est stocké uniquement sur cet appareil et votre propre backend, jamais sur les serveurs de l'application."
}
}
diff --git a/src/locales/fr/repositories.json b/src/locales/fr/repositories.json
index 6e752331d..9d934b7b3 100644
--- a/src/locales/fr/repositories.json
+++ b/src/locales/fr/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub a refusé ce jeton (403). Pour consulter ou ajouter des étoiles, activez Starring en lecture/écriture et Metadata en lecture avec un jeton à granularité fine, ou public_repo avec un jeton classique (repo pour les dépôts privés).",
"title": "Ajouter des étoiles depuis des liens",
"hint": "Collez un texte contenant des liens GitHub, vérifiez les dépôts, puis ajoutez une étoile. Les liens vers les autres sites sont ignorés.",
"history": "Historique des textes",
diff --git a/src/locales/ja/app.json b/src/locales/ja/app.json
index 63f2a4e36..8af873178 100644
--- a/src/locales/ja/app.json
+++ b/src/locales/ja/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "新しいバージョンが利用可能かどうかを確認する",
"contact-information": "連絡先",
"if-you-encounter-any-issues-or-have-suggestions": "使用中に問題が発生したり、提案がある場合は、次の方法でご連絡ください。",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "{{login}} としてサインイン中です。期限切れのトークンはログアウトせずにここで更新できます。",
+ "token-hint": "期限切れのトークンはログアウトせずにここで更新できます。",
+ "token-permission-guide": "トークン設定ガイド"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "バックアップ/エクスポート時にキーを含める",
diff --git a/src/locales/ja/login.json b/src/locales/ja/login.json
index 9d3721008..76e7f79d8 100644
--- a/src/locales/ja/login.json
+++ b/src/locales/ja/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub トークンの権限",
+ "token-permissions-check": "ログインでは本人確認のみを行い、すべての権限は確認しません。権限不足は機能の使用時に判明する場合があります。",
"please-enter-the-backend-url-and-api-key": "バックエンド URL と API キーを入力してください",
"invalid-backend-url-remote-backends-must-use-htt": "無効なバックエンド アドレス: リモート バックエンドには HTTPS が必要です。HTTP を使用できるのはローカルホストのみです",
"unable-to-connect-to-this-backend-url": "バックエンド URL に接続できません",
@@ -26,12 +28,6 @@
"connect-to-github": "GitHub に接続する",
"connect-and-restore-data": "データの接続と復元",
"save-and-continue": "保存して続行",
- "how-to-create-a-github-token": "GitHub トークンを作成する方法:",
- "go-to-github-settings-developer-settings-persona": "GitHub 設定 → 開発者設定 → 個人アクセス トークンにアクセスします。",
- "click-generate-new-token-classic": "「新しいトークンを生成(クラシック)」をクリックします。",
- "select-scopes": "権限の範囲を選択します:",
- "and": "そして",
- "copy-the-generated-token-and-paste-it-above": "生成されたトークンをコピーして上に貼り付けます",
"create-token-on-github": "GitHub でトークンを作成 →",
"already-have-backend-data": "すでにバックエンドデータがある",
"sign-in-with-github-token": "GitHub トークンを使用してログインする",
@@ -41,6 +37,23 @@
"keep-local": "ローカルに保つ",
"please-enter-a-valid-github-token": "有効な GitHub トークンを入力してください",
"signed-in-but-failed-to-save-github-token-to-bac": "ログインしましたが、GitHub トークンをバックエンドに保存できず、README などのバックエンド プロキシ機能が利用できない可能性があります。",
- "failed-to-authenticate-please-check-your-token": "認証に失敗しました。トークンを確認してください。"
+ "failed-to-authenticate-please-check-your-token": "認証に失敗しました。トークンを確認してください。",
+ "token-permissions-tab-finegrained": "Fine-grained",
+ "token-permissions-tab-classic": "クラシック",
+ "token-permissions-feature-star": "Star の管理",
+ "token-permissions-feature-gists": "Gist",
+ "token-permissions-feature-star-lists": "Star リスト",
+ "token-permissions-feature-fork-sync": "Fork 同期",
+ "token-permissions-feature-workflows": "ワークフロー実行",
+ "token-permissions-feature-fork-workflows": "Fork 同期 / ワークフロー",
+ "token-permissions-fine-star": "`Starring` 読み書き、`Metadata` 読み取り",
+ "token-permissions-fine-gists": "`Gists` 書き込み",
+ "token-permissions-fine-fork-sync": "`Contents` 書き込み",
+ "token-permissions-fine-workflows": "`Actions` 書き込み",
+ "token-permissions-classic-star": "`public_repo`(非公開リポジトリには `repo`)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "トークンはこのデバイスと自分のバックエンドにのみ保存され、アプリのサーバーには送信されません。"
}
}
diff --git a/src/locales/ja/repositories.json b/src/locales/ja/repositories.json
index 4260979cf..943877f92 100644
--- a/src/locales/ja/repositories.json
+++ b/src/locales/ja/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub がこのトークンを拒否しました(403)。Star の確認や追加には、Fine-grained トークンで Starring の読み書きと Metadata の読み取り、またはクラシックトークンで public_repo(非公開リポジトリは repo)が必要です。",
"title": "リンクからスター",
"hint": "GitHub リンクを含むテキストを貼り付け、リポジトリを確認してから Star を付けます。他のサイトのリンクは無視されます。",
"history": "貼り付け履歴",
diff --git a/src/locales/ko/app.json b/src/locales/ko/app.json
index 4843982cc..5e5c29542 100644
--- a/src/locales/ko/app.json
+++ b/src/locales/ko/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "새 버전이 있는지 확인하세요.",
"contact-information": "연락처 정보",
"if-you-encounter-any-issues-or-have-suggestions": "사용 중 문제가 발생하거나 제안 사항이 있는 경우 다음 방법을 통해 저에게 연락해 주세요.",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "{{login}}(으)로 로그인했습니다. 만료된 토큰은 로그아웃하지 않고 여기서 갱신할 수 있습니다.",
+ "token-hint": "만료된 토큰은 로그아웃하지 않고 여기서 갱신할 수 있습니다.",
+ "token-permission-guide": "토큰 설정 가이드"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "백업/내보내기 시 키 포함",
diff --git a/src/locales/ko/login.json b/src/locales/ko/login.json
index 3b54e1c8f..90b879c0d 100644
--- a/src/locales/ko/login.json
+++ b/src/locales/ko/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub 토큰 권한",
+ "token-permissions-check": "로그인은 신원만 확인하며 모든 권한을 검사하지 않습니다. 권한 부족은 해당 기능을 사용할 때 나타날 수 있습니다.",
"please-enter-the-backend-url-and-api-key": "백엔드 URL과 API 키를 입력하세요.",
"invalid-backend-url-remote-backends-must-use-htt": "잘못된 백엔드 주소: 원격 백엔드에는 HTTPS가 필요하며 로컬 호스트만 HTTP를 사용할 수 있습니다.",
"unable-to-connect-to-this-backend-url": "백엔드 URL에 연결할 수 없습니다.",
@@ -26,12 +28,6 @@
"connect-to-github": "GitHub에 연결",
"connect-and-restore-data": "데이터 연결 및 복원",
"save-and-continue": "저장하고 계속하세요",
- "how-to-create-a-github-token": "GitHub 토큰을 만드는 방법:",
- "go-to-github-settings-developer-settings-persona": "GitHub 설정 → 개발자 설정 → 개인 액세스 토큰을 방문하세요.",
- "click-generate-new-token-classic": "\"새 토큰 생성(클래식)\"을 클릭하세요.",
- "select-scopes": "권한 범위 선택:",
- "and": "그리고",
- "copy-the-generated-token-and-paste-it-above": "생성된 토큰을 복사하여 위에 붙여넣으세요.",
"create-token-on-github": "GitHub에서 토큰 생성 →",
"already-have-backend-data": "이미 백엔드 데이터가 있음",
"sign-in-with-github-token": "GitHub 토큰을 사용하여 로그인",
@@ -41,6 +37,23 @@
"keep-local": "지역을 유지하다",
"please-enter-a-valid-github-token": "유효한 GitHub 토큰을 입력하세요.",
"signed-in-but-failed-to-save-github-token-to-bac": "로그인했지만 GitHub 토큰이 백엔드에 저장되지 않아 README와 같은 백엔드 프록시 기능을 사용하지 못할 수 있습니다.",
- "failed-to-authenticate-please-check-your-token": "인증에 실패했습니다. 토큰을 확인하세요."
+ "failed-to-authenticate-please-check-your-token": "인증에 실패했습니다. 토큰을 확인하세요.",
+ "token-permissions-tab-finegrained": "세분화",
+ "token-permissions-tab-classic": "클래식",
+ "token-permissions-feature-star": "Star 관리",
+ "token-permissions-feature-gists": "Gist",
+ "token-permissions-feature-star-lists": "Star 목록",
+ "token-permissions-feature-fork-sync": "Fork 동기화",
+ "token-permissions-feature-workflows": "워크플로 실행",
+ "token-permissions-feature-fork-workflows": "Fork 동기화 / 워크플로",
+ "token-permissions-fine-star": "`Starring` 읽기/쓰기, `Metadata` 읽기",
+ "token-permissions-fine-gists": "`Gists` 쓰기",
+ "token-permissions-fine-fork-sync": "`Contents` 쓰기",
+ "token-permissions-fine-workflows": "`Actions` 쓰기",
+ "token-permissions-classic-star": "`public_repo`(비공개 저장소는 `repo`)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "토큰은 이 기기와 직접 구성한 백엔드에만 저장되며 앱 서버로 전송되지 않습니다."
}
}
diff --git a/src/locales/ko/repositories.json b/src/locales/ko/repositories.json
index 6d12880ba..7129a7c22 100644
--- a/src/locales/ko/repositories.json
+++ b/src/locales/ko/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub가 이 토큰을 거부했습니다(403). Star 확인과 추가에는 세분화된 토큰의 Starring 읽기/쓰기 및 저장소 Metadata 읽기 권한이 필요합니다. 클래식 토큰은 public_repo(비공개 저장소는 repo)가 필요합니다.",
"title": "링크로 별표 추가",
"hint": "GitHub 링크가 포함된 텍스트를 붙여넣고 저장소를 확인한 뒤 Star를 추가하세요. 다른 사이트의 링크는 무시됩니다.",
"history": "붙여넣기 기록",
diff --git a/src/locales/pt-BR/app.json b/src/locales/pt-BR/app.json
index fd4d31608..d8a44e90e 100644
--- a/src/locales/pt-BR/app.json
+++ b/src/locales/pt-BR/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Verifique se uma nova versão está disponível",
"contact-information": "Informações de contato",
"if-you-encounter-any-issues-or-have-suggestions": "Se você encontrar algum problema ou tiver sugestões durante o uso, entre em contato comigo através dos seguintes métodos:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Conectado como {{login}}. Renove um token expirado aqui sem encerrar a sessão.",
+ "token-hint": "Renove um token expirado aqui sem encerrar a sessão.",
+ "token-permission-guide": "Guia de configuração do token"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Incluir chaves ao fazer backup/exportar",
diff --git a/src/locales/pt-BR/login.json b/src/locales/pt-BR/login.json
index 28dd5de6a..9ef1ee8f8 100644
--- a/src/locales/pt-BR/login.json
+++ b/src/locales/pt-BR/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "Permissões do token do GitHub",
+ "token-permissions-check": "O login verifica sua identidade, não todas as permissões. Uma permissão ausente pode aparecer só quando você usar o recurso.",
"please-enter-the-backend-url-and-api-key": "Insira o URL de back-end e a chave de API",
"invalid-backend-url-remote-backends-must-use-htt": "Endereço de back-end inválido: o back-end remoto requer HTTPS, apenas localhost pode usar HTTP",
"unable-to-connect-to-this-backend-url": "Não foi possível conectar-se ao URL de back-end",
@@ -26,12 +28,6 @@
"connect-to-github": "Conecte-se ao GitHub",
"connect-and-restore-data": "Conecte e restaure dados",
"save-and-continue": "Salvar e continuar",
- "how-to-create-a-github-token": "Como criar um token GitHub:",
- "go-to-github-settings-developer-settings-persona": "Visite Configurações do GitHub → Configurações do desenvolvedor → Tokens de acesso pessoal",
- "click-generate-new-token-classic": "Clique em \"Gerar novo token (clássico)\"",
- "select-scopes": "Selecione o escopo da permissão:",
- "and": "e",
- "copy-the-generated-token-and-paste-it-above": "Copie o token gerado e cole-o acima",
"create-token-on-github": "Crie um token no GitHub →",
"already-have-backend-data": "Já tem dados de back-end",
"sign-in-with-github-token": "Faça login usando o token GitHub",
@@ -41,6 +37,23 @@
"keep-local": "manter local",
"please-enter-a-valid-github-token": "Insira um token GitHub válido",
"signed-in-but-failed-to-save-github-token-to-bac": "Você fez login, mas o token GitHub não foi salvo no back-end e as funções de proxy de back-end, como README, podem não estar disponíveis.",
- "failed-to-authenticate-please-check-your-token": "Falha na autenticação. Verifique seu token."
+ "failed-to-authenticate-please-check-your-token": "Falha na autenticação. Verifique seu token.",
+ "token-permissions-tab-finegrained": "Refinado",
+ "token-permissions-tab-classic": "Clássico",
+ "token-permissions-feature-star": "Gerenciar estrelas",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Listas de estrelas",
+ "token-permissions-feature-fork-sync": "Sincronização de forks",
+ "token-permissions-feature-workflows": "Executar workflows",
+ "token-permissions-feature-fork-workflows": "Forks / workflows",
+ "token-permissions-fine-star": "`Starring` leitura e escrita, `Metadata` leitura",
+ "token-permissions-fine-gists": "`Gists` gravação",
+ "token-permissions-fine-fork-sync": "`Contents` gravação",
+ "token-permissions-fine-workflows": "`Actions` gravação",
+ "token-permissions-classic-star": "`public_repo` (`repo` para repositórios privados)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Seu token é armazenado apenas neste dispositivo e no seu próprio backend, nunca nos servidores do app."
}
}
diff --git a/src/locales/pt-BR/repositories.json b/src/locales/pt-BR/repositories.json
index d87442218..9b8874f02 100644
--- a/src/locales/pt-BR/repositories.json
+++ b/src/locales/pt-BR/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "O GitHub recusou este token (403). Para consultar ou adicionar estrelas, ative Starring com leitura/escrita e Metadata com leitura em um token refinado, ou public_repo em um token clássico (repo para repositórios privados).",
"title": "Favoritar por links",
"hint": "Cole qualquer texto com links do GitHub, confira os repositórios e adicione uma estrela. Links de outros sites são ignorados.",
"history": "Histórico de textos",
diff --git a/src/locales/ru/app.json b/src/locales/ru/app.json
index 8467efd37..ec316fdd2 100644
--- a/src/locales/ru/app.json
+++ b/src/locales/ru/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "Проверьте, доступна ли новая версия",
"contact-information": "Контактная информация",
"if-you-encounter-any-issues-or-have-suggestions": "Если у вас возникнут какие-либо проблемы или у вас есть предложения во время использования, свяжитесь со мной следующими способами:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "Вы вошли как {{login}}. Просроченный токен можно обновить здесь без выхода из аккаунта.",
+ "token-hint": "Просроченный токен можно обновить здесь без выхода из аккаунта.",
+ "token-permission-guide": "Руководство по настройке токена"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "Включить ключи при резервном копировании/экспорте",
diff --git a/src/locales/ru/login.json b/src/locales/ru/login.json
index e72a15090..1c09d34e7 100644
--- a/src/locales/ru/login.json
+++ b/src/locales/ru/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "Права токена GitHub",
+ "token-permissions-check": "Вход проверяет личность, но не все права. Нехватка прав может проявиться только при использовании функции.",
"please-enter-the-backend-url-and-api-key": "Введите URL-адрес серверной части и ключ API.",
"invalid-backend-url-remote-backends-must-use-htt": "Неверный адрес бэкэнда: удаленному бэкэнду требуется HTTPS, только локальный хост может использовать HTTP.",
"unable-to-connect-to-this-backend-url": "Невозможно подключиться к внутреннему URL-адресу",
@@ -26,12 +28,6 @@
"connect-to-github": "Подключиться к GitHub",
"connect-and-restore-data": "Подключитесь и восстановите данные",
"save-and-continue": "Сохранить и продолжить",
- "how-to-create-a-github-token": "Как создать токен GitHub:",
- "go-to-github-settings-developer-settings-persona": "Посетите «Настройки GitHub» → «Настройки разработчика» → «Токены личного доступа».",
- "click-generate-new-token-classic": "Нажмите «Создать новый токен (классический)».",
- "select-scopes": "Выберите область разрешений:",
- "and": "и",
- "copy-the-generated-token-and-paste-it-above": "Скопируйте сгенерированный токен и вставьте его выше.",
"create-token-on-github": "Создать токен на GitHub →",
"already-have-backend-data": "У вас уже есть серверные данные",
"sign-in-with-github-token": "Войдите в систему, используя токен GitHub.",
@@ -41,6 +37,23 @@
"keep-local": "сохранять локальность",
"please-enter-a-valid-github-token": "Введите действительный токен GitHub.",
"signed-in-but-failed-to-save-github-token-to-bac": "Вы вошли в систему, но токен GitHub не удалось сохранить на серверной стороне, а функции внутреннего прокси, такие как README, могут быть недоступны.",
- "failed-to-authenticate-please-check-your-token": "Аутентификация не удалась, проверьте свой токен."
+ "failed-to-authenticate-please-check-your-token": "Аутентификация не удалась, проверьте свой токен.",
+ "token-permissions-tab-finegrained": "Fine-grained",
+ "token-permissions-tab-classic": "Классический",
+ "token-permissions-feature-star": "Управление звёздами",
+ "token-permissions-feature-gists": "Gists",
+ "token-permissions-feature-star-lists": "Списки звёзд",
+ "token-permissions-feature-fork-sync": "Синхронизация форков",
+ "token-permissions-feature-workflows": "Запуск workflow",
+ "token-permissions-feature-fork-workflows": "Форки / workflow",
+ "token-permissions-fine-star": "`Starring` чтение и запись, `Metadata` чтение",
+ "token-permissions-fine-gists": "`Gists` запись",
+ "token-permissions-fine-fork-sync": "`Contents` запись",
+ "token-permissions-fine-workflows": "`Actions` запись",
+ "token-permissions-classic-star": "`public_repo` (`repo` для приватных репозиториев)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Токен хранится только на этом устройстве и вашем собственном бэкенде — никогда на серверах приложения."
}
}
diff --git a/src/locales/ru/repositories.json b/src/locales/ru/repositories.json
index 83a31d8e2..0d1394203 100644
--- a/src/locales/ru/repositories.json
+++ b/src/locales/ru/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub отклонил токен (403). Для проверки или добавления звёзд токену с точной настройкой нужны Starring на чтение/запись и Metadata на чтение; классическому — public_repo (для приватных репозиториев repo).",
"title": "Добавить звёзды по ссылкам",
"hint": "Вставьте любой текст со ссылками на GitHub, проверьте репозитории и добавьте звёзды. Ссылки на другие сайты игнорируются.",
"history": "История вставок",
diff --git a/src/locales/zh-TW/app.json b/src/locales/zh-TW/app.json
index f5c4683f0..460fe0358 100644
--- a/src/locales/zh-TW/app.json
+++ b/src/locales/zh-TW/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "檢查是否有新版本可用",
"contact-information": "聯絡方式",
"if-you-encounter-any-issues-or-have-suggestions": "如果您在使用過程中遇到任何問題或有建議,歡迎透過以下方式與我聯絡:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "目前帳號 {{login}}。Token 過期後可直接在此更換,不必登出。",
+ "token-hint": "Token 過期後可直接在此更換,不必登出。",
+ "token-permission-guide": "查看 Token 設定指引"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "備份/匯出時包含金鑰",
diff --git a/src/locales/zh-TW/login.json b/src/locales/zh-TW/login.json
index 8a2ceefa7..00df782db 100644
--- a/src/locales/zh-TW/login.json
+++ b/src/locales/zh-TW/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub Token 權限",
+ "token-permissions-check": "登入只驗證身分,不會檢查所有功能權限;權限不足可能在使用功能時才出現。",
"please-enter-the-backend-url-and-api-key": "請輸入後端 URL 和 API Key",
"invalid-backend-url-remote-backends-must-use-htt": "後端位址無效:遠端後端需使用 HTTPS,僅 localhost 可使用 HTTP",
"unable-to-connect-to-this-backend-url": "無法連線到該後端 URL",
@@ -26,12 +28,6 @@
"connect-to-github": "連接到GitHub",
"connect-and-restore-data": "連線並恢復數據",
"save-and-continue": "保存並繼續",
- "how-to-create-a-github-token": "如何建立GitHub token:",
- "go-to-github-settings-developer-settings-persona": "訪問GitHub Settings → Developer settings → Personal access tokens",
- "click-generate-new-token-classic": "點選\"Generate new token (classic)\"",
- "select-scopes": "選擇權限範圍:",
- "and": "和",
- "copy-the-generated-token-and-paste-it-above": "複製生成的token並貼上到上方",
"create-token-on-github": "在GitHub上建立token →",
"already-have-backend-data": "已有後端數據",
"sign-in-with-github-token": "使用 GitHub Token 登入",
@@ -41,6 +37,23 @@
"keep-local": "保留本地",
"please-enter-a-valid-github-token": "請輸入有效的GitHub token",
"signed-in-but-failed-to-save-github-token-to-bac": "已登錄,但 GitHub Token 未能保存到後端,README 等後端代理功能可能無法使用。",
- "failed-to-authenticate-please-check-your-token": "認證失敗,請檢查您的token。"
+ "failed-to-authenticate-please-check-your-token": "認證失敗,請檢查您的token。",
+ "token-permissions-tab-finegrained": "細粒度 Token",
+ "token-permissions-tab-classic": "經典 Token",
+ "token-permissions-feature-star": "為儲存庫新增 Star",
+ "token-permissions-feature-gists": "Gist",
+ "token-permissions-feature-star-lists": "Star 清單",
+ "token-permissions-feature-fork-sync": "Fork 儲存庫同步",
+ "token-permissions-feature-workflows": "觸發工作流程",
+ "token-permissions-feature-fork-workflows": "Fork 同步 / 觸發工作流程",
+ "token-permissions-fine-star": "`Starring` 讀寫、`Metadata` 讀取",
+ "token-permissions-fine-gists": "`Gists` 寫入",
+ "token-permissions-fine-fork-sync": "`Contents` 寫入",
+ "token-permissions-fine-workflows": "`Actions` 寫入",
+ "token-permissions-classic-star": "`public_repo`(私有儲存庫用 `repo`)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Token 僅儲存在本機與你設定的後端,不會上傳到應用方伺服器。"
}
}
diff --git a/src/locales/zh-TW/repositories.json b/src/locales/zh-TW/repositories.json
index 63e773c0e..f2aaef8da 100644
--- a/src/locales/zh-TW/repositories.json
+++ b/src/locales/zh-TW/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub 拒絕了此 Token(403)。檢查或新增 Star 時,細緻權限 Token 需開啟 Starring 讀寫及儲存庫 Metadata 讀取;傳統 Token 需 public_repo(私有儲存庫用 repo)。",
"title": "從連結批次 Star",
"hint": "貼上任何包含 GitHub 連結的文字,確認儲存庫後再 Star。其他網站的連結會被忽略。",
"history": "貼上歷史",
diff --git a/src/locales/zh/app.json b/src/locales/zh/app.json
index 39df6ee8b..e3685b517 100644
--- a/src/locales/zh/app.json
+++ b/src/locales/zh/app.json
@@ -934,7 +934,10 @@
"check-if-a-new-version-is-available": "检查是否有新版本可用",
"contact-information": "联系方式",
"if-you-encounter-any-issues-or-have-suggestions": "如果您在使用过程中遇到任何问题或有建议,欢迎通过以下方式联系我:",
- "github": "GitHub"
+ "github": "GitHub",
+ "account-token-hint": "当前账号 {{login}}。过期后可在此直接更换 token,不必退出登录。",
+ "token-hint": "过期后可在此直接更换 token,不必退出登录。",
+ "token-permission-guide": "查看 Token 配置指引"
},
"includeKeysToggle": {
"include-keys-in-backup-export": "备份/导出时包含密钥",
diff --git a/src/locales/zh/login.json b/src/locales/zh/login.json
index f187801de..c4133ef9f 100644
--- a/src/locales/zh/login.json
+++ b/src/locales/zh/login.json
@@ -1,5 +1,7 @@
{
"loginScreen": {
+ "token-permissions-title": "GitHub Token 权限",
+ "token-permissions-check": "登录只验证身份,不会检查所有功能权限;权限不足可能在使用相应功能时才出现。",
"please-enter-the-backend-url-and-api-key": "请输入后端 URL 和 API Key",
"invalid-backend-url-remote-backends-must-use-htt": "后端地址无效:远程后端需使用 HTTPS,仅 localhost 可使用 HTTP",
"unable-to-connect-to-this-backend-url": "无法连接到该后端 URL",
@@ -26,12 +28,6 @@
"connect-to-github": "连接到GitHub",
"connect-and-restore-data": "连接并恢复数据",
"save-and-continue": "保存并继续",
- "how-to-create-a-github-token": "如何创建GitHub token:",
- "go-to-github-settings-developer-settings-persona": "访问GitHub Settings → Developer settings → Personal access tokens",
- "click-generate-new-token-classic": "点击\"Generate new token (classic)\"",
- "select-scopes": "选择权限范围:",
- "and": "和",
- "copy-the-generated-token-and-paste-it-above": "复制生成的token并粘贴到上方",
"create-token-on-github": "在GitHub上创建token →",
"already-have-backend-data": "已有后端数据",
"sign-in-with-github-token": "使用 GitHub Token 登录",
@@ -41,6 +37,23 @@
"keep-local": "保留本地",
"please-enter-a-valid-github-token": "请输入有效的GitHub token",
"signed-in-but-failed-to-save-github-token-to-bac": "已登录,但 GitHub Token 未能保存到后端,README 等后端代理功能可能不可用。",
- "failed-to-authenticate-please-check-your-token": "认证失败,请检查您的token。"
+ "failed-to-authenticate-please-check-your-token": "认证失败,请检查您的token。",
+ "token-permissions-tab-finegrained": "细粒度 Token",
+ "token-permissions-tab-classic": "经典 Token",
+ "token-permissions-feature-star": "为仓库添加 Star",
+ "token-permissions-feature-gists": "Gist",
+ "token-permissions-feature-star-lists": "Star 清单",
+ "token-permissions-feature-fork-sync": "Fork 储存库同步",
+ "token-permissions-feature-workflows": "触发工作流",
+ "token-permissions-feature-fork-workflows": "Fork 同步 / 触发工作流",
+ "token-permissions-fine-star": "`Starring` 读写、`Metadata` 读取",
+ "token-permissions-fine-gists": "`Gists` 写入",
+ "token-permissions-fine-fork-sync": "`Contents` 写入",
+ "token-permissions-fine-workflows": "`Actions` 写入",
+ "token-permissions-classic-star": "`public_repo`(私有仓库用 `repo`)",
+ "token-permissions-classic-gists": "`gist`",
+ "token-permissions-classic-star-lists": "`user`",
+ "token-permissions-classic-fork-workflows": "`repo`",
+ "token-permissions-local-storage": "Token 仅保存在本机与你配置的后端,不会上传到应用方服务器。"
}
}
diff --git a/src/locales/zh/repositories.json b/src/locales/zh/repositories.json
index 58b589cd4..793e18484 100644
--- a/src/locales/zh/repositories.json
+++ b/src/locales/zh/repositories.json
@@ -1,5 +1,6 @@
{
"batchStar": {
+ "token-permission-error": "GitHub 拒绝了此 Token(403)。检查或添加 Star 时,细粒度 Token 需开启 Starring 读写及仓库 Metadata 读取;传统 Token 需 public_repo(私有仓库用 repo)。",
"title": "从链接批量 Star",
"hint": "粘贴任何包含 GitHub 链接的文字,确认仓库后再 Star。其他网站的链接会被忽略。",
"history": "粘贴历史",
diff --git a/src/services/githubApi.starStatus.test.ts b/src/services/githubApi.starStatus.test.ts
index cc227eb07..6f82c56ca 100644
--- a/src/services/githubApi.starStatus.test.ts
+++ b/src/services/githubApi.starStatus.test.ts
@@ -1,5 +1,5 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
-import { GitHubApiService } from './githubApi';
+import { GitHubApiService, GitHubTokenPermissionError } from './githubApi';
afterEach(() => vi.unstubAllGlobals());
@@ -16,6 +16,29 @@ describe('GitHubApiService.isRepositoryStarred', () => {
await expect(new GitHubApiService('test-token').isRepositoryStarred('owner', 'repo')).rejects.toThrow('403');
});
+ it('identifies a PAT permission failure without conflating it with rate limiting', async () => {
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(
+ JSON.stringify({ message: 'Resource not accessible by personal access token' }),
+ { status: 403, statusText: 'Forbidden', headers: { 'X-RateLimit-Remaining': '4999' } },
+ )));
+ await expect(new GitHubApiService('test-token').isRepositoryStarred('owner', 'repo'))
+ .rejects.toBeInstanceOf(GitHubTokenPermissionError);
+ });
+
+ it('does not reuse a previous zero rate limit for a later permission failure', async () => {
+ const fetchMock = vi.fn()
+ .mockResolvedValueOnce(new Response(null, { status: 204, headers: { 'X-RateLimit-Remaining': '0' } }))
+ .mockResolvedValueOnce(new Response(
+ JSON.stringify({ message: 'Resource not accessible by personal access token' }),
+ { status: 403, statusText: 'Forbidden' },
+ ));
+ vi.stubGlobal('fetch', fetchMock);
+ const api = new GitHubApiService('test-token');
+ expect(await api.isRepositoryStarred('owner', 'first')).toBe(true);
+ await expect(api.isRepositoryStarred('owner', 'second'))
+ .rejects.toBeInstanceOf(GitHubTokenPermissionError);
+ });
+
it('uses the configured backend proxy', async () => {
const fetchMock = vi.fn().mockResolvedValue(new Response(null, { status: 204 }));
vi.stubGlobal('fetch', fetchMock);
diff --git a/src/services/githubApi.ts b/src/services/githubApi.ts
index 4215d5b99..ebf073fe4 100644
--- a/src/services/githubApi.ts
+++ b/src/services/githubApi.ts
@@ -257,6 +257,14 @@ const GITHUB_API_BASE = 'https://api.github.com';
// Sentinel message for the 401 thrown above; callers match on it to tell a
// confirmed auth failure apart from network/rate-limit/5xx errors.
export const GITHUB_TOKEN_INVALID_ERROR = 'GitHub token expired or invalid';
+
+/** GitHub accepted the token, but it lacks permission for this request. */
+export class GitHubTokenPermissionError extends Error {
+ constructor() {
+ super('Resource not accessible by personal access token');
+ this.name = 'GitHubTokenPermissionError';
+ }
+}
// Sentinel for 401s produced by the backend proxy's own auth middleware (its
// body carries code: 'UNAUTHORIZED'). Kept distinct from the GitHub sentinel
// so callers can tell a stale backend API key from a dead GitHub token.
@@ -488,13 +496,20 @@ export class GitHubApiService {
}
throw new Error(GITHUB_TOKEN_INVALID_ERROR);
}
- if (response.status === 403 && this.rateLimitRemaining === 0) {
+ if (response.status === 403 && remaining === '0') {
const resetDate = this.rateLimitReset
? new Date(this.rateLimitReset * 1000).toLocaleString()
: 'unknown';
logger.warn('githubApi', 'API request failed: rate limit exceeded', { method, endpoint, status: response.status, durationMs });
throw new Error(`GitHub API rate limit exceeded. Resets at ${resetDate}`);
}
+ if (response.status === 403) {
+ const body = await response.clone().json().catch(() => null) as { message?: string } | null;
+ if (body?.message === 'Resource not accessible by personal access token') {
+ logger.warn('githubApi', 'API request failed: token permission', { method, endpoint, status: response.status, durationMs });
+ throw new GitHubTokenPermissionError();
+ }
+ }
// 5xx 视为可重试的瞬时故障;其余 4xx 直接抛出(重试无意义)。
const isRetryable = response.status >= 500 && response.status <= 599;