mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
Show the PR panel's state, activity verbs, and thread badges in the app language (#6225)
* fix(app): show PR panel state, activity verbs, and thread badges in the app language The PR panel's state label, the verb after each activity author, and the Resolved and Outdated thread badges were English literals, so they stayed English in every other language. The state and verb translations already existed and were unused; the badges get new keys in every locale. Closes #6214 * fix(app): translate every PR panel verb and state, and phrase them after the author The zh-CN state and review labels still held English ("Open", "Draft", "已 review"), and the Spanish and Portuguese verbs were adjectives that do not read after an author's name. The translation test now checks each verb and state on its own, so one English label fails it. Co-authored-by: Dillon <dillonzq@outlook.com> --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: Dillon <dillonzq@outlook.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
import { getStateLabel } from "@/git/pull-request-panel/data";
|
||||
import { en } from "@/i18n/resources/en";
|
||||
import { openPullRequestPanel } from "./workspace-tabs";
|
||||
|
||||
export async function openPrPane(page: Page): Promise<void> {
|
||||
@@ -14,7 +14,7 @@ export async function expectPrPaneState(
|
||||
page: Page,
|
||||
state: "open" | "merged" | "closed" | "draft",
|
||||
): Promise<void> {
|
||||
await expect(page.getByTestId("pr-pane-state")).toHaveText(getStateLabel(state), {
|
||||
await expect(page.getByTestId("pr-pane-state")).toHaveText(en.workspace.git.pr.states[state], {
|
||||
timeout: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,12 +9,13 @@ import {
|
||||
isPipelineActiveStatus,
|
||||
mapPipelineStatus,
|
||||
} from "@/git/forges/gitlab";
|
||||
import { i18n } from "@/i18n/i18next";
|
||||
import { IDENTITY_COLOR_NAMES, identityColor } from "@/styles/identity-colors";
|
||||
import {
|
||||
deriveAvatarColor,
|
||||
formatAge,
|
||||
getActivityVerb,
|
||||
getStateLabel,
|
||||
getActivityVerbKey,
|
||||
getStateLabelKey,
|
||||
mapPrPaneData,
|
||||
} from "./data";
|
||||
|
||||
@@ -779,37 +780,34 @@ describe("formatAge", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getStateLabel", () => {
|
||||
const english = i18n.getFixedT("en");
|
||||
const french = i18n.getFixedT("fr");
|
||||
|
||||
describe("getStateLabelKey", () => {
|
||||
it.each([
|
||||
["open", "Open"],
|
||||
["draft", "Draft"],
|
||||
["merged", "Merged"],
|
||||
["closed", "Closed"],
|
||||
] as const)("maps %s → %s", (state, expected) => {
|
||||
expect(getStateLabel(state)).toBe(expected);
|
||||
["open", "Open", "Ouverte"],
|
||||
["draft", "Draft", "Brouillon"],
|
||||
["merged", "Merged", "Fusionnée"],
|
||||
["closed", "Closed", "Fermée"],
|
||||
] as const)("labels %s as %s, and %s in French", (state, englishLabel, frenchLabel) => {
|
||||
expect(english(getStateLabelKey(state))).toBe(englishLabel);
|
||||
expect(french(getStateLabelKey(state))).toBe(frenchLabel);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getActivityVerb", () => {
|
||||
it("returns Commented for comment kind", () => {
|
||||
expect(getActivityVerb({ kind: "comment" })).toBe("Commented");
|
||||
});
|
||||
|
||||
it("returns Approved for approved review", () => {
|
||||
expect(getActivityVerb({ kind: "review", reviewState: "approved" })).toBe("Approved");
|
||||
});
|
||||
|
||||
it("returns Requested changes for changes_requested review", () => {
|
||||
expect(getActivityVerb({ kind: "review", reviewState: "changes_requested" })).toBe(
|
||||
describe("getActivityVerbKey", () => {
|
||||
it.each([
|
||||
[{ kind: "comment" }, "Commented", "A commenté"],
|
||||
[{ kind: "review", reviewState: "approved" }, "Approved", "A approuvé"],
|
||||
[
|
||||
{ kind: "review", reviewState: "changes_requested" },
|
||||
"Requested changes",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns Reviewed for a commented review with body (generic case)", () => {
|
||||
expect(getActivityVerb({ kind: "review", reviewState: "commented" })).toBe("Reviewed");
|
||||
});
|
||||
|
||||
it("returns Reviewed when reviewState is undefined", () => {
|
||||
expect(getActivityVerb({ kind: "review" })).toBe("Reviewed");
|
||||
"A demandé des modifications",
|
||||
],
|
||||
[{ kind: "review", reviewState: "commented" }, "Reviewed", "A relu"],
|
||||
[{ kind: "review" }, "Reviewed", "A relu"],
|
||||
] as const)("labels %o as %s, and %s in French", (item, englishVerb, frenchVerb) => {
|
||||
expect(english(getActivityVerbKey(item))).toBe(englishVerb);
|
||||
expect(french(getActivityVerbKey(item))).toBe(frenchVerb);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -318,16 +318,18 @@ function parsePullRequestNumber(url: string): number | null {
|
||||
}
|
||||
}
|
||||
|
||||
export function getStateLabel(state: PrState): string {
|
||||
if (state === "draft") return "Draft";
|
||||
if (state === "merged") return "Merged";
|
||||
if (state === "closed") return "Closed";
|
||||
return "Open";
|
||||
export function getStateLabelKey(state: PrState) {
|
||||
if (state === "draft") return "workspace.git.pr.states.draft";
|
||||
if (state === "merged") return "workspace.git.pr.states.merged";
|
||||
if (state === "closed") return "workspace.git.pr.states.closed";
|
||||
return "workspace.git.pr.states.open";
|
||||
}
|
||||
|
||||
export function getActivityVerb(item: Pick<PrPaneActivity, "kind" | "reviewState">): string {
|
||||
if (item.kind === "comment") return "Commented";
|
||||
if (item.reviewState === "approved") return "Approved";
|
||||
if (item.reviewState === "changes_requested") return "Requested changes";
|
||||
return "Reviewed";
|
||||
export function getActivityVerbKey(item: Pick<PrPaneActivity, "kind" | "reviewState">) {
|
||||
if (item.kind === "comment") return "workspace.git.pr.activity.commented";
|
||||
if (item.reviewState === "approved") return "workspace.git.pr.activity.approved";
|
||||
if (item.reviewState === "changes_requested") {
|
||||
return "workspace.git.pr.activity.requestedChanges";
|
||||
}
|
||||
return "workspace.git.pr.activity.reviewed";
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ import {
|
||||
canAddPullRequestActivityToChat,
|
||||
} from "./context-attachment";
|
||||
import { ChecksSection, getCheckIdentity } from "./checks-section";
|
||||
import { getActivityVerb, getStateLabel } from "./data";
|
||||
import { getActivityVerbKey, getStateLabelKey } from "./data";
|
||||
import type { PrPaneActivity, PrPaneCheck, PrPaneData, PrState } from "./data";
|
||||
import type { ForgeSpecificStatusFacts } from "@/git/merge-capability";
|
||||
import { CheckPresentationIcon } from "@/git/check-presentation.view";
|
||||
@@ -538,7 +538,7 @@ export function PullRequestPane({
|
||||
<View style={styles.metaLine}>
|
||||
<StateIcon size={14} uniProps={statePresentation.iconColor} />
|
||||
<Text style={stateLabelStyle(data.state)} testID="pr-pane-state">
|
||||
{getStateLabel(data.state)}
|
||||
{t(getStateLabelKey(data.state))}
|
||||
</Text>
|
||||
{nativeHeaderMeta}
|
||||
{repoIdentity ? (
|
||||
@@ -760,7 +760,8 @@ function ActivityAvatar({ activity, size }: { activity: PrPaneActivity; size: nu
|
||||
}
|
||||
|
||||
function ActivityVerb({ activity }: { activity: PrPaneActivity }) {
|
||||
const verb = getActivityVerb(activity).toLowerCase();
|
||||
const { t } = useTranslation();
|
||||
const verb = t(getActivityVerbKey(activity)).toLowerCase();
|
||||
if (activity.kind === "review" && activity.reviewState === "approved") {
|
||||
return (
|
||||
<View style={styles.verbGroup}>
|
||||
@@ -1065,8 +1066,12 @@ function ThreadBlock({
|
||||
? formatPullRequestThreadPath(thread.location)
|
||||
: t("workspace.git.pr.thread.discussion")}
|
||||
</Text>
|
||||
{thread.isResolved ? <StatusBadge label="Resolved" variant="success" /> : null}
|
||||
{thread.location?.isOutdated ? <StatusBadge label="Outdated" /> : null}
|
||||
{thread.isResolved ? (
|
||||
<StatusBadge label={t("workspace.git.pr.thread.resolved")} variant="success" />
|
||||
) : null}
|
||||
{thread.location?.isOutdated ? (
|
||||
<StatusBadge label={t("workspace.git.pr.thread.outdated")} />
|
||||
) : null}
|
||||
<View style={styles.headerTrailing}>
|
||||
{collapsed ? (
|
||||
<View style={styles.threadCount}>
|
||||
|
||||
@@ -76,6 +76,7 @@ const untranslatedLocalFallbacks = [
|
||||
|
||||
const pullRequestPanelSources = [
|
||||
"git/pull-request-panel/pane.tsx",
|
||||
"git/pull-request-panel/data.ts",
|
||||
"git/pull-request-panel/checks-section.tsx",
|
||||
"components/sidebar/sidebar-status-list.tsx",
|
||||
] as const;
|
||||
@@ -87,6 +88,16 @@ const untranslatedPullRequestPanelLabels = [
|
||||
"Adding...",
|
||||
"Comment actions",
|
||||
"Thread actions",
|
||||
"Commented",
|
||||
"Approved",
|
||||
"Requested changes",
|
||||
"Reviewed",
|
||||
"Draft",
|
||||
"Merged",
|
||||
"Closed",
|
||||
"Open",
|
||||
"Resolved",
|
||||
"Outdated",
|
||||
] as const;
|
||||
|
||||
function findUntranslatedPullRequestPanelLabels(): string[] {
|
||||
@@ -244,6 +255,14 @@ describe("translation resources", () => {
|
||||
expect(pr.actions.addingToChat).not.toBe(englishPr.actions.addingToChat);
|
||||
expect(pr.accessibility.commentActions).not.toBe(englishPr.accessibility.commentActions);
|
||||
expect(pr.accessibility.threadActions).not.toBe(englishPr.accessibility.threadActions);
|
||||
for (const verb of Object.keys(englishPr.activity) as (keyof typeof englishPr.activity)[]) {
|
||||
expect(pr.activity[verb]).not.toBe(englishPr.activity[verb]);
|
||||
}
|
||||
for (const state of Object.keys(englishPr.states) as (keyof typeof englishPr.states)[]) {
|
||||
expect(pr.states[state]).not.toBe(englishPr.states[state]);
|
||||
}
|
||||
expect(pr.thread.resolved).not.toBe(englishPr.thread.resolved);
|
||||
expect(pr.thread.outdated).not.toBe(englishPr.thread.outdated);
|
||||
expect(resource.sidebar.statusGroupAccessibility).not.toBe(
|
||||
en.sidebar.statusGroupAccessibility,
|
||||
);
|
||||
|
||||
@@ -1070,6 +1070,8 @@ export const ar: TranslationResources = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "سلسلة المناقشة",
|
||||
resolved: "تم الحل",
|
||||
outdated: "قديم",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "غير قادر على تحميل حالة طلب السحب",
|
||||
|
||||
@@ -1078,6 +1078,8 @@ export const en = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "Discussion thread",
|
||||
resolved: "Resolved",
|
||||
outdated: "Outdated",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "Unable to load pull request status",
|
||||
|
||||
@@ -1093,16 +1093,18 @@ export const es: TranslationResources = {
|
||||
open: "Abierto",
|
||||
},
|
||||
activity: {
|
||||
commented: "Comentado",
|
||||
approved: "Aprobado",
|
||||
requestedChanges: "Cambios solicitados",
|
||||
reviewed: "Revisado",
|
||||
commented: "Comentó",
|
||||
approved: "Aprobó",
|
||||
requestedChanges: "Solicitó cambios",
|
||||
reviewed: "Revisó",
|
||||
},
|
||||
time: {
|
||||
justNow: "En este momento",
|
||||
},
|
||||
thread: {
|
||||
discussion: "Hilo de discusión",
|
||||
resolved: "Resuelto",
|
||||
outdated: "Desactualizado",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "No se puede cargar el estado de la solicitud de extracción",
|
||||
|
||||
@@ -1094,6 +1094,8 @@ export const fr: TranslationResources = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "Fil de discussion",
|
||||
resolved: "Résolu",
|
||||
outdated: "Obsolète",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "Impossible de charger le statut de la pull request",
|
||||
|
||||
@@ -1083,6 +1083,8 @@ export const ja: TranslationResources = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "ディスカッションスレッド",
|
||||
resolved: "解決済み",
|
||||
outdated: "古い",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "プルリクエストのステータスを読み込めません",
|
||||
|
||||
@@ -1077,6 +1077,8 @@ export const ko: TranslationResources = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "토론 스레드",
|
||||
resolved: "해결됨",
|
||||
outdated: "오래됨",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "풀 리퀘스트 상태를 불러올 수 없습니다",
|
||||
|
||||
@@ -1084,15 +1084,17 @@ export const ptBR: TranslationResources = {
|
||||
},
|
||||
activity: {
|
||||
commented: "Comentou",
|
||||
approved: "Aprovado",
|
||||
approved: "Aprovou",
|
||||
requestedChanges: "Solicitou alterações",
|
||||
reviewed: "Revisado",
|
||||
reviewed: "Revisou",
|
||||
},
|
||||
time: {
|
||||
justNow: "agora mesmo",
|
||||
},
|
||||
thread: {
|
||||
discussion: "Tópico de discussão",
|
||||
resolved: "Resolvido",
|
||||
outdated: "Desatualizado",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "Não foi possível carregar o status da pull request",
|
||||
|
||||
@@ -1087,6 +1087,8 @@ export const ru: TranslationResources = {
|
||||
},
|
||||
thread: {
|
||||
discussion: "Ветка обсуждения",
|
||||
resolved: "Решено",
|
||||
outdated: "Устарело",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "Не удалось загрузить статус PR",
|
||||
|
||||
@@ -1046,22 +1046,24 @@ export const zhCN: TranslationResources = {
|
||||
},
|
||||
},
|
||||
states: {
|
||||
draft: "Draft",
|
||||
merged: "已 merge",
|
||||
draft: "草稿",
|
||||
merged: "已合并",
|
||||
closed: "已关闭",
|
||||
open: "Open",
|
||||
open: "开放",
|
||||
},
|
||||
activity: {
|
||||
commented: "已评论",
|
||||
approved: "已批准",
|
||||
requestedChanges: "请求修改",
|
||||
reviewed: "已 review",
|
||||
reviewed: "已审查",
|
||||
},
|
||||
time: {
|
||||
justNow: "刚刚",
|
||||
},
|
||||
thread: {
|
||||
discussion: "讨论主题",
|
||||
resolved: "已解决",
|
||||
outdated: "已过时",
|
||||
},
|
||||
errors: {
|
||||
statusLoadFailed: "无法加载 Pull Request 状态",
|
||||
|
||||
Reference in New Issue
Block a user