منبع حقیقت، محتوا، انتشار و رسانه · فصل ۲ — Page/Version/Block، Forms، SEO و Rollback · 157
Static Locale Routing با Astro
محتوا یا media تولید میکند اما provenance، rights، version، approval و release boundary را یک سیستم واحد نمیبیند. موضوع جاری: «Static Locale Routing با Astro». میتواند «Static Locale Routing با Astro» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
خلاصهٔ درس
محتوا یا media تولید میکند اما provenance، rights، version، approval و release boundary را یک سیستم واحد نمیبیند. موضوع جاری: «Static Locale Routing با Astro».
میتواند «Static Locale Routing با Astro» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
خروجی این درس
میتواند «Static Locale Routing با Astro» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
پیشنیازها
1. URL ساختهشده را با محتوای مجاز یکی نگیر
فرض کن سایت استاتیک شما سه locale به نامهای fa، en و de دارد و fa زبان پیشفرض است. Astro میتواند مسیر /de/about/ را بشناسد یا برای آن fallback داشته باشد؛ اما این رفتار routing ثابت نمیکند که نسخه آلمانی محتوای about واقعاً موجود، به release فعلی bind و برای انتشار مجاز است. در این درس سه چیز را جدا نگه میداریم: وجود route، رفتار navigation/fallback و publication eligibility. اگر این سه در یک Boolean ادغام شوند، سایت ممکن است URL سالم تحویل دهد ولی محتوای اشتباه یا بدون evidence را عمومی کند.
2. مرز مالکیت CON-006
CON-006 فقط قرارداد locale routing استاتیک را مالک است: supported localeها، default locale، نسخه policy مسیر، شکل prefix، مسیر deterministic، collision، missing locale و fallback navigation. مدل immutable صفحه و release projection متعلق به CON-007 است؛ فرم و consent متعلق به CON-008؛ canonical و redirect hygiene متعلق به CON-009؛ monitoring و rollback متعلق به CON-010. پس این درس نمیگوید «چه صفحهای باید canonical باشد» یا «چه releaseی سالم است»؛ فقط میگوید routing layer چه چیزی را میتواند با evidence خودش ثابت کند.
3. supported_locale و default_locale را versioned config بدان
در Astro، پیکربندی i18n فهرست locales و یک defaultLocale دارد. default locale باید عضوی از localeهای پشتیبانیشده باشد. برای ممیزی، این دو را صرفاً از حافظه build یا UI نخوان؛ آنها را در route policy version ثبت کن. مثلاً RPOL-12 میتواند بگوید locales=[fa,en,de] و default=fa. هر row از matrix باید به همین policy version اشاره کند تا بعداً معلوم باشد path بر اساس کدام قرارداد تولید شده است.
4. prefixDefaultLocale شکل URL را عوض میکند
اگر prefixDefaultLocale=false باشد، صفحه about در locale پیشفرض fa میتواند /about/ باشد و localeهای دیگر مثل /en/about/ prefix بگیرند. اگر policy به true تغییر کند، همان محتوای فارسی باید از نظر route contract به /fa/about/ منتقل شود. محتوای صفحه ممکن است هیچ تغییری نکرده باشد، ولی route set تغییر کرده است. بنابراین path قدیمی را فقط بهخاطر یکسان بودن content ID معتبر فرض نکن.
5. file-based routing و getStaticPaths فقط route generation هستند
Astro از ساختار src/pages/ route میسازد و در static output، dynamic routeها میتوانند با getStaticPaths() در build time materialize شوند. این قابلیت درباره «چه URLی ساخته میشود» حرف میزند، نه درباره «آیا محتوای locale از نظر سیستم انتشار ما معتبر است». MAKNOW باید نتیجه framework را با content_binding_ref و release_manifest_ref مستقل intersect کند.
6. Locale Route Matrix را authority عملیاتی کن
برای هر (content_id, content_version, locale) یک row بساز. حداقل این فیلدها را نگه دار: route_policy_version، default_locale، prefix_default_locale، routing_mode، generated_path، route_exists، fallback_locale، fallback_type، content_binding_status، release_manifest_ref، release_eligible، locale_collision، decision و reason. Matrix باید به اندازهای کامل باشد که reviewer بدون دیدن config یا کد پنهان بتواند تصمیم را بازسازی کند.
7. مسیر را deterministic محاسبه کن
در fixture این درس، rule ساده است: اگر locale پیشفرض باشد و prefix policy خاموش باشد، path برابر /{slug}/ است؛ در غیر این صورت /{locale}/{slug}/. این rule یک مدل آموزشی محدود است، نه ادعای جامع درباره همه پروژههای Astro. نکته مهم این است که generated_path باید از inputهای versioned محاسبه شود و با policy اعلامشده سازگار باشد. path دستی که با policy نمیخواند باید BLOCK_ROUTE_POLICY شود.
8. browser_preference فقط signal است
Accept-Language یا helper تشخیص زبان میتواند برای navigation مفید باشد، اما authority محتوایی نیست. اگر browser کاربر en را ترجیح دهد ولی row مورد بررسی fa باشد، این preference نباید content binding فارسی را عوض کند یا content ID را silently repoint کند. preference میتواند پیشنهاد redirect بدهد، نه اینکه missing evidence را بسازد.
9. fallback را از publication جدا کن
Fallback یعنی کاربر برای تجربه navigation به محتوای locale دیگری هدایت شود. اگر de موجود نیست و fallback به en فعال است، میتوان تصمیم FALLBACK_NAVIGATION_ONLY داشت؛ اما row آلمانی همچنان publication_eligible=false میماند. این distinction مهم است: fallback یک رفتار دسترسی است، نه تولید ترجمه، approval یا release binding برای locale مفقود.
10. missing locale را typed نگه دار
وقتی localized content وجود ندارد، بهجای ساختن یک success مبهم، state دقیق ثبت کن: LOCALE_CONTENT_MISSING، CONTENT_BINDING_UNKNOWN یا FALLBACK_TARGET_UNKNOWN. اگر fallback معتبر هم نداریم، تصمیم باید fail-closed باشد. این typed state به تیم بعدی میگوید چه چیزی باید تولید، bind یا دوباره بررسی شود.
11. route collision یک خطای مستقل است
دو record مختلف نباید به یک public path بدون policy صریح برسند. collision میتواند از slug یکسان، aliasهای locale یا تغییر prefix policy ایجاد شود. حتی اگر هر دو content record معتبر باشند، collision باید routing decision را block کند تا انتخاب مقصد به رفتار تصادفی build یا ترتیب فایلها واگذار نشود.
12. release binding را جدا از route_exists بسنج
route_exists=true فقط میگوید build یا routing layer مسیر را materialize کرده است. برای PUBLISH_ROUTE_READY باید content binding verified باشد، release manifest دقیق وجود داشته باشد و release_eligible=true باشد. اگر release reference نامشخص، stale یا ineligible است، تصمیم routing باید BLOCK_RELEASE_BINDING شود—even if the HTML route exists.
13. مثال منفی: German URL هست، German content نیست
فرض کن /de/about/ بهدلیل fallback یا route pattern قابل resolve است، اما record آلمانی حذف شده است. اشتباه رایج این است که «پس route سالم است» را معادل «صفحه آلمانی منتشر شده» بگیریم. Matrix درست، route/fallback behavior را ثبت میکند ولی publication را برای de رد میکند. اگر fallback انگلیسی خودش release-eligible باشد، کاربر میتواند به انگلیسی هدایت شود؛ این هیچ evidence تازهای برای German locale تولید نمیکند.
14. Transfer: prefix policy را عوض کن و یک ترجمه را حذف کن
اکنون prefixDefaultLocale را از false به true تغییر بده. برای fa/about مسیر باید از /about/ به /fa/about/ تغییر کند. همزمان German content را حذف کن ولی content ID اصلی را نگه دار. Matrix جدید باید دو تغییر مستقل را نشان دهد: path-set change ناشی از policy و missing-locale state ناشی از content evidence. تصمیم قبلی را copy نکن؛ همه rowها را از evidence جدید بازسازی کن.
15. خروجی قابل ممیزی
خروجی نهایی این درس Locale Route Contract & Static Route Matrix v1 است. reviewer باید بتواند برای هر row پاسخ دهد: locale پشتیبانی میشود؟ default چیست؟ policy version کدام است؟ path چگونه تولید شده؟ content binding verified است؟ release reference چیست؟ fallback چه میکند؟ collision وجود دارد؟ و publication eligibility دقیقاً بر چه evidenceای بنا شده است؟ اگر پاسخ یکی از اینها UNKNOWN است، همان UNKNOWN باید در artifact باقی بماند؛ framework helper یا redirect نباید آن را به success تبدیل کند.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
Q1 concept
Q2 diagnosis
Q3 diagnosis
Q4 transfer
ملاکهای ارزیابی (rubric)
- Route contract: supported locales, default locale, policy version and prefix behavior are explicit.
- Deterministic path: generated paths match versioned route policy.
- Evidence boundary: route existence, fallback navigation and publication eligibility stay separate.
- Negative states: missing/unknown/collision/release-blocked states remain typed.
- Transfer: changed prefix policy and missing translation are rebuilt from new evidence.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
Inspect the eight synthetic locale-routing fixtures and implement evaluate(case) in starter.py. Keep route generation, browser preference/fallback navigation, and localized publication eligibility separate. Recompute paths from the declared policy and preserve missing/blocked states. Final expected labels are intentionally not provided.