Compare commits

..
Author SHA1 Message Date
Justin Mitchell 27c4be8a34 Implement chunked allocation for glyph bitmaps
Replace single contiguous allocation with fixed-size chunks to handle heap fragmentation. Glyph bitmaps are now stored in 4KB chunks (up to 24 chunks per style/page) to allow allocation when memory is fragmented. Each glyph bitmap fits entirely within one chunk and is addressed via virtual offset.
2026-08-05 18:42:44 -04:00
59 changed files with 691 additions and 2024 deletions

No files matched your search

+2 -1
View File
@@ -29,5 +29,6 @@ lib/EpdFont/scripts/output/
/.dummy
/CMakeLists.txt
/dependencies.lock
/sdkconfig.*
/sdkconfig.default
/sdkconfig.defaults
sdkconfig.sticky
-1
View File
@@ -153,7 +153,6 @@ To convert your own TrueType/OpenType fonts:
| `armenian` | Armenian |
| `ethiopic` | Ethiopic + Extended |
| `vietnamese` | Vietnamese subset (ơ/ư and combining marks) |
| `ipa-chars` | IPA Extensions + Spacing Modifier Letters (phonetic transcription) |
| `punctuation` | General punctuation (U+2000–U+206F) |
| `cjk` | CJK Unified Ideographs + Hiragana + Katakana + Fullwidth |
| `hangul` | Korean Hangul syllables + Jamo + Compatibility Jamo |
+74 -19
View File
@@ -99,8 +99,11 @@ void SdCardFont::freeStyleMiniData(PerStyle& s) {
s.miniIntervals = nullptr;
delete[] s.miniGlyphs;
s.miniGlyphs = nullptr;
delete[] s.miniBitmap;
s.miniBitmap = nullptr;
for (auto& chunk : s.miniBitmapChunks) {
delete[] chunk;
chunk = nullptr;
}
s.miniBitmapChunkCount = 0;
s.miniIntervalCount = 0;
s.miniGlyphCount = 0;
s.miniIntervalCapacity = 0;
@@ -1010,30 +1013,66 @@ int SdCardFont::prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint3
totalBitmapSize += s.miniGlyphs[i].dataLength;
}
if (!ensureArrayCapacity(s.miniBitmap, s.miniBitmapCapacity, totalBitmapSize)) {
LOG_ERR("SDCF", "Failed to allocate mini bitmap (%u bytes) for style %u", totalBitmapSize, styleIdx);
delete[] readOrder;
delete[] mappings;
freeStyleMiniData(s);
return static_cast<int>(cpCount);
}
s.miniBitmapUsed = totalBitmapSize; // underuse-hysteresis signal for resetStyleMiniData
// Read bitmap data sorted by file offset
std::sort(readOrder, readOrder + validCount,
[&](uint32_t a, uint32_t b) { return s.miniGlyphs[a].dataOffset < s.miniGlyphs[b].dataOffset; });
uint32_t miniBitmapOffset = 0;
// Assemble the bitmap arena from on-demand 4 KB chunks (see MINI_BM_CHUNK_*).
// `span` is the running virtual offset into the arena; each glyph is placed
// wholly within one chunk, skipping past a boundary rather than straddling it.
// glyph.dataOffset becomes the virtual offset, decoded at render time by
// miniGlyphBitmap(). Chunks are allocated only as span reaches them, so a
// sparse page never allocates the full ceiling.
uint32_t span = 0;
uint32_t lastBitmapEnd = UINT32_MAX;
for (uint32_t i = 0; i < validCount; i++) {
uint32_t mapIdx = readOrder[i];
EpdGlyph& glyph = s.miniGlyphs[mapIdx];
const uint32_t len = glyph.dataLength;
if (glyph.dataLength == 0) {
glyph.dataOffset = miniBitmapOffset;
if (len == 0) {
glyph.dataOffset = span;
continue;
}
if (len > MINI_BM_CHUNK_SIZE) {
// A single glyph larger than one chunk cannot be placed. Real fonts never
// hit this (a 4 KB 2bpp glyph would be enormous); bail rather than corrupt.
LOG_ERR("SDCF", "Prewarm: glyph %u B exceeds chunk %u B (style %u)", len, MINI_BM_CHUNK_SIZE, styleIdx);
file.close();
delete[] readOrder;
delete[] mappings;
freeStyleMiniData(s);
return static_cast<int>(cpCount);
}
// Skip to the next chunk boundary if this glyph would straddle one.
const uint32_t within = span & (MINI_BM_CHUNK_SIZE - 1);
if (within != 0 && within + len > MINI_BM_CHUNK_SIZE) {
span += MINI_BM_CHUNK_SIZE - within;
}
const uint32_t chunkIdx = span >> MINI_BM_CHUNK_SHIFT;
if (chunkIdx >= MINI_BM_MAX_CHUNKS) {
LOG_ERR("SDCF", "Prewarm: mini bitmap needs > %u chunks (style %u)", MINI_BM_MAX_CHUNKS, styleIdx);
file.close();
delete[] readOrder;
delete[] mappings;
freeStyleMiniData(s);
return static_cast<int>(cpCount);
}
if (!s.miniBitmapChunks[chunkIdx]) {
s.miniBitmapChunks[chunkIdx] = new (std::nothrow) uint8_t[MINI_BM_CHUNK_SIZE];
if (!s.miniBitmapChunks[chunkIdx]) {
LOG_ERR("SDCF", "Failed to allocate mini bitmap chunk %u (style %u)", chunkIdx, styleIdx);
file.close();
delete[] readOrder;
delete[] mappings;
freeStyleMiniData(s);
return static_cast<int>(cpCount);
}
if (chunkIdx + 1 > s.miniBitmapChunkCount) s.miniBitmapChunkCount = chunkIdx + 1;
}
const uint32_t off = span & (MINI_BM_CHUNK_SIZE - 1);
uint32_t fileOff = s.bitmapFileOffset + glyph.dataOffset;
if (fileOff != lastBitmapEnd) {
if (!file.seekSet(fileOff)) {
@@ -1046,18 +1085,21 @@ int SdCardFont::prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint3
}
seekCount++;
}
if (file.read(s.miniBitmap + miniBitmapOffset, glyph.dataLength) != static_cast<int>(glyph.dataLength)) {
if (file.read(s.miniBitmapChunks[chunkIdx] + off, len) != static_cast<int>(len)) {
LOG_ERR("SDCF", "Prewarm: short bitmap read (style %u)", styleIdx);
delete[] readOrder;
delete[] mappings;
freeStyleMiniData(s);
return static_cast<int>(cpCount);
}
lastBitmapEnd = fileOff + glyph.dataLength;
lastBitmapEnd = fileOff + len;
glyph.dataOffset = miniBitmapOffset;
miniBitmapOffset += glyph.dataLength;
glyph.dataOffset = span;
span += len;
}
// Footprint including inter-chunk padding: the underuse-hysteresis signal.
s.miniBitmapUsed = span;
s.miniBitmapCapacity = s.miniBitmapChunkCount * MINI_BM_CHUNK_SIZE;
}
uint32_t sdTime = millis() - sdStart;
@@ -1080,7 +1122,10 @@ int SdCardFont::prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint3
s.miniMetadataOnly = metadataOnly;
s.miniHysteresisPending = !metadataOnly; // one hysteresis evaluation per rebuild
memset(&s.miniData, 0, sizeof(s.miniData));
s.miniData.bitmap = s.miniBitmap;
// The mini bitmap is chunked (non-contiguous), so there is no single base
// pointer. Prewarmed SD glyphs are resolved via SdCardFont::miniGlyphBitmap()
// in the renderer; leave bitmap null so any stray &bitmap[dataOffset] faults.
s.miniData.bitmap = nullptr;
s.miniData.glyph = s.miniGlyphs;
s.miniData.intervals = s.miniIntervals;
s.miniData.intervalCount = s.miniIntervalCount;
@@ -1517,4 +1562,14 @@ const uint8_t* SdCardFont::getOverflowBitmap(const EpdGlyph* glyph) const {
return nullptr;
}
const uint8_t* SdCardFont::miniGlyphBitmap(const void* ctx, uint32_t dataOffset) const {
const auto* octx = static_cast<const OverflowContext*>(ctx);
const PerStyle& s = styles_[octx->styleIdx];
const uint32_t chunkIdx = dataOffset >> MINI_BM_CHUNK_SHIFT;
if (chunkIdx >= s.miniBitmapChunkCount) return nullptr;
const uint8_t* chunk = s.miniBitmapChunks[chunkIdx];
if (!chunk) return nullptr;
return chunk + (dataOffset & (MINI_BM_CHUNK_SIZE - 1));
}
SdCardFont* SdCardFont::fromMissCtx(void* ctx) { return static_cast<OverflowContext*>(ctx)->self; }
+22 -1
View File
@@ -94,6 +94,12 @@ class SdCardFont {
// Returns the bitmap for an on-demand-loaded (overflow) glyph.
const uint8_t* getOverflowBitmap(const EpdGlyph* glyph) const;
// Resolves a prewarmed mini glyph's chunked bitmap. `ctx` is the glyphMissCtx
// (an OverflowContext identifying the style); `dataOffset` is the glyph's
// virtual offset into the style's chunked arena. Returns nullptr if the chunk
// is absent or out of range. Called by GfxRenderer::getGlyphBitmap().
const uint8_t* miniGlyphBitmap(const void* ctx, uint32_t dataOffset) const;
// Extract SdCardFont* from an opaque glyphMissCtx pointer.
// Used by GfxRenderer::getGlyphBitmap() to recover the SdCardFont from EpdFontData::glyphMissCtx.
static SdCardFont* fromMissCtx(void* ctx);
@@ -129,6 +135,18 @@ class SdCardFont {
uint8_t ligaturePairCount = 0;
};
// The per-style mini bitmap arena is stored as a list of fixed-size chunks
// rather than one contiguous block. A whole page's 2bpp glyph bitmaps can run
// tens of KB; on a fragmented heap a single contiguous allocation of that size
// fails even when the same bytes are available as several smaller free blocks.
// Chunking lets the arena be assembled from blocks the allocator can actually
// provide. Each glyph's bitmap is placed wholly within one chunk (never
// straddling a boundary), so a glyph is addressed by a virtual offset that
// maps to (chunk index, offset-in-chunk) via miniGlyphBitmap().
static constexpr uint32_t MINI_BM_CHUNK_SHIFT = 12; // 4 KB chunks
static constexpr uint32_t MINI_BM_CHUNK_SIZE = 1u << MINI_BM_CHUNK_SHIFT;
static constexpr uint32_t MINI_BM_MAX_CHUNKS = 24; // 96 KB ceiling per style/page
// All per-style data: file offsets, intervals, kern/lig, prewarm cache, EpdFont
struct PerStyle {
CpFontHeader header{};
@@ -188,7 +206,10 @@ class SdCardFont {
EpdFontData miniData{};
EpdUnicodeInterval* miniIntervals = nullptr;
EpdGlyph* miniGlyphs = nullptr;
uint8_t* miniBitmap = nullptr;
// Chunked mini bitmap arena (see MINI_BM_CHUNK_* above). Chunks are allocated
// on demand during prewarm; miniBitmapChunkCount is how many are live.
uint8_t* miniBitmapChunks[MINI_BM_MAX_CHUNKS] = {};
uint32_t miniBitmapChunkCount = 0;
uint32_t miniIntervalCount = 0;
uint32_t miniGlyphCount = 0;
uint32_t miniIntervalCapacity = 0;
@@ -49,7 +49,6 @@ INTERVAL_PRESETS = {
"armenian": [(0x0530, 0x058F)],
"ethiopic": [(0x1200, 0x137F), (0x1380, 0x139F), (0x2D80, 0x2DDF)],
"vietnamese": [(0x01A0, 0x01B0), (0x1EA0, 0x1EF9)],
"ipa-chars": [(0x0250, 0x02AF), (0x02B0, 0x02FF)],
"punctuation": [(0x2000, 0x206F)],
"cjk": [(0x3000, 0x303F), (0x3040, 0x309F), (0x30A0, 0x30FF),
(0x4E00, 0x9FFF), (0xF900, 0xFAFF), (0xFF00, 0xFFEF)],
+21 -21
View File
@@ -35,7 +35,7 @@ families:
- name: Literata
description: "Screen-optimized serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/googlefonts/literata/main/fonts/ttf/Literata-Regular.ttf"}
@@ -45,7 +45,7 @@ families:
- name: SourceSerif4
description: "Adobe transitional serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/adobe-fonts/source-serif/release/TTF/SourceSerif4-Regular.ttf"}
@@ -55,7 +55,7 @@ families:
- name: NotoSerifExtended
description: "Serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/notofonts/NotoSerif/main/fonts/ttf/unhinted/instance_ttf/NotoSerif-Regular.ttf"}
@@ -65,7 +65,7 @@ families:
- name: Merriweather
description: "Warm serif for long-form reading (Latin, Cyrillic)"
intervals: latin-ext,cyrillic,ipa-chars
intervals: latin-ext,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/SorkinType/Merriweather/master/fonts/ttf/Merriweather-Regular.ttf"}
@@ -75,7 +75,7 @@ families:
- name: Lora
description: "Calligraphic serif for literary reading (Latin, Cyrillic)"
intervals: latin-ext,cyrillic,ipa-chars
intervals: latin-ext,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/cyrealtype/Lora-Cyrillic/main/fonts/ttf/Lora-Regular.ttf"}
@@ -85,7 +85,7 @@ families:
- name: GentiumBookPlus
description: "Scholarly serif with wide Unicode coverage (Latin, Greek, Cyrillic, IPA)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/gentiumbookplus/GentiumBookPlus-Regular.ttf"}
@@ -95,7 +95,7 @@ families:
- name: IBMPlexSerif
description: "Professional serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/ibmplexserif/IBMPlexSerif-Regular.ttf"}
@@ -105,7 +105,7 @@ families:
- name: Bitter
description: "Slab serif designed for e-ink (Latin, Cyrillic)"
intervals: latin-ext,cyrillic,ipa-chars
intervals: latin-ext,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/bitter/Bitter%5Bwght%5D.ttf", variable: {wght: 500}}
@@ -115,7 +115,7 @@ families:
- name: Domitian
description: "A humanist serif for literary reading (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://mirrors.ctan.org/fonts/domitian/opentype/Domitian-Roman.otf"}
@@ -125,7 +125,7 @@ families:
- name: LibreBaskerville
description: "A serif reimplementing the classic Baskerville (Latin)"
intervals: latin-ext,ipa-chars
intervals: latin-ext
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/impallari/Libre-Baskerville/master/fonts/ttf/LibreBaskerville-Regular.ttf"}
@@ -135,7 +135,7 @@ families:
- name: Vollkorn
description: "A serif for bread and butter use by Friedrich Althausen (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/vollkorn/Vollkorn%5Bwght%5D.ttf", variable: {wght: 400}}
@@ -147,7 +147,7 @@ families:
- name: NotoSansExtended
description: "Sans-serif (Latin, Greek, Cyrillic, Georgian, Armenian, Ethiopic)"
intervals: latin-ext,greek,cyrillic,georgian,armenian,ethiopic,ipa-chars
intervals: latin-ext,greek,cyrillic,georgian,armenian,ethiopic
sizes: [12, 14, 16, 18]
styles:
regular: {path: "builtinFonts/source/NotoSans/NotoSans-Regular.ttf"}
@@ -157,7 +157,7 @@ families:
- name: Inter
description: "Modern sans-serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/inter/Inter%5Bopsz%2Cwght%5D.ttf", variable: {wght: 400, opsz: 14}}
@@ -167,7 +167,7 @@ families:
- name: SourceSans3
description: "Adobe humanist sans-serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Regular.ttf"}
@@ -177,7 +177,7 @@ families:
- name: IBMPlexSans
description: "IBM corporate sans-serif (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/IBM/plex/master/packages/plex-sans/fonts/complete/ttf/IBMPlexSans-Regular.ttf"}
@@ -187,7 +187,7 @@ families:
- name: Alegreya
description: "Calligraphic serif/display (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/alegreya/Alegreya%5Bwght%5D.ttf", variable: {wght: 400}}
@@ -199,7 +199,7 @@ families:
- name: IBMPlexMono
description: "Monospace for code and technical reading (Latin, Greek, Cyrillic)"
intervals: latin-ext,greek,cyrillic,ipa-chars
intervals: latin-ext,greek,cyrillic
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/ibmplexmono/IBMPlexMono-Regular.ttf"}
@@ -209,7 +209,7 @@ families:
- name: SourceCodePro
description: "Adobe monospace with excellent hinting (Latin)"
intervals: latin-ext,ipa-chars
intervals: latin-ext
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Regular.ttf"}
@@ -221,7 +221,7 @@ families:
- name: OpenDyslexic
description: "Dyslexia-friendly font (Latin)"
intervals: latin-ext,ipa-chars
intervals: latin-ext
sizes: [8, 10, 12, 14]
styles:
regular: {path: "builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf"}
@@ -233,7 +233,7 @@ families:
- name: AtkinsonHyperlegibleNext
description: "Accessibility font for low vision (Latin)"
intervals: latin-ext,ipa-chars
intervals: latin-ext
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/googlefonts/atkinson-hyperlegible-next/main/fonts/ttf/AtkinsonHyperlegibleNext-Regular.ttf"}
@@ -243,7 +243,7 @@ families:
- name: LexicaUltralegible
description: "Accessibility font for low vision / dyslexia (Latin)"
intervals: latin-ext,ipa-chars
intervals: latin-ext
sizes: [12, 14, 16, 18]
styles:
regular: {url: "https://raw.githubusercontent.com/jacobxperez/lexica-ultralegible/main/fonts/ttf/LexicaUltralegible-Regular.ttf"}
+83 -93
View File
@@ -681,76 +681,6 @@ static inline bool isCjkIdeograph(uint32_t cp) {
(cp >= 0x20000 && cp <= 0x3FFFF);
}
// The first word of a line may have its ruby characters wider than the word (the base text). In that case, we need to
// move the base text to the right a bit so that ruby text doesn't overflow the left border, and it is still centered
// over the base text. This function calculates how much we need to move the base text to the right.
int ParsedText::calculateRubyExtraStartOffset(const size_t wordIdx, const size_t maxWordIdx,
const GfxRenderer& renderer, const int fontId) const {
if (rubyTexts.empty() || wordIdx >= rubyTexts.size() || rubyTexts[wordIdx].empty() ||
(wordStyles[wordIdx] & EpdFontFamily::RUBY_CONTINUE) != 0) {
return 0;
}
size_t groupWordCount = 1;
while (wordIdx + groupWordCount < maxWordIdx &&
(wordStyles[wordIdx + groupWordCount] & EpdFontFamily::RUBY_CONTINUE) != 0) {
groupWordCount++;
}
int groupActualWidth = 0;
for (size_t k = 0; k < groupWordCount; ++k) {
groupActualWidth += measureWordWidth(renderer, fontId, words[wordIdx + k], wordStyles[wordIdx + k]);
}
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[wordIdx].c_str(), EpdFontFamily::SUP);
if (rubyWidth <= groupActualWidth) {
return 0;
}
const int leftOverlap = (rubyWidth - groupActualWidth) / 2;
// This function is only ever called for the first word of a line.
// words[wordIdx - 1], if it exists, is always the last word of the *prior* line
// and cannot absorb any left overhang on the current line.
// The full leftOverlap must therefore be reserved as a visual indent so the
// ruby text does not overflow the left margin.
return leftOverlap;
}
// The last ruby group on a line may have its ruby characters wider than the group's base text.
// The right half of that overhang protrudes past the last base character. This function returns
// the amount of right-margin space that must be reserved so the ruby does not overflow the right
// border. It mirrors calculateRubyExtraStartOffset: words[lineBreak] is on the *next* line and
// cannot absorb any of the right overhang on the current line, so the full rightOverlap is returned.
int ParsedText::calculateRubyExtraEndOffset(const size_t lineStartIdx, const size_t lineBreakIdx,
const GfxRenderer& renderer, const int fontId) const {
if (rubyTexts.empty() || lineBreakIdx == 0 || lineStartIdx >= lineBreakIdx) {
return 0;
}
// Walk backwards from the last word to find the leader of the last ruby group on the line.
size_t leaderIdx = lineBreakIdx - 1;
while (leaderIdx > lineStartIdx && (wordStyles[leaderIdx] & EpdFontFamily::RUBY_CONTINUE) != 0) {
leaderIdx--;
}
// leaderIdx must be a ruby group leader (non-empty ruby, no RUBY_CONTINUE flag).
if (leaderIdx >= rubyTexts.size() || rubyTexts[leaderIdx].empty() ||
(wordStyles[leaderIdx] & EpdFontFamily::RUBY_CONTINUE) != 0) {
return 0;
}
// Measure the group.
int groupActualWidth = 0;
for (size_t k = leaderIdx; k < lineBreakIdx; ++k) {
groupActualWidth += measureWordWidth(renderer, fontId, words[k], wordStyles[k]);
}
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[leaderIdx].c_str(), EpdFontFamily::SUP);
if (rubyWidth <= groupActualWidth) {
return 0;
}
return (rubyWidth - groupActualWidth) / 2;
}
std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& renderer, const int fontId) {
std::vector<uint16_t> wordWidths;
wordWidths.reserve(words.size());
@@ -761,6 +691,9 @@ std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& rendere
// Adjust widths for ruby groups to comply with JLReq standards
if (!rubyTexts.empty()) {
const int ascender = renderer.getFontAscenderSize(fontId);
const int maxOverhang = ascender / 2; // Maximum overhang over non-ideographic characters (Kana, punctuation, etc.)
struct RubyGroupInfo {
size_t start;
size_t count;
@@ -797,10 +730,9 @@ std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& rendere
if (g.start > 0) {
const uint32_t cpPrev = lastCodepoint(words[g.start - 1]);
if (isCjkIdeograph(cpPrev)) {
wordWidths[g.start - 1] += g.leftOverlap;
wordWidths[g.start] += g.leftOverlap;
} else {
const int maxLeftOverhang = wordWidths[g.start - 1] / 2;
wordWidths[g.start - 1] += std::max(0, g.leftOverlap - maxLeftOverhang);
wordWidths[g.start] += std::max(0, g.leftOverlap - maxOverhang);
}
}
@@ -820,8 +752,7 @@ std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& rendere
if (isCjkIdeograph(cpNext)) {
wordWidths[g.start + g.count - 1] += g.rightOverlap;
} else {
const int maxRightOverhang = wordWidths[nextIdx] / 2;
wordWidths[g.start + g.count - 1] += std::max(0, g.rightOverlap - maxRightOverhang);
wordWidths[g.start + g.count - 1] += std::max(0, g.rightOverlap - maxOverhang);
}
// Check if there is another ruby group further ahead separated only by non-ideographs
@@ -838,10 +769,8 @@ std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& rendere
gapWidth += wordWidths[k];
}
if (onlyNonIdeographsInBetween) {
const int maxRightOverhang = wordWidths[g.start + g.count - 1] / 2;
const int maxLeftOverhang = wordWidths[nextG.start - 1] / 2;
const int allowedRight = std::min(g.rightOverlap, maxRightOverhang);
const int allowedLeft = std::min(nextG.leftOverlap, maxLeftOverhang);
const int allowedRight = std::min(g.rightOverlap, maxOverhang);
const int allowedLeft = std::min(nextG.leftOverlap, maxOverhang);
const int touchOverlap = allowedRight + allowedLeft - gapWidth;
if (touchOverlap > 0) {
wordWidths[g.start + g.count - 1] += touchOverlap;
@@ -908,7 +837,36 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
}
// Calculate extraStartOffset for the first word on the line (i) (protect left margin)
const int extraStartOffset = (j == i) ? calculateRubyExtraStartOffset(i, totalWordCount, renderer, fontId) : 0;
int extraStartOffset = 0;
if (j == i && !rubyTexts.empty() && i < rubyTexts.size() && !rubyTexts[i].empty() &&
(wordStyles[i] & EpdFontFamily::RUBY_CONTINUE) == 0) {
int groupWordCount = 1;
while (i + groupWordCount < totalWordCount &&
(wordStyles[i + groupWordCount] & EpdFontFamily::RUBY_CONTINUE) != 0) {
groupWordCount++;
}
int groupActualWidth = 0;
for (int k = 0; k < groupWordCount; ++k) {
groupActualWidth += measureWordWidth(renderer, fontId, words[i + k], wordStyles[i + k]);
}
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[i].c_str(), EpdFontFamily::SUP);
if (rubyWidth > groupActualWidth) {
const int leftOverlap = (rubyWidth - groupActualWidth) / 2;
const int ascender = renderer.getFontAscenderSize(fontId);
const int maxOverhang = ascender / 2;
int expansion_added = 0;
if (i > 0) {
const uint32_t cpPrev = lastCodepoint(words[i - 1]);
if (isCjkIdeograph(cpPrev)) {
expansion_added = leftOverlap;
} else {
expansion_added = std::max(0, leftOverlap - maxOverhang);
}
}
extraStartOffset = leftOverlap - expansion_added;
}
}
currlen += wordWidths[j] + gap + (j == i ? extraStartOffset : 0);
@@ -921,7 +879,46 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
continue;
}
const int extraEndOffset = calculateRubyExtraEndOffset(i, j + 1, renderer, fontId);
// Calculate extraEndOffset if we break after word j (protect right margin)
int extraEndOffset = 0;
if (!rubyTexts.empty() && j < rubyTexts.size()) {
bool isLastOfGroup = false;
size_t leaderIdx = j;
while (true) {
if (!rubyTexts[leaderIdx].empty() && (wordStyles[leaderIdx] & EpdFontFamily::RUBY_CONTINUE) == 0) {
isLastOfGroup = true;
break;
}
if (leaderIdx == 0 || (wordStyles[leaderIdx] & EpdFontFamily::RUBY_CONTINUE) == 0) {
break;
}
leaderIdx--;
}
if (isLastOfGroup && (j + 1 == totalWordCount || (wordStyles[j + 1] & EpdFontFamily::RUBY_CONTINUE) == 0)) {
int groupActualWidth = 0;
for (size_t k = leaderIdx; k <= j; ++k) {
groupActualWidth += measureWordWidth(renderer, fontId, words[k], wordStyles[k]);
}
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[leaderIdx].c_str(), EpdFontFamily::SUP);
if (rubyWidth > groupActualWidth) {
const int rightOverlap = (rubyWidth - groupActualWidth) / 2;
const int ascender = renderer.getFontAscenderSize(fontId);
const int maxOverhang = ascender / 2;
int expansion_added = 0;
if (j + 1 < totalWordCount) {
const uint32_t cpNext = firstCodepoint(words[j + 1]);
if (isCjkIdeograph(cpNext)) {
expansion_added = rightOverlap;
} else {
expansion_added = std::max(0, rightOverlap - maxOverhang);
}
}
extraEndOffset = rightOverlap - expansion_added;
}
}
}
if (currlen + extraEndOffset > effectivePageWidth) {
continue; // Cannot split here as it would overflow the right margin
@@ -942,9 +939,7 @@ std::vector<size_t> ParsedText::computeLineBreaks(const GfxRenderer& renderer, c
}
}
// Favor longer lines when line-breaking costs are equal, to avoid unnecessary short lines in Chinese and Japanese
// text.
if (cost <= dp[i]) {
if (cost < dp[i]) {
dp[i] = cost;
ans[i] = j; // j is the index of the last word in this optimal line
}
@@ -1176,9 +1171,6 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
std::copy(rubyTexts.begin() + lastBreakAt, rubyTexts.begin() + lastBreakAt + copyCount, lineRubyTexts.begin());
}
const int extraStartOffset = calculateRubyExtraStartOffset(lastBreakAt, lineBreak, renderer, fontId);
const int extraEndOffset = calculateRubyExtraEndOffset(lastBreakAt, lineBreak, renderer, fontId);
std::vector<std::string> lineWords;
lineWords.reserve(lineWordCount);
std::vector<EpdFontFamily::Style> lineWordStyles;
@@ -1233,9 +1225,8 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
? CssTextAlign::Right
: blockStyle.alignment;
// For justified text, compute per-gap extra to distribute remaining space evenly.
// extraEndOffset reserves space for any ruby group at the right edge of the line.
const int spareSpace = effectivePageWidth - extraStartOffset - extraEndOffset - lineWordWidthSum - totalNaturalGaps;
// For justified text, compute per-gap extra to distribute remaining space evenly
const int spareSpace = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
const int justifyExtra = (effectiveAlignment == CssTextAlign::Justify && !isLastLine)
? computeJustifyExtra(spareSpace, actualGapCount)
: 0;
@@ -1316,8 +1307,7 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
}
}
const int reorderedSpare =
effectivePageWidth - extraStartOffset - extraEndOffset - reorderedWordWidthSum - reorderedNaturalGaps;
const int reorderedSpare = effectivePageWidth - reorderedWordWidthSum - reorderedNaturalGaps;
const int reorderedJustifyExtra = (effectiveAlignment == CssTextAlign::Justify && !isLastLine)
? computeJustifyExtra(reorderedSpare, reorderedGapCount)
: 0;
@@ -1422,7 +1412,7 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const
}
} else {
// LTR: position words from left to right
int xpos = firstLineIndent + extraStartOffset;
int xpos = firstLineIndent;
if (effectiveAlignment == CssTextAlign::Right) {
xpos = effectivePageWidth - lineWordWidthSum - totalNaturalGaps;
} else if (effectiveAlignment == CssTextAlign::Center) {
-3
View File
@@ -59,9 +59,6 @@ class ParsedText {
void pushVisibleOffset(uint32_t offset);
void insertVisibleOffset(size_t wordIndex, uint32_t offset);
void eraseVisibleOffsetPrefix(size_t count);
int calculateRubyExtraStartOffset(size_t wordIdx, size_t maxWordIdx, const GfxRenderer& renderer, int fontId) const;
int calculateRubyExtraEndOffset(size_t lineStartIdx, size_t lineBreakIdx, const GfxRenderer& renderer,
int fontId) const;
int resolveFirstLineIndent(bool isFirstLine, const GfxRenderer& renderer, int fontId) const;
std::vector<size_t> computeLineBreaks(const GfxRenderer& renderer, int fontId, int pageWidth,
std::vector<uint16_t>& wordWidths, std::vector<bool>& continuesVec,
+1 -1
View File
@@ -31,7 +31,7 @@ namespace {
// match. Keeps <br>-per-paragraph books (common CJK formatting) from
// re-adding container spacing at every paragraph.
// v35: Persist a uint32_t visible-text start offset for every page.
constexpr uint8_t SECTION_FILE_VERSION = 36;
constexpr uint8_t SECTION_FILE_VERSION = 35;
// Written into the version field while a build is in progress; patched to
// SECTION_FILE_VERSION only when the build is finalized. An abandoned /
// crash-interrupted .bin therefore carries version 0, which loadSectionFile rejects
+60 -6
View File
@@ -135,32 +135,86 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int
const bool scanning = renderer.isFontCacheScanning();
const int ascender = renderer.getFontAscenderSize(fontId);
// Resolve ruby positions. Layout (extractLine) has already reserved extraStartOffset on the
// left and extraEndOffset on the right, so the centered rubyX is always within the page margins.
// Resolve ruby collisions left-to-right to prevent adjacent ruby texts from overlapping
struct RubyDrawInfo {
int x;
int width;
std::string text;
BidiUtils::BidiBaseDir baseDir;
};
// hasRuby() is an O(numWords) scan, so resolve it once here rather than per word.
// Both arrays below are only ever read when the line carries ruby, so they stay
// empty (zero allocations) for the ruby-less case, which is every line of a
// non-CJK book. Sized lazily inside the branch.
const bool blockHasRuby = hasRuby();
std::vector<int> wordShiftArr;
std::vector<RubyDrawInfo> rubies;
if (blockHasRuby) {
wordShiftArr.assign(numWords, 0);
rubies.resize(numWords);
int accumulatedShift = 0;
int lastEnd = -9999;
for (uint16_t i = 0; i < numWords; i++) {
wordShiftArr[i] = accumulatedShift;
if (i < rubyTexts.size() && !rubyTexts[i].empty() && (wordStyle(i) & EpdFontFamily::RUBY_CONTINUE) == 0) {
// Find the group size (how many words are part of this ruby annotation)
int groupWordCount = 1;
while (i + groupWordCount < numWords && (wordStyle(i + groupWordCount) & EpdFontFamily::RUBY_CONTINUE) != 0) {
groupWordCount++;
}
// Compute actual width for the group
int groupActualWidth = 0;
for (int k = 0; k < groupWordCount; ++k) {
groupActualWidth += renderer.getTextAdvanceX(fontId, wordText(i + k), wordStyle(i + k));
}
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[i].c_str(), EpdFontFamily::SUP);
const char* word = wordText(i);
const int leaderWordX = xposArr[i] + x;
const int leaderWordX_shifted = leaderWordX + accumulatedShift;
const auto baseDir =
static_cast<BidiUtils::BidiBaseDir>(BidiUtils::detectParagraphLevel(wordText(i), blockStyle.isRtl ? 1 : 0));
rubies[i] = {leaderWordX - (rubyWidth - groupActualWidth) / 2, rubyTexts[i], baseDir};
static_cast<BidiUtils::BidiBaseDir>(BidiUtils::detectParagraphLevel(word, blockStyle.isRtl ? 1 : 0));
const int rubyWidth = renderer.getTextAdvanceX(fontId, rubyTexts[i].c_str(), EpdFontFamily::SUP);
const int screenWidth = renderer.getScreenWidth();
int rubyX = 0;
int groupDrawX = 0;
if (rubyWidth > groupActualWidth) {
rubyX = leaderWordX_shifted - (rubyWidth - groupActualWidth) / 2;
if (i == 0) {
rubyX = std::max(leaderWordX_shifted, rubyX);
}
if (rubyX < lastEnd) {
rubyX = lastEnd;
}
groupDrawX = rubyX + (rubyWidth - groupActualWidth) / 2;
} else {
groupDrawX = leaderWordX_shifted;
rubyX = groupDrawX + (groupActualWidth - rubyWidth) / 2;
if (i == 0) {
rubyX = std::max(leaderWordX_shifted, rubyX);
}
if (rubyX < lastEnd) {
const int push = lastEnd - rubyX;
rubyX = lastEnd;
groupDrawX += push;
}
}
rubyX = std::max(0, std::min(rubyX, screenWidth - rubyWidth));
// Keep groupDrawX aligned if rubyX was clamped by screen edges
if (rubyWidth > groupActualWidth) {
groupDrawX = rubyX + (rubyWidth - groupActualWidth) / 2;
}
rubies[i] = {rubyX, rubyWidth, rubyTexts[i], baseDir};
lastEnd = rubyX + rubyWidth;
// Propagate shift to all words in the group and subsequent words
const int groupShift = groupDrawX - leaderWordX;
accumulatedShift = groupShift;
for (int k = 0; k < groupWordCount; ++k) {
wordShiftArr[i + k] = accumulatedShift;
}
i += groupWordCount - 1;
}
}
@@ -221,7 +275,7 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int
wordY += ascender / 4;
}
const int drawX = wordX;
const int drawX = wordX + (blockHasRuby ? wordShiftArr[i] : 0);
if (boundary > 0) {
// Focus split: draw bold prefix, then the regular suffix at a pre-computed x offset.
+3
View File
@@ -81,6 +81,9 @@ const uint8_t* GfxRenderer::getGlyphBitmap(const EpdFontData* fontData, const Ep
if (sdFont->isOverflowGlyph(glyph)) {
return sdFont->getOverflowBitmap(glyph); // may be nullptr for zero-width glyphs
}
// Prewarmed SD glyph: the mini bitmap is chunked (non-contiguous), so there is
// no fontData->bitmap base to index. Resolve via the per-style chunk table.
return sdFont->miniGlyphBitmap(fontData->glyphMissCtx, glyph->dataOffset);
}
return &fontData->bitmap[glyph->dataOffset];
}
-41
View File
@@ -10,7 +10,6 @@ STR_BROWSE_FILES: "تصفح الملفات"
STR_FILE_TRANSFER: "نقل الملفات"
STR_SETTINGS_TITLE: "الإعدادات"
STR_CONTINUE_READING: "متابعة القراءة"
STR_RESUME: "استئناف"
STR_NO_OPEN_BOOK: "لا يوجد كتاب مفتوح"
STR_START_READING: "ابدأ القراءة أدناه"
STR_NO_FILES_FOUND: "لم يتم العثور على ملفات"
@@ -23,20 +22,9 @@ STR_INDEX_FAILED: "فشلت الفهرسة - كتاب غير صالح"
STR_MEMORY_ERROR: "خطأ في الذاكرة"
STR_PAGE_LOAD_ERROR: "خطأ في تحميل الصفحة"
STR_EMPTY_FILE: "ملف فارغ"
STR_INVALID_BMP_FILE: "ملف BMP غير صالح"
STR_FILE_OPEN_FAILED: "تعذر فتح الملف"
STR_OUT_OF_BOUNDS: "خارج النطاق"
STR_LOADING: "جاري التحميل..."
STR_LOADING_POPUP: "جاري التحميل"
STR_LOOKUP: "بحث"
STR_DICT_LOOKING_UP: "جاري البحث..."
STR_DICT_INDEXING: "جاري فهرسة القاموس..."
STR_DICT_NOT_FOUND: "غير موجود"
STR_DICT_NO_DICT_SET: "لم يتم تحديد قاموس"
STR_DICT_ERROR: "خطأ في القاموس"
STR_DICT_READ_FAILED: "تعذر قراءة التعريف"
STR_DICT_DECOMPRESS_ERROR: "تعذر فك ضغط التعريف"
STR_DICT_LOW_MEMORY: "الذاكرة غير كافية"
STR_WIFI_NETWORKS: "شبكات Wi-Fi"
STR_NO_NETWORKS: "لم يتم العثور على شبكات"
STR_NETWORKS_FOUND: "تم العثور على %zu شبكة"
@@ -93,7 +81,6 @@ STR_EOB_CONTINUE_WITH: "المتابعة إلى"
STR_SHORT_PWR_BTN: "ضغطة قصيرة على زر التشغيل"
STR_ORIENTATION: "اتجاه القراءة"
STR_SIDE_BTN_LAYOUT: "تخطيط الأزرار الجانبية (أثناء القراءة)"
STR_TOUCH_READER_CONTROLS: "التحكم باللمس (أثناء القراءة)"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "تدوير الأزرار الأمامية مع الشاشة"
STR_LONG_PRESS_BEHAVIOR: "سلوك الضغطة الطويلة"
STR_LONG_PRESS_BEHAVIOR_OFF: "إيقاف"
@@ -103,13 +90,6 @@ STR_LONG_PRESS_MENU: "قائمة الضغطة الطويلة"
STR_FONT_PREVIEW_TEXT: "نص حكيم له سر قاطع وذو شأن عظيم مكتوب على ثوب أخضر ومغلف بجلد أزرق"
STR_FONT_FAMILY: "خط القراءة"
STR_FONT_SIZE: "حجم الخط"
STR_TEXT_SETTINGS: "إعدادات النص"
STR_FONT: "الخط"
STR_SIZE: "الحجم"
STR_LAYOUT: "التخطيط"
STR_ALIGNMENT: "المحاذاة"
STR_STYLE: "النمط"
STR_NOT_IN_PREVIEW: "غير معروض في المعاينة"
STR_LINE_SPACING: "تباعد الأسطر"
STR_SCREEN_MARGIN: "هوامش شاشة القراءة"
STR_PARA_ALIGNMENT: "محاذاة الفقرات"
@@ -128,15 +108,7 @@ STR_PASSWORD: "كلمة المرور"
STR_SYNC_SERVER_URL: "عنوان خادم المزامنة"
STR_DOCUMENT_MATCHING: "مطابقة المستندات"
STR_SEND_METADATA: "إرسال البيانات الوصفية للمستند"
STR_SYNC_BEHAVIOR: "سلوك المزامنة"
STR_ASK_EVERY_TIME: "اسأل في كل مرة"
STR_SMART_SYNC: "مزامنة ذكية"
STR_AUTHENTICATE: "تسجيل الدخول"
STR_SIGN_UP: "إنشاء حساب"
STR_CREATING_ACCOUNT: "جاري إنشاء الحساب..."
STR_ACCOUNT_CREATED: "تم إنشاء الحساب"
STR_SIGNUP_FAILED: "فشل إنشاء الحساب"
STR_USERNAME_TAKEN: "اسم المستخدم مسجل مسبقا"
STR_KOREADER_USERNAME: "اسم مستخدم KOReader"
STR_KOREADER_PASSWORD: "كلمة مرور KOReader"
STR_FILENAME: "اسم الملف"
@@ -182,7 +154,6 @@ STR_PREV_NEXT: "السابق/التالي"
STR_NEXT_PREV: "التالي/السابق"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "إشارة مرجعية"
STR_DICTIONARY: "القاموس"
STR_DISABLED: "معطل"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
@@ -239,7 +210,6 @@ STR_CONNECT: "اتصال"
STR_OPEN: "فتح"
STR_DOWNLOAD: "تنزيل"
STR_RETRY: "إعادة المحاولة"
STR_TAP_TO_RETRY: "اضغط لإعادة المحاولة"
STR_YES: "نعم"
STR_NO: "لا"
STR_SHOW: "عرض"
@@ -252,9 +222,6 @@ STR_DIR_RIGHT: "يمين"
STR_DIR_UP: "أعلى"
STR_DIR_DOWN: "أسفل"
STR_OK_BUTTON: "موافق"
STR_KEY_SHIFT: "Shift"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "مرشح غلاف شاشة السكون"
STR_FILTER_CONTRAST: "التباين"
STR_CUSTOMISE_STATUS_BAR: "تخصيص شريط الحالة"
@@ -353,7 +320,6 @@ STR_UPLOAD_LOCAL: "رفع التقدم المحلي"
STR_NO_REMOTE_MSG: "لا يوجد تقدم على الخادم"
STR_UPLOAD_PROMPT: "رفع الموضع الحالي؟"
STR_UPLOAD_SUCCESS: "تم رفع التقدم!"
STR_ALREADY_SYNCED: "متزامن مسبقا"
STR_SYNC_FAILED_MSG: "فشلت المزامنة"
STR_SAVE_PROGRESS_FAILED: "تعذر حفظ التقدم"
STR_SECTION_PREFIX: "القسم "
@@ -363,7 +329,6 @@ STR_EMBEDDED_STYLE: "التنسيق المضمن"
STR_FOCUS_READING: "قراءة مركزة"
STR_OPDS_SERVER_URL: "عنوان خادم OPDS"
STR_PWR_BTN_FOOTNOTE_BACK: "عودة سريعة من الحواشي"
STR_BACK_SHORT_TO_FILE_BROWSER: "عودة سريعة إلى متصفح الملفات"
STR_SET_SLEEP_COVER: "تعيين الغلاف"
STR_FOOTNOTES: "الحواشي"
STR_NO_FOOTNOTES: "لا توجد حواش في هذه الصفحة"
@@ -378,12 +343,6 @@ STR_SERVER_NAME: "اسم الخادم"
STR_NO_SERVERS: "لم يتم إعداد خوادم OPDS"
STR_DELETE_SERVER: "حذف الخادم"
STR_OPDS_SERVERS: "خوادم OPDS"
STR_OPDS_DOWNLOAD_FOLDER: "مجلد التنزيل"
STR_OPDS_FILENAME_FORMAT: "تنسيق اسم الملف"
STR_FMT_AUTHOR_TITLE: "المؤلف - العنوان"
STR_FMT_TITLE_AUTHOR: "العنوان - المؤلف"
STR_FMT_TITLE: "العنوان"
STR_OPDS_SD_ROOT: "جذر بطاقة SD"
STR_AUTO_TURN_ENABLED: "التقليب التلقائي مفعل: "
STR_AUTO_TURN_PAGES_PER_MIN: "التقليب التلقائي (صفحات في الدقيقة)"
STR_MANAGE_FONTS: "إدارة الخطوط"
+1 -118
View File
@@ -10,7 +10,6 @@ STR_BROWSE_FILES: "Прагляд файлаў"
STR_FILE_TRANSFER: "Перадача файлаў"
STR_SETTINGS_TITLE: "Налады"
STR_CONTINUE_READING: "Працягнуць чытанне"
STR_RESUME: "Працягнуць"
STR_NO_OPEN_BOOK: "Няма адкрытай кнігі"
STR_START_READING: "Пачніце чытанне ніжэй"
STR_NO_FILES_FOUND: "Файлы не знойдзены"
@@ -19,32 +18,17 @@ STR_NO_CHAPTERS: "Раздзелаў няма"
STR_END_OF_BOOK: "Канец кнігі"
STR_EMPTY_CHAPTER: "Пусты раздзел"
STR_INDEXING: "Індэксацыя"
STR_INDEX_FAILED: "Памылка індэксацыі — няправільная кніга"
STR_MEMORY_ERROR: "Памылка памяці"
STR_PAGE_LOAD_ERROR: "Памылка загрузкі старонкі"
STR_EMPTY_FILE: "Пусты файл"
STR_INVALID_BMP_FILE: "Няправільны файл BMP"
STR_FILE_OPEN_FAILED: "Не ўдалося адкрыць файл"
STR_OUT_OF_BOUNDS: "Выхад за межы"
STR_LOADING: "Загрузка..."
STR_LOADING_POPUP: "Загрузка"
STR_LOOKUP: "Шукаць"
STR_DICT_LOOKING_UP: "Пошук..."
STR_DICT_INDEXING: "Індэксацыя слоўніка..."
STR_DICT_NOT_FOUND: "Не знойдзена"
STR_DICT_NO_DICT_SET: "Слоўнік не выбраны"
STR_DICT_ERROR: "Памылка слоўніка"
STR_DICT_READ_FAILED: "Не ўдалося прачытаць азначэнне"
STR_DICT_DECOMPRESS_ERROR: "Не ўдалося распакаваць азначэнне"
STR_DICT_LOW_MEMORY: "Не хапае памяці"
STR_WIFI_NETWORKS: "Сеткі Wi-Fi"
STR_NO_NETWORKS: "Сеткі не знойдзены"
STR_NETWORKS_FOUND: "Знойдзена сетак: %zu"
STR_SCANNING: "Сканаванне..."
STR_FINDING_SAVED_WIFI: "Пошук захаванай сеткі Wi-Fi..."
STR_CONNECTING: "Падключэнне..."
STR_CONNECTING_SAVED_WIFI: "Падключэнне да захаванай сеткі Wi-Fi..."
STR_SHOW_NETWORKS: "Паказаць"
STR_CONNECTED: "Падключана!"
STR_CONNECTION_FAILED: "Памылка падключэння"
STR_FORGET_NETWORK: "Забыць сетку?"
@@ -86,11 +70,7 @@ STR_ORIENTATION: "Арыентацыя чытання"
STR_SIDE_BTN_LAYOUT: "Бакавыя кнопкі"
STR_TOUCH_READER_CONTROLS: "Сэнсарнае кіраванне чытаннем"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Арыентаваць пярэднія кнопкі"
STR_LONG_PRESS_BEHAVIOR: "Дзеянне доўгага націскання"
STR_LONG_PRESS_BEHAVIOR_OFF: "ВЫКЛ"
STR_LONG_PRESS_BEHAVIOR_SKIP: "Змена раздзела"
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Змена арыентацыі"
STR_LONG_PRESS_MENU: "Меню доўгім націсканнем"
STR_LONG_PRESS_SKIP: "Доўгае націсканне - змена раздзела"
STR_FONT_PREVIEW_TEXT: "У Іўі худы жвавы чорт у зялёнай камізэльцы пабег пад'есці фаршу з юшкай"
STR_FONT_FAMILY: "Шрыфт чытання"
STR_FONT_SIZE: "Памер шрыфту інтэрфейсу"
@@ -116,15 +96,7 @@ STR_PASSWORD: "Пароль"
STR_SYNC_SERVER_URL: "URL сервера сінхранізацыі"
STR_DOCUMENT_MATCHING: "Супастаўленне дакументаў"
STR_SEND_METADATA: "Адпраўляць метаданыя дакумента"
STR_SYNC_BEHAVIOR: "Рэжым сінхранізацыі"
STR_ASK_EVERY_TIME: "Пытацца кожны раз"
STR_SMART_SYNC: "Разумная сінхранізацыя"
STR_AUTHENTICATE: "Аўтарызацыя"
STR_SIGN_UP: "Рэгістрацыя"
STR_CREATING_ACCOUNT: "Стварэнне ўліковага запісу..."
STR_ACCOUNT_CREATED: "Уліковы запіс створаны"
STR_SIGNUP_FAILED: "Памылка рэгістрацыі"
STR_USERNAME_TAKEN: "Такое імя карыстальніка ўжо занята"
STR_KOREADER_USERNAME: "Імя карыстальніка KOReader"
STR_KOREADER_PASSWORD: "Пароль KOReader"
STR_FILENAME: "Імя файла"
@@ -160,7 +132,6 @@ STR_ALWAYS: "Заўсёды"
STR_IGNORE: "Ігнараваць"
STR_SLEEP: "Сон"
STR_PAGE_TURN: "Перагортванне"
STR_FORCE_REFRESH: "Абнавіць экран"
STR_PORTRAIT: "Партрэт"
STR_LANDSCAPE_CW: "Ландшафт (CW)"
STR_INVERTED: "Інверсія"
@@ -168,10 +139,6 @@ STR_ORIENTATION_INVERTED: "Партрэт 180°"
STR_LANDSCAPE_CCW: "Ландшафт (CCW)"
STR_PREV_NEXT: "Назад/Наперад"
STR_NEXT_PREV: "Наперад/Назад"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Закладка"
STR_DICTIONARY: "Слоўнік"
STR_DISABLED: "Адключана"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
STR_TIGHT: "Вузкі"
@@ -196,7 +163,6 @@ STR_NO_UPDATE: "Абнаўленняў няма"
STR_UPDATE_FAILED: "Памылка абнаўлення"
STR_UPDATE_COMPLETE: "Абнаўленне завершана"
STR_POWER_ON_HINT: "Утрымлівайце кнопку сілкавання для ўключэння"
STR_RESTARTING_HINT: "Перазапуск... Калі прылада не перазапусцілася, утрымлівайце кнопку сілкавання некалькі секунд."
STR_NO_ENTRIES: "Запісы не знойдзены"
STR_DOWNLOADING: "Спампоўка..."
STR_DOWNLOAD_FAILED: "Памылка спампоўкі"
@@ -205,8 +171,6 @@ STR_UNNAMED: "Без імя"
STR_NO_SERVER_URL: "URL сервера не наладжаны"
STR_FETCH_FEED_FAILED: "Не ўдалося атрымаць стужку"
STR_PARSE_FEED_FAILED: "Не ўдалося апрацаваць стужку"
STR_NEXT_PAGE: "Наступная старонка »"
STR_PREV_PAGE: "« Папярэдняя старонка"
STR_NETWORK_PREFIX: "Сетка:"
STR_IP_ADDRESS_PREFIX: "IP-адрас:"
STR_ERROR_GENERAL_FAILURE: "Памылка: Агульная памылка"
@@ -227,7 +191,6 @@ STR_CONNECT: "Падкл."
STR_OPEN: "Адкрыць"
STR_DOWNLOAD: "Спампаваць"
STR_RETRY: "Паўтарыць"
STR_TAP_TO_RETRY: "Націсніце, каб паўтарыць"
STR_YES: "Так"
STR_NO: "Не"
STR_STATE_ON: "УКЛ"
@@ -238,23 +201,16 @@ STR_DIR_RIGHT: "Управа"
STR_DIR_UP: "Уверх"
STR_DIR_DOWN: "Уніз"
STR_OK_BUTTON: "OK"
STR_KEY_SHIFT: "Shift"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "Фільтр экрана сну"
STR_FILTER_CONTRAST: "Кантраст"
STR_UI_THEME: "Тэма інтэрфейсу"
STR_THEME_CLASSIC: "Класічная"
STR_THEME_LYRA: "Lyra"
STR_THEME_ROUNDEDRAFF: "RoundedRaff"
STR_THEME_LYRA_EXTENDED: "Lyra Extended"
STR_SUNLIGHT_FADING_FIX: "Кампенсацыя выцвітання"
STR_QUICK_RESUME_TIMEOUT: "Хуткае узнаўленне пасля таймаўту"
STR_REMAP_FRONT_BUTTONS: "Пераназначыць пярэднія кнопкі"
STR_BOOKMARKS: "Закладкі"
STR_BOOKMARK_ADDED: "Закладка дададзена."
STR_OPDS_BROWSER: "OPDS браўзер"
STR_SEARCH: "Пошук"
STR_COVER_CUSTOM: "Вокладка + Свой"
STR_QUICK_RESUME: "Хуткае узнаўленне"
STR_MENU_RECENT_BOOKS: "Нядаўнія кнігі"
@@ -303,7 +259,6 @@ STR_UPLOAD_LOCAL: "Адправіць лакальны прагрэс"
STR_NO_REMOTE_MSG: "Аддалены прагрэс не знойдзены"
STR_UPLOAD_PROMPT: "Адправіць бягучую пазіцыю?"
STR_UPLOAD_SUCCESS: "Прагрэс адпраўлены!"
STR_ALREADY_SYNCED: "Ужо сінхранізавана"
STR_SYNC_FAILED_MSG: "Памылка сінхранізацыі"
STR_SAVE_PROGRESS_FAILED: "Не ўдалося захаваць прагрэс"
STR_SECTION_PREFIX: "Раздзел"
@@ -312,16 +267,11 @@ STR_BOOK_S_STYLE: "Стыль кнігі"
STR_EMBEDDED_STYLE: "Убудаваны стыль"
STR_FOCUS_READING: "Фокуснае чытанне"
STR_OPDS_SERVER_URL: "URL OPDS сервера"
STR_PWR_BTN_FOOTNOTE_BACK: "Хуткае вяртанне з зносак"
STR_BACK_SHORT_TO_FILE_BROWSER: "Кароткае «Назад» да файлаў"
STR_SET_SLEEP_COVER: "Задаць вокладку"
STR_SCREENSHOT_BUTTON: "Зрабіць здымак экрана"
STR_IMAGES: "Выявы"
STR_IMAGES_DISPLAY: "Паказваць"
STR_IMAGES_PLACEHOLDER: "Запаўняльнік"
STR_IMAGES_SUPPRESS: "Хаваць"
STR_EOB_HOME: "Галоўная"
STR_EOB_CONTINUE_WITH: "Працягнуць з"
STR_SHOW_HIDDEN_FILES: "Паказваць схаваныя файлы"
STR_REMOVE_READ_FROM_RECENTS: "Ачышчаць прачытаныя кнігі са спісу нядаўніх"
STR_MOVE_FINISHED_TO_READ: "Перамяшчаць прачытаныя кнігі ў тэчку Read"
@@ -343,26 +293,7 @@ STR_EXAMPLE_BOOK: "Назва кнігі"
STR_PREVIEW: "Перадпрагляд"
STR_TITLE: "Назва"
STR_BATTERY: "Батарэя"
STR_XTC_STATUS_BAR: "Радок стану XTC"
STR_BOTTOM: "Унізе"
STR_TOP: "Уверсе"
STR_CLOCK: "Гадзіннік"
STR_CLOCK_UTC_OFFSET: "Зрух гадзінніка ад UTC"
STR_CLOCK_FORMAT: "Фармат часу"
STR_CLOCK_FORMAT_24H: "24-гадзінны"
STR_CLOCK_FORMAT_12H: "12-гадзінны"
STR_CURRENT_TIME: "Бягучы час:"
STR_NEXT_FIELD: "Далей"
STR_CLOCK_SYNC: "Сінхранізаваць гадзіннік"
STR_CLOCK_SYNC_NOW: "Сінхранізаваць зараз"
STR_CLOCK_SYNCING: "Сінхранізацыя праз NTP..."
STR_CLOCK_SYNC_OK: "Гадзіннік сінхранізаваны"
STR_CLOCK_SYNC_FAIL: "Памылка сінхранізацыі"
STR_CLOCK_SYNC_NO_WIFI: "Wi-Fi не падключаны"
STR_CLOCK_SYNC_NO_WIFI_HINT: "Спачатку падключыцеся да Wi-Fi, потым паўтарыце."
STR_CLOCK_SYNCED: "Гадзіннік сінхранізаваны"
STR_DELETE: "Выдаліць"
STR_CONFIRM_DELETE_BOOKMARK: "Выдаліць гэтую закладку?"
STR_DISPLAY_QR: "Паказаць старонку як QR"
STR_FOOTNOTES: "Зноскі"
STR_NO_FOOTNOTES: "На гэтай старонцы няма зносак"
@@ -371,61 +302,13 @@ STR_SLEEP_TIMER_VALUE_FORMAT: "%u хв"
STR_SLEEP_NEVER: "Ніколі"
STR_STEP_HINT_FRONT: "Пярэднія кнопкі:"
STR_STEP_HINT_SIDE: "Бакавыя кнопкі:"
STR_ADD_SERVER: "Дадаць сервер"
STR_SERVER_NAME: "Назва сервера"
STR_NO_SERVERS: "Серверы OPDS не наладжаны"
STR_DELETE_SERVER: "Выдаліць сервер"
STR_OPDS_SERVERS: "Серверы OPDS"
STR_OPDS_DOWNLOAD_FOLDER: "Папка для спампоўкі"
STR_OPDS_FILENAME_FORMAT: "Фармат назвы файла"
STR_FMT_AUTHOR_TITLE: "Аўтар - Назва"
STR_FMT_TITLE_AUTHOR: "Назва - Аўтар"
STR_FMT_TITLE: "Назва"
STR_OPDS_SD_ROOT: "Корань SD"
STR_AUTO_TURN_ENABLED: "Аўтаперагортванне: "
STR_AUTO_TURN_PAGES_PER_MIN: "Аўтаперагортванне (старонак за хвіліну)"
STR_MANAGE_FONTS: "Кіраванне шрыфтамі"
STR_FONT_BROWSER: "Агляд шрыфтоў"
STR_LOADING_FONT_LIST: "Загрузка спісу шрыфтоў..."
STR_NO_FONTS_AVAILABLE: "Няма даступных шрыфтоў"
STR_FONT_INSTALLED: "Шрыфт усталяваны!"
STR_FONT_INSTALL_FAILED: "Не ўдалося ўсталяваць шрыфт"
STR_INSTALLED: "Усталявана"
STR_DOWNLOAD_ALL: "Спампаваць усе"
STR_UPDATE_ALL: "Абнавіць усе"
STR_UPDATE_AVAILABLE: "Абнавіць"
STR_CRASH_TITLE: "Збой сістэмы"
STR_CRASH_DESCRIPTION: "Падрабязная справаздача захавана ў crash_report.txt. Калі ласка, далучыце гэты файл да паведамлення пра памылку."
STR_CRASH_REASON: "Прычына збою:"
STR_CRASH_NO_REASON: "(Прычына не зафіксавана)"
STR_TILT_PAGE_TURN: "Перагортванне нахілам"
STR_KB_HINT_MOVE_CURSOR: "Націсніце ЎЛЕВА ці ЎПРАВА, каб перамясціць курсор"
STR_KB_HINT_RETURN_CURSOR: "Націсніце ЎЛЕВА, каб вярнуцца да курсора"
STR_KB_HINT_HIDE_PASSWORD: "Утрымлівайце ЎПРАВА, потым [***], каб схаваць пароль"
STR_KB_HINT_SHOW_PASSWORD: "Утрымлівайце ЎПРАВА, потым [abc], каб паказаць пароль"
STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Націсніце [***], каб схаваць пароль"
STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Націсніце [abc], каб паказаць пароль"
STR_KB_HINT_EDIT_ENTRY: "Утрымлівайце ЎВЕРХ, каб рэдагаваць запіс"
STR_KB_TIPS: "Падказкі:"
STR_KB_HINT_RETURN_KEYBOARD: "Націсніце ЎНІЗ, каб вярнуцца да клавіятуры"
STR_KB_HINT_EXIT_URL_MODE: "Націсніце ABC, каб выйсці з рэжыму URL"
STR_KB_HINT_CLEAR_TEXT: "Утрымлівайце DEL, каб сцерці ўвесь тэкст"
STR_KB_HINT_SECONDARY_CHAR: "Утрымлівайце SELECT для дадатковага сімвала"
STR_KB_HINT_UPPER_SECONDARY: "Утрымлівайце SELECT для ВЯЛІКАЙ ЛІТАРЫ ці дадатковага сімвала"
STR_KB_HINT_LOWER_SECONDARY: "Утрымлівайце SELECT для малой літары ці дадатковага сімвала"
STR_KB_HINT_URL_SNIPPETS: "Націсніце URL для шаблонаў"
STR_SD_FIRMWARE_UPDATE: "Абнаўленне прашыўкі з SD-карты"
STR_SELECT_FIRMWARE_FILE: "Абярыце файл прашыўкі (.bin)"
STR_NO_BIN_FILES: "Файлы .bin не знойдзены"
STR_VALIDATING_FIRMWARE: "Праверка прашыўкі..."
STR_INVALID_FIRMWARE: "Няправільны файл прашыўкі"
STR_FIRMWARE_TOO_LARGE: "Прашыўка завялікая для раздзела"
STR_FIRMWARE_TOO_SMALL: "Файл прашыўкі занадта малы"
STR_FIRMWARE_UPDATE_PROMPT: "Абнавіць прашыўку?"
STR_FIRMWARE_FILE_OPEN_FAILED: "Не ўдалося адкрыць файл"
STR_FIRMWARE_WRITE_FAILED: "Не ўдалося запісаць прашыўку"
STR_FIRMWARE_UPDATE_DO_NOT_POWER_OFF: "Не выключайце прыладу!"
STR_RECOVERY_MODE: "Рэжым аднаўлення"
STR_RECOVERY_MODE_HINT: "Змясціце firmware.bin у корань SD-карты і абярыце яго"
STR_ADD_HIDDEN_NETWORK: "Дадаць схаваную сетку..."
STR_ENTER_WIFI_SSID: "Увядзіце назву сеткі (SSID)"
+8 -49
View File
@@ -9,7 +9,6 @@ STR_BROWSE_FILES: "Pregled datoteka"
STR_FILE_TRANSFER: "Prijenos datoteka"
STR_SETTINGS_TITLE: "Postavke"
STR_CONTINUE_READING: "Nastavi čitanje"
STR_RESUME: "Nastavi"
STR_NO_OPEN_BOOK: "Nema otvorene knjige"
STR_START_READING: "Počni čitati ispod"
STR_NO_FILES_FOUND: "Nema pronađenih datoteka"
@@ -22,20 +21,9 @@ STR_INDEX_FAILED: "Indeksiranje nije uspjelo - nevažeća knjiga"
STR_MEMORY_ERROR: "Greška memorije"
STR_PAGE_LOAD_ERROR: "Greška pri učitavanju stranice"
STR_EMPTY_FILE: "Prazna datoteka"
STR_INVALID_BMP_FILE: "Nevažeća BMP datoteka"
STR_FILE_OPEN_FAILED: "Datoteka se ne može otvoriti"
STR_OUT_OF_BOUNDS: "Izvan granica"
STR_LOADING: "Učitavanje..."
STR_LOADING_POPUP: "Učitavanje"
STR_LOOKUP: "Potraži"
STR_DICT_LOOKING_UP: "Traženje..."
STR_DICT_INDEXING: "Indeksiranje rječnika..."
STR_DICT_NOT_FOUND: "Nije pronađeno"
STR_DICT_NO_DICT_SET: "Nije postavljen rječnik"
STR_DICT_ERROR: "Greška rječnika"
STR_DICT_READ_FAILED: "Čitanje definicije nije uspjelo"
STR_DICT_DECOMPRESS_ERROR: "Dekompresija definicije nije uspjela"
STR_DICT_LOW_MEMORY: "Nedovoljno memorije"
STR_WIFI_NETWORKS: "Wi-Fi mreže"
STR_NO_NETWORKS: "Nema pronađenih mreža"
STR_NETWORKS_FOUND: "%zu pronađenih mreža"
@@ -92,7 +80,6 @@ STR_EOB_CONTINUE_WITH: "Nastavi sa"
STR_SHORT_PWR_BTN: "Kratak klik dugmeta napajanja"
STR_ORIENTATION: "Orijentacija čitanja"
STR_SIDE_BTN_LAYOUT: "Raspored bočnih dugmadi (čitač)"
STR_TOUCH_READER_CONTROLS: "Dodirne kontrole čitača"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Orijentiši prednja dugmad"
STR_LONG_PRESS_BEHAVIOR: "Ponašanje dugog pritiska dugmeta"
STR_LONG_PRESS_BEHAVIOR_OFF: "ISKLJUČENO"
@@ -100,15 +87,8 @@ STR_LONG_PRESS_BEHAVIOR_SKIP: "Preskakanje poglavlja"
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Promjena orijentacije"
STR_LONG_PRESS_MENU: "Meni dugog pritiska"
STR_FONT_PREVIEW_TEXT: "Brza smeđa lisica preskače lijenog psa"
STR_FONT_FAMILY: "Porodica pisma čitača"
STR_FONT_SIZE: "Veličina pisma čitača"
STR_TEXT_SETTINGS: "Postavke teksta"
STR_FONT: "Pismo"
STR_SIZE: "Veličina"
STR_LAYOUT: "Izgled"
STR_ALIGNMENT: "Poravnanje"
STR_STYLE: "Stil"
STR_NOT_IN_PREVIEW: "Nije prikazano u pregledu"
STR_FONT_FAMILY: "Porodica fonta čitača"
STR_FONT_SIZE: "Veličina fonta čitača"
STR_LINE_SPACING: "Razmak između redova čitača"
STR_SCREEN_MARGIN: "Margina ekrana čitača"
STR_PARA_ALIGNMENT: "Poravnanje paragrafa čitača"
@@ -127,15 +107,7 @@ STR_PASSWORD: "Lozinka"
STR_SYNC_SERVER_URL: "URL servera za sinhronizaciju"
STR_DOCUMENT_MATCHING: "Podudaranje dokumenata"
STR_SEND_METADATA: "Pošalji metapodatke dokumenta"
STR_SYNC_BEHAVIOR: "Ponašanje sinhronizacije"
STR_ASK_EVERY_TIME: "Pitaj svaki put"
STR_SMART_SYNC: "Pametna sinhronizacija"
STR_AUTHENTICATE: "Autentifikuj"
STR_SIGN_UP: "Registruj se"
STR_CREATING_ACCOUNT: "Kreiranje računa..."
STR_ACCOUNT_CREATED: "Račun je kreiran"
STR_SIGNUP_FAILED: "Registracija nije uspjela"
STR_USERNAME_TAKEN: "Korisničko ime je već registrovano"
STR_KOREADER_USERNAME: "KOReader korisničko ime"
STR_KOREADER_PASSWORD: "KOReader lozinka"
STR_FILENAME: "Naziv datoteke"
@@ -181,7 +153,6 @@ STR_PREV_NEXT: "Prethodno/Sljedeće"
STR_NEXT_PREV: "Sljedeće/Prethodno"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Obilježivač"
STR_DICTIONARY: "Rječnik"
STR_DISABLED: "Onemogućeno"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
@@ -238,7 +209,6 @@ STR_CONNECT: "Poveži"
STR_OPEN: "Otvori"
STR_DOWNLOAD: "Preuzmi"
STR_RETRY: "Pokušaj ponovo"
STR_TAP_TO_RETRY: "Dodirni za ponovni pokušaj"
STR_YES: "Da"
STR_NO: "Ne"
STR_SHOW: "Prikaži"
@@ -251,9 +221,6 @@ STR_DIR_RIGHT: "Desno"
STR_DIR_UP: "Gore"
STR_DIR_DOWN: "Dolje"
STR_OK_BUTTON: "OK"
STR_KEY_SHIFT: "Shift"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "Filter korica ekrana mirovanja"
STR_FILTER_CONTRAST: "Kontrast"
STR_CUSTOMISE_STATUS_BAR: "Prilagodi statusnu traku"
@@ -352,7 +319,6 @@ STR_UPLOAD_LOCAL: "Pošalji lokalni napredak"
STR_NO_REMOTE_MSG: "Nije pronađen udaljeni napredak"
STR_UPLOAD_PROMPT: "Poslati trenutnu poziciju?"
STR_UPLOAD_SUCCESS: "Napredak poslan!"
STR_ALREADY_SYNCED: "Već sinhronizovano"
STR_SYNC_FAILED_MSG: "Sinhronizacija nije uspjela"
STR_SAVE_PROGRESS_FAILED: "Napredak nije mogao biti sačuvan"
STR_SECTION_PREFIX: "Sekcija "
@@ -362,7 +328,6 @@ STR_EMBEDDED_STYLE: "Ugrađeni stil"
STR_FOCUS_READING: "Fokusirano čitanje"
STR_OPDS_SERVER_URL: "URL OPDS servera"
STR_PWR_BTN_FOOTNOTE_BACK: "Brzi povratak iz fusnota"
STR_BACK_SHORT_TO_FILE_BROWSER: "Brzi povratak na pregled datoteka"
STR_SET_SLEEP_COVER: "Postavi korice"
STR_FOOTNOTES: "Fusnote"
STR_NO_FOOTNOTES: "Nema fusnota na ovoj stranici"
@@ -377,20 +342,14 @@ STR_SERVER_NAME: "Naziv servera"
STR_NO_SERVERS: "Nema podešenih OPDS servera"
STR_DELETE_SERVER: "Obriši server"
STR_OPDS_SERVERS: "OPDS serveri"
STR_OPDS_DOWNLOAD_FOLDER: "Folder za preuzimanje"
STR_OPDS_FILENAME_FORMAT: "Format naziva datoteke"
STR_FMT_AUTHOR_TITLE: "Autor - Naslov"
STR_FMT_TITLE_AUTHOR: "Naslov - Autor"
STR_FMT_TITLE: "Naslov"
STR_OPDS_SD_ROOT: "SD korijen"
STR_AUTO_TURN_ENABLED: "Automatsko okretanje omogućeno: "
STR_AUTO_TURN_PAGES_PER_MIN: "Automatsko okretanje (stranica po minuti)"
STR_MANAGE_FONTS: "Upravljaj pismima"
STR_FONT_BROWSER: "Pregledač pisama"
STR_LOADING_FONT_LIST: "Učitavanje liste pisama..."
STR_NO_FONTS_AVAILABLE: "Nema dostupnih pisama"
STR_FONT_INSTALLED: "Pismo instalirano!"
STR_FONT_INSTALL_FAILED: "Instalacija pisma nije uspjela"
STR_MANAGE_FONTS: "Upravljaj fontovima"
STR_FONT_BROWSER: "Pregledač fontova"
STR_LOADING_FONT_LIST: "Učitavanje liste fontova..."
STR_NO_FONTS_AVAILABLE: "Nema dostupnih fontova"
STR_FONT_INSTALLED: "Font instaliran!"
STR_FONT_INSTALL_FAILED: "Instalacija fonta nije uspjela"
STR_INSTALLED: "Instalirano"
STR_DOWNLOAD_ALL: "Preuzmi sve"
STR_UPDATE_ALL: "Ažuriraj sve"
-3
View File
@@ -34,9 +34,6 @@ STR_DICT_INDEXING: "S'està indexant el diccionari..."
STR_DICT_NOT_FOUND: "No s'ha trobat"
STR_DICT_NO_DICT_SET: "No hi ha cap diccionari configurat"
STR_DICT_ERROR: "Error del diccionari"
STR_DICT_READ_FAILED: "No s'ha pogut llegir la definició"
STR_DICT_DECOMPRESS_ERROR: "No s'ha pogut descomprimir la definició"
STR_DICT_LOW_MEMORY: "No hi ha prou memòria"
STR_WIFI_NETWORKS: "Xarxes Wi-Fi"
STR_NO_NETWORKS: "No s'han trobat xarxes"
STR_NETWORKS_FOUND: "%zu xarxes trobades"
-5
View File
@@ -21,8 +21,6 @@ STR_INDEXING: "Indexování"
STR_MEMORY_ERROR: "Chyba paměti"
STR_PAGE_LOAD_ERROR: "Chyba načítání stránky"
STR_EMPTY_FILE: "Prázdný soubor"
STR_INVALID_BMP_FILE: "Neplatný soubor BMP"
STR_FILE_OPEN_FAILED: "Nelze otevřít soubor"
STR_OUT_OF_BOUNDS: "Mimo hranice"
STR_LOADING: "Načítání..."
STR_LOADING_POPUP: "Načítání"
@@ -334,9 +332,6 @@ STR_DICT_INDEXING: "Indexování slovníku..."
STR_DICT_LOOKING_UP: "Vyhledávání..."
STR_DICT_NOT_FOUND: "Nenalezeno"
STR_DICT_NO_DICT_SET: "Není nastaven žádný slovník"
STR_DICT_READ_FAILED: "Nelze přečíst definici"
STR_DICT_DECOMPRESS_ERROR: "Nelze dekomprimovat definici"
STR_DICT_LOW_MEMORY: "Nedostatek paměti"
STR_DISABLED: "Zakázáno"
STR_DISPLAY_QR: "Zobrazit stránku jako QR"
STR_DOWNLOAD_ALL: "Stáhnout vše"
-1
View File
@@ -423,7 +423,6 @@ STR_VALIDATING_FIRMWARE: "Validating firmware..."
STR_INVALID_FIRMWARE: "Invalid firmware file"
STR_FIRMWARE_TOO_LARGE: "Firmware too large for partition"
STR_FIRMWARE_TOO_SMALL: "Firmware file is too small"
STR_FIRMWARE_WRONG_DEVICE: "Firmware is for a different device"
STR_FIRMWARE_UPDATE_PROMPT: "Update firmware?"
STR_FIRMWARE_FILE_OPEN_FAILED: "Cannot open file"
STR_FIRMWARE_WRITE_FAILED: "Firmware write failed"
+13 -126
View File
@@ -10,7 +10,6 @@ STR_BROWSE_FILES: "Parcourir les fichiers"
STR_FILE_TRANSFER: "Transfert de fichiers"
STR_SETTINGS_TITLE: "Réglages"
STR_CONTINUE_READING: "Reprendre la lecture"
STR_RESUME: "Reprendre"
STR_NO_OPEN_BOOK: "Aucun livre ouvert"
STR_START_READING: "Commencer la lecture"
STR_NO_FILES_FOUND: "Aucun fichier trouvé"
@@ -19,32 +18,17 @@ STR_NO_CHAPTERS: "Aucun chapitre"
STR_END_OF_BOOK: "Fin du livre"
STR_EMPTY_CHAPTER: "Chapitre vide"
STR_INDEXING: "Indexation en cours"
STR_INDEX_FAILED: "Échec de l'indexation - livre invalide"
STR_MEMORY_ERROR: "Erreur de mémoire"
STR_PAGE_LOAD_ERROR: "Erreur de chargement"
STR_EMPTY_FILE: "Fichier vide"
STR_INVALID_BMP_FILE: "Fichier BMP invalide"
STR_FILE_OPEN_FAILED: "Impossible d'ouvrir le fichier"
STR_OUT_OF_BOUNDS: "Dépassement de mémoire"
STR_LOADING: "Chargement…"
STR_LOADING_POPUP: "Chargement"
STR_LOOKUP: "Rechercher"
STR_DICT_LOOKING_UP: "Recherche dans le dictionnaire…"
STR_DICT_INDEXING: "Indexation du dictionnaire…"
STR_DICT_NOT_FOUND: "Non trouvé"
STR_DICT_NO_DICT_SET: "Aucun dictionnaire défini"
STR_DICT_ERROR: "Erreur de dictionnaire"
STR_DICT_READ_FAILED: "Impossible de lire la définition"
STR_DICT_DECOMPRESS_ERROR: "Échec décompression définition"
STR_DICT_LOW_MEMORY: "Mémoire insuffisante"
STR_WIFI_NETWORKS: "Réseaux Wi-Fi"
STR_NO_NETWORKS: "Aucun réseau"
STR_NETWORKS_FOUND: "%zu réseaux"
STR_SCANNING: "Recherche en cours…"
STR_FINDING_SAVED_WIFI: "Recherche Wi-Fi connu…"
STR_CONNECTING: "Connexion en cours…"
STR_CONNECTING_SAVED_WIFI: "Connexion au Wi-Fi connu…"
STR_SHOW_NETWORKS: "Afficher"
STR_CONNECTED: "Connecté !"
STR_CONNECTION_FAILED: "Échec de la connexion"
STR_FORGET_NETWORK: "Oublier ce réseau ?"
@@ -65,8 +49,6 @@ STR_NETWORK_LEGEND: "* = Sécurisé | + = Sauvegardé"
STR_MAC_ADDRESS: "Adresse MAC :"
STR_CHECKING_WIFI: "Vérification du Wi-Fi…"
STR_ENTER_WIFI_PASSWORD: "Entrez le mot de passe Wi-Fi"
STR_ADD_HIDDEN_NETWORK: "Ajouter un réseau masqué..."
STR_ENTER_WIFI_SSID: "Saisir le nom du réseau (SSID)"
STR_TO_PREFIX: "vers "
STR_CALIBRE_RECEIVING: "Réception : "
STR_CALIBRE_RECEIVED: "Reçu : "
@@ -79,27 +61,23 @@ STR_CAT_READER: "Lecteur"
STR_CAT_CONTROLS: "Commandes"
STR_CAT_SYSTEM: "Système"
STR_SLEEP_SCREEN: "Écran de veille"
STR_QUICK_RESUME_TIMEOUT: "Reprise rapide après délai"
STR_SLEEP_COVER_MODE: "Mode écran de veille"
STR_HIDE_BATTERY: "Masquer % batterie"
STR_EXTRA_SPACING: "Espacement paragraphes supp."
STR_EXTRA_SPACING: "Espacement paragraphes"
STR_TEXT_AA: "Lissage du texte"
STR_IMAGES: "Images"
STR_IMAGES_DISPLAY: "Affichage"
STR_IMAGES_PLACEHOLDER: "Espace réservé"
STR_IMAGES_SUPPRESS: "Masquer"
STR_EOB_HOME: "Accueil"
STR_EOB_CONTINUE_WITH: "Poursuivre avec"
STR_SHORT_PWR_BTN: "Appui court bouton alim."
STR_SHORT_PWR_BTN: "Appui court alim."
STR_ORIENTATION: "Orientation de lecture"
STR_SIDE_BTN_LAYOUT: "Boutons latéraux (lecteur)"
STR_SIDE_BTN_LAYOUT: "Boutons latéraux"
STR_TOUCH_READER_CONTROLS: "Commandes tactiles lecteur"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Orienter boutons avant"
STR_LONG_PRESS_BEHAVIOR: "Comportement lors d'un appui long"
STR_LONG_PRESS_BEHAVIOR_OFF: "Désactivé"
STR_LONG_PRESS_BEHAVIOR_SKIP: "Saut de chapitre"
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Changement d'orientation"
STR_LONG_PRESS_MENU: "Menu appui long"
STR_FONT_PREVIEW_TEXT: "Portez ce vieux whisky au juge blond qui fume"
STR_FONT_FAMILY: "Police de caractères du lecteur"
STR_FONT_SIZE: "Taille police lecteur"
@@ -107,9 +85,9 @@ STR_TEXT_SETTINGS: "Réglages du texte"
STR_FONT: "Police"
STR_SIZE: "Taille"
STR_LAYOUT: "Disposition"
STR_ALIGNMENT: "Alignement"
STR_STYLE: "Style"
STR_NOT_IN_PREVIEW: "Absent de l'aperçu"
STR_ALIGNMENT: "Alignement"
STR_LINE_SPACING: "Interligne"
STR_SCREEN_MARGIN: "Marges"
STR_PARA_ALIGNMENT: "Alignement du paragraphe"
@@ -128,17 +106,9 @@ STR_PASSWORD: "Mot de passe"
STR_SYNC_SERVER_URL: "URL du serveur"
STR_DOCUMENT_MATCHING: "Correspondance"
STR_SEND_METADATA: "Envoyer métadonnées"
STR_SYNC_BEHAVIOR: "Comportement de synchro"
STR_ASK_EVERY_TIME: "Toujours demander"
STR_SMART_SYNC: "Synchro intelligente"
STR_AUTHENTICATE: "Connexion"
STR_SIGN_UP: "Créer un compte"
STR_CREATING_ACCOUNT: "Création du compte…"
STR_ACCOUNT_CREATED: "Compte créé"
STR_SIGNUP_FAILED: "Échec de la création"
STR_USERNAME_TAKEN: "Nom d'utilisateur déjà pris"
STR_KOREADER_USERNAME: "Utilisateur KOReader"
STR_KOREADER_PASSWORD: "Mot de passe KOReader"
STR_KOREADER_USERNAME: "Utilisateur"
STR_KOREADER_PASSWORD: "Mot de passe"
STR_FILENAME: "Nom de fichier"
STR_BINARY: "Binaire"
STR_SET_CREDENTIALS_FIRST: "Identifiants manquants"
@@ -156,7 +126,7 @@ STR_CLEAR_CACHE_WARNING_4: "à la prochaine ouverture."
STR_CLEARING_CACHE: "Nettoyage du cache…"
STR_CACHE_CLEARED: "Cache vidé"
STR_ITEMS_REMOVED: "éléments supprimés"
STR_FAILED_LOWER: "Echec"
STR_FAILED_LOWER: "ont échoué"
STR_CLEAR_CACHE_FAILED: "Échec nettoyage cache"
STR_CHECK_SERIAL_OUTPUT: "Voir console pour détails"
STR_DARK: "Sombre"
@@ -172,7 +142,6 @@ STR_ALWAYS: "Toujours"
STR_IGNORE: "Ignorer"
STR_SLEEP: "Mise en veille"
STR_PAGE_TURN: "Page suivante"
STR_FORCE_REFRESH: "Rafraîchir l'écran"
STR_PORTRAIT: "Portrait"
STR_LANDSCAPE_CW: "Paysage"
STR_INVERTED: "Inversé"
@@ -180,10 +149,6 @@ STR_ORIENTATION_INVERTED: "Portrait 180°"
STR_LANDSCAPE_CCW: "Paysage inversé"
STR_PREV_NEXT: "Préc/Suiv"
STR_NEXT_PREV: "Suiv/Préc"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Marque-page"
STR_DICTIONARY: "Dictionnaire"
STR_DISABLED: "Désactivé"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
STR_TIGHT: "Serré"
@@ -208,18 +173,14 @@ STR_NO_UPDATE: "Aucune mise à jour"
STR_UPDATE_FAILED: "Échec de la mise à jour"
STR_UPDATE_COMPLETE: "Mise à jour effectuée"
STR_POWER_ON_HINT: "Maintenir Power pour redémarrer"
STR_RESTARTING_HINT: "Redémarrage… Si l'appareil ne redémarre pas, maintenez le bouton Power enfoncé quelques secondes."
STR_NO_ENTRIES: "Aucune entrée"
STR_DOWNLOADING: "Téléchargement…"
STR_DOWNLOAD_FAILED: "Échec du téléchargement"
STR_ERROR_MSG: "Erreur : "
STR_UNNAMED: "Sans titre"
STR_HOLD_OPEN_TO_DELETE: "Maintenir Ouvrir pour supprimer"
STR_NO_SERVER_URL: "URL serveur non configurée"
STR_FETCH_FEED_FAILED: "Échec récupération flux"
STR_PARSE_FEED_FAILED: "Échec analyse flux"
STR_NEXT_PAGE: "Page suivante »"
STR_PREV_PAGE: "« Page précédente"
STR_NETWORK_PREFIX: "Réseau : "
STR_IP_ADDRESS_PREFIX: "IP : "
STR_ERROR_GENERAL_FAILURE: "Erreur : Échec général"
@@ -233,13 +194,14 @@ STR_SELECT: "OK"
STR_SELECTED: "Sélectionné"
STR_TOGGLE: "Modifier"
STR_TOGGLE_BOOKMARK: "Basculer le marque-page"
STR_BOOKMARK_REMOVED: "Marque-page supprimé."
STR_HOLD_OPEN_TO_DELETE: "Maintenir Ouvrir pour supprimer"
STR_CONFIRM: "Confirmer"
STR_CANCEL: "Annuler"
STR_CONNECT: "Connecter"
STR_OPEN: "Ouvrir"
STR_DOWNLOAD: "Télécharger"
STR_RETRY: "Réessayer"
STR_TAP_TO_RETRY: "Appuyer pour réessayer"
STR_YES: "Oui"
STR_NO: "Non"
STR_SHOW: "Afficher"
@@ -252,9 +214,6 @@ STR_DIR_RIGHT: "Droite"
STR_DIR_UP: "Haut"
STR_DIR_DOWN: "Bas"
STR_OK_BUTTON: "OK"
STR_KEY_SHIFT: "Maj"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "Filtre écran de veille"
STR_FILTER_CONTRAST: "Contraste"
STR_CUSTOMISE_STATUS_BAR: "Personnaliser la barre d'état"
@@ -272,36 +231,15 @@ STR_EXAMPLE_BOOK: "Titre du livre"
STR_PREVIEW: "Aperçu"
STR_TITLE: "Titre"
STR_BATTERY: "Batterie"
STR_XTC_STATUS_BAR: "Barre d'état XTC"
STR_BOTTOM: "Bas"
STR_TOP: "Haut"
STR_CLOCK: "Horloge"
STR_CLOCK_UTC_OFFSET: "Décalage UTC horloge"
STR_CLOCK_FORMAT: "Format de l'heure"
STR_CLOCK_FORMAT_24H: "24 heures"
STR_CLOCK_FORMAT_12H: "12 heures"
STR_CURRENT_TIME: "Heure actuelle :"
STR_NEXT_FIELD: "Suivant"
STR_CLOCK_SYNC: "Synchro horloge"
STR_CLOCK_SYNC_NOW: "Synchroniser l'heure"
STR_CLOCK_SYNCING: "Synchro via NTP…"
STR_CLOCK_SYNC_OK: "Horloge synchronisée"
STR_CLOCK_SYNC_FAIL: "Échec synchro"
STR_CLOCK_SYNC_NO_WIFI: "Wi-Fi non connecté"
STR_CLOCK_SYNC_NO_WIFI_HINT: "Connectez le Wi-Fi avant de réessayer."
STR_CLOCK_SYNCED: "Horloge synchronisée"
STR_UI_THEME: "Thème interface"
STR_THEME_CLASSIC: "Classique"
STR_THEME_LYRA: "Lyra"
STR_THEME_ROUNDEDRAFF: "RoundedRaff"
STR_THEME_LYRA_EXTENDED: "Lyra Extended"
STR_SUNLIGHT_FADING_FIX: "Correction lisibilité au soleil"
STR_QUICK_RESUME_TIMEOUT: "Reprise rapide après délai"
STR_REMAP_FRONT_BUTTONS: "Configurer boutons façade"
STR_BOOKMARKS: "Marque-pages"
STR_BOOKMARK_ADDED: "Marque-page ajouté."
STR_BOOKMARK_REMOVED: "Marque-page supprimé."
STR_OPDS_BROWSER: "Navigateur OPDS"
STR_SEARCH: "Rechercher"
STR_COVER_CUSTOM: "Couverture + Perso"
STR_QUICK_RESUME: "Reprise rapide"
STR_MENU_RECENT_BOOKS: "Livres récents"
@@ -329,7 +267,6 @@ STR_GO_HOME_BUTTON: "Retour Accueil"
STR_SYNC_PROGRESS: "Synchro progression"
STR_DELETE_CACHE: "Supprimer cache livre"
STR_DELETE: "Supprimer"
STR_CONFIRM_DELETE_BOOKMARK: "Supprimer ce marque-page ?"
STR_DISPLAY_QR: "Afficher la page en QR"
STR_CHAPTER_PREFIX: "Chapitre : "
STR_PAGES_SEPARATOR: " pages | "
@@ -353,7 +290,6 @@ STR_UPLOAD_LOCAL: "Envoyer progression locale"
STR_NO_REMOTE_MSG: "Aucune progression en ligne"
STR_UPLOAD_PROMPT: "Envoyer position actuelle ?"
STR_UPLOAD_SUCCESS: "Progression envoyée !"
STR_ALREADY_SYNCED: "Déjà synchronisé"
STR_SYNC_FAILED_MSG: "Échec de la synchro"
STR_SAVE_PROGRESS_FAILED: "Échec de l'enregistrement"
STR_SECTION_PREFIX: "Section "
@@ -362,70 +298,21 @@ STR_BOOK_S_STYLE: "Style du livre"
STR_EMBEDDED_STYLE: "Style intégré"
STR_FOCUS_READING: "Lecture focalisée"
STR_OPDS_SERVER_URL: "URL serveur OPDS"
STR_PWR_BTN_FOOTNOTE_BACK: "Retour rapide depuis notes de bas de page"
STR_BACK_SHORT_TO_FILE_BROWSER: "Retour court vers fichiers"
STR_SET_SLEEP_COVER: "Définir comme couverture"
STR_FOOTNOTES: "Notes de bas de page"
STR_NO_FOOTNOTES: "Aucune note sur cette page"
STR_LINK: "[lien]"
STR_SCREENSHOT_BUTTON: "Capture d'écran"
STR_SLEEP_TIMER_VALUE_FORMAT: "%u min"
STR_SLEEP_NEVER: "Jamais"
STR_STEP_HINT_FRONT: "Boutons avant :"
STR_STEP_HINT_SIDE: "Boutons latéraux :"
STR_ADD_SERVER: "Ajouter un serveur"
STR_SERVER_NAME: "Nom du serveur"
STR_NO_SERVERS: "Aucun serveur OPDS configuré"
STR_DELETE_SERVER: "Supprimer le serveur"
STR_OPDS_SERVERS: "Serveurs OPDS"
STR_OPDS_DOWNLOAD_FOLDER: "Dossier de téléchargement"
STR_OPDS_FILENAME_FORMAT: "Format du nom de fichier"
STR_FMT_AUTHOR_TITLE: "Auteur - Titre"
STR_FMT_TITLE_AUTHOR: "Titre - Auteur"
STR_FMT_TITLE: "Titre"
STR_OPDS_SD_ROOT: "Racine SD"
STR_SCREENSHOT_BUTTON: "Capture d'écran"
STR_AUTO_TURN_ENABLED: "Tourne-page auto : "
STR_AUTO_TURN_PAGES_PER_MIN: "Tourne-page auto (pages par minute)"
STR_MANAGE_FONTS: "Gérer les polices"
STR_FONT_BROWSER: "Navigateur de polices"
STR_LOADING_FONT_LIST: "Chargement des polices…"
STR_NO_FONTS_AVAILABLE: "Aucune police disponible"
STR_FONT_INSTALLED: "Police installée !"
STR_FONT_INSTALL_FAILED: "Échec installation police"
STR_INSTALLED: "Installée"
STR_DOWNLOAD_ALL: "Tout télécharger"
STR_UPDATE_ALL: "Tout mettre à jour"
STR_UPDATE_AVAILABLE: "Mettre à jour"
STR_CRASH_TITLE: "Plantage système"
STR_CRASH_DESCRIPTION: "Un rapport détaillé a été enregistré sous crash_report.txt. Veuillez l'inclure dans votre rapport de bug."
STR_CRASH_REASON: "Raison du plantage :"
STR_CRASH_NO_REASON: "(Aucune raison enregistrée)"
STR_TILT_PAGE_TURN: "Tourner par inclinaison"
STR_KB_HINT_MOVE_CURSOR: "Appuyer GAUCHE ou DROITE pour déplacer le curseur"
STR_KB_HINT_RETURN_CURSOR: "Appuyer GAUCHE pour revenir au curseur"
STR_KB_HINT_HIDE_PASSWORD: "Maintenir DROITE puis appuyer [***] pour masquer"
STR_KB_HINT_SHOW_PASSWORD: "Maintenir DROITE puis appuyer [abc] pour afficher"
STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Appuyer [***] pour masquer le mot de passe"
STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Appuyer [abc] pour afficher le mot de passe"
STR_KB_HINT_EDIT_ENTRY: "Maintenir HAUT pour modifier"
STR_KB_TIPS: "Conseils :"
STR_KB_HINT_RETURN_KEYBOARD: "Appuyer BAS pour revenir au clavier"
STR_KB_HINT_EXIT_URL_MODE: "Appuyer ABC pour quitter le mode URL"
STR_KB_HINT_CLEAR_TEXT: "Maintenir DEL pour effacer le texte"
STR_KB_HINT_SECONDARY_CHAR: "Maintenir OK pour caractère secondaire"
STR_KB_HINT_UPPER_SECONDARY: "Maintenir OK pour MAJUSCULE ou secondaire"
STR_KB_HINT_LOWER_SECONDARY: "Maintenir OK pour minuscule ou secondaire"
STR_KB_HINT_URL_SNIPPETS: "Appuyer URL pour les raccourcis"
STR_SD_FIRMWARE_UPDATE: "Mise à jour du firmware par carte SD"
STR_SELECT_FIRMWARE_FILE: "Sélectionner le fichier firmware (.bin)"
STR_NO_BIN_FILES: "Aucun fichier .bin trouvé"
STR_VALIDATING_FIRMWARE: "Validation du firmware…"
STR_INVALID_FIRMWARE: "Fichier firmware invalide"
STR_FIRMWARE_TOO_LARGE: "Firmware trop volumineux pour la partition"
STR_FIRMWARE_TOO_SMALL: "Fichier firmware trop petit"
STR_FIRMWARE_UPDATE_PROMPT: "Mettre à jour le firmware ?"
STR_FIRMWARE_FILE_OPEN_FAILED: "Impossible d'ouvrir le fichier"
STR_FIRMWARE_WRITE_FAILED: "Échec de l'écriture du firmware"
STR_FIRMWARE_UPDATE_DO_NOT_POWER_OFF: "Ne pas éteindre l'appareil !"
STR_RECOVERY_MODE: "Mode Récupération"
STR_RECOVERY_MODE_HINT: "Placez firmware.bin à la racine de la carte SD et sélectionnez-le"
STR_ADD_HIDDEN_NETWORK: "Ajouter un réseau masqué..."
STR_ENTER_WIFI_SSID: "Saisir le nom du réseau (SSID)"
-35
View File
@@ -394,38 +394,3 @@ STR_RECOVERY_MODE: "Wiederherstellungsmodus"
STR_RECOVERY_MODE_HINT: "Lege firmware.bin im SD-Kartenwurzelverzeichnis ab und wähle es aus"
STR_ADD_HIDDEN_NETWORK: "Verstecktes Netzwerk hinzufügen…"
STR_ENTER_WIFI_SSID: "Netzwerknamen eingeben (SSID)"
STR_ACCOUNT_CREATED: "Konto erstellt"
STR_ALREADY_SYNCED: "Bereits synchronisiert"
STR_ASK_EVERY_TIME: "Immer fragen"
STR_BOOKMARK_OPTION: "Lesezeichen"
STR_CONNECTING_SAVED_WIFI: "Verbinde mit gespeichertem WLAN-Netzwerk…"
STR_CREATING_ACCOUNT: "Erstelle Konto…"
STR_DICTIONARY: "Wörterbuch"
STR_DICT_ERROR: "Wörterbuch Fehler"
STR_DICT_INDEXING: "Indexiere Wörterbuch…"
STR_DICT_LOOKING_UP: "Suche…"
STR_DICT_NOT_FOUND: "Nicht gefunden"
STR_DICT_NO_DICT_SET: "Kein Wörterbuch festgelegt"
STR_EOB_CONTINUE_WITH: "Weiter mit"
STR_EOB_HOME: "Home"
STR_FINDING_SAVED_WIFI: "Finde gespeichertes WLAN-Netzwerk…"
STR_INDEX_FAILED: "Fehler beim Indexieren - ungültiges Buch"
STR_KEY_MODE_ABC: "abc"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_SHIFT: "Shift"
STR_KOSYNC: "KOSync"
STR_LOOKUP: "Nachschlagen"
STR_OPDS_SD_ROOT: "SD-Karten Hauptverzeichnis"
STR_PWR_BTN_FOOTNOTE_BACK: "Schnellrücksprung aus Fußnoten"
STR_SHOW_NETWORKS: "Zeige Netzwerke"
STR_SIGNUP_FAILED: "Anmeldung fehlgeschlagen"
STR_SIGN_UP: "Anmelden"
STR_SMART_SYNC: "Smart"
STR_SYNC_BEHAVIOR: "Synchronisierungsverhalten"
STR_TAP_TO_RETRY: "Tippen zum Wiederholen"
STR_USERNAME_TAKEN: "Benutzername ist bereits registriert"
STR_FILE_OPEN_FAILED: "Kann Datei nicht öffnen"
STR_INVALID_BMP_FILE: "Ungültige BMP-Datei"
STR_DICT_DECOMPRESS_ERROR: "Konnte Definition nicht entpacken"
STR_DICT_LOW_MEMORY: "Nicht genug Speicher"
STR_DICT_READ_FAILED: "Konnte Definition nicht lesen"
+28 -62
View File
@@ -10,41 +10,25 @@ STR_BROWSE_FILES: "סייר קבצים"
STR_FILE_TRANSFER: "העברת קבצים"
STR_SETTINGS_TITLE: "הגדרות"
STR_CONTINUE_READING: "המשך קריאה"
STR_RESUME: "המשך"
STR_NO_OPEN_BOOK: "אין ספר פתוח"
STR_START_READING: "התחל לקרוא"
STR_START_READING: "התחל לקרוא למטה"
STR_NO_FILES_FOUND: "לא נמצאו קבצים"
STR_SELECT_CHAPTER: "בחר פרק"
STR_NO_CHAPTERS: "אין פרקים"
STR_END_OF_BOOK: "סוף הספר"
STR_EMPTY_CHAPTER: "פרק ריק"
STR_INDEXING: "מאנדקס..."
STR_INDEX_FAILED: "האינדוקס נכשל - ספר לא תקין"
STR_MEMORY_ERROR: "שגיאת זיכרון"
STR_PAGE_LOAD_ERROR: "שגיאה בטעינת הדף"
STR_EMPTY_FILE: "קובץ ריק"
STR_INVALID_BMP_FILE: "קובץ BMP לא תקין"
STR_FILE_OPEN_FAILED: "לא ניתן לפתוח את הקובץ"
STR_OUT_OF_BOUNDS: "מחוץ לטווח"
STR_LOADING: "טוען..."
STR_LOADING_POPUP: "טוען"
STR_LOOKUP: "חפש במילון"
STR_DICT_LOOKING_UP: "מחפש..."
STR_DICT_INDEXING: "מאנדקס מילון..."
STR_DICT_NOT_FOUND: "לא נמצא"
STR_DICT_NO_DICT_SET: "לא הוגדר מילון"
STR_DICT_ERROR: "שגיאת מילון"
STR_DICT_READ_FAILED: "לא ניתן לקרוא את ההגדרה"
STR_DICT_DECOMPRESS_ERROR: "לא ניתן לחלץ את ההגדרה"
STR_DICT_LOW_MEMORY: "אין מספיק זיכרון"
STR_WIFI_NETWORKS: "רשתות אלחוטיות (WiFi)"
STR_NO_NETWORKS: "לא נמצאו רשתות"
STR_NETWORKS_FOUND: "נמצאו %zu רשתות"
STR_SCANNING: "סורק..."
STR_FINDING_SAVED_WIFI: "מחפש רשת אלחוטית שמורה..."
STR_CONNECTING: "מתחבר..."
STR_CONNECTING_SAVED_WIFI: "מתחבר לרשת אלחוטית שמורה..."
STR_SHOW_NETWORKS: "הצג"
STR_CONNECTED: "מחובר!"
STR_CONNECTION_FAILED: "החיבור נכשל"
STR_FORGET_NETWORK: "לשכוח רשת זו?"
@@ -75,7 +59,7 @@ STR_CALIBRE_INSTRUCTION_3: "3) בתוכנת Calibre: בחר \"שלח למכשי
STR_CALIBRE_INSTRUCTION_4: "השאר מסך זה פתוח בזמן ההעברה"
STR_CAT_DISPLAY: "תצוגה"
STR_CAT_READER: "קורא"
STR_CAT_CONTROLS: "לחצנים"
STR_CAT_CONTROLS: "מקשים"
STR_CAT_SYSTEM: "מערכת"
STR_SLEEP_SCREEN: "מסך מצב שינה"
STR_SLEEP_COVER_MODE: "תצוגת כריכה במצב שינה"
@@ -84,13 +68,11 @@ STR_EXTRA_SPACING: "מרווח פסקאות מוגדל"
STR_TEXT_AA: "החלקת קצוות טקסט"
STR_IMAGES: "תמונות"
STR_IMAGES_DISPLAY: "הצג תמונות"
STR_IMAGES_PLACEHOLDER: "מסגרת ריקה"
STR_IMAGES_PLACEHOLDER: "סמן"
STR_IMAGES_SUPPRESS: "הסתר תמונות"
STR_EOB_HOME: "מסך הבית"
STR_EOB_CONTINUE_WITH: "המשך עם"
STR_SHORT_PWR_BTN: "לחיצה קצרה על לחצן ההפעלה"
STR_ORIENTATION: "כיוון מסך"
STR_SIDE_BTN_LAYOUT: "פריסת לחצני צד (בקריאה)"
STR_SHORT_PWR_BTN: "לחיצה קצרה על כפתור ההפעלה"
STR_ORIENTATION: "כיוון קריאה (מסך)"
STR_SIDE_BTN_LAYOUT: "פריסת כפתורי צד (בקריאה)"
STR_TOUCH_READER_CONTROLS: "שליטה במגע (קורא)"
STR_LONG_PRESS_BEHAVIOR: "פעולת לחיצה ארוכה"
STR_LONG_PRESS_BEHAVIOR_OFF: "כבוי"
@@ -106,11 +88,11 @@ STR_LAYOUT: "פריסה"
STR_STYLE: "סגנון"
STR_NOT_IN_PREVIEW: "לא מוצג בתצוגה המקדימה"
STR_ALIGNMENT: "יישור"
STR_LINE_SPACING: "מרווח בין שורות"
STR_LINE_SPACING: "מרווח שורות"
STR_SCREEN_MARGIN: "שוליים"
STR_PARA_ALIGNMENT: "יישור פסקה"
STR_HYPHENATION: "מיקוף"
STR_TIME_TO_SLEEP: "טיימר למצב שינה"
STR_TIME_TO_SLEEP: "זמן עד לשינה"
STR_SHOW_HIDDEN_FILES: "הצג קבצים נסתרים"
STR_REFRESH_FREQ: "תדירות רענון מסך"
STR_KOREADER_SYNC: "סנכרון KOReader"
@@ -122,19 +104,11 @@ STR_PASSWORD: "סיסמה"
STR_SYNC_SERVER_URL: "כתובת שרת סנכרון"
STR_DOCUMENT_MATCHING: "התאמת מסמכים"
STR_SEND_METADATA: "שלח מטא-נתוני מסמך"
STR_SYNC_BEHAVIOR: "אופן הסנכרון"
STR_ASK_EVERY_TIME: "שאל בכל פעם"
STR_SMART_SYNC: "סנכרון חכם"
STR_AUTHENTICATE: "התחבר לחשבון"
STR_SIGN_UP: "הרשמה"
STR_CREATING_ACCOUNT: "יוצר חשבון..."
STR_ACCOUNT_CREATED: "החשבון נוצר"
STR_SIGNUP_FAILED: "ההרשמה נכשלה"
STR_USERNAME_TAKEN: "שם המשתמש כבר רשום במערכת"
STR_AUTHENTICATE: "התחבר"
STR_KOREADER_USERNAME: "שם משתמש ב-KOReader"
STR_KOREADER_PASSWORD: "סיסמת KOReader"
STR_FILENAME: "לפי שם קובץ"
STR_BINARY: "לפי תוכן"
STR_FILENAME: "שם קובץ"
STR_BINARY: "בינארי"
STR_SET_CREDENTIALS_FIRST: "הגדר תחילה פרטי התחברות"
STR_WIFI_CONN_FAILED: "חיבור הרשת נכשל"
STR_AUTHENTICATING: "מאמת נתונים..."
@@ -169,7 +143,7 @@ STR_PAGE_TURN: "העברת דף"
STR_FORCE_REFRESH: "רענון מסך מלא"
STR_PORTRAIT: "לאורך"
STR_LANDSCAPE_CW: "לרוחב (ימינה)"
STR_INVERTED: "הפוך"
STR_INVERTED: "היפוך צבעים"
STR_ORIENTATION_INVERTED: "לאורך 180°"
STR_LANDSCAPE_CCW: "לרוחב (שמאלה)"
STR_PREV_NEXT: "הקודם/הבא"
@@ -197,8 +171,8 @@ STR_UPDATING: "מעדכן..."
STR_NO_UPDATE: "לא נמצאו עדכונים"
STR_UPDATE_FAILED: "העדכון נכשל"
STR_UPDATE_COMPLETE: "העדכון הושלם"
STR_POWER_ON_HINT: "לחץ לחיצה ארוכה על לחצן ההפעלה כדי להדליק שוב"
STR_RESTARTING_HINT: "מופעל מחדש... אם המכשיר לא נדלק, החזק את לחצן ההפעלה מספר שניות."
STR_POWER_ON_HINT: "לחץ לחיצה ארוכה על כפתור ההפעלה כדי להדליק שוב"
STR_RESTARTING_HINT: "מופעל מחדש... אם המכשיר לא נדלק, החזק את כפתור ההפעלה מספר שניות."
STR_NO_ENTRIES: "לא נמצאו רשומות"
STR_DOWNLOADING: "מוריד..."
STR_DOWNLOAD_FAILED: "ההורדה נכשלה"
@@ -220,7 +194,7 @@ STR_EXIT: "יציאה »"
STR_HOME: "מסך הבית »"
STR_SELECT: "בחר"
STR_SELECTED: "נבחר"
STR_TOGGLE: "שנה"
STR_TOGGLE: "בחר"
STR_TOGGLE_BOOKMARK: "הוסף/הסר סימנייה"
STR_CONFIRM: "אישור"
STR_CANCEL: "ביטול"
@@ -228,7 +202,6 @@ STR_CONNECT: "התחבר"
STR_OPEN: "פתח"
STR_DOWNLOAD: "הורד"
STR_RETRY: "נסה שוב"
STR_TAP_TO_RETRY: "הקש כדי לנסות שוב"
STR_YES: "כן"
STR_NO: "לא"
STR_SHOW: "הצג"
@@ -241,9 +214,6 @@ STR_DIR_RIGHT: "ימין"
STR_DIR_UP: "למעלה"
STR_DIR_DOWN: "למטה"
STR_OK_BUTTON: "אישור"
STR_KEY_SHIFT: "Shift"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "פילטר תמונה במצב שינה"
STR_FILTER_CONTRAST: "ניגודיות (קונטרסט)"
STR_CUSTOMISE_STATUS_BAR: "התאם אישית שורת מצב"
@@ -270,7 +240,7 @@ STR_THEME_LYRA: "Lyra"
STR_THEME_ROUNDEDRAFF: "RoundedRaff"
STR_THEME_LYRA_EXTENDED: "Lyra מורחב"
STR_SUNLIGHT_FADING_FIX: "תיקון דהיית מסך בשמש"
STR_REMAP_FRONT_BUTTONS: "שנה תפקיד ללחצנים קדמיים"
STR_REMAP_FRONT_BUTTONS: "שנה תפקיד לכפתורים קדמיים"
STR_OPDS_BROWSER: "דפדפן OPDS"
STR_SEARCH: "חיפוש"
STR_COVER_CUSTOM: "כריכה + מותאם אישית"
@@ -284,16 +254,16 @@ STR_CALIBRE_SETUP: "הגדרות"
STR_CALIBRE_STATUS: "מצב"
STR_CLEAR_BUTTON: "נקה"
STR_DEFAULT_VALUE: "ברירת מחדל"
STR_REMAP_PROMPT: "לחץ על לחצן קדמי לכל פעולה"
STR_REMAP_PROMPT: "לחץ על כפתור קדמי לכל פעולה"
STR_UNASSIGNED: "לא מוקצה"
STR_ALREADY_ASSIGNED: "כבר בשימוש"
STR_REMAP_RESET_HINT: "לחצן צד עליון: שחזר לפריסת ברירת מחדל"
STR_REMAP_CANCEL_HINT: "לחצן צד תחתון: בטל הגדרה מחדש"
STR_HW_BACK_LABEL: "חזור (לחצן 1)"
STR_HW_CONFIRM_LABEL: "אישור (לחצן 2)"
STR_HW_LEFT_LABEL: "שמאלה (לחצן 3)"
STR_HW_RIGHT_LABEL: "ימינה (לחצן 4)"
STR_GO_TO_PERCENT: "קפוץ למיקום (%)"
STR_REMAP_RESET_HINT: "כפתור צד עליון: שחזר לפריסת ברירת מחדל"
STR_REMAP_CANCEL_HINT: "כפתור צד תחתון: בטל הגדרה מחדש"
STR_HW_BACK_LABEL: "חזור (כפתור 1)"
STR_HW_CONFIRM_LABEL: "אישור (כפתור 2)"
STR_HW_LEFT_LABEL: "שמאלה (כפתור 3)"
STR_HW_RIGHT_LABEL: "ימינה (כפתור 4)"
STR_GO_TO_PERCENT: "עבור לאחוז %"
STR_GO_HOME_BUTTON: "חזור למסך הבית"
STR_SYNC_PROGRESS: "סנכרן התקדמות"
STR_DELETE_CACHE: "מחק קבצי מטמון (Cache)"
@@ -321,16 +291,14 @@ STR_UPLOAD_LOCAL: "העלה התקדמות מהמכשיר לשרת"
STR_NO_REMOTE_MSG: "לא נמצאה התקדמות בשרת"
STR_UPLOAD_PROMPT: "להעלות את המיקום הנוכחי לשרת?"
STR_UPLOAD_SUCCESS: "ההתקדמות הועלתה בהצלחה!"
STR_ALREADY_SYNCED: "כבר מסונכרן"
STR_SYNC_FAILED_MSG: "הסנכרון נכשל"
STR_SAVE_PROGRESS_FAILED: "שמירת ההתקדמות נכשלה"
STR_SECTION_PREFIX: "חלק "
STR_UPLOAD: "העלה"
STR_BOOK_S_STYLE: "לפי הספר"
STR_BOOK_S_STYLE: "עיצוב הספר המקורי"
STR_EMBEDDED_STYLE: "סגנון מוטמע"
STR_FOCUS_READING: "קריאה ממוקדת"
STR_OPDS_SERVER_URL: "כתובת שרת OPDS"
STR_BACK_SHORT_TO_FILE_BROWSER: "חזרה קצרה לסייר הקבצים"
STR_SET_SLEEP_COVER: "הגדר כריכה"
STR_FOOTNOTES: "הערות שוליים"
STR_NO_FOOTNOTES: "אין הערות שוליים בדף זה"
@@ -347,7 +315,6 @@ STR_OPDS_FILENAME_FORMAT: "תבנית שם קובץ"
STR_FMT_AUTHOR_TITLE: "מחבר - כותרת"
STR_FMT_TITLE_AUTHOR: "כותרת - מחבר"
STR_FMT_TITLE: "כותרת"
STR_OPDS_SD_ROOT: "שורש כרטיס ה-SD"
STR_AUTO_TURN_ENABLED: "דפדוף אוטומטי פועל: "
STR_AUTO_TURN_PAGES_PER_MIN: "דפדוף אוטומטי (דפים בדקה)"
STR_MANAGE_FONTS: "ניהול גופנים"
@@ -380,7 +347,7 @@ STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "לחץ על [abc] כדי להציג סיסמ
STR_KB_HINT_EDIT_ENTRY: "החזק למעלה כדי לערוך"
STR_KB_TIPS: "טיפים:"
STR_KB_HINT_RETURN_KEYBOARD: "לחץ למטה כדי לחזור למקלדת"
STR_KB_HINT_EXIT_URL_MODE: "לחץ על ABC ליציאה ממצב URL"
STR_KB_HINT_EXIT_URL_MODE: "לחץ על ABC ליציאה ממצב אינטרנט"
STR_KB_HINT_CLEAR_TEXT: "החזק מחיקה (DEL) לניקוי כל הטקסט"
STR_KB_HINT_SECONDARY_CHAR: "החזק בחר (SELECT) לתו משני"
STR_KB_HINT_UPPER_SECONDARY: "החזק בחר (SELECT) לאות גדולה או לתו משני"
@@ -402,8 +369,8 @@ STR_RECOVERY_MODE_HINT: "שים את הקובץ firmware.bin בתיקייה הר
STR_QUICK_RESUME_TIMEOUT: "חזרה מהירה לאחר פסק זמן"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "התאמת לחצנים קדמיים לכיוון המסך"
STR_REMOVE_READ_FROM_RECENTS: "הסר ספרים שנקראו מרשימת האחרונים"
STR_MOVE_FINISHED_TO_READ: "העבר ספרים שהסתיימו לתיקיית 'read'"
STR_DISABLED: "כבוי"
STR_MOVE_FINISHED_TO_READ: "העבר ספרים שהסתיימו לתיקיית 'נקראו'"
STR_DISABLED: "מבוטל"
STR_HOLD_OPEN_TO_DELETE: "לחיצה ארוכה על 'פתח' כדי למחוק"
STR_CLOCK: "שעון"
STR_CLOCK_UTC_OFFSET: "הפרש זמן UTC"
@@ -429,7 +396,6 @@ STR_CONFIRM_DELETE_BOOKMARK: "למחוק סימנייה זו?"
STR_LONG_PRESS_MENU: "לחיצה ארוכה על אישור"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "סימנייה"
STR_DICTIONARY: "מילון"
STR_PWR_BTN_FOOTNOTE_BACK: "חזרה מהירה מהערות שוליים"
STR_SLEEP_TIMER_VALUE_FORMAT: "%u דקות"
STR_SLEEP_NEVER: "אף פעם"
Loaded 20 of 59 files, more files were not shown because too many files have changed in this diff. Show more