@intlayer/docs 8.0.0 → 8.0.1-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/generated/docs.entry.cjs +160 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +160 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +8 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/intlayer_with_adonisjs.md +394 -0
- package/docs/ar/intlayer_with_hono.md +223 -0
- package/docs/ar/intlayer_with_vite+preact.md +317 -675
- package/docs/ar/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ar/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ar/packages/adonis-intlayer/t.md +149 -0
- package/docs/ar/packages/hono-intlayer/exports.md +59 -0
- package/docs/ar/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ar/packages/hono-intlayer/t.md +268 -0
- package/docs/de/intlayer_with_adonisjs.md +392 -0
- package/docs/de/intlayer_with_hono.md +418 -0
- package/docs/de/intlayer_with_vite+preact.md +272 -632
- package/docs/de/packages/adonis-intlayer/exports.md +50 -0
- package/docs/de/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/de/packages/adonis-intlayer/t.md +149 -0
- package/docs/de/packages/hono-intlayer/exports.md +59 -0
- package/docs/de/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/de/packages/hono-intlayer/t.md +316 -0
- package/docs/en/index.md +8 -0
- package/docs/en/intlayer_with_adonisjs.md +388 -0
- package/docs/en/intlayer_with_hono.md +418 -0
- package/docs/en/intlayer_with_vite+preact.md +171 -556
- package/docs/en/introduction.md +1 -0
- package/docs/en/packages/adonis-intlayer/exports.md +50 -0
- package/docs/en/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/en/packages/adonis-intlayer/t.md +149 -0
- package/docs/en/packages/hono-intlayer/exports.md +59 -0
- package/docs/en/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/en/packages/hono-intlayer/t.md +316 -0
- package/docs/en-GB/intlayer_with_adonisjs.md +394 -0
- package/docs/en-GB/intlayer_with_hono.md +418 -0
- package/docs/en-GB/intlayer_with_vite+preact.md +236 -583
- package/docs/en-GB/packages/adonis-intlayer/exports.md +50 -0
- package/docs/en-GB/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/en-GB/packages/adonis-intlayer/t.md +149 -0
- package/docs/en-GB/packages/hono-intlayer/exports.md +59 -0
- package/docs/en-GB/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/en-GB/packages/hono-intlayer/t.md +316 -0
- package/docs/es/intlayer_with_adonisjs.md +388 -0
- package/docs/es/intlayer_with_hono.md +418 -0
- package/docs/es/intlayer_with_vite+preact.md +286 -650
- package/docs/es/packages/adonis-intlayer/exports.md +50 -0
- package/docs/es/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/es/packages/adonis-intlayer/t.md +149 -0
- package/docs/es/packages/hono-intlayer/exports.md +59 -0
- package/docs/es/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/es/packages/hono-intlayer/t.md +316 -0
- package/docs/fr/intlayer_with_adonisjs.md +388 -0
- package/docs/fr/intlayer_with_hono.md +418 -0
- package/docs/fr/intlayer_with_vite+preact.md +274 -614
- package/docs/fr/packages/adonis-intlayer/exports.md +50 -0
- package/docs/fr/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/fr/packages/adonis-intlayer/t.md +149 -0
- package/docs/fr/packages/hono-intlayer/exports.md +59 -0
- package/docs/fr/packages/hono-intlayer/intlayer.md +59 -0
- package/docs/fr/packages/hono-intlayer/t.md +316 -0
- package/docs/hi/intlayer_with_adonisjs.md +394 -0
- package/docs/hi/intlayer_with_hono.md +227 -0
- package/docs/hi/intlayer_with_vite+preact.md +304 -680
- package/docs/hi/packages/adonis-intlayer/exports.md +50 -0
- package/docs/hi/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/hi/packages/adonis-intlayer/t.md +149 -0
- package/docs/hi/packages/hono-intlayer/exports.md +59 -0
- package/docs/hi/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/hi/packages/hono-intlayer/t.md +268 -0
- package/docs/id/intlayer_with_adonisjs.md +394 -0
- package/docs/id/intlayer_with_hono.md +227 -0
- package/docs/id/intlayer_with_vite+preact.md +297 -697
- package/docs/id/packages/adonis-intlayer/exports.md +50 -0
- package/docs/id/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/id/packages/adonis-intlayer/t.md +149 -0
- package/docs/id/packages/hono-intlayer/exports.md +59 -0
- package/docs/id/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/id/packages/hono-intlayer/t.md +268 -0
- package/docs/it/intlayer_with_adonisjs.md +394 -0
- package/docs/it/intlayer_with_hono.md +227 -0
- package/docs/it/intlayer_with_vite+preact.md +290 -659
- package/docs/it/packages/adonis-intlayer/exports.md +50 -0
- package/docs/it/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/it/packages/adonis-intlayer/t.md +149 -0
- package/docs/it/packages/hono-intlayer/exports.md +59 -0
- package/docs/it/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/it/packages/hono-intlayer/t.md +268 -0
- package/docs/ja/intlayer_with_adonisjs.md +394 -0
- package/docs/ja/intlayer_with_hono.md +227 -0
- package/docs/ja/intlayer_with_vite+preact.md +307 -662
- package/docs/ja/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ja/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ja/packages/adonis-intlayer/t.md +149 -0
- package/docs/ja/packages/hono-intlayer/exports.md +59 -0
- package/docs/ja/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ja/packages/hono-intlayer/t.md +268 -0
- package/docs/ko/intlayer_with_adonisjs.md +394 -0
- package/docs/ko/intlayer_with_hono.md +227 -0
- package/docs/ko/intlayer_with_vite+preact.md +303 -703
- package/docs/ko/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ko/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ko/packages/adonis-intlayer/t.md +149 -0
- package/docs/ko/packages/hono-intlayer/exports.md +59 -0
- package/docs/ko/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ko/packages/hono-intlayer/t.md +268 -0
- package/docs/pl/intlayer_with_adonisjs.md +394 -0
- package/docs/pl/intlayer_with_hono.md +227 -0
- package/docs/pl/intlayer_with_vite+preact.md +289 -690
- package/docs/pl/packages/adonis-intlayer/exports.md +50 -0
- package/docs/pl/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/pl/packages/adonis-intlayer/t.md +149 -0
- package/docs/pl/packages/hono-intlayer/exports.md +59 -0
- package/docs/pl/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/pl/packages/hono-intlayer/t.md +268 -0
- package/docs/pt/intlayer_with_adonisjs.md +394 -0
- package/docs/pt/intlayer_with_hono.md +227 -0
- package/docs/pt/intlayer_with_vite+preact.md +275 -637
- package/docs/pt/packages/adonis-intlayer/exports.md +50 -0
- package/docs/pt/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/pt/packages/adonis-intlayer/t.md +149 -0
- package/docs/pt/packages/hono-intlayer/exports.md +59 -0
- package/docs/pt/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/pt/packages/hono-intlayer/t.md +268 -0
- package/docs/ru/intlayer_with_adonisjs.md +393 -0
- package/docs/ru/intlayer_with_hono.md +223 -0
- package/docs/ru/intlayer_with_vite+preact.md +319 -683
- package/docs/ru/packages/adonis-intlayer/exports.md +50 -0
- package/docs/ru/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/ru/packages/adonis-intlayer/t.md +149 -0
- package/docs/ru/packages/hono-intlayer/exports.md +59 -0
- package/docs/ru/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/ru/packages/hono-intlayer/t.md +268 -0
- package/docs/tr/intlayer_with_adonisjs.md +394 -0
- package/docs/tr/intlayer_with_hono.md +227 -0
- package/docs/tr/intlayer_with_vite+preact.md +332 -665
- package/docs/tr/packages/adonis-intlayer/exports.md +50 -0
- package/docs/tr/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/tr/packages/adonis-intlayer/t.md +149 -0
- package/docs/tr/packages/hono-intlayer/exports.md +59 -0
- package/docs/tr/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/tr/packages/hono-intlayer/t.md +268 -0
- package/docs/uk/intlayer_with_adonisjs.md +394 -0
- package/docs/uk/intlayer_with_hono.md +227 -0
- package/docs/uk/intlayer_with_vite+preact.md +228 -626
- package/docs/uk/packages/adonis-intlayer/exports.md +50 -0
- package/docs/uk/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/uk/packages/adonis-intlayer/t.md +149 -0
- package/docs/uk/packages/hono-intlayer/exports.md +59 -0
- package/docs/uk/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/uk/packages/hono-intlayer/t.md +268 -0
- package/docs/vi/intlayer_with_adonisjs.md +394 -0
- package/docs/vi/intlayer_with_hono.md +227 -0
- package/docs/vi/intlayer_with_vite+preact.md +294 -679
- package/docs/vi/packages/adonis-intlayer/exports.md +50 -0
- package/docs/vi/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/vi/packages/adonis-intlayer/t.md +149 -0
- package/docs/vi/packages/hono-intlayer/exports.md +59 -0
- package/docs/vi/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/vi/packages/hono-intlayer/t.md +268 -0
- package/docs/zh/intlayer_with_adonisjs.md +393 -0
- package/docs/zh/intlayer_with_hono.md +418 -0
- package/docs/zh/intlayer_with_vite+preact.md +338 -743
- package/docs/zh/packages/adonis-intlayer/exports.md +50 -0
- package/docs/zh/packages/adonis-intlayer/intlayer.md +54 -0
- package/docs/zh/packages/adonis-intlayer/t.md +149 -0
- package/docs/zh/packages/hono-intlayer/exports.md +59 -0
- package/docs/zh/packages/hono-intlayer/intlayer.md +60 -0
- package/docs/zh/packages/hono-intlayer/t.md +294 -0
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +160 -0
|
@@ -24,7 +24,7 @@ history:
|
|
|
24
24
|
changes: بداية التاريخ
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
# ترجم Vite
|
|
27
|
+
# ترجم موقعك الإلكتروني المبني بـ Vite و Preact باستخدام Intlayer | التدويل (i18n)
|
|
28
28
|
|
|
29
29
|
<Tabs defaultTab="video">
|
|
30
30
|
<Tab label="Video" value="video">
|
|
@@ -45,25 +45,27 @@ history:
|
|
|
45
45
|
</Tab>
|
|
46
46
|
</Tabs>
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
## جدول المحتويات
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
<TOC/>
|
|
51
51
|
|
|
52
52
|
## ما هو Intlayer؟
|
|
53
53
|
|
|
54
|
-
**Intlayer**
|
|
54
|
+
**Intlayer** هو مكتبة تدويل (i18n) مبتكرة ومفتوحة المصدر مصممة لتبسيط دعم اللغات المتعددة في تطبيقات الويب الحديثة.
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
باستخدام Intlayer، يمكنك:
|
|
57
57
|
|
|
58
58
|
- **إدارة الترجمات بسهولة** باستخدام قواميس إعلانية على مستوى المكون.
|
|
59
59
|
- **توطين البيانات الوصفية والمسارات والمحتوى ديناميكيًا**.
|
|
60
60
|
- **ضمان دعم TypeScript** بأنواع مولدة تلقائيًا، مما يحسن الإكمال التلقائي واكتشاف الأخطاء.
|
|
61
|
-
- **الاستفادة من الميزات المتقدمة**، مثل
|
|
61
|
+
- **الاستفادة من الميزات المتقدمة**، مثل الاكتشاف الديناميكي للغة وتبديلها.
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
65
|
## دليل خطوة بخطوة لإعداد Intlayer في تطبيق Vite و Preact
|
|
66
66
|
|
|
67
|
+
راجع [قالب التطبيق](https://github.com/aymericzip/intlayer-vite-preact-template) على GitHub.
|
|
68
|
+
|
|
67
69
|
### الخطوة 1: تثبيت التبعيات
|
|
68
70
|
|
|
69
71
|
قم بتثبيت الحزم اللازمة باستخدام npm:
|
|
@@ -94,17 +96,19 @@ bunx intlayer init
|
|
|
94
96
|
|
|
95
97
|
- **intlayer**
|
|
96
98
|
|
|
97
|
-
الحزمة الأساسية التي توفر أدوات التدويل لإدارة
|
|
99
|
+
الحزمة الأساسية التي توفر أدوات التدويل لإدارة التكوين والترجمة و[إعلان المحتوى](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/dictionary/content_file.md) والترجمة البرمجية و[أوامر CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/cli/index.md).
|
|
98
100
|
|
|
99
101
|
- **preact-intlayer**
|
|
100
|
-
|
|
102
|
+
|
|
103
|
+
الحزمة التي تدمج Intlayer مع تطبيق Preact. توفر مزودي السياق والخطافات لتدويل Preact.
|
|
101
104
|
|
|
102
105
|
- **vite-intlayer**
|
|
103
|
-
|
|
106
|
+
|
|
107
|
+
تتضمن إضافة Vite لدمج Intlayer مع [أداة تجميع Vite](https://vite.dev/guide/why.html#why-bundle-for-production)، بالإضافة إلى وسيط لاكتشاف اللغة المفضلة للمستخدم وإدارة ملفات تعريف الارتباط والتعامل مع إعادة توجيه عناوين URL.
|
|
104
108
|
|
|
105
109
|
### الخطوة 2: تكوين مشروعك
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
أنشئ ملف تكوين لتحديد لغات تطبيقك:
|
|
108
112
|
|
|
109
113
|
```typescript fileName="intlayer.config.ts" codeFormat="typescript"
|
|
110
114
|
import { Locales, type IntlayerConfig } from "intlayer";
|
|
@@ -119,6 +123,10 @@ const config: IntlayerConfig = {
|
|
|
119
123
|
],
|
|
120
124
|
defaultLocale: Locales.ENGLISH,
|
|
121
125
|
},
|
|
126
|
+
routing: {
|
|
127
|
+
mode: "prefix-no-default", // افتراضي: بادئة لجميع اللغات ما عدا اللغة الافتراضية
|
|
128
|
+
storage: ["cookie", "header"], // افتراضي: حفظ اللغة في ملف تعريف الارتباط والكشف من الرأس
|
|
129
|
+
},
|
|
122
130
|
};
|
|
123
131
|
|
|
124
132
|
export default config;
|
|
@@ -138,6 +146,10 @@ const config = {
|
|
|
138
146
|
],
|
|
139
147
|
defaultLocale: Locales.ENGLISH,
|
|
140
148
|
},
|
|
149
|
+
routing: {
|
|
150
|
+
mode: "prefix-no-default", // افتراضي: بادئة لجميع اللغات ما عدا اللغة الافتراضية
|
|
151
|
+
storage: ["cookie", "header"], // افتراضي: حفظ اللغة في ملف تعريف الارتباط والكشف من الرأس
|
|
152
|
+
},
|
|
141
153
|
};
|
|
142
154
|
|
|
143
155
|
export default config;
|
|
@@ -157,16 +169,20 @@ const config = {
|
|
|
157
169
|
],
|
|
158
170
|
defaultLocale: Locales.ENGLISH,
|
|
159
171
|
},
|
|
172
|
+
routing: {
|
|
173
|
+
mode: "prefix-no-default", // افتراضي: بادئة لجميع اللغات ما عدا اللغة الافتراضية
|
|
174
|
+
storage: ["cookie", "header"], // افتراضي: حفظ اللغة في ملف تعريف الارتباط والكشف من الرأس
|
|
175
|
+
},
|
|
160
176
|
};
|
|
161
177
|
|
|
162
178
|
module.exports = config;
|
|
163
179
|
```
|
|
164
180
|
|
|
165
|
-
من خلال ملف التكوين هذا، يمكنك إعداد عناوين URL
|
|
181
|
+
> من خلال ملف التكوين هذا، يمكنك إعداد عناوين URL الموطنة، وأوضاع التوجيه، وخيارات التخزين، وأسماء ملفات تعريف الارتباط، وموقع وامتداد إعلانات المحتوى الخاصة بك، وتعطيل سجلات Intlayer في وحدة التحكم، والمزيد. للحصول على قائمة كاملة بالمعلمات المتاحة، راجع [وثائق التكوين](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/configuration.md).
|
|
166
182
|
|
|
167
183
|
### الخطوة 3: دمج Intlayer في تكوين Vite الخاص بك
|
|
168
184
|
|
|
169
|
-
أضف
|
|
185
|
+
أضف المكون الإضافي intlayer إلى تكوينك.
|
|
170
186
|
|
|
171
187
|
```typescript fileName="vite.config.ts" codeFormat="typescript"
|
|
172
188
|
import { defineConfig } from "vite";
|
|
@@ -201,11 +217,11 @@ module.exports = defineConfig({
|
|
|
201
217
|
});
|
|
202
218
|
```
|
|
203
219
|
|
|
204
|
-
>
|
|
220
|
+
> يُستخدم المكون الإضافي Vite `intlayer()` لدمج Intlayer مع Vite. يضمن بناء ملفات إعلان المحتوى ويراقبها في وضع التطوير. كما يحدد متغيرات بيئة Intlayer داخل تطبيق Vite. بالإضافة إلى ذلك، فإنه يوفر أسماء مستعارة لتحسين الأداء.
|
|
205
221
|
|
|
206
222
|
### الخطوة 4: إعلان المحتوى الخاص بك
|
|
207
223
|
|
|
208
|
-
|
|
224
|
+
أنشئ وأدر إعلانات المحتوى الخاصة بك لتخزين الترجمات:
|
|
209
225
|
|
|
210
226
|
```tsx fileName="src/app.content.tsx" contentDeclarationFormat="typescript"
|
|
211
227
|
import { t, type Dictionary } from "intlayer";
|
|
@@ -222,7 +238,7 @@ const appContent = {
|
|
|
222
238
|
preactLogo: t({
|
|
223
239
|
en: "Preact logo",
|
|
224
240
|
fr: "Logo Preact",
|
|
225
|
-
es: "
|
|
241
|
+
es: "Logo Preact",
|
|
226
242
|
}),
|
|
227
243
|
|
|
228
244
|
title: "Vite + Preact",
|
|
@@ -236,7 +252,7 @@ const appContent = {
|
|
|
236
252
|
edit: t<ComponentChildren>({
|
|
237
253
|
en: (
|
|
238
254
|
<>
|
|
239
|
-
|
|
255
|
+
Edit <code>src/app.tsx</code> and save to test HMR
|
|
240
256
|
</>
|
|
241
257
|
),
|
|
242
258
|
fr: (
|
|
@@ -252,7 +268,7 @@ const appContent = {
|
|
|
252
268
|
}),
|
|
253
269
|
|
|
254
270
|
readTheDocs: t({
|
|
255
|
-
en: "
|
|
271
|
+
en: "Click on the Vite and Preact logos to learn more",
|
|
256
272
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
257
273
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
258
274
|
}),
|
|
@@ -274,13 +290,11 @@ const appContent = {
|
|
|
274
290
|
en: "Vite logo",
|
|
275
291
|
fr: "Logo Vite",
|
|
276
292
|
es: "Logo Vite",
|
|
277
|
-
ar: "شعار Vite",
|
|
278
293
|
}),
|
|
279
294
|
preactLogo: t({
|
|
280
295
|
en: "Preact logo",
|
|
281
296
|
fr: "Logo Preact",
|
|
282
297
|
es: "Logo Preact",
|
|
283
|
-
ar: "شعار Preact",
|
|
284
298
|
}),
|
|
285
299
|
|
|
286
300
|
title: "Vite + Preact",
|
|
@@ -289,14 +303,11 @@ const appContent = {
|
|
|
289
303
|
en: "count is ",
|
|
290
304
|
fr: "le compte est ",
|
|
291
305
|
es: "el recuento es ",
|
|
292
|
-
ar: "العدد هو ",
|
|
293
306
|
}),
|
|
294
307
|
|
|
295
308
|
edit: t({
|
|
296
309
|
en: "Edit src/app.jsx and save to test HMR",
|
|
297
310
|
fr: "Éditez src/app.jsx et enregistrez pour tester HMR",
|
|
298
|
-
ar: "حرر src/app.jsx واحفظ لاختبار HMR",
|
|
299
|
-
}),
|
|
300
311
|
es: "Edita src/app.jsx y guarda para probar HMR",
|
|
301
312
|
}),
|
|
302
313
|
|
|
@@ -304,7 +315,6 @@ const appContent = {
|
|
|
304
315
|
en: "Click on the Vite and Preact logos to learn more",
|
|
305
316
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
306
317
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
307
|
-
ar: "انقر على شعارات Vite و Preact لمعرفة المزيد",
|
|
308
318
|
}),
|
|
309
319
|
},
|
|
310
320
|
};
|
|
@@ -314,7 +324,7 @@ export default appContent;
|
|
|
314
324
|
|
|
315
325
|
```javascript fileName="src/app.content.cjs" contentDeclarationFormat="commonjs"
|
|
316
326
|
const { t } = require("intlayer");
|
|
317
|
-
// const { h } = require('preact'); //
|
|
327
|
+
// const { h } = require('preact'); // مطلوب إذا كنت تستخدم JSX مباشرة في .cjs
|
|
318
328
|
|
|
319
329
|
/** @type {import('intlayer').Dictionary} */
|
|
320
330
|
const appContent = {
|
|
@@ -324,12 +334,11 @@ const appContent = {
|
|
|
324
334
|
en: "Vite logo",
|
|
325
335
|
fr: "Logo Vite",
|
|
326
336
|
es: "Logo Vite",
|
|
327
|
-
ar: "شعار Vite",
|
|
328
337
|
}),
|
|
329
338
|
preactLogo: t({
|
|
330
339
|
en: "Preact logo",
|
|
331
|
-
fr: "
|
|
332
|
-
es: "
|
|
340
|
+
fr: "Logo Preact",
|
|
341
|
+
es: "Logo Preact",
|
|
333
342
|
}),
|
|
334
343
|
|
|
335
344
|
title: "Vite + Preact",
|
|
@@ -338,21 +347,18 @@ const appContent = {
|
|
|
338
347
|
en: "count is ",
|
|
339
348
|
fr: "le compte est ",
|
|
340
349
|
es: "el recuento es ",
|
|
341
|
-
ar: "العدد هو ",
|
|
342
350
|
}),
|
|
343
351
|
|
|
344
352
|
edit: t({
|
|
345
353
|
en: "Edit src/app.tsx and save to test HMR",
|
|
346
354
|
fr: "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
347
355
|
es: "Edita src/app.tsx y guarda para probar HMR",
|
|
348
|
-
ar: "حرر src/app.tsx واحفظ لاختبار HMR",
|
|
349
356
|
}),
|
|
350
357
|
|
|
351
358
|
readTheDocs: t({
|
|
352
359
|
en: "Click on the Vite and Preact logos to learn more",
|
|
353
360
|
fr: "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
354
361
|
es: "Haga clic en los logotipos de Vite y Preact para obtener más información",
|
|
355
|
-
ar: "انقر على شعاري Vite و Preact لمعرفة المزيد",
|
|
356
362
|
}),
|
|
357
363
|
},
|
|
358
364
|
};
|
|
@@ -368,7 +374,6 @@ module.exports = appContent;
|
|
|
368
374
|
"viteLogo": {
|
|
369
375
|
"nodeType": "translation",
|
|
370
376
|
"translation": {
|
|
371
|
-
"ar": "شعار Vite",
|
|
372
377
|
"en": "Vite logo",
|
|
373
378
|
"fr": "Logo Vite",
|
|
374
379
|
"es": "Logo Vite"
|
|
@@ -377,7 +382,6 @@ module.exports = appContent;
|
|
|
377
382
|
"preactLogo": {
|
|
378
383
|
"nodeType": "translation",
|
|
379
384
|
"translation": {
|
|
380
|
-
"ar": "شعار Preact",
|
|
381
385
|
"en": "Preact logo",
|
|
382
386
|
"fr": "Logo Preact",
|
|
383
387
|
"es": "Logo Preact"
|
|
@@ -386,7 +390,6 @@ module.exports = appContent;
|
|
|
386
390
|
"title": {
|
|
387
391
|
"nodeType": "translation",
|
|
388
392
|
"translation": {
|
|
389
|
-
"ar": "Vite + Preact",
|
|
390
393
|
"en": "Vite + Preact",
|
|
391
394
|
"fr": "Vite + Preact",
|
|
392
395
|
"es": "Vite + Preact"
|
|
@@ -395,7 +398,6 @@ module.exports = appContent;
|
|
|
395
398
|
"count": {
|
|
396
399
|
"nodeType": "translation",
|
|
397
400
|
"translation": {
|
|
398
|
-
"ar": "العدد هو ",
|
|
399
401
|
"en": "count is ",
|
|
400
402
|
"fr": "le compte est ",
|
|
401
403
|
"es": "el recuento es "
|
|
@@ -404,7 +406,6 @@ module.exports = appContent;
|
|
|
404
406
|
"edit": {
|
|
405
407
|
"nodeType": "translation",
|
|
406
408
|
"translation": {
|
|
407
|
-
"ar": "حرر src/app.tsx واحفظ لاختبار HMR",
|
|
408
409
|
"en": "Edit src/app.tsx and save to test HMR",
|
|
409
410
|
"fr": "Éditez src/app.tsx et enregistrez pour tester HMR",
|
|
410
411
|
"es": "Edita src/app.tsx y guarda para probar HMR"
|
|
@@ -413,7 +414,6 @@ module.exports = appContent;
|
|
|
413
414
|
"readTheDocs": {
|
|
414
415
|
"nodeType": "translation",
|
|
415
416
|
"translation": {
|
|
416
|
-
"ar": "انقر على شعارات Vite و Preact لمعرفة المزيد",
|
|
417
417
|
"en": "Click on the Vite and Preact logos to learn more",
|
|
418
418
|
"fr": "Cliquez sur les logos Vite et Preact pour en savoir plus",
|
|
419
419
|
"es": "Haga clic en los logotipos de Vite y Preact para obtener más información"
|
|
@@ -423,22 +423,22 @@ module.exports = appContent;
|
|
|
423
423
|
}
|
|
424
424
|
```
|
|
425
425
|
|
|
426
|
-
> يمكن تعريف إعلانات المحتوى الخاصة بك في أي مكان في تطبيقك
|
|
426
|
+
> يمكن تعريف إعلانات المحتوى الخاصة بك في أي مكان في تطبيقك طالما كانت مدرجة في دليل `contentDir` (افتراضيًا، `./src`). وتتطابق مع امتداد ملف إعلان المحتوى (افتراضيًا، `.content.{json,ts,tsx,js,jsx,mjs,cjs}`).
|
|
427
427
|
|
|
428
|
-
> لمزيد من التفاصيل، راجع [
|
|
428
|
+
> لمزيد من التفاصيل، راجع [وثائق إعلان المحتوى](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/dictionary/content_file.md).
|
|
429
429
|
|
|
430
|
-
> إذا كان ملف المحتوى الخاص بك يتضمن كود TSX، فقد تحتاج إلى استيراد `import { h } from "preact";` أو التأكد من
|
|
430
|
+
> إذا كان ملف المحتوى الخاص بك يتضمن كود TSX، فقد تحتاج إلى استيراد `import { h } from "preact";` أو التأكد من ضبط براغما JSX بشكل صحيح لـ Preact.
|
|
431
431
|
|
|
432
432
|
### الخطوة 5: استخدام Intlayer في كودك
|
|
433
433
|
|
|
434
|
-
|
|
434
|
+
قم بالوصول إلى قواميس المحتوى الخاصة بك في جميع أنحاء تطبيقك:
|
|
435
435
|
|
|
436
436
|
```tsx {6,10} fileName="src/app.tsx" codeFormat="typescript"
|
|
437
437
|
import { useState } from "preact/hooks";
|
|
438
438
|
import type { FunctionalComponent } from "preact";
|
|
439
|
-
import preactLogo from "./assets/preact.svg"; //
|
|
439
|
+
import preactLogo from "./assets/preact.svg"; // بفرض أن لديك preact.svg
|
|
440
440
|
import viteLogo from "/vite.svg";
|
|
441
|
-
import "./app.css"; //
|
|
441
|
+
import "./app.css"; // بفرض أن ملف CSS الخاص بك يسمى app.css
|
|
442
442
|
import { IntlayerProvider, useIntlayer } from "preact-intlayer";
|
|
443
443
|
|
|
444
444
|
const AppContent: FunctionalComponent = () => {
|
|
@@ -467,6 +467,12 @@ const AppContent: FunctionalComponent = () => {
|
|
|
467
467
|
</button>
|
|
468
468
|
<p>{content.edit}</p>
|
|
469
469
|
</div>
|
|
470
|
+
{/* محتوى Markdown */}
|
|
471
|
+
<div>{content.myMarkdownContent}</div>
|
|
472
|
+
|
|
473
|
+
{/* محتوى HTML */}
|
|
474
|
+
<div>{content.myHtmlContent}</div>
|
|
475
|
+
|
|
470
476
|
<p class="read-the-docs">{content.readTheDocs}</p>
|
|
471
477
|
</>
|
|
472
478
|
);
|
|
@@ -575,19 +581,19 @@ const App = () => (
|
|
|
575
581
|
module.exports = App;
|
|
576
582
|
```
|
|
577
583
|
|
|
578
|
-
> إذا كنت تريد استخدام المحتوى الخاص بك في خاصية
|
|
584
|
+
> إذا كنت تريد استخدام المحتوى الخاص بك في خاصية `string` ، مثل `alt` ، `title` ، `href` ، `aria-label` ، وما إلى ذلك ، فيجب عليك استدعاء قيمة الدالة ، مثل:
|
|
579
585
|
|
|
580
586
|
> ```jsx
|
|
581
587
|
> <img src={content.image.src.value} alt={content.image.value} />
|
|
582
588
|
> ```
|
|
583
589
|
|
|
584
|
-
> ملاحظة: في Preact، عادةً ما
|
|
590
|
+
> ملاحظة: في Preact، عادةً ما يتم كتابة `className` كـ `class`.
|
|
585
591
|
|
|
586
|
-
> لمعرفة المزيد
|
|
592
|
+
> لمعرفة المزيد حول الخطاف `useIntlayer` ، راجع [الوثائق](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/react-intlayer/useIntlayer.md) (واجهة برمجة التطبيقات مماثلة لـ `preact-intlayer`).
|
|
587
593
|
|
|
588
594
|
### (اختياري) الخطوة 6: تغيير لغة المحتوى الخاص بك
|
|
589
595
|
|
|
590
|
-
لتغيير لغة المحتوى الخاص
|
|
596
|
+
لتغيير لغة المحتوى الخاص بك ، يمكنك استخدام وظيفة `setLocale` التي يوفرها خطاف `useLocale`. تتيح لك هذه الوظيفة تعيين لغة التطبيق وتحديث المحتوى وفقًا لذلك.
|
|
591
597
|
|
|
592
598
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
593
599
|
import type { FunctionalComponent } from "preact";
|
|
@@ -599,7 +605,7 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
599
605
|
|
|
600
606
|
return (
|
|
601
607
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
602
|
-
|
|
608
|
+
Change Language to English
|
|
603
609
|
</button>
|
|
604
610
|
);
|
|
605
611
|
};
|
|
@@ -616,7 +622,7 @@ const LocaleSwitcher = () => {
|
|
|
616
622
|
|
|
617
623
|
return (
|
|
618
624
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
619
|
-
|
|
625
|
+
Change Language to English
|
|
620
626
|
</button>
|
|
621
627
|
);
|
|
622
628
|
};
|
|
@@ -633,7 +639,7 @@ const LocaleSwitcher = () => {
|
|
|
633
639
|
|
|
634
640
|
return (
|
|
635
641
|
<button onClick={() => setLocale(Locales.ENGLISH)}>
|
|
636
|
-
|
|
642
|
+
Change Language to English
|
|
637
643
|
</button>
|
|
638
644
|
);
|
|
639
645
|
};
|
|
@@ -641,11 +647,11 @@ const LocaleSwitcher = () => {
|
|
|
641
647
|
module.exports = LocaleSwitcher;
|
|
642
648
|
```
|
|
643
649
|
|
|
644
|
-
> لمعرفة المزيد
|
|
650
|
+
> لمعرفة المزيد حول الخطاف `useLocale` ، راجع [الوثائق](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/react-intlayer/useLocale.md) (واجهة برمجة التطبيقات مماثلة لـ `preact-intlayer`).
|
|
645
651
|
|
|
646
|
-
### (اختياري) الخطوة 7: إضافة
|
|
652
|
+
### (اختياري) الخطوة 7: إضافة توجيه محلي إلى تطبيقك
|
|
647
653
|
|
|
648
|
-
الغرض من هذه الخطوة هو
|
|
654
|
+
الغرض من هذه الخطوة هو إنشاء مسارات فريدة لكل لغة. هذا مفيد لتحسين محركات البحث (SEO) وعناوين URL الصديقة لمحركات البحث.
|
|
649
655
|
مثال:
|
|
650
656
|
|
|
651
657
|
```plaintext
|
|
@@ -654,407 +660,107 @@ module.exports = LocaleSwitcher;
|
|
|
654
660
|
- https://example.com/fr/about
|
|
655
661
|
```
|
|
656
662
|
|
|
657
|
-
>
|
|
658
|
-
|
|
659
|
-
لإضافة التوجيه المحلي إلى تطبيقك، يمكنك إنشاء مكون `LocaleRouter` الذي يلف مسارات تطبيقك ويتعامل مع التوجيه بناءً على اللغة. إليك مثالًا باستخدام [preact-iso](https://github.com/preactjs/preact-iso):
|
|
660
|
-
|
|
661
|
-
أولاً، قم بتثبيت `preact-iso`:
|
|
662
|
-
|
|
663
|
-
```bash packageManager="npm"
|
|
664
|
-
npm install preact-iso
|
|
665
|
-
npx intlayer init
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
```bash packageManager="pnpm"
|
|
669
|
-
pnpm add preact-iso
|
|
670
|
-
pnpm intlayer init
|
|
671
|
-
```
|
|
663
|
+
> افتراضيًا، لا يتم إضافة بادئة للمسارات للغة الافتراضية. إذا كنت ترغب في إضافة بادئة للغة الافتراضية، يمكنك تعيين خيار `routing.mode` إلى `"prefix-all"` في التكوين الخاص بك. راجع [وثائق التكوين](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/configuration.md) لمزيد من المعلومات.
|
|
672
664
|
|
|
673
|
-
|
|
674
|
-
yarn add preact-iso
|
|
675
|
-
```
|
|
665
|
+
لإضافة توجيه محلي إلى تطبيقك، يمكنك إنشاء مكون `LocaleRouter` يلف مسارات تطبيقك ويتعامل مع التوجيه المستند إلى اللغة. إليك مثال باستخدام [preact-iso](https://github.com/preactjs/preact-iso):
|
|
676
666
|
|
|
677
667
|
```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
|
|
678
|
-
import {
|
|
679
|
-
import { ComponentChildren, FunctionalComponent } from "preact";
|
|
668
|
+
import { localeMap } from "intlayer";
|
|
680
669
|
import { IntlayerProvider } from "preact-intlayer";
|
|
681
|
-
import { LocationProvider,
|
|
682
|
-
import {
|
|
683
|
-
|
|
684
|
-
const { internationalization, middleware } = configuration;
|
|
685
|
-
const { locales, defaultLocale } = internationalization;
|
|
686
|
-
|
|
687
|
-
const Navigate: FunctionalComponent<{ to: string; replace?: boolean }> = ({
|
|
688
|
-
to,
|
|
689
|
-
replace,
|
|
690
|
-
}) => {
|
|
691
|
-
const { route } = useLocation();
|
|
692
|
-
useEffect(() => {
|
|
693
|
-
route(to, replace);
|
|
694
|
-
}, [to, replace, route]);
|
|
695
|
-
return null;
|
|
696
|
-
};
|
|
670
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
671
|
+
import type { ComponentChildren, FunctionalComponent } from "preact";
|
|
697
672
|
|
|
698
673
|
/**
|
|
699
|
-
|
|
700
|
-
*
|
|
701
|
-
* يدير اكتشاف اللغة بناءً على عنوان URL والتحقق من صحتها.
|
|
702
|
-
*/
|
|
703
|
-
const AppLocalized: FunctionalComponent<{
|
|
704
|
-
children: ComponentChildren;
|
|
705
|
-
locale?: Locales;
|
|
706
|
-
}> = ({ children, locale }) => {
|
|
707
|
-
const { path: pathname, url } = useLocation();
|
|
708
|
-
|
|
709
|
-
if (!url) {
|
|
710
|
-
return null;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
const search = url.substring(pathname.length);
|
|
714
|
-
|
|
715
|
-
// تحديد اللغة الحالية، مع الرجوع إلى اللغة الافتراضية إذا لم يتم توفيرها
|
|
716
|
-
const currentLocale = locale ?? defaultLocale;
|
|
717
|
-
|
|
718
|
-
// إزالة بادئة اللغة من المسار لبناء مسار أساسي
|
|
719
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
720
|
-
pathname // مسار URL الحالي
|
|
721
|
-
);
|
|
722
|
-
|
|
723
|
-
/**
|
|
724
|
-
* إذا كانت الخاصية middleware.prefixDefault صحيحة، يجب دائمًا إضافة بادئة للغة الافتراضية.
|
|
725
|
-
*/
|
|
726
|
-
if (middleware.prefixDefault) {
|
|
727
|
-
// التحقق من صحة اللغة
|
|
728
|
-
if (!locale || !locales.includes(locale)) {
|
|
729
|
-
// إعادة التوجيه إلى اللغة الافتراضية مع المسار المحدث
|
|
730
|
-
return (
|
|
731
|
-
<Navigate
|
|
732
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
733
|
-
replace // استبدال الإدخال الحالي في السجل بالإدخال الجديد
|
|
734
|
-
/>
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// تغليف العناصر الفرعية بمزود Intlayer وتعيين اللغة الحالية
|
|
739
|
-
return (
|
|
740
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
741
|
-
);
|
|
742
|
-
} else {
|
|
743
|
-
/**
|
|
744
|
-
* عندما تكون الخاصية middleware.prefixDefault خاطئة، لا تتم إضافة بادئة للغة الافتراضية.
|
|
745
|
-
* تأكد من أن اللغة الحالية صالحة وليست اللغة الافتراضية.
|
|
746
|
-
*/
|
|
747
|
-
if (
|
|
748
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
749
|
-
!locales
|
|
750
|
-
.filter(
|
|
751
|
-
(loc) => loc.toString() !== defaultLocale.toString() // استبعاد اللغة الافتراضية
|
|
752
|
-
)
|
|
753
|
-
.includes(currentLocale) // تحقق مما إذا كانت اللغة الحالية ضمن قائمة اللغات الصالحة
|
|
754
|
-
) {
|
|
755
|
-
// إعادة التوجيه إلى المسار بدون بادئة اللغة
|
|
756
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// لف العناصر الفرعية بمزود Intlayer وتعيين اللغة الحالية
|
|
760
|
-
return (
|
|
761
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
};
|
|
765
|
-
|
|
766
|
-
const RouterContent: FunctionalComponent<{
|
|
767
|
-
children: ComponentChildren;
|
|
768
|
-
}> = ({ children }) => {
|
|
769
|
-
const { path } = useLocation();
|
|
770
|
-
|
|
771
|
-
if (!path) {
|
|
772
|
-
return null;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const pathLocale = path.split("/")[1] as Locales;
|
|
776
|
-
|
|
777
|
-
const isLocaleRoute = locales
|
|
778
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
779
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
780
|
-
|
|
781
|
-
if (isLocaleRoute) {
|
|
782
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
return (
|
|
786
|
-
<AppLocalized
|
|
787
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
788
|
-
>
|
|
789
|
-
{children}
|
|
790
|
-
</AppLocalized>
|
|
791
|
-
);
|
|
792
|
-
};
|
|
793
|
-
|
|
794
|
-
/**
|
|
795
|
-
* مكون راوتر يقوم بإعداد مسارات خاصة بكل لغة.
|
|
796
|
-
* يستخدم preact-iso لإدارة التنقل وعرض المكونات المترجمة.
|
|
674
|
+
* مكون راوتر يقوم بإعداد مسارات خاصة باللغة.
|
|
675
|
+
* يستخدم preact-iso لإدارة التنقل وعرض المكونات المحلية.
|
|
797
676
|
*/
|
|
798
677
|
export const LocaleRouter: FunctionalComponent<{
|
|
799
678
|
children: ComponentChildren;
|
|
800
679
|
}> = ({ children }) => (
|
|
801
680
|
<LocationProvider>
|
|
802
|
-
<
|
|
681
|
+
<Router>
|
|
682
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
683
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
684
|
+
.map(({ locale, urlPrefix }) => (
|
|
685
|
+
<Route
|
|
686
|
+
key={locale}
|
|
687
|
+
path={`${urlPrefix}/:rest*`}
|
|
688
|
+
component={() => (
|
|
689
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
690
|
+
)}
|
|
691
|
+
/>
|
|
692
|
+
))}
|
|
693
|
+
</Router>
|
|
803
694
|
</LocationProvider>
|
|
804
695
|
);
|
|
805
696
|
```
|
|
806
697
|
|
|
807
698
|
```jsx fileName="src/components/LocaleRouter.jsx" codeFormat="esm"
|
|
808
|
-
|
|
809
|
-
import { configuration, getPathWithoutLocale } from "intlayer";
|
|
699
|
+
import { localeMap } from "intlayer";
|
|
810
700
|
import { IntlayerProvider } from "preact-intlayer";
|
|
811
|
-
import { LocationProvider,
|
|
812
|
-
import { useEffect } from "preact/hooks";
|
|
813
|
-
import { h } from "preact"; // مطلوب لـ JSX
|
|
814
|
-
|
|
815
|
-
// تفكيك التكوين من Intlayer
|
|
816
|
-
const { internationalization, middleware } = configuration;
|
|
817
|
-
const { locales, defaultLocale } = internationalization;
|
|
818
|
-
|
|
819
|
-
const Navigate = ({ to, replace }) => {
|
|
820
|
-
const { route } = useLocation();
|
|
821
|
-
useEffect(() => {
|
|
822
|
-
route(to, replace);
|
|
823
|
-
}, [to, replace, route]);
|
|
824
|
-
return null;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* مكون يتعامل مع التوطين ويغلف الأطفال بسياق اللغة المناسب.
|
|
829
|
-
* يدير اكتشاف اللغة بناءً على عنوان URL والتحقق من صحتها.
|
|
830
|
-
*/
|
|
831
|
-
const AppLocalized = ({ children, locale }) => {
|
|
832
|
-
const { path: pathname, url } = useLocation();
|
|
833
|
-
|
|
834
|
-
if (!url) {
|
|
835
|
-
return null;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
const search = url.substring(pathname.length);
|
|
839
|
-
|
|
840
|
-
// تحديد اللغة الحالية، والرجوع إلى اللغة الافتراضية إذا لم يتم توفيرها
|
|
841
|
-
const currentLocale = locale ?? defaultLocale;
|
|
842
|
-
|
|
843
|
-
// إزالة بادئة اللغة من المسار لبناء مسار أساسي
|
|
844
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
845
|
-
pathname // مسار URL الحالي
|
|
846
|
-
);
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
* إذا كانت middleware.prefixDefault صحيحة، يجب دائمًا إضافة بادئة اللغة الافتراضية.
|
|
850
|
-
*/
|
|
851
|
-
if (middleware.prefixDefault) {
|
|
852
|
-
// التحقق من صحة اللغة
|
|
853
|
-
if (!locale || !locales.includes(locale)) {
|
|
854
|
-
// إعادة التوجيه إلى اللغة الافتراضية مع المسار المحدث
|
|
855
|
-
return (
|
|
856
|
-
<Navigate
|
|
857
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
858
|
-
replace // استبدال الإدخال الحالي في السجل بالإدخال الجديد
|
|
859
|
-
/>
|
|
860
|
-
);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// تغليف الأطفال بمزود Intlayer وتعيين اللغة الحالية
|
|
864
|
-
return (
|
|
865
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
866
|
-
);
|
|
867
|
-
} else {
|
|
868
|
-
/**
|
|
869
|
-
* عندما يكون middleware.prefixDefault خاطئًا، لا يتم إضافة بادئة للغة الافتراضية.
|
|
870
|
-
* تأكد من أن اللغة الحالية صالحة وليست اللغة الافتراضية.
|
|
871
|
-
*/
|
|
872
|
-
if (
|
|
873
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
874
|
-
!locales
|
|
875
|
-
.filter(
|
|
876
|
-
(loc) => loc.toString() !== defaultLocale.toString() // استبعاد اللغة الافتراضية
|
|
877
|
-
)
|
|
878
|
-
.includes(currentLocale) // التحقق مما إذا كانت اللغة الحالية ضمن قائمة اللغات الصالحة
|
|
879
|
-
) {
|
|
880
|
-
// إعادة التوجيه إلى المسار بدون بادئة اللغة
|
|
881
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// تغليف العناصر الفرعية بمزود Intlayer وتعيين اللغة الحالية
|
|
885
|
-
return (
|
|
886
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
887
|
-
);
|
|
888
|
-
}
|
|
889
|
-
};
|
|
890
|
-
|
|
891
|
-
const RouterContent = ({ children }) => {
|
|
892
|
-
const { path } = useLocation();
|
|
893
|
-
|
|
894
|
-
if (!path) {
|
|
895
|
-
return null;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
const pathLocale = path.split("/")[1];
|
|
899
|
-
|
|
900
|
-
const isLocaleRoute = locales
|
|
901
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
902
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
903
|
-
|
|
904
|
-
if (isLocaleRoute) {
|
|
905
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
return (
|
|
909
|
-
<AppLocalized
|
|
910
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
911
|
-
>
|
|
912
|
-
{children}
|
|
913
|
-
</AppLocalized>
|
|
914
|
-
);
|
|
915
|
-
};
|
|
701
|
+
import { LocationProvider, Router, Route } from "preact-iso";
|
|
916
702
|
|
|
917
703
|
/**
|
|
918
|
-
* مكون راوتر يقوم بإعداد مسارات خاصة
|
|
919
|
-
* يستخدم preact-iso لإدارة التنقل وعرض المكونات
|
|
704
|
+
* مكون راوتر يقوم بإعداد مسارات خاصة باللغة.
|
|
705
|
+
* يستخدم preact-iso لإدارة التنقل وعرض المكونات المحلية.
|
|
920
706
|
*/
|
|
921
707
|
export const LocaleRouter = ({ children }) => (
|
|
922
708
|
<LocationProvider>
|
|
923
|
-
<
|
|
709
|
+
<Router>
|
|
710
|
+
{localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
711
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
712
|
+
.map(({ locale, urlPrefix }) => (
|
|
713
|
+
<Route
|
|
714
|
+
key={locale}
|
|
715
|
+
path={`${urlPrefix}/:rest*`}
|
|
716
|
+
component={() => (
|
|
717
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
718
|
+
)}
|
|
719
|
+
/>
|
|
720
|
+
))}
|
|
721
|
+
</Router>
|
|
924
722
|
</LocationProvider>
|
|
925
723
|
);
|
|
926
724
|
```
|
|
927
725
|
|
|
928
726
|
```jsx fileName="src/components/LocaleRouter.cjsx" codeFormat="commonjs"
|
|
929
|
-
|
|
930
|
-
const { configuration, getPathWithoutLocale } = require("intlayer");
|
|
727
|
+
const { localeMap } = require("intlayer");
|
|
931
728
|
const { IntlayerProvider } = require("preact-intlayer");
|
|
932
|
-
const { LocationProvider,
|
|
933
|
-
const { useEffect } = require("preact/hooks");
|
|
934
|
-
const { h } = require("preact"); // مطلوب لـ JSX
|
|
935
|
-
|
|
936
|
-
// تفكيك التهيئة من Intlayer
|
|
937
|
-
const { internationalization, middleware } = configuration;
|
|
938
|
-
const { locales, defaultLocale } = internationalization;
|
|
939
|
-
|
|
940
|
-
const Navigate = ({ to, replace }) => {
|
|
941
|
-
const { route } = useLocation();
|
|
942
|
-
useEffect(() => {
|
|
943
|
-
route(to, replace);
|
|
944
|
-
}, [to, replace, route]);
|
|
945
|
-
return null;
|
|
946
|
-
};
|
|
729
|
+
const { LocationProvider, Router, Route } = require("preact-iso");
|
|
947
730
|
|
|
948
731
|
/**
|
|
949
|
-
* مكون
|
|
950
|
-
*
|
|
732
|
+
* مكون راوتر يقوم بإعداد مسارات خاصة باللغة.
|
|
733
|
+
* يستخدم preact-iso لإدارة التنقل وعرض المكونات المحلية.
|
|
951
734
|
*/
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
);
|
|
968
|
-
|
|
969
|
-
/**
|
|
970
|
-
* إذا كانت middleware.prefixDefault صحيحة، يجب دائمًا إضافة بادئة اللغة الافتراضية.
|
|
971
|
-
*/
|
|
972
|
-
if (middleware.prefixDefault) {
|
|
973
|
-
// التحقق من صحة اللغة
|
|
974
|
-
if (!locale || !locales.includes(locale)) {
|
|
975
|
-
// إعادة التوجيه إلى اللغة الافتراضية مع المسار المحدث
|
|
976
|
-
return (
|
|
977
|
-
<Navigate
|
|
978
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
979
|
-
replace // استبدال الإدخال الحالي في السجل بالإدخال الجديد
|
|
980
|
-
/>
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// تغليف العناصر الفرعية بـ IntlayerProvider وتعيين اللغة الحالية
|
|
985
|
-
return (
|
|
986
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
987
|
-
);
|
|
988
|
-
} else {
|
|
989
|
-
/**
|
|
990
|
-
* عندما تكون middleware.prefixDefault خاطئة، لا يتم إضافة بادئة اللغة الافتراضية.
|
|
991
|
-
* تأكد من أن اللغة الحالية صالحة وليست اللغة الافتراضية.
|
|
992
|
-
*/
|
|
993
|
-
if (
|
|
994
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
995
|
-
!locales
|
|
996
|
-
.filter(
|
|
997
|
-
(loc) => loc.toString() !== defaultLocale.toString() // استبعاد اللغة الافتراضية
|
|
735
|
+
const LocaleRouter = ({ children }) =>
|
|
736
|
+
h(
|
|
737
|
+
LocationProvider,
|
|
738
|
+
{},
|
|
739
|
+
h(
|
|
740
|
+
Router,
|
|
741
|
+
{},
|
|
742
|
+
localeMap(({ locale, urlPrefix }) => ({ locale, urlPrefix }))
|
|
743
|
+
.sort((a, b) => b.urlPrefix.length - a.urlPrefix.length)
|
|
744
|
+
.map(({ locale, urlPrefix }) =>
|
|
745
|
+
h(Route, {
|
|
746
|
+
key: locale,
|
|
747
|
+
path: `${urlPrefix}/:rest*`,
|
|
748
|
+
component: () => h(IntlayerProvider, { locale }, children),
|
|
749
|
+
})
|
|
998
750
|
)
|
|
999
|
-
|
|
1000
|
-
) {
|
|
1001
|
-
// إعادة التوجيه إلى المسار بدون بادئة اللغة
|
|
1002
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
// لف العناصر الفرعية بمزود Intlayer وتعيين اللغة الحالية
|
|
1006
|
-
return (
|
|
1007
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
1008
|
-
);
|
|
1009
|
-
}
|
|
1010
|
-
};
|
|
1011
|
-
|
|
1012
|
-
const RouterContent = ({ children }) => {
|
|
1013
|
-
const { path } = useLocation();
|
|
1014
|
-
|
|
1015
|
-
if (!path) {
|
|
1016
|
-
return null;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
const pathLocale = path.split("/")[1];
|
|
1020
|
-
|
|
1021
|
-
const isLocaleRoute = locales
|
|
1022
|
-
.filter((locale) => middleware.prefixDefault || locale !== defaultLocale)
|
|
1023
|
-
.some((locale) => locale.toString() === pathLocale);
|
|
1024
|
-
|
|
1025
|
-
if (isLocaleRoute) {
|
|
1026
|
-
return <AppLocalized locale={pathLocale}>{children}</AppLocalized>;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
return (
|
|
1030
|
-
<AppLocalized
|
|
1031
|
-
locale={!middleware.prefixDefault ? defaultLocale : undefined}
|
|
1032
|
-
>
|
|
1033
|
-
{children}
|
|
1034
|
-
</AppLocalized>
|
|
751
|
+
)
|
|
1035
752
|
);
|
|
1036
|
-
};
|
|
1037
|
-
|
|
1038
|
-
/**
|
|
1039
|
-
* مكون راوتر يقوم بإعداد مسارات خاصة بكل لغة.
|
|
1040
|
-
* يستخدم preact-iso لإدارة التنقل وعرض المكونات المترجمة.
|
|
1041
|
-
*/
|
|
1042
|
-
const LocaleRouter = ({ children }) => (
|
|
1043
|
-
<LocationProvider>
|
|
1044
|
-
<RouterContent>{children}</RouterContent>
|
|
1045
|
-
</LocationProvider>
|
|
1046
|
-
);
|
|
1047
753
|
|
|
1048
754
|
module.exports = { LocaleRouter };
|
|
1049
755
|
```
|
|
1050
756
|
|
|
1051
|
-
|
|
757
|
+
بعد ذلك، يمكنك استخدام مكون `LocaleRouter` في تطبيقك:
|
|
1052
758
|
|
|
1053
759
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1054
760
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1055
761
|
import type { FunctionalComponent } from "preact";
|
|
1056
|
-
|
|
1057
|
-
// ... مكون AppContent الخاص بك
|
|
762
|
+
|
|
763
|
+
// ... مكون AppContent الخاص بك
|
|
1058
764
|
|
|
1059
765
|
const App: FunctionalComponent = () => (
|
|
1060
766
|
<LocaleRouter>
|
|
@@ -1067,7 +773,8 @@ export default App;
|
|
|
1067
773
|
|
|
1068
774
|
```jsx fileName="src/app.jsx" codeFormat="esm"
|
|
1069
775
|
import { LocaleRouter } from "./components/LocaleRouter";
|
|
1070
|
-
|
|
776
|
+
|
|
777
|
+
// ... مكون AppContent الخاص بك
|
|
1071
778
|
|
|
1072
779
|
const App = () => (
|
|
1073
780
|
<LocaleRouter>
|
|
@@ -1080,7 +787,8 @@ export default App;
|
|
|
1080
787
|
|
|
1081
788
|
```jsx fileName="src/app.cjsx" codeFormat="commonjs"
|
|
1082
789
|
const { LocaleRouter } = require("./components/LocaleRouter");
|
|
1083
|
-
|
|
790
|
+
|
|
791
|
+
// ... مكون AppContent الخاص بك
|
|
1084
792
|
|
|
1085
793
|
const App = () => (
|
|
1086
794
|
<LocaleRouter>
|
|
@@ -1091,47 +799,12 @@ const App = () => (
|
|
|
1091
799
|
module.exports = App;
|
|
1092
800
|
```
|
|
1093
801
|
|
|
1094
|
-
بالتوازي، يمكنك أيضًا استخدام `intlayerProxy` لإضافة التوجيه من جانب الخادم إلى تطبيقك. سيقوم هذا المكون الإضافي تلقائيًا بالكشف عن اللغة الحالية بناءً على عنوان URL وتعيين ملف تعريف الارتباط المناسب للغة. إذا لم يتم تحديد لغة، سيحدد المكون الإضافي اللغة الأنسب بناءً على تفضيلات لغة متصفح المستخدم. إذا لم يتم الكشف عن أي لغة، فسيتم إعادة التوجيه إلى اللغة الافتراضية.
|
|
1095
|
-
|
|
1096
|
-
```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
|
|
1097
|
-
import { defineConfig } from "vite";
|
|
1098
|
-
import preact from "@preact/preset-vite";
|
|
1099
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1100
|
-
|
|
1101
|
-
// https://vitejs.dev/config/
|
|
1102
|
-
export default defineConfig({
|
|
1103
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1104
|
-
});
|
|
1105
|
-
```
|
|
1106
|
-
|
|
1107
|
-
```javascript {3,7} fileName="vite.config.mjs" codeFormat="esm"
|
|
1108
|
-
import { defineConfig } from "vite";
|
|
1109
|
-
import preact from "@preact/preset-vite";
|
|
1110
|
-
import { intlayer, intlayerProxy } from "vite-intlayer";
|
|
1111
|
-
|
|
1112
|
-
// https://vitejs.dev/config/
|
|
1113
|
-
export default defineConfig({
|
|
1114
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1115
|
-
});
|
|
1116
|
-
```
|
|
1117
|
-
|
|
1118
|
-
```javascript {3,7} fileName="vite.config.cjs" codeFormat="commonjs"
|
|
1119
|
-
const { defineConfig } = require("vite");
|
|
1120
|
-
const preact = require("@preact/preset-vite");
|
|
1121
|
-
const { intlayer, intlayerProxy } = require("vite-intlayer");
|
|
1122
|
-
|
|
1123
|
-
// https://vitejs.dev/config/
|
|
1124
|
-
module.exports = defineConfig({
|
|
1125
|
-
plugins: [preact(), intlayer(), intlayerProxy()],
|
|
1126
|
-
});
|
|
1127
|
-
```
|
|
1128
|
-
|
|
1129
802
|
### (اختياري) الخطوة 8: تغيير عنوان URL عند تغيير اللغة
|
|
1130
803
|
|
|
1131
|
-
لتغيير عنوان URL عند تغيير اللغة، يمكنك استخدام
|
|
804
|
+
لتغيير عنوان URL عند تغيير اللغة، يمكنك استخدام خاصية `onLocaleChange` التي يوفرها خطاف `useLocale`. بالتوازي، يمكنك استخدام طريقة `route` من `useLocation` في `preact-iso` لتحديث مسار URL.
|
|
1132
805
|
|
|
1133
806
|
```tsx fileName="src/components/LocaleSwitcher.tsx" codeFormat="typescript"
|
|
1134
|
-
import { useLocation
|
|
807
|
+
import { useLocation } from "preact-iso";
|
|
1135
808
|
import {
|
|
1136
809
|
Locales,
|
|
1137
810
|
getHTMLTextDir,
|
|
@@ -1142,16 +815,15 @@ import { useLocale } from "preact-intlayer";
|
|
|
1142
815
|
import type { FunctionalComponent } from "preact";
|
|
1143
816
|
|
|
1144
817
|
const LocaleSwitcher: FunctionalComponent = () => {
|
|
1145
|
-
const
|
|
818
|
+
const { url, route } = useLocation();
|
|
1146
819
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1147
820
|
onLocaleChange: (newLocale) => {
|
|
1148
|
-
|
|
1149
|
-
// بناء عنوان URL مع اللغة المحدّثة
|
|
821
|
+
// بناء عنوان URL باللغة المحدثة
|
|
1150
822
|
// مثال: /es/about?foo=bar
|
|
1151
|
-
const pathWithLocale = getLocalizedUrl(
|
|
823
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1152
824
|
|
|
1153
825
|
// تحديث مسار URL
|
|
1154
|
-
route(pathWithLocale, true); // true للاستبدال
|
|
826
|
+
route(pathWithLocale, true); // true للاستبدال (replace)
|
|
1155
827
|
},
|
|
1156
828
|
});
|
|
1157
829
|
|
|
@@ -1161,7 +833,7 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
1161
833
|
<div id="localePopover" popover="auto">
|
|
1162
834
|
{availableLocales.map((localeItem) => (
|
|
1163
835
|
<a
|
|
1164
|
-
href={getLocalizedUrl(
|
|
836
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1165
837
|
hreflang={localeItem}
|
|
1166
838
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1167
839
|
onClick={(e) => {
|
|
@@ -1172,19 +844,19 @@ const LocaleSwitcher: FunctionalComponent = () => {
|
|
|
1172
844
|
key={localeItem}
|
|
1173
845
|
>
|
|
1174
846
|
<span>
|
|
1175
|
-
{/* اللغة -
|
|
847
|
+
{/* اللغة - مثلاً FR */}
|
|
1176
848
|
{localeItem}
|
|
1177
849
|
</span>
|
|
1178
850
|
<span>
|
|
1179
|
-
{/* اللغة بلغتها الأصلية -
|
|
851
|
+
{/* اللغة بلغتها الأصلية - مثلاً Français */}
|
|
1180
852
|
{getLocaleName(localeItem, localeItem)}
|
|
1181
853
|
</span>
|
|
1182
854
|
<span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
|
|
1183
|
-
{/* اللغة باللغة الحالية -
|
|
855
|
+
{/* اللغة باللغة الحالية - مثلاً Francés مع تعيين اللغة الحالية إلى Locales.SPANISH */}
|
|
1184
856
|
{getLocaleName(localeItem, locale)}
|
|
1185
857
|
</span>
|
|
1186
858
|
<span dir="ltr" lang={Locales.ENGLISH}>
|
|
1187
|
-
{/* اللغة بالإنجليزية -
|
|
859
|
+
{/* اللغة بالإنجليزية - مثلاً French */}
|
|
1188
860
|
{getLocaleName(localeItem, Locales.ENGLISH)}
|
|
1189
861
|
</span>
|
|
1190
862
|
</a>
|
|
@@ -1198,7 +870,7 @@ export default LocaleSwitcher;
|
|
|
1198
870
|
```
|
|
1199
871
|
|
|
1200
872
|
```jsx fileName="src/components/LocaleSwitcher.jsx" codeFormat="esm"
|
|
1201
|
-
import { useLocation
|
|
873
|
+
import { useLocation } from "preact-iso";
|
|
1202
874
|
import {
|
|
1203
875
|
Locales,
|
|
1204
876
|
getHTMLTextDir,
|
|
@@ -1206,14 +878,12 @@ import {
|
|
|
1206
878
|
getLocalizedUrl,
|
|
1207
879
|
} from "intlayer";
|
|
1208
880
|
import { useLocale } from "preact-intlayer";
|
|
1209
|
-
import { h } from "preact"; // للـ JSX
|
|
1210
881
|
|
|
1211
882
|
const LocaleSwitcher = () => {
|
|
1212
|
-
const
|
|
883
|
+
const { url, route } = useLocation();
|
|
1213
884
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1214
885
|
onLocaleChange: (newLocale) => {
|
|
1215
|
-
const
|
|
1216
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
886
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1217
887
|
route(pathWithLocale, true);
|
|
1218
888
|
},
|
|
1219
889
|
});
|
|
@@ -1224,7 +894,7 @@ const LocaleSwitcher = () => {
|
|
|
1224
894
|
<div id="localePopover" popover="auto">
|
|
1225
895
|
{availableLocales.map((localeItem) => (
|
|
1226
896
|
<a
|
|
1227
|
-
href={getLocalizedUrl(
|
|
897
|
+
href={getLocalizedUrl(url, localeItem)}
|
|
1228
898
|
hreflang={localeItem}
|
|
1229
899
|
aria-current={locale === localeItem ? "page" : undefined}
|
|
1230
900
|
onClick={(e) => {
|
|
@@ -1252,7 +922,7 @@ export default LocaleSwitcher;
|
|
|
1252
922
|
```
|
|
1253
923
|
|
|
1254
924
|
```jsx fileName="src/components/LocaleSwitcher.cjsx" codeFormat="commonjs"
|
|
1255
|
-
const { useLocation
|
|
925
|
+
const { useLocation } = require("preact-iso");
|
|
1256
926
|
const {
|
|
1257
927
|
Locales,
|
|
1258
928
|
getHTMLTextDir,
|
|
@@ -1260,45 +930,51 @@ const {
|
|
|
1260
930
|
getLocalizedUrl,
|
|
1261
931
|
} = require("intlayer");
|
|
1262
932
|
const { useLocale } = require("preact-intlayer");
|
|
1263
|
-
const { h } = require("preact"); // للـ JSX
|
|
1264
933
|
|
|
1265
934
|
const LocaleSwitcher = () => {
|
|
1266
|
-
const
|
|
935
|
+
const { url, route } = useLocation();
|
|
1267
936
|
const { locale, availableLocales, setLocale } = useLocale({
|
|
1268
937
|
onLocaleChange: (newLocale) => {
|
|
1269
|
-
const
|
|
1270
|
-
const pathWithLocale = getLocalizedUrl(currentFullPath, newLocale);
|
|
938
|
+
const pathWithLocale = getLocalizedUrl(url, newLocale);
|
|
1271
939
|
route(pathWithLocale, true);
|
|
1272
940
|
},
|
|
1273
941
|
});
|
|
1274
942
|
|
|
1275
|
-
return (
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
943
|
+
return h(
|
|
944
|
+
"div",
|
|
945
|
+
{},
|
|
946
|
+
h("button", { popovertarget: "localePopover" }, getLocaleName(locale)),
|
|
947
|
+
h(
|
|
948
|
+
"div",
|
|
949
|
+
{ id: "localePopover", popover: "auto" },
|
|
950
|
+
availableLocales.map((localeItem) =>
|
|
951
|
+
h(
|
|
952
|
+
"a",
|
|
953
|
+
{
|
|
954
|
+
href: getLocalizedUrl(url, localeItem),
|
|
955
|
+
hreflang: localeItem,
|
|
956
|
+
"aria-current": locale === localeItem ? "page" : undefined,
|
|
957
|
+
onClick: (e) => {
|
|
1285
958
|
e.preventDefault();
|
|
1286
959
|
setLocale(localeItem);
|
|
1287
|
-
}
|
|
1288
|
-
key
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
960
|
+
},
|
|
961
|
+
key: localeItem,
|
|
962
|
+
},
|
|
963
|
+
h("span", {}, localeItem),
|
|
964
|
+
h("span", {}, getLocaleName(localeItem, localeItem)),
|
|
965
|
+
h(
|
|
966
|
+
"span",
|
|
967
|
+
{ dir: getHTMLTextDir(localeItem), lang: localeItem },
|
|
968
|
+
getLocaleName(localeItem, locale)
|
|
969
|
+
),
|
|
970
|
+
h(
|
|
971
|
+
"span",
|
|
972
|
+
{ dir: "ltr", lang: Locales.ENGLISH },
|
|
973
|
+
getLocaleName(localeItem, Locales.ENGLISH)
|
|
974
|
+
)
|
|
975
|
+
)
|
|
976
|
+
)
|
|
977
|
+
)
|
|
1302
978
|
);
|
|
1303
979
|
};
|
|
1304
980
|
|
|
@@ -1307,34 +983,21 @@ module.exports = LocaleSwitcher;
|
|
|
1307
983
|
|
|
1308
984
|
> مراجع التوثيق:
|
|
1309
985
|
>
|
|
1310
|
-
> > - [`useLocale`
|
|
1311
|
-
>
|
|
1312
|
-
> - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocaleName.md)
|
|
1313
|
-
> - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocalizedUrl.md)
|
|
1314
|
-
> - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getHTMLTextDir.md)
|
|
1315
|
-
> - [`hreflang` attribute](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr)
|
|
1316
|
-
> - [`lang` attribute](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/lang)
|
|
1317
|
-
> - [`dir` attribute](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/dir)
|
|
1318
|
-
> - [`aria-current` attribute](https://developer.mozilla.org/ar/docs/Web/Accessibility/ARIA/Attributes/aria-current)
|
|
1319
|
-
> - [واجهة برمجة تطبيقات Popover](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) > > - [`useLocale` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/react-intlayer/useLocale.md) (واجهة برمجة التطبيقات مشابهة لـ `preact-intlayer`) > - [`getLocaleName` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocaleName.md) > - [`getLocalizedUrl` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocalizedUrl.md) > - [`getHTMLTextDir` hook](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getHTMLTextDir.md) > - [خاصية `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=ar) > - [خاصية `lang`](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/lang) > - [خاصية `dir`](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/dir) > - [خاصية `aria-current`](https://developer.mozilla.org/ar/docs/Web/Accessibility/ARIA/Attributes/aria-current) > - [واجهة برمجة التطبيقات Popover](https://developer.mozilla.org/ar/docs/Web/API/Popover_API)
|
|
986
|
+
> > - [خطاف `useLocale`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/react-intlayer/useLocale.md) (واجهة برمجة التطبيقات مماثلة لـ `preact-intlayer`)> - [خطاف `getLocaleName`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocaleName.md)> - [خطاف `getLocalizedUrl`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getLocalizedUrl.md)> - [خطاف `getHTMLTextDir`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/packages/intlayer/getHTMLTextDir.md)> - [خاصية `hreflang`](https://developers.google.com/search/docs/specialty/international/localized-versions?hl=ar)> - [خاصية `lang`](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/lang)> - [خاصية `dir`](https://developer.mozilla.org/ar/docs/Web/HTML/Global_attributes/dir)> - [خاصية `aria-current`](https://developer.mozilla.org/ar/docs/Web/Accessibility/ARIA/Attributes/aria-current)> - [واجهة برمجة تطبيقات Popover](https://developer.mozilla.org/ar/docs/Web/API/Popover_API)
|
|
1320
987
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
---
|
|
988
|
+
### (اختياري) الخطوة 9: تبديل سمات اللغة والاتجاه لـ HTML
|
|
1324
989
|
|
|
1325
|
-
|
|
990
|
+
عندما يدعم تطبيقك لغات متعددة، من الضروري تحديث سمتي `lang` و `dir` في وسم `<html>` لتتوافق مع اللغة الحالية. القيام بذلك يضمن:
|
|
1326
991
|
|
|
1327
|
-
|
|
992
|
+
- **إمكانية الوصول**: تعتمد أجهزة قراءة الشاشة والتقنيات المساعدة على سمة `lang` الصحيحة لنطق وتفسير المحتوى بدقة.
|
|
993
|
+
- **عرض النص**: تضمن سمة `dir` (الاتجاه) عرض النص بالترتيب الصحيح (على سبيل المثال، من اليسار إلى اليمين للغة الإنجليزية، ومن اليمين إلى اليسار للغة العربية أو العبرية)، وهو أمر أساسي لسهولة القراءة.
|
|
994
|
+
- **تحسين محركات البحث (SEO)**: تستخدم محركات البحث سمة `lang` لتحديد لغة صفحتك، مما يساعد في تقديم المحتوى المحلي المناسب في نتائج البحث.
|
|
1328
995
|
|
|
1329
|
-
|
|
1330
|
-
- **عرض النص**: تضمن خاصية `dir` (الاتجاه) عرض النص بالترتيب الصحيح (مثلًا من اليسار إلى اليمين للإنجليزية، ومن اليمين إلى اليسار للعربية أو العبرية)، وهو أمر أساسي لسهولة القراءة.
|
|
1331
|
-
- **تحسين محركات البحث (SEO)**: تستخدم محركات البحث الخاصية `lang` لتحديد لغة صفحتك، مما يساعد في تقديم المحتوى المحلي المناسب في نتائج البحث.
|
|
996
|
+
من خلال تحديث هذه السمات ديناميكيًا عند تغيير اللغة، تضمن تجربة متسقة وسهلة الوصول للمستخدمين عبر جميع اللغات المدعومة.
|
|
1332
997
|
|
|
1333
|
-
|
|
998
|
+
#### تنفيذ الخطاف (Hook)
|
|
1334
999
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
قم بإنشاء hook مخصص لإدارة خصائص HTML. يستمع الـ hook لتغييرات اللغة ويحدث الخصائص وفقًا لذلك:
|
|
1000
|
+
أنشئ خطافًا مخصصًا لإدارة سمات HTML. يستمع الخطاف لتغييرات اللغة ويحدث السمات وفقًا لذلك:
|
|
1338
1001
|
|
|
1339
1002
|
```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx" codeFormat="typescript"
|
|
1340
1003
|
import { useEffect } from "preact/hooks";
|
|
@@ -1342,17 +1005,17 @@ import { useLocale } from "preact-intlayer";
|
|
|
1342
1005
|
import { getHTMLTextDir } from "intlayer";
|
|
1343
1006
|
|
|
1344
1007
|
/**
|
|
1345
|
-
* يقوم بتحديث
|
|
1346
|
-
* - `lang`:
|
|
1347
|
-
* - `dir`: يضمن ترتيب القراءة الصحيح (
|
|
1008
|
+
* يقوم بتحديث سمتي `lang` و `dir` لعنصر HTML <html> بناءً على اللغة الحالية.
|
|
1009
|
+
* - `lang`: يخبر المتصفحات ومحركات البحث بلغة الصفحة.
|
|
1010
|
+
* - `dir`: يضمن ترتيب القراءة الصحيح (مثلاً، 'ltr' للإنجليزية، 'rtl' للعربية).
|
|
1348
1011
|
*
|
|
1349
|
-
* هذا التحديث الديناميكي ضروري لعرض النص بشكل صحيح،
|
|
1012
|
+
* هذا التحديث الديناميكي ضروري لعرض النص بشكل صحيح، وإمكانية الوصول، وتحسين محركات البحث (SEO).
|
|
1350
1013
|
*/
|
|
1351
1014
|
export const useI18nHTMLAttributes = () => {
|
|
1352
1015
|
const { locale } = useLocale();
|
|
1353
1016
|
|
|
1354
1017
|
useEffect(() => {
|
|
1355
|
-
// تحديث
|
|
1018
|
+
// تحديث سمة اللغة إلى اللغة الحالية.
|
|
1356
1019
|
document.documentElement.lang = locale;
|
|
1357
1020
|
|
|
1358
1021
|
// تعيين اتجاه النص بناءً على اللغة الحالية.
|
|
@@ -1367,7 +1030,7 @@ import { useLocale } from "preact-intlayer";
|
|
|
1367
1030
|
import { getHTMLTextDir } from "intlayer";
|
|
1368
1031
|
|
|
1369
1032
|
/**
|
|
1370
|
-
* يقوم بتحديث
|
|
1033
|
+
* يقوم بتحديث سمتي `lang` و `dir` لعنصر HTML <html> بناءً على اللغة الحالية.
|
|
1371
1034
|
*/
|
|
1372
1035
|
export const useI18nHTMLAttributes = () => {
|
|
1373
1036
|
const { locale } = useLocale();
|
|
@@ -1385,7 +1048,7 @@ const { useLocale } = require("preact-intlayer");
|
|
|
1385
1048
|
const { getHTMLTextDir } = require("intlayer");
|
|
1386
1049
|
|
|
1387
1050
|
/**
|
|
1388
|
-
* يقوم بتحديث
|
|
1051
|
+
* يقوم بتحديث سمتي `lang` و `dir` لعنصر HTML <html> بناءً على اللغة الحالية.
|
|
1389
1052
|
*/
|
|
1390
1053
|
const useI18nHTMLAttributes = () => {
|
|
1391
1054
|
const { locale } = useLocale();
|
|
@@ -1399,9 +1062,9 @@ const useI18nHTMLAttributes = () => {
|
|
|
1399
1062
|
module.exports = { useI18nHTMLAttributes };
|
|
1400
1063
|
```
|
|
1401
1064
|
|
|
1402
|
-
#### استخدام
|
|
1065
|
+
#### استخدام الخطاف في تطبيقك
|
|
1403
1066
|
|
|
1404
|
-
|
|
1067
|
+
قم بدمج الخطاف في مكونك الرئيسي بحيث يتم تحديث سمات HTML كلما تغيرت اللغة:
|
|
1405
1068
|
|
|
1406
1069
|
```tsx fileName="src/app.tsx" codeFormat="typescript"
|
|
1407
1070
|
import type { FunctionalComponent } from "preact";
|
|
@@ -1411,10 +1074,10 @@ import "./app.css";
|
|
|
1411
1074
|
// تعريف AppContent من الخطوة 5
|
|
1412
1075
|
|
|
1413
1076
|
const AppWithHooks: FunctionalComponent = () => {
|
|
1414
|
-
// تطبيق
|
|
1077
|
+
// تطبيق الخطاف لتحديث سمتي lang و dir في وسم <html> بناءً على اللغة.
|
|
1415
1078
|
useI18nHTMLAttributes();
|
|
1416
1079
|
|
|
1417
|
-
//
|
|
1080
|
+
// بفرض أن AppContent هو مكون عرض المحتوى الرئيسي الخاص بك من الخطوة 5
|
|
1418
1081
|
return <AppContent />;
|
|
1419
1082
|
};
|
|
1420
1083
|
|
|
@@ -1467,203 +1130,182 @@ const App = () => (
|
|
|
1467
1130
|
module.exports = App;
|
|
1468
1131
|
```
|
|
1469
1132
|
|
|
1470
|
-
بتطبيق هذه التغييرات، سيقوم تطبيقك بـ:
|
|
1471
|
-
|
|
1472
|
-
- التأكد من أن خاصية **اللغة** (`lang`) تعكس اللغة الحالية بشكل صحيح، وهو أمر مهم لتحسين محركات البحث وسلوك المتصفح.
|
|
1473
|
-
- ضبط **اتجاه النص** (`dir`) وفقًا للغة المختارة، مما يعزز من قابلية القراءة وسهولة الاستخدام للغات ذات اتجاهات قراءة مختلفة.
|
|
1474
|
-
- توفير تجربة أكثر **سهولة في الوصول**، حيث تعتمد تقنيات المساعدة على هذه السمات لتعمل بشكل مثالي.
|
|
1475
|
-
|
|
1476
1133
|
### (اختياري) الخطوة 10: إنشاء مكون رابط محلي
|
|
1477
1134
|
|
|
1478
|
-
لضمان أن
|
|
1135
|
+
لضمان أن تنقل تطبيقك يحترم اللغة الحالية، يمكنك إنشاء مكون `Link` مخصص. يقوم هذا المكون تلقائيًا بإضافة بادئة اللغة الحالية إلى عناوين URL الداخلية.
|
|
1479
1136
|
|
|
1480
1137
|
هذا السلوك مفيد لعدة أسباب:
|
|
1481
1138
|
|
|
1482
|
-
- **تحسين محركات البحث وتجربة المستخدم**: تساعد عناوين URL
|
|
1483
|
-
- **الاتساق**: باستخدام رابط محلي في جميع أنحاء تطبيقك، تضمن بقاء التنقل ضمن اللغة الحالية، مما يمنع
|
|
1484
|
-
- **قابلية الصيانة**:
|
|
1139
|
+
- **تحسين محركات البحث وتجربة المستخدم**: تساعد عناوين URL الموطنة محركات البحث على فهرسة الصفحات الخاصة بلغات معينة بشكل صحيح وتوفر للمستخدمين محتوى بلغتهم المفضلة.
|
|
1140
|
+
- **الاتساق**: باستخدام رابط محلي في جميع أنحاء تطبيقك، فإنك تضمن بقاء التنقل ضمن اللغة الحالية، مما يمنع تبديلات اللغة غير المتوقعة.
|
|
1141
|
+
- **قابلية الصيانة**: تبسيط إدارة عناوين URL من خلال مركزية منطق التوطين في مكون واحد.
|
|
1485
1142
|
|
|
1486
|
-
|
|
1143
|
+
إليك تنفيذ مكون `Link` محلي في Preact:
|
|
1487
1144
|
|
|
1488
|
-
```tsx fileName="src/components/
|
|
1145
|
+
```tsx fileName="src/components/Link.tsx" codeFormat="typescript"
|
|
1489
1146
|
import { getLocalizedUrl } from "intlayer";
|
|
1490
|
-
import { useLocale
|
|
1491
|
-
|
|
1492
|
-
import type { JSX } from "preact";
|
|
1493
|
-
import { forwardRef } from "preact/compat"; // لإعادة توجيه المراجع
|
|
1147
|
+
import { useLocale } from "preact-intlayer";
|
|
1148
|
+
import { forwardRef } from "preact/compat";
|
|
1149
|
+
import type { JSX } from "preact";
|
|
1494
1150
|
|
|
1495
|
-
export interface
|
|
1151
|
+
export interface LinkProps extends JSX.HTMLAttributes<HTMLAnchorElement> {
|
|
1496
1152
|
href: string;
|
|
1497
|
-
replace?: boolean; // اختياري: لاستبدال حالة التاريخ
|
|
1498
1153
|
}
|
|
1499
1154
|
|
|
1500
1155
|
/**
|
|
1501
|
-
* دالة مساعدة للتحقق مما إذا كان
|
|
1502
|
-
* إذا بدأ
|
|
1156
|
+
* دالة مساعدة للتحقق مما إذا كان عنوان URL معين خارجيًا.
|
|
1157
|
+
* إذا بدأ عنوان URL بـ http:// أو https://، فإنه يعتبر خارجيًا.
|
|
1503
1158
|
*/
|
|
1504
1159
|
export const checkIsExternalLink = (href?: string): boolean =>
|
|
1505
1160
|
/^https?:\/\//.test(href ?? "");
|
|
1506
1161
|
|
|
1507
1162
|
/**
|
|
1508
|
-
* مكون
|
|
1509
|
-
* بالنسبة للروابط الداخلية، يستخدم `getLocalizedUrl` لإضافة بادئة اللغة إلى عنوان URL (
|
|
1510
|
-
* هذا
|
|
1511
|
-
* يستخدم وسم <a> عادي ولكنه يمكن أن يفعّل التنقل من جهة العميل باستخدام `route` من preact-iso.
|
|
1163
|
+
* مكون Link مخصص يقوم بتكييف سمة href بناءً على اللغة الحالية.
|
|
1164
|
+
* بالنسبة للروابط الداخلية، فإنه يستخدم `getLocalizedUrl` لإضافة بادئة اللغة إلى عنوان URL (مثل /fr/about).
|
|
1165
|
+
* يضمن هذا بقاء التنقل داخل نفس سياق اللغة.
|
|
1512
1166
|
*/
|
|
1513
|
-
export const
|
|
1514
|
-
({ href, children,
|
|
1167
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
1168
|
+
({ href, children, ...props }, ref) => {
|
|
1515
1169
|
const { locale } = useLocale();
|
|
1516
|
-
const location = useLocation(); // من preact-iso
|
|
1517
1170
|
const isExternalLink = checkIsExternalLink(href);
|
|
1518
1171
|
|
|
1172
|
+
// إذا كان الرابط داخليًا وتم توفير href صالح، فاحصل على عنوان URL المحلي.
|
|
1519
1173
|
const hrefI18n =
|
|
1520
1174
|
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1521
1175
|
|
|
1522
|
-
const handleClick = (event: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
|
|
1523
|
-
if (onClick) {
|
|
1524
|
-
onClick(event);
|
|
1525
|
-
}
|
|
1526
|
-
if (
|
|
1527
|
-
!isExternalLink &&
|
|
1528
|
-
href && // التأكد من تعريف href
|
|
1529
|
-
event.button === 0 && // نقرة زر الفأرة الأيسر
|
|
1530
|
-
!event.metaKey &&
|
|
1531
|
-
!event.ctrlKey &&
|
|
1532
|
-
!event.shiftKey &&
|
|
1533
|
-
!event.altKey && // التحقق من عدم وجود مفاتيح تعديل قياسية
|
|
1534
|
-
!props.target // عدم استهداف نافذة/تبويب جديد
|
|
1535
|
-
) {
|
|
1536
|
-
event.preventDefault();
|
|
1537
|
-
if (location.url !== hrefI18n) {
|
|
1538
|
-
// التنقل فقط إذا كان الرابط مختلفًا
|
|
1539
|
-
route(hrefI18n, replace); // استخدام route من preact-iso
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
};
|
|
1543
|
-
|
|
1544
1176
|
return (
|
|
1545
|
-
<a href={hrefI18n} ref={ref}
|
|
1177
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1546
1178
|
{children}
|
|
1547
1179
|
</a>
|
|
1548
1180
|
);
|
|
1549
1181
|
}
|
|
1550
1182
|
);
|
|
1183
|
+
|
|
1184
|
+
Link.displayName = "Link";
|
|
1551
1185
|
```
|
|
1552
1186
|
|
|
1553
|
-
```jsx fileName="src/components/
|
|
1187
|
+
```jsx fileName="src/components/Link.jsx" codeFormat="esm"
|
|
1554
1188
|
import { getLocalizedUrl } from "intlayer";
|
|
1555
1189
|
import { useLocale } from "preact-intlayer";
|
|
1556
|
-
import { useLocation, route } from "preact-iso"; // استيراد من preact-iso
|
|
1557
1190
|
import { forwardRef } from "preact/compat";
|
|
1558
|
-
import { h } from "preact"; // من أجل JSX
|
|
1559
1191
|
|
|
1192
|
+
/**
|
|
1193
|
+
* دالة مساعدة للتحقق مما إذا كان عنوان URL معين خارجيًا.
|
|
1194
|
+
* إذا بدأ عنوان URL بـ http:// أو https://، فإنه يعتبر خارجيًا.
|
|
1195
|
+
*/
|
|
1560
1196
|
export const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1561
1197
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1198
|
+
/**
|
|
1199
|
+
* مكون Link مخصص يقوم بتكييف سمة href بناءً على اللغة الحالية.
|
|
1200
|
+
* بالنسبة للروابط الداخلية، فإنه يستخدم `getLocalizedUrl` لإضافة بادئة اللغة إلى عنوان URL (مثل /fr/about).
|
|
1201
|
+
* يضمن هذا بقاء التنقل داخل نفس سياق اللغة.
|
|
1202
|
+
*/
|
|
1203
|
+
export const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1204
|
+
const { locale } = useLocale();
|
|
1205
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1567
1206
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1207
|
+
// إذا كان الرابط داخليًا وتم توفير href صالح، فاحصل على عنوان URL المحلي.
|
|
1208
|
+
const hrefI18n =
|
|
1209
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1570
1210
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
href &&
|
|
1578
|
-
event.button === 0 &&
|
|
1579
|
-
!event.metaKey &&
|
|
1580
|
-
!event.ctrlKey &&
|
|
1581
|
-
!event.shiftKey &&
|
|
1582
|
-
!event.altKey &&
|
|
1583
|
-
!props.target
|
|
1584
|
-
) {
|
|
1585
|
-
event.preventDefault();
|
|
1586
|
-
if (location.url !== hrefI18n) {
|
|
1587
|
-
route(hrefI18n, replace);
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
};
|
|
1211
|
+
return (
|
|
1212
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
1213
|
+
{children}
|
|
1214
|
+
</a>
|
|
1215
|
+
);
|
|
1216
|
+
});
|
|
1591
1217
|
|
|
1592
|
-
|
|
1593
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1594
|
-
{children}
|
|
1595
|
-
</a>
|
|
1596
|
-
);
|
|
1597
|
-
}
|
|
1598
|
-
);
|
|
1218
|
+
Link.displayName = "Link";
|
|
1599
1219
|
```
|
|
1600
1220
|
|
|
1601
|
-
```jsx fileName="src/components/
|
|
1221
|
+
```jsx fileName="src/components/Link.cjsx" codeFormat="commonjs"
|
|
1602
1222
|
const { getLocalizedUrl } = require("intlayer");
|
|
1603
1223
|
const { useLocale } = require("preact-intlayer");
|
|
1604
|
-
const { useLocation, route } = require("preact-iso"); // استيراد من preact-iso
|
|
1605
1224
|
const { forwardRef } = require("preact/compat");
|
|
1606
|
-
const { h } = require("preact"); // من أجل JSX
|
|
1607
|
-
|
|
1608
|
-
const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? ""); // تحقق مما إذا كان الرابط خارجيًا
|
|
1609
1225
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1226
|
+
/**
|
|
1227
|
+
* دالة مساعدة للتحقق مما إذا كان عنوان URL معين خارجيًا.
|
|
1228
|
+
* إذا بدأ عنوان URL بـ http:// أو https://، فإنه يعتبر خارجيًا.
|
|
1229
|
+
*/
|
|
1230
|
+
const checkIsExternalLink = (href) => /^https?:\/\//.test(href ?? "");
|
|
1615
1231
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1232
|
+
/**
|
|
1233
|
+
* مكون Link مخصص يقوم بتكييف سمة href بناءً على اللغة الحالية.
|
|
1234
|
+
* بالنسبة للروابط الداخلية، فإنه يستخدم `getLocalizedUrl` لإضافة بادئة اللغة إلى عنوان URL (مثل /fr/about).
|
|
1235
|
+
* يضمن هذا بقاء التنقل داخل نفس سياق اللغة.
|
|
1236
|
+
*/
|
|
1237
|
+
const Link = forwardRef(({ href, children, ...props }, ref) => {
|
|
1238
|
+
const { locale } = useLocale();
|
|
1239
|
+
const isExternalLink = checkIsExternalLink(href);
|
|
1240
|
+
|
|
1241
|
+
// إذا كان الرابط داخليًا وتم توفير href صالح، فاحصل على عنوان URL المحلي.
|
|
1242
|
+
const hrefI18n =
|
|
1243
|
+
href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
|
|
1244
|
+
|
|
1245
|
+
return h(
|
|
1246
|
+
"a",
|
|
1247
|
+
{
|
|
1248
|
+
href: hrefI18n,
|
|
1249
|
+
ref: ref,
|
|
1250
|
+
...props,
|
|
1251
|
+
},
|
|
1252
|
+
children
|
|
1253
|
+
);
|
|
1254
|
+
});
|
|
1618
1255
|
|
|
1619
|
-
|
|
1620
|
-
if (onClick) {
|
|
1621
|
-
onClick(event); // استدعاء دالة النقر إذا كانت موجودة
|
|
1622
|
-
}
|
|
1623
|
-
if (
|
|
1624
|
-
!isExternalLink &&
|
|
1625
|
-
href &&
|
|
1626
|
-
event.button === 0 &&
|
|
1627
|
-
!event.metaKey &&
|
|
1628
|
-
!event.ctrlKey &&
|
|
1629
|
-
!event.shiftKey &&
|
|
1630
|
-
!event.altKey &&
|
|
1631
|
-
!props.target
|
|
1632
|
-
) {
|
|
1633
|
-
event.preventDefault(); // منع السلوك الافتراضي للنقر
|
|
1634
|
-
if (location.url !== hrefI18n) {
|
|
1635
|
-
route(hrefI18n, replace);
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
};
|
|
1256
|
+
Link.displayName = "Link";
|
|
1639
1257
|
|
|
1640
|
-
|
|
1641
|
-
<a href={hrefI18n} ref={ref} onClick={handleClick} {...props}>
|
|
1642
|
-
{children}
|
|
1643
|
-
</a>
|
|
1644
|
-
);
|
|
1645
|
-
}
|
|
1646
|
-
);
|
|
1647
|
-
|
|
1648
|
-
module.exports = { LocalizedLink, checkIsExternalLink };
|
|
1258
|
+
module.exports = { Link, checkIsExternalLink };
|
|
1649
1259
|
```
|
|
1650
1260
|
|
|
1651
1261
|
#### كيف يعمل
|
|
1652
1262
|
|
|
1653
1263
|
- **كشف الروابط الخارجية**:
|
|
1654
|
-
|
|
1655
|
-
-
|
|
1656
|
-
يوفر
|
|
1657
|
-
- **توطين
|
|
1658
|
-
بالنسبة للروابط
|
|
1659
|
-
- **التنقل من جانب العميل**:
|
|
1660
|
-
تتحقق دالة `handleClick` مما إذا كان الرابط داخليًا وإذا كان يجب منع التنقل القياسي. إذا كان الأمر كذلك، فإنها تستخدم دالة `route` من مكتبة `preact-iso` (التي يتم الحصول عليها عبر `useLocation` أو استيرادها مباشرة) لتنفيذ التنقل على جانب العميل. هذا يوفر سلوكًا يشبه تطبيق الصفحة الواحدة (SPA) بدون إعادة تحميل الصفحة بالكامل.
|
|
1264
|
+
تحدد الدالة المساعدة `checkIsExternalLink` ما إذا كان عنوان URL خارجيًا. تُترك الروابط الخارجية دون تغيير لأنها لا تحتاج إلى توطين.
|
|
1265
|
+
- **استرداد اللغة الحالية**:
|
|
1266
|
+
يوفر خطاف `useLocale` اللغة الحالية (مثلاً `fr` للفرنسية).
|
|
1267
|
+
- **توطين عنوان URL**:
|
|
1268
|
+
بالنسبة للروابط الداخلية (أي غير الخارجية)، يتم استخدام `getLocalizedUrl` لإضافة بادئة اللغة الحالية تلقائيًا إلى عنوان URL. هذا يعني أنه إذا كان مستخدمك باللغة الفرنسية، فإن تمرير `/about` كـ `href` سيحوله إلى `/fr/about`.
|
|
1661
1269
|
- **إرجاع الرابط**:
|
|
1662
|
-
|
|
1270
|
+
يعيد المكون عنصر `<a>` مع عنوان URL المحلي، مما يضمن أن التنقل متسق مع اللغة.
|
|
1271
|
+
|
|
1272
|
+
### (اختياري) الخطوة 11: عرض Markdown و HTML
|
|
1273
|
+
|
|
1274
|
+
يدعم Intlayer عرض محتوى Markdown و HTML في Preact.
|
|
1275
|
+
|
|
1276
|
+
يمكنك تخصيص عرض محتوى Markdown و HTML باستخدام طريقة `.use()`. تسمح لك هذه الطريقة بتجاوز العرض الافتراضي لعلامات محددة.
|
|
1277
|
+
|
|
1278
|
+
```tsx
|
|
1279
|
+
import { useIntlayer } from "preact-intlayer";
|
|
1280
|
+
|
|
1281
|
+
const { myMarkdownContent, myHtmlContent } = useIntlayer("my-component");
|
|
1282
|
+
|
|
1283
|
+
// ...
|
|
1284
|
+
|
|
1285
|
+
return (
|
|
1286
|
+
<div>
|
|
1287
|
+
{/* العرض الأساسي */}
|
|
1288
|
+
{myMarkdownContent}
|
|
1289
|
+
|
|
1290
|
+
{/* العرض المخصص لـ Markdown */}
|
|
1291
|
+
{myMarkdownContent.use({
|
|
1292
|
+
h1: (props) => <h1 style={{ color: "red" }} {...props} />,
|
|
1293
|
+
})}
|
|
1294
|
+
|
|
1295
|
+
{/* العرض الأساسي لـ HTML */}
|
|
1296
|
+
{myHtmlContent}
|
|
1297
|
+
|
|
1298
|
+
{/* العرض المخصص لـ HTML */}
|
|
1299
|
+
{myHtmlContent.use({
|
|
1300
|
+
b: (props) => <strong style={{ color: "blue" }} {...props} />,
|
|
1301
|
+
})}
|
|
1302
|
+
</div>
|
|
1303
|
+
);
|
|
1304
|
+
```
|
|
1663
1305
|
|
|
1664
1306
|
### تكوين TypeScript
|
|
1665
1307
|
|
|
1666
|
-
يستخدم Intlayer توسيع الوحدات (module augmentation)
|
|
1308
|
+
يستخدم Intlayer توسيع الوحدات (module augmentation) للحصول على فوائد TypeScript وجعل قاعدة الكود الخاصة بك أقوى.
|
|
1667
1309
|
|
|
1668
1310
|

|
|
1669
1311
|
|
|
@@ -1691,9 +1333,9 @@ module.exports = { LocalizedLink, checkIsExternalLink };
|
|
|
1691
1333
|
|
|
1692
1334
|
### تكوين Git
|
|
1693
1335
|
|
|
1694
|
-
يوصى بتجاهل الملفات التي تم إنشاؤها بواسطة Intlayer.
|
|
1336
|
+
يوصى بتجاهل الملفات التي تم إنشاؤها بواسطة Intlayer. يتيح لك ذلك تجنب الالتزام بها في مستودع Git الخاص بك.
|
|
1695
1337
|
|
|
1696
|
-
|
|
1338
|
+
للقيام بذلك، يمكنك إضافة التعليمات التالية إلى ملف `.gitignore` الخاص بك:
|
|
1697
1339
|
|
|
1698
1340
|
```plaintext
|
|
1699
1341
|
# تجاهل الملفات التي تم إنشاؤها بواسطة Intlayer
|
|
@@ -1704,21 +1346,21 @@ module.exports = { LocalizedLink, checkIsExternalLink };
|
|
|
1704
1346
|
|
|
1705
1347
|
لتحسين تجربة التطوير الخاصة بك مع Intlayer، يمكنك تثبيت **إضافة Intlayer الرسمية لـ VS Code**.
|
|
1706
1348
|
|
|
1707
|
-
[التثبيت من
|
|
1349
|
+
[التثبيت من متجر VS Code](https://marketplace.visualstudio.com/items?itemName=intlayer.intlayer-vs-code-extension)
|
|
1708
1350
|
|
|
1709
|
-
|
|
1351
|
+
توفر هذه الإضافة:
|
|
1710
1352
|
|
|
1711
1353
|
- **الإكمال التلقائي** لمفاتيح الترجمة.
|
|
1712
|
-
- **كشف الأخطاء في الوقت
|
|
1354
|
+
- **كشف الأخطاء في الوقت الفعلي** للترجمات المفقودة.
|
|
1713
1355
|
- **معاينات داخلية** للمحتوى المترجم.
|
|
1714
|
-
- **إجراءات سريعة** لإنشاء
|
|
1356
|
+
- **إجراءات سريعة** لإنشاء وتحديث الترجمات بسهولة.
|
|
1715
1357
|
|
|
1716
1358
|
لمزيد من التفاصيل حول كيفية استخدام الإضافة، راجع [توثيق إضافة Intlayer لـ VS Code](https://intlayer.org/doc/vs-code-extension).
|
|
1717
1359
|
|
|
1718
1360
|
---
|
|
1719
1361
|
|
|
1720
|
-
###
|
|
1362
|
+
### اذهب أبعد من ذلك
|
|
1721
1363
|
|
|
1722
|
-
|
|
1364
|
+
للذهاب أبعد من ذلك، يمكنك تنفيذ [المحرر المرئي](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/intlayer_visual_editor.md) أو توفير المحتوى الخاص بك خارجيًا باستخدام [نظام إدارة المحتوى (CMS)](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/intlayer_CMS.md).
|
|
1723
1365
|
|
|
1724
1366
|
---
|