Allow to change language

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2020-06-16 18:00:27 +02:00
parent 08b4fb9b08
commit 5cb3f478ae
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
8 changed files with 110 additions and 9 deletions

View file

@ -106,6 +106,7 @@ export const USER_SETTINGS_FRAGMENT = gql`
export const USER_SETTINGS = gql` export const USER_SETTINGS = gql`
query UserSetting { query UserSetting {
loggedUser { loggedUser {
locale
settings { settings {
...UserSettingFragment ...UserSettingFragment
} }
@ -189,3 +190,12 @@ export const GET_USER = gql`
} }
} }
`; `;
export const UPDATE_USER_LOCALE = gql`
mutation UpdateUserLocale($locale: String!) {
updateLocale(locale: $locale) {
id
locale
}
}
`;

View file

@ -644,5 +644,6 @@
"more than 1360 contributors": "more than 1360 contributors", "more than 1360 contributors": "more than 1360 contributors",
"{moderator} has unsuspended profile {profile}": "{moderator} has unsuspended profile {profile}", "{moderator} has unsuspended profile {profile}": "{moderator} has unsuspended profile {profile}",
"{moderator} has deleted user {user}": "{moderator} has deleted user {user}", "{moderator} has deleted user {user}": "{moderator} has deleted user {user}",
"Change timezone": "Change timezone" "Change timezone": "Change timezone",
"Select a language": "Select a language"
} }

View file

@ -667,5 +667,6 @@
"more than 1360 contributors": "plus de 1360 contributeur·ices", "more than 1360 contributors": "plus de 1360 contributeur·ices",
"{moderator} has unsuspended profile {profile}": "{moderator} a annulé la suspension de {profile}", "{moderator} has unsuspended profile {profile}": "{moderator} a annulé la suspension de {profile}",
"{moderator} has deleted user {user}": "{moderator} a supprimé l'utilisateur·ice {user}", "{moderator} has deleted user {user}": "{moderator} a supprimé l'utilisateur·ice {user}",
"Change timezone": "Changer de fuseau horaire" "Change timezone": "Changer de fuseau horaire",
"Select a language": "Choisissez une langue"
} }

30
js/src/i18n/langs.json Normal file
View file

@ -0,0 +1,30 @@
{
"ar": "العربية",
"bg": "Български",
"be": "Беларуская мова",
"br": "Brezhoneg",
"ca": "Català",
"co": "Corsu",
"cs": "čeština",
"de": "Deutsch",
"en": "English",
"eo": "Esperanto",
"es": "Español",
"fi": "suomi",
"fr": "Français",
"gl": "Galego",
"hu": "Magyar",
"it": "Italiano",
"ja": "日本語",
"nl": "Dutch",
"oc": "Occitan",
"pl": "Polski",
"pt": "Português",
"pt_PT": "Português (Portugal)",
"ru": "Русский",
"sq": "Shqip",
"sv": "Svenska",
"tr": "Türkçe",
"vi": "Tiếng Việt",
"zh_Hant_TW": "繁體中文(台灣)"
}

View file

@ -17,12 +17,12 @@ export interface ICurrentUser {
defaultActor: IPerson; defaultActor: IPerson;
drafts: IEvent[]; drafts: IEvent[];
settings: IUserSettings; settings: IUserSettings;
locale: string;
} }
export interface IUser extends ICurrentUser { export interface IUser extends ICurrentUser {
confirmedAt: Date; confirmedAt: Date;
confirmationSendAt: Date; confirmationSendAt: Date;
locale: String;
actors: IPerson[]; actors: IPerson[];
disabled: boolean; disabled: boolean;
} }

View file

@ -1,5 +1,16 @@
<template> <template>
<div> <div>
<b-field :label="$t('Language')">
<b-select
:loading="!config || !loggedUser"
v-model="$i18n.locale"
:placeholder="$t('Select a language')"
>
<option v-for="(language, lang) in languages" :value="lang" :key="lang">
{{ language }}
</option>
</b-select>
</b-field>
<b-field :label="$t('Timezone')"> <b-field :label="$t('Timezone')">
<b-select <b-select
:placeholder="$t('Select a timezone')" :placeholder="$t('Select a timezone')"
@ -17,19 +28,20 @@
</optgroup> </optgroup>
</b-select> </b-select>
</b-field> </b-field>
<span>{{ <em>{{
$t("Timezone detected as {timezone}.", { $t("Timezone detected as {timezone}.", {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}) })
}}</span> }}</em>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator"; import { Component, Vue, Watch } from "vue-property-decorator";
import { TIMEZONES } from "../../graphql/config"; import { TIMEZONES } from "../../graphql/config";
import { USER_SETTINGS, SET_USER_SETTINGS } from "../../graphql/user"; import { USER_SETTINGS, SET_USER_SETTINGS, UPDATE_USER_LOCALE } from "../../graphql/user";
import { IConfig } from "../../types/config.model"; import { IConfig } from "../../types/config.model";
import { ICurrentUser } from "../../types/current-user.model"; import { ICurrentUser } from "../../types/current-user.model";
import langs from "../../i18n/langs.json";
@Component({ @Component({
apollo: { apollo: {
@ -44,6 +56,8 @@ export default class Preferences extends Vue {
selectedTimezone: string | null = null; selectedTimezone: string | null = null;
locale: string | null = null;
@Watch("loggedUser") @Watch("loggedUser")
setSavedTimezone(loggedUser: ICurrentUser) { setSavedTimezone(loggedUser: ICurrentUser) {
if (loggedUser && loggedUser.settings.timezone) { if (loggedUser && loggedUser.settings.timezone) {
@ -51,6 +65,11 @@ export default class Preferences extends Vue {
} else { } else {
this.selectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; this.selectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
} }
if (loggedUser && loggedUser.locale) {
this.locale = loggedUser.locale;
} else {
this.locale = this.$i18n.locale;
}
} }
sanitize(timezone: string): string { sanitize(timezone: string): string {
@ -77,8 +96,23 @@ export default class Preferences extends Vue {
}, {}); }, {});
} }
get languages(): object {
return this.$i18n.availableLocales.reduce((acc: object, lang: string) => {
// @ts-ignore
if (langs[lang]) {
return {
...acc,
// @ts-ignore
[lang]: langs[lang],
};
}
return acc;
}, {} as object);
}
@Watch("selectedTimezone") @Watch("selectedTimezone")
async updateTimezone() { async updateTimezone() {
if (this.selectedTimezone !== this.loggedUser.settings.timezone) {
await this.$apollo.mutate<{ setUserSetting: string }>({ await this.$apollo.mutate<{ setUserSetting: string }>({
mutation: SET_USER_SETTINGS, mutation: SET_USER_SETTINGS,
variables: { variables: {
@ -87,4 +121,15 @@ export default class Preferences extends Vue {
}); });
} }
} }
@Watch("$i18n.locale")
async updateLocale() {
await this.$apollo.mutate({
mutation: UPDATE_USER_LOCALE,
variables: {
locale: this.$i18n.locale,
},
});
}
}
</script> </script>

View file

@ -477,4 +477,13 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
{:error, "Error while saving user setting"} {:error, "Error while saving user setting"}
end end
end end
def update_locale(_parent, %{locale: locale}, %{
context: %{current_user: %User{id: logged_user_id, locale: current_locale} = user}
}) do
with true == current_locale != locale,
{:ok, %User{} = updated_user} <- Users.update_user(user, %{locale: locale}) do
{:ok, updated_user}
end
end
end end

View file

@ -250,5 +250,10 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
arg(:notification_pending_participation, :notification_pending_participation_enum) arg(:notification_pending_participation, :notification_pending_participation_enum)
resolve(&User.set_user_setting/3) resolve(&User.set_user_setting/3)
end end
field :update_locale, :user do
arg(:locale, :string)
resolve(&User.update_locale/3)
end
end end
end end