diff --git a/backend/api/package.json b/backend/api/package.json index 188f8dc..3054163 100644 --- a/backend/api/package.json +++ b/backend/api/package.json @@ -1,7 +1,7 @@ { "name": "@compass/api", "description": "Backend API endpoints", - "version": "1.5.1", + "version": "1.6.0", "private": true, "scripts": { "watch:serve": "tsx watch src/serve.ts", diff --git a/backend/api/src/get-profiles.ts b/backend/api/src/get-profiles.ts index b1ff001..f33a03c 100644 --- a/backend/api/src/get-profiles.ts +++ b/backend/api/src/get-profiles.ts @@ -17,6 +17,16 @@ export type profileQueryType = { pref_age_max?: number | undefined, drinks_min?: number | undefined, drinks_max?: number | undefined, + big5_openness_min?: number | undefined, + big5_openness_max?: number | undefined, + big5_conscientiousness_min?: number | undefined, + big5_conscientiousness_max?: number | undefined, + big5_extraversion_min?: number | undefined, + big5_extraversion_max?: number | undefined, + big5_agreeableness_min?: number | undefined, + big5_agreeableness_max?: number | undefined, + big5_neuroticism_min?: number | undefined, + big5_neuroticism_max?: number | undefined, pref_relation_styles?: string[] | undefined, pref_romantic_styles?: string[] | undefined, diet?: string[] | undefined, @@ -60,6 +70,16 @@ export const loadProfiles = async (props: profileQueryType) => { pref_age_max, drinks_min, drinks_max, + big5_openness_min, + big5_openness_max, + big5_conscientiousness_min, + big5_conscientiousness_max, + big5_extraversion_min, + big5_extraversion_max, + big5_agreeableness_min, + big5_agreeableness_max, + big5_neuroticism_min, + big5_neuroticism_max, pref_relation_styles, pref_romantic_styles, diet, @@ -211,6 +231,42 @@ export const loadProfiles = async (props: profileQueryType) => { drinks_max && where(`drinks_per_month <= $(drinks_max) or drinks_per_month is null`, {drinks_max}), + big5_openness_min && + where(`big5_openness >= $(big5_openness_min) or big5_openness is null`, {big5_openness_min}), + + big5_openness_max && + where(`big5_openness <= $(big5_openness_max) or big5_openness is null`, {big5_openness_max}), + + big5_conscientiousness_min && + where( + `big5_conscientiousness >= $(big5_conscientiousness_min) or big5_conscientiousness is null`, + {big5_conscientiousness_min} + ), + + big5_conscientiousness_max && + where( + `big5_conscientiousness <= $(big5_conscientiousness_max) or big5_conscientiousness is null`, + {big5_conscientiousness_max} + ), + + big5_extraversion_min && + where(`big5_extraversion >= $(big5_extraversion_min) or big5_extraversion is null`, {big5_extraversion_min}), + + big5_extraversion_max && + where(`big5_extraversion <= $(big5_extraversion_max) or big5_extraversion is null`, {big5_extraversion_max}), + + big5_agreeableness_min && + where(`big5_agreeableness >= $(big5_agreeableness_min) or big5_agreeableness is null`, {big5_agreeableness_min}), + + big5_agreeableness_max && + where(`big5_agreeableness <= $(big5_agreeableness_max) or big5_agreeableness is null`, {big5_agreeableness_max}), + + big5_neuroticism_min && + where(`big5_neuroticism >= $(big5_neuroticism_min) or big5_neuroticism is null`, {big5_neuroticism_min}), + + big5_neuroticism_max && + where(`big5_neuroticism <= $(big5_neuroticism_max) or big5_neuroticism is null`, {big5_neuroticism_max}), + pref_relation_styles?.length && where( `pref_relation_styles IS NULL OR pref_relation_styles = '{}' OR pref_relation_styles && $(pref_relation_styles)`, diff --git a/backend/email/emails/functions/mock.ts b/backend/email/emails/functions/mock.ts index b863c3d..a3154ac 100644 --- a/backend/email/emails/functions/mock.ts +++ b/backend/email/emails/functions/mock.ts @@ -113,6 +113,11 @@ export const sinclairProfile: ProfileRow = { search_text: 'the futa in futarchy', search_tsv: 'the futa in futarchy', age: 25, + big5_agreeableness: 10, + big5_openness: 10, + big5_conscientiousness: 10, + big5_extraversion: 10, + big5_neuroticism: 10, } export const jamesUser: User = { @@ -226,4 +231,9 @@ export const jamesProfile: ProfileRow = { search_text: 'the futa in futarchy', search_tsv: 'the futa in futarchy', age: 32, + big5_agreeableness: 10, + big5_openness: 10, + big5_conscientiousness: 10, + big5_extraversion: 10, + big5_neuroticism: 10, } diff --git a/backend/supabase/migrations/20260213_add_big_5_to_profiles.sql b/backend/supabase/migrations/20260213_add_big_5_to_profiles.sql new file mode 100644 index 0000000..1d2321b --- /dev/null +++ b/backend/supabase/migrations/20260213_add_big_5_to_profiles.sql @@ -0,0 +1,23 @@ +ALTER TABLE profiles + ADD COLUMN big5_openness SMALLINT, + ADD COLUMN big5_conscientiousness SMALLINT, + ADD COLUMN big5_extraversion SMALLINT, + ADD COLUMN big5_agreeableness SMALLINT, + ADD COLUMN big5_neuroticism SMALLINT; + + +ALTER TABLE profiles + ADD CONSTRAINT big5_range_check + CHECK ( + big5_openness BETWEEN 0 AND 100 AND + big5_conscientiousness BETWEEN 0 AND 100 AND + big5_extraversion BETWEEN 0 AND 100 AND + big5_agreeableness BETWEEN 0 AND 100 AND + big5_neuroticism BETWEEN 0 AND 100 + ); + +CREATE INDEX profiles_big5_open_idx ON profiles (big5_openness); +CREATE INDEX profiles_big5_cons_idx ON profiles (big5_conscientiousness); +CREATE INDEX profiles_big5_extra_idx ON profiles (big5_extraversion); +CREATE INDEX profiles_big5_agree_idx ON profiles (big5_agreeableness); +CREATE INDEX profiles_big5_neur_idx ON profiles (big5_neuroticism); diff --git a/common/src/api/schema.ts b/common/src/api/schema.ts index 616e7ba..aeed446 100644 --- a/common/src/api/schema.ts +++ b/common/src/api/schema.ts @@ -509,6 +509,16 @@ export const API = (_apiTypeCheck = { pref_age_max: z.coerce.number().optional(), drinks_min: z.coerce.number().optional(), drinks_max: z.coerce.number().optional(), + big5_openness_min: z.coerce.number().optional(), + big5_openness_max: z.coerce.number().optional(), + big5_conscientiousness_min: z.coerce.number().optional(), + big5_conscientiousness_max: z.coerce.number().optional(), + big5_extraversion_min: z.coerce.number().optional(), + big5_extraversion_max: z.coerce.number().optional(), + big5_agreeableness_min: z.coerce.number().optional(), + big5_agreeableness_max: z.coerce.number().optional(), + big5_neuroticism_min: z.coerce.number().optional(), + big5_neuroticism_max: z.coerce.number().optional(), religion: arraybeSchema.optional(), pref_relation_styles: arraybeSchema.optional(), pref_romantic_styles: arraybeSchema.optional(), diff --git a/common/src/api/zod-types.ts b/common/src/api/zod-types.ts index 42de723..8b62e09 100644 --- a/common/src/api/zod-types.ts +++ b/common/src/api/zod-types.ts @@ -56,6 +56,7 @@ export const baseProfilesSchema = z.object({ country: z.string().optional().nullable(), gender: genderType, geodb_city_id: z.string().optional().nullable(), + languages: z.array(z.string()).optional().nullable(), looking_for_matches: zBoolean, photo_urls: z.array(z.string()).nullable(), pinned_url: z.string(), @@ -67,13 +68,18 @@ export const baseProfilesSchema = z.object({ region_code: z.string().optional().nullable(), visibility: z.union([z.literal('public'), z.literal('member')]), wants_kids_strength: z.number().nullable(), - languages: z.array(z.string()).optional().nullable(), }) const optionalProfilesSchema = z.object({ avatar_url: z.string().optional().nullable(), bio: contentSchema.optional().nullable(), + big5_openness: z.number().min(0).max(100).optional().nullable(), + big5_conscientiousness: z.number().min(0).max(100).optional().nullable(), + big5_extraversion: z.number().min(0).max(100).optional().nullable(), + big5_agreeableness: z.number().min(0).max(100).optional().nullable(), + big5_neuroticism: z.number().min(0).max(100).optional().nullable(), born_in_location: z.string().optional().nullable(), + causes: z.array(z.string()).optional().nullable(), comments_enabled: zBoolean.optional(), company: z.string().optional().nullable(), diet: z.array(z.string()).optional().nullable(), @@ -82,29 +88,27 @@ const optionalProfilesSchema = z.object({ drinks_min: z.number().min(0).optional().nullable(), drinks_per_month: z.number().min(0).optional().nullable(), education_level: z.string().optional().nullable(), - mbti: z.string().optional().nullable(), ethnicity: z.array(z.string()).optional().nullable(), has_kids: z.number().min(0).optional().nullable(), has_pets: zBoolean.optional().nullable(), height_in_inches: z.number().optional().nullable(), + image_descriptions: z.any().optional().nullable(), + interests: z.array(z.string()).optional().nullable(), is_smoker: zBoolean.optional().nullable(), + mbti: z.string().optional().nullable(), occupation: z.string().optional().nullable(), occupation_title: z.string().optional().nullable(), political_beliefs: z.array(z.string()).optional().nullable(), - interests: z.array(z.string()).optional().nullable(), - work: z.array(z.string()).optional().nullable(), - causes: z.array(z.string()).optional().nullable(), - relationship_status: z.array(z.string()).optional().nullable(), political_details: z.string().optional().nullable(), pref_romantic_styles: z.array(z.string()).nullable(), + relationship_status: z.array(z.string()).optional().nullable(), religion: z.array(z.string()).optional().nullable(), religious_belief_strength: z.number().optional().nullable(), religious_beliefs: z.string().optional().nullable(), twitter: z.string().optional().nullable(), university: z.string().optional().nullable(), website: z.string().optional().nullable(), - image_descriptions: z.any().optional().nullable(), + work: z.array(z.string()).optional().nullable(), }) -export const combinedProfileSchema = - baseProfilesSchema.merge(optionalProfilesSchema) +export const combinedProfileSchema = baseProfilesSchema.merge(optionalProfilesSchema) diff --git a/common/src/filters.ts b/common/src/filters.ts index c75c037..c7fec93 100644 --- a/common/src/filters.ts +++ b/common/src/filters.ts @@ -22,6 +22,17 @@ export type FilterFields = { shortBio: boolean | undefined drinks_min: number | undefined drinks_max: number | undefined + // Big Five personality filters (0-100 range) + big5_openness_min: number | undefined + big5_openness_max: number | undefined + big5_conscientiousness_min: number | undefined + big5_conscientiousness_max: number | undefined + big5_extraversion_min: number | undefined + big5_extraversion_max: number | undefined + big5_agreeableness_min: number | undefined + big5_agreeableness_max: number | undefined + big5_neuroticism_min: number | undefined + big5_neuroticism_max: number | undefined } & { [K in OptionTableKey]: string[] } @@ -89,6 +100,16 @@ export const initialFilters: Partial = { shortBio: undefined, drinks_min: undefined, drinks_max: undefined, + big5_openness_min: undefined, + big5_openness_max: undefined, + big5_conscientiousness_min: undefined, + big5_conscientiousness_max: undefined, + big5_extraversion_min: undefined, + big5_extraversion_max: undefined, + big5_agreeableness_min: undefined, + big5_agreeableness_max: undefined, + big5_neuroticism_min: undefined, + big5_neuroticism_max: undefined, orderBy: 'created_time', } diff --git a/common/src/supabase/schema.ts b/common/src/supabase/schema.ts index d5507e1..4890028 100644 --- a/common/src/supabase/schema.ts +++ b/common/src/supabase/schema.ts @@ -856,6 +856,11 @@ export type Database = { profiles: { Row: { age: number | null + big5_agreeableness: number | null + big5_conscientiousness: number | null + big5_extraversion: number | null + big5_neuroticism: number | null + big5_openness: number | null bio: Json | null bio_length: number | null bio_text: string | null @@ -913,6 +918,11 @@ export type Database = { } Insert: { age?: number | null + big5_agreeableness?: number | null + big5_conscientiousness?: number | null + big5_extraversion?: number | null + big5_neuroticism?: number | null + big5_openness?: number | null bio?: Json | null bio_length?: number | null bio_text?: string | null @@ -970,6 +980,11 @@ export type Database = { } Update: { age?: number | null + big5_agreeableness?: number | null + big5_conscientiousness?: number | null + big5_extraversion?: number | null + big5_neuroticism?: number | null + big5_openness?: number | null bio?: Json | null bio_length?: number | null bio_text?: string | null @@ -1204,7 +1219,15 @@ export type Database = { ts?: string user_id?: string | null } - Relationships: [] + Relationships: [ + { + foreignKeyName: 'user_events_user_id_fkey' + columns: ['user_id'] + isOneToOne: false + referencedRelation: 'users' + referencedColumns: ['id'] + }, + ] } user_notifications: { Row: { diff --git a/web/components/filters/big5-filter.tsx b/web/components/filters/big5-filter.tsx new file mode 100644 index 0000000..e3cd262 --- /dev/null +++ b/web/components/filters/big5-filter.tsx @@ -0,0 +1,181 @@ +import clsx from 'clsx' +import {RangeSlider} from 'web/components/widgets/slider' +import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' + +export const BIG5_MIN = 0 +export const BIG5_MAX = 100 + +export type Big5Key = + | 'big5_openness' + | 'big5_conscientiousness' + | 'big5_extraversion' + | 'big5_agreeableness' + | 'big5_neuroticism' + +export type Big5MinMaxKey = + | 'big5_openness_min' + | 'big5_openness_max' + | 'big5_conscientiousness_min' + | 'big5_conscientiousness_max' + | 'big5_extraversion_min' + | 'big5_extraversion_max' + | 'big5_agreeableness_min' + | 'big5_agreeableness_max' + | 'big5_neuroticism_min' + | 'big5_neuroticism_max' + +export function hasAnyBig5Filter(filters: Partial) { + return ( + filters.big5_openness_min != null || + filters.big5_openness_max != null || + filters.big5_conscientiousness_min != null || + filters.big5_conscientiousness_max != null || + filters.big5_extraversion_min != null || + filters.big5_extraversion_max != null || + filters.big5_agreeableness_min != null || + filters.big5_agreeableness_max != null || + filters.big5_neuroticism_min != null || + filters.big5_neuroticism_max != null + ) +} + +export function Big5FilterText(props: { + filters: Partial + highlightedClass?: string +}) { + const {filters, highlightedClass} = props + const t = useT() + const hasAny = hasAnyBig5Filter(filters) + + if (!hasAny) { + return ( + + {t('filter.big5.any', 'Any Big 5')} + + ) + } + + return ( + + {t('filter.big5.custom', 'Custom Big 5')} + + ) +} + +export function Big5SliderRow(props: { + label: string + minValue: number | null | undefined + maxValue: number | null | undefined + onChange: (min: number | undefined, max: number | undefined) => void +}) { + const {label, minValue, maxValue, onChange} = props + + return ( +
+
+ {label} + + {minValue == null && maxValue == null + ? '0 – 100' + : `${minValue ?? BIG5_MIN} – ${maxValue ?? BIG5_MAX}`} + +
+ { + onChange( + low > BIG5_MIN ? Math.round(low) : undefined, + high < BIG5_MAX ? Math.round(high) : undefined + ) + }} + marks={[ + {value: 0, label: '0'}, + {value: 25, label: '25'}, + {value: 50, label: '50'}, + {value: 75, label: '75'}, + {value: 100, label: '100'}, + ].map((m) => ({ + value: ((m.value - BIG5_MIN) / (BIG5_MAX - BIG5_MIN)) * 100, + label: m.label, + }))} + /> +
+ ) +} + +export function Big5Filters(props: { + filters: Partial + updateFilter: (newState: Partial) => void +}) { + const {filters, updateFilter} = props + const t = useT() + + return ( +
+ + updateFilter({ + big5_openness_min: min, + big5_openness_max: max, + }) + } + /> + + updateFilter({ + big5_conscientiousness_min: min, + big5_conscientiousness_max: max, + }) + } + /> + + updateFilter({ + big5_extraversion_min: min, + big5_extraversion_max: max, + }) + } + /> + + updateFilter({ + big5_agreeableness_min: min, + big5_agreeableness_max: max, + }) + } + /> + + updateFilter({ + big5_neuroticism_min: min, + big5_neuroticism_max: max, + }) + } + /> +
+ ) +} + + diff --git a/web/components/filters/desktop-filters.tsx b/web/components/filters/desktop-filters.tsx index 8eb125d..1f8dbc2 100644 --- a/web/components/filters/desktop-filters.tsx +++ b/web/components/filters/desktop-filters.tsx @@ -42,6 +42,7 @@ import {InterestFilter, InterestFilterText} from "web/components/filters/interes import {OptionTableKey} from "common/profiles/constants"; import {useT} from "web/lib/locale"; import {ResetFiltersButton} from "web/components/searches/button"; +import {Big5Filters, Big5FilterText, hasAnyBig5Filter} from "web/components/filters/big5-filter"; export function DesktopFilters(props: { filters: Partial @@ -646,6 +647,31 @@ export function DesktopFilters(props: { menuWidth="w-[400px]" /> + {/* BIG FIVE PERSONALITY */} + ( + + + + + } + /> + )} + dropdownMenuContent={ + + + + } + popoverClassName="bg-canvas-50" + menuWidth="w-[420px]" + /> + {/* EDUCATION */} ( diff --git a/web/components/filters/mobile-filters.tsx b/web/components/filters/mobile-filters.tsx index 823890a..6820bd2 100644 --- a/web/components/filters/mobile-filters.tsx +++ b/web/components/filters/mobile-filters.tsx @@ -43,6 +43,7 @@ import {LuCigarette, LuGraduationCap} from "react-icons/lu"; import {RiScales3Line} from "react-icons/ri"; import {PiHandsPrayingBold} from "react-icons/pi"; import {ResetFiltersButton} from "web/components/searches/button"; +import {Big5Filters, Big5FilterText, hasAnyBig5Filter} from "web/components/filters/big5-filter"; import {FilterGuide} from "web/components/guidance"; function MobileFilters(props: { @@ -534,6 +535,25 @@ function MobileFilters(props: { + {/* BIG FIVE PERSONALITY */} + } + selection={ + + } + > + + + {/* EDUCATION */} + {/* Big Five personality traits (0–100) */} + + +
+ setProfile('big5_openness', v)} + /> + setProfile('big5_conscientiousness', v)} + /> + setProfile('big5_extraversion', v)} + /> + setProfile('big5_agreeableness', v)} + /> + setProfile('big5_neuroticism', v)} + /> +

+ {t( + 'profile.big5_hint', + 'Drag each slider to set where you see yourself on these traits (0 = low, 100 = high).' + )} +

+
+ + @@ -900,3 +950,33 @@ function Category({title, className}: { title: string, className?: string }) { return

{title}

; } +const Big5Slider = (props: { + label: string + value: number + onChange: (v: number) => void +}) => { + const {label, value, onChange} = props + return ( +
+
+ {label} + {Math.round(value)} +
+ onChange(Math.round(v))} + marks={[ + {value: 0, label: '0'}, + {value: 25, label: '25'}, + {value: 50, label: '50'}, + {value: 75, label: '75'}, + {value: 100, label: '100'}, + ]} + /> +
+ ) +} + + diff --git a/web/components/profile-about.tsx b/web/components/profile-about.tsx index a3015c8..aa9eefe 100644 --- a/web/components/profile-about.tsx +++ b/web/components/profile-about.tsx @@ -34,6 +34,7 @@ import {FaBriefcase, FaHandsHelping, FaHeart, FaStar} from "react-icons/fa"; import {useLocale, useT} from "web/lib/locale"; import {useChoices} from "web/hooks/use-choices"; import {getSeekingGenderText} from "web/lib/profile/seeking"; +import {TbBulb, TbCheck, TbMoodSad, TbUsers} from "react-icons/tb"; export function AboutRow(props: { icon: ReactNode @@ -119,6 +120,7 @@ export default function ProfileAbout(props: { icon={} text={profile.mbti ? INVERTED_MBTI_CHOICES[profile.mbti] : null} /> + } text={profile.ethnicity @@ -340,6 +342,85 @@ function LastOnline(props: { lastOnlineTime?: string }) { ) } +function Big5Traits(props: { profile: Profile }) { + const t = useT() + const {profile} = props + + const traits = [ + { + key: 'big5_openness', + icon: , + label: t('profile.big5_openness', 'Openness'), + value: profile.big5_openness + }, + { + key: 'big5_conscientiousness', + icon: , + label: t('profile.big5_conscientiousness', 'Conscientiousness'), + value: profile.big5_conscientiousness + }, + { + key: 'big5_extraversion', + icon: , + label: t('profile.big5_extraversion', 'Extraversion'), + value: profile.big5_extraversion + }, + { + key: 'big5_agreeableness', + icon: , + label: t('profile.big5_agreeableness', 'Agreeableness'), + value: profile.big5_agreeableness + }, + { + key: 'big5_neuroticism', + icon: , + label: t('profile.big5_neuroticism', 'Neuroticism'), + value: profile.big5_neuroticism + } + ] + + const hasAnyTraits = traits.some(trait => trait.value !== null && trait.value !== undefined) + + if (!hasAnyTraits) { + return <> + } + + return ( + +
+ {t('profile.big5', 'Big Five personality traits')}: +
+
+ {traits.map((trait) => { + if (trait.value === null || trait.value === undefined) return null + + let levelText: string + if (trait.value <= 20) { + levelText = t('profile.big5_very_low', 'Very low') + } else if (trait.value <= 40) { + levelText = t('profile.big5_low', 'Low') + } else if (trait.value <= 60) { + levelText = t('profile.big5_average', 'Average') + } else if (trait.value <= 80) { + levelText = t('profile.big5_high', 'High') + } else { + levelText = t('profile.big5_very_high', 'Very high') + } + + return ( + +
{trait.icon}
+
+ {trait.label}: {levelText} ({trait.value}) +
+
+ ) + })} +
+ + ) +} + function HasKids(props: { profile: Profile }) { const t = useT() const {profile} = props diff --git a/web/messages/de.json b/web/messages/de.json index 0bb97bd..2c1c46c 100644 --- a/web/messages/de.json +++ b/web/messages/de.json @@ -212,6 +212,8 @@ "filter.any_relationship": "Jede romantische Beziehung", "filter.any_religion": "Jede Religion", "filter.any_work": "Jede Arbeit", + "filter.big5.any": "Beliebige Big 5", + "filter.big5.custom": "Benutzerdefinierte Big 5", "filter.gender.any": "Alle", "filter.gender.gender": "Geschlecht", "filter.gender.genders": "Geschlechter", @@ -647,6 +649,19 @@ "profile.optional.username_or_url": "Benutzername oder URL", "profile.optional.want_kids": "Ich möchte Kinder haben", "profile.optional.work": "Arbeit", + "profile.big5_openness": "Offenheit", + "profile.big5_conscientiousness": "Gewissenhaftigkeit", + "profile.big5_extraversion": "Extraversion", + "profile.big5_agreeableness": "Verträglichkeit", + "profile.big5_neuroticism": "Neurotizismus", + "profile.big5": "Persönlichkeit (Big Five)", + "profile.big5_hint": "Ziehen Sie jeden Schieber, um festzulegen, wo Sie sich bei diesen Merkmalen sehen (0 = niedrig, 100 = hoch).", + "profile.big5_very_low": "Sehr niedrig", + "profile.big5_low": "Niedrig", + "profile.big5_average": "Durchschnittlich", + "profile.big5_high": "Hoch", + "profile.big5_very_high": "Sehr hoch", + "profile.optional.big5_hint": "Ziehen Sie jeden Schieber, um festzulegen, wo Sie sich bei diesen Merkmalen sehen (0 = niedrig, 100 = hoch).", "profile.political.conservative": "Konservativ", "profile.political.e/acc": "Effektiver Akzelerationismus", "profile.political.green": "Grün / Ökosozialismus", diff --git a/web/messages/fr.json b/web/messages/fr.json index 7a424f9..77672e7 100644 --- a/web/messages/fr.json +++ b/web/messages/fr.json @@ -212,6 +212,8 @@ "filter.any_relationship": "Toute relation amoureuse", "filter.any_religion": "Toute religion", "filter.any_work": "Tout travail", + "filter.big5.any": "Tout Big 5", + "filter.big5.custom": "Certains Big 5", "filter.gender.any": "Tout", "filter.gender.gender": "genre", "filter.gender.genders": "genres", @@ -647,6 +649,19 @@ "profile.optional.username_or_url": "Nom d'utilisateur ou URL", "profile.optional.want_kids": "Je souhaite avoir des enfants", "profile.optional.work": "Domaine de travail", + "profile.big5_openness": "Ouverture", + "profile.big5_conscientiousness": "Conscienciosité", + "profile.big5_extraversion": "Extraversion", + "profile.big5_agreeableness": "Agréabilité", + "profile.big5_neuroticism": "Névrosisme", + "profile.big5": "Big Five", + "profile.big5_hint": "Faites glisser chaque curseur pour définir où vous vous situez sur ces traits (0 = faible, 100 = élevé).", + "profile.big5_very_low": "Très faible", + "profile.big5_low": "Faible", + "profile.big5_average": "Moyen", + "profile.big5_high": "Élevé", + "profile.big5_very_high": "Très élevé", + "profile.optional.big5_hint": "Faites glisser chaque curseur pour définir où vous vous situez sur ces traits (0 = faible, 100 = élevé).", "profile.political.conservative": "Conservateur·trice", "profile.political.e/acc": "Accélérationnisme efficace", "profile.political.green": "Vert·e / Éco-socialiste",