<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MENA Marketing Playbooks]]></title><description><![CDATA[Practical marketing tools, playbooks, and systems for MENA teams across paid media, analytics, conversion, Arabic localization, search, and AI.]]></description><link>https://mena-marketing-playbooks.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6af578edffb235a509d81b0a/cdde7068-2820-4ab1-9a94-ab235ca183c4.png</url><title>MENA Marketing Playbooks</title><link>https://mena-marketing-playbooks.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 15 Nov 2026 18:53:25 GMT</lastBuildDate><atom:link href="https://mena-marketing-playbooks.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a Bilingual, Problem-First Resource Finder with Client-Side Search]]></title><description><![CDATA[A static-site case study of bilingual client-side search: normalize Arabic and English input, filter a curated resource index, and state the limits.]]></description><link>https://mena-marketing-playbooks.hashnode.dev/building-a-bilingual-problem-first-resource-finder-with-client-side-search</link><guid isPermaLink="true">https://mena-marketing-playbooks.hashnode.dev/building-a-bilingual-problem-first-resource-finder-with-client-side-search</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Arabic ]]></category><dc:creator><![CDATA[Mahmoud Abdelnaby]]></dc:creator><pubDate>Thu, 12 Nov 2026 09:01:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6af578edffb235a509d81b0a/7025df84-38ed-438b-ac52-9869f051f743.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A search box that accepts a full sentence can look like an AI feature even when it is not. That distinction matters. In this project, the finder runs in the browser, searches a curated index, and does not send the query to a server or language model. Its job is narrower: help someone move from a marketing problem to a useful next resource.</p>
<h2>The navigation problem</h2>
<p>A library organized only by content type asks readers to know what they need before they arrive: a calculator, a playbook, a framework, or a skill guide. Many people start somewhere less tidy: “Customers click WhatsApp, but orders are not coming in,” or “My Arabic ads sound translated.”</p>
<p>The resource finder starts from those situations. Each problem area connects a short diagnosis to a small set of tools, practical guides, and skill areas. The current page has 12 starting points, including lead quality, checkout loss, campaign measurement, Arabic localization, search visibility, and GCC market entry.</p>
<h2>Why keep the first version static?</h2>
<p>The page already has a bounded catalogue. It does not need to generate answers or invent recommendations; it needs to find the relevant entries that were reviewed and mapped to each problem. A local search keeps the interaction simple and avoids sending the reader’s wording to an external model.</p>
<p>That choice also defines the feature honestly: it is client-side keyword matching, not semantic search. It can be quick and useful without pretending to understand every sentence.</p>
<h2>1. Make the resource card the unit of discovery</h2>
<p>The page groups each scenario into a card. A card includes the problem statement, a short next-step explanation, and links to resources that do different jobs. For example, a profitability question can point to a calculation tool, a reconciliation guide, and an analytics skill area.</p>
<p>This is more useful than returning a flat list of unrelated links: the user sees why a resource is relevant and can choose the level of help they need.</p>
<h2>2. Put searchable aliases beside the content</h2>
<p>Each card carries a compact search index alongside its visible copy. The index includes an intent category and alternate English and Arabic phrasings. This keeps the search catalogue close to the content it represents, so a new problem card can be reviewed with its own aliases and destinations.</p>
<p>The visible page is the source of truth for the recommendations. Search filters those reviewed cards; it does not create new advice.</p>
<h2>3. Normalize Arabic and English before matching</h2>
<p>Before comparison, it calls JavaScript’s <code>toLocaleLowerCase()</code> without an explicit locale, applies Unicode normalization, removes the Arabic marks in U+064B–U+065F and U+0670, and maps أ/إ/آ to ا, ى to ي, and ؤ/ئ to ء. It then replaces punctuation with spaces. This reduces simple spelling and formatting mismatches without claiming full Arabic language understanding.</p>
<p>A simplified excerpt of the normalization step looks like this:</p>
<pre><code class="language-js">function normalize(value) {
  return (value || "")
    .toLocaleLowerCase()
    .normalize("NFKD")
    .replace(/[\u064b-\u065f\u0670]/g, "")
    .replace(/[أإآ]/g, "ا")
    .replace(/ى/g, "ي")
    .replace(/[ؤئ]/g, "ء")
    .replace(/[^\p{L}\p{N}]+/gu, " ")
    .trim();
}
</code></pre>
<p>Normalization is a practical compatibility layer, not translation. The index still needs human-written phrases that reflect how people actually describe a problem in each language.</p>
<h2>4. Filter locally, and be clear about the limit</h2>
<p>The search splits the normalized query into terms and checks those terms against each card’s index. In the current implementation, a card matches when <strong>any</strong> query term appears. That makes the interaction forgiving, but it can also return broad matches for a long sentence. It does not rank by relevance, infer intent, or understand synonyms that were not added to the index.</p>
<p>When there is no match, the page says so and offers other library routes. That is a useful fallback: it gives the reader another path instead of presenting an empty search as a technical failure.</p>
<h2>What I would test before adding complexity</h2>
<p>Try short queries and full sentences in both languages: “low quality leads,” “clicks but no orders,” “إعلاناتي العربية مترجمة,” and “بصرف على الإعلانات ومش عارف الأرباح.” Check that each result points to the right kind of resource and that a nonsense query reaches the no-match state.</p>
<p>Then review the misses. If readers repeatedly use a phrase that is absent from the index, add that phrase as an alias. If common queries return too many cards, consider a measured change such as phrase-first matching or weighted ranking. Do not add an AI model just because the input accepts natural language; first establish that the simpler method is failing in a way that matters.</p>
<p>This implementation is a small static-site pattern, not a search benchmark or a claim that the feature improves conversion. Its value is that the behavior is inspectable: curated problem cards, explicit destinations, local matching, and a clear fallback.</p>
<h2>Try it and inspect the source</h2>
<ul>
<li><a href="https://mahmoudabdelnaby1.github.io/resources/">Open the problem-based resource finder</a></li>
<li><a href="https://github.com/mahmoudabdelnaby1/mahmoudabdelnaby1.github.io/blob/main/assets/resources.js">Read the search implementation</a></li>
</ul>
<p>The finder is part of a larger portfolio of marketing tools and guides, but this article focuses on one engineering decision: make discovery useful before making it more complex.</p>
]]></content:encoded></item></channel></rss>