From bb423ba0e4ed77e1b39dbd9fdc769cae4793b9a9 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 4 Jan 2026 12:42:53 +0200 Subject: [PATCH] Translate filters --- common/src/parsing.ts | 4 +- web/components/about-settings.tsx | 4 +- web/components/filters/age-filter.tsx | 16 +- web/components/filters/choices.tsx | 6 + web/components/filters/desktop-filters.tsx | 20 +- web/components/filters/diet-filter.tsx | 14 +- web/components/filters/drinks-filter.tsx | 15 +- web/components/filters/education-filter.tsx | 15 +- web/components/filters/gender-filter.tsx | 23 +- web/components/filters/has-kids-filter.tsx | 31 +- web/components/filters/interest-filter.tsx | 16 +- web/components/filters/language-filter.tsx | 20 +- web/components/filters/location-filter.tsx | 17 +- web/components/filters/mbti-filter.tsx | 7 +- web/components/filters/mobile-filters.tsx | 44 +- web/components/filters/my-matches-toggle.tsx | 8 +- web/components/filters/political-filter.tsx | 21 +- web/components/filters/pref-gender-filter.tsx | 31 +- .../filters/relationship-filter.tsx | 11 +- .../filters/relationship-status-filter.tsx | 11 +- web/components/filters/religion-filter.tsx | 25 +- web/components/filters/romantic-filter.tsx | 16 +- web/components/filters/short-bio-toggle.tsx | 4 +- web/components/filters/smoker-filter.tsx | 16 +- web/components/filters/wants-kids-filter.tsx | 41 +- web/components/multi-checkbox.tsx | 14 +- web/components/profile/delete-yourself.tsx | 18 +- .../widgets/choices-toggle-group.tsx | 35 +- web/messages/fr.json | 1511 +++++++++-------- 29 files changed, 1090 insertions(+), 924 deletions(-) diff --git a/common/src/parsing.ts b/common/src/parsing.ts index c574c66c..1d83ac82 100644 --- a/common/src/parsing.ts +++ b/common/src/parsing.ts @@ -1,3 +1,3 @@ -export const toKey = (str: string) => { - return str.replace(/ /g, '_').toLowerCase() +export const toKey = (str: string | number | boolean) => { + return String(str).replace(/ /g, '_').toLowerCase() } \ No newline at end of file diff --git a/web/components/about-settings.tsx b/web/components/about-settings.tsx index 0088f245..85d4e1d9 100644 --- a/web/components/about-settings.tsx +++ b/web/components/about-settings.tsx @@ -146,7 +146,7 @@ const LoadedAboutSettings = (props: { const handleCopy = async () => { if (!diagnostics) return await navigator.clipboard.writeText(diagnosticsToText(diagnostics)) - setCopyFeedback(t('aboutsettings.copied', 'Copied!')) + setCopyFeedback(t('about.settings.copied', 'Copied!')) setTimeout(() => { setCopyFeedback('') }, 2000) @@ -161,7 +161,7 @@ const LoadedAboutSettings = (props: { onClick={handleCopy} className="w-fit mt-4" > - {copyFeedback || t('aboutsettings.copy_info', 'Copy Info')} + {copyFeedback || t('about.settings.copy_info', 'Copy Info')} } diff --git a/web/components/filters/age-filter.tsx b/web/components/filters/age-filter.tsx index 86f98262..11ab7a80 100644 --- a/web/components/filters/age-filter.tsx +++ b/web/components/filters/age-filter.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx' -import { RangeSlider } from 'web/components/widgets/slider' -import {FilterFields} from "common/filters"; +import {RangeSlider} from 'web/components/widgets/slider' +import {FilterFields} from "common/filters" +import {useT} from 'web/lib/locale' export const PREF_AGE_MIN = 18 export const PREF_AGE_MAX = 100 @@ -22,11 +23,12 @@ export function AgeFilterText(props: { const { pref_age_min, pref_age_max, highlightedClass } = props const [noMinAge, noMaxAge] = getNoMinMaxAge(pref_age_min, pref_age_max) + const t = useT() if (noMinAge && noMaxAge) { return ( - Any{' '} - age + {t('filter.age.any', 'Any')}{' '} + {t('filter.age.age', 'age')} ) } @@ -37,7 +39,7 @@ export function AgeFilterText(props: { {'<'} {pref_age_max} {' '} - years + {t('filter.age.years', 'years')} ) } @@ -48,7 +50,7 @@ export function AgeFilterText(props: { {'>'} {pref_age_min} {' '} - years + {t('filter.age.years', 'years')} ) } @@ -59,7 +61,7 @@ export function AgeFilterText(props: { {' - '} {pref_age_max} {' '} - years + {t('filter.age.years', 'years')} ) } diff --git a/web/components/filters/choices.tsx b/web/components/filters/choices.tsx index 84b218a6..f89ff292 100644 --- a/web/components/filters/choices.tsx +++ b/web/components/filters/choices.tsx @@ -225,6 +225,12 @@ export const GENDERS = { Other: 'other', } +export const GENDERS_PLURAL = { + Women: 'female', + Men: 'male', + Other: 'other', +} + export const INVERTED_RELATIONSHIP_CHOICES = invert(RELATIONSHIP_CHOICES) export const INVERTED_RELATIONSHIP_STATUS_CHOICES = invert(RELATIONSHIP_STATUS_CHOICES) export const INVERTED_ROMANTIC_CHOICES = invert(ROMANTIC_CHOICES) diff --git a/web/components/filters/desktop-filters.tsx b/web/components/filters/desktop-filters.tsx index df84855b..310fe5b7 100644 --- a/web/components/filters/desktop-filters.tsx +++ b/web/components/filters/desktop-filters.tsx @@ -16,7 +16,7 @@ import {FilterFields} from "common/filters"; import {ShortBioToggle} from "web/components/filters/short-bio-toggle"; import {PrefGenderFilter, PrefGenderFilterText} from "web/components/filters/pref-gender-filter"; import DropdownMenu from "web/components/comments/dropdown-menu"; -import {KidsLabel, wantsKidsLabelsWithIcon} from "web/components/filters/wants-kids-filter"; +import {KidsLabel, useWantsKidsLabelsWithIcon} from "web/components/filters/wants-kids-filter"; import {hasKidsLabels} from "common/has-kids"; import {HasKidsLabel} from "web/components/filters/has-kids-filter"; import {RomanticFilter, RomanticFilterText} from "web/components/filters/romantic-filter"; @@ -27,7 +27,7 @@ import {GiFruitBowl} from "react-icons/gi"; import {RiScales3Line} from "react-icons/ri"; import {EducationFilter, EducationFilterText} from "web/components/filters/education-filter"; import {MbtiFilter, MbtiFilterText} from "web/components/filters/mbti-filter"; -import {BsPersonVcard} from "react-icons/bs"; +import {BsPersonHeart, BsPersonVcard} from "react-icons/bs"; import {LuCigarette, LuGraduationCap} from "react-icons/lu"; import {DrinksFilter, DrinksFilterText} from "web/components/filters/drinks-filter"; import {MdLanguage, MdLocalBar} from 'react-icons/md' @@ -39,9 +39,9 @@ import { RelationshipStatusFilter, RelationshipStatusFilterText } from "web/components/filters/relationship-status-filter"; -import {BsPersonHeart} from "react-icons/bs"; import {InterestFilter, InterestFilterText} from "web/components/filters/interest-filter"; import {OptionTableKey} from "common/profiles/constants"; +import {useT} from "web/lib/locale"; export function DesktopFilters(props: { filters: Partial @@ -66,6 +66,9 @@ export function DesktopFilters(props: { choices, } = props + const t = useT() + const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon() + return ( <> @@ -439,7 +442,7 @@ export function DesktopFilters(props: { | undefined } highlightedClass={open ? 'text-primary-500' : undefined} - label={'interest'} + label={'interests'} /> } @@ -474,7 +477,7 @@ export function DesktopFilters(props: { | undefined } highlightedClass={open ? 'text-primary-500' : undefined} - label={'cause'} + label={'causes'} /> } @@ -596,7 +599,7 @@ export function DesktopFilters(props: { } @@ -656,6 +659,7 @@ export function DesktopFilters(props: { } popoverClassName="bg-canvas-50" + menuWidth="w-50" /> {/* Short Bios */} @@ -669,7 +673,7 @@ export function DesktopFilters(props: { className="text-ink-900 hover:text-primary-500 underline" onClick={clearFilters} > - Reset filters + {t('filter.reset', 'Reset filters')} ) diff --git a/web/components/filters/diet-filter.tsx b/web/components/filters/diet-filter.tsx index 465f9a31..4653bf92 100644 --- a/web/components/filters/diet-filter.tsx +++ b/web/components/filters/diet-filter.tsx @@ -3,8 +3,9 @@ import {convertDietTypes, DietType,} from 'web/lib/util/convert-types' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' -import {DIET_CHOICES} from "web/components/filters/choices"; -import {FilterFields} from "common/filters"; +import {DIET_CHOICES} from 'web/components/filters/choices' +import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' export function DietFilterText(props: { options: DietType[] | undefined @@ -13,9 +14,13 @@ export function DietFilterText(props: { const {options, highlightedClass} = props const length = (options ?? []).length + const t = useT() + if (!options || length < 1) { return ( - Any diet + + {t('filter.any_diet', 'Any diet')} + ) } @@ -27,7 +32,7 @@ export function DietFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) @@ -53,6 +58,7 @@ export function DietFilter(props: { { updateFilter({diet: c}) }} diff --git a/web/components/filters/drinks-filter.tsx b/web/components/filters/drinks-filter.tsx index 8e379116..eab63bd9 100644 --- a/web/components/filters/drinks-filter.tsx +++ b/web/components/filters/drinks-filter.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx' import {RangeSlider} from 'web/components/widgets/slider' import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' export const DRINKS_MIN = 0 export const DRINKS_MAX = 20 @@ -22,12 +23,13 @@ export function DrinksFilterText(props: { }) { const {drinks_min, drinks_max, highlightedClass} = props const [noMin, noMax] = getNoMinMaxDrinks(drinks_min, drinks_max) + const t = useT() if (drinks_max === DRINKS_MIN) { return ( - {drinks_max} / mo + {drinks_max} {t('common.per_month', '/ mo')} ) } @@ -35,8 +37,7 @@ export function DrinksFilterText(props: { if (noMin && noMax) { return ( - Any{' '} - drinks + {t('filter.any_drinks', 'Any drinks')} ) } @@ -47,7 +48,7 @@ export function DrinksFilterText(props: { {' < '} {drinks_max} {' '} - / mo + {t('common.per_month', '/ mo')} ) } @@ -58,14 +59,14 @@ export function DrinksFilterText(props: { {' > '} {drinks_min} {' '} - / mo + {t('common.per_month', '/ mo')} ) } if (drinks_min === drinks_max) { return ( - {drinks_min} / mo + {drinks_min} {t('common.per_month', '/ mo')} ) } @@ -76,7 +77,7 @@ export function DrinksFilterText(props: { {' - '} {drinks_max} {' '} - /mo + {t('common.per_month', '/ mo')} ) } diff --git a/web/components/filters/education-filter.tsx b/web/components/filters/education-filter.tsx index d131aa9f..729fd72a 100644 --- a/web/components/filters/education-filter.tsx +++ b/web/components/filters/education-filter.tsx @@ -5,7 +5,9 @@ import {FilterFields} from "common/filters"; import {EDUCATION_CHOICES} from "web/components/filters/choices"; import {convertEducationTypes} from "web/lib/util/convert-types"; import stringOrStringArrayToText from "web/lib/util/string-or-string-array-to-text"; -import {getSortedOptions} from "common/util/sorting"; +import {getSortedOptions} from 'common/util/sorting' +import {useT} from 'web/lib/locale' +import {toKey} from 'common/parsing' export function EducationFilterText(props: { options: string[] | undefined @@ -14,14 +16,20 @@ export function EducationFilterText(props: { const {options, highlightedClass} = props const length = (options ?? []).length + const t = useT() + if (!options || length < 1) { return ( - Any education + + {t('filter.any_education', 'Any education')} + ) } const sortedOptions = getSortedOptions(options, EDUCATION_CHOICES) - const convertedTypes = sortedOptions.map((r) => convertEducationTypes(r as any)) + const convertedTypes = sortedOptions.map((r) => + t(`profile.education.${toKey(r)}`, convertEducationTypes(r as any)) + ) return (
@@ -45,6 +53,7 @@ export function EducationFilter(props: { { updateFilter({education_levels: c}) }} diff --git a/web/components/filters/gender-filter.tsx b/web/components/filters/gender-filter.tsx index ef471959..781bfc06 100644 --- a/web/components/filters/gender-filter.tsx +++ b/web/components/filters/gender-filter.tsx @@ -1,10 +1,11 @@ import clsx from 'clsx' import GenderIcon from '../gender-icon' -import { Gender } from 'common/gender' -import { Row } from 'web/components/layout/row' -import { MultiCheckbox } from 'web/components/multi-checkbox' - +import {Gender} from 'common/gender' +import {Row} from 'web/components/layout/row' +import {MultiCheckbox} from 'web/components/multi-checkbox' +import {useT} from 'web/lib/locale' import {FilterFields} from "common/filters"; +import {GENDERS_PLURAL} from "web/components/filters/choices"; export function GenderFilterText(props: { gender: Gender[] | undefined @@ -12,11 +13,12 @@ export function GenderFilterText(props: { }) { const { gender, highlightedClass } = props + const t = useT() if (!gender || gender.length < 1) { return ( - Any{' '} - gender + {t('filter.gender.any', 'Any')}{' '} + {t('filter.gender.gender', 'gender')} ) } @@ -28,7 +30,7 @@ export function GenderFilterText(props: { ) })}{' '} - gender{gender.length > 1 ? 's' : ''} + {gender.length > 1 ? t('filter.gender.genders', 'genders') : t('filter.gender.gender', 'gender')} ) @@ -43,11 +45,8 @@ export function GenderFilter(props: { <> { updateFilter({ genders: c }) }} diff --git a/web/components/filters/has-kids-filter.tsx b/web/components/filters/has-kids-filter.tsx index 2d006953..d1535e73 100644 --- a/web/components/filters/has-kids-filter.tsx +++ b/web/components/filters/has-kids-filter.tsx @@ -2,8 +2,9 @@ import clsx from 'clsx' import {Row} from 'web/components/layout/row' import {ChoicesToggleGroup} from 'web/components/widgets/choices-toggle-group' import {FaChild} from 'react-icons/fa6' -import {FilterFields} from "common/filters"; -import {generateChoicesMap, hasKidsLabels} from "common/has-kids"; +import {FilterFields} from 'common/filters' +import {generateChoicesMap, hasKidsLabels} from 'common/has-kids' +import {useT} from 'web/lib/locale' export function HasKidsLabel(props: { @@ -12,23 +13,26 @@ export function HasKidsLabel(props: { mobile?: boolean }) { const {has_kids, highlightedClass, mobile} = props + const t = useT() + + // Get the appropriate label based on has_kids value + let labelKey = 'no_preference' + let labelValue = hasKidsLabels.no_preference.name + + if (has_kids === hasKidsLabels.has_kids.value) { + labelKey = 'has_kids' + labelValue = mobile ? hasKidsLabels.has_kids.shortName : hasKidsLabels.has_kids.name + } else if (has_kids === hasKidsLabels.doesnt_have_kids.value) { + labelKey = 'doesnt_have_kids' + labelValue = mobile ? hasKidsLabels.doesnt_have_kids.shortName : hasKidsLabels.doesnt_have_kids.name + } return ( - {has_kids == hasKidsLabels.has_kids.value - ? mobile - ? hasKidsLabels.has_kids.shortName - : hasKidsLabels.has_kids.name - : has_kids == hasKidsLabels.doesnt_have_kids.value - ? mobile - ? hasKidsLabels.doesnt_have_kids.shortName - : hasKidsLabels.doesnt_have_kids.name - : mobile - ? hasKidsLabels.no_preference.shortName - : hasKidsLabels.no_preference.name} + {t(`profile.has_kids.${labelKey}`, labelValue)} ) @@ -43,6 +47,7 @@ export function HasKidsFilter(props: { updateFilter({has_kids: Number(c)})} toggleClassName="w-1/3 justify-center" /> diff --git a/web/components/filters/interest-filter.tsx b/web/components/filters/interest-filter.tsx index 8895d9dc..12f4880a 100644 --- a/web/components/filters/interest-filter.tsx +++ b/web/components/filters/interest-filter.tsx @@ -2,19 +2,24 @@ import clsx from 'clsx' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' import {FilterFields} from "common/filters"; -import {OptionTableKey} from "common/profiles/constants"; +import {OptionTableKey} from 'common/profiles/constants' +import {useT} from 'web/lib/locale' +import {toKey} from "common/parsing"; export function InterestFilterText(props: { options: string[] | undefined highlightedClass?: string - label: string + label: OptionTableKey }) { const {options, highlightedClass, label} = props + const t = useT() const length = (options ?? []).length if (!options || length < 1) { return ( - Any {label} + + {t(`filter.any_${label}`, `Any ${label}`)} + ) } @@ -22,7 +27,7 @@ export function InterestFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) @@ -32,7 +37,7 @@ export function InterestFilterText(props: {
{stringOrStringArrayToText({ - text: options, + text: options.map((o) => t(`profile.${label}.${toKey(o)}`, o)), capitalizeFirstLetterOption: true, })}{' '} @@ -51,6 +56,7 @@ export function InterestFilter(props: { { updateFilter({[label]: c}) }} diff --git a/web/components/filters/language-filter.tsx b/web/components/filters/language-filter.tsx index 40a59227..e747a14c 100644 --- a/web/components/filters/language-filter.tsx +++ b/web/components/filters/language-filter.tsx @@ -3,9 +3,10 @@ import {convertLanguageTypes,} from 'web/lib/util/convert-types' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' -import {LANGUAGE_CHOICES} from "web/components/filters/choices"; -import {FilterFields} from "common/filters"; -import {getSortedOptions} from "common/util/sorting"; +import {LANGUAGE_CHOICES} from 'web/components/filters/choices' +import {FilterFields} from 'common/filters' +import {getSortedOptions} from 'common/util/sorting' +import {useT} from 'web/lib/locale' export function LanguageFilterText(props: { options: string[] | undefined @@ -14,9 +15,13 @@ export function LanguageFilterText(props: { const {options, highlightedClass} = props const length = (options ?? []).length + const t = useT() + if (!options || length < 1) { return ( - Any language + + {t('filter.any_language', 'Any language')} + ) } @@ -24,14 +29,16 @@ export function LanguageFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) } const sortedOptions = getSortedOptions(options, LANGUAGE_CHOICES) - const convertedTypes = sortedOptions.map((r) => convertLanguageTypes(r as any)) + const convertedTypes = sortedOptions.map((r) => + t(`profile.language.${r}`, convertLanguageTypes(r as any)) + ) return (
@@ -54,6 +61,7 @@ export function LanguageFilter(props: { { updateFilter({languages: c}) }} diff --git a/web/components/filters/location-filter.tsx b/web/components/filters/location-filter.tsx index 2a89fad4..f2d68294 100644 --- a/web/components/filters/location-filter.tsx +++ b/web/components/filters/location-filter.tsx @@ -3,10 +3,11 @@ import {Col} from 'web/components/layout/col' import {Slider} from 'web/components/widgets/slider' import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state' import {Row} from 'web/components/layout/row' -import {City, CityRow, profileToCity, originToCity, useCitySearch,} from '../search-location' +import {City, CityRow, originToCity, profileToCity, useCitySearch,} from '../search-location' import {Profile} from 'common/profiles/profile' import {useEffect, useState} from 'react' import {Input} from 'web/components/widgets/input' +import {useT} from 'web/lib/locale' import {XIcon} from '@heroicons/react/solid' import {uniqBy} from 'lodash' import {buildArray} from 'common/util/array' @@ -20,11 +21,12 @@ export function LocationFilterText(props: { }) { const { location, radius, highlightedClass } = props + const t = useT() if (!location) { return ( - Any - location + {t('filter.location.any', 'Any')} + {t('filter.location', 'location')} ) } @@ -66,6 +68,8 @@ export function LocationFilter(props: { const youCity = youProfile && profileToCity(youProfile) + const t = useT() + const [lastCity, setLastCity] = usePersistentInMemoryState( location ? originToCity(location) : youCity || DEFAULT_LAST_CITY, 'last-used-city' @@ -94,7 +98,7 @@ export function LocationFilter(props: { setQuery(e.target.value)} - placeholder={'Search city...'} + placeholder={t('filter.location.search_city', 'Search city...')} className="h-8 w-full rounded-none border-0 bg-transparent px-1 focus:border-b focus:ring-0 focus:ring-transparent" autoFocus // onBlur // TODO @@ -169,6 +173,7 @@ function LocationResults(props: { } }, [loading]) + const t = useT() return ( {showAny && ( @@ -177,8 +182,8 @@ function LocationResults(props: { className="hover:bg-primary-200 hover:text-ink-950 cursor-pointer px-4 py-2 transition-colors" > - - Set to Any City + + {t('filter.location.set_any_city', 'Set to Any City')} )} diff --git a/web/components/filters/mbti-filter.tsx b/web/components/filters/mbti-filter.tsx index dde825be..91dd2f35 100644 --- a/web/components/filters/mbti-filter.tsx +++ b/web/components/filters/mbti-filter.tsx @@ -4,6 +4,7 @@ import {FilterFields} from 'common/filters' import {getSortedOptions} from 'common/util/sorting' import {MultiCheckbox} from 'web/components/multi-checkbox' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' +import {useT} from 'web/lib/locale' export function MbtiFilterText(props: { options: string[] | undefined @@ -11,9 +12,10 @@ export function MbtiFilterText(props: { defaultLabel?: string }) { const {options, highlightedClass, defaultLabel} = props + const t = useT() const length = (options ?? []).length - const label = defaultLabel || 'Any' + const label = defaultLabel || t('filter.any', 'Any') if (!options || length < 1) { return ( @@ -25,7 +27,7 @@ export function MbtiFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) @@ -57,6 +59,7 @@ export function MbtiFilter(props: { className={'grid grid-cols-2 xs:grid-cols-4'} selected={filters.mbti ?? []} choices={MBTI_CHOICES as any} + translationPrefix={'profile.mbti'} onChange={(c) => { updateFilter({mbti: c}) }} diff --git a/web/components/filters/mobile-filters.tsx b/web/components/filters/mobile-filters.tsx index a07825fa..3547e488 100644 --- a/web/components/filters/mobile-filters.tsx +++ b/web/components/filters/mobile-filters.tsx @@ -34,6 +34,7 @@ import {MbtiFilter, MbtiFilterText} from "web/components/filters/mbti-filter"; import {InterestFilter, InterestFilterText} from "web/components/filters/interest-filter"; import {OptionTableKey} from "common/profiles/constants"; import {NewBadge} from "web/components/new-badge"; +import {useT} from "web/lib/locale"; function MobileFilters(props: { filters: Partial @@ -46,6 +47,7 @@ function MobileFilters(props: { includeRelationshipFilters: boolean | undefined choices: Record> }) { + const t = useT() const { filters, youProfile, @@ -88,16 +90,16 @@ function MobileFilters(props: { /> {/* RELATIONSHIP STYLE */} { @@ -333,7 +335,7 @@ function MobileFilters(props: { {/* SMOKER */} void @@ -13,7 +14,8 @@ export function MyMatchesToggle(props: { return <> } - const label = 'Your filters' + const t = useT() + const label = t('filter.mine_toggle', 'Your filters') return ( diff --git a/web/components/filters/political-filter.tsx b/web/components/filters/political-filter.tsx index c0e4212d..23f48376 100644 --- a/web/components/filters/political-filter.tsx +++ b/web/components/filters/political-filter.tsx @@ -3,9 +3,11 @@ import {convertPoliticalTypes,} from 'web/lib/util/convert-types' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' -import {POLITICAL_CHOICES} from "web/components/filters/choices"; -import {FilterFields} from "common/filters"; -import {getSortedOptions} from "common/util/sorting"; +import {POLITICAL_CHOICES} from 'web/components/filters/choices' +import {FilterFields} from 'common/filters' +import {getSortedOptions} from 'common/util/sorting' +import {useT} from 'web/lib/locale' +import {toKey} from 'common/parsing' export function PoliticalFilterText(props: { options: string[] | undefined @@ -14,9 +16,13 @@ export function PoliticalFilterText(props: { const {options, highlightedClass} = props const length = (options ?? []).length + const t = useT() + if (!options || length < 1) { return ( - Any politics + + {t('filter.any_politics', 'Any politics')} + ) } @@ -24,14 +30,16 @@ export function PoliticalFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) } const sortedOptions = getSortedOptions(options, POLITICAL_CHOICES) - const convertedTypes = sortedOptions.map((r) => convertPoliticalTypes(r as any)) + const convertedTypes = sortedOptions.map((r) => + t(`profile.political.${toKey(r)}`, convertPoliticalTypes(r as any)) + ) return (
@@ -54,6 +62,7 @@ export function PoliticalFilter(props: { { updateFilter({political_beliefs: c}) }} diff --git a/web/components/filters/pref-gender-filter.tsx b/web/components/filters/pref-gender-filter.tsx index 7c01a2c4..69cb3a9c 100644 --- a/web/components/filters/pref-gender-filter.tsx +++ b/web/components/filters/pref-gender-filter.tsx @@ -1,35 +1,37 @@ import clsx from 'clsx' import GenderIcon from '../gender-icon' -import { Gender } from 'common/gender' -import { Row } from 'web/components/layout/row' -import { MultiCheckbox } from 'web/components/multi-checkbox' - -import {FilterFields} from "common/filters"; +import {Gender} from 'common/gender' +import {Row} from 'web/components/layout/row' +import {MultiCheckbox} from 'web/components/multi-checkbox' +import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' +import {GENDERS_PLURAL} from "web/components/filters/choices"; export function PrefGenderFilterText(props: { pref_gender: Gender[] | undefined highlightedClass?: string }) { - const { pref_gender, highlightedClass } = props + const {pref_gender, highlightedClass} = props + const t = useT() if (!pref_gender || pref_gender.length < 1) { return ( - Gender they seek: + {t('filter.gender.they_seek', 'Gender they seek')}: - any + {t('filter.any', 'any')} ) } return ( - Gender they seek: + {t('filter.gender.they_seek', 'Gender they seek')}: {pref_gender.map((gender) => { return ( updateFilter: (newState: Partial) => void }) { - const { filters, updateFilter } = props + const {filters, updateFilter} = props return ( { - updateFilter({ pref_gender: c }) + updateFilter({pref_gender: c}) }} /> ) diff --git a/web/components/filters/relationship-filter.tsx b/web/components/filters/relationship-filter.tsx index edd652e6..a9af1cdf 100644 --- a/web/components/filters/relationship-filter.tsx +++ b/web/components/filters/relationship-filter.tsx @@ -2,6 +2,7 @@ import clsx from 'clsx' import {convertRelationshipType, RelationshipType,} from 'web/lib/util/convert-types' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' +import {useT} from 'web/lib/locale' import {RELATIONSHIP_CHOICES} from "web/components/filters/choices"; import {FilterFields} from "common/filters"; @@ -13,21 +14,24 @@ export function RelationshipFilterText(props: { const {relationship, highlightedClass} = props const relationshipLength = (relationship ?? []).length + const t = useT() if (!relationship || relationshipLength < 1) { return ( - Any connection + + {t('filter.relationship.any_connection', 'Any connection')} + ) } const convertedRelationships = relationship.map((r) => - convertRelationshipType(r) + t(`profile.relationship.${r}`, convertRelationshipType(r)) ) if (relationshipLength > 1) { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) @@ -53,6 +57,7 @@ export function RelationshipFilter(props: { { updateFilter({pref_relation_styles: c}) }} diff --git a/web/components/filters/relationship-status-filter.tsx b/web/components/filters/relationship-status-filter.tsx index ad3d54d1..f6a16fb8 100644 --- a/web/components/filters/relationship-status-filter.tsx +++ b/web/components/filters/relationship-status-filter.tsx @@ -6,6 +6,7 @@ import {MultiCheckbox} from 'web/components/multi-checkbox' import {RELATIONSHIP_STATUS_CHOICES} from "web/components/filters/choices" import {FilterFields} from "common/filters" import {getSortedOptions} from "common/util/sorting" +import {useT} from 'web/lib/locale' export function RelationshipStatusFilterText(props: { options: string[] | undefined @@ -13,9 +14,10 @@ export function RelationshipStatusFilterText(props: { defaultLabel?: string }) { const {options, highlightedClass, defaultLabel} = props + const t = useT() const length = (options ?? []).length - const label = defaultLabel || 'Any' + const label = defaultLabel || t('filter.any', 'Any') if (!options || length < 1) { return ( @@ -27,14 +29,16 @@ export function RelationshipStatusFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) } const sortedOptions = getSortedOptions(options, RELATIONSHIP_STATUS_CHOICES) - const convertedTypes = sortedOptions.map((r) => convertRelationshipStatusTypes(r as any)) + const convertedTypes = sortedOptions.map((r) => + t(`profile.relationship_status.${r}`, convertRelationshipStatusTypes(r)) + ) return (
@@ -57,6 +61,7 @@ export function RelationshipStatusFilter(props: { { updateFilter({relationship_status: c}) }} diff --git a/web/components/filters/religion-filter.tsx b/web/components/filters/religion-filter.tsx index b5a39e01..67a0b9f0 100644 --- a/web/components/filters/religion-filter.tsx +++ b/web/components/filters/religion-filter.tsx @@ -1,11 +1,13 @@ import clsx from 'clsx' import {MultiCheckbox} from 'web/components/multi-checkbox' -import {FilterFields} from "common/filters"; -import {RELIGION_CHOICES} from "web/components/filters/choices"; -import {convertReligionTypes} from "web/lib/util/convert-types"; -import stringOrStringArrayToText from "web/lib/util/string-or-string-array-to-text"; -import {getSortedOptions} from "common/util/sorting"; +import {FilterFields} from 'common/filters' +import {RELIGION_CHOICES} from 'web/components/filters/choices' +import {convertReligionTypes} from 'web/lib/util/convert-types' +import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' +import {getSortedOptions} from 'common/util/sorting' +import {useT} from 'web/lib/locale' +import {toKey} from 'common/parsing' export function ReligionFilterText(props: { @@ -15,9 +17,13 @@ export function ReligionFilterText(props: { const {options, highlightedClass} = props const length = (options ?? []).length + const t = useT() + if (!options || length < 1) { return ( - Any religion + + {t('filter.any_religion', 'Any religion')} + ) } @@ -25,14 +31,16 @@ export function ReligionFilterText(props: { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) } const sortedOptions = getSortedOptions(options, RELIGION_CHOICES) - const convertedTypes = sortedOptions.map((r) => convertReligionTypes(r as any)) + const convertedTypes = sortedOptions.map((r) => + t(`profile.religion.${toKey(r)}`, convertReligionTypes(r as any)) + ) return (
@@ -57,6 +65,7 @@ export function ReligionFilter(props: { { updateFilter({religion: c}) }} diff --git a/web/components/filters/romantic-filter.tsx b/web/components/filters/romantic-filter.tsx index 8e53fae5..05f81ca4 100644 --- a/web/components/filters/romantic-filter.tsx +++ b/web/components/filters/romantic-filter.tsx @@ -3,31 +3,36 @@ import {convertRomanticTypes, RomanticType,} from 'web/lib/util/convert-types' import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text' import {MultiCheckbox} from 'web/components/multi-checkbox' -import {ROMANTIC_CHOICES} from "web/components/filters/choices"; -import {FilterFields} from "common/filters"; +import {ROMANTIC_CHOICES} from 'web/components/filters/choices' +import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' +import {toKey} from "common/parsing"; export function RomanticFilterText(props: { relationship: RomanticType[] | undefined highlightedClass?: string }) { const {relationship, highlightedClass} = props + const t = useT() const length = (relationship ?? []).length if (!relationship || length < 1) { return ( - Any relationship + + {t('filter.any_relationship', 'Any relationship')} + ) } const convertedTypes = relationship.map((r) => - convertRomanticTypes(r) + t(`profile.romantic.${toKey(r)}`, convertRomanticTypes(r)) ) if (length > 1) { return ( - Multiple + {t('filter.multiple', 'Multiple')} ) @@ -53,6 +58,7 @@ export function RomanticFilter(props: { { updateFilter({pref_romantic_styles: c}) }} diff --git a/web/components/filters/short-bio-toggle.tsx b/web/components/filters/short-bio-toggle.tsx index d320348e..161ae7bb 100644 --- a/web/components/filters/short-bio-toggle.tsx +++ b/web/components/filters/short-bio-toggle.tsx @@ -1,6 +1,7 @@ import {Row} from 'web/components/layout/row' import clsx from 'clsx' import {FilterFields} from "common/filters"; +import {useT} from "web/lib/locale"; export function ShortBioToggle(props: { filters: Partial @@ -12,7 +13,8 @@ export function ShortBioToggle(props: { return <> } - const label = 'Include Short Bios' + const t = useT() + const label = t('filter.short_bio_toggle', 'Include Short Bios') const on = filters.shortBio || false diff --git a/web/components/filters/smoker-filter.tsx b/web/components/filters/smoker-filter.tsx index 3754bd37..f33aa88a 100644 --- a/web/components/filters/smoker-filter.tsx +++ b/web/components/filters/smoker-filter.tsx @@ -2,6 +2,7 @@ import clsx from 'clsx' import {Row} from 'web/components/layout/row' import {ChoicesToggleGroup} from 'web/components/widgets/choices-toggle-group' import {FilterFields} from 'common/filters' +import {useT} from 'web/lib/locale' export function SmokerFilterText(props: { is_smoker: boolean | null | undefined @@ -9,14 +10,15 @@ export function SmokerFilterText(props: { mobile?: boolean }) { const {is_smoker, highlightedClass, mobile} = props + const t = useT() return ( {is_smoker == null - ? mobile ? 'Either' : 'Either' + ? t('common.either', 'Either') : is_smoker - ? mobile ? 'Yes' : 'Smoker' - : mobile ? 'No' : "Non-smoker"} + ? mobile ? t('common.yes', 'Yes') : t('profile.smoker.yes', 'Smoker') + : mobile ? t('common.no', 'No') : t('profile.smoker.no', 'Non-smoker')} ) @@ -34,16 +36,16 @@ export function SmokerFilter(props: { No: 'no', } as const - const currentChoice = - filters.is_smoker == null ? choicesMap.Either : filters.is_smoker ? choicesMap.Yes : choicesMap.No + const currentChoice = filters.is_smoker == null ? 'either' : filters.is_smoker ? 'yes' : 'no' return ( { - if (c === choicesMap.Either) updateFilter({is_smoker: undefined}) - else if (c === choicesMap.Yes) updateFilter({is_smoker: true}) + if (c === 'either') updateFilter({is_smoker: undefined}) + else if (c === 'yes') updateFilter({is_smoker: true}) else updateFilter({is_smoker: false}) }} toggleClassName="w-1/3 justify-center" diff --git a/web/components/filters/wants-kids-filter.tsx b/web/components/filters/wants-kids-filter.tsx index 0a36de1c..85dff297 100644 --- a/web/components/filters/wants-kids-filter.tsx +++ b/web/components/filters/wants-kids-filter.tsx @@ -6,6 +6,7 @@ import clsx from 'clsx' import {FilterFields} from "common/filters"; import {generateChoicesMap, KidLabel, wantsKidsLabels} from "common/wants-kids" +import {useT} from "web/lib/locale"; interface KidLabelWithIcon extends KidLabel { icon: ReactNode @@ -15,25 +16,35 @@ interface KidsLabelsMapWithIcon { [key: string]: KidLabelWithIcon } -export const wantsKidsLabelsWithIcon: KidsLabelsMapWithIcon = { - ...wantsKidsLabels, - no_preference: { - ...wantsKidsLabels.no_preference, - icon: , - }, - wants_kids: { - ...wantsKidsLabels.wants_kids, - icon: , - }, - doesnt_want_kids: { - ...wantsKidsLabels.doesnt_want_kids, - icon: , - }, +export const useWantsKidsLabelsWithIcon = () => { + const t = useT() + return { + no_preference: { + ...wantsKidsLabels.no_preference, + name: t('filter.wants_kids.any_preference', 'Any preference'), + shortName: t('filter.wants_kids.either', 'Either'), + icon: , + }, + wants_kids: { + ...wantsKidsLabels.wants_kids, + name: t('filter.wants_kids.wants_kids', 'Wants kids'), + shortName: t('common.yes', 'Yes'), + icon: , + }, + doesnt_want_kids: { + ...wantsKidsLabels.doesnt_want_kids, + name: t('filter.wants_kids.doesnt_want_kids', "Doesn't want kids"), + shortName: t('common.no', 'No'), + icon: , + }, + } as KidsLabelsMapWithIcon } export function WantsKidsIcon(props: { strength: number; className?: string }) { const {strength, className} = props + const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon() + return ( {strength == wantsKidsLabelsWithIcon.no_preference.strength @@ -51,6 +62,7 @@ export function KidsLabel(props: { mobile?: boolean }) { const {strength, highlightedClass, mobile} = props + const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon() return ( @@ -82,6 +94,7 @@ export function WantsKidsFilter(props: { updateFilter: (newState: Partial) => void }) { const {filters, updateFilter} = props + const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon() return ( value choices: { [key: string]: string } @@ -119,7 +119,7 @@ export const MultiCheckbox = (props: { {filteredEntries.map(([key, value]) => ( { if (checked) { diff --git a/web/components/profile/delete-yourself.tsx b/web/components/profile/delete-yourself.tsx index c8d311f7..56aec956 100644 --- a/web/components/profile/delete-yourself.tsx +++ b/web/components/profile/delete-yourself.tsx @@ -12,18 +12,18 @@ import {useT} from 'web/lib/locale' export function DeleteYourselfButton() { const [deleteAccountConfirmation, setDeleteAccountConfirmation] = useState('') const t = useT() - const confirmPhrase = t('deleteyourself.confirm_phrase', 'delete my account') + const confirmPhrase = t('delete_yourself.confirm_phrase', 'delete my account') return ( , color: 'red', }} submitBtn={{ - label: t('deleteyourself.submit', 'Delete account'), + label: t('delete_yourself.submit', 'Delete account'), color: deleteAccountConfirmation == confirmPhrase ? 'red' : 'gray', }} @@ -31,13 +31,13 @@ export function DeleteYourselfButton() { if (deleteAccountConfirmation == confirmPhrase) { toast .promise(deleteAccount(), { - loading: t('deleteyourself.toast.loading', 'Deleting account...'), + loading: t('delete_yourself.toast.loading', 'Deleting account...'), success: () => { router.push('/') - return t('deleteyourself.toast.success', 'Your account has been deleted.') + return t('delete_yourself.toast.success', 'Your account has been deleted.') }, error: () => { - return t('deleteyourself.toast.error', 'Failed to delete account.') + return t('delete_yourself.toast.error', 'Failed to delete account.') }, }) .then(() => { @@ -51,16 +51,16 @@ export function DeleteYourselfButton() { }} > - {t('deleteyourself.title', 'Are you sure?')} + {t('delete_yourself.title', 'Are you sure?')}
{t( - 'deleteyourself.description', + 'delete_yourself.description', 'Deleting your account means you will no longer be able to use your account. You will lose access to all of your data.' )}
setDeleteAccountConfirmation(e.target.value)} diff --git a/web/components/widgets/choices-toggle-group.tsx b/web/components/widgets/choices-toggle-group.tsx index 7e0c0de8..3e5f14da 100644 --- a/web/components/widgets/choices-toggle-group.tsx +++ b/web/components/widgets/choices-toggle-group.tsx @@ -1,5 +1,7 @@ -import { RadioGroup } from '@headlessui/react' +import {RadioGroup} from '@headlessui/react' import clsx from 'clsx' +import {toKey} from "common/parsing"; +import {useT} from "web/lib/locale"; const colorClasses = { 'indigo-dark': @@ -15,16 +17,17 @@ export type ColorType = keyof typeof colorClasses export function ChoicesToggleGroup>( props: { - currentChoice: T[keyof T] | undefined | null - choicesMap: T - disabled?: boolean - disabledOptions?: Array - setChoice: (val: T[keyof T]) => void - color?: ColorType - className?: string - toggleClassName?: string - children?: React.ReactNode -}) { + currentChoice: T[keyof T] | undefined | null + choicesMap: T + disabled?: boolean + disabledOptions?: Array + setChoice: (val: T[keyof T]) => void + color?: ColorType + className?: string + toggleClassName?: string + children?: React.ReactNode + translationPrefix?: string + }) { const { currentChoice, setChoice, @@ -35,7 +38,12 @@ export function ChoicesToggleGroup ( + // console.log(`${translationPrefix}.${toKey(String(choice))}`) + // )) return ( + className={({disabled}) => clsx( disabled ? 'text-ink-300 aria-checked:bg-ink-300 aria-checked:text-ink-0 cursor-not-allowed' @@ -62,7 +70,8 @@ export function ChoicesToggleGroup - {choiceKey} + {translationPrefix ? t(`${translationPrefix}.${toKey(String(choice))}`, choiceKey) : choiceKey} ))} {children} diff --git a/web/messages/fr.json b/web/messages/fr.json index 43df6c96..958a9ce3 100644 --- a/web/messages/fr.json +++ b/web/messages/fr.json @@ -1,659 +1,456 @@ { - "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", - "settings.general.account": "Compte", - "settings.general.email": "Courriel", - "settings.email.verified": "Courriel vérifié ✔️", - "settings.email.send_verification": "Envoyer un courriel de vérification", - "settings.email.change": "Modifier l'adresse e‑mail", - "settings.email.new_placeholder": "Nouvelle adresse e‑mail", - "settings.email.required": "Le courriel est requis", - "settings.email.invalid": "Adresse e‑mail invalide", - "settings.action.save": "Enregistrer", - "settings.action.cancel": "Annuler", - "settings.general.password": "Mot de passe", - "settings.password.send_reset": "Envoyer un e‑mail de réinitialisation de mot de passe", - "settings.danger_zone": "Zone dangereuse", - "settings.delete_account": "Supprimer le compte", - "settings.delete_confirm": "Êtes-vous sûr de vouloir supprimer votre profil ? Cela ne peut pas être annulé.", - "settings.delete.loading": "Suppression du compte..", - "settings.delete.success": "Votre compte a été supprimé.", - "settings.delete.error": "Échec de la suppression du compte.", - "settings.email.updated_success": "Adresse e‑mail mise à jour avec succès", - "settings.email.update_failed": "Échec de la mise à jour de l'adresse e‑mail", - "settings.email.same_as_current": "Le nouveau courriel est identique à l'actuel", - "settings.email.no_email": "Aucun courriel trouvé sur votre compte.", - "settings.email.must_sign_in": "Vous devez être connecté pour envoyer un courriel de vérification.", - "settings.email.sending": "Envoi du courriel de vérification...", - "settings.email.verification_sent": "Courriel de vérification envoyé — vérifiez votre boîte de réception et les spams.", - "settings.email.verification_failed": "Échec de l'envoi du courriel de vérification.", - "home.title": "Fini les swipes.", - "home.typewriter": "Cherche.", - "home.sign_up": "S'inscrire", - "home.subtitle": "Trouvez des personnes qui partagent vos valeurs, idées et intentions — pas seulement vos photos.", - "home.feature1.title": "Transparence radicale", - "home.feature1.text": "Pas d’algorithmes. Chaque profil est consultable. Vous décidez qui découvrir.", - "home.feature2.title": "Conçu pour la profondeur", - "home.feature2.text": "Recherchez et filtrez par valeurs, centres d’intérêt, objectifs et mots-clés — de « stoïcisme » à « vie durable ». Faites émerger les connexions qui comptent vraiment.", - "home.feature3.title": "Communautaire & Open Source", - "home.feature3.text": "Gratuit pour toujours. Pas de pubs, pas d’abonnements. Construit par et pour la communauté.", - "home.bottom": "Compass est aux relations humaines ce que Linux est au logiciel, Wikipédia est au savoir, et Firefox est à la navigation — un bien numérique public conçu pour servir les gens, pas le profit.", - "nav.sign_in": "Se connecter", - "nav.sign_out": "Se déconnecter", - "nav.sign_up": "S'inscrire", - "nav.sign_up_now": "S'inscrire maintenant", - "nav.people": "Personnes", - "nav.home": "Accueil", - "nav.faq": "FAQ", - "nav.about": "À propos", - "nav.notifs": "Notifications", - "nav.messages": "Messages", - "nav.social": "Social", - "nav.organization": "Organisation", - "nav.vote": "Vote", - "nav.contact": "Contact", - "nav.news": "Quoi de neuf", - "news.title": "Quoi de neuf", - "news.seo.description": "Voir les dernières mises à jour et fonctionnalités", - "news.seo.description_general": "Toutes les actualités et mises à jour du code pour Compass", - "news.failed": "Échec de la récupération des versions.", - "news.no_release_notes": "_Aucune note de version fournie._", - "news.view_on_github": "Voir sur GitHub", - "nav.settings": "Paramètres", - "nav.more": "Plus", - "nav.profile": "Profil", - "about.seo.title": "À propos", - "about.seo.description": "À propos de Compass", - "about.title": "Pourquoi choisir Compass ?", - "about.subtitle": "Trouvez vos personnes en toute simplicité.", - "about.block.keyword.title": "Recherche par mots-clés", - "about.block.keyword.text": "\"Méditation\", \"Randonnée\", \"Neurosciences\", \"Nietzsche\". Accédez à n'importe quel profil et trouvez votre niche.", - "about.block.notify.title": "Recevez des notifications de recherches", - "about.block.notify.text": "Plus besoin de vérifier constamment l'application ! Nous vous contacterons lorsque de nouveaux utilisateurs correspondent à vos recherches.", - "about.block.free.title": "Gratuit", - "about.block.free.text": "Sans abonnement. Sans paywall. Sans publicité.", - "about.block.personality.title": "Centré sur la personnalité", - "about.block.personality.text": "Valeurs et centres d'intérêt d'abord, les photos sont secondaires.", - "about.block.transparent.title": "Transparence", - "about.block.transparent.text": "Code open source et conception communautaire.", - "about.block.democratic.title": "Démocratique", - "about.block.democratic.prefix": "Gouverné et ", + "about.block.democratic.link_constitution": "constitution", "about.block.democratic.link_voted": "voté", "about.block.democratic.middle": " par la communauté, tout en garantissant aucune dérive via notre ", - "about.block.democratic.link_constitution": "constitution", + "about.block.democratic.prefix": "Gouverné et ", "about.block.democratic.suffix": ".", - "about.block.mission.title": "Une mission", + "about.block.democratic.title": "Démocratique", + "about.block.free.text": "Sans abonnement. Sans paywall. Sans publicité.", + "about.block.free.title": "Gratuit", + "about.block.keyword.text": "\"Méditation\", \"Randonnée\", \"Neurosciences\", \"Nietzsche\". Accédez à n'importe quel profil et trouvez votre niche.", + "about.block.keyword.title": "Recherche par mots-clés", "about.block.mission.text": "Notre unique mission est de créer plus de relations humaines authentiques, et chaque décision doit servir cet objectif.", - "about.block.vision.title": "Vision", + "about.block.mission.title": "Une mission", + "about.block.notify.text": "Plus besoin de vérifier constamment l'application ! Nous vous contacterons lorsque de nouveaux utilisateurs correspondent à vos recherches.", + "about.block.notify.title": "Recevez des notifications de recherches", + "about.block.personality.text": "Valeurs et centres d'intérêt d'abord, les photos sont secondaires.", + "about.block.personality.title": "Centré sur la personnalité", + "about.block.transparent.text": "Code open source et conception communautaire.", + "about.block.transparent.title": "Transparence", "about.block.vision.text": "Compass est aux relations humaines ce que Linux, Wikipédia et Firefox sont aux logiciels et au savoir : un bien public construit par les personnes qui l'utilisent, pour le bien de tous.", - "about.help.title": "Aidez Compass", - "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 e‑mail", - "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.block.vision.title": "Vision", "about.dev.button": "Voir le code", - "about.join.title": "Rejoindre la communauté", - "about.join.text": "Façonnons la plateforme ensemble.", - "about.join.button": "Rejoindre le Discord", - "about.donate.title": "Faire un don", - "about.donate.text": "Soutenez notre infrastructure à but non lucratif.", + "about.dev.text": "Le code source complet et les instructions sont disponibles sur GitHub.", + "about.dev.title": "Développer l'application", "about.donate.button": "Options de don", - "about.final.title": "Parlez-en à vos amis et votre famille", + "about.donate.text": "Soutenez notre infrastructure à but non lucratif.", + "about.donate.title": "Faire un don", "about.final.text": "Merci de soutenir notre mission !", - "stats.seo.title": "Statistiques", - "stats.seo.description": "Statistiques", - "stats.title": "Croissance et statistiques", - "stats.members": "Membres", - "stats.active_members": "Membres actifs (le mois dernier)", - "stats.discussions": "Discussions", - "stats.total": "Total", - "stats.with_bio": "Avec bio", - "stats.messages": "Messages", - "stats.compatibility_prompts": "Questions de compatibilité", - "stats.prompts_answered": "Questions répondues", - "stats.proposals": "Propositions", - "stats.votes": "Votes", - "stats.searches_bookmarked": "Recherches mises en favoris", - "stats.endorsements": "Recommandations", - "stats.number_members": "Nombre de membres", + "about.final.title": "Parlez-en à vos amis et votre famille", + "about.help.title": "Aidez Compass", + "about.join.button": "Rejoindre le Discord", + "about.join.text": "Façonnons la plateforme ensemble.", + "about.join.title": "Rejoindre la communauté", + "about.seo.description": "À propos de Compass", + "about.seo.title": "À propos", + "about.subtitle": "Trouvez vos personnes en toute simplicité.", + "about.suggestions.button": "Suggérer ici", + "about.suggestions.text": "Faites des suggestions ou dites-nous que vous voulez aider via ce formulaire !", + "about.suggestions.title": "Faire des suggestions ou contribuer", + "about.title": "Pourquoi choisir Compass ?", + "about.settings.copied": "Copié !", + "about.settings.copy_info": "Copier les infos", + "add_photos.add_description": "Ajouter une description", + "add_photos.profile_picture_hint": "L'image mise en surbrillance est votre photo de profil", + "answers.add.error_create": "Erreur lors de la création de la question de compatibilité. Réessayez ?", + "answers.add.submit_own": "Proposez la vôtre !", + "answers.answer.answer_skipped": "Répondre à {n} questions ignorées", + "answers.answer.answer_yourself": "Répondez vous-même", + "answers.answer.cta": "Répondre{core} aux questions", + "answers.answer.view_list": "Voir la liste des questions", + "answers.compatible": "Compatible", + "answers.content.answers_you_accept": "Réponses que vous acceptez", + "answers.content.your_thoughts": "Vos pensées (optionnelles, mais recommendées)", + "answers.display.acceptable": "Acceptable", + "answers.display.add_some": "Ajoutez-en pour mieux voir avec qui vous seriez le plus compatible.", + "answers.display.already_answered_all": "Vous avez déjà répondu à toutes les questions de compatibilité —", + "answers.display.also_acceptable": "Également acceptable", + "answers.display.answer_more": "Répondez à plus de questions pour augmenter vos scores de compatibilité — ou ", + "answers.display.none": "Aucune", + "answers.display.none_answered_user": "{name} n'a pas encore répondu aux questions de compatibilité !", + "answers.display.none_answered_you": "Vous n'avez pas encore répondu aux questions de compatibilité !", + "answers.display.user_prompts": "Questions de compatibilité de {name}", + "answers.display.your_prompts": "Vos questions de compatibilité", + "answers.finish": "Terminer", + "answers.free.add_free_response": "Ajouter une réponse libre", + "answers.free.choose_question": "Choisissez une question à laquelle répondre", + "answers.free.see_others": "Voir {count} autres réponses", + "answers.importance.0": "Peu important", + "answers.importance.1": "Assez important", + "answers.importance.2": "Important", + "answers.importance.3": "Très important", + "answers.incompatible": "Incompatible", + "answers.menu.delete": "Supprimer", + "answers.menu.edit": "Modifier", + "answers.menu.skip": "Ignorer", + "answers.modal.preferred_of_user": "Les réponses préférées de {name}", + "answers.modal.user_marked": "{name} a marqué ceci comme ", + "answers.modal.you_marked": "Vous avez marqué ceci comme ", + "answers.modal.your_preferred": "Vos réponses préférées", + "answers.next": "Suivant", + "answers.opinion.edit": "Modifier", + "answers.opinion.fill": "Remplir l'échelle d'opinion", + "answers.preferred.user_answer": "La réponse de {name}", + "answers.preferred.your_answer": "Votre réponse", + "answers.sort.important_to_them": "Important pour {name}", + "answers.sort.important_to_user": "Important pour {name}", + "answers.sort.important_to_you": "Important pour vous", + "answers.sort.incompatible": "Incompatible", + "answers.sort.unanswered_by_you": "Sans réponse de votre part", + "block_user.block": "Bloquer", + "block_user.toast.error": "Erreur lors du blocage de l'utilisateur", + "block_user.toast.loading": "Blocage en cours...", + "block_user.toast.success": "Vous ne verrez plus le contenu de cet utilisateur", + "block_user.unblock": "Débloquer", + "button.share.label": "Partager", "charts.date": "Date", - "contact.seo.title": "Contact", - "contact.seo.description": "Contactez-nous", - "contact.title": "Contact", - "contact.intro_prefix": "Vous pouvez aussi nous contacter via ce ", - "contact.form_link": "formulaire de retour", - "contact.intro_middle": " ou via nos ", - "contact.socials": "réseaux", - "contact.intro_suffix": ". N'hésitez pas à laisser vos coordonnées si vous souhaitez que nous revenions vers vous.", - "contact.editor.placeholder": "Contactez-nous ici...", - "contact.submit": "Envoyer", - "contact.toast.failed": "Échec de l'envoi — réessayez ou contactez-nous...", - "contact.toast.success": "Merci pour votre message !", - "vote.seo.title": "Propositions", - "vote.seo.description": "Un endroit pour voter sur les décisions", - "vote.title": "Propositions", - "vote.order.label": "Trier par :", - "vote.discuss.prefix": "Vous pouvez discuter de ces propositions via le ", - "vote.discuss.link_contact": "formulaire de contact", - "vote.discuss.middle": ", le ", - "vote.discuss.link_feedback": "formulaire de retour", - "vote.discuss.and": ", ou sur nos ", - "vote.discuss.link_socials": "réseaux", - "vote.discuss.suffix": ".", - "vote.showmore.closed": "Ajouter une nouvelle proposition", - "vote.showmore.open": "Masquer", - "vote.form.title_placeholder": "Titre", - "vote.form.anonymous": "Anonyme ?", - "vote.form.submit": "Soumettre", - "vote.toast.create_failed": "Échec de la création de la proposition — réessayez ou contactez-nous...", - "vote.toast.created": "Proposition créée", - "vote.creator.placeholder": "Veuillez décrire votre proposition ici", - "vote.sign_in_required": "Veuillez vous connecter pour voter", - "vote.voted": "Vote enregistré", - "vote.with_priority": "avec priorité", - "vote.failed": "Échec du vote — veuillez réessayer", - "vote.for": "Pour", - "vote.abstain": "Abstention", - "vote.against": "Contre", - "vote.priority": "Priorité", - "vote.urgent": "Urgente", - "vote.high": "Haute", - "vote.medium": "Moyenne", - "vote.low": "Faible", - "vote.sort.recent": "Plus récents", - "vote.sort.mostVoted": "Plus votés", - "vote.sort.priority": "Plus prioritaires", - "vote.status.draft": "Brouillon", - "vote.status.under_review": "En révision", - "vote.status.voting_open": "Vote ouvert", - "vote.status.voting_closed": "Vote clos", - "vote.status.accepted": "Accepté", - "vote.status.pending": "En attente d'implémentation", - "vote.status.implemented": "Implémenté ✔️", - "vote.status.rejected": "Rejeté ❌", - "vote.status.cancelled": "Annulé 🚫", - "vote.status.superseded": "Remplacé", - "vote.status.expired": "Expiré ⌛", - "vote.status.archived": "Archivé", - "signin.seo.title": "Se connecter", - "signin.seo.description": "Connectez-vous à votre compte", - "signin.title": "Se connecter", - "signin.email": "Courriel", - "signin.password": "Mot de passe", - "signin.password_placeholder": "Votre mot de passe", - "signin.submit": "Se connecter", - "signin.no_account": "Vous n'avez pas de compte ?", - "signin.link_sign_up": "S'inscrire", - "signin.forgot_password": "Mot de passe oublié ?", - "signin.enter_email": "Veuillez taper votre email", - "signin.continue": "Ou continuez avec", - "signup.seo.title": "S'inscrire", - "signup.seo.description": "Créez un nouveau compte", - "signup.title": "Créer un compte", - "signin.failed_credentials": "Echec de connexion avec cet email et mot de passe", - "signup.name": "Nom", - "signup.name_placeholder": "Votre nom", - "signup.email": "Courriel", - "signup.email_placeholder": "vous@exemple.com", - "signup.password": "Mot de passe", - "signup.password_placeholder": "Créez un mot de passe", - "signup.password_confirm": "Confirmez le mot de passe", - "signup.password_confirm_placeholder": "Confirmez votre mot de passe", - "signup.submit": "Créer le compte", - "signup.have_account": "Vous avez déjà un compte ?", - "signup.link_sign_in": "Se connecter", - "signup.error_password_mismatch": "Les mots de passe ne correspondent pas", - "signup.toast.created": "Compte créé", - "register.seo.title": "S'inscrire", - "register.seo.description": "Inscrivez-vous pour un nouveau compte", - "register.check_email.title": "Vérifiez votre courriel", - "register.check_email.sent_prefix": "Nous avons envoyé un lien de vérification à ", - "register.check_email.sent_suffix": ".", - "register.check_email.help_prefix": "Vous n'avez pas reçu l'e-mail ? Vérifiez vos spams ou ", - "register.check_email.try_again": "réessayez", - "register.check_email.help_suffix": ".", - "register.back_to_login": "Retour à la connexion", - "register.get_started": "Commencer", - "register.email_label": "Courriel", - "register.email_placeholder": "Courriel", - "register.password_label": "Mot de passe", - "register.password_placeholder": "Mot de passe", - "register.agreement.prefix": "En vous inscrivant, j'accepte les ", - "register.terms": "Conditions générales", - "register.agreement.and": " et ", - "register.privacy": "Politique de confidentialité", - "register.agreement.suffix": ".", - "register.error.all_fields_required": "Tous les champs sont requis", - "register.error.email_in_use": "Cet e‑mail est déjà enregistré", - "register.error.unknown": "Échec de l'inscription", - "register.toast.signup_failed": "Échec de l'inscription : ", - "register.button.creating": "Création du compte..", - "register.button.email": "S'inscrire avec l'e‑mail", - "register.or_sign_up_with": "Ou inscrivez-vous avec", - "register.already_account": "Vous avez déjà un compte ?", - "register.link_signin": "Se connecter", - "compatibility.title": "Vos questions de compatibilité", - "compatibility.tabs.answered": "Répondu", - "compatibility.tabs.to_answer": "À répondre", - "compatibility.tabs.skipped": "Ignorés", - "compatibility.sign_in_prompt": "Veuillez vous connecter pour voir vos questions de compatibilité", + "common.active": "Actif", + "common.add": "Ajouter", + "common.close": "Fermer", + "common.compatible": "Compatible", + "common.either": "N'importe", + "common.new": "Nouveau", + "common.next": "Suivant", + "common.no": "Non", + "common.notified": "Être notifié", + "common.or": "Ou", + "common.people": "personnes", + "common.per_month": "/ mois", + "common.person": "personne", + "common.saved": "Enregistré !", + "common.yes": "Oui", "compatibility.empty.answered": "Vous n'avez répondu à aucune question pour le moment.", "compatibility.empty.not_answered": "Toutes les questions ont été répondues !", "compatibility.empty.skipped": "Vous n'avez ignoré aucune question.", - "delete.seo.title": "Supprimer le compte", - "delete.seo.description": "Demander la suppression du compte pour Compass", - "delete.title": "Supprimer votre compte", - "delete.intro": "Nous sommes désolés de vous voir partir. Vous pouvez supprimer votre compte depuis la page Paramètres. Sinon, voici comment demander la suppression de votre compte par e‑mail.", - "delete.how.title": "Comment supprimer votre compte", - "delete.how.step1": "Envoyez un e‑mail à", - "delete.how.step1_subject": "avec l'objet « Demande de suppression de compte »", - "delete.how.step2": "Incluez votre nom d'utilisateur et l'adresse e‑mail associée à votre compte", - "delete.how.step3": "Indiquez si vous souhaitez télécharger vos données avant la suppression", - "delete.how.step4": "Nous traiterons votre demande sous 30 jours", - "delete.request_button": "Demander la suppression du compte", - "delete.what_happens.title": "Ce qui se passe lorsque vous supprimez votre compte", - "delete.what_happens.profile": "Votre profil, y compris toutes les photos et informations personnelles, sera supprimé définitivement", - "delete.what_happens.messages": "Vos messages seront supprimés de nos serveurs", - "delete.what_happens.username": "Votre nom d'utilisateur pourra être réutilisé par d'autres", - "delete.what_happens.history": "Votre historique d'activité sera anonymisé", - "delete.data.title": "Données que nous conservons", + "compatibility.sign_in_prompt": "Veuillez vous connecter pour voir vos questions de compatibilité", + "compatibility.tabs.answered": "Répondu", + "compatibility.tabs.skipped": "Ignorés", + "compatibility.tabs.to_answer": "À répondre", + "compatibility.title": "Vos questions de compatibilité", + "contact.editor.placeholder": "Contactez-nous ici...", + "contact.form_link": "formulaire de retour", + "contact.intro_middle": " ou via nos ", + "contact.intro_prefix": "Vous pouvez aussi nous contacter via ce ", + "contact.intro_suffix": ". N'hésitez pas à laisser vos coordonnées si vous souhaitez que nous revenions vers vous.", + "contact.seo.description": "Contactez-nous", + "contact.seo.title": "Contact", + "contact.socials": "réseaux", + "contact.submit": "Envoyer", + "contact.title": "Contact", + "contact.toast.failed": "Échec de l'envoi — réessayez ou contactez-nous...", + "contact.toast.success": "Merci pour votre message !", "delete.data.intro": "Pour des raisons légales et opérationnelles, nous pouvons conserver certaines informations après la suppression du compte :", "delete.data.item1": "Dossiers de transaction (le cas échéant) pour la comptabilité et la conformité", "delete.data.item2": "Copies des communications avec notre équipe de support", "delete.data.item3": "Informations nécessaires pour prévenir la fraude, respecter des obligations légales ou faire respecter nos conditions", "delete.data.note": "Nous ne conservons ces données que le temps nécessaire à ces fins et conformément à notre Politique de confidentialité.", - "delete.need_help.title": "Besoin d'aide ?", + "delete.data.title": "Données que nous conservons", + "delete.how.step1": "Envoyez un e‑mail à", + "delete.how.step1_subject": "avec l'objet « Demande de suppression de compte »", + "delete.how.step2": "Incluez votre nom d'utilisateur et l'adresse e‑mail associée à votre compte", + "delete.how.step3": "Indiquez si vous souhaitez télécharger vos données avant la suppression", + "delete.how.step4": "Nous traiterons votre demande sous 30 jours", + "delete.how.title": "Comment supprimer votre compte", + "delete.intro": "Nous sommes désolés de vous voir partir. Vous pouvez supprimer votre compte depuis la page Paramètres. Sinon, voici comment demander la suppression de votre compte par e‑mail.", "delete.need_help.text": "Si vous avez des questions concernant la suppression du compte ou besoin d'assistance, veuillez contacter notre équipe de support à", - "donate.seo.title": "Faire un don", + "delete.need_help.title": "Besoin d'aide ?", + "delete.request_button": "Demander la suppression du compte", + "delete.seo.description": "Demander la suppression du compte pour Compass", + "delete.seo.title": "Supprimer le compte", + "delete.title": "Supprimer votre compte", + "delete.what_happens.history": "Votre historique d'activité sera anonymisé", + "delete.what_happens.messages": "Vos messages seront supprimés de nos serveurs", + "delete.what_happens.profile": "Votre profil, y compris toutes les photos et informations personnelles, sera supprimé définitivement", + "delete.what_happens.title": "Ce qui se passe lorsque vous supprimez votre compte", + "delete.what_happens.username": "Votre nom d'utilisateur pourra être réutilisé par d'autres", + "delete_yourself.confirm_phrase": "delete my account", + "delete_yourself.description": "Supprimer votre compte signifie que vous ne pourrez plus l'utiliser. Vous perdrez l'accès à toutes vos données.", + "delete_yourself.input_placeholder": "Tapez 'delete my account' pour confirmer", + "delete_yourself.open_label": "Supprimer définitivement ce compte", + "delete_yourself.submit": "Supprimer le compte", + "delete_yourself.title": "Êtes-vous sûr ?", + "delete_yourself.toast.error": "Échec de la suppression du compte.", + "delete_yourself.toast.loading": "Suppression du compte..", + "delete_yourself.toast.success": "Votre compte a été supprimé.", "donate.seo.description": "Faites un don pour soutenir Compass", + "donate.seo.title": "Faire un don", "donate.title": "Faire un don", - "profile.seo.title": "Profil", - "profile.seo.description": "Votre profil", - "profile.save": "Enregistrer", - "privacy.seo.title": "Confidentialité", - "privacy.seo.description": "Politique de confidentialité pour Compass", - "privacy.title": "Politique de confidentialité", - "privacy.effective_date": "Date d'entrée en vigueur : 1er janvier 2025", - "privacy.intro.prefix": "Chez ", - "privacy.intro.suffix": ", nous accordons de l'importance à la transparence et au respect de vos données. Cette politique de confidentialité explique comment nous traitons vos informations.", - "profile.optional.title": "Plus d'informations à mon sujet", - "profile.optional.subtitle": "Informations optionnelles", - "profile.optional.location": "Localisation", - "profile.optional.search_city": "Rechercher une ville...", - "profile.optional.age": "Âge", - "profile.optional.gender": "Genre", - "profile.optional.interested_in": "Intéressé(e) par", - "profile.optional.age_range": "Âgés entre", - "profile.optional.connection_type": "Type de relation", - "profile.optional.relationship_status": "Situation amoureuse", - "profile.optional.relationship_style": "Style de relation", - "profile.optional.want_kids": "Je souhaite avoir des enfants", - "profile.optional.num_kids": "Nombre actuel d'enfants", - "profile.optional.socials": "Réseaux sociaux", - "profile.optional.username_or_url": "Nom d'utilisateur ou URL", - "profile.optional.site_url": "URL du site", - "profile.optional.languages": "Langues parlées", - "profile.optional.political_beliefs": "Opinions politiques", - "profile.optional.details": "Détails", - "profile.optional.religious_beliefs": "Croyances religieuses", - "profile.optional.mbti": "Type de personnalité MBTI", - "profile.optional.diet": "Régime alimentaire", - "profile.optional.company": "Entreprise", - "profile.optional.job_title": "Poste actuel", - "profile.optional.job_title_at_company": "Poste actuel chez {company}", - "profile.optional.education_level": "Niveau d'études le plus élevé", - "profile.optional.university": "Université", - "profile.optional.smoke": "Fumez-vous ?", - "profile.optional.drinks_per_month": "Boissons alcoolisées consommées par mois", - "profile.optional.height": "Taille", - "profile.optional.feet": "Pieds", - "profile.optional.inches": "Pouces", - "profile.optional.centimeters": "Centimètres", - "profile.optional.ethnicity": "Origine ethnique", - "profile.optional.photos": "Photos", - "profile.optional.interests": "Intérets", - "profile.optional.work": "Travail", - "profile.optional.causes": "Causes morales", - "privacy.info.title": "1. Informations que nous collectons", - "privacy.info.text": "Nous collectons des informations de base de compte telles que votre nom, votre courriel et les données de profil. De plus, nous pouvons collecter des données d'utilisation pour améliorer les fonctionnalités de la plateforme.", - "privacy.use.title": "2. Comment nous utilisons vos données", - "privacy.use.text": "Vos données sont utilisées uniquement pour faire fonctionner, personnaliser et améliorer la plateforme. Nous ne vendons pas vos informations personnelles à des tiers.", - "privacy.storage.title": "3. Stockage et sécurité des données", - "privacy.storage.text": "Nous utilisons des pratiques modernes de chiffrement et de sécurité pour protéger vos données. Cependant, aucun système en ligne n'est complètement sûr, utilisez la plateforme de manière responsable.", - "privacy.third_party.title": "4. Services tiers", - "privacy.third_party.text": "Compass peut s'intégrer à des outils tiers (par ex., Google Sign-In). Ces services ont leurs propres politiques de confidentialité que nous vous encourageons à consulter.", - "privacy.rights.title": "5. Vos droits", - "privacy.rights.text": "Vous pouvez demander la suppression de votre compte et de vos données à tout moment en contactant", - "privacy.contact": "Pour toute question concernant cette politique de confidentialité, contactez", - "organization.seo.title": "Organisation", - "organization.seo.description": "Organisation", - "organization.title": "Organisation", - "organization.stats": "Croissance & Statistiques", - "organization.support": "Support", - "organization.help": "Aide", - "organization.constitution": "Constitution", - "organization.vote": "Propositions", - "organization.financials": "Finances", - "organization.terms": "Conditions générales", - "organization.privacy": "Politique de confidentialité", - "organization.security": "Sécurité", - "organization.contact": "Contact", - "notifications.title": "Mises à jour", - "notifications.tabs.notifications": "Notifications", - "notifications.tabs.settings": "Paramètres", - "notifications.empty": "Vous n'avez pas encore de notifications.", - "security.seo.title": "Sécurité", - "security.seo.description": "Signalez les vulnérabilités de sécurité à l'équipe Compass", - "security.title": "Sécurité", - "security.intro": "Nous prenons la sécurité de notre communauté au sérieux. Si vous pensez avoir trouvé une vulnérabilité ou un problème de sécurité, veuillez le signaler de manière responsable afin que nous puissions enquêter et le corriger rapidement.", - "security.how.title": "Comment signaler", - "security.how.text": "Veuillez ne pas ouvrir de tickets GitHub publics pour les rapports de sécurité. Contactez-nous directement par l'un des moyens suivants :", - "security.how.contact_prefix": "Utilisez le ", - "security.how.contact_form": "formulaire de contact", - "security.how.contact_suffix": " et choisissez la catégorie sécurité si disponible.", - "security.how.email_prefix": "Envoyez-nous un e‑mail à ", - "security.include.title": "Informations à inclure", - "security.include.text": "Pour nous aider à trier et à résoudre rapidement le problème, veuillez inclure :", - "security.include.item1": "Une description claire du problème et de son impact potentiel", - "security.include.item2": "Les étapes pour reproduire (URL, comptes de test, requêtes/réponses exactes le cas échéant)", - "security.include.item3": "Toutes captures d'écran, vidéos ou code de preuve de concept", - "security.include.item4": "Votre système d'exploitation, navigateur et détails d'environnement", - "security.response.title": "Notre réponse", - "security.response.text": "Nous nous efforçons d'accuser réception des nouveaux rapports de sécurité sous quelques jours ouvrables et nous vous tiendrons informé pendant notre enquête et remédiation. Les délais peuvent varier selon la gravité et la complexité.", - "security.scope.title": "Hors périmètre", - "security.scope.text": "Veuillez éviter les tests susceptibles de dégrader le service pour d'autres utilisateurs (par ex., déni de service) ou impliquant l'accès aux données d'un autre utilisateur sans permission explicite.", - "security.contact.title": "Nous contacter", - "security.contact.form": "Formulaire de contact", - "security.contact.email_button": "E‑mail", - "social.seo.title": "Réseaux sociaux", - "social.seo.description": "Réseaux sociaux", - "social.title": "Réseaux sociaux", - "social.discord": "Discord", - "social.stoat": "Revolt / Stoat", - "social.reddit": "Reddit", - "social.github": "GitHub", - "social.x": "X", - "social.email_button": "E‑mail", - "terms.seo.title": "Conditions générales", - "terms.seo.description": "Conditions générales de Compass", - "terms.title": "Conditions générales", - "terms.effective_date": "Date d'entrée en vigueur : 1er janvier 2025", - "terms.intro.prefix": "Bienvenue sur ", - "terms.intro.suffix": ", une plateforme pour se connecter, collaborer et construire des interactions pertinentes. En accédant à notre service ou en l'utilisant, vous acceptez les présentes Conditions générales.", - "terms.eligibility.title": "1. Admissibilité", - "terms.eligibility.text": "Vous devez avoir au moins 15 ans pour créer un compte et utiliser Compass. En vous inscrivant, vous confirmez répondre à cette exigence.", - "terms.responsibilities.title": "2. Responsabilités de l'utilisateur", - "terms.responsibilities.text": "Les utilisateurs doivent interagir avec respect, éviter le spam et s'abstenir de tout comportement perturbant la communauté ou violant les lois applicables.", - "terms.ip.title": "3. Propriété intellectuelle et licences", - "terms.ip.a": "a. Propriété et Licence. Compass est développé et maintenu en tant que projet libre et open source. Sauf indication contraire, tout le code source, les designs et les documents associés (« Matériels du projet ») sont sous licence AGPL-3.0. Certains composants peuvent être sous des licences open source permissives, comme indiqué explicitement. Sous réserve des termes de la licence applicable, vous recevez une licence mondiale, gratuite, non exclusive et irrévocable pour utiliser, copier, modifier, fusionner, publier, distribuer, sous‑licencier et/ou vendre des copies des Matériels du projet conformément aux termes de la licence applicable.", - "terms.ip.b": "b. Gouvernance communautaire. Compass fonctionne selon un modèle de gouvernance piloté par la communauté. Toute modification substantielle des licences, de la monétisation (y compris la publicité) ou des structures de gouvernance nécessite l'approbation via le processus défini par la communauté Compass. Toutes les décisions de gouvernance seront rendues publiques.", - "terms.ip.c": "c. Contributions. En soumettant du code, des designs, de la documentation ou d'autres contributions (« Contributions ») à Compass, vous acceptez que ces Contributions soient sous la même licence open source régissant les Matériels du projet au moment de la contribution. Vous déclarez et garantissez avoir le droit d'accorder une telle licence et que vos Contributions ne portent pas atteinte aux droits de tiers.", - "terms.ip.d": "d. Absence de restrictions propriétaires. Compass reste exempt de publicité, de verrouillages propriétaires et de monétisation des données, sauf approbation explicite de la communauté conformément à son processus de gouvernance. Les utilisateurs et contributeurs ne doivent pas introduire de telles restrictions sans approbation préalable de la communauté.", - "terms.safety.title": "4. Normes communautaires et sécurité", - "terms.safety.a": "a. Nudité et contenu sexuel. Compass n'autorise pas le partage public de nudité ou de contenu sexuellement explicite. Tout contenu incluant de la nudité, des actes sexuels ou des éléments suggestifs sera supprimé et pourra entraîner la suspension ou la résiliation des comptes concernés.", - "terms.safety.b": "b. Abus et exploitation sexuelle des enfants (CSAE). Compass applique une politique de tolérance zéro envers toute forme d'abus ou d'exploitation sexuelle d'enfants (« CSAE »). Le CSAE désigne tout contenu ou comportement exploitant, abusant ou mettant en danger les enfants — y compris, sans s'y limiter, l'aguichage en vue d'exploitation sexuelle, l'extorsion sexuelle, la traite d'un enfant à des fins sexuelles, ou toute autre forme d'exploitation sexuelle d'un enfant. Tout CSAE suspect entraînera la résiliation immédiate du compte et pourra être signalé aux forces de l'ordre et au NCMEC, comme l'exige la loi.", - "terms.safety.c": "c. Violence et contenu nuisible. Compass n'autorise pas le partage de violences réelles et graphiques en dehors d'un contexte d'actualité, contextuel ou éducatif. Tout contenu faisant la promotion ou glorifiant la violence sera supprimé.", - "terms.safety.d": "d. Partage de localisation. Compass ne partage pas l'emplacement physique précis des utilisateurs avec d'autres sans consentement explicite. Toute fonctionnalité optionnelle liée à la localisation indiquera clairement l'usage et le partage des données de localisation.", - "terms.safety.e": "e. Biens numériques et transactions. Compass est une plateforme entièrement gratuite. Elle ne vend pas de biens numériques, ne propose pas d'achats intégrés ni ne facture l'accès à des fonctionnalités. Toutes les fonctionnalités sont disponibles sans paiement.", - "terms.safety.f": "f. Contrôles de sécurité utilisateur. Compass inclut des fonctionnalités intégrées permettant aux utilisateurs de :", - "terms.safety.f1": "Bloquer d'autres utilisateurs ou du contenu généré par les utilisateurs.", - "terms.safety.f2": "Signaler des utilisateurs ou du contenu qui enfreignent les normes communautaires.", - "terms.safety.f3": "Bénéficier d'une modération active des discussions pour garantir un environnement sûr et respectueux.", - "terms.safety.f4": "Limiter les interactions aux amis invités uniquement, lorsque la fonctionnalité le permet.", - "terms.liability.title": "5. Responsabilité", - "terms.liability.text": "Compass n'est pas responsable des litiges entre utilisateurs ni des dommages résultant de l'utilisation de la plateforme. Utilisez la plateforme à votre propre discrétion.", - "terms.changes.title": "6. Modifications", - "terms.changes.text": "Nous pouvons mettre à jour ces Conditions périodiquement. La poursuite de l'utilisation de Compass après les mises à jour vaut acceptation des nouvelles Conditions.", - "terms.contact": "Pour toute question concernant ces Conditions, veuillez nous contacter à ", - "help.seo.title": "Aide", - "help.seo.description": "Aide et support pour Compass", - "help.title": "Aide et support", - "help.intro": "Rencontrez un problème ou avez une question ? Cette page présente les moyens les plus rapides d'obtenir de l'aide et de trouver des réponses.", - "help.links.title": "Liens rapides", - "help.links.read_prefix": "Lisez la ", - "help.links.read_suffix": " pour les questions courantes", - "help.links.contact_prefix": "Contactez-nous via le ", - "help.links.consult_prefix": "Consultez notre ", - "help.links.consult_and": " et ", - "help.report.title": "Signaler un problème", - "help.report.paragraph_prefix": "Si quelque chose ne fonctionne pas comme prévu, veuillez inclure autant de détails que possible (ce que vous avez fait, ce que vous attendiez, ce qui s'est passé, captures d'écran). Le moyen le plus rapide pour nous joindre est le ", - "help.report.paragraph_suffix": ".", - "help.account.title": "Problèmes de compte et de profil", + "filter.age.age": "âge", + "filter.age.any": "Tout", + "filter.age.years": "ans", + "filter.any": "Tous", + "filter.any_causes": "Toute cause", + "filter.any_diet": "Tout régime", + "filter.any_drinks": "Toute boisson", + "filter.any_education": "Tous niveaux d'études", + "filter.any_interests": "Tout intérêt", + "filter.any_language": "Toutes les langues", + "filter.any_mbti": "Tout MBTI", + "filter.any_politics": "Toute orientations politique", + "filter.any_relationship": "Toute relation amoureuse", + "filter.any_religion": "Toute religion", + "filter.any_work": "Tout travail", + "filter.gender.any": "Tout", + "filter.gender.gender": "genre", + "filter.gender.genders": "genres", + "filter.gender.they_seek": "Genre qu'ils recherchent", + "filter.location": "localisation", + "filter.location.any": "Toute", + "filter.location.distance_miles": "Distance (miles)", + "filter.location.search_city": "Rechercher une ville...", + "filter.location.set_any_city": "N'importe quelle ville", + "filter.mine_toggle": "Mes filtres", + "filter.multiple": "Multiple", + "filter.relationship.any_connection": "Toute relation", + "filter.relationship_status.any": "Tout statut romantique", + "filter.reset": "Réinitialiser", + "filter.short_bio_toggle": "Inclure les bios courtes", + "filter.wants_kids.any_preference": "Toutes préférences", + "filter.wants_kids.doesnt_want_kids": "Ne veut pas d'enfants", + "filter.wants_kids.either": "Peu importe", + "filter.wants_kids.wants_kids": "Veut des enfants", + "help.account.delete_instructions": "Vous voulez supprimer votre compte ? Allez dans les paramètres de votre profil, cliquez sur le menu à trois points en haut à droite, puis sélectionnez « Supprimer le compte »", "help.account.login_issue": "Impossible de se connecter ? Essayez de vous déconnecter puis de vous reconnecter, ou actualisez la page et réessayez.", "help.account.profile_update": "Les mises à jour du profil n'apparaissent pas ? Patientez quelques secondes et actualisez. Si le problème persiste, signalez-le via le formulaire de contact.", - "help.account.delete_instructions": "Vous voulez supprimer votre compte ? Allez dans les paramètres de votre profil, cliquez sur le menu à trois points en haut à droite, puis sélectionnez « Supprimer le compte »", - "help.security.paragraph_prefix": "Si vous pensez avoir découvert une vulnérabilité de sécurité, veuillez la signaler de manière responsable. Consultez notre ", - "help.security.paragraph_suffix": " pour les détails et les moyens de nous contacter.", - "help.need_help.title": "Besoin d'aide ?", + "help.account.title": "Problèmes de compte et de profil", "help.actions.contact_button": "Nous contacter", "help.actions.faq_button": "Consulter la FAQ", - "messages.title": "Messages", - "messages.seo.description": "Vos messages", + "help.intro": "Rencontrez un problème ou avez une question ? Cette page présente les moyens les plus rapides d'obtenir de l'aide et de trouver des réponses.", + "help.links.consult_and": " et ", + "help.links.consult_prefix": "Consultez notre ", + "help.links.contact_prefix": "Contactez-nous via le ", + "help.links.read_prefix": "Lisez la ", + "help.links.read_suffix": " pour les questions courantes", + "help.links.title": "Liens rapides", + "help.need_help.title": "Besoin d'aide ?", + "help.report.paragraph_prefix": "Si quelque chose ne fonctionne pas comme prévu, veuillez inclure autant de détails que possible (ce que vous avez fait, ce que vous attendiez, ce qui s'est passé, captures d'écran). Le moyen le plus rapide pour nous joindre est le ", + "help.report.paragraph_suffix": ".", + "help.report.title": "Signaler un problème", + "help.security.paragraph_prefix": "Si vous pensez avoir découvert une vulnérabilité de sécurité, veuillez la signaler de manière responsable. Consultez notre ", + "help.security.paragraph_suffix": " pour les détails et les moyens de nous contacter.", + "help.seo.description": "Aide et support pour Compass", + "help.seo.title": "Aide", + "help.title": "Aide et support", + "home.bottom": "Compass est aux relations humaines ce que Linux est au logiciel, Wikipédia est au savoir, et Firefox est à la navigation — un bien numérique public conçu pour servir les gens, pas le profit.", + "home.feature1.text": "Pas d’algorithmes. Chaque profil est consultable. Vous décidez qui découvrir.", + "home.feature1.title": "Transparence radicale", + "home.feature2.text": "Recherchez et filtrez par valeurs, centres d’intérêt, objectifs et mots-clés — de « stoïcisme » à « vie durable ». Faites émerger les connexions qui comptent vraiment.", + "home.feature2.title": "Conçu pour la profondeur", + "home.feature3.text": "Gratuit pour toujours. Pas de pubs, pas d’abonnements. Construit par et pour la communauté.", + "home.feature3.title": "Communautaire & Open Source", + "home.sign_up": "S'inscrire", + "home.subtitle": "Trouvez des personnes qui partagent vos valeurs, idées et intentions — pas seulement vos photos.", + "home.title": "Fini les swipes.", + "home.typewriter": "Cherche.", + "messages.action.add_reaction": "Ajouter une réaction", + "messages.action.delete": "Supprimer", + "messages.action.edit": "Modifier", + "messages.create": "Créer", + "messages.delete_confirm": "Êtes-vous sûr de vouloir supprimer ce message ?", + "messages.delete_failed": "Échec de la suppression du message", + "messages.deleted": "Message supprimé", + "messages.edited": "modifié", + "messages.empty": "Vous n'avez pas encore de messages.", "messages.input_placeholder": "Envoyer un message", - "messages.menu.see_members": "Voir les membres", + "messages.menu.leave_chat": "Quitter la conversation", "messages.menu.mute_1_day": "Couper notifs pendant 1 jour", "messages.menu.mute_forever": "Couper notifs définitivement", - "messages.menu.leave_chat": "Quitter la conversation", - "messages.action.edit": "Modifier", - "messages.action.delete": "Supprimer", - "messages.action.add_reaction": "Ajouter une réaction", - "messages.toast.muting_1_day.loading": "Couper notifs pour 1 jour...", - "messages.toast.muting_1_day.success": "Notifs coupées pour 1 jour", - "messages.toast.muting_1_day.error": "Échec de la coupure des notifs", - "messages.toast.muting_forever.loading": "Couper notifs définitivement...", - "messages.toast.muting_forever.success": "Notifs coupées définitivement", - "messages.toast.muting_forever.error": "Échec de la coupure des notifs", - "messages.empty": "Vous n'avez pas encore de messages.", - "messages.delete_confirm": "Êtes-vous sûr de vouloir supprimer ce message ?", - "messages.deleted": "Message supprimé", - "messages.delete_failed": "Échec de la suppression du message", + "messages.menu.see_members": "Voir les membres", "messages.more": " de plus", "messages.new_message": "Nouveau message", - "messages.create": "Créer", - "messages.you_prefix": "Vous : ", - "messages.edited": "modifié", + "messages.seo.description": "Vos messages", + "messages.title": "Messages", "messages.toast.edit_failed": "Échec de la modification du message.", + "messages.toast.muting_1_day.error": "Échec de la coupure des notifs", + "messages.toast.muting_1_day.loading": "Couper notifs pour 1 jour...", + "messages.toast.muting_1_day.success": "Notifs coupées pour 1 jour", + "messages.toast.muting_forever.error": "Échec de la coupure des notifs", + "messages.toast.muting_forever.loading": "Couper notifs définitivement...", + "messages.toast.muting_forever.success": "Notifs coupées définitivement", "messages.toast.send_failed": "Échec de l'envoi du message. Veuillez réessayer plus tard ou contacter le support si le problème persiste.", - "aboutsettings.copied": "Copié !", - "aboutsettings.copy_info": "Copier les infos", - "profiles.title": "Personnes", - "profile.visibility.question.public": "Rendre le profil visible publiquement ?", - "profile.visibility.question.member": "Limiter le profil aux membres uniquement ?", - "profile.visibility.desc.public": "Votre profil sera visible par tout visiteur sans connexion.", - "profile.visibility.desc.member": "Votre profil ne sera visible que par les membres. Les visiteurs devront se connecter pour voir votre profil.", - "profile.visibility.make_public": "Rendre public", - "profile.visibility.limit_to_members": "Limiter aux membres", - "profile.info.signup_to_see": "Inscrivez-vous pour voir le profil", - "profile.header.disabled_notice": "Vous avez désactivé votre profil, personne d'autre ne peut y accéder.", - "profile.header.menu.list_public": "Lister le profil publiquement", - "profile.header.menu.limit_members": "Limiter aux membres uniquement", - "profile.header.menu.enable_profile": "Activer le profil", - "profile.header.menu.disable_profile": "Désactiver le profil", - "profile.header.toast.enabling": "Activation du profil...", - "profile.header.toast.disabling": "Désactivation du profil...", - "profile.header.toast.enabled": "Profil activé", - "profile.header.toast.disabled": "Profil désactivé", - "profile.header.toast.failed_enable": "Échec de l'activation du profil", - "profile.header.toast.failed_disable": "Échec de la désactivation du profil", - "report.user.type.spam": "Spam", - "report.user.type.inappropriate": "Contenu inapproprié ou choquant", - "report.user.type.violence": "Violence ou menaces", - "report.user.type.fraud": "Activité frauduleuse", - "report.user.type.other": "Autre", - "report.user.toast.loading": "Signalement en cours...", - "report.user.toast.success": "Signalé", - "report.user.toast.error": "Erreur lors du signalement de l'utilisateur", - "report.user.thanks": "Merci pour votre signalement.", - "report.user.review_message": "Nous examinerons cet utilisateur et prendrons les mesures nécessaires si besoin.", - "report.user.instructions": "Veuillez sélectionner la ou les raisons de signaler cet utilisateur et ajouter un lien vers le contenu.", - "report.user.placeholder": "Ajoutez plus de contexte et/ou fournissez un lien vers le contenu", - "report.user.submit": "Signaler l'utilisateur", - "common.close": "Fermer", - "deleteyourself.confirm_phrase": "delete my account", - "deleteyourself.open_label": "Supprimer définitivement ce compte", - "deleteyourself.submit": "Supprimer le compte", - "deleteyourself.toast.loading": "Suppression du compte..", - "deleteyourself.toast.success": "Votre compte a été supprimé.", - "deleteyourself.toast.error": "Échec de la suppression du compte.", - "deleteyourself.title": "Êtes-vous sûr ?", - "deleteyourself.description": "Supprimer votre compte signifie que vous ne pourrez plus l'utiliser. Vous perdrez l'accès à toutes vos données.", - "deleteyourself.input_placeholder": "Tapez 'delete my account' pour confirmer", - "block_user.toast.loading": "Blocage en cours...", - "block_user.toast.success": "Vous ne verrez plus le contenu de cet utilisateur", - "block_user.toast.error": "Erreur lors du blocage de l'utilisateur", - "block_user.unblock": "Débloquer", - "block_user.block": "Bloquer", - "button.share.label": "Partager", - "answers.add.submit_own": "Proposez la vôtre !", - "answers.add.error_create": "Erreur lors de la création de la question de compatibilité. Réessayez ?", - "answers.answer.cta": "Répondre{core} aux questions", - "answers.answer.answer_yourself": "Répondez vous-même", - "answers.answer.view_list": "Voir la liste des questions", - "answers.answer.answer_skipped": "Répondre à {n} questions ignorées", - "answers.preferred.your_answer": "Votre réponse", - "answers.content.answers_you_accept": "Réponses que vous acceptez", - "answers.preferred.user_answer": "La réponse de {name}", - "answers.menu.edit": "Modifier", - "answers.menu.delete": "Supprimer", - "answers.menu.skip": "Ignorer", - "answers.compatible": "Compatible", - "answers.finish": "Terminer", - "answers.next": "Suivant", - "answers.incompatible": "Incompatible", - "answers.modal.preferred_of_user": "Les réponses préférées de {name}", - "answers.modal.user_marked": "{name} a marqué ceci comme ", - "answers.modal.your_preferred": "Vos réponses préférées", - "answers.modal.you_marked": "Vous avez marqué ceci comme ", - "answers.opinion.fill": "Remplir l'échelle d'opinion", - "answers.opinion.edit": "Modifier", - "answers.free.add_free_response": "Ajouter une réponse libre", - "answers.free.choose_question": "Choisissez une question à laquelle répondre", - "answers.free.see_others": "Voir {count} autres réponses", - "answers.display.your_prompts": "Vos questions de compatibilité", - "answers.display.user_prompts": "Questions de compatibilité de {name}", - "answers.display.none_answered_you": "Vous n'avez pas encore répondu aux questions de compatibilité !", - "answers.display.none_answered_user": "{name} n'a pas encore répondu aux questions de compatibilité !", - "answers.display.add_some": "Ajoutez-en pour mieux voir avec qui vous seriez le plus compatible.", - "answers.display.already_answered_all": "Vous avez déjà répondu à toutes les questions de compatibilité —", - "answers.display.answer_more": "Répondez à plus de questions pour augmenter vos scores de compatibilité — ou ", - "answers.display.none": "Aucune", - "answers.display.acceptable": "Acceptable", - "answers.display.also_acceptable": "Également acceptable", - "answers.importance.0": "Peu important", - "answers.importance.1": "Assez important", - "answers.importance.2": "Important", - "answers.importance.3": "Très important", - "answers.content.your_thoughts": "Vos pensées (optionnelles, mais recommendées)", - "profile.basics.title": "Les bases", - "profile.basics.subtitle": "Pas de formulaire sans fin — écrivez votre propre biographie à votre manière.", - "profile.basics.display_name": "Nom d'affichage", - "profile.basics.username": "Nom d'utilisateur", - "profile.basics.bio": "Biographie", - "common.next": "Suivant", - "profile.interested_in": "Intéressé·e par", + "messages.you_prefix": "Vous : ", + "multi-checkbox.search_or_add": "Chercher ou ajouter", + "nav.about": "À propos", + "nav.contact": "Contact", + "nav.faq": "FAQ", + "nav.home": "Accueil", + "nav.messages": "Messages", + "nav.more": "Plus", + "nav.news": "Quoi de neuf", + "nav.notifs": "Notifications", + "nav.organization": "Organisation", + "nav.people": "Personnes", + "nav.profile": "Profil", + "nav.settings": "Paramètres", + "nav.sign_in": "Se connecter", + "nav.sign_out": "Se déconnecter", + "nav.sign_up": "S'inscrire", + "nav.sign_up_now": "S'inscrire maintenant", + "nav.social": "Social", + "nav.vote": "Vote", + "news.failed": "Échec de la récupération des versions.", + "news.no_release_notes": "_Aucune note de version fournie._", + "news.seo.description": "Voir les dernières mises à jour et fonctionnalités", + "news.seo.description_general": "Toutes les actualités et mises à jour du code pour Compass", + "news.title": "Quoi de neuf", + "news.view_on_github": "Voir sur GitHub", + "notifications.empty": "Vous n'avez pas encore de notifications.", + "notifications.heading": "Où voulez-vous être notifié lorsqu'une personne", + "notifications.options.email": "Par e‑mail", + "notifications.options.page": "Sur la page des notifications", + "notifications.question.new_endorsement": "... vous recommande ?", + "notifications.question.new_match": "... correspond avec vous ?", + "notifications.question.new_message": "... vous envoie un nouveau message ?", + "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.question.tagged_user": "... vous mentionne ?", + "notifications.tabs.notifications": "Notifications", + "notifications.tabs.settings": "Paramètres", + "notifications.title": "Mises à jour", + "organization.constitution": "Constitution", + "organization.contact": "Contact", + "organization.financials": "Finances", + "organization.help": "Aide", + "organization.privacy": "Politique de confidentialité", + "organization.security": "Sécurité", + "organization.seo.description": "Organisation", + "organization.seo.title": "Organisation", + "organization.stats": "Croissance & Statistiques", + "organization.support": "Support", + "organization.terms": "Conditions générales", + "organization.title": "Organisation", + "organization.vote": "Propositions", + "privacy.contact": "Pour toute question concernant cette politique de confidentialité, contactez", + "privacy.effective_date": "Date d'entrée en vigueur : 1er janvier 2025", + "privacy.info.text": "Nous collectons des informations de base de compte telles que votre nom, votre courriel et les données de profil. De plus, nous pouvons collecter des données d'utilisation pour améliorer les fonctionnalités de la plateforme.", + "privacy.info.title": "1. Informations que nous collectons", + "privacy.intro.prefix": "Chez ", + "privacy.intro.suffix": ", nous accordons de l'importance à la transparence et au respect de vos données. Cette politique de confidentialité explique comment nous traitons vos informations.", + "privacy.rights.text": "Vous pouvez demander la suppression de votre compte et de vos données à tout moment en contactant", + "privacy.rights.title": "5. Vos droits", + "privacy.seo.description": "Politique de confidentialité pour Compass", + "privacy.seo.title": "Confidentialité", + "privacy.storage.text": "Nous utilisons des pratiques modernes de chiffrement et de sécurité pour protéger vos données. Cependant, aucun système en ligne n'est complètement sûr, utilisez la plateforme de manière responsable.", + "privacy.storage.title": "3. Stockage et sécurité des données", + "privacy.third_party.text": "Compass peut s'intégrer à des outils tiers (par ex., Google Sign-In). Ces services ont leurs propres politiques de confidentialité que nous vous encourageons à consulter.", + "privacy.third_party.title": "4. Services tiers", + "privacy.title": "Politique de confidentialité", + "privacy.use.text": "Vos données sont utilisées uniquement pour faire fonctionner, personnaliser et améliorer la plateforme. Nous ne vendons pas vos informations personnelles à des tiers.", + "privacy.use.title": "2. Comment nous utilisons vos données", "profile.age_any": "de tout âge", + "profile.age_between": "entre {min} et {max} ans", "profile.age_exact": "exactement {min} ans", "profile.age_older_than": "plus de {min} ans", "profile.age_younger_than": "moins de {max} ans", - "profile.age_between": "entre {min} et {max} ans", - "profile.seeking": "Recherche", "profile.at": "à", - "profile.smokes": "Fume", - "profile.doesnt_smoke": "Ne fume pas", - "profile.doesnt_drink": "Ne boit pas", - "profile.drinks_one": "1 boisson par mois", - "profile.drinks_many": "{count} boissons par mois", - "profile.wants_kids_0": "Ne veut pas d'enfants", - "profile.wants_kids_1": "Préfère ne pas avoir d'enfants", - "profile.wants_kids_2": "Neutre ou ouvert·e à avoir des enfants", - "profile.wants_kids_3": "Tend à vouloir des enfants", - "profile.wants_kids_4": "Veut des enfants", - "profile.last_online": "Dernière connexion {time}", - "profile.has_kids_one": "A {count} enfant", - "profile.has_kids_many": "A {count} enfants", - "profile.gender.male": "Homme", - "profile.gender.plural.male": "Hommes", - "profile.gender.female": "Femme", - "profile.gender.plural.female": "Femmes", - "profile.gender.other": "Autre", - "profile.gender.plural.other": "Autres", - "profile.relationship.collaboration": "Collaboration", - "profile.relationship.friendship": "Amitié", - "profile.relationship.relationship": "Relation", - "profile.relationship_status.single": "Célibataire", - "profile.relationship_status.married": "Marié·e", - "profile.relationship_status.casual": "En relation informelle", - "profile.relationship_status.long_term": "En relation à long terme", - "profile.relationship_status.open": "En relation ouverte", - "profile.romantic.mono": "Monogame", - "profile.romantic.poly": "Polyamoureux·se", - "profile.romantic.open": "Relation ouverte", - "profile.political.progressive": "Progressiste", - "profile.political.liberal": "Libéral·e", - "profile.political.moderate": "Modéré·e / Centriste", - "profile.political.conservative": "Conservateur·trice", - "profile.political.socialist": "Socialiste", - "profile.political.nationalist": "Nationaliste", - "profile.political.populist": "Populiste", - "profile.political.green": "Vert·e / Éco-socialiste", - "profile.political.technocratic": "Technocrate", - "profile.political.libertarian": "Libertarien·ne", - "profile.political.e/acc": "Accélérationnisme efficace", - "profile.political.pause ai": "Pause IA / Sceptique de la technologie", - "profile.political.other": "Indépendant·e / Autre", - "profile.diet.omnivore": "Omnivore", - "profile.diet.veg": "Végétarien·ne", - "profile.diet.vegan": "Végan·e", + "profile.basics.bio": "Biographie", + "profile.basics.display_name": "Nom d'affichage", + "profile.basics.subtitle": "Pas de formulaire sans fin — écrivez votre propre biographie à votre manière.", + "profile.basics.title": "Les bases", + "profile.basics.username": "Nom d'utilisateur", + "profile.bio.about_me": "À propos de moi", + "profile.bio.add_characters_many": "Ajoutez {count} caractères de plus pour apparaître dans les résultats de recherche — ou prenez votre temps et commencez par explorer les autres.", + "profile.bio.add_characters_one": "Ajoutez {count} caractère de plus pour apparaître dans les résultats de recherche — ou prenez votre temps et commencez par explorer les autres.", + "profile.bio.cancel": "Annuler", + "profile.bio.delete": "Supprimer", + "profile.bio.edit": "Modifier", + "profile.bio.hide_info": "Masquer les informations", + "profile.bio.placeholder": "Parlez-nous de vous — et de ce que vous recherchez !", + "profile.bio.save": "Enregistrer", + "profile.bio.tips": "Conseils", + "profile.bio.tips_intro": "Rédigez une bio claire et engageante pour aider les autres à comprendre qui vous êtes et les connexions que vous recherchez. Incluez :", + "profile.bio.tips_link": "Lire tous les conseils pour rédiger une bio de haute qualité", + "profile.bio.tips_list": "- Vos valeurs fondamentales, intérêts et activités\n- Traits de personnalité, ce qui vous rend unique et ce qui vous tient à cœur\n- Objectifs de connexion (collaboration, amitié, romantique)\n- Attentes et limites\n- Disponibilité, comment vous contacter ou démarrer une conversation (e-mail, réseaux sociaux, etc.)\n- Optionnel : préférences romantiques, habitudes de vie et sujets de conversation", + "profile.bio.too_short": "Bio trop courte. Le profil peut être filtré des résultats de recherche.", + "profile.bio.too_short_tooltip": "Comme votre bio est trop courte, l'algorithme de Compass filtre votre profil des résultats de recherche (sauf si « Inclure les bios courtes » est sélectionné). Cela garantit que les recherches affichent des profils significatifs.", + "profile.causes.ai_safety": "Sécurité de l'IA", + "profile.causes.animal_rights": "Droits des animaux", + "profile.causes.animal_welfare": "Bien-être animal", + "profile.causes.biodiversity": "Biodiversité", + "profile.causes.cause_agnostic": "Cause agnostique", + "profile.causes.climate_change": "Changement climatique", + "profile.causes.degrowth": "Décroissance", + "profile.causes.disaster_relief": "Secours en cas de catastrophe", + "profile.causes.education": "Éducation", + "profile.causes.extreme_poverty": "Pauvreté extrême", + "profile.causes.gender_equality": "Égalité des genres", + "profile.causes.human_rights": "Droits humains", + "profile.causes.mental_health": "Santé mentale", + "profile.causes.sustainability": "Durabilité", + "profile.comments.current_user_hint": "Les autres utilisateurs peuvent vous laisser des recommandations ici.", + "profile.comments.disabled": "Recommandations désactivées", + "profile.comments.disabling": "Désactivation des recommandations des autres utilisateurs", + "profile.comments.enable_tooltip": "Activer/Désactiver les recommandations des autres utilisateurs", + "profile.comments.enabled": "Recommandations activées", + "profile.comments.enabling": "Activation des recommandations des autres utilisateurs", + "profile.comments.feature_disabled_other": "{name} a désactivé les recommandations des autres utilisateurs.", + "profile.comments.feature_disabled_self": "Cette fonctionnalité est désactivée", + "profile.comments.other_user_hint": "Si vous les connaissez, écrivez quelque chose de sympa qui enrichira leur profil.", + "profile.comments.section_title": "Recommandations", + "profile.comments.update_error": "Échec de la mise à jour des paramètres de recommandation", "profile.diet.keto": "Cétogène", + "profile.diet.omnivore": "Omnivore", + "profile.diet.other": "Autre", "profile.diet.paleo": "Paléo", "profile.diet.pescetarian": "Pescétarien·ne", - "profile.diet.other": "Autre", - "profile.education.high-school": "Lycée / Secondaire", - "profile.education.some-college": "Supérieur", + "profile.diet.veg": "Végétarien·ne", + "profile.diet.vegan": "Végan·e", + "profile.doesnt_drink": "Ne boit pas", + "profile.doesnt_smoke": "Ne fume pas", + "profile.drinks": "Boissons", + "profile.drinks_many": "{count} boissons par mois", + "profile.drinks_one": "1 boisson par mois", "profile.education.bachelors": "Licence / Baccalauréat", - "profile.education.masters": "Master", "profile.education.doctorate": "Doctorat", - "profile.religion.atheist": "Athée", - "profile.religion.agnostic": "Agnostique", - "profile.religion.spiritual": "Spirituel·le", - "profile.religion.christian": "Chrétien·ne", - "profile.religion.muslim": "Musulman·e", - "profile.religion.jewish": "Juif·ve", - "profile.religion.hindu": "Hindou·e", - "profile.religion.buddhist": "Bouddhiste", - "profile.religion.sikh": "Sikh", - "profile.religion.taoist": "Taoïste", - "profile.religion.jain": "Jaïn", - "profile.religion.shinto": "Shinto", - "profile.religion.animist": "Animiste", - "profile.religion.zoroastrian": "Zoroastrien·ne", - "profile.religion.unitarian_universalist": "Unitaire universaliste", - "profile.religion.other": "Autre", - "profile.race.african": "Origine noire/africaine", - "profile.race.asian": "Asiatique de l'Est", - "profile.race.south_asian": "Asiatique du Sud/Sud-Est", - "profile.race.caucasian": "Blanc·he / Caucasien·ne", - "profile.race.hispanic": "Hispanique/Latino·a", - "profile.race.middle_eastern": "Moyen-Orient", - "profile.race.native_american": "Amérindien·ne / Autochtone", - "profile.race.other": "Autre", + "profile.education.high-school": "Lycée / Secondaire", + "profile.education.masters": "Master", + "profile.education.short_name": "Education", + "profile.education.some-college": "Supérieur", + "profile.gender.female": "Femme", + "profile.gender.male": "Homme", + "profile.gender.other": "Autre", + "profile.gender.plural.female": "Femmes", + "profile.gender.plural.male": "Hommes", + "profile.gender.plural.other": "Autres", + "profile.has_kids": "A des enfants", + "profile.has_kids.-1": "Peu importe", + "profile.has_kids.0": "Non", + "profile.has_kids.1": "Oui", + "profile.has_kids.doesnt_have_kids": "N'a pas d'enfants", + "profile.has_kids.has_kids": "A des enfants", + "profile.has_kids.no_preference": "Peu importe", + "profile.has_kids_many": "A {count} enfants", + "profile.has_kids_one": "A {count} enfant", + "profile.header.disabled_notice": "Vous avez désactivé votre profil, personne d'autre ne peut y accéder.", + "profile.header.menu.disable_profile": "Désactiver le profil", + "profile.header.menu.enable_profile": "Activer le profil", + "profile.header.menu.limit_members": "Limiter aux membres uniquement", + "profile.header.menu.list_public": "Lister le profil publiquement", + "profile.header.toast.disabled": "Profil désactivé", + "profile.header.toast.disabling": "Désactivation du profil...", + "profile.header.toast.enabled": "Profil activé", + "profile.header.toast.enabling": "Activation du profil...", + "profile.header.toast.failed_disable": "Échec de la désactivation du profil", + "profile.header.toast.failed_enable": "Échec de l'activation du profil", + "profile.info.signup_to_see": "Inscrivez-vous pour voir le profil", + "profile.interested_in": "Intéressé·e par", + "profile.interests.chess": "Échecs", + "profile.interests.coding": "Programmation", + "profile.interests.collecting": "Collection", + "profile.interests.cooking": "Cuisine", + "profile.interests.crafting": "Artisanat", + "profile.interests.crochet": "Crochet", + "profile.interests.dancing": "Danse", + "profile.interests.drawing": "Dessin", + "profile.interests.game_design": "Conception de jeux", + "profile.interests.gardening": "Jardinage", + "profile.interests.guitar": "Guitare", + "profile.interests.gym": "Salle de sport", + "profile.interests.hiking": "Randonnée", + "profile.interests.meditation": "Méditation", + "profile.interests.music_listening": "Écoute de musique", + "profile.interests.music_playing": "Pratique musicale", + "profile.interests.painting": "Peinture", + "profile.interests.philosophy": "Philosophie", + "profile.interests.photography": "Photographie", + "profile.interests.piano": "Piano", + "profile.interests.pottery": "Poterie", + "profile.interests.reading": "Lecture", + "profile.interests.running": "Course à pied", + "profile.interests.traveling": "Voyage", + "profile.interests.video_games": "Jeux vidéo", + "profile.interests.writing": "Écriture", + "profile.interests.yoga": "Yoga", "profile.language.akan": "Akan", "profile.language.amharic": "Amharique", "profile.language.arabic": "Arabe", @@ -734,8 +531,8 @@ "profile.language.southern-min": "Min du Sud", "profile.language.spanish": "Espagnol", "profile.language.sundanese": "Soundanais", - "profile.language.swedish": "Suédois", "profile.language.swahili": "Swahili", + "profile.language.swedish": "Suédois", "profile.language.sylheti": "Sylheti", "profile.language.tagalog": "Tagalog", "profile.language.tamil": "Tamoul", @@ -755,127 +552,379 @@ "profile.language.yue": "Yue", "profile.language.zhuang": "Zhuang", "profile.language.zulu": "Zoulou", - "profile.interests.crafting": "Artisanat", - "profile.interests.piano": "Piano", - "profile.interests.guitar": "Guitare", - "profile.interests.cooking": "Cuisine", - "profile.interests.crochet": "Crochet", - "profile.interests.collecting": "Collection", - "profile.interests.dancing": "Danse", - "profile.interests.video_games": "Jeux vidéo", - "profile.interests.photography": "Photographie", - "profile.interests.traveling": "Voyage", - "profile.interests.running": "Course à pied", - "profile.interests.chess": "Échecs", - "profile.interests.coding": "Programmation", - "profile.interests.writing": "Écriture", - "profile.interests.reading": "Lecture", - "profile.interests.gym": "Salle de sport", - "profile.interests.music_listening": "Écoute de musique", - "profile.interests.gardening": "Jardinage", - "profile.interests.music_playing": "Pratique musicale", - "profile.interests.hiking": "Randonnée", - "profile.interests.meditation": "Méditation", - "profile.interests.yoga": "Yoga", - "profile.interests.game_design": "Conception de jeux", - "profile.interests.drawing": "Dessin", - "profile.interests.painting": "Peinture", - "profile.interests.pottery": "Poterie", - "profile.interests.philosophy": "Philosophie", - "profile.causes.disaster_relief": "Secours en cas de catastrophe", - "profile.causes.gender_equality": "Égalité des genres", - "profile.causes.cause_agnostic": "Cause agnostique", - "profile.causes.human_rights": "Droits humains", - "profile.causes.degrowth": "Décroissance", - "profile.causes.animal_rights": "Droits des animaux", - "profile.causes.biodiversity": "Biodiversité", - "profile.causes.mental_health": "Santé mentale", - "profile.causes.sustainability": "Durabilité", - "profile.causes.animal_welfare": "Bien-être animal", - "profile.causes.climate_change": "Changement climatique", - "profile.causes.extreme_poverty": "Pauvreté extrême", - "profile.causes.education": "Éducation", - "profile.causes.ai_safety": "Sécurité de l'IA", - "profile.work.law": "Droit", - "profile.work.it": "Informatique", - "profile.work.construction": "Construction", - "profile.work.music": "Musique", - "profile.work.film": "Cinéma", - "profile.work.medicine": "Médecine", - "profile.work.nursing": "Soins infirmiers", - "profile.work.tourism": "Tourisme", - "profile.work.sports": "Sport", - "profile.work.agriculture": "Agriculture", - "profile.work.spirits_maker": "Fabricant de spiritueux", - "profile.work.engineering": "Ingénierie", - "profile.work.journalism": "Journalisme", + "profile.last_online": "Dernière connexion {time}", + "profile.optional.age": "Âge", + "profile.optional.age_range": "Âgés entre", + "profile.optional.causes": "Causes morales", + "profile.optional.centimeters": "Centimètres", + "profile.optional.company": "Entreprise", + "profile.optional.connection_type": "Type de relation", + "profile.optional.details": "Détails", + "profile.optional.diet": "Régime alimentaire", + "profile.optional.drinks_per_month": "Boissons alcoolisées consommées par mois", + "profile.optional.education_level": "Niveau d'études le plus élevé", + "profile.optional.ethnicity": "Origine ethnique", + "profile.optional.feet": "Pieds", + "profile.optional.gender": "Genre", + "profile.optional.height": "Taille", + "profile.optional.inches": "Pouces", + "profile.optional.interested_in": "Intéressé(e) par", + "profile.optional.interests": "Intérêts", + "profile.optional.job_title": "Poste actuel", + "profile.optional.job_title_at_company": "Poste actuel chez {company}", + "profile.optional.languages": "Langues parlées", + "profile.optional.location": "Localisation", + "profile.optional.mbti": "Type de personnalité MBTI", + "profile.optional.num_kids": "Nombre actuel d'enfants", + "profile.optional.photos": "Photos", + "profile.optional.political_beliefs": "Opinions politiques", + "profile.optional.relationship_status": "Situation amoureuse", + "profile.optional.relationship_style": "Style de relation", + "profile.optional.religious_beliefs": "Croyances religieuses", + "profile.optional.search_city": "Rechercher une ville...", + "profile.optional.site_url": "URL du site", + "profile.optional.smoke": "Fumez-vous ?", + "profile.optional.socials": "Réseaux sociaux", + "profile.optional.subtitle": "Informations optionnelles", + "profile.optional.title": "Plus d'informations à mon sujet", + "profile.optional.university": "Université", + "profile.optional.username_or_url": "Nom d'utilisateur ou URL", + "profile.optional.want_kids": "Je souhaite avoir des enfants", + "profile.optional.work": "Travail", + "profile.political.conservative": "Conservateur·trice", + "profile.political.e/acc": "Accélérationnisme efficace", + "profile.political.green": "Vert·e / Éco-socialiste", + "profile.political.liberal": "Libéral·e", + "profile.political.libertarian": "Libertarien·ne", + "profile.political.moderate": "Modéré·e / Centriste", + "profile.political.nationalist": "Nationaliste", + "profile.political.other": "Indépendant·e / Autre", + "profile.political.pause ai": "Pause IA / Sceptique de la technologie", + "profile.political.populist": "Populiste", + "profile.political.progressive": "Progressiste", + "profile.political.socialist": "Socialiste", + "profile.political.technocratic": "Technocrate", + "profile.race.african": "Origine noire/africaine", + "profile.race.asian": "Asiatique de l'Est", + "profile.race.caucasian": "Blanc·he / Caucasien·ne", + "profile.race.hispanic": "Hispanique/Latino·a", + "profile.race.middle_eastern": "Moyen-Orient", + "profile.race.native_american": "Amérindien·ne / Autochtone", + "profile.race.other": "Autre", + "profile.race.south_asian": "Asiatique du Sud/Sud-Est", + "profile.relationship.collaboration": "Collaboration", + "profile.relationship.friendship": "Amitié", + "profile.relationship.relationship": "Relation", + "profile.relationship_status.casual": "En relation informelle", + "profile.relationship_status.long_term": "En relation à long terme", + "profile.relationship_status.married": "Marié·e", + "profile.relationship_status.open": "En relation ouverte", + "profile.relationship_status.single": "Célibataire", + "profile.religion.agnostic": "Agnostique", + "profile.religion.animist": "Animiste", + "profile.religion.atheist": "Athée", + "profile.religion.buddhist": "Bouddhiste", + "profile.religion.christian": "Chrétien·ne", + "profile.religion.hindu": "Hindou·e", + "profile.religion.jain": "Jaïn", + "profile.religion.jewish": "Juif·ve", + "profile.religion.muslim": "Musulman·e", + "profile.religion.other": "Autre", + "profile.religion.shinto": "Shinto", + "profile.religion.sikh": "Sikh", + "profile.religion.spiritual": "Spirituel·le", + "profile.religion.taoist": "Taoïste", + "profile.religion.unitarian_universalist": "Unitaire universaliste", + "profile.religion.zoroastrian": "Zoroastrien·ne", + "profile.romantic.mono": "Monogame", + "profile.romantic.open": "Relation ouverte", + "profile.romantic.poly": "Polyamoureux·se", + "profile.romantic.style": "Style", + "profile.save": "Enregistrer", + "profile.seeking": "Recherche", + "profile.seo.description": "Votre profil", + "profile.seo.title": "Profil", + "profile.smoker.either": "N'importe", + "profile.smoker.no": "Non-fumeur", + "profile.smoker.yes": "Fumeur", + "profile.smokes": "Fume", + "profile.visibility.desc.member": "Votre profil ne sera visible que par les membres. Les visiteurs devront se connecter pour voir votre profil.", + "profile.visibility.desc.public": "Votre profil sera visible par tout visiteur sans connexion.", + "profile.visibility.limit_to_members": "Limiter aux membres", + "profile.visibility.make_public": "Rendre public", + "profile.visibility.question.member": "Limiter le profil aux membres uniquement ?", + "profile.visibility.question.public": "Rendre le profil visible publiquement ?", + "profile.wants_kids_0": "Ne veut pas d'enfants", + "profile.wants_kids_1": "Préfère ne pas avoir d'enfants", + "profile.wants_kids_2": "Neutre ou ouvert·e à avoir des enfants", + "profile.wants_kids_3": "Tend à vouloir des enfants", + "profile.wants_kids_4": "Veut des enfants", "profile.work.academia": "Monde universitaire", - "profile.work.data_science": "Science des données", - "profile.work.social_work": "Travail social", - "profile.work.social_enterprise": "Entreprise sociale", - "profile.work.research_and_design": "Recherche et conception", - "profile.work.human_resources": "Ressources humaines", + "profile.work.agriculture": "Agriculture", + "profile.work.construction": "Construction", "profile.work.consulting": "Conseil", + "profile.work.content_design": "Design de contenu", + "profile.work.data_science": "Science des données", + "profile.work.education": "Éducation", + "profile.work.engineering": "Ingénierie", + "profile.work.fashion": "Mode", + "profile.work.film": "Cinéma", + "profile.work.finance": "Finance", + "profile.work.graphic_design": "Design graphique", + "profile.work.human_resources": "Ressources humaines", + "profile.work.it": "Informatique", + "profile.work.journalism": "Journalisme", + "profile.work.law": "Droit", "profile.work.management": "Gestion", "profile.work.marketing": "Marketing", - "profile.work.fashion": "Mode", - "profile.work.education": "Éducation", - "profile.work.graphic_design": "Design graphique", - "profile.work.content_design": "Design de contenu", + "profile.work.medicine": "Médecine", + "profile.work.music": "Musique", + "profile.work.nursing": "Soins infirmiers", + "profile.work.research_and_design": "Recherche et conception", "profile.work.sales": "Vente", - "profile.work.finance": "Finance", - "profile.bio.about_me": "À propos de moi", - "profile.bio.too_short": "Bio trop courte. Le profil peut être filtré des résultats de recherche.", - "profile.bio.too_short_tooltip": "Comme votre bio est trop courte, l'algorithme de Compass filtre votre profil des résultats de recherche (sauf si « Inclure les bios courtes » est sélectionné). Cela garantit que les recherches affichent des profils significatifs.", - "profile.bio.placeholder": "Parlez-nous de vous — et de ce que vous recherchez !", - "profile.bio.tips": "Conseils", - "profile.bio.hide_info": "Masquer les informations", - "profile.bio.tips_intro": "Rédigez une bio claire et engageante pour aider les autres à comprendre qui vous êtes et les connexions que vous recherchez. Incluez :", - "profile.bio.tips_link": "Lire tous les conseils pour rédiger une bio de haute qualité", - "profile.bio.edit": "Modifier", - "profile.bio.delete": "Supprimer", - "profile.bio.cancel": "Annuler", - "profile.bio.save": "Enregistrer", - "profile.bio.add_characters_one": "Ajoutez {count} caractère de plus pour apparaître dans les résultats de recherche — ou prenez votre temps et commencez par explorer les autres.", - "profile.bio.add_characters_many": "Ajoutez {count} caractères de plus pour apparaître dans les résultats de recherche — ou prenez votre temps et commencez par explorer les autres.", - "profile.bio.tips_list": "- Vos valeurs fondamentales, intérêts et activités\n- Traits de personnalité, ce qui vous rend unique et ce qui vous tient à cœur\n- Objectifs de connexion (collaboration, amitié, romantique)\n- Attentes et limites\n- Disponibilité, comment vous contacter ou démarrer une conversation (e-mail, réseaux sociaux, etc.)\n- Optionnel : préférences romantiques, habitudes de vie et sujets de conversation", - "profile.comments.section_title": "Recommandations", - "profile.comments.enable_tooltip": "Activer/Désactiver les recommandations des autres utilisateurs", - "profile.comments.enabling": "Activation des recommandations des autres utilisateurs", - "profile.comments.disabling": "Désactivation des recommandations des autres utilisateurs", - "profile.comments.enabled": "Recommandations activées", - "profile.comments.disabled": "Recommandations désactivées", - "profile.comments.update_error": "Échec de la mise à jour des paramètres de recommandation", - "profile.comments.current_user_hint": "Les autres utilisateurs peuvent vous laisser des recommandations ici.", - "profile.comments.other_user_hint": "Si vous les connaissez, écrivez quelque chose de sympa qui enrichira leur profil.", - "common.new": "Nouveau", - "common.compatible": "Compatible", - "common.active": "Actif", - "common.saved": "Enregistré !", - "common.notified": "Être notifié", - "common.people": "personnes", - "common.person": "personne", - "saved_searches.button": "Recherches enregistrées", - "saved_searches.title": "Recherches enregistrées", - "saved_searches.notification_note": "Nous vous préviendrons quotidiennement lorsque de nouvelles personnes correspondront à vos recherches ci-dessous.", - "saved_searches.empty_state": "Vous n'avez enregistré aucune recherche. Pour en enregistrer une, cliquez sur Être notifié et nous vous préviendrons quotidiennement lorsque de nouvelles personnes correspondront.", - "saved_people.button": "Personnes enregistrées", - "saved_people.title": "Personnes enregistrées", - "saved_people.list_header": "Voici les personnes que vous avez enregistrées :", - "profile.comments.feature_disabled_self": "Cette fonctionnalité est désactivée", - "profile.comments.feature_disabled_other": "{name} a désactivé les recommandations des autres utilisateurs.", - "multi-checkbox.search_or_add": "Chercher ou ajouter", - "answers.sort.important_to_user": "Important pour {name}", - "answers.sort.important_to_you": "Important pour vous", - "answers.sort.important_to_them": "Important pour {name}", - "answers.sort.incompatible": "Incompatible", - "answers.sort.unanswered_by_you": "Sans réponse de votre part", - "common.add": "Ajouter", - "common.or": "Ou", - "common.yes": "Oui", - "common.no": "Non", + "profile.work.social_enterprise": "Entreprise sociale", + "profile.work.social_work": "Travail social", + "profile.work.spirits_maker": "Fabricant de spiritueux", + "profile.work.sports": "Sport", + "profile.work.tourism": "Tourisme", "profile_grid.no_profiles": "Aucun profil trouvé.", "profile_grid.notification_cta": "N'hésitez pas à cliquer sur \"Être notifié\" et nous vous préviendrons quand de nouveaux utilisateurs correspondront à votre recherche !", - "add_photos.add_description": "Ajouter une description", - "add_photos.profile_picture_hint": "L'image mise en surbrillance est votre photo de profil" + "profiles.title": "Personnes", + "register.agreement.and": " et ", + "register.agreement.prefix": "En vous inscrivant, j'accepte les ", + "register.agreement.suffix": ".", + "register.already_account": "Vous avez déjà un compte ?", + "register.back_to_login": "Retour à la connexion", + "register.button.creating": "Création du compte..", + "register.button.email": "S'inscrire avec l'e‑mail", + "register.check_email.help_prefix": "Vous n'avez pas reçu l'e-mail ? Vérifiez vos spams ou ", + "register.check_email.help_suffix": ".", + "register.check_email.sent_prefix": "Nous avons envoyé un lien de vérification à ", + "register.check_email.sent_suffix": ".", + "register.check_email.title": "Vérifiez votre courriel", + "register.check_email.try_again": "réessayez", + "register.email_label": "Courriel", + "register.email_placeholder": "Courriel", + "register.error.all_fields_required": "Tous les champs sont requis", + "register.error.email_in_use": "Cet e‑mail est déjà enregistré", + "register.error.unknown": "Échec de l'inscription", + "register.get_started": "Commencer", + "register.link_signin": "Se connecter", + "register.or_sign_up_with": "Ou inscrivez-vous avec", + "register.password_label": "Mot de passe", + "register.password_placeholder": "Mot de passe", + "register.privacy": "Politique de confidentialité", + "register.seo.description": "Inscrivez-vous pour un nouveau compte", + "register.seo.title": "S'inscrire", + "register.terms": "Conditions générales", + "register.toast.signup_failed": "Échec de l'inscription : ", + "report.user.instructions": "Veuillez sélectionner la ou les raisons de signaler cet utilisateur et ajouter un lien vers le contenu.", + "report.user.placeholder": "Ajoutez plus de contexte et/ou fournissez un lien vers le contenu", + "report.user.review_message": "Nous examinerons cet utilisateur et prendrons les mesures nécessaires si besoin.", + "report.user.submit": "Signaler l'utilisateur", + "report.user.thanks": "Merci pour votre signalement.", + "report.user.toast.error": "Erreur lors du signalement de l'utilisateur", + "report.user.toast.loading": "Signalement en cours...", + "report.user.toast.success": "Signalé", + "report.user.type.fraud": "Activité frauduleuse", + "report.user.type.inappropriate": "Contenu inapproprié ou choquant", + "report.user.type.other": "Autre", + "report.user.type.spam": "Spam", + "report.user.type.violence": "Violence ou menaces", + "saved_people.button": "Personnes enregistrées", + "saved_people.list_header": "Voici les personnes que vous avez enregistrées :", + "saved_people.title": "Personnes enregistrées", + "saved_searches.button": "Recherches enregistrées", + "saved_searches.empty_state": "Vous n'avez enregistré aucune recherche. Pour en enregistrer une, cliquez sur Être notifié et nous vous préviendrons quotidiennement lorsque de nouvelles personnes correspondront.", + "saved_searches.notification_note": "Nous vous préviendrons quotidiennement lorsque de nouvelles personnes correspondront à vos recherches ci-dessous.", + "saved_searches.title": "Recherches enregistrées", + "security.contact.email_button": "E‑mail", + "security.contact.form": "Formulaire de contact", + "security.contact.title": "Nous contacter", + "security.how.contact_form": "formulaire de contact", + "security.how.contact_prefix": "Utilisez le ", + "security.how.contact_suffix": " et choisissez la catégorie sécurité si disponible.", + "security.how.email_prefix": "Envoyez-nous un e‑mail à ", + "security.how.text": "Veuillez ne pas ouvrir de tickets GitHub publics pour les rapports de sécurité. Contactez-nous directement par l'un des moyens suivants :", + "security.how.title": "Comment signaler", + "security.include.item1": "Une description claire du problème et de son impact potentiel", + "security.include.item2": "Les étapes pour reproduire (URL, comptes de test, requêtes/réponses exactes le cas échéant)", + "security.include.item3": "Toutes captures d'écran, vidéos ou code de preuve de concept", + "security.include.item4": "Votre système d'exploitation, navigateur et détails d'environnement", + "security.include.text": "Pour nous aider à trier et à résoudre rapidement le problème, veuillez inclure :", + "security.include.title": "Informations à inclure", + "security.intro": "Nous prenons la sécurité de notre communauté au sérieux. Si vous pensez avoir trouvé une vulnérabilité ou un problème de sécurité, veuillez le signaler de manière responsable afin que nous puissions enquêter et le corriger rapidement.", + "security.response.text": "Nous nous efforçons d'accuser réception des nouveaux rapports de sécurité sous quelques jours ouvrables et nous vous tiendrons informé pendant notre enquête et remédiation. Les délais peuvent varier selon la gravité et la complexité.", + "security.response.title": "Notre réponse", + "security.scope.text": "Veuillez éviter les tests susceptibles de dégrader le service pour d'autres utilisateurs (par ex., déni de service) ou impliquant l'accès aux données d'un autre utilisateur sans permission explicite.", + "security.scope.title": "Hors périmètre", + "security.seo.description": "Signalez les vulnérabilités de sécurité à l'équipe Compass", + "security.seo.title": "Sécurité", + "security.title": "Sécurité", + "settings.action.cancel": "Annuler", + "settings.action.save": "Enregistrer", + "settings.danger_zone": "Zone dangereuse", + "settings.delete.error": "Échec de la suppression du compte.", + "settings.delete.loading": "Suppression du compte..", + "settings.delete.success": "Votre compte a été supprimé.", + "settings.delete_account": "Supprimer le compte", + "settings.delete_confirm": "Êtes-vous sûr de vouloir supprimer votre profil ? Cela ne peut pas être annulé.", + "settings.email.change": "Modifier l'adresse e‑mail", + "settings.email.invalid": "Adresse e‑mail invalide", + "settings.email.must_sign_in": "Vous devez être connecté pour envoyer un courriel de vérification.", + "settings.email.new_placeholder": "Nouvelle adresse e‑mail", + "settings.email.no_email": "Aucun courriel trouvé sur votre compte.", + "settings.email.required": "Le courriel est requis", + "settings.email.same_as_current": "Le nouveau courriel est identique à l'actuel", + "settings.email.send_verification": "Envoyer un courriel de vérification", + "settings.email.sending": "Envoi du courriel de vérification...", + "settings.email.update_failed": "Échec de la mise à jour de l'adresse e‑mail", + "settings.email.updated_success": "Adresse e‑mail mise à jour avec succès", + "settings.email.verification_failed": "Échec de l'envoi du courriel de vérification.", + "settings.email.verification_sent": "Courriel de vérification envoyé — vérifiez votre boîte de réception et les spams.", + "settings.email.verified": "Courriel vérifié ✔️", + "settings.general.account": "Compte", + "settings.general.email": "Courriel", + "settings.general.language": "Langue", + "settings.general.password": "Mot de passe", + "settings.general.theme": "Thème", + "settings.password.send_reset": "Envoyer un e‑mail de réinitialisation de mot de passe", + "settings.tabs.about": "À propos", + "settings.tabs.general": "Général", + "settings.tabs.notifications": "Notifications", + "settings.title": "Paramètres", + "signin.continue": "Ou continuez avec", + "signin.email": "Courriel", + "signin.enter_email": "Veuillez taper votre email", + "signin.failed_credentials": "Echec de connexion avec cet email et mot de passe", + "signin.forgot_password": "Mot de passe oublié ?", + "signin.link_sign_up": "S'inscrire", + "signin.no_account": "Vous n'avez pas de compte ?", + "signin.password": "Mot de passe", + "signin.password_placeholder": "Votre mot de passe", + "signin.seo.description": "Connectez-vous à votre compte", + "signin.seo.title": "Se connecter", + "signin.submit": "Se connecter", + "signin.title": "Se connecter", + "signup.email": "Courriel", + "signup.email_placeholder": "vous@exemple.com", + "signup.error_password_mismatch": "Les mots de passe ne correspondent pas", + "signup.have_account": "Vous avez déjà un compte ?", + "signup.link_sign_in": "Se connecter", + "signup.name": "Nom", + "signup.name_placeholder": "Votre nom", + "signup.password": "Mot de passe", + "signup.password_confirm": "Confirmez le mot de passe", + "signup.password_confirm_placeholder": "Confirmez votre mot de passe", + "signup.password_placeholder": "Créez un mot de passe", + "signup.seo.description": "Créez un nouveau compte", + "signup.seo.title": "S'inscrire", + "signup.submit": "Créer le compte", + "signup.title": "Créer un compte", + "signup.toast.created": "Compte créé", + "social.discord": "Discord", + "social.email_button": "E‑mail", + "social.github": "GitHub", + "social.reddit": "Reddit", + "social.seo.description": "Réseaux sociaux", + "social.seo.title": "Réseaux sociaux", + "social.stoat": "Revolt / Stoat", + "social.title": "Réseaux sociaux", + "social.x": "X", + "stats.active_members": "Membres actifs (le mois dernier)", + "stats.compatibility_prompts": "Questions de compatibilité", + "stats.discussions": "Discussions", + "stats.endorsements": "Recommandations", + "stats.members": "Membres", + "stats.messages": "Messages", + "stats.number_members": "Nombre de membres", + "stats.prompts_answered": "Questions répondues", + "stats.proposals": "Propositions", + "stats.searches_bookmarked": "Recherches mises en favoris", + "stats.seo.description": "Statistiques", + "stats.seo.title": "Statistiques", + "stats.title": "Croissance et statistiques", + "stats.total": "Total", + "stats.votes": "Votes", + "stats.with_bio": "Avec bio", + "terms.changes.text": "Nous pouvons mettre à jour ces Conditions périodiquement. La poursuite de l'utilisation de Compass après les mises à jour vaut acceptation des nouvelles Conditions.", + "terms.changes.title": "6. Modifications", + "terms.contact": "Pour toute question concernant ces Conditions, veuillez nous contacter à ", + "terms.effective_date": "Date d'entrée en vigueur : 1er janvier 2025", + "terms.eligibility.text": "Vous devez avoir au moins 15 ans pour créer un compte et utiliser Compass. En vous inscrivant, vous confirmez répondre à cette exigence.", + "terms.eligibility.title": "1. Admissibilité", + "terms.intro.prefix": "Bienvenue sur ", + "terms.intro.suffix": ", une plateforme pour se connecter, collaborer et construire des interactions pertinentes. En accédant à notre service ou en l'utilisant, vous acceptez les présentes Conditions générales.", + "terms.ip.a": "a. Propriété et Licence. Compass est développé et maintenu en tant que projet libre et open source. Sauf indication contraire, tout le code source, les designs et les documents associés (« Matériels du projet ») sont sous licence AGPL-3.0. Certains composants peuvent être sous des licences open source permissives, comme indiqué explicitement. Sous réserve des termes de la licence applicable, vous recevez une licence mondiale, gratuite, non exclusive et irrévocable pour utiliser, copier, modifier, fusionner, publier, distribuer, sous‑licencier et/ou vendre des copies des Matériels du projet conformément aux termes de la licence applicable.", + "terms.ip.b": "b. Gouvernance communautaire. Compass fonctionne selon un modèle de gouvernance piloté par la communauté. Toute modification substantielle des licences, de la monétisation (y compris la publicité) ou des structures de gouvernance nécessite l'approbation via le processus défini par la communauté Compass. Toutes les décisions de gouvernance seront rendues publiques.", + "terms.ip.c": "c. Contributions. En soumettant du code, des designs, de la documentation ou d'autres contributions (« Contributions ») à Compass, vous acceptez que ces Contributions soient sous la même licence open source régissant les Matériels du projet au moment de la contribution. Vous déclarez et garantissez avoir le droit d'accorder une telle licence et que vos Contributions ne portent pas atteinte aux droits de tiers.", + "terms.ip.d": "d. Absence de restrictions propriétaires. Compass reste exempt de publicité, de verrouillages propriétaires et de monétisation des données, sauf approbation explicite de la communauté conformément à son processus de gouvernance. Les utilisateurs et contributeurs ne doivent pas introduire de telles restrictions sans approbation préalable de la communauté.", + "terms.ip.title": "3. Propriété intellectuelle et licences", + "terms.liability.text": "Compass n'est pas responsable des litiges entre utilisateurs ni des dommages résultant de l'utilisation de la plateforme. Utilisez la plateforme à votre propre discrétion.", + "terms.liability.title": "5. Responsabilité", + "terms.responsibilities.text": "Les utilisateurs doivent interagir avec respect, éviter le spam et s'abstenir de tout comportement perturbant la communauté ou violant les lois applicables.", + "terms.responsibilities.title": "2. Responsabilités de l'utilisateur", + "terms.safety.a": "a. Nudité et contenu sexuel. Compass n'autorise pas le partage public de nudité ou de contenu sexuellement explicite. Tout contenu incluant de la nudité, des actes sexuels ou des éléments suggestifs sera supprimé et pourra entraîner la suspension ou la résiliation des comptes concernés.", + "terms.safety.b": "b. Abus et exploitation sexuelle des enfants (CSAE). Compass applique une politique de tolérance zéro envers toute forme d'abus ou d'exploitation sexuelle d'enfants (« CSAE »). Le CSAE désigne tout contenu ou comportement exploitant, abusant ou mettant en danger les enfants — y compris, sans s'y limiter, l'aguichage en vue d'exploitation sexuelle, l'extorsion sexuelle, la traite d'un enfant à des fins sexuelles, ou toute autre forme d'exploitation sexuelle d'un enfant. Tout CSAE suspect entraînera la résiliation immédiate du compte et pourra être signalé aux forces de l'ordre et au NCMEC, comme l'exige la loi.", + "terms.safety.c": "c. Violence et contenu nuisible. Compass n'autorise pas le partage de violences réelles et graphiques en dehors d'un contexte d'actualité, contextuel ou éducatif. Tout contenu faisant la promotion ou glorifiant la violence sera supprimé.", + "terms.safety.d": "d. Partage de localisation. Compass ne partage pas l'emplacement physique précis des utilisateurs avec d'autres sans consentement explicite. Toute fonctionnalité optionnelle liée à la localisation indiquera clairement l'usage et le partage des données de localisation.", + "terms.safety.e": "e. Biens numériques et transactions. Compass est une plateforme entièrement gratuite. Elle ne vend pas de biens numériques, ne propose pas d'achats intégrés ni ne facture l'accès à des fonctionnalités. Toutes les fonctionnalités sont disponibles sans paiement.", + "terms.safety.f": "f. Contrôles de sécurité utilisateur. Compass inclut des fonctionnalités intégrées permettant aux utilisateurs de :", + "terms.safety.f1": "Bloquer d'autres utilisateurs ou du contenu généré par les utilisateurs.", + "terms.safety.f2": "Signaler des utilisateurs ou du contenu qui enfreignent les normes communautaires.", + "terms.safety.f3": "Bénéficier d'une modération active des discussions pour garantir un environnement sûr et respectueux.", + "terms.safety.f4": "Limiter les interactions aux amis invités uniquement, lorsque la fonctionnalité le permet.", + "terms.safety.title": "4. Normes communautaires et sécurité", + "terms.seo.description": "Conditions générales de Compass", + "terms.seo.title": "Conditions générales", + "terms.title": "Conditions générales", + "theme.auto": "Automatique", + "theme.dark": "Sombre", + "theme.light": "Clair", + "vote.abstain": "Abstention", + "vote.against": "Contre", + "vote.creator.placeholder": "Veuillez décrire votre proposition ici", + "vote.discuss.and": ", ou sur nos ", + "vote.discuss.link_contact": "formulaire de contact", + "vote.discuss.link_feedback": "formulaire de retour", + "vote.discuss.link_socials": "réseaux", + "vote.discuss.middle": ", le ", + "vote.discuss.prefix": "Vous pouvez discuter de ces propositions via le ", + "vote.discuss.suffix": ".", + "vote.failed": "Échec du vote — veuillez réessayer", + "vote.for": "Pour", + "vote.form.anonymous": "Anonyme ?", + "vote.form.submit": "Soumettre", + "vote.form.title_placeholder": "Titre", + "vote.high": "Haute", + "vote.low": "Faible", + "vote.medium": "Moyenne", + "vote.order.label": "Trier par :", + "vote.priority": "Priorité", + "vote.seo.description": "Un endroit pour voter sur les décisions", + "vote.seo.title": "Propositions", + "vote.showmore.closed": "Ajouter une nouvelle proposition", + "vote.showmore.open": "Masquer", + "vote.sign_in_required": "Veuillez vous connecter pour voter", + "vote.sort.mostVoted": "Plus votés", + "vote.sort.priority": "Plus prioritaires", + "vote.sort.recent": "Plus récents", + "vote.status.accepted": "Accepté", + "vote.status.archived": "Archivé", + "vote.status.cancelled": "Annulé 🚫", + "vote.status.draft": "Brouillon", + "vote.status.expired": "Expiré ⌛", + "vote.status.implemented": "Implémenté ✔️", + "vote.status.pending": "En attente d'implémentation", + "vote.status.rejected": "Rejeté ❌", + "vote.status.superseded": "Remplacé", + "vote.status.under_review": "En révision", + "vote.status.voting_closed": "Vote clos", + "vote.status.voting_open": "Vote ouvert", + "vote.title": "Propositions", + "vote.toast.create_failed": "Échec de la création de la proposition — réessayez ou contactez-nous...", + "vote.toast.created": "Proposition créée", + "vote.urgent": "Urgente", + "vote.voted": "Vote enregistré", + "vote.with_priority": "avec priorité" } \ No newline at end of file