i18n(users): translate the terminated-sessions toast
Both toasts printed the endpoint's own message field verbatim, so a Russian UI
answered "Terminated 0 sessions". That string is assembled in Python and can
never be translated where it is built, so the endpoints now also return the raw
count and the phrase is composed on the client.
message is kept: it goes to the audit log and may have other consumers, and
adding a field breaks no one.
Russian needs three forms, and zero does not land in the obvious one — 0 is the
"many" category ("сессий", not "сессии") — hence four keys against English's
two.
Fixes both call sites: the per-user button in the table row and Terminate all
sessions on the Sessions tab, which shared the same untranslated string.
This commit is contained in:
@@ -978,7 +978,9 @@ async def terminate_user_sessions(
|
||||
resource_name=user.username
|
||||
)
|
||||
|
||||
return {"message": f"Terminated {count} sessions"}
|
||||
# count отдаётся отдельным полем: фронтенд склоняет фразу сам, показывать
|
||||
# message пользователю нельзя — он не переводится.
|
||||
return {"message": f"Terminated {count} sessions", "count": count}
|
||||
|
||||
|
||||
# ==================== Security Settings API ====================
|
||||
@@ -1167,7 +1169,7 @@ async def terminate_all_sessions(
|
||||
ip_address=get_client_ip(request)
|
||||
)
|
||||
|
||||
return {"message": f"Terminated {deleted} sessions"}
|
||||
return {"message": f"Terminated {deleted} sessions", "count": deleted}
|
||||
|
||||
|
||||
# ==================== Security Events API ====================
|
||||
|
||||
@@ -262,7 +262,7 @@ function UsersTab() {
|
||||
variant="ghost" size="icon" className="h-7 w-7"
|
||||
title={t('users.terminate_sessions')}
|
||||
onClick={() => terminateSessions.mutate(u.id, {
|
||||
onSuccess: r => toast.success(r.message),
|
||||
onSuccess: r => toast.success(t('users.sessions_terminated', { count: r.count })),
|
||||
onError: e => toast.error(getErrMsg(e)),
|
||||
})}
|
||||
>
|
||||
@@ -1074,7 +1074,7 @@ function SessionsTab() {
|
||||
variant="destructive" size="sm"
|
||||
disabled={sessions.length === 0 || terminateAll.isPending}
|
||||
onClick={() => terminateAll.mutate(undefined, {
|
||||
onSuccess: r => toast.success(r.message),
|
||||
onSuccess: r => toast.success(t('users.sessions_terminated', { count: r.count })),
|
||||
onError: e => toast.error(getErrMsg(e)),
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -173,11 +173,20 @@ export function useUnlockUser() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* `message` is the backend's own English wording and is not shown to the user;
|
||||
* the toast is built from `count` so it can be translated and declined.
|
||||
*/
|
||||
export interface TerminateSessionsResult {
|
||||
message: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export function useTerminateUserSessions() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (userId: number) =>
|
||||
apiClient.post<{ message: string }>(`/admin/api/users/${userId}/terminate-sessions`),
|
||||
apiClient.post<TerminateSessionsResult>(`/admin/api/users/${userId}/terminate-sessions`),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: userKeys.sessions }),
|
||||
});
|
||||
}
|
||||
@@ -337,7 +346,7 @@ export function useTerminateSession() {
|
||||
export function useTerminateAllSessions() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: () => apiClient.post<{ message: string }>('/admin/api/sessions/terminate-all'),
|
||||
mutationFn: () => apiClient.post<TerminateSessionsResult>('/admin/api/sessions/terminate-all'),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: userKeys.sessions }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1509,7 +1509,9 @@
|
||||
"used": "Used",
|
||||
"unlimited": "unlimited",
|
||||
"saved": "Quota saved"
|
||||
}
|
||||
},
|
||||
"sessions_terminated_one": "Terminated {{count}} session",
|
||||
"sessions_terminated_other": "Terminated {{count}} sessions"
|
||||
},
|
||||
"workspaces": {
|
||||
"create": "Create Workspace",
|
||||
|
||||
@@ -1509,7 +1509,11 @@
|
||||
"used": "Использовано",
|
||||
"unlimited": "без лимита",
|
||||
"saved": "Квоты сохранены"
|
||||
}
|
||||
},
|
||||
"sessions_terminated_one": "Завершена {{count}} сессия",
|
||||
"sessions_terminated_few": "Завершено {{count}} сессии",
|
||||
"sessions_terminated_many": "Завершено {{count}} сессий",
|
||||
"sessions_terminated_other": "Завершено {{count}} сессий"
|
||||
},
|
||||
"workspaces": {
|
||||
"create": "Создать рабочую область",
|
||||
|
||||
Reference in New Issue
Block a user