This commit is contained in:
@@ -1024,7 +1024,6 @@
|
||||
"Unable to start RSVP": "تعذر بدء RSVP",
|
||||
"RSVP not supported for PDF": "RSVP غير مدعوم لملفات PDF",
|
||||
"Select Chapter": "اختر الفصل",
|
||||
"{{number}} WPM": "{{number}} كلمة في الدقيقة",
|
||||
"Context": "السياق",
|
||||
"Ready": "جاهز",
|
||||
"Chapter Progress": "تقدم الفصل",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP शुरू করতে অসমর্থ",
|
||||
"RSVP not supported for PDF": "PDF-এর জন্য RSVP সমর্থিত নয়",
|
||||
"Select Chapter": "অধ্যায় নির্বাচন করুন",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "প্রসঙ্গ",
|
||||
"Ready": "প্রস্তুত",
|
||||
"Chapter Progress": "অধ্যায় অগ্রগতি",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "RSVP འགོ་འཛུགས་མ་ཐུབ།",
|
||||
"RSVP not supported for PDF": "PDF ལ་ RSVP རྒྱབ་སྐྱོར་མེད།",
|
||||
"Select Chapter": "ལེའུ་འདེམས་པ།",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "བརྗོད་དོན།",
|
||||
"Ready": "གྲ་སྒྲིག་ཡོད།",
|
||||
"Chapter Progress": "ལེའུའི་འཕེལ་རིམ།",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP kann nicht gestartet werden",
|
||||
"RSVP not supported for PDF": "RSVP wird für PDF nicht unterstützt",
|
||||
"Select Chapter": "Kapitel auswählen",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Kontext",
|
||||
"Ready": "Bereit",
|
||||
"Chapter Progress": "Kapitelfortschritt",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "Αδυναμία έναρξης RSVP",
|
||||
"RSVP not supported for PDF": "Το RSVP δεν υποστηρίζεται για PDF",
|
||||
"Select Chapter": "Επιλογή Κεφαλαίου",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Πλαίσιο",
|
||||
"Ready": "Έτοιμο",
|
||||
"Chapter Progress": "Πρόοδος Κεφαλαίου",
|
||||
|
||||
@@ -988,7 +988,6 @@
|
||||
"Unable to start RSVP": "No se puede iniciar RSVP",
|
||||
"RSVP not supported for PDF": "RSVP no es compatible con PDF",
|
||||
"Select Chapter": "Seleccionar capítulo",
|
||||
"{{number}} WPM": "{{number}} PPM",
|
||||
"Context": "Contexto",
|
||||
"Ready": "Listo",
|
||||
"Chapter Progress": "Progreso del capítulo",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "قادر به شروع RSVP نیست",
|
||||
"RSVP not supported for PDF": "RSVP برای PDF پشتیبانی نمیشود",
|
||||
"Select Chapter": "انتخاب فصل",
|
||||
"{{number}} WPM": "{{number}} کلمه در دقیقه",
|
||||
"Context": "زمینه",
|
||||
"Ready": "آماده",
|
||||
"Chapter Progress": "پیشرفت فصل",
|
||||
|
||||
@@ -988,7 +988,6 @@
|
||||
"Unable to start RSVP": "Impossible de démarrer RSVP",
|
||||
"RSVP not supported for PDF": "RSVP non pris en charge pour PDF",
|
||||
"Select Chapter": "Sélectionner le chapitre",
|
||||
"{{number}} WPM": "{{number}} MPM",
|
||||
"Context": "Contexte",
|
||||
"Ready": "Prêt",
|
||||
"Chapter Progress": "Progression du chapitre",
|
||||
|
||||
@@ -487,7 +487,6 @@
|
||||
"Select Chapter": "בחר פרק",
|
||||
"Speed Reading": "קריאה מהירה",
|
||||
"Close Speed Reading": "סגור קריאה מהירה",
|
||||
"{{number}} WPM": "{{number}} מילים לדקה",
|
||||
"Context": "הקשר",
|
||||
"Ready": "מוכן",
|
||||
"Chapter Progress": "התקדמות הפרק",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP शुरू करने में असमर्थ",
|
||||
"RSVP not supported for PDF": "PDF के लिए RSVP समर्थित नहीं है",
|
||||
"Select Chapter": "अध्याय चुनें",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "संदर्भ",
|
||||
"Ready": "तैयार",
|
||||
"Chapter Progress": "अध्याय प्रगति",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "Tidak dapat memulai RSVP",
|
||||
"RSVP not supported for PDF": "RSVP tidak didukung untuk PDF",
|
||||
"Select Chapter": "Pilih Bab",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Konteks",
|
||||
"Ready": "Siap",
|
||||
"Chapter Progress": "Kemajuan Bab",
|
||||
|
||||
@@ -988,7 +988,6 @@
|
||||
"Unable to start RSVP": "Impossibile avviare RSVP",
|
||||
"RSVP not supported for PDF": "RSVP non supportato per PDF",
|
||||
"Select Chapter": "Seleziona capitolo",
|
||||
"{{number}} WPM": "{{number}} PPM",
|
||||
"Context": "Contesto",
|
||||
"Ready": "Pronto",
|
||||
"Chapter Progress": "Progresso capitolo",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "RSVPを起動できません",
|
||||
"RSVP not supported for PDF": "PDFはRSVPに対応していません",
|
||||
"Select Chapter": "章を選択",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "コンテキスト",
|
||||
"Ready": "準備完了",
|
||||
"Chapter Progress": "章の進捗",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "RSVP를 시작할 수 없습니다",
|
||||
"RSVP not supported for PDF": "PDF는 RSVP를 지원하지 않습니다",
|
||||
"Select Chapter": "챕터 선택",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "문맥",
|
||||
"Ready": "준비됨",
|
||||
"Chapter Progress": "챕터 진행 상황",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "Tidak dapat memulakan RSVP",
|
||||
"RSVP not supported for PDF": "RSVP tidak disokong untuk PDF",
|
||||
"Select Chapter": "Pilih Bab",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Konteks",
|
||||
"Ready": "Sedia",
|
||||
"Chapter Progress": "Kemajuan Bab",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "Kan RSVP niet starten",
|
||||
"RSVP not supported for PDF": "RSVP niet ondersteund voor PDF",
|
||||
"Select Chapter": "Hoofdstuk selecteren",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Context",
|
||||
"Ready": "Klaar",
|
||||
"Chapter Progress": "Hoofdstukvoortgang",
|
||||
|
||||
@@ -1000,7 +1000,6 @@
|
||||
"Unable to start RSVP": "Nie można uruchomić RSVP",
|
||||
"RSVP not supported for PDF": "RSVP nie jest obsługiwane dla PDF",
|
||||
"Select Chapter": "Wybierz rozdział",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Kontekst",
|
||||
"Ready": "Gotowy",
|
||||
"Chapter Progress": "Postęp rozdziału",
|
||||
|
||||
@@ -988,7 +988,6 @@
|
||||
"Unable to start RSVP": "Não foi possível iniciar o RSVP",
|
||||
"RSVP not supported for PDF": "RSVP não suportado para PDF",
|
||||
"Select Chapter": "Selecionar capítulo",
|
||||
"{{number}} WPM": "{{number}} PPM",
|
||||
"Context": "Contexto",
|
||||
"Ready": "Pronto",
|
||||
"Chapter Progress": "Progresso do capítulo",
|
||||
|
||||
@@ -1000,7 +1000,6 @@
|
||||
"Unable to start RSVP": "Не удалось запустить RSVP",
|
||||
"RSVP not supported for PDF": "RSVP не поддерживается для PDF",
|
||||
"Select Chapter": "Выбрать главу",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Контекст",
|
||||
"Ready": "Готово",
|
||||
"Chapter Progress": "Прогресс главы",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP ආරම්භ කිරීමට නොහැක",
|
||||
"RSVP not supported for PDF": "PDF සඳහා RSVP සහාය නොදක්වයි",
|
||||
"Select Chapter": "පරිච්ඡේදය තෝරන්න",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "සන්දර්භය",
|
||||
"Ready": "සූදානම්",
|
||||
"Chapter Progress": "පරිච්ඡේදයේ ප්රගතිය",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "Kunde inte starta RSVP",
|
||||
"RSVP not supported for PDF": "RSVP stöds inte för PDF",
|
||||
"Select Chapter": "Välj kapitel",
|
||||
"{{number}} WPM": "{{number}} ord/min",
|
||||
"Context": "Sammanhang",
|
||||
"Ready": "Klar",
|
||||
"Chapter Progress": "Kapitelframsteg",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP-ஐத் தொடங்க முடியவில்லை",
|
||||
"RSVP not supported for PDF": "PDF-க்கு RSVP ஆதரவு இல்லை",
|
||||
"Select Chapter": "அத்தியாயத்தைத் தேர்ந்தெடு",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "சூழல்",
|
||||
"Ready": "தயார்",
|
||||
"Chapter Progress": "அத்தியாய முன்னேற்றம்",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "ไม่สามารถเริ่ม RSVP ได้",
|
||||
"RSVP not supported for PDF": "ไม่รองรับ RSVP สำหรับ PDF",
|
||||
"Select Chapter": "เลือกบท",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "บริบท",
|
||||
"Ready": "พร้อม",
|
||||
"Chapter Progress": "ความคืบหน้าของบท",
|
||||
|
||||
@@ -976,7 +976,6 @@
|
||||
"Unable to start RSVP": "RSVP başlatılamadı",
|
||||
"RSVP not supported for PDF": "PDF için RSVP desteklenmiyor",
|
||||
"Select Chapter": "Bölüm Seç",
|
||||
"{{number}} WPM": "{{number}} Kelime/Dakika",
|
||||
"Context": "Bağlam",
|
||||
"Ready": "Hazır",
|
||||
"Chapter Progress": "Bölüm İlerlemesi",
|
||||
|
||||
@@ -1000,7 +1000,6 @@
|
||||
"Unable to start RSVP": "Не вдалося запустити RSVP",
|
||||
"RSVP not supported for PDF": "RSVP не підтримується для PDF",
|
||||
"Select Chapter": "Вибрати розділ",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Контекст",
|
||||
"Ready": "Готово",
|
||||
"Chapter Progress": "Прогрес розділу",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "Không thể bắt đầu RSVP",
|
||||
"RSVP not supported for PDF": "RSVP không được hỗ trợ cho PDF",
|
||||
"Select Chapter": "Chọn chương",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "Ngữ cảnh",
|
||||
"Ready": "Sẵn sàng",
|
||||
"Chapter Progress": "Tiến độ chương",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "无法启动 RSVP",
|
||||
"RSVP not supported for PDF": "PDF 不支持 RSVP",
|
||||
"Select Chapter": "选择章节",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "上下文",
|
||||
"Ready": "准备就绪",
|
||||
"Chapter Progress": "章节进度",
|
||||
|
||||
@@ -964,7 +964,6 @@
|
||||
"Unable to start RSVP": "無法啟動 RSVP",
|
||||
"RSVP not supported for PDF": "PDF 不支援 RSVP",
|
||||
"Select Chapter": "選擇章節",
|
||||
"{{number}} WPM": "{{number}} WPM",
|
||||
"Context": "上下文",
|
||||
"Ready": "準備就緒",
|
||||
"Chapter Progress": "章節進度",
|
||||
|
||||
@@ -55,6 +55,7 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
{ label: _('Title'), value: LibrarySortByType.Title },
|
||||
{ label: _('Author'), value: LibrarySortByType.Author },
|
||||
{ label: _('Format'), value: LibrarySortByType.Format },
|
||||
{ label: _('Series'), value: LibrarySortByType.Series },
|
||||
{ label: _('Date Read'), value: LibrarySortByType.Updated },
|
||||
{ label: _('Date Added'), value: LibrarySortByType.Created },
|
||||
{ label: _('Date Published'), value: LibrarySortByType.Published },
|
||||
|
||||
@@ -105,6 +105,8 @@ export const createBookSorter = (sortBy: string, uiLanguage: string) => (a: Book
|
||||
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
||||
case LibrarySortByType.Format:
|
||||
return a.format.localeCompare(b.format, uiLanguage || navigator.language);
|
||||
case LibrarySortByType.Series:
|
||||
return (a.metadata?.seriesIndex || 0) - (b.metadata?.seriesIndex || 0);
|
||||
case LibrarySortByType.Published:
|
||||
const aPublished = a.metadata?.published || '0001-01-01';
|
||||
const bPublished = b.metadata?.published || '0001-01-01';
|
||||
|
||||
@@ -250,7 +250,7 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
<span className='font-bold'>{_('Series')}</span>
|
||||
<p className='text-neutral-content text-sm'>{metadata?.series || _('Unknown')}</p>
|
||||
</div>
|
||||
<div className='overflow-hidden'>
|
||||
<div className='overflow-hidden pe-1 text-end'>
|
||||
<span className='font-bold'>{_('Series Index')}</span>
|
||||
<p className='text-neutral-content text-sm'>
|
||||
{metadata?.seriesIndex || _('Unknown')}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BookFormat } from '@/types/book';
|
||||
import { Contributor, Identifier, LanguageMap } from '@/utils/book';
|
||||
import { Collection, Contributor, Identifier, LanguageMap } from '@/utils/book';
|
||||
import * as epubcfi from 'foliate-js/epubcfi.js';
|
||||
|
||||
export const CFI = epubcfi;
|
||||
@@ -47,6 +47,10 @@ export type BookMetadata = {
|
||||
subject?: string | string[] | Contributor;
|
||||
identifier?: string;
|
||||
altIdentifier?: string | string[] | Identifier;
|
||||
belongsTo?: {
|
||||
collection?: Array<Collection> | Collection;
|
||||
series?: Array<Collection> | Collection;
|
||||
};
|
||||
|
||||
subtitle?: string;
|
||||
series?: string;
|
||||
|
||||
@@ -408,12 +408,22 @@ export abstract class BaseAppService implements AppService {
|
||||
sourceTitle: formatTitle(loadedBook.metadata.title),
|
||||
primaryLanguage,
|
||||
author: formatAuthors(loadedBook.metadata.author, primaryLanguage),
|
||||
metadata: loadedBook.metadata,
|
||||
createdAt: existingBook ? existingBook.createdAt : Date.now(),
|
||||
uploadedAt: existingBook ? existingBook.uploadedAt : null,
|
||||
deletedAt: transient ? Date.now() : null,
|
||||
downloadedAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
// update series info from metadata
|
||||
if (book.metadata?.belongsTo?.series) {
|
||||
const belongsTo = book.metadata.belongsTo.series;
|
||||
const series = Array.isArray(belongsTo) ? belongsTo[0] : belongsTo;
|
||||
if (series) {
|
||||
book.metadata.series = formatTitle(series.name);
|
||||
book.metadata.seriesIndex = parseFloat(series.position || '0');
|
||||
}
|
||||
}
|
||||
// update book metadata when reimporting the same book
|
||||
if (existingBook) {
|
||||
existingBook.format = book.format;
|
||||
@@ -421,6 +431,7 @@ export abstract class BaseAppService implements AppService {
|
||||
existingBook.sourceTitle = existingBook.sourceTitle ?? book.sourceTitle;
|
||||
existingBook.author = existingBook.author ?? book.author;
|
||||
existingBook.primaryLanguage = existingBook.primaryLanguage ?? book.primaryLanguage;
|
||||
existingBook.metadata = book.metadata;
|
||||
existingBook.downloadedAt = Date.now();
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,16 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
|
||||
const primaryLanguage = getPrimaryLanguage(bookDoc.metadata.language);
|
||||
book.primaryLanguage = book.primaryLanguage ?? primaryLanguage;
|
||||
book.metadata = book.metadata ?? bookDoc.metadata;
|
||||
|
||||
// Update series info from metadata
|
||||
if (bookDoc.metadata.belongsTo?.series) {
|
||||
const belongsTo = bookDoc.metadata.belongsTo.series;
|
||||
const series = Array.isArray(belongsTo) ? belongsTo[0] : belongsTo;
|
||||
if (series) {
|
||||
book.metadata.series = formatTitle(series.name);
|
||||
book.metadata.seriesIndex = parseFloat(series.position || '0');
|
||||
}
|
||||
}
|
||||
// TODO: uncomment this when we can ensure metaHash is correctly generated for all books
|
||||
// book.metaHash = book.metaHash ?? getMetadataHash(bookDoc.metadata);
|
||||
book.metaHash = getMetadataHash(bookDoc.metadata);
|
||||
|
||||
@@ -13,6 +13,7 @@ export const LibrarySortByType = {
|
||||
Author: 'author',
|
||||
Updated: 'updated',
|
||||
Created: 'created',
|
||||
Series: 'series',
|
||||
Size: 'size',
|
||||
Format: 'format',
|
||||
Published: 'published',
|
||||
|
||||
@@ -56,6 +56,11 @@ export interface Contributor {
|
||||
name: LanguageMap;
|
||||
}
|
||||
|
||||
export interface Collection {
|
||||
name: string;
|
||||
position?: string;
|
||||
}
|
||||
|
||||
const formatLanguageMap = (x: string | LanguageMap, defaultLang = false): string => {
|
||||
const userLang = getUserLang();
|
||||
if (!x) return '';
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: e304090ce2...21293c82b8
Reference in New Issue
Block a user