From 7c4a76cc89824544d45135def033d3d651bea345 Mon Sep 17 00:00:00 2001 From: Thomas Citharel <tcit@tcit.fr> Date: Sun, 7 Nov 2021 21:02:06 +0100 Subject: [PATCH] More bidi improvements Signed-off-by: Thomas Citharel <tcit@tcit.fr> --- config/dev.exs | 2 +- js/src/common.scss | 33 +++++++++++ .../components/About/InstanceContactLink.vue | 4 +- js/src/components/Account/ActorCard.vue | 2 +- js/src/components/Comment/Comment.vue | 4 +- js/src/components/Event/EventMetadataList.vue | 1 + .../components/Event/EventMinimalistCard.vue | 1 + .../Event/EventParticipationCard.vue | 4 +- .../Event/FullAddressAutoComplete.vue | 1 + js/src/components/Event/OrganizerPicker.vue | 3 +- .../Event/OrganizerPickerWrapper.vue | 2 + .../components/Event/ParticipationButton.vue | 4 +- js/src/components/Event/TagInput.vue | 1 + js/src/components/Post/PostListItem.vue | 3 +- js/src/components/SearchField.vue | 1 + js/src/i18n/ar.json | 2 +- js/src/i18n/be.json | 2 +- js/src/i18n/ca.json | 3 +- js/src/i18n/cs.json | 2 +- js/src/i18n/de.json | 3 +- js/src/i18n/en_US.json | 3 +- js/src/i18n/es.json | 5 +- js/src/i18n/fa.json | 2 +- js/src/i18n/fi.json | 3 +- js/src/i18n/fr_FR.json | 5 +- js/src/i18n/gd.json | 3 +- js/src/i18n/gl.json | 3 +- js/src/i18n/hu.json | 3 +- js/src/i18n/id.json | 3 +- js/src/i18n/it.json | 3 +- js/src/i18n/nl.json | 2 +- js/src/i18n/nn.json | 5 +- js/src/i18n/oc.json | 3 +- js/src/i18n/pl.json | 3 +- js/src/i18n/pt.json | 2 +- js/src/i18n/pt_BR.json | 3 +- js/src/i18n/ru.json | 3 +- js/src/i18n/sl.json | 3 +- js/src/i18n/sv.json | 4 +- js/src/utils/i18n.ts | 6 ++ js/src/views/About/AboutInstance.vue | 4 +- js/src/views/Event/Edit.vue | 1 + js/src/views/Event/Event.vue | 57 ++++--------------- js/src/views/Group/Group.vue | 8 ++- js/src/views/Posts/Edit.vue | 1 + js/src/views/Search.vue | 1 + .../__snapshots__/PostListItem.spec.ts.snap | 12 ++-- lib/web/views/utils.ex | 11 +++- 48 files changed, 127 insertions(+), 113 deletions(-) diff --git a/config/dev.exs b/config/dev.exs index 291bdc463..cd4d9ea1c 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -58,7 +58,7 @@ config :logger, :console, format: "[$level] $message\n", level: :debug config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim -config :mobilizon, Mobilizon.Web.Gettext, allowed_locales: ["fr", "en"] +config :mobilizon, Mobilizon.Web.Gettext, allowed_locales: ["fr", "en", "ar"] # Set a higher stacktrace during development. Avoid configuring such # in production as building large stacktraces may be expensive. diff --git a/js/src/common.scss b/js/src/common.scss index 9566e8925..65301b01b 100644 --- a/js/src/common.scss +++ b/js/src/common.scss @@ -165,3 +165,36 @@ p { .icon { vertical-align: middle; } + +.tags .tag:not(:last-child) { + margin-right: unset; + @include margin-right(0.5rem); +} + +.button .icon { + &:first-child:not(:last-child) { + @include margin-left(calc(-0.5em - 1px)); + @include margin-right(0.25em); + } + &:last-child:not(:first-child) { + @include margin-right(calc(-0.5em - 1px)); + @include margin-left(0.25em); + } +} + +.buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: unset; + @include margin-right(0.5rem); +} + +.breadcrumb li:first-child a { + padding-left: unset; + @include padding-left(0); + @include padding-right(0.75em); +} +.media-left { + @include margin-left(1rem); +} +a.dropdown-item { + @include padding-right(3rem); +} diff --git a/js/src/components/About/InstanceContactLink.vue b/js/src/components/About/InstanceContactLink.vue index 80d17ecea..429e7fb67 100644 --- a/js/src/components/About/InstanceContactLink.vue +++ b/js/src/components/About/InstanceContactLink.vue @@ -1,9 +1,9 @@ <template> <p> - <a :title="contact" v-if="configLink" :href="configLink.uri">{{ + <a dir="auto" :title="contact" v-if="configLink" :href="configLink.uri">{{ configLink.text }}</a> - <span v-else-if="contact">{{ contact }}</span> + <span dir="auto" v-else-if="contact">{{ contact }}</span> <span v-else>{{ $t("contact uninformed") }}</span> </p> </template> diff --git a/js/src/components/Account/ActorCard.vue b/js/src/components/Account/ActorCard.vue index 4b7a9b11a..d319bd898 100644 --- a/js/src/components/Account/ActorCard.vue +++ b/js/src/components/Account/ActorCard.vue @@ -12,7 +12,7 @@ {{ actor.name || `@${usernameWithDomain(actor)}` }} </p> <p class="has-text-grey-dark" v-if="actor.name"> - @{{ usernameWithDomain(actor) }} + <span dir="ltr">@{{ usernameWithDomain(actor) }}</span> </p> <div v-if="full" diff --git a/js/src/components/Comment/Comment.vue b/js/src/components/Comment/Comment.vue index 86fa68f5a..28267be3c 100644 --- a/js/src/components/Comment/Comment.vue +++ b/js/src/components/Comment/Comment.vue @@ -36,7 +36,7 @@ <strong :class="{ organizer: commentFromOrganizer }">{{ comment.actor.name }}</strong> - <small>@{{ usernameWithDomain(comment.actor) }}</small> + <small dir="ltr">@{{ usernameWithDomain(comment.actor) }}</small> </span> <a v-else class="comment-link" :href="commentURL"> <span>{{ $t("[deleted]") }}</span> @@ -128,7 +128,7 @@ <div class="content"> <span class="first-line"> <strong>{{ currentActor.name }}</strong> - <small>@{{ currentActor.preferredUsername }}</small> + <small dir="ltr">@{{ currentActor.preferredUsername }}</small> </span> <br /> <span class="editor-line"> diff --git a/js/src/components/Event/EventMetadataList.vue b/js/src/components/Event/EventMetadataList.vue index 9868cbedd..c43bd70cf 100644 --- a/js/src/components/Event/EventMetadataList.vue +++ b/js/src/components/Event/EventMetadataList.vue @@ -25,6 +25,7 @@ :placeholder="$t('e.g. Accessibility, Twitch, PeerTube')" id="event-metadata-autocomplete" @select="(option) => addElement(option)" + dir="auto" > <template slot-scope="props"> <div class="media"> diff --git a/js/src/components/Event/EventMinimalistCard.vue b/js/src/components/Event/EventMinimalistCard.vue index 0e6a5715a..be0e47815 100644 --- a/js/src/components/Event/EventMinimalistCard.vue +++ b/js/src/components/Event/EventMinimalistCard.vue @@ -1,6 +1,7 @@ <template> <router-link class="event-minimalist-card-wrapper" + dir="auto" :to="{ name: RouteName.EVENT, params: { uuid: event.uuid } }" > <div class="event-preview mr-0 ml-0"> diff --git a/js/src/components/Event/EventParticipationCard.vue b/js/src/components/Event/EventParticipationCard.vue index 9b6328273..5c75a6110 100644 --- a/js/src/components/Event/EventParticipationCard.vue +++ b/js/src/components/Event/EventParticipationCard.vue @@ -43,8 +43,8 @@ </router-link> </div> </div> - <div class="list-card-content" dir="auto"> - <div class="title-wrapper"> + <div class="list-card-content"> + <div class="title-wrapper" dir="auto"> <router-link :to="{ name: RouteName.EVENT, diff --git a/js/src/components/Event/FullAddressAutoComplete.vue b/js/src/components/Event/FullAddressAutoComplete.vue index 7518aa2f3..0434e944f 100644 --- a/js/src/components/Event/FullAddressAutoComplete.vue +++ b/js/src/components/Event/FullAddressAutoComplete.vue @@ -35,6 +35,7 @@ v-bind="$attrs" :id="id" :disabled="disabled" + dir="auto" > <template #default="{ option }"> <b-icon :icon="option.poiInfos.poiIcon.icon" /> diff --git a/js/src/components/Event/OrganizerPicker.vue b/js/src/components/Event/OrganizerPicker.vue index 771e183ae..99e044042 100644 --- a/js/src/components/Event/OrganizerPicker.vue +++ b/js/src/components/Event/OrganizerPicker.vue @@ -1,6 +1,7 @@ <template> <div class="list is-hoverable"> <b-input + dir="auto" :placeholder="$t('Filter by profile or group name')" v-model="actorFilter" /> @@ -11,7 +12,7 @@ v-for="availableActor in actualFilteredAvailableActors" :key="availableActor.id" > - <div class="media"> + <div class="media" dir="auto"> <figure class="image is-48x48" v-if="availableActor.avatar"> <img class="media-left is-rounded" diff --git a/js/src/components/Event/OrganizerPickerWrapper.vue b/js/src/components/Event/OrganizerPickerWrapper.vue index 77b36a79e..268e266a6 100644 --- a/js/src/components/Event/OrganizerPickerWrapper.vue +++ b/js/src/components/Event/OrganizerPickerWrapper.vue @@ -4,6 +4,7 @@ <div v-if="inline && selectedActor.id" class="inline box" + dir="auto" @click="isComponentModalActive = true" > <div class="media"> @@ -65,6 +66,7 @@ <b-input :placeholder="$t('Filter by name')" v-model="contactFilter" + dir="auto" /> <p class="field" diff --git a/js/src/components/Event/ParticipationButton.vue b/js/src/components/Event/ParticipationButton.vue index 4fa3bd5c6..48fd0b93a 100644 --- a/js/src/components/Event/ParticipationButton.vue +++ b/js/src/components/Event/ParticipationButton.vue @@ -123,8 +123,8 @@ A button to set your participation @keyup.enter="joinEvent(currentActor)" > <div class="media"> - <div class="media-left"> - <figure class="image is-32x32" v-if="currentActor.avatar"> + <div class="media-left" v-if="currentActor.avatar"> + <figure class="image is-32x32"> <img class="is-rounded" :src="currentActor.avatar.url" alt /> </figure> </div> diff --git a/js/src/components/Event/TagInput.vue b/js/src/components/Event/TagInput.vue index c484471ba..ec4606fc4 100644 --- a/js/src/components/Event/TagInput.vue +++ b/js/src/components/Event/TagInput.vue @@ -23,6 +23,7 @@ :placeholder="$t('Eg: Stockholm, Dance, Chess…')" @typing="getFilteredTags" :id="id" + dir="auto" > </b-taginput> </b-field> diff --git a/js/src/components/Post/PostListItem.vue b/js/src/components/Post/PostListItem.vue index a2899dc5a..ac08a2e6d 100644 --- a/js/src/components/Post/PostListItem.vue +++ b/js/src/components/Post/PostListItem.vue @@ -1,6 +1,7 @@ <template> <router-link class="post-minimalist-card-wrapper" + dir="auto" :to="{ name: RouteName.POST, params: { slug: post.slug } }" > <lazy-image-wrapper @@ -12,7 +13,7 @@ <h3 class="post-minimalist-title">{{ post.title }}</h3> <p class="post-publication-date"> <b-icon icon="clock" /> - <span class="has-text-grey-dark" v-if="isBeforeLastWeek">{{ + <span dir="auto" class="has-text-grey-dark" v-if="isBeforeLastWeek">{{ publishedAt | formatDateTimeString(undefined, false, "short") }}</span> <span v-else>{{ diff --git a/js/src/components/SearchField.vue b/js/src/components/SearchField.vue index 9261059a3..c81650761 100644 --- a/js/src/components/SearchField.vue +++ b/js/src/components/SearchField.vue @@ -7,6 +7,7 @@ icon="magnify" type="search" rounded + dir="auto" :placeholder="defaultPlaceHolder" v-model="search" @keyup.native.enter="enter" diff --git a/js/src/i18n/ar.json b/js/src/i18n/ar.json index 2f900c2ed..32eade87e 100644 --- a/js/src/i18n/ar.json +++ b/js/src/i18n/ar.json @@ -29,7 +29,7 @@ "Are you sure you want to cancel your participation at event \"{title}\"?": "هل أنت متأكد مِن أنك تريد الغاء مشاركتك في فعالية \"{title}\"؟", "Avatar": "الصورة الرمزية", "Back to previous page": "العودة إلى الصفحة السابقة", - "By @{username}": "حسب @{username}", + "By {username}": "حسب {username}", "By {username} and {group}": "مِن {username} و {group}", "Cancel": "الغاء", "Cancel creation": "إلغاء الإنشاء", diff --git a/js/src/i18n/be.json b/js/src/i18n/be.json index 97c0936ac..9903ad94e 100644 --- a/js/src/i18n/be.json +++ b/js/src/i18n/be.json @@ -34,7 +34,7 @@ "Are you sure you want to delete this event? This action cannot be reverted.": "Вы сапраўды хочаце выдаліць гэту падзею? Гэта дзеянне нельга адмяніць.", "Avatar": "Аватар", "Before you can login, you need to click on the link inside it to validate your account.": "Каб увайсці з уліковым запісам, патрэбна спачатку перайсці па спасылцы, якая прыйшла вам у лісце.", - "By @{username}": "Ад @{username}", + "By {username}": "Ад {username}", "Cancel": "Адмяніць", "Cancel creation": "Адмяніць стварэнне", "Cancel edition": "Адмяніць рэдагаванне", diff --git a/js/src/i18n/ca.json b/js/src/i18n/ca.json index 89d2c4117..6fc2c8c03 100644 --- a/js/src/i18n/ca.json +++ b/js/src/i18n/ca.json @@ -120,8 +120,7 @@ "Begins on": "Comença a", "Bold": "Negreta", "Browser notifications": "Notificacions de navegador", - "By @{group}": "De @{group}", - "By @{username}": "De @{username}", + "By {username}": "De {username}", "By others": "Les d'altres", "By {author}": "De {author}", "By {group}": "De {group}", diff --git a/js/src/i18n/cs.json b/js/src/i18n/cs.json index 068bf175c..d40660a09 100644 --- a/js/src/i18n/cs.json +++ b/js/src/i18n/cs.json @@ -31,7 +31,7 @@ "Avatar": "Avatar", "Back to previous page": "Zpět na předchozí stránku", "Before you can login, you need to click on the link inside it to validate your account.": "Před přihlášením musíte kliknout na odkaz v e-mailu pro potvrzení účtu.", - "By @{username}": "Od @{username}", + "By {username}": "Od {username}", "Cancel": "Zrušit", "Cancel anonymous participation": "Zrušit anonymní účast", "Cancel creation": "Zrušit vytváření", diff --git a/js/src/i18n/de.json b/js/src/i18n/de.json index ecb2d459c..68dc1b6be 100644 --- a/js/src/i18n/de.json +++ b/js/src/i18n/de.json @@ -118,8 +118,7 @@ "Begins on": "Beginnt um", "Bold": "Fett", "Browser notifications": "Browserbenachrichtigungen", - "By @{group}": "Von @{group}", - "By @{username}": "von @{username}", + "By {username}": "von {username}", "By others": "Von Anderen", "By {author}": "Von {author}", "By {group}": "Von {group}", diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 43630c71d..98c5994af 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -34,7 +34,7 @@ "Avatar": "Avatar", "Back to previous page": "Back to previous page", "Before you can login, you need to click on the link inside it to validate your account.": "Before you can login, you need to click on the link inside it to validate your account.", - "By @{username}": "By @{username}", + "By {username}": "By {username}", "Cancel anonymous participation": "Cancel anonymous participation", "Cancel creation": "Cancel creation", "Cancel edition": "Cancel edition", @@ -418,7 +418,6 @@ "(Masked)": "(Masked)", "{available}/{capacity} available places": "No places left|{available}/{capacity} available places", "No one is participating|One person participating|{going} people participating": "No one is participating|One person participating|{going} people participating", - "By @{group}": "By @{group}", "Date and time": "Date and time", "Location": "Location", "No resources selected": "No resources selected|One resources selected|{count} resources selected", diff --git a/js/src/i18n/es.json b/js/src/i18n/es.json index 5612c1090..98f86115e 100644 --- a/js/src/i18n/es.json +++ b/js/src/i18n/es.json @@ -146,12 +146,11 @@ "Breadcrumbs": "Migajas", "Browser notifications": "Notificaciones del navegador", "Bullet list": "Lista de puntos", - "By @{group}": "Por @{group}", - "By @{username}": "Por @{username}", + "By {username}": "Por {username}", "By @{username} and @{group}": "Por @{username} y @{group}", "By others": "Por otros", "By {author}": "Por {author}", - "By {group}": "Por {grup}", + "By {group}": "Por {group}", "By {username} and {group}": "Por {username} y {group}", "Can be an email or a link, or just plain text.": "Puede ser un correo electrónico o un enlace, o simplemente texto sin formato.", "Cancel": "Cancelar", diff --git a/js/src/i18n/fa.json b/js/src/i18n/fa.json index 8b8ec5e85..a742da210 100644 --- a/js/src/i18n/fa.json +++ b/js/src/i18n/fa.json @@ -33,7 +33,7 @@ "Avatar": "آواتار", "Back to previous page": "بازگشت به صفحه قبلی", "Before you can login, you need to click on the link inside it to validate your account.": "پیش از آن که بتواند وارد شوید لازم است روی پیوندی که داخل آن است کلیک کنید تا حسابتان اعتبارسنجی شود.", - "By @{username}": "توسط @{username}", + "By {username}": "توسط {username}", "Cancel": "لغو", "Cancel anonymous participation": "غلو حضور ناشناس", "Cancel creation": "لغو ساخت", diff --git a/js/src/i18n/fi.json b/js/src/i18n/fi.json index b44e55622..2f4ca26a4 100644 --- a/js/src/i18n/fi.json +++ b/js/src/i18n/fi.json @@ -132,8 +132,7 @@ "Booking": "Varaus", "Breadcrumbs": "Leivänmurut", "Browser notifications": "Selaimen ilmoitukset", - "By @{group}": "Tehnyt @{group}", - "By @{username}": "Tehnyt @{username}", + "By {username}": "Tehnyt {username}", "By others": "Muilta", "By {author}": "Tekijä {author}", "By {group}": "Tekijä {group}", diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 48bae4f31..d1b380733 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -133,8 +133,7 @@ "Breadcrumbs": "Fil d'Ariane", "Browser notifications": "Notifications du navigateur", "Bullet list": "Liste à puce", - "By @{group}": "Par @{group}", - "By @{username}": "Par @{username}", + "By {username}": "Par {username}", "By others": "Des autres", "By {author}": "Par {author}", "By {group}": "Par {group}", @@ -1031,7 +1030,7 @@ "Whether the event is accessible with a wheelchair": "Si l'événement est accessible avec un fauteuil roulant", "Whether the event is interpreted in sign language": "Si l'événement est interprété en langue des signes", "Whether the event live video is subtitled": "Si le direct vidéo de l'événement est sous-titré", - "Who can post a comment?": "Who can post a comment?", + "Who can post a comment?": "Qui peut poster un commentaire ?", "Who can view this event and participate": "Qui peut voir cet événement et y participer", "Who can view this post": "Qui peut voir ce billet", "Who published {number} events": "Ayant publié {number} événements", diff --git a/js/src/i18n/gd.json b/js/src/i18n/gd.json index 91dced484..832ae6332 100644 --- a/js/src/i18n/gd.json +++ b/js/src/i18n/gd.json @@ -132,8 +132,7 @@ "Breadcrumbs": "Breadcrumbs", "Browser notifications": "Brathan a’ bhrabhsair", "Bullet list": "Liosta pheilearaichte", - "By @{group}": "Le @{group}", - "By @{username}": "Le @{username}", + "By {username}": "Le {username}", "By others": "Le daoine eile", "By {author}": "Le {author}", "By {group}": "Le {group}", diff --git a/js/src/i18n/gl.json b/js/src/i18n/gl.json index cd246ad1a..e790bdf7a 100644 --- a/js/src/i18n/gl.json +++ b/js/src/i18n/gl.json @@ -123,8 +123,7 @@ "Bold": "Resaltado", "Breadcrumbs": "Breadcrumbs", "Browser notifications": "Notificacións do navegador", - "By @{group}": "Por @{group}", - "By @{username}": "Por @{username}", + "By {username}": "Por {username}", "By others": "Por outras", "By {author}": "Por {author}", "By {group}": "Por {group}", diff --git a/js/src/i18n/hu.json b/js/src/i18n/hu.json index b1ea212c2..cf6738e3a 100644 --- a/js/src/i18n/hu.json +++ b/js/src/i18n/hu.json @@ -97,8 +97,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Mielőtt bejelentkezne, rá kell kattintania a benne lévő hivatkozásra a fiókja ellenőrzéséhez.", "Begins on": "Ekkor kezdődik", "Bold": "Félkövér", - "By @{group}": "@{group} által", - "By @{username}": "@{username} által", + "By {username}": "{username} által", "By others": "Másoktól származó", "By {author}": "{author} által", "By {group}": "{group} által", diff --git a/js/src/i18n/id.json b/js/src/i18n/id.json index 42bdf9d4b..bdbe88a03 100644 --- a/js/src/i18n/id.json +++ b/js/src/i18n/id.json @@ -77,8 +77,7 @@ "Big Blue Button": "Big Blue Button", "Bold": "Tebal", "Browser notifications": "Notifikasi browser", - "By @{group}": "Oleh @{group}", - "By @{username}": "Oleh @{username}", + "By {username}": "Oleh {username}", "By others": "Dari orang lain", "By {author}": "Oleh {author}", "By {group}": "Oleh {group}", diff --git a/js/src/i18n/it.json b/js/src/i18n/it.json index 6d13f2275..b50af865e 100644 --- a/js/src/i18n/it.json +++ b/js/src/i18n/it.json @@ -97,8 +97,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Prima di poter accedere, è necessario cliccare sul collegamento al suo interno per convalidare il tuo account.", "Begins on": "Comincia a", "Bold": "Grassetto", - "By @{group}": "Di @{group}", - "By @{username}": "Da @{username}", + "By {username}": "Da {username}", "By {author}": "Da {author}", "By {group}": "Da {group}", "Can be an email or a link, or just plain text.": "Può essere un'email o un collegamento, oppure testo semplice.", diff --git a/js/src/i18n/nl.json b/js/src/i18n/nl.json index f8a0372d2..12d4dc460 100644 --- a/js/src/i18n/nl.json +++ b/js/src/i18n/nl.json @@ -33,7 +33,7 @@ "Are you sure you want to delete this event? This action cannot be reverted.": "Bent u zeker dat u dit evenement wil verwijderen? Dit kan niet ongedaan gemaakt worden.", "Avatar": "Profielfoto", "Before you can login, you need to click on the link inside it to validate your account.": "Voordat u zich kan aanmelden, moet u op de link erin klikken om uw account te valideren.", - "By @{username}": "Door @{username}", + "By {username}": "Door {username}", "Cancel": "Annuleren", "Cancel creation": "Aanmaken annuleren", "Cancel edition": "Bewerken annuleren", diff --git a/js/src/i18n/nn.json b/js/src/i18n/nn.json index 9644f81a1..ea9808cf0 100644 --- a/js/src/i18n/nn.json +++ b/js/src/i18n/nn.json @@ -135,11 +135,10 @@ "Breadcrumbs": "Navigeringsmerke", "Browser notifications": "Nettlesarvarsel", "Bullet list": "Punktliste", - "By @{group}": "Av @{group}", - "By @{username}": "Av @{username}", + "By {username}": "Av {username}", "By others": "Av andre", "By {author}": "Av {author}", - "By {group}": "Av {gruppe}", + "By {group}": "Av {group}", "Can be an email or a link, or just plain text.": "Kan vera ei epostadresse eller ei lenke, eller rein tekst.", "Cancel": "Avbryt", "Cancel anonymous participation": "Avbryt anonym deltaking", diff --git a/js/src/i18n/oc.json b/js/src/i18n/oc.json index 4e9721b3b..af375b931 100644 --- a/js/src/i18n/oc.json +++ b/js/src/i18n/oc.json @@ -100,8 +100,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Abans que poscatz vos marcar, devètz clicar lo ligam dedins per validar lo compte.", "Begins on": "Comença lo", "Bold": "Gras", - "By @{group}": "Per @{group}", - "By @{username}": "Per @{username}", + "By {username}": "Per {username}", "By @{username} and @{group}": "Per @{username} e @{group}", "By {author}": "Per {author}", "By {group}": "Per {group}", diff --git a/js/src/i18n/pl.json b/js/src/i18n/pl.json index 7aa74282e..f5734a9ec 100644 --- a/js/src/i18n/pl.json +++ b/js/src/i18n/pl.json @@ -87,8 +87,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Zanim się zalogujesz, musisz odwiedzić odnośnik znajdujący się w niej, aby potwierdzić swoje konto.", "Begins on": "Zaczyna się", "Bold": "Pogrubione", - "By @{group}": "Od @{group}", - "By @{username}": "Od @{username}", + "By {username}": "Od {username}", "By {author}": "Autorstwa {author}", "By {group}": "Autorstwa {group}", "Can be an email or a link, or just plain text.": "Może być adresem e-mail, odnośnikiem lub zwykłym tekstem.", diff --git a/js/src/i18n/pt.json b/js/src/i18n/pt.json index 0940180be..6231cd837 100644 --- a/js/src/i18n/pt.json +++ b/js/src/i18n/pt.json @@ -33,7 +33,7 @@ "Avatar": "Avatar", "Back to previous page": "Voltar à página anterior", "Before you can login, you need to click on the link inside it to validate your account.": "Antes de entrar, precisas de clicar no link dentro para validar a tua conta.", - "By @{username}": "Por @{username}", + "By {username}": "Por {username}", "Cancel": "Cancelar", "Cancel anonymous participation": "Cancelar participação anónima", "Cancel creation": "Aborto", diff --git a/js/src/i18n/pt_BR.json b/js/src/i18n/pt_BR.json index 6d1e12562..567c24eae 100644 --- a/js/src/i18n/pt_BR.json +++ b/js/src/i18n/pt_BR.json @@ -90,8 +90,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Antes de você entrar, você precisa clicar no link interno para validar a sua conta.", "Begins on": "Começa às", "Bold": "Negrito", - "By @{group}": "Por @{group}", - "By @{username}": "Por @{username}", + "By {username}": "Por {username}", "By {author}": "Por {author}", "By {group}": "Por {group}", "Can be an email or a link, or just plain text.": "Pode ser um email ou um link, ou apenas um texto simples.", diff --git a/js/src/i18n/ru.json b/js/src/i18n/ru.json index 36f0c7959..3f9b29a11 100644 --- a/js/src/i18n/ru.json +++ b/js/src/i18n/ru.json @@ -133,8 +133,7 @@ "Breadcrumbs": "Хлебные крошки", "Browser notifications": "Уведомления в браузере", "Bullet list": "Маркированный список", - "By @{group}": "Из @{group}", - "By @{username}": "От @{username}", + "By {username}": "От {username}", "By others": "Другими", "By {author}": "Автор {author}", "By {group}": "Автор: {group}", diff --git a/js/src/i18n/sl.json b/js/src/i18n/sl.json index 3d7a83696..827d97a5a 100644 --- a/js/src/i18n/sl.json +++ b/js/src/i18n/sl.json @@ -94,8 +94,7 @@ "Before you can login, you need to click on the link inside it to validate your account.": "Preden se lahko prijavite, morate klikniti na povezavo znotraj njega, da potrdite svoj račun.", "Begins on": "Začne se v", "Bold": "Krepko", - "By @{group}": "Avtor @{group}", - "By @{username}": "Od @{username}", + "By {username}": "Od {username}", "By others": "Od drugih", "By {author}": "Od {author}", "By {group}": "Od {group}", diff --git a/js/src/i18n/sv.json b/js/src/i18n/sv.json index 4d37b5723..75ec4a770 100644 --- a/js/src/i18n/sv.json +++ b/js/src/i18n/sv.json @@ -39,8 +39,8 @@ "Avatar": "Avatar", "Back to previous page": "Tillbaka till föregående sida", "Before you can login, you need to click on the link inside it to validate your account.": "Innan du loggar in måste du klicka på länken inuti det för att validera ditt konto.", - "By @{group}": "Av @{group}", - "By @{username}": "Av @{username}", + "By {group}": "Av {group}", + "By {username}": "Av {username}", "By {username} and {group}": "Av {username} och {group}", "Cancel": "Avbryt", "Cancel anonymous participation": "Avbryt anonymt deltagande", diff --git a/js/src/utils/i18n.ts b/js/src/utils/i18n.ts index 01c003f09..7ec7e7eba 100644 --- a/js/src/utils/i18n.ts +++ b/js/src/utils/i18n.ts @@ -67,6 +67,12 @@ function setLanguageInDOM(lang: string): void { if (documentLang !== fixedLang) { html.setAttribute("lang", fixedLang); } + + const direction = ["ar", "ae", "he", "fa", "ku", "ur"].includes(fixedLang) + ? "rtl" + : "ltr"; + console.debug("setDirection with", [fixedLang, direction]); + html.setAttribute("dir", direction); } function fileForLanguage(matches: Record<string, string>, lang: string) { diff --git a/js/src/views/About/AboutInstance.vue b/js/src/views/About/AboutInstance.vue index 433a9a716..a301fde04 100644 --- a/js/src/views/About/AboutInstance.vue +++ b/js/src/views/About/AboutInstance.vue @@ -3,8 +3,8 @@ <section class="hero is-primary"> <div class="hero-body"> <div class="container"> - <h1 class="title">{{ config.name }}</h1> - <p>{{ config.description }}</p> + <h1 class="title" dir="auto">{{ config.name }}</h1> + <p dir="auto">{{ config.description }}</p> </div> </div> </section> diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue index 611e1f6da..802351c2d 100644 --- a/js/src/views/Event/Edit.vue +++ b/js/src/views/Event/Edit.vue @@ -28,6 +28,7 @@ required v-model="event.title" id="title" + dir="auto" /> </b-field> diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue index 8adcd56ff..8154cbdd8 100755 --- a/js/src/views/Event/Event.vue +++ b/js/src/views/Event/Event.vue @@ -7,7 +7,7 @@ <div class="date-calendar-icon-wrapper"> <date-calendar-icon :date="event.beginsOn" /> </div> - <section class="intro"> + <section class="intro" dir="auto"> <div class="columns"> <div class="column"> <h1 class="title" style="margin: 0" dir="auto"> @@ -19,57 +19,24 @@ :actor="event.organizerActor" :inline="true" > - <span> - {{ - $t("By @{username}", { - username: usernameWithDomain(event.organizerActor), - }) - }} - </span> + <i18n path="By {username}" dir="auto"> + <span dir="ltr" slot="username" + >@{{ usernameWithDomain(event.organizerActor) }}</span + > + </i18n> </popover-actor-card> </div> - <span - v-else-if=" - event.attributedTo && - event.options.hideOrganizerWhenGroupEvent - " - > + <span v-else-if="event.attributedTo"> <popover-actor-card :actor="event.attributedTo" :inline="true" > - {{ - $t("By @{group}", { - group: usernameWithDomain(event.attributedTo), - }) - }} - </popover-actor-card> - </span> - <span v-else-if="event.organizerActor && event.attributedTo"> - <i18n path="By {group}"> - <popover-actor-card - :actor="event.attributedTo" - slot="group" - :inline="true" - > - <router-link - :to="{ - name: RouteName.GROUP, - params: { - preferredUsername: usernameWithDomain( - event.attributedTo - ), - }, - }" + <i18n path="By {group}" dir="auto"> + <span dir="ltr" slot="group" + >@{{ usernameWithDomain(event.attributedTo) }}</span > - {{ - $t("@{group}", { - group: usernameWithDomain(event.attributedTo), - }) - }} - </router-link> - </popover-actor-card> - </i18n> + </i18n> + </popover-actor-card> </span> </div> <p diff --git a/js/src/views/Group/Group.vue b/js/src/views/Group/Group.vue index 36d45d378..7f12f6207 100644 --- a/js/src/views/Group/Group.vue +++ b/js/src/views/Group/Group.vue @@ -60,7 +60,10 @@ <div class="title-container"> <h1 v-if="group.name">{{ group.name }}</h1> <b-skeleton v-else :animated="true" /> - <small class="has-text-grey-dark" v-if="group.preferredUsername" + <small + dir="ltr" + class="has-text-grey-dark" + v-if="group.preferredUsername" >@{{ usernameWithDomain(group) }}</small > <b-skeleton v-else :animated="true" /> @@ -503,7 +506,7 @@ }}</span> <div class="address" v-if="physicalAddress"> <div> - <address> + <address dir="auto"> <p class="addressDescription" :title="physicalAddress.poiInfos.name" @@ -533,6 +536,7 @@ <section> <subtitle>{{ $t("About") }}</subtitle> <div + dir="auto" v-html="group.summary" v-if="group.summary && group.summary !== '<p></p>'" /> diff --git a/js/src/views/Posts/Edit.vue b/js/src/views/Posts/Edit.vue index 7d1a3182b..8dcb2aadd 100644 --- a/js/src/views/Posts/Edit.vue +++ b/js/src/views/Posts/Edit.vue @@ -64,6 +64,7 @@ required v-model="editablePost.title" id="post-title" + dir="auto" /> </b-field> diff --git a/js/src/views/Search.vue b/js/src/views/Search.vue index 93e7d607c..885368b21 100644 --- a/js/src/views/Search.vue +++ b/js/src/views/Search.vue @@ -20,6 +20,7 @@ id="search" :value="search" @input="debouncedUpdateSearchQuery" + dir="auto" :placeholder=" $t('For instance: London, Taekwondo, Architecture…') " diff --git a/js/tests/unit/specs/components/Post/__snapshots__/PostListItem.spec.ts.snap b/js/tests/unit/specs/components/Post/__snapshots__/PostListItem.spec.ts.snap index 6bbf41328..258a06f7b 100644 --- a/js/tests/unit/specs/components/Post/__snapshots__/PostListItem.spec.ts.snap +++ b/js/tests/unit/specs/components/Post/__snapshots__/PostListItem.spec.ts.snap @@ -1,11 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`PostListItem renders post list item with basic informations 1`] = ` -<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper"> +<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto"> <!----> <div class="title-info-wrapper has-text-grey-dark"> <h3 class="post-minimalist-title">My Blog Post</h3> - <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span class="has-text-grey-dark">Dec 2, 2020</span></p> + <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p> <!----> <!----> </div> @@ -13,11 +13,11 @@ exports[`PostListItem renders post list item with basic informations 1`] = ` `; exports[`PostListItem renders post list item with publisher name 1`] = ` -<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper"> +<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto"> <!----> <div class="title-info-wrapper has-text-grey-dark"> <h3 class="post-minimalist-title">My Blog Post</h3> - <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span class="has-text-grey-dark">Dec 2, 2020</span></p> + <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p> <!----> <p class="post-publisher has-text-grey-dark"><span class="icon"><i class="mdi mdi-account-edit mdi-24px"></i></span> <span>Published by <b class="has-text-weight-medium">An author</b></span></p> </div> @@ -25,11 +25,11 @@ exports[`PostListItem renders post list item with publisher name 1`] = ` `; exports[`PostListItem renders post list item with tags 1`] = ` -<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper"> +<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto"> <!----> <div class="title-info-wrapper has-text-grey-dark"> <h3 class="post-minimalist-title">My Blog Post</h3> - <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span class="has-text-grey-dark">Dec 2, 2020</span></p> + <p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p> <div class="tags" style="display: inline;"><span class="icon"><i class="mdi mdi-tag mdi-24px"></i></span> <span class="tag"><!----><span class="">A tag</span> <!----></span> </div> diff --git a/lib/web/views/utils.ex b/lib/web/views/utils.ex index 93336f44f..ab1dad8b1 100644 --- a/lib/web/views/utils.ex +++ b/lib/web/views/utils.ex @@ -49,11 +49,20 @@ defmodule Mobilizon.Web.Views.Utils do defp do_replacements(index_content, tags, locale) do index_content |> replace_meta(tags) - |> String.replace("<html lang=\"en\">", "<html lang=\"#{locale}\">") + |> String.replace( + "<html lang=\"en\" dir=\"auto\">", + "<html lang=\"#{locale}\" dir=\"#{get_language_direction(locale)}\">" + ) end @spec get_locale(Plug.Conn.t()) :: String.t() def get_locale(%Plug.Conn{assigns: assigns}) do Map.get(assigns, :locale) end + + @ltr_languages ["ar", "ae", "he", "fa", "ku", "ur"] + + @spec get_language_direction(String.t()) :: String.t() + defp get_language_direction(locale) when locale in @ltr_languages, do: "rtl" + defp get_language_direction(_locale), do: "ltr" end