Translate theme and notif settings

This commit is contained in:
MartinBraquet
2026-01-02 14:41:55 +02:00
parent c408d895b1
commit 8712424b89
5 changed files with 59 additions and 34 deletions

View File

@@ -10,6 +10,7 @@ import {api} from "web/lib/api";
import {MultiSelectAnswers} from "web/components/answers/answer-compatibility-question-content";
import {PrivateUser} from "common/user";
import {WithPrivateUser} from "web/components/user/with-user";
import {useT} from 'web/lib/locale'
export const NotificationSettings = () => (
<WithPrivateUser>
@@ -27,6 +28,8 @@ function LoadedNotificationSettings(props: {
'notification-preferences'
)
const t = useT()
const notificationTypes: {
type: notification_preference
question: string
@@ -34,11 +37,11 @@ function LoadedNotificationSettings(props: {
{
type: 'new_match',
question:
'... matches with you?',
t('notifications.question.new_match', '... matches with you?'),
},
{
type: 'new_message',
question: '... sends you a new message?',
question: t('notifications.question.new_message', '... sends you a new message?'),
},
// {
// type: 'new_profile_like',
@@ -46,7 +49,7 @@ function LoadedNotificationSettings(props: {
// },
{
type: 'new_endorsement',
question: '... endorses you?',
question: t('notifications.question.new_endorsement', '... endorses you?'),
},
// {
// type: 'new_profile_ship',
@@ -54,7 +57,7 @@ function LoadedNotificationSettings(props: {
// },
{
type: 'tagged_user',
question: '... mentions you?',
question: t('notifications.question.tagged_user', '... mentions you?'),
},
// {
// type: 'on_new_follow',
@@ -62,19 +65,19 @@ function LoadedNotificationSettings(props: {
// },
{
type: 'new_search_alerts',
question: 'Alerts from bookmarked searches?',
question: t('notifications.question.new_search_alerts', 'Alerts from bookmarked searches?'),
},
{
type: 'opt_out_all',
question:
'Opt out of all notifications? (You can always change this later)',
t('notifications.question.opt_out_all', 'Opt out of all notifications? (You can always change this later)'),
},
]
return (
<div className="mx-auto max-w-2xl">
<div className="flex flex-col gap-8 p-4">
<p className="text-ink-700 font-medium">Where do you want to be notified when someone</p>
<p className="text-ink-700 font-medium">{t('notifications.heading', 'Where do you want to be notified when someone')}</p>
{notificationTypes.map(({type, question}) => (
<NotificationOption
key={type}
@@ -98,6 +101,7 @@ const NotificationOption = (props: {
onUpdate: (selected: notification_destination_types[]) => void
}) => {
const {type, question, selected, onUpdate} = props
const t = useT()
const getSelectedValues = (destinations: string[]) => {
const values: number[] = []
@@ -144,7 +148,10 @@ const NotificationOption = (props: {
<div className="flex flex-col gap-2">
<div className="text-ink-700 font-medium">{question}</div>
<MultiSelectAnswers
options={['By email', 'On notifications page']}
options={[
t('notifications.options.email', 'By email'),
t('notifications.options.page', 'On notifications page'),
]}
values={getSelectedValues(selected)}
setValue={setValue}
/>

View File

@@ -2,24 +2,26 @@ import {MoonIcon, SunIcon} from "@heroicons/react/outline"
import clsx from "clsx"
import {useTheme} from "web/hooks/use-theme"
import {Row} from "web/components/layout/row";
import {useT} from 'web/lib/locale'
export default function ThemeIcon(props: {
className?: string
}) {
const {className} = props
const {theme, setTheme} = useTheme()
const t = useT()
const toggleTheme = () => {
setTheme(theme === 'auto' ? 'dark' : theme === 'dark' ? 'light' : 'auto')
}
const children = theme === 'light' ? (
'Light'
t('theme.light', 'Light')
) : theme === 'dark' ? (
'Dark'
t('theme.dark', 'Dark')
) : (
<>
<span className="hidden dark:inline">Dark</span>
<span className="inline dark:hidden">Light</span> (auto)
<span className="hidden dark:inline">{t('theme.dark', 'Dark')}</span>
<span className="inline dark:hidden">{t('theme.light', 'Light')}</span> ({t('theme.auto', 'auto')})
</>
)
const icon = <>
@@ -27,12 +29,9 @@ export default function ThemeIcon(props: {
<SunIcon className={clsx(className, 'block dark:hidden')}/>
</>
return <button onClick={toggleTheme}>
<Row className="items-center gap-1 border-2 border-gray-500 rounded-full p-1 max-w-fit mx-2">
<Row className="items-center gap-1 border-2 border-gray-500 rounded-full p-1 max-w-fit mx-2 px-3">
{icon}
{children}
</Row>
</button>
}

View File

@@ -2,6 +2,9 @@
"settings.title": "Paramètres",
"settings.tabs.general": "Général",
"settings.tabs.notifications": "Notifications",
"theme.light": "Clair",
"theme.dark": "Sombre",
"theme.auto": "Automatique",
"settings.tabs.about": "À propos",
"settings.general.theme": "Thème",
"settings.general.language": "Langue",
@@ -94,6 +97,15 @@
"about.suggestions.title": "Faire des suggestions ou contribuer",
"about.suggestions.text": "Faites des suggestions ou dites-nous que vous voulez aider via ce formulaire !",
"about.suggestions.button": "Suggérer ici",
"notifications.heading": "Où voulez-vous être notifié lorsqu'une personne",
"notifications.question.new_match": "... correspond avec vous ?",
"notifications.question.new_message": "... vous envoie un nouveau message ?",
"notifications.question.new_endorsement": "... vous recommande ?",
"notifications.question.tagged_user": "... vous mentionne ?",
"notifications.question.new_search_alerts": "Recevoir les alertes des recherches enregistrées ?",
"notifications.question.opt_out_all": "Se désabonner de toutes les notifications ? (Vous pouvez toujours modifier cela plus tard)",
"notifications.options.email": "Par email",
"notifications.options.page": "Sur la page des notifications",
"about.dev.title": "Développer l'application",
"about.dev.text": "Le code source complet et les instructions sont disponibles sur GitHub.",
"about.dev.button": "Voir le code",
@@ -393,5 +405,10 @@
"help.security.paragraph_suffix": " pour les détails et les moyens de nous contacter.",
"help.need_help.title": "Besoin d'aide ?",
"help.actions.contact_button": "Nous contacter",
"help.actions.faq_button": "Consulter la FAQ"
"help.actions.faq_button": "Consulter la FAQ",
"messages.title": "Messages",
"messages.seo.description": "Vos messages",
"messages.empty": "Vous n'avez pas encore de messages.",
"messages.more": " de plus",
"messages.you_prefix": "Vous : "
}

View File

@@ -20,26 +20,29 @@ import {MultipleOrSingleAvatars} from 'web/components/multiple-or-single-avatars
import {BannedBadge} from 'web/components/widgets/user-link'
import {PrivateMessageChannel} from 'common/supabase/private-messages'
import {SEO} from "web/components/SEO";
import {useT} from 'web/lib/locale'
export default function MessagesPage() {
useRedirectIfSignedOut()
const currentUser = useUser()
const t = useT()
return (
<PageBase trackPageView={'messages page'} className={'p-2'}>
<SEO
title={'Messages'}
description={'Your Messages'}
title={t('messages.title', 'Messages')}
description={t('messages.seo.description', 'Your Messages')}
url={`/messages`}
/>
{currentUser && <MessagesContent currentUser={currentUser}/>}
{currentUser && <MessagesContent currentUser={currentUser}/>}
</PageBase>
)
}
export function MessagesContent(props: { currentUser: User }) {
const {currentUser} = props
const t = useT()
const {channels, memberIdsByChannelId} = useSortedPrivateMessageMemberships(
currentUser.id
)
@@ -51,13 +54,13 @@ export function MessagesContent(props: { currentUser: User }) {
return (
<>
<Row className="justify-between">
<Title>Messages</Title>
<Title>{t('messages.title', 'Messages')}</Title>
<NewMessageButton/>
</Row>
<Col className={'w-full overflow-hidden'}>
{channels && channels.length === 0 && (
<div className={'text-ink-500 dark:text-ink-600 mt-4 text-center'}>
You have no messages, yet.
{t('messages.empty', 'You have no messages, yet.')}
</div>
)}
{channels?.map((channel) => {
@@ -93,6 +96,7 @@ export const MessageChannelRow = (props: {
const unseen = (messages?.[0]?.createdTimeTs ?? '0') > lastSeenTime
const chat = messages?.[0]
const numOthers = otherUsers?.length ?? 0
const t = useT()
const isBanned = otherUsers?.length == 1 && otherUsers[0].isBannedFromPosting
return (
@@ -118,7 +122,12 @@ export const MessageChannelRow = (props: {
.map((user) => user.name.split(' ')[0].trim())
.slice(0, 2)
.join(', ')}
{otherUsers.length > 2 && ` & ${otherUsers.length - 2} more`}
{otherUsers.length > 2 && (
<>
{` & ${otherUsers.length - 2}`}
{t('messages.more', ' more')}
</>
)}
</span>
)}
{isBanned && <BannedBadge/>}
@@ -136,7 +145,7 @@ export const MessageChannelRow = (props: {
>
{chat && (
<>
{chat.userId == currentUser.id && 'You: '}
{chat.userId == currentUser.id && t('messages.you_prefix', 'You: ')}
{parseJsonContentToText(chat.content)}
</>
)}

View File

@@ -21,8 +21,6 @@ import {sendPasswordReset} from "web/lib/firebase/password";
import {AboutSettings} from "web/components/about-settings";
import {LanguagePicker} from "web/components/language/language-picker";
import {useT} from "web/lib/locale";
import {NewBadge} from "web/components/new-badge";
import {Row} from "web/components/layout/row"
export default function NotificationsPage() {
const t = useT()
@@ -134,15 +132,10 @@ const LoadedGeneralSettings = (props: {
<div className="flex flex-col gap-2 max-w-fit">
<h3>{t('settings.general.theme', 'Theme')}</h3>
<ThemeIcon className="h-6 w-6"/>
<h3>{t('settings.general.language', 'Language')}</h3>
<Row className="flex flex-col sm:flex-row items-center gap-10">
<div className="flex-none">
<NewBadge classes={'mr-2'} created={"2025-12-27"}/>
</div>
<div className="flex-auto">
<LanguagePicker/>
</div>
</Row>
<LanguagePicker className={'w-fit min-w-[120px]'}/>
<h3>{t('settings.general.account', 'Account')}</h3>
<h5>{t('settings.general.email', 'Email')}</h5>