From 96169a149ee47db36aa11b66eca1f272877feab4 Mon Sep 17 00:00:00 2001 From: Seif Soliman Date: Wed, 17 Dec 2025 20:18:46 +0200 Subject: [PATCH 1/6] fix(caret): align caret correctly in RTL tape mode (@byseif21) (#7259) * In RTL tests, enabling tape mode causes the main caret to be misaligned from the start of the test and remain offset while typing. The tape margin was always calculated from the left side, which is correct for LTR but incorrect for RTL layouts. fix * we should have mirrored the margin from the right side. --- frontend/src/ts/utils/caret.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/frontend/src/ts/utils/caret.ts b/frontend/src/ts/utils/caret.ts index 60c603c482ba..1b2b658afb7f 100644 --- a/frontend/src/ts/utils/caret.ts +++ b/frontend/src/ts/utils/caret.ts @@ -450,6 +450,9 @@ export class Caret { let left = 0; let top = 0; + const tapeOffset = + wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100); + // yes, this is all super verbose, but its easier to maintain and understand if (isWordRTL) { let afterLetterCorrection = 0; @@ -475,8 +478,7 @@ export class Caret { left += options.letter.getOffsetLeft(); left += afterLetterCorrection; if (this.isMainCaret && lockedMainCaretInTape) { - left += - wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100); + left += wordsWrapperCache.getOffsetWidth() - tapeOffset; } else { left += options.word.getOffsetLeft(); left += options.word.getOffsetWidth(); @@ -486,8 +488,7 @@ export class Caret { left += width * -1; } if (this.isMainCaret && lockedMainCaretInTape) { - left += - wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100); + left += wordsWrapperCache.getOffsetWidth() - tapeOffset; } else { left += options.letter.getOffsetLeft(); left += options.word.getOffsetLeft(); @@ -508,15 +509,13 @@ export class Caret { left += options.letter.getOffsetLeft(); left += afterLetterCorrection; if (this.isMainCaret && lockedMainCaretInTape) { - left += - wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100); + left += tapeOffset; } else { left += options.word.getOffsetLeft(); } } else if (Config.tapeMode === "letter") { if (this.isMainCaret && lockedMainCaretInTape) { - left += - wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100); + left += tapeOffset; } else { left += options.letter.getOffsetLeft(); left += options.word.getOffsetLeft(); From 97b9085f7e252a080b950aff7979d9c58fa886ce Mon Sep 17 00:00:00 2001 From: Md Moushuf Alam <149342172+MoushufAlam@users.noreply.github.com> Date: Wed, 17 Dec 2025 23:49:43 +0530 Subject: [PATCH 2/6] refactor: replace jquery with dom utils in scroll-to-top button (@MoushufAlam) (#7257) ### Description Replaces jQuery usage with dom utils in the scroll-to-top button. Scope intentionally kept small per contributing guidelines. ### Checks - [x] Adding/modifying Typescript code? - [x] I have used `qs`, `qsa` or `qsr` instead of JQuery selectors. - [x] Check if any open issues are related to this PR; if so, be sure to tag them below. - [x] Make sure the PR title follows the Conventional Commits standard. (https://www.conventionalcommits.org for more info) - [x] Make sure to include your GitHub username prefixed with @ inside parentheses at the end of the PR title. Related to #7186 --- frontend/src/ts/elements/scroll-to-top.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/src/ts/elements/scroll-to-top.ts b/frontend/src/ts/elements/scroll-to-top.ts index 4eb654f11b10..2ebd2d48ea82 100644 --- a/frontend/src/ts/elements/scroll-to-top.ts +++ b/frontend/src/ts/elements/scroll-to-top.ts @@ -1,27 +1,30 @@ import * as ActivePage from "../states/active-page"; import { prefersReducedMotion } from "../utils/misc"; +import { qsr } from "../utils/dom"; let visible = false; +const button = qsr(".scrollToTopButton"); + export function hide(): void { - $(".scrollToTopButton").addClass("invisible"); + button.addClass("invisible"); visible = false; } function show(): void { - $(".scrollToTopButton").removeClass("invisible"); + button.removeClass("invisible"); visible = true; } -$(document).on("click", ".scrollToTopButton", () => { - $(".scrollToTopButton").addClass("invisible"); +button.on("click", () => { + button.addClass("invisible"); window.scrollTo({ top: 0, behavior: prefersReducedMotion() ? "instant" : "smooth", }); }); -$(window).on("scroll", () => { +window.addEventListener("scroll", () => { const page = ActivePage.get(); if (page === "test") return; From 74bafad7d5022badd9b41c64e23191c117ed1cb3 Mon Sep 17 00:00:00 2001 From: 100daysummer <138024460+100daysummer@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:32:49 +0200 Subject: [PATCH 3/6] impr(language): add bulgarian 1k (@100daysummer) (#7232) ### Description This commit expands the two bulgarian wordlists - bulgarian.json and bulgarian_latin.json ### Checks - [ ] Adding/modifying Typescript code? - [ ] I have used `qs`,`qsa` or `qsr` instead of JQuery selectors. - [ ] Adding quotes? - [ ] Make sure to include translations for the quotes in the description (or another comment) so we can verify their content. - [x] Adding a language? - Make sure to follow the [languages documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/LANGUAGES.md) - [x] Add language to `packages/schemas/src/languages.ts` - [x] Add language to exactly one group in `frontend/src/ts/constants/languages.ts` - [x] Add language json file to `frontend/static/languages` - [ ] Adding a theme? - Make sure to follow the [themes documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/THEMES.md) - [ ] Add theme to `packages/schemas/src/themes.ts` - [ ] Add theme to `frontend/src/ts/constants/themes.ts` - [ ] Add theme css file to `frontend/static/themes` - [ ] Add some screenshot of the theme, especially with different test settings (colorful, flip colors) to your pull request - [ ] Adding a layout? - [ ] Make sure to follow the [layouts documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/LAYOUTS.md) - [ ] Add layout to `packages/schemas/src/layouts.ts` - [ ] Add layout json file to `frontend/static/layouts` - [ ] Adding a font? - Make sure to follow the [themes documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/FONTS.md) - [ ] Add font file to `frontend/static/webfonts` - [ ] Add font to `packages/schemas/src/fonts.ts` - [ ] Add font to `frontend/src/ts/constants/fonts.ts` - [ ] Check if any open issues are related to this PR; if so, be sure to tag them below. - [x] Make sure the PR title follows the Conventional Commits standard. (https://www.conventionalcommits.org for more info) - [x] Make sure to include your GitHub username prefixed with @ inside parentheses at the end of the PR title. --------- Co-authored-by: Jack --- frontend/src/ts/constants/languages.ts | 7 +- frontend/static/languages/bulgarian.json | 4 + frontend/static/languages/bulgarian_1k.json | 1020 +++++++++++++++++ .../static/languages/bulgarian_latin.json | 4 + .../static/languages/bulgarian_latin_1k.json | 1017 ++++++++++++++++ packages/schemas/src/languages.ts | 2 + 6 files changed, 2053 insertions(+), 1 deletion(-) create mode 100644 frontend/static/languages/bulgarian_1k.json create mode 100644 frontend/static/languages/bulgarian_latin_1k.json diff --git a/frontend/src/ts/constants/languages.ts b/frontend/src/ts/constants/languages.ts index af5eddfd3565..fd963dfed479 100644 --- a/frontend/src/ts/constants/languages.ts +++ b/frontend/src/ts/constants/languages.ts @@ -188,7 +188,12 @@ export const LanguageGroups: Record = { swahili: ["swahili_1k"], maori: ["maori_1k"], catalan: ["catalan", "catalan_1k"], - bulgarian: ["bulgarian", "bulgarian_latin"], + bulgarian: [ + "bulgarian", + "bulgarian_1k", + "bulgarian_latin", + "bulgarian_latin_1k", + ], bosnian: ["bosnian", "bosnian_4k"], esperanto: [ "esperanto", diff --git a/frontend/static/languages/bulgarian.json b/frontend/static/languages/bulgarian.json index 5776c70e64b4..0f0ced2400bd 100644 --- a/frontend/static/languages/bulgarian.json +++ b/frontend/static/languages/bulgarian.json @@ -1,5 +1,9 @@ { "name": "bulgarian", + "rightToLeft": false, + "ligatures": false, + "orderedByFrequency": false, + "bcp47": "bg", "noLazyMode": true, "words": [ "а", diff --git a/frontend/static/languages/bulgarian_1k.json b/frontend/static/languages/bulgarian_1k.json new file mode 100644 index 000000000000..40235cfea26c --- /dev/null +++ b/frontend/static/languages/bulgarian_1k.json @@ -0,0 +1,1020 @@ +{ + "name": "bulgarian_1k", + "rightToLeft": false, + "ligatures": false, + "orderedByFrequency": false, + "bcp47": "bg", + "noLazyMode": true, + "words": [ + "а", + "август", + "автобус", + "автовоз", + "автоматичен", + "автомобил", + "автомобилен", + "автосалон", + "агония", + "адрес", + "аз", + "ако", + "активен", + "актьор", + "актьори", + "ами", + "ангел", + "април", + "асанасьор", + "асистент", + "асоциация", + "асфалт", + "атака", + "атаки", + "атакувам", + "атакуван", + "аудио", + "баба", + "бавен", + "балон", + "банка", + "баня", + "барабан", + "баскетбол", + "баща", + "бе", + "бебе", + "без", + "бездомник", + "безсмислен", + "бесило", + "беше", + "би", + "бил", + "билет", + "било", + "бира", + "битка", + "бих", + "благ", + "благодарност", + "благодаря", + "благоденствие", + "благоухание", + "ближен", + "близо", + "блок", + "богат", + "боли", + "болка", + "боровинка", + "боя", + "брат", + "братя", + "буря", + "бутилка", + "бутон", + "бъде", + "бърз", + "бял", + "бях", + "в", + "вагон", + "важен", + "ваза", + "вампир", + "вана", + "вар", + "варовик", + "вас", + "веднага", + "весел", + "вест", + "вече", + "вечер", + "взимам", + "ви", + "видим", + "видя", + "вие", + "виж", + "вилица", + "винаги", + "вино", + "виновен", + "виновна", + "виновното", + "висота", + "вихрушка", + "вихър", + "вкус", + "вкъщи", + "влак", + "власт", + "влезе", + "вода", + "воден", + "воденица", + "война", + "войник", + "волейбол", + "восък", + "враг", + "врата", + "време", + "връзка", + "връх", + "все", + "всеки", + "вселена", + "всички", + "всичко", + "всъщност", + "вход", + "вцепенен", + "вчера", + "във", + "въздух", + "въпрос", + "вятър", + "галерия", + "гащи", + "гел", + "ги", + "гирлянд", + "глагол", + "глад", + "глас", + "гласовит", + "глоба", + "глобален", + "глух", + "го", + "говоря", + "години", + "гол", + "голям", + "голямо", + "гора", + "гост", + "готвач", + "град", + "градина", + "грамота", + "граница", + "грешка", + "грозде", + "група", + "гръб", + "гръмотевица", + "гума", + "гърмя", + "да", + "дажба", + "дай", + "далече", + "дали", + "данък", + "дар", + "дарявам", + "дата", + "дванадесет", + "дванайсет", + "две", + "двор", + "дворец", + "девет", + "дело", + "делфин", + "ден", + "десет", + "дете", + "деца", + "диван", + "династия", + "днес", + "до", + "добавка", + "добавям", + "добър", + "довод", + "дойде", + "доказателство", + "докато", + "дол", + "долен", + "дом", + "домат", + "допир", + "дори", + "доста", + "достатъчно", + "достъп", + "доя", + "дреха", + "друг", + "друго", + "думa", + "дупка", + "душа", + "дъвка", + "дъга", + "дъжд", + "дълбок", + "дървета", + "дърво", + "държава", + "дюнер", + "дядо", + "дял", + "е", + "един", + "единадесет", + "единайсет", + "една", + "едно", + "езеро", + "език", + "ей", + "екип", + "екран", + "ела", + "електронен", + "електроника", + "епизод", + "есен", + "етаж", + "ето", + "жаба", + "жаден", + "жажда", + "жена", + "жив", + "живот", + "животно", + "жълт", + "за", + "завеса", + "завод", + "завъртам", + "задача", + "заедно", + "заек", + "закон", + "зала", + "залеж", + "залез", + "заливам", + "залязвам", + "запад", + "запалвам", + "заплаха", + "зар", + "заради", + "затова", + "зашивам", + "зашит", + "защипвам", + "защитавам", + "защо", + "защото", + "заявка", + "звук", + "звяр", + "здание", + "здраве", + "здравей", + "зеле", + "зелен", + "зима", + "зла", + "злато", + "зло", + "злоба", + "змей", + "змия", + "знае", + "знаете", + "знаеш", + "знам", + "знание", + "значи", + "зная", + "зъб", + "и", + "ивица", + "ивици", + "иглолистно", + "игра", + "играчи", + "играя", + "идея", + "избор", + "изглежда", + "излезе", + "излизам", + "изложба", + "изложение", + "изпратен", + "изпращам", + "изход", + "или", + "им", + "има", + "имам", + "имаме", + "имате", + "имаш", + "име", + "имена", + "инат", + "инструмент", + "иска", + "истина", + "история", + "йод", + "кабел", + "каза", + "казах", + "казвам", + "как", + "каква", + "какво", + "каквото", + "както", + "какъв", + "камера", + "камион", + "капачка", + "карта", + "картон", + "картоф", + "категория", + "катерица", + "като", + "кафе", + "квадрат", + "квартал", + "киви", + "китара", + "кифла", + "кифли", + "кифличка", + "кифлички", + "клавиатура", + "клавиш", + "клас", + "клетка", + "клон", + "ключ", + "книга", + "когато", + "което", + "кожа", + "които", + "кой", + "който", + "кокошка", + "кола", + "колко", + "колона", + "коляно", + "кон", + "конституция", + "континент", + "копая", + "копие", + "копирам", + "кораб", + "коса", + "котка", + "която", + "крава", + "крави", + "крак", + "кралица", + "кран", + "красив", + "крещя", + "кръв", + "кръг", + "крясък", + "култура", + "курс", + "кутия", + "куче", + "къде", + "където", + "към", + "къща", + "лале", + "лампа", + "ламя", + "легло", + "лежа", + "леля", + "лепенка", + "лесен", + "леха", + "леща", + "ли", + "лисица", + "листо", + "литература", + "лица", + "лице", + "лоби", + "логика", + "логичен", + "лодка", + "локално", + "лук", + "луна", + "лъв", + "лъжица", + "любимец", + "лято", + "магазин", + "магистрала", + "майка", + "маймуна", + "макарон", + "малина", + "малко", + "мама", + "мантия", + "мантията", + "маса", + "масаж", + "масивен", + "масло", + "масово", + "математика", + "матрак", + "мафия", + "мач", + "мащаб", + "мащабен", + "мая", + "ме", + "мед", + "медал", + "между", + "мен", + "мента", + "меса", + "месец", + "месо", + "мечта", + "ми", + "минавам", + "миниатюра", + "минута", + "мирис", + "мисля", + "мляко", + "мляскам", + "много", + "мога", + "могила", + "мода", + "може", + "мокра", + "молба", + "молив", + "моля", + "момент", + "момиче", + "момче", + "море", + "морков", + "морфема", + "мост", + "моя", + "му", + "музика", + "музикален", + "муха", + "място", + "мяу", + "на", + "навик", + "навреме", + "навън", + "над", + "надлез", + "надпис", + "наистина", + "накит", + "нали", + "намек", + "намери", + "намерих", + "наметвам", + "наметна", + "намеци", + "намирам", + "наоколо", + "направи", + "направя", + "напред", + "нар", + "наред", + "нарцис", + "нарязан", + "нас", + "насекоми", + "насекомо", + "насип", + "наставник", + "натиск", + "нахален", + "находка", + "начин", + "не", + "небе", + "небостъргач", + "него", + "негови", + "неговите", + "нежен", + "нежна", + "неин", + "нейн", + "нека", + "нектар", + "неща", + "нещо", + "нея", + "неясен", + "ни", + "нива", + "ние", + "никога", + "никой", + "нито", + "нищо", + "но", + "нов", + "новатор", + "новина", + "нож", + "номер", + "нос", + "носорог", + "нощ", + "нужда", + "някой", + "няколко", + "ням", + "няма", + "нямам", + "обичам", + "обработвам", + "обработка", + "обратен", + "обратно", + "обръщам", + "общ", + "общество", + "обяд", + "овощна", + "огън", + "ода", + "океан", + "око", + "опа", + "опит", + "ориз", + "осем", + "остров", + "островен", + "острови", + "от", + "отговор", + "отново", + "отрасъл", + "отрицание", + "отрова", + "очаквам", + "очи", + "още", + "паваж", + "пазар", + "пак", + "палеж", + "паница", + "пари", + "парк", + "пасивен", + "пате", + "патица", + "перон", + "песен", + "пет", + "печка", + "пеш", + "пея", + "пиеса", + "пиле", + "пингвин", + "пирамида", + "писан", + "писател", + "писмен", + "писменост", + "писмо", + "писък", + "писъци", + "питка", + "плаж", + "план", + "планета", + "планетариум", + "платно", + "плача", + "плет", + "плещи", + "плещите", + "плискам", + "плитка", + "плод", + "пляскам", + "по", + "повече", + "повечето", + "поглед", + "под", + "подаден", + "подем", + "позор", + "покривка", + "поле", + "полет", + "политика", + "полицай", + "полиция", + "полюс", + "помогнаха", + "помощ", + "популярен", + "поради", + "портал", + "посев", + "после", + "посока", + "посочвам", + "почасов", + "поща", + "право", + "правя", + "празен", + "празник", + "прасе", + "прах", + "прашен", + "пращам", + "превня", + "пред", + "предвид", + "преди", + "предмет", + "представител", + "предстои", + "предстоя", + "през", + "президент", + "премествам", + "пренебрегвам", + "пренебрежение", + "при", + "прибирам", + "прикритие", + "прилагателно", + "приличам", + "приличаш", + "пример", + "принтер", + "природа", + "пристрастен", + "пришивам", + "приятел", + "проблем", + "провеждам", + "прозорец", + "производител", + "пролет", + "промяна", + "прост", + "просто", + "простор", + "простота", + "професионалист", + "професия", + "професор", + "прошепвам", + "прошепнеш", + "пръст", + "прът", + "пръчка", + "птица", + "птици", + "пускам", + "пчела", + "първи", + "път", + "пътека", + "пътентранспорт", + "работа", + "равно", + "радиатор", + "радост", + "разбирам", + "развод", + "разговор", + "разказ", + "размер", + "разстройство", + "разтвор", + "разходка", + "рай", + "рак", + "рана", + "ранен", + "ранени", + "раница", + "рано", + "ред", + "режа", + "резба", + "река", + "релса", + "репичка", + "република", + "ресторант", + "решение", + "риба", + "род", + "роза", + "розова", + "розово", + "рокля", + "рояк", + "ръка", + "рядко", + "рядкост", + "рядък", + "с", + "са", + "сам", + "сама", + "само", + "светкавица", + "свещ", + "свобода", + "свързвам", + "свят", + "сграда", + "се", + "себе", + "сега", + "седем", + "седя", + "село", + "селски", + "семейство", + "сено", + "си", + "сигурен", + "сила", + "син", + "скалп", + "скачам", + "скелет", + "скеч", + "скоро", + "скорост", + "скоростен", + "скорпион", + "скъпа", + "сладко", + "след", + "слепец", + "случи", + "слънце", + "сляп", + "сме", + "смъквам", + "смърт", + "снеговалеж", + "снежен", + "снежинка", + "сняг", + "сол", + "спане", + "списък", + "спомен", + "спорт", + "сравнение", + "сравни", + "среща", + "става", + "ставам", + "стан", + "стар", + "стара", + "старост", + "стая", + "сте", + "стена", + "стене", + "стига", + "стикер", + "сто", + "стой", + "стол", + "страна", + "страст", + "страх", + "стрелям", + "струна", + "студ", + "супермаркет", + "сутрин", + "съдържание", + "съжалявам", + "съм", + "сън", + "сърце", + "със", + "състезавам", + "състезание", + "също", + "сяра", + "тава", + "таван", + "тази", + "тайна", + "така", + "там", + "танц", + "тате", + "татко", + "твърд", + "те", + "теб", + "тези", + "телевизия", + "телевизор", + "телефон", + "тенджера", + "тенджери", + "тетрадка", + "тефтер", + "техен", + "ти", + "тиган", + "тих", + "тихо", + "тича", + "тичам", + "това", + "тогава", + "този", + "той", + "толкова", + "тор", + "тост", + "точно", + "трактор", + "трамвай", + "три", + "тринадесет", + "тринайсет", + "триъгълник", + "труден", + "трябва", + "тук", + "тя", + "тяло", + "тях", + "уважение", + "уединение", + "украса", + "украсявам", + "ум", + "уплаха", + "уплашен", + "упражнение", + "ура", + "уред", + "усет", + "успех", + "успешен", + "устройство", + "утре", + "ухо", + "ученик", + "ученичка", + "училище", + "учител", + "файл", + "фактура", + "фараон", + "фенер", + "филм", + "финтирам", + "фитнес", + "флаг", + "фланелка", + "флейта", + "фокус", + "форма", + "фрактура", + "футбол", + "хайде", + "харесвам", + "хладилник", + "хляб", + "ход", + "хор", + "хора", + "хората", + "хотел", + "храст", + "хризантема", + "художник", + "цар", + "царевица", + "царица", + "цвете", + "цвят", + "цел", + "целина", + "цена", + "ценен", + "ценностс", + "църква", + "чайка", + "чакай", + "чакайте", + "чар", + "чаршаф", + "час", + "часовник", + "чаша", + "че", + "чепка", + "червена", + "червено", + "червеното", + "чест", + "често", + "четири", + "четиринадесет", + "четиринайсет", + "четка", + "чешма", + "числа", + "числително", + "число", + "чист", + "чистач", + "човек", + "чорапогащник", + "чужбина", + "чук", + "чучур", + "чушка", + "шанс", + "шепот", + "шептя", + "шест", + "широколистно", + "шише", + "шия", + "шкаф", + "шпатула", + "щастие", + "ще", + "щора", + "юг", + "юли", + "юни", + "юрган", + "ютия", + "я", + "ябълка", + "ягода", + "яде", + "ядене", + "яйце", + "яма", + "ями", + "яре", + "ярост", + "ярък", + "ясен", + "ястреб", + "ято" + ] +} diff --git a/frontend/static/languages/bulgarian_latin.json b/frontend/static/languages/bulgarian_latin.json index 5dc11a2c79ad..abe7937e8cdf 100644 --- a/frontend/static/languages/bulgarian_latin.json +++ b/frontend/static/languages/bulgarian_latin.json @@ -1,5 +1,9 @@ { "name": "bulgarian_latin", + "rightToLeft": false, + "ligatures": false, + "orderedByFrequency": false, + "bcp47": "bg", "noLazyMode": true, "words": [ "a", diff --git a/frontend/static/languages/bulgarian_latin_1k.json b/frontend/static/languages/bulgarian_latin_1k.json new file mode 100644 index 000000000000..cedc09b479d5 --- /dev/null +++ b/frontend/static/languages/bulgarian_latin_1k.json @@ -0,0 +1,1017 @@ +{ + "name": "bulgarian_latin_1k", + "rightToLeft": false, + "ligatures": false, + "orderedByFrequency": false, + "bcp47": "bg", + "noLazyMode": true, + "words": [ + "a", + "adres", + "agoniya", + "ako", + "aktiori", + "aktiven", + "aktor", + "ami", + "angel", + "april", + "asansior", + "asfalt", + "asistent", + "asociaciya", + "ataka", + "ataki", + "atakuvam", + "atakuvan", + "audio", + "avgust", + "avtobus", + "avtomatichen", + "avtomobil", + "avtomobilen", + "avtosalon", + "avtovoz", + "az", + "baba", + "balon", + "banka", + "banya", + "baraban", + "bashta", + "basketbol", + "baven", + "be", + "bebe", + "beshe", + "besilo", + "bez", + "bezdomnik", + "bezsmislen", + "bi", + "bih", + "bil", + "bilet", + "bilo", + "bira", + "bitka", + "blag", + "blagodarnost", + "blagodarq", + "blagodenstvie", + "blagouhanie", + "blizhen", + "blizo", + "blok", + "bogat", + "boli", + "bolka", + "borovinka", + "boya", + "bqh", + "brat", + "bratya", + "bude", + "burya", + "burz", + "butilka", + "buton", + "byal", + "car", + "carevica", + "carica", + "carkva", + "cel", + "celina", + "cena", + "cenen", + "cennosts", + "chakai", + "chakayte", + "char", + "charshaf", + "chas", + "chasha", + "chasovnik", + "chayka", + "che", + "chepka", + "chervena", + "cherveno", + "chervenoto", + "cheshma", + "chest", + "chesto", + "chetiri", + "chetirinadeset", + "chetirinayset", + "chetka", + "chisla", + "chislitelno", + "chislo", + "chist", + "chistach", + "chorapogashtnik", + "chovek", + "chuchur", + "chujbina", + "chuk", + "chushka", + "cvete", + "cvyat", + "da", + "dai", + "dajd", + "dalbok", + "daleche", + "dali", + "danuk", + "dar", + "darveta", + "daryavam", + "darzhava", + "data", + "davka", + "dazhba", + "deca", + "delfin", + "delo", + "den", + "deset", + "dete", + "devet", + "dinastiya", + "divan", + "dnes", + "do", + "dobavka", + "dobavyam", + "dobur", + "doide", + "dokato", + "dokazatelstvo", + "dol", + "dolen", + "dom", + "domat", + "dopir", + "dori", + "dosta", + "dostap", + "dostatuchno", + "dovod", + "doya", + "dreha", + "drug", + "drugo", + "duga", + "duma", + "dupka", + "durvo", + "dusha", + "dvanadeset", + "dvanayset", + "dve", + "dvor", + "dvorec", + "dyado", + "dyal", + "dyuner", + "e", + "edin", + "edinadeset", + "edinayset", + "edna", + "edno", + "ei", + "ekip", + "ekran", + "ela", + "elektronika", + "epizod", + "esen", + "etaj", + "eto", + "ezero", + "ezik", + "faktura", + "faraon", + "fayl", + "fener", + "film", + "fintiram", + "fitnes", + "flag", + "flanelka", + "fleyta", + "fokus", + "forma", + "fraktura", + "futbol", + "galeriya", + "gashti", + "gel", + "gi", + "girlyand", + "glad", + "glagol", + "glas", + "glasovit", + "globa", + "globalen", + "gluh", + "go", + "godini", + "gol", + "golyam", + "golyamo", + "gora", + "gost", + "gotvach", + "govorq", + "grad", + "gradina", + "gramota", + "gramotevica", + "granica", + "greshka", + "grozde", + "grub", + "grupa", + "guma", + "gurmq", + "haide", + "haresvam", + "hladilnik", + "hlyab", + "hod", + "hor", + "hora", + "horata", + "hotel", + "hrast", + "hrizantema", + "hudozhnik", + "i", + "ideya", + "iglolistno", + "igra", + "igrachi", + "igraya", + "ili", + "im", + "ima", + "imam", + "imame", + "imash", + "imate", + "ime", + "imena", + "inat", + "instrument", + "iska", + "istina", + "istoriya", + "ivica", + "ivici", + "izbor", + "izglejda", + "izhod", + "izleze", + "izlizam", + "izlozhba", + "izlozhenie", + "izprashtam", + "izpraten", + "jaba", + "jaden", + "jena", + "jiv", + "jivot", + "kabel", + "kadeto", + "kafe", + "kak", + "kakto", + "kakuv", + "kakva", + "kakvo", + "kakvoto", + "kamera", + "kamion", + "kapachka", + "karta", + "kartof", + "karton", + "kashta", + "kategoriya", + "katerica", + "kato", + "kaza", + "kazah", + "kazvam", + "kifla", + "kifli", + "kiflichka", + "kiflichki", + "kitara", + "kivi", + "klas", + "klaviatura", + "klavish", + "kletka", + "klon", + "klyuch", + "kniga", + "koeto", + "kogato", + "koi", + "koito", + "koja", + "kokoshka", + "kola", + "kolko", + "kolona", + "kolyano", + "kon", + "konstituciya", + "kontinent", + "kopaya", + "kopie", + "kopiram", + "koqto", + "korab", + "kosa", + "kotka", + "krag", + "krak", + "kralica", + "kran", + "krasiv", + "krava", + "kravi", + "kreshtya", + "kruv", + "kryasyk", + "kuche", + "kude", + "kultura", + "kum", + "kurs", + "kutiya", + "kvadrat", + "kvartal", + "lale", + "lampa", + "lamya", + "lav", + "lazhica", + "leglo", + "leha", + "lelya", + "lepenka", + "lesen", + "leshta", + "lezha", + "li", + "lica", + "lice", + "lisica", + "listo", + "literatura", + "lobi", + "lodka", + "logichen", + "logika", + "lokalno", + "luk", + "luna", + "lyato", + "lyubimec", + "mach", + "mafiya", + "magazin", + "magistrala", + "maika", + "makaron", + "malina", + "malko", + "mama", + "mantiya", + "mantiyata", + "masa", + "masazh", + "mashtab", + "mashtaben", + "masiven", + "maslo", + "masovo", + "matematika", + "matrak", + "maya", + "maymuna", + "me", + "mechta", + "med", + "medal", + "mejdu", + "men", + "menta", + "mesa", + "mesec", + "meso", + "mi", + "minavam", + "miniatyura", + "minuta", + "miris", + "mislq", + "mlyako", + "mlyaskam", + "mnogo", + "moda", + "moga", + "mogila", + "moje", + "mokra", + "molba", + "moliv", + "molq", + "momche", + "moment", + "momiche", + "moq", + "more", + "morfema", + "morkov", + "most", + "mqsto", + "mu", + "muha", + "muzika", + "muzikalen", + "myau", + "na", + "nachin", + "nad", + "nadlez", + "nadpis", + "nahalen", + "nahodka", + "naistina", + "nakit", + "nali", + "nameci", + "namek", + "nameri", + "namerih", + "nametna", + "nametvam", + "namiram", + "naokolo", + "napravi", + "napravq", + "napred", + "nar", + "narcis", + "nared", + "naryazan", + "nas", + "nasekomi", + "nasekomo", + "nasip", + "nastavnik", + "natisk", + "navan", + "navik", + "navreme", + "ne", + "nebe", + "nebostargach", + "nego", + "negovi", + "negovite", + "nein", + "neka", + "nektar", + "neq", + "neshta", + "neshto", + "neyasen", + "neyn", + "nezhen", + "nezhna", + "ni", + "nie", + "nikoga", + "nikoi", + "nishto", + "nito", + "niva", + "no", + "nomer", + "nos", + "nosht", + "nosorog", + "nov", + "novator", + "novina", + "nozh", + "nqkoi", + "nqkolko", + "nqma", + "nqmam", + "nujda", + "nyam", + "obicham", + "obrabotka", + "obrabotvam", + "obrashtam", + "obraten", + "obratno", + "obsht", + "obshtestvo", + "obyad", + "ochakvam", + "ochi", + "oda", + "ogun", + "okean", + "oko", + "opa", + "opit", + "oriz", + "osem", + "oshte", + "ostrov", + "ostroven", + "ostrovi", + "ot", + "otgovor", + "otnovo", + "otrasal", + "otricanie", + "otrova", + "ovoshtna", + "pak", + "palezh", + "panica", + "pari", + "park", + "parvi", + "pasiven", + "pate", + "pateka", + "patentransport", + "patica", + "pavazh", + "pazar", + "pchela", + "pechka", + "peq", + "peron", + "pesen", + "pesh", + "pet", + "piesa", + "pile", + "pingvin", + "piramida", + "pisaci", + "pisak", + "pisan", + "pisatel", + "pismen", + "pismenost", + "pismo", + "pitka", + "placha", + "plaj", + "plan", + "planeta", + "planetarium", + "platno", + "pleshti", + "pleshtite", + "plet", + "pliskam", + "plitka", + "plod", + "plyaskam", + "po", + "pochasov", + "pod", + "podaden", + "podem", + "pogled", + "pokrivka", + "pole", + "polet", + "policay", + "policiya", + "politika", + "polyus", + "pomognaha", + "pomosht", + "populyaren", + "poradi", + "portal", + "posev", + "poshta", + "posle", + "posochvam", + "posoka", + "poveche", + "povecheto", + "pozor", + "prachka", + "prah", + "prase", + "prashen", + "prashtam", + "prat", + "pravo", + "pravq", + "prazen", + "praznik", + "pred", + "predi", + "predmet", + "predstavitel", + "predstoi", + "predstoya", + "predvid", + "premestvam", + "prenebregvam", + "prenebrezhenie", + "prevnya", + "prez", + "prezident", + "pri", + "pribiram", + "prikritie", + "prilagatelno", + "prilicham", + "prilichash", + "primer", + "printer", + "priqtel", + "priroda", + "prishivam", + "pristrasten", + "problem", + "profesionalist", + "profesiya", + "profesor", + "proizvoditel", + "prolet", + "promyana", + "proshepnesh", + "proshepvam", + "prost", + "prosto", + "prostor", + "prostota", + "provezhdam", + "prozorec", + "prust", + "ptica", + "ptici", + "puskam", + "put", + "q", + "rabota", + "radiator", + "radost", + "rak", + "rana", + "ranen", + "raneni", + "ranica", + "rano", + "ravno", + "ray", + "razbiram", + "razgovar", + "razhodka", + "razkaz", + "razmer", + "razstroystvo", + "raztvor", + "razvod", + "red", + "reka", + "relsa", + "repichka", + "republika", + "reshenie", + "restorant", + "rezba", + "rezha", + "riba", + "rod", + "roklya", + "royak", + "roza", + "rozova", + "rozovo", + "ruka", + "ryadak", + "ryadko", + "ryadkost", + "s", + "sa", + "sadarzhanie", + "sam", + "sama", + "samo", + "sastezanie", + "sastezavam", + "se", + "sebe", + "sedem", + "sedq", + "sega", + "selo", + "selski", + "semeystvo", + "seno", + "sgrada", + "shans", + "shepot", + "sheptya", + "shest", + "shirokolistno", + "shishe", + "shiya", + "shkaf", + "shpatula", + "shtastie", + "shte", + "shtora", + "si", + "siguren", + "sila", + "sin", + "skacham", + "skalp", + "skech", + "skelet", + "skoro", + "skorost", + "skorosten", + "skorpion", + "skupa", + "sladko", + "sled", + "slepec", + "sluchi", + "slunce", + "slyap", + "smakvam", + "smart", + "sme", + "snegovalezh", + "snezhen", + "snezhinka", + "snyag", + "sol", + "spane", + "spisak", + "spomen", + "sport", + "sravnenie", + "sravni", + "sreshta", + "stan", + "star", + "stara", + "starost", + "stava", + "stavam", + "staya", + "ste", + "stena", + "stene", + "stiga", + "stiker", + "sto", + "stol", + "stoy", + "strah", + "strana", + "strast", + "strelyam", + "struna", + "stud", + "sujelqvam", + "sum", + "sun", + "supermarket", + "surce", + "sus", + "sushto", + "sutrin", + "svarzvam", + "svesht", + "svetkavica", + "svoboda", + "svyat", + "syara", + "taka", + "tam", + "tanc", + "tate", + "tatko", + "tava", + "tavan", + "tayna", + "tazi", + "te", + "teb", + "tefter", + "tehen", + "telefon", + "televiziya", + "televizor", + "tendzhera", + "tendzheri", + "tetradka", + "tezi", + "ti", + "ticha", + "ticham", + "tigan", + "tih", + "tiho", + "tochno", + "togava", + "toi", + "tolkova", + "tor", + "tost", + "tova", + "tozi", + "tq", + "tqh", + "traktor", + "tramvay", + "tri", + "triagalnik", + "trinadeset", + "trinayset", + "trqbva", + "truden", + "tuk", + "tvard", + "tyalo", + "uchenichka", + "uchenik", + "uchilishte", + "uchitel", + "uedinenie", + "uho", + "ukrasa", + "ukrasyavam", + "um", + "uplaha", + "uplashen", + "uprazhnenie", + "ura", + "ured", + "uset", + "uspeh", + "uspeshen", + "ustroystvo", + "utre", + "uvazhenie", + "v", + "vagon", + "vampir", + "vana", + "vapros", + "var", + "varovik", + "vas", + "vaza", + "vazduh", + "vazhen", + "vcepenen", + "vchera", + "veche", + "vecher", + "vednaga", + "vesel", + "vest", + "vi", + "vidim", + "vidq", + "vie", + "vihar", + "vihrushka", + "vij", + "vilica", + "vinagi", + "vino", + "vinoven", + "vinovna", + "vinovnoto", + "visota", + "vkashti", + "vkus", + "vlak", + "vlast", + "vleze", + "voda", + "voden", + "vodenica", + "voleibol", + "vosak", + "voyna", + "vrag", + "vrah", + "vrata", + "vrazka", + "vreme", + "vse", + "vseki", + "vselena", + "vsichki", + "vsichko", + "vsushtnost", + "vuv", + "vyatar", + "vzimam", + "yabalka", + "yade", + "yadene", + "yagoda", + "yama", + "yami", + "yarak", + "yare", + "yarost", + "yasen", + "yastreb", + "yato", + "yayce", + "yod", + "yug", + "yuli", + "yuni", + "yurgan", + "yutiya", + "za", + "zadacha", + "zaedno", + "zaek", + "zakon", + "zala", + "zalez", + "zalezh", + "zalivam", + "zalyazvam", + "zapad", + "zapalvam", + "zaplaha", + "zar", + "zaradi", + "zashit", + "zashivam", + "zashtipvam", + "zashtitavam", + "zashto", + "zashtoto", + "zatova", + "zavartam", + "zavesa", + "zavod", + "zayavka", + "zdanie", + "zdrave", + "zdravei", + "zele", + "zelen", + "zhazhda", + "zhivotno", + "zhult", + "zima", + "zla", + "zlatna", + "zlato", + "zlo", + "zloba", + "zmey", + "zmiya", + "zna,", + "znachi", + "znae", + "znaesh", + "znaete", + "znanie", + "znaya", + "zub", + "zvuk", + "zvyar" + ] +} diff --git a/packages/schemas/src/languages.ts b/packages/schemas/src/languages.ts index d199e0e8acf3..7e26911a3c91 100644 --- a/packages/schemas/src/languages.ts +++ b/packages/schemas/src/languages.ts @@ -235,7 +235,9 @@ export const LanguageSchema = z.enum( "lithuanian_1k", "lithuanian_3k", "bulgarian", + "bulgarian_1k", "bulgarian_latin", + "bulgarian_latin_1k", "bangla", "bangla_letters", "bangla_10k", From bd9951931e7d49c3ec1db57efa6e2951eafa090a Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 17 Dec 2025 20:27:52 +0100 Subject: [PATCH 4/6] fix: timer resetting to initial value when test finishes closes #7263 --- frontend/src/ts/states/time.ts | 4 ++-- frontend/src/ts/test/test-timer.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/ts/states/time.ts b/frontend/src/ts/states/time.ts index 899bf154be04..c18761a1a208 100644 --- a/frontend/src/ts/states/time.ts +++ b/frontend/src/ts/states/time.ts @@ -4,8 +4,8 @@ export function get(): number { return time; } -export function set(active: number): void { - time = active; +export function set(number: number): void { + time = number; } export function increment(): void { diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts index 17c2a46dba0b..d0921a0f9db8 100644 --- a/frontend/src/ts/test/test-timer.ts +++ b/frontend/src/ts/test/test-timer.ts @@ -62,7 +62,6 @@ export function enableTimerDebug(): void { export function clear(): void { clearLowFpsMode(); - Time.set(0); newTimer.reset(); if (timer !== null) clearTimeout(timer); } From 0e5dd85db2cc0b34ae2176e3f469323669e83cc0 Mon Sep 17 00:00:00 2001 From: Seif Soliman Date: Wed, 17 Dec 2025 21:41:55 +0200 Subject: [PATCH 5/6] fix(lazy-mode): respect manual toggle after unsupported language (@byseif21) (#7260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description * lazy mode status “stuck” after switching to a language that does not support it then goes back to the one that supports it. * to reproduce After seeing the “This language does not support lazy mode” warning, switch back to the one that was working with and manually toggling lazy mode. It would not update to the selected option. --- frontend/src/ts/states/arabic-lazy-mode.ts | 16 ----- frontend/src/ts/states/remember-lazy-mode.ts | 30 +++++++++ frontend/src/ts/test/test-logic.ts | 66 ++++++++++---------- 3 files changed, 63 insertions(+), 49 deletions(-) delete mode 100644 frontend/src/ts/states/arabic-lazy-mode.ts create mode 100644 frontend/src/ts/states/remember-lazy-mode.ts diff --git a/frontend/src/ts/states/arabic-lazy-mode.ts b/frontend/src/ts/states/arabic-lazy-mode.ts deleted file mode 100644 index 590fd50e55ea..000000000000 --- a/frontend/src/ts/states/arabic-lazy-mode.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from "zod"; -import { LocalStorageWithSchema } from "../utils/local-storage-with-schema"; - -const ls = new LocalStorageWithSchema({ - key: "prefersArabicLazyMode", - schema: z.boolean(), - fallback: true, -}); - -export function get(): boolean { - return ls.get(); -} - -export function set(value: boolean): void { - ls.set(value); -} diff --git a/frontend/src/ts/states/remember-lazy-mode.ts b/frontend/src/ts/states/remember-lazy-mode.ts new file mode 100644 index 000000000000..08d04a662533 --- /dev/null +++ b/frontend/src/ts/states/remember-lazy-mode.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; +import { LocalStorageWithSchema } from "../utils/local-storage-with-schema"; + +const rememberLazyModeLS = new LocalStorageWithSchema({ + key: "rememberLazyMode", + schema: z.boolean(), + fallback: false, +}); + +const arabicLazyModeLS = new LocalStorageWithSchema({ + key: "prefersArabicLazyMode", + schema: z.boolean(), + fallback: true, +}); + +export function getRemember(): boolean { + return rememberLazyModeLS.get(); +} + +export function setRemember(value: boolean): void { + rememberLazyModeLS.set(value); +} + +export function getArabicPref(): boolean { + return arabicLazyModeLS.get(); +} + +export function setArabicPref(value: boolean): void { + arabicLazyModeLS.set(value); +} diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 76d3a34706c9..479fa9df3240 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -39,7 +39,7 @@ import * as AnalyticsController from "../controllers/analytics-controller"; import { getAuthenticatedUser, isAuthenticated } from "../firebase"; import * as ConnectionState from "../states/connection"; import * as KeymapEvent from "../observables/keymap-event"; -import * as ArabicLazyMode from "../states/arabic-lazy-mode"; +import * as LazyModeState from "../states/remember-lazy-mode"; import Format from "../utils/format"; import { QuoteLength, QuoteLengthConfig } from "@monkeytype/schemas/configs"; import { Mode } from "@monkeytype/schemas/shared"; @@ -342,7 +342,6 @@ export function restart(options = {} as RestartOptions): void { } let lastInitError: Error | null = null; -let rememberLazyMode: boolean; let showedLazyModeNotification: boolean = false; let testReinitCount = 0; @@ -421,39 +420,43 @@ async function init(): Promise { .some((lang) => !lang.noLazyMode); if (Config.lazyMode && !anySupportsLazyMode) { - rememberLazyMode = true; - Notifications.add( - "None of the selected polyglot languages support lazy mode.", - 0, - { - important: true, - }, - ); + LazyModeState.setRemember(true); + if (!showedLazyModeNotification) { + Notifications.add( + "None of the selected polyglot languages support lazy mode.", + 0, + { + important: true, + }, + ); + showedLazyModeNotification = true; + } setConfig("lazyMode", false); - } else if (rememberLazyMode && anySupportsLazyMode) { - setConfig("lazyMode", true, { - nosave: true, - }); + } else if (LazyModeState.getRemember() && anySupportsLazyMode) { + setConfig("lazyMode", true); + LazyModeState.setRemember(false); + showedLazyModeNotification = false; } } else { // normal mode if (Config.lazyMode && !allowLazyMode) { - rememberLazyMode = true; - showedLazyModeNotification = true; - Notifications.add("This language does not support lazy mode.", 0, { - important: true, - }); - + LazyModeState.setRemember(true); + if (!showedLazyModeNotification) { + Notifications.add("This language does not support lazy mode.", 0, { + important: true, + }); + showedLazyModeNotification = true; + } setConfig("lazyMode", false); - } else if (rememberLazyMode && !language.noLazyMode) { - setConfig("lazyMode", true, { - nosave: true, - }); + } else if (LazyModeState.getRemember() && allowLazyMode) { + setConfig("lazyMode", true); + LazyModeState.setRemember(false); + showedLazyModeNotification = false; } } if (!Config.lazyMode && !language.noLazyMode) { - rememberLazyMode = false; + LazyModeState.setRemember(false); } if (Config.mode === "custom") { @@ -1549,7 +1552,10 @@ ConfigEvent.subscribe(({ key, newValue, nosave }) => { if (ActivePage.get() === "test") { if (key === "language") { //automatically enable lazy mode for arabic - if ((newValue as string)?.startsWith("arabic") && ArabicLazyMode.get()) { + if ( + (newValue as string)?.startsWith("arabic") && + LazyModeState.getArabicPref() + ) { setConfig("lazyMode", true, { nosave: true, }); @@ -1582,13 +1588,7 @@ ConfigEvent.subscribe(({ key, newValue, nosave }) => { } if (key === "lazyMode" && !nosave) { if (Config.language.startsWith("arabic")) { - ArabicLazyMode.set(newValue); - } - if (newValue) { - if (!showedLazyModeNotification) { - rememberLazyMode = false; - } - showedLazyModeNotification = false; + LazyModeState.setArabicPref(newValue); } } }); From c222098a05f1155e37a073e71c4f5a066ebdc7fb Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 17 Dec 2025 20:49:03 +0100 Subject: [PATCH 6/6] fix: previous commit nuking the timer --- frontend/src/ts/test/test-logic.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 479fa9df3240..4232665906ab 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -68,6 +68,7 @@ import { canQuickRestart } from "../utils/quick-restart"; import { animate } from "animejs"; import { setInputElementValue } from "../input/input-element"; import { debounce } from "throttle-debounce"; +import * as Time from "../states/time"; let failReason = ""; @@ -100,6 +101,7 @@ export function startTest(now: number): boolean { Replay.startReplayRecording(); Replay.replayGetWordsList(TestWords.words.list); TestInput.resetKeypressTimings(); + Time.set(0); TestTimer.clear(); for (const fb of getActiveFunboxesWithFunction("start")) {