Merge branch 'master' of https://github.com/jpirnay/crosspoint-reader into feat-page-overlay
This commit is contained in:
@@ -274,11 +274,13 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
}
|
||||
|
||||
bool BookMetadataCache::cleanupTmpFiles() const {
|
||||
if (Storage.exists((cachePath + tmpSpineBinFile).c_str())) {
|
||||
Storage.remove((cachePath + tmpSpineBinFile).c_str());
|
||||
const auto spineBinFile = cachePath + tmpSpineBinFile;
|
||||
if (Storage.exists(spineBinFile.c_str())) {
|
||||
Storage.remove(spineBinFile.c_str());
|
||||
}
|
||||
if (Storage.exists((cachePath + tmpTocBinFile).c_str())) {
|
||||
Storage.remove((cachePath + tmpTocBinFile).c_str());
|
||||
const auto tocBinFile = cachePath + tmpTocBinFile;
|
||||
if (Storage.exists(tocBinFile.c_str())) {
|
||||
Storage.remove(tocBinFile.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -144,9 +144,12 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
|
||||
return {};
|
||||
}
|
||||
|
||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
||||
// Calculate first line indent (only for left/justified text).
|
||||
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||
// it is structural (positions the bullet/marker), not decorative.
|
||||
const int firstLineIndent =
|
||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 0;
|
||||
@@ -275,9 +278,12 @@ std::vector<size_t> ParsedText::computeHyphenatedLineBreaks(const GfxRenderer& r
|
||||
const int pageWidth, const int spaceWidth,
|
||||
std::vector<uint16_t>& wordWidths,
|
||||
std::vector<bool>& continuesVec) {
|
||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
||||
// Calculate first line indent (only for left/justified text).
|
||||
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||
// it is structural (positions the bullet/marker), not decorative.
|
||||
const int firstLineIndent =
|
||||
blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 0;
|
||||
@@ -443,10 +449,13 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
||||
const size_t lastBreakAt = breakIndex > 0 ? lineBreakIndices[breakIndex - 1] : 0;
|
||||
const size_t lineWordCount = lineBreak - lastBreakAt;
|
||||
|
||||
// Calculate first line indent (only for left/justified text without extra paragraph spacing)
|
||||
// Calculate first line indent (only for left/justified text).
|
||||
// Positive text-indent (paragraph indent) is suppressed when extraParagraphSpacing is on.
|
||||
// Negative text-indent (hanging indent, e.g. margin-left:3em; text-indent:-1em) always applies —
|
||||
// it is structural (positions the bullet/marker), not decorative.
|
||||
const bool isFirstLine = breakIndex == 0;
|
||||
const int firstLineIndent =
|
||||
isFirstLine && blockStyle.textIndent > 0 && !extraParagraphSpacing &&
|
||||
isFirstLine && blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) &&
|
||||
(blockStyle.alignment == CssTextAlign::Justify || blockStyle.alignment == CssTextAlign::Left)
|
||||
? blockStyle.textIndent
|
||||
: 0;
|
||||
@@ -485,8 +494,9 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
||||
? spareSpace / static_cast<int>(actualGapCount)
|
||||
: 0;
|
||||
|
||||
// Calculate initial x position (first line starts at indent for left/justified text)
|
||||
auto xpos = static_cast<uint16_t>(firstLineIndent);
|
||||
// Calculate initial x position (first line starts at indent for left/justified text;
|
||||
// may be negative for hanging indents, e.g. margin-left:3em; text-indent:-1em).
|
||||
auto xpos = static_cast<int16_t>(firstLineIndent);
|
||||
if (blockStyle.alignment == CssTextAlign::Right) {
|
||||
xpos = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
|
||||
} else if (blockStyle.alignment == CssTextAlign::Center) {
|
||||
@@ -495,7 +505,7 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
|
||||
|
||||
// Pre-calculate X positions for words
|
||||
// Continuation words attach to the previous word with no space before them
|
||||
std::vector<uint16_t> lineXPos;
|
||||
std::vector<int16_t> lineXPos;
|
||||
lineXPos.reserve(lineWordCount);
|
||||
|
||||
for (size_t wordIdx = 0; wordIdx < lineWordCount; wordIdx++) {
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
#include "parsers/ChapterHtmlSlimParser.h"
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t SECTION_FILE_VERSION = 14;
|
||||
constexpr uint8_t SECTION_FILE_VERSION = 17;
|
||||
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(uint8_t) +
|
||||
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) +
|
||||
sizeof(uint32_t);
|
||||
sizeof(uint8_t) + sizeof(uint32_t);
|
||||
} // namespace
|
||||
|
||||
uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
||||
@@ -36,7 +36,7 @@ uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
||||
void Section::writeSectionFileHeader(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const bool embeddedStyle) {
|
||||
const bool embeddedStyle, const uint8_t imageRendering) {
|
||||
if (!file) {
|
||||
LOG_DBG("SCT", "File not open for writing header");
|
||||
return;
|
||||
@@ -44,7 +44,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
||||
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
||||
sizeof(extraParagraphSpacing) + sizeof(paragraphAlignment) + sizeof(viewportWidth) +
|
||||
sizeof(viewportHeight) + sizeof(pageCount) + sizeof(hyphenationEnabled) +
|
||||
sizeof(embeddedStyle) + sizeof(uint32_t),
|
||||
sizeof(embeddedStyle) + sizeof(imageRendering) + sizeof(uint32_t),
|
||||
"Header size mismatch");
|
||||
serialization::writePod(file, SECTION_FILE_VERSION);
|
||||
serialization::writePod(file, fontId);
|
||||
@@ -55,13 +55,15 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
||||
serialization::writePod(file, viewportHeight);
|
||||
serialization::writePod(file, hyphenationEnabled);
|
||||
serialization::writePod(file, embeddedStyle);
|
||||
serialization::writePod(file, imageRendering);
|
||||
serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written)
|
||||
serialization::writePod(file, static_cast<uint32_t>(0)); // Placeholder for LUT offset
|
||||
}
|
||||
|
||||
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle) {
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle,
|
||||
const uint8_t imageRendering) {
|
||||
if (!Storage.openFileForRead("SCT", filePath, file)) {
|
||||
return false;
|
||||
}
|
||||
@@ -84,6 +86,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
uint8_t fileParagraphAlignment;
|
||||
bool fileHyphenationEnabled;
|
||||
bool fileEmbeddedStyle;
|
||||
uint8_t fileImageRendering;
|
||||
serialization::readPod(file, fileFontId);
|
||||
serialization::readPod(file, fileLineCompression);
|
||||
serialization::readPod(file, fileExtraParagraphSpacing);
|
||||
@@ -92,11 +95,13 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
serialization::readPod(file, fileViewportHeight);
|
||||
serialization::readPod(file, fileHyphenationEnabled);
|
||||
serialization::readPod(file, fileEmbeddedStyle);
|
||||
serialization::readPod(file, fileImageRendering);
|
||||
|
||||
if (fontId != fileFontId || lineCompression != fileLineCompression ||
|
||||
extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment ||
|
||||
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) {
|
||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle ||
|
||||
imageRendering != fileImageRendering) {
|
||||
file.close();
|
||||
LOG_ERR("SCT", "Deserialization failed: Parameters do not match");
|
||||
clearCache();
|
||||
@@ -129,7 +134,7 @@ bool Section::clearCache() const {
|
||||
bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle,
|
||||
const std::function<void()>& popupFn) {
|
||||
const uint8_t imageRendering, const std::function<void()>& popupFn) {
|
||||
const auto localPath = epub->getSpineItem(spineIndex).href;
|
||||
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
||||
|
||||
@@ -179,7 +184,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
return false;
|
||||
}
|
||||
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
||||
viewportHeight, hyphenationEnabled, embeddedStyle);
|
||||
viewportHeight, hyphenationEnabled, embeddedStyle, imageRendering);
|
||||
std::vector<uint32_t> lut = {};
|
||||
|
||||
// Derive the content base directory and image cache path prefix for the parser
|
||||
@@ -201,7 +206,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
epub, tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
|
||||
viewportHeight, hyphenationEnabled,
|
||||
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
|
||||
embeddedStyle, contentBase, imageBasePath, popupFn, cssParser);
|
||||
embeddedStyle, contentBase, imageBasePath, imageRendering, popupFn, cssParser);
|
||||
Hyphenator::setPreferredLanguage(epub->getLanguage());
|
||||
success = visitor.parseAndBuildPages();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class Section {
|
||||
|
||||
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
|
||||
bool embeddedStyle);
|
||||
bool embeddedStyle, uint8_t imageRendering);
|
||||
uint32_t onPageComplete(std::unique_ptr<Page> page);
|
||||
|
||||
public:
|
||||
@@ -30,10 +30,11 @@ class Section {
|
||||
filePath(epub->getCachePath() + "/sections/" + std::to_string(spineIndex) + ".bin") {}
|
||||
~Section() = default;
|
||||
bool loadSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle);
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle,
|
||||
uint8_t imageRendering);
|
||||
bool clearCache() const;
|
||||
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle,
|
||||
const std::function<void()>& popupFn = nullptr);
|
||||
uint8_t imageRendering, const std::function<void()>& popupFn = nullptr);
|
||||
std::unique_ptr<Page> loadPageFromSectionFile();
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ bool TextBlock::serialize(FsFile& file) const {
|
||||
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||
uint16_t wc;
|
||||
std::vector<std::string> words;
|
||||
std::vector<uint16_t> wordXpos;
|
||||
std::vector<int16_t> wordXpos;
|
||||
std::vector<EpdFontFamily::Style> wordStyles;
|
||||
BlockStyle blockStyle;
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
class TextBlock final : public Block {
|
||||
private:
|
||||
std::vector<std::string> words;
|
||||
std::vector<uint16_t> wordXpos;
|
||||
std::vector<int16_t> wordXpos;
|
||||
std::vector<EpdFontFamily::Style> wordStyles;
|
||||
BlockStyle blockStyle;
|
||||
|
||||
public:
|
||||
explicit TextBlock(std::vector<std::string> words, std::vector<uint16_t> word_xpos,
|
||||
explicit TextBlock(std::vector<std::string> words, std::vector<int16_t> word_xpos,
|
||||
std::vector<EpdFontFamily::Style> word_styles, const BlockStyle& blockStyle = BlockStyle())
|
||||
: words(std::move(words)),
|
||||
wordXpos(std::move(word_xpos)),
|
||||
|
||||
@@ -243,7 +243,14 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
}
|
||||
}
|
||||
|
||||
if (!src.empty()) {
|
||||
// imageRendering: 0=display, 1=placeholder (alt text only), 2=suppress entirely
|
||||
if (self->imageRendering == 2) {
|
||||
self->skipUntilDepth = self->depth;
|
||||
self->depth += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!src.empty() && self->imageRendering != 1) {
|
||||
LOG_DBG("EHP", "Found image: src=%s", src.c_str());
|
||||
|
||||
{
|
||||
@@ -278,8 +285,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
const float emSize =
|
||||
static_cast<float>(self->renderer.getLineHeight(self->fontId)) * self->lineCompression;
|
||||
const float emSize = static_cast<float>(self->renderer.getFontAscenderSize(self->fontId));
|
||||
CssStyle imgStyle = self->cssParser ? self->cssParser->resolveStyle("img", classAttr) : CssStyle{};
|
||||
// Merge inline style (e.g. style="height: 2em") so it overrides stylesheet rules
|
||||
if (!styleAttr.empty()) {
|
||||
@@ -505,7 +511,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
}
|
||||
}
|
||||
|
||||
const float emSize = static_cast<float>(self->renderer.getLineHeight(self->fontId)) * self->lineCompression;
|
||||
const float emSize = static_cast<float>(self->renderer.getFontAscenderSize(self->fontId));
|
||||
const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle(
|
||||
cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth);
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class ChapterHtmlSlimParser {
|
||||
bool hyphenationEnabled;
|
||||
const CssParser* cssParser;
|
||||
bool embeddedStyle;
|
||||
uint8_t imageRendering;
|
||||
std::string contentBase;
|
||||
std::string imageBasePath;
|
||||
int imageCounter = 0;
|
||||
@@ -94,8 +95,8 @@ class ChapterHtmlSlimParser {
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||
const bool embeddedStyle, const std::string& contentBase,
|
||||
const std::string& imageBasePath, const std::function<void()>& popupFn = nullptr,
|
||||
const CssParser* cssParser = nullptr)
|
||||
const std::string& imageBasePath, const uint8_t imageRendering = 0,
|
||||
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
|
||||
|
||||
: epub(epub),
|
||||
filepath(filepath),
|
||||
@@ -111,6 +112,7 @@ class ChapterHtmlSlimParser {
|
||||
popupFn(popupFn),
|
||||
cssParser(cssParser),
|
||||
embeddedStyle(embeddedStyle),
|
||||
imageRendering(imageRendering),
|
||||
contentBase(contentBase),
|
||||
imageBasePath(imageBasePath) {}
|
||||
|
||||
|
||||
@@ -36,12 +36,10 @@ ContentOpfParser::~ContentOpfParser() {
|
||||
if (tempItemStore) {
|
||||
tempItemStore.close();
|
||||
}
|
||||
if (Storage.exists((cachePath + itemCacheFile).c_str())) {
|
||||
Storage.remove((cachePath + itemCacheFile).c_str());
|
||||
const auto itemCachePath = cachePath + itemCacheFile;
|
||||
if (Storage.exists(itemCachePath.c_str())) {
|
||||
Storage.remove(itemCachePath.c_str());
|
||||
}
|
||||
itemIndex.clear();
|
||||
itemIndex.shrink_to_fit();
|
||||
useItemIndex = false;
|
||||
}
|
||||
|
||||
size_t ContentOpfParser::write(const uint8_t data) { return write(&data, 1); }
|
||||
|
||||
@@ -92,6 +92,10 @@ STR_STATUS_BAR: "Status Bar"
|
||||
STR_HIDE_BATTERY: "Hide Battery %"
|
||||
STR_EXTRA_SPACING: "Extra Paragraph Spacing"
|
||||
STR_TEXT_AA: "Text Anti-Aliasing"
|
||||
STR_IMAGES: "Images"
|
||||
STR_IMAGES_DISPLAY: "Display"
|
||||
STR_IMAGES_PLACEHOLDER: "Placeholder"
|
||||
STR_IMAGES_SUPPRESS: "Suppress"
|
||||
STR_SHORT_PWR_BTN: "Short Power Button Click"
|
||||
STR_ORIENTATION: "Reading Orientation"
|
||||
STR_FRONT_BTN_LAYOUT: "Front Button Layout"
|
||||
|
||||
@@ -63,7 +63,7 @@ STR_MAC_ADDRESS: "MAC-Adresse:"
|
||||
STR_CHECKING_WIFI: "WLAN prüfen…"
|
||||
STR_ENTER_WIFI_PASSWORD: "WLAN-Passwort eingeben"
|
||||
STR_ENTER_TEXT: "Text eingeben"
|
||||
STR_TO_PREFIX: "bis"
|
||||
STR_TO_PREFIX: "mit "
|
||||
STR_CALIBRE_DISCOVERING: "Calibre finden..."
|
||||
STR_CALIBRE_CONNECTING_TO: "Verbinden mit"
|
||||
STR_CALIBRE_CONNECTED_TO: "Verbunden mit"
|
||||
@@ -120,7 +120,7 @@ STR_SELECT_WALLPAPER: "Bildauswahl Standby"
|
||||
STR_CLEAR_READING_CACHE: "Lese-Cache leeren"
|
||||
STR_CALIBRE: "Calibre"
|
||||
STR_USERNAME: "Benutzername"
|
||||
STR_PASSWORD: "Passwort nötig"
|
||||
STR_PASSWORD: "Passwort"
|
||||
STR_SYNC_SERVER_URL: "Sync-Server-URL"
|
||||
STR_DOCUMENT_MATCHING: "Dateizuordnung"
|
||||
STR_AUTHENTICATE: "Authentifizieren"
|
||||
@@ -169,7 +169,7 @@ STR_FRONT_LAYOUT_BCLR: "Zurück, Bst, L, R"
|
||||
STR_FRONT_LAYOUT_LRBC: "L, R, Zurück, Bst"
|
||||
STR_FRONT_LAYOUT_LBCR: "L, Zurück, Bst, R"
|
||||
STR_PREV_NEXT: "Zurück/Weiter"
|
||||
STR_NEXT_PREV: "Weiter/Zuürck"
|
||||
STR_NEXT_PREV: "Weiter/Zurück"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
@@ -236,6 +236,8 @@ STR_DOWNLOAD: "Herunterladen"
|
||||
STR_RETRY: "Wiederh."
|
||||
STR_YES: "Ja"
|
||||
STR_NO: "Nein"
|
||||
STR_SHOW: "Zeigen"
|
||||
STR_HIDE: "Ausblenden"
|
||||
STR_STATE_ON: "An"
|
||||
STR_STATE_OFF: "Aus"
|
||||
STR_NOT_SET: "Leer"
|
||||
@@ -248,6 +250,21 @@ STR_CAPS_OFF: "umsch"
|
||||
STR_OK_BUTTON: "OK"
|
||||
STR_SLEEP_COVER_FILTER: "Standby-Coverfilter"
|
||||
STR_FILTER_CONTRAST: "Kontrast"
|
||||
STR_CUSTOMISE_STATUS_BAR: "Statusleiste anpassen"
|
||||
STR_CHAPTER_PAGE_COUNT: "Kapitel-Seitenanzahl"
|
||||
STR_BOOK_PROGRESS_PERCENTAGE: "Buchfortschritt in %"
|
||||
STR_PROGRESS_BAR: "Fortschrittsbalken"
|
||||
STR_PROGRESS_BAR_THICKNESS: "Balkenstärke"
|
||||
STR_PROGRESS_BAR_THIN: "Dünn"
|
||||
STR_PROGRESS_BAR_MEDIUM: "Mittel"
|
||||
STR_PROGRESS_BAR_THICK: "Dick"
|
||||
STR_BOOK: "Buch"
|
||||
STR_CHAPTER: "Kapitel"
|
||||
STR_EXAMPLE_CHAPTER: "Kapitel 21"
|
||||
STR_EXAMPLE_BOOK: "Buchtitel"
|
||||
STR_PREVIEW: "Vorschau"
|
||||
STR_TITLE: "Titel"
|
||||
STR_BATTERY: "Batterie"
|
||||
STR_UI_THEME: "System-Design"
|
||||
STR_THEME_CLASSIC: "Klassisch"
|
||||
STR_THEME_LYRA: "Lyra"
|
||||
@@ -280,6 +297,7 @@ STR_GO_TO_PERCENT: "Gehe zu %"
|
||||
STR_GO_HOME_BUTTON: "Zum Anfang"
|
||||
STR_SYNC_PROGRESS: "Fortschritt synchronisieren"
|
||||
STR_DELETE_CACHE: "Buch-Cache leeren"
|
||||
STR_DISPLAY_QR: "Seite als QR anzeigen"
|
||||
STR_DELETE: "Löschen"
|
||||
STR_CHAPTER_PREFIX: "Kapitel:"
|
||||
STR_PAGES_SEPARATOR: " Seiten | "
|
||||
@@ -289,7 +307,7 @@ STR_KBD_SHIFT_CAPS: "UMSCH"
|
||||
STR_KBD_LOCK: "FESTST"
|
||||
STR_CALIBRE_URL_HINT: "Calibre: URL um /opds ergänzen"
|
||||
STR_PERCENT_STEP_HINT: "links/rechts: 1% hoch/runter: 10%"
|
||||
STR_SYNCING_TIME: "Zeit synchonisieren…"
|
||||
STR_SYNCING_TIME: "Zeit synchronisieren…"
|
||||
STR_CALC_HASH: "Dokument-Hash berechnen…"
|
||||
STR_HASH_FAILED: "Dokument-Hash fehlgeschlagen"
|
||||
STR_FETCH_PROGRESS: "Externen Fortschritt abrufen..."
|
||||
@@ -302,8 +320,8 @@ STR_LOCAL_LABEL: "Lokal:"
|
||||
STR_PAGE_OVERALL_FORMAT: " Seite %d, %.2f%% insgesamt"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: " Seite %d/%d, %.2f%% insgesamt"
|
||||
STR_DEVICE_FROM_FORMAT: " Von: %s"
|
||||
STR_APPLY_REMOTE: "Ext. Fortschritt übern."
|
||||
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochl."
|
||||
STR_APPLY_REMOTE: "Externen Fortschritt übernehmen"
|
||||
STR_UPLOAD_LOCAL: "Lokalen Fortschritt hochladen"
|
||||
STR_NO_REMOTE_MSG: "Kein externer Fortschritt"
|
||||
STR_UPLOAD_PROMPT: "Aktuelle Position hochladen?"
|
||||
STR_UPLOAD_SUCCESS: "Hochgeladen!"
|
||||
@@ -314,3 +332,8 @@ STR_BOOK_S_STYLE: "Buch-Stil"
|
||||
STR_EMBEDDED_STYLE: "Eingebetteter Stil"
|
||||
STR_OPDS_SERVER_URL: "OPDS-Server-URL"
|
||||
STR_SCREENSHOT_BUTTON: "Screenshot aufnehmen"
|
||||
STR_FOOTNOTES: "Fußnoten"
|
||||
STR_NO_FOOTNOTES: "Keine Fußnoten auf dieser Seite"
|
||||
STR_LINK: "[Link]"
|
||||
STR_AUTO_TURN_ENABLED: "Auto-Umblättern aktiv: "
|
||||
STR_AUTO_TURN_PAGES_PER_MIN: "Auto-Umblättern (Seiten/Min.)"
|
||||
|
||||
@@ -6,7 +6,7 @@ STR_CROSSPOINT: "CrossPoint"
|
||||
STR_BOOTING: "Iniciando..."
|
||||
STR_SLEEPING: "Suspendido"
|
||||
STR_ENTERING_SLEEP: "Entrando en suspensión"
|
||||
STR_BROWSE_FILES: "Explorador de Archivos"
|
||||
STR_BROWSE_FILES: "Explorador de archivos"
|
||||
STR_FILE_TRANSFER: "Transferir archivos"
|
||||
STR_SETTINGS_TITLE: "Ajustes"
|
||||
STR_CALIBRE_LIBRARY: "Biblioteca de Calibre"
|
||||
@@ -46,11 +46,11 @@ STR_PRESS_ANY_CONTINUE: "Pulse cualquier botón para continuar"
|
||||
STR_SELECT_HINT: "Izq./Der.: Seleccionar | OK: Confirmar"
|
||||
STR_HOW_CONNECT: "¿Cómo desea conectarse?"
|
||||
STR_JOIN_NETWORK: "Unirse a una red"
|
||||
STR_CREATE_HOTSPOT: "Crear Punto de Acceso"
|
||||
STR_CREATE_HOTSPOT: "Crear punto de acceso"
|
||||
STR_JOIN_DESC: "Conectarse a una red Wi-Fi existente"
|
||||
STR_HOTSPOT_DESC: "Conectarse a este dispositivo"
|
||||
STR_STARTING_HOTSPOT: "Iniciando Punto de Acceso..."
|
||||
STR_HOTSPOT_MODE: "Modo Punto de Acceso"
|
||||
STR_STARTING_HOTSPOT: "Iniciando punto de acceso..."
|
||||
STR_HOTSPOT_MODE: "Modo punto de acceso"
|
||||
STR_CONNECT_WIFI_HINT: "Conecte su dispositivo a esta red Wi-Fi"
|
||||
STR_OPEN_URL_HINT: "Abra esta dirección en su navegador"
|
||||
STR_OR_HTTP_PREFIX: "o http://"
|
||||
@@ -65,22 +65,22 @@ STR_ENTER_WIFI_PASSWORD: "Introduzca la contraseña del Wi-Fi"
|
||||
STR_ENTER_TEXT: "Introduzca el texto"
|
||||
STR_TO_PREFIX: "a "
|
||||
STR_CALIBRE_DISCOVERING: "Buscando Calibre..."
|
||||
STR_CALIBRE_CONNECTING_TO: "Conectándose a"
|
||||
STR_CALIBRE_CONNECTING_TO: "Conectándose a "
|
||||
STR_CALIBRE_CONNECTED_TO: "Conectado a "
|
||||
STR_CALIBRE_WAITING_COMMANDS: "Esperando comandos..."
|
||||
STR_CONNECTION_FAILED_RETRYING: "(Error de conexión, reintentando...)"
|
||||
STR_CALIBRE_DISCONNECTED: "Calibre desconectado"
|
||||
STR_CALIBRE_WAITING_TRANSFER: "Esperando transferencia..."
|
||||
STR_CALIBRE_TRANSFER_HINT: "Si la transferencia falla, active \\n'Ignorar espacio libre' en la configuración del \\nPlugin Smart Device de Calibre."
|
||||
STR_CALIBRE_TRANSFER_HINT: "Si la transferencia falla, active\\n\"Ignorar espacio libre\" en la configuración del\\ncomplemento SmartDevice de Calibre."
|
||||
STR_CALIBRE_RECEIVING: "Recibiendo: "
|
||||
STR_CALIBRE_RECEIVED: "Recibido: "
|
||||
STR_CALIBRE_WAITING_MORE: "Esperando más..."
|
||||
STR_CALIBRE_FAILED_CREATE_FILE: "Error al crear el archivo"
|
||||
STR_CALIBRE_PASSWORD_REQUIRED: "Contraseña requerida"
|
||||
STR_CALIBRE_TRANSFER_INTERRUPTED: "Transferencia interrumpida"
|
||||
STR_CALIBRE_INSTRUCTION_1: "1) Instale el Plugin CrossPoint Reader"
|
||||
STR_CALIBRE_INSTRUCTION_1: "1) Instale el complemento CrossPoint Reader"
|
||||
STR_CALIBRE_INSTRUCTION_2: "2) Conéctese a la misma red Wi-Fi"
|
||||
STR_CALIBRE_INSTRUCTION_3: "3) Desde Calibre seleccione: \"Enviar a dispositivo\""
|
||||
STR_CALIBRE_INSTRUCTION_3: "3) Desde Calibre, seleccione \"Enviar a dispositivo\""
|
||||
STR_CALIBRE_INSTRUCTION_4: "\"Permanezca en esta pantalla mientras se envía\""
|
||||
STR_CAT_DISPLAY: "Pantalla"
|
||||
STR_CAT_READER: "Lector"
|
||||
@@ -92,15 +92,15 @@ STR_STATUS_BAR: "Barra de estado"
|
||||
STR_HIDE_BATTERY: "Ocultar % de batería"
|
||||
STR_EXTRA_SPACING: "Espaciado entre párrafos"
|
||||
STR_TEXT_AA: "Suavizado de texto"
|
||||
STR_SHORT_PWR_BTN: "Función especial botón Power"
|
||||
STR_SHORT_PWR_BTN: "Toque corto botón encendido"
|
||||
STR_ORIENTATION: "Orientación"
|
||||
STR_FRONT_BTN_LAYOUT: "Diseño de los botones frontales"
|
||||
STR_SIDE_BTN_LAYOUT: "Función botones laterales (Lector)"
|
||||
STR_SIDE_BTN_LAYOUT: "Función botones laterales (lector)"
|
||||
STR_LONG_PRESS_SKIP: "Saltar capítulo (pulsación larga)"
|
||||
STR_FONT_FAMILY: "Tipografía"
|
||||
STR_EXT_READER_FONT: "Tipografía externa"
|
||||
STR_EXT_CHINESE_FONT: "Tipografía"
|
||||
STR_EXT_UI_FONT: "Tipografía (Pantalla)"
|
||||
STR_EXT_UI_FONT: "Tipografía (interfaz)"
|
||||
STR_FONT_SIZE: "Tamaño"
|
||||
STR_LINE_SPACING: "Interlineado"
|
||||
STR_ASCII_LETTER_SPACING: "Espaciado entre letras ASCII"
|
||||
@@ -126,7 +126,7 @@ STR_DOCUMENT_MATCHING: "Coincidencia de doc."
|
||||
STR_AUTHENTICATE: "Autenticar"
|
||||
STR_KOREADER_USERNAME: "Usuario de KOReader"
|
||||
STR_KOREADER_PASSWORD: "Contraseña de KOReader"
|
||||
STR_FILENAME: "Nombre del archivo"
|
||||
STR_FILENAME: "Nombre de archivo"
|
||||
STR_BINARY: "Binario"
|
||||
STR_SET_CREDENTIALS_FIRST: "Configurar credenciales"
|
||||
STR_WIFI_CONN_FAILED: "Fallo de conexión Wi-Fi"
|
||||
@@ -142,8 +142,8 @@ STR_CLEAR_CACHE_WARNING_3: "Los libros deberán ser reindexados"
|
||||
STR_CLEAR_CACHE_WARNING_4: "cuando se vuelvan a abrir."
|
||||
STR_CLEARING_CACHE: "Borrando caché..."
|
||||
STR_CACHE_CLEARED: "Caché borrada"
|
||||
STR_ITEMS_REMOVED: "Elementos eliminados"
|
||||
STR_FAILED_LOWER: "Error"
|
||||
STR_ITEMS_REMOVED: "elementos eliminados"
|
||||
STR_FAILED_LOWER: "falló"
|
||||
STR_CLEAR_CACHE_FAILED: "No se pudo borrar la caché"
|
||||
STR_CHECK_SERIAL_OUTPUT: "Consulte los registros del puerto serie"
|
||||
STR_DARK: "Oscuro"
|
||||
@@ -184,16 +184,16 @@ STR_JUSTIFY: "Justificado"
|
||||
STR_ALIGN_LEFT: "Izquierda"
|
||||
STR_CENTER: "Centro"
|
||||
STR_ALIGN_RIGHT: "Derecha"
|
||||
STR_MIN_1: "1 Minuto"
|
||||
STR_MIN_5: "5 Minutos"
|
||||
STR_MIN_10: "10 Minutos"
|
||||
STR_MIN_15: "15 Minutos"
|
||||
STR_MIN_30: "30 Minutos"
|
||||
STR_PAGES_1: "1 Página"
|
||||
STR_PAGES_5: "5 Páginas"
|
||||
STR_PAGES_10: "10 Páginas"
|
||||
STR_PAGES_15: "15 Páginas"
|
||||
STR_PAGES_30: "30 Páginas"
|
||||
STR_MIN_1: "1 min."
|
||||
STR_MIN_5: "5 min."
|
||||
STR_MIN_10: "10 min."
|
||||
STR_MIN_15: "15 min."
|
||||
STR_MIN_30: "30 min."
|
||||
STR_PAGES_1: "1 pág."
|
||||
STR_PAGES_5: "5 pág."
|
||||
STR_PAGES_10: "10 pág."
|
||||
STR_PAGES_15: "15 pág."
|
||||
STR_PAGES_30: "30 pág."
|
||||
STR_UPDATE: "Actualizar"
|
||||
STR_CHECKING_UPDATE: "Verificando actualización..."
|
||||
STR_NEW_UPDATE: "¡Nueva actualización disponible!"
|
||||
@@ -203,20 +203,20 @@ STR_UPDATING: "Actualizando..."
|
||||
STR_NO_UPDATE: "No hay actualizaciones disponibles"
|
||||
STR_UPDATE_FAILED: "Fallo de actualización"
|
||||
STR_UPDATE_COMPLETE: "Actualización completada"
|
||||
STR_POWER_ON_HINT: "Pulse y mantenga presionado el botón de encendido para volver a encender"
|
||||
STR_POWER_ON_HINT: "Reinicie manteniendo pulsado botón de encendido"
|
||||
STR_EXTERNAL_FONT: "Fuente externa"
|
||||
STR_BUILTIN_DISABLED: "Incorporado (Desactivado)"
|
||||
STR_BUILTIN_DISABLED: "Incorporado (desactivado)"
|
||||
STR_NO_ENTRIES: "No se encontraron elementos"
|
||||
STR_DOWNLOADING: "Descargando..."
|
||||
STR_DOWNLOAD_FAILED: "Fallo de descarga"
|
||||
STR_ERROR_MSG: "Error"
|
||||
STR_ERROR_MSG: "Error:"
|
||||
STR_UNNAMED: "Sin nombre"
|
||||
STR_NO_SERVER_URL: "No se ha configurado la URL del servidor"
|
||||
STR_NO_SERVER_URL: "No se configuró URL de servidor"
|
||||
STR_FETCH_FEED_FAILED: "Fallo al obtener el feed"
|
||||
STR_PARSE_FEED_FAILED: "Fallo al procesar el feed"
|
||||
STR_NETWORK_PREFIX: "Red: "
|
||||
STR_IP_ADDRESS_PREFIX: "IP: "
|
||||
STR_SCAN_QR_WIFI_HINT: "O escanee el código QR con su teléfono para conectarse a Wi-Fi."
|
||||
STR_SCAN_QR_WIFI_HINT: "o lea el QR con su tfno. para conectarse al Wi-Fi."
|
||||
STR_ERROR_GENERAL_FAILURE: "Error: Fallo general"
|
||||
STR_ERROR_NETWORK_NOT_FOUND: "Error: Red no encontrada"
|
||||
STR_ERROR_CONNECTION_TIMEOUT: "Error: Tiempo de conexión agotado"
|
||||
@@ -225,7 +225,8 @@ STR_BACK: "« Atrás"
|
||||
STR_EXIT: "« Salir"
|
||||
STR_HOME: "« Inicio"
|
||||
STR_SAVE: "« Guardar"
|
||||
STR_SELECT: "Elegir"
|
||||
STR_SELECT: "Selec."
|
||||
STR_SELECTED: "Seleccionado"
|
||||
STR_TOGGLE: "Cambiar"
|
||||
STR_CONFIRM: "Confirmar"
|
||||
STR_CANCEL: "Cancelar"
|
||||
@@ -235,6 +236,8 @@ STR_DOWNLOAD: "Descargar"
|
||||
STR_RETRY: "Reintentar"
|
||||
STR_YES: "Sí"
|
||||
STR_NO: "No"
|
||||
STR_SHOW: "Mostrar"
|
||||
STR_HIDE: "Ocultar"
|
||||
STR_STATE_ON: "Activado"
|
||||
STR_STATE_OFF: "Desactivado"
|
||||
STR_NOT_SET: "No configurado"
|
||||
@@ -247,6 +250,21 @@ STR_CAPS_OFF: "minúsculas"
|
||||
STR_OK_BUTTON: "OK"
|
||||
STR_SLEEP_COVER_FILTER: "Filtro de pantalla de suspensión"
|
||||
STR_FILTER_CONTRAST: "Contraste"
|
||||
STR_CUSTOMISE_STATUS_BAR: "Personalizar barra de estado"
|
||||
STR_CHAPTER_PAGE_COUNT: "Contador pág. cap."
|
||||
STR_BOOK_PROGRESS_PERCENTAGE: "Porcentaje progreso libro"
|
||||
STR_PROGRESS_BAR: "Barra de progreso"
|
||||
STR_PROGRESS_BAR_THICKNESS: "Grosor de barra de progreso"
|
||||
STR_PROGRESS_BAR_THIN: "Fino"
|
||||
STR_PROGRESS_BAR_MEDIUM: "Medio"
|
||||
STR_PROGRESS_BAR_THICK: "Ancho"
|
||||
STR_BOOK: "Libro"
|
||||
STR_CHAPTER: "Capítulo"
|
||||
STR_EXAMPLE_CHAPTER: "Capítulo 21"
|
||||
STR_EXAMPLE_BOOK: "Título del libro"
|
||||
STR_PREVIEW: "Previsualización"
|
||||
STR_TITLE: "Título"
|
||||
STR_BATTERY: "Batería"
|
||||
STR_UI_THEME: "Interfaz"
|
||||
STR_THEME_CLASSIC: "Clásico"
|
||||
STR_THEME_LYRA: "Lyra"
|
||||
@@ -269,37 +287,38 @@ STR_DEFAULT_VALUE: "Predeterminado"
|
||||
STR_REMAP_PROMPT: "Pulse un botón frontal para cada función"
|
||||
STR_UNASSIGNED: "Sin asignar"
|
||||
STR_ALREADY_ASSIGNED: "Ya asignado"
|
||||
STR_REMAP_RESET_HINT: "Botón lateral arriba: Restablecer configuración"
|
||||
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: Anular reconfiguración"
|
||||
STR_HW_BACK_LABEL: "Atrás (Primer botón)"
|
||||
STR_HW_CONFIRM_LABEL: "Confirmar (Segundo botón)"
|
||||
STR_HW_LEFT_LABEL: "Izq. (Tercer botón)"
|
||||
STR_HW_RIGHT_LABEL: "Der. (Cuarto botón)"
|
||||
STR_REMAP_RESET_HINT: "Botón lateral arriba: restablecer configuración"
|
||||
STR_REMAP_CANCEL_HINT: "Botón lateral abajo: anular reconfiguración"
|
||||
STR_HW_BACK_LABEL: "Atrás (primer botón)"
|
||||
STR_HW_CONFIRM_LABEL: "Confirmar (segundo botón)"
|
||||
STR_HW_LEFT_LABEL: "Izq. (tercer botón)"
|
||||
STR_HW_RIGHT_LABEL: "Der. (cuarto botón)"
|
||||
STR_GO_TO_PERCENT: "Ir a %"
|
||||
STR_GO_HOME_BUTTON: "Volver a inicio"
|
||||
STR_DELETE: "Borrar"
|
||||
STR_GO_HOME_BUTTON: "Volver al menú Inicio"
|
||||
STR_SYNC_PROGRESS: "Sincronizar progreso de lectura"
|
||||
STR_DELETE_CACHE: "Borrar caché del libro"
|
||||
STR_CHAPTER_PREFIX: "Cap.:"
|
||||
STR_PAGES_SEPARATOR: " Páginas |"
|
||||
STR_BOOK_PREFIX: "Libro:"
|
||||
STR_KBD_SHIFT: "shift"
|
||||
STR_KBD_SHIFT_CAPS: "SHIFT"
|
||||
STR_DELETE: "Borrar"
|
||||
STR_DISPLAY_QR: "Mostrar página como QR"
|
||||
STR_CHAPTER_PREFIX: "Cap.: "
|
||||
STR_PAGES_SEPARATOR: " Págs. | "
|
||||
STR_BOOK_PREFIX: "Libro: "
|
||||
STR_KBD_SHIFT: "minús."
|
||||
STR_KBD_SHIFT_CAPS: "MAYÚS."
|
||||
STR_KBD_LOCK: "BLOQUEAR"
|
||||
STR_CALIBRE_URL_HINT: "Para Calibre, agregue /opds a su URL"
|
||||
STR_PERCENT_STEP_HINT: "Izq./Der.: 1% | Subir/Bajar: 10%"
|
||||
STR_SYNCING_TIME: "Tiempo de sincronización..."
|
||||
STR_CALC_HASH: "Calculando HASH del documento..."
|
||||
STR_HASH_FAILED: "No se pudo calcular el HASH del documento"
|
||||
STR_CALC_HASH: "Calculando hash del documento..."
|
||||
STR_HASH_FAILED: "No se pudo calcular el hash del documento"
|
||||
STR_FETCH_PROGRESS: "Recuperando progreso remoto..."
|
||||
STR_UPLOAD_PROGRESS: "Subiendo progreso..."
|
||||
STR_NO_CREDENTIALS_MSG: "No se han configurado credenciales"
|
||||
STR_KOREADER_SETUP_HINT: "Configure una cuenta de KOReader en la configuración"
|
||||
STR_PROGRESS_FOUND: "¡Progreso encontrado!"
|
||||
STR_REMOTE_LABEL: "Remoto"
|
||||
STR_LOCAL_LABEL: "Local"
|
||||
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% Completada"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% Completada"
|
||||
STR_REMOTE_LABEL: "Remoto:"
|
||||
STR_LOCAL_LABEL: "Local:"
|
||||
STR_PAGE_OVERALL_FORMAT: "Página %d, %.2f%% completado"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Página %d / %d, %.2f%% completado"
|
||||
STR_DEVICE_FROM_FORMAT: " De: %s"
|
||||
STR_APPLY_REMOTE: "Aplicar progreso remoto"
|
||||
STR_UPLOAD_LOCAL: "Subir progreso local"
|
||||
@@ -312,4 +331,9 @@ STR_UPLOAD: "Subir"
|
||||
STR_BOOK_S_STYLE: "Estilo del libro"
|
||||
STR_EMBEDDED_STYLE: "Estilo integrado"
|
||||
STR_OPDS_SERVER_URL: "URL del servidor OPDS"
|
||||
STR_FOOTNOTES: "Pie de página"
|
||||
STR_NO_FOOTNOTES: "No hay notas al pie de esta página"
|
||||
STR_LINK: "[enlace]"
|
||||
STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla"
|
||||
STR_AUTO_TURN_ENABLED: "Paso pág. automático: "
|
||||
STR_AUTO_TURN_PAGES_PER_MIN: "Páginas por minuto"
|
||||
|
||||
@@ -297,6 +297,7 @@ STR_GO_TO_PERCENT: "Перейти до %"
|
||||
STR_GO_HOME_BUTTON: "На головну"
|
||||
STR_SYNC_PROGRESS: "Прогрес синхронізації"
|
||||
STR_DELETE_CACHE: "Видалити кеш книги"
|
||||
STR_DELETE: "Видалити"
|
||||
STR_DISPLAY_QR: "Показати сторінку як QR-код"
|
||||
STR_CHAPTER_PREFIX: "Розділ: "
|
||||
STR_PAGES_SEPARATOR: " сторінок | "
|
||||
@@ -334,3 +335,5 @@ STR_FOOTNOTES: "Зноски"
|
||||
STR_NO_FOOTNOTES: "На цій сторінці немає зносок"
|
||||
STR_LINK: "[посилання]"
|
||||
STR_SCREENSHOT_BUTTON: "Знімок екрана"
|
||||
STR_AUTO_TURN_ENABLED: "Автоперегортання увімк: "
|
||||
STR_AUTO_TURN_PAGES_PER_MIN: "Автоперегортання (ст/хв)"
|
||||
Reference in New Issue
Block a user