- #1038 (partial): Add .erase() for consumed words in layoutAndExtractLines to fix redundant early flush bug; fix wordContinues flag in hyphenateWordAtIndex - #1037: Add combining mark handling for hyphenation (NFC-like precomposition) and rendering (base glyph tracking in EpdFont, GfxRenderer including CCW) - #1045: Shorten STR_FORGET_BUTTON labels across all 9 translation files - #1019: Display file extensions in File Browser via getFileExtension helper - Pull romanian.yaml from upstream/master (merged PR #987) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,6 +17,11 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
|
||||
int cursorX = startX;
|
||||
const int cursorY = startY;
|
||||
int lastBaseX = startX;
|
||||
int lastBaseAdvance = 0;
|
||||
int lastBaseTop = 0;
|
||||
bool hasBaseGlyph = false;
|
||||
constexpr int MIN_COMBINING_GAP_PX = 1;
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&string)))) {
|
||||
const EpdGlyph* glyph = getGlyph(cp);
|
||||
@@ -30,12 +35,31 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
continue;
|
||||
}
|
||||
|
||||
*minX = std::min(*minX, cursorX + glyph->left);
|
||||
*maxX = std::max(*maxX, cursorX + glyph->left + glyph->width);
|
||||
*minY = std::min(*minY, cursorY + glyph->top - glyph->height);
|
||||
*maxY = std::max(*maxY, cursorY + glyph->top);
|
||||
const bool isCombining = utf8IsCombiningMark(cp);
|
||||
int raiseBy = 0;
|
||||
if (isCombining && hasBaseGlyph) {
|
||||
const int currentGap = glyph->top - glyph->height - lastBaseTop;
|
||||
if (currentGap < MIN_COMBINING_GAP_PX) {
|
||||
raiseBy = MIN_COMBINING_GAP_PX - currentGap;
|
||||
}
|
||||
}
|
||||
|
||||
const int glyphBaseX = (isCombining && hasBaseGlyph) ? (lastBaseX + lastBaseAdvance / 2) : cursorX;
|
||||
const int glyphBaseY = cursorY - raiseBy;
|
||||
|
||||
*minX = std::min(*minX, glyphBaseX + glyph->left);
|
||||
*maxX = std::max(*maxX, glyphBaseX + glyph->left + glyph->width);
|
||||
*minY = std::min(*minY, glyphBaseY + glyph->top - glyph->height);
|
||||
*maxY = std::max(*maxY, glyphBaseY + glyph->top);
|
||||
|
||||
if (!isCombining) {
|
||||
lastBaseX = cursorX;
|
||||
lastBaseAdvance = glyph->advanceX;
|
||||
lastBaseTop = glyph->top;
|
||||
hasBaseGlyph = true;
|
||||
cursorX += glyph->advanceX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EpdFont::getTextDimensions(const char* string, int* w, int* h) const {
|
||||
|
||||
@@ -100,6 +100,15 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
|
||||
for (size_t i = 0; i < lineCount; ++i) {
|
||||
extractLine(i, pageWidth, spaceWidth, wordWidths, wordContinues, lineBreakIndices, processLine);
|
||||
}
|
||||
|
||||
// Remove consumed words so size() reflects only remaining words
|
||||
if (lineCount > 0) {
|
||||
const size_t consumed = lineBreakIndices[lineCount - 1];
|
||||
words.erase(words.begin(), words.begin() + consumed);
|
||||
wordStyles.erase(wordStyles.begin(), wordStyles.begin() + consumed);
|
||||
wordContinues.erase(wordContinues.begin(), wordContinues.begin() + consumed);
|
||||
forceBreakAfter.erase(forceBreakAfter.begin(), forceBreakAfter.begin() + consumed);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint16_t> ParsedText::calculateWordWidths(const GfxRenderer& renderer, const int fontId) {
|
||||
@@ -392,11 +401,8 @@ bool ParsedText::hyphenateWordAtIndex(const size_t wordIndex, const int availabl
|
||||
words.insert(words.begin() + wordIndex + 1, remainder);
|
||||
wordStyles.insert(wordStyles.begin() + wordIndex + 1, style);
|
||||
|
||||
// The remainder inherits whatever continuation status the original word had with the word after it.
|
||||
const bool originalContinuedToNext = wordContinues[wordIndex];
|
||||
// The original word (now prefix) does NOT continue to remainder (hyphen separates them)
|
||||
wordContinues[wordIndex] = false;
|
||||
wordContinues.insert(wordContinues.begin() + wordIndex + 1, originalContinuedToNext);
|
||||
// Preserve the prefix's attach-to-previous flag; allow a break between prefix and remainder.
|
||||
wordContinues.insert(wordContinues.begin() + wordIndex + 1, false);
|
||||
|
||||
// Forced break belongs to the original whole word; transfer it to the remainder (last part).
|
||||
if (!forceBreakAfter.empty()) {
|
||||
|
||||
@@ -174,6 +174,213 @@ std::vector<CodepointInfo> collectCodepoints(const std::string& word) {
|
||||
while (*ptr != 0) {
|
||||
const unsigned char* current = ptr;
|
||||
const uint32_t cp = utf8NextCodepoint(&ptr);
|
||||
// If this is a combining diacritic (e.g., U+0301 = acute) and there's
|
||||
// a previous base character that can be composed into a single
|
||||
// precomposed Unicode scalar (Latin-1 / Latin-Extended), do that
|
||||
// composition here. This provides lightweight NFC-like behavior for
|
||||
// common Western European diacritics (acute, grave, circumflex, tilde,
|
||||
// diaeresis, cedilla) without pulling in a full Unicode normalization
|
||||
// library.
|
||||
if (!cps.empty()) {
|
||||
uint32_t prev = cps.back().value;
|
||||
uint32_t composed = 0;
|
||||
switch (cp) {
|
||||
case 0x0300: // grave
|
||||
switch (prev) {
|
||||
case 0x0041:
|
||||
composed = 0x00C0;
|
||||
break; // A -> À
|
||||
case 0x0061:
|
||||
composed = 0x00E0;
|
||||
break; // a -> à
|
||||
case 0x0045:
|
||||
composed = 0x00C8;
|
||||
break; // E -> È
|
||||
case 0x0065:
|
||||
composed = 0x00E8;
|
||||
break; // e -> è
|
||||
case 0x0049:
|
||||
composed = 0x00CC;
|
||||
break; // I -> Ì
|
||||
case 0x0069:
|
||||
composed = 0x00EC;
|
||||
break; // i -> ì
|
||||
case 0x004F:
|
||||
composed = 0x00D2;
|
||||
break; // O -> Ò
|
||||
case 0x006F:
|
||||
composed = 0x00F2;
|
||||
break; // o -> ò
|
||||
case 0x0055:
|
||||
composed = 0x00D9;
|
||||
break; // U -> Ù
|
||||
case 0x0075:
|
||||
composed = 0x00F9;
|
||||
break; // u -> ù
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0301: // acute
|
||||
switch (prev) {
|
||||
case 0x0041:
|
||||
composed = 0x00C1;
|
||||
break; // A -> Á
|
||||
case 0x0061:
|
||||
composed = 0x00E1;
|
||||
break; // a -> á
|
||||
case 0x0045:
|
||||
composed = 0x00C9;
|
||||
break; // E -> É
|
||||
case 0x0065:
|
||||
composed = 0x00E9;
|
||||
break; // e -> é
|
||||
case 0x0049:
|
||||
composed = 0x00CD;
|
||||
break; // I -> Í
|
||||
case 0x0069:
|
||||
composed = 0x00ED;
|
||||
break; // i -> í
|
||||
case 0x004F:
|
||||
composed = 0x00D3;
|
||||
break; // O -> Ó
|
||||
case 0x006F:
|
||||
composed = 0x00F3;
|
||||
break; // o -> ó
|
||||
case 0x0055:
|
||||
composed = 0x00DA;
|
||||
break; // U -> Ú
|
||||
case 0x0075:
|
||||
composed = 0x00FA;
|
||||
break; // u -> ú
|
||||
case 0x0059:
|
||||
composed = 0x00DD;
|
||||
break; // Y -> Ý
|
||||
case 0x0079:
|
||||
composed = 0x00FD;
|
||||
break; // y -> ý
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0302: // circumflex
|
||||
switch (prev) {
|
||||
case 0x0041:
|
||||
composed = 0x00C2;
|
||||
break; // A -> Â
|
||||
case 0x0061:
|
||||
composed = 0x00E2;
|
||||
break; // a -> â
|
||||
case 0x0045:
|
||||
composed = 0x00CA;
|
||||
break; // E -> Ê
|
||||
case 0x0065:
|
||||
composed = 0x00EA;
|
||||
break; // e -> ê
|
||||
case 0x0049:
|
||||
composed = 0x00CE;
|
||||
break; // I -> Î
|
||||
case 0x0069:
|
||||
composed = 0x00EE;
|
||||
break; // i -> î
|
||||
case 0x004F:
|
||||
composed = 0x00D4;
|
||||
break; // O -> Ô
|
||||
case 0x006F:
|
||||
composed = 0x00F4;
|
||||
break; // o -> ô
|
||||
case 0x0055:
|
||||
composed = 0x00DB;
|
||||
break; // U -> Û
|
||||
case 0x0075:
|
||||
composed = 0x00FB;
|
||||
break; // u -> û
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0303: // tilde
|
||||
switch (prev) {
|
||||
case 0x0041:
|
||||
composed = 0x00C3;
|
||||
break; // A -> Ã
|
||||
case 0x0061:
|
||||
composed = 0x00E3;
|
||||
break; // a -> ã
|
||||
case 0x004E:
|
||||
composed = 0x00D1;
|
||||
break; // N -> Ñ
|
||||
case 0x006E:
|
||||
composed = 0x00F1;
|
||||
break; // n -> ñ
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0308: // diaeresis/umlaut
|
||||
switch (prev) {
|
||||
case 0x0041:
|
||||
composed = 0x00C4;
|
||||
break; // A -> Ä
|
||||
case 0x0061:
|
||||
composed = 0x00E4;
|
||||
break; // a -> ä
|
||||
case 0x0045:
|
||||
composed = 0x00CB;
|
||||
break; // E -> Ë
|
||||
case 0x0065:
|
||||
composed = 0x00EB;
|
||||
break; // e -> ë
|
||||
case 0x0049:
|
||||
composed = 0x00CF;
|
||||
break; // I -> Ï
|
||||
case 0x0069:
|
||||
composed = 0x00EF;
|
||||
break; // i -> ï
|
||||
case 0x004F:
|
||||
composed = 0x00D6;
|
||||
break; // O -> Ö
|
||||
case 0x006F:
|
||||
composed = 0x00F6;
|
||||
break; // o -> ö
|
||||
case 0x0055:
|
||||
composed = 0x00DC;
|
||||
break; // U -> Ü
|
||||
case 0x0075:
|
||||
composed = 0x00FC;
|
||||
break; // u -> ü
|
||||
case 0x0059:
|
||||
composed = 0x0178;
|
||||
break; // Y -> Ÿ
|
||||
case 0x0079:
|
||||
composed = 0x00FF;
|
||||
break; // y -> ÿ
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0327: // cedilla
|
||||
switch (prev) {
|
||||
case 0x0043:
|
||||
composed = 0x00C7;
|
||||
break; // C -> Ç
|
||||
case 0x0063:
|
||||
composed = 0x00E7;
|
||||
break; // c -> ç
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (composed != 0) {
|
||||
cps.back().value = composed;
|
||||
continue; // skip pushing the combining mark itself
|
||||
}
|
||||
}
|
||||
|
||||
cps.push_back({cp, static_cast<size_t>(current - base)});
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ static void renderCharImpl(const GfxRenderer& renderer, GfxRenderer::RenderMode
|
||||
}
|
||||
}
|
||||
|
||||
if (!utf8IsCombiningMark(cp)) {
|
||||
if constexpr (rotation == TextRotation::Rotated90CW) {
|
||||
*cursorY -= glyph->advanceX;
|
||||
} else if constexpr (rotation == TextRotation::Rotated90CCW) {
|
||||
@@ -181,6 +182,7 @@ static void renderCharImpl(const GfxRenderer& renderer, GfxRenderer::RenderMode
|
||||
} else {
|
||||
*cursorX += glyph->advanceX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IMPORTANT: This function is in critical rendering path and is called for every pixel. Please keep it as simple and
|
||||
@@ -241,6 +243,11 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
const EpdFontFamily::Style style) const {
|
||||
int yPos = y + getFontAscenderSize(fontId);
|
||||
int xpos = x;
|
||||
int lastBaseX = x;
|
||||
int lastBaseY = yPos;
|
||||
int lastBaseAdvance = 0;
|
||||
int lastBaseTop = 0;
|
||||
bool hasBaseGlyph = false;
|
||||
|
||||
// cannot draw a NULL / empty string
|
||||
if (text == nullptr || *text == '\0') {
|
||||
@@ -253,9 +260,43 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
return;
|
||||
}
|
||||
const auto& font = fontIt->second;
|
||||
constexpr int MIN_COMBINING_GAP_PX = 1;
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
if (utf8IsCombiningMark(cp) && hasBaseGlyph) {
|
||||
const EpdGlyph* combiningGlyph = font.getGlyph(cp, style);
|
||||
if (!combiningGlyph) {
|
||||
combiningGlyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
int raiseBy = 0;
|
||||
if (combiningGlyph) {
|
||||
const int currentGap = combiningGlyph->top - combiningGlyph->height - lastBaseTop;
|
||||
if (currentGap < MIN_COMBINING_GAP_PX) {
|
||||
raiseBy = MIN_COMBINING_GAP_PX - currentGap;
|
||||
}
|
||||
}
|
||||
|
||||
int combiningX = lastBaseX + lastBaseAdvance / 2;
|
||||
int combiningY = lastBaseY - raiseBy;
|
||||
renderChar(font, cp, &combiningX, &combiningY, black, style);
|
||||
continue;
|
||||
}
|
||||
|
||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
if (!utf8IsCombiningMark(cp)) {
|
||||
lastBaseX = xpos;
|
||||
lastBaseY = yPos;
|
||||
lastBaseAdvance = glyph ? glyph->advanceX : 0;
|
||||
lastBaseTop = glyph ? glyph->top : 0;
|
||||
hasBaseGlyph = true;
|
||||
}
|
||||
|
||||
renderChar(font, cp, &xpos, &yPos, black, style);
|
||||
}
|
||||
}
|
||||
@@ -963,6 +1004,9 @@ int GfxRenderer::getTextAdvanceX(const int fontId, const char* text, const EpdFo
|
||||
int width = 0;
|
||||
const auto& font = fontIt->second;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
if (utf8IsCombiningMark(cp)) {
|
||||
continue;
|
||||
}
|
||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||
if (!glyph) glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
if (glyph) width += glyph->advanceX;
|
||||
@@ -1016,9 +1060,48 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
|
||||
|
||||
int xPos = x;
|
||||
int yPos = y;
|
||||
int lastBaseX = x;
|
||||
int lastBaseY = y;
|
||||
int lastBaseAdvance = 0;
|
||||
int lastBaseTop = 0;
|
||||
bool hasBaseGlyph = false;
|
||||
constexpr int MIN_COMBINING_GAP_PX = 1;
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
if (utf8IsCombiningMark(cp) && hasBaseGlyph) {
|
||||
const EpdGlyph* combiningGlyph = font.getGlyph(cp, style);
|
||||
if (!combiningGlyph) {
|
||||
combiningGlyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
int raiseBy = 0;
|
||||
if (combiningGlyph) {
|
||||
const int currentGap = combiningGlyph->top - combiningGlyph->height - lastBaseTop;
|
||||
if (currentGap < MIN_COMBINING_GAP_PX) {
|
||||
raiseBy = MIN_COMBINING_GAP_PX - currentGap;
|
||||
}
|
||||
}
|
||||
|
||||
int combiningX = lastBaseX - raiseBy;
|
||||
int combiningY = lastBaseY - lastBaseAdvance / 2;
|
||||
renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, &combiningX, &combiningY, black, style);
|
||||
continue;
|
||||
}
|
||||
|
||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
if (!utf8IsCombiningMark(cp)) {
|
||||
lastBaseX = xPos;
|
||||
lastBaseY = yPos;
|
||||
lastBaseAdvance = glyph ? glyph->advanceX : 0;
|
||||
lastBaseTop = glyph ? glyph->top : 0;
|
||||
hasBaseGlyph = true;
|
||||
}
|
||||
|
||||
renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, &xPos, &yPos, black, style);
|
||||
}
|
||||
}
|
||||
@@ -1040,9 +1123,48 @@ void GfxRenderer::drawTextRotated90CCW(const int fontId, const int x, const int
|
||||
|
||||
int xPos = x;
|
||||
int yPos = y;
|
||||
int lastBaseX = x;
|
||||
int lastBaseY = y;
|
||||
int lastBaseAdvance = 0;
|
||||
int lastBaseTop = 0;
|
||||
bool hasBaseGlyph = false;
|
||||
constexpr int MIN_COMBINING_GAP_PX = 1;
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
if (utf8IsCombiningMark(cp) && hasBaseGlyph) {
|
||||
const EpdGlyph* combiningGlyph = font.getGlyph(cp, style);
|
||||
if (!combiningGlyph) {
|
||||
combiningGlyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
int raiseBy = 0;
|
||||
if (combiningGlyph) {
|
||||
const int currentGap = combiningGlyph->top - combiningGlyph->height - lastBaseTop;
|
||||
if (currentGap < MIN_COMBINING_GAP_PX) {
|
||||
raiseBy = MIN_COMBINING_GAP_PX - currentGap;
|
||||
}
|
||||
}
|
||||
|
||||
int combiningX = lastBaseX + raiseBy;
|
||||
int combiningY = lastBaseY + lastBaseAdvance / 2;
|
||||
renderCharImpl<TextRotation::Rotated90CCW>(*this, renderMode, font, cp, &combiningX, &combiningY, black, style);
|
||||
continue;
|
||||
}
|
||||
|
||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
if (!utf8IsCombiningMark(cp)) {
|
||||
lastBaseX = xPos;
|
||||
lastBaseY = yPos;
|
||||
lastBaseAdvance = glyph ? glyph->advanceX : 0;
|
||||
lastBaseTop = glyph ? glyph->top : 0;
|
||||
hasBaseGlyph = true;
|
||||
}
|
||||
|
||||
renderCharImpl<TextRotation::Rotated90CCW>(*this, renderMode, font, cp, &xPos, &yPos, black, style);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ extern const char* const STRINGS_CZ[];
|
||||
extern const char* const STRINGS_PO[];
|
||||
extern const char* const STRINGS_RU[];
|
||||
extern const char* const STRINGS_SV[];
|
||||
extern const char* const STRINGS_RO[];
|
||||
} // namespace i18n_strings
|
||||
|
||||
// Language enum
|
||||
@@ -25,6 +26,7 @@ enum class Language : uint8_t {
|
||||
PORTUGUESE = 5,
|
||||
RUSSIAN = 6,
|
||||
SWEDISH = 7,
|
||||
ROMANIAN = 8,
|
||||
_COUNT
|
||||
};
|
||||
|
||||
@@ -419,6 +421,8 @@ inline const char* const* getStringArray(Language lang) {
|
||||
return i18n_strings::STRINGS_RU;
|
||||
case Language::SWEDISH:
|
||||
return i18n_strings::STRINGS_SV;
|
||||
case Language::ROMANIAN:
|
||||
return i18n_strings::STRINGS_RO;
|
||||
default:
|
||||
return i18n_strings::STRINGS_EN;
|
||||
}
|
||||
|
||||
@@ -15,5 +15,6 @@ extern const char* const STRINGS_CZ[];
|
||||
extern const char* const STRINGS_PO[];
|
||||
extern const char* const STRINGS_RU[];
|
||||
extern const char* const STRINGS_SV[];
|
||||
extern const char* const STRINGS_RO[];
|
||||
|
||||
} // namespace i18n_strings
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Nedávné knihy"
|
||||
STR_NO_RECENT_BOOKS: "Žádné nedávné knihy"
|
||||
STR_CALIBRE_DESC: "Používat přenosy bezdrátových zařízení Calibre"
|
||||
STR_FORGET_AND_REMOVE: "Zapomenout síť a odstranit uložené heslo?"
|
||||
STR_FORGET_BUTTON: "Zapomenout na síť"
|
||||
STR_FORGET_BUTTON: "Zapomenout"
|
||||
STR_CALIBRE_STARTING: "Spuštění Calibre..."
|
||||
STR_CALIBRE_SETUP: "Nastavení"
|
||||
STR_CALIBRE_STATUS: "Stav"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Recent Books"
|
||||
STR_NO_RECENT_BOOKS: "No recent books"
|
||||
STR_CALIBRE_DESC: "Use Calibre wireless device transfers"
|
||||
STR_FORGET_AND_REMOVE: "Forget network and remove saved password?"
|
||||
STR_FORGET_BUTTON: "Forget network"
|
||||
STR_FORGET_BUTTON: "Forget"
|
||||
STR_CALIBRE_STARTING: "Starting Calibre..."
|
||||
STR_CALIBRE_SETUP: "Setup"
|
||||
STR_CALIBRE_STATUS: "Status"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Livres récents"
|
||||
STR_NO_RECENT_BOOKS: "Aucun livre récent"
|
||||
STR_CALIBRE_DESC: "Utiliser les transferts sans fil Calibre"
|
||||
STR_FORGET_AND_REMOVE: "Oublier le réseau et supprimer le mot de passe enregistré ?"
|
||||
STR_FORGET_BUTTON: "Oublier le réseau"
|
||||
STR_FORGET_BUTTON: "Oublier"
|
||||
STR_CALIBRE_STARTING: "Démarrage de Calibre..."
|
||||
STR_CALIBRE_SETUP: "Configuration"
|
||||
STR_CALIBRE_STATUS: "Statut"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Zuletzt gelesen"
|
||||
STR_NO_RECENT_BOOKS: "Keine Bücher"
|
||||
STR_CALIBRE_DESC: "Calibre-Übertragung (WLAN)"
|
||||
STR_FORGET_AND_REMOVE: "WLAN entfernen & Passwort löschen?"
|
||||
STR_FORGET_BUTTON: "WLAN entfernen"
|
||||
STR_FORGET_BUTTON: "Entfernen"
|
||||
STR_CALIBRE_STARTING: "Calibre starten…"
|
||||
STR_CALIBRE_SETUP: "Installation"
|
||||
STR_CALIBRE_STATUS: "Status"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Livros recentes"
|
||||
STR_NO_RECENT_BOOKS: "Sem livros recentes"
|
||||
STR_CALIBRE_DESC: "Usar transferências sem fio Calibre"
|
||||
STR_FORGET_AND_REMOVE: "Esquecer a rede e remover a senha salva?"
|
||||
STR_FORGET_BUTTON: "Esquecer rede"
|
||||
STR_FORGET_BUTTON: "Esquecer"
|
||||
STR_CALIBRE_STARTING: "Iniciando Calibre..."
|
||||
STR_CALIBRE_SETUP: "Configuração"
|
||||
STR_CALIBRE_STATUS: "Status"
|
||||
|
||||
318
lib/I18n/translations/romanian.yaml
Normal file
318
lib/I18n/translations/romanian.yaml
Normal file
@@ -0,0 +1,318 @@
|
||||
_language_name: "Română"
|
||||
_language_code: "ROMANIAN"
|
||||
_order: "8"
|
||||
|
||||
STR_CROSSPOINT: "CrossPoint"
|
||||
STR_BOOTING: "PORNEŞTE"
|
||||
STR_SLEEPING: "REPAUS"
|
||||
STR_ENTERING_SLEEP: "Intră în repaus..."
|
||||
STR_BROWSE_FILES: "Răsfoieşte fişierele"
|
||||
STR_FILE_TRANSFER: "Transfer de fişiere"
|
||||
STR_SETTINGS_TITLE: "Setări"
|
||||
STR_CALIBRE_LIBRARY: "Biblioteca Calibre"
|
||||
STR_CONTINUE_READING: "Continuă lectura"
|
||||
STR_NO_OPEN_BOOK: "Nicio carte deschisă"
|
||||
STR_START_READING: "Începeţi lectura"
|
||||
STR_BOOKS: "Cărţi"
|
||||
STR_NO_BOOKS_FOUND: "Nicio carte găsită"
|
||||
STR_SELECT_CHAPTER: "Selectaţi capitolul"
|
||||
STR_NO_CHAPTERS: "Niciun capitol"
|
||||
STR_END_OF_BOOK: "Sfârşitul cărţii"
|
||||
STR_EMPTY_CHAPTER: "Capitol gol"
|
||||
STR_INDEXING: "Indexează..."
|
||||
STR_MEMORY_ERROR: "Eroare de memorie"
|
||||
STR_PAGE_LOAD_ERROR: "Eroare la încărcarea paginii"
|
||||
STR_EMPTY_FILE: "Fişier gol"
|
||||
STR_OUT_OF_BOUNDS: "Eroare: În afara limitelor"
|
||||
STR_LOADING: "Se încarcă..."
|
||||
STR_LOADING_POPUP: "Se încarcă..."
|
||||
STR_LOAD_XTC_FAILED: "Eroare la încărcarea XTC"
|
||||
STR_LOAD_TXT_FAILED: "Eroare la încărcarea TXT"
|
||||
STR_LOAD_EPUB_FAILED: "Eroare la încărcarea EPUB"
|
||||
STR_SD_CARD_ERROR: "Eroare la cardul SD"
|
||||
STR_WIFI_NETWORKS: "Reţele WiFi"
|
||||
STR_NO_NETWORKS: "Nu s-au găsit reţele"
|
||||
STR_NETWORKS_FOUND: "%zu reţele găsite"
|
||||
STR_SCANNING: "Scanează..."
|
||||
STR_CONNECTING: "Se conectează..."
|
||||
STR_CONNECTED: "Conectat!"
|
||||
STR_CONNECTION_FAILED: "Conexiune eşuată"
|
||||
STR_CONNECTION_TIMEOUT: "Timp de conectare depăşit"
|
||||
STR_FORGET_NETWORK: "Uitaţi reţeaua?"
|
||||
STR_SAVE_PASSWORD: "Salvaţi parola?"
|
||||
STR_REMOVE_PASSWORD: "Ştergeţi parola salvată?"
|
||||
STR_PRESS_OK_SCAN: "Apăsaţi OK pentru a scana din nou"
|
||||
STR_PRESS_ANY_CONTINUE: "Apăsaţi orice buton pentru a continua"
|
||||
STR_SELECT_HINT: "STÂNGA/DREAPTA: Selectaţi | OK: Confirmaţi"
|
||||
STR_HOW_CONNECT: "Cum doriţi să vă conectaţi?"
|
||||
STR_JOIN_NETWORK: "Conectaţi-vă la o reţea"
|
||||
STR_CREATE_HOTSPOT: "Creaţi un hotspot"
|
||||
STR_JOIN_DESC: "Conectaţi-vă la o reţea WiFi existentă"
|
||||
STR_HOTSPOT_DESC: "Creaţi un hotspot WiFi"
|
||||
STR_STARTING_HOTSPOT: "Hotspot porneşte..."
|
||||
STR_HOTSPOT_MODE: "Mod Hotspot"
|
||||
STR_CONNECT_WIFI_HINT: "Conectaţi-vă dispozitivul la această reţea WiFi"
|
||||
STR_OPEN_URL_HINT: "Deschideţi acest URL în browserul dvs."
|
||||
STR_OR_HTTP_PREFIX: "sau http://"
|
||||
STR_SCAN_QR_HINT: "sau scanaţi codul QR cu telefonul dvs.:"
|
||||
STR_CALIBRE_WIRELESS: "Calibre Wireless"
|
||||
STR_CALIBRE_WEB_URL: "Calibre URL"
|
||||
STR_CONNECT_WIRELESS: "Conectaţi-vă ca dispozitiv wireless"
|
||||
STR_NETWORK_LEGEND: "* = Criptat | + = Salvat"
|
||||
STR_MAC_ADDRESS: "Adresă MAC:"
|
||||
STR_CHECKING_WIFI: "Verificare WiFi..."
|
||||
STR_ENTER_WIFI_PASSWORD: "Introduceţi parola WiFi"
|
||||
STR_ENTER_TEXT: "Introduceţi textul"
|
||||
STR_TO_PREFIX: "la "
|
||||
STR_CALIBRE_DISCOVERING: "Descoperă Calibre..."
|
||||
STR_CALIBRE_CONNECTING_TO: "Se conectează la "
|
||||
STR_CALIBRE_CONNECTED_TO: "Conectat la "
|
||||
STR_CALIBRE_WAITING_COMMANDS: "Se aşteaptă comenzi..."
|
||||
STR_CONNECTION_FAILED_RETRYING: "(Conexiune eşuată, se reîncearcă)"
|
||||
STR_CALIBRE_DISCONNECTED: "Calibre deconectat"
|
||||
STR_CALIBRE_WAITING_TRANSFER: "Se aşteaptă transfer..."
|
||||
STR_CALIBRE_TRANSFER_HINT: "Dacă transferul eşuează, activaţi\\n'Ignoraţi spaţiul liber' în setările\\nplugin-ului SmartDevice din Calibre."
|
||||
STR_CALIBRE_RECEIVING: "Se primeşte: "
|
||||
STR_CALIBRE_RECEIVED: "Primite: "
|
||||
STR_CALIBRE_WAITING_MORE: "Se aşteaptă mai multe..."
|
||||
STR_CALIBRE_FAILED_CREATE_FILE: "Creare fişier eşuată"
|
||||
STR_CALIBRE_PASSWORD_REQUIRED: "Necesită parolă"
|
||||
STR_CALIBRE_TRANSFER_INTERRUPTED: "Transfer întrerupt"
|
||||
STR_CALIBRE_INSTRUCTION_1: "1) Instalaţi plugin-ul CrossPoint Reader"
|
||||
STR_CALIBRE_INSTRUCTION_2: "2) Fiţi în aceeaşi reţea WiFi"
|
||||
STR_CALIBRE_INSTRUCTION_3: "3) În Calibre: \"Trimiteţi la dispozitiv\""
|
||||
STR_CALIBRE_INSTRUCTION_4: "\"Păstraţi acest ecran deschis în timpul trimiterii\""
|
||||
STR_CAT_DISPLAY: "Ecran"
|
||||
STR_CAT_READER: "Lectură"
|
||||
STR_CAT_CONTROLS: "Controale"
|
||||
STR_CAT_SYSTEM: "Sistem"
|
||||
STR_SLEEP_SCREEN: "Ecran de repaus"
|
||||
STR_SLEEP_COVER_MODE: "Mod ecran de repaus cu copertă"
|
||||
STR_STATUS_BAR: "Bara de stare"
|
||||
STR_HIDE_BATTERY: "Ascunde procentul bateriei"
|
||||
STR_EXTRA_SPACING: "Spaţiere suplimentară între paragrafe"
|
||||
STR_TEXT_AA: "Anti-Aliasing text"
|
||||
STR_SHORT_PWR_BTN: "Apăsare scurtă întrerupător"
|
||||
STR_ORIENTATION: "Orientare lectură"
|
||||
STR_FRONT_BTN_LAYOUT: "Aspect butoane frontale"
|
||||
STR_SIDE_BTN_LAYOUT: "Aspect butoane laterale (lectură)"
|
||||
STR_LONG_PRESS_SKIP: "Sărire capitol la apăsare lungă"
|
||||
STR_FONT_FAMILY: "Familie font lectură"
|
||||
STR_EXT_READER_FONT: "Font lectură extern"
|
||||
STR_EXT_CHINESE_FONT: "Font lectură"
|
||||
STR_EXT_UI_FONT: "Font meniu"
|
||||
STR_FONT_SIZE: "Dimensiune font"
|
||||
STR_LINE_SPACING: "Spaţiere între rânduri"
|
||||
STR_ASCII_LETTER_SPACING: "Spaţiere litere ASCII "
|
||||
STR_ASCII_DIGIT_SPACING: "Spaţiere cifre ASCII"
|
||||
STR_CJK_SPACING: "Spaţiere CJK"
|
||||
STR_COLOR_MODE: "Mod culoare"
|
||||
STR_SCREEN_MARGIN: "Margine ecran lectură"
|
||||
STR_PARA_ALIGNMENT: "Aliniere paragrafe reader"
|
||||
STR_HYPHENATION: "Silabisire"
|
||||
STR_TIME_TO_SLEEP: "Timp până la repaus"
|
||||
STR_REFRESH_FREQ: "Frecvenţă reîmprospătare"
|
||||
STR_CALIBRE_SETTINGS: "Setări Calibre"
|
||||
STR_KOREADER_SYNC: "Sincronizare KOReader"
|
||||
STR_CHECK_UPDATES: "Căutaţi actualizări"
|
||||
STR_LANGUAGE: "Limbă"
|
||||
STR_SELECT_WALLPAPER: "Selectaţi imaginea de fundal"
|
||||
STR_CLEAR_READING_CACHE: "Goliţi cache-ul de lectură"
|
||||
STR_CALIBRE: "Calibre"
|
||||
STR_USERNAME: "Utilizator"
|
||||
STR_PASSWORD: "Parolă"
|
||||
STR_SYNC_SERVER_URL: "URL server sincronizare"
|
||||
STR_DOCUMENT_MATCHING: "Corespondenţă document"
|
||||
STR_AUTHENTICATE: "Autentificare"
|
||||
STR_KOREADER_USERNAME: "Nume utilizator KOReader"
|
||||
STR_KOREADER_PASSWORD: "Parolă KOReader"
|
||||
STR_FILENAME: "Nume fişier"
|
||||
STR_BINARY: "Fişier binar"
|
||||
STR_SET_CREDENTIALS_FIRST: "Vă rugăm să setaţi mai întâi acreditările"
|
||||
STR_WIFI_CONN_FAILED: "Conexiune WiFi eşuată"
|
||||
STR_AUTHENTICATING: "Se autentifică..."
|
||||
STR_AUTH_SUCCESS: "Autentificare reuşită!"
|
||||
STR_KOREADER_AUTH: "Autentificare KOReader"
|
||||
STR_SYNC_READY: "Sincronizare KOReader gata de utilizare"
|
||||
STR_AUTH_FAILED: "Autentificare eşuată"
|
||||
STR_DONE: "Gata"
|
||||
STR_CLEAR_CACHE_WARNING_1: "Aceasta va şterge tot cache-ul de lectură."
|
||||
STR_CLEAR_CACHE_WARNING_2: "Tot progresul de lectură va fi pierdut!"
|
||||
STR_CLEAR_CACHE_WARNING_3: "Cărţile vor trebui reindexate"
|
||||
STR_CLEAR_CACHE_WARNING_4: "când vor fi deschise din nou."
|
||||
STR_CLEARING_CACHE: "Se şterge cache-ul..."
|
||||
STR_CACHE_CLEARED: "Cache şters"
|
||||
STR_ITEMS_REMOVED: "elemente eliminate"
|
||||
STR_FAILED_LOWER: "eşuat"
|
||||
STR_CLEAR_CACHE_FAILED: "ştergerea cache-ului a eşuat"
|
||||
STR_CHECK_SERIAL_OUTPUT: "Verificaţi ieşirea serială pentru detalii"
|
||||
STR_DARK: "Întunecat"
|
||||
STR_LIGHT: "Luminos"
|
||||
STR_CUSTOM: "Personalizat"
|
||||
STR_COVER: "Copertă"
|
||||
STR_NONE_OPT: "Niciunul"
|
||||
STR_FIT: "Potrivit"
|
||||
STR_CROP: "Decupat"
|
||||
STR_NO_PROGRESS: "Fără progres"
|
||||
STR_FULL_OPT: "Complet"
|
||||
STR_NEVER: "Niciodată"
|
||||
STR_IN_READER: "În lectură"
|
||||
STR_ALWAYS: "Întotdeauna"
|
||||
STR_IGNORE: "Ignoră"
|
||||
STR_SLEEP: "Repaus"
|
||||
STR_PAGE_TURN: "Răsfoire pagină"
|
||||
STR_PORTRAIT: "Vertical"
|
||||
STR_LANDSCAPE_CW: "Orizontal dreapta"
|
||||
STR_INVERTED: "Invers"
|
||||
STR_LANDSCAPE_CCW: "Orizontal stânga"
|
||||
STR_FRONT_LAYOUT_BCLR: "Înapoi, Cnfrm, St, Dr"
|
||||
STR_FRONT_LAYOUT_LRBC: "St, Dr, Înapoi, Cnfrm"
|
||||
STR_FRONT_LAYOUT_LBCR: "St, Înapoi, Cnfrm, Dr"
|
||||
STR_PREV_NEXT: "Înainte/Înapoi"
|
||||
STR_NEXT_PREV: "Înapoi/Înainte"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
STR_SMALL: "Mic"
|
||||
STR_MEDIUM: "Mediu"
|
||||
STR_LARGE: "Mare"
|
||||
STR_X_LARGE: "Foarte mare"
|
||||
STR_TIGHT: "Strâns"
|
||||
STR_NORMAL: "Normal"
|
||||
STR_WIDE: "Larg"
|
||||
STR_JUSTIFY: "Aliniere"
|
||||
STR_ALIGN_LEFT: "Stânga"
|
||||
STR_CENTER: "Centru"
|
||||
STR_ALIGN_RIGHT: "Dreapta"
|
||||
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 pagină"
|
||||
STR_PAGES_5: "5 pagini"
|
||||
STR_PAGES_10: "10 pagini"
|
||||
STR_PAGES_15: "15 pagini"
|
||||
STR_PAGES_30: "30 pagini"
|
||||
STR_UPDATE: "Actualizare"
|
||||
STR_CHECKING_UPDATE: "Se verifică actualizările..."
|
||||
STR_NEW_UPDATE: "Nouă actualizare disponibilă!"
|
||||
STR_CURRENT_VERSION: "Versiune curentă: "
|
||||
STR_NEW_VERSION: "Noua versiune: "
|
||||
STR_UPDATING: "Se actualizează..."
|
||||
STR_NO_UPDATE: "Nicio actualizare disponibilă"
|
||||
STR_UPDATE_FAILED: "Actualizare eşuată"
|
||||
STR_UPDATE_COMPLETE: "Actualizare completă"
|
||||
STR_POWER_ON_HINT: "Apăsaţi şi menţineţi apăsat întrerupătorul pentru a porni din nou"
|
||||
STR_EXTERNAL_FONT: "Font extern"
|
||||
STR_BUILTIN_DISABLED: "Încorporat (Dezactivat)"
|
||||
STR_NO_ENTRIES: "Niciun rezultat găsit"
|
||||
STR_DOWNLOADING: "Se descarcă..."
|
||||
STR_DOWNLOAD_FAILED: "Descărcare eşuată"
|
||||
STR_ERROR_MSG: "Eroare:"
|
||||
STR_UNNAMED: "Fără nume"
|
||||
STR_NO_SERVER_URL: "Niciun URL de server configurat"
|
||||
STR_FETCH_FEED_FAILED: "Eşec la preluarea feed-ului"
|
||||
STR_PARSE_FEED_FAILED: "Eşec la analizarea feed-ului"
|
||||
STR_NETWORK_PREFIX: "Reţea: "
|
||||
STR_IP_ADDRESS_PREFIX: "Adresă IP: "
|
||||
STR_SCAN_QR_WIFI_HINT: "sau scanaţi codul QR cu telefonul pentru a vă conecta la Wifi."
|
||||
STR_ERROR_GENERAL_FAILURE: "Eroare: Eşec general"
|
||||
STR_ERROR_NETWORK_NOT_FOUND: "Eroare: Reţea negăsită"
|
||||
STR_ERROR_CONNECTION_TIMEOUT: "Eroare: Timp de conectare depăşit"
|
||||
STR_SD_CARD: "Card SD"
|
||||
STR_BACK: "« Înapoi"
|
||||
STR_EXIT: "« Ieşire"
|
||||
STR_HOME: "« Acasă"
|
||||
STR_SAVE: "« Salvare"
|
||||
STR_SELECT: "Selectează"
|
||||
STR_TOGGLE: "Schimbă"
|
||||
STR_CONFIRM: "Confirmă"
|
||||
STR_CANCEL: "Anulare"
|
||||
STR_CONNECT: "Conectare"
|
||||
STR_OPEN: "Deschidere"
|
||||
STR_DOWNLOAD: "Descarcă"
|
||||
STR_RETRY: "Reîncercare"
|
||||
STR_YES: "Da"
|
||||
STR_NO: "Nu"
|
||||
STR_STATE_ON: "Pornit"
|
||||
STR_STATE_OFF: "Oprit"
|
||||
STR_SET: "Setare"
|
||||
STR_NOT_SET: "Neconfigurat"
|
||||
STR_DIR_LEFT: "Stânga"
|
||||
STR_DIR_RIGHT: "Dreapta"
|
||||
STR_DIR_UP: "Sus"
|
||||
STR_DIR_DOWN: "Jos"
|
||||
STR_CAPS_ON: "CAPS"
|
||||
STR_CAPS_OFF: "caps"
|
||||
STR_OK_BUTTON: "OK"
|
||||
STR_ON_MARKER: "[ON]"
|
||||
STR_SLEEP_COVER_FILTER: "Filtru ecran de repaus"
|
||||
STR_FILTER_CONTRAST: "Contrast"
|
||||
STR_STATUS_BAR_FULL_PERCENT: "Complet cu procentaj"
|
||||
STR_STATUS_BAR_FULL_BOOK: "Complet cu bara de carte"
|
||||
STR_STATUS_BAR_BOOK_ONLY: "Doar bara de carte"
|
||||
STR_STATUS_BAR_FULL_CHAPTER: "Complet cu bara de capitol"
|
||||
STR_UI_THEME: "Tema UI"
|
||||
STR_THEME_CLASSIC: "Clasic"
|
||||
STR_THEME_LYRA: "Lyra"
|
||||
STR_SUNLIGHT_FADING_FIX: "Corecţie estompare lumină"
|
||||
STR_REMAP_FRONT_BUTTONS: "Remapare butoane frontale"
|
||||
STR_OPDS_BROWSER: "Browser OPDS"
|
||||
STR_COVER_CUSTOM: "Copertă + Personalizat"
|
||||
STR_RECENTS: "Recente"
|
||||
STR_MENU_RECENT_BOOKS: "Cărţi recente"
|
||||
STR_NO_RECENT_BOOKS: "Nicio carte recentă"
|
||||
STR_CALIBRE_DESC: "Utilizaţi transferurile wireless ale dispozitivului Calibre"
|
||||
STR_FORGET_AND_REMOVE: "Uitaţi reţeaua şi eliminaţi parola salvată?"
|
||||
STR_FORGET_BUTTON: "Uitaţi"
|
||||
STR_CALIBRE_STARTING: "Pornirea Calibre..."
|
||||
STR_CALIBRE_SETUP: "Configurare"
|
||||
STR_CALIBRE_STATUS: "Stare"
|
||||
STR_CLEAR_BUTTON: "ştergere"
|
||||
STR_DEFAULT_VALUE: "Implicit"
|
||||
STR_REMAP_PROMPT: "Apăsaţi un buton frontal pentru fiecare rol"
|
||||
STR_UNASSIGNED: "Neatribuit"
|
||||
STR_ALREADY_ASSIGNED: "Deja atribuit"
|
||||
STR_REMAP_RESET_HINT: "Buton lateral Sus: Resetaţi la aspectul implicit"
|
||||
STR_REMAP_CANCEL_HINT: "Buton lateral Jos: Anulaţi remaparea"
|
||||
STR_HW_BACK_LABEL: "Înapoi (butonul 1)"
|
||||
STR_HW_CONFIRM_LABEL: "Confirmare (butonul 2)"
|
||||
STR_HW_LEFT_LABEL: "Stânga (butonul 3)"
|
||||
STR_HW_RIGHT_LABEL: "Dreapta (butonul 4)"
|
||||
STR_GO_TO_PERCENT: "Săriţi la %"
|
||||
STR_GO_HOME_BUTTON: "Acasă"
|
||||
STR_SYNC_PROGRESS: "Progres sincronizare"
|
||||
STR_DELETE_CACHE: "Ştergere cache cărţi"
|
||||
STR_CHAPTER_PREFIX: "Capitol: "
|
||||
STR_PAGES_SEPARATOR: " pagini | "
|
||||
STR_BOOK_PREFIX: "Carte: "
|
||||
STR_KBD_SHIFT: "shift"
|
||||
STR_KBD_SHIFT_CAPS: "SHIFT"
|
||||
STR_KBD_LOCK: "LOCK"
|
||||
STR_CALIBRE_URL_HINT: "Pentru Calibre, adăugaţi /opds la URL"
|
||||
STR_PERCENT_STEP_HINT: "Stânga/Dreapta: 1% Sus/Jos: 10%"
|
||||
STR_SYNCING_TIME: "Timp de sincronizare..."
|
||||
STR_CALC_HASH: "Calcularea hash-ului documentului..."
|
||||
STR_HASH_FAILED: "Eşec la calcularea hash-ului documentului"
|
||||
STR_FETCH_PROGRESS: "Preluarea progresului de la distanţă..."
|
||||
STR_UPLOAD_PROGRESS: "Încărcarea progresului..."
|
||||
STR_NO_CREDENTIALS_MSG: "Nicio acreditare configurată"
|
||||
STR_KOREADER_SETUP_HINT: "Configuraţi contul KOReader în setări"
|
||||
STR_PROGRESS_FOUND: "Progres găsit!"
|
||||
STR_REMOTE_LABEL: "Remote:"
|
||||
STR_LOCAL_LABEL: "Local:"
|
||||
STR_PAGE_OVERALL_FORMAT: "Pagina %d, %.2f%% din total"
|
||||
STR_PAGE_TOTAL_OVERALL_FORMAT: "Pagina %d/%d, %.2f%% din total"
|
||||
STR_DEVICE_FROM_FORMAT: " De la: %s"
|
||||
STR_APPLY_REMOTE: "Aplică progresul remote"
|
||||
STR_UPLOAD_LOCAL: "Încărcaţi progresul local"
|
||||
STR_NO_REMOTE_MSG: "Niciun progres remote găsit"
|
||||
STR_UPLOAD_PROMPT: "Încărcaţi poziţia curentă?"
|
||||
STR_UPLOAD_SUCCESS: "Progres încărcat!"
|
||||
STR_SYNC_FAILED_MSG: "Sincronizare eşuată"
|
||||
STR_SECTION_PREFIX: "Secţiune "
|
||||
STR_UPLOAD: "Încărcare"
|
||||
STR_BOOK_S_STYLE: "Stilul cărţii"
|
||||
STR_EMBEDDED_STYLE: "Stil încorporat"
|
||||
STR_OPDS_SERVER_URL: "URL server OPDS"
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Недавние книги"
|
||||
STR_NO_RECENT_BOOKS: "Нет недавних книг"
|
||||
STR_CALIBRE_DESC: "Использовать беспроводную передачу Calibre"
|
||||
STR_FORGET_AND_REMOVE: "Забыть сеть и удалить сохранённый пароль?"
|
||||
STR_FORGET_BUTTON: "Забыть сеть"
|
||||
STR_FORGET_BUTTON: "Забыть"
|
||||
STR_CALIBRE_STARTING: "Запуск Calibre..."
|
||||
STR_CALIBRE_SETUP: "Настройка"
|
||||
STR_CALIBRE_STATUS: "Статус"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Libros recientes"
|
||||
STR_NO_RECENT_BOOKS: "No hay libros recientes"
|
||||
STR_CALIBRE_DESC: "Utilice las transferencias dispositivos inalámbricos de calibre"
|
||||
STR_FORGET_AND_REMOVE: "Olvidar la red y eliminar la contraseña guardada?"
|
||||
STR_FORGET_BUTTON: "Olvidar la red"
|
||||
STR_FORGET_BUTTON: "Olvidar"
|
||||
STR_CALIBRE_STARTING: "Iniciando calibre..."
|
||||
STR_CALIBRE_SETUP: "Configuración"
|
||||
STR_CALIBRE_STATUS: "Estado"
|
||||
|
||||
@@ -267,7 +267,7 @@ STR_MENU_RECENT_BOOKS: "Senaste böckerna"
|
||||
STR_NO_RECENT_BOOKS: "Inga senaste böcker"
|
||||
STR_CALIBRE_DESC: "Använd Calibres trådlösa enhetsöverföring"
|
||||
STR_FORGET_AND_REMOVE: "Glöm nätverk och ta bort sparat lösenord?"
|
||||
STR_FORGET_BUTTON: "Glöm nätverk"
|
||||
STR_FORGET_BUTTON: "Glöm"
|
||||
STR_CALIBRE_STARTING: "Starar Calibre…"
|
||||
STR_CALIBRE_SETUP: "Inställning"
|
||||
STR_CALIBRE_STATUS: "Status"
|
||||
|
||||
@@ -9,3 +9,11 @@ uint32_t utf8NextCodepoint(const unsigned char** string);
|
||||
size_t utf8RemoveLastChar(std::string& str);
|
||||
// Truncate string by removing N UTF-8 codepoints from the end.
|
||||
void utf8TruncateChars(std::string& str, size_t numChars);
|
||||
|
||||
// Returns true for Unicode combining diacritical marks that should not advance the cursor.
|
||||
inline bool utf8IsCombiningMark(const uint32_t cp) {
|
||||
return (cp >= 0x0300 && cp <= 0x036F) // Combining Diacritical Marks
|
||||
|| (cp >= 0x1DC0 && cp <= 0x1DFF) // Combining Diacritical Marks Supplement
|
||||
|| (cp >= 0x20D0 && cp <= 0x20FF) // Combining Diacritical Marks for Symbols
|
||||
|| (cp >= 0xFE20 && cp <= 0xFE2F); // Combining Half Marks
|
||||
}
|
||||
|
||||
@@ -196,6 +196,15 @@ std::string getFileName(std::string filename) {
|
||||
return filename.substr(0, pos);
|
||||
}
|
||||
|
||||
std::string getFileExtension(std::string filename) {
|
||||
if (filename.back() == '/') {
|
||||
return "";
|
||||
}
|
||||
const auto pos = filename.rfind('.');
|
||||
if (pos == std::string::npos) return "";
|
||||
return filename.substr(pos);
|
||||
}
|
||||
|
||||
void MyLibraryActivity::render(Activity::RenderLock&&) {
|
||||
renderer.clearScreen();
|
||||
|
||||
@@ -214,7 +223,8 @@ void MyLibraryActivity::render(Activity::RenderLock&&) {
|
||||
GUI.drawList(
|
||||
renderer, Rect{0, contentTop, pageWidth, contentHeight}, files.size(), selectorIndex,
|
||||
[this](int index) { return getFileName(files[index]); }, nullptr,
|
||||
[this](int index) { return UITheme::getFileIcon(files[index]); });
|
||||
[this](int index) { return UITheme::getFileIcon(files[index]); },
|
||||
[this](int index) { return getFileExtension(files[index]); }, false);
|
||||
}
|
||||
|
||||
// Help text
|
||||
|
||||
Reference in New Issue
Block a user