<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged mutlilanguage</title>
<link>https://coderlegion.com/tag/mutlilanguage</link>
<description>Powered by Question2Answer</description>
<item>
<title>Multilingual Recipe Search</title>
<link>https://coderlegion.com/32000/multilingual-recipe-search</link>
<description>&lt;p&gt;When building &lt;a rel=&quot;nofollow&quot; href=&quot;https://recipe-finder.org&quot;&gt;Recipe Finder&lt;/a&gt;, we hit a frustrating limitation with our upstream data provider: the Spoonacular API only understands English queries. &lt;/p&gt;
&lt;p&gt;If a user typed a craving in their native language—like &lt;em&gt;cartofi&lt;/em&gt; in Romanian or &lt;em&gt;стейк&lt;/em&gt; in Cyrillic—the search returned zero results, even when hundreds of matching recipes existed in the database. Worse, our search fallback logic would spend up to four API requests trying to find matches before giving up and rendering an empty state.&lt;/p&gt;
&lt;p&gt;Rebuilding the entire platform around a new recipe database wasn't practical. Instead, for Release 2.20.0, we built a lightweight, fail-safe translation layer in front of the search pipeline using Google Gemini Flash and a normalized lookup cache.&lt;/p&gt;
&lt;h3 id=&quot;what-s-new&quot;&gt;What's New&lt;/h3&gt;
&lt;p&gt;Until now, Recipe Finder searched in English only. With release 2.20.0, the search automatically detects which language you wrote in and finds the exact same recipes you would get by searching in English:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Search in the language you think in&lt;/strong&gt;, with no need to translate first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full support for non-Latin alphabets&lt;/strong&gt; (e.g., Cyrillic queries return steak recipes, and searching for &lt;em&gt;cartofi&lt;/em&gt; in Romanian returns potato recipes).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero impact on English queries&lt;/strong&gt;, which behave identically to before.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-it-works-the-architecture&quot;&gt;How It Works: The Architecture&lt;/h3&gt;
&lt;p&gt;The core rule is deliberately simple: &lt;strong&gt;if a query is in English, we use exactly what you typed; if it isn't, we resolve its English translation before hitting the recipe API.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;                [ Raw Query: &quot;cartofi&quot; ]
                            │
                            ▼
              ┌───────────────────────────┐
              │ Normalize (case &amp;amp; spaces) │
              └─────────────┬─────────────┘
                            │
                            ▼
                     ┌─────────────┐
           ┌─────────┤  DB Cache   ├─────────┐
           │         └─────────────┘         │
      MISS │                                 │ HIT
           ▼                                 │
 ┌───────────────────┐                       │
 │ Gemini Flash API  │                       │
 │ (Reasoning: Off)  │                       │
 └───┬───────────┬───┘                       │
     │           │                           │
   OK│           │ERROR / SLOW               │
     ▼           │(Fallback: raw query)      │
┌─────────┐      │                           │
│ Save DB │      │                           │
└────┬────┘      │                           │
     │           │                           │
     └───────────┴──────────┬────────────────┘
                            │
                            ▼
                [ Resolved: &quot;potatoes&quot; ]
                            │
                            ▼
              ┌───────────────────────────┐
              │  Spoonacular Search API   │
              │  &amp;amp; Relevance Re-Ranking   │
              └───────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;step-by-step-pipeline&quot;&gt;Step-by-Step Pipeline&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cache first:&lt;/strong&gt; The incoming query is normalized (case and spacing) and looked up in our database. If we have seen it before, we already know the answer and skip the AI layer entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One language check:&lt;/strong&gt; On a first-time query, a single request to Google Gemini Flash decides whether the text is English and, if not, returns the English equivalent. Both outcomes are saved to the database—including &lt;em&gt;&quot;this is already English&quot;&lt;/em&gt;—so common English searches never trigger a second check.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search and rank with the right query:&lt;/strong&gt; The recipe search runs with the resolved query, and results are ranked against it so the best matches appear first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safe by design:&lt;/strong&gt; If the language check is slow, fails, or the database is unavailable, the search simply runs with the original query, exactly as it did before this release. Translation can never break a search.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id=&quot;key-engineering-trade-offs&quot;&gt;Key Engineering Trade-offs&lt;/h3&gt;
&lt;h4 id=&quot;1-sequential-vs-parallel-execution&quot;&gt;1. Sequential vs. Parallel Execution&lt;/h4&gt;
&lt;p&gt;We chose to run the language check &lt;em&gt;before&lt;/em&gt; the recipe search, rather than in parallel. Running both at once would hide the wait on uncached queries, but it would also spend a recipe-search request on every non-English query—and that daily API quota is our scarcer resource.&lt;/p&gt;
&lt;h4 id=&quot;2-disabling-extended-reasoning&quot;&gt;2. Disabling Extended Reasoning&lt;/h4&gt;
&lt;p&gt;We disabled Gemini's extended reasoning for this specific request. Detecting and translating a short food phrase doesn't need chain-of-thought tokens, and leaving it off keeps the call significantly faster and cheaper. Other AI features in the app remain unaffected.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;performance-and-cost&quot;&gt;Performance and Cost&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speed:&lt;/strong&gt; In our testing, first-time searches completed in roughly &lt;strong&gt;1 to 1.5 seconds end-to-end&lt;/strong&gt;, including the recipe search itself. Repeat searches hit the cache and skip the language check entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Based on Google's published Gemini Flash pricing, we estimate roughly &lt;strong&gt;$0.0001 per language check&lt;/strong&gt;, which works out to about &lt;strong&gt;$1 for every 10,000 new, distinct searches&lt;/strong&gt;. Repeated searches cost nothing because of the cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fewer wasted requests:&lt;/strong&gt; A non-English search used to consume up to four recipe-search requests and still find nothing. It now uses &lt;strong&gt;one&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;current-limitations-amp-what-s-next&quot;&gt;Current Limitations &amp;amp; What's Next&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Recipe titles and descriptions are still shown in English, because that is how the recipes are stored upstream.&lt;/li&gt;
&lt;li&gt;The results page currently displays what you typed rather than its translated equivalent.&lt;/li&gt;
&lt;li&gt;The ingredient include/exclude filters are not translated yet.&lt;/li&gt;
&lt;li&gt;The first search for a brand-new phrase takes slightly longer than a repeat search.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we plan to add a &lt;em&gt;&quot;Showing results for…&quot;&lt;/em&gt; indicator so it's clear when a search was translated, and extend the same translation pipeline to the ingredient filters. &lt;/p&gt;
&lt;p&gt;If there's a language or regional dish phrase that doesn't work well for you, we'd love to hear about it—&lt;strong&gt;give it a try at &lt;a rel=&quot;nofollow&quot; href=&quot;https://recipe-finder.org&quot;&gt;recipe-finder.org&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32000/multilingual-recipe-search</guid>
<pubDate>Wed, 21 Oct 2026 19:31:41 +0000</pubDate>
</item>
</channel>
</rss>