create-mithaq 0.1.1 → 0.2.0
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/LICENSES/openstatus-time-picker.txt +21 -0
- package/index.js +457 -63
- package/package.json +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/package.json +5 -3
- package/template/apps/{asas-platform → asas-backoffice}/src/api.ts +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/src/auth-frame.tsx +12 -12
- package/template/apps/asas-backoffice/src/components.ts +35 -0
- package/template/apps/asas-backoffice/src/first-user.ts +14 -0
- package/template/apps/{asas-platform → asas-backoffice}/src/links.ts +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/src/locale-switch.tsx +7 -5
- package/template/apps/asas-backoffice/src/no-organization.tsx +5 -0
- package/template/apps/asas-backoffice/src/redirect.ts +1 -0
- package/template/apps/{asas-platform → asas-backoffice}/src/request-headers.ts +1 -1
- package/template/apps/asas-backoffice/src/routeTree.gen.ts +206 -0
- package/template/apps/asas-backoffice/src/router.tsx +18 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice/files.ts +10 -0
- package/template/apps/{asas-platform/src/routes/(screens)/platform → asas-backoffice/src/routes/(screens)/backoffice}/screen.json +426 -64
- package/template/apps/{asas-platform/src/routes/(screens)/platform → asas-backoffice/src/routes/(screens)/backoffice}/types.ts +18 -0
- package/template/apps/{asas-platform/src/routes/(screens)/platform.$.tsx → asas-backoffice/src/routes/(screens)/backoffice.$.tsx} +4 -4
- package/template/apps/{asas-platform/src/routes/(screens)/platform.index.tsx → asas-backoffice/src/routes/(screens)/backoffice.index.tsx} +3 -3
- package/template/apps/{asas-platform/src/routes/(screens)/platform.tsx → asas-backoffice/src/routes/(screens)/backoffice.tsx} +3 -3
- package/template/apps/{asas-platform → asas-backoffice}/src/routes/__root.tsx +2 -2
- package/template/apps/asas-backoffice/src/routes/api/$.ts +34 -0
- package/template/apps/asas-backoffice/src/routes/auth.create-first-user.tsx +113 -0
- package/template/apps/{asas-platform → asas-backoffice}/src/routes/auth.sign-in.tsx +9 -4
- package/template/apps/{asas-platform → asas-backoffice}/src/routes/unauthorized.tsx +24 -12
- package/template/apps/{asas-platform → asas-backoffice}/src/screen-form.tsx +5 -3
- package/template/apps/{asas-platform → asas-backoffice}/src/screen-list.tsx +6 -5
- package/template/apps/{asas-platform → asas-backoffice}/src/screen-names.ts +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/src/screens.tsx +46 -26
- package/template/apps/asas-backoffice/src/server.ts +30 -0
- package/template/apps/{asas-platform → asas-backoffice}/src/slide.ts +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/src/start.ts +1 -1
- package/template/apps/{asas-platform → asas-backoffice}/src/styles.css +9 -7
- package/template/apps/{asas-platform → asas-backoffice}/tsconfig.json +2 -2
- package/template/apps/{asas-platform → asas-backoffice}/vite.config.ts +7 -1
- package/template/apps/asas-tanstack/package.json +4 -2
- package/template/apps/asas-tanstack/src/api.ts +1 -1
- package/template/apps/asas-tanstack/src/auth-frame.tsx +12 -12
- package/template/apps/asas-tanstack/src/choose-password.tsx +150 -0
- package/template/apps/asas-tanstack/src/components.ts +35 -0
- package/template/apps/asas-tanstack/src/copy.ts +416 -79
- package/template/apps/asas-tanstack/src/first-run.ts +16 -0
- package/template/apps/asas-tanstack/src/links.ts +1 -1
- package/template/apps/asas-tanstack/src/locale-switch.tsx +7 -5
- package/template/apps/asas-tanstack/src/no-organization.tsx +108 -0
- package/template/apps/asas-tanstack/src/redirect.ts +20 -1
- package/template/apps/asas-tanstack/src/request-headers.ts +1 -1
- package/template/apps/asas-tanstack/src/routeTree.gen.ts +42 -0
- package/template/apps/asas-tanstack/src/router.tsx +12 -1
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/files.ts +9 -2
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/screen.json +475 -116
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/types.ts +4 -2
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/files.ts +7 -2
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/screen.json +83 -319
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/types.ts +3 -1
- package/template/apps/asas-tanstack/src/routes/__root.tsx +1 -1
- package/template/apps/asas-tanstack/src/routes/auth.accept-invitation.tsx +14 -7
- package/template/apps/asas-tanstack/src/routes/auth.first-run.tsx +114 -0
- package/template/apps/asas-tanstack/src/routes/auth.forgot-password.tsx +2 -2
- package/template/apps/asas-tanstack/src/routes/auth.handoff.ts +5 -5
- package/template/apps/asas-tanstack/src/routes/auth.reset-password.tsx +7 -100
- package/template/apps/asas-tanstack/src/routes/auth.set-password.tsx +16 -0
- package/template/apps/asas-tanstack/src/routes/auth.sign-in.tsx +27 -15
- package/template/apps/asas-tanstack/src/routes/auth.sign-up.tsx +59 -38
- package/template/apps/asas-tanstack/src/routes/index.tsx +18 -14
- package/template/apps/asas-tanstack/src/routes/unauthorized.tsx +24 -12
- package/template/apps/asas-tanstack/src/screen-form.tsx +5 -3
- package/template/apps/asas-tanstack/src/screen-list.tsx +6 -5
- package/template/apps/asas-tanstack/src/screen-names.ts +1 -1
- package/template/apps/asas-tanstack/src/screens.tsx +46 -26
- package/template/apps/asas-tanstack/src/server.ts +10 -0
- package/template/apps/asas-tanstack/src/slide.ts +1 -1
- package/template/apps/asas-tanstack/src/styles.css +7 -3
- package/template/apps/asas-tanstack/tsconfig.json +2 -2
- package/template/apps/asas-tanstack/vite.config.ts +7 -1
- package/template/package.json +3 -3
- package/template/templates/asas/.claude/skills/add-field/SKILL.md +27 -0
- package/template/templates/asas/.claude/skills/add-kayan/SKILL.md +26 -0
- package/template/templates/asas/.claude/skills/eject-admin-piece/SKILL.md +28 -0
- package/template/templates/asas/.claude/skills/upgrade-mithaq/SKILL.md +35 -0
- package/template/templates/asas/.env.example +22 -5
- package/template/templates/asas/AGENTS.md +101 -0
- package/template/templates/asas/CLAUDE.md +1 -0
- package/template/templates/asas/README.md +1056 -0
- package/template/templates/asas/package.json +19 -4
- package/template/templates/asas/src/asas.ts +81 -56
- package/template/templates/asas/src/{platform-http.ts → backoffice-http.ts} +48 -27
- package/template/templates/asas/src/dev-setup.ts +112 -0
- package/template/templates/asas/src/local-database.ts +22 -0
- package/template/templates/asas/src/messages/account.json +129 -103
- package/template/templates/asas/src/messages/auditLog.json +223 -105
- package/template/templates/asas/src/messages/backofficeLog.json +132 -0
- package/template/templates/asas/src/messages/courses.json +256 -214
- package/template/templates/asas/src/messages/enrollments.json +45 -27
- package/template/templates/asas/src/messages/invitation.json +72 -56
- package/template/templates/asas/src/messages/localUsers.json +34 -28
- package/template/templates/asas/src/messages/media.json +31 -21
- package/template/templates/asas/src/messages/member.json +59 -39
- package/template/templates/asas/src/messages/memberRoles.json +37 -31
- package/template/templates/asas/src/messages/mithaq.json +206 -162
- package/template/templates/asas/src/messages/organization.json +63 -41
- package/template/templates/asas/src/messages/organizationRole.json +59 -47
- package/template/templates/asas/src/messages/roles.json +59 -45
- package/template/templates/asas/src/messages/session.json +99 -79
- package/template/templates/asas/src/messages/sessions.json +110 -80
- package/template/templates/asas/src/messages/settings.json +51 -53
- package/template/templates/asas/src/messages/tags.json +31 -21
- package/template/templates/asas/src/messages/user.json +109 -87
- package/template/templates/asas/src/messages/verification.json +59 -47
- package/template/templates/asas/src/migrations/20261014221355_tags_restrict/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014221355_tags_restrict/snapshot.json +3881 -0
- package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/snapshot.json +3894 -0
- package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/snapshot.json +3907 -0
- package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/snapshot.json +3907 -0
- package/template/templates/asas/src/migrations/20261015042444_organization_names/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261015042444_organization_names/snapshot.json +3920 -0
- package/template/templates/asas/src/migrations/20261015053212_member_last_seen/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261015053212_member_last_seen/snapshot.json +3933 -0
- package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/snapshot.json +4113 -0
- package/template/templates/asas/src/migrations/20261015095752_portal/migration.sql +2 -0
- package/template/templates/asas/src/migrations/20261015095752_portal/snapshot.json +4113 -0
- package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/migration.sql +9 -0
- package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/snapshot.json +4302 -0
- package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/migration.sql +27 -0
- package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/snapshot.json +4289 -0
- package/template/templates/asas/src/migrations/schema.ts +1 -0
- package/template/templates/asas/src/mithaq.ts +4 -406
- package/template/templates/asas/src/organizations.ts +3 -0
- package/template/templates/asas/src/seed.ts +147 -45
- package/template/templates/asas/src/{ui-platform → ui-backoffice}/home.tsx +9 -9
- package/template/templates/asas/src/ui-backoffice/organization-actions.tsx +121 -0
- package/template/templates/asas/src/{ui-platform → ui-backoffice}/record-page.tsx +4 -4
- package/template/templates/asas/src/{ui-platform → ui-backoffice}/role-cells.tsx +13 -6
- package/template/templates/asas/src/{ui-platform → ui-backoffice}/user-actions.tsx +46 -48
- package/template/templates/asas/src/ui-dashboard/dashboard.tsx +10 -4
- package/template/templates/asas/src/ui-dashboard/home.tsx +73 -0
- package/template/templates/asas/src/ui-dashboard/members-card.tsx +147 -0
- package/template/templates/asas/src/ui-dashboard/members.tsx +637 -438
- package/template/templates/asas/src/ui-dashboard/versions.tsx +22 -8
- package/template/templates/asas/src/ui-portal/courses-home.tsx +96 -0
- package/template/templates/asas/src/ui-portal/home.tsx +9 -13
- package/template/templates/features/audit-log/audit-log/audit-log.ts +284 -0
- package/template/templates/features/audit-log/backoffice-log/backoffice-log.ts +67 -0
- package/template/templates/features/audit-log/index.ts +4 -0
- package/template/templates/features/audit-log/package.json +13 -0
- package/template/templates/features/auth/index.ts +11 -0
- package/template/templates/{asas/src → features/auth}/local-users/local-users.ts +7 -7
- package/template/templates/{auth → features/auth}/package.json +2 -3
- package/template/templates/{asas/src/kayan → features}/auth/user/account.access.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/account.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/invitation.access.ts +1 -1
- package/template/templates/{asas/src/kayan → features}/auth/user/invitation.ts +3 -3
- package/template/templates/{asas/src/kayan → features}/auth/user/member.access.ts +4 -4
- package/template/templates/{asas/src/kayan → features}/auth/user/member.screens.ts +5 -5
- package/template/templates/{asas/src/kayan → features}/auth/user/member.ts +4 -3
- package/template/templates/{asas/src/kayan → features}/auth/user/organization.access.ts +6 -6
- package/template/templates/{asas/src/kayan → features}/auth/user/organization.screens.ts +6 -6
- package/template/templates/{asas/src/kayan → features}/auth/user/organization.ts +2 -1
- package/template/templates/{asas/src/kayan → features}/auth/user/organizationRole.access.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/organizationRole.ts +3 -3
- package/template/templates/{asas/src/kayan → features}/auth/user/session.access.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/session.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/user.access.ts +8 -7
- package/template/templates/{asas/src/kayan → features}/auth/user/user.screens.ts +9 -9
- package/template/templates/{asas/src/kayan → features}/auth/user/user.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/verification.access.ts +2 -2
- package/template/templates/{asas/src/kayan → features}/auth/user/verification.ts +2 -2
- package/template/templates/{asas/src → features/courses}/courses/courses.ts +122 -133
- package/template/templates/features/courses/courses/cover-reads.ts +33 -0
- package/template/templates/features/courses/courses/ui/archived-badge.tsx +9 -0
- package/template/templates/{asas/src → features/courses}/courses/ui/fee-cell.tsx +1 -1
- package/template/templates/{asas/src → features/courses}/courses/ui/status-cell.tsx +5 -3
- package/template/templates/features/courses/courses/ui/unpublish-button.tsx +15 -0
- package/template/templates/features/courses/domain/archive.ts +39 -0
- package/template/templates/features/courses/domain/on-offer.ts +6 -0
- package/template/templates/features/courses/enrollments/enrollments.ts +309 -0
- package/template/templates/{asas/src → features/courses}/enrollments/ui/session-cell.tsx +17 -7
- package/template/templates/{asas/src → features/courses/enrollments}/ui/session-labels.tsx +3 -3
- package/template/templates/features/courses/index.ts +8 -0
- package/template/templates/features/courses/package.json +24 -0
- package/template/templates/features/courses/portal/ui/catalogue.tsx +86 -0
- package/template/templates/features/courses/portal/ui/course.tsx +176 -0
- package/template/templates/features/courses/portal/ui/enrollments.tsx +170 -0
- package/template/templates/features/courses/portal/ui/parts.tsx +95 -0
- package/template/templates/features/courses/portal/ui/reads.ts +76 -0
- package/template/templates/features/courses/portal/ui/rules.ts +87 -0
- package/template/templates/features/courses/portal/ui/shell.tsx +194 -0
- package/template/templates/features/courses/sessions/seats.ts +42 -0
- package/template/templates/{asas/src → features/courses}/sessions/sessions.ts +45 -14
- package/template/templates/features/media/index.ts +10 -0
- package/template/templates/{asas/src → features/media}/media/media.ts +34 -40
- package/template/templates/{asas/src → features/media}/media/ui/preview.tsx +2 -2
- package/template/templates/features/media/package.json +19 -0
- package/template/templates/features/roles/index.ts +4 -0
- package/template/templates/{asas/src → features/roles}/member-roles/member-roles.ts +15 -15
- package/template/templates/features/roles/package.json +21 -0
- package/template/templates/{asas/src → features/roles}/roles/roles.ts +23 -23
- package/template/templates/{asas/src → features/roles}/roles/ui/role-form.tsx +65 -24
- package/template/templates/{asas/src → features/roles}/roles/ui/roles.tsx +49 -25
- package/template/templates/features/settings/index.ts +3 -0
- package/template/templates/features/settings/package.json +13 -0
- package/template/templates/{asas/src → features/settings}/settings/settings.ts +12 -17
- package/template/templates/features/tags/index.ts +3 -0
- package/template/templates/features/tags/package.json +14 -0
- package/template/templates/{asas/src → features/tags}/tags/tags.ts +15 -15
- package/template/templates/mithaq/package.json +33 -0
- package/template/templates/mithaq/src/mail/index.ts +32 -0
- package/template/templates/mithaq/src/mail/mailers.ts +36 -0
- package/template/templates/{asas/src/audit-log/sink.ts → mithaq/src/mithaq/audit-sink.ts} +31 -9
- package/template/templates/{auth/src/platform-roles.ts → mithaq/src/mithaq/auth/backoffice-roles.ts} +44 -23
- package/template/templates/mithaq/src/mithaq/auth/index.ts +1859 -0
- package/template/templates/mithaq/src/mithaq/auth/organizations.ts +80 -0
- package/template/templates/{asas/src → mithaq/src/mithaq}/pages.ts +16 -7
- package/template/templates/mithaq/src/mithaq/rich-text-nodes.ts +19 -0
- package/template/templates/mithaq/src/mithaq.ts +593 -0
- package/template/templates/mithaq/src/roles/default-member-roles.ts +29 -0
- package/template/templates/{asas → mithaq}/src/roles/grants.ts +1 -1
- package/template/templates/mithaq/src/roles/member-access.ts +11 -0
- package/template/templates/{asas/src → mithaq/src/roles}/statements.ts +6 -4
- package/template/templates/mithaq/src/roles/system-roles.ts +16 -0
- package/template/templates/{asas/src → mithaq/src/roles}/tenant-access.ts +96 -57
- package/template/templates/{asas/src → mithaq/src/roles}/tenant-roles.ts +84 -25
- package/template/templates/{asas → mithaq}/src/steps/expected-updated-at.ts +2 -2
- package/template/templates/{asas → mithaq}/src/storage/index.ts +3 -1
- package/template/templates/mithaq/src/ui/activity-page.tsx +33 -0
- package/template/templates/mithaq/src/ui/activity.tsx +527 -0
- package/template/templates/{asas → mithaq}/src/ui/app-shell.tsx +27 -19
- package/template/templates/mithaq/src/ui/rich-text-nodes.tsx +33 -0
- package/template/templates/{asas → mithaq}/src/ui/screen-nav.tsx +1 -1
- package/template/templates/{asas → mithaq}/src/ui/top-shell.tsx +8 -8
- package/template/apps/asas-platform/src/components/mithaq/cells.tsx +0 -112
- package/template/apps/asas-platform/src/components/mithaq/controls.tsx +0 -650
- package/template/apps/asas-platform/src/components/mithaq/field-shell.tsx +0 -53
- package/template/apps/asas-platform/src/components/mithaq/filter-operators.ts +0 -108
- package/template/apps/asas-platform/src/components/mithaq/form.tsx +0 -1467
- package/template/apps/asas-platform/src/components/mithaq/list-columns.tsx +0 -108
- package/template/apps/asas-platform/src/components/mithaq/list-filters.tsx +0 -368
- package/template/apps/asas-platform/src/components/mithaq/list-pagination.tsx +0 -153
- package/template/apps/asas-platform/src/components/mithaq/list-query.ts +0 -432
- package/template/apps/asas-platform/src/components/mithaq/list-selection.tsx +0 -74
- package/template/apps/asas-platform/src/components/mithaq/list.tsx +0 -865
- package/template/apps/asas-platform/src/components/mithaq/nav.tsx +0 -871
- package/template/apps/asas-platform/src/components/mithaq/nodes.tsx +0 -1024
- package/template/apps/asas-platform/src/components/mithaq/relationship-cell.tsx +0 -127
- package/template/apps/asas-platform/src/components/mithaq/relationship-control.tsx +0 -400
- package/template/apps/asas-platform/src/components/mithaq/rich-text-nodes.ts +0 -6
- package/template/apps/asas-platform/src/components/mithaq/rich-text.tsx +0 -1083
- package/template/apps/asas-platform/src/components/mithaq/upload.tsx +0 -686
- package/template/apps/asas-platform/src/components/ui/drawer.tsx +0 -216
- package/template/apps/asas-platform/src/redirect.ts +0 -1
- package/template/apps/asas-platform/src/routeTree.gen.ts +0 -181
- package/template/apps/asas-platform/src/router.tsx +0 -7
- package/template/apps/asas-platform/src/routes/(screens)/platform/files.ts +0 -4
- package/template/apps/asas-platform/src/routes/api/$.ts +0 -30
- package/template/apps/asas-platform/src/server.ts +0 -20
- package/template/apps/asas-tanstack/src/components/mithaq/cells.tsx +0 -112
- package/template/apps/asas-tanstack/src/components/mithaq/controls.tsx +0 -650
- package/template/apps/asas-tanstack/src/components/mithaq/field-shell.tsx +0 -53
- package/template/apps/asas-tanstack/src/components/mithaq/filter-operators.ts +0 -108
- package/template/apps/asas-tanstack/src/components/mithaq/form.tsx +0 -1467
- package/template/apps/asas-tanstack/src/components/mithaq/list-columns.tsx +0 -108
- package/template/apps/asas-tanstack/src/components/mithaq/list-filters.tsx +0 -368
- package/template/apps/asas-tanstack/src/components/mithaq/list-pagination.tsx +0 -153
- package/template/apps/asas-tanstack/src/components/mithaq/list-query.ts +0 -432
- package/template/apps/asas-tanstack/src/components/mithaq/list-selection.tsx +0 -74
- package/template/apps/asas-tanstack/src/components/mithaq/list.tsx +0 -865
- package/template/apps/asas-tanstack/src/components/mithaq/nav.tsx +0 -871
- package/template/apps/asas-tanstack/src/components/mithaq/nodes.tsx +0 -1024
- package/template/apps/asas-tanstack/src/components/mithaq/relationship-cell.tsx +0 -127
- package/template/apps/asas-tanstack/src/components/mithaq/relationship-control.tsx +0 -400
- package/template/apps/asas-tanstack/src/components/mithaq/rich-text-nodes.ts +0 -6
- package/template/apps/asas-tanstack/src/components/mithaq/rich-text.tsx +0 -1083
- package/template/apps/asas-tanstack/src/components/mithaq/upload.tsx +0 -686
- package/template/apps/asas-tanstack/src/components/ui/drawer.tsx +0 -215
- package/template/templates/asas/src/audit-log/audit-log.ts +0 -187
- package/template/templates/asas/src/audit-log/ui/activity.tsx +0 -243
- package/template/templates/asas/src/courses/ui/archive-button.tsx +0 -25
- package/template/templates/asas/src/courses/ui/no-courses-on-offer.tsx +0 -11
- package/template/templates/asas/src/courses/ui/on-offer.ts +0 -6
- package/template/templates/asas/src/enrollments/enrollments.ts +0 -137
- package/template/templates/asas/src/rich-text-nodes.ts +0 -11
- package/template/templates/asas/src/roles.ts +0 -16
- package/template/templates/asas/src/ui/rich-text-nodes.tsx +0 -15
- package/template/templates/asas/src/ui-platform/organization-actions.tsx +0 -114
- package/template/templates/auth/src/index.ts +0 -690
- /package/template/apps/{asas-platform → asas-backoffice}/components.json +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/gitignore +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/public/favicon.svg +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/accordion.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/alert-dialog.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/avatar.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/badge.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/breadcrumb.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/button-group.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/button.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/calendar.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/card.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/chart.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/checkbox.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/collapsible.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/combobox.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/dialog.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/direction.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/directional-icon.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/dropdown-menu.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/field.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input-group.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input-otp.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/input.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/label.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/popover.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/radio-group.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/resizable.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/scroll-area.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/select.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/separator.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/sheet.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/sidebar.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/skeleton.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/slider.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/spinner.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/switch.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/table.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/tabs.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/textarea.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/toggle-group.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/toggle.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/components/ui/tooltip.tsx +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/copy.ts +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/hooks/use-mobile.ts +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/lib/utils.ts +0 -0
- /package/template/apps/{asas-platform → asas-backoffice}/src/theme.ts +0 -0
- /package/template/templates/{asas/src/kayan → features}/auth/user/index.ts +0 -0
- /package/template/templates/{asas/src → features/courses}/courses/ui/no-courses.tsx +0 -0
- /package/template/templates/{asas → mithaq}/components.json +0 -0
- /package/template/templates/{asas → mithaq}/src/storage/defaults.ts +0 -0
- /package/template/templates/{asas → mithaq}/src/storage/local.ts +0 -0
- /package/template/templates/{asas → mithaq}/src/storage/r2.ts +0 -0
- /package/template/templates/{asas → mithaq}/src/storage/s3.ts +0 -0
- /package/template/templates/{asas → mithaq}/src/storage/uploadthing.ts +0 -0
- /package/template/templates/{asas → mithaq}/src/ui/kpi-card.tsx +0 -0
- /package/template/templates/{asas → mithaq}/src/ui/record-page.tsx +0 -0
- /package/template/templates/{asas → mithaq}/src/ui/table-page.tsx +0 -0
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
// Imports no router, stylesheet or React, so a test can load this under plain `node`.
|
|
2
|
+
import { flattenMessageFile } from 'mithaq/admin'
|
|
3
|
+
import { organizations, showOrganization } from 'asas/organizations'
|
|
4
|
+
import localUsers from 'asas/messages/localUsers.json' with { type: 'json' }
|
|
5
|
+
import organization from 'asas/messages/organization.json' with { type: 'json' }
|
|
6
|
+
import tags from 'asas/messages/tags.json' with { type: 'json' }
|
|
7
|
+
// add-on: audit-log
|
|
2
8
|
import auditLog from 'asas/messages/auditLog.json' with { type: 'json' }
|
|
9
|
+
import backofficeLog from 'asas/messages/backofficeLog.json' with { type: 'json' }
|
|
10
|
+
// end add-on: audit-log
|
|
11
|
+
// add-on: courses
|
|
3
12
|
import courses from 'asas/messages/courses.json' with { type: 'json' }
|
|
4
13
|
import enrollments from 'asas/messages/enrollments.json' with { type: 'json' }
|
|
5
|
-
import
|
|
14
|
+
import sessions from 'asas/messages/sessions.json' with { type: 'json' }
|
|
15
|
+
// end add-on: courses
|
|
16
|
+
// add-on: media
|
|
6
17
|
import media from 'asas/messages/media.json' with { type: 'json' }
|
|
7
|
-
|
|
18
|
+
// end add-on: media
|
|
19
|
+
// add-on: roles
|
|
8
20
|
import memberRoles from 'asas/messages/memberRoles.json' with { type: 'json' }
|
|
9
21
|
import roles from 'asas/messages/roles.json' with { type: 'json' }
|
|
10
|
-
|
|
22
|
+
// end add-on: roles
|
|
23
|
+
// add-on: settings
|
|
11
24
|
import settings from 'asas/messages/settings.json' with { type: 'json' }
|
|
12
|
-
|
|
25
|
+
// end add-on: settings
|
|
13
26
|
|
|
14
27
|
// Restated, not imported: the original lives in a `.tsx` file and the test runner has no JSX compiler.
|
|
15
28
|
type Translate = (key: string, fallback?: string) => string | undefined
|
|
@@ -17,6 +30,11 @@ type Translate = (key: string, fallback?: string) => string | undefined
|
|
|
17
30
|
/** The locales this project declares. */
|
|
18
31
|
export const locales = ['ar', 'en'] as const
|
|
19
32
|
|
|
33
|
+
/** The app reads either message-file format during the upgrade release. */
|
|
34
|
+
export const copyFile = (file: Record<string, unknown>): Record<string, Record<string, string>> =>
|
|
35
|
+
Object.fromEntries(Object.entries(flattenMessageFile({ file, locales })).map(([key, value]) =>
|
|
36
|
+
[key, typeof value === 'string' ? Object.fromEntries(locales.map((locale) => [locale, value])) : value ?? {}]))
|
|
37
|
+
|
|
20
38
|
/** One of the locales this project declares. */
|
|
21
39
|
export type Locale = (typeof locales)[number]
|
|
22
40
|
|
|
@@ -42,20 +60,17 @@ export const localeOf = (asked: string | null | undefined): Locale =>
|
|
|
42
60
|
/** Which way a document in one locale runs. */
|
|
43
61
|
export const dirOf = (locale: Locale): 'rtl' | 'ltr' => (locale === 'ar' ? 'rtl' : 'ltr')
|
|
44
62
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*/
|
|
49
|
-
export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
63
|
+
/** The copy every organization mode starts from; `scopes` below lays the mode's words over it. */
|
|
64
|
+
const ownScopes: Record<string, Record<string, Record<string, string>>> = {
|
|
65
|
+
// add-on: courses
|
|
50
66
|
courses: {
|
|
51
|
-
...courses,
|
|
67
|
+
...copyFile(courses),
|
|
52
68
|
'delete.confirm': { en: 'Delete this course', ar: 'احذف هذه الدورة' },
|
|
53
69
|
dangerZoneWarning: { en: 'These actions change this course for everyone.', ar: 'هذه الإجراءات تغير هذه الدورة للجميع.' },
|
|
54
70
|
none: { en: 'No courses yet.', ar: 'لا توجد دورات بعد.' },
|
|
55
71
|
noneOnOffer: { en: 'No courses on offer yet.', ar: 'لا توجد دورات معروضة بعد.' },
|
|
56
72
|
'operations.archive': { en: 'Archive', ar: 'أرشفة' },
|
|
57
73
|
'operations.archive.warning': { en: 'This archives {name}.', ar: 'يؤرشف هذا الإجراء {name}.' },
|
|
58
|
-
'operations.archive.portalReason': { en: 'Archived from the portal by {name}', ar: 'أُرشفت من البوابة بواسطة {name}' },
|
|
59
74
|
'operations.findWithSessions': { en: 'View with its sessions', ar: 'عرض مع جلساتها' },
|
|
60
75
|
new: { en: 'New course', ar: 'دورة جديدة' },
|
|
61
76
|
'archived.true': { en: 'Archived', ar: 'مؤرشف' },
|
|
@@ -68,7 +83,12 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
68
83
|
en: 'An archive reason is at most 200 characters.',
|
|
69
84
|
ar: 'سبب الأرشفة 200 حرف على الأكثر.',
|
|
70
85
|
},
|
|
86
|
+
'operations.unarchive': { en: 'Unarchive', ar: 'إلغاء الأرشفة' },
|
|
87
|
+
'operations.unarchive.reason.required': { en: 'A reason to bring it back is required.', ar: 'سبب إلغاء الأرشفة مطلوب.' },
|
|
88
|
+
'operations.unarchive.reason.maxLength': { en: 'A reason to bring it back is at most 200 characters.', ar: 'سبب إلغاء الأرشفة 200 حرف على الأكثر.' },
|
|
89
|
+
'operations.unpublish': { en: 'Unpublish', ar: 'إلغاء النشر' },
|
|
71
90
|
},
|
|
91
|
+
// end add-on: courses
|
|
72
92
|
admin: {
|
|
73
93
|
nav: { en: 'Admin', ar: 'الإدارة' },
|
|
74
94
|
yes: { en: 'Yes', ar: 'نعم' },
|
|
@@ -91,6 +111,17 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
91
111
|
stopImpersonating: { en: 'Stop impersonating', ar: 'إيقاف انتحال الصفة' },
|
|
92
112
|
cancel: { en: 'Cancel', ar: 'إلغاء' },
|
|
93
113
|
close: { en: 'Close', ar: 'إغلاق' },
|
|
114
|
+
'done.created': { en: '{kind} created', ar: 'تم إنشاء {kind}' },
|
|
115
|
+
'done.saved': { en: '{kind} saved', ar: 'تم حفظ {kind}' },
|
|
116
|
+
'done.published': { en: '{kind} published', ar: 'تم نشر {kind}' },
|
|
117
|
+
'done.draftSaved': { en: 'Draft saved', ar: 'تم حفظ المسودة' },
|
|
118
|
+
'done.deleted': { en: '{kind} deleted', ar: 'تم حذف {kind}' },
|
|
119
|
+
'done.archive': { en: '{kind} archived', ar: 'تمت أرشفة {kind}' },
|
|
120
|
+
'done.unarchive': { en: '{kind} unarchived', ar: 'تم إلغاء أرشفة {kind}' },
|
|
121
|
+
'done.unpublish': { en: '{kind} unpublished', ar: 'تم إلغاء نشر {kind}' },
|
|
122
|
+
'done.restoreVersion': { en: 'Version restored', ar: 'استُعيدت النسخة' },
|
|
123
|
+
'done.ran': { en: '{operation}: done', ar: '{operation}: تم' },
|
|
124
|
+
requestFailed: { en: 'Something went wrong, so nothing was saved. Try again.', ar: 'حدث خطأ، فلم يُحفظ شيء. حاول مرة أخرى.' },
|
|
94
125
|
deleteWarning: { en: 'This cannot be undone.', ar: 'لا يمكن التراجع عن هذا.' },
|
|
95
126
|
deleteConfirm: { en: 'Delete for good', ar: 'احذف نهائيا' },
|
|
96
127
|
deleteFailed: { en: 'Something went wrong, so nothing was deleted. Try again.', ar: 'حدث خطأ، فلم يُحذف شيء. حاول مرة أخرى.' },
|
|
@@ -192,6 +223,9 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
192
223
|
noMatches: { en: 'No rows match this filter.', ar: 'لا توجد صفوف تطابق هذا المرشح.' },
|
|
193
224
|
refused: { en: 'That list could not be read.', ar: 'تعذرت قراءة هذه القائمة.' },
|
|
194
225
|
cannotSee: { en: 'You can\'t see this', ar: 'لا يمكنك رؤية هذا' },
|
|
226
|
+
// A held id with no row: one a read of its kayan answered without, and one the viewer may not read.
|
|
227
|
+
deleted: { en: 'Deleted', ar: 'محذوف' },
|
|
228
|
+
notAvailable: { en: 'Not available', ar: 'غير متاح' },
|
|
195
229
|
clearFilters: { en: 'Clear filters', ar: 'مسح المرشحات' },
|
|
196
230
|
selectAll: { en: 'Select every row on this page', ar: 'حدد كل صف في هذه الصفحة' },
|
|
197
231
|
selectRow: { en: 'Select this row', ar: 'حدد هذا الصف' },
|
|
@@ -230,6 +264,13 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
230
264
|
permissions: { en: 'Permissions', ar: 'الصلاحيات' },
|
|
231
265
|
record: { en: 'Record', ar: 'السجل' },
|
|
232
266
|
invalidFields: { en: 'Fields needing attention: {count}', ar: 'حقول تحتاج إلى مراجعة: {count}' },
|
|
267
|
+
errorSummary: { en: 'Check these fields:', ar: 'راجع هذه الحقول:' },
|
|
268
|
+
addNew: { en: 'Add new {kind}', ar: 'إضافة {kind}' },
|
|
269
|
+
backToList: { en: 'Back to list', ar: 'العودة إلى القائمة' },
|
|
270
|
+
reload: { en: 'Reload', ar: 'إعادة التحميل' },
|
|
271
|
+
hours: { en: 'Hours', ar: 'الساعات' },
|
|
272
|
+
minutes: { en: 'Minutes', ar: 'الدقائق' },
|
|
273
|
+
period: { en: 'AM or PM', ar: 'صباحا أو مساء' },
|
|
233
274
|
organizations: { en: 'Organizations', ar: 'المؤسسات' },
|
|
234
275
|
organization: { en: 'Organization', ar: 'مؤسسة' },
|
|
235
276
|
noOrganization: { en: 'No organization', ar: 'لا توجد مؤسسة' },
|
|
@@ -254,15 +295,116 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
254
295
|
welcome: { en: 'Welcome, {name}', ar: 'مرحبا، {name}' },
|
|
255
296
|
about: { en: 'What you may open here, and how many of each you may read.', ar: 'ما يمكنك فتحه هنا، وعدد ما يمكنك قراءته من كل منها.' },
|
|
256
297
|
open: { en: 'Open the list', ar: 'افتح القائمة' },
|
|
298
|
+
// add-on: courses
|
|
299
|
+
title: { en: 'Portal', ar: 'البوابة' },
|
|
300
|
+
navigation: { en: 'Portal', ar: 'البوابة' },
|
|
301
|
+
myEnrollments: { en: 'My enrollments', ar: 'تسجيلاتي' },
|
|
302
|
+
'greeting.morning': { en: 'Good morning, {name}', ar: 'صباح الخير يا {name}' },
|
|
303
|
+
'greeting.afternoon': { en: 'Good afternoon, {name}', ar: 'مساء الخير يا {name}' },
|
|
304
|
+
'greeting.evening': { en: 'Good evening, {name}', ar: 'مساء الخير يا {name}' },
|
|
305
|
+
yourNext: { en: 'Your next session', ar: 'جلستك القادمة' },
|
|
306
|
+
startsIn: { en: 'Starts {when}', ar: 'تبدأ {when}' },
|
|
307
|
+
viewCourse: { en: 'View course', ar: 'عرض الدورة' },
|
|
308
|
+
canJoin: { en: 'Courses you can join', ar: 'دورات يمكنك الانضمام إليها' },
|
|
309
|
+
seeAll: { en: 'See all courses', ar: 'كل الدورات' },
|
|
310
|
+
noneToJoin: { en: 'No course has a session coming up just now.', ar: 'لا توجد دورة لها جلسة قادمة الآن.' },
|
|
311
|
+
search: { en: 'Search courses', ar: 'ابحث في الدورات' },
|
|
312
|
+
byTag: { en: 'Filter by tag', ar: 'التصفية حسب الوسم' },
|
|
313
|
+
allTags: { en: 'All', ar: 'الكل' },
|
|
314
|
+
noMatch: { en: 'No course matches.', ar: 'لا توجد دورة مطابقة.' },
|
|
315
|
+
next: { en: 'Next session', ar: 'الجلسة القادمة' },
|
|
316
|
+
noSession: { en: 'No session scheduled yet', ar: 'لا توجد جلسة مجدولة بعد' },
|
|
317
|
+
free: { en: 'Free', ar: 'مجانا' },
|
|
318
|
+
perSeat: { en: 'per seat', ar: 'لكل مقعد' },
|
|
319
|
+
back: { en: 'Back to courses', ar: 'العودة إلى الدورات' },
|
|
320
|
+
aboutCourse: { en: 'About this course', ar: 'عن هذه الدورة' },
|
|
321
|
+
choose: { en: 'Choose a session', ar: 'اختر جلسة' },
|
|
322
|
+
full: { en: 'Full', ar: 'مكتملة' },
|
|
323
|
+
seatsLeft_zero: { en: '{count} seats left', ar: 'لم يبق أي مقعد' },
|
|
324
|
+
seatsLeft_one: { en: '{count} seat left', ar: 'بقي مقعد واحد' },
|
|
325
|
+
seatsLeft_two: { en: '{count} seats left', ar: 'بقي مقعدان' },
|
|
326
|
+
seatsLeft_few: { en: '{count} seats left', ar: 'بقيت {count} مقاعد' },
|
|
327
|
+
seatsLeft_many: { en: '{count} seats left', ar: 'بقي {count} مقعدا' },
|
|
328
|
+
seatsLeft_other: { en: '{count} seats left', ar: 'بقي {count} مقعد' },
|
|
329
|
+
total: { en: 'Total', ar: 'الإجمالي' },
|
|
330
|
+
pick: { en: 'Pick a session', ar: 'اختر جلسة' },
|
|
331
|
+
enrollIn: { en: 'Enroll on {when}', ar: 'سجّلني في {when}' },
|
|
332
|
+
enrolled: { en: 'You are enrolled.', ar: 'تم تسجيلك.' },
|
|
333
|
+
enrollFailed: { en: 'The seat was not taken. Please try again.', ar: 'لم يُحجز المقعد. حاول مرة أخرى.' },
|
|
334
|
+
holding: { en: 'You hold a seat on {when}.', ar: 'لك مقعد في {when}.' },
|
|
335
|
+
askSchool: { en: 'Ask your school to enroll you.', ar: 'اطلب من مدرستك تسجيلك.' },
|
|
336
|
+
upcoming: { en: 'Upcoming', ar: 'القادمة' },
|
|
337
|
+
past: { en: 'Past', ar: 'السابقة' },
|
|
338
|
+
noneUpcoming: { en: 'No session to come.', ar: 'لا توجد جلسة قادمة.' },
|
|
339
|
+
nonePast: { en: 'No past session.', ar: 'لا توجد جلسة سابقة.' },
|
|
340
|
+
course: { en: 'Course', ar: 'الدورة' },
|
|
341
|
+
place: { en: 'Venue and format', ar: 'المكان والصيغة' },
|
|
342
|
+
leave: { en: 'Cancel enrollment', ar: 'إلغاء التسجيل' },
|
|
343
|
+
leaveTitle: { en: 'Cancel this enrollment?', ar: 'إلغاء هذا التسجيل؟' },
|
|
344
|
+
leaveBody: { en: 'Your seat goes back to the session, and someone else may take it.', ar: 'يعود مقعدك إلى الجلسة، وقد يأخذه غيرك.' },
|
|
345
|
+
keep: { en: 'Keep it', ar: 'أبقِه' },
|
|
346
|
+
left: { en: 'Your enrollment is cancelled.', ar: 'أُلغي تسجيلك.' },
|
|
347
|
+
leaveFailed: { en: 'The enrollment was not cancelled. Please try again.', ar: 'لم يُلغَ التسجيل. حاول مرة أخرى.' },
|
|
348
|
+
failed: { en: 'This could not be read just now.', ar: 'تعذرت قراءة هذا الآن.' },
|
|
349
|
+
retry: { en: 'Try again', ar: 'حاول مرة أخرى' },
|
|
350
|
+
// end add-on: courses
|
|
351
|
+
// add-on: courses, settings
|
|
352
|
+
closed: { en: 'Closed for maintenance', ar: 'مغلقة للصيانة' },
|
|
353
|
+
closedBody: { en: 'The school is working on the portal. Please come back soon.', ar: 'تعمل المدرسة على البوابة. عد قريبا من فضلك.' },
|
|
354
|
+
contact: { en: 'Questions? Write to', ar: 'لديك سؤال؟ راسل' },
|
|
355
|
+
// end add-on: courses, settings
|
|
257
356
|
},
|
|
258
357
|
auth: {
|
|
259
358
|
signIn: { en: 'Sign in', ar: 'تسجيل الدخول' },
|
|
260
|
-
signInDescription: { en: 'Sign in
|
|
261
|
-
|
|
359
|
+
signInDescription: { en: 'Welcome back. Sign in with your email and password.', ar: 'مرحبا بعودتك. سجّل الدخول ببريدك الإلكتروني وكلمة المرور.' },
|
|
360
|
+
signInBackofficeDescription: { en: 'Sign in to reach the backoffice.', ar: 'سجل الدخول للوصول إلى لوحة الإدارة الخلفية.' },
|
|
262
361
|
signInPending: { en: 'Signing in…', ar: 'جارٍ تسجيل الدخول…' },
|
|
362
|
+
createFirstUser: { en: 'Create the first administrator', ar: 'إنشاء أول مسؤول' },
|
|
363
|
+
createFirstUserDescription: {
|
|
364
|
+
en: 'No one administers this backoffice yet. The account made here becomes its first administrator.',
|
|
365
|
+
ar: 'لا أحد يدير لوحة الإدارة الخلفية هذه بعد. الحساب الذي يُنشأ هنا يصبح أول مسؤول عنها.',
|
|
366
|
+
},
|
|
367
|
+
createFirstUserSubmit: { en: 'Create the administrator', ar: 'إنشاء المسؤول' },
|
|
368
|
+
createFirstUserPending: { en: 'Creating…', ar: 'جارٍ الإنشاء…' },
|
|
369
|
+
createFirstUserFailed: { en: 'That administrator could not be created.', ar: 'تعذر إنشاء هذا المسؤول.' },
|
|
370
|
+
setupCode: { en: 'Setup code', ar: 'رمز الإعداد' },
|
|
371
|
+
setupCodeDescription: { en: 'The SETUP_CODE this server was started with.', ar: 'قيمة SETUP_CODE التي شُغّل بها هذا الخادم.' },
|
|
372
|
+
setupCodeWrong: { en: 'That is not the setup code.', ar: 'هذا ليس رمز الإعداد.' },
|
|
373
|
+
setupCodeUnset: {
|
|
374
|
+
en: 'The first administrator is made only with a setup code, and this server has none it can use: SETUP_CODE is unset or shorter than 32 characters. Set SETUP_CODE where the backoffice app runs to a random value of 32 characters or more, restart it, and open this page again.',
|
|
375
|
+
ar: 'لا يُنشأ أول مسؤول إلا برمز إعداد، وليس لدى هذا الخادم رمز يمكنه استعماله: SETUP_CODE غير مضبوط أو أقصر من 32 حرفا. اضبط SETUP_CODE حيث يعمل تطبيق لوحة الإدارة الخلفية على قيمة عشوائية من 32 حرفا أو أكثر، ثم أعد تشغيله وافتح هذه الصفحة مرة أخرى.',
|
|
376
|
+
},
|
|
377
|
+
firstRegisterClosed: {
|
|
378
|
+
en: 'This backoffice has its administrator, so this page is closed. Sign in instead.',
|
|
379
|
+
ar: 'للوحة الإدارة الخلفية هذه مسؤولها، لذا أُغلقت هذه الصفحة. سجل الدخول بدلا من ذلك.',
|
|
380
|
+
},
|
|
381
|
+
firstRun: { en: 'Set up this app', ar: 'إعداد هذا التطبيق' },
|
|
382
|
+
firstRunDescription: {
|
|
383
|
+
en: 'Nobody owns this app yet. The account made here becomes its owner and first administrator.',
|
|
384
|
+
ar: 'لا أحد يملك هذا التطبيق بعد. الحساب الذي يُنشأ هنا يصبح مالكه وأول مسؤول عنه.',
|
|
385
|
+
},
|
|
386
|
+
firstRunSubmit: { en: 'Set up the app', ar: 'إعداد التطبيق' },
|
|
387
|
+
firstRunCodeUnset: {
|
|
388
|
+
en: 'This app is set up only with a setup code, and this server has none it can use: SETUP_CODE is unset or shorter than 32 characters. Set SETUP_CODE where the app runs to a random value of 32 characters or more, restart it, and open this page again.',
|
|
389
|
+
ar: 'لا يُعدّ هذا التطبيق إلا برمز إعداد، وليس لدى هذا الخادم رمز يمكنه استعماله: SETUP_CODE غير مضبوط أو أقصر من 32 حرفا. اضبط SETUP_CODE حيث يعمل التطبيق على قيمة عشوائية من 32 حرفا أو أكثر، ثم أعد تشغيله وافتح هذه الصفحة مرة أخرى.',
|
|
390
|
+
},
|
|
391
|
+
firstRunPending: { en: 'Setting up…', ar: 'جارٍ الإعداد…' },
|
|
392
|
+
firstRunFailed: { en: 'That owner could not be made.', ar: 'تعذر إنشاء هذا المالك.' },
|
|
393
|
+
firstRunClosed: { en: 'This app has its owner, so this page is closed. Sign in instead.', ar: 'لهذا التطبيق مالكه، لذا أُغلقت هذه الصفحة. سجل الدخول بدلا من ذلك.' },
|
|
394
|
+
setupPending: { en: 'This app is not set up yet. Its administrator sets it up first.', ar: 'لم يُعدّ هذا التطبيق بعد. يُعدّه مسؤوله أولا.' },
|
|
395
|
+
inviteOnly: {
|
|
396
|
+
en: 'Accounts here are made by invitation. Open the link of the invitation sent to you, or sign in.',
|
|
397
|
+
ar: 'تُنشأ الحسابات هنا بدعوة. افتح رابط الدعوة المرسلة إليك، أو سجل الدخول.',
|
|
398
|
+
},
|
|
399
|
+
outsideDomains: { en: 'This email address is not at a domain that may sign up here.', ar: 'هذا البريد الإلكتروني ليس من نطاق يُسمح له بإنشاء حساب هنا.' },
|
|
400
|
+
verifySent: { en: 'Check your email', ar: 'تحقق من بريدك الإلكتروني' },
|
|
401
|
+
verifySentDescription: {
|
|
402
|
+
en: 'We sent a link to {email}. Open it to confirm your address and choose your password; it signs you in. It lasts an hour.',
|
|
403
|
+
ar: 'أرسلنا رابطا إلى {email}. افتحه لتأكيد عنوانك واختيار كلمة المرور، فتدخل به مباشرة. وهو صالح ساعة.',
|
|
404
|
+
},
|
|
263
405
|
failed: { en: 'That sign-in did not work.', ar: 'لم ينجح تسجيل الدخول.' },
|
|
264
406
|
signUp: { en: 'Sign up', ar: 'إنشاء حساب' },
|
|
265
|
-
signUpDescription: { en: 'Make an account
|
|
407
|
+
signUpDescription: { en: 'Make an account.', ar: 'أنشئ حسابا.' },
|
|
266
408
|
signUpPending: { en: 'Signing up…', ar: 'جارٍ إنشاء الحساب…' },
|
|
267
409
|
signUpFailed: { en: 'That sign-up did not work.', ar: 'لم ينجح إنشاء الحساب.' },
|
|
268
410
|
organizationFailed: { en: 'That organization could not be created.', ar: 'تعذر إنشاء هذه المؤسسة.' },
|
|
@@ -296,6 +438,10 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
296
438
|
},
|
|
297
439
|
backToSignIn: { en: 'Back to login', ar: 'العودة إلى تسجيل الدخول' },
|
|
298
440
|
resetPassword: { en: 'Reset password', ar: 'إعادة تعيين كلمة المرور' },
|
|
441
|
+
setPassword: { en: 'Choose your password', ar: 'اختر كلمة المرور' },
|
|
442
|
+
organizationNameIn: { en: 'Its name in {language}, if it has one', ar: 'اسمها بـ{language}، إن كان لها اسم بها' },
|
|
443
|
+
setPasswordSubmit: { en: 'Confirm and set password', ar: 'أكّد واحفظ كلمة المرور' },
|
|
444
|
+
passwordChosen: { en: 'Your address is confirmed and your password is set. Sign in with it.', ar: 'تأكّد عنوانك وحُفظت كلمة المرور. سجّل الدخول بها.' },
|
|
299
445
|
newPassword: { en: 'New password', ar: 'كلمة مرور جديدة' },
|
|
300
446
|
passwordReset: { en: 'Password reset successfully.', ar: 'تمت إعادة تعيين كلمة المرور بنجاح.' },
|
|
301
447
|
tokenInvalid: { en: 'Token is either invalid or has expired.', ar: 'الرمز غير صالح أو انتهت صلاحيته.' },
|
|
@@ -308,7 +454,10 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
308
454
|
},
|
|
309
455
|
tooManyRequests: { en: 'Too many attempts. Wait a moment and try again.', ar: 'محاولات كثيرة جدا. انتظر قليلا ثم حاول مرة أخرى.' },
|
|
310
456
|
invalidCredentials: { en: 'The email or password provided is incorrect.', ar: 'البريد الإلكتروني أو كلمة المرور غير صحيحة.' },
|
|
311
|
-
emailNotVerified: {
|
|
457
|
+
emailNotVerified: {
|
|
458
|
+
en: 'This email address is not confirmed yet. Open the link we sent to it, or ask for a password reset to get a new one.',
|
|
459
|
+
ar: 'لم يُؤكَّد هذا البريد الإلكتروني بعد. افتح الرابط الذي أرسلناه إليه، أو اطلب إعادة تعيين كلمة المرور لتحصل على رابط جديد.',
|
|
460
|
+
},
|
|
312
461
|
banned: { en: 'This account is banned, so it cannot sign in.', ar: 'هذا الحساب محظور، لذا لا يمكنه تسجيل الدخول.' },
|
|
313
462
|
userExists: { en: 'An account with this email already exists. Use another email.', ar: 'يوجد حساب بهذا البريد الإلكتروني. استخدم بريدا آخر.' },
|
|
314
463
|
requestFailed: { en: 'That request did not work.', ar: 'لم ينجح هذا الطلب.' },
|
|
@@ -342,8 +491,8 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
342
491
|
ar: 'أنشئ حسابا بالبريد الإلكتروني الذي أُرسلت إليه الدعوة.',
|
|
343
492
|
},
|
|
344
493
|
haveAccount: { en: 'Already have an account?', ar: 'لديك حساب بالفعل؟' },
|
|
345
|
-
unauthorized: { en: '
|
|
346
|
-
unauthorizedDescription: { en: '
|
|
494
|
+
unauthorized: { en: 'Choose where to go', ar: 'اختر وجهتك' },
|
|
495
|
+
unauthorizedDescription: { en: 'This page isn\'t part of your account. Where would you like to go?', ar: 'هذه الصفحة ليست ضمن حسابك. إلى أين تريد الذهاب؟' },
|
|
347
496
|
unauthorizedPage: { en: 'Your role does not open that page: {page}.', ar: 'دورك لا يفتح تلك الصفحة: {page}.' },
|
|
348
497
|
noAccess: { en: 'Your account has no access yet', ar: 'لا يملك حسابك أي وصول بعد' },
|
|
349
498
|
noAccessDescription: {
|
|
@@ -352,34 +501,27 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
352
501
|
},
|
|
353
502
|
switchTo: { en: 'Switch to {organization}', ar: 'التبديل إلى {organization}' },
|
|
354
503
|
accountStatus: { en: 'See your account status', ar: 'اطّلع على حالة حسابك' },
|
|
355
|
-
noOrganization: {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
},
|
|
504
|
+
noOrganization: { en: '{email} belongs to no organization yet.', ar: '{email} لا ينتمي إلى أي مؤسسة بعد.' },
|
|
505
|
+
yourInvitations: { en: 'Your invitations', ar: 'دعواتك' },
|
|
506
|
+
invitationDecline: { en: 'Decline', ar: 'رفض' },
|
|
507
|
+
createOrganization: { en: 'Create an organization', ar: 'أنشئ مؤسسة' },
|
|
508
|
+
createOrganizationSubmit: { en: 'Create', ar: 'إنشاء' },
|
|
509
|
+
workspaceOf: { en: '{name}\'s workspace', ar: 'مساحة عمل {name}' },
|
|
510
|
+
askToBeInvited: { en: 'Ask an administrator to invite {email}.', ar: 'اطلب من أحد المسؤولين أن يدعو {email}.' },
|
|
359
511
|
},
|
|
360
512
|
marketing: {
|
|
361
513
|
brand: { en: 'Asas', ar: 'أساس' },
|
|
362
514
|
getStarted: { en: 'Get started', ar: 'ابدأ الآن' },
|
|
363
515
|
openScreen: { en: 'Open {screen}', ar: 'افتح {screen}' },
|
|
364
|
-
heroTitle: { en: 'Run
|
|
516
|
+
heroTitle: { en: 'Run your organization without the busywork', ar: 'أدر مؤسستك دون العمل الروتيني' },
|
|
365
517
|
heroSubtitle: {
|
|
366
|
-
en: 'Asas is a dashboard and a portal for organizations
|
|
367
|
-
ar: 'أساس لوحة تحكم وبوابة
|
|
518
|
+
en: 'Asas is a dashboard and a portal for organizations: keep your records in one place, and keep every role to what it should see.',
|
|
519
|
+
ar: 'أساس لوحة تحكم وبوابة للمؤسسات: احفظ سجلاتك في مكان واحد، واحصر كل دور بما ينبغي أن يراه.',
|
|
368
520
|
},
|
|
369
|
-
featuresTitle: { en: 'Everything
|
|
521
|
+
featuresTitle: { en: 'Everything an organization needs', ar: 'كل ما تحتاجه مؤسسة' },
|
|
370
522
|
featuresSubtitle: {
|
|
371
|
-
en: 'One system for
|
|
372
|
-
ar: 'نظام واحد
|
|
373
|
-
},
|
|
374
|
-
featureCoursesTitle: { en: 'Courses and sessions', ar: 'الدورات والجلسات' },
|
|
375
|
-
featureCoursesDescription: {
|
|
376
|
-
en: 'Create courses, set their fee and schedule, and open or archive them as they run.',
|
|
377
|
-
ar: 'أنشئ الدورات، حدد رسومها وجدولها، وافتحها أو أرشفها أثناء انعقادها.',
|
|
378
|
-
},
|
|
379
|
-
featureEnrollmentsTitle: { en: 'Enrollments', ar: 'التسجيلات' },
|
|
380
|
-
featureEnrollmentsDescription: {
|
|
381
|
-
en: 'See who enrolled in each course and when, with the day-by-day count on the dashboard.',
|
|
382
|
-
ar: 'اطلع على من سجل في كل دورة ومتى، مع العدد اليومي في لوحة التحكم.',
|
|
523
|
+
en: 'One system for your records, from the first entry to who may see it.',
|
|
524
|
+
ar: 'نظام واحد لسجلاتك، من أول إدخال إلى من يحق له رؤيته.',
|
|
383
525
|
},
|
|
384
526
|
featureRolesTitle: { en: 'Roles and permissions', ar: 'الأدوار والصلاحيات' },
|
|
385
527
|
featureRolesDescription: {
|
|
@@ -399,23 +541,23 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
399
541
|
howTitle: { en: 'How it works', ar: 'كيف يعمل' },
|
|
400
542
|
howStep1Title: { en: 'Set up your organization', ar: 'أنشئ مؤسستك' },
|
|
401
543
|
howStep1Description: { en: 'Sign up and create your organization in one step.', ar: 'أنشئ حسابك ومؤسستك في خطوة واحدة.' },
|
|
402
|
-
howStep2Title: { en: 'Add
|
|
544
|
+
howStep2Title: { en: 'Add your records and roles', ar: 'أضف سجلاتك وأدوارك' },
|
|
403
545
|
howStep2Description: {
|
|
404
|
-
en: 'List your
|
|
405
|
-
ar: 'أدرج
|
|
546
|
+
en: 'List what your organization keeps and decide what each role may do.',
|
|
547
|
+
ar: 'أدرج ما تحفظه مؤسستك وحدد ما يحق لكل دور القيام به.',
|
|
406
548
|
},
|
|
407
549
|
howStep3Title: { en: 'Open the portal to your customers', ar: 'افتح البوابة لعملائك' },
|
|
408
550
|
howStep3Description: {
|
|
409
|
-
en: 'Customers sign in to their own portal to see
|
|
410
|
-
ar: 'يسجل العملاء الدخول إلى بوابتهم الخاصة لرؤية
|
|
551
|
+
en: 'Customers sign in to their own portal to see what is theirs.',
|
|
552
|
+
ar: 'يسجل العملاء الدخول إلى بوابتهم الخاصة لرؤية ما يخصهم.',
|
|
411
553
|
},
|
|
412
|
-
ctaTitle: { en: 'Start running your
|
|
413
|
-
ctaSubtitle: { en: 'Create your organization and add your first
|
|
414
|
-
footer: { en: 'Asas —
|
|
554
|
+
ctaTitle: { en: 'Start running your organization on Asas', ar: 'ابدأ بإدارة مؤسستك على أساس' },
|
|
555
|
+
ctaSubtitle: { en: 'Create your organization and add your first record in minutes.', ar: 'أنشئ مؤسستك وأضف أول سجل لك خلال دقائق.' },
|
|
556
|
+
footer: { en: 'Asas — one place for an organization\'s records.', ar: 'أساس — مكان واحد لسجلات المؤسسة.' },
|
|
415
557
|
},
|
|
416
558
|
dashboard: {
|
|
417
559
|
dashboard: { en: 'Dashboard', ar: 'لوحة التحكم' },
|
|
418
|
-
|
|
560
|
+
openBackoffice: { en: 'Open the backoffice', ar: 'فتح لوحة الإدارة الخلفية' },
|
|
419
561
|
members: { en: 'Members', ar: 'الأعضاء' },
|
|
420
562
|
membersAbout: { en: 'Who works in this organization, and the role each holds.', ar: 'من يعمل في هذه المؤسسة، والدور الذي يشغله كل منهم.' },
|
|
421
563
|
membersRoles: { en: 'Roles', ar: 'الأدوار' },
|
|
@@ -424,6 +566,20 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
424
566
|
membersJoined: { en: 'Joined', ar: 'تاريخ الانضمام' },
|
|
425
567
|
membersNone: { en: 'No one works in this organization yet.', ar: 'لا يعمل أحد في هذه المؤسسة بعد.' },
|
|
426
568
|
invite: { en: 'Invite', ar: 'دعوة' },
|
|
569
|
+
addPerson: { en: 'Add person', ar: 'إضافة شخص' },
|
|
570
|
+
addPersonTitle: { en: 'Add a person', ar: 'إضافة شخص' },
|
|
571
|
+
addPersonAbout: {
|
|
572
|
+
en: 'They get an account here and a link by email to choose their password. Someone who already has an account is sent an invitation instead.',
|
|
573
|
+
ar: 'يحصل على حساب هنا ورابط بالبريد لاختيار كلمة مروره. ومن لديه حساب بالفعل تُرسل إليه دعوة بدلا من ذلك.',
|
|
574
|
+
},
|
|
575
|
+
addPersonRole: { en: 'Role', ar: 'الدور' },
|
|
576
|
+
addPersonNoRole: { en: 'No role yet', ar: 'بلا دور بعد' },
|
|
577
|
+
addPersonSubmit: { en: 'Add', ar: 'إضافة' },
|
|
578
|
+
addPersonLink: {
|
|
579
|
+
en: 'No mailer is configured. Hand this link to them alone: it chooses their password and lasts 48 hours.',
|
|
580
|
+
ar: 'لم يُضبط أي مرسل بريد. سلّم هذا الرابط له وحده: به يختار كلمة مروره، وهو صالح 48 ساعة.',
|
|
581
|
+
},
|
|
582
|
+
addPersonRefused: { en: 'The server refused to add that person.', ar: 'رفض الخادم إضافة هذا الشخص.' },
|
|
427
583
|
inviteTitle: { en: 'Invite someone', ar: 'دعوة شخص' },
|
|
428
584
|
inviteAbout: {
|
|
429
585
|
en: 'They join this organization as a member once they accept. Give them roles here after that.',
|
|
@@ -431,14 +587,25 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
431
587
|
},
|
|
432
588
|
inviteSend: { en: 'Send invitation', ar: 'إرسال الدعوة' },
|
|
433
589
|
inviteRefused: { en: 'The server refused that invitation.', ar: 'رفض الخادم هذه الدعوة.' },
|
|
590
|
+
inviteSent: { en: 'Invitation sent to {email}', ar: 'أُرسلت الدعوة إلى {email}' },
|
|
591
|
+
inviteCancelled: { en: 'Invitation cancelled', ar: 'أُلغيت الدعوة' },
|
|
592
|
+
rolesSaved: { en: 'Roles saved for {name}', ar: 'حُفظت أدوار {name}' },
|
|
593
|
+
memberRemoved: { en: '{name} removed', ar: 'أُزيل {name}' },
|
|
594
|
+
personAdded: { en: '{name} added. A link to choose a password was sent to {email}.', ar: 'أُضيف {name}. أُرسل إلى {email} رابط لاختيار كلمة المرور.' },
|
|
595
|
+
personAddedLink: { en: '{name} added. Hand them the link below.', ar: 'أُضيف {name}. سلّمه الرابط أدناه.' },
|
|
434
596
|
inviteAlreadyMember: { en: 'This person is already a member of this organization.', ar: 'هذا الشخص عضو في هذه المؤسسة بالفعل.' },
|
|
435
597
|
inviteAlreadyInvited: { en: 'This person already has an invitation that is not yet accepted.', ar: 'لدى هذا الشخص دعوة لم تُقبل بعد.' },
|
|
436
598
|
inviteNotAllowed: { en: 'You may not invite people to this organization.', ar: 'لا يحق لك دعوة أشخاص إلى هذه المؤسسة.' },
|
|
437
599
|
inviteNoMailer: {
|
|
438
|
-
en: 'No mailer is configured, so no email is sent. In development the link is written to the server log
|
|
439
|
-
ar: 'لم يُضبط أي مرسل بريد، لذا لا تُرسل أي رسالة. في بيئة التطوير يُكتب الرابط في سجل
|
|
600
|
+
en: 'No mailer is configured, so no email is sent. In development the link is written to the server log.',
|
|
601
|
+
ar: 'لم يُضبط أي مرسل بريد، لذا لا تُرسل أي رسالة. في بيئة التطوير يُكتب الرابط في سجل الخادم.',
|
|
440
602
|
},
|
|
441
603
|
inviteCopy: { en: 'Copy link', ar: 'نسخ الرابط' },
|
|
604
|
+
link: { en: 'Link', ar: 'الرابط' },
|
|
605
|
+
inviteLinkOwn: {
|
|
606
|
+
en: 'A copied link lets whoever holds it join as the invited address: hand it to that person alone.',
|
|
607
|
+
ar: 'الرابط المنسوخ يتيح لمن يحمله الانضمام بالعنوان المدعو: سلّمه لذلك الشخص وحده.',
|
|
608
|
+
},
|
|
442
609
|
inviteCopied: { en: 'Link copied', ar: 'تم نسخ الرابط' },
|
|
443
610
|
inviteCancel: { en: 'Cancel invitation', ar: 'إلغاء الدعوة' },
|
|
444
611
|
inviteCancelRefused: { en: 'The server refused to cancel that invitation.', ar: 'رفض الخادم إلغاء هذه الدعوة.' },
|
|
@@ -454,13 +621,31 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
454
621
|
removeLastOwner: { en: 'The organization\'s only owner cannot be removed.', ar: 'لا يمكن إزالة المالك الوحيد للمؤسسة.' },
|
|
455
622
|
removeNotAllowed: { en: 'You may not remove members of this organization.', ar: 'لا يحق لك إزالة أعضاء هذه المؤسسة.' },
|
|
456
623
|
rolesHolderUnnamed: { en: 'A member', ar: 'أحد الأعضاء' },
|
|
457
|
-
|
|
624
|
+
invitationsTab: { en: 'Invitations ({count})', ar: 'الدعوات ({count})' },
|
|
625
|
+
invitesNone: { en: 'No invitation is waiting to be accepted.', ar: 'لا توجد دعوة تنتظر القبول.' },
|
|
626
|
+
inviteByLink: { en: 'Invite by link', ar: 'الدعوة برابط' },
|
|
627
|
+
inviteSentBy: { en: 'Sent by', ar: 'أرسلها' },
|
|
628
|
+
inviteExpired: { en: 'Expired', ar: 'منتهية' },
|
|
629
|
+
inviteResend: { en: 'Resend', ar: 'إعادة الإرسال' },
|
|
630
|
+
inviteResent: { en: 'Invitation sent again to {email}', ar: 'أُعيد إرسال الدعوة إلى {email}' },
|
|
631
|
+
membersRoleFilter: { en: 'Role', ar: 'الدور' },
|
|
632
|
+
membersEveryRole: { en: 'Every role', ar: 'كل الأدوار' },
|
|
633
|
+
membersNotGrantable: {
|
|
634
|
+
en: 'It grants keys you do not hold, so only someone who holds them gives or takes it.',
|
|
635
|
+
ar: 'يمنح صلاحيات لا تملكها، لذا لا يمنحه أو يسحبه إلا من يملكها.',
|
|
636
|
+
},
|
|
637
|
+
passwordLink: { en: 'Send a new password link', ar: 'إرسال رابط جديد لكلمة المرور' },
|
|
638
|
+
passwordLinkSent: { en: 'A link to choose a password was sent to {email}', ar: 'أُرسل إلى {email} رابط لاختيار كلمة المرور' },
|
|
639
|
+
passwordLinkRefused: { en: 'The server refused to send that link.', ar: 'رفض الخادم إرسال هذا الرابط.' },
|
|
640
|
+
passwordLinkHanded: {
|
|
641
|
+
en: 'No mailer is configured. Hand this link to {name} alone: it chooses their password and lasts 48 hours.',
|
|
642
|
+
ar: 'لم يُضبط أي مرسل بريد. سلّم هذا الرابط إلى {name} وحده: به يختار كلمة مروره، وهو صالح 48 ساعة.',
|
|
643
|
+
},
|
|
644
|
+
removeTitle: { en: 'Remove {name}?', ar: 'إزالة {name}؟' },
|
|
458
645
|
inviteExpires: { en: 'Expires', ar: 'تنتهي في' },
|
|
459
|
-
membersActions: { en: 'Actions', ar: 'الإجراءات' },
|
|
460
646
|
membersEdit: { en: 'Edit roles', ar: 'تعديل الأدوار' },
|
|
461
647
|
membersFixed: { en: 'Fixed roles', ar: 'الأدوار الثابتة' },
|
|
462
648
|
membersCustom: { en: 'Custom roles', ar: 'الأدوار المخصصة' },
|
|
463
|
-
membersPermissions: { en: '{count} permissions', ar: 'الصلاحيات: {count}' },
|
|
464
649
|
membersNoRoles: { en: 'There is no role you may read to assign.', ar: 'لا يوجد دور يمكنك قراءته لإسناده.' },
|
|
465
650
|
membersRefused: { en: 'The server refused that change.', ar: 'رفض الخادم هذا التغيير.' },
|
|
466
651
|
everyPermission: { en: 'Every permission', ar: 'كل الصلاحيات' },
|
|
@@ -472,6 +657,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
472
657
|
rolesKind: { en: 'Kind', ar: 'النوع' },
|
|
473
658
|
rolesFixed: { en: 'Fixed', ar: 'ثابت' },
|
|
474
659
|
rolesCustom: { en: 'Custom', ar: 'مخصص' },
|
|
660
|
+
rolesOpen: { en: 'Open {role}', ar: 'فتح {role}' },
|
|
475
661
|
rolesFixedAbout: {
|
|
476
662
|
en: 'This role ships with the project. What it holds is code, so it cannot be edited or deleted here.',
|
|
477
663
|
ar: 'يأتي هذا الدور مع المشروع. ما يمنحه مكتوب في الشيفرة، لذا لا يمكن تعديله أو حذفه هنا.',
|
|
@@ -484,6 +670,8 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
484
670
|
},
|
|
485
671
|
permissionsScreens: { en: 'Screens', ar: 'الشاشات' },
|
|
486
672
|
permissionsFields: { en: 'Fields', ar: 'الحقول' },
|
|
673
|
+
permissionsCount: { en: '{count} permissions', ar: 'الصلاحيات: {count}' },
|
|
674
|
+
permissionsCountOne: { en: '1 permission', ar: 'صلاحية واحدة' },
|
|
487
675
|
permissionsOther: { en: 'Other', ar: 'أخرى' },
|
|
488
676
|
permissionsRequired: { en: 'Permissions, required', ar: 'الصلاحيات، مطلوبة' },
|
|
489
677
|
membersOwnRole: {
|
|
@@ -535,20 +723,20 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
535
723
|
screens: {
|
|
536
724
|
dashboard: { en: 'Dashboard', ar: 'لوحة التحكم' },
|
|
537
725
|
portal: { en: 'Portal', ar: 'البوابة' },
|
|
538
|
-
|
|
539
|
-
},
|
|
540
|
-
|
|
541
|
-
title: { en: '
|
|
542
|
-
brand: { en: 'Asas
|
|
543
|
-
about: { en: 'Every organization and every person
|
|
544
|
-
role: { en: '
|
|
545
|
-
noRole: { en: 'No
|
|
726
|
+
backoffice: { en: 'Backoffice', ar: 'لوحة الإدارة الخلفية' },
|
|
727
|
+
},
|
|
728
|
+
backoffice: {
|
|
729
|
+
title: { en: 'Backoffice', ar: 'لوحة الإدارة الخلفية' },
|
|
730
|
+
brand: { en: 'Asas backoffice', ar: 'لوحة الإدارة الخلفية لأساس' },
|
|
731
|
+
about: { en: 'Every organization and every person, for the backoffice staff.', ar: 'كل مؤسسة وكل شخص، لفريق لوحة الإدارة الخلفية.' },
|
|
732
|
+
role: { en: 'Backoffice role', ar: 'دور في لوحة الإدارة الخلفية' },
|
|
733
|
+
noRole: { en: 'No backoffice role', ar: 'بلا دور في لوحة الإدارة الخلفية' },
|
|
546
734
|
setRole: { en: 'Set role', ar: 'تعيين الدور' },
|
|
547
735
|
ban: { en: 'Ban', ar: 'حظر' },
|
|
548
736
|
unban: { en: 'Unban', ar: 'رفع الحظر' },
|
|
549
737
|
impersonate: { en: 'Impersonate', ar: 'انتحال الصفة' },
|
|
550
|
-
confirmRole: { en: 'Give {name} the
|
|
551
|
-
pickRole: { en: 'Pick another
|
|
738
|
+
confirmRole: { en: 'Give {name} the backoffice role "{role}"?', ar: 'منح {name} الدور "{role}" في لوحة الإدارة الخلفية؟' },
|
|
739
|
+
pickRole: { en: 'Pick another backoffice role for {name}.', ar: 'اختر دورًا آخر في لوحة الإدارة الخلفية لـ {name}.' },
|
|
552
740
|
confirmBan: {
|
|
553
741
|
en: 'Ban {name}? They are signed out of both apps and cannot sign in until the ban ends.',
|
|
554
742
|
ar: 'حظر {name}؟ سيُسجَّل خروجه من التطبيقين ولن يتمكن من تسجيل الدخول حتى ينتهي الحظر.',
|
|
@@ -558,7 +746,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
558
746
|
en: 'Impersonate {name}? You act as them in the tenant app until you stop.',
|
|
559
747
|
ar: 'انتحال صفة {name}؟ ستتصرف باسمه في تطبيق المؤسسة حتى تتوقف.',
|
|
560
748
|
},
|
|
561
|
-
roleSet: { en: '{name} now holds the
|
|
749
|
+
roleSet: { en: '{name} now holds the backoffice role "{role}".', ar: 'أصبح دور {name} في لوحة الإدارة الخلفية "{role}".' },
|
|
562
750
|
banned: { en: '{name} is banned.', ar: 'تم حظر {name}.' },
|
|
563
751
|
unbanned: { en: 'The ban on {name} is lifted.', ar: 'تم رفع الحظر عن {name}.' },
|
|
564
752
|
renamed: { en: 'The organization is now named {name}.', ar: 'أصبح اسم المؤسسة {name}.' },
|
|
@@ -571,6 +759,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
571
759
|
banWeek: { en: 'Seven days', ar: 'سبعة أيام' },
|
|
572
760
|
banMonth: { en: 'Thirty days', ar: 'ثلاثون يومًا' },
|
|
573
761
|
rename: { en: 'Rename', ar: 'إعادة التسمية' },
|
|
762
|
+
nameIn: { en: 'Name in {language}, if it has one', ar: 'الاسم بـ{language}، إن كان لها اسم بها' },
|
|
574
763
|
slugPattern: {
|
|
575
764
|
en: 'A slug is lowercase letters and digits joined by single dashes, such as admin-org.',
|
|
576
765
|
ar: 'المعرف النصي أحرف إنجليزية صغيرة وأرقام تفصل بينها شرطات مفردة، مثل admin-org.',
|
|
@@ -580,7 +769,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
580
769
|
ar: 'يحل الاسم والمعرّف الجديدان محل القديمين لكل من في هذه المؤسسة.',
|
|
581
770
|
},
|
|
582
771
|
members: { en: 'Members', ar: 'الأعضاء' },
|
|
583
|
-
refused: { en: 'The
|
|
772
|
+
refused: { en: 'The backoffice refused that action.', ar: 'رفضت لوحة الإدارة الخلفية هذا الإجراء.' },
|
|
584
773
|
'membership.owner': { en: 'Owner', ar: 'المالك' },
|
|
585
774
|
'membership.admin': { en: 'Admin', ar: 'مشرف' },
|
|
586
775
|
'membership.member': { en: 'Member', ar: 'عضو' },
|
|
@@ -594,7 +783,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
594
783
|
email: { en: 'Email', ar: 'البريد الإلكتروني' },
|
|
595
784
|
emailVerified: { en: 'Email verified', ar: 'البريد موثق' },
|
|
596
785
|
image: { en: 'Image', ar: 'الصورة' },
|
|
597
|
-
role: { en: '
|
|
786
|
+
role: { en: 'Backoffice role', ar: 'دور في لوحة الإدارة الخلفية' },
|
|
598
787
|
banned: { en: 'Banned', ar: 'محظور' },
|
|
599
788
|
banReason: { en: 'Ban reason', ar: 'سبب الحظر' },
|
|
600
789
|
banExpires: { en: 'Ban ends', ar: 'ينتهي الحظر' },
|
|
@@ -602,7 +791,7 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
602
791
|
updatedAt: { en: 'Updated at', ar: 'تاريخ التعديل' },
|
|
603
792
|
},
|
|
604
793
|
organization: {
|
|
605
|
-
...organization,
|
|
794
|
+
...copyFile(organization),
|
|
606
795
|
singular: { en: 'Organization', ar: 'مؤسسة' },
|
|
607
796
|
plural: { en: 'Organizations', ar: 'المؤسسات' },
|
|
608
797
|
none: { en: 'No organizations yet.', ar: 'لا توجد مؤسسات بعد.' },
|
|
@@ -624,14 +813,18 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
624
813
|
role: { en: 'Membership role', ar: 'دور العضوية' },
|
|
625
814
|
createdAt: { en: 'Created at', ar: 'تاريخ الإنشاء' },
|
|
626
815
|
updatedAt: { en: 'Updated at', ar: 'تاريخ التعديل' },
|
|
816
|
+
lastSeenAt: { en: 'Last seen', ar: 'آخر ظهور' },
|
|
627
817
|
},
|
|
818
|
+
// add-on: settings
|
|
628
819
|
settings: {
|
|
629
|
-
...settings,
|
|
820
|
+
...copyFile(settings),
|
|
630
821
|
singular: { en: 'Settings', ar: 'الإعدادات' },
|
|
631
822
|
plural: { en: 'Settings', ar: 'الإعدادات' },
|
|
632
823
|
},
|
|
824
|
+
// end add-on: settings
|
|
825
|
+
// add-on: roles
|
|
633
826
|
roles: {
|
|
634
|
-
...roles,
|
|
827
|
+
...copyFile(roles),
|
|
635
828
|
singular: { en: 'Role', ar: 'دور' },
|
|
636
829
|
plural: { en: 'Roles', ar: 'الأدوار' },
|
|
637
830
|
'delete.confirm': { en: 'Delete this role', ar: 'احذف هذا الدور' },
|
|
@@ -646,17 +839,27 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
646
839
|
ar: 'المعرف النصي للدور، الذي يسميه كل إسناد له، مثل course-editor. يقرأ الناس الدور بتسميته أدناه.',
|
|
647
840
|
},
|
|
648
841
|
},
|
|
842
|
+
// end add-on: roles
|
|
843
|
+
// add-on: courses
|
|
649
844
|
sessions: {
|
|
650
|
-
...sessions,
|
|
845
|
+
...copyFile(sessions),
|
|
651
846
|
singular: { en: 'Session', ar: 'جلسة' },
|
|
652
847
|
plural: { en: 'Sessions', ar: 'الجلسات' },
|
|
653
848
|
'operations.archiveMany': { en: 'Archive many', ar: 'أرشفة عدة جلسات' },
|
|
849
|
+
'operations.archive': { en: 'Archive', ar: 'أرشفة' },
|
|
850
|
+
'operations.archive.reason.required': { en: 'An archive reason is required.', ar: 'سبب الأرشفة مطلوب.' },
|
|
851
|
+
'operations.archive.reason.maxLength': { en: 'An archive reason is at most 200 characters.', ar: 'سبب الأرشفة 200 حرف على الأكثر.' },
|
|
852
|
+
'operations.unarchive': { en: 'Unarchive', ar: 'إلغاء الأرشفة' },
|
|
853
|
+
'operations.unarchive.reason.required': { en: 'A reason to bring it back is required.', ar: 'سبب إلغاء الأرشفة مطلوب.' },
|
|
854
|
+
'operations.unarchive.reason.maxLength': { en: 'A reason to bring it back is at most 200 characters.', ar: 'سبب إلغاء الأرشفة 200 حرف على الأكثر.' },
|
|
654
855
|
new: { en: 'New session', ar: 'جلسة جديدة' },
|
|
655
856
|
none: { en: 'No sessions yet.', ar: 'لا توجد جلسات بعد.' },
|
|
656
857
|
dangerZoneWarning: { en: 'These actions change this session for everyone.', ar: 'هذه الإجراءات تغير هذه الجلسة للجميع.' },
|
|
657
858
|
},
|
|
859
|
+
// end add-on: courses
|
|
860
|
+
// add-on: courses
|
|
658
861
|
enrollments: {
|
|
659
|
-
...enrollments,
|
|
862
|
+
...copyFile(enrollments),
|
|
660
863
|
singular: { en: 'Enrollment', ar: 'تسجيل' },
|
|
661
864
|
plural: { en: 'Enrollments', ar: 'التسجيلات' },
|
|
662
865
|
'operations.others': { en: 'Everyone\'s enrollments', ar: 'تسجيلات الجميع' },
|
|
@@ -664,14 +867,16 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
664
867
|
none: { en: 'No enrollments yet.', ar: 'لا توجد تسجيلات بعد.' },
|
|
665
868
|
dangerZoneWarning: { en: 'These actions change this enrollment for everyone.', ar: 'هذه الإجراءات تغير هذا التسجيل للجميع.' },
|
|
666
869
|
},
|
|
870
|
+
// end add-on: courses
|
|
667
871
|
tags: {
|
|
668
|
-
...tags,
|
|
872
|
+
...copyFile(tags),
|
|
669
873
|
new: { en: 'New tag', ar: 'وسم جديد' },
|
|
670
874
|
none: { en: 'No tags yet.', ar: 'لا توجد وسوم بعد.' },
|
|
671
875
|
dangerZoneWarning: { en: 'These actions change this tag for everyone.', ar: 'هذه الإجراءات تغير هذا الوسم للجميع.' },
|
|
672
876
|
},
|
|
877
|
+
// add-on: media
|
|
673
878
|
media: {
|
|
674
|
-
...media,
|
|
879
|
+
...copyFile(media),
|
|
675
880
|
new: { en: 'New image', ar: 'صورة جديدة' },
|
|
676
881
|
none: { en: 'No images yet.', ar: 'لا توجد صور بعد.' },
|
|
677
882
|
newAbout: { en: 'Choose an image and describe it. It is uploaded before it is saved.', ar: 'اختر صورة وصِفها. تُرفع قبل أن تُحفظ.' },
|
|
@@ -680,21 +885,30 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
680
885
|
replaceAbout: { en: 'Replace file uploads a new image and opens it. This one stays until you delete it.', ar: 'يرفع استبدال الملف صورة جديدة ويفتحها. تبقى هذه الصورة حتى تحذفها.' },
|
|
681
886
|
dangerZoneWarning: { en: 'These actions change this image for everyone.', ar: 'هذه الإجراءات تغير هذه الصورة للجميع.' },
|
|
682
887
|
},
|
|
683
|
-
|
|
684
|
-
|
|
888
|
+
// end add-on: media
|
|
889
|
+
localUsers: { ...copyFile(localUsers), none: { en: 'No local accounts yet.', ar: 'لا توجد حسابات محلية بعد.' } },
|
|
890
|
+
// add-on: audit-log
|
|
891
|
+
auditLog: copyFile(auditLog),
|
|
892
|
+
backofficeLog: { ...copyFile(backofficeLog), none: { en: 'No staff action yet.', ar: 'لا يوجد إجراء للطاقم بعد.' } },
|
|
893
|
+
// end add-on: audit-log
|
|
894
|
+
// add-on: roles
|
|
685
895
|
memberRoles: {
|
|
686
|
-
...memberRoles,
|
|
896
|
+
...copyFile(memberRoles),
|
|
687
897
|
singular: { en: 'Member role', ar: 'دور عضو' },
|
|
688
898
|
plural: { en: 'Member roles', ar: 'أدوار الأعضاء' },
|
|
689
899
|
none: { en: 'No member roles yet.', ar: 'لا توجد أدوار أعضاء بعد.' },
|
|
690
900
|
},
|
|
901
|
+
// end add-on: roles
|
|
691
902
|
version: {
|
|
692
903
|
saveDraft: { en: 'Save draft', ar: 'حفظ المسودة' },
|
|
904
|
+
noReadableChange: { en: 'No field you may read changed.', ar: 'لم يتغير حقل يمكنك قراءته.' },
|
|
905
|
+
publish: { en: 'Publish', ar: 'نشر' },
|
|
693
906
|
publishChanges: { en: 'Publish changes', ar: 'نشر التغييرات' },
|
|
694
907
|
status: { en: 'Status', ar: 'الحالة' },
|
|
695
908
|
draft: { en: 'Draft', ar: 'مسودة' },
|
|
696
909
|
published: { en: 'Published', ar: 'منشور' },
|
|
697
910
|
changed: { en: 'Changed', ar: 'تغييرات غير منشورة' },
|
|
911
|
+
archived: { en: 'Archived', ar: 'مؤرشف' },
|
|
698
912
|
saving: { en: 'Saving…', ar: 'جارٍ الحفظ…' },
|
|
699
913
|
saved: { en: 'Saved', ar: 'تم الحفظ' },
|
|
700
914
|
updatedAgo: { en: 'Updated {time}', ar: 'تم التحديث {time}' },
|
|
@@ -782,6 +996,8 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
782
996
|
ar: 'تسجيل الدخول المحلي متوقف على هذا الخادم: لم يُضبط LOCAL_AUTH_SECRET. اضبطه بسر من 32 حرفا على الأقل وأعد تشغيل الخادم.',
|
|
783
997
|
},
|
|
784
998
|
'not_found.row': { en: 'That row is no longer there.', ar: 'لم يعد هذا السجل موجودا.' },
|
|
999
|
+
'conflict.retry': { en: 'Another write interrupted this transaction. Try again.', ar: 'تعارضت هذه المعاملة مع عملية أخرى. حاول مرة أخرى.' },
|
|
1000
|
+
'conflict.target': { en: 'The authorized record cannot change.', ar: 'لا يمكن تغيير السجل المصرح به.' },
|
|
785
1001
|
'conflict.unique': { en: 'Another row already holds that value.', ar: 'يحمل سجل آخر هذه القيمة بالفعل.' },
|
|
786
1002
|
'conflict.stale': { en: 'This was changed by someone else since you opened it. Reload it and make your change again.', ar: 'غيّر شخص آخر هذا منذ فتحته. أعد تحميله ثم أعد إجراء تغييرك.' },
|
|
787
1003
|
'invalid.reference': { en: 'That record is not one you may choose.', ar: 'هذا السجل ليس مما يمكنك اختياره.' },
|
|
@@ -796,6 +1012,15 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
796
1012
|
'forbidden.owner_role': { en: 'The owner of the organization always holds the administrator role, so it is not taken from them.', ar: 'مالك المؤسسة يشغل دور المدير دائما، لذا لا يُسحب منه.' },
|
|
797
1013
|
'invalid.member_role': { en: 'A role is named exactly, with no spaces around it.', ar: 'يُسمّى الدور بدقة، دون مسافات حوله.' },
|
|
798
1014
|
'conflict.last_manager': { en: 'This would leave the organization with nobody who may manage roles. Give another member such a role first.', ar: 'سيترك هذا المؤسسة دون أي عضو يملك إدارة الأدوار. امنح عضوا آخر دورا كهذا أولا.' },
|
|
1015
|
+
'invalid.archived_session': { en: 'This session is archived, or its course is, so it takes no new seat. Pick an open session.', ar: 'هذه الحصة مؤرشفة، أو دورتها مؤرشفة، فلا تقبل مقعدا جديدا. اختر حصة مفتوحة.' },
|
|
1016
|
+
// add-on: courses
|
|
1017
|
+
'invalid.enrollment_closed': { en: 'Students of this course do not enroll themselves. Ask your school to enroll you.', ar: 'لا يسجّل طلاب هذه الدورة أنفسهم. اطلب من مدرستك تسجيلك.' },
|
|
1018
|
+
'invalid.session_started': { en: 'This session has started, so its seats no longer change.', ar: 'بدأت هذه الجلسة، فلم تعد مقاعدها تتغير.' },
|
|
1019
|
+
'conflict.session_full': { en: 'Every seat of this session is taken. Pick another session.', ar: 'كل مقاعد هذه الجلسة محجوزة. اختر جلسة أخرى.' },
|
|
1020
|
+
// end add-on: courses
|
|
1021
|
+
// add-on: courses, settings
|
|
1022
|
+
'invalid.portal_closed': { en: 'The portal is closed for maintenance, so no enrollment changes from it just now.', ar: 'البوابة مغلقة للصيانة، فلا يتغير منها أي تسجيل الآن.' },
|
|
1023
|
+
// end add-on: courses, settings
|
|
799
1024
|
'invalid.draft_sessions': { en: 'A course saved as a draft makes no sessions. Publish the course, then add its sessions.', ar: 'الدورة المحفوظة كمسودة لا تُنشئ جلسات. انشر الدورة أولًا، ثم أضف جلساتها.' },
|
|
800
1025
|
'invalid.upload_request': { en: 'The file has no name, or no size, that can be uploaded.', ar: 'ليس للملف اسم أو حجم يمكن رفعه.' },
|
|
801
1026
|
'invalid.upload_type': { en: 'Files of this type are not taken here.', ar: 'لا تُقبل هنا ملفات من هذا النوع.' },
|
|
@@ -803,18 +1028,110 @@ export const scopes: Record<string, Record<string, Record<string, string>>> = {
|
|
|
803
1028
|
'invalid.upload_reference': { en: 'The upload has expired or is not this one. Upload the file again.', ar: 'انتهت صلاحية الرفع أو أنه ليس لهذا الملف. ارفع الملف مرة أخرى.' },
|
|
804
1029
|
'invalid.upload_verify': { en: 'The file is not what it said it was, so it was not kept. Upload another.', ar: 'الملف ليس كما ادّعى، لذا لم يُحفظ. ارفع ملفا آخر.' },
|
|
805
1030
|
'not_found.file': { en: 'That file is not here.', ar: 'هذا الملف غير موجود.' },
|
|
806
|
-
'conflict.referenced': {
|
|
807
|
-
en: 'Something still uses this, so it is not deleted. An image stays while a course shows it. A session stays while an enrollment records a seat in it, and a person stays while one records their seat, a withdrawn one included.',
|
|
808
|
-
ar: 'ما زال شيء يستخدم هذا، لذا لا يُحذف. تبقى الصورة ما دامت دورة تعرضها. وتبقى الحصة ما دام تسجيل يحفظ مقعدا فيها، ويبقى الشخص ما دام تسجيل يحفظ مقعده، ولو كان قد انسحب.',
|
|
809
|
-
},
|
|
1031
|
+
'conflict.referenced': { en: 'Something still uses this, so it is not deleted.', ar: 'ما زال شيء يستخدم هذا، لذا لا يُحذف.' },
|
|
810
1032
|
'conflict.member_holds_roles': {
|
|
811
1033
|
en: 'This member still holds a role in this organization. Take each role from them first, then remove them.',
|
|
812
1034
|
ar: 'ما زال هذا العضو يشغل دورا في هذه المؤسسة. اسحب منه كل دور أولا، ثم أزله.',
|
|
813
1035
|
},
|
|
814
1036
|
'conflict.referencedBy': { en: '{kind} still use this, so it is not deleted.', ar: 'ما زالت {kind} تستخدم هذا، لذا لا يُحذف.' },
|
|
1037
|
+
'conflict.usedBy': { en: 'Used by {count} {kind}: {titles}.', ar: 'تستخدمه {kind} ({count}): {titles}.' },
|
|
1038
|
+
'conflict.usedByUnnamed': { en: 'Used by {count} {kind}.', ar: 'تستخدمه {kind} ({count}).' },
|
|
1039
|
+
'conflict.usedMore': { en: '{count} more', ar: '{count} أخرى' },
|
|
1040
|
+
'conflict.usedHint': { en: 'Take it out of them first.', ar: 'أزله منها أولا.' },
|
|
1041
|
+
'conflict.sole_owner': {
|
|
1042
|
+
en: 'This person is the only owner of an organization, so they are not deleted. Make another member its owner first.',
|
|
1043
|
+
ar: 'هذا الشخص هو المالك الوحيد لمؤسسة، لذا لا يُحذف. اجعل عضوا آخر مالكا لها أولا.',
|
|
1044
|
+
},
|
|
815
1045
|
},
|
|
816
1046
|
}
|
|
817
1047
|
|
|
1048
|
+
type Wording = Record<string, Record<string, { en: string; ar: string }>>
|
|
1049
|
+
|
|
1050
|
+
/** With one organization, nobody founds one on signing up: an owner sets the app up once. */
|
|
1051
|
+
const one: Wording = {
|
|
1052
|
+
auth: {
|
|
1053
|
+
noOrganization: { en: '{email} has no access here yet.', ar: 'لا يملك {email} وصولا هنا بعد.' },
|
|
1054
|
+
},
|
|
1055
|
+
marketing: {
|
|
1056
|
+
howStep1Title: { en: 'Set it up once', ar: 'أعدّه مرة واحدة' },
|
|
1057
|
+
howStep1Description: { en: 'Its owner sets the app up, then invites the people who use it.', ar: 'يُعدّ مالكه التطبيق، ثم يدعو من يستعملونه.' },
|
|
1058
|
+
ctaSubtitle: { en: 'Sign in and add your first record in minutes.', ar: 'سجل الدخول وأضف أول سجل لك خلال دقائق.' },
|
|
1059
|
+
},
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/** With the one organization never shown, it is the app itself, so no page names an organization. */
|
|
1063
|
+
const unnamed: Wording = {
|
|
1064
|
+
auth: {
|
|
1065
|
+
invitationJoin: { en: 'You are invited to join this app.', ar: 'أنت مدعو للانضمام إلى هذا التطبيق.' },
|
|
1066
|
+
invitationInviterGone: {
|
|
1067
|
+
en: 'Whoever sent this invitation no longer uses this app, so it cannot be accepted. Ask someone else to invite you.',
|
|
1068
|
+
ar: 'من أرسل هذه الدعوة لم يعد يستعمل هذا التطبيق، لذا لا يمكن قبولها. اطلب من شخص آخر أن يدعوك.',
|
|
1069
|
+
},
|
|
1070
|
+
noAccessDescription: { en: '{email} holds no role that opens a screen here. Ask an administrator to give you one.', ar: '{email} لا يملك دورا يفتح أي شاشة هنا. اطلب من أحد المسؤولين أن يمنحك دورا.' },
|
|
1071
|
+
},
|
|
1072
|
+
admin: {
|
|
1073
|
+
noColumns: { en: 'Your role can\'t see any column of this list. Ask an administrator for access.', ar: 'لا يستطيع دورك رؤية أي عمود في هذه القائمة. اطلب الوصول من أحد المسؤولين.' },
|
|
1074
|
+
},
|
|
1075
|
+
marketing: {
|
|
1076
|
+
heroTitle: { en: 'Run your work without the busywork', ar: 'أدر عملك دون العمل الروتيني' },
|
|
1077
|
+
heroSubtitle: {
|
|
1078
|
+
en: 'Asas is a dashboard and a portal: keep your records in one place, and keep every role to what it should see.',
|
|
1079
|
+
ar: 'أساس لوحة تحكم وبوابة: احفظ سجلاتك في مكان واحد، واحصر كل دور بما ينبغي أن يراه.',
|
|
1080
|
+
},
|
|
1081
|
+
featuresTitle: { en: 'Everything you need', ar: 'كل ما تحتاجه' },
|
|
1082
|
+
featureRolesDescription: {
|
|
1083
|
+
en: 'Every screen, field and action follows what a role may read or write.',
|
|
1084
|
+
ar: 'تتبع كل شاشة وحقل وإجراء ما يحق للدور قراءته أو تعديله.',
|
|
1085
|
+
},
|
|
1086
|
+
howStep2Description: { en: 'List what you keep and decide what each role may do.', ar: 'أدرج ما تحفظه وحدد ما يحق لكل دور القيام به.' },
|
|
1087
|
+
ctaTitle: { en: 'Start on Asas', ar: 'ابدأ على أساس' },
|
|
1088
|
+
footer: { en: 'Asas — one place for your records.', ar: 'أساس — مكان واحد لسجلاتك.' },
|
|
1089
|
+
},
|
|
1090
|
+
dashboard: {
|
|
1091
|
+
members: { en: 'Users', ar: 'المستخدمون' },
|
|
1092
|
+
membersAbout: { en: 'Who uses this app, and the role each holds.', ar: 'من يستعمل هذا التطبيق، والدور الذي يشغله كل منهم.' },
|
|
1093
|
+
membersNone: { en: 'No one uses this app yet.', ar: 'لا يستعمل أحد هذا التطبيق بعد.' },
|
|
1094
|
+
inviteAbout: { en: 'They join as a user once they accept. Give them roles here after that.', ar: 'ينضم مستخدمًا بعد أن يقبل الدعوة. امنحه الأدوار هنا بعد ذلك.' },
|
|
1095
|
+
inviteAlreadyMember: { en: 'This person already uses this app.', ar: 'هذا الشخص يستعمل هذا التطبيق بالفعل.' },
|
|
1096
|
+
inviteNotAllowed: { en: 'You may not invite people.', ar: 'لا يحق لك دعوة أشخاص.' },
|
|
1097
|
+
removeMember: { en: 'Remove from the app', ar: 'إزالة من التطبيق' },
|
|
1098
|
+
removeAbout: {
|
|
1099
|
+
en: 'They lose access to this app and every role they hold in it. Inviting them again does not give the roles back.',
|
|
1100
|
+
ar: 'يفقد الوصول إلى هذا التطبيق وكل الأدوار التي يشغلها فيه. دعوته مرة أخرى لا تعيد إليه أدواره.',
|
|
1101
|
+
},
|
|
1102
|
+
removeLastOwner: { en: 'The app\'s only owner cannot be removed.', ar: 'لا يمكن إزالة المالك الوحيد للتطبيق.' },
|
|
1103
|
+
removeNotAllowed: { en: 'You may not remove users.', ar: 'لا يحق لك إزالة مستخدمين.' },
|
|
1104
|
+
rolesAbout: { en: 'Fixed roles ship with the project and cannot be changed here. Custom roles are this app\'s own.', ar: 'الأدوار الثابتة تأتي مع المشروع ولا يمكن تغييرها هنا. الأدوار المخصصة خاصة بهذا التطبيق.' },
|
|
1105
|
+
membersOwnerRole: { en: 'The owner of the app always holds this role.', ar: 'مالك التطبيق يشغل هذا الدور دائما.' },
|
|
1106
|
+
dashboardAbout: { en: 'What this app holds, and how many have enrolled lately.', ar: 'ما يضمه هذا التطبيق، وعدد من سجلوا مؤخرا.' },
|
|
1107
|
+
dashboardAboutCatalogue: { en: 'What this app holds.', ar: 'ما يضمه هذا التطبيق.' },
|
|
1108
|
+
},
|
|
1109
|
+
error: {
|
|
1110
|
+
'invalid.tenant_reference': { en: 'That record is not one of this app\'s.', ar: 'هذا السجل ليس من سجلات هذا التطبيق.' },
|
|
1111
|
+
'conflict.last_manager': { en: 'This would leave nobody who may manage roles. Give another user such a role first.', ar: 'سيترك هذا التطبيق دون أي مستخدم يملك إدارة الأدوار. امنح مستخدما آخر دورا كهذا أولا.' },
|
|
1112
|
+
'forbidden.owner_role': { en: 'The owner of the app always holds the administrator role, so it is not taken from them.', ar: 'مالك التطبيق يشغل دور المدير دائما، لذا لا يُسحب منه.' },
|
|
1113
|
+
'invalid.role': { en: 'That role is not one of this app\'s.', ar: 'هذا الدور ليس من أدوار هذا التطبيق.' },
|
|
1114
|
+
'conflict.role_assigned': { en: 'An assignment still names that role, so no role takes the name until it is removed.', ar: 'ما زال إسناد يسمي هذا الدور، لذا لا يأخذ أي دور هذا الاسم حتى يُزال.' },
|
|
1115
|
+
'conflict.member_holds_roles': { en: 'This user still holds a role. Take each role from them first, then remove them.', ar: 'ما زال هذا المستخدم يشغل دورا. اسحب منه كل دور أولا، ثم أزله.' },
|
|
1116
|
+
'conflict.sole_owner': { en: 'This person is the app\'s only owner, so they are not deleted. Make another user an owner first.', ar: 'هذا الشخص هو المالك الوحيد للتطبيق، لذا لا يُحذف. اجعل مستخدما آخر مالكا أولا.' },
|
|
1117
|
+
},
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/** The words the organization mode changes, laid over the base copy key by key. */
|
|
1121
|
+
export const wordingFor = (mode: { organizations: 'one' | 'many'; showOrganization: boolean }): Wording =>
|
|
1122
|
+
mode.organizations === 'many' ? {} : mode.showOrganization ? one : Object.fromEntries([...new Set([...Object.keys(one), ...Object.keys(unnamed)])].map((scope) => [scope, { ...one[scope], ...unnamed[scope] }]))
|
|
1123
|
+
|
|
1124
|
+
/** The base copy with `wording` laid over it, so a key the mode changes reads the mode's words. */
|
|
1125
|
+
export const withWording = (base: typeof ownScopes, wording: Wording) =>
|
|
1126
|
+
Object.fromEntries(Object.entries(base).map(([scope, keys]) => [scope, { ...keys, ...wording[scope] }])) as typeof ownScopes
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* Every scope this app's `t` can answer from, in this project's organization mode. Each entry
|
|
1130
|
+
* carries a string per declared locale: a key left unanswered here shows an Arabic viewer the
|
|
1131
|
+
* English fallback.
|
|
1132
|
+
*/
|
|
1133
|
+
export const scopes = withWording(ownScopes, wordingFor({ organizations, showOrganization }))
|
|
1134
|
+
|
|
818
1135
|
// A `Map`, so a code named for a key of `Object.prototype` answers nothing. A taken organization
|
|
819
1136
|
// name has no entry: names may repeat, and sign-up makes the slug unique itself.
|
|
820
1137
|
const refusalKeys = new Map([
|
|
@@ -834,6 +1151,13 @@ const refusalKeys = new Map([
|
|
|
834
1151
|
['YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER', 'dashboard.removeNotAllowed'],
|
|
835
1152
|
['RESET_PASSWORD_DISABLED', 'auth.resetDisabled'],
|
|
836
1153
|
['INVALID_TOKEN', 'auth.tokenInvalid'],
|
|
1154
|
+
['SETUP_CODE_WRONG', 'auth.setupCodeWrong'],
|
|
1155
|
+
['SETUP_CODE_UNSET', 'auth.setupCodeUnset'],
|
|
1156
|
+
['FIRST_REGISTER_CLOSED', 'auth.firstRegisterClosed'],
|
|
1157
|
+
['FIRST_RUN_CLOSED', 'auth.firstRunClosed'],
|
|
1158
|
+
['FIRST_RUN_PENDING', 'auth.setupPending'],
|
|
1159
|
+
['SIGN_UP_INVITE_ONLY', 'auth.inviteOnly'],
|
|
1160
|
+
['SIGN_UP_DOMAIN', 'auth.outsideDomains'],
|
|
837
1161
|
])
|
|
838
1162
|
/** The key of this app's own sentence for a provider refusal, or nothing. The provider's `message` is English on every page and is never shown. */
|
|
839
1163
|
export const refusalKey = (status: number, code: unknown): string | undefined =>
|
|
@@ -859,9 +1183,22 @@ export const documentHead = ({ locale, app }: { locale: Locale; app?: string },
|
|
|
859
1183
|
return { meta: [{ title: name && own ? `${name} · ${own}` : name || own }] }
|
|
860
1184
|
}
|
|
861
1185
|
|
|
1186
|
+
/**
|
|
1187
|
+
* Sets the cookie the request middleware reads and redraws the page in `to` where it stands, as Payload's language
|
|
1188
|
+
* switch refreshes its router: nothing typed into a form is lost. The root route reads the locale off the document.
|
|
1189
|
+
*/
|
|
1190
|
+
export const showLocale = async ({ to, router }: { to: string; router: { invalidate(): Promise<unknown> } }) => {
|
|
1191
|
+
const locale = localeOf(to)
|
|
1192
|
+
document.cookie = localeCookieValue(locale)
|
|
1193
|
+
document.documentElement.lang = locale
|
|
1194
|
+
document.documentElement.dir = dirOf(locale)
|
|
1195
|
+
await router.invalidate()
|
|
1196
|
+
}
|
|
1197
|
+
|
|
862
1198
|
/**
|
|
863
1199
|
* Sets the cookie the request middleware reads, then reloads so the server draws the document
|
|
864
|
-
* in it
|
|
1200
|
+
* in it: a screen's form is seeded again from whatever row the host hands, so the shell asks before it
|
|
1201
|
+
* drops a change nobody saved, and its own unsaved-changes guard is dropped because the shell already asked.
|
|
865
1202
|
*/
|
|
866
1203
|
export const switchLocale = ({ to }: { to: string }): void => {
|
|
867
1204
|
window.onbeforeunload = null
|