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.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.

View file

@ -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);
}

View file

@ -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>

View file

@ -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"

View file

@ -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">

View file

@ -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">

View file

@ -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">

View file

@ -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,

View file

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

View file

@ -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"

View file

@ -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"

View file

@ -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>

View file

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

View file

@ -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>{{

View file

@ -7,6 +7,7 @@
icon="magnify"
type="search"
rounded
dir="auto"
:placeholder="defaultPlaceHolder"
v-model="search"
@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}\"؟",
"Avatar": "الصورة الرمزية",
"Back to previous page": "العودة إلى الصفحة السابقة",
"By @{username}": "حسب @{username}",
"By {username}": "حسب {username}",
"By {username} and {group}": "مِن {username} و {group}",
"Cancel": "الغاء",
"Cancel creation": "إلغاء الإنشاء",

View file

@ -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": "Адмяніць рэдагаванне",

View file

@ -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}",

View file

@ -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í",

View file

@ -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}",

View file

@ -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",

View file

@ -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",

View file

@ -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": "لغو ساخت",

View file

@ -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}",

View file

@ -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",

View file

@ -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}",

View file

@ -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}",

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.",
"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",

View file

@ -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}",

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.",
"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.",

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.",
"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",

View file

@ -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",

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.",
"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}",

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.",
"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.",

View file

@ -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",

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.",
"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.",

View file

@ -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}",

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.",
"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}",

View file

@ -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",

View file

@ -13,7 +13,7 @@ import { groupsRoutes } from "./groups";
import { discussionRoutes } from "./discussion";
import { userRoutes } from "./user";
import RouteName from "./name";
import { i18n } from "@/utils/i18n";
import { AVAILABLE_LANGUAGES, i18n } from "@/utils/i18n";
Vue.use(Router);
@ -183,11 +183,22 @@ export const routes = [
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: "*",
redirect: { name: RouteName.PAGE_NOT_FOUND },
},
];
});
const router = new Router({
scrollBehavior,

View file

@ -10,6 +10,8 @@ const DEFAULT_LOCALE = "en_US";
const localeInLocalStorage = getLocaleData();
export const AVAILABLE_LANGUAGES = Object.keys(langs);
console.debug("localeInLocalStorage", localeInLocalStorage);
let language =
@ -67,6 +69,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) {

View file

@ -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>

View file

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

View file

@ -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"
<i18n path="By {group}" dir="auto">
<span dir="ltr" slot="group"
>@{{ usernameWithDomain(event.attributedTo) }}</span
>
<router-link
:to="{
name: RouteName.GROUP,
params: {
preferredUsername: usernameWithDomain(
event.attributedTo
),
},
}"
>
{{
$t("@{group}", {
group: usernameWithDomain(event.attributedTo),
})
}}
</router-link>
</popover-actor-card>
</i18n>
</popover-actor-card>
</span>
</div>
<p

View file

@ -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>'"
/>

View file

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

View file

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

View file

@ -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>

View file

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

View file

@ -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(
~s(<html lang="en" dir="auto">),
~s(<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