add declension of words
This commit is contained in:
@@ -198,7 +198,7 @@ export const StackedBarChart = ({ data }: Files) => {
|
|||||||
<div
|
<div
|
||||||
className={`font-bold text-[${CHECKS_COLOR}]`}
|
className={`font-bold text-[${CHECKS_COLOR}]`}
|
||||||
>
|
>
|
||||||
{t('check')}: {totalChecks}
|
{t('checks')}: {totalChecks}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`font-bold text-[${VIOLATIONS_COLOR}]`}
|
className={`font-bold text-[${VIOLATIONS_COLOR}]`}
|
||||||
|
|||||||
@@ -668,7 +668,7 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
|
|||||||
{t('all-types')}
|
{t('all-types')}
|
||||||
</li>
|
</li>
|
||||||
<li value="image">
|
<li value="image">
|
||||||
{t('images')}
|
{t('images-few')}
|
||||||
</li>
|
</li>
|
||||||
<li value="video">
|
<li value="video">
|
||||||
{t('videos')}
|
{t('videos')}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export const pluralize = (number: number, one: string, few: string, many: string) => {
|
||||||
|
const n = Math.abs(number) % 100;
|
||||||
|
const n1 = n % 10;
|
||||||
|
|
||||||
|
if (n > 10 && n < 20) return many; // 11-19
|
||||||
|
if (n1 > 1 && n1 < 5) return few; // 2-4 (кроме 12-14)
|
||||||
|
if (n1 === 1) return one; // 1 (кроме 11)
|
||||||
|
|
||||||
|
return many; // 0, 5-9, 10-20, 25-30 и т.д.
|
||||||
|
};
|
||||||
@@ -96,6 +96,10 @@
|
|||||||
|
|
||||||
.protection-stat-label {
|
.protection-stat-label {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
|
&::first-letter {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useClickOutside } from '@/app/hooks/useClickOutside';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getUserFilesInfo } from '@/app/actions/action';
|
import { getUserFilesInfo } from '@/app/actions/action';
|
||||||
import { convertBytes } from '@/app/lib/convertBytes';
|
import { convertBytes } from '@/app/lib/convertBytes';
|
||||||
|
import { pluralize } from '@/app/lib/pluralize';
|
||||||
|
|
||||||
type FilesInfo = {
|
type FilesInfo = {
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
@@ -86,7 +87,7 @@ export default function ProtectionOverview() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFilesCount([
|
setFilesCount([
|
||||||
{
|
{
|
||||||
name: 'images',
|
name: 'images-few',
|
||||||
value: filesInfo?.imageSize ? filesInfo?.imageSize : 0,
|
value: filesInfo?.imageSize ? filesInfo?.imageSize : 0,
|
||||||
color: '#f08c00'
|
color: '#f08c00'
|
||||||
},
|
},
|
||||||
@@ -103,6 +104,24 @@ export default function ProtectionOverview() {
|
|||||||
])
|
])
|
||||||
}, [filesInfo]);
|
}, [filesInfo]);
|
||||||
|
|
||||||
|
const pluralizeFiles = (number: number) => {
|
||||||
|
const translate = [t('file'), t('files-few'), t('files')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluralizeCheks = (number: number) => {
|
||||||
|
const translate = [t('check'), t('checks-few'), t('checks')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluralizeViolations = (number: number) => {
|
||||||
|
const translate = [t('violation'), t('violations-few'), t('violations')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CHECKS = 6;
|
||||||
|
const VIOLATIONS = 2;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="protection-overview">
|
<div className="protection-overview">
|
||||||
<h3>{t('protecting-your-content')}</h3>
|
<h3>{t('protecting-your-content')}</h3>
|
||||||
@@ -116,13 +135,21 @@ export default function ProtectionOverview() {
|
|||||||
<div className="protection-stat-value">
|
<div className="protection-stat-value">
|
||||||
{filesInfo?.totalCount ? filesInfo?.totalCount : 0}
|
{filesInfo?.totalCount ? filesInfo?.totalCount : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="protection-stat-label">{t('total-files')}</div>
|
<div className="protection-stat-label">
|
||||||
|
{pluralizeFiles(filesInfo?.totalCount || 0)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="protection-stat total-checks">
|
<div className="protection-stat total-checks">
|
||||||
<div className="protection-stat-value">0</div>
|
<div className="protection-stat-value">
|
||||||
<div className="protection-stat-label">{t('check')}</div>
|
{CHECKS}
|
||||||
<div className="protection-stat-value">0</div>
|
</div>
|
||||||
<div className="protection-stat-label">{t('violations')}</div>
|
<div className="protection-stat-label">
|
||||||
|
{pluralizeCheks(CHECKS || 0)}
|
||||||
|
</div>
|
||||||
|
<div className="protection-stat-value">{VIOLATIONS}</div>
|
||||||
|
<div className="protection-stat-label">
|
||||||
|
{pluralizeViolations(VIOLATIONS)}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { getUserFilesData } from '@/app/actions/fileEntity';
|
import { getUserFilesData } from '@/app/actions/fileEntity';
|
||||||
import { getUserFilesInfo } from '@/app/actions/action';
|
import { getUserFilesInfo } from '@/app/actions/action';
|
||||||
import { convertBytes } from '@/app/lib/convertBytes';
|
import { convertBytes } from '@/app/lib/convertBytes';
|
||||||
|
import { pluralize } from '@/app/lib/pluralize';
|
||||||
|
|
||||||
type FilesInfo = {
|
type FilesInfo = {
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
@@ -69,6 +70,23 @@ export default function ProtectionSummary({ fileType }: { fileType: string }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pluralizeFilesName = (number: number) => {
|
||||||
|
const translate = [t(`${fileType}`), t(`${fileType}s-few`), t(`${fileType}s`)];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluralizeCheks = (number: number) => {
|
||||||
|
const translate = [t('check'), t('checks-few'), t('checks')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluralizeViolations = (number: number) => {
|
||||||
|
const translate = [t('violation'), t('violations-few'), t('violations')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CHECKS = 6;
|
||||||
|
const VIOLATIONS = 2;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="protection-overview grow">
|
<div className="protection-overview grow">
|
||||||
@@ -78,16 +96,18 @@ export default function ProtectionSummary({ fileType }: { fileType: string }) {
|
|||||||
<div className="protection-stat total-files">
|
<div className="protection-stat total-files">
|
||||||
<div className="protection-stat-value">{filesInfo?.totalCount ? filesInfo?.totalCount : 0}</div>
|
<div className="protection-stat-value">{filesInfo?.totalCount ? filesInfo?.totalCount : 0}</div>
|
||||||
<div className="protection-stat-label">
|
<div className="protection-stat-label">
|
||||||
{t('total-files')}
|
{pluralizeFilesName(filesInfo?.totalCount || 0)}
|
||||||
<br />
|
|
||||||
({t(`${fileType}s`)})
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="protection-stat total-checks">
|
<div className="protection-stat total-checks">
|
||||||
<div className="protection-stat-value">0</div>
|
<div className="protection-stat-value">{CHECKS}</div>
|
||||||
<div className="protection-stat-label">{t('check')}</div>
|
<div className="protection-stat-label">
|
||||||
<div className="protection-stat-value">0</div>
|
{pluralizeCheks(CHECKS)}
|
||||||
<div className="protection-stat-label">{t('violations')}</div>
|
</div>
|
||||||
|
<div className="protection-stat-value">{VIOLATIONS}</div>
|
||||||
|
<div className="protection-stat-label">
|
||||||
|
{pluralizeViolations(VIOLATIONS)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="protection-stat total-usage">
|
<div className="protection-stat total-usage">
|
||||||
<div className="protection-stat-value">{filesInfo?.totalSize ? convertBytes(filesInfo?.totalSize) : 0} / 0</div>
|
<div className="protection-stat-value">{filesInfo?.totalSize ? convertBytes(filesInfo?.totalSize) : 0} / 0</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { getUserFilesInfo } from '@/app/actions/action';
|
import { getUserFilesInfo } from '@/app/actions/action';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { convertBytes } from '@/app/lib/convertBytes';
|
import { convertBytes } from '@/app/lib/convertBytes';
|
||||||
|
import { pluralize } from '@/app/lib/pluralize';
|
||||||
|
|
||||||
export default function MyContentInfoBlock() {
|
export default function MyContentInfoBlock() {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
@@ -67,6 +68,11 @@ export default function MyContentInfoBlock() {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pluralizeFiles = (number: number) => {
|
||||||
|
const translate = [t('file'), t('files-few'), t('files')];
|
||||||
|
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="block-wrapper auto grow">
|
<div className="block-wrapper auto grow">
|
||||||
<div className="file-stats-container">
|
<div className="file-stats-container">
|
||||||
@@ -83,7 +89,7 @@ export default function MyContentInfoBlock() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="file-stat-details">
|
<div className="file-stat-details">
|
||||||
<span className="file-stat-count">
|
<span className="file-stat-count">
|
||||||
{filesInfo.images_quantity ? filesInfo.images_quantity : 0} {t('files')}
|
{filesInfo.images_quantity || 0} {pluralizeFiles(filesInfo.images_quantity || 0)}
|
||||||
</span>
|
</span>
|
||||||
<span className="file-stat-size">
|
<span className="file-stat-size">
|
||||||
{filesInfo.images_size ? convertBytes(filesInfo.images_size) : 0}
|
{filesInfo.images_size ? convertBytes(filesInfo.images_size) : 0}
|
||||||
@@ -103,7 +109,7 @@ export default function MyContentInfoBlock() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="file-stat-details">
|
<div className="file-stat-details">
|
||||||
<span className="file-stat-count">
|
<span className="file-stat-count">
|
||||||
{filesInfo.videos_quantity ? filesInfo.videos_quantity : 0} {t('files')}
|
{filesInfo.videos_quantity || 0} {pluralizeFiles(filesInfo.videos_quantity || 0)}
|
||||||
</span>
|
</span>
|
||||||
<span className="file-stat-size">
|
<span className="file-stat-size">
|
||||||
{filesInfo.videos_size ? convertBytes(filesInfo.videos_size) : 0}
|
{filesInfo.videos_size ? convertBytes(filesInfo.videos_size) : 0}
|
||||||
@@ -123,7 +129,7 @@ export default function MyContentInfoBlock() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="file-stat-details">
|
<div className="file-stat-details">
|
||||||
<span className="file-stat-count">
|
<span className="file-stat-count">
|
||||||
{filesInfo.audios_quantity ? filesInfo.audios_quantity : 0} {t('files')}
|
{filesInfo.audios_quantity || 0} {pluralizeFiles(filesInfo.audios_quantity || 0)}
|
||||||
</span>
|
</span>
|
||||||
<span className="file-stat-size">
|
<span className="file-stat-size">
|
||||||
{filesInfo.audios_size ? convertBytes(filesInfo.audios_size) : 0}
|
{filesInfo.audios_size ? convertBytes(filesInfo.audios_size) : 0}
|
||||||
@@ -143,7 +149,7 @@ export default function MyContentInfoBlock() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="file-stat-details">
|
<div className="file-stat-details">
|
||||||
<span className="file-stat-count">
|
<span className="file-stat-count">
|
||||||
{filesInfo.documents_quantity ? filesInfo.documents_quantity : 0} {t('files')}
|
{filesInfo.documents_quantity || 0} {pluralizeFiles(filesInfo.documents_quantity || 0)}
|
||||||
</span>
|
</span>
|
||||||
<span className="file-stat-size">
|
<span className="file-stat-size">
|
||||||
{filesInfo.documents_size ? convertBytes(filesInfo.documents_size) : 0}
|
{filesInfo.documents_size ? convertBytes(filesInfo.documents_size) : 0}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export default function MyContentPieChart() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFilesCount([
|
setFilesCount([
|
||||||
{
|
{
|
||||||
name: 'images',
|
name: 'images-few',
|
||||||
value: filesInfo?.imageSize ? filesInfo?.imageSize : 0,
|
value: filesInfo?.imageSize ? filesInfo?.imageSize : 0,
|
||||||
color: '#f08c00'
|
color: '#f08c00'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,18 +10,26 @@
|
|||||||
"your-content": "Your content",
|
"your-content": "Your content",
|
||||||
"file": "File",
|
"file": "File",
|
||||||
"files": "Files",
|
"files": "Files",
|
||||||
|
"files-few": "files",
|
||||||
"content-type": "Content type",
|
"content-type": "Content type",
|
||||||
"quantity": "Quantity",
|
"quantity": "Quantity",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
|
"violation": "Violation",
|
||||||
|
"violations-few": "Violations",
|
||||||
"violations": "Violations",
|
"violations": "Violations",
|
||||||
|
"check": "Check",
|
||||||
"checks": "Checks",
|
"checks": "Checks",
|
||||||
"check": "Checks",
|
"checks-few": "Checks",
|
||||||
"documents": "Documents",
|
"documents": "Documents",
|
||||||
"videos": "Videos",
|
|
||||||
"video": "video",
|
"video": "video",
|
||||||
"audios": "Audio",
|
"videos": "Videos",
|
||||||
|
"videos-few": "video",
|
||||||
"audio": "audio",
|
"audio": "audio",
|
||||||
|
"audios": "Audios",
|
||||||
|
"audios-few": "Audios",
|
||||||
|
"image": "image",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
|
"images-few": "Images",
|
||||||
"main": "Main",
|
"main": "Main",
|
||||||
"marking": "Marking",
|
"marking": "Marking",
|
||||||
"reports": "Reports",
|
"reports": "Reports",
|
||||||
@@ -128,7 +136,6 @@
|
|||||||
"drag-the-file-here": "Drag the file here",
|
"drag-the-file-here": "Drag the file here",
|
||||||
"select-files-to-protect": "Select files to protect",
|
"select-files-to-protect": "Select files to protect",
|
||||||
"upload-for-protection": "Upload {fileType} for protection",
|
"upload-for-protection": "Upload {fileType} for protection",
|
||||||
"image": "image",
|
|
||||||
"file-has-no-extension": "File has no extension",
|
"file-has-no-extension": "File has no extension",
|
||||||
"have-unsaved-changes": "You have unsaved changes. Are you sure you want to delete this page?",
|
"have-unsaved-changes": "You have unsaved changes. Are you sure you want to delete this page?",
|
||||||
"image-size": "Image size",
|
"image-size": "Image size",
|
||||||
|
|||||||
@@ -10,18 +10,26 @@
|
|||||||
"your-content": "Ваш контент",
|
"your-content": "Ваш контент",
|
||||||
"file": "Файл",
|
"file": "Файл",
|
||||||
"files": "Файлов",
|
"files": "Файлов",
|
||||||
|
"files-few": "Файла",
|
||||||
"content-type": "Тип контента",
|
"content-type": "Тип контента",
|
||||||
"quantity": "Количество",
|
"quantity": "Количество",
|
||||||
"size": "Размер",
|
"size": "Размер",
|
||||||
"violations": "Нарушения",
|
"violation": "Нарушениe",
|
||||||
"checks": "Проверки",
|
"violations-few": "Нарушения",
|
||||||
"check": "Проверок",
|
"violations": "Нарушений",
|
||||||
|
"check": "Проверка",
|
||||||
|
"checks": "Проверок",
|
||||||
|
"checks-few": "Проверки",
|
||||||
"documents": "Документы",
|
"documents": "Документы",
|
||||||
"videos": "Видео",
|
|
||||||
"video": "видео",
|
"video": "видео",
|
||||||
"audios": "Аудио",
|
"videos": "Видео",
|
||||||
|
"videos-few": "Видео",
|
||||||
"audio": "аудио",
|
"audio": "аудио",
|
||||||
"images": "Изображения",
|
"audios": "Аудио",
|
||||||
|
"audios-few": "Аудио",
|
||||||
|
"image": "изображение",
|
||||||
|
"images": "Изображений",
|
||||||
|
"images-few": "Изображения",
|
||||||
"main": "Главная",
|
"main": "Главная",
|
||||||
"marking": "Маркировка",
|
"marking": "Маркировка",
|
||||||
"reports": "Отчёты",
|
"reports": "Отчёты",
|
||||||
@@ -128,7 +136,6 @@
|
|||||||
"drag-the-file-here": "Перетащите файл сюда",
|
"drag-the-file-here": "Перетащите файл сюда",
|
||||||
"select-files-to-protect": "Выбрать файлы для защиты",
|
"select-files-to-protect": "Выбрать файлы для защиты",
|
||||||
"upload-for-protection": "Загрузить {fileType} для защиты",
|
"upload-for-protection": "Загрузить {fileType} для защиты",
|
||||||
"image": "изображение",
|
|
||||||
"file-has-no-extension": "Файл не имеет расширения",
|
"file-has-no-extension": "Файл не имеет расширения",
|
||||||
"have-unsaved-changes": "У вас есть несохраненные изменения. Вы уверены, что хотите покинуть страницу?",
|
"have-unsaved-changes": "У вас есть несохраненные изменения. Вы уверены, что хотите покинуть страницу?",
|
||||||
"image-size": "Размер изображения",
|
"image-size": "Размер изображения",
|
||||||
|
|||||||
Reference in New Issue
Block a user