Skip to content

Commit 26706f4

Browse files
authored
Merge pull request #102 from MathisBurger/feature/translations
Translations
2 parents 7711fd1 + 696880e commit 26706f4

Some content is hidden

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

65 files changed

+970
-256
lines changed

web/app/dashboard/page.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
import useCurrentUser from "@/hooks/useCurrentUser";
33
import {Container, Title, Text, Card, Grid, Group, Flex} from "@mantine/core";
44
import {IconTrophyFilled} from "@tabler/icons-react";
5+
import {useTranslation} from "react-i18next";
56

67
const DashboardPage = () => {
78
const { user } = useCurrentUser();
9+
const {t} = useTranslation('dashboard');
810

911
return (
1012
<Container fluid>
11-
<Title>Welcome back, {user?.username}!</Title>
13+
<Title>{t('welcome-back')} {user?.username}!</Title>
1214
<Card
1315
shadow="sm"
1416
padding="xl"
1517
mt={20}
1618
>
1719
<Text mt="xs" c="dimmed" size="sm">
18-
Hey, its us again. Please be aware of that this software is totally free to use for you. We do not store
19-
any personal data except from your username and password. Nevertheless, we have to pay our fees, for domains
20-
and server hosting. So if you want, feel free to support us, because developing this application takes a lot of time.
20+
{t('us-again-text')}
2121
</Text>
2222
</Card>
2323
<Grid>
@@ -30,9 +30,8 @@ const DashboardPage = () => {
3030
<Group justify="space-between">
3131
<IconTrophyFilled color="#bfba40" size={100} />
3232
<Flex direction="column">
33-
<Title order={5}>Oleggtro: contributor of year!</Title>
34-
<Text>Throughout the year, Oleggtro has gone above and beyond, consistently sharing insights, knowledge, and support with our community. His dedication and contributions have made a significant impact, enriching our platform and setting a high standard for collaboration.
35-
Thank you, Oleggtro, for your hard work, passion, and unwavering commitment. We are incredibly grateful to have you as part of our team! Here’s to many more achievements together.</Text>
33+
<Title order={5}>{t('ole-title')}</Title>
34+
<Text>{t('ole-text')}</Text>
3635
</Flex>
3736
</Group>
3837
</Card>
@@ -43,14 +42,15 @@ const DashboardPage = () => {
4342
padding="xl"
4443
mt={20}
4544
>
46-
<Title order={2}>Release v0.1.5</Title>
45+
<Title order={2}>Release v0.2.0</Title>
4746
<Text>
4847
We had some groundbreaking changes within our app for the current release:<br />
49-
- Comments on solutions by the tutor <br/>
50-
- Stage2 spotlight search <br/>
51-
- Bug reporting feature <br/>
52-
- Assignment wishes within the group <br/>
53-
- Assignments without due date
48+
- German translation <br/>
49+
- Login attempt limit <br/>
50+
- Some minor bug fixes <br/>
51+
- Pagination <br/>
52+
- Code View tabs <br/>
53+
- Some administrative & performance updates
5454
</Text>
5555
</Card>
5656
</Grid.Col>

web/app/groups/[groupId]/assignments/[assignmentId]/page.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import AssignmentCompletedByTab from "@/components/assignments/AssignmentComplet
1919
import CreateOrUpdateQuestionsModal from "@/components/assignments/CreateOrUpdateQuestionsModal";
2020
import QuestionAnswersDisplay from "@/components/solution/questions/QuestionAnswersDisplay";
2121
import { useSpotlightStage2 } from "@/hooks/spotlight/stage2";
22+
import {useTranslation} from "react-i18next";
2223

2324
const AssignmentDetailsPage = ({
2425
params,
@@ -36,6 +37,7 @@ const AssignmentDetailsPage = ({
3637
() => api.getAssignmentForGroup(groupId, assignmentId),
3738
[assignmentId, groupId],
3839
);
40+
const {t} = useTranslation(['common', 'assignment']);
3941

4042
const {addAssignment} = useSpotlightStage2();
4143

@@ -48,7 +50,7 @@ const AssignmentDetailsPage = ({
4850
if (isNaN(groupId) || isNaN(assignmentId)) {
4951
return (
5052
<Container fluid>
51-
<Title>Invalid Group ID</Title>
53+
<Title>{t('invalid-group-id')}</Title>
5254
</Container>
5355
);
5456
}
@@ -70,33 +72,33 @@ const AssignmentDetailsPage = ({
7072
{isGranted(user, [UserRoles.Tutor, UserRoles.Admin]) &&
7173
assignment.language !== AssignmentLanguage.QuestionBased && (
7274
<Button onClick={() => setFileStructureModalOpen(true)}>
73-
Code tests
75+
{t('assignment:code-tests')}
7476
</Button>
7577
)}
7678
{isGranted(user, [UserRoles.Tutor, UserRoles.Admin]) &&
7779
assignment.language === AssignmentLanguage.QuestionBased && (
7880
<Button onClick={() => setQuestionsModalOpen(true)}>
79-
Questions
81+
{t('assignment:questions')}
8082
</Button>
8183
)}
8284
</Group>
8385
<Tabs defaultValue="task">
8486
<Tabs.List>
85-
<Tabs.Tab value="task">Task</Tabs.Tab>
87+
<Tabs.Tab value="task">{t('assignment:task')}</Tabs.Tab>
8688
{isGranted(user, [UserRoles.Tutor, UserRoles.Admin]) &&
8789
assignment.file_structure !== null &&
8890
assignment.language !== AssignmentLanguage.QuestionBased && (
89-
<Tabs.Tab value="codeTests">Code Tests</Tabs.Tab>
91+
<Tabs.Tab value="codeTests">{t('assignment:code-tests')}</Tabs.Tab>
9092
)}
9193
{isGranted(user, [UserRoles.Tutor, UserRoles.Admin]) &&
9294
assignment.question_catalogue !== null &&
9395
assignment.language === AssignmentLanguage.QuestionBased && (
94-
<Tabs.Tab value="questions">Questions</Tabs.Tab>
96+
<Tabs.Tab value="questions">{t('assignment:questions')}</Tabs.Tab>
9597
)}
9698
{isGranted(user, [UserRoles.Tutor, UserRoles.Admin]) && (
9799
<>
98-
<Tabs.Tab value="solutions">Solutions</Tabs.Tab>
99-
<Tabs.Tab value="completedBy">Completed by</Tabs.Tab>
100+
<Tabs.Tab value="solutions">{t('assignment:solutions')}</Tabs.Tab>
101+
<Tabs.Tab value="completedBy">{t('assignment:completed-by')}</Tabs.Tab>
100102
</>
101103
)}
102104
</Tabs.List>

web/app/groups/[groupId]/client.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ import GroupAssignmentsTab from "@/components/assignments/GroupAssignmentsTab";
1717
import useCurrentUser from "@/hooks/useCurrentUser";
1818
import { isGranted } from "@/service/auth";
1919
import GroupAssignmentWishesTab from "@/components/group/GroupAssignmentWishesTab";
20+
import {useTranslation} from "react-i18next";
2021

2122
const MembersComponent: React.FC<{ members: TaskyUser[] }> = ({ members }) => {
23+
24+
const {t} = useTranslation('common');
25+
2226
const cols: EntityListCol[] = [
2327
{
2428
field: "id",
25-
label: "ID",
29+
label: t('cols.id'),
2630
},
2731
{
2832
field: "username",
29-
label: "Username",
33+
label: t('cols.username'),
3034
},
3135
];
3236

@@ -43,22 +47,23 @@ export const JoinRequestsComponent: React.FC<{
4347
() => api.getGroupJoinRequests(group?.id ?? -1, page),
4448
[group?.id, page],
4549
);
50+
const {t} = useTranslation('common');
4651

4752
const cols: EntityListCol[] = [
4853
{
4954
field: "id",
50-
label: "ID",
55+
label: t('cols.id'),
5156
},
5257
{
5358
field: "username",
54-
label: "Username",
59+
label: t('cols.username'),
5560
getter: (row) => row.requestor.username,
5661
},
5762
];
5863

5964
const actions: EntityListRowAction[] = [
6065
{
61-
name: "Approve",
66+
name: t('actions.approve'),
6267
color: "green",
6368
onClick: (row) =>
6469
api.approveGroupJoinRequest(row.group_id, row.id).then(() => {
@@ -68,7 +73,7 @@ export const JoinRequestsComponent: React.FC<{
6873
auth: [UserRoles.Tutor, UserRoles.Admin],
6974
},
7075
{
71-
name: "Reject",
76+
name: t('actions.reject'),
7277
color: "red",
7378
onClick: (row) =>
7479
api.rejectGroupJoinRequest(row.group_id, row.id).then(() => {
@@ -96,13 +101,14 @@ export const TabsComponent: React.FC<{
96101
refetch: () => void;
97102
}> = ({ group, refetch }) => {
98103
const { user } = useCurrentUser();
104+
const {t} = useTranslation('group');
99105

100106
return (
101107
<Tabs defaultValue="assignments" style={{ marginTop: "2em" }}>
102108
<Tabs.List>
103-
<Tabs.Tab value="assignments">Assignments</Tabs.Tab>
104-
<Tabs.Tab value="members">Members</Tabs.Tab>
105-
<Tabs.Tab value="assignmentWishes">Assignment Wishes</Tabs.Tab>
109+
<Tabs.Tab value="assignments">{t('tabs.assignments')}</Tabs.Tab>
110+
<Tabs.Tab value="members">{t('tabs.members')}</Tabs.Tab>
111+
<Tabs.Tab value="assignmentWishes">{t('tabs.assignment-wishes')}</Tabs.Tab>
106112
{isGranted(user, [UserRoles.Admin, UserRoles.Tutor]) && (
107113
<Tabs.Tab
108114
value="joinRequests"
@@ -112,7 +118,7 @@ export const TabsComponent: React.FC<{
112118
) : null
113119
}
114120
>
115-
Join Requests
121+
{t('tabs.join-requests')}
116122
</Tabs.Tab>
117123
)}
118124
</Tabs.List>

web/app/groups/[groupId]/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import useApiServiceClient from "@/hooks/useApiServiceClient";
77
import CentralLoading from "@/components/CentralLoading";
88
import {useSpotlightStage2} from "@/hooks/spotlight/stage2";
99
import {useEffect} from "react";
10+
import {useTranslation} from "react-i18next";
1011

1112
const GroupDetailsPage = ({ params }: { params: { groupId: string } }) => {
1213
const id = parseInt(`${params.groupId}`, 10);
1314
const api = useApiServiceClient();
1415
const [group, refetch] = useClientQuery<GroupType>(() => api.getGroup(id));
1516
const {addGroup} = useSpotlightStage2();
17+
const {t} = useTranslation('common');
1618

1719
useEffect(() => {
1820
if (group) {
@@ -23,7 +25,7 @@ const GroupDetailsPage = ({ params }: { params: { groupId: string } }) => {
2325
if (isNaN(id)) {
2426
return (
2527
<Container fluid>
26-
<Title>Invalid Group ID</Title>
28+
<Title>{t('invalid-group-id')}</Title>
2729
</Container>
2830
);
2931
}

web/app/groups/displayComponent.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import useApiServiceClient from "@/hooks/useApiServiceClient";
1010
import { notifications } from "@mantine/notifications";
1111
import useCurrentUser from "@/hooks/useCurrentUser";
1212
import { isGranted } from "@/service/auth";
13+
import {useTranslation} from "react-i18next";
1314

1415
interface DisplayComponentProps {
1516
groups: MinifiedGroup[];
@@ -23,22 +24,23 @@ const GroupsDisplayComponent = ({
2324
refetch,
2425
}: DisplayComponentProps) => {
2526
const router = useRouter();
27+
const {t} = useTranslation(['common', 'group']);
2628
const cols: EntityListCol[] = [
2729
{
2830
field: "id",
29-
label: "ID",
31+
label: t('cols.id'),
3032
},
3133
{
3234
field: "title",
33-
label: "Title",
35+
label: t('group:cols.title'),
3436
},
3537
{
3638
field: "member_count",
37-
label: "Members Count",
39+
label: t('group:cols.members-count'),
3840
},
3941
{
4042
field: "tutor",
41-
label: "Tutor",
43+
label: t('group:cols.tutor'),
4244
getter: (row) => row.tutor.username,
4345
},
4446
];
@@ -48,7 +50,7 @@ const GroupsDisplayComponent = ({
4850
const actions: EntityListRowAction[] = [
4951
{
5052
color: "blue",
51-
name: "View",
53+
name: t('actions.view'),
5254
onClick: (row) => router.push(`/groups/${row.id}`),
5355
auth: [UserRoles.Admin, UserRoles.Tutor, UserRoles.Student],
5456
authFunc: (row) =>
@@ -58,12 +60,12 @@ const GroupsDisplayComponent = ({
5860
},
5961
{
6062
color: "blue",
61-
name: "Request Join",
63+
name: t('actions.request-join'),
6264
onClick: (row) =>
6365
api.createGroupJoinRequest(row.id).then(() => {
6466
notifications.show({
65-
title: "Join Request created",
66-
message: "Created join request on group " + row.title,
67+
title: t('messages.join-request-created-title'),
68+
message: t('messages.join-request-created-text') + row.title,
6769
});
6870
if (refetch) refetch();
6971
}),

web/app/groups/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import GroupsDisplayComponent from "@/app/groups/displayComponent";
55
import useApiServiceClient from "@/hooks/useApiServiceClient";
66
import useClientQuery from "@/hooks/useClientQuery";
77
import {useState} from "react";
8+
import {useTranslation} from "react-i18next";
89

910
const GroupsPage = () => {
1011
const api = useApiServiceClient();
1112
const [page, setPage] = useState(1);
1213
const [groups, refetch] = useClientQuery<GroupsResponse>(() =>
1314
api.getGroups(page),
1415
[page]);
16+
const {t} = useTranslation('group');
1517

1618
return (
1719
<Container fluid>
18-
<Title>Groups</Title>
20+
<Title>{t('groups')}</Title>
1921
<GroupsDisplayComponent
2022
groups={groups?.groups ?? []}
2123
page="groups"

web/app/layout.tsx

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ import Footer from "@/components/Footer";
2121
import { publicRoutes } from "@/static/routes";
2222
import Stage2SpotlightContextWrapper from "@/components/spotlight/Stage2SpotlightContextWrapper";
2323
import {Stage2Type} from "@/hooks/spotlight/stage2";
24+
import i18n from "../i18n"
25+
import CentralLoading from "@/components/CentralLoading";
2426

2527
export default function RootLayout({
2628
children,
2729
}: Readonly<{
2830
children: React.ReactNode;
2931
}>) {
3032
const [user, setUser] = useState<User | null>(null);
33+
const [loading, setLoading] = useState<boolean>(true);
3134
const pathname = usePathname();
3235
const showNavbar = useMemo(
3336
() => publicRoutes.indexOf(pathname) === -1,
@@ -51,6 +54,8 @@ export default function RootLayout({
5154
console.error(e);
5255
}
5356
}
57+
i18n.init();
58+
setLoading(false);
5459
}, []);
5560

5661
return (
@@ -67,25 +72,29 @@ export default function RootLayout({
6772
<CurrentUserContext.Provider value={{ user, setUser }}>
6873
<MantineProvider theme={{}}>
6974
<DatesProvider settings={{ timezone: null }}>
70-
<Stage2SpotlightContextWrapper>
71-
<Notifications />
72-
<AppShell
73-
header={{ height: 100 }}
74-
navbar={showNavbar ? { width: 250, breakpoint: "" } : undefined}
75-
>
76-
<AppShell.Header>
77-
<Header />
78-
</AppShell.Header>
79-
{showNavbar && (
80-
<AppShell.Navbar>
81-
<Navbar />
82-
</AppShell.Navbar>
83-
)}
84-
<AppShell.Main mb={100}>{children}</AppShell.Main>
85-
<AppShell.Footer><Footer /></AppShell.Footer>
86-
</AppShell>
87-
<SpotlightWrapper />
88-
</Stage2SpotlightContextWrapper>
75+
{loading ? (
76+
<CentralLoading />
77+
) : (
78+
<Stage2SpotlightContextWrapper>
79+
<Notifications />
80+
<AppShell
81+
header={{ height: 100 }}
82+
navbar={showNavbar ? { width: 250, breakpoint: "" } : undefined}
83+
>
84+
<AppShell.Header>
85+
<Header />
86+
</AppShell.Header>
87+
{showNavbar && (
88+
<AppShell.Navbar>
89+
<Navbar />
90+
</AppShell.Navbar>
91+
)}
92+
<AppShell.Main mb={100}>{children}</AppShell.Main>
93+
<AppShell.Footer><Footer /></AppShell.Footer>
94+
</AppShell>
95+
<SpotlightWrapper />
96+
</Stage2SpotlightContextWrapper>
97+
)}
8998
</DatesProvider>
9099
</MantineProvider>
91100
</CurrentUserContext.Provider>

0 commit comments

Comments
 (0)