diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index c1609ea8..f2689668 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -622,5 +622,6 @@ "Opacity": "شفافية", "Size": "حجم", "Cover": "غطاء", - "Contain": "احتواء" + "Contain": "احتواء", + "{{number}} pages left in chapter": "تبقّت {{number}} صفحات في هذا الفصل" } diff --git a/apps/readest-app/public/locales/bn/translation.json b/apps/readest-app/public/locales/bn/translation.json index 464ac116..065ae1ce 100644 --- a/apps/readest-app/public/locales/bn/translation.json +++ b/apps/readest-app/public/locales/bn/translation.json @@ -606,5 +606,6 @@ "Opacity": "স্বচ্ছতা", "Size": "আকার", "Cover": "ঢাকা", - "Contain": "ধারণ" + "Contain": "ধারণ", + "{{number}} pages left in chapter": "অধ্যায়ে {{number}} পৃষ্ঠা বাকি" } diff --git a/apps/readest-app/public/locales/bo/translation.json b/apps/readest-app/public/locales/bo/translation.json index 49b5528b..ed654a66 100644 --- a/apps/readest-app/public/locales/bo/translation.json +++ b/apps/readest-app/public/locales/bo/translation.json @@ -602,5 +602,6 @@ "Opacity": "སྤོ་སྐོར་གྱི་འོད་ཟེར།", "Size": "ཨང་", "Cover": "དེབ་གྱི་སྤྱོད་བྱས་མ་ཐུབ།", - "Contain": "འབྱོར་བ།" + "Contain": "འབྱོར་བ།", + "{{number}} pages left in chapter": "དོན་ཚན་ནང་ཤོག་ཨང་ {{number}} ལོག་གི་འདུག།" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 14cfd48c..a9081a31 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -606,5 +606,6 @@ "Opacity": "Opazität", "Size": "Größe", "Cover": "Cover", - "Contain": "Inhalt" + "Contain": "Inhalt", + "{{number}} pages left in chapter": "{{number}} Seiten verbleibend im Kapitel" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index e47424ab..f29bc84d 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -606,5 +606,6 @@ "Opacity": "Αδιαφάνεια", "Size": "Μέγεθος", "Cover": "Εξώφυλλο", - "Contain": "Περιέχει" + "Contain": "Περιέχει", + "{{number}} pages left in chapter": "Μένουν {{number}} σελίδες στο κεφάλαιο" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index d8d38782..917a5d78 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -610,5 +610,6 @@ "Opacity": "Opacidad", "Size": "Tamaño", "Cover": "Cubierta", - "Contain": "Contener" + "Contain": "Contener", + "{{number}} pages left in chapter": "{{number}} páginas restantes en el capítulo" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 8dcf77d8..6858c312 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -610,5 +610,6 @@ "Opacity": "Opacité", "Size": "Taille", "Cover": "Couverture", - "Contain": "Contenir" + "Contain": "Contenir", + "{{number}} pages left in chapter": "{{number}} pages restantes dans le chapitre" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 11201f96..5c907db8 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -606,5 +606,6 @@ "Opacity": "अस्पष्टता", "Size": "आकार", "Cover": "कवर", - "Contain": "समाहित करें" + "Contain": "समाहित करें", + "{{number}} pages left in chapter": "इस अध्याय में {{number}} पृष्ठ शेष हैं" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 40edca82..eaa7deff 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -602,5 +602,6 @@ "Opacity": "Keburaman", "Size": "Ukuran", "Cover": "Sampul", - "Contain": "Mengandung" + "Contain": "Mengandung", + "{{number}} pages left in chapter": "{{number}} halaman tersisa di bab" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 722d733d..01fa7ded 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -610,5 +610,6 @@ "Opacity": "Opacità", "Size": "Dimensione", "Cover": "Copertura", - "Contain": "Contenere" + "Contain": "Contenere", + "{{number}} pages left in chapter": "{{number}} pagine rimaste nel capitolo" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index b9b08493..2d0b24f9 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -602,5 +602,6 @@ "Opacity": "不透明度", "Size": "サイズ", "Cover": "カバー", - "Contain": "含む" + "Contain": "含む", + "{{number}} pages left in chapter": "章に{{number}}ページ残り" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index dea64344..4ab5e8b4 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -602,5 +602,6 @@ "Opacity": "불투명도", "Size": "크기", "Cover": "표지", - "Contain": "포함" + "Contain": "포함", + "{{number}} pages left in chapter": "남은 페이지 {{number}}장" } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index 56268b89..50268f8b 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -606,5 +606,6 @@ "Opacity": "Doorzichtigheid", "Size": "Grootte", "Cover": "Omslag", - "Contain": "Bevatten" + "Contain": "Bevatten", + "{{number}} pages left in chapter": "Nog {{number}} pagina’s in hoofdstuk" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 0fa637fe..f28b3a60 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -614,5 +614,6 @@ "Opacity": "Przezroczystość", "Size": "Rozmiar", "Cover": "Okładka", - "Contain": "Zawierać" + "Contain": "Zawierać", + "{{number}} pages left in chapter": "Pozostało {{number}} stron w rozdziale" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 64b12c96..e0b97e12 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -610,5 +610,6 @@ "Opacity": "Opacidade", "Size": "Tamanho", "Cover": "Capa", - "Contain": "Contém" + "Contain": "Contém", + "{{number}} pages left in chapter": "Faltam {{number}} páginas neste capítulo" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 2726349b..3b0d6706 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -614,5 +614,6 @@ "Opacity": "Непрозрачность", "Size": "Размер", "Cover": "Обложка", - "Contain": "Содержать" + "Contain": "Содержать", + "{{number}} pages left in chapter": "Осталось {{number}} страниц в главе" } diff --git a/apps/readest-app/public/locales/si/translation.json b/apps/readest-app/public/locales/si/translation.json index c5728fb5..a3f855ff 100644 --- a/apps/readest-app/public/locales/si/translation.json +++ b/apps/readest-app/public/locales/si/translation.json @@ -606,5 +606,6 @@ "Opacity": "පැහැදිලිත්වය", "Size": "ප්‍රමාණය", "Cover": "ආවරණය", - "Contain": "අඩංගු වන්න" + "Contain": "අඩංගු වන්න", + "{{number}} pages left in chapter": "පරිච්ඡේදයේ පිටු {{number}} ඉතිරිව ඇත" } diff --git a/apps/readest-app/public/locales/sv/translation.json b/apps/readest-app/public/locales/sv/translation.json index 518ddce9..c229bf79 100644 --- a/apps/readest-app/public/locales/sv/translation.json +++ b/apps/readest-app/public/locales/sv/translation.json @@ -606,5 +606,6 @@ "Opacity": "Opacitet", "Size": "Storlek", "Cover": "Omslag", - "Contain": "Innehålla" + "Contain": "Innehålla", + "{{number}} pages left in chapter": "{{number}} sidor kvar i kapitlet" } diff --git a/apps/readest-app/public/locales/ta/translation.json b/apps/readest-app/public/locales/ta/translation.json index a73fc7d2..326c6cfa 100644 --- a/apps/readest-app/public/locales/ta/translation.json +++ b/apps/readest-app/public/locales/ta/translation.json @@ -606,5 +606,6 @@ "Opacity": "பார்வை", "Size": "அளவு", "Cover": "மூடு", - "Contain": "அடங்கும்" + "Contain": "அடங்கும்", + "{{number}} pages left in chapter": "அத்தியாயத்தில் {{number}} பக்கங்கள் மீதமுள்ளன" } diff --git a/apps/readest-app/public/locales/th/translation.json b/apps/readest-app/public/locales/th/translation.json index 2c9938dc..996b4d2a 100644 --- a/apps/readest-app/public/locales/th/translation.json +++ b/apps/readest-app/public/locales/th/translation.json @@ -602,5 +602,6 @@ "Opacity": "ความโปร่งใส", "Size": "ขนาด", "Cover": "ปก", - "Contain": "บรรจุ" + "Contain": "บรรจุ", + "{{number}} pages left in chapter": "เหลือ {{number}} หน้าในบท" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index e7fce096..3576b330 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -606,5 +606,6 @@ "Opacity": "Opaklık", "Size": "Boyut", "Cover": "Kapak", - "Contain": "İçerir" + "Contain": "İçerir", + "{{number}} pages left in chapter": "Bu bölümde {{number}} sayfa kaldı" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 6bf1d50e..2168a062 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -614,5 +614,6 @@ "Opacity": "Непрозорість", "Size": "Розмір", "Cover": "Обкладинка", - "Contain": "Вміщати" + "Contain": "Вміщати", + "{{number}} pages left in chapter": "Залишилось {{number}} сторінок у розділі" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index 3d1e961b..50b295a9 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -602,5 +602,6 @@ "Opacity": "Độ mờ", "Size": "Kích thước", "Cover": "Bìa", - "Contain": "Chứa" + "Contain": "Chứa", + "{{number}} pages left in chapter": "Còn {{number}} trang trong chương" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 1080b3f3..7802850c 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -601,6 +601,7 @@ "Import Image": "导入图片", "Opacity": "不透明度", "Size": "大小", - "Cover": "封面", - "Contain": "包含" + "Cover": "覆盖", + "Contain": "适应", + "{{number}} pages left in chapter": "本章剩余{{number}}页" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index e9e39357..4fad7913 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -601,6 +601,7 @@ "Import Image": "匯入圖片", "Opacity": "不透明度", "Size": "大小", - "Cover": "封面", - "Contain": "包含" + "Cover": "覆蓋", + "Contain": "適應", + "{{number}} pages left in chapter": "本章剩餘{{number}}頁" } diff --git a/apps/readest-app/src/app/reader/components/ProgressInfo.tsx b/apps/readest-app/src/app/reader/components/ProgressInfo.tsx index df892333..056f61dc 100644 --- a/apps/readest-app/src/app/reader/components/ProgressInfo.tsx +++ b/apps/readest-app/src/app/reader/components/ProgressInfo.tsx @@ -6,7 +6,7 @@ import { useEnv } from '@/context/EnvContext'; import { useReaderStore } from '@/store/readerStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useBookDataStore } from '@/store/bookDataStore'; -import { formatReadingProgress } from '@/utils/progress'; +import { formatNumber, formatProgress } from '@/utils/progress'; interface PageInfoProps { bookKey: string; @@ -40,24 +40,34 @@ const ProgressInfoView: React.FC = ({ const isVertical = viewSettings.vertical; const { progressStyle: readingProgressStyle } = viewSettings; - const formatTemplate = + const template = readingProgressStyle === 'fraction' ? isVertical ? '{current} · {total}' : '{current} / {total}' : '{percent}%'; - const pageProgress = bookData?.isFixedLayout ? section : pageinfo; - const progressInfo = bookData?.isFixedLayout - ? formatReadingProgress(pageProgress?.current, pageProgress?.total, formatTemplate) - : formatReadingProgress(pageProgress?.current, pageProgress?.total, formatTemplate); + const lang = localStorage?.getItem('i18nextLng') || ''; + const localize = isVertical && lang.toLowerCase().startsWith('zh'); + const progress = bookData?.isFixedLayout ? section : pageinfo; + const progressInfo = formatProgress(progress?.current, progress?.total, template, localize, lang); const timeLeft = timeinfo - ? _('{{time}} min left in chapter', { time: Math.round(timeinfo.section) }) + ? _('{{time}} min left in chapter', { + time: formatNumber(Math.round(timeinfo.section), localize, lang), + }) : ''; const { page = 0, pages = 0 } = view?.renderer || {}; const pageLeft = - pages - 1 > page ? _('{{count}} pages left in chapter', { count: pages - 1 - page }) : ''; + pages - 1 > page + ? localize + ? _('{{number}} pages left in chapter', { + number: formatNumber(pages - page - 1, localize, lang), + }) + : _('{{count}} pages left in chapter', { + count: pages - page - 1, + }) + : ''; return (
= ({ isScrolled && !isVertical && 'bg-base-100', )} aria-label={[ - pageProgress + progress ? _('On {{current}} of {{total}} page', { - current: pageProgress.current + 1, - total: pageProgress.total, + current: progress.current + 1, + total: progress.total, }) : '', timeLeft, @@ -99,7 +109,7 @@ const ProgressInfoView: React.FC = ({
); diff --git a/apps/readest-app/src/utils/number.ts b/apps/readest-app/src/utils/number.ts new file mode 100644 index 00000000..e06baaa7 --- /dev/null +++ b/apps/readest-app/src/utils/number.ts @@ -0,0 +1,52 @@ +export const localizeNumber = (num: number, language: string, isIndex = false): string => { + const lang = language.toLowerCase(); + const isChinese = lang.startsWith('zh'); + if (!isChinese) { + return num.toString(); + } + + const isTraditional = lang.includes('tw') || lang.includes('hk'); + + const baseDigits = isTraditional ? '零壹貳叁肆伍陸柒捌玖' : '零一二三四五六七八九'; + const zeroChar = isIndex ? '〇' : '零'; + const digits = baseDigits.replace('零', zeroChar); + const units = isTraditional + ? ['', '拾', '佰', '仟', '萬', '億'] + : ['', '十', '百', '千', '万', '亿']; + + const str = String(num); + const len = str.length; + let result = ''; + for (let i = 0; i < len; i++) { + const n = Number(str[i]); + const pos = len - i - 1; + if (n !== 0) { + result += digits[n]! + units[pos % 4]!; + } else if (!result.endsWith(zeroChar) && i < len - 1) { + result += zeroChar; + } + if (pos === 4) result += units[4]; + if (pos === 8) result += units[5]; + } + result = result + .replace(new RegExp(`${zeroChar}+$`), '') + .replace(`${zeroChar}萬`, '萬') + .replace(`${zeroChar}万`, '万') + .replace(new RegExp(`${zeroChar}+`, 'g'), zeroChar); + + if (!isIndex) { + if (isTraditional) { + result = result.replace( + /^貳$|(? 0 && current >= 0) { + const currentStr = localize ? localizeNumber(current + 1, language, true) : String(current + 1); + const totalStr = localize ? localizeNumber(total, language, true) : String(total); return template - .replace('{current}', String(current + 1)) - .replace('{total}', String(total)) + .replace('{current}', currentStr) + .replace('{total}', totalStr) .replace('{percent}', (((current + 1) / total) * 100).toFixed(1)); } else { return ''; } } + +export function formatNumber( + number: number | undefined, + localize: boolean = false, + language: string = 'en', +): string { + if (number === undefined || number < 0) { + return ''; + } + return localize ? localizeNumber(number, language) : String(number); +}