Browse Source

fix: ensure RTL direction and title alignment for assessment intro pages and onboarding slider

master
mortezaei 1 week ago
parent
commit
94129c8345
  1. 3
      src/app/layout.tsx
  2. 63
      src/app/questions-list/[slug]/question-detail-client.tsx
  3. 10
      src/app/questions-list/[slug]/test-intro-client.tsx
  4. 10
      src/components/Componentes/slider-header.tsx
  5. 57
      src/components/Componentes/slider-page.test.tsx
  6. 7
      src/components/Componentes/slider-page.tsx
  7. 23
      src/components/Componentes/slider-slide-five.tsx
  8. 26
      src/components/Componentes/slider-slide-four.tsx
  9. 22
      src/components/Componentes/slider-slide-three.tsx
  10. 19
      src/components/Componentes/test-intro-page.tsx
  11. 8
      src/components/Componentes/token-switcher.tsx
  12. 20
      src/lib/view-paddings.ts
  13. 6
      src/translations/locales/ar.json
  14. 6
      src/translations/locales/az.json
  15. 6
      src/translations/locales/bn.json
  16. 6
      src/translations/locales/da.json
  17. 6
      src/translations/locales/de.json
  18. 6
      src/translations/locales/en.json
  19. 6
      src/translations/locales/es.json
  20. 6
      src/translations/locales/fa.json
  21. 6
      src/translations/locales/fr.json
  22. 6
      src/translations/locales/gu.json
  23. 6
      src/translations/locales/ha.json
  24. 6
      src/translations/locales/he.json
  25. 6
      src/translations/locales/hi.json
  26. 6
      src/translations/locales/id.json
  27. 6
      src/translations/locales/ks.json
  28. 6
      src/translations/locales/pt.json
  29. 6
      src/translations/locales/ru.json
  30. 6
      src/translations/locales/sw.json
  31. 6
      src/translations/locales/tg.json
  32. 6
      src/translations/locales/tr.json
  33. 6
      src/translations/locales/ul.json
  34. 6
      src/translations/locales/ur.json
  35. 6
      src/translations/locales/uz.json
  36. 6
      src/translations/locales/zh.json

3
src/app/layout.tsx

@ -303,7 +303,8 @@ export default async function RootLayout({
document.cookie = 'HABIB_LANGUAGE=' + encodeURIComponent(String(code)) + '; Path=/; Max-Age=31536000; SameSite=Lax' + secure; document.cookie = 'HABIB_LANGUAGE=' + encodeURIComponent(String(code)) + '; Path=/; Max-Age=31536000; SameSite=Lax' + secure;
document.cookie = 'habib_language=' + encodeURIComponent(String(code)) + '; Path=/; Max-Age=31536000; SameSite=Lax' + secure; document.cookie = 'habib_language=' + encodeURIComponent(String(code)) + '; Path=/; Max-Age=31536000; SameSite=Lax' + secure;
root.lang = String(code); root.lang = String(code);
root.dir = (locale.isRTL || locale.isRtl || locale.is_rtl) ? 'rtl' : 'ltr';
var rtlCodes = ['fa', 'ar', 'ur', 'he', 'ks'];
root.dir = (locale.isRTL || locale.isRtl || locale.is_rtl || rtlCodes.indexOf(String(code).toLowerCase()) !== -1) ? 'rtl' : 'ltr';
var knownLocales = ['fa', 'ar', 'en', 'ur', 'tr', 'ru', 'fr', 'es', 'de', 'id', 'bn', 'hi', 'pt', 'ha', 'sw', 'uz', 'az', 'tg', 'ks', 'zh', 'da', 'he', 'gu', 'ul']; var knownLocales = ['fa', 'ar', 'en', 'ur', 'tr', 'ru', 'fr', 'es', 'de', 'id', 'bn', 'hi', 'pt', 'ha', 'sw', 'uz', 'az', 'tg', 'ks', 'zh', 'da', 'he', 'gu', 'ul'];
var segments = window.location.pathname.split('/'); var segments = window.location.pathname.split('/');
var currentCode = segments[1]; var currentCode = segments[1];

63
src/app/questions-list/[slug]/question-detail-client.tsx

@ -54,7 +54,12 @@ import {
readScopedAssessmentDraft, readScopedAssessmentDraft,
removeScopedAssessmentDraft, removeScopedAssessmentDraft,
} from "@/lib/user-scoped-storage"; } from "@/lib/user-scoped-storage";
import { defaultLocale, type Locale } from "@/translations/config";
import {
defaultLocale,
type Locale,
localeDirections,
rtlLanguages,
} from "@/translations/config";
import { formatEstimateTime } from "@/translations/format-estimate"; import { formatEstimateTime } from "@/translations/format-estimate";
import { useI18n } from "@/translations/provider"; import { useI18n } from "@/translations/provider";
@ -259,13 +264,16 @@ export default function QuestionDetailClient({
description, description,
informationLabel, informationLabel,
itemSlug, itemSlug,
locale = defaultLocale,
locale: propLocale = defaultLocale,
questionsListHref, questionsListHref,
title, title,
onClose, onClose,
}: QuestionDetailClientProps) { }: QuestionDetailClientProps) {
const router = useRouter(); const router = useRouter();
const { dictionary: t } = useI18n();
const { dictionary: t, locale: contextLocale } = useI18n();
const locale = contextLocale || propLocale;
const isRtl =
localeDirections[locale] === "rtl" || rtlLanguages.includes(locale);
const [isTestStarted, setIsTestStarted] = useState(false); const [isTestStarted, setIsTestStarted] = useState(false);
const [hasTestProgress, setHasTestProgress] = useState(false); const [hasTestProgress, setHasTestProgress] = useState(false);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@ -539,7 +547,10 @@ export default function QuestionDetailClient({
return ( return (
<> <>
{renderPageBackground()} {renderPageBackground()}
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader <StickyHeader
sticky={false} sticky={false}
className="question-detail-header shrink-0" className="question-detail-header shrink-0"
@ -584,7 +595,10 @@ export default function QuestionDetailClient({
return ( return (
<> <>
{renderPageBackground()} {renderPageBackground()}
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader <StickyHeader
sticky={false} sticky={false}
className="question-detail-header shrink-0" className="question-detail-header shrink-0"
@ -620,7 +634,10 @@ export default function QuestionDetailClient({
return ( return (
<> <>
{renderPageBackground()} {renderPageBackground()}
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader <StickyHeader
sticky={false} sticky={false}
className="question-detail-header shrink-0" className="question-detail-header shrink-0"
@ -805,7 +822,10 @@ export default function QuestionDetailClient({
return ( return (
<> <>
{renderPageBackground()} {renderPageBackground()}
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader <StickyHeader
sticky={false} sticky={false}
className="question-detail-header shrink-0" className="question-detail-header shrink-0"
@ -855,7 +875,7 @@ export default function QuestionDetailClient({
}} }}
> >
{isCattellSlug ? ( {isCattellSlug ? (
<div className="mt-5 text-start">
<div className="mt-5 text-start" dir={isRtl ? "rtl" : "ltr"}>
<ul className="space-y-4"> <ul className="space-y-4">
{[ {[
{ {
@ -898,10 +918,16 @@ export default function QuestionDetailClient({
}, },
].map((bullet, index) => ( ].map((bullet, index) => (
<li key={index} className="min-w-0"> <li key={index} className="min-w-0">
<h4 className="group-12 font-bold text-[#1B1B1B] leading-snug">
<h4
dir={isRtl ? "rtl" : "ltr"}
className="group-12 font-bold text-[#1B1B1B] leading-snug text-start rtl:text-right"
>
{bullet.title} {bullet.title}
</h4> </h4>
<p className="group-12 text-[#5A5A5A] mt-1 leading-[1.55] text-justify">
<p
dir={isRtl ? "rtl" : "ltr"}
className="group-12 text-[#5A5A5A] mt-1 leading-[1.55] text-justify"
>
{bullet.desc} {bullet.desc}
</p> </p>
</li> </li>
@ -909,7 +935,7 @@ export default function QuestionDetailClient({
</ul> </ul>
</div> </div>
) : isGlasserSlug ? ( ) : isGlasserSlug ? (
<div className="mt-5 text-start">
<div className="mt-5 text-start" dir={isRtl ? "rtl" : "ltr"}>
<ul className="space-y-4"> <ul className="space-y-4">
{[ {[
{ {
@ -951,10 +977,16 @@ export default function QuestionDetailClient({
}, },
].map((bullet, index) => ( ].map((bullet, index) => (
<li key={index} className="min-w-0"> <li key={index} className="min-w-0">
<h4 className="group-12 font-bold text-[#1B1B1B] leading-snug">
<h4
dir={isRtl ? "rtl" : "ltr"}
className="group-12 font-bold text-[#1B1B1B] leading-snug text-start rtl:text-right"
>
{bullet.title} {bullet.title}
</h4> </h4>
<p className="group-12 text-[#5A5A5A] mt-1 leading-[1.55] text-justify">
<p
dir={isRtl ? "rtl" : "ltr"}
className="group-12 text-[#5A5A5A] mt-1 leading-[1.55] text-justify"
>
{bullet.desc} {bullet.desc}
</p> </p>
</li> </li>
@ -987,7 +1019,10 @@ export default function QuestionDetailClient({
questions={item.questions} questions={item.questions}
locale={locale} locale={locale}
> >
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader <StickyHeader
sticky={false} sticky={false}
className="question-detail-header shrink-0" className="question-detail-header shrink-0"

10
src/app/questions-list/[slug]/test-intro-client.tsx

@ -5,6 +5,8 @@ import TestIntroPage from "@/components/Componentes/test-intro-page";
import NavigationButton from "@/components/Componentes/navigation-button"; import NavigationButton from "@/components/Componentes/navigation-button";
import StickyHeader from "@/components/Componentes/sticky-header"; import StickyHeader from "@/components/Componentes/sticky-header";
import { PageBackground } from "@/components/Componentes/page-background"; import { PageBackground } from "@/components/Componentes/page-background";
import { localeDirections, rtlLanguages } from "@/translations/config";
import { useI18n } from "@/translations/provider";
type TestIntroClientProps = { type TestIntroClientProps = {
title: string; title: string;
@ -28,11 +30,17 @@ export default function TestIntroClient({
informationLabel, informationLabel,
}: TestIntroClientProps) { }: TestIntroClientProps) {
const router = useRouter(); const router = useRouter();
const { locale } = useI18n();
const isRtl =
localeDirections[locale] === "rtl" || rtlLanguages.includes(locale);
return ( return (
<> <>
<PageBackground disabled variant="cream" /> <PageBackground disabled variant="cream" />
<main className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]">
<main
dir={isRtl ? "rtl" : "ltr"}
className="question-detail-main flex h-svh flex-col overflow-hidden bg-[#F7F1F0]"
>
<StickyHeader sticky={false} className="shrink-0"> <StickyHeader sticky={false} className="shrink-0">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<NavigationButton <NavigationButton

10
src/components/Componentes/slider-header.tsx

@ -1,5 +1,6 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { SHOW_INTRO_VIDEOS } from "@/config/features"; import { SHOW_INTRO_VIDEOS } from "@/config/features";
import { useI18n } from "@/translations/provider";
type SliderHeaderProps = { type SliderHeaderProps = {
index: number; index: number;
@ -14,10 +15,17 @@ export function SliderHeader({
totalSteps = SHOW_INTRO_VIDEOS ? 5 : 4, totalSteps = SHOW_INTRO_VIDEOS ? 5 : 4,
stepLabel, stepLabel,
}: SliderHeaderProps) { }: SliderHeaderProps) {
const { dictionary: t } = useI18n();
const tRecord = t as Record<string, string>;
const defaultStepLabel = (tRecord["Step {step} of {total}"] || "Step {step} of {total}")
.replace("{step}", String(index + 1))
.replace("{total}", String(totalSteps));
return ( return (
<div className="text-center"> <div className="text-center">
<p className="text-[#747474] group-10 font-semibold"> <p className="text-[#747474] group-10 font-semibold">
{stepLabel || `Step ${index + 1} of ${totalSteps}`}
{stepLabel || defaultStepLabel}
</p> </p>
<p className="text-[#111111] group-16 font-bold">{title}</p> <p className="text-[#111111] group-16 font-bold">{title}</p>
</div> </div>

57
src/components/Componentes/slider-page.test.tsx

@ -37,18 +37,24 @@ vi.mock('next/navigation', () => ({
}), }),
})); }));
let mockLocale = 'en';
vi.mock('@/translations/provider', () => ({ vi.mock('@/translations/provider', () => ({
useI18n: () => ({ useI18n: () => ({
locale: 'en',
locale: mockLocale,
dictionary: { dictionary: {
"Something went wrong. Please check your internet connection and try again.": "Something went wrong. Please check your internet connection and try again.", "Something went wrong. Please check your internet connection and try again.": "Something went wrong. Please check your internet connection and try again.",
"Accept & Continue": "Accept & Continue", "Accept & Continue": "Accept & Continue",
"Select your gender": "جنسیت خود را انتخاب کنید",
"Registration Type": "نوع ثبت‌نام",
"Final Notice": "توجه نهایی",
}, },
}), }),
})); }));
vi.mock('@/translations/config', () => ({ vi.mock('@/translations/config', () => ({
localizePath: (path: string, locale: string) => path, localizePath: (path: string, locale: string) => path,
localeDirections: { en: 'ltr', fa: 'rtl' },
})); }));
describe('SliderPage', () => { describe('SliderPage', () => {
@ -56,6 +62,7 @@ describe('SliderPage', () => {
beforeEach(() => { beforeEach(() => {
vi.resetAllMocks(); vi.resetAllMocks();
mockLocale = 'en';
queryClient = new QueryClient(); queryClient = new QueryClient();
vi.spyOn(queryClient, 'setQueryData'); vi.spyOn(queryClient, 'setQueryData');
}); });
@ -316,9 +323,51 @@ describe('SliderPage', () => {
// Still on Slide 1 (terms) // Still on Slide 1 (terms)
expect(screen.getByText('Terms & Conditions')).toBeInTheDocument(); expect(screen.getByText('Terms & Conditions')).toBeInTheDocument();
} finally { } finally {
if (origScrollHeight) Object.defineProperty(HTMLElement.prototype, 'scrollHeight', origScrollHeight);
if (origClientHeight) Object.defineProperty(HTMLElement.prototype, 'clientHeight', origClientHeight);
if (origScrollTop) Object.defineProperty(HTMLElement.prototype, 'scrollTop', origScrollTop);
if (origScrollHeight) {
Object.defineProperty(HTMLElement.prototype, 'scrollHeight', origScrollHeight);
} else {
delete (HTMLElement.prototype as any).scrollHeight;
}
if (origClientHeight) {
Object.defineProperty(HTMLElement.prototype, 'clientHeight', origClientHeight);
} else {
delete (HTMLElement.prototype as any).clientHeight;
}
if (origScrollTop) {
Object.defineProperty(HTMLElement.prototype, 'scrollTop', origScrollTop);
} else {
delete (HTMLElement.prototype as any).scrollTop;
}
} }
}); });
it('h. RTL mode: calculates positive translateX when moving forward in RTL', async () => {
mockLocale = 'fa';
render(
<QueryClientProvider client={queryClient}>
<SliderPage />
</QueryClientProvider>
);
const acceptBtn = screen.getByRole('button', { name: /accept/i });
fireEvent.click(acceptBtn);
// Slide 2 in RTL should have positive translateX(100%)
const track = document.querySelector('main > div');
expect(track).toHaveStyle({ transform: 'translateX(100%)' });
// Header title for gender slide should use translated text
expect(screen.getByText('جنسیت خود را انتخاب کنید')).toBeInTheDocument();
// Advance to Slide 3 (index 2) -> translateX(200%)
const nextBtn = screen.getByRole('button', { name: /next/i });
fireEvent.click(nextBtn);
expect(track).toHaveStyle({ transform: 'translateX(200%)' });
expect(screen.getByText('نوع ثبت‌نام')).toBeInTheDocument();
// Advance to Slide 4 (index 3) -> translateX(300%)
fireEvent.click(nextBtn);
expect(track).toHaveStyle({ transform: 'translateX(300%)' });
expect(screen.getByText('توجه نهایی')).toBeInTheDocument();
});
}); });

7
src/components/Componentes/slider-page.tsx

@ -12,7 +12,7 @@ import {
getSubmitPath, getSubmitPath,
hasCompletedMarriageProfileBasics, hasCompletedMarriageProfileBasics,
} from "@/lib/get-submit-path"; } from "@/lib/get-submit-path";
import { localizePath } from "@/translations/config";
import { localizePath, localeDirections } from "@/translations/config";
import { useI18n } from "@/translations/provider"; import { useI18n } from "@/translations/provider";
import Button from "./button"; import Button from "./button";
import ErrorToast from "./error-toast"; import ErrorToast from "./error-toast";
@ -178,6 +178,9 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
} }
}; };
const isRtl = localeDirections?.[locale] === "rtl";
const translatePercent = (isRtl ? 1 : -1) * activeSlide * 100;
return ( return (
<div className="relative flex h-[100dvh] max-h-[100dvh] flex-col overflow-hidden"> <div className="relative flex h-[100dvh] max-h-[100dvh] flex-col overflow-hidden">
{submitError && ( {submitError && (
@ -224,7 +227,7 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
<main className="flex min-h-0 flex-1 overflow-hidden pt-2"> <main className="flex min-h-0 flex-1 overflow-hidden pt-2">
<div <div
className="flex h-full w-full transition-transform duration-300 ease-out" className="flex h-full w-full transition-transform duration-300 ease-out"
style={{ transform: `translateX(-${activeSlide * 100}%)` }}
style={{ transform: `translateX(${translatePercent}%)` }}
> >
<SliderSlideOne <SliderSlideOne
index={0} index={0}

23
src/components/Componentes/slider-slide-five.tsx

@ -1,3 +1,6 @@
"use client";
import { useI18n } from "@/translations/provider";
import { SliderHeader } from "./slider-header"; import { SliderHeader } from "./slider-header";
import type { SliderSlideProps } from "./slider-slide"; import type { SliderSlideProps } from "./slider-slide";
@ -10,25 +13,33 @@ const NOTICE_ITEMS = [
"We provide a safe and respectful environment at every step.", "We provide a safe and respectful environment at every step.",
]; ];
const MAIN_NOTICE =
"Your privacy and safety are our top priorities. We are committed to keeping your information secure and giving you full control throughout the process.";
export function SliderSlideFive({ index, totalSteps }: SliderSlideProps) { export function SliderSlideFive({ index, totalSteps }: SliderSlideProps) {
const { dictionary: t } = useI18n();
const tRecord = t as Record<string, string>;
return ( return (
<section <section
aria-label={`Slide ${index + 1}`} aria-label={`Slide ${index + 1}`}
className="flex h-full min-h-0 w-full shrink-0 flex-col" className="flex h-full min-h-0 w-full shrink-0 flex-col"
> >
<div className="min-h-0 flex-1 overflow-y-auto pb-28"> <div className="min-h-0 flex-1 overflow-y-auto pb-28">
<SliderHeader index={index} totalSteps={totalSteps} title="Final Notice" />
<SliderHeader
index={index}
totalSteps={totalSteps}
title={tRecord["Final Notice"] || "Final Notice"}
/>
<div className="mt-6 space-y-5"> <div className="mt-6 space-y-5">
<p className="text-[#36363C] text-sm font-semibold leading-5"> <p className="text-[#36363C] text-sm font-semibold leading-5">
Your privacy and safety are our top priorities. We are committed to
keeping your information secure and giving you full control
throughout the process.
{tRecord[MAIN_NOTICE] || MAIN_NOTICE}
</p> </p>
<ul className="list-disc space-y-2 pl-5 text-[#36363C] text-sm font-semibold leading-5">
<ul className="list-disc space-y-2 ps-5 text-[#36363C] text-sm font-semibold leading-5">
{NOTICE_ITEMS.map((item) => ( {NOTICE_ITEMS.map((item) => (
<li key={item}>{item}</li>
<li key={item}>{tRecord[item] || item}</li>
))} ))}
</ul> </ul>
</div> </div>

26
src/components/Componentes/slider-slide-four.tsx

@ -1,5 +1,6 @@
"use client"; "use client";
import { useI18n } from "@/translations/provider";
import NoticeBox from "./notice-box"; import NoticeBox from "./notice-box";
import { SliderHeader } from "./slider-header"; import { SliderHeader } from "./slider-header";
import type { RegistrationAnswer, SliderSlideProps } from "./slider-slide"; import type { RegistrationAnswer, SliderSlideProps } from "./slider-slide";
@ -9,15 +10,27 @@ type SliderSlideFourProps = SliderSlideProps & {
onRegistrationChange: (registration: RegistrationAnswer) => void; onRegistrationChange: (registration: RegistrationAnswer) => void;
}; };
const NOTICE_TEXT =
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.";
export function SliderSlideFour({ export function SliderSlideFour({
index, index,
totalSteps, totalSteps,
selectedRegistration, selectedRegistration,
onRegistrationChange, onRegistrationChange,
}: SliderSlideFourProps) { }: SliderSlideFourProps) {
const { dictionary: t } = useI18n();
const tRecord = t as Record<string, string>;
const options = [ const options = [
{ id: "self", label: "Registering for myself" },
{ id: "other", label: "Registering for someone else" },
{
id: "self",
label: tRecord["Registering for myself"] || "Registering for myself",
},
{
id: "other",
label: tRecord["Registering for someone else"] || "Registering for someone else",
},
] as const; ] as const;
return ( return (
@ -29,15 +42,10 @@ export function SliderSlideFour({
<SliderHeader <SliderHeader
index={index} index={index}
totalSteps={totalSteps} totalSteps={totalSteps}
title="Registration Type"
title={tRecord["Registration Type"] || "Registration Type"}
/> />
<NoticeBox className="mt-8" align="justify"> <NoticeBox className="mt-8" align="justify">
You can register both for yourself and for your loved ones, but
obtaining the explicit consent and permission of the person you are
creating the profile for is mandatory. To ensure accuracy, it is best
to let the individual complete the subsequent steps themselves.
Remember that all matches are introduced with absolute privacy and
strictly based on the information you provide.
{tRecord[NOTICE_TEXT] || NOTICE_TEXT}
</NoticeBox> </NoticeBox>
<div className="flex min-h-[calc(100dvh-520px)] items-center justify-center pt-6"> <div className="flex min-h-[calc(100dvh-520px)] items-center justify-center pt-6">
<div className="w-full max-w-[440px] space-y-4"> <div className="w-full max-w-[440px] space-y-4">

22
src/components/Componentes/slider-slide-three.tsx

@ -1,12 +1,14 @@
"use client"; "use client";
import Image from "next/image"; import Image from "next/image";
import { useI18n } from "@/translations/provider";
import { SliderHeader } from "./slider-header"; import { SliderHeader } from "./slider-header";
import type { GenderAnswer, SliderSlideProps } from "./slider-slide"; import type { GenderAnswer, SliderSlideProps } from "./slider-slide";
type GenderOption = { type GenderOption = {
id: GenderAnswer; id: GenderAnswer;
label: string;
labelKey: string;
defaultLabel: string;
alt: string; alt: string;
enabledSrc: string; enabledSrc: string;
disabledSrc: string; disabledSrc: string;
@ -15,14 +17,16 @@ type GenderOption = {
const GENDER_OPTIONS: GenderOption[] = [ const GENDER_OPTIONS: GenderOption[] = [
{ {
id: "man", id: "man",
label: "Man",
labelKey: "Man",
defaultLabel: "Man",
alt: "man", alt: "man",
enabledSrc: "/assets/images/Group 27033.svg", enabledSrc: "/assets/images/Group 27033.svg",
disabledSrc: "/assets/images/disabled Group 27033.svg", disabledSrc: "/assets/images/disabled Group 27033.svg",
}, },
{ {
id: "woman", id: "woman",
label: "Woman",
labelKey: "Woman",
defaultLabel: "Woman",
alt: "woman", alt: "woman",
enabledSrc: "/assets/images/enabled Group 27032.svg", enabledSrc: "/assets/images/enabled Group 27032.svg",
disabledSrc: "/assets/images/Group 27032.svg", disabledSrc: "/assets/images/Group 27032.svg",
@ -40,16 +44,24 @@ export function SliderSlideThree({
selectedGender, selectedGender,
onGenderChange, onGenderChange,
}: SliderSlideThreeProps) { }: SliderSlideThreeProps) {
const { dictionary: t } = useI18n();
const tRecord = t as Record<string, string>;
return ( return (
<section <section
aria-label={`Slide ${index + 1}`} aria-label={`Slide ${index + 1}`}
className="flex h-full min-h-0 w-full shrink-0 flex-col justify-between" className="flex h-full min-h-0 w-full shrink-0 flex-col justify-between"
> >
<SliderHeader index={index} totalSteps={totalSteps} title="Select your gender" />
<SliderHeader
index={index}
totalSteps={totalSteps}
title={tRecord["Select your gender"] || "Select your gender"}
/>
<div className="flex w-full items-center justify-evenly"> <div className="flex w-full items-center justify-evenly">
{GENDER_OPTIONS.map((option) => { {GENDER_OPTIONS.map((option) => {
const isSelected = option.id === selectedGender; const isSelected = option.id === selectedGender;
const label = tRecord[option.labelKey] || option.defaultLabel;
return ( return (
<button <button
@ -88,7 +100,7 @@ export function SliderSlideThree({
isSelected ? "text-[#FF6175]" : "text-[#111111]", isSelected ? "text-[#FF6175]" : "text-[#111111]",
].join(" ")} ].join(" ")}
> >
{option.label}
{label}
</p> </p>
</button> </button>
); );

19
src/components/Componentes/test-intro-page.tsx

@ -2,6 +2,8 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { Ic } from "@/icons"; import { Ic } from "@/icons";
import { localeDirections, rtlLanguages } from "@/translations/config";
import { useI18n } from "@/translations/provider";
import Button from "./button"; import Button from "./button";
type TestIntroPageProps = { type TestIntroPageProps = {
@ -25,8 +27,15 @@ export default function TestIntroPage({
onStart, onStart,
children, children,
}: TestIntroPageProps) { }: TestIntroPageProps) {
const { locale } = useI18n();
const isRtl =
localeDirections[locale] === "rtl" || rtlLanguages.includes(locale);
return ( return (
<div className="flex flex-1 flex-col min-h-0 overflow-y-auto">
<div
dir={isRtl ? "rtl" : "ltr"}
className="flex flex-1 flex-col min-h-0 overflow-y-auto"
>
{/* Hero Image */} {/* Hero Image */}
<div className="mx-auto w-[348px] h-[156px] shrink-0 overflow-hidden rounded-[20px] shadow-[0_8px_28px_rgba(0,0,0,0.08)]"> <div className="mx-auto w-[348px] h-[156px] shrink-0 overflow-hidden rounded-[20px] shadow-[0_8px_28px_rgba(0,0,0,0.08)]">
<img <img
@ -46,12 +55,12 @@ export default function TestIntroPage({
{/* Test Info Section */} {/* Test Info Section */}
<div className="mt-5 px-1"> <div className="mt-5 px-1">
<h2 className="group-16 font-bold text-[#1B1B1B] leading-tight">
<h2 className="group-16 font-bold text-[#1B1B1B] leading-tight text-start rtl:text-right">
{title} {title}
</h2> </h2>
{/* Estimate Time */} {/* Estimate Time */}
<div className="mt-2.5 flex items-center gap-1.5">
<div className="mt-2.5 flex items-center gap-1.5 text-start rtl:text-right">
<Ic name="clock" className="size-4 text-[#5A5A5A]" /> <Ic name="clock" className="size-4 text-[#5A5A5A]" />
<span className="group-12 font-medium text-[#5A5A5A]"> <span className="group-12 font-medium text-[#5A5A5A]">
{description}: {estimateTime} {description}: {estimateTime}
@ -62,11 +71,11 @@ export default function TestIntroPage({
{children ? ( {children ? (
<div className="mt-4">{children}</div> <div className="mt-4">{children}</div>
) : bulletPoints.length > 0 ? ( ) : bulletPoints.length > 0 ? (
<ul className="mt-4 space-y-3 pl-1">
<ul className="mt-4 space-y-3 ps-1">
{bulletPoints.map((point, index) => ( {bulletPoints.map((point, index) => (
<li <li
key={index} key={index}
className="flex items-start gap-2 group-12 leading-[1.55] text-[#3A3A3A]"
className="flex items-start gap-2 group-12 leading-[1.55] text-[#3A3A3A] text-start rtl:text-right"
> >
<span className="mt-[6px] h-[5px] w-[5px] shrink-0 rounded-full bg-[#3A3A3A]" /> <span className="mt-[6px] h-[5px] w-[5px] shrink-0 rounded-full bg-[#3A3A3A]" />
<span>{point}</span> <span>{point}</span>

8
src/components/Componentes/token-switcher.tsx

@ -182,10 +182,10 @@ export function TokenSwitcher({
const resolvedLocale = isLocale(pathLocale) const resolvedLocale = isLocale(pathLocale)
? pathLocale ? pathLocale
: isLocale(cookieLocale)
? cookieLocale
: isLocale(savedDevLocale)
? savedDevLocale
: isLocale(cookieLocale ?? undefined)
? cookieLocale!
: isLocale(savedDevLocale ?? undefined)
? savedDevLocale!
: "fa"; : "fa";
setActiveLocale(resolvedLocale); setActiveLocale(resolvedLocale);

20
src/lib/view-paddings.ts

@ -272,7 +272,14 @@ class ViewPaddingsBridge {
locale: data?.locale locale: data?.locale
? { ? {
languageCode: String(data.locale.languageCode ?? ""), languageCode: String(data.locale.languageCode ?? ""),
isRTL: Boolean(data.locale.isRTL ?? data.locale.isRtl),
isRTL: Boolean(
data.locale.isRTL ??
data.locale.isRtl ??
(data.locale.languageCode &&
["fa", "ar", "ur", "he", "ks"].includes(
String(data.locale.languageCode).toLowerCase(),
)),
),
} }
: null, : null,
}; };
@ -295,11 +302,18 @@ class ViewPaddingsBridge {
private applyLocale(locale: any) { private applyLocale(locale: any) {
if (!locale) return; if (!locale) return;
const langCode = String(locale.languageCode ?? locale.language_code ?? "");
this.config = { this.config = {
...this.config, ...this.config,
locale: { locale: {
languageCode: String(locale.languageCode ?? locale.language_code ?? ""),
isRTL: Boolean(locale.isRTL ?? locale.isRtl ?? locale.is_rtl),
languageCode: langCode,
isRTL: Boolean(
locale.isRTL ??
locale.isRtl ??
locale.is_rtl ??
(langCode &&
["fa", "ar", "ur", "he", "ks"].includes(langCode.toLowerCase())),
),
}, },
}; };
this.notifyConfigListeners(); this.notifyConfigListeners();

6
src/translations/locales/ar.json

@ -2121,5 +2121,9 @@
"16 min": "16 دقيقة", "16 min": "16 دقيقة",
"Photo upload failed. Please try again.": "فشل تحميل الصورة. يرجى المحاولة مرة أخرى.", "Photo upload failed. Please try again.": "فشل تحميل الصورة. يرجى المحاولة مرة أخرى.",
"Failed to load image. Please try uploading again.": "فشل تحميل الصورة. يرجى إعادة المحاولة.", "Failed to load image. Please try uploading again.": "فشل تحميل الصورة. يرجى إعادة المحاولة.",
"File size exceeds the 10 MB limit.": "حجم الملف يتجاوز الحد المسموح به وهو 10 ميغابايت."
"File size exceeds the 10 MB limit.": "حجم الملف يتجاوز الحد المسموح به وهو 10 ميغابايت.",
"Man": "رجل",
"Woman": "امرأة",
"Step {step} of {total}": "الخطوة {step} من {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "يمكنك التسجيل لنفسك ولأحبائك، ولكن الحصول على الموافقة الصريحة والإذن من الشخص الذي تنشئ الملف الشخصي له أمر إلزامي. لضمان الدقة، من الأفضل ترك الشخص يكمل الخطوات التالية بنفسه. تذكر أن جميع الترشيحات تتم بخصوصية تامة وبناءً على المعلومات التي تقدمها فقط."
} }

6
src/translations/locales/az.json

@ -2119,5 +2119,9 @@
"16 min": "16 dəq", "16 min": "16 dəq",
"Photo upload failed. Please try again.": "Şəkil yüklənmədi. Zəhmət olmasa yenidən cəhd edin.", "Photo upload failed. Please try again.": "Şəkil yüklənmədi. Zəhmət olmasa yenidən cəhd edin.",
"Failed to load image. Please try uploading again.": "Şəkil yüklənmədi. Zəhmət olmasa yenidən yükləyin.", "Failed to load image. Please try uploading again.": "Şəkil yüklənmədi. Zəhmət olmasa yenidən yükləyin.",
"File size exceeds the 10 MB limit.": "Fayl ölçüsü 10 MB limitini aşır."
"File size exceeds the 10 MB limit.": "Fayl ölçüsü 10 MB limitini aşır.",
"Man": "Kişi",
"Woman": "Qadın",
"Step {step} of {total}": "{total} mərhələdən {step}-ci mərhələ",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Həm özünüz, həm də yaxınlarınız üçün qeydiyyatdan keçə bilərsiniz, lakin profil yaratdığınız şəxsin açıq razılığını və icazəsini almaq məcburidir. Dəqiqliyi təmin etmək üçün sonrakı addımları şəxsin özünün tamamlaması daha yaxşıdır. Unutmayın ki, bütün uyğunluqlar tam məxfiliklə və yalnız təqdim etdiyiniz məlumatlar əsasında təqdim edilir."
} }

6
src/translations/locales/bn.json

@ -2119,5 +2119,9 @@
"16 min": "১৬ মিনিট", "16 min": "১৬ মিনিট",
"Photo upload failed. Please try again.": "ছবি আপলোড ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।", "Photo upload failed. Please try again.": "ছবি আপলোড ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।",
"Failed to load image. Please try uploading again.": "ছবি লোড করতে ব্যর্থ হয়েছে। অনুগ্রহ করে আবার আপলোড করুন।", "Failed to load image. Please try uploading again.": "ছবি লোড করতে ব্যর্থ হয়েছে। অনুগ্রহ করে আবার আপলোড করুন।",
"File size exceeds the 10 MB limit.": "ফাইলের আকার 10 MB সীমা অতিক্রম করেছে।"
"File size exceeds the 10 MB limit.": "ফাইলের আকার 10 MB সীমা অতিক্রম করেছে।",
"Man": "পুরুষ",
"Woman": "মহিলা",
"Step {step} of {total}": "{total} এর মধ্যে {step} ধাপ",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "আপনি নিজের এবং আপনার প্রিয়জন উভয়ের জন্যই নিবন্ধন করতে পারেন, তবে আপনি যার জন্য প্রোফাইল তৈরি করছেন তার স্পষ্ট সম্মতি ও অনুমতি নেওয়া বাধ্যতামূলক। সঠিকতা নিশ্চিত করতে, পরবর্তী পদক্ষেপগুলি সংশ্লিষ্ট ব্যক্তিকে নিজে সম্পন্ন করতে দেওয়াই শ্রেয়। মনে রাখবেন যে সমস্ত পরিচয় সম্পূর্ণ গোপনীয়তার সাথে এবং কঠোরভাবে আপনার প্রদত্ত তথ্যের ভিত্তিতে করানো হয়।"
} }

6
src/translations/locales/da.json

@ -2119,5 +2119,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Billedoverførsel mislykkedes. Prøv venligst igen.", "Photo upload failed. Please try again.": "Billedoverførsel mislykkedes. Prøv venligst igen.",
"Failed to load image. Please try uploading again.": "Kunne ikke indlæse billede. Prøv venligst at uploade igen.", "Failed to load image. Please try uploading again.": "Kunne ikke indlæse billede. Prøv venligst at uploade igen.",
"File size exceeds the 10 MB limit.": "Filstørrelsen overstiger grænsen på 10 MB."
"File size exceeds the 10 MB limit.": "Filstørrelsen overstiger grænsen på 10 MB.",
"Man": "Mand",
"Woman": "Kvinde",
"Step {step} of {total}": "Trin {step} af {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Du kan registrere dig både for dig selv og for dine kære, men det er obligatorisk at indhente udtrykkeligt samtykke og tilladelse fra den person, du opretter profilen for. For at sikre nøjagtighed er det bedst at lade personen selv udfylde de efterfølgende trin. Husk, at alle matches introduceres med fuld diskretion og udelukkende baseret på de oplysninger, du giver."
} }

6
src/translations/locales/de.json

@ -2119,5 +2119,9 @@
"16 min": "16 Min.", "16 min": "16 Min.",
"Photo upload failed. Please try again.": "Foto-Upload fehlgeschlagen. Bitte versuchen Sie es erneut.", "Photo upload failed. Please try again.": "Foto-Upload fehlgeschlagen. Bitte versuchen Sie es erneut.",
"Failed to load image. Please try uploading again.": "Fehler beim Laden des Bildes. Bitte erneut hochladen.", "Failed to load image. Please try uploading again.": "Fehler beim Laden des Bildes. Bitte erneut hochladen.",
"File size exceeds the 10 MB limit.": "Die Dateigröße überschreitet das Limit von 10 MB."
"File size exceeds the 10 MB limit.": "Die Dateigröße überschreitet das Limit von 10 MB.",
"Man": "Mann",
"Woman": "Frau",
"Step {step} of {total}": "Schritt {step} von {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Sie können sich sowohl für sich selbst als auch für Ihre Angehörigen registrieren, jedoch ist die ausdrückliche Zustimmung und Erlaubnis der Person, für die Sie das Profil erstellen, zwingend erforderlich. Um Genauigkeit zu gewährleisten, ist es am besten, wenn die Person die weiteren Schritte selbst ausfüllt. Denken Sie daran, dass alle Vermittlungen unter strikter Geheimhaltung und ausschließlich auf Grundlage der von Ihnen gemachten Angaben erfolgen."
} }

6
src/translations/locales/en.json

@ -2110,5 +2110,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Photo upload failed. Please try again.", "Photo upload failed. Please try again.": "Photo upload failed. Please try again.",
"Failed to load image. Please try uploading again.": "Failed to load image. Please try uploading again.", "Failed to load image. Please try uploading again.": "Failed to load image. Please try uploading again.",
"File size exceeds the 10 MB limit.": "File size exceeds the 10 MB limit."
"File size exceeds the 10 MB limit.": "File size exceeds the 10 MB limit.",
"Man": "Man",
"Woman": "Woman",
"Step {step} of {total}": "Step {step} of {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide."
} }

6
src/translations/locales/es.json

@ -2119,5 +2119,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Error al subir la foto. Inténtalo de nuevo.", "Photo upload failed. Please try again.": "Error al subir la foto. Inténtalo de nuevo.",
"Failed to load image. Please try uploading again.": "Error al cargar la imagen. Intenta subirla de nuevo.", "Failed to load image. Please try uploading again.": "Error al cargar la imagen. Intenta subirla de nuevo.",
"File size exceeds the 10 MB limit.": "El tamaño del archivo supera el límite de 10 MB."
"File size exceeds the 10 MB limit.": "El tamaño del archivo supera el límite de 10 MB.",
"Man": "Hombre",
"Woman": "Mujer",
"Step {step} of {total}": "Paso {step} de {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Puede registrarse tanto para usted como para sus seres queridos, pero es obligatorio obtener el consentimiento explícito y el permiso de la persona para quien está creando el perfil. Para garantizar la precisión, es mejor permitir que la persona complete los pasos posteriores por sí misma. Recuerde que todas las presentaciones se realizan con absoluta privacidad y estrictamente basadas en la información que proporcione."
} }

6
src/translations/locales/fa.json

@ -2131,5 +2131,9 @@
"16 min": "۱۶ دقیقه", "16 min": "۱۶ دقیقه",
"Photo upload failed. Please try again.": "خطا در آپلود عکس. لطفاً دوباره امتحان کنید.", "Photo upload failed. Please try again.": "خطا در آپلود عکس. لطفاً دوباره امتحان کنید.",
"Failed to load image. Please try uploading again.": "خطا در بارگذاری تصویر. لطفاً مجدداً آپلود کنید.", "Failed to load image. Please try uploading again.": "خطا در بارگذاری تصویر. لطفاً مجدداً آپلود کنید.",
"File size exceeds the 10 MB limit.": "حجم فایل بیشتر از حد مجاز (۱۰ مگابایت) است."
"File size exceeds the 10 MB limit.": "حجم فایل بیشتر از حد مجاز (۱۰ مگابایت) است.",
"Man": "مرد",
"Woman": "زن",
"Step {step} of {total}": "مرحله {step} از {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "شما می‌توانید هم برای خودتان و هم برای عزیزانتان ثبت‌نام کنید، اما کسب رضایت و اجازه صریح فردی که برای او پروفایل می‌سازید الزامی است. جهت دقت اطلاعات، بهتر است تکمیل مراحل بعدی توسط خود فرد انجام شود. به یاد داشته باشید که تمامی موارد با حفظ حریم خصوصی کامل و صرفاً بر اساس اطلاعات ثبت‌شده معرفی می‌شوند."
} }

6
src/translations/locales/fr.json

@ -2119,5 +2119,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Échec du téléversement de la photo. Veuillez réessayer.", "Photo upload failed. Please try again.": "Échec du téléversement de la photo. Veuillez réessayer.",
"Failed to load image. Please try uploading again.": "Échec du chargement de l'image. Veuillez réessayer le téléversement.", "Failed to load image. Please try uploading again.": "Échec du chargement de l'image. Veuillez réessayer le téléversement.",
"File size exceeds the 10 MB limit.": "La taille du fichier dépasse la limite de 10 Mo."
"File size exceeds the 10 MB limit.": "La taille du fichier dépasse la limite de 10 Mo.",
"Man": "Homme",
"Woman": "Femme",
"Step {step} of {total}": "Étape {step} sur {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Vous pouvez vous inscrire pour vous-même ainsi que pour vos proches, mais l'obtention du consentement explicite et de l'autorisation de la personne pour laquelle vous créez le profil est obligatoire. Pour garantir l'exactitude des données, il est préférable de laisser la personne compléter elle-même les étapes suivantes. N'oubliez pas que toutes les présentations sont faites dans une confidentialité absolue et strictement basées sur les informations fournies."
} }

6
src/translations/locales/gu.json

@ -2121,5 +2121,9 @@
"16 min": "16 મિનિટ", "16 min": "16 મિનિટ",
"Photo upload failed. Please try again.": "ફોટો અપલોડ નિષ્ફળ ગયો. કૃપા કરીને ફરી પ્રયાસ કરો.", "Photo upload failed. Please try again.": "ફોટો અપલોડ નિષ્ફળ ગયો. કૃપા કરીને ફરી પ્રયાસ કરો.",
"Failed to load image. Please try uploading again.": "છબી લોડ કરવામાં નિષ્ફળ. કૃપા કરીને ફરીથી અપલોડ કરવાનો પ્રયાસ કરો.", "Failed to load image. Please try uploading again.": "છબી લોડ કરવામાં નિષ્ફળ. કૃપા કરીને ફરીથી અપલોડ કરવાનો પ્રયાસ કરો.",
"File size exceeds the 10 MB limit.": "ફાઇલનું કદ 10 MB ની મર્યાદા કરતાં વધી ગયું છે."
"File size exceeds the 10 MB limit.": "ફાઇલનું કદ 10 MB ની મર્યાદા કરતાં વધી ગયું છે.",
"Man": "પુરુષ",
"Woman": "સ્ત્રી",
"Step {step} of {total}": "{total} માંથી {step} પગલું",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "તમે તમારા માટે અને તમારા પ્રિયજનો બંને માટે નોંધણી કરાવી શકો છો, પરંતુ તમે જેના માટે પ્રોફાઇલ બનાવી રહ્યા છો તે વ્યક્તિની સ્પષ્ટ સંમતિ અને પરવાનગી મેળવવી ફરજિયાત છે. ચોકસાઈની ખાતરી કરવા માટે, બાકીના પગલાં વ્યક્તિ પોતે જ પૂર્ણ કરે તે વધુ સારું છે. યાદ રાખો કે તમામ પરિચય સંપૂર્ણ ગોપનીયતા સાથે અને ફક્ત તમારા દ્વારા પૂરી પાડવામાં આવેલ માહિતીના આધારે કરવામાં આવે છે."
} }

6
src/translations/locales/ha.json

@ -2119,5 +2119,9 @@
"16 min": "Minti 16", "16 min": "Minti 16",
"Photo upload failed. Please try again.": "Kashin hoton ya gaza. Da fatan za a sake gwadawa.", "Photo upload failed. Please try again.": "Kashin hoton ya gaza. Da fatan za a sake gwadawa.",
"Failed to load image. Please try uploading again.": "An kasa loda hoton. Da fatan za a sake lodawa.", "Failed to load image. Please try uploading again.": "An kasa loda hoton. Da fatan za a sake lodawa.",
"File size exceeds the 10 MB limit.": "Girman fayil ya wuce iyakar 10 MB."
"File size exceeds the 10 MB limit.": "Girman fayil ya wuce iyakar 10 MB.",
"Man": "Namiji",
"Woman": "Mace",
"Step {step} of {total}": "Mataki {step} na {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Kuna iya yin rajista don kanku da kuma masoyanku, amma samun cikakken yarda da izinin mutumin da kuke ƙirƙirar masa asusu wajibi ne. Don tabbatar da daidaito, ya fi kyau a bar mutumin ya cika matakai na gaba da kansa. Ku tuna cewa duk gabatarwa ana yin ta ne cikin cikakkiyar sirri da kuma bisa bayanan da kuka bayar kawai."
} }

6
src/translations/locales/he.json

@ -2384,5 +2384,9 @@
"16 min": "16 דק׳", "16 min": "16 דק׳",
"Photo upload failed. Please try again.": "העלאת התמונה נכשלה. אנא נסה שוב.", "Photo upload failed. Please try again.": "העלאת התמונה נכשלה. אנא נסה שוב.",
"Failed to load image. Please try uploading again.": "טעינת התמונה נכשלה. אנא נסה להעלות שוב.", "Failed to load image. Please try uploading again.": "טעינת התמונה נכשלה. אנא נסה להעלות שוב.",
"File size exceeds the 10 MB limit.": "גודל הקובץ חורג ממגבלת 10 MB."
"File size exceeds the 10 MB limit.": "גודל הקובץ חורג ממגבלת 10 MB.",
"Man": "גבר",
"Woman": "אישה",
"Step {step} of {total}": "שלב {step} מתוך {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "באפשרותך להירשם הן עבור עצמך והן עבור יקיריך, אך קבלת הסכמה מפורשת ואישור מהאדם שעבורו נבנה הפרופיל היא חובה. כדי להבטיח דיוק מרבי, עדיף לאפשר לאדם עצמו להשלים את השלבים הבאים. זכור/י כי כל ההיכרויות מבוצעות בסודיות מוחלטת ובהתבסס אך ורק על המידע שסיפקת."
} }

6
src/translations/locales/hi.json

@ -2119,5 +2119,9 @@
"16 min": "16 मिनट", "16 min": "16 मिनट",
"Photo upload failed. Please try again.": "फ़ोटो अपलोड विफल रहा। कृपया पुन: प्रयास करें।", "Photo upload failed. Please try again.": "फ़ोटो अपलोड विफल रहा। कृपया पुन: प्रयास करें।",
"Failed to load image. Please try uploading again.": "छवि लोड करने में विफल। कृपया फिर से अपलोड करने का प्रयास करें।", "Failed to load image. Please try uploading again.": "छवि लोड करने में विफल। कृपया फिर से अपलोड करने का प्रयास करें।",
"File size exceeds the 10 MB limit.": "फ़ाइल का आकार 10 MB की सीमा से अधिक है।"
"File size exceeds the 10 MB limit.": "फ़ाइल का आकार 10 MB की सीमा से अधिक है।",
"Man": "पुरुष",
"Woman": "महिला",
"Step {step} of {total}": "{total} में से चरण {step}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "आप अपने लिए और अपने प्रियजनों दोनों के लिए पंजीकरण कर सकते हैं, लेकिन जिस व्यक्ति के लिए आप प्रोफ़ाइल बना रहे हैं उसकी स्पष्ट सहमति और अनुमति प्राप्त करना अनिवार्य है। सटीकता सुनिश्चित करने के लिए, यह सबसे अच्छा है कि व्यक्ति स्वयं बाद के चरणों को पूरा करे। याद रखें कि सभी मिलान पूर्ण गोपनीयता के साथ और केवल आपके द्वारा प्रदान की गई जानकारी के आधार पर ही प्रस्तुत किए जाते हैं।"
} }

6
src/translations/locales/id.json

@ -2384,5 +2384,9 @@
"16 min": "16 mnt", "16 min": "16 mnt",
"Photo upload failed. Please try again.": "Gagal mengunggah foto. Silakan coba lagi.", "Photo upload failed. Please try again.": "Gagal mengunggah foto. Silakan coba lagi.",
"Failed to load image. Please try uploading again.": "Gagal memuat gambar. Silakan coba unggah lagi.", "Failed to load image. Please try uploading again.": "Gagal memuat gambar. Silakan coba unggah lagi.",
"File size exceeds the 10 MB limit.": "Ukuran file melebihi batas 10 MB."
"File size exceeds the 10 MB limit.": "Ukuran file melebihi batas 10 MB.",
"Man": "Pria",
"Woman": "Wanita",
"Step {step} of {total}": "Langkah {step} dari {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Anda dapat mendaftar untuk diri sendiri maupun orang terkasih, namun memperoleh persetujuan eksplisit dan izin dari orang yang Anda buatkan profilnya adalah wajib. Untuk memastikan keakuratan, sebaiknya biarkan yang bersangkutan menyelesaikan langkah-langkah berikutnya sendiri. Ingatlah bahwa semua perkenalan dilakukan dengan kerahasiaan penuh dan semata-mata berdasarkan informasi yang Anda berikan."
} }

6
src/translations/locales/ks.json

@ -2384,5 +2384,9 @@
"16 min": "۱۶ منٹ", "16 min": "۱۶ منٹ",
"Photo upload failed. Please try again.": "فوٹو اپلوڈ گژھنہٕ منٛز خرٲبی۔ مہر کرِو دوبارٕ کوشش۔", "Photo upload failed. Please try again.": "فوٹو اپلوڈ گژھنہٕ منٛز خرٲبی۔ مہر کرِو دوبارٕ کوشش۔",
"Failed to load image. Please try uploading again.": "تصویر لوڈ گژھنہٕ منٛز خرٲبی۔ مہربٲنی کٔرِتھ کرِو دوبارٕ کوشش۔", "Failed to load image. Please try uploading again.": "تصویر لوڈ گژھنہٕ منٛز خرٲبی۔ مہربٲنی کٔرِتھ کرِو دوبارٕ کوشش۔",
"File size exceeds the 10 MB limit.": "فائل سائِز چھُ 10 MB حد کھوتہٕ زیادہ۔"
"File size exceeds the 10 MB limit.": "فائل سائِز چھُ 10 MB حد کھوتہٕ زیادہ۔",
"Man": "مَرٕد",
"Woman": "زَنَن",
"Step {step} of {total}": "{total} مَنٛز مرحلہٕ {step}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "تۄہیٚ ہیکِو پانے تہٕ پننؠن عزیزن خٲطرٕ تہِ رجسٹریشن کٔرِتھ، مگر یتھ شخصس خٲطرٕ تۄہیٚ پروفائل بناوان چھِو تٔمؠ سٕنٛز واضح رضامندی تہٕ اجازت حٲصل کرٕنؠ چھِ لازمی۔ درستگی یقینی بناونہٕ خٲطرٕ چھُ بہتر زِ سُہ شخص کٔرِ باقی مرحلہٕ پانے مکمل۔ یاد تھٲوِو زِ تمام تعارف چھِ مکمل رازداری تہٕ صِرف تُہنٛزِ دژمٕژ معلومات کِس بُنیادس پؠٹھ پیش یوان کرنہٕ۔"
} }

6
src/translations/locales/pt.json

@ -2384,5 +2384,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Falha ao enviar foto. Por favor, tente novamente.", "Photo upload failed. Please try again.": "Falha ao enviar foto. Por favor, tente novamente.",
"Failed to load image. Please try uploading again.": "Falha ao carregar a imagem. Tente carregar novamente.", "Failed to load image. Please try uploading again.": "Falha ao carregar a imagem. Tente carregar novamente.",
"File size exceeds the 10 MB limit.": "O tamanho do arquivo excede o limite de 10 MB."
"File size exceeds the 10 MB limit.": "O tamanho do arquivo excede o limite de 10 MB.",
"Man": "Homem",
"Woman": "Mulher",
"Step {step} of {total}": "Etapa {step} de {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Você pode se cadastrar tanto para si mesmo quanto para seus entes queridos, mas obter o consentimento explícito e a permissão da pessoa para quem está criando o perfil é obrigatório. Para garantir a precisão, é melhor deixar que a própria pessoa complete os passos seguintes. Lembre-se de que todas as combinações são apresentadas com total privacidade e estritamente com base nas informações fornecidas."
} }

6
src/translations/locales/ru.json

@ -2115,5 +2115,9 @@
"16 min": "16 мин", "16 min": "16 мин",
"Photo upload failed. Please try again.": "Ошибка загрузки фото. Пожалуйста, попробуйте еще раз.", "Photo upload failed. Please try again.": "Ошибка загрузки фото. Пожалуйста, попробуйте еще раз.",
"Failed to load image. Please try uploading again.": "Не удалось загрузить изображение. Попробуйте загрузить снова.", "Failed to load image. Please try uploading again.": "Не удалось загрузить изображение. Попробуйте загрузить снова.",
"File size exceeds the 10 MB limit.": "Размер файла превышает лимит 10 МБ."
"File size exceeds the 10 MB limit.": "Размер файла превышает лимит 10 МБ.",
"Man": "Мужчина",
"Woman": "Женщина",
"Step {step} of {total}": "Шаг {step} из {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Вы можете зарегистрироваться как для себя, так и для своих близких, однако получение явного согласия и разрешения от человека, для которого создается профиль, является обязательным. Для обеспечения точности данных лучше позволить человеку завершить последующие шаги самостоятельно. Помните, что все совпадения подбираются в условиях абсолютной конфиденциальности и строго на основе предоставленной вами информации."
} }

6
src/translations/locales/sw.json

@ -2384,5 +2384,9 @@
"16 min": "dak 16", "16 min": "dak 16",
"Photo upload failed. Please try again.": "Upakiaji wa picha umeshindikana. Tafadhali jaribu tena.", "Photo upload failed. Please try again.": "Upakiaji wa picha umeshindikana. Tafadhali jaribu tena.",
"Failed to load image. Please try uploading again.": "Imeshindwa kupakia picha. Tafadhali jaribu kupakia tena.", "Failed to load image. Please try uploading again.": "Imeshindwa kupakia picha. Tafadhali jaribu kupakia tena.",
"File size exceeds the 10 MB limit.": "Ukubwa wa faili unazidi kikomo cha MB 10."
"File size exceeds the 10 MB limit.": "Ukubwa wa faili unazidi kikomo cha MB 10.",
"Man": "Mwanaume",
"Woman": "Mwanamke",
"Step {step} of {total}": "Hatua ya {step} kati ya {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Unaweza kujisajili kwa ajili yako mwenyewe au kwa ajili ya wapendwa wako, lakini kupata idhini ya wazi na ruhusa kutoka kwa mtu unayemtengenezea wasifu ni lazima. Ili kuhakikisha usahihi, ni bora kumruhusu mtu huyo akamilishe hatua zinazofuata yeye mwenyewe. Kumbuka kuwa mapendekezo yote yanatolewa kwa usiri kamili na kwa kuzingatia tu taarifa ulizotoa."
} }

6
src/translations/locales/tg.json

@ -2384,5 +2384,9 @@
"16 min": "16 дақ", "16 min": "16 дақ",
"Photo upload failed. Please try again.": "Боркунии акс ноком шуд. Лутфан бори дигар кӯшиш кунед.", "Photo upload failed. Please try again.": "Боркунии акс ноком шуд. Лутфан бори дигар кӯшиш кунед.",
"Failed to load image. Please try uploading again.": "Боргирии тасвир ноком шуд. Лутфан бори дигар бор кунед.", "Failed to load image. Please try uploading again.": "Боргирии тасвир ноком шуд. Лутфан бори дигар бор кунед.",
"File size exceeds the 10 MB limit.": "Ҳаҷми файл аз ҳадди 10 МБ зиёд аст."
"File size exceeds the 10 MB limit.": "Ҳаҷми файл аз ҳадди 10 МБ зиёд аст.",
"Man": "Мард",
"Woman": "Зан",
"Step {step} of {total}": "Қадами {step} аз {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Шумо метавонед ҳам барои худатон ва ҳам барои наздиконатон сабти ном кунед, аммо гирифтани розигии ошкоро ва иҷозати шахсе, ки барои ӯ профил месозед, ҳатмист. Барои таъмини саҳеҳӣ, беҳтар аст, ки худи шахс қадамҳои минбаъдаро анҷом диҳад. Дар хотир доред, ки ҳамаи муаррифиҳо бо махфияти комил ва танҳо дар асоси маълумоти пешниҳодкардаи шумо сурат мегиранд."
} }

6
src/translations/locales/tr.json

@ -2384,5 +2384,9 @@
"16 min": "16 dk", "16 min": "16 dk",
"Photo upload failed. Please try again.": "Fotoğraf yüklenemedi. Lütfen tekrar deneyin.", "Photo upload failed. Please try again.": "Fotoğraf yüklenemedi. Lütfen tekrar deneyin.",
"Failed to load image. Please try uploading again.": "Resim yüklenemedi. Lütfen tekrar yüklemeyi deneyin.", "Failed to load image. Please try uploading again.": "Resim yüklenemedi. Lütfen tekrar yüklemeyi deneyin.",
"File size exceeds the 10 MB limit.": "Dosya boyutu 10 MB sınırını aşıyor."
"File size exceeds the 10 MB limit.": "Dosya boyutu 10 MB sınırını aşıyor.",
"Man": "Erkek",
"Woman": "Kadın",
"Step {step} of {total}": "Adım {step} / {total}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Hem kendiniz hem de sevdikleriniz için kayıt olabilirsiniz, ancak profilini oluşturduğunuz kişinin açık rızasını ve iznini almanız zorunludur. Doğruluk açısından, sonraki adımları kişinin kendisinin tamamlaması en iyisidir. Tüm eşleşmelerin mutlak gizlilik içinde ve yalnızca sağladığınız bilgilere dayanarak tanıtıldığını unutmayın."
} }

6
src/translations/locales/ul.json

@ -2384,5 +2384,9 @@
"16 min": "16 min", "16 min": "16 min",
"Photo upload failed. Please try again.": "Tasveer upload nakam ho gayi. Barah-e-karam dobara koshish karein.", "Photo upload failed. Please try again.": "Tasveer upload nakam ho gayi. Barah-e-karam dobara koshish karein.",
"Failed to load image. Please try uploading again.": "Tasveer load karne mein nakami. Barah-e-karam dobara upload karein.", "Failed to load image. Please try uploading again.": "Tasveer load karne mein nakami. Barah-e-karam dobara upload karein.",
"File size exceeds the 10 MB limit.": "File ka size 10 MB ki had se zyada hai."
"File size exceeds the 10 MB limit.": "File ka size 10 MB ki had se zyada hai.",
"Man": "Mard",
"Woman": "Aurat",
"Step {step} of {total}": "{total} mein se marhala {step}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Aap apne liye aur apne pyaron ke liye bhi registration kar sakte hain, lekin jis shakhs ke liye aap profile bana rahe hain us ki wazeh razamandi aur ijazat haasil karna laazmi hai. Durustagi ke liye, behtar hai ke baad ke marahil woh shakhs khud mukammal kare. Yaad rakhein ke tamaam rishtay mukammal raazdari ke saath aur sirf aap ki faraham kardah maloomat ki bunyad par mutaarif karaye jaate hain."
} }

6
src/translations/locales/ur.json

@ -2384,5 +2384,9 @@
"16 min": "16 منٹ", "16 min": "16 منٹ",
"Photo upload failed. Please try again.": "تصویر اپ لوڈ نہیں ہو سکی۔ براہ کرم دوبارہ کوشش کریں۔", "Photo upload failed. Please try again.": "تصویر اپ لوڈ نہیں ہو سکی۔ براہ کرم دوبارہ کوشش کریں۔",
"Failed to load image. Please try uploading again.": "تصویر لوڈ کرنے میں ناکامی۔ براہ کرم دوبارہ اپ لوڈ کریں۔", "Failed to load image. Please try uploading again.": "تصویر لوڈ کرنے میں ناکامی۔ براہ کرم دوبارہ اپ لوڈ کریں۔",
"File size exceeds the 10 MB limit.": "فائل کا سائز 10 MB کی حد سے تجاوز کر گیا ہے۔"
"File size exceeds the 10 MB limit.": "فائل کا سائز 10 MB کی حد سے تجاوز کر گیا ہے۔",
"Man": "مرد",
"Woman": "عورت",
"Step {step} of {total}": "{total} میں سے مرحلہ {step}",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "آپ اپنے لیے اور اپنے پیاروں کے لیے بھی رجسٹریشن کر سکتے ہیں، لیکن جس شخص کے لیے آپ پروفائل بنا رہے ہیں اس کی واضح رضامندی اور اجازت حاصل کرنا لازمی ہے۔ درستگی کے لیے، بہتر ہے کہ بعد کے مراحل وہ شخص خود مکمل کرے۔ یاد رکھیں کہ تمام رشتے مکمل رازداری کے ساتھ اور صرف آپ کی فراہم کردہ معلومات کی بنیاد پر متعارف کرائے جاتے ہیں۔"
} }

6
src/translations/locales/uz.json

@ -2384,5 +2384,9 @@
"16 min": "16 daq", "16 min": "16 daq",
"Photo upload failed. Please try again.": "Surat yuklanmadi. Iltimos, qayta urinib ko'ring.", "Photo upload failed. Please try again.": "Surat yuklanmadi. Iltimos, qayta urinib ko'ring.",
"Failed to load image. Please try uploading again.": "Rasm yuklanmadi. Iltimos, qayta yuklashga urinib ko'ring.", "Failed to load image. Please try uploading again.": "Rasm yuklanmadi. Iltimos, qayta yuklashga urinib ko'ring.",
"File size exceeds the 10 MB limit.": "Fayl hajmi 10 MB chegarasidan oshib ketdi."
"File size exceeds the 10 MB limit.": "Fayl hajmi 10 MB chegarasidan oshib ketdi.",
"Man": "Erkak",
"Woman": "Ayol",
"Step {step} of {total}": "{total} bosqichdan {step}-bosqich",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "Siz o'zingiz uchun ham, yaqinlaringiz uchun ham ro'yxatdan o'tishingiz mumkin, ammo profili yaratilayotgan shaxsning aniq roziligi va ruxsatini olish majburiydir. Ma'lumotlarning aniqligi uchun keyingi bosqichlarni shaxsning o'zi to'ldirgani ma'qul. Unutmangki, barcha mosliklar to'liq maxfiylikda va faqat siz taqdim etgan ma'lumotlar asosida taqdim etiladi."
} }

6
src/translations/locales/zh.json

@ -2119,5 +2119,9 @@
"16 min": "16分钟", "16 min": "16分钟",
"Photo upload failed. Please try again.": "照片上传失败。请再试一次。", "Photo upload failed. Please try again.": "照片上传失败。请再试一次。",
"Failed to load image. Please try uploading again.": "图片加载失败。请重试上传。", "Failed to load image. Please try uploading again.": "图片加载失败。请重试上传。",
"File size exceeds the 10 MB limit.": "文件大小超过 10 MB 限制。"
"File size exceeds the 10 MB limit.": "文件大小超过 10 MB 限制。",
"Man": "男士",
"Woman": "女士",
"Step {step} of {total}": "第 {step} 步,共 {total} 步",
"You can register both for yourself and for your loved ones, but obtaining the explicit consent and permission of the person you are creating the profile for is mandatory. To ensure accuracy, it is best to let the individual complete the subsequent steps themselves. Remember that all matches are introduced with absolute privacy and strictly based on the information you provide.": "您可以为自己或您的挚爱之人进行注册,但必须征得被创建资料者的明确同意与许可。为确保信息准确,后续步骤最好由本人亲自填写完成。请记住,所有匹配介绍均在严格保密的前提下、完全基于您所提供的信息进行。"
} }
Loading…
Cancel
Save