[reader] Fixed bug when a word is too big

This commit is contained in:
Laury
2022-04-08 19:03:13 +02:00
parent 22ba190542
commit 2bf6de5044
17 changed files with 218 additions and 75 deletions

View File

@@ -1,6 +1,6 @@
# LaTeX Parser
In the reader app, you can read a txt file. You can also read a txt file with LaTeX expression inside of it.
In the reader app, you can read a txt file. You can also read a .urt file with LaTeX expression inside of it.
All the symbols you can use are listed here :

View File

@@ -1,3 +1,5 @@
ReaderApp = "Leser"
ReaderAppCapital = "LESER"
NoFileToDisplay = "Keine Dateien zum Anzeigen"
NoFileToDisplay = "Keine Dateien zum Anzeigen"
FileError1 = "Fehler beim Lesen der Datei"
FileError2 = "Bitte überprüfen Sie die Syntax"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Reader"
ReaderAppCapital = "READER"
NoFileToDisplay = "No file to display"
NoFileToDisplay = "No file to display"
FileError1 = "Error while reading file"
FileError2 = "Please check its syntax"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lector"
ReaderAppCapital = "LECTOR"
NoFileToDisplay ="No hay archivos para mostrar"
NoFileToDisplay ="No hay archivos para mostrar"
FileError1 = "Error al leer el archivo"
FileError2 = "Por favor revise su sintaxis"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Liseuse"
ReaderAppCapital = "LISEUSE"
NoFileToDisplay = "Aucun fichier à afficher"
NoFileToDisplay = "Aucun fichier à afficher"
FileError1 = "Erreur durant la lecture du fichier"
FileError2 = "Veuillez vérifier sa syntaxe"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Olvasó"
ReaderAppCapital = "OLVASÓ"
NoFileToDisplay = "Nincs megjeleníthető fájl"
NoFileToDisplay = "Nincs megjeleníthető fájl"
FileError1 = "Hiba a fájl olvasása közben"
FileError2 = "Kérjük, ellenőrizze a szintaxisát"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lettore"
ReaderAppCapital = "LETTORE"
NoFileToDisplay = "essun file da visualizzare"
NoFileToDisplay = "essun file da visualizzare"
FileError1 = "Errore durante la lettura del file"
FileError2 = "Si prega di controllare la sua sintassi"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Lezer"
ReaderAppCapital = "LEZER"
NoFileToDisplay = "Geen bestanden om weer te geven"
NoFileToDisplay = "Geen bestanden om weer te geven"
FileError1 = "Fout tijdens het lezen van bestand"
FileError2 = "Controleer de syntaxis ervan"

View File

@@ -1,3 +1,5 @@
ReaderApp = "Leitor"
ReaderAppCapital = "LEITOR"
NoFileToDisplay = "Nenhum arquivo para exibir"
NoFileToDisplay = "Nenhum arquivo para exibir"
FileError1 = "Erro ao ler o arquivo"
FileError2 = "Verifique sua sintaxe"

View File

@@ -1,10 +1,12 @@
#include "read_book_controller.h"
#include <apps/apps_container.h>
namespace Reader
namespace Reader
{
ReadBookController::ReadBookController(Responder * parentResponder) :
ViewController(parentResponder)
ViewController(parentResponder),
m_readerView(this)
{
}
@@ -18,7 +20,7 @@ void ReadBookController::setBook(const External::Archive::File& file, bool isRic
m_readerView.setText(reinterpret_cast<const char*>(file.data), file.dataLength, isRichTextFile);
}
bool ReadBookController::handleEvent(Ion::Events::Event event) {
bool ReadBookController::handleEvent(Ion::Events::Event event) {
if(event == Ion::Events::Down) {
m_readerView.nextPage();
return true;
@@ -34,6 +36,13 @@ void ReadBookController::viewDidDisappear() {
savePosition();
}
void ReadBookController::throwError() {
static_cast<StackViewController *>(parentResponder())->pop();
Container::activeApp()->displayWarning(I18n::Message::SyntaxError);
// As the error is thrown when we are drawing, me must redraw the whole screen
AppsContainer::sharedAppsContainer()->redrawWindow();
}
void ReadBookController::savePosition() const {
BookSave save = m_readerView.getBookSave();

View File

@@ -16,6 +16,7 @@ public:
void viewDidDisappear() override;
void savePosition() const;
void loadPosition();
void throwError();
private:
WordWrapTextView m_readerView;
const External::Archive::File* m_file;
@@ -23,4 +24,4 @@ private:
}
#endif
#endif

View File

@@ -129,6 +129,13 @@ const char * StartOfPrintableWord(const char * word, const char * start) {
if (word == start) {
return word;
}
// Go to start of code point with some code points dark magic
if (!(*word & 0x80 == 0)) {
word--;
while (!(*word & 0x80 && *word & 0x40)) {
word--;
}
}
UTF8Decoder decoder(start, word);
CodePoint codePoint = decoder.previousCodePoint();
const char * result = word;

View File

@@ -5,17 +5,19 @@
#include <poincare/expression.h>
#include "../shared/poincare_helpers.h"
#include <poincare/undefined.h>
#include "read_book_controller.h"
namespace Reader
{
WordWrapTextView::WordWrapTextView() :
WordWrapTextView::WordWrapTextView(ReadBookController * readBookController) :
PointerTextView(GlobalPreferences::sharedGlobalPreferences()->font()),
m_pageOffset(0),
m_nextPageOffset(0),
m_length(0),
m_isRichTextFile(false), // Value isn't important, it will change when the file is loaded
m_lastPagesOffsetsIndex(0)
m_lastPagesOffsetsIndex(0),
m_readBookController(readBookController)
{
for (int i = 0; i < k_lastOffsetsBufferSize; i++) {
m_lastPagesOffsets[i] = -1; // -1 Means : no informations
@@ -96,7 +98,8 @@ void WordWrapTextView::richTextPreviousPage() {
endOfWord = startOfWord - 1; // Update next endOfWord
continue;
} else {
// TODO: print error
m_readBookController->throwError();
return;
}
}
@@ -110,7 +113,7 @@ void WordWrapTextView::richTextPreviousPage() {
if (expressionStart < text()) {
break; // File isn't rightly formated
}
expressionStart ++;
expressionStart --;
}
TexParser parser = TexParser(expressionStart, endOfWord);
@@ -175,13 +178,16 @@ void WordWrapTextView::plainTextPreviousPage() {
KDPoint textEndPosition(m_frame.width() - k_margin, m_frame.height() - k_margin);
while(startOfWord>=text()) {
startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
endOfWord = UTF8Helper::EndOfWord(startOfWord);
while(endOfWord>text()) {
KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
KDPoint textStartPosition = KDPoint(textEndPosition.x()-textSize.width(), textEndPosition.y());
if (textStartPosition.x() < k_margin) {
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
startOfWord = endOfWord - (textEndPosition.x() - k_margin) / charWidth;
continue;
}
textEndPosition = KDPoint(m_frame.width() - k_margin, textEndPosition.y() - charHeight);
textStartPosition = KDPoint(textEndPosition.x() - textSize.width(), textEndPosition.y());
}
@@ -203,16 +209,23 @@ void WordWrapTextView::plainTextPreviousPage() {
break;
}
if (textStartPosition.y() != textEndPosition.y()) { // If line changed, x is at start of line
if (textStartPosition.y() != textEndPosition.y()) { // If line changed, x is at start of line
textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y());
}
if (textStartPosition.x() < k_margin) { // Go to line if left overflow
if (textStartPosition.x() <= k_margin) { // Go to line if left overflow
textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y() - charHeight);
}
textEndPosition = textStartPosition;
endOfWord = startOfWord + 1;
startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
}
while (endOfWord < text() + m_length && (*endOfWord == ' ' || *endOfWord == '\n')) {
endOfWord++;
}
m_pageOffset = endOfWord - text();
}
void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
@@ -242,11 +255,12 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
const int wordMaxLength = (m_frame.width() - 2*k_margin ) / charWidth;
char word[wordMaxLength];
Layout layout;
Layout tooBigLayout = EmptyLayout::Builder(); // To store layouts that are too big to be displayed entirely on one line
KDCoordinate tooBigLayoutAlreadyWroteWidth = 0; // We store here the part of the layout that has already been written
KDPoint textPosition = KDPoint(k_margin, k_margin);
while (!endOfPage && startOfWord < endOfFile) {
while (!endOfPage && (startOfWord < endOfFile || !tooBigLayout.isEmpty())) {
// We process line by line
const char * firstReadIndex = startOfWord;
@@ -256,8 +270,19 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
KDCoordinate baseline = charHeight / 2;
while (firstReadIndex < endOfFile) {
// 1.0. We check if we are drawing a too big layout
if (!tooBigLayout.isEmpty()) {
lineSize = tooBigLayout.layoutSize();
baseline = tooBigLayout.baseline();
if (tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth > m_frame.width() - 2 * k_margin) {
// Remaining part of the layout don't fit on the line
break;
}
}
KDSize textSize = KDSizeZero;
KDCoordinate updatedBaseline = 0; // 0 if it's not a layout
// 1.1. And we check if we are at the end of the line
if(*firstReadIndex == '\n') {
@@ -265,12 +290,20 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
// 1.2. Check if we are in a color change
if (*firstReadIndex == '%') { // We assume each '%' non-escaped is announcing a color change // TODO : check file is rightly formated
if (*firstReadIndex == '%') { // We assume each '%' non-escaped is announcing a color change
// We go to the end of the color change + 1
const char * startIndex = firstReadIndex;
do {
firstReadIndex ++;
} while (*firstReadIndex != '%');
} while (*firstReadIndex != '%' && firstReadIndex < endOfFile && startIndex - firstReadIndex < 5);
firstReadIndex ++;
if (firstReadIndex - startIndex > 5) {
m_readBookController->throwError();
return;
}
continue;
}
@@ -286,16 +319,17 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
TexParser parser = TexParser(expressionStart, firstReadIndex);
Layout layout = parser.getLayout();
Layout firstReadLayout = parser.getLayout();
KDCoordinate layoutBaseline = layout.baseline();
// We check if we must change baseline
KDCoordinate layoutBaseline = firstReadLayout.baseline();
updatedBaseline = baseline; // We really update baseline after, if the layout fit on the line
if (layoutBaseline > baseline) {
baseline = layoutBaseline;
updatedBaseline = layoutBaseline;
}
KDSize layoutSize = layout.layoutSize();
textSize = KDSize(layoutSize.width(), layoutSize.height() + baseline - layoutBaseline);
KDSize layoutSize = firstReadLayout.layoutSize();
textSize = KDSize(layoutSize.width(), layoutSize.height() + updatedBaseline - layoutBaseline);
firstReadIndex ++;
}
@@ -315,11 +349,16 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// 1.5. We update size
int newWidth = lineSize.width() + textSize.width();
// We check if the new text fit on the line
if (newWidth > m_frame.width() - 2 * k_margin) {
// We check if the new text fit on the line.
// If not, we look if only the word cannot fit on one line. If so, we do not go to the line
if (newWidth > m_frame.width() - 2 * k_margin && !(textSize.width() > m_frame.width() - 2 * k_margin)) {
break;
}
if (updatedBaseline) { // Now we update baseline
baseline = updatedBaseline;
}
int newHeight;
if (lineSize.height() > textSize.height()) {
newHeight = lineSize.height();
@@ -345,7 +384,30 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
}
// 2. And now... we read the line again to draw it !
while (startOfWord < endOfFile) {
while (startOfWord < endOfFile || !tooBigLayout.isEmpty()) {
// 2.0 Before all, we check if we were drawing a layout that was too big to fit on one line.
// In this case, we do all the routine here.
if (!tooBigLayout.isEmpty()) {
KDPoint position = KDPoint(textPosition.x() - tooBigLayoutAlreadyWroteWidth, textPosition.y());
tooBigLayout.draw(ctx, position, m_textColor, m_backgroundColor);
// We fill the left margin
ctx->fillRect(KDRect(0, textPosition.y(), k_margin, tooBigLayout.layoutSize().height()), m_backgroundColor);
KDCoordinate drawnWidth = tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth;
tooBigLayoutAlreadyWroteWidth += drawnWidth;
if (drawnWidth > m_frame.width() - 2 * k_margin) {
// We have to fill the margin with the background color
ctx->fillRect(KDRect(textPosition.x() + drawnWidth, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
break;
} else {
tooBigLayout = EmptyLayout::Builder(); // We have finished drawing the tooBigLayout
}
continue;
}
Layout layout;
//2.1. We check if we are at the end of the line
if (*startOfWord == '\n') {
@@ -355,7 +417,6 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// We aren't supposed to be at the end of the page, else the loop on top would have stopped drawing
}
const char * endOfWord;
// 2.2. Check if we are in a color change
@@ -369,7 +430,8 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
continue;
}
else {
// TODO: Print exception
m_readBookController->throwError();
return;
}
}
@@ -412,14 +474,34 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
// 2.4.1. Check if we need to go to the next line
if(endTextPosition.x() > m_frame.width() - k_margin) {
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
break;
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
if (toDraw == ToDraw::Text) {
startOfWord = endOfWord - (endTextPosition.x() - k_margin) / charWidth;
continue;
} else {
assert(toDraw == ToDraw::Expression);
tooBigLayout = layout;
tooBigLayoutAlreadyWroteWidth += m_frame.width() - k_margin - textPosition.x();
endTextPosition = KDPoint(k_margin, textPosition.y() + lineSize.height()); // We jump line now, because this will be the next value of textPosition
}
} else {
textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
// endTextPosition will be updated later
break;
}
}
// 2.5. Now we draw !
if (toDraw == ToDraw::Expression) {
KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - layout.baseline());
layout.draw(ctx, position, m_textColor, m_backgroundColor);
if (!tooBigLayout.isEmpty()) {
// We fill the margin
ctx->fillRect(KDRect(m_frame.width() - k_margin, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
}
}
else {
KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - charHeight / 2);
@@ -435,6 +517,11 @@ void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
textPosition = KDPoint(textPosition.x() + charWidth, textPosition.y());
}
startOfWord = endOfWord;
// 2.8. We exit now if we are in the "too big layout" case
if (!tooBigLayout.isEmpty()) {
break;
}
}
}
m_nextPageOffset = startOfWord - text();
@@ -446,7 +533,7 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
const char * endOfFile = text() + m_length;
const char * startOfWord = text() + m_pageOffset;
const char * endOfWord = UTF8Helper::EndOfWord(startOfWord);
const char * endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
KDPoint textPosition(k_margin, k_margin);
const int wordMaxLength = 128;
@@ -458,8 +545,13 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
while(startOfWord < endOfFile) {
KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
KDPoint nextTextPosition = KDPoint(textPosition.x()+textSize.width(), textPosition.y());
if(nextTextPosition.x() > m_frame.width() - k_margin) { // Right overflow
// We check if the word is too long to be displayed entirely on just one line
if(textSize.width() > m_frame.width() - 2 * k_margin) {
endOfWord = startOfWord + (m_frame.width() - k_margin - textPosition.x()) / charWidth;
continue;
}
textPosition = KDPoint(k_margin, textPosition.y() + textSize.height());
nextTextPosition = KDPoint(k_margin + textSize.width(), textPosition.y());
}
@@ -488,15 +580,15 @@ void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
if(nextTextPosition.y() + textSize.height() > m_frame.height() - k_margin) { // If out of page, quit
break;
}
if(nextTextPosition.y() != textPosition.y()) { // If line changed, x is at start of line
if(nextTextPosition.y() != textPosition.y()) { // If line changed, x is at start of line
nextTextPosition = KDPoint(k_margin, nextTextPosition.y());
}
if(nextTextPosition.x() > m_frame.width() - k_margin) { // Go to line if right overflow
if(nextTextPosition.x() >= m_frame.width() - k_margin) { // Go to line if right overflow
nextTextPosition = KDPoint(k_margin, nextTextPosition.y() + textSize.height());
}
textPosition = nextTextPosition;
endOfWord = UTF8Helper::EndOfWord(startOfWord);
endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
}
m_nextPageOffset = startOfWord - text();
@@ -523,7 +615,7 @@ bool WordWrapTextView::updateTextColorForward(const char * colorStart) const {
int keySize = 1;
KDColor lastColor = m_textColor;
switch (*(colorStart+1))
{
case 'r':
@@ -666,6 +758,6 @@ bool WordWrapTextView::updateTextColorBackward(const char * colorStart) const {
}
return true;
}
}
}

View File

@@ -12,9 +12,11 @@ struct BookSave {
KDColor color;
};
class ReadBookController;
class WordWrapTextView : public PointerTextView {
public:
WordWrapTextView();
WordWrapTextView(ReadBookController * readBookController);
void drawRect(KDContext * ctx, KDRect rect) const override;
void setText(const char*, int length, bool isRichTextFile);
void nextPage();
@@ -42,6 +44,7 @@ private:
*/
int m_lastPagesOffsets[k_lastOffsetsBufferSize];
int m_lastPagesOffsetsIndex;
ReadBookController * m_readBookController;
};
}

View File

@@ -5,7 +5,7 @@ import os
import re
import sys
import argparse
from typing import Dict, List
# Deep translator import
try:
from deep_translator import GoogleTranslator
@@ -64,14 +64,14 @@ def translate(text: str, output_language: str, input_language: str = 'auto')\
return translator.translate(text)
def get_all_files_in_directory(directory: str) -> list[str]:
def get_all_files_in_directory(directory: str) -> List[str]:
"""Get all files in the given directory recursively.
Args:
directory (str): The directory
Returns:
List[str]: The list of files in the directory
Liststr]: The list of files in the directory
"""
# Initialize the list of files
@@ -92,7 +92,7 @@ def get_all_files_in_directory(directory: str) -> list[str]:
return files
def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
def get_i18n_files(directory: str = '.') -> Dict[str, List[str]]:
"""Get the list of i18n files in the given directory.
Args:
@@ -100,13 +100,13 @@ def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
Defaults to '.'.
Returns:
dict[list[str]]: The list of i18n files in a dictionary of languages.
Dict[List[str]]: The list of i18n files in a dictionary of languages.
"""
# Get all files in the directory recursively
files = get_all_files_in_directory(directory)
# Initialize the dictionary
i18n_files_language: dict[str, list[str]] = {}
i18n_files_language: Dict[str, List[str]] = {}
# Iterate over all files in the directory
for i in files:
# If the file is an i18n file
@@ -125,21 +125,21 @@ def get_i18n_files(directory: str = '.') -> dict[str, list[str]]:
return i18n_files_language
def need_to_be_translated(keys: dict[str, list[list[str]]])\
-> dict[str, list[list[str]]]:
def need_to_be_translated(keys: Dict[str, List[List[str]]])\
-> Dict[str, List[List[str]]]:
"""Return the key that needs to be translated by locale.
Args:
keys (dict[str, list[str]]): The keys of the i18n files
keys (Dict[str, List[str]]): The keys of the i18n files
Returns:
dict[str, list[str]]: The keys that needs to be translated,
Dict[str, List[str]]: The keys that needs to be translated,
sorted by locale
"""
# Initialize the list of keys
keys_list: list[list[str]] = []
keys_to_translate: dict[str, list[list[str]]] = {}
keys_list: List[List[str]] = []
keys_to_translate: Dict[str, List[List[str]]] = {}
# Iterate over all locales
for value_ in keys.values():
# Iterate on keys of the locale
@@ -151,14 +151,14 @@ def need_to_be_translated(keys: dict[str, list[list[str]]])\
keys_list.append(key)
for locale, value in keys.items():
# Initialize the list of keys in the locale
keys_in_locale: list[str] = [i[0] for i in value]
keys_in_locale: List[str] = [i[0] for i in value]
# Get the keys of keys that need to be translated
keys_to_translate_in_locale: list[list[str]] = [
keys_to_translate_in_locale: List[List[str]] = [
key for key in keys_list if key[0] not in keys_in_locale
]
# Remove duplicates from the list
# Initialize the deduplicated list
keys_to_translate_in_locale_deduplicated: list[list[str]] = []
keys_to_translate_in_locale_deduplicated: List[List[str]] = []
# Iterate over the duplicated list
for item in keys_to_translate_in_locale:
# If the key is not in the deduplicated list, add it
@@ -170,14 +170,14 @@ def need_to_be_translated(keys: dict[str, list[list[str]]])\
return keys_to_translate
def get_keys_in_file(filename: str) -> list[list[str]]:
def get_keys_in_file(filename: str) -> List[List[str]]:
"""Return a list of keys in the file.
Args:
filename (str): The name of the file to read
Returns:
list[str]: The keys in the file
List[str]: The keys in the file
"""
# Initialize the list of keys in the file
@@ -211,19 +211,19 @@ def get_keys_in_file(filename: str) -> list[list[str]]:
return keys
def list_keys(i18n_files: dict[str, list[str]]) -> dict[str, list[list[str]]]:
def list_keys(i18n_files: Dict[str, List[str]]) -> Dict[str, List[List[str]]]:
"""List all keys in the i18n files.
Args:
i18n_files (dict[str, list[str]]): I18n files list
i18n_files (Dict[str, List[str]]): I18n files list
Returns:
dict[str, list[str]]: The dictionnary of keys in the i18n files by
Dict[str, List[str]]: The dictionnary of keys in the i18n files by
locale.
"""
# Initialize the list of keys in the i18n files
keys_dict: dict[str, list[list[str]]] = {}
keys_dict: Dict[str, List[List[str]]] = {}
# Iterate on the locales
for locale in i18n_files:
# Initialize the dictionary for the locale
@@ -294,22 +294,22 @@ def get_value_from_key(key_to_find: str, filename_generic: str, locale: str)\
return ""
def translate_missing_keys(keys_to_translate: dict[str, list[list[str]]],
input_language: str) -> dict[str, list[list[str]]]:
def translate_missing_keys(keys_to_translate: Dict[str, List[List[str]]],
input_language: str) -> Dict[str, List[List[str]]]:
"""Get a dictionary of file with the keys and translations to add.
Args:
keys_to_translate (dict[str, list[list[str]]]): The list of keys to
keys_to_translate (Dict[str, List[List[str]]]): The list of keys to
translate
input_language (str): The language to get the text that will be
translated
Returns:
dict[str, list[str]]: The dictionary of files with translations
Dict[str, List[str]]: The dictionary of files with translations
"""
# Initialize the dictionary of translations
output: dict[str, list[list[str]]] = {}
output: Dict[str, List[List[str]]] = {}
# Initialize the variable to store the number of translated keys
keys_translated: int = 0
# Iterate over the locales of the dictionary of untranslated keys
@@ -373,11 +373,11 @@ def translate_missing_keys(keys_to_translate: dict[str, list[list[str]]],
return output
def save_translations(missing_keys_translation: dict[str, list[list[str]]]):
def save_translations(missing_keys_translation: Dict[str, List[List[str]]]):
"""Save the translations.
Args:
missing_keys_translation (dict[str, list[list[str]]]): The dictionary
missing_keys_translation (Dict[str, List[List[str]]]): The dictionary
of translations
"""

View File

@@ -120,6 +120,7 @@ size_t StringGlyphLength(const char * s, int maxSize = -1);
const char * BeginningOfWord(const char * text, const char * word);
// Returns the position of the first following char ' ', '\n' or 0
const char * EndOfWord(const char * word);
const char * EndOfWord(const char * word, const char * end);
// On a line, count number of glyphs before and after locations
void countGlyphsInLine(const char * text, int * before, int * after, const char * beforeLocation, const char *afterLocation = nullptr);

View File

@@ -475,6 +475,20 @@ const char * EndOfWord(const char * word) {
return result;
}
const char * EndOfWord(const char * word, const char * end) {
UTF8Decoder decoder(word);
CodePoint codePoint = decoder.nextCodePoint();
const char * result = word;
while (!CodePointIsEndOfWord(codePoint)) {
result = decoder.stringPosition();
if (result >= end) {
break;
}
codePoint = decoder.nextCodePoint();
}
return result;
}
void countGlyphsInLine(const char * text, int * before, int * after, const char * beforeLocation, const char *afterLocation) {
UTF8Helper::CodePointAction countGlyph = [](int, void * glyphCount, int, int) {
int * castedCount = (int *) glyphCount;