<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BottleneckPC</title>
    <description>The latest articles on DEV Community by BottleneckPC (bottleneckpc).</description>
    <link>https://dev.to/bottleneckpc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14028%2Ff9a0fb48-328d-4abc-9487-3970e8b2d29a.png</url>
      <title>DEV Community: BottleneckPC</title>
      <link>https://dev.to/bottleneckpc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bottleneckpc"/>
    <language>en</language>
    <item>
      <title>Eleven languages for zero new translation work</title>
      <dc:creator>BottleneckPC</dc:creator>
      <pubDate>Mon, 03 Aug 2026 17:10:32 +0000</pubDate>
      <link>https://dev.to/bottleneckpc/eleven-languages-for-zero-new-translation-work-4ep3</link>
      <guid>https://dev.to/bottleneckpc/eleven-languages-for-zero-new-translation-work-4ep3</guid>
      <description>&lt;p&gt;We shipped an embeddable version of our calculator in eleven languages last week. The translation&lt;br&gt;
cost was zero, and not because we used machine translation. It was zero because the strings already&lt;br&gt;
existed and we had never noticed.&lt;/p&gt;

&lt;p&gt;This is a short post about a boring realisation: if you localise an app properly, the embeddable&lt;br&gt;
version of that app is usually already localised, and the only thing standing between you and&lt;br&gt;
eleven markets is where you read the locale from.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The product is a CPU and GPU bottleneck calculator. A while back we translated it into ten&lt;br&gt;
languages beyond English, which meant building the usual things: a dictionary per locale, a route&lt;br&gt;
per locale, and a rule that the URL slug is a keyword in that language rather than a transliteration&lt;br&gt;
of the English one. Somebody searching &lt;code&gt;calculadora cuello de botella&lt;/code&gt; should see that phrase in&lt;br&gt;
the path, because on a head term the URL is part of the signal.&lt;/p&gt;

&lt;p&gt;Separately, we had an embeddable widget. An iframe, deliberately chrome-less, so other sites could&lt;br&gt;
drop the calculator into an article. It was English only.&lt;/p&gt;

&lt;p&gt;The instinct was to treat "localise the widget" as a project. Estimate the strings, get them&lt;br&gt;
translated, wire up a language switcher.&lt;/p&gt;
&lt;h2&gt;
  
  
  The realisation
&lt;/h2&gt;

&lt;p&gt;Every string the widget renders was already in the dictionaries.&lt;/p&gt;

&lt;p&gt;Of course it was. The widget is the same calculator. It shows a CPU label, a GPU label, two search&lt;br&gt;
placeholders, a resolution control, and a verdict line that says balanced, CPU limited or GPU&lt;br&gt;
limited. All of that had been translated months earlier for the full-page version. The widget was&lt;br&gt;
English purely because nothing ever told it otherwise.&lt;/p&gt;

&lt;p&gt;The actual work was one decision: &lt;strong&gt;where does an iframe read its locale from?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the main site, locale comes from the path - &lt;code&gt;/es/...&lt;/code&gt;, &lt;code&gt;/de/...&lt;/code&gt;. An iframe embedded on somebody&lt;br&gt;
else's page has no path of ours to read. It has a query string, and that is it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/embed?cpu=&amp;lt;id&amp;gt;&amp;amp;gpu=&amp;lt;id&amp;gt;&amp;amp;res=1440p&amp;amp;lang=de
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the locale is read client-side from the query string, and the host page chooses the language by&lt;br&gt;
choosing the URL. That is the entire feature.&lt;/p&gt;
&lt;h2&gt;
  
  
  The bug that was hiding underneath
&lt;/h2&gt;

&lt;p&gt;One line spoiled it, and it is the kind of thing that only shows up when you localise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// renders "CPU LIMITED" in every language&lt;/span&gt;
&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verdict was being built by upper-casing an internal enum value. In English that reads as a&lt;br&gt;
sentence and nobody questions it. In German it reads as an English word sitting in the middle of a&lt;br&gt;
German widget.&lt;/p&gt;

&lt;p&gt;The fix is obvious once seen - map the enum to a dictionary key rather than rendering the enum -&lt;br&gt;
but the lesson generalises: &lt;strong&gt;any string you construct from a variable rather than look up is a&lt;br&gt;
string you have not translated.&lt;/strong&gt; Grep for &lt;code&gt;toUpperCase&lt;/code&gt;, &lt;code&gt;capitalize&lt;/code&gt;, and template literals that&lt;br&gt;
interpolate an internal value into user-visible text. That is where untranslated strings hide, not&lt;br&gt;
in the JSX where they are easy to see.&lt;/p&gt;
&lt;h2&gt;
  
  
  The part that actually mattered commercially
&lt;/h2&gt;

&lt;p&gt;An embeddable widget is a distribution mechanism. Somebody puts it on their page, and the&lt;br&gt;
attribution link under it points back at you.&lt;/p&gt;

&lt;p&gt;That link has to sit &lt;strong&gt;outside&lt;/strong&gt; the iframe. Search engines do not pass equity through an iframe,&lt;br&gt;
so a widget with the credit inside its own frame gives you traffic and nothing else. Ours is a&lt;br&gt;
paragraph in the host page's own HTML, generated alongside the embed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://bottleneckpc.com/embed?lang=de"&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://bottleneckpc.com/de/flaschenhals-rechner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Flaschenhals-Rechner&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
   by &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://bottleneckpc.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;BottleneckPC&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the anchor text and target. For a German host we link the German page with its German name,&lt;br&gt;
not the English one. A reader clicking through lands somewhere that makes sense to them, which is&lt;br&gt;
the difference between a link that gets kept and a link that gets removed six months later.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing, and it cost nothing
&lt;/h2&gt;

&lt;p&gt;While testing on other people's pages it became obvious that the widget was loading our analytics&lt;br&gt;
and our ad partner's script onto their site. That is a bad thing to ask of anyone, and an&lt;br&gt;
impossible thing to ask of a European publisher with a privacy policy.&lt;/p&gt;

&lt;p&gt;The root layout now path-guards every third-party script, so the embed route loads none of them.&lt;br&gt;
The verification is simple enough to be worth doing rather than assuming: open the widget in a real&lt;br&gt;
browser and count the requests that leave your own domain. Ours is zero.&lt;/p&gt;

&lt;p&gt;If you ship an embeddable anything, do that check. The answer is rarely what you assume.&lt;/p&gt;




&lt;p&gt;We build &lt;a href="https://bottleneckpc.com" rel="noopener noreferrer"&gt;BottleneckPC&lt;/a&gt;, a free CPU and GPU bottleneck calculator. The&lt;br&gt;
widget is &lt;a href="https://bottleneckpc.com/bottleneck-calculator-widget" rel="noopener noreferrer"&gt;free to embed&lt;/a&gt; in any of the&lt;br&gt;
eleven languages, and the scoring engine is &lt;a href="https://github.com/BottleneckPC/bottleneck-checker" rel="noopener noreferrer"&gt;open source&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>i18n</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
