From 879f8645758fc8dc1e1aaeb7f335f2d8f36aee45 Mon Sep 17 00:00:00 2001 From: mortezaei Date: Thu, 20 Aug 2026 03:04:27 +0330 Subject: [PATCH] feat: implement phone number formatting, dynamic placeholders, and validation for QuestionPhone component with multi-language support --- .../Componentes/question-phone.test.tsx | 101 +++++++++- src/components/Componentes/question-phone.tsx | 174 +++++++++++++++--- .../Componentes/question-snap-list.tsx | 40 ++-- .../question-viewport-coordinator.ts | 10 +- src/translations/locales/ar.json | 3 +- src/translations/locales/az.json | 3 +- src/translations/locales/bn.json | 3 +- src/translations/locales/da.json | 3 +- src/translations/locales/de.json | 3 +- src/translations/locales/en.json | 3 +- src/translations/locales/es.json | 3 +- src/translations/locales/fa.json | 3 +- src/translations/locales/fr.json | 3 +- src/translations/locales/gu.json | 3 +- src/translations/locales/ha.json | 3 +- src/translations/locales/he.json | 3 +- src/translations/locales/hi.json | 3 +- src/translations/locales/id.json | 3 +- src/translations/locales/ks.json | 3 +- src/translations/locales/pt.json | 3 +- src/translations/locales/ru.json | 3 +- src/translations/locales/sw.json | 3 +- src/translations/locales/tg.json | 3 +- src/translations/locales/tr.json | 3 +- src/translations/locales/ul.json | 3 +- src/translations/locales/ur.json | 3 +- src/translations/locales/uz.json | 3 +- src/translations/locales/zh.json | 3 +- 28 files changed, 331 insertions(+), 66 deletions(-) diff --git a/src/components/Componentes/question-phone.test.tsx b/src/components/Componentes/question-phone.test.tsx index 163bc81..4620e97 100644 --- a/src/components/Componentes/question-phone.test.tsx +++ b/src/components/Componentes/question-phone.test.tsx @@ -30,6 +30,8 @@ vi.mock("@/translations/provider", () => ({ "Select country": "Select country", Close: "Close", Confirm: "Confirm", + "Enter a valid phone number with country code.": + "Enter a valid phone number with country code.", }, }), })); @@ -207,7 +209,7 @@ describe("QuestionPhone IP country detection and shimmer", () => { expect(container.querySelectorAll(".shimmer-bg").length).toBe(0); expect(screen.getByText("+1")).toBeDefined(); - expect(screen.getByDisplayValue("2025550143")).toBeDefined(); + expect(screen.getByDisplayValue("202-555-0143")).toBeDefined(); expect(httpMocks.get).not.toHaveBeenCalled(); }); @@ -219,10 +221,10 @@ describe("QuestionPhone IP country detection and shimmer", () => { httpMocks.get.mockReturnValue(regionPromise); - render(); + render(); const input = screen.getByRole("textbox"); - fireEvent.change(input, { target: { value: "123456" } }); + fireEvent.change(input, { target: { value: "7400123456" } }); await act(async () => { resolveRegion({ @@ -233,6 +235,97 @@ describe("QuestionPhone IP country detection and shimmer", () => { }); }); - expect(screen.getByDisplayValue("123456")).toBeDefined(); + expect(screen.getByDisplayValue("7400 123456")).toBeDefined(); + }); + + it("formats Iranian phone numbers as 3-3-4 Telegram style as digits are typed", async () => { + httpMocks.get.mockResolvedValue({ + data: { country: "Iran", country_code: "IR" }, + }); + + render(); + + const input = screen.getByRole("textbox") as HTMLInputElement; + + // Type 3 digits + fireEvent.change(input, { target: { value: "912" } }); + expect(input.value).toBe("912"); + + // Type 6 digits + fireEvent.change(input, { target: { value: "912345" } }); + expect(input.value).toBe("912 345"); + + // Type 10 digits + fireEvent.change(input, { target: { value: "9123456789" } }); + expect(input.value).toBe("912 345 6789"); + }); + + it("shows dynamic placeholder based on resolved country code", async () => { + let resolveRegion!: (value: unknown) => void; + const regionPromise = new Promise((resolve) => { + resolveRegion = resolve; + }); + + httpMocks.get.mockReturnValue(regionPromise); + + render(); + + const input = screen.getByRole("textbox") as HTMLInputElement; + expect(input.placeholder).toBe("7400 123456"); + + await act(async () => { + resolveRegion({ + data: { + country: "Iran", + country_code: "IR", + }, + }); + }); + + await waitFor(() => { + expect(input.placeholder).toBe("912 345 6789"); + }); + }); + + it("does not show validation error on active typing, only shows error on blur if incomplete", async () => { + httpMocks.get.mockResolvedValue({ + data: { country: "Iran", country_code: "IR" }, + }); + + const { container } = render( + , + ); + + const input = screen.getByRole("textbox") as HTMLInputElement; + + // Focus and start typing incomplete number + fireEvent.focus(input); + fireEvent.change(input, { target: { value: "912" } }); + + // No error while focused and typing + expect( + screen.queryByText("Enter a valid phone number with country code."), + ).toBeNull(); + expect(container.querySelector(".border-\\[\\#F2465F\\]")).toBeNull(); + + // Blur input without completing + fireEvent.blur(input); + + // Error appears after blur + expect( + screen.getByText("Enter a valid phone number with country code."), + ).toBeDefined(); + expect(container.querySelector(".border-\\[\\#F2465F\\]")).not.toBeNull(); + + // Focus back and complete valid number + fireEvent.focus(input); + fireEvent.change(input, { target: { value: "9123456789" } }); + fireEvent.blur(input); + + // Error is gone + expect( + screen.queryByText("Enter a valid phone number with country code."), + ).toBeNull(); + expect(container.querySelector(".border-\\[\\#F2465F\\]")).toBeNull(); }); }); diff --git a/src/components/Componentes/question-phone.tsx b/src/components/Componentes/question-phone.tsx index f7add32..0ddfaba 100644 --- a/src/components/Componentes/question-phone.tsx +++ b/src/components/Componentes/question-phone.tsx @@ -1,6 +1,10 @@ "use client"; -import { PhoneNumberFormat, PhoneNumberUtil } from "google-libphonenumber"; +import { + AsYouTypeFormatter, + PhoneNumberFormat, + PhoneNumberUtil, +} from "google-libphonenumber"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; import type { MarriagePhoneFieldValue } from "@/hooks/marriage/types"; @@ -264,10 +268,11 @@ function readPhoneValue(value: unknown, fallbackCode: string): PhoneValueParts { function getMaxLengthForCountry(codeValue: string): number { try { const cleanCode = codeValue.replace(/[^\d]/g, ""); - if (!cleanCode) return 15; + if (!cleanCode) return 18; + if (cleanCode === "98") return 12; // 3 + 1 + 3 + 1 + 4 = 12 chars const countryCode = Number(cleanCode); const regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode); - if (!regionCode || regionCode === "ZZ") return 15; + if (!regionCode || regionCode === "ZZ") return 18; const exampleMobile = phoneUtil.getExampleNumberForType( regionCode, @@ -283,9 +288,93 @@ function getMaxLengthForCountry(codeValue: string): number { : 0; const baseLen = Math.max(lenMobile, lenGeneral, 8); - return baseLen + 1; + return baseLen + 6; } catch { - return 15; + return 18; + } +} + +function getCountryPlaceholder( + codeValue: string, + defaultPlaceholder?: string, +): string { + try { + const cleanCode = codeValue.replace(/[^\d]/g, ""); + if (!cleanCode) { + return defaultPlaceholder?.replace(/^\+\d+\s*/, "") || "912 345 6789"; + } + + if (cleanCode === "98") { + return "912 345 6789"; + } + + const countryCode = Number(cleanCode); + const regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode); + if (!regionCode || regionCode === "ZZ") { + return defaultPlaceholder?.replace(/^\+\d+\s*/, "") || "912 345 6789"; + } + + const example = + phoneUtil.getExampleNumberForType( + regionCode, + 1, // MOBILE + ) || phoneUtil.getExampleNumber(regionCode); + + if (!example) { + return defaultPlaceholder?.replace(/^\+\d+\s*/, "") || "912 345 6789"; + } + + const intl = phoneUtil.format(example, PhoneNumberFormat.INTERNATIONAL); + const prefix = `+${cleanCode} `; + if (intl.startsWith(prefix)) { + return intl.slice(prefix.length); + } + return String(example.getNationalNumber()); + } catch { + return defaultPlaceholder?.replace(/^\+\d+\s*/, "") || "912 345 6789"; + } +} + +function formatPhoneNumberAsYouType( + rawInput: string, + codeValue: string, +): string { + const cleanCode = codeValue.replace(/[^\d]/g, ""); + const rawDigits = rawInput.replace(/\D/g, ""); + if (!rawDigits) return ""; + + // Special telegram-style handling for Iran (+98): 3 - 3 - 4 (e.g. 912 345 6789) + if (cleanCode === "98") { + const digits = rawDigits.startsWith("0") ? rawDigits.slice(1) : rawDigits; + const max10 = digits.slice(0, 10); + if (max10.length <= 3) return max10; + if (max10.length <= 6) return `${max10.slice(0, 3)} ${max10.slice(3)}`; + return `${max10.slice(0, 3)} ${max10.slice(3, 6)} ${max10.slice(6)}`; + } + + const countryCode = Number(cleanCode); + const regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode); + if (!regionCode || regionCode === "ZZ") { + return rawDigits; + } + + try { + const formatter = new AsYouTypeFormatter(regionCode); + let formatted = ""; + const fullNumber = `+${cleanCode}${rawDigits}`; + for (const char of fullNumber) { + formatted = formatter.inputDigit(char); + } + const codePrefix = `+${cleanCode} `; + if (formatted.startsWith(codePrefix)) { + return formatted.slice(codePrefix.length); + } + if (formatted.startsWith(`+${cleanCode}`)) { + return formatted.slice(`+${cleanCode}`.length).trim(); + } + return rawDigits; + } catch { + return rawDigits; } } @@ -433,13 +522,23 @@ export function QuestionPhone({ }, [value, defaultCodeValue]); const initialPhone = useMemo(() => { - return readPhoneValue(value, defaultCodeValue).phoneValue; - }, [value, defaultCodeValue]); + const rawPhone = readPhoneValue(value, defaultCodeValue).phoneValue; + return formatPhoneNumberAsYouType(rawPhone, initialCode); + }, [value, defaultCodeValue, initialCode]); const [codeValue, setCodeValue] = useState(initialCode); const [phoneValue, setPhoneValue] = useState(initialPhone); + const [isFocused, setIsFocused] = useState(false); + const [isTouched, setIsTouched] = useState(false); const lastCommittedValueRef = useRef(value); + const dynamicPlaceholder = useMemo(() => { + return getCountryPlaceholder( + codeValue || defaultCodeValue, + question.extras?.placeHolder, + ); + }, [codeValue, defaultCodeValue, question.extras?.placeHolder]); + const [isOpen, setIsOpen] = useState(false); const [isClosing, setIsClosing] = useState(false); const [searchQuery, setSearchQuery] = useState(""); @@ -471,6 +570,11 @@ export function QuestionPhone({ const onGeoCodeResolved = (resolvedCode: string) => { if (!isMounted || userInteractedRef.current) return; setCodeValue(resolvedCode); + if (phoneValue) { + setPhoneValue((prev) => + formatPhoneNumberAsYouType(prev, resolvedCode), + ); + } setIsResolvingCountry(false); }; @@ -480,7 +584,13 @@ export function QuestionPhone({ .then((resolvedCode) => { if (!isMounted) return; if (!userInteractedRef.current) { - setCodeValue(resolvedCode || defaultCodeValue); + const finalCode = resolvedCode || defaultCodeValue; + setCodeValue(finalCode); + if (phoneValue) { + setPhoneValue((prev) => + formatPhoneNumberAsYouType(prev, finalCode), + ); + } } setIsResolvingCountry(false); }) @@ -496,10 +606,12 @@ export function QuestionPhone({ isMounted = false; geoListeners.delete(onGeoCodeResolved); }; - }, [hasExplicitValue, isResolvingCountry, defaultCodeValue]); + }, [hasExplicitValue, isResolvingCountry, defaultCodeValue, phoneValue]); const normalizedPhoneState = getNormalizedPhoneValue(codeValue, phoneValue); const showInvalidState = + isTouched && + !isFocused && codeValue.trim().length > 0 && phoneValue.trim().length > 0 && !normalizedPhoneState.isValid; @@ -631,13 +743,19 @@ export function QuestionPhone({ if (explicit) { setIsResolvingCountry(false); setCodeValue(nextValue.codeValue); - const maxLen = getMaxLengthForCountry(nextValue.codeValue); - setPhoneValue(nextValue.phoneValue.slice(0, maxLen)); + const formatted = formatPhoneNumberAsYouType( + nextValue.phoneValue, + nextValue.codeValue, + ); + setPhoneValue(formatted); } else if (value !== null && value !== undefined) { const resolvedCode = cachedCode || defaultCodeValue; setCodeValue(resolvedCode); - const maxLen = getMaxLengthForCountry(resolvedCode); - setPhoneValue(nextValue.phoneValue.slice(0, maxLen)); + const formatted = formatPhoneNumberAsYouType( + nextValue.phoneValue, + resolvedCode, + ); + setPhoneValue(formatted); } lastCommittedValueRef.current = value; @@ -664,12 +782,11 @@ export function QuestionPhone({ userInteractedRef.current = true; setIsResolvingCountry(false); setManuallySelectedGeoCode(selectedCode); - const maxLen = getMaxLengthForCountry(selectedCode); - const truncatedPhone = phoneValue.slice(0, maxLen); + const reformatted = formatPhoneNumberAsYouType(phoneValue, selectedCode); setCodeValue(selectedCode); - setPhoneValue(truncatedPhone); - updateStoredValue(selectedCode, truncatedPhone); + setPhoneValue(reformatted); + updateStoredValue(selectedCode, reformatted); closeSheet(); }; @@ -768,19 +885,27 @@ export function QuestionPhone({ data-bwignore="true" data-form-type="other" disabled={disabled} - placeholder={question.extras.placeHolder?.replace(/^\+\d+\s*/, "")} + placeholder={dynamicPlaceholder} value={phoneValue} maxLength={getMaxLengthForCountry(codeValue)} + onFocus={() => { + setIsFocused(true); + }} + onBlur={() => { + setIsFocused(false); + setIsTouched(true); + }} onChange={(event) => { userInteractedRef.current = true; setIsResolvingCountry(false); setManuallySelectedGeoCode(codeValue); - const nextPhoneValue = sanitizePhoneNumber(event.target.value); - const maxLen = getMaxLengthForCountry(codeValue); - const truncatedPhone = nextPhoneValue.slice(0, maxLen); + const formatted = formatPhoneNumberAsYouType( + event.target.value, + codeValue, + ); - setPhoneValue(truncatedPhone); - updateStoredValue(codeValue, truncatedPhone); + setPhoneValue(formatted); + updateStoredValue(codeValue, formatted); }} dir="ltr" className="h-full w-full border-0 bg-transparent p-0 text-left text-[15px] font-medium leading-none text-[#181818] tabular-nums outline-none placeholder:text-[#98A2B3]" @@ -789,7 +914,8 @@ export function QuestionPhone({ {showInvalidState ? ( - Enter a valid phone number with country code. + {t["Enter a valid phone number with country code."] || + "Enter a valid phone number with country code."} ) : null} diff --git a/src/components/Componentes/question-snap-list.tsx b/src/components/Componentes/question-snap-list.tsx index 53d5a75..b73a6e5 100644 --- a/src/components/Componentes/question-snap-list.tsx +++ b/src/components/Componentes/question-snap-list.tsx @@ -14,20 +14,20 @@ import { useQuestionViewportCoordinator, } from "./question-viewport-coordinator"; -const WHEEL_GESTURE_IDLE_MS = 320; -const BACKGROUND_DRAG_SLOP = 10; -const OPTION_CARD_DRAG_SLOP = 16; -const FAST_FLICK_MIN_DISTANCE = 36; -const DRAG_COMMIT_RATIO = 0.3; -const DRAG_FLICK_VELOCITY = 0.4; -const SNAP_ANIMATION_MS = 340; -const SNAP_EASE = "cubic-bezier(0.22, 1, 0.36, 1)"; -const RUBBER_BAND_RESISTANCE = 0.4; +const WHEEL_GESTURE_IDLE_MS = 280; +const BACKGROUND_DRAG_SLOP = 8; +const OPTION_CARD_DRAG_SLOP = 14; +const TEXT_INPUT_DRAG_SLOP = 16; +const FAST_FLICK_MIN_DISTANCE = 24; +const DRAG_COMMIT_RATIO = 0.15; +const DRAG_FLICK_VELOCITY = 0.22; +const SNAP_ANIMATION_MS = 240; +const SNAP_EASE = "cubic-bezier(0.16, 1, 0.3, 1)"; +const RUBBER_BAND_RESISTANCE = 0.35; /** - * Text inputs and direct embedded controls that MUST be completely isolated - * from the snap/drag gesture recognizer so first-tap focus, virtual keyboard, - * and caret manipulation work 100% reliably. + * Text inputs and direct embedded controls that MUST allow clean 1st-tap focus + * while still permitting intentional vertical swipe when dragged beyond slop. */ const TEXT_INPUT_SELECTOR = [ 'input:not([type="radio"]):not([type="checkbox"])', @@ -58,6 +58,7 @@ const OPTION_CARD_SELECTOR = [ type SnapDragState = { pointerDown: boolean; hardIgnored: boolean; + isTextInput: boolean; isOptionCard: boolean; engaged: boolean; didDrag: boolean; @@ -113,6 +114,7 @@ export function QuestionSnapList({ const dragRef = useRef({ pointerDown: false, hardIgnored: false, + isTextInput: false, isOptionCard: false, engaged: false, didDrag: false, @@ -397,14 +399,19 @@ export function QuestionSnapList({ const movedPastFlick = Math.abs(drag.offset) >= FAST_FLICK_MIN_DISTANCE; let direction: 0 | 1 | -1 = 0; + let reason = "none"; if (!cancelled && (draggedFar || flicked || movedPastFlick)) { if ((drag.offset > 0 || drag.velocity > 0) && canNext) { direction = 1; + reason = flicked ? "flick_next" : (draggedFar ? "drag_far_next" : "moved_past_flick_next"); } else if ((drag.offset < 0 || drag.velocity < 0) && canPrev) { direction = -1; + reason = flicked ? "flick_prev" : (draggedFar ? "drag_far_prev" : "moved_past_flick_prev"); } } + console.log(`[Snap] FinishDrag -> dir: ${direction} (${reason}) | offset: ${drag.offset.toFixed(0)}px | vel: ${drag.velocity.toFixed(2)} | threshold: ${(drag.height * DRAG_COMMIT_RATIO).toFixed(0)}px`); + if (direction === 0) { snapPanelsTo(0); return; @@ -491,6 +498,8 @@ export function QuestionSnapList({ drag.startTime = performance.now(); drag.lastMoveTime = drag.startTime; touchStartYRef.current = drag.startY; + + console.log(`[Snap] TouchStart at (${drag.startX.toFixed(0)}, ${drag.startY.toFixed(0)}) on <${target?.tagName?.toLowerCase()}> (isOption: ${isOptionCard})`); }; const onTouchMove = (event: TouchEvent) => { @@ -526,7 +535,7 @@ export function QuestionSnapList({ } // Must be primarily vertical gesture (avoid hijacking horizontal swipe / scroll) - if (absY < absX * 1.1) { + if (absY < absX * 0.9) { return; } @@ -535,8 +544,13 @@ export function QuestionSnapList({ drag.didDrag = true; suppressNextClickRef.current = true; + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + const elapsed = Math.max(1, now - drag.startTime); drag.velocity = (drag.startY - currentY) / elapsed; + console.log(`[Snap] Drag Engaged: deltaY=${deltaY.toFixed(0)}px, slop=${slop}px`); } // Non-passive preventDefault stops native pan and guarantees gesture ownership diff --git a/src/components/Componentes/question-viewport-coordinator.ts b/src/components/Componentes/question-viewport-coordinator.ts index d6aab31..6f40493 100644 --- a/src/components/Componentes/question-viewport-coordinator.ts +++ b/src/components/Componentes/question-viewport-coordinator.ts @@ -94,7 +94,15 @@ function setLift(nextLift: number) { function getKeyboardTop() { if (!keyboardVisible || !activeQuestionInput) return null; - const flutterTop = window.innerHeight - keyboardHeight; + // When keyboard is opening/visible, use the projected full keyboard height + // (either current incoming height or last known full keyboard height) + // so the CSS transition animates in ONE single smooth, continuous curve concurrent with OS keyboard. + const targetHeight = Math.max( + keyboardHeight, + lastKeyboardHeight > 200 ? lastKeyboardHeight : 320, + ); + + const flutterTop = window.innerHeight - targetHeight; const viewport = window.visualViewport; const viewportBottom = viewport ? viewport.offsetTop + viewport.height diff --git a/src/translations/locales/ar.json b/src/translations/locales/ar.json index 5513099..6914976 100644 --- a/src/translations/locales/ar.json +++ b/src/translations/locales/ar.json @@ -785,5 +785,6 @@ "Voice Call": "مكالمة صوتية", "Video Call": "مكالمة فيديو", "No public information is available to display.": "لا توجد معلومات عامة متاحة للعرض.", - "General Information & Personal Details": "المعلومات العامة والتفاصيل الشخصية" + "General Information & Personal Details": "المعلومات العامة والتفاصيل الشخصية", + "Enter a valid phone number with country code.": "يرجى إدخال رقم هاتف صالح مع رمز الدولة." } diff --git a/src/translations/locales/az.json b/src/translations/locales/az.json index 9bbafab..5e15907 100644 --- a/src/translations/locales/az.json +++ b/src/translations/locales/az.json @@ -785,5 +785,6 @@ "Voice Call": "Səsli Zəng", "Video Call": "Video Zəng", "No public information is available to display.": "Göstəriləcək heç bir ictimai məlumat qeyd edilməyib.", - "General Information & Personal Details": "Ümumi məlumat və fərdi xüsusiyyətlər" + "General Information & Personal Details": "Ümumi məlumat və fərdi xüsusiyyətlər", + "Enter a valid phone number with country code.": "Zəhmət olmasa ölkə kodu ilə birlikdə etibarlı bir telefon nömrəsi daxil edin." } diff --git a/src/translations/locales/bn.json b/src/translations/locales/bn.json index 24ed516..93e6af0 100644 --- a/src/translations/locales/bn.json +++ b/src/translations/locales/bn.json @@ -785,5 +785,6 @@ "Voice Call": "ভয়েস কল", "Video Call": "ভিডিও কল", "No public information is available to display.": "প্রদর্শনের জন্য কোনও সর্বজনীন তথ্য পাওয়া যায়নি।", - "General Information & Personal Details": "সাধারণ তথ্য এবং ব্যক্তিগত বিবরণ" + "General Information & Personal Details": "সাধারণ তথ্য এবং ব্যক্তিগত বিবরণ", + "Enter a valid phone number with country code.": "দেশের কোড সহ একটি বৈধ ফোন নম্বর লিখুন।" } diff --git a/src/translations/locales/da.json b/src/translations/locales/da.json index 9b6464d..c6f2850 100644 --- a/src/translations/locales/da.json +++ b/src/translations/locales/da.json @@ -785,5 +785,6 @@ "Voice Call": "Taleopkald", "Video Call": "Videoopkald", "No public information is available to display.": "Ingen offentlige oplysninger er tilgængelige.", - "General Information & Personal Details": "Generelle oplysninger og personlige detaljer" + "General Information & Personal Details": "Generelle oplysninger og personlige detaljer", + "Enter a valid phone number with country code.": "Indtast et gyldigt telefonnummer med landekode." } diff --git a/src/translations/locales/de.json b/src/translations/locales/de.json index 7ddbdf4..34a6b3b 100644 --- a/src/translations/locales/de.json +++ b/src/translations/locales/de.json @@ -785,5 +785,6 @@ "Voice Call": "Sprachanruf", "Video Call": "Videoanruf", "No public information is available to display.": "Keine öffentlichen Informationen zur Anzeige verfügbar.", - "General Information & Personal Details": "Allgemeine Informationen und persönliche Details" + "General Information & Personal Details": "Allgemeine Informationen und persönliche Details", + "Enter a valid phone number with country code.": "Geben Sie eine gültige Telefonnummer mit Ländercode ein." } diff --git a/src/translations/locales/en.json b/src/translations/locales/en.json index 99fa0d7..b28a09b 100644 --- a/src/translations/locales/en.json +++ b/src/translations/locales/en.json @@ -833,5 +833,6 @@ "Text Message": "Text Message", "Video Call": "Video Call", "No public information is available to display.": "No public information is available to display.", - "General Information & Personal Details": "General Information & Personal Details" + "General Information & Personal Details": "General Information & Personal Details", + "Enter a valid phone number with country code.": "Enter a valid phone number with country code." } diff --git a/src/translations/locales/es.json b/src/translations/locales/es.json index 36130b7..f086b92 100644 --- a/src/translations/locales/es.json +++ b/src/translations/locales/es.json @@ -785,5 +785,6 @@ "Voice Call": "Llamada de Voz", "Video Call": "Llamada de Video", "No public information is available to display.": "No hay información pública disponible para mostrar.", - "General Information & Personal Details": "Información general y detalles personales" + "General Information & Personal Details": "Información general y detalles personales", + "Enter a valid phone number with country code.": "Introduce un número de teléfono válido con código de país." } diff --git a/src/translations/locales/fa.json b/src/translations/locales/fa.json index 5445a0a..97a9350 100644 --- a/src/translations/locales/fa.json +++ b/src/translations/locales/fa.json @@ -833,5 +833,6 @@ "Text Message": "پیام متنی", "Video Call": "تماس تصویری", "No public information is available to display.": "اطلاعات عمومی قابل نمایشی ثبت نشده است.", - "General Information & Personal Details": "اطلاعات عمومی و مشخصات فردی" + "General Information & Personal Details": "اطلاعات عمومی و مشخصات فردی", + "Enter a valid phone number with country code.": "لطفاً یک شماره تماس معتبر به همراه کد کشور وارد کنید." } diff --git a/src/translations/locales/fr.json b/src/translations/locales/fr.json index 5800140..7edfd6d 100644 --- a/src/translations/locales/fr.json +++ b/src/translations/locales/fr.json @@ -785,5 +785,6 @@ "Voice Call": "Appel vocal", "Video Call": "Appel vidéo", "No public information is available to display.": "Aucune information publique disponible à afficher.", - "General Information & Personal Details": "Informations générales et détails personnels" + "General Information & Personal Details": "Informations générales et détails personnels", + "Enter a valid phone number with country code.": "Entrez un numéro de téléphone valide avec l'indicatif du pays." } diff --git a/src/translations/locales/gu.json b/src/translations/locales/gu.json index 208f5b2..8d1b0e0 100644 --- a/src/translations/locales/gu.json +++ b/src/translations/locales/gu.json @@ -785,5 +785,6 @@ "Voice Call": "વૉઇસ કૉલ", "Video Call": "વિડિયો કૉલ", "No public information is available to display.": "પ્રદર્શિત કરવા માટે કોઈ જાહેર માહિતી ઉપલબ્ધ નથી.", - "General Information & Personal Details": "સામાન્ય માહિતી અને વ્યક્તિગત વિગતો" + "General Information & Personal Details": "સામાન્ય માહિતી અને વ્યક્તિગત વિગતો", + "Enter a valid phone number with country code.": "દેશના કોડ સાથે માન્ય ફોન નંબર દાખલ કરો." } diff --git a/src/translations/locales/ha.json b/src/translations/locales/ha.json index d39d20e..e0a8c79 100644 --- a/src/translations/locales/ha.json +++ b/src/translations/locales/ha.json @@ -785,5 +785,6 @@ "Voice Call": "Kiran Murya", "Video Call": "Kiran Bidiyo", "No public information is available to display.": "Babu bayanan jama'a da za a iya nunawa.", - "General Information & Personal Details": "Bayanai na gama-gari da cikakkun bayanan sirri" + "General Information & Personal Details": "Bayanai na gama-gari da cikakkun bayanan sirri", + "Enter a valid phone number with country code.": "Shigar da lambar waya mai aiki tare da lambar ƙasa." } diff --git a/src/translations/locales/he.json b/src/translations/locales/he.json index 61ce359..7a97a98 100644 --- a/src/translations/locales/he.json +++ b/src/translations/locales/he.json @@ -322,5 +322,6 @@ "Voice Call": "Voice Call", "Video Call": "Video Call", "No public information is available to display.": "אין מידע ציבורי זמין להצגה.", - "General Information & Personal Details": "מידע כללי ופרטים אישיים" + "General Information & Personal Details": "מידע כללי ופרטים אישיים", + "Enter a valid phone number with country code.": "הזן מספר טלפון חוקי עם קידומת מדינה." } diff --git a/src/translations/locales/hi.json b/src/translations/locales/hi.json index c8d07f8..377dacf 100644 --- a/src/translations/locales/hi.json +++ b/src/translations/locales/hi.json @@ -785,5 +785,6 @@ "Voice Call": "वॉइस कॉल", "Video Call": "वीडियो कॉल", "No public information is available to display.": "प्रदर्शित करने के लिए कोई सार्वजनिक जानकारी उपलब्ध नहीं है।", - "General Information & Personal Details": "सामान्य जानकारी और व्यक्तिगत विवरण" + "General Information & Personal Details": "सामान्य जानकारी और व्यक्तिगत विवरण", + "Enter a valid phone number with country code.": "देश कोड के साथ एक मान्य फ़ोन नंबर दर्ज करें।" } diff --git a/src/translations/locales/id.json b/src/translations/locales/id.json index 51dbe6e..ab848a4 100644 --- a/src/translations/locales/id.json +++ b/src/translations/locales/id.json @@ -322,5 +322,6 @@ "Voice Call": "Panggilan Suara", "Video Call": "Panggilan Video", "No public information is available to display.": "Tidak ada informasi publik yang tersedia untuk ditampilkan.", - "General Information & Personal Details": "Informasi Umum & Rincian Pribadi" + "General Information & Personal Details": "Informasi Umum & Rincian Pribadi", + "Enter a valid phone number with country code.": "Masukkan nomor telepon yang valid dengan kode negara." } diff --git a/src/translations/locales/ks.json b/src/translations/locales/ks.json index 1fc72dd..e6e29f7 100644 --- a/src/translations/locales/ks.json +++ b/src/translations/locales/ks.json @@ -322,5 +322,6 @@ "Voice Call": "آوازی کال", "Video Call": "ویڈیو کال", "No public information is available to display.": "ڈسپلے کرنہٕ خٲطرٕ کانہہ عام معلومات دٔستیاب چُھنہٕ۔", - "General Information & Personal Details": "عام معلومات تہٕ ذٲتی تفصیٖل" + "General Information & Personal Details": "عام معلومات تہٕ ذٲتی تفصیٖل", + "Enter a valid phone number with country code.": "ملک کے کوڈ کے ساتھ ایک درست فون نمبر درج کریں۔" } diff --git a/src/translations/locales/pt.json b/src/translations/locales/pt.json index cd10a27..b4082ea 100644 --- a/src/translations/locales/pt.json +++ b/src/translations/locales/pt.json @@ -322,5 +322,6 @@ "Voice Call": "Chamada de Voz", "Video Call": "Chamada de Vídeo", "No public information is available to display.": "Nenhuma informação pública disponível para exibição.", - "General Information & Personal Details": "Informações Gerais e Detalhes Pessoais" + "General Information & Personal Details": "Informações Gerais e Detalhes Pessoais", + "Enter a valid phone number with country code.": "Introduza um número de telefone válido com o código do país." } diff --git a/src/translations/locales/ru.json b/src/translations/locales/ru.json index 508d103..728ddbc 100644 --- a/src/translations/locales/ru.json +++ b/src/translations/locales/ru.json @@ -789,5 +789,6 @@ "Voice Call": "Голосовой звонок", "Video Call": "Видеозвонок", "No public information is available to display.": "Нет общедоступной информации для отображения.", - "General Information & Personal Details": "Общая информация и личные данные" + "General Information & Personal Details": "Общая информация и личные данные", + "Enter a valid phone number with country code.": "Введите действительный номер телефона с кодом страны." } diff --git a/src/translations/locales/sw.json b/src/translations/locales/sw.json index adec3d4..b985ddd 100644 --- a/src/translations/locales/sw.json +++ b/src/translations/locales/sw.json @@ -322,5 +322,6 @@ "Voice Call": "Simu ya Sauti", "Video Call": "Simu ya Video", "No public information is available to display.": "Hakuna taarifa za umma zinazoweza kuonyeshwa.", - "General Information & Personal Details": "Taarifa za Jumla na Maelezo Binafsi" + "General Information & Personal Details": "Taarifa za Jumla na Maelezo Binafsi", + "Enter a valid phone number with country code.": "Weka nambari halali ya simu yenye msimbo wa nchi." } diff --git a/src/translations/locales/tg.json b/src/translations/locales/tg.json index c103341..186a37c 100644 --- a/src/translations/locales/tg.json +++ b/src/translations/locales/tg.json @@ -322,5 +322,6 @@ "Voice Call": "Зангҳои овозӣ", "Video Call": "Зангҳои видеоӣ", "No public information is available to display.": "Маълумоти умумии дастрас барои намоиш нест.", - "General Information & Personal Details": "Маълумоти умумӣ ва мушаххасоти инфиродӣ" + "General Information & Personal Details": "Маълумоти умумӣ ва мушаххасоти инфиродӣ", + "Enter a valid phone number with country code.": "Рақами телефони дурустро бо рамзи кишвар ворид кунед." } diff --git a/src/translations/locales/tr.json b/src/translations/locales/tr.json index 5e69373..e1cc802 100644 --- a/src/translations/locales/tr.json +++ b/src/translations/locales/tr.json @@ -322,5 +322,6 @@ "Voice Call": "Sesli Arama", "Video Call": "Görüntülü Arama", "No public information is available to display.": "Görüntülenecek genel bilgi bulunmamaktadır.", - "General Information & Personal Details": "Genel Bilgiler ve Kişisel Detaylar" + "General Information & Personal Details": "Genel Bilgiler ve Kişisel Detaylar", + "Enter a valid phone number with country code.": "Ülke kodu ile geçerli bir telefon numarası girin." } diff --git a/src/translations/locales/ul.json b/src/translations/locales/ul.json index e562cc9..563ab85 100644 --- a/src/translations/locales/ul.json +++ b/src/translations/locales/ul.json @@ -322,5 +322,6 @@ "Voice Call": "Voice Call", "Video Call": "Video Call", "No public information is available to display.": "Görüntülenecek genel bilgi bulunmamaktadır.", - "General Information & Personal Details": "Genel Bilgiler ve Kişisel Detaylar" + "General Information & Personal Details": "Genel Bilgiler ve Kişisel Detaylar", + "Enter a valid phone number with country code.": "ملک کے کوڈ کے ساتھ ایک درست فون نمبر درج کریں۔" } diff --git a/src/translations/locales/ur.json b/src/translations/locales/ur.json index ec760a4..b65159f 100644 --- a/src/translations/locales/ur.json +++ b/src/translations/locales/ur.json @@ -322,5 +322,6 @@ "Voice Call": "وائس کال", "Video Call": "ویڈیو کال", "No public information is available to display.": "دکھانے کے لیے کوئی عوامی معلومات دستیاب نہیں ہے۔", - "General Information & Personal Details": "عام معلومات اور ذاتی تفصیلات" + "General Information & Personal Details": "عام معلومات اور ذاتی تفصیلات", + "Enter a valid phone number with country code.": "ملک کے کوڈ کے ساتھ ایک درست فون نمبر درج کریں۔" } diff --git a/src/translations/locales/uz.json b/src/translations/locales/uz.json index c0f2c72..7ec0beb 100644 --- a/src/translations/locales/uz.json +++ b/src/translations/locales/uz.json @@ -322,5 +322,6 @@ "Voice Call": "Овозли қўнғироқ", "Video Call": "Видео қўнғироқ", "No public information is available to display.": "Ko'rsatish uchun umumiy ma'lumot mavjud emas.", - "General Information & Personal Details": "Umumiy ma'lumotlar va shaxsiy tafsilotlar" + "General Information & Personal Details": "Umumiy ma'lumotlar va shaxsiy tafsilotlar", + "Enter a valid phone number with country code.": "Mamlakat kodi bilan to'g'ri telefon raqamini kiriting." } diff --git a/src/translations/locales/zh.json b/src/translations/locales/zh.json index 8fa35b9..16d3607 100644 --- a/src/translations/locales/zh.json +++ b/src/translations/locales/zh.json @@ -785,5 +785,6 @@ "Voice Call": "语音通话", "Video Call": "视频通话", "No public information is available to display.": "没有可显示的公开信息。", - "General Information & Personal Details": "一般信息和个人资料" + "General Information & Personal Details": "一般信息和个人资料", + "Enter a valid phone number with country code.": "请输入包含国家代码的有效电话号码。" }