<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fa">
  <title>komeil — fa</title>
  <id>https://komeil.me/feeds/fa.xml</id>
  <link rel="self" href="https://komeil.me/feeds/fa.xml"/>
  <link rel="alternate" href="https://komeil.me/fa"/>
  <updated>2026-06-01T00:00:00Z</updated>
  <author><name>komeil</name></author>
  <entry xml:lang="fa">
    <title>Bilingual metadata that fails loudly</title>
    <id>https://komeil.me/fa/writing/bilingual-metadata</id>
    <link rel="alternate" href="https://komeil.me/fa/writing/bilingual-metadata"/>
    <published>2026-04-22T00:00:00Z</published>
    <updated>2026-06-01T00:00:00Z</updated>
    <summary>Hope is not a localization strategy.</summary>
    <content type="html">&lt;p&gt;Bilingual sites fail quietly. An English page ships without a Persian alternate. A &lt;code&gt;lang&lt;/code&gt; attribute lies. A feed mixes languages. Search indexes conflate scripts. Users adapt; SEO does not.&lt;/p&gt;&lt;p&gt;This site models language &lt;strong&gt;explicitly&lt;/strong&gt;:&lt;/p&gt;&lt;h2&gt;translation_key&lt;/h2&gt;&lt;p&gt;Every post and page carries a &lt;code&gt;translation_key&lt;/code&gt; shared across languages. English and Persian versions of the same essay use the same key. The build groups by key and requires exactly one entry per supported language for published content.&lt;/p&gt;&lt;p&gt;Missing translations are not warnings in production — they are build failures.&lt;/p&gt;&lt;h2&gt;URL structure&lt;/h2&gt;&lt;p&gt;&lt;code&gt;/en/...&lt;/code&gt; and &lt;code&gt;/fa/...&lt;/code&gt;. No query-parameter language switching. No cookie-guessed locale for public content. The root &lt;code&gt;/&lt;/code&gt; is a minimal selector with &lt;code&gt;hreflang&lt;/code&gt; alternates.&lt;/p&gt;&lt;h2&gt;Metadata&lt;/h2&gt;&lt;p&gt;Every rendered page includes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;lang&lt;/code&gt; and &lt;code&gt;dir&lt;/code&gt; on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Canonical URL&lt;/li&gt;&lt;li&gt;&lt;code&gt;link rel=&amp;quot;alternate&amp;quot; hreflang=...&lt;/code&gt; for each translation&lt;/li&gt;&lt;li&gt;Separate Atom and RSS feeds per language&lt;/li&gt;&lt;li&gt;&lt;code&gt;sitemap.xml&lt;/code&gt; entries with alternates&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Search&lt;/h2&gt;&lt;p&gt;Per-language JSON indices at &lt;code&gt;/static/search-en.json&lt;/code&gt; and &lt;code&gt;/static/search-fa.json&lt;/code&gt;. Client-side normalisation unifies Persian character variants so typing is forgiving without mixing corpora.&lt;/p&gt;&lt;h2&gt;UI strings&lt;/h2&gt;&lt;p&gt;Navigation, form labels, and chrome strings live in a typed &lt;code&gt;i18n&lt;/code&gt; catalogue — not scattered literals. The build checks that every key exists in both languages.&lt;/p&gt;&lt;p&gt;Explicit modeling costs author time. It saves the kind of embarrassment that only shows up in Search Console six months later.&lt;/p&gt;</content>
  </entry>
  <entry xml:lang="fa">
    <title>Static-first publishing as a discipline</title>
    <id>https://komeil.me/fa/writing/static-first-publishing</id>
    <link rel="alternate" href="https://komeil.me/fa/writing/static-first-publishing"/>
    <published>2026-03-10T00:00:00Z</published>
    <updated>2026-07-16T00:00:00Z</updated>
    <summary>The build is the editor's last line of defence.</summary>
    <content type="html">&lt;p&gt;Most personal sites do not need a runtime. They need &lt;strong&gt;files&lt;/strong&gt;, &lt;strong&gt;checks&lt;/strong&gt;, and &lt;strong&gt;a deploy step you can explain in one sentence&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Static-first publishing means the production artifact is HTML on disk. The server — if there is one — handles the exceptions: forms, webhooks, admin tools. Not page rendering. Not content queries. Not template compilation at request time.&lt;/p&gt;&lt;h2&gt;What you gain&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Speed by default.&lt;/strong&gt; No hydration tax, no framework boot, no layout shift from client rendering.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inspectable output.&lt;/strong&gt; You can open &lt;code&gt;dist/en/writing/my-post/index.html&lt;/code&gt; and see exactly what ships.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Cheap hosting.&lt;/strong&gt; Any object store or CDN works. Scale is someone else&amp;#39;s problem.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A real review surface.&lt;/strong&gt; Content changes are diffs. Translation pairing is a build error, not a production surprise.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;What you give up&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Instant publish without a build.&lt;/strong&gt; Acceptable. A two-minute CI run is cheaper than operating a CMS database.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Per-request personalization.&lt;/strong&gt; Not missed on a personal site.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Plugin ecosystems.&lt;/strong&gt; Replaced by typed code you own.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;The discipline&lt;/h2&gt;&lt;p&gt;Treat the build as part of the product. Translation validators, link checkers, and draft guards are not &amp;quot;nice to have&amp;quot; — they are how you keep a bilingual site honest without hiring an editor.&lt;/p&gt;&lt;p&gt;The contact form posts to &lt;code&gt;/api/contact&lt;/code&gt;. Everything else is already HTML when the first byte leaves the CDN.&lt;/p&gt;</content>
  </entry>
</feed>
