<?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: Hofer Ivan</title>
    <description>The latest articles on DEV Community by Hofer Ivan (@ivanhofer).</description>
    <link>https://dev.to/ivanhofer</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%2F589898%2F25cb5970-7a7c-4da4-8f2d-4eb103a86153.jpeg</url>
      <title>DEV Community: Hofer Ivan</title>
      <link>https://dev.to/ivanhofer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivanhofer"/>
    <language>en</language>
    <item>
      <title>Svelte and TypeScript - Guide</title>
      <dc:creator>Hofer Ivan</dc:creator>
      <pubDate>Mon, 21 Mar 2022 13:55:44 +0000</pubDate>
      <link>https://dev.to/ivanhofer/svelte-and-typescript-guide-2cp6</link>
      <guid>https://dev.to/ivanhofer/svelte-and-typescript-guide-2cp6</guid>
      <description>&lt;p&gt;Ever asked if &lt;code&gt;Svelte&lt;/code&gt; could be used for business applications? Have you ever wanted to write &lt;code&gt;TypeScript&lt;/code&gt; inside your &lt;code&gt;Svelte&lt;/code&gt; and &lt;code&gt;SvelteKit&lt;/code&gt; applications? Ever struggled to get started?&lt;/p&gt;

&lt;p&gt;Then you will finally get an answer here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should you care about TypeScript?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; does not have a static type system, so we need &lt;code&gt;TypeScript&lt;/code&gt; to benefit from the capabilities that types can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;common error prevention&lt;/li&gt;
&lt;li&gt;code completion&lt;/li&gt;
&lt;li&gt;auto-documenting code (kind of)&lt;/li&gt;
&lt;li&gt;great help for refactoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially if you work a larger team or on a long-running project by using TypeScript you will catch a lot of errors before they even reach the production system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;I have collected a few examples that help you get started with &lt;code&gt;TypeScript&lt;/code&gt; inside &lt;code&gt;Svelte&lt;/code&gt; projects. They should help you getting started. There are also some more advanced example that will help you build complex use-cases in a typesafe way. Along the road you will hopefully also learn some useful &lt;code&gt;TypeScript&lt;/code&gt; tipps.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="https://github.com/ivanhofer/sveltekit-typescript-showcase"&gt;https://github.com/ivanhofer/sveltekit-typescript-showcase&lt;/a&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>typescript</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>i18n - my journey to a simple, powerful and type-safe solution</title>
      <dc:creator>Hofer Ivan</dc:creator>
      <pubDate>Tue, 16 Mar 2021 16:37:37 +0000</pubDate>
      <link>https://dev.to/ivanhofer/i18n-my-journey-to-a-simple-powerful-and-type-safe-solution-2c46</link>
      <guid>https://dev.to/ivanhofer/i18n-my-journey-to-a-simple-powerful-and-type-safe-solution-2c46</guid>
      <description>&lt;p&gt;Two years ago I was looking for an easy solution to localize a TypeScript application that I wrote. The app was written in svelte and I wanted to continue the svelte-way: &lt;strong&gt;easy to use&lt;/strong&gt; and &lt;strong&gt;easy on bandwidth&lt;/strong&gt;. I tried a lot of i18n packages but could not find any solution that fits my needs.&lt;/p&gt;

&lt;p&gt;So, like every software-engineer would do, I hacked together my own solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;the problem&lt;/li&gt;
&lt;li&gt;the journey&lt;/li&gt;
&lt;li&gt;the solution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The problem I want to solve
&lt;/h2&gt;

&lt;p&gt;I was happy with my solution. It works well, was simple, supported basic plural rules and was only a few kilobytes small. But yet, I came across a few things, that made me always wonder about all key-value based i18n solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what if I have a typo in my translation key?&lt;/li&gt;
&lt;li&gt;what if I accidential access a locale, I do not support?&lt;/li&gt;
&lt;li&gt;what if I forget to add a translation to one of my locale files?&lt;/li&gt;
&lt;li&gt;what if I forget to pass arguments to the translation function?&lt;/li&gt;
&lt;li&gt;what if I pass the wrong order of arguments?&lt;/li&gt;
&lt;li&gt;what if I pass the wrong type of an argument?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All these questions where not only of theoretical nature, as I encountered them in our project. Most of the times we catched the errors through our code-review process, but still a few bugs passed all the way to the production environment.&lt;br&gt;
Not because it was an self-build i18n solution. No! Because there are some general issues with key-value based i18n solutions: &lt;strong&gt;they don't support static type checking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fast forward to a few weeks ago: I had some free time and wanted to learn something new about TypeScript. The first thing tht came to my mind: can there be a typesafe solution to the i18n problem I encountered?&lt;/p&gt;

&lt;p&gt;Well, I would not have written this article if the answer wasn't: &lt;strong&gt;YES!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript today is very powerful. I recently came across the repository &lt;a href="https://github.com/type-challenges/type-challenges" rel="noopener noreferrer"&gt;type-challenges&lt;/a&gt; where a lot of smart people do some crazy magic without code - &lt;strong&gt;only&lt;/strong&gt; types.&lt;/p&gt;

&lt;p&gt;But can it be so powerful to fulfill my needs? The answer is yes and no at the same time. The type-system is powerful enough, but who should write all these types? But lets begin with the basics:&lt;/p&gt;

&lt;h2&gt;
  
  
  The journey
&lt;/h2&gt;

&lt;p&gt;Every i18n solution needs a system to get to your desired output. So lets start with the translation function:&lt;/p&gt;

&lt;h3&gt;
  
  
  parsing strings
&lt;/h3&gt;

&lt;p&gt;I wanted a solution where I only need paste a string from a translator into my codebase and maybe only modify some dynamic parts. So I wrote my own little string-parser. The syntax looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi {0}!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; outputs to e.g. 'Hi John!'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi {name}!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// or with keyed syntax&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;{0}&lt;/code&gt; and &lt;code&gt;{name}&lt;/code&gt; are the dynamic parts, you would need to pass to the translation function.&lt;/p&gt;

&lt;p&gt;When calling the translation function the first time, the string is parsed to an optimized object representation. The result is kept in memory and when calling the translation function the second time, no parsing is needed anymore. Only the dynamic parts need to be replaced by the arguments you pass to the function. This can be done fast by browsers, so in a few milliseconds you could easily replace the whole content on-the-fly with a new locale.&lt;/p&gt;

&lt;h3&gt;
  
  
  adding some more features
&lt;/h3&gt;

&lt;p&gt;Sometimes you need a little bit more than just passing arguments to be able to translate your application.&lt;/p&gt;

&lt;h4&gt;
  
  
  plural rules
&lt;/h4&gt;

&lt;p&gt;In some parts of your application, you might need your string to adapt depending on a number you pass in as an argument. To rescue, here comes the plural-syntax:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{0} {{apple|apples}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; e.g. '1 apple' &lt;/span&gt;
&lt;span class="c1"&gt;// or the short-syntax:&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{0} apple{{s}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// e.g. '7 apples'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where the first part &lt;code&gt;'apple'&lt;/code&gt; is the singular version and the second &lt;code&gt;'apples'&lt;/code&gt; is the plural version. The parts are split by the pipe-character (&lt;code&gt;|&lt;/code&gt;). Under the hood, the browser's built-in &lt;a href="https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules" rel="noopener noreferrer"&gt;Intl.PluralRules&lt;/a&gt; is used. It is supported in all modern browsers and can handle a variety of locales.&lt;/p&gt;

&lt;h4&gt;
  
  
  formatting values
&lt;/h4&gt;

&lt;p&gt;Especially when it comes to date and numbers, most locales have their own way to display values. The syntax for formatting values is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// for locale 'en'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The car costs {0|euro}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'The car costs €19,999.00'&lt;/span&gt;

&lt;span class="c1"&gt;// for locale 'de'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Das Auto kostet {0|euro}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Das Auto kostet 19.999,00 €'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;euro&lt;/code&gt; is the name of the formatter it should call.&lt;br&gt;
All formatters are passed when initializing the translation function. In this example we would pass following object to get the locale-dependent currency format:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// for locale 'en'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;euroFormatterEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NumberFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;formattersEN&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="s1"&gt;currency&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;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;euroFormatterEN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// for locale 'de'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;euroFormatterDE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NumberFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&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;formattersDE&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="s1"&gt;currency&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;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;euroFormatterDE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;This example uses &lt;a href="https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat" rel="noopener noreferrer"&gt;Intl.NumberFormat&lt;/a&gt; all modern browsers support. Of course you can write your own solution or use another library to format values.&lt;/p&gt;

&lt;h3&gt;
  
  
  translation-functions
&lt;/h3&gt;

&lt;p&gt;Here is a complete example how a setup to translate strings would look like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LLL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;i18nString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formatters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;LLL&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 {name|uppercase}!&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;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Hello WORLD!'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;i18nString&lt;/code&gt; is function to initialize the translation function.&lt;/p&gt;

&lt;p&gt;Of course you don't want to pass in the strings by yourself. You want to have a collection of all your translations in one place. So you could use:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;HI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello {name}!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;RESET_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reset password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="cm"&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;formatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&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;LL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;i18nObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;translations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formatters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;LL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Hello world!'&lt;/span&gt;
&lt;span class="nx"&gt;LL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RESET_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'reset password'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;i18nObject&lt;/code&gt; is a wrapper around the &lt;code&gt;i18nString&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;It could be that you need to call a translation for different locales in the same function e.g. in a server environment where the locale comes from an users session. This can also be done:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localeTranslations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Today is {date|weekday}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Heute ist {date|weekday}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oggi è {date|weekday}&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;localeTranslations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;locale&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;initFormatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateFormatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;weekday&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;long&lt;/span&gt;&lt;span class="dl"&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="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dateFormatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loadLocale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initFormatters&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;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Today is friday'&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Heute ist Freitag'&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; 'Oggi è venerdì'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;i18n&lt;/code&gt; is a wrapper around the &lt;code&gt;i18nObject&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;With these three function a variety of use-cases are covered. Next comes the best part:&lt;/p&gt;

&lt;h3&gt;
  
  
  type-safety
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;i18nObject&lt;/code&gt; and &lt;code&gt;i18n&lt;/code&gt; mark the base. These functions are typed using &lt;a href="https://www.typescriptlang.org/docs/handbook/generics.html" rel="noopener noreferrer"&gt;generics&lt;/a&gt; and support you with some basic type checking. You already can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see what locales you can access
&lt;img src="https://media.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%2F0rv5s0f3csld2wzpqgqm.png" alt="typesafe locales completion"&gt;
&lt;/li&gt;
&lt;li&gt;see what keys you can access to call the translation function
&lt;img src="https://media.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%2F1ywvjtgfx95dftu60i87.png" alt="typesafe translation key completion"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This support for type-checking is more than most of existing i18n solutions can provide. So I am done, right?&lt;/p&gt;

&lt;p&gt;Not quiet yet. We have only covered point 1 and 2 of the problems we want to solve.&lt;/p&gt;

&lt;p&gt;Here the more complex part begins...&lt;/p&gt;

&lt;p&gt;The generic types of the translation-object can help us with our problems. Until here we haven't passed any generic types. The functions infer the types from the objects we pass to the initialize function and use some fallback types to cover the basics.&lt;/p&gt;

&lt;p&gt;But someone also has to provide the correct types, so the functions can unfold their full potential. You could write the types yourself and pass them when initializing like in this example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;HI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello {name|uppercase}&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;formatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i18nObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Locales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TranslationFunctions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Formatters&lt;/span&gt;&lt;span class="o"&gt;&amp;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;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;translations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formatters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;with following types:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Translation&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="s1"&gt;HI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TranslationFunctions&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="s1"&gt;HI&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;span class="na"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Formatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When you now try to access the translation by calling &lt;code&gt;LL.HI()&lt;/code&gt; TypeScript will complain, because you missed to pass an argument. So lets add an argument and call &lt;code&gt;LL.HI('John')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Still an error...&lt;/p&gt;

&lt;p&gt;Oh yeah right, we need to pass an Object with a &lt;code&gt;name&lt;/code&gt; attribute:&lt;br&gt;
&lt;code&gt;LL.HI({ name: 'John' })&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now TypeScript is happy and we can compile our application.&lt;/p&gt;

&lt;p&gt;I hope you see the benefit from the additional types. But writing these types is a repetitive task no-one is willing to do. Sounds like a task a computer could and should solve for you. Here the &lt;strong&gt;generator&lt;/strong&gt; comes in play:&lt;/p&gt;

&lt;h3&gt;
  
  
  The generator
&lt;/h3&gt;

&lt;p&gt;This little helper, assists you by analyzing your base locale file and provides you with the types you need to get a nice i18n experience.&lt;/p&gt;

&lt;p&gt;The generator looks for changes in your base-locale file. When a change is detected, it will generate corresponding types for you. You then can use these types to get fully-typed i18n functions. Some wrappers around the base translation-functions are also generated, so you don't have to pass the types by yourself.&lt;/p&gt;

&lt;p&gt;The generator needs an opinionated folder structure to do its work.&lt;br&gt;
Your locales will need to be located in the same root-folder. Each locale has its own folder with a &lt;code&gt;default export&lt;/code&gt; in the &lt;code&gt;index.ts&lt;/code&gt; file. You will only have one base-locale file, all other locales should have the generated type of &lt;code&gt;Translation&lt;/code&gt;. Why? Because then you can see if one of your locales is missing a translation.&lt;/p&gt;

&lt;p&gt;We now have successfully covered point 3 of our problems and now we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see all available locales
&lt;img src="https://media.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%2Fd6dsjh09d97igyn6da88.png" alt="typesafe locales completion"&gt;
&lt;/li&gt;
&lt;li&gt;see all available keys to call an translation
&lt;img src="https://media.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%2Fje76v0j5jct9fn1gjpl9.png" alt="typesafe translation key completion"&gt;
&lt;/li&gt;
&lt;li&gt;see if we have missed to add a translation to one of our locales
&lt;img src="https://media.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%2F5w6ii3seyqj9wmcsqbad.png" alt="typesafe keys in translations"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;all without you needing to write or to pass any types or objects. This is all done automatically for you.&lt;/p&gt;

&lt;h4&gt;
  
  
  formatters
&lt;/h4&gt;

&lt;p&gt;But what happened to the formatters? Well.. the generator can handle this also for you - kind of. It will detect all the formatters you are using in your translation function, and (yes, you guessed it) generate types for your formatter functions. It generates a wrapper object in the &lt;code&gt;formatters.ts&lt;/code&gt; file where you only need to define your formatting functions. If you forget to define a function, TypeScript will complain and you can't start your application.&lt;/p&gt;

&lt;p&gt;There are still some problems left to solve...&lt;/p&gt;

&lt;h4&gt;
  
  
  typed arguments
&lt;/h4&gt;

&lt;p&gt;Because we are parsing your base-translation, we can also define some types in there. The syntax is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello {name:string}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this example the argument &lt;code&gt;name&lt;/code&gt; is marked as a &lt;code&gt;string&lt;/code&gt;. So when you try to call the translation with a wrong type e.g. a number, TypeScript will make you aware of it.&lt;/p&gt;

&lt;p&gt;Built-in JavaScript types are supported. If you want to pass your own types or union-types, you need to define them as an export in the &lt;code&gt;custom-types.ts&lt;/code&gt; file. So if you have the translation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Total: {0:Cart|calculateSum}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;where the type 'Cart' must be defined in &lt;code&gt;custom-types.ts&lt;/code&gt; e.g. as following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
   &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}[]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The generator will detect that you want to pass an argument of type &lt;code&gt;Cart&lt;/code&gt; to your &lt;code&gt;calculateSum&lt;/code&gt; formatting function and will generate the corresponding type for you. The formatters then must look something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formatters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;calculateSum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With the help of the generator we can also cover the last three problems and we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see that you need to pass arguments
&lt;img src="https://media.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%2F7k6dfwauthfchlyd0pni.png" alt="typesafe number of arguments"&gt;
&lt;/li&gt;
&lt;li&gt;see what type of arguments you need to pass
&lt;img src="https://media.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%2Fypl3ormaig7smhcu5joh.png" alt="typesafe arguments 1"&gt;
&lt;img src="https://media.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%2Fsjde9pbuthqa4sqrye0x.png" alt="typesafe arguments 2"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am really happy with my solution. We now can be confident that we call all the translation functions correctly.&lt;/p&gt;

&lt;p&gt;But then I encountered another problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what if in a translation we forget to add an argument the base-translation has?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  bonus round
&lt;/h3&gt;

&lt;p&gt;During my research I stumbled across a new TypeScript feature introduced with version 4.1: &lt;a href="https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html" rel="noopener noreferrer"&gt;Template Literal Types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this feature we now can also type strings. So when we have the base translation&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi {name:string}!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;we can say that we always expect a translation for that string to contain at least the argument-part &lt;code&gt;{name}&lt;/code&gt; in it.&lt;br&gt;
This can be typed as following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ArgName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;{name}&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You will notice, that we have omitted the type &lt;code&gt;string&lt;/code&gt; in the translations. We only need types for our base translation. &lt;/p&gt;

&lt;p&gt;We now also can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see if we forgot to include a parameter in a translation
&lt;img src="https://media.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%2Fv7vttkbzif4onmgs72za.png" alt="typesafe arguments in translation"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what if someone has not upgraded to the latest TypeScript version yet? Well, the generator only outputs types, your current TypeScript version supports. If you later upgrade and run the generator again, better types will be generated for you ;)&lt;/p&gt;

&lt;p&gt;Congratulations, you have reached the end of my story and learned the basics on how a typesafe i18n experience can be accomplished. I am happy to share the outcome of my work with you:&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/ivanhofer/typesafe-i18n" rel="noopener noreferrer"&gt;&lt;code&gt;typesafe-i18n&lt;/code&gt;&lt;/a&gt; - an opinionated, fully type-safe, lightweight localization library for TypeScript projects with no external dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F0qa3fs1fa5v4mynwh1p0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0qa3fs1fa5v4mynwh1p0.gif" alt="typesafe-i18n in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Advantages of my library are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it is &lt;strong&gt;lightweight&lt;/strong&gt; (the base translation function is only 765 bytes gzipped)&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;full type-safe&lt;/strong&gt; and prevents you from making mistakes&lt;/li&gt;
&lt;li&gt;it uses an &lt;strong&gt;easy to use syntax&lt;/strong&gt; (at least to me :P)&lt;/li&gt;
&lt;li&gt;has &lt;strong&gt;fast and efficient&lt;/strong&gt; type-generation and code execution&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;supports plural rules&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;allows &lt;strong&gt;formatting of values&lt;/strong&gt; e.g. locale-dependent date or number formats&lt;/li&gt;
&lt;li&gt;can be used in &lt;strong&gt;any kind of TypeScript applications&lt;/strong&gt; (JavaScript is also supported)&lt;/li&gt;
&lt;li&gt;uses &lt;strong&gt;no external dependencies&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I created some (basic) &lt;a href="https://github.com/ivanhofer/typesafe-i18n/tree/master/examples" rel="noopener noreferrer"&gt;examples&lt;/a&gt; so you can see how this package can be used in a variety of projects.&lt;/p&gt;

&lt;p&gt;Initially I needed a solution for my svelte-application. So I also created a small wrapper around the i18n-functions. The generator can also export a full-typed svelte-store by setting the &lt;code&gt;adapter&lt;/code&gt;-&lt;a href="https://github.com/ivanhofer/typesafe-i18n#options" rel="noopener noreferrer"&gt;option&lt;/a&gt; to &lt;code&gt;'svelte'&lt;/code&gt;. Other frameworks can also be added by a few lines of code.&lt;/p&gt;

&lt;p&gt;I learned a lot during my journey. I hope you enjoyed my story. Let me know in the comments what you think :)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>i18n</category>
      <category>svelte</category>
      <category>node</category>
    </item>
  </channel>
</rss>
