Merge branch 'bugs' into 'master'

More bidi improvements

See merge request framasoft/mobilizon!1101
This commit is contained in:
Thomas Citharel 2021-11-07 20:36:56 +00:00
commit c0dfb1bec6
51 changed files with 171 additions and 118 deletions

View File

@ -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.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 # Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive. # in production as building large stacktraces may be expensive.

View File

@ -165,3 +165,36 @@ p {
.icon { .icon {
vertical-align: middle; 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);
}

View File

@ -1,9 +1,9 @@
<template> <template>
<p> <p>
<a :title="contact" v-if="configLink" :href="configLink.uri">{{ <a dir="auto" :title="contact" v-if="configLink" :href="configLink.uri">{{
configLink.text configLink.text
}}</a> }}</a>
<span v-else-if="contact">{{ contact }}</span> <span dir="auto" v-else-if="contact">{{ contact }}</span>
<span v-else>{{ $t("contact uninformed") }}</span> <span v-else>{{ $t("contact uninformed") }}</span>
</p> </p>
</template> </template>

View File

@ -12,7 +12,7 @@
{{ actor.name || `@${usernameWithDomain(actor)}` }} {{ actor.name || `@${usernameWithDomain(actor)}` }}
</p> </p>
<p class="has-text-grey-dark" v-if="actor.name"> <p class="has-text-grey-dark" v-if="actor.name">
@{{ usernameWithDomain(actor) }} <span dir="ltr">@{{ usernameWithDomain(actor) }}</span>
</p> </p>
<div <div
v-if="full" v-if="full"

View File

@ -36,7 +36,7 @@
<strong :class="{ organizer: commentFromOrganizer }">{{ <strong :class="{ organizer: commentFromOrganizer }">{{
comment.actor.name comment.actor.name
}}</strong> }}</strong>
<small>@{{ usernameWithDomain(comment.actor) }}</small> <small dir="ltr">@{{ usernameWithDomain(comment.actor) }}</small>
</span> </span>
<a v-else class="comment-link" :href="commentURL"> <a v-else class="comment-link" :href="commentURL">
<span>{{ $t("[deleted]") }}</span> <span>{{ $t("[deleted]") }}</span>
@ -128,7 +128,7 @@
<div class="content"> <div class="content">
<span class="first-line"> <span class="first-line">
<strong>{{ currentActor.name }}</strong> <strong>{{ currentActor.name }}</strong>
<small>@{{ currentActor.preferredUsername }}</small> <small dir="ltr">@{{ currentActor.preferredUsername }}</small>
</span> </span>
<br /> <br />
<span class="editor-line"> <span class="editor-line">

View File

@ -25,6 +25,7 @@
:placeholder="$t('e.g. Accessibility, Twitch, PeerTube')" :placeholder="$t('e.g. Accessibility, Twitch, PeerTube')"
id="event-metadata-autocomplete" id="event-metadata-autocomplete"
@select="(option) => addElement(option)" @select="(option) => addElement(option)"
dir="auto"
> >
<template slot-scope="props"> <template slot-scope="props">
<div class="media"> <div class="media">

View File

@ -1,6 +1,7 @@
<template> <template>
<router-link <router-link
class="event-minimalist-card-wrapper" class="event-minimalist-card-wrapper"
dir="auto"
:to="{ name: RouteName.EVENT, params: { uuid: event.uuid } }" :to="{ name: RouteName.EVENT, params: { uuid: event.uuid } }"
> >
<div class="event-preview mr-0 ml-0"> <div class="event-preview mr-0 ml-0">

View File

@ -43,8 +43,8 @@
</router-link> </router-link>
</div> </div>
</div> </div>
<div class="list-card-content" dir="auto"> <div class="list-card-content">
<div class="title-wrapper"> <div class="title-wrapper" dir="auto">
<router-link <router-link
:to="{ :to="{
name: RouteName.EVENT, name: RouteName.EVENT,

View File

@ -35,6 +35,7 @@
v-bind="$attrs" v-bind="$attrs"
:id="id" :id="id"
:disabled="disabled" :disabled="disabled"
dir="auto"
> >
<template #default="{ option }"> <template #default="{ option }">
<b-icon :icon="option.poiInfos.poiIcon.icon" /> <b-icon :icon="option.poiInfos.poiIcon.icon" />

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="list is-hoverable"> <div class="list is-hoverable">
<b-input <b-input
dir="auto"
:placeholder="$t('Filter by profile or group name')" :placeholder="$t('Filter by profile or group name')"
v-model="actorFilter" v-model="actorFilter"
/> />
@ -11,7 +12,7 @@
v-for="availableActor in actualFilteredAvailableActors" v-for="availableActor in actualFilteredAvailableActors"
:key="availableActor.id" :key="availableActor.id"
> >
<div class="media"> <div class="media" dir="auto">
<figure class="image is-48x48" v-if="availableActor.avatar"> <figure class="image is-48x48" v-if="availableActor.avatar">
<img <img
class="media-left is-rounded" class="media-left is-rounded"

View File

@ -4,6 +4,7 @@
<div <div
v-if="inline && selectedActor.id" v-if="inline && selectedActor.id"
class="inline box" class="inline box"
dir="auto"
@click="isComponentModalActive = true" @click="isComponentModalActive = true"
> >
<div class="media"> <div class="media">
@ -65,6 +66,7 @@
<b-input <b-input
:placeholder="$t('Filter by name')" :placeholder="$t('Filter by name')"
v-model="contactFilter" v-model="contactFilter"
dir="auto"
/> />
<p <p
class="field" class="field"

View File

@ -123,8 +123,8 @@ A button to set your participation
@keyup.enter="joinEvent(currentActor)" @keyup.enter="joinEvent(currentActor)"
> >
<div class="media"> <div class="media">
<div class="media-left"> <div class="media-left" v-if="currentActor.avatar">
<figure class="image is-32x32" v-if="currentActor.avatar"> <figure class="image is-32x32">
<img class="is-rounded" :src="currentActor.avatar.url" alt /> <img class="is-rounded" :src="currentActor.avatar.url" alt />
</figure> </figure>
</div> </div>

View File

@ -23,6 +23,7 @@
:placeholder="$t('Eg: Stockholm, Dance, Chess…')" :placeholder="$t('Eg: Stockholm, Dance, Chess…')"
@typing="getFilteredTags" @typing="getFilteredTags"
:id="id" :id="id"
dir="auto"
> >
</b-taginput> </b-taginput>
</b-field> </b-field>

View File

@ -1,6 +1,7 @@
<template> <template>
<router-link <router-link
class="post-minimalist-card-wrapper" class="post-minimalist-card-wrapper"
dir="auto"
:to="{ name: RouteName.POST, params: { slug: post.slug } }" :to="{ name: RouteName.POST, params: { slug: post.slug } }"
> >
<lazy-image-wrapper <lazy-image-wrapper
@ -12,7 +13,7 @@
<h3 class="post-minimalist-title">{{ post.title }}</h3> <h3 class="post-minimalist-title">{{ post.title }}</h3>
<p class="post-publication-date"> <p class="post-publication-date">
<b-icon icon="clock" /> <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") publishedAt | formatDateTimeString(undefined, false, "short")
}}</span> }}</span>
<span v-else>{{ <span v-else>{{

View File

@ -7,6 +7,7 @@
icon="magnify" icon="magnify"
type="search" type="search"
rounded rounded
dir="auto"
:placeholder="defaultPlaceHolder" :placeholder="defaultPlaceHolder"
v-model="search" v-model="search"
@keyup.native.enter="enter" @keyup.native.enter="enter"

View File

@ -0,0 +1,15 @@
<template>
<div>a</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import RouteName from "@/router/name";
@Component
export default class HomepageRedirectComponent extends Vue {
created(): void {
this.$router.replace({ name: RouteName.HOME });
}
}
</script>

View File

@ -29,7 +29,7 @@
"Are you sure you want to cancel your participation at event \"{title}\"?": "هل أنت متأكد مِن أنك تريد الغاء مشاركتك في فعالية \"{title}\"؟", "Are you sure you want to cancel your participation at event \"{title}\"?": "هل أنت متأكد مِن أنك تريد الغاء مشاركتك في فعالية \"{title}\"؟",
"Avatar": "الصورة الرمزية", "Avatar": "الصورة الرمزية",
"Back to previous page": "العودة إلى الصفحة السابقة", "Back to previous page": "العودة إلى الصفحة السابقة",
"By @{username}": "حسب @{username}", "By {username}": "حسب {username}",
"By {username} and {group}": "مِن {username} و {group}", "By {username} and {group}": "مِن {username} و {group}",
"Cancel": "الغاء", "Cancel": "الغاء",
"Cancel creation": "إلغاء الإنشاء", "Cancel creation": "إلغاء الإنشاء",

View File

@ -34,7 +34,7 @@
"Are you sure you want to delete this event? This action cannot be reverted.": "Вы сапраўды хочаце выдаліць гэту падзею? Гэта дзеянне нельга адмяніць.", "Are you sure you want to delete this event? This action cannot be reverted.": "Вы сапраўды хочаце выдаліць гэту падзею? Гэта дзеянне нельга адмяніць.",
"Avatar": "Аватар", "Avatar": "Аватар",
"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}": "Ад @{username}", "By {username}": "Ад {username}",
"Cancel": "Адмяніць", "Cancel": "Адмяніць",
"Cancel creation": "Адмяніць стварэнне", "Cancel creation": "Адмяніць стварэнне",
"Cancel edition": "Адмяніць рэдагаванне", "Cancel edition": "Адмяніць рэдагаванне",

View File

@ -120,8 +120,7 @@
"Begins on": "Comença a", "Begins on": "Comença a",
"Bold": "Negreta", "Bold": "Negreta",
"Browser notifications": "Notificacions de navegador", "Browser notifications": "Notificacions de navegador",
"By @{group}": "De @{group}", "By {username}": "De {username}",
"By @{username}": "De @{username}",
"By others": "Les d'altres", "By others": "Les d'altres",
"By {author}": "De {author}", "By {author}": "De {author}",
"By {group}": "De {group}", "By {group}": "De {group}",

View File

@ -31,7 +31,7 @@
"Avatar": "Avatar", "Avatar": "Avatar",
"Back to previous page": "Zpět na předchozí stránku", "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.", "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": "Zrušit",
"Cancel anonymous participation": "Zrušit anonymní účast", "Cancel anonymous participation": "Zrušit anonymní účast",
"Cancel creation": "Zrušit vytváření", "Cancel creation": "Zrušit vytváření",

View File

@ -118,8 +118,7 @@
"Begins on": "Beginnt um", "Begins on": "Beginnt um",
"Bold": "Fett", "Bold": "Fett",
"Browser notifications": "Browserbenachrichtigungen", "Browser notifications": "Browserbenachrichtigungen",
"By @{group}": "Von @{group}", "By {username}": "von {username}",
"By @{username}": "von @{username}",
"By others": "Von Anderen", "By others": "Von Anderen",
"By {author}": "Von {author}", "By {author}": "Von {author}",
"By {group}": "Von {group}", "By {group}": "Von {group}",

View File

@ -34,7 +34,7 @@
"Avatar": "Avatar", "Avatar": "Avatar",
"Back to previous page": "Back to previous page", "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.", "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 anonymous participation": "Cancel anonymous participation",
"Cancel creation": "Cancel creation", "Cancel creation": "Cancel creation",
"Cancel edition": "Cancel edition", "Cancel edition": "Cancel edition",
@ -418,7 +418,6 @@
"(Masked)": "(Masked)", "(Masked)": "(Masked)",
"{available}/{capacity} available places": "No places left|{available}/{capacity} available places", "{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", "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", "Date and time": "Date and time",
"Location": "Location", "Location": "Location",
"No resources selected": "No resources selected|One resources selected|{count} resources selected", "No resources selected": "No resources selected|One resources selected|{count} resources selected",

View File

@ -146,12 +146,11 @@
"Breadcrumbs": "Migajas", "Breadcrumbs": "Migajas",
"Browser notifications": "Notificaciones del navegador", "Browser notifications": "Notificaciones del navegador",
"Bullet list": "Lista de puntos", "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 @{username} and @{group}": "Por @{username} y @{group}",
"By others": "Por otros", "By others": "Por otros",
"By {author}": "Por {author}", "By {author}": "Por {author}",
"By {group}": "Por {grup}", "By {group}": "Por {group}",
"By {username} and {group}": "Por {username} y {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.", "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", "Cancel": "Cancelar",

View File

@ -33,7 +33,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}": "توسط @{username}", "By {username}": "توسط {username}",
"Cancel": "لغو", "Cancel": "لغو",
"Cancel anonymous participation": "غلو حضور ناشناس", "Cancel anonymous participation": "غلو حضور ناشناس",
"Cancel creation": "لغو ساخت", "Cancel creation": "لغو ساخت",

View File

@ -132,8 +132,7 @@
"Booking": "Varaus", "Booking": "Varaus",
"Breadcrumbs": "Leivänmurut", "Breadcrumbs": "Leivänmurut",
"Browser notifications": "Selaimen ilmoitukset", "Browser notifications": "Selaimen ilmoitukset",
"By @{group}": "Tehnyt @{group}", "By {username}": "Tehnyt {username}",
"By @{username}": "Tehnyt @{username}",
"By others": "Muilta", "By others": "Muilta",
"By {author}": "Tekijä {author}", "By {author}": "Tekijä {author}",
"By {group}": "Tekijä {group}", "By {group}": "Tekijä {group}",

View File

@ -133,8 +133,7 @@
"Breadcrumbs": "Fil d'Ariane", "Breadcrumbs": "Fil d'Ariane",
"Browser notifications": "Notifications du navigateur", "Browser notifications": "Notifications du navigateur",
"Bullet list": "Liste à puce", "Bullet list": "Liste à puce",
"By @{group}": "Par @{group}", "By {username}": "Par {username}",
"By @{username}": "Par @{username}",
"By others": "Des autres", "By others": "Des autres",
"By {author}": "Par {author}", "By {author}": "Par {author}",
"By {group}": "Par {group}", "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 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 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é", "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 event and participate": "Qui peut voir cet événement et y participer",
"Who can view this post": "Qui peut voir ce billet", "Who can view this post": "Qui peut voir ce billet",
"Who published {number} events": "Ayant publié {number} événements", "Who published {number} events": "Ayant publié {number} événements",

View File

@ -132,8 +132,7 @@
"Breadcrumbs": "Breadcrumbs", "Breadcrumbs": "Breadcrumbs",
"Browser notifications": "Brathan a bhrabhsair", "Browser notifications": "Brathan a bhrabhsair",
"Bullet list": "Liosta pheilearaichte", "Bullet list": "Liosta pheilearaichte",
"By @{group}": "Le @{group}", "By {username}": "Le {username}",
"By @{username}": "Le @{username}",
"By others": "Le daoine eile", "By others": "Le daoine eile",
"By {author}": "Le {author}", "By {author}": "Le {author}",
"By {group}": "Le {group}", "By {group}": "Le {group}",

View File

@ -123,8 +123,7 @@
"Bold": "Resaltado", "Bold": "Resaltado",
"Breadcrumbs": "Breadcrumbs", "Breadcrumbs": "Breadcrumbs",
"Browser notifications": "Notificacións do navegador", "Browser notifications": "Notificacións do navegador",
"By @{group}": "Por @{group}", "By {username}": "Por {username}",
"By @{username}": "Por @{username}",
"By others": "Por outras", "By others": "Por outras",
"By {author}": "Por {author}", "By {author}": "Por {author}",
"By {group}": "Por {group}", "By {group}": "Por {group}",

View File

@ -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.", "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", "Begins on": "Ekkor kezdődik",
"Bold": "Félkövér", "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 others": "Másoktól származó",
"By {author}": "{author} által", "By {author}": "{author} által",
"By {group}": "{group} által", "By {group}": "{group} által",

View File

@ -77,8 +77,7 @@
"Big Blue Button": "Big Blue Button", "Big Blue Button": "Big Blue Button",
"Bold": "Tebal", "Bold": "Tebal",
"Browser notifications": "Notifikasi browser", "Browser notifications": "Notifikasi browser",
"By @{group}": "Oleh @{group}", "By {username}": "Oleh {username}",
"By @{username}": "Oleh @{username}",
"By others": "Dari orang lain", "By others": "Dari orang lain",
"By {author}": "Oleh {author}", "By {author}": "Oleh {author}",
"By {group}": "Oleh {group}", "By {group}": "Oleh {group}",

View File

@ -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.", "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", "Begins on": "Comincia a",
"Bold": "Grassetto", "Bold": "Grassetto",
"By @{group}": "Di @{group}", "By {username}": "Da {username}",
"By @{username}": "Da @{username}",
"By {author}": "Da {author}", "By {author}": "Da {author}",
"By {group}": "Da {group}", "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.", "Can be an email or a link, or just plain text.": "Può essere un'email o un collegamento, oppure testo semplice.",

View File

@ -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.", "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", "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.", "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": "Annuleren",
"Cancel creation": "Aanmaken annuleren", "Cancel creation": "Aanmaken annuleren",
"Cancel edition": "Bewerken annuleren", "Cancel edition": "Bewerken annuleren",

View File

@ -135,11 +135,10 @@
"Breadcrumbs": "Navigeringsmerke", "Breadcrumbs": "Navigeringsmerke",
"Browser notifications": "Nettlesarvarsel", "Browser notifications": "Nettlesarvarsel",
"Bullet list": "Punktliste", "Bullet list": "Punktliste",
"By @{group}": "Av @{group}", "By {username}": "Av {username}",
"By @{username}": "Av @{username}",
"By others": "Av andre", "By others": "Av andre",
"By {author}": "Av {author}", "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.", "Can be an email or a link, or just plain text.": "Kan vera ei epostadresse eller ei lenke, eller rein tekst.",
"Cancel": "Avbryt", "Cancel": "Avbryt",
"Cancel anonymous participation": "Avbryt anonym deltaking", "Cancel anonymous participation": "Avbryt anonym deltaking",

View File

@ -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.", "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", "Begins on": "Comença lo",
"Bold": "Gras", "Bold": "Gras",
"By @{group}": "Per @{group}", "By {username}": "Per {username}",
"By @{username}": "Per @{username}",
"By @{username} and @{group}": "Per @{username} e @{group}", "By @{username} and @{group}": "Per @{username} e @{group}",
"By {author}": "Per {author}", "By {author}": "Per {author}",
"By {group}": "Per {group}", "By {group}": "Per {group}",

View File

@ -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.", "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ę", "Begins on": "Zaczyna się",
"Bold": "Pogrubione", "Bold": "Pogrubione",
"By @{group}": "Od @{group}", "By {username}": "Od {username}",
"By @{username}": "Od @{username}",
"By {author}": "Autorstwa {author}", "By {author}": "Autorstwa {author}",
"By {group}": "Autorstwa {group}", "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.", "Can be an email or a link, or just plain text.": "Może być adresem e-mail, odnośnikiem lub zwykłym tekstem.",

View File

@ -33,7 +33,7 @@
"Avatar": "Avatar", "Avatar": "Avatar",
"Back to previous page": "Voltar à página anterior", "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.", "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": "Cancelar",
"Cancel anonymous participation": "Cancelar participação anónima", "Cancel anonymous participation": "Cancelar participação anónima",
"Cancel creation": "Aborto", "Cancel creation": "Aborto",

View File

@ -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.", "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", "Begins on": "Começa às",
"Bold": "Negrito", "Bold": "Negrito",
"By @{group}": "Por @{group}", "By {username}": "Por {username}",
"By @{username}": "Por @{username}",
"By {author}": "Por {author}", "By {author}": "Por {author}",
"By {group}": "Por {group}", "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.", "Can be an email or a link, or just plain text.": "Pode ser um email ou um link, ou apenas um texto simples.",

View File

@ -133,8 +133,7 @@
"Breadcrumbs": "Хлебные крошки", "Breadcrumbs": "Хлебные крошки",
"Browser notifications": "Уведомления в браузере", "Browser notifications": "Уведомления в браузере",
"Bullet list": "Маркированный список", "Bullet list": "Маркированный список",
"By @{group}": "Из @{group}", "By {username}": "От {username}",
"By @{username}": "От @{username}",
"By others": "Другими", "By others": "Другими",
"By {author}": "Автор {author}", "By {author}": "Автор {author}",
"By {group}": "Автор: {group}", "By {group}": "Автор: {group}",

View File

@ -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.", "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", "Begins on": "Začne se v",
"Bold": "Krepko", "Bold": "Krepko",
"By @{group}": "Avtor @{group}", "By {username}": "Od {username}",
"By @{username}": "Od @{username}",
"By others": "Od drugih", "By others": "Od drugih",
"By {author}": "Od {author}", "By {author}": "Od {author}",
"By {group}": "Od {group}", "By {group}": "Od {group}",

View File

@ -39,8 +39,8 @@
"Avatar": "Avatar", "Avatar": "Avatar",
"Back to previous page": "Tillbaka till föregående sida", "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.", "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 {group}": "Av {group}",
"By @{username}": "Av @{username}", "By {username}": "Av {username}",
"By {username} and {group}": "Av {username} och {group}", "By {username} and {group}": "Av {username} och {group}",
"Cancel": "Avbryt", "Cancel": "Avbryt",
"Cancel anonymous participation": "Avbryt anonymt deltagande", "Cancel anonymous participation": "Avbryt anonymt deltagande",

View File

@ -13,7 +13,7 @@ import { groupsRoutes } from "./groups";
import { discussionRoutes } from "./discussion"; import { discussionRoutes } from "./discussion";
import { userRoutes } from "./user"; import { userRoutes } from "./user";
import RouteName from "./name"; import RouteName from "./name";
import { i18n } from "@/utils/i18n"; import { AVAILABLE_LANGUAGES, i18n } from "@/utils/i18n";
Vue.use(Router); Vue.use(Router);
@ -183,11 +183,22 @@ export const routes = [
announcer: { message: (): string => i18n.t("Page not found") as string }, announcer: { message: (): string => i18n.t("Page not found") as string },
}, },
}, },
{ ];
for (const locale of AVAILABLE_LANGUAGES) {
routes.push({
path: `/${locale}`,
component: (): Promise<ImportedComponent> =>
import(
/* webpackChunkName: "HomepageRedirectComponent" */ "../components/Utils/HomepageRedirectComponent.vue"
),
});
}
routes.push({
path: "*", path: "*",
redirect: { name: RouteName.PAGE_NOT_FOUND }, redirect: { name: RouteName.PAGE_NOT_FOUND },
}, });
];
const router = new Router({ const router = new Router({
scrollBehavior, scrollBehavior,

View File

@ -10,6 +10,8 @@ const DEFAULT_LOCALE = "en_US";
const localeInLocalStorage = getLocaleData(); const localeInLocalStorage = getLocaleData();
export const AVAILABLE_LANGUAGES = Object.keys(langs);
console.debug("localeInLocalStorage", localeInLocalStorage); console.debug("localeInLocalStorage", localeInLocalStorage);
let language = let language =
@ -67,6 +69,12 @@ function setLanguageInDOM(lang: string): void {
if (documentLang !== fixedLang) { if (documentLang !== fixedLang) {
html.setAttribute("lang", 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) { function fileForLanguage(matches: Record<string, string>, lang: string) {

View File

@ -3,8 +3,8 @@
<section class="hero is-primary"> <section class="hero is-primary">
<div class="hero-body"> <div class="hero-body">
<div class="container"> <div class="container">
<h1 class="title">{{ config.name }}</h1> <h1 class="title" dir="auto">{{ config.name }}</h1>
<p>{{ config.description }}</p> <p dir="auto">{{ config.description }}</p>
</div> </div>
</div> </div>
</section> </section>

View File

@ -28,6 +28,7 @@
required required
v-model="event.title" v-model="event.title"
id="title" id="title"
dir="auto"
/> />
</b-field> </b-field>

View File

@ -7,7 +7,7 @@
<div class="date-calendar-icon-wrapper"> <div class="date-calendar-icon-wrapper">
<date-calendar-icon :date="event.beginsOn" /> <date-calendar-icon :date="event.beginsOn" />
</div> </div>
<section class="intro"> <section class="intro" dir="auto">
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<h1 class="title" style="margin: 0" dir="auto"> <h1 class="title" style="margin: 0" dir="auto">
@ -19,57 +19,24 @@
:actor="event.organizerActor" :actor="event.organizerActor"
:inline="true" :inline="true"
> >
<span> <i18n path="By {username}" dir="auto">
{{ <span dir="ltr" slot="username"
$t("By @{username}", { >@{{ usernameWithDomain(event.organizerActor) }}</span
username: usernameWithDomain(event.organizerActor), >
}) </i18n>
}}
</span>
</popover-actor-card> </popover-actor-card>
</div> </div>
<span <span v-else-if="event.attributedTo">
v-else-if="
event.attributedTo &&
event.options.hideOrganizerWhenGroupEvent
"
>
<popover-actor-card <popover-actor-card
:actor="event.attributedTo" :actor="event.attributedTo"
:inline="true" :inline="true"
> >
{{ <i18n path="By {group}" dir="auto">
$t("By @{group}", { <span dir="ltr" slot="group"
group: usernameWithDomain(event.attributedTo), >@{{ usernameWithDomain(event.attributedTo) }}</span
})
}}
</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
),
},
}"
>
{{
$t("@{group}", {
group: usernameWithDomain(event.attributedTo),
})
}}
</router-link>
</popover-actor-card>
</i18n> </i18n>
</popover-actor-card>
</span> </span>
</div> </div>
<p <p

View File

@ -60,7 +60,10 @@
<div class="title-container"> <div class="title-container">
<h1 v-if="group.name">{{ group.name }}</h1> <h1 v-if="group.name">{{ group.name }}</h1>
<b-skeleton v-else :animated="true" /> <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 >@{{ usernameWithDomain(group) }}</small
> >
<b-skeleton v-else :animated="true" /> <b-skeleton v-else :animated="true" />
@ -503,7 +506,7 @@
}}</span> }}</span>
<div class="address" v-if="physicalAddress"> <div class="address" v-if="physicalAddress">
<div> <div>
<address> <address dir="auto">
<p <p
class="addressDescription" class="addressDescription"
:title="physicalAddress.poiInfos.name" :title="physicalAddress.poiInfos.name"
@ -533,6 +536,7 @@
<section> <section>
<subtitle>{{ $t("About") }}</subtitle> <subtitle>{{ $t("About") }}</subtitle>
<div <div
dir="auto"
v-html="group.summary" v-html="group.summary"
v-if="group.summary && group.summary !== '<p></p>'" v-if="group.summary && group.summary !== '<p></p>'"
/> />

View File

@ -64,6 +64,7 @@
required required
v-model="editablePost.title" v-model="editablePost.title"
id="post-title" id="post-title"
dir="auto"
/> />
</b-field> </b-field>

View File

@ -20,6 +20,7 @@
id="search" id="search"
:value="search" :value="search"
@input="debouncedUpdateSearchQuery" @input="debouncedUpdateSearchQuery"
dir="auto"
:placeholder=" :placeholder="
$t('For instance: London, Taekwondo, Architecture…') $t('For instance: London, Taekwondo, Architecture…')
" "

View File

@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PostListItem renders post list item with basic informations 1`] = ` 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"> <div class="title-info-wrapper has-text-grey-dark">
<h3 class="post-minimalist-title">My Blog Post</h3> <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> </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`] = ` 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"> <div class="title-info-wrapper has-text-grey-dark">
<h3 class="post-minimalist-title">My Blog Post</h3> <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> <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> </div>
@ -25,11 +25,11 @@ exports[`PostListItem renders post list item with publisher name 1`] = `
`; `;
exports[`PostListItem renders post list item with tags 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"> <div class="title-info-wrapper has-text-grey-dark">
<h3 class="post-minimalist-title">My Blog Post</h3> <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> <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> <!----></span>
</div> </div>

View File

@ -18,11 +18,13 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
def call(conn, _) do def call(conn, _) do
locale = locale =
[ [
eventual_path_locale(conn.path_info),
conn.assigns[:user_locale], conn.assigns[:user_locale],
conn.assigns[:detected_locale], conn.assigns[:detected_locale],
default_locale(), default_locale(),
"en" "en"
] ]
|> Enum.filter(& &1)
|> Enum.map(&determine_best_locale/1) |> Enum.map(&determine_best_locale/1)
|> Enum.filter(&supported_locale?/1) |> Enum.filter(&supported_locale?/1)
|> hd() |> hd()
@ -31,6 +33,15 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
assign(conn, :locale, locale) assign(conn, :locale, locale)
end end
defp eventual_path_locale(path_info) do
with [locale] <- path_info,
true <- supported_locale?(locale) do
locale
else
_ -> nil
end
end
@spec supported_locale?(String.t()) :: boolean() @spec supported_locale?(String.t()) :: boolean()
defp supported_locale?(locale) do defp supported_locale?(locale) do
GettextBackend GettextBackend

View File

@ -49,11 +49,20 @@ defmodule Mobilizon.Web.Views.Utils do
defp do_replacements(index_content, tags, locale) do defp do_replacements(index_content, tags, locale) do
index_content index_content
|> replace_meta(tags) |> replace_meta(tags)
|> String.replace("<html lang=\"en\">", "<html lang=\"#{locale}\">") |> String.replace(
~s(<html lang="en" dir="auto">),
~s(<html lang="#{locale}" dir="#{get_language_direction(locale)}">)
)
end end
@spec get_locale(Plug.Conn.t()) :: String.t() @spec get_locale(Plug.Conn.t()) :: String.t()
def get_locale(%Plug.Conn{assigns: assigns}) do def get_locale(%Plug.Conn{assigns: assigns}) do
Map.get(assigns, :locale) Map.get(assigns, :locale)
end 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 end