Skip to content

Commit

Permalink
feat(i18n): add support for translatable column labels in DataTable
Browse files Browse the repository at this point in the history
Enhanced the `DataTable` component to support translatable column labels:

- Updated `TableColumns` type to accept translation objects with `id` and `defaultMessage`.
- Refactored `processColumns` to translate labels using `useTranslation`.
- Ensured compatibility with existing column options and React components.

This update improves internationalization (i18n) support for dynamic table headers.
  • Loading branch information
phungmanhcuong committed Dec 17, 2024
1 parent eed61a6 commit 601fb15
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC, memo, useEffect, useState } from 'react';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Avatar, AvatarGroup, Box, Tooltip } from '@mui/material';
import { TableColumns } from 'types/components/DataTable';
import {
Expand Down Expand Up @@ -48,6 +48,30 @@ const translations = defineMessages({
id: 'course.leaderboard.LeaderboardTable.achievements',
defaultMessage: 'Achievements',
},
rank: {
id: 'course.leaderboard.LeaderboardTable.rank',
defaultMessage: 'Rank',
},
name: {
id: 'course.leaderboard.LeaderboardTable.name',
defaultMessage: 'Name',
},
level: {
id: 'course.leaderboard.LeaderboardTable.level',
defaultMessage: 'Level',
},
averageExperience: {
id: 'course.leaderboard.LeaderboardTable.averageExperience',
defaultMessage: 'Average Experience',
},
averageAchievements: {
id: 'course.leaderboard.LeaderboardTable.averageAchievements',
defaultMessage: 'Average Achievements',
},
members: {
id: 'course.leaderboard.LeaderboardTable.members',
defaultMessage: 'Members',
},
});

const styles = {
Expand Down Expand Up @@ -78,6 +102,7 @@ const styles = {

const LeaderboardTable: FC<Props> = (props: Props) => {
const { data, id: tableType } = props;
const { formatMessage: t } = useIntl();
const tabletView = useMedia.MinWidth('sm');
const phoneView = useMedia.MinWidth('xs');
const [maxAvatars, setMaxAvatars] = useState(6);
Expand All @@ -95,7 +120,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
const columns: TableColumns[] = [
{
name: 'id',
label: 'Rank',
label: t(translations.rank),
options: {
filter: false,
sort: false,
Expand All @@ -116,7 +141,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
| LeaderboardAchievement[];
columns.push({
name: 'name',
label: 'Name',
label: t(translations.name),
options: {
filter: false,
sort: false,
Expand Down Expand Up @@ -157,7 +182,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
columns.push(
{
name: 'level',
label: 'Level',
label: t(translations.level),
options: {
filter: false,
sort: false,
Expand All @@ -172,7 +197,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
},
{
name: 'experience',
label: 'Experience',
label: t(translations.experience),
options: {
filter: false,
sort: false,
Expand All @@ -192,7 +217,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
const achievementData = data as LeaderboardAchievement[];
columns.push({
name: 'achievements',
label: 'Achievements',
label: t(translations.achievements),
options: {
filter: false,
sort: false,
Expand Down Expand Up @@ -249,7 +274,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
columns.push(
{
name: 'name',
label: 'Name',
label: t(translations.name),
options: {
filter: false,
sort: false,
Expand All @@ -268,7 +293,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
},
{
name: 'members',
label: 'Members',
label: t(translations.members),
options: {
filter: false,
sort: false,
Expand Down Expand Up @@ -306,7 +331,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
const groupPointData = data as GroupLeaderboardPoints[];
columns.push({
name: 'points',
label: 'Average Experience',
label: t(translations.averageExperience),
options: {
filter: false,
sort: false,
Expand All @@ -332,7 +357,7 @@ const LeaderboardTable: FC<Props> = (props: Props) => {
const groupAchievementData = data as GroupLeaderboardAchievement[];
columns.push({
name: 'achievements',
label: 'Average Achievements',
label: t(translations.averageAchievements),
options: {
filter: false,
sort: false,
Expand Down
20 changes: 14 additions & 6 deletions client/app/lib/components/core/layouts/DataTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import MUIDataTable from 'mui-datatables';

import styles from 'lib/components/core/layouts/layout.scss';
import LoadingOverlay from 'lib/components/core/LoadingOverlay';
import useTranslation from "lib/hooks/useTranslation";
import React from "react";

const options = {
filter: true,
Expand Down Expand Up @@ -59,22 +61,26 @@ const processTheme = (theme, newHeight, grid, alignCenter, newPadding) =>
},
});

const processColumns = (includeRowNumber, columns) => {
const processColumns = (includeRowNumber, columns, t) => {
if (!columns.length) return columns;

const processed = columns.map((column) => {
if (!column.options?.alignCenter && !column.options?.hideInSmallScreen)
return column;

return produce(column, (draft) => {
if (typeof draft.label !== 'string' && !React.isValidElement(draft.label)) {
draft.label = t(draft.label);
}

draft.options.setCellHeaderProps = () => {
let align = null;
let className = '';
if (column.options?.alignCenter) {
if (draft.options?.alignCenter) {
className += `${styles.centeredTableHead}`;
align = 'center';
}
if (column.options?.hideInSmallScreen) {
if (draft.options?.hideInSmallScreen) {
className += ' !hidden sm:!table-cell';
}
return {
Expand All @@ -86,11 +92,12 @@ const processColumns = (includeRowNumber, columns) => {
draft.options.setCellProps = () => {
let align = null;
let className = '';
if (column.options?.alignCenter) {
if (draft.options?.alignCenter) {
align = 'center';
}
if (column.options?.hideInSmallScreen)
if (draft.options?.hideInSmallScreen) {
className += ' !hidden sm:!table-cell';
}
return {
...(align && { align }),
className,
Expand Down Expand Up @@ -120,6 +127,7 @@ const processColumns = (includeRowNumber, columns) => {
*/
const DataTable = (props) => {
const theme = useTheme();
const { t } = useTranslation();

return (
<ThemeProvider
Expand All @@ -135,7 +143,7 @@ const DataTable = (props) => {
{props.isLoading && <LoadingOverlay />}
<MUIDataTable
{...props}
columns={processColumns(props.includeRowNumber, props.columns)}
columns={processColumns(props.includeRowNumber, props.columns, t)}
options={{ ...options, ...(props.options ?? {}) }}
/>
</div>
Expand Down
8 changes: 7 additions & 1 deletion client/app/types/components/DataTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { CSSProperties } from 'react';
*/
export interface TableColumns {
name: string;
label: string | JSX.Element;
label:
| string
| JSX.Element
| {
id: string;
defaultMessage: string;
};
options: {
alignCenter?: boolean;
alignLeft?: boolean;
Expand Down

0 comments on commit 601fb15

Please sign in to comment.