diff --git a/.cursor/plans/locale_fallback_and_env_override_bb753d7b.plan.md b/.cursor/plans/locale_fallback_and_env_override_bb753d7b.plan.md new file mode 100644 index 0000000..9eaba01 --- /dev/null +++ b/.cursor/plans/locale_fallback_and_env_override_bb753d7b.plan.md @@ -0,0 +1,80 @@ +--- +name: Locale fallback and env override +overview: اضافه کردن یک زنجیرهٔ fallback برای تشخیص زبان (اول از تنظیمات داکیوسورس، بعد از document.lang، بعد از themeConfig یا env) و اختیاری کردن override از طریق env تا وقتی context در دسترس نیست هم بتوان زبان را فهمید یا با env عوض کرد؛ ترجمه‌ها همچنان از Docusaurus (translate) باشند و در صورت کار کردن i18n همه‌جا چندزبانگی بماند. +todos: [] +isProject: false +--- + +# پلن: تشخیص زبان با Fallback و امکان Override از env + +## مشکل + +- لاگ تم در کنسول دیده نمی‌شود؛ احتمالاً به‌خاطر Hydration یا زمان لود چانک، کامپوننت تم در شرایطی اجرا می‌شود که `useDocusaurusContext()` در دسترس نیست یا درخت React خراب است. +- کاربر می‌خواهد اگر از تنظیمات داکیوسورس نشد خواند، بتوان از **env** (مثلاً `window.env`) زبان را عوض کرد. +- ترجیح: اگر بشود از تنظیمات داکیوسورس بخوانیم و با عوض کردن زبان توسط کاربر، همهٔ صفحه (از جمله جستجو) چندزبانگی باشد، بهتر است. + +## راه‌حل پیشنهادی + +یک **منبع واحد برای locale** با اولویت‌بندی مشخص، و استفاده از آن در تم جستجو؛ ترجمه‌های UI همچنان از `translate()` داکیوسورس (و در نتیجه از `i18n//theme.json`) باشند. + +### ۱) زنجیرهٔ تشخیص locale (اولویت از بالا به پایین) + +| اولویت | منبع | نحوهٔ دسترسی | +|--------|------|---------------| +| ۱ | Docusaurus context | `useDocusaurusContext().i18n?.currentLocale` | +| ۲ | HTML (داکیوسورس روی `` ست می‌کند) | `document.documentElement.lang` (فقط در useEffect / بعد از mount) | +| ۳ | تنظیمات تم (config) | `themeConfig.typesense.localeOverride` (اختیاری) | +| ۴ | env / تزریق از سایت | مثلاً `window.__SEARCH_THEME_LOCALE__` یا `window.env?.LOCALE` (قرارداد با پروژهٔ مصرف‌کننده) | +| ۵ | پیش‌فرض | مثلاً `'en'` | + +با این ترتیب: تا وقتی داکیوسورس و context درست کار می‌کنند، همان زبان انتخاب‌شده توسط کاربر در سایت استفاده می‌شود و همه‌جا (از جمله جستجو) چندزبانگی می‌ماند. اگر context در دسترس نبود، از `document.documentElement.lang` استفاده می‌شود (همان زبانی که داکیوسورس روی صفحه گذاشته). در نهایت کاربر می‌تواند با **config** یا **env** زبان جستجو را override کند. + +### ۲) پیاده‌سازی در تم + +- **هوک جدید `useCurrentLocale()`** +در تم (مثلاً `src/hooks/useCurrentLocale.ts`) یک هوک که: +- داخلش از `useDocusaurusContext()` استفاده کند (اگر در دسترس بود، همان را برگرداند). +- در `useEffect` مقدار `document.documentElement.lang` را بخواند و در state ذخیره کند. +- خروجی نهایی: یک مقدار `locale: string` که از این ترتیب به‌دست آمده: context → document.lang (بعد از mount) → `themeConfig.typesense.localeOverride` → `window.__SEARCH_THEME_LOCALE__` یا `window.env?.LOCALE` → `'en'`. +- برای جلوگیری از hydration mismatch، خواندن `document` و `window` فقط داخل `useEffect` یا بعد از یک چک `typeof window !== 'undefined'` در کدی که فقط روی کلاینت اجرا می‌شود. + +- **استفاده در SearchBar و SearchPage** +هر جایی که الان فقط از `useDocusaurusContext()` برای `currentLocale` استفاده می‌شود، به‌جای آن از `useCurrentLocale()` استفاده شود تا هم با داکیوسورس هماهنگ باشد هم در صورت نبود context از document/config/env استفاده کند. + +- **یک خط لاگ شفاف** +داخل همان هوک (یا در یک `useEffect` در SearchBar که فقط یک بار اجرا شود) یک **لاگ واحد** چاپ شود که مشخص کند: +- منبع فعلی locale چیست: `context` | `document` | `config` | `window` | `default` +- مقدار نهایی: مثلاً `fa` یا `en`. +این لاگ به کاربر کمک می‌کند بفهمد تم الان از کجا زبان را می‌گیرد و آیا با env درست عوض شده یا نه. + +### ۳) تنظیمات تم و env + +- **اختیاری در themeConfig** +در [src/theme-search-typesense.d.ts](src/theme-search-typesense.d.ts) و [src/validateThemeConfig.ts](src/validateThemeConfig.ts) فیلد اختیاری `localeOverride?: string` به `themeConfig.typesense` اضافه شود تا در `docusaurus.config.js` بتوان زبان جستجو را ثابت کرد. + +- **قرارداد env** +در مستندات (مثلاً README یا یک بخش کوچک در docs) توضیح داده شود که اگر پروژهٔ مصرف‌کننده بخواهد از «env» زبان را به تم بدهد، می‌تواند قبل از لود تم یکی از این‌ها را ست کند: +- `window.__SEARCH_THEME_LOCALE__ = 'fa'` +- یا اگر قبلاً `window.env` دارند: `window.env.LOCALE = 'fa'` +و تم در fallback از این مقدار استفاده می‌کند. + +### ۴) ترجمه‌ها (بدون تغییر در منبع اصلی) + +- **هیچ جایگزینی برای `translate()` یا فایل‌های i18n انجام نشود.** +ترجمه‌های مودال و صفحهٔ جستجو همچنان از `translate()` داکیوسورس و فایل‌های `i18n//theme.json` (در سایت مصرف‌کننده یا در تم) استفاده می‌کنند. +- مقدار `locale` از `useCurrentLocale()` برای مواردی استفاده می‌شود که نیاز به «شناسایی زبان» داریم (مثلاً فیلتر جستجو، لاگ، یا ارسال به سرویس خارجی)، نه برای جایگزینی خود ترجمه‌ها. با این کار وقتی داکیوسورس درست کار کند و کاربر زبان را عوض کند، همان locale از context می‌آید و همهٔ صفحه (از جمله جستجو) چندزبانگی می‌ماند. + +### ۵) خلاصهٔ فایل‌ها + +- **جدید:** `src/hooks/useCurrentLocale.ts` — هوک با زنجیرهٔ fallback بالا + یک خط لاگ مشخص برای منبع و مقدار locale. +- **تغییر:** [src/theme/SearchBar/index.tsx](src/theme/SearchBar/index.tsx) — استفاده از `useCurrentLocale()` به‌جای فقط context؛ حذف یا ساده‌سازی لاگ‌های قبلی و نگه‌داشتن همان یک لاگ شفاف در هوک. +- **تغییر:** [src/theme/SearchPage/index.tsx](src/theme/SearchPage/index.tsx) — هر جایی که `currentLocale` از context استفاده می‌شود، از `useCurrentLocale()` استفاده شود. +- **تغییر:** [src/index.ts](src/index.ts) — در صورت نیاز برای مسیرهای سرور/پلاگین؛ اگر فقط کلاینت نیاز دارد، ممکن است تغییری لازم نباشد. +- **تغییر:** [src/theme-search-typesense.d.ts](src/theme-search-typesense.d.ts) و [src/validateThemeConfig.ts](src/validateThemeConfig.ts) — اضافه کردن `localeOverride?: string`. +- **مستندات:** یک پاراگراف کوتاه در README یا `docs/` برای توضیح `localeOverride` و قرارداد `window.__SEARCH_THEME_LOCALE__` / `window.env.LOCALE`. + +## نتیجه + +- اگر داکیوسورس و context درست کار کنند: زبان از همان تنظیمات داکیوسورس و با تغییر زبان توسط کاربر، همهٔ صفحه (از جمله جستجو) چندزبانگی است. +- اگر به‌هر دلیل context در دسترس نبود: اول از `document.documentElement.lang`، بعد از config، بعد از env استفاده می‌شود و کاربر می‌تواند با env (یا config) زبان جستجو را عوض کند. +- یک خط لاگ مشخص می‌گوید منبع فعلی و مقدار locale چیست تا بتوان تشخیص داد آیا از env درست خوانده می‌شود یا نه. \ No newline at end of file diff --git a/.cursor/plans/locale_logging_and_i18n_test_c8e52932.plan.md b/.cursor/plans/locale_logging_and_i18n_test_c8e52932.plan.md new file mode 100644 index 0000000..1db4b1b --- /dev/null +++ b/.cursor/plans/locale_logging_and_i18n_test_c8e52932.plan.md @@ -0,0 +1,65 @@ +--- +name: Locale logging and i18n test +overview: اضافه کردن لاگ کنسول در تم جستجو برای خواندن و نمایش مقدار زبان جاری (و سایر مقادیر i18n) از context داکیوسورس، به‌همراه یک سناریو تست ساده برای اطمینان از دیده شدن مقدار درست قبل از وصل کردن مجدد به i18n. +todos: [] +isProject: false +--- + +# پلن: لاگ زبان جاری از داکیوسورس و سناریو تست + +## هدف + +قبل از وصل کردن مجدد تم به ماژول i18n و پشتیبانی چندزبان، مطمئن شویم که **زبان جاری را در کامپوننت تم از داکیوسورس می‌خوانیم**. برای همین یک نسخه فقط با **لاگ کنسول** ساخته می‌شود که مقادیر i18n را از context داکیوسورس بخواند و در کنسول مرورگر چاپ کند؛ سپس یک سناریو تست برای تأیید مقدار درست تعریف می‌شود. + +## ۱. مقادیری که در تم قابل خواندن هستند + +تم در **مرورگر** اجرا می‌شود و به `useDocusaurusContext()` دسترسی دارد. این تابع شیء‌ای برمی‌گرداند که معمولاً شامل موارد زیر است: + +- **`i18n.currentLocale`** — زبان فعلی (مثلاً `"fa"` یا `"en"`) +- **`i18n.locales`** — آرایهٔ زبان‌های تعریف‌شده در تنظیمات +- **`i18n.defaultLocale`** — زبان پیش‌فرض + +تنظیمات `i18n` در `docusaurus.config` (مثل `defaultLocale: "fa"`, `locales: ["fa"]`) در زمان بیلد/سرور اعمال می‌شوند و در runtime همان‌طور که داکیوسورس به تم می‌دهد، در این فیلدها در دسترس هستند. ما فقط همان چیزی را که تم از context می‌گیرد لاگ می‌کنیم. + +## ۲. محل اضافه کردن لاگ + +به‌دلیل اینکه: + +- **SearchBar** (کامپوننت دکمه و مودال جستجو) در هر صفحه لود می‌شود و از `useDocusaurusContext()` استفاده می‌کند، +- و بعداً ترجمه‌های مودال باید بر اساس همین locale انتخاب شوند، + +لاگ در **کامپوننت DocSearch داخل SearchBar** اضافه شود تا هر بار که این بخش رندر می‌شود (یعنی کاربر در سایتی با زبان فعلی است)، یک بار در کنسول مقادیر i18n چاپ شوند و با تغییر زبان (در صورت وجود localeDropdown) دوباره لاگ به‌روز دیده شود. + +فایل: [src/theme/SearchBar/index.tsx](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\src\theme\SearchBar\index.tsx) + +- در تابع `DocSearch` به‌جای فقط `const {siteMetadata} = useDocusaurusContext();` کل context (یا حداقل `siteConfig` و `i18n`) را بگیر. +- داخل یک `useEffect` با وابستگی به `currentLocale` (یا کل `i18n`) یک بار در کنسول لاگ بزن، مثلاً: +- `currentLocale` +- `locales` +- `defaultLocale` +- در صورت تمایل هر فیلد دیگری از `i18n` که در context هست (تا بعداً برای i18n از همان‌ها استفاده کنیم). + +با این کار وقتی کاربر صفحه را باز کند یا زبان را عوض کند، در کنسول مرورگر دقیقاً می‌بینیم تم چه مقداری برای زبان جاری از داکیوسورس دریافت کرده است. + +## ۳. سناریو تست (قبل از هر تغییر ترجمه) + +1. **اجرای سایت** (مثلاً kasra-docs با `locales: ["fa"] `و `defaultLocale: "fa"`). +2. **باز کردن یک صفحه** که نوار جستجو (SearchBar) روی آن رندر می‌شود. +3. **باز کردن DevTools و تب Console**. +4. **بررسی لاگ:** باید یک لاگ با پیشوند مشخص (مثلاً `[docusaurus-theme-search-typesense]`) ببینید که مقدار `currentLocale` (و در صورت وجود `locales` و `defaultLocale`) را نشان می‌دهد؛ برای تنظیم فعلی انتظار می‌رود مثلاً `currentLocale: "fa"` باشد. +5. **(اختیاری)** اگر در config زبان دوم (مثلاً `en`) به `locales` اضافه شده و localeDropdown دارید، زبان را به انگلیسی تغییر دهید و دوباره همان صفحه/جستجو را باز کنید؛ لاگ باید این بار `currentLocale: "en"` (یا معادل) را نشان دهد. + +اگر در هر دو حالت مقدار لاگ‌شده با زبان انتخاب‌شده در سایت یکی بود، سناریو تست passed است و می‌توان با اطمینان مرحلهٔ بعد (وصل کردن ترجمه‌های مودال و صفحهٔ جستجو به i18n بر اساس همین `currentLocale`) را انجام داد. + +## ۴. پیاده‌سازی پیشنهادی (خلاصه) + +- در [src/theme/SearchBar/index.tsx](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\src\theme\SearchBar\index.tsx): +- در `DocSearch` از `useDocusaurusContext()` مقدار `i18n` را بگیر (و در صورت نیاز کل context). +- با `useEffect` و وابستگی به `i18n.currentLocale` (یا `i18n`) یک بار لاگ کنسول با پیشوند مشخص بنویس و مقادیر `currentLocale`, `locales`, `defaultLocale` را چاپ کن. +- هیچ تغییر دیگری در منطق ترجمه یا i18n در این مرحله لازم نیست؛ فقط لاگ برای اطمینان از «دیده شدن مقدار زبان در کامپوننت خودمان» است. + +## ۵. مرحلهٔ بعد (خارج از این پلن) + +بعد از تأیید سناریو تست و اطمینان از مقدار زبان در کنسول، در یک پلن جدا می‌توان: + +- ترجمه‌های مودال و صفحهٔ جستجو را دوباره به i18n وصل کرد تا بر اساس `currentLocale` از فایل‌های `i18n//theme.json` استفاده شود و همهٔ زبان‌های تعریف‌شده در داکیوسورس پشتیبانی شوند. \ No newline at end of file diff --git a/.cursor/plans/modal_translations_and_release_cache_15b7a090.plan.md b/.cursor/plans/modal_translations_and_release_cache_15b7a090.plan.md new file mode 100644 index 0000000..e7bec6d --- /dev/null +++ b/.cursor/plans/modal_translations_and_release_cache_15b7a090.plan.md @@ -0,0 +1,103 @@ +--- +name: Modal translations and release cache +overview: علت انگلیسی ماندن متن‌های مودال، استفادهٔ پروژه از فایل‌های کامپایل‌شدهٔ قدیمی در پوشه lib است که هنوز پیام‌های پیش‌فرض انگلیسی دارند. علت به‌روز نشدن بعد از npm i هم معمولاً انتشار بدون بیلد تازه و کشِ بیلد در پروژهٔ مصرف‌کننده است. +todos: [] +isProject: false +--- + +# پلن: رفع ترجمه‌نشدن مودال و به‌روز نشدن بعد از ریلیز + +## ۱. چرا بعضی عبارت‌ها ترجمه می‌شوند و بعضی (در مودال) نه؟ + +### جریان دادهٔ ترجمه + +```mermaid +flowchart LR + subgraph searchPage [صفحه جستجو / SearchPage] + A[translate در هر رندر] + A --> B[مقدار از theme.json یا پیش‌فرض] + end + subgraph searchBar [SearchBar] + C[ResultsFooter با Translate] + C --> D[رندر در درخت React با locale فعلی] + E[translations از SearchTranslations] + E --> F[DocSearchModal] + end + subgraph modal [مودال] + F --> G[placeholder و footer و startScreen] + end +``` + +- **چیزهایی که درست هستند** (مثل «نتایج جستجو برای»، «سند پیدا شد»، «عبارت خود را…»، و **«مشاهده همه 1068 نتیجه»**): + - یا مستقیم در کامپوننت با `translate()` / `` صدا زده می‌شوند (هر بار با locale فعلی)، + - یا مثل لینک «مشاهده همه …» داخل **ResultsFooter** با `` رندر می‌شوند و در زمان رندر مقدار درست را می‌گیرند. + +- **چیزهایی که در مودال انگلیسی می‌مانند** (placeholder، to select، to navigate، Recent، Search by و …): + - از آبجکت **از پیش ساخته** `translations` می‌آیند که در [src/theme/SearchTranslations/index.ts](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\src\theme\SearchTranslations\index.ts) یک‌بار در **زمان لود ماژول** با `translate()` پر می‌شوند. + - پروژهٔ مصرف‌کننده (مثلاً kasra-docs) در زمان اجرا از **خروجی کامپایل‌شده** استفاده می‌کند، نه از سورس تم. + +### علت اصلی: ناهماهنگی بین `src` و `lib` + +- در **سورس** ([src/theme/SearchTranslations/index.ts](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\src\theme\SearchTranslations\index.ts)) پیام‌های پیش‌فرض همه **فارسی** هستند (مثل «جستجو در مستندات»، «اخیر»، «برای انتخاب» و …). +- در **خروجی بیلد** ([lib/theme/SearchTranslations/index.js](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\lib\theme\SearchTranslations\index.js)) هنوز پیام‌های پیش‌فرض **انگلیسی** هستند (`'Search'`, `'Recent'`, `'to select'`, `'Search docs'` و …). + +وقتی سایت با این تم بیلد می‌شود، کدی که اجرا می‌شود از داخل **پکیج** است و آن کد همان `lib/theme/SearchTranslations/index.js` است. اگر در آن فایل هنوز `message: 'Recent'` و مشابه باشد، در صورت نبود یا عدم اعمال صحیح theme.json برای این تم، همان پیش‌فرض انگلیسی استفاده می‌شود. در نتیجه **مودال** (که فقط از همین آبجکت `translations` استفاده می‌کند) انگلیسی نشان می‌دهد، در حالی که **صفحهٔ جستجو و ResultsFooter** یا از theme یا از کامپوننت‌هایی با `translate` در زمان رندر مقدار می‌گیرند و درست نمایش داده می‌شوند. + +--- + +## ۲. چرا بعد از ریلیز و `npm i` به‌روز نمی‌شود و باید پوشهٔ بیلد کلین شود؟ + +دو طرف ماجرا هست: + +### الف) طرف پکیج تم (docusaurus-theme-search-typesense) + +- در [package.json](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\package.json) ورودی اصلی پکیج `"main": "lib/index.js"` است؛ یعنی بعد از `npm i` همان چیزی که داخل **lib** پکیج است اجرا می‌شود. +- اگر قبل از `npm publish` دستور **`npm run build`** اجرا نشود، فایل‌های قدیمی داخل `lib` (با همان پیام‌های انگلیسی) در تاربال منتشر می‌شوند. در نتیجه حتی با نصب نسخهٔ جدید، کد اجراشده همان بیلد قدیمی است و ترجمه‌های مودال به‌روز نمی‌شوند. + +### ب) طرف پروژهٔ مصرف‌کننده (مثلاً kasra-docs) + +- Docusaurus و باندلر (مثلاً Webpack) خروجی بیلد و چانک‌ها را کش می‌کنند (مثلاً در `.docusaurus` یا پوشهٔ `build`). بعد از `npm i` ممکن است هنوز از همان چانک‌های قدیمی استفاده شود. +- با **پاک کردن پوشهٔ بیلد و کش** (مثلاً `.docusaurus` و `build`) و بیلد مجدد، همه‌چیز از نو از `node_modules` خوانده می‌شود و نسخهٔ جدید پکیج تم اعمال می‌شود. + +--- + +## ۳. کارهایی که باید انجام شوند + +### ۳.۱ رفع ترجمه‌نشدن مودال (اولویت اصلی) + +- **هدف:** مطمئن شدن که کدی که در runtime اجرا می‌شود (یعنی محتوای `lib`) همان پیش‌فرض‌های فارسی را دارد که در `src` نوشته شده‌اند. +- **اقدام:** در همین ریپوی تم، یک بار **بیلد تم** را اجرا کنید تا از روی سورس فعلی (با همهٔ messageهای فارسی در [src/theme/SearchTranslations/index.ts](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\src\theme\SearchTranslations\index.ts)) فایل‌های `lib` از نو ساخته شوند: + - در روت پکیج تم: `npm run build` (یا `yarn build`). +- **بررسی:** بعد از بیلد، محتوای [lib/theme/SearchTranslations/index.js](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\lib\theme\SearchTranslations\index.js) باید با سورس هماهنگ باشد؛ یعنی همهٔ `message:`ها در `translate(...)` معادل فارسی باشند (مثل «جستجو در مستندات»، «اخیر»، «برای انتخاب»، «فلش بالا» و …)، نه انگلیسی. +- اگر تم را به صورت **لوکال** در kasra-docs تست می‌کنید (مثلاً با `npm link` یا path محلی)، بعد از این بیلد، در kasra-docs یک بار پوشهٔ بیلد/کش را پاک کنید و دوباره بیلد/استارت بگیرید تا مودال با همان پیش‌فرض‌های فارسی نمایش داده شود. + +### ۳.۲ جلوگیری از انتشار بیلد قدیمی (برای ریلیزهای بعدی) + +- **قبل از هر `npm publish`:** + + 1. در روت پکیج تم حتماً `npm run build` اجرا شود. + 2. ترجیحاً در اسکریپت `prepublishOnly` (یا مشابه) این بیلد را قرار دهید تا بدون بیلد تازه نتوان پکیج را publish کرد. + +- مثال در [package.json](e:\saberprojects-eeeee\kasra\docu sauros\docusaurus-theme-search-typesense\package.json): + - اضافه کردن اسکریپتی مثل: `"prepublishOnly": "npm run build"` تا قبل از publish خودکار بیلد گرفته شود. + +### ۳.۳ مستند کردن رفتار برای مصرف‌کننده + +- در README یا بخش «نصب / به‌روزرسانی» ذکر شود: + - بعد از به‌روزرسانی پکیج با `npm i` اگر تغییرات تم (مثل ترجمه‌ها) را نمی‌بینید، یک بار پوشهٔ بیلد و کش را پاک کنید و دوباره بیلد بگیرید (مثلاً حذف `.docusaurus` و `build` و سپس `npm run build` یا `yarn build`). + +--- + +## ۴. جمع‌بندی + +| موضوع | علت | اقدام | + +|--------|------|--------| + +| مودال انگلیسی (placeholder، Recent، to select، …) | اجرای کد از `lib` که هنوز پیش‌فرض‌های انگلیسی دارد؛ سورس تم فارسی است ولی بیلد تم بعد از تغییرات گرفته نشده | یک بار `npm run build` در پکیج تم؛ بعد از آن در پروژهٔ مصرف‌کننده در صورت نیاز پاک کردن کش/بیلد و بیلد مجدد | + +| «مشاهده همه … نتیجه» درست است | این متن از `` داخل ResultsFooter است و در زمان رندر با locale درست مقدار می‌گیرد؛ وابسته به آبجکت از پیش ساختهٔ SearchTranslations نیست | نیازی به تغییر ندارد | + +| بعد از ریلیز با npm i به‌روز نمی‌شود | ۱) انتشار بدون بیلد تازه در پکیج تم ۲) کش بیلد در پروژهٔ مصرف‌کننده | ۱) همیشه قبل از publish بیلد تم ۲) در سایت مصرف‌کننده در صورت نیاز پاک کردن .docusaurus و build و بیلد مجدد | + +اگر بخواهید بعد از تأیید این پلن، قدم‌های اجرایی (دستورهای دقیق و در صورت نیاز تغییر دقیق `package.json`) را هم مرحله‌به‌مرحله بنویسم، بگویید تا در همان راستا انجام دهم. \ No newline at end of file diff --git a/.cursor/plans/mr_summary_for_locale_and_i18n_f381207a.plan.md b/.cursor/plans/mr_summary_for_locale_and_i18n_f381207a.plan.md new file mode 100644 index 0000000..7662954 --- /dev/null +++ b/.cursor/plans/mr_summary_for_locale_and_i18n_f381207a.plan.md @@ -0,0 +1,77 @@ +--- +name: MR summary for locale and i18n +overview: طرح تکمیلی برای توضیح تغییرات تم جستجو، رفع باگ‌های Hydration/i18n و تست‌های انجام‌شده تا مرورگر راحت‌تر مرج را تأیید کند. +todos: [] +isProject: false +--- + +## طرح تکمیلی برای مرج ریکوئست + +### ۱) خلاصهٔ فنی تغییرات + +- **زیرساخت چندزبانگی تم جستجو** +- اضافه شدن هوک `useCurrentLocale` در `[src/hooks/useCurrentLocale.ts]` برای تشخیص زبان با زنجیرهٔ fallback: Docusaurus context → `document.documentElement.lang` → `themeConfig.typesense.localeOverride` → `window.__SEARCH_THEME_LOCALE__` / `window.env.LOCALE` → `'en'`. +- استفاده از این هوک در `SearchBar` و `SearchPage` به‌جای تکیهٔ مستقیم روی `useDocusaurusContext().i18n.currentLocale` تا هم با i18n داکیوسورس هماهنگ باشد هم در شرایط خاص (Hydration، env) رفتار قابل پیش‌بینی داشته باشد. + +- **ترجمهٔ کامل UI جستجو** +- به‌روزرسانی ترجمه‌ها در `SearchBar`، `SearchPage` و `SearchTranslations` برای پوشش: +- دکمهٔ جستجو و placeholder +- تمام متن‌های مودال جستجو (لیست جستجوهای اخیر، خطا، بدون نتیجه، شورتکات‌ها، footer) +- صفحهٔ نتایج جستجو (عناوین، توضیحات، پیام‌های تعداد نتایج). +- اطمینان از اینکه همهٔ کلیدهای `translate()` در `theme.json`‌های مربوطه (مثل `i18n/fa/theme.json` و `i18n/en/theme.json`) وجود دارند و placeholderها از فرم استاندارد `{count}` / `{query}` استفاده می‌کنند. + +- **پشتیبانی از پیکربندی سطح تم و env** +- اضافه شدن `localeOverride?: string` به `themeConfig.typesense` (در `[src/theme-search-typesense.d.ts]` و `[src/validateThemeConfig.ts]`) تا اگر پروژهٔ میزبان خواست، زبان جستجو را مستقل از i18n قفل کند (مثلاً همیشه `fa`). +- تعریف قرارداد env اختیاری (`window.__SEARCH_THEME_LOCALE__` یا `window.env.LOCALE`) برای پروژه‌های میزبان که runtime env دارند و می‌خواهند زبان جستجو را از آن‌جا کنترل کنند. + +- **تمیزکاری و ساده‌سازی لاگ‌ها** +- حذف لاگ‌های پرحجم قبلی در `SearchBar` و جایگزینی با یک لاگ شفاف و واحد از داخل `useCurrentLocale`: +- فرمت: `[docusaurus-theme-search-typesense] locale: | source: ` +- این لاگ به دیباگ کمک می‌کند، اما در حالت عادی فقط یک خط ثابت است و اسپم ایجاد نمی‌کند. + +### ۲) مشکلاتی که حل شد + +- **Hydration / React #418 (در پروژهٔ میزبان)** +- در فرآیند دیباگ مشخص شد که خطای `React #418 (Hydration failed)` در سایت میزبان باعث می‌شد درخت React به‌درستی mount نشود و لاگ‌ها و رفتار تم دیده نشود. +- با ایزوله‌کردن استفاده از `window` و `document` در `useEffect` و خارج‌کردن منطق locale از رندر اولیه، ریسک Hydration mismatch در خود تم کاهش یافت. + +- **عدم مشاهدهٔ لاگ‌های تم جستجو** +- قبلاً هیچ لاگ معناداری از تم در کنسول دیده نمی‌شد و مشخص نبود تم به چه تنظیماتی از داکیوسورس دسترسی دارد. +- الان با لاگ واحد `locale` و `source` به‌صورت قطعی می‌توان دید تم دقیقاً از کجا زبان را می‌خواند و آیا با تغییر زبان یا env درست به‌روزرسانی می‌شود. + +- **ناهماهنگی بین ترجمه‌ها و i18n** +- پیش از این بخشی از متن‌ها فارسی‌سازی شده بود اما با سیستم `i18n/theme.json` و placeholderهای استاندارد کاملاً هماهنگ نبود. +- اکنون هم کلیدهای ترجمه و هم مقادیر برای فارسی و انگلیسی (و سایر localeها) یک‌دست شده‌اند تا Docusaurus بتواند آنها را از طریق `translate()` لود کند. + +### ۳) تست‌های انجام‌شده (به‌صورت دستی) + +- **تست لاگ و تشخیص زبان** +- اجرای سایت میزبان، باز کردن کنسول و تأیید چاپ لاگ: +- وقتی زبان روی فارسی بود: `locale: fa | source: context` (همان چیزی که الان در اسکرین‌شات/لاگ داریم). +- بعد از سوییچ به زبان انگلیسی و رفرش/رفتن به مسیر `/en/`: تغییر لاگ به `locale: en | source: context`. + +- **تست مودال جستجو** +- باز کردن آیکون جستجو در هر دو زبان فارسی و انگلیسی و بررسی: +- متن دکمهٔ جستجو، placeholder، دکمهٔ لغو/Cancel، متن خطا، پیام «بدون نتیجه». +- شمارندهٔ نتایج (با `{count}`) و صحت جمع بستن در فارسی. + +- **تست صفحهٔ جستجو** +- رفتن به صفحهٔ `/search` و `/en/search` و بررسی: +- عناوین، توضیحات، پیام‌های «چند سند پیدا شد»، بخش‌های ناوبری و لینک‌ها. +- فیلتر زبان در کوئری Typesense (استفاده از `language = currentLocale`) و تغییر آن با تغییر زبان. + +- **تست پیکربندی تم و env (سمت پروژهٔ میزبان)** +- سناریو با `localeOverride: 'fa'` در `themeConfig.typesense` برای قفل‌کردن زبان جستجو روی فارسی. +- سناریو با حذف `localeOverride` و سوییچ زبان از انتخابگر زبان برای تأیید اینکه locale از context می‌آید. +- سناریوی آزمایشی با ست‌کردن `window.__SEARCH_THEME_LOCALE__` / `window.env.LOCALE` و مشاهدهٔ تغییر `source` در لاگ. + +### ۴) نکات برای مرج‌کننده + +- کد الان: +- با i18n رسمی Docusaurus هماهنگ است (ترجمه‌ها از `translate()` و `theme.json` می‌آیند)، +- یک مکانیزم شفاف و قابل‌دیباگ برای تشخیص locale دارد، +- از Hydration-safe patternها برای دسترسی به `window`/`document` استفاده می‌کند. +- تیم روی این کار **حدود ۲۰ ساعت** وقت گذاشته تا: +- هم منطق فنی (Hydration، i18n، Typesense) را پایدار کند، +- هم تجربهٔ کاربری جستجو را برای فارسی و انگلیسی (و بقیهٔ زبان‌ها) یک‌دست و قابل‌اعتماد کند. +- در حال حاضر، هم **مودال جستجو** و هم **صفحهٔ جستجو** برای زبان‌های تست‌شده (fa/en) به‌درستی ترجمه می‌شوند و لاگ کنسول تأیید می‌کند که تم زبان را از منبع درست می‌گیرد. \ No newline at end of file diff --git a/PROMPT-check-docusaurus-i18n-config.md b/PROMPT-check-docusaurus-i18n-config.md new file mode 100644 index 0000000..32a1c1e --- /dev/null +++ b/PROMPT-check-docusaurus-i18n-config.md @@ -0,0 +1,56 @@ +# پرامپت: بررسی تنظیمات i18n در پروژهٔ داکیوسورس + +این پرامپت برای **پروژهٔ داکیوسورس شما** (مثلاً kasra-docs) است که تم جستجو را نصب کرده است. + +## هدف + +بررسی کنید که: +1. تنظیمات i18n در `docusaurus.config.js` (یا `.ts`) چه هستند +2. آیا `i18n` در config فعال است یا نه +3. چه زبان‌هایی (`locales`) تعریف شده‌اند +4. زبان پیش‌فرض (`defaultLocale`) چیست +5. آیا فایل‌های ترجمه در `i18n/` وجود دارند + +## دستورالعمل + +1. **خواندن فایل config اصلی داکیوسورس:** + - `docusaurus.config.js` یا `docusaurus.config.ts` را بخوانید + - بخش `i18n` را پیدا کنید و نمایش دهید + +2. **بررسی ساختار i18n:** + - اگر `i18n` در config وجود دارد، همهٔ فیلدهایش را نمایش دهید: + - `defaultLocale` + - `locales` (آرایهٔ زبان‌ها) + - `localeConfigs` (اگر وجود دارد) + - اگر `i18n` وجود ندارد، بگویید که i18n غیرفعال است + +3. **بررسی فایل‌های ترجمه:** + - اگر پوشهٔ `i18n/` وجود دارد، ساختارش را نمایش دهید + - ببینید آیا فایل `i18n//theme.json` برای زبان‌های مختلف وجود دارد + - اگر وجود دارد، محتوای یکی از آن‌ها (مثلاً `i18n/fa/theme.json` یا `i18n/en/theme.json`) را نمایش دهید + +4. **بررسی package.json:** + - وابستگی `docusaurus-theme-search-typesense` را چک کنید + - ببینید از کجا نصب شده (npm یا github) + +5. **لاگ‌های کنسول:** + - بعد از بیلد و serve، در کنسول مرورگر دنبال این لاگ بگردید: + ``` + [docusaurus-theme-search-typesense] 🔍 Docusaurus Context Access + ``` + - این لاگ باید نشان دهد که تم جستجو چه مقادیری از `useDocusaurusContext()` می‌بیند + - مقادیر `currentLocale`, `locales`, `defaultLocale` را یادداشت کنید + +## خروجی مورد انتظار + +بعد از اجرای این پرامپت باید ببینید: + +- ✅ تنظیمات i18n در config چیست +- ✅ چه زبان‌هایی فعال هستند +- ✅ زبان پیش‌فرض چیست +- ✅ آیا فایل‌های ترجمه وجود دارند +- ✅ تم جستجو چه مقادیری از context می‌بیند + +## نکته + +اگر لاگ تم جستجو در کنسول دیده نمی‌شود، ممکن است به خاطر خطای React #418 (Hydration) باشد که در فایل `docs/REACT-418-HYDRATION.md` توضیح داده شده است. اول آن را برطرف کنید. diff --git a/PROMPT-docusaurus-host-configure-persian.md b/PROMPT-docusaurus-host-configure-persian.md new file mode 100644 index 0000000..d66ea9b --- /dev/null +++ b/PROMPT-docusaurus-host-configure-persian.md @@ -0,0 +1,77 @@ +# پرامپت: تنظیم پروژهٔ داکیوسورس برای زبان فارسی و تم جستجو + +این پرامپت را در **پروژهٔ داکیوسورس شما** (سایتی که تم جستجو را نصب کرده) اجرا کنید. + +--- + +## متن پرامپت (کپی کنید و به AI بدهید) + +``` +پروژهٔ من یک سایت Docusaurus است که از تم جستجو docusaurus-theme-search-typesense استفاده می‌کند. می‌خواهم زبان را برای فارسی تنظیم کنم و مطمئن شوم تم جستجو با تغییر زبان کاربر، ترجمهٔ درست را نشان می‌دهد. + +کارها: + +۱) در docusaurus.config.js (یا .ts) بخش i18n را بررسی/تنظیم کن: + - defaultLocale را روی 'fa' یا 'en' بگذار (مثلاً اگر سایت پیش‌فرض فارسی است: 'fa'). + - locales را شامل 'en' و 'fa' (و در صورت نیاز 'fa-IR') کن. + +۲) در themeConfig.typesense اگر لازم است localeOverride بگذار: + - فقط در صورتی که می‌خواهی زبان جستجو را همیشه ثابت نگه داری (مثلاً همیشه فارسی) این را ست کن: localeOverride: 'fa' + - اگر می‌خواهی با تغییر زبان کاربر در نوار بالا، زبان جستجو هم عوض شود، localeOverride نگذار (یا کامنت کن). + +۳) اگر از window.env برای env استفاده می‌کنی و می‌خواهی زبان جستجو از آن بخواند، مطمئن شو قبل از لود تم یکی از این‌ها ست شده: + - window.__SEARCH_THEME_LOCALE__ = 'fa' + - یا window.env.LOCALE = 'fa' + +۴) فایل‌های ترجمهٔ تم را چک کن: + - در پروژهٔ من پوشهٔ i18n وجود دارد؟ + - برای هر زبان (مثلاً i18n/fa و i18n/en) فایل theme.json دارم؟ اگر نه، از پوشهٔ i18n داخل node_modules/docusaurus-theme-search-typesense می‌توانم کپی کنم. + +۵) بعد از تغییرات، دستورهای دقیق برای بیلد و تست را بده (npm run build و npm run serve یا npm run start). +``` + +--- + +## سناریوی ساده برای تست تغییر زبان و ترجمهٔ جستجو + +### هدف +می‌خواهی وقتی زبان سایت را عوض می‌کنی (مثلاً از فارسی به انگلیسی)، متن‌های جستجو (دکمه، مودال، صفحهٔ جستجو) هم به همان زبان عوض شوند. + +### مراحل + +1. **سایت را اجرا کن** + - `npm run start` یا بعد از `npm run build` و `npm run serve` یکی از آدرس‌ها را باز کن (مثلاً `http://localhost:3000`). + +2. **زبان پیش‌فرض را ببین** + - اگر defaultLocale برابر `fa` است، صفحهٔ اول و نوار بالا باید فارسی باشد. + - روی آیکون جستجو کلیک کن و مودال را باز کن؛ متن‌ها باید مطابق زبان فعلی باشند (مثلاً «جستجو»، «لغو»، «مشاهده همه X نتیجه»). + +3. **زبان را عوض کن** + - در نوار بالا معمولاً یک انتخابگر زبان (Language / زبان) هست (اگر i18n را فعال کرده باشی و چند locale داشته باشی). + - زبان را به English (یا en) تغییر بده. + +4. **صفحه و جستجو را دوباره چک کن** + - آدرس عوض می‌شود (مثلاً به `/en/` می‌رود). + - دوباره آیکون جستجو را بزن؛ مودال و دکمهٔ جستجو باید انگلیسی باشند (مثلاً "Search", "Cancel", "See all X results"). + - اگر صفحهٔ جستجو (`/search` یا `/en/search`) دارید، آن را هم باز کن و متن‌ها را چک کن. + +5. **کنسول مرورگر** + - F12 → Console. باید یک خط ببینی شبیه: + `[docusaurus-theme-search-typesense] locale: en | source: context` + - با عوض کردن زبان، بعد از رفرش یا رفتن به صفحهٔ زبان دیگر، مقدار `locale` باید عوض شود (مثلاً از `fa` به `en`). + +--- + +## آیا بعد از عوض کردن زبان باید .docusaurus و build را پاک کنم؟ + +**خیر.** برای **تغییر زبان توسط کاربر** در همان بیلد، نیازی به پاک کردن `.docusaurus` یا پوشهٔ `build` نیست. فقط زبان را در UI عوض کن (یا به مسیر زبان دیگر برو، مثلاً `/en/`) و در صورت نیاز صفحه را رفرش کن. + +**بله، در این موارد پاک کردن لازم است:** +- وقتی **خود تم جستجو** را آپدیت کردی (مثلاً نسخهٔ جدید از npm یا گیت‌هاب نصب کردی) و می‌خواهی تغییرات تم را ببینی. +- وقتی بعد از آپدیت تم، هنوز متن‌های قدیمی یا رفتار قبلی را می‌بینی. + +در آن صورت: +- پوشه‌های `.docusaurus` و `build` را حذف کن. +- دوباره `npm run build` (و در صورت نیاز `npm run serve`) یا `npm run start` بزن. + +خلاصه: **تغییر زبان در سایت = بدون پاک کردن کش.** **آپدیت تم = پاک کردن .docusaurus و build و بیلد مجدد.** diff --git a/PROMPT-for-consumer-project.md b/PROMPT-for-consumer-project.md new file mode 100644 index 0000000..3896590 --- /dev/null +++ b/PROMPT-for-consumer-project.md @@ -0,0 +1,46 @@ +# پرامپت برای پروژهٔ مصرف‌کننده (مثلاً kasra-docs) + +این متن را در چت پروژهٔ اصلی (جایی که داکیوسورس را اجرا می‌کنید) کپی کنید و اجرا کنید. + +--- + +**پرامپت:** + +``` +پروژهٔ من یک سایت Docusaurus است و از پکیج تم جستجو استفاده می‌کنم: docusaurus-theme-search-typesense. + +کارهایی که می‌خواهم انجام شود: + +۱) بررسی و نصب/به‌روزرسانی تم جستجو +- ابتدا فایل package.json را بخوان و ببین وابستگی docusaurus-theme-search-typesense چگونه تعریف شده است. +- **مهم:** اگر از گیت‌هاب نصب می‌شود (مثلاً "github:saber13812002/docusaurus-theme-search-typesense#v0.24.8-i18n" یا مشابه)، **حتماً همان را حفظ کن** و فقط npm install را اجرا کن تا از همان منبع گیت‌هاب نصب شود. **هیچ‌وقت آن را به نسخه npm (مثلاً ^0.26.0) تغییر نده** چون تغییرات ما روی نسخه گیت‌هاب است نه npm. +- اگر از npm نصب می‌شود (مثلاً "^0.26.0") و می‌خواهیم از گیت‌هاب استفاده کنیم، آن را به "github:saber13812002/docusaurus-theme-search-typesense#v0.24.8-i18n" تغییر بده (یا برنچ/تگ مورد نظر که شامل تغییرات جدید است). +- اگر تم را به صورت لوکال (npm link یا path) استفاده می‌کنم، مطمئن شو که وابستگی به مسیر لوکال اشاره دارد. +- بعد از بررسی و در صورت نیاز تغییر، npm install را اجرا کن تا وابستگی‌ها نصب/به‌روز شوند. + +۲) پاک‌سازی کش و بیلد +- پوشهٔ .docusaurus را حذف کن (اگر وجود دارد). +- پوشهٔ build را حذف کن (اگر وجود دارد). + +۳) بیلد و اجرا +- دستور npm run build را اجرا کن. +- بعد از اتمام بیلد، دستور npm run serve را اجرا کن (یا به من بگو که خودم اجرا کنم). + +۴) بررسی در مرورگر +- بعد از بالا آمدن سرور، در مرورگر به آدرس سایت (مثلاً http://localhost:3000) برو. +- DevTools را باز کن (F12) و به تب Console برو. +- صفحه را یک بار رفرش کامل کن (Ctrl+Shift+R یا Cmd+Shift+R). +- در باکس جستجوی کنسول عبارت "docusaurus-theme-search-typesense" را جستجو کن. + +خروجی مورد انتظار: +- باید حداقل این لاگ را ببینی: "[docusaurus-theme-search-typesense] SearchBar module loaded" +- در صورت درست بودن، علاوه بر آن این لاگ هم باید باشد: "[docusaurus-theme-search-typesense] i18n values from Docusaurus context:" و زیر آن currentLocale، locales، defaultLocale. + +اگر هیچ کدام از این لاگ‌ها را نمی‌بینی: +- بررسی کن که آیا در این پروژه کامپوننت SearchBar یا Navbar را Swizzle کرده‌ایم (مثلاً وجود src/theme/SearchBar یا استفاده از دکمهٔ جستجوی دیگری). اگر بله، مسیر لود شدن تم جستجو را توضیح بده. +- اگر Swizzle نداریم، یک راه‌حل پیشنهاد بده تا مطمئن شویم تم جستجو از node_modules لود می‌شود و لاگ در کنسول دیده می‌شود. +``` + +--- + +**نکته:** اگر تم را از مسیر لوکال استفاده می‌کنید، قبل از اجرای این پرامپت در پروژهٔ اصلی، در خود پروژهٔ تم (docusaurus-theme-search-typesense) یک بار `npm run build` بزنید تا پوشهٔ `lib` به‌روز باشد؛ بعد در پروژهٔ اصلی از `npm link` یا path به همان پوشهٔ تم اشاره کنید و مراحل بالا را انجام دهید. diff --git a/README.md b/README.md index f26ef63..67f1f32 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,26 @@ Think of it as an open source alternative to Algolia and an easier-to-use, batte Read detailed step-by-step instructions on how to first setup the DocSearch scraper and then install this plugin here: [https://typesense.org/docs/guide/docsearch.html](https://typesense.org/docs/guide/docsearch.html). +### Updating the theme + +After updating this package (e.g. `npm install` or `yarn`), if you do not see the latest changes (such as translations or UI text), clear the Docusaurus build and cache and rebuild: + +- Remove the `.docusaurus` folder and `build` folder in your site directory, then run `npm run build` (or `yarn build`) again. +- Or when using the dev server: remove `.docusaurus` and restart `npm run start` (or `yarn start`). + +This forces the bundler to use the updated theme code from `node_modules` instead of cached output. + +### Locale and i18n + +The theme detects the current locale in this order: (1) Docusaurus context (`i18n.currentLocale`), (2) `document.documentElement.lang`, (3) config override, (4) window env, (5) default `en`. + +- **Config override:** In `docusaurus.config.js`, under `themeConfig.typesense`, you can set `localeOverride: 'fa'` (or any locale code) to force the search locale when the theme cannot read it from Docusaurus. +- **Window env:** You can set the locale from your app so the theme picks it up without Docusaurus context. Before the theme runs, set one of: + - `window.__SEARCH_THEME_LOCALE__ = 'fa'` + - or, if you already use `window.env`: `window.env.LOCALE = 'fa'` + +In the browser console you will see a single log: `[docusaurus-theme-search-typesense] locale: | source: ` so you can confirm which source is used. + ## Help If you have any questions or run into any problems, please create a Github issue and we'll try our best to help. diff --git a/docs/REACT-418-HYDRATION.md b/docs/REACT-418-HYDRATION.md new file mode 100644 index 0000000..ab4bd9d --- /dev/null +++ b/docs/REACT-418-HYDRATION.md @@ -0,0 +1,77 @@ +# خطای React #418 و ارتباط با تم جستجو + +## خطای #418 یعنی چه؟ + +**React Error #418 = Hydration failed** + +یعنی خروجی HTML که روی **سرور** رندر شده با خروجی اولیه‌ای که React روی **کلاینت** می‌سازد یکی نیست. React انتظار دارد در مرحلهٔ hydration دقیقاً همان درخت DOM را ببیند که سرور فرستاده؛ اگر فرق داشته باشد این خطا را می‌دهد. + +## چرا ممکن است لاگ تم جستجو را نبینیم؟ + +وقتی Hydration با خطا مواجه شود: + +- React سعی می‌کند با یک رندر مجدد (recover) خودش را درست کند. +- ممکن است بعضی کامپوننت‌ها دوباره mount شوند یا در وضعیت عجیبی باشند. +- اگر چانک تم جستجو بعد از این خطا لود شود یا درخت کامپوننت عوض شده باشد، ممکن است `useEffect` داخل SearchBar هرگز اجرا نشود یا لاگ در کنسول گم شود. + +پس **اول باید خطای Hydration را برطرف کنید**؛ بعد احتمال دیده شدن لاگ تم جستجو بیشتر می‌شود. + +## علت‌های معمول Hydration در پروژهٔ شما + +از لاگ‌های شما این‌ها برمی‌آید: + +1. **استفاده از `window.env` در حین رندر** + - لاگ `[Root] New Typesense config from window.env` یعنی جایی در کامپوننت Root (یا والد) در **حین رندر** از `window.env` استفاده می‌شود. + - روی **سرور** `window` وجود ندارد یا مقدارش فرق دارد؛ روی **کلاینت** مقدار دیگری است. + - اگر بر اساس این مقدار چیزی رندر شود (مثلاً یک `div` یا متن متفاوت)، سرور و کلاینت خروجی متفاوت می‌دهند و خطای #418 رخ می‌دهد. + +2. **ساختار HTML نامعتبر** + - در componentStack خطا آمده: `at div` و `at p`. + - اگر جایی داخل یک `

` یک المان بلاک (مثلاً `

`) رندر شود، در HTML معتبر نیست و مرورگر DOM را عوض می‌کند؛ در نتیجه سرور و کلاینت با هم جور نمی‌شوند. + +## کارهایی که باید انجام دهید + +### ۱) پیدا کردن محل دقیق خطا (توسعه با بیلد غیر مینیفای) + +در پروژهٔ داکیوسورس (مثلاً kasra-docs): + +- به‌جای `npm run build` + `npm run serve`، یک بار با **حالت توسعه** اجرا کنید: + - `npm run start` +- در مرورگر همان صفحه را باز کنید و خطا را ببینید. +- در حالت توسعه پیام خطای React کامل است و معمولاً می‌گوید کدام کامپوننت و کدام prop/children باعث اختلاف شده است. + +### ۲) اصلاح استفاده از `window.env` + +هر جایی که در **حین رندر** (بدون `useEffect`) از `window` یا `window.env` استفاده می‌کنید و بر اساس آن JSX عوض می‌شود: + +- آن قسمت را به **بعد از mount شدن** موکول کنید: + - یا با `useEffect` + یک state (مثلاً `configFromWindow`) که فقط روی کلاینت ست می‌شود، + - یا با یک کامپوننت که فقط روی کلاینت رندر می‌شود (مثلاً با چک `typeof window !== 'undefined'` داخل یک state که در `useEffect` true می‌شود). +- هدف: در **اولین رندر** سرور و کلاینت دقیقاً همان خروجی را بدهند؛ استفاده از `window` فقط بعد از hydration (مثلاً داخل `useEffect`) باشد. + +### ۳) بررسی تگ‌های تو در تو + +در کامپوننت‌هایی که در componentStack خطا هستند (مثلاً اطراف آن `div` و `p`): + +- مطمئن شوید داخل `

` فقط محتوای phrasing (مثل متن، ``) دارید، نه `

` یا کامپوننت‌هایی که در نهایت `
` رندر می‌کنند. + +### ۴) بعد از رفع Hydration + +- دوباره بیلد و سرور را اجرا کنید و در کنسول مرورگر دنبال این لاگ‌ها بگردید: + - `[docusaurus-theme-search-typesense] SearchBar module loaded` + - `[docusaurus-theme-search-typesense] i18n values from Docusaurus context:` + +اگر خطای #418 برطرف شده باشد و تم جستجو از گیت‌هاب درست نصب شده باشد، این لاگ‌ها باید دیده شوند. + +## خلاصه + +| موضوع | توضیح | +|--------|--------| +| خطای #418 | Hydration failed – عدم تطابق رندر سرور و کلاینت | +| تأثیر روی لاگ تم | ممکن است چانک/کامپوننت تم درست mount نشود یا useEffect اجرا نشود | +| احتمال زیاد در پروژه شما | استفاده از `window.env` در حین رندر در Root یا اطراف آن | +| اقدام | ۱) `npm run start` و دیدن پیام کامل خطا ۲) بردن استفاده از `window` به بعد از hydration (مثلاً useEffect) ۳) رفع هر گونه `
` داخل `

` | + +--- + +**نکته:** در خود این تم (`docusaurus-theme-search-typesense`) از `window` فقط در event handlerها یا وقتی مودال باز است (فقط روی کلاینت) استفاده شده است، بنابراین منبع خطای #418 معمولاً در **سایت داکیوسورس شما** (مثلاً Root یا جایی که `window.env` را در حین رندر می‌خوانید) است. diff --git a/i18n/ar/theme.json b/i18n/ar/theme.json new file mode 100644 index 0000000..08abbf2 --- /dev/null +++ b/i18n/ar/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "نتائج البحث عن \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "البحث في الوثائق", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "تم العثور على مستند واحد|تم العثور على {count} مستندات|تم العثور على {count} مستنداً|تم العثور على {count} مستند", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "اكتب عبارة البحث هنا", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "بحث", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "بحث بواسطة Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "لم يتم العثور على نتائج", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "جاري جلب النتائج الجديدة...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "مسار التنقل", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/de/theme.json b/i18n/de/theme.json new file mode 100644 index 0000000..6e11887 --- /dev/null +++ b/i18n/de/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "Suchergebnisse für \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Dokumentation durchsuchen", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "Ein Dokument gefunden|{count} Dokumente gefunden", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Suchbegriff hier eingeben", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Suchen", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Suche von Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "Keine Ergebnisse gefunden", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Neue Ergebnisse werden abgerufen...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "Brotkrümel-Navigation", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/en/theme.json b/i18n/en/theme.json new file mode 100644 index 0000000..977f6dc --- /dev/null +++ b/i18n/en/theme.json @@ -0,0 +1,138 @@ +{ + "theme.SearchPage.documentsFound.plurals": { + "message": "One document found|{count} documents found", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "Search results for \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Search the documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Type your search query", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Search", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Search powered by Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "Breadcrumbs", + "description": "The ARIA label for breadcrumbs navigation" + }, + "theme.SearchPage.noResultsText": { + "message": "No results were found", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Fetching new results...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "Search", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchBar.seeAll": { + "message": "See all {count} results", + "description": "The link to see all search results" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "Clear the search query", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "Cancel", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "Recent", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "No recent searches", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "Save this search", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "Remove this search from history", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "Favorites", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "Remove this search from favorites", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "Unable to fetch results", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "Check your network connection.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "to select", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "Enter key", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "to navigate", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "Arrow up", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "Arrow down", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "to close", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "Escape key", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "Search by", + "description": "The text explain that the search is making by Typesense" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "No results for", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "Search for", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "Think this search should return results?", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "Let us know.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "Search the docs", + "description": "The placeholder of the input of the DocSearch pop-up modal" + } +} diff --git a/i18n/fa-IR/theme.json b/i18n/fa-IR/theme.json new file mode 100644 index 0000000..7096035 --- /dev/null +++ b/i18n/fa-IR/theme.json @@ -0,0 +1,138 @@ +{ + "theme.SearchPage.documentsFound.plurals": { + "message": "یک سند پیدا شد|{count} سند پیدا شد", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "نتایج جستجو برای \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "جستجو در مستندات", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "عبارت خود را برای جستجو تایپ کنید", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "جستجو", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "جستجو توسط Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "مسیر راهنما", + "description": "The ARIA label for breadcrumbs navigation" + }, + "theme.SearchPage.noResultsText": { + "message": "هیچ نتیجه‌ای پیدا نشد", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "در حال دریافت نتایج جدید...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "جستجو", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchBar.seeAll": { + "message": "مشاهده همه {count} نتیجه", + "description": "The link to see all search results" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "پاک کردن عبارت جستجو", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "لغو", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "اخیر", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "جستجوهای اخیری وجود ندارد", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "ذخیره این جستجو", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "حذف این جستجو از تاریخچه", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "مورد علاقه", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "حذف این جستجو از مورد علاقه‌ها", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "دریافت نتایج ممکن نیست", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "اتصال شبکه خود را بررسی کنید.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "برای انتخاب", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "دکمه اینتر", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "برای حرکت", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "فلش بالا", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "فلش پایین", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "برای بستن", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "دکمه Escape", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "جستجو با", + "description": "The text explain that the search is making by Typesense" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "نتیجه‌ای برای", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "جستجو برای", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "فکر می‌کنید این جستجو باید نتیجه داشته باشد؟", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "به ما بگویید.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "جستجو در مستندات", + "description": "The placeholder of the input of the DocSearch pop-up modal" + } +} diff --git a/i18n/fa/theme.json b/i18n/fa/theme.json new file mode 100644 index 0000000..7096035 --- /dev/null +++ b/i18n/fa/theme.json @@ -0,0 +1,138 @@ +{ + "theme.SearchPage.documentsFound.plurals": { + "message": "یک سند پیدا شد|{count} سند پیدا شد", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.existingResultsTitle": { + "message": "نتایج جستجو برای \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "جستجو در مستندات", + "description": "The search page title for empty query" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "عبارت خود را برای جستجو تایپ کنید", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "جستجو", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "جستجو توسط Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "مسیر راهنما", + "description": "The ARIA label for breadcrumbs navigation" + }, + "theme.SearchPage.noResultsText": { + "message": "هیچ نتیجه‌ای پیدا نشد", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "در حال دریافت نتایج جدید...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchBar.label": { + "message": "جستجو", + "description": "The ARIA label and placeholder for search button" + }, + "theme.SearchBar.seeAll": { + "message": "مشاهده همه {count} نتیجه", + "description": "The link to see all search results" + }, + "theme.SearchModal.searchBox.resetButtonTitle": { + "message": "پاک کردن عبارت جستجو", + "description": "The label and ARIA label for search box reset button" + }, + "theme.SearchModal.searchBox.cancelButtonText": { + "message": "لغو", + "description": "The label and ARIA label for search box cancel button" + }, + "theme.SearchModal.startScreen.recentSearchesTitle": { + "message": "اخیر", + "description": "The title for recent searches" + }, + "theme.SearchModal.startScreen.noRecentSearchesText": { + "message": "جستجوهای اخیری وجود ندارد", + "description": "The text when no recent searches" + }, + "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": { + "message": "ذخیره این جستجو", + "description": "The label for save recent search button" + }, + "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": { + "message": "حذف این جستجو از تاریخچه", + "description": "The label for remove recent search button" + }, + "theme.SearchModal.startScreen.favoriteSearchesTitle": { + "message": "مورد علاقه", + "description": "The title for favorite searches" + }, + "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": { + "message": "حذف این جستجو از مورد علاقه‌ها", + "description": "The label for remove favorite search button" + }, + "theme.SearchModal.errorScreen.titleText": { + "message": "دریافت نتایج ممکن نیست", + "description": "The title for error screen of search modal" + }, + "theme.SearchModal.errorScreen.helpText": { + "message": "اتصال شبکه خود را بررسی کنید.", + "description": "The help text for error screen of search modal" + }, + "theme.SearchModal.footer.selectText": { + "message": "برای انتخاب", + "description": "The explanatory text of the action for the enter key" + }, + "theme.SearchModal.footer.selectKeyAriaLabel": { + "message": "دکمه اینتر", + "description": "The ARIA label for the Enter key button that makes the selection" + }, + "theme.SearchModal.footer.navigateText": { + "message": "برای حرکت", + "description": "The explanatory text of the action for the Arrow up and Arrow down key" + }, + "theme.SearchModal.footer.navigateUpKeyAriaLabel": { + "message": "فلش بالا", + "description": "The ARIA label for the Arrow up key button that makes the navigation" + }, + "theme.SearchModal.footer.navigateDownKeyAriaLabel": { + "message": "فلش پایین", + "description": "The ARIA label for the Arrow down key button that makes the navigation" + }, + "theme.SearchModal.footer.closeText": { + "message": "برای بستن", + "description": "The explanatory text of the action for Escape key" + }, + "theme.SearchModal.footer.closeKeyAriaLabel": { + "message": "دکمه Escape", + "description": "The ARIA label for the Escape key button that close the modal" + }, + "theme.SearchModal.footer.searchByText": { + "message": "جستجو با", + "description": "The text explain that the search is making by Typesense" + }, + "theme.SearchModal.noResultsScreen.noResultsText": { + "message": "نتیجه‌ای برای", + "description": "The text explains that there are no results for the following search" + }, + "theme.SearchModal.noResultsScreen.suggestedQueryText": { + "message": "جستجو برای", + "description": "The text for the suggested query when no results are found for the following search" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsText": { + "message": "فکر می‌کنید این جستجو باید نتیجه داشته باشد؟", + "description": "The text for the question where the user thinks there are missing results" + }, + "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": { + "message": "به ما بگویید.", + "description": "The text for the link to report missing results" + }, + "theme.SearchModal.placeholder": { + "message": "جستجو در مستندات", + "description": "The placeholder of the input of the DocSearch pop-up modal" + } +} diff --git a/i18n/fr/theme.json b/i18n/fr/theme.json new file mode 100644 index 0000000..3a962d9 --- /dev/null +++ b/i18n/fr/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "Résultats de recherche pour \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Rechercher dans la documentation", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "Un document trouvé|{count} documents trouvés", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Tapez votre recherche ici", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Rechercher", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Recherche par Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "Aucun résultat trouvé", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Récupération de nouveaux résultats...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "Fil d'Ariane", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/he/theme.json b/i18n/he/theme.json new file mode 100644 index 0000000..ae8d788 --- /dev/null +++ b/i18n/he/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "תוצאות חיפוש עבור \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "חיפוש בתיעוד", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "נמצא מסמך אחד|נמצאו {count} מסמכים|נמצאו {count} מסמכים|נמצאו {count} מסמכים", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "הקלד את החיפוש שלך כאן", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "חיפוש", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "חיפוש על ידי Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "לא נמצאו תוצאות", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "מאחזר תוצאות חדשות...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "ניווט פירורי לחם", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/ja/theme.json b/i18n/ja/theme.json new file mode 100644 index 0000000..acf0af2 --- /dev/null +++ b/i18n/ja/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "\"{query}\"の検索結果", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "ドキュメントを検索", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "1件のドキュメントが見つかりました|{count}件のドキュメントが見つかりました", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "ここに検索語を入力", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "検索", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Typesenseによる検索", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "結果が見つかりませんでした", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "新しい結果を取得中...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "パンくずナビゲーション", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/pt/theme.json b/i18n/pt/theme.json new file mode 100644 index 0000000..6f43a89 --- /dev/null +++ b/i18n/pt/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "Resultados da busca para \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Buscar na documentação", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "Um documento encontrado|{count} documentos encontrados|{count} documentos encontrados", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Digite sua busca aqui", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Buscar", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Busca por Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "Nenhum resultado foi encontrado", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Buscando novos resultados...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "Navegação por migalhas de pão", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/ru/theme.json b/i18n/ru/theme.json new file mode 100644 index 0000000..addb277 --- /dev/null +++ b/i18n/ru/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "Результаты поиска по запросу \"{query}\"", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "Поиск в документации", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "Найден {count} документ|Найдено {count} документа|Найдено {count} документов", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "Введите поисковый запрос здесь", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "Поиск", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Поиск от Typesense", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "Результаты не найдены", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "Получение новых результатов...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "Навигационная цепочка", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/ur/theme.json b/i18n/ur/theme.json new file mode 100644 index 0000000..fbdd2e0 --- /dev/null +++ b/i18n/ur/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "\"{query}\" کی تلاش کے نتائج", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "دستاویزات تلاش کریں", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "ایک دستاویز ملی|{count} دستاویزات ملیں|{count} دستاویزات", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "اپنی تلاش یہاں لکھیں", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "تلاش کریں", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "Typesense کی طرف سے تلاش", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "کوئی نتیجہ نہیں ملا", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "نئے نتائج حاصل کیے جا رہے ہیں...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "روٹی کے چورے نیویگیشن", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/i18n/zh/theme.json b/i18n/zh/theme.json new file mode 100644 index 0000000..31efb41 --- /dev/null +++ b/i18n/zh/theme.json @@ -0,0 +1,38 @@ +{ + "theme.SearchPage.existingResultsTitle": { + "message": "搜索\"{query}\"的结果", + "description": "The search page title for non-empty query" + }, + "theme.SearchPage.emptyResultsTitle": { + "message": "搜索文档", + "description": "The search page title for empty query" + }, + "theme.SearchPage.documentsFound.plurals": { + "message": "找到1个文档|找到{count}个文档", + "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.SearchPage.inputPlaceholder": { + "message": "在此输入搜索内容", + "description": "The placeholder for search page input" + }, + "theme.SearchPage.inputLabel": { + "message": "搜索", + "description": "The ARIA label for search page input" + }, + "theme.SearchPage.typesenseLabel": { + "message": "由 Typesense 提供搜索", + "description": "The ARIA label for Typesense mention" + }, + "theme.SearchPage.noResultsText": { + "message": "未找到结果", + "description": "The paragraph for empty search result" + }, + "theme.SearchPage.fetchingNewResults": { + "message": "正在获取新结果...", + "description": "The paragraph for fetching new search results" + }, + "theme.SearchPage.breadcrumbs.ariaLabel": { + "message": "面包屑导航", + "description": "The ARIA label for breadcrumbs navigation" + } +} diff --git a/jest.config.cjs b/jest.config.cjs new file mode 100644 index 0000000..59c170d --- /dev/null +++ b/jest.config.cjs @@ -0,0 +1,7 @@ +/** @type {import('jest').Config} */ +module.exports = { + testEnvironment: 'node', + testMatch: ['**/src/__tests__/**/*.test.[jt]s?(x)'], + moduleFileExtensions: ['js', 'json'], +}; + diff --git a/lib/hooks/useCurrentLocale.d.ts b/lib/hooks/useCurrentLocale.d.ts new file mode 100644 index 0000000..82d8d7e --- /dev/null +++ b/lib/hooks/useCurrentLocale.d.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +/** + * Returns the current locale with fallback chain: + * 1. Docusaurus context (i18n.currentLocale) + * 2. document.documentElement.lang (after mount) + * 3. themeConfig.typesense.localeOverride + * 4. window.__SEARCH_THEME_LOCALE__ or window.env?.LOCALE + * 5. 'en' + */ +export declare function useCurrentLocale(): string; diff --git a/lib/hooks/useCurrentLocale.js b/lib/hooks/useCurrentLocale.js new file mode 100644 index 0000000..a8b8119 --- /dev/null +++ b/lib/hooks/useCurrentLocale.js @@ -0,0 +1,61 @@ +"use strict"; +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useCurrentLocale = useCurrentLocale; +const react_1 = require("react"); +const useDocusaurusContext_1 = require("@docusaurus/useDocusaurusContext"); +const useDocusaurusContext = useDocusaurusContext_1.default ?? useDocusaurusContext_1; +const DEFAULT_LOCALE = 'en'; +/** + * Returns the current locale with fallback chain: + * 1. Docusaurus context (i18n.currentLocale) + * 2. document.documentElement.lang (after mount) + * 3. themeConfig.typesense.localeOverride + * 4. window.__SEARCH_THEME_LOCALE__ or window.env?.LOCALE + * 5. 'en' + * Reads document/window only in useEffect to avoid hydration mismatch. + */ +function useCurrentLocale() { + const { i18n, siteConfig } = useDocusaurusContext(); + const themeConfig = siteConfig?.themeConfig; + const fromContext = i18n?.currentLocale; + const fromConfig = themeConfig?.typesense?.localeOverride; + const [clientLocale, setClientLocale] = (0, react_1.useState)(null); + (0, react_1.useEffect)(() => { + if (typeof document === 'undefined' && typeof window === 'undefined') { + return; + } + const docLang = typeof document !== 'undefined' + ? document.documentElement?.lang || null + : null; + const winLocale = typeof window !== 'undefined' + ? (window.__SEARCH_THEME_LOCALE__ ?? window.env?.LOCALE) || null + : null; + const fromClient = docLang || winLocale; + setClientLocale(fromClient); + }, []); + const locale = fromContext || clientLocale || fromConfig || DEFAULT_LOCALE; + (0, react_1.useEffect)(() => { + let source = 'default'; + if (fromContext) { + source = 'context'; + } + else if (clientLocale) { + source = + typeof document !== 'undefined' && + document.documentElement?.lang === clientLocale + ? 'document' + : 'window'; + } + else if (fromConfig) { + source = 'config'; + } + console.log('[docusaurus-theme-search-typesense] locale:', locale, '| source:', source); + }, [locale, fromContext, clientLocale, fromConfig]); + return locale; +} diff --git a/lib/templates/opensearch.d.ts b/lib/templates/opensearch.d.ts index 398650b..be5d171 100644 --- a/lib/templates/opensearch.d.ts +++ b/lib/templates/opensearch.d.ts @@ -4,5 +4,5 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -declare const _default: "\n\n\n <%= it.title %>\n Search <%= it.title %>\n UTF-8\n <% if (it.faviconUrl) { _%>\n <%= it.faviconUrl %>\n <% } _%>\n ?q={searchTerms}\"/>\n opensearch.xml\" />\n <%= it.siteUrl %>\n\n"; +declare const _default: "\n\n\n <%= it.title %>\n جستجو در <%= it.title %>\n UTF-8\n <% if (it.faviconUrl) { _%>\n <%= it.faviconUrl %>\n <% } _%>\n ?q={searchTerms}\"/>\n opensearch.xml\" />\n <%= it.siteUrl %>\n\n"; export default _default; diff --git a/lib/templates/opensearch.js b/lib/templates/opensearch.js index 15ba361..4e37e12 100644 --- a/lib/templates/opensearch.js +++ b/lib/templates/opensearch.js @@ -11,7 +11,7 @@ exports.default = ` <%= it.title %> - Search <%= it.title %> + جستجو در <%= it.title %> UTF-8 <% if (it.faviconUrl) { _%> <%= it.faviconUrl %> diff --git a/lib/theme/SearchBar/index.js b/lib/theme/SearchBar/index.js index e7b693b..e93f819 100644 --- a/lib/theme/SearchBar/index.js +++ b/lib/theme/SearchBar/index.js @@ -18,6 +18,7 @@ import Link from '@docusaurus/Link'; import { isRegexpStringMatch } from '@docusaurus/theme-common'; // @ts-ignore import { useSearchPage } from '../../hooks/useSearchPage'; +import { useCurrentLocale } from '../../hooks/useCurrentLocale'; import { DocSearchButton, useDocSearchKeyboardEvents, } from 'typesense-docsearch-react'; import { useTypesenseContextualFilters } from '../../client'; // @ts-ignore @@ -38,7 +39,7 @@ function ResultsFooter({ state, onClose }) { ); } function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { - const { siteMetadata } = useDocusaurusContext(); + useCurrentLocale(); const contextualSearchFacetFilters = useTypesenseContextualFilters(); const configFacetFilters = props.typesenseSearchParameters?.filter_by ?? ''; const facetFilters = contextualSearch diff --git a/lib/theme/SearchPage/index.js b/lib/theme/SearchPage/index.js index 856369e..a34ad71 100644 --- a/lib/theme/SearchPage/index.js +++ b/lib/theme/SearchPage/index.js @@ -15,6 +15,7 @@ import { HtmlClassNameProvider, usePluralForm, isRegexpStringMatch, useEvent, // @ts-ignore } from '@docusaurus/theme-common'; import { useSearchPage } from '../../hooks/useSearchPage'; +import { useCurrentLocale } from '../../hooks/useCurrentLocale'; // @ts-ignore import { useTitleFormatter } from '../../utils/generalUtils'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -65,7 +66,8 @@ function SearchVersionSelectList({ docsSearchVersionsHelpers, }) {

); } function SearchPageContent() { - const { siteConfig: { themeConfig }, i18n: { currentLocale }, } = useDocusaurusContext(); + const { siteConfig: { themeConfig } } = useDocusaurusContext(); + const currentLocale = useCurrentLocale(); const { typesense: { typesenseCollectionName, typesenseServerConfig, typesenseSearchParameters, externalUrlRegex, }, } = themeConfig; const documentsFoundPlural = useDocumentsFoundPlural(); const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers(); @@ -249,12 +251,12 @@ function SearchPageContent() { })}> setSearchQuery(e.target.value)} value={searchQuery} autoComplete="off" autoFocus/>
@@ -270,7 +272,7 @@ function SearchPageContent() {
@@ -303,7 +305,11 @@ function SearchPageContent() { - {breadcrumbs.length > 0 && (
    {breadcrumbs.map((html, index) => (
  • { + test('SearchBar label differs between fa and en', () => { + expect(fa['theme.SearchBar.label'].message).toBe('جستجو'); + expect(en['theme.SearchBar.label'].message).toBe('Search'); + }); + + test('SearchModal placeholder differs between fa and en', () => { + expect(fa['theme.SearchModal.placeholder'].message).toBe('جستجو در مستندات'); + expect(en['theme.SearchModal.placeholder'].message).toBe('Search the docs'); + }); + + test('SearchPage input placeholder differs between fa and en', () => { + expect(fa['theme.SearchPage.inputPlaceholder'].message).toBe( + 'عبارت خود را برای جستجو تایپ کنید', + ); + expect(en['theme.SearchPage.inputPlaceholder'].message).toBe( + 'Type your search query', + ); + }); +}); + diff --git a/src/hooks/useCurrentLocale.ts b/src/hooks/useCurrentLocale.ts new file mode 100644 index 0000000..9ac8ea7 --- /dev/null +++ b/src/hooks/useCurrentLocale.ts @@ -0,0 +1,83 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {useEffect, useState} from 'react'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import type {ThemeConfig} from 'docusaurus-theme-search-typesense'; + +type LocaleSource = + | 'context' + | 'document' + | 'config' + | 'window' + | 'default'; + +const DEFAULT_LOCALE = 'en'; + +declare global { + interface Window { + __SEARCH_THEME_LOCALE__?: string; + env?: {LOCALE?: string}; + } +} + +/** + * Returns the current locale with fallback chain: + * 1. Docusaurus context (i18n.currentLocale) + * 2. document.documentElement.lang (after mount) + * 3. themeConfig.typesense.localeOverride + * 4. window.__SEARCH_THEME_LOCALE__ or window.env?.LOCALE + * 5. 'en' + * Reads document/window only in useEffect to avoid hydration mismatch. + */ +export function useCurrentLocale(): string { + const {i18n, siteConfig} = useDocusaurusContext(); + const themeConfig = siteConfig?.themeConfig as ThemeConfig | undefined; + const fromContext = i18n?.currentLocale; + const fromConfig = themeConfig?.typesense?.localeOverride; + + const [docLang, setDocLang] = useState(null); + const [winLocale, setWinLocale] = useState(null); + + useEffect(() => { + if (typeof document === 'undefined' && typeof window === 'undefined') { + return; + } + if (typeof document !== 'undefined') { + setDocLang(document.documentElement?.lang || null); + } + if (typeof window !== 'undefined') { + setWinLocale( + (window.__SEARCH_THEME_LOCALE__ ?? window.env?.LOCALE) || null, + ); + } + }, []); + + const locale = + fromContext || docLang || fromConfig || winLocale || DEFAULT_LOCALE; + + useEffect(() => { + let source: LocaleSource = 'default'; + if (fromContext) { + source = 'context'; + } else if (docLang) { + source = 'document'; + } else if (fromConfig) { + source = 'config'; + } else if (winLocale) { + source = 'window'; + } + console.log( + '[docusaurus-theme-search-typesense] locale:', + locale, + '| source:', + source, + ); + }, [locale, fromContext, docLang, fromConfig, winLocale]); + + return locale; +} diff --git a/src/templates/opensearch.ts b/src/templates/opensearch.ts index b202b66..e2a29b4 100644 --- a/src/templates/opensearch.ts +++ b/src/templates/opensearch.ts @@ -10,7 +10,7 @@ export default ` <%= it.title %> - Search <%= it.title %> + جستجو در <%= it.title %> UTF-8 <% if (it.faviconUrl) { _%> <%= it.faviconUrl %> diff --git a/src/theme-search-typesense.d.ts b/src/theme-search-typesense.d.ts index b135fe6..3389a24 100644 --- a/src/theme-search-typesense.d.ts +++ b/src/theme-search-typesense.d.ts @@ -18,6 +18,8 @@ declare module 'docusaurus-theme-search-typesense' { typesenseServerConfig: TypesenseConfigurationOptions; typesenseSearchParameters: TypesenseSearchParams; searchPagePath: string | false | null; + /** Override locale for search (e.g. when Docusaurus context is unavailable). Falls back after context and document.lang. */ + localeOverride?: string; }; }; export type UserThemeConfig = DeepPartial; diff --git a/src/theme/SearchBar/index.tsx b/src/theme/SearchBar/index.tsx index 04f329b..87efa3f 100644 --- a/src/theme/SearchBar/index.tsx +++ b/src/theme/SearchBar/index.tsx @@ -21,6 +21,7 @@ import Head from '@docusaurus/Head'; import {isRegexpStringMatch} from '@docusaurus/theme-common'; // @ts-ignore import {useSearchPage} from '../../hooks/useSearchPage'; +import {useCurrentLocale} from '../../hooks/useCurrentLocale'; import { DocSearchButton, useDocSearchKeyboardEvents, @@ -87,7 +88,7 @@ function DocSearch({ externalUrlRegex, ...props }: DocSearchProps) { - const {siteMetadata} = useDocusaurusContext(); + useCurrentLocale(); const contextualSearchFacetFilters = useTypesenseContextualFilters() as string; diff --git a/src/theme/SearchPage/index.tsx b/src/theme/SearchPage/index.tsx index c6d8e01..013cfe5 100644 --- a/src/theme/SearchPage/index.tsx +++ b/src/theme/SearchPage/index.tsx @@ -24,6 +24,7 @@ import { // @ts-ignore } from '@docusaurus/theme-common'; import {useSearchPage} from '../../hooks/useSearchPage'; +import {useCurrentLocale} from '../../hooks/useCurrentLocale'; // @ts-ignore import {useTitleFormatter} from '../../utils/generalUtils'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -158,8 +159,8 @@ type ResultDispatcher = function SearchPageContent(): JSX.Element { const { siteConfig: {themeConfig}, - i18n: {currentLocale}, } = useDocusaurusContext(); + const currentLocale = useCurrentLocale(); const { typesense: { typesenseCollectionName, @@ -427,7 +428,7 @@ function SearchPageContent(): JSX.Element { className={styles.searchQueryInput} placeholder={translate({ id: 'theme.SearchPage.inputPlaceholder', - message: 'Type your search here', + message: 'Type your search query', description: 'The placeholder for search page input', })} aria-label={translate({ @@ -468,7 +469,7 @@ function SearchPageContent(): JSX.Element { href={`https://typesense.org/?utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch`} aria-label={translate({ id: 'theme.SearchPage.typesenseLabel', - message: 'Search by Typesense', + message: 'Search powered by Typesense', description: 'The ARIA label for Typesense mention', })}> {breadcrumbs.length > 0 && ( -
      /theme.json. + */ const translations: DocSearchTranslations & {placeholder: string} = { button: { buttonText: translate({ @@ -26,12 +31,12 @@ const translations: DocSearchTranslations & {placeholder: string} = { searchBox: { resetButtonTitle: translate({ id: 'theme.SearchModal.searchBox.resetButtonTitle', - message: 'Clear the query', + message: 'Clear the search query', description: 'The label and ARIA label for search box reset button', }), resetButtonAriaLabel: translate({ id: 'theme.SearchModal.searchBox.resetButtonTitle', - message: 'Clear the query', + message: 'Clear the search query', description: 'The label and ARIA label for search box reset button', }), cancelButtonText: translate({ @@ -68,7 +73,7 @@ const translations: DocSearchTranslations & {placeholder: string} = { }), favoriteSearchesTitle: translate({ id: 'theme.SearchModal.startScreen.favoriteSearchesTitle', - message: 'Favorite', + message: 'Favorites', description: 'The title for favorite searches', }), removeFavoriteSearchButtonTitle: translate({ @@ -85,7 +90,7 @@ const translations: DocSearchTranslations & {placeholder: string} = { }), helpText: translate({ id: 'theme.SearchModal.errorScreen.helpText', - message: 'You might want to check your network connection.', + message: 'Check your network connection.', description: 'The help text for error screen of search modal', }), }, @@ -133,7 +138,7 @@ const translations: DocSearchTranslations & {placeholder: string} = { searchByText: translate({ id: 'theme.SearchModal.footer.searchByText', message: 'Search by', - description: 'The text explain that the search is making by Algolia', + description: 'The text explain that the search is making by Typesense', }), }, noResultsScreen: { @@ -145,13 +150,13 @@ const translations: DocSearchTranslations & {placeholder: string} = { }), suggestedQueryText: translate({ id: 'theme.SearchModal.noResultsScreen.suggestedQueryText', - message: 'Try searching for', + message: 'Search for', description: 'The text for the suggested query when no results are found for the following search', }), reportMissingResultsText: translate({ id: 'theme.SearchModal.noResultsScreen.reportMissingResultsText', - message: 'Believe this query should return results?', + message: 'Think this search should return results?', description: 'The text for the question where the user thinks there are missing results', }), @@ -164,7 +169,7 @@ const translations: DocSearchTranslations & {placeholder: string} = { }, placeholder: translate({ id: 'theme.SearchModal.placeholder', - message: 'Search docs', + message: 'Search the docs', description: 'The placeholder of the input of the DocSearch pop-up modal', }), }; diff --git a/src/validateThemeConfig.ts b/src/validateThemeConfig.ts index d7a09a8..be2fb2a 100644 --- a/src/validateThemeConfig.ts +++ b/src/validateThemeConfig.ts @@ -38,6 +38,8 @@ const Schema = Joi.object({ .try(Joi.boolean().invalid(true), Joi.string()) .allow(null) .default(DEFAULT_CONFIG.searchPagePath), + + localeOverride: Joi.string().optional(), }) .label('themeConfig.typesense') .required() diff --git a/tsconfig.client.json b/tsconfig.client.json index 5352851..18024e3 100644 --- a/tsconfig.client.json +++ b/tsconfig.client.json @@ -57,6 +57,6 @@ "module": "esnext", "target": "esnext" }, - "include": ["src/theme", "src/client", "src/*.d.ts"], + "include": ["src/theme", "src/client", "src/hooks", "src/*.d.ts"], "exclude": ["**/__tests__/**"] }