Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions css/public-rtl.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

/**
* RTL (Right-to-Left) adjustments for Hebrew, Arabic, Farsi, and other RTL languages
* This file is automatically loaded by Nextcloud when ?forceLanguage=he (or other RTL language)
* is present in the URL and a RTL language is detected via IL10N->isRTL()
*/

/* ============================================
Global RTL Direction
============================================ */

/* Set global direction to RTL for main containers */
body,
html,
#content,
#content-vue {
direction: rtl;
text-align: right;
}

/* ============================================
Form Header and Title
============================================ */

/* Form title and description */
.form-title {
text-align: right;
direction: rtl;
}

.form-desc,
.info-message {
text-align: right;
direction: rtl;
}

/* ============================================
Form Elements and Inputs
============================================ */

/* Text inputs and textareas */
input[type="text"],
input[type="email"],
input[type="number"],
input[type="tel"],
input[type="url"],
textarea {
direction: rtl;
text-align: right;
}

/* Question containers */
.question {
direction: rtl;
}

.question__header,
.question__text {
text-align: right;
direction: rtl;
}

.question__content {
direction: rtl;
}

/* ============================================
Buttons and Actions
============================================ */

/* Form action buttons */
.form-buttons {
justify-content: flex-end !important;
flex-direction: row-reverse;
}

.form-buttons .submit-button {
margin-right: 35px !important;
}

.submit-button {
margin-left: 0 !important;
margin-right: 5px !important;
}

.submit-button:first-child {
margin-right: 0 !important;
}

/* Button icons - flip to the left side */
.button-vue {
flex-direction: row-reverse;
}

/* ============================================
Lists and Options
============================================ */

/* Checkbox and radio button options */
.question__item {
direction: rtl;
text-align: right;
}

/* Answer options text */
.answer-text,
.option-text {
text-align: right;
direction: rtl;
}

/* ============================================
Empty Content / Messages
============================================ */

/* Empty content messages */
.empty-content,
.forms-emptycontent {
direction: rtl;
}

.empty-content__name,
.empty-content__description {
text-align: right;
}

.submission-message {
text-align: right !important;
direction: rtl;
}

/* ============================================
Date Picker
============================================ */

/* Date picker inputs */
.mx-datepicker {
direction: rtl;
}

.mx-input {
text-align: right;
direction: rtl;
}

/* ============================================
Multiselect Dropdown
============================================ */

/* Multiselect component */
.multiselect {
direction: rtl;
text-align: right;
}

.multiselect__tags {
text-align: right;
}

.multiselect__option {
text-align: right;
}

.multiselect__single {
text-align: right;
}

/* ============================================
Modal Dialogs
============================================ */

/* Dialog windows */
.modal-container,
.dialog {
direction: rtl;
}

.modal-container__content,
.dialog__content {
text-align: right;
}

/* ============================================
Icons and Visual Elements
============================================ */

/* Required asterisk positioning */
.asterisk,
.required-asterisk {
margin-left: 0;
margin-right: 4px;
}

/* ============================================
Responsive and Mobile
============================================ */

/* Ensure RTL on all screen sizes */
@media (max-width: 1024px) {
body,
#content,
#content-vue {
direction: rtl;
}
}
5 changes: 5 additions & 0 deletions l10n/he.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ OC.L10N.register(
"Abort" : "להפסיק",
"Submit" : "שליחה",
"Clear" : "פינוי",
"Clear form" : "ניקוי הטופס",
"Enter your answer" : "הזנת תשובתך",
"Add new file as answer" : "הוספת קובץ חדש כתשובה",
"Some answers are not valid" : "חלק מהתשובות אינן תקפות",
"There was an error submitting the form: {message}" : "אירעה שגיאה בשליחת הטופס: {message}",
"There was an error submitting the form" : "עלתה שגיאה בעת הגשת הטופס",
"Submit form" : "הגשת הטופס",
"Thank you for completing the form!" : "תודה לך על שהשלמת את הטופס!",
Expand Down
5 changes: 5 additions & 0 deletions l10n/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
"Abort" : "להפסיק",
"Submit" : "שליחה",
"Clear" : "פינוי",
"Clear form" : "ניקוי הטופס",
"Enter your answer" : "הזנת תשובתך",
"Add new file as answer" : "הוספת קובץ חדש כתשובה",
"Some answers are not valid" : "חלק מהתשובות אינן תקפות",
"There was an error submitting the form: {message}" : "אירעה שגיאה בשליחת הטופס: {message}",
"There was an error submitting the form" : "עלתה שגיאה בעת הגשת הטופס",
"Submit form" : "הגשת הטופס",
"Thank you for completing the form!" : "תודה לך על שהשלמת את הטופס!",
Expand Down
18 changes: 18 additions & 0 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ protected function provideEmptyContent(string $renderAs, ?Form $form = null): Te
return $this->provideTemplate(self::TEMPLATE_MAIN, $form);
}

/**
* Check if current language is RTL (Right-to-Left)
*
* @return bool
*/
private function isRTL(): bool {
$rtlLanguages = ['ar', 'he', 'fa', 'ur', 'ps', 'ku', 'sd', 'yi'];
$currentLanguage = $this->l10n->getLanguageCode();
return in_array($currentLanguage, $rtlLanguages, true);
}

/**
* Helper function to create a template response from a form
* @param string $template
Expand All @@ -229,9 +240,16 @@ protected function provideEmptyContent(string $renderAs, ?Form $form = null): Te
*/
protected function provideTemplate(string $template, ?Form $form = null, array $options = []): TemplateResponse {
Util::addStyle($this->appName, 'forms-style');

// If not logged in, use PublicTemplate
if (!$this->userSession->isLoggedIn()) {
Util::addStyle($this->appName, 'public');

// Load RTL styles for public pages if language is RTL
if ($this->isRTL()) {
Util::addStyle($this->appName, 'public-rtl');
}

$response = new PublicTemplateResponse($this->appName, $template, array_merge([
'id-app-content' => '#app-content-vue',
'id-app-navigation' => null,
Expand Down