diff --git a/apps/reader/TexParser.md b/apps/reader/TexParser.md index b530498cd..2ff9e9865 100644 --- a/apps/reader/TexParser.md +++ b/apps/reader/TexParser.md @@ -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 : diff --git a/apps/reader/base.de.i18n b/apps/reader/base.de.i18n index 3dcf262d7..9cbb39897 100644 --- a/apps/reader/base.de.i18n +++ b/apps/reader/base.de.i18n @@ -1,3 +1,5 @@ ReaderApp = "Leser" ReaderAppCapital = "LESER" -NoFileToDisplay = "Keine Dateien zum Anzeigen" \ No newline at end of file +NoFileToDisplay = "Keine Dateien zum Anzeigen" +FileError1 = "Fehler beim Lesen der Datei" +FileError2 = "Bitte überprüfen Sie die Syntax" diff --git a/apps/reader/base.en.i18n b/apps/reader/base.en.i18n index 0b0a2de2a..2cb016526 100644 --- a/apps/reader/base.en.i18n +++ b/apps/reader/base.en.i18n @@ -1,3 +1,5 @@ ReaderApp = "Reader" ReaderAppCapital = "READER" -NoFileToDisplay = "No file to display" \ No newline at end of file +NoFileToDisplay = "No file to display" +FileError1 = "Error while reading file" +FileError2 = "Please check its syntax" diff --git a/apps/reader/base.es.i18n b/apps/reader/base.es.i18n index bcbe8f0cd..76962dca3 100644 --- a/apps/reader/base.es.i18n +++ b/apps/reader/base.es.i18n @@ -1,3 +1,5 @@ ReaderApp = "Lector" ReaderAppCapital = "LECTOR" -NoFileToDisplay ="No hay archivos para mostrar" \ No newline at end of file +NoFileToDisplay ="No hay archivos para mostrar" +FileError1 = "Error al leer el archivo" +FileError2 = "Por favor revise su sintaxis" diff --git a/apps/reader/base.fr.i18n b/apps/reader/base.fr.i18n index f8b97e036..b74e6add0 100644 --- a/apps/reader/base.fr.i18n +++ b/apps/reader/base.fr.i18n @@ -1,3 +1,5 @@ ReaderApp = "Liseuse" ReaderAppCapital = "LISEUSE" -NoFileToDisplay = "Aucun fichier à afficher" \ No newline at end of file +NoFileToDisplay = "Aucun fichier à afficher" +FileError1 = "Erreur durant la lecture du fichier" +FileError2 = "Veuillez vérifier sa syntaxe" \ No newline at end of file diff --git a/apps/reader/base.hu.i18n b/apps/reader/base.hu.i18n index 09357ced7..9580dc40a 100644 --- a/apps/reader/base.hu.i18n +++ b/apps/reader/base.hu.i18n @@ -1,3 +1,5 @@ ReaderApp = "Olvasó" ReaderAppCapital = "OLVASÓ" -NoFileToDisplay = "Nincs megjeleníthető fájl" \ No newline at end of file +NoFileToDisplay = "Nincs megjeleníthető fájl" +FileError1 = "Hiba a fájl olvasása közben" +FileError2 = "Kérjük, ellenőrizze a szintaxisát" diff --git a/apps/reader/base.it.i18n b/apps/reader/base.it.i18n index c553356d9..abfa80eda 100644 --- a/apps/reader/base.it.i18n +++ b/apps/reader/base.it.i18n @@ -1,3 +1,5 @@ ReaderApp = "Lettore" ReaderAppCapital = "LETTORE" -NoFileToDisplay = "essun file da visualizzare" \ No newline at end of file +NoFileToDisplay = "essun file da visualizzare" +FileError1 = "Errore durante la lettura del file" +FileError2 = "Si prega di controllare la sua sintassi" diff --git a/apps/reader/base.nl.i18n b/apps/reader/base.nl.i18n index 576752673..9f8c2304f 100644 --- a/apps/reader/base.nl.i18n +++ b/apps/reader/base.nl.i18n @@ -1,3 +1,5 @@ ReaderApp = "Lezer" ReaderAppCapital = "LEZER" -NoFileToDisplay = "Geen bestanden om weer te geven" \ No newline at end of file +NoFileToDisplay = "Geen bestanden om weer te geven" +FileError1 = "Fout tijdens het lezen van bestand" +FileError2 = "Controleer de syntaxis ervan" diff --git a/apps/reader/base.pt.i18n b/apps/reader/base.pt.i18n index 2aa88319b..0c2281287 100644 --- a/apps/reader/base.pt.i18n +++ b/apps/reader/base.pt.i18n @@ -1,3 +1,5 @@ ReaderApp = "Leitor" ReaderAppCapital = "LEITOR" -NoFileToDisplay = "Nenhum arquivo para exibir" \ No newline at end of file +NoFileToDisplay = "Nenhum arquivo para exibir" +FileError1 = "Erro ao ler o arquivo" +FileError2 = "Verifique sua sintaxe" diff --git a/apps/reader/read_book_controller.cpp b/apps/reader/read_book_controller.cpp index b80e6cdae..85ef0b77c 100644 --- a/apps/reader/read_book_controller.cpp +++ b/apps/reader/read_book_controller.cpp @@ -1,10 +1,12 @@ #include "read_book_controller.h" +#include -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(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(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(); diff --git a/apps/reader/read_book_controller.h b/apps/reader/read_book_controller.h index 642269d99..7fb42b165 100644 --- a/apps/reader/read_book_controller.h +++ b/apps/reader/read_book_controller.h @@ -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 \ No newline at end of file +#endif diff --git a/apps/reader/utility.cpp b/apps/reader/utility.cpp index 6ffc5820a..d0f9e172c 100644 --- a/apps/reader/utility.cpp +++ b/apps/reader/utility.cpp @@ -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; diff --git a/apps/reader/word_wrap_view.cpp b/apps/reader/word_wrap_view.cpp index 367e2b039..032b039ec 100644 --- a/apps/reader/word_wrap_view.cpp +++ b/apps/reader/word_wrap_view.cpp @@ -5,17 +5,19 @@ #include #include "../shared/poincare_helpers.h" #include +#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; -} +} } diff --git a/apps/reader/word_wrap_view.h b/apps/reader/word_wrap_view.h index 714f1a5f5..c50dba126 100644 --- a/apps/reader/word_wrap_view.h +++ b/apps/reader/word_wrap_view.h @@ -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; }; } diff --git a/build/utilities/translate.py b/build/utilities/translate.py index 72f851e45..1bfc533e6 100755 --- a/build/utilities/translate.py +++ b/build/utilities/translate.py @@ -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 """ diff --git a/ion/include/ion/unicode/utf8_helper.h b/ion/include/ion/unicode/utf8_helper.h index ba00c1950..a3ce96df8 100644 --- a/ion/include/ion/unicode/utf8_helper.h +++ b/ion/include/ion/unicode/utf8_helper.h @@ -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); diff --git a/ion/src/shared/unicode/utf8_helper.cpp b/ion/src/shared/unicode/utf8_helper.cpp index 9393069a6..0481df941 100644 --- a/ion/src/shared/unicode/utf8_helper.cpp +++ b/ion/src/shared/unicode/utf8_helper.cpp @@ -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;