1
0
Fork 0
mirror of https://github.com/mastodon/mastodon.git synced 2024-08-20 21:08:15 -07:00

Add a way for the user to select which languages they understand

Closes #29989
This commit is contained in:
Adam Niedzielski 2024-07-30 14:52:01 +02:00
parent dfd43869c9
commit e955a580fa
No known key found for this signature in database
GPG key ID: D97FC2C798BAC058
11 changed files with 42 additions and 12 deletions

View file

@ -19,6 +19,6 @@ class Settings::Preferences::BaseController < Settings::BaseController
end
def user_params
params.require(:user).permit(:locale, :time_zone, chosen_languages: [], settings_attributes: UserSettings.keys)
params.require(:user).permit(:locale, :time_zone, spoken_languages: [], chosen_languages: [], settings_attributes: UserSettings.keys)
end
end

View file

@ -13,7 +13,7 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'
import { Icon } from 'mastodon/components/icon';
import PollContainer from 'mastodon/containers/poll_container';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
import { autoPlayGif, spokenLanguages, languages as preloadedLanguages } from 'mastodon/initial_state';
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
@ -237,6 +237,10 @@ class StatusContent extends PureComponent {
this.node = c;
};
spokenByUser() {
return spokenLanguages.includes(this.props.status.get('language'));
};
render () {
const { status, intl, statusContent } = this.props;
@ -244,7 +248,7 @@ class StatusContent extends PureComponent {
const renderReadMore = this.props.onClick && status.get('collapsed');
const contentLocale = intl.locale.replace(/[_-].*/, '');
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && !this.spokenByUser() && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
const content = { __html: statusContent ?? getStatusContent(status) };
const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') };

View file

@ -13,7 +13,7 @@ import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import TranslateIcon from '@/material-icons/400-24px/translate.svg?react';
import { Icon } from 'mastodon/components/icon';
import { languages as preloadedLanguages } from 'mastodon/initial_state';
import { spokenLanguages, languages as preloadedLanguages } from 'mastodon/initial_state';
const messages = defineMessages({
changeLanguage: { id: 'compose.language.change', defaultMessage: 'Change language' },
@ -84,6 +84,9 @@ class LanguageDropdownMenu extends PureComponent {
const { languages, value, frequentlyUsedLanguages } = this.props;
const { searchValue } = this.state;
// first show spoken languages and then frequently used
const orderedLanguages = spokenLanguages.concat(frequentlyUsedLanguages.filter((item) => spokenLanguages.indexOf(item) < 0));
if (searchValue === '') {
return [...languages].sort((a, b) => {
// Push current selection to the top of the list
@ -93,10 +96,8 @@ class LanguageDropdownMenu extends PureComponent {
} else if (b[0] === value) {
return 1;
} else {
// Sort according to frequently used languages
const indexOfA = frequentlyUsedLanguages.indexOf(a[0]);
const indexOfB = frequentlyUsedLanguages.indexOf(b[0]);
const indexOfA = orderedLanguages.indexOf(a[0]);
const indexOfB = orderedLanguages.indexOf(b[0]);
return ((indexOfA > -1 ? indexOfA : Infinity) - (indexOfB > -1 ? indexOfB : Infinity));
}

View file

@ -118,6 +118,7 @@ export const criticalUpdatesPending = initialState?.critical_updates_pending;
// @ts-expect-error
export const statusPageUrl = getMeta('status_page_url');
export const sso_redirect = getMeta('sso_redirect');
export const spokenLanguages = getMeta('spoken_languages');
/**
* @returns {string | undefined}

View file

@ -40,6 +40,7 @@
# settings :text
# time_zone :string
# otp_secret :string
# spoken_languages :string default([]), not null, is an Array
#
class User < ApplicationRecord
@ -134,6 +135,7 @@ class User < ApplicationRecord
normalizes :locale, with: ->(locale) { I18n.available_locales.exclude?(locale.to_sym) ? nil : locale }
normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone }
normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence }
normalizes :spoken_languages, with: ->(spoken_languages) { spoken_languages.compact_blank }
has_many :session_activations, dependent: :destroy

View file

@ -29,6 +29,7 @@ class InitialStateSerializer < ActiveModel::Serializer
store[:use_blurhash] = object_account_user.setting_use_blurhash
store[:use_pending_items] = object_account_user.setting_use_pending_items
store[:show_trends] = Setting.trends && object_account_user.setting_trends
store[:spoken_languages] = object_account_user.spoken_languages
else
store[:auto_play_gif] = Setting.auto_play_gif
store[:display_media] = Setting.display_media

View file

@ -44,7 +44,7 @@
label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'),
wrapper: :with_label
%h4= t 'preferences.public_timelines'
%h4= t 'preferences.languages'
.fields-group
= f.input :chosen_languages,
@ -57,5 +57,16 @@
required: false,
wrapper: :with_block_label
.fields-group
= f.input :spoken_languages,
as: :check_boxes,
collection_wrapper_tag: 'ul',
collection: filterable_languages,
include_blank: false,
item_wrapper_tag: 'li',
label_method: ->(locale) { native_locale_name(locale) },
required: false,
wrapper: :with_block_label
.actions
= f.button :button, t('generic.save_changes'), type: :submit

View file

@ -1544,9 +1544,9 @@ en:
too_few_options: must have more than one item
too_many_options: can't contain more than %{max} items
preferences:
languages: Languages
other: Other
posting_defaults: Posting defaults
public_timelines: Public timelines
privacy:
hint_html: "<strong>Customize how you want your profile and your posts to be found.</strong> A variety of features in Mastodon can help you reach a wider audience when enabled. Take a moment to review these settings to make sure they fit your use case."
privacy: Privacy

View file

@ -131,6 +131,7 @@ en:
user:
chosen_languages: When checked, only posts in selected languages will be displayed in public timelines
role: The role controls which permissions the user has
spoken_languages: Mastodon will not suggest to translate statuses in the languages that you speak
user_role:
color: Color to be used for the role throughout the UI, as RGB in hex format
highlighted: This makes the role publicly visible
@ -181,7 +182,7 @@ en:
autofollow: Invite to follow your account
avatar: Profile picture
bot: This is an automated account
chosen_languages: Filter languages
chosen_languages: Filter languages in public timelines
confirm_new_password: Confirm new password
confirm_password: Confirm password
context: Filter contexts
@ -228,6 +229,7 @@ en:
setting_use_pending_items: Slow mode
severity: Severity
sign_in_token_attempt: Security code
spoken_languages: Languages that you can speak
title: Title
type: Import type
username: Username

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddSpokenLanguagesToUsers < ActiveRecord::Migration[7.1]
def change
add_column :users, :spoken_languages, :string, array: true, null: false, default: []
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_07_24_181224) do
ActiveRecord::Schema[7.1].define(version: 2024_07_29_134058) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -1205,6 +1205,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_24_181224) do
t.text "settings"
t.string "time_zone"
t.string "otp_secret"
t.string "spoken_languages", default: [], null: false, array: true
t.index ["account_id"], name: "index_users_on_account_id"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)"