mirror of
https://github.com/BreizhHardware/Jellystat.git
synced 2026-01-18 16:27:20 +01:00
Added localization to Activity Table
Fixed Localization on Library Activity Watch TIme Stats Fixed Search placeholder not localized
This commit is contained in:
@@ -81,8 +81,22 @@
|
||||
},
|
||||
"IP_ADDRESS": "IP Address",
|
||||
"CLIENT": "Client",
|
||||
"DEVICE": "Device",
|
||||
"PLAYBACK_DURATION": "Playback Duration",
|
||||
"TOTAL_PLAYBACK": "Total Playback"
|
||||
"TOTAL_PLAYBACK": "Total Playback",
|
||||
"EXPAND": "Expand",
|
||||
"COLLAPSE": "Collapse",
|
||||
"SORT_BY": "Sort by",
|
||||
"ASCENDING": "Ascending",
|
||||
"DESCENDING": "Descending",
|
||||
"CLEAR_SORT": "Clear Sort",
|
||||
"CLEAR_FILTER": "Clear Filter",
|
||||
"FILTER_BY": "Filter by",
|
||||
"COLUMN_ACTIONS": "Column Actions",
|
||||
"TOGGLE_SELECT_ROW": "Toggle Select Row",
|
||||
"TOGGLE_SELECT_ALL": "Toggle Select All",
|
||||
"MIN": "Min",
|
||||
"MAX": "Max"
|
||||
},
|
||||
"TABLE_NAV_BUTTONS": {
|
||||
"FIRST": "First",
|
||||
@@ -118,6 +132,8 @@
|
||||
"SHOW_ARCHIVED_LIBRARIES": "Show Archived Libraries",
|
||||
"HIDE_ARCHIVED_LIBRARIES": "Hide Archived Libraries",
|
||||
"UNITS": {
|
||||
"MONTH": "Month",
|
||||
"MONTHS": "Months",
|
||||
"DAY": "Day",
|
||||
"DAYS": "Days",
|
||||
"HOUR": "Hour",
|
||||
@@ -204,6 +220,7 @@
|
||||
"GITHUB": "Github",
|
||||
"Backup": "Backup Jellystat"
|
||||
},
|
||||
"SEARCH": "Search",
|
||||
"TOTAL": "Total",
|
||||
"LAST": "Last",
|
||||
"SERIES": "Series",
|
||||
@@ -212,6 +229,7 @@
|
||||
"EPISODE": "Episode",
|
||||
"EPISODES": "Episodes",
|
||||
"MOVIES": "Movies",
|
||||
"MUSIC": "Music",
|
||||
"SONGS": "Songs",
|
||||
"FILES": "Files",
|
||||
"LIBRARIES": "Libraries",
|
||||
|
||||
@@ -80,9 +80,23 @@
|
||||
"HEADER": "Stream Info"
|
||||
},
|
||||
"IP_ADDRESS": "Adresse IP",
|
||||
"CLIENT": "Appareil",
|
||||
"CLIENT": "Client",
|
||||
"DEVICE": "Appareil",
|
||||
"PLAYBACK_DURATION": "Durée de la lecture",
|
||||
"TOTAL_PLAYBACK": "Lecture totale"
|
||||
"TOTAL_PLAYBACK": "Lecture totale",
|
||||
"EXPAND": "Développer",
|
||||
"COLLAPSE": "Réduire",
|
||||
"SORT_BY": "Trier par",
|
||||
"ASCENDING": "Croissant",
|
||||
"DESCENDING": "Décroissant",
|
||||
"CLEAR_SORT": "Annuler le tri",
|
||||
"CLEAR_FILTER": "Annuler le filtre",
|
||||
"FILTER_BY": "Filtrer par",
|
||||
"COLUMN_ACTIONS": "Actions supplémentaires",
|
||||
"TOGGLE_SELECT_ROW": "Inverser la sélection",
|
||||
"TOGGLE_SELECT_ALL": "Inverser toutes les sélections",
|
||||
"MIN": "Min",
|
||||
"MAX": "Max"
|
||||
},
|
||||
"TABLE_NAV_BUTTONS": {
|
||||
"FIRST": "Première",
|
||||
@@ -118,6 +132,8 @@
|
||||
"SHOW_ARCHIVED_LIBRARIES": "Afficher les médiathèques archivées",
|
||||
"HIDE_ARCHIVED_LIBRARIES": "Cacher les médiathèques archivées",
|
||||
"UNITS": {
|
||||
"MONTH": "Mois",
|
||||
"MONTHS": "Mois",
|
||||
"DAY": "Jour",
|
||||
"DAYS": "Jours",
|
||||
"HOUR": "Heure",
|
||||
@@ -202,6 +218,7 @@
|
||||
"GITHUB": "Github",
|
||||
"Backup": "Sauvegarde de Jellystat"
|
||||
},
|
||||
"SEARCH": "Recherche",
|
||||
"TOTAL": "Total",
|
||||
"LAST": "Last",
|
||||
"SERIES": "Séries",
|
||||
@@ -210,6 +227,7 @@
|
||||
"EPISODE": "Épisode",
|
||||
"EPISODES": "Épisodes",
|
||||
"MOVIES": "Films",
|
||||
"MUSIC": "Musiques",
|
||||
"SONGS": "Chansons",
|
||||
"FILES": "Fichiers",
|
||||
"LIBRARIES": "Médiathèques",
|
||||
|
||||
@@ -9,6 +9,7 @@ import ActivityTable from "./components/activity/activity-table";
|
||||
import Loading from "./components/general/loading";
|
||||
import { Trans } from "react-i18next";
|
||||
import { FormControl, FormSelect } from "react-bootstrap";
|
||||
import i18next from "i18next";
|
||||
|
||||
function Activity() {
|
||||
const [data, setData] = useState();
|
||||
@@ -115,7 +116,7 @@ function Activity() {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import axios from "axios";
|
||||
import { enUS } from "@mui/material/locale";
|
||||
import { MRT_Localization_EN } from "material-react-table/locales/en";
|
||||
|
||||
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
|
||||
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
||||
|
||||
@@ -135,7 +135,7 @@ export default function ActivityTable(props) {
|
||||
const columns = [
|
||||
{
|
||||
accessorKey: "UserName",
|
||||
header: "User",
|
||||
header: i18next.t("USER"),
|
||||
filterVariant: "select",
|
||||
filterSelectOptions: uniqueUserNames,
|
||||
Cell: ({ row }) => {
|
||||
@@ -149,7 +149,7 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "RemoteEndPoint",
|
||||
header: "IP Address",
|
||||
header: i18next.t("ACTIVITY_TABLE.IP_ADDRESS"),
|
||||
|
||||
Cell: ({ row }) => {
|
||||
row = row.original;
|
||||
@@ -175,7 +175,7 @@ export default function ActivityTable(props) {
|
||||
? row.NowPlayingItemName
|
||||
: row.SeriesName + " : S" + row.SeasonNumber + "E" + row.EpisodeNumber + " - " + row.NowPlayingItemName
|
||||
}`,
|
||||
header: "Title",
|
||||
header: i18next.t("TITLE"),
|
||||
minSize: 300,
|
||||
Cell: ({ row }) => {
|
||||
row = row.original;
|
||||
@@ -190,7 +190,7 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "Client",
|
||||
header: "Client",
|
||||
header: i18next.t("ACTIVITY_TABLE.CLIENT"),
|
||||
filterVariant: "select",
|
||||
filterSelectOptions: uniqueClients,
|
||||
Cell: ({ row }) => {
|
||||
@@ -204,11 +204,11 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "DeviceName",
|
||||
header: "Device",
|
||||
header: i18next.t("ACTIVITY_TABLE.DEVICE"),
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => new Date(row.ActivityDateInserted),
|
||||
header: "Date",
|
||||
header: i18next.t("DATE"),
|
||||
size: 110,
|
||||
filterVariant: "date-range",
|
||||
Cell: ({ row }) => {
|
||||
@@ -227,7 +227,7 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "PlaybackDuration",
|
||||
header: "Total Playback",
|
||||
header: i18next.t("ACTIVITY_TABLE.TOTAL_PLAYBACK"),
|
||||
minSize: 200,
|
||||
filterFn: (row, id, filterValue) => formatTotalWatchTime(row.getValue(id)).startsWith(filterValue),
|
||||
|
||||
@@ -235,7 +235,7 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => Number(row.TotalPlays ?? 1),
|
||||
header: "Total Plays",
|
||||
header: i18next.t("TOTAL_PLAYS"),
|
||||
filterFn: "betweenInclusive",
|
||||
|
||||
Cell: ({ cell }) => <span>{cell.getValue() ?? 1}</span>,
|
||||
@@ -249,6 +249,17 @@ export default function ActivityTable(props) {
|
||||
const table = useMaterialReactTable({
|
||||
columns,
|
||||
data,
|
||||
localization: {
|
||||
expand: i18next.t("ACTIVITY_TABLE.EXPAND"),
|
||||
collapse: i18next.t("ACTIVITY_TABLE.COLLAPSE"),
|
||||
sortByColumnAsc: `${i18next.t("ACTIVITY_TABLE.SORT_BY")} {column} - ${i18next.t("ACTIVITY_TABLE.ASCENDING")}`,
|
||||
sortByColumnDesc: `${i18next.t("ACTIVITY_TABLE.SORT_BY")} {column} - ${i18next.t("ACTIVITY_TABLE.DESCENDING")}`,
|
||||
clearFilter: i18next.t("ACTIVITY_TABLE.CLEAR_FILTER"),
|
||||
clearSort: i18next.t("ACTIVITY_TABLE.CLEAR_SORT"),
|
||||
filterByColumn: `${i18next.t("ACTIVITY_TABLE.FILTER_BY")} {column}`,
|
||||
toggleSelectAll: i18next.t("ACTIVITY_TABLE.TOGGLE_SELECT_ALL"),
|
||||
toggleSelectRow: i18next.t("ACTIVITY_TABLE.TOGGLE_SELECT_ROW"),
|
||||
},
|
||||
columnFilterDisplayMode: "popover",
|
||||
layoutMode: "grid",
|
||||
enableExpandAll: false,
|
||||
@@ -266,7 +277,6 @@ export default function ActivityTable(props) {
|
||||
},
|
||||
],
|
||||
},
|
||||
localization: { MRT_Localization_EN },
|
||||
showAlertBanner: false,
|
||||
enableHiding: false,
|
||||
enableFullScreenToggle: false,
|
||||
|
||||
@@ -3,6 +3,7 @@ import axios from "axios";
|
||||
import ActivityTable from "../activity/activity-table";
|
||||
import { Trans } from "react-i18next";
|
||||
import { FormControl, FormSelect } from "react-bootstrap";
|
||||
import i18next from "i18next";
|
||||
|
||||
function ItemActivity(props) {
|
||||
const [data, setData] = useState();
|
||||
@@ -81,7 +82,7 @@ function ItemActivity(props) {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
@@ -6,9 +6,9 @@ function WatchTimeStats(props) {
|
||||
|
||||
function formatTime(totalSeconds, numberClassName, labelClassName) {
|
||||
const units = [
|
||||
{ label: i18next.t("UNITS.DAY"), seconds: 86400 },
|
||||
{ label: i18next.t("UNITS.HOUR"), seconds: 3600 },
|
||||
{ label: i18next.t("UNITS.MINUTE"), seconds: 60 },
|
||||
{ label: [i18next.t("UNITS.DAY"),i18next.t("UNITS.DAYS")], seconds: 86400 },
|
||||
{ label: [i18next.t("UNITS.HOUR"),i18next.t("UNITS.HOURS")], seconds: 3600 },
|
||||
{ label: [i18next.t("UNITS.MINUTE"),i18next.t("UNITS.MINUTES")], seconds: 60 },
|
||||
];
|
||||
|
||||
const parts = units.reduce((result, { label, seconds }) => {
|
||||
@@ -17,7 +17,7 @@ function WatchTimeStats(props) {
|
||||
const formattedValue = <p className={numberClassName}>{value}</p>;
|
||||
const formattedLabel = (
|
||||
<span className={labelClassName}>
|
||||
{value === 1 ? label : i18next.t(`UNITS.${label.toUpperCase()}S`) }
|
||||
{value === 1 ? label[0] : label[1] }
|
||||
</span>
|
||||
);
|
||||
result.push(
|
||||
|
||||
@@ -4,6 +4,7 @@ import axios from "axios";
|
||||
import ActivityTable from "../activity/activity-table";
|
||||
import { Trans } from "react-i18next";
|
||||
import { FormControl, FormSelect } from "react-bootstrap";
|
||||
import i18next from "i18next";
|
||||
|
||||
function LibraryActivity(props) {
|
||||
const [data, setData] = useState();
|
||||
@@ -81,7 +82,7 @@ function LibraryActivity(props) {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
@@ -53,22 +53,28 @@ function LibraryCard(props) {
|
||||
const days = Math.floor(seconds / 86400); // 1 day = 86400 seconds
|
||||
const hours = Math.floor((seconds % 86400) / 3600); // 1 hour = 3600 seconds
|
||||
const minutes = Math.floor(((seconds % 86400) % 3600) / 60); // 1 minute = 60 seconds
|
||||
|
||||
const units = {
|
||||
months: [i18next.t("UNITS.MONTH"), i18next.t("UNITS.MONTHS")],
|
||||
days: [i18next.t("UNITS.DAY"), i18next.t("UNITS.DAYS")],
|
||||
hours: [i18next.t("UNITS.HOUR"), i18next.t("UNITS.HOURS")],
|
||||
minutes: [i18next.t("UNITS.MINUTE"), i18next.t("UNITS.MINUTES")]
|
||||
};
|
||||
|
||||
let formattedTime = '';
|
||||
if (days) {
|
||||
formattedTime += `${days} day${days > 1 ? 's' : ''}`;
|
||||
formattedTime += `${days} ${days > 1 ? units.days[1] : units.days[0]}`;
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
formattedTime += ` ${hours} hour${hours > 1 ? 's' : ''}`;
|
||||
formattedTime += ` ${hours} ${hours > 1 ? units.hours[1] : units.hours[0]}`;
|
||||
}
|
||||
|
||||
if (minutes) {
|
||||
formattedTime += ` ${minutes} minute${minutes > 1 ? 's' : ''}`;
|
||||
if (minutes) { formattedTime += ` ${minutes} ${minutes > 1 ? units.minutes[1] : units.minutes[0]}`;
|
||||
}
|
||||
|
||||
if (!days && !hours && !minutes) {
|
||||
formattedTime = '0 minutes';
|
||||
formattedTime =`0 ${units.minutes[1]}`;
|
||||
}
|
||||
|
||||
return formattedTime;
|
||||
@@ -82,24 +88,31 @@ function LibraryCard(props) {
|
||||
const minutes = Math.floor((seconds % 3600) / 60); // 1 minute = 60 seconds
|
||||
|
||||
const timeComponents = [];
|
||||
|
||||
const units = {
|
||||
months: [i18next.t("UNITS.MONTH"), i18next.t("UNITS.MONTHS")],
|
||||
days: [i18next.t("UNITS.DAY"), i18next.t("UNITS.DAYS")],
|
||||
hours: [i18next.t("UNITS.HOUR"), i18next.t("UNITS.HOURS")],
|
||||
minutes: [i18next.t("UNITS.MINUTE"), i18next.t("UNITS.MINUTES")]
|
||||
};
|
||||
|
||||
if (months) {
|
||||
timeComponents.push(`${months} Month${months > 1 ? 's' : ''}`);
|
||||
timeComponents.push(`${months} ${months > 1 ? units.months[1] : units.months[0] }`);
|
||||
}
|
||||
|
||||
if (days) {
|
||||
timeComponents.push(`${days} day${days > 1 ? 's' : ''}`);
|
||||
timeComponents.push(`${days} ${days > 1 ? units.days[1] : units.days[0]}`);
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
timeComponents.push(`${hours} hour${hours > 1 ? 's' : ''}`);
|
||||
timeComponents.push(`${hours} ${hours > 1 ? units.hours[1] : units.hours[0]}`);
|
||||
}
|
||||
|
||||
if (!months && minutes) {
|
||||
timeComponents.push(`${minutes} minute${minutes > 1 ? 's' : ''}`);
|
||||
timeComponents.push(`${minutes} ${minutes > 1 ? units.minutes[1] : units.minutes[0]}`);
|
||||
}
|
||||
|
||||
const formattedTime = timeComponents.length > 0 ? timeComponents.join(' ') : '0 minutes';
|
||||
const formattedTime = timeComponents.length > 0 ? timeComponents.join(' ') : `0 ${units.minutes[1]}`;
|
||||
return formattedTime;
|
||||
}
|
||||
|
||||
@@ -151,7 +164,7 @@ function LibraryCard(props) {
|
||||
|
||||
<Row className="space-between-end card-row">
|
||||
<Col className="card-label"><Trans i18nKey="TYPE" /></Col>
|
||||
<Col className="text-end">{props.data.CollectionType==='tvshows' ? 'Series' : props.data.CollectionType==='movies'? "Movies" : props.data.CollectionType==='music'? "Music" : 'Mixed'}</Col>
|
||||
<Col className="text-end">{props.data.CollectionType==='tvshows' ? <Trans i18nKey="SERIES" /> : props.data.CollectionType==='movies'? <Trans i18nKey="MOVIES" /> : props.data.CollectionType==='music'? <Trans i18nKey="MUSIC" /> : 'Mixed'}</Col>
|
||||
</Row>
|
||||
|
||||
<Row className="space-between-end card-row">
|
||||
|
||||
@@ -431,7 +431,7 @@ function Users() {
|
||||
</div>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
placeholder= {i18next.t("SEARCH")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="ms-md-3 my-3 w-sm-100 w-md-75"
|
||||
|
||||
Reference in New Issue
Block a user