Merge pull request #12 from DavronNabijonv/dev
detail page text translation added
This commit is contained in:
@@ -34,6 +34,8 @@
|
|||||||
"PlagiarismCheck": {
|
"PlagiarismCheck": {
|
||||||
"badge": "Originality Check",
|
"badge": "Originality Check",
|
||||||
"title": "Submit Your Document",
|
"title": "Submit Your Document",
|
||||||
|
"submissionSuccess": "Submission successful! ID",
|
||||||
|
"secureNote": "Your document is processed securely and not stored beyond the analysis period.",
|
||||||
"description": "Upload a document to verify its originality. Results are typically ready within a few minutes.",
|
"description": "Upload a document to verify its originality. Results are typically ready within a few minutes.",
|
||||||
"documentTopic": "Document Topic",
|
"documentTopic": "Document Topic",
|
||||||
"topicPlaceholder": "e.g. The Impact of Artificial Intelligence on Education",
|
"topicPlaceholder": "e.g. The Impact of Artificial Intelligence on Education",
|
||||||
@@ -80,6 +82,26 @@
|
|||||||
"fileName": "File Name",
|
"fileName": "File Name",
|
||||||
"fileSize": "File Size",
|
"fileSize": "File Size",
|
||||||
"submitted": "Submitted",
|
"submitted": "Submitted",
|
||||||
|
"failedToLoadDocument": "Failed to load document",
|
||||||
|
"unexpectedError": "An unexpected error occurred.",
|
||||||
|
"documentNumber": "Document #{{id}}",
|
||||||
|
"downloadPdf": "Download PDF",
|
||||||
|
"created": "Created",
|
||||||
|
"updated": "Updated",
|
||||||
|
"hash": "Hash",
|
||||||
|
"analysisScores": "Analysis Scores",
|
||||||
|
"documentText": "Document Text",
|
||||||
|
"plagiarismHighlights": "Plagiarism Highlights",
|
||||||
|
"plainText": "Plain Text",
|
||||||
|
"highlightedHint": "Highlighted fragments indicate potential plagiarism matches",
|
||||||
|
"textStatistics": "Text Statistics",
|
||||||
|
"detectionFlags": "Detection Flags",
|
||||||
|
"topWords": "Top Words",
|
||||||
|
"aiContentDetected": "AI Content Detected",
|
||||||
|
"possibleAiContent": "Possible AI Content",
|
||||||
|
"likelyOriginal": "Likely Original",
|
||||||
|
"aiProbabilityText": "AI probability score: {{score}}% — content may have been generated or assisted by an AI model.",
|
||||||
|
"resultFooter": "Result ID #{{id}} · Analyzed {{date}}",
|
||||||
"payment": "Payment",
|
"payment": "Payment",
|
||||||
"resultTitle": "Result",
|
"resultTitle": "Result",
|
||||||
"analysisInProgress": "Analysis in progress",
|
"analysisInProgress": "Analysis in progress",
|
||||||
@@ -211,5 +233,5 @@
|
|||||||
},
|
},
|
||||||
"unknownUser": "Username not found",
|
"unknownUser": "Username not found",
|
||||||
"file": "File",
|
"file": "File",
|
||||||
"upload":"Download certificate"
|
"upload": "Download certificate"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
"PlagiarismCheck": {
|
"PlagiarismCheck": {
|
||||||
"badge": "Проверка оригинальности",
|
"badge": "Проверка оригинальности",
|
||||||
"title": "Отправьте ваш документ",
|
"title": "Отправьте ваш документ",
|
||||||
|
"submissionSuccess": "Отправка прошла успешно! ID",
|
||||||
|
"secureNote": "Ваш документ обрабатывается безопасно и не хранится после периода анализа.",
|
||||||
"description": "Загрузите документ для проверки его оригинальности. Результаты обычно готовы в течение нескольких минут.",
|
"description": "Загрузите документ для проверки его оригинальности. Результаты обычно готовы в течение нескольких минут.",
|
||||||
"documentTopic": "Тема документа",
|
"documentTopic": "Тема документа",
|
||||||
"topicPlaceholder": "например: Влияние искусственного интеллекта на образование",
|
"topicPlaceholder": "например: Влияние искусственного интеллекта на образование",
|
||||||
@@ -80,6 +82,26 @@
|
|||||||
"fileName": "Имя файла",
|
"fileName": "Имя файла",
|
||||||
"fileSize": "Размер файла",
|
"fileSize": "Размер файла",
|
||||||
"submitted": "Отправлено",
|
"submitted": "Отправлено",
|
||||||
|
"failedToLoadDocument": "Не удалось загрузить документ",
|
||||||
|
"unexpectedError": "Произошла непредвиденная ошибка.",
|
||||||
|
"documentNumber": "Документ №{{id}}",
|
||||||
|
"downloadPdf": "Скачать PDF",
|
||||||
|
"created": "Создан",
|
||||||
|
"updated": "Обновлен",
|
||||||
|
"hash": "Hash",
|
||||||
|
"analysisScores": "Оценки анализа",
|
||||||
|
"documentText": "Текст документа",
|
||||||
|
"plagiarismHighlights": "Выделения плагиата",
|
||||||
|
"plainText": "Обычный текст",
|
||||||
|
"highlightedHint": "Выделенные фрагменты указывают на возможный плагиат",
|
||||||
|
"textStatistics": "Статистика текста",
|
||||||
|
"detectionFlags": "Флаги обнаружения",
|
||||||
|
"topWords": "Топ слова",
|
||||||
|
"aiContentDetected": "Обнаружен AI-контент",
|
||||||
|
"possibleAiContent": "Возможный AI-контент",
|
||||||
|
"likelyOriginal": "Вероятно оригинал",
|
||||||
|
"aiProbabilityText": "Вероятность AI: {{score}}% — контент может быть создан или сгенерирован AI.",
|
||||||
|
"resultFooter": "Результат ID #{{id}} · Анализирован {{date}}",
|
||||||
"payment": "Оплата",
|
"payment": "Оплата",
|
||||||
"resultTitle": "Результат",
|
"resultTitle": "Результат",
|
||||||
"analysisInProgress": "Анализ выполняется",
|
"analysisInProgress": "Анализ выполняется",
|
||||||
@@ -210,6 +232,6 @@
|
|||||||
"payButton": "Оплатить через Payme"
|
"payButton": "Оплатить через Payme"
|
||||||
},
|
},
|
||||||
"unknownUser": "Имя пользователя не найдено",
|
"unknownUser": "Имя пользователя не найдено",
|
||||||
"file":"Файл",
|
"file": "Файл",
|
||||||
"upload":"Скачать сертификат"
|
"upload": "Скачать сертификат"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ declare const messages: {
|
|||||||
PlagiarismCheck: {
|
PlagiarismCheck: {
|
||||||
badge: 'Orijinallik tekshiruvi';
|
badge: 'Orijinallik tekshiruvi';
|
||||||
title: 'Hujjatni yuboring';
|
title: 'Hujjatni yuboring';
|
||||||
|
submissionSuccess: 'Yuborish muvaffaqiyatli yakunlandi! ID';
|
||||||
|
secureNote: 'Hujjatingiz xavfsiz qayta ishlanadi va tahlil muddati tugagach saqlanmaydi.';
|
||||||
description: "Hujjatning orijinalligini tekshirish uchun yuklang. Natijalar odatda bir necha daqiqada tayyor bo'ladi.";
|
description: "Hujjatning orijinalligini tekshirish uchun yuklang. Natijalar odatda bir necha daqiqada tayyor bo'ladi.";
|
||||||
documentTopic: 'Hujjat mavzusi';
|
documentTopic: 'Hujjat mavzusi';
|
||||||
topicPlaceholder: "masalan: Sun'iy intellektning ta'limga ta'siri";
|
topicPlaceholder: "masalan: Sun'iy intellektning ta'limga ta'siri";
|
||||||
@@ -87,6 +89,26 @@ declare const messages: {
|
|||||||
resultTitle: 'Natija';
|
resultTitle: 'Natija';
|
||||||
analysisInProgress: 'Tahlil davom etmoqda';
|
analysisInProgress: 'Tahlil davom etmoqda';
|
||||||
resultsReadyAfterProcessing: "Natijalar qayta ishlash tugagach paydo bo'ladi.";
|
resultsReadyAfterProcessing: "Natijalar qayta ishlash tugagach paydo bo'ladi.";
|
||||||
|
failedToLoadDocument: 'Hujjatni yuklash muvaffaqiyatsiz tugadi';
|
||||||
|
unexpectedError: 'Kutilmagan xatolik yuz berdi.';
|
||||||
|
documentNumber: 'Hujjat №{{id}}';
|
||||||
|
downloadPdf: 'PDFni yuklab olish';
|
||||||
|
created: 'Yaratilgan';
|
||||||
|
updated: 'Yangilangan';
|
||||||
|
hash: 'Hash';
|
||||||
|
analysisScores: 'Tahlil ballari';
|
||||||
|
documentText: 'Hujjat matni';
|
||||||
|
plagiarismHighlights: 'Plagiat belgilari';
|
||||||
|
plainText: 'Oddiy matn';
|
||||||
|
highlightedHint: 'Belgilangan bo‘limlar plagiat ehtimolini ko‘rsatadi';
|
||||||
|
textStatistics: 'Matn statistikalari';
|
||||||
|
detectionFlags: 'Aniqlash bayroqlari';
|
||||||
|
topWords: 'Top so‘zlar';
|
||||||
|
aiContentDetected: 'AI kontent aniqlandi';
|
||||||
|
possibleAiContent: 'Ehtimoliy AI kontent';
|
||||||
|
likelyOriginal: 'Ehtimol original';
|
||||||
|
aiProbabilityText: 'AI ehtimollik balli: {{score}}% — kontent AI model tomonidan yaratilgan yoki yordam berilgan bo‘lishi mumkin.';
|
||||||
|
resultFooter: 'Natija ID #{{id}} · Tahlil qilingan {{date}}';
|
||||||
noResultAvailable: 'Natija mavjud emas.';
|
noResultAvailable: 'Natija mavjud emas.';
|
||||||
plagiarismResult: 'Plagiat natijasi';
|
plagiarismResult: 'Plagiat natijasi';
|
||||||
wordsChecked: "Tekshirilgan so'zlar";
|
wordsChecked: "Tekshirilgan so'zlar";
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
"PlagiarismCheck": {
|
"PlagiarismCheck": {
|
||||||
"badge": "Orijinallik tekshiruvi",
|
"badge": "Orijinallik tekshiruvi",
|
||||||
"title": "Hujjatni yuboring",
|
"title": "Hujjatni yuboring",
|
||||||
|
"submissionSuccess": "Yuborish muvaffaqiyatli yakunlandi! ID",
|
||||||
|
"secureNote": "Hujjatingiz xavfsiz qayta ishlanadi va tahlil muddati tugagach saqlanmaydi.",
|
||||||
"description": "Hujjatning orijinalligini tekshirish uchun yuklang. Natijalar odatda bir necha daqiqada tayyor bo'ladi.",
|
"description": "Hujjatning orijinalligini tekshirish uchun yuklang. Natijalar odatda bir necha daqiqada tayyor bo'ladi.",
|
||||||
"documentTopic": "Hujjat mavzusi",
|
"documentTopic": "Hujjat mavzusi",
|
||||||
"topicPlaceholder": "masalan: Sun'iy intellektning ta'limga ta'siri",
|
"topicPlaceholder": "masalan: Sun'iy intellektning ta'limga ta'siri",
|
||||||
@@ -84,6 +86,26 @@
|
|||||||
"resultTitle": "Natija",
|
"resultTitle": "Natija",
|
||||||
"analysisInProgress": "Tahlil davom etmoqda",
|
"analysisInProgress": "Tahlil davom etmoqda",
|
||||||
"resultsReadyAfterProcessing": "Natijalar qayta ishlash tugagach paydo bo'ladi.",
|
"resultsReadyAfterProcessing": "Natijalar qayta ishlash tugagach paydo bo'ladi.",
|
||||||
|
"failedToLoadDocument": "Hujjatni yuklash muvaffaqiyatsiz tugadi",
|
||||||
|
"unexpectedError": "Kutilmagan xatolik yuz berdi.",
|
||||||
|
"documentNumber": "Hujjat №{{id}}",
|
||||||
|
"downloadPdf": "PDFni yuklab olish",
|
||||||
|
"created": "Yaratilgan",
|
||||||
|
"updated": "Yangilangan",
|
||||||
|
"hash": "Hash",
|
||||||
|
"analysisScores": "Tahlil ballari",
|
||||||
|
"documentText": "Hujjat matni",
|
||||||
|
"plagiarismHighlights": "Plagiat belgilari",
|
||||||
|
"plainText": "Oddiy matn",
|
||||||
|
"highlightedHint": "Belgilangan bo‘limlar plagiat ehtimolini ko‘rsatadi",
|
||||||
|
"textStatistics": "Matn statistikalari",
|
||||||
|
"detectionFlags": "Aniqlash bayroqlari",
|
||||||
|
"topWords": "Top so‘zlar",
|
||||||
|
"aiContentDetected": "AI kontent aniqlandi",
|
||||||
|
"possibleAiContent": "Ehtimoliy AI kontent",
|
||||||
|
"likelyOriginal": "Ehtimol original",
|
||||||
|
"aiProbabilityText": "AI ehtimollik balli: {{score}}% — kontent AI model tomonidan yaratilgan yoki yordam berilgan bo‘lishi mumkin.",
|
||||||
|
"resultFooter": "Natija ID #{{id}} · Tahlil qilingan {{date}}",
|
||||||
"noResultAvailable": "Natija mavjud emas.",
|
"noResultAvailable": "Natija mavjud emas.",
|
||||||
"plagiarismResult": "Plagiat natijasi",
|
"plagiarismResult": "Plagiat natijasi",
|
||||||
"wordsChecked": "Tekshirilgan so'zlar",
|
"wordsChecked": "Tekshirilgan so'zlar",
|
||||||
@@ -209,7 +231,7 @@
|
|||||||
"connecting": "Paymega ulanmoqda…",
|
"connecting": "Paymega ulanmoqda…",
|
||||||
"payButton": "Payme orqali to'lash"
|
"payButton": "Payme orqali to'lash"
|
||||||
},
|
},
|
||||||
"unknownUser":"Foydalanuvchi topilmadi",
|
"unknownUser": "Foydalanuvchi topilmadi",
|
||||||
"file":"Fayl",
|
"file": "Fayl",
|
||||||
"upload":"Sertifikatni yuklab olish"
|
"upload": "Sertifikatni yuklab olish"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useParams } from 'next/navigation';
|
||||||
import { links } from '@/shared/request/links';
|
import { links } from '@/shared/request/links';
|
||||||
import { apiRequest } from '@/shared/request/apiRequest';
|
import { apiRequest } from '@/shared/request/apiRequest';
|
||||||
import Sertifikat from './sertifikat';
|
import Sertifikat from './sertifikat';
|
||||||
@@ -69,8 +71,8 @@ function parseHighlightedText(text_res: string): React.ReactNode[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDate(iso: string): string {
|
function formatDate(iso: string, locale: string): string {
|
||||||
return new Date(iso).toLocaleString('uz-UZ', {
|
return new Date(iso).toLocaleString(locale, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
@@ -243,8 +245,9 @@ function LoadingSkeleton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Error State ───────────────────────────────────────────────────────────────
|
// ── Error State ───────────────────────────────────────────────────────────────
|
||||||
|
type TFunction = ReturnType<typeof useTranslations>;
|
||||||
|
|
||||||
function ErrorState({ message }: { message?: string }) {
|
function ErrorState({ message, t }: { message?: string; t: TFunction }) {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-5xl mx-auto px-6 py-20 flex flex-col items-center gap-4 text-center">
|
<div className="max-w-5xl mx-auto px-6 py-20 flex flex-col items-center gap-4 text-center">
|
||||||
<div className="w-14 h-14 rounded-full bg-red-50 flex items-center justify-center">
|
<div className="w-14 h-14 rounded-full bg-red-50 flex items-center justify-center">
|
||||||
@@ -262,9 +265,11 @@ function ErrorState({ message }: { message?: string }) {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-slate-700 font-semibold">Failed to load document</p>
|
<p className="text-slate-700 font-semibold">
|
||||||
|
{t('failedToLoadDocument')}
|
||||||
|
</p>
|
||||||
<p className="text-slate-400 text-sm">
|
<p className="text-slate-400 text-sm">
|
||||||
{message ?? 'An unexpected error occurred.'}
|
{message ?? t('unexpectedError')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -273,6 +278,9 @@ function ErrorState({ message }: { message?: string }) {
|
|||||||
// ── Main Page ─────────────────────────────────────────────────────────────────
|
// ── Main Page ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export default function DocumentDetailPage({ id }: { id: number }) {
|
export default function DocumentDetailPage({ id }: { id: number }) {
|
||||||
|
const t = useTranslations('DetailPage');
|
||||||
|
const { locale } = useParams() as { locale: string };
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: doc,
|
data: doc,
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -305,7 +313,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-50">
|
<div className="min-h-screen bg-slate-50">
|
||||||
<header className="bg-white border-b border-slate-200 h-16.25" />
|
<header className="bg-white border-b border-slate-200 h-16.25" />
|
||||||
<ErrorState message={(error as Error)?.message} />
|
<ErrorState message={(error as Error)?.message} t={t} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -329,9 +337,9 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
low: 'text-emerald-600 bg-emerald-50 border-emerald-200',
|
low: 'text-emerald-600 bg-emerald-50 border-emerald-200',
|
||||||
};
|
};
|
||||||
const aiLabel: Record<string, string> = {
|
const aiLabel: Record<string, string> = {
|
||||||
high: 'AI Content Detected',
|
high: t('aiContentDetected'),
|
||||||
medium: 'Possible AI Content',
|
medium: t('possibleAiContent'),
|
||||||
low: 'Likely Original',
|
low: t('likelyOriginal'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Partition analyze_text dynamically:
|
// Partition analyze_text dynamically:
|
||||||
@@ -377,7 +385,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-[11px] uppercase tracking-widest text-slate-400 font-semibold">
|
<p className="text-[11px] uppercase tracking-widest text-slate-400 font-semibold">
|
||||||
Document #{doc.id}
|
{t('documentNumber', { id: doc.id })}
|
||||||
</p>
|
</p>
|
||||||
<h1 className="text-base font-bold text-slate-800 leading-tight">
|
<h1 className="text-base font-bold text-slate-800 leading-tight">
|
||||||
{doc.title}
|
{doc.title}
|
||||||
@@ -407,7 +415,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Download PDF
|
{t('downloadPdf')}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -431,7 +439,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Created: {formatDate(doc.created_at)}
|
{t('created')}: {formatDate(doc.created_at, locale)}
|
||||||
</span>
|
</span>
|
||||||
<span className="flex items-center gap-1.5">
|
<span className="flex items-center gap-1.5">
|
||||||
<svg
|
<svg
|
||||||
@@ -447,7 +455,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Updated: {formatDate(doc.updated_at)}
|
{t('updated')}: {formatDate(doc.updated_at, locale)}
|
||||||
</span>
|
</span>
|
||||||
{res?.hash && (
|
{res?.hash && (
|
||||||
<span className="flex items-center gap-1.5 font-mono">
|
<span className="flex items-center gap-1.5 font-mono">
|
||||||
@@ -464,14 +472,14 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
d="M7 20l4-16m2 16l4-16M6 9h14M4 15h14"
|
d="M7 20l4-16m2 16l4-16M6 9h14M4 15h14"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Hash: {res.hash}
|
{t('hash')}: {res.hash}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Score Overview ── */}
|
{/* ── Score Overview ── */}
|
||||||
{res && (
|
{res && (
|
||||||
<Section title="Analysis Scores" accent="bg-violet-500">
|
<Section title={t('analysisScores')} accent="bg-violet-500">
|
||||||
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-8">
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-8">
|
||||||
<div className="flex flex-wrap justify-around gap-8">
|
<div className="flex flex-wrap justify-around gap-8">
|
||||||
<ScoreRing
|
<ScoreRing
|
||||||
@@ -511,8 +519,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
<div>
|
<div>
|
||||||
<p className="font-bold text-sm">{aiLabel[aiRisk]}</p>
|
<p className="font-bold text-sm">{aiLabel[aiRisk]}</p>
|
||||||
<p className="text-xs opacity-75 mt-0.5">
|
<p className="text-xs opacity-75 mt-0.5">
|
||||||
AI probability score: <strong>{res.ai}%</strong> — content
|
{t('aiProbabilityText', { score: res.ai })}
|
||||||
may have been generated or assisted by an AI model.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -522,7 +529,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
|
|
||||||
{/* ── Document Text ── */}
|
{/* ── Document Text ── */}
|
||||||
{(res?.text || textRes) && (
|
{(res?.text || textRes) && (
|
||||||
<Section title="Document Text" accent="bg-blue-500">
|
<Section title={t('documentText')} accent="bg-blue-500">
|
||||||
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
|
||||||
<div className="flex border-b border-slate-100">
|
<div className="flex border-b border-slate-100">
|
||||||
{(['highlighted', 'plain'] as const).map((tab) => (
|
{(['highlighted', 'plain'] as const).map((tab) => (
|
||||||
@@ -536,8 +543,8 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{tab === 'highlighted'
|
{tab === 'highlighted'
|
||||||
? 'Plagiarism Highlights'
|
? t('plagiarismHighlights')
|
||||||
: 'Plain Text'}
|
: t('plainText')}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -553,7 +560,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
{activeTab === 'highlighted' && (
|
{activeTab === 'highlighted' && (
|
||||||
<div className="px-6 pb-5 flex items-center gap-2 text-xs text-slate-500">
|
<div className="px-6 pb-5 flex items-center gap-2 text-xs text-slate-500">
|
||||||
<span className="inline-block w-3 h-3 rounded-sm bg-amber-200 border border-amber-300" />
|
<span className="inline-block w-3 h-3 rounded-sm bg-amber-200 border border-amber-300" />
|
||||||
Highlighted fragments indicate potential plagiarism matches
|
{t('highlightedHint')}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -562,7 +569,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
|
|
||||||
{/* ── Text Statistics (all numeric / non-boolean keys) ── */}
|
{/* ── Text Statistics (all numeric / non-boolean keys) ── */}
|
||||||
{statKeys.length > 0 && (
|
{statKeys.length > 0 && (
|
||||||
<Section title="Text Statistics" accent="bg-teal-500">
|
<Section title={t('textStatistics')} accent="bg-teal-500">
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3">
|
||||||
{statKeys.map((key) => (
|
{statKeys.map((key) => (
|
||||||
<StatCard key={key} label={key} value={analyze[key]} />
|
<StatCard key={key} label={key} value={analyze[key]} />
|
||||||
@@ -573,7 +580,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
|
|
||||||
{/* ── Detection Flags (all boolean Yes/No keys) ── */}
|
{/* ── Detection Flags (all boolean Yes/No keys) ── */}
|
||||||
{flagKeys.length > 0 && (
|
{flagKeys.length > 0 && (
|
||||||
<Section title="Detection Flags" accent="bg-rose-500">
|
<Section title={t('detectionFlags')} accent="bg-rose-500">
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||||
{flagKeys.map((key) => {
|
{flagKeys.map((key) => {
|
||||||
const val = analyze[key];
|
const val = analyze[key];
|
||||||
@@ -607,7 +614,7 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
|
|
||||||
{/* ── Top Words (key detected by "топ"/"top" substring) ── */}
|
{/* ── Top Words (key detected by "топ"/"top" substring) ── */}
|
||||||
{topWordsValue && (
|
{topWordsValue && (
|
||||||
<Section title="Top Words" accent="bg-orange-500">
|
<Section title={t('topWords')} accent="bg-orange-500">
|
||||||
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-6">
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-6">
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{topWordsValue
|
{topWordsValue
|
||||||
@@ -639,7 +646,10 @@ export default function DocumentDetailPage({ id }: { id: number }) {
|
|||||||
{/* ── Footer ── */}
|
{/* ── Footer ── */}
|
||||||
{result && (
|
{result && (
|
||||||
<footer className="text-center text-xs text-slate-400 pb-10 mt-4">
|
<footer className="text-center text-xs text-slate-400 pb-10 mt-4">
|
||||||
Result ID #{result.id} · Analyzed {formatDate(result.created_at)}
|
{t('resultFooter', {
|
||||||
|
id: result.id,
|
||||||
|
date: formatDate(result.created_at, locale),
|
||||||
|
})}
|
||||||
</footer>
|
</footer>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export function PlagiarismCheckForm() {
|
|||||||
{submission.status === 'success' && (
|
{submission.status === 'success' && (
|
||||||
<StatusBanner
|
<StatusBanner
|
||||||
status="success"
|
status="success"
|
||||||
message={`Submission successful! ID`}
|
message={t('submissionSuccess')}
|
||||||
onDismiss={resetSubmission}
|
onDismiss={resetSubmission}
|
||||||
dismissText={t('dismiss')}
|
dismissText={t('dismiss')}
|
||||||
/>
|
/>
|
||||||
@@ -177,8 +177,7 @@ export function PlagiarismCheckForm() {
|
|||||||
|
|
||||||
{/* Footer note */}
|
{/* Footer note */}
|
||||||
<p className="text-center text-xs text-stone-400 mt-5">
|
<p className="text-center text-xs text-stone-400 mt-5">
|
||||||
Your document is processed securely and not stored beyond the
|
{t('secureNote')}
|
||||||
analysis period.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user