-
Notifications
You must be signed in to change notification settings - Fork 881
added react-i18next to FE #3682
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import relativeTime from "dayjs/plugin/relativeTime" | |
import timezone from "dayjs/plugin/timezone" | ||
import utc from "dayjs/plugin/utc" | ||
import { useRef, useState } from "react" | ||
import { useTranslation } from "react-i18next" | ||
import { Workspace } from "../../api/typesGenerated" | ||
import { isWorkspaceOn } from "../../util/workspace" | ||
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule" | ||
|
@@ -26,12 +27,6 @@ dayjs.extend(duration) | |
dayjs.extend(relativeTime) | ||
dayjs.extend(timezone) | ||
|
||
export const Language = { | ||
schedule: "Schedule", | ||
editDeadlineMinus: "Subtract one hour", | ||
editDeadlinePlus: "Add one hour", | ||
} | ||
|
||
export const shouldDisplayPlusMinus = (workspace: Workspace): boolean => { | ||
if (!isWorkspaceOn(workspace)) { | ||
return false | ||
|
@@ -57,6 +52,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ( | |
deadlineMinusEnabled, | ||
canUpdateWorkspace, | ||
}) => { | ||
const { t } = useTranslation("workspacePage") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the primary way we should access translations in components: by using the |
||
const anchorRef = useRef<HTMLButtonElement>(null) | ||
const [isOpen, setIsOpen] = useState(false) | ||
const id = isOpen ? "schedule-popover" : undefined | ||
|
@@ -78,7 +74,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ( | |
disabled={!deadlineMinusEnabled()} | ||
onClick={onDeadlineMinus} | ||
> | ||
<Tooltip title={Language.editDeadlineMinus}> | ||
<Tooltip title={t("workspaceScheduleButton.editDeadlineMinus")}> | ||
<RemoveIcon /> | ||
</Tooltip> | ||
</IconButton> | ||
|
@@ -88,7 +84,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ( | |
disabled={!deadlinePlusEnabled()} | ||
onClick={onDeadlinePlus} | ||
> | ||
<Tooltip title={Language.editDeadlinePlus}> | ||
<Tooltip title={t("workspaceScheduleButton.editDeadlinePlus")}> | ||
<AddIcon /> | ||
</Tooltip> | ||
</IconButton> | ||
|
@@ -104,7 +100,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ( | |
}} | ||
className={styles.scheduleButton} | ||
> | ||
{Language.schedule} | ||
{t("workspaceScheduleButton.schedule")} | ||
</Button> | ||
<Popover | ||
classes={{ paper: styles.popoverPaper }} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,24 +4,11 @@ import StopIcon from "@material-ui/icons/PauseOutlined" | |
import PlayIcon from "@material-ui/icons/PlayArrowOutlined" | ||
import { WorkspaceBuild } from "api/typesGenerated" | ||
import { Pill } from "components/Pill/Pill" | ||
import i18next from "i18next" | ||
import React from "react" | ||
import { PaletteIndex } from "theme/palettes" | ||
import { getWorkspaceStatus } from "util/workspace" | ||
|
||
const StatusLanguage = { | ||
loading: "Loading", | ||
started: "Running", | ||
starting: "Starting", | ||
stopping: "Stopping", | ||
stopped: "Stopped", | ||
deleting: "Deleting", | ||
deleted: "Deleted", | ||
canceling: "Canceling action", | ||
canceled: "Canceled action", | ||
failed: "Failed", | ||
queued: "Queued", | ||
} | ||
|
||
const LoadingIcon: React.FC = () => { | ||
return <CircularProgress size={10} style={{ color: "#FFF" }} /> | ||
} | ||
|
@@ -34,70 +21,72 @@ export const getStatus = ( | |
icon: React.ReactNode | ||
} => { | ||
const status = getWorkspaceStatus(build) | ||
const { t } = i18next | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is another way we can access translations: directly from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is the hook preferable when you have the choice? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh is it because it takes the namespace? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely! But also, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great to know. Can you add something to Notion about this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! |
||
|
||
switch (status) { | ||
case undefined: | ||
return { | ||
text: StatusLanguage.loading, | ||
text: t("workspaceStatus.loading", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
case "started": | ||
return { | ||
type: "success", | ||
text: StatusLanguage.started, | ||
text: t("workspaceStatus.started", { ns: "common" }), | ||
icon: <PlayIcon />, | ||
} | ||
case "starting": | ||
return { | ||
type: "success", | ||
text: StatusLanguage.starting, | ||
text: t("workspaceStatus.starting", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
case "stopping": | ||
return { | ||
type: "warning", | ||
text: StatusLanguage.stopping, | ||
text: t("workspaceStatus.stopping", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
case "stopped": | ||
return { | ||
type: "warning", | ||
text: StatusLanguage.stopped, | ||
text: t("workspaceStatus.stopped", { ns: "common" }), | ||
icon: <StopIcon />, | ||
} | ||
case "deleting": | ||
return { | ||
type: "warning", | ||
text: StatusLanguage.deleting, | ||
text: t("workspaceStatus.deleting", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
case "deleted": | ||
return { | ||
type: "error", | ||
text: StatusLanguage.deleted, | ||
text: t("workspaceStatus.deleted", { ns: "common" }), | ||
icon: <ErrorIcon />, | ||
} | ||
case "canceling": | ||
return { | ||
type: "warning", | ||
text: StatusLanguage.canceling, | ||
text: t("workspaceStatus.canceling", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
case "canceled": | ||
return { | ||
type: "warning", | ||
text: StatusLanguage.canceled, | ||
text: t("workspaceStatus.canceled", { ns: "common" }), | ||
icon: <ErrorIcon />, | ||
} | ||
case "error": | ||
return { | ||
type: "error", | ||
text: StatusLanguage.failed, | ||
text: t("workspaceStatus.failed", { ns: "common" }), | ||
icon: <ErrorIcon />, | ||
} | ||
case "queued": | ||
return { | ||
type: "info", | ||
text: StatusLanguage.queued, | ||
text: t("workspaceStatus.queued", { ns: "common" }), | ||
icon: <LoadingIcon />, | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"workspaceStatus": { | ||
"loading": "Loading", | ||
"started": "Running", | ||
"starting": "Starting", | ||
"stopping": "Stopping", | ||
"stopped": "Stopped", | ||
"deleting": "Deleting", | ||
"deleted": "Deleted", | ||
"canceling": "Canceling action", | ||
"canceled": "Canceled action", | ||
"failed": "Failed", | ||
"queued": "Queued" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import common from "./common.json" | ||
import workspacePage from "./workspacePage.json" | ||
|
||
export const en = { | ||
common, | ||
workspacePage, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"workspaceScheduleButton": { | ||
"schedule": "Schedule", | ||
"editDeadlineMinus": "Subtract one hour", | ||
"editDeadlinePlus": "Add one hour" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import i18next from "i18next" | ||
import { initReactI18next } from "react-i18next" | ||
import { en } from "./en" | ||
|
||
export const defaultNS = "common" | ||
export const resources = { en } as const | ||
|
||
export const i18n = i18next.use(initReactI18next) | ||
|
||
i18n | ||
.init({ | ||
fallbackLng: "en", | ||
interpolation: { | ||
escapeValue: false, // not needed for react as it escapes by default | ||
}, | ||
resources, | ||
}) | ||
.catch((error) => { | ||
// we are catching here to avoid lint's no-floating-promises error | ||
console.error("[Translation Service]:", error) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./i18n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. barrel file FTW 🚀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I figure this is a good place for one. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
import ThemeProvider from "@material-ui/styles/ThemeProvider" | ||
import { render as wrappedRender, RenderResult } from "@testing-library/react" | ||
import { createMemoryHistory } from "history" | ||
import { i18n } from "i18n" | ||
import { FC, ReactElement } from "react" | ||
import { HelmetProvider } from "react-helmet-async" | ||
import { I18nextProvider } from "react-i18next" | ||
import { | ||
MemoryRouter, | ||
Route, | ||
|
@@ -48,11 +50,13 @@ export function renderWithAuth( | |
<HelmetProvider> | ||
<MemoryRouter initialEntries={[route]}> | ||
<XServiceProvider> | ||
<ThemeProvider theme={dark}> | ||
<Routes> | ||
<Route path={path ?? route} element={<RequireAuth>{ui}</RequireAuth>} /> | ||
</Routes> | ||
</ThemeProvider> | ||
<I18nextProvider i18n={i18n}> | ||
<ThemeProvider theme={dark}> | ||
<Routes> | ||
<Route path={path ?? route} element={<RequireAuth>{ui}</RequireAuth>} /> | ||
</Routes> | ||
</ThemeProvider> | ||
</I18nextProvider> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When testing, we must wrap rendered components inside this provider. |
||
</XServiceProvider> | ||
</MemoryRouter> | ||
</HelmetProvider>, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Why do we import this here? Is that to initialize translations or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, it's part of the setup!