<?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: Kirill Chernenko</title>
    <description>The latest articles on DEV Community by Kirill Chernenko (@kirill_c_7b35589230).</description>
    <link>https://dev.to/kirill_c_7b35589230</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%2F3840162%2F0a552a07-f891-4252-ac5a-1198f31d6dba.jpg</url>
      <title>DEV Community: Kirill Chernenko</title>
      <link>https://dev.to/kirill_c_7b35589230</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kirill_c_7b35589230"/>
    <language>en</language>
    <item>
      <title>Stop importing locale bundles. The browser already knows how to say "3 hours ago" in Arabic, Japanese, and 200 other languages. "anywhen" wraps native Intl in 800b . Zero deps, zero config. npm install anywhen</title>
      <dc:creator>Kirill Chernenko</dc:creator>
      <pubDate>Sun, 29 Mar 2026 08:30:25 +0000</pubDate>
      <link>https://dev.to/kirill_c_7b35589230/stop-importing-locale-bundles-the-browser-already-knows-how-to-say-3-hours-ago-in-arabic-4j8h</link>
      <guid>https://dev.to/kirill_c_7b35589230/stop-importing-locale-bundles-the-browser-already-knows-how-to-say-3-hours-ago-in-arabic-4j8h</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2" class="crayons-story__hidden-navigation-link"&gt;Your browser speaks 200+ languages.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kirill_c_7b35589230" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3840162%2F0a552a07-f891-4252-ac5a-1198f31d6dba.jpg" alt="kirill_c_7b35589230 profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kirill_c_7b35589230" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kirill Chernenko
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kirill Chernenko
                
              
              &lt;div id="story-author-preview-content-3424075" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kirill_c_7b35589230" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3840162%2F0a552a07-f891-4252-ac5a-1198f31d6dba.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kirill Chernenko&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 29&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2" id="article-link-3424075"&gt;
          Your browser speaks 200+ languages.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/npm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;npm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/i18n"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;i18n&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>npm</category>
      <category>typescript</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Your browser speaks 200+ languages.</title>
      <dc:creator>Kirill Chernenko</dc:creator>
      <pubDate>Sun, 29 Mar 2026 08:16:58 +0000</pubDate>
      <link>https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2</link>
      <guid>https://dev.to/kirill_c_7b35589230/your-browser-speaks-200-languages-lb2</guid>
      <description>&lt;p&gt;Let's say you're building a chat app. International. You're launching in Germany, Japan, and Brazil next quarter — because apparently that's the plan now, and you found out on a Tuesday afternoon.&lt;br&gt;
You have a timestamp. A user was online 5 hours ago. You want to show that. &lt;br&gt;
Simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In English: "5 hours ago"
In German: "vor 5 Stunden"
In Japanese: "5時間前"
In Brazilian Portuguese: "há 5 horas"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or maybe you have an event. It's in two days. You want to say that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In English: "in 2 days"
In Arabic: "خلال يومين"
In Turkish: "2 gün içinde"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just a date. March 25, 2026. Simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In English: "Mar 25, 2026"
In Russian: "25 мар. 2026 г."
In Chinese: "2026年3月25日"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of this is hard to display. It's hard to display correctly, in the right language, without shipping a dictionary to every user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious solution that isn't great
&lt;/h2&gt;

&lt;p&gt;You open dayjs. You find the locale system. You import German. Portugal... and over and over more.&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;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs/locale/de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs/locale/ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs/locale/pt-br&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. Three locales down, forty-seven to go — and you're not sure which forty-seven, because that depends on where the business decides to expand next.&lt;/p&gt;

&lt;p&gt;Then someone asks for Arabic. Arabic has six plural forms — "1 hour ago", "2 hours ago", "3 hours ago" are all different grammatical structures. You import the locale file. Then Serbian. Then Korean. &lt;/p&gt;

&lt;p&gt;Then there's a meeting where someone says "we should support all major languages" and you smile and nod and quietly go update your webpack config.&lt;/p&gt;

&lt;p&gt;The locale bundle grows. The import list grows. Any better ideas?&lt;/p&gt;

&lt;h2&gt;
  
  
  My solution
&lt;/h2&gt;

&lt;p&gt;Three functions. That's it. No classes, no configuration objects, no "please read the 40-page migration guide". Just install.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;anywhen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anyago&lt;/span&gt; &lt;span class="p"&gt;}&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;anywhen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each function answers one question you already ask yourself when writing UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  anywhen — just make it readable
&lt;/h2&gt;

&lt;p&gt;This is the one that thinks for you. You give it a date, it figures out what a human would actually say. Recent things get relative time. Yesterday gets "yesterday". Older things get a proper date. Future things get "in 2 weeks". You stop making these decisions in every component.&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="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "just now"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "10 minutes ago"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "today, 2:35 PM"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "yesterday, 9:00 AM"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "Wednesday, 11:20 AM"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "Mar 5, 2016"&lt;/span&gt;
&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "in 2 weeks"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The switching logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt; 45 seconds   →  "just now"
&amp;lt; 1 hour       →  "10 minutes ago"
future &amp;gt; 1h    →  "in 2 weeks"
same day       →  "today, 14:35"
yesterday      →  "yesterday, 09:00"
&amp;lt; 7 days       →  "Wednesday, 11:20"
older          →  "Mar 5, 2016"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  anydate — what's the exact date, just a formatter?
&lt;/h2&gt;

&lt;p&gt;Maybe, but smart. For when you need a clean, localized date string. A post timestamp. An invoice date. A birthday. Something absolute that doesn't change based on when the user is reading it.&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="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "Mar 25, 2026"&lt;/span&gt;
&lt;span class="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "25. März 2026"&lt;/span&gt;
&lt;span class="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "2026年3月25日"&lt;/span&gt;
&lt;span class="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "٢٥ مارس ٢٠٢٦"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need more control? Pass any Intl.DateTimeFormat options:&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="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="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="na"&gt;month&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="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// "Wednesday, March 25"&lt;/span&gt;

&lt;span class="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// "2:35 PM"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  anyago — how long ago? how far ahead?
&lt;/h2&gt;

&lt;p&gt;For when the exact date doesn't matter — the distance does. A comment was posted. An event is coming. A subscription expires. You want to say "3 hours ago" or "in 2 days", not "March 25, 2026 at 14:35:00 UTC".&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="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "5 hours ago"&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "vor 5 Stunden"&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "5 saat önce"&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ru&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "5 часов назад"&lt;/span&gt;

&lt;span class="c1"&gt;// works for the future too&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="c1"&gt;// "in 2 days"&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "خلال يومين"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes you don't want "yesterday" — you want "1 day ago". Just add  flag &lt;strong&gt;true&lt;/strong&gt;:&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="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "1 day ago" instead of "yesterday"&lt;/span&gt;
&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "1 week ago" instead of "last week"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  anywhere — same locale everywhere
&lt;/h2&gt;

&lt;p&gt;If you're formatting multiple dates in one component, passing the locale every time gets old fast. &lt;strong&gt;anywhere&lt;/strong&gt; binds it once.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;anywhere&lt;/span&gt; &lt;span class="p"&gt;}&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;anywhen&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;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;anywhere&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;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anydate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "25. März 2026"&lt;/span&gt;
&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anywhen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// "heute, 09:00"&lt;/span&gt;
&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anyago&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;// "vor 5 Stunden"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locale set once and forgotten.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;800 bytes. That includes every language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;p&gt;Honest section. I like these.&lt;br&gt;
No custom format strings like &lt;strong&gt;DD/MM/YYYY&lt;/strong&gt;. No timezone handling (at least now).&lt;br&gt;
No date arithmetic. No parsing of whatever creative format your backend decided to use in 2013.&lt;/p&gt;

&lt;p&gt;The 7-day cutoff in &lt;strong&gt;anywhen&lt;/strong&gt; — after which it shows an absolute date instead of a weekday — is fixed. If you need custom logic, use &lt;strong&gt;anyago&lt;/strong&gt; and &lt;strong&gt;anydate&lt;/strong&gt; directly and wire it yourself.&lt;/p&gt;

&lt;p&gt;This library is for one specific thing: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;displaying dates to humans in their language. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Chat timestamps. Event countdowns. Comment dates. Notification feeds. If that's what you need, it's 800 bytes and you're done. If you need to parse timezones or do date math — use date-fns. No shame in that.&lt;/p&gt;

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

&lt;p&gt;Live demo where you can pick any method, any date, any locale and see the output: &lt;a href="//anywhen-kappa.vercel.app"&gt;Demo page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source is on &lt;a href="https://github.com/kirilinsky/anywhen" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The whole thing is small enough to read in one sitting. If something is broken or missing — open an issue. I built this because I needed it, and I'm really curious whether other people do too.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>npm</category>
      <category>typescript</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Wrote up the whole process of rehabilitating an npm package I forgot for 5 years — TypeScript migration, CSS-in-JS regrets, Intl API revelation and why I now check bundle size more than my messages.</title>
      <dc:creator>Kirill Chernenko</dc:creator>
      <pubDate>Fri, 27 Mar 2026 19:22:13 +0000</pubDate>
      <link>https://dev.to/kirill_c_7b35589230/wrote-up-the-whole-process-of-rehabilitating-an-npm-package-i-forgot-for-5-years-typescript-420c</link>
      <guid>https://dev.to/kirill_c_7b35589230/wrote-up-the-whole-process-of-rehabilitating-an-npm-package-i-forgot-for-5-years-typescript-420c</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl" class="crayons-story__hidden-navigation-link"&gt;NPM Archaeology: 5 Years in the Ground, Still Breathing&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kirill_c_7b35589230" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3840162%2F0a552a07-f891-4252-ac5a-1198f31d6dba.jpg" alt="kirill_c_7b35589230 profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kirill_c_7b35589230" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kirill Chernenko
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kirill Chernenko
                
              
              &lt;div id="story-author-preview-content-3416675" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kirill_c_7b35589230" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3840162%2F0a552a07-f891-4252-ac5a-1198f31d6dba.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kirill Chernenko&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 27&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl" id="article-link-3416675"&gt;
          NPM Archaeology: 5 Years in the Ground, Still Breathing
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/npm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;npm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/react"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;react&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>npm</category>
      <category>react</category>
      <category>opensource</category>
    </item>
    <item>
      <title>NPM Archaeology: 5 Years in the Ground, Still Breathing</title>
      <dc:creator>Kirill Chernenko</dc:creator>
      <pubDate>Fri, 27 Mar 2026 19:05:37 +0000</pubDate>
      <link>https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl</link>
      <guid>https://dev.to/kirill_c_7b35589230/npm-archaeology-5-years-in-the-ground-still-breathing-nnl</guid>
      <description>&lt;p&gt;Let me set the scene: It's a Saturday. Nothing particularly dramatic is happening. I'm just sitting there, scrolling through my old GitHub repos kinda digital archaeologist, and I find it&lt;br&gt;
 — react-calendar-datetime. &lt;br&gt;
My old and abandoned calendar package. &lt;br&gt;
Version 1.3.1 Last update: five years ago. ~100 downloads a month. A couple of themes. A moment.js dependency that probably weighs more than the entire package should.&lt;/p&gt;

&lt;p&gt;I don't know what came over me. Maybe it was lazy weekend. Maybe it was nostalgia. Maybe I just wanted to feel something. Either way, I opened it up and thought: let's see how bad this is.&lt;/p&gt;

&lt;h2&gt;
  
  
  State of Things
&lt;/h2&gt;

&lt;p&gt;Honestly? It wasn't that bad. The core worked. The calendar rendered dates correctly and didn't catch fire when you clicked on it. By the standards of "abandoned weekend projects", this was actually in pretty good shape.&lt;/p&gt;

&lt;p&gt;But I cannot look at working code and leave it alone. I wanted to try to optimize it, pour in everything I'd learned over the past 5 years — and if that didn't work out, at least break something :D&lt;/p&gt;

&lt;p&gt;So what started as "let me just poke around" turned into a two-week sprint that took the package from v1.3.1 all the way to v3. I have no one to blame but myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Boss: TypeScript
&lt;/h2&gt;

&lt;p&gt;The first real challenge was migrating to TypeScript. I'd been putting this off for years — not because I don't like TypeScript (I really do), but because migrating an existing JS project to TS is exactly as fun as it sounds. You think you're just adding types. You are not just adding types. You start finding every lazy shortcut you ever took with your data, all at once, while the compiler just stares at you and judges.&lt;/p&gt;

&lt;p&gt;It took a while. But once it was done, everything felt more solid. Like the project had grown a spine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dependency Problem (Or: My Obsession With Bundle Size)
&lt;/h2&gt;

&lt;p&gt;Here's something I didn't expect to become a personality trait: I got absolutely fixated on bundle size.&lt;br&gt;
It started innocently. The original package had moment.js. Classic. I migrated to dayjs, felt very smart about it, moved on. Then I started actually measuring the bundle. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Then I couldn't stop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I started resenting every single byte that wasn't mine.&lt;br&gt;
So I removed dayjs too :D&lt;br&gt;
Wrote my own date utilities. They're not fancy — no one's going to write a blog post about my addMonths function — but they work, they're pretty small, and they belong to me.&lt;/p&gt;

&lt;p&gt;Final score: zero external dependencies. Bundle stayed around: ~5-7kb gzipped. I check this number more often than I'd like to admit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CSS Saga
&lt;/h2&gt;

&lt;p&gt;I moved all styles from SCSS to goober, a CSS-in-JS library. Felt modern. Felt good. 1kb of injected code. Shipped it.&lt;/p&gt;

&lt;p&gt;But I couldn't stop thinking about zero dependency library.&lt;/p&gt;

&lt;p&gt;And what we have now: CSS Modules. No more goober. I slept better after this decision and I'm not joking. At least for next few weeks :D&lt;/p&gt;

&lt;h2&gt;
  
  
  The Localization Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;This is my favorite part of the whole story, because it went from "annoying problem" to "surprisingly elegant solution" in a way that felt like cheating.&lt;br&gt;
Originally, locales were only supported for presets — "Today", "Yesterday", etc. and just for few languages.&lt;br&gt;
Then I added dayjs locale support for month names, weeks... &lt;br&gt;
This was... fine, but the list of supported locales was limited, and every new locale added weight to the bundle. (Remember my obsession?)&lt;/p&gt;

&lt;p&gt;The more languages I wanted to support, the fatter the package got. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It was a trap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I discovered &lt;strong&gt;Intl&lt;/strong&gt; — the native browser internationalization API. And I just... used that instead.&lt;/p&gt;

&lt;p&gt;400+ locales. Month names, weekday names, relative time formatting for presets — all of it, natively, with zero extra bytes. No dictionaries. No JSON files. No dependencies.&lt;/p&gt;

&lt;p&gt;I just sat back and stared at the ceiling for a moment. Sometimes the platform just gives you what you need and you've been ignoring it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Theme System (My Proudest Weird Thing)
&lt;/h2&gt;

&lt;p&gt;At some point I started making themes. Then I made more themes. Then I couldn't stop making themes. The package now has 18 of them — dark, light, brutalist, pastel, neon — and I love each one like a slightly chaotic parent.&lt;/p&gt;

&lt;p&gt;But more importantly: trying to manage all these themes efficiently (bundle size!) pushed me to design a proper theming system based on CSS variables.&lt;br&gt;
Seven variables per theme, one lookup table, predictable output. That system ended up being clean enough that I extracted it into a separate npm package &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We all need more NPM packages :D &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's just what happens when you get bored on a weekend.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Easy Win I Didn't Expect
&lt;/h2&gt;

&lt;p&gt;Migrating from &lt;strong&gt;rollup&lt;/strong&gt; to &lt;strong&gt;tsup&lt;/strong&gt;, and later to &lt;strong&gt;tsdown&lt;/strong&gt; — I expected this to be a nightmare. Build tooling migrations have a reputation, and it's not a good one.&lt;br&gt;
It was fine. It was suspiciously fine. The authors of these tools did a great job and I got to just... configure a few things and move on. After weeks of one thing leading to another, this was a nice surprise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Things Stand
&lt;/h2&gt;

&lt;p&gt;Two weeks of obsessive weekend coding later:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v3.1.2&lt;/strong&gt; is out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully modular: toggle time picker, month grid, year selector, presets independently&lt;/li&gt;
&lt;li&gt;18 themes with a CSS variable system, gradients, shades.&lt;/li&gt;
&lt;li&gt;400+ locales via Intl&lt;/li&gt;
&lt;li&gt;Week numbers, weekend highlighting, swipe gestures, jelly mode (don't ask, just try it)&lt;/li&gt;
&lt;li&gt;~5.9kb gzipped&lt;/li&gt;
&lt;li&gt;Accessibility work in progress (there's always more to do here, I know)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Downloads went from 100/month to... more than 100/month. I'm not going to oversell it. But people are using it, filing issues, and occasionally saying nice things, which is more than I had before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Conclusion
&lt;/h2&gt;

&lt;p&gt;Open source has always made me nervous — I've tried before and it never really clicked. This time feels different, maybe because I'm not trying to make something important. I'm just trying to make something good.&lt;br&gt;
If you have an old project collecting dust somewhere: maybe don't let it sit for five years. Or do. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get bored on a Saturday.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See what happens.&lt;br&gt;
The package is &lt;a href="https://www.npmjs.com/package/react-calendar-datetime" rel="noopener noreferrer"&gt;react-calendar-datetime&lt;/a&gt; if you want to take a look. PRs welcome. Issues welcome. Gentle feedback about my themes collection absolutely welcome.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>npm</category>
      <category>react</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
