diff --git a/api-tests/core/upload/content-api/private-file-signing.test.api.js b/api-tests/core/upload/content-api/private-file-signing.test.api.js new file mode 100644 index 0000000000..4a0604c665 --- /dev/null +++ b/api-tests/core/upload/content-api/private-file-signing.test.api.js @@ -0,0 +1,343 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const { createTestBuilder } = require('api-tests/builder'); +const { createStrapiInstance } = require('api-tests/strapi'); +const { createContentAPIRequest } = require('api-tests/request'); + +const builder = createTestBuilder(); +let strapi; +let rq; + +const modelUID = 'api::model.model'; +const componentUID = 'default.component'; + +const models = { + [modelUID]: { + displayName: 'Model', + singularName: 'model', + pluralName: 'models', + kind: 'collectionType', + attributes: { + name: { + type: 'text', + }, + media: { + type: 'media', + }, + media_repeatable: { + type: 'media', + multiple: true, + }, + compo_media: { + type: 'component', + component: componentUID, + }, + compo_media_repeatable: { + type: 'component', + repeatable: true, + component: componentUID, + }, + dynamicZone: { + type: 'dynamiczone', + components: [componentUID], + }, + }, + }, + [componentUID]: { + displayName: 'component', + attributes: { + media_repeatable: { + type: 'media', + multiple: true, + }, + media: { + type: 'media', + multiple: false, + }, + }, + }, +}; + +const populate = { + media: true, + media_repeatable: true, + compo_media: { + populate: { + media: true, + media_repeatable: true, + }, + }, + compo_media_repeatable: { + populate: { + media: true, + media_repeatable: true, + }, + }, + dynamicZone: { + populate: { + media: true, + media_repeatable: true, + }, + }, +}; + +let isPrivate = true; + +const mockProvider = () => ({ + init() { + return { + isPrivate() { + return isPrivate; + }, + getSignedUrl() { + return { url: 'signedUrl' }; + }, + uploadStream(file) { + file.url = 'strapi.jpg'; + }, + upload(file) { + file.url = 'strapi.jpg'; + }, + delete() {}, + checkFileSize() {}, + }; + }, +}); + +const createModel = async (name = 'name') => { + return strapi.entityService.create(modelUID, { + data: { + name, + media: singleMedia, + media_repeatable: repeatable, + compo_media: mediaEntry, + compo_media_repeatable: [mediaEntry, mediaEntry], + dynamicZone: [ + { + __component: componentUID, + ...mediaEntry, + }, + ], + }, + populate, + }); +}; + +const uploadImg = (fileName) => { + return rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, `../utils/${fileName}`)), + }, + }); +}; + +let repeatable; +let singleMedia; +let mediaEntry = {}; +let model; + +describe('Upload Plugin url signing', () => { + const expectMedia = (media, expectedUrl) => { + expect(media.url).toEqual(expectedUrl); + }; + + const expectRepeatable = (repeatable, expectedUrl) => { + for (const media of repeatable) { + expectMedia(media, expectedUrl); + } + }; + + const responseExpectations = (result, expectedUrl) => { + expectMedia(result.media, expectedUrl); + expectRepeatable(result.media_repeatable, expectedUrl); + + expect(result.compo_media.media.url).toEqual(expectedUrl); + for (const media of result.compo_media.media_repeatable) { + expect(media.url).toEqual(expectedUrl); + } + + for (const component of result.compo_media_repeatable) { + expect(component.media.url).toEqual(expectedUrl); + for (const media of component.media_repeatable) { + expect(media.url).toEqual(expectedUrl); + } + } + + for (const component of result.dynamicZone) { + expect(component.media.url).toEqual(expectedUrl); + for (const media of component.media_repeatable) { + expect(media.url).toEqual(expectedUrl); + } + } + }; + + beforeAll(async () => { + const localProviderPath = require.resolve('@strapi/provider-upload-local'); + jest.mock(localProviderPath, () => mockProvider(true)); + + // Create builder + await builder.addComponent(models[componentUID]).addContentType(models[modelUID]).build(); + + // Create api instance + strapi = await createStrapiInstance(); + + rq = await createContentAPIRequest({ strapi }); + + const imgRes = [await uploadImg('strapi.jpg'), await uploadImg('strapi.jpg')]; + + repeatable = imgRes.map((img) => img.body[0].id); + singleMedia = imgRes[0].body[0].id; + mediaEntry = { + media: singleMedia, + media_repeatable: repeatable, + }; + + model = await createModel('model1'); + }); + + afterAll(async () => { + await strapi.destroy(); + await builder.cleanup(); + }); + + describe('Returns signed media URLs on', () => { + test('entityService.create', async () => { + let entity = await createModel(); + responseExpectations(entity, 'signedUrl'); + }); + + test('entityService.findOne', async () => { + const entity = await strapi.entityService.findOne(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'signedUrl'); + }); + + test('entityService.findMany', async () => { + const entities = await strapi.entityService.findMany(modelUID, { + populate, + }); + + for (const entity of entities) { + responseExpectations(entity, 'signedUrl'); + } + }); + + test('entityService.findPage', async () => { + const entities = await strapi.entityService.findPage(modelUID, { + populate, + }); + for (const entity of entities.results) { + responseExpectations(entity, 'signedUrl'); + } + }); + + test('entityService.update', async () => { + const model = await createModel(); + const entity = await strapi.entityService.update(modelUID, model.id, { + data: { + name: 'model_updated', + }, + populate, + }); + + responseExpectations(entity, 'signedUrl'); + }); + + test('entityService.delete', async () => { + const model = await createModel(); + const entity = await strapi.entityService.delete(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'signedUrl'); + }); + + test('entityService.load', async () => { + const model = await createModel(); + const media_repeatable = await strapi.entityService.load( + modelUID, + { id: model.id }, + 'media_repeatable' + ); + + expectRepeatable(media_repeatable, 'signedUrl'); + }); + }); + + describe('Does not return signed media URLs on', () => { + beforeAll(async () => { + isPrivate = false; + }); + + test('entityService.create', async () => { + let entity = await createModel(); + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.findOne', async () => { + const entity = await strapi.entityService.findOne(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.findMany', async () => { + const entities = await strapi.entityService.findMany(modelUID, { + populate, + }); + + for (const entity of entities) { + responseExpectations(entity, 'strapi.jpg'); + } + }); + + test('entityService.findPage', async () => { + const entities = await strapi.entityService.findPage(modelUID, { + populate, + }); + for (const entity of entities.results) { + responseExpectations(entity, 'strapi.jpg'); + } + }); + + test('entityService.update', async () => { + const model = await createModel(); + const entity = await strapi.entityService.update(modelUID, model.id, { + data: { + name: 'model_updated', + }, + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.delete', async () => { + const model = await createModel(); + const entity = await strapi.entityService.delete(modelUID, model.id, { + populate, + }); + + responseExpectations(entity, 'strapi.jpg'); + }); + + test('entityService.load', async () => { + const model = await createModel(); + const media_repeatable = await strapi.entityService.load( + modelUID, + { id: model.id }, + 'media_repeatable' + ); + + expectRepeatable(media_repeatable, 'strapi.jpg'); + }); + }); +}); diff --git a/docs/docs/docs/01-core/database/relations/_category_.json b/docs/docs/docs/01-core/database/01-relations/_category_.json similarity index 100% rename from docs/docs/docs/01-core/database/relations/_category_.json rename to docs/docs/docs/01-core/database/01-relations/_category_.json diff --git a/docs/docs/docs/01-core/database/relations/reordering.mdx b/docs/docs/docs/01-core/database/01-relations/reordering.mdx similarity index 100% rename from docs/docs/docs/01-core/database/relations/reordering.mdx rename to docs/docs/docs/01-core/database/01-relations/reordering.mdx diff --git a/docs/docs/docs/01-core/database/02-transactions.md b/docs/docs/docs/01-core/database/02-transactions.md new file mode 100644 index 0000000000..3ecbd2d146 --- /dev/null +++ b/docs/docs/docs/01-core/database/02-transactions.md @@ -0,0 +1,109 @@ +--- +title: Transactions +description: Conceptual guide to transactions in Strapi +tags: + - database + - experimental +--- + +:::caution +This is an experimental feature and is subject to change in future versions. +::: + +An API to wrap a set of operations in a transaction that ensures the integrity of data. + +## What are transactions + +Transactions are a set of operations that are executed together as a single unit. If any of the operations fail, the entire transaction fails and the data is rolled back to its previous state. If all operations succeed, the transaction is committed and the data is permanently saved to the database. + +## Usage + +Transactions are handled by passing a handler function into `strapi.db.transaction`: + +```js +await strapi.db.transaction(async ({ trx, rollback, commit, onCommit, onRollback }) => { + // It will implicitly use the transaction + await strapi.entityService.create(); + await strapi.entityService.create(); +}); +``` + +After the transaction handler is executed, the transaction is committed if all operations succeed. If any of the operations throws, the transaction is rolled back and the data is restored to its previous state. + +:::note +Every `strapi.entityService` or `strapi.db.query` operation performed in a transaction block will implicitly use the transaction. +::: + +### Transaction handler properties + +The handler function receives an object with the following properties: + +| Property | Description | +| ------------ | ------------------------------------------------------------------------------------------- | +| `trx` | The transaction object. It can be used to perform knex queries within the transaction. | +| `commit` | Function to commit the transaction. | +| `rollback` | Function to rollback the transaction. | +| `onCommit` | Function to register a callback that will be executed after the transaction is committed. | +| `onRollback` | Function to register a callback that will be executed after the transaction is rolled back. | + +### Nested transactions + +Transactions can be nested. When a transaction is nested, the inner transaction is committed or rolled back when the outer transaction is committed or rolled back. + +```js +await strapi.db.transaction(async () => { + // It will implicitly use the transaction + await strapi.entityService.create(); + + // Nested transactions will implicitly use the outer transaction + await strapi.db.transaction(async ({}) => { + await strapi.entityService.create(); + }); +}); +``` + +### onCommit and onRollback + +The `onCommit` and `onRollback` hooks can be used to execute code after the transaction is committed or rolled back. + +```js +await strapi.db.transaction(async ({ onCommit, onRollback }) => { + // It will implicitly use the transaction + await strapi.entityService.create(); + await strapi.entityService.create(); + + onCommit(() => { + // This will be executed after the transaction is committed + }); + + onRollback(() => { + // This will be executed after the transaction is rolled back + }); +}); +``` + +### Using knex queries + +Transactions can also be used with knex queries, but in those cases `.transacting(trx)` must be explicitly called. + +```js +await strapi.db.transaction(async ({ trx, rollback, commit }) => { + await knex('users').where('id', 1).update({ name: 'foo' }).transacting(trx); +}); +``` + +## When to use transactions + +Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a new user, the user should be created in the database and a welcome email should be sent to the user. If the email fails to send, the user should not be created in the database. + +## When not to use transactions + +Transactions should not be used for operations that are not dependent on each other since it can result in performance penalties. + +## Potential problems of transactions + +Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete. + +Furthermore, transactions can stall if they are not committed or rolled back appropriately. + +For example, if a transaction is opened but there is a path in your code that does not close it, the transaction will be left open indefinitely and could cause instability until your server is restarted and the connection is forced to close. These issues can be difficult to debug, so use transactions with care in the cases they are necessary. diff --git a/packages/core/admin/admin/src/translations/ar.json b/packages/core/admin/admin/src/translations/ar.json index 47a40a81a9..9b653f8325 100644 --- a/packages/core/admin/admin/src/translations/ar.json +++ b/packages/core/admin/admin/src/translations/ar.json @@ -205,5 +205,688 @@ "content-manager.success.record.save": "حُفظ", "notification.error": "حدث خطأ", "notification.error.layout": "تعذّر استرداد التنسيق", - "request.error.model.unknown": "هذا النموذج غير موجود" + "request.error.model.unknown": "هذا النموذج غير موجود", + "admin.pages.MarketPlacePage.filters.categories": "فئات", + "admin.pages.MarketPlacePage.filters.collections": "المجموعات", + "admin.pages.MarketPlacePage.helmet": "السوق - الإضافات", + "admin.pages.MarketPlacePage.missingPlugin.description": "أخبرنا ما هو المكون الإضافي الذي تبحث عنه وسنعلم مطوري المكونات الإضافية في مجتمعنا في حال كانوا يبحثون عن الإلهام!", + "admin.pages.MarketPlacePage.missingPlugin.title": "هل فقدت مكونًا إضافيًا؟", + "admin.pages.MarketPlacePage.offline.subtitle": "يجب أن تكون متصلاً بالإنترنت للوصول إلى سوق سترابي", + "admin.pages.MarketPlacePage.offline.title": "انت غير متصل", + "admin.pages.MarketPlacePage.plugin.copy": "أمر نسخ التثبيت", + "admin.pages.MarketPlacePage.plugin.copy.success": "قم بتثبيت الأمر جاهزًا ليتم لصقه في الجهاز الطرفي", + "admin.pages.MarketPlacePage.plugin.downloads": "يتم تنزيل هذا المكون الإضافي {downloadsCount} أسبوعيًا", + "admin.pages.MarketPlacePage.plugin.githubStars": "تم تمييز هذا المكون الإضافي بنجمة على GitHub", + "admin.pages.MarketPlacePage.plugin.info": "يتعلم أكثر", + "admin.pages.MarketPlacePage.plugin.info.label": "تعرف على المزيد حول {pluginName}", + "admin.pages.MarketPlacePage.plugin.info.text": "أكثر", + "admin.pages.MarketPlacePage.plugin.installed": "المثبتة", + "admin.pages.MarketPlacePage.plugin.tooltip.madeByStrapi": "صنع بواسطة ستربي", + "admin.pages.MarketPlacePage.plugin.tooltip.verified": "Strapi تم التحقق من البرنامج المساعد من قبل ", + "admin.pages.MarketPlacePage.plugins": "الإضافات", + "admin.pages.MarketPlacePage.provider.downloads": "هذا الموفر لديه {downloadsCount} من التنزيلات الأسبوعية", + "admin.pages.MarketPlacePage.provider.githubStars": "{GitHub} على {starsCount} تم تميز هذا المزود ", + "admin.pages.MarketPlacePage.providers": "الموفرون", + "admin.pages.MarketPlacePage.search.clear": "مسح البحث", + "admin.pages.MarketPlacePage.search.empty": " \"{target}\" لا توجد نتيجة ل", + "admin.pages.MarketPlacePage.search.placeholder": "يبحث", + "admin.pages.MarketPlacePage.sort.alphabetical": "ترتيب ابجدي", + "admin.pages.MarketPlacePage.sort.alphabetical.selected": "فرز حسب الترتيب الأبجدي", + "admin.pages.MarketPlacePage.sort.githubStars": "GitHub عدد نجوم", + "admin.pages.MarketPlacePage.sort.githubStars.selected": "GitHub الترتيب حسب نجوم", + "admin.pages.MarketPlacePage.sort.newest": "الأحدث", + "admin.pages.MarketPlacePage.sort.newest.selected": "ترتيب حسب الأحدث", + "admin.pages.MarketPlacePage.sort.npmDownloads": "عدد التنزيلات", + "admin.pages.MarketPlacePage.sort.npmDownloads.selected": "npm فرز حسب التنزيلات ", + "admin.pages.MarketPlacePage.submit.plugin.link": "إرسال البرنامج المساعد", + "admin.pages.MarketPlacePage.submit.provider.link": "إرسال مزود", + "admin.pages.MarketPlacePage.subtitle": " Strapi احصل على المزيد من", + "admin.pages.MarketPlacePage.tab-group.label": "Strapi الإضافات ومقدمي ", + "Analytics": "تحليلات", + "anErrorOccurred": "عذرًا! هناك خطأ ما. حاول مرة اخرى.", + "app.component.CopyToClipboard.label": "نسخ إلى الحافظة", + "app.component.search.label": "{target} بحث عن", + "app.component.table.duplicate": "{target} ينسخ", + "app.component.table.edit": "{target} يحرر", + "app.component.table.read": "{target}يقرأ", + "app.component.table.select.one-entry": "{target}يختار", + "app.component.table.view": "{target} تفاصيل", + "app.components.BlockLink.blog": "مدونة", + "admin.pages.MarketPlacePage.filters.categoriesSelected": "{count, plural, =0 {No categories} واحد {# category} آخر{# categories}} المحدد", + "admin.pages.MarketPlacePage.plugin.version": " قم بتحديث إصدار الخاص بك : \"{strapiAppVersion}\" ل: \"{versionRange}\"", + "admin.pages.MarketPlacePage.plugin.version.null": "تعذر التحقق من التوافق مع إصدار Strapi الخاص بك: \"{strapiAppVersion}\"", + "app.components.BlockLink.blog.content": "اقرأ آخر الأخبار حول Strapi والنظام البيئي.", + "app.components.BlockLink.cloud": "Strapi سحاب", + "app.components.BlockLink.cloud.content": "نظام أساسي قابل للإنشاء والتعاون بشكل كامل لزيادة سرعة فريقك.", + "app.components.BlockLink.code.content": "تعلم من خلال اختبار المشاريع الحقيقية التي طورها المجتمع.", + "app.components.BlockLink.documentation.content": "اكتشف المفاهيم الأساسية والأدلة والتعليمات.", + "app.components.BlockLink.tutorial": "دروس", + "app.components.BlockLink.tutorial.content": "Strapi اتبع التعليمات خطوة بخطوة للاستخدام والتخصيص.", + "app.components.Button.confirm": "يتأكد", + "app.components.Button.reset": "إعادة ضبط", + "app.components.ConfirmDialog.title": "تأكيد", + "app.components.EmptyStateLayout.content-document": "لم يتم العثور على محتوى", + "app.components.EmptyStateLayout.content-permissions": "ليس لديك أذونات للوصول إلى هذا المحتوى", + "app.components.GuidedTour.apiTokens.create.content": "
قم بإنشاء رمز المصادقة هنا واسترجع المحتوى الذي أنشأته للتو.
", + "app.components.GuidedTour.apiTokens.create.cta.title": "API إنشاء رمز", + "app.components.GuidedTour.apiTokens.create.title": "🚀 مشاهدة المحتوى في العمل", + "app.components.GuidedTour.apiTokens.success.cta.title": "العودة الى الصفحة الرئيسية", + "app.components.GuidedTour.apiTokens.success.title": "✅ الخطوة 3: اكتمل", + "app.components.GuidedTour.CM.create.content": "قم بإنشاء وإدارة كل المحتوى هنا في إدارة المحتوى.
مثال: أخذ مثال موقع المدونة إلى أبعد من ذلك ، يمكن للمرء كتابة مقال وحفظه ونشره كما يحلو له.
💡 نصيحة سريعة - لا تنس النقر على ’نشر’ على المحتوى الذي تنشئه.
", + "app.components.GuidedTour.CM.create.title": "⚡️ أنشئ محتوى", + "app.components.GuidedTour.CM.success.content": "رائع ، خطوة أخيرة يجب أن تبدأ بها!
🚀 مشاهدة المحتوى في العمل", + "app.components.GuidedTour.CM.success.cta.title": "API اختبر ملف", + "app.components.GuidedTour.CM.success.title": "✅ الخطوة 2: اكتمل", + "app.components.GuidedTour.create-content": "أنشئ محتوى", + "app.components.GuidedTour.CTB.create.content": "تساعدك أنواع المجموعات على إدارة عدة إدخالات ، والأنواع الفردية مناسبة لإدارة إدخال واحد فقط. p>
على سبيل المثال: بالنسبة إلى موقع مدونة ، ستكون المقالات من نوع المجموعة بينما تكون الصفحة الرئيسية من النوع الفردي.
", + "app.components.GuidedTour.CTB.create.cta.title": "بناء نوع المجموعة", + "app.components.GuidedTour.CTB.create.title": "🧠 قم بإنشاء أول نوع مجموعة", + "app.components.GuidedTour.CTB.success.content": "جيد!
⚡️ ما الذي تود مشاركته مع العالم؟", + "app.components.GuidedTour.CTB.success.title": "الخطوة 1: ✅ مكتمل", + "app.components.GuidedTour.home.apiTokens.cta.title": "API اختبار ", + "app.components.GuidedTour.home.CM.title": "⚡️ ما الذي تود مشاركته مع العالم؟", + "app.components.GuidedTour.home.CTB.cta.title": "Content type Builder انتقل إلى", + "app.components.GuidedTour.home.CTB.title": "🧠 بناء هيكل المحتوى", + "app.components.GuidedTour.skip": "تخطي الجولة", + "app.components.GuidedTour.title": "خطوات للبدء ٣", + "app.components.HomePage.create": "قم بإنشاء نوع المحتوى الأول الخاص بك", + "app.components.HomePage.roadmap": "انظر خارطة الطريق لدينا", + "app.components.InstallPluginPage.Download.description": "قد يستغرق تنزيل المكون الإضافي وتثبيته بضع ثوانٍ", + "app.components.InstallPluginPage.Download.title": "جارى التحميل...", + "app.components.LeftMenu.collapse": "تصغير شريط التنقل", + "app.components.LeftMenu.expand": "قم بتوسيع شريط التنقل", + "app.components.LeftMenu.general": "عام", + "app.components.LeftMenu.logo.alt": "شعار التطبيق", + "app.components.LeftMenu.logout": "تسجيل خروج", + "app.components.LeftMenu.navbrand.title": "Strapi لوحة القيادة", + "app.components.LeftMenu.navbrand.workplace": "مكان العمل", + "app.components.LeftMenu.plugins": "الإضافات", + "app.components.LeftMenuFooter.help": "يساعد", + "app.components.LeftMenuLinkContainer.collectionTypes": "أنواع المجموعات", + "app.components.LeftMenuLinkContainer.singleTypes": "أنواع مفردة", + "app.components.ListPluginsPage.deletePlugin.description": "قد يستغرق الأمر بضع ثوان لإلغاء تثبيت المكون الإضافي", + "app.components.ListPluginsPage.deletePlugin.title": "إلغاء التثبيت", + "app.components.MarketplaceBanner": "اكتشف المكونات الإضافية التي أنشأها المجتمع ، والعديد من الأشياء الرائعة لبدء مشروعك ، في سوق Strapi.", + "app.components.MarketplaceBanner.image.alt": "شعار صاروخ Strapi", + "app.components.MarketplaceBanner.link": "افحصه الآن", + "app.components.Onboarding.help.button": "زر المساعدة", + "app.components.Onboarding.label.completed": "% مكتمل", + "app.components.Onboarding.link.build-content": "بناء بنية المحتوى", + "app.components.Onboarding.link.manage-content": "إضافة وإدارة المحتوى", + "app.components.Onboarding.link.manage-media": "إدارة الوسائط", + "app.components.Onboarding.link.more-videos": "شاهد المزيد من مقاطع الفيديو", + "app.components.Onboarding.title": "ابدأ مقاطع الفيديو", + "app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed": "يجب تمكين ميزة AutoReload. `yarn develop` يرجى بدء تطبيقك بـ .", + "app.components.PluginCard.PopUpWarning.install.impossible.confirm": "أفهم!", + "app.components.PluginCard.PopUpWarning.install.impossible.environment": "لأسباب أمنية ، لا يمكن تنزيل المكون الإضافي إلا في بيئة التطوير.", + "app.components.PluginCard.PopUpWarning.install.impossible.title": "التنزيل مستحيل", + "app.components.ToggleCheckbox.off-label": "خطأ", + "app.components.ToggleCheckbox.on-label": "حقيقي", + "app.components.Users.MagicLink.connect": "انسخ هذا الرابط وشاركه لمنح حق الوصول لهذا المستخدم", + "app.components.Users.MagicLink.connect.sso": "أرسل هذا الرابط إلى المستخدم ، حيث يمكن إجراء أول تسجيل دخول عبر موفر خدمة الدخول الموحد", + "app.components.Users.ModalCreateBody.block-title.details": "بيانات المستخدم", + "app.components.Users.ModalCreateBody.block-title.roles": "أدوار المستخدم", + "app.components.Users.ModalCreateBody.block-title.roles.description": "يمكن للمستخدم أن يكون له دور واحد أو عدة أدوار", + "app.components.Users.SortPicker.button-label": "ترتيب حسب", + "app.components.Users.SortPicker.sortby.email_asc": "البريد الإلكتروني (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.email_desc": "بريد إلكتروني (من ي إلى أ)", + "app.components.Users.SortPicker.sortby.firstname_asc": "الاسم الأول (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.firstname_desc": "الاسم الأول (ي إلى أ)", + "app.components.Users.SortPicker.sortby.lastname_asc": "الاسم الأخير (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.lastname_desc": "الاسم الأخير (ي إلى أ)", + "app.components.Users.SortPicker.sortby.username_asc": "اسم المستخدم (من الألف إلى الياء)", + "app.components.Users.SortPicker.sortby.username_desc": "اسم المستخدم (من ي إلى أ)", + "app.containers.App.notification.error.init": "API حدث خطأ أثناء الطلب", + "app.containers.AuthPage.ForgotPasswordSuccess.text.contact-admin": "إذا لم تستلم هذا الرابط ، فيرجى الاتصال بالمسؤول.", + "app.containers.AuthPage.ForgotPasswordSuccess.text.email": "قد يستغرق استلام رابط استعادة كلمة المرور بضع دقائق.", + "app.containers.AuthPage.ForgotPasswordSuccess.title": "أرسل البريد الإلكتروني", + "app.containers.Users.EditPage.form.active.label": "فعال", + "app.containers.Users.EditPage.header.label": "تعديل {الاسم}", + "app.containers.Users.EditPage.header.label-loading": "تحرير العضو", + "app.containers.Users.EditPage.roles-bloc-title": "الأدوار المنسوبة", + "app.containers.Users.ModalForm.footer.button-success": "قم بدعوة المستخدم", + "app.links.configure-view": "تكوين العرض", + "app.page.not.found": "أُووبس! يبدو أنه لا يمكننا العثور على الصفحة التي تبحث عنها ...", + "app.static.links.cheatsheet": "ورقة الغش", + "app.utils.add-filter": "أضف عامل تصفية", + "app.utils.close-label": "يغلق", + "app.utils.delete": "يمسح", + "app.utils.duplicate": "ينسخ", + "app.utils.edit": "يحرر", + "app.utils.errors.file-too-big.message": "الملف كبير جدًا", + "app.utils.filter-value": "قيمة التصفية", + "app.utils.filters": "المرشحات", + "app.utils.notify.data-loaded": "{target} تم تحميل", + "app.utils.publish": "أصدر", + "app.utils.select-all": "اختر الكل", + "app.utils.select-field": "حدد المجال", + "app.utils.select-filter": "حدد عامل تصفية", + "app.utils.unpublish": "إلغاء النشر", + "Auth.components.Oops.text": "تم تعليق حسابك.", + "Auth.components.Oops.text.admin": "إذا كان هذا خطأ ، يرجى الاتصال بالمسؤول.", + "Auth.components.Oops.title": "أُووبس...", + "Auth.form.active.label": "فعال", + "Auth.form.button.go-home": "ارجع الى الصفحة الرئيسية", + "Auth.form.button.login.providers.error": "لا يمكننا توصيلك من خلال المزود المحدد.", + "Auth.form.button.login.strapi": "Strapi تسجيل الدخول عبر", + "Auth.form.button.password-recovery": "استعادة كلمة السر", + "Auth.form.confirmPassword.label": "تأكيد كلمة المرور", + "Auth.form.currentPassword.label": "كلمة السر الحالية", + "Auth.form.error.blocked": "تم حظر حسابك من قبل المسؤول.", + "Auth.form.error.confirmed": "لم يتم تأكيد البريد الإلكتروني لحسابك.", + "Auth.form.error.ratelimit": "محاولات كثيرة ، يرجى المحاولة مرة أخرى خلال دقيقة.", + "Auth.form.firstname.label": "الاسم الأول", + "Auth.form.firstname.placeholder": "على سبيل المثال سمر", + "Auth.form.lastname.label": "اسم العائلة", + "Auth.form.lastname.placeholder": "على سبيل المثال سامي", + "Auth.form.password.hide-password": "اخفاء كلمة المرور", + "Auth.form.password.hint": "يجب ألا يقل عدد الأحرف عن 8 أحرف ، وحرف كبير واحد ، ورقم واحد صغير ، ورقم واحد", + "Auth.form.password.show-password": "عرض كلمة المرور", + "Auth.form.register.news.label": "ابقني على اطلاع بالميزات الجديدة والتحسينات القادمة (من خلال القيام بذلك فأنت تقبل {terms} و ال {policy}).", + "Auth.form.register.subtitle": "تُستخدم بيانات الاعتماد فقط للمصادقة في Strapi. سيتم تخزين جميع البيانات المحفوظة في قاعدة البيانات الخاصة بك.", + "Auth.form.welcome.subtitle": "Strapi قم بتسجيل الدخول إلى حسابك على", + "Auth.form.welcome.title": "Strapi! مرحبا بك في", + "Auth.link.signin": "تسجيل الدخول", + "Auth.link.signin.account": "هل لديك حساب؟", + "Auth.login.sso.divider": "أو تسجيل الدخول باستخدام", + "Auth.login.sso.loading": "تحميل الموفرين ...", + "Auth.login.sso.subtitle": "SSO تسجيل الدخول إلى حسابك عبر", + "Auth.privacy-policy-agreement.policy": "سياسة الخصوصية", + "Auth.privacy-policy-agreement.terms": "شروط", + "Auth.reset-password.title": "إعادة تعيين كلمة المرور", + "clearLabel": "حذف", + "coming.soon": "هذا المحتوى قيد الإنشاء حاليًا وسيعود في غضون أسابيع قليلة!", + "component.Input.error.validation.integer": "يجب أن تكون القيمة عددًا صحيحًا", + "components.AutoReloadBlocker.description": "Strapi قم بتشغيل باستخدام أحد الأوامر التالية:", + "components.FilterOptions.FILTER_TYPES.$contains": "يحتوي على (حساس لحالة الأحرف)", + "components.FilterOptions.FILTER_TYPES.$endsWith": "ينتهي بـ", + "components.FilterOptions.FILTER_TYPES.$eq": "هو", + "components.FilterOptions.FILTER_TYPES.$gt": "أكبر من", + "components.FilterOptions.FILTER_TYPES.$gte": "أكبر من أو يساوي", + "components.FilterOptions.FILTER_TYPES.$lt": "أقل من", + "components.FilterOptions.FILTER_TYPES.$lte": "أقل من أو يساوي", + "components.FilterOptions.FILTER_TYPES.$ne": "ليس", + "components.FilterOptions.FILTER_TYPES.$notContains": "لا يحتوي على (حساس لحالة الأحرف)", + "components.FilterOptions.FILTER_TYPES.$notNull": "هو ليس لاشيء", + "components.FilterOptions.FILTER_TYPES.$null": "هو لاشيء", + "components.FilterOptions.FILTER_TYPES.$startsWith": "يبدا ب", + "components.Input.error.contain.lowercase": "يجب أن تحتوي كلمة المرور على حرف صغير واحد على الأقل", + "components.Input.error.contain.number": "يجب ان تحتوي كلمة المرور على الاقل رقما واحدا", + "components.Input.error.contain.uppercase": "يجب أن تحتوي كلمة المرور على حرف كبير واحد على الأقل", + "components.Input.error.validation.lowercase": "يجب أن تكون القيمة سلسلة أحرف صغيرة", + "components.Input.error.validation.unique": "هذه القيمة مستخدمة بالفعل.", + "components.InputSelect.option.placeholder": "اختر هنا", + "components.NotAllowedInput.text": "لا أذونات لرؤية هذا المجال", + "components.OverlayBlocker.description.serverError": "يجب إعادة تشغيل الخادم ، يرجى التحقق من سجلاتك في المحطة.", + "components.OverlayBlocker.title.serverError": "تستغرق إعادة التشغيل وقتًا أطول من المتوقع", + "components.pagination.go-to": "{page} انتقل إلى صفحة", + "components.pagination.go-to-next": "انتقل إلى الصفحة التالية", + "components.pagination.go-to-previous": "الانتقال إلى الصفحة السابقة", + "components.pagination.remaining-links": "روابط أخرى{number} و", + "components.popUpWarning.button.cancel": "لا ، إلغاء", + "components.popUpWarning.button.confirm": "نعم ، قم بالتأكيد", + "components.Search.placeholder": "بحث...", + "components.TableHeader.sort": "{label} الفرز على", + "components.Wysiwyg.ToggleMode.markdown-mode": "وضع Markdown", + "components.Wysiwyg.ToggleMode.preview-mode": "وضعية المعاينة", + "Content Type Builder": "منشئ أنواع المحتوى", + "content-manager.api.id": "معرف API", + "content-manager.apiError.This attribute must be unique": "{field} يجب أن يكون فريدًا", + "content-manager.App.schemas.data-loaded": "تم تحميل المخططات بنجاح", + "content-manager.components.DraggableCard.delete.field": "{item} حذف", + "content-manager.components.DraggableCard.edit.field": "{item} حرر", + "content-manager.components.DraggableCard.move.field": "{item} تحرك", + "content-manager.components.DragHandle-label": "جر", + "content-manager.components.DynamicTable.row-line": "{number} سطر البند", + "content-manager.components.DynamicZone.add-component": "{componentName} أضف مكونًا إلى", + "content-manager.components.DynamicZone.ComponentPicker-label": "اختر مكونًا واحدًا", + "content-manager.components.DynamicZone.delete-label": "{name} حذف", + "content-manager.components.DynamicZone.error-message": "يحتوي المكون على خطأ (أخطاء)", + "content-manager.components.DynamicZone.missing-components": "There {number, plural, =0 {are # missing components} واحد {is # missing component} آخر {are # missing components}}", + "content-manager.components.DynamicZone.move-down-label": "انقل المكون لأسفل", + "content-manager.components.DynamicZone.move-up-label": "انقل المكون لأعلى", + "content-manager.components.DynamicZone.pick-compo": "اختر مكونًا واحدًا", + "content-manager.components.DynamicZone.required": "المكون مطلوب", + "content-manager.components.empty-repeatable": "لا دخول حتى الان. انقر فوق الزر أدناه لإضافة واحد.", + "content-manager.components.FieldItem.linkToComponentLayout": "قم بتعيين تخطيط المكون", + "content-manager.components.FieldSelect.label": "أضف حقلاً", + "content-manager.components.LeftMenu.collection-types": "أنواع المجموعات", + "content-manager.components.LeftMenu.Search.label": "ابحث عن نوع المحتوى", + "content-manager.components.LeftMenu.single-types": "أنواع مفردة", + "content-manager.components.NotAllowedInput.text": "لا أذونات لرؤية هذا المجال", + "content-manager.components.notification.info.maximum-requirement": "لقد وصلت بالفعل إلى الحد الأقصى لعدد الحقول", + "content-manager.components.notification.info.minimum-requirement": "تمت إضافة حقل لمطابقة الحد الأدنى من المتطلبات", + "content-manager.components.RelationInput.icon-button-aria-label": "جر", + "content-manager.components.repeatable.reorder.error": "حدث خطأ أثناء إعادة ترتيب حقل المكون الخاص بك ، يرجى المحاولة مرة أخرى", + "content-manager.components.RepeatableComponent.error-message": "يحتوي المكون (المكونات) على خطأ (أخطاء)", + "content-manager.components.reset-entry": "إعادة الدخول", + "content-manager.components.Select.draft-info-title": "الحالة: مسودة", + "content-manager.components.Select.publish-info-title": "الحالة: منشور", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "تخصيص كيف سيبدو عرض التحرير.", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "حدد إعدادات عرض القائمة.", + "content-manager.components.SettingsViewWrapper.pluginHeader.title": "{name} تكوين العرض -", + "content-manager.components.TableDelete.label": "{number, plural, one {# entry} آخر {# entries}} selected", + "content-manager.components.uid.apply": "طبق", + "content-manager.components.uid.available": "متاح", + "content-manager.components.uid.regenerate": "تجديد", + "content-manager.components.uid.suggested": "مقترح", + "content-manager.components.uid.unavailable": "غير متوفره", + "content-manager.containers.Edit.delete-entry": "احذف هذا الإدخال", + "content-manager.containers.Edit.information": "معلومة", + "content-manager.containers.Edit.information.by": "بواسطة", + "content-manager.containers.Edit.information.created": "أُنشء", + "content-manager.containers.Edit.information.draftVersion": "نسخة المسودة", + "content-manager.containers.Edit.information.editing": "التحرير", + "content-manager.containers.Edit.information.lastUpdate": "اخر تحديث", + "content-manager.containers.Edit.information.publishedVersion": "النسخة المنشورة", + "content-manager.containers.Edit.Link.Layout": "تكوين التخطيط", + "content-manager.containers.Edit.Link.Model": "تحرير نوع المجموعة", + "content-manager.containers.Edit.pluginHeader.title.new": "قم بإنشاء إدخال", + "content-manager.containers.EditSettingsView.modal-form.edit-field": "قم بتحرير الحقل", + "content-manager.containers.EditView.add.new-entry": "أضف إدخالاً", + "content-manager.containers.EditView.notification.errors": "النموذج يحتوي على بعض الأخطاء", + "content-manager.containers.List.draft": "مسودة", + "content-manager.containers.List.published": "نشرت", + "content-manager.containers.ListPage.items": "{number, plural, =0 {items} one {item} other {items}}", + "content-manager.containers.ListPage.table-headers.publishedAt": "State", + "content-manager.containers.ListSettingsView.modal-form.edit-label": "{fieldName} تعديل", + "content-manager.containers.SettingPage.add.field": "أدخل حقل آخر", + "content-manager.containers.SettingPage.add.relational-field": "أدخل حقل آخر ذي صلة", + "content-manager.containers.SettingPage.editSettings.entry.title": "عنوان الإدخال", + "content-manager.containers.SettingPage.editSettings.entry.title.description": "اضبط الحقل المعروض لإدخالك", + "content-manager.containers.SettingPage.editSettings.relation-field.description": "قم بتعيين الحقل المعروض في كل من طريقتي التحرير وعرض القائمة", + "content-manager.containers.SettingPage.layout": "تَخطِيط", + "content-manager.containers.SettingPage.listSettings.description": "تكوين الخيارات لنوع المجموعة هذا", + "content-manager.containers.SettingPage.pluginHeaderDescription": "تكوين الإعدادات المحددة لنوع المجموعة هذا", + "content-manager.containers.SettingPage.relations": "حقول ذات صله", + "content-manager.containers.SettingPage.settings": "إعدادات", + "content-manager.containers.SettingPage.view": "رؤية", + "content-manager.containers.SettingsPage.Block.contentType.title": "أنواع المجموعات", + "content-manager.containers.SettingsPage.Block.generalSettings.description": "تكوين الخيارات الافتراضية لأنواع المجموعة الخاصة بك", + "content-manager.containers.SettingsPage.pluginHeaderDescription": "قم بتكوين الإعدادات لجميع أنواع المجموعات والمجموعات الخاصة بك", + "content-manager.containers.SettingsView.list.subtitle": "تكوين تخطيط وعرض أنواع المجموعات والمجموعات الخاصة بك", + "content-manager.containers.SettingsView.list.title": "تكوينات العرض", + "content-manager.containers.SettingViewModel.pluginHeader.title": "{name} مدير محتوى -", + "content-manager.dnd.cancel-item": "{item}, dropped. Re-order cancelled.", + "content-manager.dnd.drop-item": "{item}, dropped. Final position in list: {position}.", + "content-manager.dnd.grab-item": "{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.", + "content-manager.dnd.instructions": "اضغط على مفتاح المسافة للاستيلاء وإعادة الترتيب", + "content-manager.dnd.reorder": "{item}, انتقل. منصب جديد في القائمة: {position}.", + "content-manager.DynamicTable.relation-loaded": "تم تحميل العلاقات", + "content-manager.DynamicTable.relation-loading": "يتم تحميل العلاقات", + "content-manager.DynamicTable.relation-more": "تحتوي هذه العلاقة على كيانات أكثر من المعروضة", + "content-manager.edit-settings-view.link-to-ctb.components": "قم بتحرير المكون", + "content-manager.edit-settings-view.link-to-ctb.content-types": "قم بتحرير نوع المحتوى", + "content-manager.emptyAttributes.button": "انتقل إلى منشئ نوع المجموعة", + "content-manager.emptyAttributes.description": "أضف حقلك الأول إلى نوع المجموعة الخاصة بك", + "content-manager.form.Input.hint.character.unit": "{maxValue, plural, one { character} other { characters}}", + "content-manager.form.Input.hint.minMaxDivider": " / ", + "content-manager.form.Input.hint.text": "{min, select, undefined {} other {min. {min}}}{divider}{max, select, undefined {} other {max. {max}}}{unit}{br}{description}", + "content-manager.form.Input.pageEntries.inputDescription": "ملاحظة: يمكنك تجاوز هذه القيمة في صفحة إعدادات نوع المجموعة.", + "content-manager.form.Input.sort.order": "ترتيب الافتراضي", + "content-manager.form.Input.wysiwyg": "WYSIWYG عرض كـ", + "content-manager.global.displayedFields": "الحقول المعروضة", + "content-manager.groups": "مجموعات", + "content-manager.groups.numbered": "({number}) مجموعات", + "content-manager.header.name": "محتوى", + "content-manager.HeaderLayout.button.label-add-entry": "إنشاء إدخال جديد", + "content-manager.link-to-ctb": "قم بتحرير النموذج", + "content-manager.models": "أنواع المجموعات", + "content-manager.models.numbered": "({number}) أنواع المجموعات", + "content-manager.notification.info.minimumFields": "يجب أن يكون لديك حقل واحد على الأقل معروض", + "content-manager.notification.upload.error": "حدث خطأ أثناء تحميل ملفاتك", + "content-manager.pages.ListView.header-subtitle": "{number, plural, =0 {# entries} one {# entry} other {# entries}} found", + "content-manager.pages.NoContentType.button": "قم بإنشاء نوع المحتوى الأول الخاص بك", + "content-manager.pages.NoContentType.text": "ليس لديك أي محتوى حتى الآن ، نوصيك بإنشاء نوع المحتوى الأول الخاص بك.", + "content-manager.permissions.not-allowed.create": "لا يسمح لك لإنشاء وثيقة", + "content-manager.permissions.not-allowed.update": "لا يسمح لك أن ترى هذه الوثيقة", + "content-manager.popover.display-relations.label": "عرض العلاقات", + "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "نعم ، انشر", + "content-manager.popUpwarning.warning.has-draft-relations.message": "{count, plural, one { relation is } آخر { relations are } } لم تنشر بعد وقد تؤدي إلى سلوك غير متوقع.", + "content-manager.popUpWarning.warning.has-draft-relations.title": "تأكيد", + "content-manager.popUpWarning.warning.publish-question": "هل مازلت تريد النشر؟", + "content-manager.popUpWarning.warning.unpublish": "إذا لم تنشر هذا المحتوى ، فسيتحول تلقائيًا إلى مسودة.", + "content-manager.popUpWarning.warning.unpublish-question": "هل أنت متأكد أنك لا تريد نشره؟", + "content-manager.relation.add": "أضف العلاقة", + "content-manager.relation.disconnect": "نزع", + "content-manager.relation.isLoading": "يتم تحميل العلاقات", + "content-manager.relation.loadMore": "تحميل المزيد", + "content-manager.relation.notAvailable": "لا توجد علاقات متاحة", + "content-manager.relation.publicationState.draft": "مسودة", + "content-manager.relation.publicationState.published": "منشور", + "content-manager.select.currently.selected": "{count} المحدد حاليا", + "content-manager.success.record.publish": "منشور", + "content-manager.success.record.unpublish": "غير منشورة", + "content-manager.utils.data-loaded": "The {number, plural, =1 {entry has} other {entries have}} successfully been loaded", + "dark": "داكن", + "Documentation": "توثيق", + "form.button.continue": "واصل", + "form.button.done": "منتهي", + "global.actions": "أجراءات", + "global.auditLogs": "سجلات التدقيق", + "global.back": "الى الوراء", + "global.cancel": "إلغاء", + "global.change-password": "تغيير كلمة المرور", + "global.content-manager": "مدير محتوى", + "global.continue": "واصل", + "global.delete": "مسح", + "global.delete-target": "{target} مسح ", + "global.description": "وصف", + "global.details": "تفاصيل", + "global.disabled": "إبطال", + "global.documentation": "توثيق", + "global.enabled": "ممكن", + "global.finish": "نهاية", + "global.marketplace": "المتجر", + "global.name": "اسم", + "global.none": "لا أحد", + "global.password": "كلمة المرور", + "global.plugins": "الإضافات", + "global.plugins.content-manager": "مدير محتوى", + "global.plugins.content-manager.description": "طريقة سريعة لرؤية وتحرير وحذف البيانات في قاعدة البيانات الخاصة بك.", + "global.plugins.content-type-builder": "منشئ نوع المحتوى", + "global.plugins.content-type-builder.description": "قم بنمذجة بنية البيانات الخاصة بواجهة برمجة التطبيقات (API) الخاصة بك. إنشاء مجالات وعلاقات جديدة في دقيقة واحدة فقط. يتم إنشاء الملفات وتحديثها تلقائيًا في مشروعك.", + "global.plugins.documentation": "توثيق", + "global.plugins.documentation.description": "قم بإنشاء مستند OpenAPI وتصور API الخاص بك باستخدام SWAGGER UI.", + "global.plugins.email": "بريد إلكتروني", + "global.plugins.email.description": "تكوين التطبيق الخاص بك لإرسال رسائل البريد الإلكتروني.", + "global.plugins.graphql": "GraphQL", + "global.plugins.graphql.description": "يضيف نقطة نهاية GraphQL بأساليب واجهة برمجة التطبيقات الافتراضية.", + "global.plugins.i18n": "تدويل", + "global.plugins.i18n.description": "يمكّن هذا المكون الإضافي من إنشاء المحتوى وقراءته وتحديثه بلغات مختلفة ، سواء من لوحة الإدارة أو من واجهة برمجة التطبيقات.", + "global.plugins.sentry": "Sentry", + "global.plugins.sentry.description": "إرسال أحداث خطأ Strapi إلى Sentry.", + "global.plugins.upload": "مكتبة الوسائط", + "global.plugins.upload.description": "إدارة ملفات الوسائط.", + "global.plugins.users-permissions": "الأدوار والأذونات", + "global.plugins.users-permissions.description": "قم بحماية API الخاص بك من خلال عملية مصادقة كاملة تعتمد على JWT. يأتي هذا المكون الإضافي أيضًا مع إستراتيجية قائمة التحكم بالوصول (ACL) التي تتيح لك إدارة الأذونات بين مجموعات المستخدمين.", + "global.profile": "حساب تعريفي", + "global.prompt.unsaved": "هل أنت متأكد أنك تريد مغادرة هذه الصفحة؟ ستفقد كل تعديلاتك", + "global.reset-password": "إعادة تعيين كلمة المرور", + "global.roles": "الأدوار", + "global.save": "يحفظ", + "global.search": "يبحث", + "global.see-more": "شاهد المزيد", + "global.select": "اختار", + "global.select-all-entries": "حدد كل الإدخالات", + "global.settings": "إعدادات", + "global.type": "نوع", + "global.users": "المستخدمون", + "HomePage.helmet.title": "الصفحة الرئيسية", + "HomePage.roadmap": "انظر خارطة الطريق لدينا", + "HomePage.welcome.congrats": "تهاني!", + "HomePage.welcome.congrats.content": "Strapiلقد قمت بتسجيل الدخول باعتبارك المسؤول الأول. لاكتشاف الميزات القوية التي يوفرها", + "HomePage.welcome.congrats.content.bold": "نوصيك بإنشاء أول نوع مجموعة خاص بك.", + "light": "فاتح", + "Media Library": "مكتبة الوسائط", + "notification.contentType.relations.conflict": "نوع المحتوى له علاقات متضاربة", + "notification.default.title": "معلومة:", + "notification.ee.warning.at-seat-limit.title": "{LicenseLimitStatus ، حدد ، OVER_LIMIT {Over} AT_LIMIT {At}} حد المقاعد ({currentUserCount} / {allowedSeats})", + "notification.ee.warning.over-.message": "أضف مقاعد إلى {LicenseLimitStatus ، حدد ، OVER_LIMIT {دعوة} AT_LIMIT {re-enable}} مستخدمين. إذا كنت قد فعلت ذلك بالفعل ولكن لم ينعكس في Strapi بعد ، فتأكد من إعادة تشغيل التطبيق الخاص بك.", + "notification.error.invalid.configuration": "لديك تكوين غير صالح ، تحقق من سجل الخادم لمزيد من المعلومات.", + "notification.error.tokennamenotunique": "تم تعيين الاسم بالفعل لرمز مميز آخر", + "notification.form.error.fields": "النموذج يحتوي على بعض الأخطاء", + "notification.form.success.fields": "تم حفظ التغييرات", + "notification.link-copied": "تم نسخ الرابط في الحافظة", + "notification.permission.not-allowed-read": "لا يسمح لك أن ترى هذه الوثيقة", + "notification.success.apitokencreated": "تم إنشاء رمز API بنجاح", + "notification.success.apitokenedited": "تم تحرير رمز API بنجاح", + "notification.success.delete": "تم حذف العنصر", + "notification.success.saved": "حفظ", + "notification.success.title": "نجاح:", + "notification.success.transfertokencreated": "تم إنشاء رمز النقل بنجاح", + "notification.success.transfertokenedited": "تم تحرير رمز النقل بنجاح", + "notification.version.update.message": "نسخة جديدة متاحة من ستربي!", + "notification.warning.404": "404 غير موجود", + "notification.warning.title": "تحذير:", + "or": "أو", + "Roles & Permissions": "الأدوار والأذونات", + "Roles.components.List.empty.withSearch": "لا يوجد دور مطابق للبحث ({search}) ...", + "Roles.ListPage.notification.delete-all-not-allowed": "تعذر حذف بعض الأدوار لأنها مرتبطة بالمستخدمين", + "Roles.ListPage.notification.delete-not-allowed": "لا يمكن حذف الدور إذا كان مرتبطًا بالمستخدمين", + "Roles.RoleRow.select-all": "حدد {name} للإجراءات المجمعة", + "Roles.RoleRow.user-count": "{number، plural، = 0 {# user} واحد {# user} آخر {# users}}", + "selectButtonTitle": "يختار", + "Settings.apiTokens.addFirstToken": "أضف رمز API الأول الخاص بك", + "Settings.apiTokens.addNewToken": "إضافة رمز API جديد", + "Settings.apiTokens.create": "إنشاء رمز API جديد", + "Settings.apiTokens.createPage.BoundRoute.title": "طريق منضم إلى", + "Settings.apiTokens.createPage.permissions.description": "يتم سرد الإجراءات المرتبطة بالمسار فقط أدناه.", + "Settings.apiTokens.createPage.permissions.header.hint": "حدد إجراءات التطبيق أو إجراءات البرنامج المساعد وانقر على أيقونة الترس لعرض المسار المنضم", + "Settings.apiTokens.createPage.permissions.header.title": "إعدادات متقدمة", + "Settings.apiTokens.createPage.permissions.title": "أذونات", + "Settings.apiTokens.createPage.title": "إنشاء رمز API", + "Settings.apiTokens.description": "قائمة الرموز التي تم إنشاؤها لاستهلاك API", + "Settings.apiTokens.emptyStateLayout": "ليس لديك أي محتوى حتى الآن ...", + "Settings.apiTokens.ListView.headers.createdAt": "أنشئت في", + "Settings.apiTokens.ListView.headers.description": "وصف", + "Settings.apiTokens.ListView.headers.lastUsedAt": "آخر أستخدام", + "Settings.apiTokens.ListView.headers.name": "اسم", + "Settings.apiTokens.ListView.headers.type": "نوع الرمز", + "Settings.apiTokens.regenerate": "تجديد", + "Settings.apiTokens.title": "رموز API", + "Settings.application.customization": "التخصيص", + "Settings.application.customization.auth-logo.carousel-hint": "استبدل الشعار في صفحات المصادقة", + "Settings.application.customization.carousel-hint": "تغيير شعار لوحة الإدارة (الحد الأقصى للبعد: {dimension} {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت)", + "Settings.application.customization.carousel-slide.label": "شريحة الشعار", + "Settings.application.customization.carousel.auth-logo.title": "شعار Auth", + "Settings.application.customization.carousel.change-action": "تغيير الشعار", + "Settings.application.customization.carousel.menu-logo.title": "شعار القائمة", + "Settings.application.customization.carousel.reset-action": "إعادة تعيين الشعار", + "Settings.application.customization.carousel.title": "شعار", + "Settings.application.customization.menu-logo.carousel-hint": "استبدل الشعار في شريط التنقل الرئيسي", + "Settings.application.customization.modal.cancel": "إلغاء", + "Settings.application.customization.modal.pending": "شعار معلق", + "Settings.application.customization.modal.pending.card-badge": "صورة", + "Settings.application.customization.modal.pending.choose-another": "اختر شعارًا آخر", + "Settings.application.customization.modal.pending.subtitle": "إدارة الشعار المختار قبل تحميله", + "Settings.application.customization.modal.pending.title": "الشعار جاهز للتحميل", + "Settings.application.customization.modal.pending.upload": "تحميل الشعار", + "Settings.application.customization.modal.tab.label": "كيف تريد تحميل الأصول الخاصة بك؟", + "Settings.application.customization.modal.upload": "تحميل الشعار", + "Settings.application.customization.modal.upload.cta.browse": "تصفح ملفات", + "Settings.application.customization.modal.upload.drag-drop": "قم بالسحب والإفلات هنا أو", + "Settings.application.customization.modal.upload.error-format": "تم تحميل تنسيق خاطئ (التنسيقات المقبولة فقط: jpeg ، jpg ، png ، svg).", + "Settings.application.customization.modal.upload.error-network": "خطأ في الشبكة", + "Settings.application.customization.modal.upload.error-size": "الملف الذي تم تحميله كبير جدًا (الحد الأقصى للبعد: {dimension} x {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت)", + "Settings.application.customization.modal.upload.file-validation": "أقصى بُعد: {dimension} x {dimension} ، الحد الأقصى للحجم: {size} كيلوبايت", + "Settings.application.customization.modal.upload.from-computer": "من الكمبيوتر", + "Settings.application.customization.modal.upload.from-url": "من URL", + "Settings.application.customization.modal.upload.from-url.input-label": "URL", + "Settings.application.customization.modal.upload.next": "التالي", + "Settings.application.customization.size-details": "أقصى بُعد: {dimension} x {dimension} ، الحد الأقصى لحجم الملف: {size} كيلوبايت", + "Settings.application.description": "المعلومات العالمية للوحة الإدارة", + "Settings.application.edition-title": "الخطة الحالية", + "Settings.application.ee-or-ce": "{communityEdition، select، true {Community Edition} أخرى {Enterprise Edition}}", + "Settings.application.ee.admin-seats.add-seats": "{isHostedOnStrapiCloud، select، true {Add seat} other {Contact sales}}", + "Settings.application.ee.admin-seats.at-limit-tooltip": "عند الحد: أضف مقاعد لدعوة المزيد من المستخدمين", + "Settings.application.ee.admin-seats.count": "