feat: add Arabic-first i18n with locale switcher#21
feat: add Arabic-first i18n with locale switcher#21abdelrhmanehab10 wants to merge 4 commits intoBLEU-IO:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces an Arabic-first internationalization setup for the Eleventy site, with / serving Arabic and /en/ serving English, plus shared translated UI and RTL support.
Changes:
- Added i18next-based build-time i18n loading + translation parity validation, with per-locale page generation via Eleventy pagination.
- Updated templates (home, blogs, contributing, layout/components) to use translation keys and locale-aware URLs.
- Added RTL/LTR styling adjustments, a navbar language switcher, and build verification scripts to ensure localized outputs exist.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
.eleventy.js |
Initializes i18n globals (t, localeUrl) and validates dictionaries during build. |
src/i18n/index.js |
Loads translation resources, validates parity, and localizes URLs. |
src/_data/locales.js |
Defines supported locales and routing prefixes. |
src/index.njk + src/index.11tydata.js |
Converts home page to localized metadata + localized routing. |
src/blogs.njk + src/blogs.11tydata.js |
Converts blogs listing page to localized metadata + localized routing. |
content/blogs/blogs.11tydata.js |
Generates localized blog post routes for both locales. |
src/contributing.njk + src/contributing.11tydata.js |
Localizes the contributing page and routes. |
src/_includes/layouts/base.njk |
Adds locale-aware <html lang/dir>, localized meta, and hreflang alternates. |
src/_includes/layouts/blog.njk |
Localizes blog UI strings and improves RTL/LTR handling for metadata/tags. |
src/_includes/components/* |
Localizes header/footer/widget/giscus and adds a language switcher. |
src/assets/css/input.css |
Adds RTL support, bidi handling, and language switcher styling; adds Arabic/Latin fonts. |
src/assets/js/main.js |
Adds language switcher navigation + stores locale; keeps tag filtering enhancement. |
scripts/check-i18n.js + scripts/verify-localized-build.js |
Adds translation validation and localized output verification during build. |
package.json + package-lock.json |
Adds i18next dependency and build steps for i18n validation/verification. |
src/_data/site.json |
Removes hardcoded tagline/description in favor of translated equivalents. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| permalink: /blogs/ | ||
| --- | ||
|
|
||
| {% set posts = collections.blogs %} |
There was a problem hiding this comment.
Same issue as the home page: iterating over collections.blogs will likely render each blog post twice (Arabic + English generated pages). Filter the collection by post.data.locale === locale (or create per-locale collections) so /blogs/ and /en/blogs/ show a single set of posts.
| {% set posts = collections.blogs %} | |
| {% set posts = (collections.blogs or []) | selectattr("data.locale", "equalto", locale) | list %} |
There was a problem hiding this comment.
I validated this one as well, and it does not reproduce with the current Eleventy setup.
collections.blogs is built from the source markdown files in .eleventy.js, so it is not currently doubled by localized output generation. I verified the generated listing pages and both of these render a single set of posts:
_site/blogs/index.html→ 3 cards_site/en/blogs/index.html→ 3 cards
So /blogs/ and /en/blogs/ are not rendering duplicate posts in the current implementation. Because of that, I’m not applying the suggested locale filter here.
| <a | ||
| href="https://github.com/{{ site.repo }}/edit/main/content/blogs/{{ page.fileSlug }}.md" | ||
| <a | ||
| href="https://github.com/{{ site.repo }}/edit/master/content/blogs/{{ page.fileSlug }}.md" |
There was a problem hiding this comment.
The “Edit on GitHub” link switched from /edit/main/... to /edit/master/.... If the repository default branch is main (as previously assumed), this link will 404. Consider reverting to main or making the branch configurable (e.g., site.defaultBranch).
| href="https://github.com/{{ site.repo }}/edit/master/content/blogs/{{ page.fileSlug }}.md" | |
| href="https://github.com/{{ site.repo }}/edit/main/content/blogs/{{ page.fileSlug }}.md" |
There was a problem hiding this comment.
I validated this against the local git metadata, and master is the current default branch in this repository context.
Local refs show:
remotes/origin/HEAD -> origin/masterremotes/origin/masterremotes/upstream/master
So switching the edit link to master was intentional and matches the branch this repo is currently using. Because of that, I’m not reverting this to main.
fahdfady
left a comment
There was a problem hiding this comment.
Really nice work overall. And the font is really cool!
I just had some comments on the translation itself. We can work on this together and get this merged.
src/i18n/ar/home.json
Outdated
| "title": "انضم إلى ديسكورد الخاص بنا", | ||
| "members": "عضو", | ||
| "online": "متصل الآن", | ||
| "joinServer": "انضم إلى الخادم" |
There was a problem hiding this comment.
كلمة "سيرفر" منطقية أكتر من "الخادم" .. على الأقل في السياق الحالي .. كلمة خادم لا تستخدم إطلاقا على حد احتكاكي.
| "description": "منصة BLEU المجتمعية لمشاركة المعرفة، والتعلّم، وبناء مستقبل التقنية معًا." | ||
| }, | ||
| "hero": { | ||
| "title": "نبني ونتعلّم ونستكشف ونتّحد", |
There was a problem hiding this comment.
ترجمة ممتازة
حقيقي ممكن اكون أمضيت بعض الوقت في محاولة لترجمة BLEU
هل في إمكانية نضيف بخط صغير تحتها الجملة الأصلية بالإنجليزية؟
Building Learning Exploring Uniting
لو في إمكانية تمام. لو شعرت إن التعديل ده خارج حدود الـ PR
ممكن نتخطاه ونركز في الباقي
| "description": "انسخ المستودع وأضف ملف Markdown الخاص بك داخل content/blogs/." | ||
| }, | ||
| "pr": { | ||
| "title": "افتح طلب سحب", |
There was a problem hiding this comment.
كلمة "طلب سحب" غريبة جدا بالنسبة لي. لا أستطيع في التفكير لمقابل ليها بالعربية لكن أنا مستنكر جدا الجملة دي. محتاجين نفكر لها في بديل. عندك فكرة تانية؟
There was a problem hiding this comment.
ممكن نسيب PR بالأنجليزي تبقي افتح PR اي رأيك؟
| "description": "أرسل طلب السحب الخاص بك. سيقوم المجتمع بمراجعته وتقديم الملاحظات." | ||
| }, | ||
| "publish": { | ||
| "title": "الدمج = النشر", |
There was a problem hiding this comment.
وكذلك مع كلمة دمج. مع إنها ترجمة جيدة لـ Merge
ولكنها في وجهة نظري ترجمة حرفية .. ممكن نشتغل عليها أكتر في ظني ونطلع بحاجة دقيقة أكتر
There was a problem hiding this comment.
ممكن نبدلها بالنشر بما انها بتنشر المقالة؟
src/i18n/ar/common.json
Outdated
| @@ -0,0 +1,29 @@ | |||
| { | |||
| "site": { | |||
| "communityLabel": "المجتمع", | |||
There was a problem hiding this comment.
من المفترض تتتكتب "مجتمع" بدون ألف ولام التعريف
لأنها في السياق الكامل "مجتمع بلو" وليس "المجتمع بلو"
src/i18n/ar/blogs.json
Outdated
| "label": "التصفية حسب الوسم:" | ||
| }, | ||
| "empty": { | ||
| "title": "لا توجد مقالات منشورة بعد.", |
| "submitViaPr": "أرسل مقالة عبر طلب سحب" | ||
| }, | ||
| "filter": { | ||
| "label": "التصفية حسب الوسم:" |
There was a problem hiding this comment.
محتاجين نشتغل برضو على كلمة "الوسم"
src/i18n/en/contributing.json
Outdated
| "guideline3": "Include code examples where helpful", | ||
| "guideline4": "Use clear, descriptive titles", | ||
| "guideline5": "Add a thumbnail image if possible (16:9 ratio recommended)", | ||
| "guideline6": "Images should be added to /src/assets/images/", |
There was a problem hiding this comment.
code block for /src/assets/images/
src/i18n/ar/contributing.json
Outdated
| "guideline3": "أضف أمثلة برمجية عند الحاجة", | ||
| "guideline4": "استخدم عناوين واضحة ومعبرة", | ||
| "guideline5": "أضف صورة مصغرة إن أمكن (يُفضّل نسبة 16:9)", | ||
| "guideline6": "أضف الصور داخل /src/assets/images/", |
There was a problem hiding this comment.
code block for /src/assets/images/
Summary
Closes #17
This PR adds an Arabic-first internationalization flow for the BLEU website.
What changed
/for Arabic/en/for EnglishTechnical notes
i18nextwith split JSON translation filesHow to test
npm installnpm run buildnpm run dev//en//blogs//en/blogs/Scope notes