Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve i18n support and add missing translations #6070

Merged
merged 89 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
853a62b
Add Japanese translations to frontend
openhands-agent Jan 6, 2025
e010788
Add Japanese language option to language selector
openhands-agent Jan 6, 2025
2228353
Add Japanese translations and update UI components
openhands-agent Jan 6, 2025
e05d7a9
Fix frontend tests and lint issues
openhands-agent Jan 6, 2025
49b12d9
Add translations for settings modal and sidebar tooltips
openhands-agent Jan 6, 2025
2039f15
Add translations for main page content
openhands-agent Jan 6, 2025
f7f7b6a
Apply suggestions from code review
neubig Jan 6, 2025
2a70fdc
Fix frontend linting issues
openhands-agent Jan 6, 2025
ace4f58
Update frontend/src/i18n/translation.json
neubig Jan 6, 2025
3241ff4
Fix suggestion localization by using proper translation keys
openhands-agent Jan 6, 2025
986de97
Add translations for all suggestions
openhands-agent Jan 6, 2025
959a181
Fix remaining linting issues
openhands-agent Jan 6, 2025
d281d5e
Fix suggestion localization and add test
openhands-agent Jan 6, 2025
72bbf93
Add missing Japanese translations for UI elements
openhands-agent Jan 6, 2025
1b55a7e
Add tests for Japanese translations and fix missing translations
openhands-agent Jan 6, 2025
8f24a99
Add more Japanese translations for UI elements
openhands-agent Jan 6, 2025
e5538da
Add more Japanese translations for UI elements
openhands-agent Jan 6, 2025
ae66a4e
Add tests for Japanese translations
openhands-agent Jan 6, 2025
0a49f21
Consolidate Japanese translation tests into landing-translations.test…
openhands-agent Jan 6, 2025
0fd1582
Improve i18n support:
openhands-agent Jan 6, 2025
4b80de4
fix: Add missing translations and improve i18n testing
openhands-agent Jan 6, 2025
998e16a
Consolidate duplicate translation keys: LETS_START_BUILDING -> LANDIN…
openhands-agent Jan 6, 2025
9645ff8
Consolidate duplicate translation keys:
openhands-agent Jan 6, 2025
f348cf1
Remove more unused translation keys:
openhands-agent Jan 6, 2025
cd59652
Merge branch 'main' into add-japanese-translations
neubig Jan 6, 2025
e1ab79c
Add missing Japanese translations and fix tests
openhands-agent Jan 7, 2025
1a87c85
Add Japanese translations for project buttons
openhands-agent Jan 7, 2025
ba04181
feat(i18n): Add Japanese translations for welcome message and VS Code…
openhands-agent Jan 7, 2025
42b3e69
feat(i18n): Update Japanese translation for welcome message
openhands-agent Jan 7, 2025
73c50f3
feat(i18n): Simplify Japanese translations for workspace, browser, an…
openhands-agent Jan 7, 2025
d3d4acd
test: Update Japanese translation tests to match new translations
openhands-agent Jan 7, 2025
a90cc37
feat(i18n): Simplify Japanese translations for workspace, browser, an…
openhands-agent Jan 7, 2025
b7701b8
fix: Update VS Code button to use correct translation key
openhands-agent Jan 7, 2025
06a8e5c
fix: Add Japanese translation for Terminal label
openhands-agent Jan 7, 2025
579c58f
fix: Initialize i18n with language from settings
openhands-agent Jan 7, 2025
7d7ae46
fix: Handle localStorage access during SSR
openhands-agent Jan 7, 2025
9e4c9e0
Add Japanese translations for LLM provider settings
openhands-agent Jan 7, 2025
91d6529
Fix Japanese translations for LLM provider settings
openhands-agent Jan 7, 2025
bd685b9
Fix i18n initialization to properly load translations
openhands-agent Jan 7, 2025
f13a1aa
Fix i18n initialization to properly transform translations
openhands-agent Jan 7, 2025
24a1921
Fix translations in settings form
openhands-agent Jan 7, 2025
77b6229
Fix translations in account settings form
openhands-agent Jan 7, 2025
40b09a2
fix: Fix code formatting and remove unused imports
openhands-agent Jan 7, 2025
b7fc110
feat: Add German translations for landing page and account settings
openhands-agent Jan 7, 2025
6b33720
fix: Restore complete translations that were accidentally removed
openhands-agent Jan 7, 2025
8697a02
fix: consolidate Japanese translations for 'What do you want to build…
openhands-agent Jan 7, 2025
e5346c7
fix: consolidate duplicate translation keys and add test
openhands-agent Jan 7, 2025
db6ce0c
Add Japanese translation for Logout
openhands-agent Jan 7, 2025
89581ff
Add tests for Japanese translations
openhands-agent Jan 7, 2025
1a05c2a
Add Japanese translations for Account Settings
openhands-agent Jan 7, 2025
43240e1
Modify translation test to check all keys
openhands-agent Jan 7, 2025
96782b3
Add missing Japanese translations
openhands-agent Jan 7, 2025
1550d9f
Add missing Chinese (Simplified) translations
openhands-agent Jan 7, 2025
cb8d704
Add missing Chinese (Traditional) translations
openhands-agent Jan 7, 2025
9df8d94
Add missing Korean translations
openhands-agent Jan 7, 2025
5a5e6ec
Add missing German translations
openhands-agent Jan 7, 2025
6844a1a
Add missing Turkish translations
openhands-agent Jan 7, 2025
95f1e5e
Add remaining Japanese translations
openhands-agent Jan 7, 2025
b3c883a
Add missing translations for various languages
openhands-agent Jan 7, 2025
1da76b3
Add missing translations for various languages
openhands-agent Jan 7, 2025
3f9e652
Merge branch 'main' into add-japanese-translations
neubig Jan 7, 2025
b8ac8aa
Remove patch file
openhands-agent Jan 7, 2025
eafaec7
Remove OpenHands submodule
openhands-agent Jan 7, 2025
f04cc01
Delete frontend/scripts/fix-duplicate-translations.py
neubig Jan 7, 2025
392f601
Remove Jest dependencies since we use Vitest
openhands-agent Jan 7, 2025
dd88322
refactor: use I18nKey enum instead of direct string translations
openhands-agent Jan 7, 2025
89793d8
refactor: fix remaining direct string translations and update tests
openhands-agent Jan 7, 2025
716c338
Delete frontend/src/i18n/translation.json.new
neubig Jan 7, 2025
5d0ceff
Update keys
openhands-agent Jan 7, 2025
bec51b7
merge
openhands-agent Jan 7, 2025
d55fd12
fix: Remove duplicate i18n keys and update tests to match translations
openhands-agent Jan 7, 2025
caab131
Convert Unicode escapes to actual characters in translation.json
openhands-agent Jan 7, 2025
4be4c4c
Remove placeholder prop from ChatInput and use translation key only
openhands-agent Jan 7, 2025
bb7f00f
Remove placeholder prop from ChatInput and update components
openhands-agent Jan 7, 2025
f164e45
Fix lint issues: Remove unused imports and variables, fix formatting
openhands-agent Jan 7, 2025
d83b509
One last piece of localization
neubig Jan 7, 2025
7a9228f
Merge branch 'add-japanese-translations' of github.com:All-Hands-AI/O…
neubig Jan 7, 2025
edb4ed6
Fix linting issues: Fix import order and add newlines at end of files
openhands-agent Jan 7, 2025
262f056
test: improve test practices based on review feedback
openhands-agent Jan 10, 2025
3f51460
test: simplify translations test structure
openhands-agent Jan 10, 2025
79bbe50
Merge main branch, keeping Japanese translations while adopting new c…
openhands-agent Jan 11, 2025
59d27a2
Remove translations consistency test
openhands-agent Jan 11, 2025
4613aa6
Fix translations test by adding required props
openhands-agent Jan 11, 2025
44216ec
Add Japanese back to available languages
openhands-agent Jan 11, 2025
480df93
Use ACCOUNT_SETTINGS for settings button tooltip
openhands-agent Jan 11, 2025
efb8290
Rename AI settings title key to avoid duplication
openhands-agent Jan 11, 2025
8236300
Update i18n declaration file
openhands-agent Jan 11, 2025
4f0c32c
Merge branch 'main' into add-japanese-translations
neubig Jan 14, 2025
7049463
fix: Update sidebar test to handle empty base URL
openhands-agent Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OpenHands
Submodule OpenHands added at efd026
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe("ConversationPanel", () => {

renderConversationPanel();

const emptyState = await screen.findByText("No conversations found");
const emptyState = await screen.findByText("CONVERSATION$NO_CONVERSATIONS");
expect(emptyState).toBeInTheDocument();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe("GitHubRepositorySelector", () => {
);

expect(
screen.getByPlaceholderText("Select a GitHub project"),
screen.getByPlaceholderText("LANDING$SELECT_REPO"),
).toBeInTheDocument();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe("InteractiveChatBox", () => {
expect(onChange).not.toHaveBeenCalledWith("");

// Submit the message with image
const submitButton = screen.getByRole("button", { name: "Send" });
const submitButton = screen.getByRole("button", { name: "BUTTON$SEND" });
await user.click(submitButton);

// Verify onSubmit was called with the message and image
Expand Down
8 changes: 4 additions & 4 deletions frontend/__tests__/components/user-avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe("UserAvatar", () => {
render(<UserAvatar onClick={onClickMock} />);
expect(screen.getByTestId("user-avatar")).toBeInTheDocument();
expect(
screen.getByLabelText("user avatar placeholder"),
screen.getByLabelText("USER$AVATAR_PLACEHOLDER"),
).toBeInTheDocument();
});

Expand All @@ -38,21 +38,21 @@ describe("UserAvatar", () => {

expect(screen.getByAltText("user avatar")).toBeInTheDocument();
expect(
screen.queryByLabelText("user avatar placeholder"),
screen.queryByLabelText("USER$AVATAR_PLACEHOLDER"),
).not.toBeInTheDocument();
});

it("should display a loading spinner instead of an avatar when isLoading is true", () => {
const { rerender } = render(<UserAvatar onClick={onClickMock} />);
expect(screen.queryByTestId("loading-spinner")).not.toBeInTheDocument();
expect(
screen.getByLabelText("user avatar placeholder"),
screen.getByLabelText("USER$AVATAR_PLACEHOLDER"),
).toBeInTheDocument();

rerender(<UserAvatar onClick={onClickMock} isLoading />);
expect(screen.getByTestId("loading-spinner")).toBeInTheDocument();
expect(
screen.queryByLabelText("user avatar placeholder"),
screen.queryByLabelText("USER$AVATAR_PLACEHOLDER"),
).not.toBeInTheDocument();

rerender(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import PauseIcon from "#/assets/pause";
import PlayIcon from "#/assets/play";
import { generateAgentStateChangeEvent } from "#/services/agent-state-service";
Expand All @@ -9,6 +11,7 @@ import { IGNORE_TASK_STATE_MAP } from "#/ignore-task-state-map.constant";
import { ActionButton } from "#/components/shared/buttons/action-button";

export function AgentControlBar() {
const { t } = useTranslation();
const { send } = useWsClient();
const { curAgentState } = useSelector((state: RootState) => state.agent);

Expand All @@ -27,8 +30,8 @@ export function AgentControlBar() {
}
content={
curAgentState === AgentState.PAUSED
? "Resume the agent task"
: "Pause the current task"
? t(I18nKey.AGENT$RESUME_TASK)
: t(I18nKey.AGENT$PAUSE_TASK)
}
action={
curAgentState === AgentState.PAUSED
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from "react";
import { useLocation, useNavigate, useParams } from "react-router";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { ConversationCard } from "./conversation-card";
import { useUserConversations } from "#/hooks/query/use-user-conversations";
import { useDeleteConversation } from "#/hooks/mutation/use-delete-conversation";
Expand All @@ -15,6 +17,7 @@ interface ConversationPanelProps {
}

export function ConversationPanel({ onClose }: ConversationPanelProps) {
const { t } = useTranslation();
const { conversationId: cid } = useParams();
const navigate = useNavigate();
const location = useLocation();
Expand Down Expand Up @@ -89,7 +92,9 @@ export function ConversationPanel({ onClose }: ConversationPanelProps) {
)}
{conversations?.length === 0 && (
<div className="flex flex-col items-center justify-center h-full">
<p className="text-neutral-400">No conversations found</p>
<p className="text-neutral-400">
{t(I18nKey.CONVERSATION$NO_CONVERSATIONS)}
</p>
</div>
)}
{conversations?.map((project) => (
Expand Down
13 changes: 8 additions & 5 deletions frontend/src/components/features/github/github-repo-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from "react";
import { useTranslation } from "react-i18next";
import {
Autocomplete,
AutocompleteItem,
AutocompleteSection,
} from "@nextui-org/react";
import { useDispatch } from "react-redux";
import posthog from "posthog-js";
import { I18nKey } from "#/i18n/declaration";
import { setSelectedRepository } from "#/state/initial-query-slice";
import { useConfig } from "#/hooks/query/use-config";
import { sanitizeQuery } from "#/utils/sanitize-query";
Expand All @@ -23,6 +25,7 @@ export function GitHubRepositorySelector({
userRepositories,
publicRepositories,
}: GitHubRepositorySelectorProps) {
const { t } = useTranslation();
const { data: config } = useConfig();
const [selectedKey, setSelectedKey] = React.useState<string | null>(null);

Expand All @@ -49,14 +52,14 @@ export function GitHubRepositorySelector({
dispatch(setSelectedRepository(null));
};

const emptyContent = "No results found.";
const emptyContent = t(I18nKey.GITHUB$NO_RESULTS);

return (
<Autocomplete
data-testid="github-repo-selector"
name="repo"
aria-label="GitHub Repository"
placeholder="Select a GitHub project"
placeholder={t(I18nKey.LANDING$SELECT_REPO)}
isVirtualized={false}
selectedKey={selectedKey}
inputProps={{
Expand Down Expand Up @@ -86,12 +89,12 @@ export function GitHubRepositorySelector({
rel="noreferrer noopener"
onClick={(e) => e.stopPropagation()}
>
Add more repositories...
{t(I18nKey.GITHUB$ADD_MORE_REPOS)}
</a>
</AutocompleteItem> // eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any)}
{userRepositories.length > 0 && (
<AutocompleteSection showDivider title="Your Repos">
<AutocompleteSection showDivider title={t(I18nKey.GITHUB$YOUR_REPOS)}>
{userRepositories.map((repo) => (
<AutocompleteItem
data-testid="github-repo-item"
Expand All @@ -106,7 +109,7 @@ export function GitHubRepositorySelector({
</AutocompleteSection>
)}
{publicRepositories.length > 0 && (
<AutocompleteSection showDivider title="Public Repos">
<AutocompleteSection showDivider title={t(I18nKey.GITHUB$PUBLIC_REPOS)}>
{publicRepositories.map((repo) => (
<AutocompleteItem
data-testid="github-repo-item"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { SuggestionBox } from "#/components/features/suggestions/suggestion-box";
import GitHubLogo from "#/assets/branding/github-logo.svg?react";
import { GitHubRepositorySelector } from "./github-repo-selector";
Expand All @@ -23,6 +25,7 @@ export function GitHubRepositoriesSuggestionBox({
gitHubAuthUrl,
user,
}: GitHubRepositoriesSuggestionBoxProps) {
const { t } = useTranslation();
const [connectToGitHubModalOpen, setConnectToGitHubModalOpen] =
React.useState(false);
const [searchQuery, setSearchQuery] = React.useState<string>("");
Expand Down Expand Up @@ -53,7 +56,7 @@ export function GitHubRepositoriesSuggestionBox({
return (
<>
<SuggestionBox
title="Open a Repo"
title={t(I18nKey.LANDING$OPEN_REPO)}
content={
isLoggedIn ? (
<GitHubRepositorySelector
Expand All @@ -64,7 +67,7 @@ export function GitHubRepositoriesSuggestionBox({
/>
) : (
<ModalButton
text="Connect to GitHub"
text={t(I18nKey.GITHUB$CONNECT)}
icon={<GitHubLogo width={20} height={20} />}
className="bg-[#791B80] w-full"
onClick={handleConnectToGitHub}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import Clip from "#/icons/clip.svg?react";

export function AttachImageLabel() {
const { t } = useTranslation();
return (
<div className="flex self-start items-center text-[#A3A3A3] text-xs leading-[18px] -tracking-[0.08px] cursor-pointer">
<Clip width={16} height={16} />
Attach images
{t(I18nKey.LANDING$ATTACH_IMAGES)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import Markdown from "react-markdown";
import SyntaxHighlighter from "react-syntax-highlighter";
import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { JupyterLine } from "#/utils/parse-cell-content";

interface JupyterCellOutputProps {
lines: JupyterLine[];
}

export function JupyterCellOutput({ lines }: JupyterCellOutputProps) {
const { t } = useTranslation();
return (
<div className="rounded-lg bg-gray-800 dark:bg-gray-900 p-2 text-xs">
<div className="mb-1 text-gray-400">STDOUT/STDERR</div>
<div className="mb-1 text-gray-400">
{t(I18nKey.JUPYTER$OUTPUT_LABEL)}
</div>
<pre
className="scrollbar-custom scrollbar-thumb-gray-500 hover:scrollbar-thumb-gray-400 dark:scrollbar-thumb-white/10 dark:hover:scrollbar-thumb-white/20 overflow-auto px-5 max-h-[60vh] bg-gray-800"
style={{ padding: 0, marginBottom: 0, fontSize: "0.75rem" }}
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/features/sidebar/user-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Tooltip } from "@nextui-org/react";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { LoadingSpinner } from "#/components/shared/loading-spinner";
import DefaultUserAvatar from "#/icons/default-user.svg?react";
import { cn } from "#/utils/utils";
Expand All @@ -11,6 +13,7 @@ interface UserAvatarProps {
}

export function UserAvatar({ onClick, avatarUrl, isLoading }: UserAvatarProps) {
const { t } = useTranslation();
const buttonContent = (
<button
data-testid="user-avatar"
Expand All @@ -24,7 +27,7 @@ export function UserAvatar({ onClick, avatarUrl, isLoading }: UserAvatarProps) {
{!isLoading && avatarUrl && <Avatar src={avatarUrl} />}
{!isLoading && !avatarUrl && (
<DefaultUserAvatar
aria-label="user avatar placeholder"
aria-label={t(I18nKey.USER$AVATAR_PLACEHOLDER)}
width={20}
height={20}
/>
Expand All @@ -34,7 +37,7 @@ export function UserAvatar({ onClick, avatarUrl, isLoading }: UserAvatarProps) {
);

return (
<Tooltip content="Account settings" closeDelay={100}>
<Tooltip content={t(I18nKey.USER$ACCOUNT_SETTINGS)} closeDelay={100}>
{buttonContent}
</Tooltip>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { SuggestionBox } from "./suggestion-box";

interface ImportProjectSuggestionBoxProps {
Expand All @@ -7,13 +9,14 @@ interface ImportProjectSuggestionBoxProps {
export function ImportProjectSuggestionBox({
onChange,
}: ImportProjectSuggestionBoxProps) {
const { t } = useTranslation();
return (
<SuggestionBox
title="+ Import Project"
title={t(I18nKey.LANDING$IMPORT_PROJECT)}
content={
<label htmlFor="import-project" className="w-full flex justify-center">
<span className="border-2 border-dashed border-neutral-600 rounded px-2 py-1 cursor-pointer">
Upload a .zip
{t(I18nKey.LANDING$UPLOAD_ZIP)}
</span>
<input
hidden
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/components/features/waitlist/tos-checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";

interface TOSCheckboxProps {
onChange: () => void;
}

export function TOSCheckbox({ onChange }: TOSCheckboxProps) {
const { t } = useTranslation();
return (
<label className="flex items-center gap-2">
<input type="checkbox" onChange={onChange} />
<span>
I accept the{" "}
{t(I18nKey.TOS$ACCEPT)}{" "}
<a
href="https://www.all-hands.dev/tos"
target="_blank"
rel="noopener noreferrer"
className="underline underline-offset-2 text-blue-500 hover:text-blue-700"
>
terms of service
{t(I18nKey.TOS$TERMS)}
</a>
</span>
</label>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/layout/beta-badge.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";

export function BetaBadge() {
const { t } = useTranslation();
return (
<span className="text-[11px] leading-5 text-root-primary bg-neutral-400 px-1 rounded-xl">
Beta
{t(I18nKey.BADGE$BETA)}
</span>
);
}
6 changes: 5 additions & 1 deletion frontend/src/components/shared/action-tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export function ActionTooltip({ type, onClick }: ActionTooltipProps) {
<button
data-testid={`action-${type}-button`}
type="button"
aria-label={type === "confirm" ? "Confirm action" : "Reject action"}
aria-label={
type === "confirm"
? t(I18nKey.ACTION$CONFIRM)
: t(I18nKey.ACTION$REJECT)
}
className="bg-neutral-700 rounded-full p-1 hover:bg-neutral-800"
onClick={onClick}
>
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/shared/buttons/stop-button.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";

interface StopButtonProps {
isDisabled?: boolean;
onClick?: () => void;
}

export function StopButton({ isDisabled, onClick }: StopButtonProps) {
const { t } = useTranslation();
return (
<button
data-testid="stop-button"
aria-label="Stop"
aria-label={t(I18nKey.BUTTON$STOP)}
disabled={isDisabled}
onClick={onClick}
type="button"
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/shared/buttons/submit-button.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { useTranslation } from "react-i18next";
import ArrowSendIcon from "#/icons/arrow-send.svg?react";
import { I18nKey } from "#/i18n/declaration";

interface SubmitButtonProps {
isDisabled?: boolean;
onClick: () => void;
}

export function SubmitButton({ isDisabled, onClick }: SubmitButtonProps) {
const { t } = useTranslation();
return (
<button
aria-label="Send"
aria-label={t(I18nKey.BUTTON$SEND)}
disabled={isDisabled}
onClick={onClick}
type="submit"
Expand Down
Loading
Loading