- Removing the token will also unlink all repositories and disable
- webhook events. This action cannot be undone.
+ {t("settings.token.removeBody", locale)}
void;
+ locale?: string;
}) {
const queryClient = useQueryClient();
const {
@@ -436,28 +447,22 @@ function AddRepoDialog({
onError: (err: unknown) => {
const code = getPluginErrorCode(err);
if (code === ErrorCode.GitLabWebhookURLNotPublic) {
- setError(
- "Cannot register webhook because this API URL is not publicly reachable (for example localhost). Configure PUBLIC_URL to a public HTTPS URL and try again.",
- );
+ setError(t("settings.addRepo.error.webhookNotPublic", locale));
return;
}
if (code === ErrorCode.GitLabWebhookCreationFailed) {
- setError(
- "Could not create the webhook. Ensure the token has the api scope, you have Maintainer/Owner on the project, and PUBLIC_URL is a public HTTPS URL GitLab can reach.",
- );
+ setError(t("settings.addRepo.error.webhookFailed", locale));
return;
}
if (code === ErrorCode.GitLabRepoAlreadyLinked) {
- setError("This repository is already linked to the project.");
+ setError(t("settings.addRepo.error.alreadyLinked", locale));
return;
}
if (code === ErrorCode.GitLabRepoNotAccessible) {
- setError(
- "Repository not found or not accessible. Check that your token has the api scope.",
- );
+ setError(t("settings.addRepo.error.notAccessible", locale));
return;
}
- setError("Failed to link repository. Please try again.");
+ setError(t("settings.addRepo.error.generic", locale));
},
});
@@ -480,11 +485,12 @@ function AddRepoDialog({
-
Add repository
+
+ {t("settings.addRepo.title", locale)}
+
- Select a repository from your GitLab account to link to this project.
- A webhook will be registered automatically.
+ {t("settings.addRepo.desc", locale)}
- This will remove the link to{" "}
+ {t("settings.unlink.bodyBefore", locale)}{" "}
{repo.full_name}
{" "}
- and attempt to delete the webhook from GitLab.
+ {t("settings.unlink.bodyAfter", locale)}
{unlinkMutation.isError && (
- Failed to unlink. Please try again.
+ {t("settings.unlink.failed", locale)}
- Link GitLab repositories to track merge requests, create branches from
- tasks, and receive webhook events automatically. You can link multiple
- repositories to a single project.
+ {t("settings.integrationDesc", locale)}
{/* Progress steps */}
@@ -798,7 +814,7 @@ function GitLabSettingsInner({
{hasRepos
- ? "Webhooks are registered automatically for each linked repository."
- : "No repositories linked yet. Link a repository to track merge requests and branches."}
+ ? t("settings.repos.webhooksAuto", locale)
+ : t("settings.repos.emptyHint", locale)}
{canEdit && (
setAddRepoOpen(true)}
>
- Add your first repository
+ {t("settings.repos.linkFirst", locale)}
)}
@@ -902,6 +920,7 @@ function GitLabSettingsInner({
projectId={projectId}
open={addRepoOpen}
onOpenChange={setAddRepoOpen}
+ locale={locale}
/>
)}
@@ -912,9 +931,7 @@ function GitLabSettingsInner({
- Webhooks are registered on all linked repositories. GitLab will push{" "}
- pull_request events to keep PR
- status in sync automatically.
+ {t("settings.webhook.hint", locale)}
)}
@@ -924,8 +941,7 @@ function GitLabSettingsInner({
- No GitLab integration configured. Add a personal access token to get
- started.
+ {t("settings.noIntegration", locale)}
);
@@ -1163,6 +1219,7 @@ export default function GitLabTaskSection({
projectId,
taskId,
canEdit = true,
+ locale,
}: GitLabTaskSectionProps) {
const api = useMemo(
() =>
@@ -1182,6 +1239,7 @@ export default function GitLabTaskSection({
projectId={projectId}
taskId={taskId}
canEdit={canEdit}
+ locale={locale}
/>
);
diff --git a/frontend/src/i18n/en.ts b/frontend/src/i18n/en.ts
index 6186b91..a76b998 100644
--- a/frontend/src/i18n/en.ts
+++ b/frontend/src/i18n/en.ts
@@ -1,12 +1,20 @@
const en = {
"settings.title": "GitLab",
+ "settings.integrationTitle": "GitLab Integration",
+ "settings.integrationDesc":
+ "Link GitLab repositories to track merge requests, create branches from tasks, and receive webhook events automatically. You can link multiple repositories to a single project.",
+ "settings.step.connectToken": "Connect a GitLab token",
+ "settings.step.linkRepo": "Link a repository",
+
"settings.token.saved": "Access token saved",
- "settings.token.encrypted": "Token is stored encrypted. It is never returned by the API.",
+ "settings.token.encrypted":
+ "Token is stored encrypted. It is never returned by the API.",
"settings.token.remove": "Remove token",
"settings.token.removeTitle": "Remove GitLab token",
"settings.token.removeBody":
"Removing the token will also unlink all repositories and disable webhook events. This action cannot be undone.",
"settings.token.cancel": "Cancel",
+ "settings.token.removing": "Removing…",
"settings.token.save": "Save token",
"settings.token.label": "Access token",
"settings.token.placeholder": "glpat-… or project/group access token",
@@ -14,20 +22,138 @@ const en = {
"settings.token.kind.personal": "Personal access token",
"settings.token.kind.project": "Project access token",
"settings.token.kind.group": "Group access token",
+ "settings.token.scopeHintBefore":
+ "Use a Personal, Project, or Group Access Token with scope",
+ "settings.token.scopeHintAfter":
+ "(Maintainer/Owner required to create project webhooks).",
+ "settings.token.show": "show",
+ "settings.token.hide": "hide",
"settings.instanceUrl": "GitLab instance URL",
- "settings.instanceUrl.hint": "Default https://gitlab.com — Self-Managed: your instance base URL",
+ "settings.instanceUrl.hint":
+ "Default https://gitlab.com — Self-Managed: your instance base URL",
"settings.token.invalid":
"GitLab rejected the token. Check scope api and Maintainer/Owner role for webhooks.",
"settings.token.saveFailed": "Failed to save token. Please try again.",
"settings.token.removeFailed": "Failed to remove token. Please try again.",
- "settings.repos.title": "Linked projects",
- "settings.repos.link": "Link project",
+
+ "settings.repos.title": "Linked Repositories",
+ "settings.repos.link": "Add repository",
+ "settings.repos.linkFirst": "Add your first repository",
+ "settings.repos.empty": "No repositories linked yet.",
+ "settings.repos.emptyHint":
+ "No repositories linked yet. Link a repository to track merge requests and branches.",
+ "settings.repos.webhooksAuto":
+ "Webhooks are registered automatically for each linked repository.",
+ "settings.repos.reload": "Reload linked repositories",
+ "settings.repos.defaultBranch": "Default branch:",
+
+ "settings.addRepo.title": "Add repository",
+ "settings.addRepo.desc":
+ "Select a repository from your GitLab account to link to this project. A webhook will be registered automatically.",
+ "settings.addRepo.search": "Search repositories…",
+ "settings.addRepo.reload": "Reload repositories",
+ "settings.addRepo.empty": "No accessible repositories found.",
+ "settings.addRepo.noMatch": 'No repositories match "{search}"',
+ "settings.addRepo.private": "Private",
+ "settings.addRepo.close": "Close",
+ "settings.addRepo.error.webhookNotPublic":
+ "Cannot register webhook because this API URL is not publicly reachable (for example localhost). Configure PUBLIC_URL to a public HTTPS URL and try again.",
+ "settings.addRepo.error.webhookFailed":
+ "Could not create the webhook. Ensure the token has the api scope, you have Maintainer/Owner on the project, and PUBLIC_URL is a public HTTPS URL GitLab can reach.",
+ "settings.addRepo.error.alreadyLinked":
+ "This repository is already linked to the project.",
+ "settings.addRepo.error.notAccessible":
+ "Repository not found or not accessible. Check that your token has the api scope.",
+ "settings.addRepo.error.generic": "Failed to link repository. Please try again.",
+
+ "settings.unlink.action": "Unlink",
+ "settings.unlink.title": "Unlink repository",
+ "settings.unlink.bodyBefore": "This will remove the link to",
+ "settings.unlink.bodyAfter":
+ "and attempt to delete the webhook from GitLab.",
+ "settings.unlink.confirm": "Unlink repository",
+ "settings.unlink.unlinking": "Unlinking…",
+ "settings.unlink.failed": "Failed to unlink. Please try again.",
+
+ "settings.webhook.hint":
+ "Webhooks are registered on all linked repositories. GitLab will push merge_request events to keep MR status in sync automatically.",
+ "settings.noIntegration":
+ "No GitLab integration configured. Add a personal access token to get started.",
+
"task.section.title": "GitLab",
+ "task.mr.title": "Merge Requests",
"task.mr.link": "Link merge request",
"task.mr.create": "Create merge request",
+ "task.mr.empty": "No merge requests linked yet.",
+ "task.mr.unlink": "Unlink merge request",
+ "task.mr.state.open": "Open",
+ "task.mr.state.merged": "Merged",
+ "task.mr.state.closed": "Closed",
+ "task.mr.by": "by {author}",
+ "task.mr.repository": "Repository",
+ "task.mr.selectRepo": "Select repository…",
+ "task.mr.inputLabel": "PR number or GitLab URL",
+ "task.mr.placeholder":
+ "42 or https://gitlab.com/owner/repo/-/merge_requests/42",
+ "task.mr.willLink": "Will link PR #{number} from {repo}",
+ "task.mr.error.noToken": "No GitLab token configured for this project.",
+ "task.mr.error.repoNotFound":
+ "Repository not found. It may have been unlinked.",
+ "task.mr.error.prNotFound":
+ "PR #{number} was not found in the selected repository.",
+ "task.mr.error.alreadyLinked": "PR #{number} is already linked to this task.",
+ "task.mr.error.permissions":
+ "Your GitLab token does not have permission to read merge requests. Update it in Project Settings > GitLab.",
+ "task.mr.error.generic": "Failed to link merge request. Please try again.",
+ "task.mr.error.repoNotLinked":
+ 'Repository "{name}" is not linked to this project.',
+ "task.mr.error.selectRepo": "Select a repository.",
+ "task.mr.error.invalidInput":
+ "Enter a valid PR number or paste a GitLab PR URL.",
+
+ "task.branch.title": "Branches",
"task.branch.create": "Create branch on GitLab",
+ "task.branch.createShort": "Create branch",
+ "task.branch.link": "Link existing branch",
+ "task.branch.linkAction": "Link branch",
+ "task.branch.empty": "No branches linked yet.",
+ "task.branch.type": "Type",
+ "task.branch.name": "Branch name",
+ "task.branch.repository": "Repository",
+ "task.branch.selectRepo": "Select repository…",
+ "task.branch.source": "Source branch",
+ "task.branch.sourceOptional": "(optional, defaults to repo default)",
+ "task.branch.orLocal": "Or create locally:",
+ "task.branch.copy": "Copy to clipboard",
+ "task.branch.nameOrUrl": "Branch name or GitLab URL",
+ "task.branch.placeholder":
+ "feature/foo or https://gitlab.com/owner/repo/tree/feature/foo",
+ "task.branch.willLink": "Will link branch {branch} from {repo}",
+ "task.branch.error.noToken": "No GitLab token configured for this project.",
+ "task.branch.error.repoNotFound":
+ "Repository not found. It may have been unlinked.",
+ "task.branch.error.alreadyLinked":
+ "This branch is already linked to the task.",
+ "task.branch.error.alreadyLinkedNamed":
+ 'Branch "{branch}" is already linked to this task.',
+ "task.branch.error.notFound":
+ 'Branch "{branch}" was not found in the selected repository.',
+ "task.branch.error.permissionsCreate":
+ "Your GitLab token does not have permission to create branches. Update it in Project Settings > GitLab with a token that has the api scope.",
+ "task.branch.error.permissionsRead":
+ "Your GitLab token does not have permission to read branches. Update it in Project Settings > GitLab.",
+ "task.branch.error.createFailed": "Failed to create branch. Please try again.",
+ "task.branch.error.linkFailed": "Failed to link branch. Please try again.",
+ "task.branch.error.nameRequired": "Branch name is required.",
+ "task.branch.error.selectRepo": "Select a repository.",
+ "task.branch.error.invalidInput":
+ "Enter a branch name or paste a GitLab branch URL.",
+ "task.branch.error.repoNotLinked":
+ 'Repository "{name}" is not linked to this project.',
+
"common.loading": "Loading…",
"common.error": "Something went wrong",
+ "common.cancel": "Cancel",
} as const;
export type MessageKey = keyof typeof en;
diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts
index 5992b99..2e5d437 100644
--- a/frontend/src/i18n/index.ts
+++ b/frontend/src/i18n/index.ts
@@ -15,9 +15,20 @@ export function resolveLocale(raw?: string | null): Locale {
return v === "it" ? "it" : "en";
}
-export function t(key: MessageKey, locale?: string | null): string {
+/** Simple `{name}` interpolation; missing vars are left as-is. */
+export function t(
+ key: MessageKey,
+ locale?: string | null,
+ vars?: Record,
+): string {
const loc = resolveLocale(locale);
- return catalogs[loc][key] ?? catalogs.en[key] ?? key;
+ let msg = catalogs[loc][key] ?? catalogs.en[key] ?? key;
+ if (vars) {
+ for (const [name, value] of Object.entries(vars)) {
+ msg = msg.split(`{${name}}`).join(String(value));
+ }
+ }
+ return msg;
}
export type { MessageKey };
diff --git a/frontend/src/i18n/it.ts b/frontend/src/i18n/it.ts
index 8b2bf40..174e42d 100644
--- a/frontend/src/i18n/it.ts
+++ b/frontend/src/i18n/it.ts
@@ -2,13 +2,21 @@ import type { MessageKey } from "./en";
const it: Record = {
"settings.title": "GitLab",
+ "settings.integrationTitle": "Integrazione GitLab",
+ "settings.integrationDesc":
+ "Collega i repository GitLab per tracciare le merge request, creare branch dalle task e ricevere automaticamente gli eventi webhook. Puoi collegare più repository a un unico progetto.",
+ "settings.step.connectToken": "Collega un token GitLab",
+ "settings.step.linkRepo": "Collega un repository",
+
"settings.token.saved": "Token di accesso salvato",
- "settings.token.encrypted": "Il token è cifrato. Non viene mai restituito dall’API.",
+ "settings.token.encrypted":
+ "Il token è cifrato. Non viene mai restituito dall’API.",
"settings.token.remove": "Rimuovi token",
"settings.token.removeTitle": "Rimuovi token GitLab",
"settings.token.removeBody":
- "Rimuovendo il token verranno scollegati tutti i progetti e disabilitati i webhook. L’azione non è reversibile.",
+ "Rimuovendo il token verranno scollegati tutti i repository e disabilitati i webhook. L’azione non è reversibile.",
"settings.token.cancel": "Annulla",
+ "settings.token.removing": "Rimozione…",
"settings.token.save": "Salva token",
"settings.token.label": "Token di accesso",
"settings.token.placeholder": "glpat-… o project/group access token",
@@ -16,20 +24,141 @@ const it: Record = {
"settings.token.kind.personal": "Personal access token",
"settings.token.kind.project": "Project access token",
"settings.token.kind.group": "Group access token",
+ "settings.token.scopeHintBefore":
+ "Usa un Personal, Project o Group Access Token con scope",
+ "settings.token.scopeHintAfter":
+ "(ruolo Maintainer/Owner richiesto per creare i webhook di progetto).",
+ "settings.token.show": "mostra",
+ "settings.token.hide": "nascondi",
"settings.instanceUrl": "URL istanza GitLab",
- "settings.instanceUrl.hint": "Default https://gitlab.com — Self-Managed: URL base della tua istanza",
+ "settings.instanceUrl.hint":
+ "Default https://gitlab.com — Self-Managed: URL base della tua istanza",
"settings.token.invalid":
"GitLab ha rifiutato il token. Verifica lo scope api e il ruolo Maintainer/Owner per i webhook.",
"settings.token.saveFailed": "Salvataggio token non riuscito. Riprova.",
"settings.token.removeFailed": "Rimozione token non riuscita. Riprova.",
- "settings.repos.title": "Progetti collegati",
- "settings.repos.link": "Collega progetto",
+
+ "settings.repos.title": "Repository collegati",
+ "settings.repos.link": "Aggiungi repository",
+ "settings.repos.linkFirst": "Aggiungi il primo repository",
+ "settings.repos.empty": "Nessun repository collegato.",
+ "settings.repos.emptyHint":
+ "Nessun repository collegato. Collega un repository per tracciare merge request e branch.",
+ "settings.repos.webhooksAuto":
+ "I webhook vengono registrati automaticamente per ogni repository collegato.",
+ "settings.repos.reload": "Ricarica repository collegati",
+ "settings.repos.defaultBranch": "Branch predefinito:",
+
+ "settings.addRepo.title": "Aggiungi repository",
+ "settings.addRepo.desc":
+ "Seleziona un repository dal tuo account GitLab da collegare a questo progetto. Verrà registrato automaticamente un webhook.",
+ "settings.addRepo.search": "Cerca repository…",
+ "settings.addRepo.reload": "Ricarica repository",
+ "settings.addRepo.empty": "Nessun repository accessibile trovato.",
+ "settings.addRepo.noMatch": 'Nessun repository corrisponde a "{search}"',
+ "settings.addRepo.private": "Privato",
+ "settings.addRepo.close": "Chiudi",
+ "settings.addRepo.error.webhookNotPublic":
+ "Impossibile registrare il webhook perché questo URL API non è raggiungibile pubblicamente (ad esempio localhost). Configura PUBLIC_URL con un URL HTTPS pubblico e riprova.",
+ "settings.addRepo.error.webhookFailed":
+ "Impossibile creare il webhook. Assicurati che il token abbia lo scope api, che tu sia Maintainer/Owner sul progetto e che PUBLIC_URL sia un URL HTTPS pubblico raggiungibile da GitLab.",
+ "settings.addRepo.error.alreadyLinked":
+ "Questo repository è già collegato al progetto.",
+ "settings.addRepo.error.notAccessible":
+ "Repository non trovato o non accessibile. Verifica che il token abbia lo scope api.",
+ "settings.addRepo.error.generic":
+ "Collegamento del repository non riuscito. Riprova.",
+
+ "settings.unlink.action": "Scollega",
+ "settings.unlink.title": "Scollega repository",
+ "settings.unlink.bodyBefore": "Questo rimuoverà il collegamento a",
+ "settings.unlink.bodyAfter":
+ "e tenterà di eliminare il webhook da GitLab.",
+ "settings.unlink.confirm": "Scollega repository",
+ "settings.unlink.unlinking": "Scollegamento…",
+ "settings.unlink.failed": "Scollegamento non riuscito. Riprova.",
+
+ "settings.webhook.hint":
+ "I webhook sono registrati su tutti i repository collegati. GitLab invierà eventi merge_request per mantenere lo stato delle MR sincronizzato automaticamente.",
+ "settings.noIntegration":
+ "Nessuna integrazione GitLab configurata. Aggiungi un token di accesso per iniziare.",
+
"task.section.title": "GitLab",
+ "task.mr.title": "Merge Request",
"task.mr.link": "Collega merge request",
"task.mr.create": "Crea merge request",
+ "task.mr.empty": "Nessuna merge request collegata.",
+ "task.mr.unlink": "Scollega merge request",
+ "task.mr.state.open": "Aperta",
+ "task.mr.state.merged": "Merged",
+ "task.mr.state.closed": "Chiusa",
+ "task.mr.by": "di {author}",
+ "task.mr.repository": "Repository",
+ "task.mr.selectRepo": "Seleziona repository…",
+ "task.mr.inputLabel": "Numero PR o URL GitLab",
+ "task.mr.placeholder":
+ "42 oppure https://gitlab.com/owner/repo/-/merge_requests/42",
+ "task.mr.willLink": "Collegherà la PR #{number} da {repo}",
+ "task.mr.error.noToken": "Nessun token GitLab configurato per questo progetto.",
+ "task.mr.error.repoNotFound":
+ "Repository non trovato. Potrebbe essere stato scollegato.",
+ "task.mr.error.prNotFound":
+ "La PR #{number} non è stata trovata nel repository selezionato.",
+ "task.mr.error.alreadyLinked": "La PR #{number} è già collegata a questa task.",
+ "task.mr.error.permissions":
+ "Il token GitLab non ha i permessi per leggere le merge request. Aggiornalo in Impostazioni progetto > GitLab.",
+ "task.mr.error.generic": "Collegamento merge request non riuscito. Riprova.",
+ "task.mr.error.repoNotLinked":
+ 'Il repository "{name}" non è collegato a questo progetto.',
+ "task.mr.error.selectRepo": "Seleziona un repository.",
+ "task.mr.error.invalidInput":
+ "Inserisci un numero PR valido o incolla un URL di PR GitLab.",
+
+ "task.branch.title": "Branch",
"task.branch.create": "Crea branch su GitLab",
+ "task.branch.createShort": "Crea branch",
+ "task.branch.link": "Collega branch esistente",
+ "task.branch.linkAction": "Collega branch",
+ "task.branch.empty": "Nessun branch collegato.",
+ "task.branch.type": "Tipo",
+ "task.branch.name": "Nome branch",
+ "task.branch.repository": "Repository",
+ "task.branch.selectRepo": "Seleziona repository…",
+ "task.branch.source": "Branch di origine",
+ "task.branch.sourceOptional":
+ "(opzionale, predefinito: branch di default del repo)",
+ "task.branch.orLocal": "Oppure crea in locale:",
+ "task.branch.copy": "Copia negli appunti",
+ "task.branch.nameOrUrl": "Nome branch o URL GitLab",
+ "task.branch.placeholder":
+ "feature/foo oppure https://gitlab.com/owner/repo/tree/feature/foo",
+ "task.branch.willLink": "Collegherà il branch {branch} da {repo}",
+ "task.branch.error.noToken":
+ "Nessun token GitLab configurato per questo progetto.",
+ "task.branch.error.repoNotFound":
+ "Repository non trovato. Potrebbe essere stato scollegato.",
+ "task.branch.error.alreadyLinked":
+ "Questo branch è già collegato alla task.",
+ "task.branch.error.alreadyLinkedNamed":
+ 'Il branch "{branch}" è già collegato a questa task.',
+ "task.branch.error.notFound":
+ 'Il branch "{branch}" non è stato trovato nel repository selezionato.',
+ "task.branch.error.permissionsCreate":
+ "Il token GitLab non ha i permessi per creare branch. Aggiornalo in Impostazioni progetto > GitLab con un token che abbia lo scope api.",
+ "task.branch.error.permissionsRead":
+ "Il token GitLab non ha i permessi per leggere i branch. Aggiornalo in Impostazioni progetto > GitLab.",
+ "task.branch.error.createFailed": "Creazione branch non riuscita. Riprova.",
+ "task.branch.error.linkFailed": "Collegamento branch non riuscito. Riprova.",
+ "task.branch.error.nameRequired": "Il nome del branch è obbligatorio.",
+ "task.branch.error.selectRepo": "Seleziona un repository.",
+ "task.branch.error.invalidInput":
+ "Inserisci un nome di branch o incolla un URL di branch GitLab.",
+ "task.branch.error.repoNotLinked":
+ 'Il repository "{name}" non è collegato a questo progetto.',
+
"common.loading": "Caricamento…",
"common.error": "Qualcosa è andato storto",
+ "common.cancel": "Annulla",
};
export default it;