My name is Ray, and I’m a third-year university student majoring in Digital Media Technology. I’ve been using your online reader for some time, and I truly think it’s one of the most well-designed tools out there. In fact, it has become the main inspiration for my graduation project.
I have a specific technical question I was hoping you might be able to help me with. Your real-time translation feature really caught my attention — especially the way that tapping on a single word brings up its definition, and tapping on two adjacent words shows a combined translation or shared meaning. I’m very curious about how that works under the hood.
More specifically, I’d love to know:
How do you determine when two words should be treated as a phrase rather than separate entries?
What kind of data structure or lookup strategy do you use to keep the translation fast and responsive?
And do you have any general advice on improving both accuracy and speed for this kind of feature?
I completely understand if you can’t share too much detail, but even a brief pointer toward the right approach or relevant technologies would mean a lot to me. I’ll be sure to credit your project properly in my thesis.
Thank you for your time, and again, I really admire what you’ve built.
This is completely determined by user behavior. They can choose to drag across multiple words to translate it as a phrase. Alternatively, if they click two adjacent words to translate them AND they have the “Merge Phrases” option enabled in the reader page settings then they will merge.
I query Google Translate (basic translations) or OpenAI (context-aware translations) for the translations. These are reasonably fast already, but I also cache the results in MongoDB so that I don’t need to query Google or OpenAI again if we’ve already done that same translation within the past few months.
For accuracy of the LLM powered context-aware translations, I’ve been experimenting with running evals on translations of the same set of words on different LLM models (e.g. gpt-4o, gpt-5, google’s gemma and gemini models, etc) and getting a very good, very expensive reasoning model to judge these results (e.g. claude opus and google gemini pro). I’ve done this for many different languages. This can give me confidence that if I alter the LLM powering the translations in future the translations will be of better quality. As part of these evals I also measure the latency so I can ensure that they aren’t too slow. As you’d expect, the reasoning models are significantly slower than the non-reasoning ones. For now I’m still using gpt-4o and gpt-4o-mini to power all the LLM based features in Readlang, but I’m going to revisit this after the summer, run more evals, and potentially update to newer and better models.