I'm Moving On From LR - My Overview and Last Thoughts/Suggestions

LanguageReactor has great potential but is held back by nonexistent development. Upon visiting the extension’s homepage, you’re introduced to a plethora of information, yet I’ve witnessed the same image for years. The extension hasn’t and likely will never come to Firefox. It’s time to remove the false claim from the website. Now that Edge is Chromium based, it works with LR…that’s how old this is! Edge switched to Chromium back in 2020!
image

In many aspects, it surpasses other services. The utilization of AI for real-time translations is one of the features that keeps me returning. I initially gravitated towards LR due to its remarkable ease of use. Simply right-clicking a word to mark it as ‘Learn’ or ‘Known,’ and for native programming without subtitles in my language, LR seamlessly fills that gap. The UI is sleek and unobtrusive. I can’t stress enough how effortlessly the overlay UI is to use—yet, it’s everything else that hampers this experience.

I started seeing the immense shortcomings of LR when I attempted to review the content I had marked for learning, I first tried PhrasePump, which turned out to be a disaster. It presents pre-set sentences with words/grammar it deems necessary, which proved ineffective. Furthermore, when attempting to incorporate words and phrases from watched shows, it limited me to the Cloze card format—a poor choice for learning new words. Promoting these cards to a cloze format for more advanced review would have been more beneficial. Phrase Pump is a flawed feature to be avoided.

So, what’s the alternative for utilizing mined content? LR allows you to export your words/phrases and media (screenshots, audio). However, the Anki export feature is completely broken in my opinion. Despite providing a How-To guide, exporting to Anki should be far simpler. This recurring theme of promising ideas falling short of realization is disappointing, especially for a paid product. Years of unfulfilled promises indicate that LR has outgrown its current development team. They either need to expand their team to actively develop a product that could potentially be the best language-learning tool on the market or consider selling it to someone who can deliver.

Now that the rant is over, perhaps you’re like me, desperately trying to make LR work for you. I’ve tried to overlook its shortcomings because I see the potential for an outstanding product that hasn’t been fully realized.

So, here’s my suggestion: either use the free version of LR, explore alternatives with better customer service, or supplement with asbplayer.

asbplayer is a free extension for Chromium browsers capable of reading subtitles from various websites like Netflix, YouTube, DisneyPlus, Hulu, etc. While lacking many features, it excels at seamlessly exporting sentences to Anki. There’s no unnecessary complexity; it simply performs this task exceptionally well and does not conflict with LR (aside from some hotkeys that can be changed :slight_smile: ). Where LR falls short, asbplayer shines. You’ll never again feel frustrated by the inability to export to Anki. Check out this video demo of asbplayer, showcasing its ease of use and efficiency. If you have any questions on how I have used LR and asbplayer together, please feel free to message me.

As for me, I’m moving on from LR. I may return out of curiosity to see if anything has changed, but at my current stage of language learning, features like word tracking aren’t useful. I need to review what I’ve learned quickly and easily—capabilities LR lacks at the moment.

To the LR development team: I’m clearly frustrated with you because I see the immense potential of what you have here. This product could be the best, and I wholeheartedly believe that. Please, do right by LR and address the necessary fixes and expand on it. For the love of God, please fix the export feature for Anki (AnkiConnect, just do it).

I wish everyone the best and good luck with your language learning journeys! Farewell!

12 Likes

Truly agree. By the way, Trancy is the best alternative I found so far, and it’s quite affordable.

2 Likes

Hi guys! You can also try LingoPear. It is the project I am developing. It’s in its early stage, and definitely I want it to grow into a mature product for all language learners. You can reach me through Discord or email contact@lingopear.com. Hope you can give it a try and let me know any feedbacks like feature requests or bugs!

2 Likes

Where’s the how-to guide on exporting to Anki?

Here is my guide: How to Export (Guide)

Official guide Language Reactor

Hey man, I totally do. I see the huge value on LR as I like the UI and being able to highlight or hover over and get a pop-up dictionary is awesome. I also found a nifty way to have ASB player auto export text/audio into an anki card with one hot key using something called Vocabseive for the word definition, but I am having a hard time getting them to play nicely. Any input?

I’m back to using LanguageReactor alongside ASBplayer, and the experience has been fantastic.

To improve compatibility, I’ve disabled ASBplayer’s navigation controls. Since I’m not using any other extensions, I can’t comment on Vocabseive. However, once ASBplayer is set up, I can simply use the hotkey “Shift+Ctrl+X” for an almost seamless, one-click experience. The only extra step is copying a definition from LanguageReactor’s dictionary, but that’s not much of an issue.

You just changed my world. Thank you!!

Vocabseive is how the definition was being copied over originally from the sentence that was mined.

Does this also bring in the natural audio-clip?

That is the great thing I really like about ASBplayer, it records the audio as well! It has a swath of other usable features as well, like being able to use RegEx to filter any sentences it pulls in.

Awesome! Do you just copy paste the definition from the pop up dictionary in LR and add it into anki?

That’s what I do yes. There are ways to set it up with other extensions like Yomitan (Japanese Dictionary), but I find it easy enough to just copy and paste.

Well I use the same setup but for the definition, I just take the one from Yomitan so it’s really one click for everything

(Translation is added afterward with Google Translate/Deepl anki addon, but it’s in bulk so it’s just a few more click per session)

1 Like

Your setup is similar to how I used to do things, and I must admit, it’s much easier once everything is in place. I’ve been exploring the AI Explanation within Context feature in LR, and I’m really enjoying it. I wasn’t aware there’s a DeepL add-on for Anki—I’ll definitely have to check it out.

BTW: your card template is super clean!

I found the solution to use both language reactor and asbplayer very useful. I also wrote a simple tempermonkey addon to automatically copy and paste definition in language reactor’s dictionary to asbplayer’s anki exporter. I will post it here in case anyone is interested or want to improve it.

  1. This script works on both local videos and netflix. I have not tuned it for youtube yet. First you need to make sure both asbplayer and language reactor are installed and work smoothly. Notice that asbplayer and language reactor have conflicts in hotkeys like arrow keys, and make sure you adjust them.
  2. For local videos to work, you need to allow asbplayer to access local files (right click → manage extensions → Allow access to file URLs). Then, play local videos on Language Reactor and select the same subtitle for asbplayer.
  3. Set up anki connect as guided by asbplayer.
  4. Install violentmonkey (or tempermonkey etc) and create a new script, adding the following content.
  5. If the script runs correctly, when you press ctrl+shift+x (the hotkey for asbplayer), an additional button named “export” should appear. It will try to detect if you are currently looking up a word using language reactor’s mini dictionary. If yes, clicking the button automatically fills in the word and the definition to the anki exporter.
// ==UserScript==
// @name         Language Learning Plugin
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Combine Language Reactor and absplayer
// @include      https://www.languagereactor.com/*
// @include      https://www.netflix.com/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const observeIframe = () => {
        const iframeObserver = new MutationObserver(() => {
            const iframe = document.querySelector('iframe.asbplayer-ui-frame:not(.asbplayer-hide)');
            if (iframe && iframe.contentDocument) {
                injectScriptIntoIframe(iframe);
            }
        });

        iframeObserver.observe(document.body, { childList: true, subtree: true });
    };

    const getWordFromDictionary = () => {
        const dictContainer = document.querySelector('.lln-full-dict');
        if (!dictContainer) return null;

        var wordElement = dictContainer.querySelector('div > div > div[style*="color: rgb(189, 189, 0)"]');
        if (!wordElement) {
            wordElement = document.querySelector('.lln-dict-section-full > div > div')
        }
        return wordElement ? wordElement.textContent.trim() : null;
    };

    const getDefinitionFromDictionary = () => {
        const dictContainer = document.querySelector('.lln-full-dict');
        if (!dictContainer) return null;

        var wordElement = dictContainer.querySelector('div > div > div[style*="color: rgb(189, 189, 0)"]');
        if (!wordElement) {
            wordElement = document.querySelector('.lln-dict-section-full > div > div')
        }
        if (!wordElement) return null;

        const outerDiv = wordElement.parentElement; // Navigate to the correct parent
        if (!outerDiv) return null;

        var pronDir = dictContainer.querySelector('span > span[style*="margin-left: 5px;"]');
        if (!pronDir) {
            pronDir = document.querySelector('.lln-dict-contextual > span[style*="color: rgb(189, 189, 0)"]')
        }
        if (!pronDir) return null;
        // Collect all text from child divs, preserving line breaks
        let definition = pronDir.textContent.trim().split(' ').pop() + '\n';
        outerDiv.childNodes.forEach(node => {
            if (node.nodeType === Node.ELEMENT_NODE) {
                const texts = node.textContent.trim().split('\n');
                texts.forEach(
                    text => {
                        if (text.trim() != wordElement.textContent.trim()) definition += text.trim() + '\n';
                    }
                )

            }
        });
        return definition.trim();
    };



    const injectScriptIntoIframe = (iframe) => {
        const iframeDoc = iframe.contentDocument;

        const waitForBody = () => {
            if (!iframeDoc.body) {
                console.warn('iframe body not ready, retrying...');
                setTimeout(waitForBody, 100); // Retry after 100ms
                return;
            }

            const observer = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList') {
                        iframeDoc.querySelectorAll('.MuiDialogActions-root').forEach(dialog => {
                            if (!dialog.querySelector('.extract-button')) {
                                const extractButton = document.createElement('button');
                                extractButton.className = 'MuiButtonBase-root MuiButton-root MuiButton-text extract-button';
                                extractButton.type = 'button';
                                extractButton.innerHTML = '<span class="MuiButton-label">Extract</span>';
                                extractButton.onclick = () => {
                                    const wordInput = iframeDoc.querySelector('input.MuiInputBase-input.MuiFilledInput-input');
                                    const definitionInput = iframeDoc.querySelector('textarea.MuiInputBase-input.MuiFilledInput-input');

                                    const word = getWordFromDictionary();
                                    const definition = getDefinitionFromDictionary();
                                    if (wordInput && word) {
                                        setReactValue(wordInput, word);
                                    }
                                    if (definitionInput && definition) {
                                        setReactValue(definitionInput, definition);
                                    }
                                    console.log('Extract button clicked: autofill complete');
                                };
                                dialog.appendChild(extractButton);

                                // Automatically click the Extract button when the dialog opens
                                extractButton.click();
                            }
                        });
                    }
                });
            });

            observer.observe(iframeDoc.body, { childList: true, subtree: true });
        };

        waitForBody();
    };

    const setReactValue = (element, value) => {
        const descriptor = Object.getOwnPropertyDescriptor(element.__proto__, 'value');
        const event = new Event('input', { bubbles: true });

        descriptor.set.call(element, value); // Set the value using the descriptor
        element.dispatchEvent(event);       // Trigger React's input event listener
    };

    window.addEventListener('load', observeIframe);
})();

2 Likes