Skip to content

Commit d3043ec

Browse files
neubigopenhands-agentamanaperbren
authored
feat: localize missing elements (#7485)
Co-authored-by: openhands <[email protected]> Co-authored-by: sp.wack <[email protected]> Co-authored-by: Robert Brennan <[email protected]>
1 parent b3baea2 commit d3043ec

File tree

58 files changed

+2844
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2844
-237
lines changed

frontend/__tests__/components/browser.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@ describe("Browser", () => {
5757
});
5858

5959
expect(screen.getByText("https://example.com")).toBeInTheDocument();
60-
expect(screen.getByAltText(/browser screenshot/i)).toBeInTheDocument();
60+
expect(screen.getByAltText("BROWSER$SCREENSHOT_ALT")).toBeInTheDocument();
6161
});
6262
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { render, screen } from "@testing-library/react";
2+
import { test, expect, describe, vi } from "vitest";
3+
import { CopyToClipboardButton } from "#/components/shared/buttons/copy-to-clipboard-button";
4+
5+
// Mock react-i18next
6+
vi.mock("react-i18next", () => ({
7+
useTranslation: () => ({
8+
t: (key: string) => key,
9+
}),
10+
}));
11+
12+
describe("CopyToClipboardButton", () => {
13+
test("should have localized aria-label", () => {
14+
render(
15+
<CopyToClipboardButton
16+
isHidden={false}
17+
isDisabled={false}
18+
onClick={() => {}}
19+
mode="copy"
20+
/>
21+
);
22+
23+
const button = screen.getByTestId("copy-to-clipboard");
24+
expect(button).toHaveAttribute("aria-label", "BUTTON$COPY");
25+
});
26+
27+
test("should have localized aria-label when copied", () => {
28+
render(
29+
<CopyToClipboardButton
30+
isHidden={false}
31+
isDisabled={false}
32+
onClick={() => {}}
33+
mode="copied"
34+
/>
35+
);
36+
37+
const button = screen.getByTestId("copy-to-clipboard");
38+
expect(button).toHaveAttribute("aria-label", "BUTTON$COPIED");
39+
});
40+
});

frontend/__tests__/components/chat/action-suggestions.test.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ vi.mock("#/context/auth-context", () => ({
1919
useAuth: vi.fn(),
2020
}));
2121

22+
// Mock react-i18next
23+
vi.mock("react-i18next", () => ({
24+
useTranslation: () => ({
25+
t: (key: string) => {
26+
const translations: Record<string, string> = {
27+
"ACTION$PUSH_TO_BRANCH": "Push to Branch",
28+
"ACTION$PUSH_CREATE_PR": "Push & Create PR",
29+
"ACTION$PUSH_CHANGES_TO_PR": "Push Changes to PR"
30+
};
31+
return translations[key] || key;
32+
},
33+
}),
34+
}));
35+
2236
describe("ActionSuggestions", () => {
2337
// Setup mocks for each test
2438
beforeEach(() => {

frontend/__tests__/components/features/conversation-panel/conversation-card.test.tsx

+34-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,31 @@ import { formatTimeDelta } from "#/utils/format-time-delta";
1515
import { ConversationCard } from "#/components/features/conversation-panel/conversation-card";
1616
import { clickOnEditButton } from "./utils";
1717

18+
// We'll use the actual i18next implementation but override the translation function
19+
import { I18nextProvider } from "react-i18next";
20+
import i18n from "i18next";
21+
22+
// Mock the t function to return our custom translations
23+
vi.mock("react-i18next", async () => {
24+
const actual = await vi.importActual("react-i18next");
25+
return {
26+
...actual,
27+
useTranslation: () => ({
28+
t: (key: string) => {
29+
const translations: Record<string, string> = {
30+
"CONVERSATION$CREATED": "Created",
31+
"CONVERSATION$AGO": "ago",
32+
"CONVERSATION$UPDATED": "Updated"
33+
};
34+
return translations[key] || key;
35+
},
36+
i18n: {
37+
changeLanguage: () => new Promise(() => {}),
38+
},
39+
}),
40+
};
41+
});
42+
1843
describe("ConversationCard", () => {
1944
const onClick = vi.fn();
2045
const onDelete = vi.fn();
@@ -47,12 +72,18 @@ describe("ConversationCard", () => {
4772
lastUpdatedAt="2021-10-01T12:00:00Z"
4873
/>,
4974
);
50-
const expectedDate = `${formatTimeDelta(new Date("2021-10-01T12:00:00Z"))} ago`;
5175

5276
const card = screen.getByTestId("conversation-card");
5377

5478
within(card).getByText("Conversation 1");
55-
within(card).getByText(expectedDate);
79+
80+
// Just check that the card contains the expected text content
81+
expect(card).toHaveTextContent("Created");
82+
expect(card).toHaveTextContent("ago");
83+
84+
// Use a regex to match the time part since it might have whitespace
85+
const timeRegex = new RegExp(formatTimeDelta(new Date("2021-10-01T12:00:00Z")));
86+
expect(card).toHaveTextContent(timeRegex);
5687
});
5788

5889
it("should render the selectedRepository if available", () => {
@@ -341,7 +372,7 @@ describe("ConversationCard", () => {
341372
await user.click(displayCostButton);
342373

343374
// Verify if metrics modal is displayed by checking for the modal content
344-
expect(screen.getByText("Metrics Information")).toBeInTheDocument();
375+
expect(screen.getByTestId("metrics-modal")).toBeInTheDocument();
345376
});
346377

347378
it("should not display the edit or delete options if the handler is not provided", async () => {

frontend/__tests__/components/features/conversation-panel/conversation-panel.test.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ describe("ConversationPanel", () => {
135135
await user.click(deleteButton);
136136

137137
// Cancel the deletion
138-
const cancelButton = screen.getByText("Cancel");
138+
const cancelButton = screen.getByRole("button", { name: /cancel/i });
139139
await user.click(cancelButton);
140140

141-
expect(screen.queryByText("Cancel")).not.toBeInTheDocument();
141+
expect(screen.queryByRole("button", { name: /cancel/i })).not.toBeInTheDocument();
142142

143143
// Ensure the conversation is not deleted
144144
cards = await screen.findAllByTestId("conversation-card");
@@ -172,10 +172,10 @@ describe("ConversationPanel", () => {
172172
await user.click(deleteButton);
173173

174174
// Confirm the deletion
175-
const confirmButton = screen.getByText("Confirm");
175+
const confirmButton = screen.getByRole("button", { name: /confirm/i });
176176
await user.click(confirmButton);
177177

178-
expect(screen.queryByText("Confirm")).not.toBeInTheDocument();
178+
expect(screen.queryByRole("button", { name: /confirm/i })).not.toBeInTheDocument();
179179

180180
// Wait for the cards to update with a longer timeout
181181
await waitFor(() => {
@@ -239,10 +239,10 @@ describe("ConversationPanel", () => {
239239
await user.click(deleteButton);
240240

241241
// Confirm the deletion
242-
const confirmButton = screen.getByText("Confirm");
242+
const confirmButton = screen.getByRole("button", { name: /confirm/i });
243243
await user.click(confirmButton);
244244

245-
expect(screen.queryByText("Confirm")).not.toBeInTheDocument();
245+
expect(screen.queryByRole("button", { name: /confirm/i })).not.toBeInTheDocument();
246246

247247
// Wait for the cards to update
248248
await waitFor(() => {

frontend/__tests__/components/features/payment/payment-form.test.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe("PaymentForm", () => {
6363
const topUpInput = await screen.findByTestId("top-up-input");
6464
await user.type(topUpInput, "50.12");
6565

66-
const topUpButton = screen.getByText("Add credit");
66+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
6767
await user.click(topUpButton);
6868

6969
expect(createCheckoutSessionSpy).toHaveBeenCalledWith(50.12);
@@ -76,7 +76,7 @@ describe("PaymentForm", () => {
7676
const topUpInput = await screen.findByTestId("top-up-input");
7777
await user.type(topUpInput, "50.125456");
7878

79-
const topUpButton = screen.getByText("Add credit");
79+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
8080
await user.click(topUpButton);
8181

8282
expect(createCheckoutSessionSpy).toHaveBeenCalledWith(50.13);
@@ -86,7 +86,7 @@ describe("PaymentForm", () => {
8686
const user = userEvent.setup();
8787
renderPaymentForm();
8888

89-
const topUpButton = screen.getByText("Add credit");
89+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
9090
expect(topUpButton).toBeDisabled();
9191

9292
const topUpInput = await screen.findByTestId("top-up-input");
@@ -102,7 +102,7 @@ describe("PaymentForm", () => {
102102
const topUpInput = await screen.findByTestId("top-up-input");
103103
await user.type(topUpInput, "50.12");
104104

105-
const topUpButton = screen.getByText("Add credit");
105+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
106106
await user.click(topUpButton);
107107

108108
expect(topUpButton).toBeDisabled();
@@ -116,7 +116,7 @@ describe("PaymentForm", () => {
116116
const topUpInput = await screen.findByTestId("top-up-input");
117117
await user.type(topUpInput, "-50.12");
118118

119-
const topUpButton = screen.getByText("Add credit");
119+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
120120
await user.click(topUpButton);
121121

122122
expect(createCheckoutSessionSpy).not.toHaveBeenCalled();
@@ -129,7 +129,7 @@ describe("PaymentForm", () => {
129129
const topUpInput = await screen.findByTestId("top-up-input");
130130
await user.type(topUpInput, " ");
131131

132-
const topUpButton = screen.getByText("Add credit");
132+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
133133
await user.click(topUpButton);
134134

135135
expect(createCheckoutSessionSpy).not.toHaveBeenCalled();
@@ -142,7 +142,7 @@ describe("PaymentForm", () => {
142142
const topUpInput = await screen.findByTestId("top-up-input");
143143
await user.type(topUpInput, "abc");
144144

145-
const topUpButton = screen.getByText("Add credit");
145+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
146146
await user.click(topUpButton);
147147

148148
expect(createCheckoutSessionSpy).not.toHaveBeenCalled();
@@ -155,7 +155,7 @@ describe("PaymentForm", () => {
155155
const topUpInput = await screen.findByTestId("top-up-input");
156156
await user.type(topUpInput, "9"); // test assumes the minimum is 10
157157

158-
const topUpButton = screen.getByText("Add credit");
158+
const topUpButton = screen.getByText("PAYMENT$ADD_CREDIT");
159159
await user.click(topUpButton);
160160

161161
expect(createCheckoutSessionSpy).not.toHaveBeenCalled();

frontend/__tests__/components/features/waitlist-modal.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe("WaitlistModal", () => {
2424
const user = userEvent.setup();
2525
render(<WaitlistModal ghTokenIsSet={false} githubAuthUrl={null} />);
2626
const checkbox = screen.getByRole("checkbox");
27-
const button = screen.getByRole("button", { name: "Connect to GitHub" });
27+
const button = screen.getByRole("button", { name: "GITHUB$CONNECT_TO_GITHUB" });
2828

2929
expect(button).toBeDisabled();
3030

@@ -45,7 +45,7 @@ describe("WaitlistModal", () => {
4545
const checkbox = screen.getByRole("checkbox");
4646
await user.click(checkbox);
4747

48-
const button = screen.getByRole("button", { name: "Connect to GitHub" });
48+
const button = screen.getByRole("button", { name: "GITHUB$CONNECT_TO_GITHUB" });
4949
await user.click(button);
5050

5151
expect(handleCaptureConsentSpy).toHaveBeenCalledWith(true);

frontend/__tests__/components/user-avatar.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe("UserAvatar", () => {
3636
/>,
3737
);
3838

39-
expect(screen.getByAltText("user avatar")).toBeInTheDocument();
39+
expect(screen.getByAltText("AVATAR$ALT_TEXT")).toBeInTheDocument();
4040
expect(
4141
screen.queryByLabelText("USER$AVATAR_PLACEHOLDER"),
4242
).not.toBeInTheDocument();
@@ -63,6 +63,6 @@ describe("UserAvatar", () => {
6363
/>,
6464
);
6565
expect(screen.getByTestId("loading-spinner")).toBeInTheDocument();
66-
expect(screen.queryByAltText("user avatar")).not.toBeInTheDocument();
66+
expect(screen.queryByAltText("AVATAR$ALT_TEXT")).not.toBeInTheDocument();
6767
});
6868
});

frontend/__tests__/routes/settings-with-payment.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@ describe("Settings Billing", () => {
8888
await user.click(credits);
8989

9090
const billingSection = await screen.findByTestId("billing-settings");
91-
within(billingSection).getByText("Manage Credits");
91+
within(billingSection).getByText("PAYMENT$MANAGE_CREDITS");
9292
});
9393
});

0 commit comments

Comments
 (0)