<?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: Kidus Adugna</title>
    <description>The latest articles on DEV Community by Kidus Adugna (@k1dv5).</description>
    <link>https://dev.to/k1dv5</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F280933%2Fc381119a-5c93-44c8-8619-5a57952fe9ce.png</url>
      <title>DEV Community: Kidus Adugna</title>
      <link>https://dev.to/k1dv5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/k1dv5"/>
    <language>en</language>
    <item>
      <title>Why I built Wuchale: Protobuf-like i18n from plain code</title>
      <dc:creator>Kidus Adugna</dc:creator>
      <pubDate>Wed, 10 Sep 2025 07:01:17 +0000</pubDate>
      <link>https://dev.to/k1dv5/why-i-built-wuchale-protobuf-like-i18n-from-plain-code-441o</link>
      <guid>https://dev.to/k1dv5/why-i-built-wuchale-protobuf-like-i18n-from-plain-code-441o</guid>
      <description>&lt;p&gt;Let's face it, most of us dread i18n. I know I do. It feels like wrestling with catalogs, boilerplate, and endless edge cases. So we avoid it when we can. And when we can't, readability suffers: what should be simple code quickly turns into a maze.&lt;/p&gt;

&lt;p&gt;I ran into this while adding i18n to a sizable project with over 1K messages. At the time, out of the available options, Lingui was the better one to start with as it handled catalog generation automatically, which spared me a ton of manual work. And it didn't completely damage readability, because messages stayed in the code.&lt;/p&gt;

&lt;p&gt;But as the project grew, I still found myself buried in boilerplate. Every new message added friction and extra complexity. The process felt heavy again. The tooling was helping, but also getting in the way. I didn't like this so much that I avoided adding i18n to another smaller project that could use it. I didn't want to go through it again.&lt;/p&gt;

&lt;p&gt;This experience got me thinking: we already can tell if a piece of text in the code is going to be visible to the user or not. For example, text inside HTML tags is going to be shown. So why do we have to write extra boilerplate just to internationalize it?&lt;/p&gt;

&lt;p&gt;That question sparked the creation of Wuchale, an i18n toolkit that does two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scans your plain code for user-visible messages, extracts/optionally translates them and then compiles them into compact keyless catalogs, just arrays, like Protobuf (more on this below)&lt;/li&gt;
&lt;li&gt;Automatically rewrites your code to get messages from the compiled catalogs by index, no keys required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It uses AST-based static analysis on your code, so it is very flexible; it will find your messages wherever they are. The result is that your source code stays clean and readable, while Wuchale handles everything under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Original code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transformed code&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;_w_runtime_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extracted catalog (after translation)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msgid "Hello"
msgstr "Hola"
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compiled catalog&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the message is at index 0&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like Protobuf, the compiled catalogs don't need metadata; the consuming code already knows the mapping. Moreover, the compiled catalogs are optimized at build time for runtime use; no string replace or anything complicated happens during runtime, even when using complex messages with interpolations and nested messages.&lt;/p&gt;

&lt;p&gt;It started with just Svelte, and then in almost three months of more than full time dedication, it has gone through many iterations and improvements with feedback from the community, and has expanded its reach. It now supports React/Preact, Svelte, SolidJS and of course JavaScript/TypeScript (even for server-side messages).&lt;/p&gt;

&lt;p&gt;But this is not the end. For the ultimate DX, HMR is key, and it has received a lot of care to make it work smoothly. You write your code as always and Wuchale keeps the catalogs in sync in the background.&lt;/p&gt;

&lt;p&gt;And further still, you can optionally use AI to translate the messages for you. Of course this does not match the quality of human translators, but if you want something quick that you can revisit later, it can do the translations on-the-fly. This enables writing your code in English and seeing the results in another language in the browser!&lt;/p&gt;

&lt;p&gt;With all of this, you might expect a lot of dependencies. Nope. One of the things I didn't like about Lingui was its huge dependency size for what I need. Wuchale has less than 10 dependencies and it shares most of the same dependencies with Vite and your framework (e.g. Svelte's own parser for parsing Svelte). That means the additional dependencies are less than 5 &lt;em&gt;(including transitive ones)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I now enjoy working with it, it feels like it's never there. FYI, I went back to that project and fully internationalized it with Wuchale in under 30 mins, using Gemini for the translation. And most of that time was spent on the language selector UI.&lt;/p&gt;

&lt;p&gt;So, what's next? The biggest update planned is support for other backend languages, Go and Python, so that even the messages from there are internationalized.&lt;/p&gt;

&lt;p&gt;Interested? Check out &lt;a href="https://wuchale.dev" rel="noopener noreferrer"&gt;the website&lt;/a&gt; or &lt;a href="https://github.com/wuchalejs/wuchale" rel="noopener noreferrer"&gt;the repo&lt;/a&gt; and give it a try!&lt;/p&gt;

&lt;p&gt;Thank you for reading and I hope you try it and enjoy working with it. And feedback is always welcome. Wuchale is fully open source and open to contributors.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@notethanun?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;note thanun&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-large-open-area-with-a-sign-that-says-welcome-I2fhimNZFIw?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>i18n</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>wuchale: Rethinking internationalization</title>
      <dc:creator>Kidus Adugna</dc:creator>
      <pubDate>Wed, 09 Jul 2025 12:30:14 +0000</pubDate>
      <link>https://dev.to/k1dv5/wuchale-rethinking-internationalization-e7m</link>
      <guid>https://dev.to/k1dv5/wuchale-rethinking-internationalization-e7m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(inspired by Rich Harris's "Rethinking Reactivity")&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🚀 &lt;strong&gt;TL;DR&lt;/strong&gt;: &lt;code&gt;wuchale&lt;/code&gt; is a blazing-fast, zero-wrapper i18n solution for Svelte that extracts and compiles translations at build time. It avoids string keys, has minimal runtime cost, plays perfectly with HMR, and even supports Gemini-powered auto translation. Think LinguiJS, but leaner, faster, and tailored for Svelte.&lt;/p&gt;

&lt;p&gt;A few years back, I needed to add i18n to my fairly large application with Preact. I evaluated the existing tools and the most common method was to write getters with keys for the actual text fragments which are located in separate language specific files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;page.home.greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, and it "might" even be fast, but I believe it's fundamentally flawed. &lt;em&gt;Text should live where it belongs: inside your markup, not behind opaque keys&lt;/em&gt;. Then I discovered LinguiJS. It was relatively new back then, but it introduced a refreshing idea. Instead of the above method, I would write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Trans&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Trans&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fragments are right there in the code. It auto extracts them using a command. This was much better and I migrated the whole application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaving Preact, entering Svelte
&lt;/h2&gt;

&lt;p&gt;Recently, I got some free time and wanted to move away from Preact to Svelte. But LinguiJS didn’t officially support Svelte. There was an adapter, but to me, it didn't feel like the real deal; it lacked the completeness and elegance of the original. Also I looked at the dependencies and apparently LinguiJS has grown to require more than 200! That was the final straw. I decided not to bring LinguiJS into my Svelte migration. However, the officially supported options for Svelte, like &lt;code&gt;svelte-i18n&lt;/code&gt; and &lt;code&gt;paraglide&lt;/code&gt;, relied on the same key-based approach I was trying to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does i18n have to be this hard?
&lt;/h2&gt;

&lt;p&gt;It then occurred to me, it doesn't.&lt;/p&gt;

&lt;p&gt;So I started playing with the svelte compiler and started to develop something that completely replaced my need for both key-based and wrapper-based methods. The design goals are simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You should just write your markup&lt;/strong&gt; and it should be translated&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It should have no compromise on performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Weeks of full time dedication later, it grew from a concept into a full open source package that you can use today.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;wuchale&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;wuchale&lt;/code&gt; is inspired by LinguiJS and built with many of the same principles, but with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;zero wrappers&lt;/li&gt;
&lt;li&gt;smaller bundles&lt;/li&gt;
&lt;li&gt;blazing fast (TM) performance&lt;/li&gt;
&lt;li&gt;no dependency bloat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More specifically, it's a &lt;code&gt;vite&lt;/code&gt; plugin that pre-transforms your code and in the process also does other things like extracting the text fragments, and compiling the translated ones. And it can handle anything you can throw at it, because it only does AST based analysis of your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Let's pick the simple "Hello" example above. &lt;code&gt;wuchale&lt;/code&gt; does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Convert your code into this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;wuchaleTrans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract the text into a per language PO file (like LinguiJS) that you can exchange with translators:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;#: src/file.svelte&lt;/span&gt;
&lt;span class="k"&gt;msgid&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;
&lt;span class="s"&gt;msgstr&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Translator fills the translated content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;#: src/file.svelte&lt;/span&gt;
&lt;span class="k"&gt;msgid&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;
&lt;span class="s"&gt;msgstr&lt;/span&gt; &lt;span class="s"&gt;"Hola"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compile the translated fragment into an array:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yes, the argument &lt;code&gt;0&lt;/code&gt; in the call &lt;code&gt;wuchaleTrans(0)&lt;/code&gt; is actually the array index! Because &lt;code&gt;wuchale&lt;/code&gt; controls the entire pipeline, it can avoid string keys altogether and still have deterministic output using arrays. This makes it output the smallest possible bundle size for the compiled fragments, even smaller than what LinguiJS produces, because LinguiJS uses string keys. And &lt;code&gt;vite&lt;/code&gt; can further minify the call into something like &lt;code&gt;w(0)&lt;/code&gt; to make the transformed code even smaller than the hand written &lt;code&gt;t('page.home.greeting')&lt;/code&gt;! All of this makes it the best at producing small bundle sizes for performance.&lt;/p&gt;

&lt;p&gt;So what happens if a translation is missing, will the user just see an index number (As LinguiJS just shows the meaningless string keys when there is no translated fragment)? Answer is no. &lt;code&gt;wuchale&lt;/code&gt; is smart enough to fall back to the source language (English in most cases) when the fragment is not yet translated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complex content? Handled beautifully
&lt;/h2&gt;

&lt;p&gt;Glad you asked! Sometimes, we have to mix text content with variables and markup. And &lt;code&gt;wuchale&lt;/code&gt; does work in the most intuitive way. It goes out of its way to preserve the text fragments that you expect to be together, no matter the boundaries between them.&lt;/p&gt;

&lt;p&gt;Let's say you have this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;, welcome!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would be transformed into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;wuchaleTrans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And extracted to the PO file as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;#: src/file.svelte&lt;/span&gt;
&lt;span class="k"&gt;msgid&lt;/span&gt; &lt;span class="s"&gt;"Hello&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kn"&gt;0&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt; &lt;span class="s"&gt;welcome!"&lt;/span&gt;
&lt;span class="s"&gt;msgstr&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And during runtime, it performs as fast as possible because it doesn't even parse and replace the placeholder. All of that heavy work is done during compile time. The compiled form of this (for English) would be&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, welcome!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the runtime has to do is just loop over the array and concatenate the strings and the arguments at the indices specified as numbers.&lt;/p&gt;

&lt;p&gt;The most complex scenarios involve text mixed with nested markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;, &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;welcome &lt;span class="nt"&gt;&amp;lt;i&amp;gt;&lt;/span&gt;home&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/b&amp;gt;&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't want &lt;code&gt;home&lt;/code&gt; to be extracted separately, but as part of the whole message. And &lt;code&gt;wuchale&lt;/code&gt; does that! It is extracted as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello {0}, &amp;lt;0&amp;gt;welcome &amp;lt;0&amp;gt;home&amp;lt;/0&amp;gt;&amp;lt;/0&amp;gt;!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the translators have the freedom to rearrange the markup as the language dictates using the placeholders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Convenience: Dev mode HMR
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;wuchale&lt;/code&gt; plays nicely with Hot Module Replacement (HMR). It integrates deeply with Vite's HMR API and Svelte's reactivity. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you update source &lt;code&gt;.svelte&lt;/code&gt; files → translations are extracted, and &lt;code&gt;.po&lt;/code&gt; files are updated&lt;/li&gt;
&lt;li&gt;When you update &lt;code&gt;.po&lt;/code&gt; files → the browser receives live updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this happens without a full page reload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Gemini-based auto translation
&lt;/h2&gt;

&lt;p&gt;Having access to the whole process allows for more features and one is automatic translation. &lt;code&gt;wuchale&lt;/code&gt; can use your Gemini API key if it finds it as an environment variable, and auto translates your content. It's not a substitute for human quality; but it gets you 80% of the way instantly.&lt;/p&gt;

&lt;p&gt;Together with support for seamless HMR, this enables you to work in your source language in the code and see the updates in the browser in another language in real-time!&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/K1DV5/wuchale" rel="noopener noreferrer"&gt;github.com/K1DV5/wuchale&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NPM: &lt;a href="https://www.npmjs.com/package/wuchale" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/wuchale&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;StackBlitz examples:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackblitz.com/github/K1DV5/wuchale/tree/main/examples/svelte" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackblitz.com/github/K1DV5/wuchale/tree/main/examples/sveltekit" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you try it, I'd love your feedback. And if you find it useful, consider starring the repo ⭐&lt;/p&gt;

&lt;p&gt;P.S. What's next? React support, perhaps. Got ideas? I'd love to hear them.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>i18n</category>
      <category>javascript</category>
      <category>ai</category>
    </item>
    <item>
      <title>Do you really need a plugin for fuzzy finding files in Neovim?</title>
      <dc:creator>Kidus Adugna</dc:creator>
      <pubDate>Tue, 06 May 2025 09:44:27 +0000</pubDate>
      <link>https://dev.to/k1dv5/do-you-really-need-a-plugin-for-fuzzy-finding-files-in-neovim-513d</link>
      <guid>https://dev.to/k1dv5/do-you-really-need-a-plugin-for-fuzzy-finding-files-in-neovim-513d</guid>
      <description>&lt;p&gt;I'm a simple man; I used &lt;a href="https://github.com/nvim-telescope/telescope.nvim" rel="noopener noreferrer"&gt;telescope.nvim&lt;/a&gt; for finding files and not for much else. But I'm also a minimalism junkie so I'm always on the lookout for ways to get more value with less dependencies.&lt;/p&gt;

&lt;p&gt;I really liked Telescope but like I said, me being me, I began to question if I need it with all it bells and whistles just for finding files. It felt overkill for the job. Also, recently I migrated to &lt;a href="https://github.com/Saghen/blink.cmp" rel="noopener noreferrer"&gt;blink.cmp&lt;/a&gt; for completion. I liked the fact that it gives you commonly used sources out of the box, and that includes cmdline completion.&lt;/p&gt;

&lt;p&gt;This morning it dawned on me that the most important pieces for my needs are already implemented in Neovim and blink and I just have to mould them into a file picker. So I came up with this lua code that I just put in &lt;code&gt;lua&lt;/code&gt; directory and call its &lt;code&gt;setup()&lt;/code&gt; in my &lt;code&gt;init.lua&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"git ls-files -c -o --exclude-standard"&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get_list_completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg_lead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmdline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cur_pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cmdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;io.popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"*a"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cmd_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tbl_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;M&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_create_user_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;"FilePick"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cmd_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_list_completion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;force&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_replace_termcodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':FilePick&amp;lt;tab&amp;gt; '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see it's just 32 lines with the empty lines. And it produces something that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkblazflwmdsw0w6vfa0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkblazflwmdsw0w6vfa0.png" alt="Screenshot" width="417" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just have to tab and enter.&lt;/p&gt;

&lt;p&gt;What it does is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It creates a command "FilePick" with a custom completion function.&lt;/li&gt;
&lt;li&gt;The completion function gets the list of files by using git's &lt;code&gt;ls-files&lt;/code&gt; but any command that lists the files can be used. I'm using this because it gives me the same output as &lt;code&gt;rg --files&lt;/code&gt; but faster (yes, than &lt;code&gt;ripgrep&lt;/code&gt; based on my crude benchmarking using &lt;code&gt;time&lt;/code&gt; but that's another topic).&lt;/li&gt;
&lt;li&gt;Then finally for convenience, creates a mapping &lt;code&gt;-&lt;/code&gt; that starts the command, and invokes the completion. From there you can type the fuzzy name, press tab (depending on your mapping) and enter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice that I made it behave like this because I have enabled the &lt;code&gt;cmdline&lt;/code&gt; completion from blink but I have its &lt;code&gt;auto_show&lt;/code&gt; and &lt;code&gt;preselect&lt;/code&gt; disabled. That's why the sequence for the last step is&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the command&lt;/li&gt;
&lt;li&gt;Invoke completion (tab), this will make the command the only candidate&lt;/li&gt;
&lt;li&gt;Press space. This invokes the custom completion function BUT does not complete the line with the first item because I want to write the fuzzy pattern next, not the full path of the first file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So there you have it, my custom file picker implemented in more or less the same number of lines as a Telescope configuration. So my answer to the title is...no. Thank you for reading.&lt;/p&gt;

&lt;p&gt;EDIT: I just enabled &lt;code&gt;preselect&lt;/code&gt; and mapped &lt;code&gt;&amp;lt;cr&amp;gt;&lt;/code&gt; to &lt;code&gt;accept_and_enter&lt;/code&gt; and now I don't even have to tab to select the first item! This resolved the last issue I had, that I had to press one additional key than I would with telescope.&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>git</category>
      <category>programming</category>
    </item>
    <item>
      <title>Gotchas when learning SolidJS with (p)react background</title>
      <dc:creator>Kidus Adugna</dc:creator>
      <pubDate>Mon, 29 Nov 2021 05:37:05 +0000</pubDate>
      <link>https://dev.to/k1dv5/gotchas-when-learning-solidjs-with-preact-background-55o3</link>
      <guid>https://dev.to/k1dv5/gotchas-when-learning-solidjs-with-preact-background-55o3</guid>
      <description>&lt;p&gt;I recently took on a new project and since I was following solid.js for a while, I thought I'd give it a try. And to reduce the time needed to develop the project I decided to port components from another project I built previously, using preact.&lt;/p&gt;

&lt;p&gt;I replaced &lt;code&gt;useState&lt;/code&gt; with &lt;code&gt;createSignal&lt;/code&gt; or &lt;code&gt;createStore&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt; with &lt;code&gt;createEffect&lt;/code&gt;, etc., with their appropriate syntax (no dependencies for &lt;code&gt;createEffect&lt;/code&gt; etc). Since solid shares a lot with react, I thought these fixes were enough. Boy was I surprised. I'll list my findings below. I might be wrong on some details so feel free to correct me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solid doesn't like custom hooks exported as default
&lt;/h2&gt;

&lt;p&gt;I had a custom hook to show a loader, whose state is controlled in a context.&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;// loader.jsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useLoading&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// component.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useLoading&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./loader.jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLoading&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nf"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the loader doesn't show. Then I copied over the hook definition to &lt;code&gt;component.jsx&lt;/code&gt; and it worked. So I tried converting it to a named export, and it worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using state outside of returned JSX is not reactive.
&lt;/h2&gt;

&lt;p&gt;I think this is because components only run once, but &lt;br&gt;
it took me hours to get this:&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="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Loader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think happens when &lt;code&gt;state.loading&lt;/code&gt; changes? Nothing. All changes must be inside the JSX for the component to be reactive.&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="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Loader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Using &lt;code&gt;For&lt;/code&gt; as a top-level return value with a changing list creates an infinite loop
&lt;/h1&gt;

&lt;p&gt;Even when the &lt;code&gt;For&lt;/code&gt; is inside a top-level fragment.&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="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/For&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{...}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/For&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of these create an infinite loop. It must be at least one level deep.&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{...}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/For&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I said in the beginning, all of these may be due to my wrong understanding, but they did take a lot of hours for me to find, and I wanted to share them here. Thanks for reading.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>solidjs</category>
    </item>
    <item>
      <title>I made a Mathcad alternative using Python</title>
      <dc:creator>Kidus Adugna</dc:creator>
      <pubDate>Sat, 15 Feb 2020 09:57:24 +0000</pubDate>
      <link>https://dev.to/k1dv5/i-made-a-mathcad-alternative-using-python-44fo</link>
      <guid>https://dev.to/k1dv5/i-made-a-mathcad-alternative-using-python-44fo</guid>
      <description>&lt;p&gt;I assume most people here are a little inclined to web development and so the name Mathcad might be new. PTC Mathcad is a desktop app built primarily for engineers to do math on a really readable document. It's like a limited word processor focused rather on doing calculations (MATLAB competitor) and how to display them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sjjzvw3dxiby9gg8dbt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sjjzvw3dxiby9gg8dbt.png" alt="Mathcad screenshot (Google images)" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now It's a really awesome tool. So why did I create an alternative? Well, it has some pain points, at least for me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not support exporting to LaTeX or Word. It can export to a Rich Text Format (.rtf) file which can be read by Word, but...&lt;/li&gt;
&lt;li&gt;When exporting to .rtf, the equations are converted to images and editing ability is lost. Also the text is in text boxes so you need to do some work in order to make your document obey some standards.&lt;/li&gt;
&lt;li&gt;For simple calculations, it's fine but for big works, which might require some programming parts like loops and conditionals, you have to learn a new language, which is more graphically oriented. Let's just say it's not for everyone.&lt;/li&gt;
&lt;li&gt;Again for big works, you may need a lot of word processing and related things (headings, TOC, citations, bibliography, index, etc.) which it does not have.&lt;/li&gt;
&lt;li&gt;It's really big, like the installer is around 900MB. I suspect that's because of the symbolic engine but for someone who does not need most of the bells and whistles, that's a lot.&lt;/li&gt;
&lt;li&gt;It is not cross-platform. This may not be a deal breaker for people who usually need something like that because (we)'re Windows users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Introducing &lt;a href="https://github.com/K1DV5/docal" rel="noopener noreferrer"&gt;&lt;strong&gt;docal&lt;/strong&gt;&lt;/a&gt; (what a name right?).  It's written in Python. It's available as a kind of a compiler CLI and also a &lt;a href="https://K1DV5/docal-tkinter" rel="noopener noreferrer"&gt;GUI built with Tkinter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxct7kwpjwyyccia8ox8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxct7kwpjwyyccia8ox8r.png" alt="docal screenshot" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It solves all of the issues above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It supports both LaTeX and Word&lt;/li&gt;
&lt;li&gt;Writes all equations in the native format of the respective document type (LaTeX or Word), means they can be editted, copied or anything as if you wrote them by hand. And all text is written normally.&lt;/li&gt;
&lt;li&gt;Very small, available as a Python package with no dependencies and a pre built GUI (whose installer is below 9MB)&lt;/li&gt;
&lt;li&gt;Cross-platform (although I have not tested it on systems other than windows, it should be, because Python is).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, the fun part, it can insert calculations into existing documents at places specified by hashtags. This is so that you make no compromises on anything. Word and LaTeX are the best for word processing. Therefore it will not try to compete with them on that. But they are not designed to do calculations. &lt;strong&gt;docal&lt;/strong&gt; fills that gap, and nothing more. You do the other parts of the document in Word or LaTeX, and the calculation parts in docal and insert them into the main document.&lt;/p&gt;

&lt;p&gt;I started working on something very primitive to this a year and a half ago when I was doing mechanical projects at university. It started out as just a text replacement program for LaTeX files, easier because they are just text files.  Then a friend suggested Word support. Then little by little, I started using it more and adding features and fixing issued along the way. Then I did my final year project with it and it was great! I was comfortable with working in a text editor and using the CLI but not all people are. So a GUI was necessary. But there was no support for displaying math in Tkinter (as far as I know). So I first used PyWebview and used KaTeX for the math. But, being a webview, it got slow for longer works. So I decided to tackle it using Tkinter.  To do that, I first had to find a way to render math. So I made &lt;a href="https://github.com/K1DV5/tkinter-math" rel="noopener noreferrer"&gt;tkinter-math&lt;/a&gt;, a package to render math on a tkinter canvas. Then everything else was easy and the current implementation happened.&lt;/p&gt;

&lt;p&gt;P.S. This is my first post on DEV, so if you think there is something I need to improve, please tell me.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tkinter</category>
      <category>engineering</category>
      <category>math</category>
    </item>
  </channel>
</rss>
