From 12a77b500655257fc307496c85c0b854abd7daab Mon Sep 17 00:00:00 2001 From: Bekiboo Date: Mon, 21 Sep 2026 09:10:14 +0300 Subject: [PATCH 01/13] feat(eid-wallet): add Russian and Ukrainian translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wallet had a language picker but no translation layer — every user-facing string was a hardcoded English literal across ~90 components, and only English was selectable. Wire in @inlang/paraglide-js, extract 515 strings into message files, and translate them into ru and uk. Slavic plural forms (one/few/many) resolve through Intl.PluralRules for contact counts, file counts and step counters. Locale resolution is localStorage -> device language -> base locale: the wallet is a Tauri app on adapter-static, so paraglide's default cookie and url strategies never resolve. Switching language repaints via a rune-backed getLocale override rather than paraglide's default reload, which in a webview would drop the unlocked session. The store now keys off PARAGLIDE_LOCALE instead of its own eid_wallet_language key, and lists languages by endonym so they stay findable whatever the UI is set to. Identity fields are persisted under English object keys, so identityLabels.ts translates them at render and leaves stored data untouched. checkJs is off because the only .js under src/ is paraglide's generated output, where a message containing "@..." lands in a JSDoc table and gets parsed as a tag. Biome ignores the same directory. Closes #1144 --- infrastructure/eid-wallet/biome.json | 6 +- infrastructure/eid-wallet/messages/en.json | 646 +++++++++++++++++ infrastructure/eid-wallet/messages/ru.json | 658 ++++++++++++++++++ infrastructure/eid-wallet/messages/uk.json | 658 ++++++++++++++++++ infrastructure/eid-wallet/package.json | 14 +- .../eid-wallet/project.inlang/settings.json | 12 + .../IdentityCard/IdentityCard.svelte | 27 +- .../SplashScreen/SplashScreen.svelte | 15 +- .../src/lib/stores/language.svelte.ts | 54 ++ .../eid-wallet/src/lib/stores/language.ts | 71 -- .../CameraPermissionDialog.svelte | 9 +- .../src/lib/ui/ContactCard/ContactCard.svelte | 3 +- .../lib/ui/CopyableEName/CopyableEName.svelte | 11 +- .../lib/ui/LoadingSheet/LoadingSheet.svelte | 3 +- .../src/lib/ui/PinDots/PinDots.svelte | 3 +- .../ui/PlatformAppCard/PlatformAppCard.svelte | 3 +- .../src/lib/utils/identityLabels.ts | 31 + .../eid-wallet/src/lib/utils/index.ts | 1 + .../src/routes/(app)/ePassport/+page.svelte | 142 ++-- .../src/routes/(app)/main/+page.svelte | 106 ++- .../main/components/AppsMarketplace.svelte | 21 +- .../main/components/BindingDocuments.svelte | 5 +- .../(app)/main/components/ENameCard.svelte | 17 +- .../(app)/main/components/EVaultCard.svelte | 9 +- .../main/components/EditNameSheet.svelte | 12 +- .../(app)/main/components/Greeting.svelte | 11 +- .../(app)/main/components/InfoDrawer.svelte | 5 +- .../main/components/LegalIdAccordion.svelte | 15 +- .../PersonalBindingAccordion.svelte | 22 +- .../(app)/main/components/ScanFAB.svelte | 7 +- .../components/SocialBindingAccordion.svelte | 16 +- .../SocialBindingDetailsSheet.svelte | 20 +- .../components/SocialBindingDrawer.svelte | 54 +- .../(app)/main/components/WelcomeTour.svelte | 43 +- .../main/legacy/KycUpgradeOverlay.svelte | 86 ++- .../routes/(app)/notifications/+page.svelte | 22 +- .../src/routes/(app)/personal/+page.svelte | 58 +- .../components/AddKnowledgeSheet.svelte | 20 +- .../components/AddParametersSheet.svelte | 16 +- .../personal/components/AddPhotoSheet.svelte | 37 +- .../src/routes/(app)/scan-qr/+page.svelte | 5 +- .../scan-qr/components/AuthDrawer.svelte | 22 +- .../scan-qr/components/LoggedInDrawer.svelte | 14 +- .../scan-qr/components/RevealDrawer.svelte | 32 +- .../scan-qr/components/SigningDrawer.svelte | 45 +- .../components/SocialBindingDrawer.svelte | 25 +- .../src/routes/(app)/settings/+layout.svelte | 5 +- .../src/routes/(app)/settings/+page.svelte | 74 +- .../(app)/settings/biometrics/+page.svelte | 11 +- .../(app)/settings/history/+page.svelte | 3 +- .../(app)/settings/language/+page.svelte | 13 +- .../(app)/settings/notifications/+page.svelte | 11 +- .../(app)/settings/passphrase/+page.svelte | 54 +- .../routes/(app)/settings/pin/+page.svelte | 28 +- .../(app)/settings/privacy/+page.svelte | 3 +- .../routes/(app)/social-bindings/+page.svelte | 19 +- .../src/routes/(auth)/+layout.svelte | 3 +- .../src/routes/(auth)/login/+page.svelte | 32 +- .../src/routes/(auth)/onboarding/+page.svelte | 215 +++--- .../onboarding/steps/BiometricsSetup.svelte | 15 +- .../(auth)/onboarding/steps/NameInput.svelte | 9 +- .../(auth)/onboarding/steps/PinCreate.svelte | 5 +- .../(auth)/onboarding/steps/PinRepeat.svelte | 9 +- .../(auth)/onboarding/steps/StepHeader.svelte | 5 +- .../open-message/[globalId]/+page.svelte | 7 +- .../src/routes/(public)/recover/+page.svelte | 222 +++--- .../eid-wallet/src/routes/+layout.svelte | 5 + .../eid-wallet/src/routes/+page.svelte | 14 +- infrastructure/eid-wallet/tsconfig.json | 5 +- infrastructure/eid-wallet/vite.config.js | 8 + pnpm-lock.yaml | 64 +- 71 files changed, 2966 insertions(+), 985 deletions(-) create mode 100644 infrastructure/eid-wallet/messages/en.json create mode 100644 infrastructure/eid-wallet/messages/ru.json create mode 100644 infrastructure/eid-wallet/messages/uk.json create mode 100644 infrastructure/eid-wallet/project.inlang/settings.json create mode 100644 infrastructure/eid-wallet/src/lib/stores/language.svelte.ts delete mode 100644 infrastructure/eid-wallet/src/lib/stores/language.ts create mode 100644 infrastructure/eid-wallet/src/lib/utils/identityLabels.ts diff --git a/infrastructure/eid-wallet/biome.json b/infrastructure/eid-wallet/biome.json index 07b14fb42..4581f62c3 100644 --- a/infrastructure/eid-wallet/biome.json +++ b/infrastructure/eid-wallet/biome.json @@ -1,7 +1,11 @@ { "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "extends": ["../../biome.json"], + "files": { + "ignore": ["src/lib/paraglide/**"] + }, "organizeImports": { - "include": ["src/**/*.ts", "src/**/*.svelte"] + "include": ["src/**/*.ts", "src/**/*.svelte"], + "ignore": ["src/lib/paraglide/**"] } } diff --git a/infrastructure/eid-wallet/messages/en.json b/infrastructure/eid-wallet/messages/en.json new file mode 100644 index 000000000..9cc0492c4 --- /dev/null +++ b/infrastructure/eid-wallet/messages/en.json @@ -0,0 +1,646 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "auth_drawer_authenticating": "Authenticating...", + "auth_drawer_pending_l1": "You have a pending", + "auth_drawer_pending_l2": "login request", + "auth_drawer_review": "Please review and confirm that you grant access to your data for the following App", + "auth_drawer_scanned_l1": "You have scanned the", + "auth_drawer_scanned_l2": "login QR code", + "auth_guard_error": "An unexpected error occurred. Please restart the application.", + "binding_docs_about_aria": "About binding documents", + "binding_docs_title": "Binding Documents", + "biometrics_unavailable_error": "Biometrics aren't available on this device.", + "biometrics_unlock_hint": "Unlock the app with your fingerprint or face", + "biometrics_use": "Use biometrics", + "camera_permission_description": "To continue, please grant camera permission in your device settings.", + "camera_permission_title": "Camera Access Required", + "common_accept": "Accept", + "common_add": "Add", + "common_and": "and", + "common_back": "Back", + "common_cancel": "Cancel", + "common_close": "Close", + "common_confirm": "Confirm", + "common_continue": "Continue", + "common_decline": "Decline", + "common_done": "Done", + "common_error": "Error", + "common_go_back": "Go Back", + "common_loading": "Loading...", + "common_next": "Next", + "common_off": "Off", + "common_ok": "Ok", + "common_okay": "Okay", + "common_on": "On", + "common_open_settings": "Open Settings", + "common_privacy_policy": "Privacy Policy", + "common_retry": "Try again", + "common_save": "Save", + "common_saving": "Saving…", + "common_scan": "Scan", + "common_something_went_wrong": "Something went wrong. Please try again.", + "common_try_again": "Try Again", + "common_unknown": "Unknown", + "copyable_copied": "Copied!", + "copyable_copy_aria": "Copy eName", + "edit_name_body": "This is the name shown on your home screen. Your legal name (from your verified ID) and your eName are not affected.", + "edit_name_label": "Display name", + "edit_name_title": "Edit name", + "epassport_add_binding_docs": "Add Binding Documents", + "epassport_enhance_trust": "Enhance Trust Level", + "epassport_missing_docs_body": "Your identity is verified locally but your eVault is missing the binding documents to prove it. Add them now to unlock the full trust level.", + "epassport_no_pending_request": "No pending social binding request found.", + "epassport_request_social_binding": "Request Social Binding", + "epassport_self_declared_body": "Your eVault only contains a self-declared binding document. Verify your identity to increase your trust level.", + "epassport_social_from": "From", + "epassport_social_qr_body": "Ask a trusted person with an eID Wallet to scan this QR and confirm it’s you.", + "epassport_social_qr_note": "They will sign a social binding for your Digital Self – no access to your data.", + "epassport_social_waiting": "Waiting for signature…", + "epassport_title": "ePassport", + "epassport_upgrade_available": "Upgrade available", + "evault_storage_percent_used": "{percent} Used", + "evault_storage_total_gb": "{total}GB total storage", + "evault_storage_used_gb": "{used}GB Used", + "history_title": "History", + "identity_date_of_birth": "Date of Birth", + "identity_demo_id": "DEMO ID", + "identity_document_number": "Document Number", + "identity_id_submitted": "ID submitted", + "identity_name": "Name", + "identity_passport_number": "Passport Number", + "identity_valid_from": "Valid From", + "identity_valid_until": "Valid Until", + "identity_value_anonymous": "Anonymous — Self Declaration", + "identity_value_verified": "Verified", + "identity_verified_id": "VERIFIED ID", + "identity_verified_on": "Verified On", + "identity_your_ename": "Your eName", + "info_binding_p1": "Link binding documents to strengthen the connection between your Digital and Real Selves. Upload verifiable artifacts to your eVault, such as official documents, photos, or confirmations from friends and family, so you can prove ownership of your eVault if needed.", + "info_binding_p2": "Unlike the usual Web 2.0 approach, where platforms make you create an account and upload your data to them, in W3DS, you have your own sovereign account — your Digital Self — and you control who can access your data. With sovereignty comes responsibility.", + "info_binding_p3": "By default, your Digital Self is tied to your Real Self via the eID App, so if anything happens to your phone, you may lose control over your data. However, if your personal artifacts — documents, photos, and social confirmations — are stored in your eVault, you can prove ownership of your Digital Self and regain control over your data.", + "info_binding_title": "Binding documents", + "info_binding_why": "Why it's important:", + "info_evault_p1": "eVault is your sovereign and secure storage. It holds all your data: photos, documents, social media posts, messages to friends, and more. Since your data is now stored by you, not platforms, you can easily switch between services.", + "info_evault_p2": "For example, if you don't like one messenger, simply switch to another, and all your messages, chats, and friends will still be there, because your data is stored with you, and the app only gets temporary permission to access it.", + "info_evault_title": "What is eVault?", + "knowledge_answer_label": "Answer", + "knowledge_hide_answer_aria": "Hide answer", + "knowledge_question_label": "Question", + "knowledge_question_placeholder": "e.g. Name of the street you grew up on", + "knowledge_sheet_body": "Ask a question that only you can answer. Tip: Include a reminder about the correct spelling of the answer.", + "knowledge_sheet_title": "Knowledge", + "knowledge_show_answer_aria": "Show answer", + "kyc_checking_device": "Checking device capabilities...", + "kyc_duplicate_body": "This identity document is already linked to an existing eVault. You can't create a duplicate — each person gets one verified eVault.", + "kyc_duplicate_ename_label": "Your existing eVault eName", + "kyc_duplicate_hint": "Use the eName above to recover access to your existing eVault instead.", + "kyc_duplicate_title": "Identity Already Registered", + "kyc_hardware_check_failed": "Hardware check failed: {reason}", + "kyc_hardware_check_timeout": "Hardware capability check timed out after 10s. Check adb logcat for crypto-hw plugin errors.", + "kyc_hardware_unavailable_body": "Hardware-backed identity verification is not available on this device.", + "kyc_missing_session_id": "Missing session ID from verification result.", + "kyc_result_review_body": "Your verification is being manually reviewed. You'll be notified when it's complete.", + "kyc_result_verified_body": "Your identity has been verified. Your eVault trust level will now be upgraded.", + "kyc_start_error_title": "Couldn't start verification", + "kyc_upgrade_failed_short": "Upgrade failed", + "kyc_upgrading": "Upgrading your eVault…", + "legal_id_document_number": "Document number", + "legal_id_empty_subtitle": "Any legal doc", + "legal_id_title": "Legal ID", + "loggedin_connected_to": "You're now connected to {platform}", + "loggedin_platform_fallback": "the platform", + "loggedin_return_prefix": "You may return to", + "loggedin_return_suffix": "and continue there", + "loggedin_title": "You're logged in!", + "login_biometric_fallback": "Please enter your PIN", + "login_biometric_reason": "You must authenticate with PIN first", + "login_biometric_subtitle": "Please authenticate to continue", + "login_biometric_title": "Login", + "login_clear_pin": "Clear PIN", + "login_deeplink_pending_body": "Sign in to continue.", + "login_deeplink_pending_title": "Authentication request pending.", + "login_forgot_pin": "Forgot your pin?", + "login_pin_mismatch": "Your PIN does not match, try again.", + "login_recover_link": "Recover your eVault.", + "login_signing_in_subtitle": "Setting things up. This only takes a moment.", + "login_signing_in_title": "Signing you in", + "login_title": "Enter your PIN", + "main_edit_name_aria": "Edit name", + "main_edit_name_empty": "Please enter a name.", + "main_edit_name_failed": "Couldn't save your new name. Please try again.", + "main_edit_name_no_vault": "No eVault available", + "main_edit_name_not_ready": "Wallet not ready.", + "main_ename_copied": "eName copied to clipboard!", + "main_ename_copy_failed": "Failed to copy eName", + "main_ename_show_qr_aria": "Show QR code", + "main_ename_title": "Your eName", + "main_ename_unverified": "Unverified ID", + "main_ename_verified": "Verified ID", + "main_evault_about_aria": "About eVault", + "main_evault_available": "available", + "main_evault_size": "5 GB", + "main_evault_title": "Your eVault", + "main_greeting_afternoon": "Good Afternoon", + "main_greeting_evening": "Good Evening", + "main_greeting_fallback": "Hi", + "main_greeting_morning": "Good Morning", + "main_greeting_tour": "Hello", + "main_notifications_aria": "Notifications", + "main_notifications_unread_aria": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "Notifications ({count} unread)", + "countPlural=other": "Notifications ({count} unread)" + } + } + ], + "main_profile_failed_body": "We couldn't set up your eVault profile. This might be due to a network issue or temporary service unavailability.", + "main_profile_failed_title": "Profile Setup Failed", + "main_profile_setup_body": "We're creating your profile in the eVault. This may take a few moments...", + "main_profile_setup_title": "Setting up your eVault profile", + "main_settings_aria": "Settings", + "marketplace_all_apps": "All apps", + "marketplace_category_finance": "Finance", + "marketplace_category_governance": "Governance", + "marketplace_category_social": "Social", + "marketplace_see_all_aria": "See all apps", + "marketplace_title": "Apps marketplace", + "notif_clear_all": "Clear all", + "notif_empty_body": "You're all caught up", + "notif_empty_title": "No notifications", + "notif_prompt_body": "Get notified about new messages, signing requests, and activity on your eVault.", + "notif_prompt_not_now": "Not now", + "notif_prompt_title": "Stay in the loop", + "notif_time_days_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count}d ago", + "countPlural=other": "{count}d ago" + } + } + ], + "notif_time_hours_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count}h ago", + "countPlural=other": "{count}h ago" + } + } + ], + "notif_time_just_now": "Just now", + "notif_time_minutes_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count}m ago", + "countPlural=other": "{count}m ago" + } + } + ], + "notifications_allow": "Allow notifications", + "notifications_disabled_hint": "Get notified when there's activity on your eVault.", + "notifications_enabled_hint": "You'll be notified about new messages and requests.", + "onboarding_anon_body": "Add your full name. Others will see it as unverified until you support this claim with an official ID or social binding.", + "onboarding_anon_consent": "By continuing, I confirm this is my name and I control this Digital Self. This statement will be cryptographically signed and stored as a binding document on your eVault.", + "onboarding_anon_dob_hint": "Stored on your device only — not included in the signed statement.", + "onboarding_anon_dob_label": "Date of Birth", + "onboarding_anon_name_label": "Full Name", + "onboarding_anon_name_placeholder": "Enter your full name", + "onboarding_anon_optional": "(optional)", + "onboarding_anon_submit": "Confirm & Create", + "onboarding_anon_title": "Self-declare your identity for now", + "onboarding_anonymous_provision_failed": "We couldn’t create your self-declared eVault. Check your connection, then tap Confirm & Create again.", + "onboarding_back_to_epassport": "Back to ePassport", + "onboarding_back_to_start": "Back to Start", + "onboarding_biometrics_body": "Use your fingerprint or face to unlock the app instead of typing your PIN every time.", + "onboarding_biometrics_enable": "Enable Biometrics", + "onboarding_biometrics_heading": "Faster, safer sign-in", + "onboarding_biometrics_skip": "Skip for now", + "onboarding_biometrics_title": "Add biometrics", + "onboarding_biometrics_unavailable": "Biometrics aren't available on this device — you can continue with just your PIN.", + "onboarding_create_cta": "Create Digital Self", + "onboarding_duplicate_error": "An eVault already exists for this identity. You cannot create a duplicate — please reclaim your existing eVault instead.", + "onboarding_go_anonymous": "Go Anonymous", + "onboarding_hardware_error_body": "Your phone doesn't support hardware crypto keys, which is a requirement for verified IDs.", + "onboarding_hardware_error_hint": "Please use the anonymous option to create an eVault instead.", + "onboarding_hardware_error_title": "Hardware Security Not Available", + "onboarding_hero_ename": "– your unique, permanent digital identifier, a number", + "onboarding_hero_epassport": "– your cryptographic keys, enabling your agency and control", + "onboarding_hero_evault": "– the secure repository of all your personal data. You will decide who can access it, and how.", + "onboarding_hero_intro": "Your Digital Self consists of three core elements:", + "onboarding_hero_subtitle": "in Web 3.0 Data Space", + "onboarding_hero_title": "Your Digital Self", + "onboarding_kyc_body": "In the Web 3.0 Data Space, identity is linked to reality. We begin by verifying your real-world passport, which serves as the foundation for issuing your secure ePassport. At the same time, we generate your eName – a unique digital identifier – and create your eVault to store and protect your personal data.", + "onboarding_kyc_decision_failed": "Failed to retrieve verification result. Please try again.", + "onboarding_kyc_incomplete": "Verification could not be completed.", + "onboarding_kyc_no_session": "Verification did not return a session ID.", + "onboarding_kyc_start_failed": "Failed to start verification. Please try again.", + "onboarding_kyc_title": "Your Digital Self begins with the Real You", + "onboarding_loading_creating_subtitle": "Generating your eName and signing your binding document.", + "onboarding_loading_creating_title": "Creating your eVault", + "onboarding_loading_decision_subtitle": "Hang tight — we're confirming your result.", + "onboarding_loading_decision_title": "Checking your verification", + "onboarding_loading_hardware_subtitle": "Looking for hardware-backed key support.", + "onboarding_loading_hardware_title": "Checking your device", + "onboarding_loading_restoring_subtitle": "Loading your identity onto this device.", + "onboarding_loading_restoring_title": "Restoring your eVault", + "onboarding_loading_upgrading_subtitle": "Linking your verified identity to your eVault.", + "onboarding_loading_upgrading_title": "Upgrading your eVault", + "onboarding_loading_verification_subtitle": "Opening a secure session with our ID partner.", + "onboarding_loading_verification_title": "Starting verification", + "onboarding_name_label": "Enter your name", + "onboarding_name_placeholder": "Alex for example", + "onboarding_name_required": "Please enter your name.", + "onboarding_name_title": "What's your name?", + "onboarding_new_subtitle": "Choose how you want to prove it’s you.", + "onboarding_new_title": "Create your Digital Self", + "onboarding_path_anonymous_body": "Start with a self-signed claim identity – you can add verified and social binding later.", + "onboarding_path_anonymous_title": "Self-declare for now", + "onboarding_path_verified_body": "Use a real-world ID to bind your Digital Self to you. This gives the strongest proof and makes recovery easier.", + "onboarding_path_verified_title": "Verify with an official ID", + "onboarding_pin_create_title": "Create PIN-code", + "onboarding_pin_repeat_title": "Repeat PIN-code", + "onboarding_pin_save_failed": "Couldn't save your PIN. Please try again.", + "onboarding_privacy_link": "Privacy Policy.", + "onboarding_provision_after_kyc_failed": "We couldn’t create your eVault after identity verification. Check your connection, then tap Continue again.", + "onboarding_provision_failed": "Couldn't create your eVault. Check your connection and try again.", + "onboarding_provision_incomplete": "Provisioning response is incomplete. Please try again.", + "onboarding_provisioning_failed": "Provisioning failed", + "onboarding_provisioning_no_ids": "Provisioning succeeded but did not return uri/w3id", + "onboarding_recover_existing": "Recover existing eVault", + "onboarding_recovery_failed": "Couldn't restore your eVault. Check your connection and try again.", + "onboarding_recovery_lost": "Recovery data lost. Please start recovery again.", + "onboarding_restore_cta": "Restore my Digital Self", + "onboarding_result_duplicate_body": "This identity document is already linked to an existing eVault. Please recover that eVault instead of creating a duplicate.", + "onboarding_result_duplicate_document": "Document:", + "onboarding_result_duplicate_ename_label": "Existing eVault eName", + "onboarding_result_duplicate_title": "Identity Already Registered", + "onboarding_result_failed_body": "Your verification could not be completed.", + "onboarding_result_failed_contact": "If you believe this was a mistake, please contact us at", + "onboarding_result_failed_title": "Verification Failed", + "onboarding_result_review_body": "Your verification is being manually reviewed. You'll be notified when it's complete.", + "onboarding_result_review_title": "Under Review", + "onboarding_result_verified_body": "Your identity has been successfully verified. You can now create your eVault.", + "onboarding_result_verified_title": "Identity Verified", + "onboarding_result_verified_upgrade_body": "Your identity has been verified. Your eVault trust level will now be upgraded.", + "onboarding_self_declare_instead": "Self-declare instead", + "onboarding_step_counter": [ + { + "declarations": [ + "input step", + "input total", + "local totalPlural = total: plural" + ], + "selectors": [ + "totalPlural" + ], + "match": { + "totalPlural=one": "{step} of {total} step", + "totalPlural=other": "{step} of {total} steps" + } + } + ], + "onboarding_terms_link": "Terms & Conditions", + "onboarding_terms_prefix": "By continuing you agree to our", + "onboarding_upgrade_failed": "Upgrade failed. Please try again.", + "onboarding_upgrade_no_vault": "No active eVault found for upgrade.", + "open_message_prompt": "Open this conversation in", + "open_message_title": "New Message", + "parameters_placeholder": "e.g. born 4 March 1992 in Lisbon, 1.78 m, brown eyes", + "parameters_sheet_body": "date and place of birth, height, eye colour, and other identifying traits.", + "parameters_sheet_lead": "Personal details:", + "parameters_sheet_title": "Parameters", + "passphrase_confirm_label": "Confirm passphrase", + "passphrase_confirm_placeholder": "Re-enter your passphrase", + "passphrase_error_empty": "Please enter a passphrase.", + "passphrase_error_mismatch": "Passphrases do not match.", + "passphrase_error_requirements": "Passphrase does not meet all requirements.", + "passphrase_error_save_failed": "Failed to save passphrase. Please try again.", + "passphrase_existing_hint": "A recovery passphrase is already set. Enter a new one below to replace it.", + "passphrase_new_hint": "Set a passphrase that will be required when recovering your eVault. Only a secure hash is stored — your passphrase is never readable.", + "passphrase_new_label": "New passphrase", + "passphrase_new_placeholder": "Enter your passphrase", + "passphrase_req_length": "At least 12 characters", + "passphrase_req_lowercase": "Lowercase letter (a–z)", + "passphrase_req_number": "Number (0–9)", + "passphrase_req_special": "Special character (!@#$…)", + "passphrase_req_uppercase": "Uppercase letter (A–Z)", + "passphrase_set_cta": "Set Passphrase", + "passphrase_success_body": "Your recovery passphrase has been securely stored. You will need it when recovering your eVault.", + "passphrase_success_title_set": "Recovery Passphrase Set!", + "passphrase_success_title_updated": "Recovery Passphrase Updated!", + "passphrase_title": "Recovery Passphrase", + "passphrase_update_cta": "Update Passphrase", + "personal_add_description": "Add description", + "personal_add_edit": "Add / Edit", + "personal_add_photo": "Add photo", + "personal_add_question": "Add question", + "personal_biography_marks": "Biography marks", + "personal_completed_aria": "Completed", + "personal_delete_photo_aria": "Delete photo", + "personal_edit_knowledge_aria": "Edit knowledge", + "personal_edit_parameters_aria": "Edit parameters", + "personal_edit_photo_aria": "Edit photo", + "personal_empty_subtitle": "Identity marks", + "personal_error_knowledge_save": "Couldn't save security question. Try again.", + "personal_error_load": "Couldn't load personal binding documents.", + "personal_error_no_evault": "No eVault available.", + "personal_error_not_ready": "Wallet not ready", + "personal_error_parameters_save": "Couldn't save parameters. Try again.", + "personal_error_photo_delete": "Couldn't delete photo. Try again.", + "personal_error_photo_save": "Couldn't save photo. Try again.", + "personal_error_wallet_state": "Couldn't load your wallet state.", + "personal_intro": "Add unique personal artifacts that only you own or know", + "personal_knowledge_empty_title": "Unique knowledge", + "personal_knowledge_filled_title": "Personal knowledge", + "personal_knowledge_subtitle": "Set a question that only you know the answer to", + "personal_marks_achieved": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} of 3 marks achieved", + "countPlural=other": "{count} of 3 marks achieved" + } + } + ], + "personal_parameters_subtitle": "Personal details: date and place of birth, height, eye colour, and other identifying traits", + "personal_parameters_title": "Personal parameters", + "personal_photo_files_uploaded": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} file uploaded", + "countPlural=other": "{count} files uploaded" + } + } + ], + "personal_photo_mark_fallback": "Photo mark", + "personal_photo_marks": "Photo marks", + "personal_photos_empty_title": "Distinctive photos", + "personal_photos_filled_title": "Personal photos", + "personal_photos_subtitle": "Unique traits: face, tattoos, moles, scars", + "personal_security_question": "Security question", + "personal_title": "Personal", + "photo_camera_permission_description": "To capture a photo mark, please grant camera permission in your device settings.", + "photo_capture": "Capture", + "photo_description_label": "Description", + "photo_description_placeholder": "Describe this photo", + "photo_discard_aria": "Discard photo", + "photo_picked_from_gallery": "Picked from gallery", + "photo_sheet_add_title": "Add photo mark", + "photo_sheet_edit_title": "Edit photo mark", + "photo_source_camera": "Camera", + "photo_source_gallery": "Gallery", + "photo_take_from": "Take from", + "photo_taken_from_camera": "Taken from camera", + "pin_change_title": "Change PIN", + "pin_dots_aria": "PIN input — 4 digits", + "pin_error_mismatch": "PIN codes don't match. Try again.", + "pin_error_must_differ": "Your new PIN must be different from your current PIN.", + "pin_error_update_failed": "Couldn't update your PIN. Check your current PIN and try again.", + "pin_error_verify_failed": "Couldn't verify your current PIN. Try again.", + "pin_error_wrong_current": "That's not your current PIN. Try again.", + "pin_step_current": "Enter your current PIN", + "pin_step_new": "Enter your new PIN", + "pin_step_repeat": "Confirm your new PIN", + "pin_success_body": "Your new PIN is now active. Use it the next time you sign in.", + "pin_success_title": "PIN code changed", + "platform_unknown_app": "Unknown app", + "privacy_title": "Privacy", + "recover_answer_heading_l1": "Enter answer", + "recover_answer_heading_l2": "to your question", + "recover_answer_placeholder": "Your answer", + "recover_create_new": "Create a new eVault", + "recover_ename_body": "We'll use your eName to look up your eVault, then ask you to answer the security question you set up.", + "recover_ename_heading": "Enter your eName", + "recover_ename_label": "Your eName", + "recover_ename_placeholder": "e.g. @4f2a9c1b-...", + "recover_error_answer_mismatch": "That answer doesn't match.", + "recover_error_answer_required": "Please enter your answer.", + "recover_error_answer_verify": "Couldn't verify your answer. Please try again.", + "recover_error_camera_open": "Couldn't open the camera. Please try again.", + "recover_error_camera_permission": "We need camera access to scan the recovery code. Open this app in your device's Settings to allow the camera.", + "recover_error_claim_failed": "Something went wrong claiming the code.", + "recover_error_code_expired": "This recovery code has expired. Ask the notary to issue a new one.", + "recover_error_code_inconsistent": "This recovery code is internally inconsistent.", + "recover_error_code_malformed": "This recovery code is malformed.", + "recover_error_code_missing_fields": "This recovery code is missing required fields.", + "recover_error_code_not_found": "We couldn't find that recovery code.", + "recover_error_code_used": "This recovery code has already been used.", + "recover_error_ename_not_found": "We couldn't find that eName. Check it and try again.", + "recover_error_ename_required": "Please enter your eName.", + "recover_error_evault_unreachable": "Couldn't reach that eVault. Check your connection and try again.", + "recover_error_generic": "Something went wrong. Please try again.", + "recover_error_generic_title": "Something went wrong", + "recover_error_liveness": "We couldn't confirm you were a live person. Please try again in good lighting.", + "recover_error_liveness_title": "Liveness check failed", + "recover_error_no_evault": "We couldn't find an eVault linked to your identity. Make sure you completed identity verification when you first set up your eVault.", + "recover_error_no_match_title": "No eVault found", + "recover_error_no_question": "This eVault has no recovery question set. Recovery isn't possible without ID verification.", + "recover_error_no_session": "The verification session did not return a session ID. Please try again.", + "recover_error_no_vault_url": "The notary didn't return a vault URL.", + "recover_error_no_verification_url": "Backend did not return a verificationUrl", + "recover_error_notary_identity": "Couldn't verify the notary's identity. Try again.", + "recover_error_notary_unreachable": "Couldn't reach the notary. Check your connection.", + "recover_error_notary_unrecognised": "This recovery code wasn't issued by a recognised notary.", + "recover_error_qr_invalid": "That QR isn't a valid notary recovery code.", + "recover_error_qr_not_notary": "That QR isn't a notary recovery code.", + "recover_error_question_malformed": "This eVault's recovery question is missing or malformed.", + "recover_error_reenter_ename": "Please re-enter your eName and try again.", + "recover_error_registry_unreachable": "Couldn't reach the registry to verify the notary.", + "recover_error_search": "Something went wrong during the search. Please try again.", + "recover_error_signature_invalid": "This recovery code's signature is invalid.", + "recover_error_store_failed": "Failed to restore your eVault. Please try again.", + "recover_forgot_answer": "I forgot my answer", + "recover_forgot_ename": "I forgot my eName", + "recover_found_body": "We confirmed your identity. Here's your previous eVault - tap Continue to restore access. If a recovery passphrase exists, we'll ask you to verify it before continuing.", + "recover_found_ename_label": "Your eName", + "recover_found_subtitle": "Please review the connection details below", + "recover_found_title": "eVault Found", + "recover_home_heading_l1": "Already have", + "recover_home_heading_l2": "an eVault?", + "recover_home_question": "Were you idenity-verified when you set up your eVault?", + "recover_home_title": "Restore DigitalSelf", + "recover_impossible_body": "Without your eName and without ID verification, there is no way to recover your eVault. Your eName is your unique identifier - it cannot be looked up without a verified identity.", + "recover_impossible_title": "Recovery not possible", + "recover_loading_find_subtitle": "Looking for an eVault linked to your identity.", + "recover_loading_find_title": "Finding your eVault", + "recover_loading_notary_subtitle": "Checking the recovery code's signature against the registry.", + "recover_loading_notary_title": "Verifying the notary", + "recover_loading_restore_subtitle": "Claiming your recovery code and loading your data.", + "recover_loading_restore_title": "Restoring your eVault", + "recover_loading_session_subtitle": "Setting up your recovery session.", + "recover_loading_session_title": "Preparing verification", + "recover_notary_body": "Without your answer, your eVault cannot be restored automatically. A Registered W3DS Notary can verify your identity in person using trusted witnesses or other proofs of ownership and authorise recovery on your behalf.", + "recover_notary_scan_hint": "Point the camera at the notary's QR", + "recover_notary_title": "Visit a W3DS Notary", + "recover_path_notary_body": "Scan the recovery QR your notary has issued for you.", + "recover_path_notary_title": "I am at a notary", + "recover_path_unverified_body": "Recover using your eName and the security question you set during onboarding.", + "recover_path_unverified_title": "No, I didn't verify my ID", + "recover_path_verified_body": "We'll use your verified identity to find and confirm your previous eVault.", + "recover_path_verified_title": "Yes, I verified my ID", + "recover_restore_cta": "Restore", + "recover_step_subtitle_unverified": "Unverified ID", + "recover_step_title": "Restore", + "reveal_cta": "Reveal", + "reveal_note_body": "This action will decrypt your choice locally. This cannot be undone and will be visible on this screen.", + "reveal_note_label": "Note:", + "reveal_poll_id_inline": "Poll ID: {id}", + "reveal_revealing": "Revealing...", + "reveal_review_body": "Please review the request from the following App.", + "reveal_scanned_l1": "You have scanned a", + "reveal_scanned_l2": "vote reveal QR code", + "reveal_selection_label": "Selection", + "reveal_success_body": "Your selection has been successfully retrieved.", + "reveal_success_title": "Vote decrypted", + "scan_camera_permission_description": "To scan QR codes, please grant camera permission in your device settings.", + "scan_hint": "Point the camera at the code", + "scan_social_relation_label": "Relationship Description", + "scan_social_relation_placeholder": "Describe how you know this person...", + "scan_social_request_sent": "Request sent", + "scan_social_review_body": "Please review the identity below before proceeding.", + "scan_social_scanned": "You have scanned a\nsocial binding QR code", + "scan_social_sign_binding": "Sign Binding", + "scan_social_signing": "Signing…", + "scan_social_success_body": "You've signed the social identity binding. The counterparty will counter-sign to complete the mutual binding.", + "scan_title": "Scan QR Code", + "settings_app_version": "App Version {version}", + "settings_biometric_login": "Biometric login", + "settings_biometrics_unavailable": "Unavailable on this device", + "settings_external_link": "External link", + "settings_language": "Language", + "settings_logout": "Logout", + "settings_logout_warning": "Attention: Logging out will unlink this device from your eVault. To regain access, you will need to re-verify and confirm some of the bindings you provided.", + "settings_notifications": "Notifications", + "settings_pin_code": "Pin-Code", + "settings_privacy_policy": "Privacy policy", + "settings_tap_to_change": "Tap to change", + "settings_tap_to_configure": "Tap to configure", + "settings_title": "Settings", + "signing_blind_vote_submitted": "Blind vote submitted!", + "signing_message_label": "Message", + "signing_message_signed": "Message signed!", + "signing_poll_title_label": "Poll Title", + "signing_review_subtitle": "Please review and confirm the request from the following App.", + "signing_scanned_blind_vote": "You have scanned a blind vote QR code", + "signing_scanned_message": "You have scanned a message signing QR code", + "signing_scanned_vote": "You have scanned a vote signing QR code", + "signing_select_option": "Select Option", + "signing_session_id_label": "Session Id", + "signing_sign": "Sign", + "signing_sign_vote": "Sign Vote", + "signing_signing": "Signing...", + "signing_submit_blind_vote": "Submit Blind Vote", + "signing_submitting": "Submitting...", + "signing_success_subtitle": "Your request was processed successfully.", + "signing_vote_signed": "Vote signed!", + "social_binding_contact_count": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} contact", + "countPlural=other": "{count} contacts" + } + } + ], + "social_binding_empty_subtitle": "New level of trust", + "social_binding_full_list": "Full list", + "social_binding_invite": "Invite", + "social_binding_preview_others": [ + { + "declarations": [ + "input names", + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{names} and {count} other", + "countPlural=other": "{names} and {count} others" + } + } + ], + "social_binding_title": "Social binding", + "social_bindings_empty_body": "Invite a contact from your eName card.", + "social_bindings_empty_title": "No social bindings yet", + "social_bindings_page_title": "Social bindings", + "social_details_awaiting": "Awaiting confirmation", + "social_details_awaiting_suffix": "· Awaiting confirmation", + "social_details_view_full_list": "View on full list", + "social_drawer_counter_signing": "Completing mutual binding…", + "social_drawer_error_fallback": "Failed to complete the binding.", + "social_drawer_error_generic": "Something went wrong.", + "social_drawer_error_title": "Something went wrong", + "social_drawer_no_vault": "No active vault found.", + "social_drawer_qr_body": "Show this code to the person you want to bind with. They scan it from their wallet to confirm the connection.", + "social_drawer_qr_title": "Your QR-Code", + "social_drawer_request_body": "wants to establish a social connection with you. Accept to confirm the binding.", + "social_drawer_request_title": "Social Connection Request", + "social_drawer_someone": "Someone", + "social_drawer_success_body": "{name} has signed your identity binding. Both eVaults now hold a mutually-signed social connection document.", + "social_drawer_success_title": "Binding Complete!", + "social_drawer_they_said": "They said", + "social_drawer_your_contact": "Your contact", + "social_role_received": "Received", + "social_role_sent": "Sent", + "social_role_sent_received": "Sent & Received", + "splash_restore_cta": "Restore Digital Self", + "tour_apps": "Discover apps that work with your eVault — their number is growing fast!", + "tour_binding_docs": "Bind your real and digital selves in different ways. This protects your identity and strengthens control over your data.", + "tour_cta_alright": "Alright", + "tour_cta_finish": "Finish", + "tour_cta_got_it": "Got it", + "tour_ename_p1": "This is your eName — a unique, persistent identifier used globally in the digital world. It is permanently tied to your real self.", + "tour_ename_p2": "Write down your eName, it may be needed for recovery. To strengthen your control over eName, we'll bind it to you in the next step.", + "tour_evault": "This is your eVault — your sovereign data storage. From now on, all platforms will read and write data about you from here, under your control.", + "tour_scan": "Log in to any W3DS service by scanning the QR code. No need to create new accounts — your Digital Self is your sovereign account for all platforms.", + "vote_poll_id_label": "Poll ID" +} diff --git a/infrastructure/eid-wallet/messages/ru.json b/infrastructure/eid-wallet/messages/ru.json new file mode 100644 index 000000000..07dbd4059 --- /dev/null +++ b/infrastructure/eid-wallet/messages/ru.json @@ -0,0 +1,658 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "auth_drawer_authenticating": "Аутентификация...", + "auth_drawer_pending_l1": "У вас есть запрос", + "auth_drawer_pending_l2": "на вход", + "auth_drawer_review": "Проверьте и подтвердите, что вы предоставляете доступ к своим данным следующему приложению", + "auth_drawer_scanned_l1": "Вы отсканировали", + "auth_drawer_scanned_l2": "QR-код для входа", + "auth_guard_error": "Произошла непредвиденная ошибка. Перезапустите приложение.", + "binding_docs_about_aria": "О связывающих документах", + "binding_docs_title": "Связывающие документы", + "biometrics_unavailable_error": "Биометрия недоступна на этом устройстве.", + "biometrics_unlock_hint": "Разблокируйте приложение отпечатком пальца или по лицу", + "biometrics_use": "Использовать биометрию", + "camera_permission_description": "Чтобы продолжить, разрешите доступ к камере в настройках устройства.", + "camera_permission_title": "Требуется доступ к камере", + "common_accept": "Принять", + "common_add": "Добавить", + "common_and": "и", + "common_back": "Назад", + "common_cancel": "Отмена", + "common_close": "Закрыть", + "common_confirm": "Подтвердить", + "common_continue": "Продолжить", + "common_decline": "Отклонить", + "common_done": "Готово", + "common_error": "Ошибка", + "common_go_back": "Вернуться", + "common_loading": "Загрузка...", + "common_next": "Далее", + "common_off": "Выкл.", + "common_ok": "Ок", + "common_okay": "Хорошо", + "common_on": "Вкл.", + "common_open_settings": "Открыть настройки", + "common_privacy_policy": "Политикой конфиденциальности", + "common_retry": "Попробовать снова", + "common_save": "Сохранить", + "common_saving": "Сохранение…", + "common_scan": "Сканировать", + "common_something_went_wrong": "Что-то пошло не так. Попробуйте ещё раз.", + "common_try_again": "Попробовать снова", + "common_unknown": "Неизвестно", + "copyable_copied": "Скопировано!", + "copyable_copy_aria": "Скопировать eName", + "edit_name_body": "Это имя отображается на главном экране. Ваше юридическое имя (из подтверждённого документа) и ваш eName не изменятся.", + "edit_name_label": "Отображаемое имя", + "edit_name_title": "Изменить имя", + "epassport_add_binding_docs": "Добавить связывающие документы", + "epassport_enhance_trust": "Повысить уровень доверия", + "epassport_missing_docs_body": "Ваша личность подтверждена локально, но в вашем eVault нет связывающих документов, подтверждающих это. Добавьте их, чтобы получить полный уровень доверия.", + "epassport_no_pending_request": "Ожидающих запросов на социальную связь не найдено.", + "epassport_request_social_binding": "Запросить социальную связь", + "epassport_self_declared_body": "В вашем eVault есть только самозаявленный связывающий документ. Подтвердите свою личность, чтобы повысить уровень доверия.", + "epassport_social_from": "От", + "epassport_social_qr_body": "Попросите человека, которому вы доверяете и у которого есть eID Wallet, отсканировать этот QR-код и подтвердить, что это вы.", + "epassport_social_qr_note": "Он подпишет социальную связь для вашей Цифровой Личности — без доступа к вашим данным.", + "epassport_social_waiting": "Ожидание подписи…", + "epassport_title": "ePassport", + "epassport_upgrade_available": "Доступно обновление", + "evault_storage_percent_used": "{percent} использовано", + "evault_storage_total_gb": "{total} ГБ всего", + "evault_storage_used_gb": "{used} ГБ использовано", + "history_title": "История", + "identity_date_of_birth": "Дата рождения", + "identity_demo_id": "ДЕМО ID", + "identity_document_number": "Номер документа", + "identity_id_submitted": "Предоставленный документ", + "identity_name": "Имя", + "identity_passport_number": "Номер паспорта", + "identity_valid_from": "Действителен с", + "identity_valid_until": "Действителен до", + "identity_value_anonymous": "Анонимно — самозаявление", + "identity_value_verified": "Подтверждён", + "identity_verified_id": "ПОДТВЕРЖДЁННЫЙ ID", + "identity_verified_on": "Подтверждён", + "identity_your_ename": "Ваш eName", + "info_binding_p1": "Добавляйте связывающие документы, чтобы усилить связь между вашей Цифровой и Реальной Личностью. Загружайте в eVault проверяемые артефакты — официальные документы, фотографии или подтверждения от друзей и родных, — чтобы при необходимости доказать право на свой eVault.", + "info_binding_p2": "В отличие от привычного подхода Web 2.0, где платформы заставляют вас создавать аккаунт и загружать данные к ним, в W3DS у вас есть собственный суверенный аккаунт — ваша Цифровая Личность — и вы решаете, кто получит доступ к вашим данным. Вместе с суверенитетом приходит и ответственность.", + "info_binding_p3": "По умолчанию ваша Цифровая Личность связана с Реальной через приложение eID, поэтому если с телефоном что-то случится, вы можете потерять контроль над данными. Но если ваши личные артефакты — документы, фотографии и социальные подтверждения — хранятся в eVault, вы сможете доказать право на свою Цифровую Личность и вернуть контроль над данными.", + "info_binding_title": "Связывающие документы", + "info_binding_why": "Почему это важно:", + "info_evault_p1": "eVault — это ваше суверенное и защищённое хранилище. В нём находятся все ваши данные: фотографии, документы, публикации в соцсетях, сообщения друзьям и многое другое. Поскольку теперь данные хранятся у вас, а не у платформ, вы легко можете переходить с одного сервиса на другой.", + "info_evault_p2": "Например, если вам разонравился один мессенджер, просто перейдите в другой — все ваши сообщения, чаты и друзья останутся на месте, потому что данные хранятся у вас, а приложение получает лишь временное разрешение на доступ к ним.", + "info_evault_title": "Что такое eVault?", + "knowledge_answer_label": "Ответ", + "knowledge_hide_answer_aria": "Скрыть ответ", + "knowledge_question_label": "Вопрос", + "knowledge_question_placeholder": "напр. Название улицы, где вы выросли", + "knowledge_sheet_body": "Задайте вопрос, ответ на который знаете только вы. Совет: добавьте напоминание о правильном написании ответа.", + "knowledge_sheet_title": "Знание", + "knowledge_show_answer_aria": "Показать ответ", + "kyc_checking_device": "Проверка возможностей устройства...", + "kyc_duplicate_body": "Этот документ уже привязан к существующему eVault. Создать дубликат нельзя — у каждого человека один подтверждённый eVault.", + "kyc_duplicate_ename_label": "eName вашего существующего eVault", + "kyc_duplicate_hint": "Используйте указанный выше eName, чтобы восстановить доступ к существующему eVault.", + "kyc_duplicate_title": "Личность уже зарегистрирована", + "kyc_hardware_check_failed": "Проверка оборудования не удалась: {reason}", + "kyc_hardware_check_timeout": "Проверка возможностей оборудования превысила 10 с. Проверьте adb logcat на наличие ошибок плагина crypto-hw.", + "kyc_hardware_unavailable_body": "Аппаратное подтверждение личности недоступно на этом устройстве.", + "kyc_missing_session_id": "В результате проверки отсутствует идентификатор сессии.", + "kyc_result_review_body": "Ваша проверка рассматривается вручную. Мы сообщим, когда она завершится.", + "kyc_result_verified_body": "Ваша личность подтверждена. Уровень доверия вашего eVault будет повышен.", + "kyc_start_error_title": "Не удалось начать проверку", + "kyc_upgrade_failed_short": "Обновление не удалось", + "kyc_upgrading": "Обновление вашего eVault…", + "legal_id_document_number": "Номер документа", + "legal_id_empty_subtitle": "Любой официальный документ", + "legal_id_title": "Официальный документ", + "loggedin_connected_to": "Вы подключены к {platform}", + "loggedin_platform_fallback": "платформе", + "loggedin_return_prefix": "Вы можете вернуться в", + "loggedin_return_suffix": "и продолжить там", + "loggedin_title": "Вы вошли!", + "login_biometric_fallback": "Введите PIN-код", + "login_biometric_reason": "Сначала нужно войти по PIN-коду", + "login_biometric_subtitle": "Пройдите аутентификацию, чтобы продолжить", + "login_biometric_title": "Вход", + "login_clear_pin": "Очистить PIN-код", + "login_deeplink_pending_body": "Войдите, чтобы продолжить.", + "login_deeplink_pending_title": "Ожидается запрос на аутентификацию.", + "login_forgot_pin": "Забыли PIN-код?", + "login_pin_mismatch": "PIN-код не совпадает, попробуйте ещё раз.", + "login_recover_link": "Восстановить eVault.", + "login_signing_in_subtitle": "Готовим всё необходимое. Это займёт не больше минуты.", + "login_signing_in_title": "Выполняем вход", + "login_title": "Введите PIN-код", + "main_edit_name_aria": "Изменить имя", + "main_edit_name_empty": "Введите имя.", + "main_edit_name_failed": "Не удалось сохранить новое имя. Попробуйте ещё раз.", + "main_edit_name_no_vault": "eVault недоступен", + "main_edit_name_not_ready": "Кошелёк не готов.", + "main_ename_copied": "eName скопирован в буфер обмена!", + "main_ename_copy_failed": "Не удалось скопировать eName", + "main_ename_show_qr_aria": "Показать QR-код", + "main_ename_title": "Ваш eName", + "main_ename_unverified": "Неподтверждённый ID", + "main_ename_verified": "Подтверждённый ID", + "main_evault_about_aria": "Об eVault", + "main_evault_available": "доступно", + "main_evault_size": "5 ГБ", + "main_evault_title": "Ваш eVault", + "main_greeting_afternoon": "Добрый день", + "main_greeting_evening": "Добрый вечер", + "main_greeting_fallback": "Привет", + "main_greeting_morning": "Доброе утро", + "main_greeting_tour": "Здравствуйте", + "main_notifications_aria": "Уведомления", + "main_notifications_unread_aria": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "Уведомления ({count} непрочитанное)", + "countPlural=few": "Уведомления ({count} непрочитанных)", + "countPlural=many": "Уведомления ({count} непрочитанных)", + "countPlural=other": "Уведомления ({count} непрочитанных)" + } + } + ], + "main_profile_failed_body": "Не удалось создать профиль в вашем eVault. Возможно, дело в проблемах с сетью или во временной недоступности сервиса.", + "main_profile_failed_title": "Не удалось создать профиль", + "main_profile_setup_body": "Создаём ваш профиль в eVault. Это займёт немного времени...", + "main_profile_setup_title": "Настраиваем профиль вашего eVault", + "main_settings_aria": "Настройки", + "marketplace_all_apps": "Все приложения", + "marketplace_category_finance": "Финансы", + "marketplace_category_governance": "Управление", + "marketplace_category_social": "Социальные", + "marketplace_see_all_aria": "Посмотреть все приложения", + "marketplace_title": "Маркетплейс приложений", + "notif_clear_all": "Очистить всё", + "notif_empty_body": "Вы всё просмотрели", + "notif_empty_title": "Нет уведомлений", + "notif_prompt_body": "Получайте уведомления о новых сообщениях, запросах на подпись и активности в вашем eVault.", + "notif_prompt_not_now": "Не сейчас", + "notif_prompt_title": "Оставайтесь в курсе", + "notif_time_days_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} д назад", + "countPlural=other": "{count} д назад" + } + } + ], + "notif_time_hours_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} ч назад", + "countPlural=other": "{count} ч назад" + } + } + ], + "notif_time_just_now": "Только что", + "notif_time_minutes_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} мин назад", + "countPlural=other": "{count} мин назад" + } + } + ], + "notifications_allow": "Разрешить уведомления", + "notifications_disabled_hint": "Получайте уведомления об активности в вашем eVault.", + "notifications_enabled_hint": "Вы будете получать уведомления о новых сообщениях и запросах.", + "onboarding_anon_body": "Укажите своё полное имя. Для других оно будет считаться неподтверждённым, пока вы не подкрепите его официальным документом или социальной связью.", + "onboarding_anon_consent": "Продолжая, я подтверждаю, что это моё имя и что я управляю этой Цифровой Личностью. Это заявление будет криптографически подписано и сохранено в вашем eVault как связывающий документ.", + "onboarding_anon_dob_hint": "Хранится только на вашем устройстве — в подписанное заявление не включается.", + "onboarding_anon_dob_label": "Дата рождения", + "onboarding_anon_name_label": "Полное имя", + "onboarding_anon_name_placeholder": "Введите своё полное имя", + "onboarding_anon_optional": "(необязательно)", + "onboarding_anon_submit": "Подтвердить и создать", + "onboarding_anon_title": "Пока заявите личность самостоятельно", + "onboarding_anonymous_provision_failed": "Не удалось создать ваш самозаявленный eVault. Проверьте подключение и снова нажмите «Подтвердить и создать».", + "onboarding_back_to_epassport": "Назад к ePassport", + "onboarding_back_to_start": "В начало", + "onboarding_biometrics_body": "Разблокируйте приложение отпечатком пальца или по лицу вместо того, чтобы каждый раз вводить PIN-код.", + "onboarding_biometrics_enable": "Включить биометрию", + "onboarding_biometrics_heading": "Быстрее и безопаснее", + "onboarding_biometrics_skip": "Пока пропустить", + "onboarding_biometrics_title": "Добавить биометрию", + "onboarding_biometrics_unavailable": "Биометрия недоступна на этом устройстве — вы можете продолжить, используя только PIN-код.", + "onboarding_create_cta": "Создать Цифровую Личность", + "onboarding_duplicate_error": "Для этой личности уже существует eVault. Создать дубликат нельзя — восстановите доступ к существующему eVault.", + "onboarding_go_anonymous": "Продолжить анонимно", + "onboarding_hardware_error_body": "Ваш телефон не поддерживает аппаратные криптографические ключи, которые необходимы для подтверждённых документов.", + "onboarding_hardware_error_hint": "Воспользуйтесь анонимным вариантом, чтобы создать eVault.", + "onboarding_hardware_error_title": "Аппаратная защита недоступна", + "onboarding_hero_ename": "— ваш уникальный постоянный цифровой идентификатор, номер", + "onboarding_hero_epassport": "— ваши криптографические ключи, дающие вам самостоятельность и контроль", + "onboarding_hero_evault": "— защищённое хранилище всех ваших личных данных. Вы решаете, кто и как получит к ним доступ.", + "onboarding_hero_intro": "Ваша Цифровая Личность состоит из трёх основных элементов:", + "onboarding_hero_subtitle": "в пространстве данных Web 3.0", + "onboarding_hero_title": "Ваша Цифровая Личность", + "onboarding_kyc_body": "В пространстве данных Web 3.0 личность связана с реальностью. Мы начинаем с проверки вашего настоящего паспорта — он становится основой для выпуска защищённого ePassport. Одновременно мы создаём ваш eName — уникальный цифровой идентификатор — и ваш eVault для хранения и защиты личных данных.", + "onboarding_kyc_decision_failed": "Не удалось получить результат проверки. Попробуйте ещё раз.", + "onboarding_kyc_incomplete": "Проверку не удалось завершить.", + "onboarding_kyc_no_session": "Проверка не вернула идентификатор сессии.", + "onboarding_kyc_start_failed": "Не удалось начать проверку. Попробуйте ещё раз.", + "onboarding_kyc_title": "Ваша Цифровая Личность начинается с настоящего вас", + "onboarding_loading_creating_subtitle": "Создаём ваш eName и подписываем связывающий документ.", + "onboarding_loading_creating_title": "Создаём ваш eVault", + "onboarding_loading_decision_subtitle": "Подождите — мы подтверждаем результат.", + "onboarding_loading_decision_title": "Проверяем результат", + "onboarding_loading_hardware_subtitle": "Ищем поддержку аппаратных ключей.", + "onboarding_loading_hardware_title": "Проверяем ваше устройство", + "onboarding_loading_restoring_subtitle": "Загружаем вашу личность на это устройство.", + "onboarding_loading_restoring_title": "Восстанавливаем ваш eVault", + "onboarding_loading_upgrading_subtitle": "Привязываем подтверждённую личность к вашему eVault.", + "onboarding_loading_upgrading_title": "Обновляем ваш eVault", + "onboarding_loading_verification_subtitle": "Открываем защищённую сессию с нашим партнёром по проверке документов.", + "onboarding_loading_verification_title": "Начинаем проверку", + "onboarding_name_label": "Введите своё имя", + "onboarding_name_placeholder": "Например, Алекс", + "onboarding_name_required": "Введите своё имя.", + "onboarding_name_title": "Как вас зовут?", + "onboarding_new_subtitle": "Выберите, как вы хотите подтвердить, что это вы.", + "onboarding_new_title": "Создайте свою Цифровую Личность", + "onboarding_path_anonymous_body": "Начните с самоподписанной заявленной личности — подтверждённые и социальные связи можно добавить позже.", + "onboarding_path_anonymous_title": "Пока заявить самостоятельно", + "onboarding_path_verified_body": "Используйте настоящий документ, чтобы привязать Цифровую Личность к себе. Это даёт самое надёжное подтверждение и упрощает восстановление.", + "onboarding_path_verified_title": "Подтвердить официальным документом", + "onboarding_pin_create_title": "Создайте PIN-код", + "onboarding_pin_repeat_title": "Повторите PIN-код", + "onboarding_pin_save_failed": "Не удалось сохранить PIN-код. Попробуйте ещё раз.", + "onboarding_privacy_link": "Политикой конфиденциальности.", + "onboarding_provision_after_kyc_failed": "Не удалось создать ваш eVault после подтверждения личности. Проверьте подключение и снова нажмите «Продолжить».", + "onboarding_provision_failed": "Не удалось создать ваш eVault. Проверьте подключение и попробуйте ещё раз.", + "onboarding_provision_incomplete": "Ответ при создании неполный. Попробуйте ещё раз.", + "onboarding_provisioning_failed": "Не удалось создать eVault", + "onboarding_provisioning_no_ids": "eVault создан, но uri/w3id не были возвращены", + "onboarding_recover_existing": "Восстановить существующий eVault", + "onboarding_recovery_failed": "Не удалось восстановить ваш eVault. Проверьте подключение и попробуйте ещё раз.", + "onboarding_recovery_lost": "Данные восстановления потеряны. Начните восстановление заново.", + "onboarding_restore_cta": "Восстановить мою Цифровую Личность", + "onboarding_result_duplicate_body": "Этот документ уже привязан к существующему eVault. Восстановите тот eVault, а не создавайте дубликат.", + "onboarding_result_duplicate_document": "Документ:", + "onboarding_result_duplicate_ename_label": "eName существующего eVault", + "onboarding_result_duplicate_title": "Личность уже зарегистрирована", + "onboarding_result_failed_body": "Проверку не удалось завершить.", + "onboarding_result_failed_contact": "Если вы считаете, что это ошибка, напишите нам на", + "onboarding_result_failed_title": "Проверка не пройдена", + "onboarding_result_review_body": "Ваша проверка рассматривается вручную. Мы сообщим, когда она завершится.", + "onboarding_result_review_title": "На рассмотрении", + "onboarding_result_verified_body": "Ваша личность успешно подтверждена. Теперь вы можете создать свой eVault.", + "onboarding_result_verified_title": "Личность подтверждена", + "onboarding_result_verified_upgrade_body": "Ваша личность подтверждена. Уровень доверия вашего eVault будет повышен.", + "onboarding_self_declare_instead": "Заявить самостоятельно", + "onboarding_step_counter": [ + { + "declarations": [ + "input step", + "input total", + "local totalPlural = total: plural" + ], + "selectors": [ + "totalPlural" + ], + "match": { + "totalPlural=one": "{step} из {total} шага", + "totalPlural=few": "{step} из {total} шагов", + "totalPlural=many": "{step} из {total} шагов", + "totalPlural=other": "{step} из {total} шагов" + } + } + ], + "onboarding_terms_link": "Условиями использования", + "onboarding_terms_prefix": "Продолжая, вы соглашаетесь с нашими", + "onboarding_upgrade_failed": "Обновление не удалось. Попробуйте ещё раз.", + "onboarding_upgrade_no_vault": "Активный eVault для обновления не найден.", + "open_message_prompt": "Открыть этот разговор в", + "open_message_title": "Новое сообщение", + "parameters_placeholder": "напр. родился 4 марта 1992 в Лиссабоне, 1,78 м, карие глаза", + "parameters_sheet_body": "дата и место рождения, рост, цвет глаз и другие отличительные признаки.", + "parameters_sheet_lead": "Личные данные:", + "parameters_sheet_title": "Параметры", + "passphrase_confirm_label": "Подтвердите парольную фразу", + "passphrase_confirm_placeholder": "Введите парольную фразу ещё раз", + "passphrase_error_empty": "Введите парольную фразу.", + "passphrase_error_mismatch": "Парольные фразы не совпадают.", + "passphrase_error_requirements": "Парольная фраза не отвечает всем требованиям.", + "passphrase_error_save_failed": "Не удалось сохранить парольную фразу. Попробуйте ещё раз.", + "passphrase_existing_hint": "Парольная фраза для восстановления уже задана. Введите новую ниже, чтобы заменить её.", + "passphrase_new_hint": "Задайте парольную фразу, которая понадобится при восстановлении eVault. Хранится только защищённый хеш — саму фразу прочитать невозможно.", + "passphrase_new_label": "Новая парольная фраза", + "passphrase_new_placeholder": "Введите парольную фразу", + "passphrase_req_length": "Не менее 12 символов", + "passphrase_req_lowercase": "Строчная буква (a–z)", + "passphrase_req_number": "Цифра (0–9)", + "passphrase_req_special": "Специальный символ (!@#$…)", + "passphrase_req_uppercase": "Заглавная буква (A–Z)", + "passphrase_set_cta": "Задать парольную фразу", + "passphrase_success_body": "Ваша парольная фраза надёжно сохранена. Она понадобится при восстановлении eVault.", + "passphrase_success_title_set": "Парольная фраза задана!", + "passphrase_success_title_updated": "Парольная фраза обновлена!", + "passphrase_title": "Парольная фраза восстановления", + "passphrase_update_cta": "Обновить парольную фразу", + "personal_add_description": "Добавить описание", + "personal_add_edit": "Добавить / изменить", + "personal_add_photo": "Добавить фото", + "personal_add_question": "Добавить вопрос", + "personal_biography_marks": "Биографические отметки", + "personal_completed_aria": "Выполнено", + "personal_delete_photo_aria": "Удалить фото", + "personal_edit_knowledge_aria": "Изменить знание", + "personal_edit_parameters_aria": "Изменить параметры", + "personal_edit_photo_aria": "Изменить фото", + "personal_empty_subtitle": "Отметки личности", + "personal_error_knowledge_save": "Не удалось сохранить контрольный вопрос. Попробуйте ещё раз.", + "personal_error_load": "Не удалось загрузить личные связывающие документы.", + "personal_error_no_evault": "eVault недоступен.", + "personal_error_not_ready": "Кошелёк не готов", + "personal_error_parameters_save": "Не удалось сохранить параметры. Попробуйте ещё раз.", + "personal_error_photo_delete": "Не удалось удалить фото. Попробуйте ещё раз.", + "personal_error_photo_save": "Не удалось сохранить фото. Попробуйте ещё раз.", + "personal_error_wallet_state": "Не удалось загрузить состояние кошелька.", + "personal_intro": "Добавьте уникальные личные артефакты, которыми владеете или о которых знаете только вы", + "personal_knowledge_empty_title": "Уникальное знание", + "personal_knowledge_filled_title": "Личное знание", + "personal_knowledge_subtitle": "Задайте вопрос, ответ на который знаете только вы", + "personal_marks_achieved": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} из 3 отметок получена", + "countPlural=few": "{count} из 3 отметок получено", + "countPlural=many": "{count} из 3 отметок получено", + "countPlural=other": "{count} из 3 отметок получено" + } + } + ], + "personal_parameters_subtitle": "Личные данные: дата и место рождения, рост, цвет глаз и другие отличительные признаки", + "personal_parameters_title": "Личные параметры", + "personal_photo_files_uploaded": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} файл загружен", + "countPlural=few": "{count} файла загружено", + "countPlural=many": "{count} файлов загружено", + "countPlural=other": "{count} файлов загружено" + } + } + ], + "personal_photo_mark_fallback": "Фотоотметка", + "personal_photo_marks": "Фотоотметки", + "personal_photos_empty_title": "Отличительные фото", + "personal_photos_filled_title": "Личные фото", + "personal_photos_subtitle": "Уникальные черты: лицо, татуировки, родинки, шрамы", + "personal_security_question": "Контрольный вопрос", + "personal_title": "Личное", + "photo_camera_permission_description": "Чтобы сделать фотоотметку, разрешите доступ к камере в настройках устройства.", + "photo_capture": "Снять", + "photo_description_label": "Описание", + "photo_description_placeholder": "Опишите это фото", + "photo_discard_aria": "Удалить фото", + "photo_picked_from_gallery": "Выбрано из галереи", + "photo_sheet_add_title": "Добавить фотоотметку", + "photo_sheet_edit_title": "Изменить фотоотметку", + "photo_source_camera": "Камера", + "photo_source_gallery": "Галерея", + "photo_take_from": "Источник", + "photo_taken_from_camera": "Снято на камеру", + "pin_change_title": "Изменить PIN-код", + "pin_dots_aria": "Ввод PIN-кода — 4 цифры", + "pin_error_mismatch": "PIN-коды не совпадают. Попробуйте ещё раз.", + "pin_error_must_differ": "Новый PIN-код должен отличаться от текущего.", + "pin_error_update_failed": "Не удалось обновить PIN-код. Проверьте текущий PIN-код и попробуйте ещё раз.", + "pin_error_verify_failed": "Не удалось проверить текущий PIN-код. Попробуйте ещё раз.", + "pin_error_wrong_current": "Это не ваш текущий PIN-код. Попробуйте ещё раз.", + "pin_step_current": "Введите текущий PIN-код", + "pin_step_new": "Введите новый PIN-код", + "pin_step_repeat": "Подтвердите новый PIN-код", + "pin_success_body": "Ваш новый PIN-код активен. Используйте его при следующем входе.", + "pin_success_title": "PIN-код изменён", + "platform_unknown_app": "Неизвестное приложение", + "privacy_title": "Конфиденциальность", + "recover_answer_heading_l1": "Введите ответ", + "recover_answer_heading_l2": "на свой вопрос", + "recover_answer_placeholder": "Ваш ответ", + "recover_create_new": "Создать новый eVault", + "recover_ename_body": "Мы используем ваш eName, чтобы найти ваш eVault, а затем попросим ответить на контрольный вопрос, который вы задали.", + "recover_ename_heading": "Введите свой eName", + "recover_ename_label": "Ваш eName", + "recover_ename_placeholder": "напр. @4f2a9c1b-...", + "recover_error_answer_mismatch": "Ответ не совпадает.", + "recover_error_answer_required": "Введите свой ответ.", + "recover_error_answer_verify": "Не удалось проверить ваш ответ. Попробуйте ещё раз.", + "recover_error_camera_open": "Не удалось открыть камеру. Попробуйте ещё раз.", + "recover_error_camera_permission": "Для сканирования кода восстановления нужен доступ к камере. Откройте это приложение в настройках устройства и разрешите доступ к камере.", + "recover_error_claim_failed": "Что-то пошло не так при использовании кода.", + "recover_error_code_expired": "Срок действия этого кода восстановления истёк. Попросите нотариуса выдать новый.", + "recover_error_code_inconsistent": "Этот код восстановления внутренне противоречив.", + "recover_error_code_malformed": "Этот код восстановления имеет неверный формат.", + "recover_error_code_missing_fields": "В этом коде восстановления отсутствуют обязательные поля.", + "recover_error_code_not_found": "Не удалось найти этот код восстановления.", + "recover_error_code_used": "Этот код восстановления уже использован.", + "recover_error_ename_not_found": "Не удалось найти такой eName. Проверьте его и попробуйте ещё раз.", + "recover_error_ename_required": "Введите свой eName.", + "recover_error_evault_unreachable": "Не удалось связаться с этим eVault. Проверьте подключение и попробуйте ещё раз.", + "recover_error_generic": "Что-то пошло не так. Попробуйте ещё раз.", + "recover_error_generic_title": "Что-то пошло не так", + "recover_error_liveness": "Не удалось убедиться, что перед камерой живой человек. Попробуйте ещё раз при хорошем освещении.", + "recover_error_liveness_title": "Проверка живости не пройдена", + "recover_error_no_evault": "Не удалось найти eVault, связанный с вашей личностью. Убедитесь, что при создании eVault вы прошли подтверждение личности.", + "recover_error_no_match_title": "eVault не найден", + "recover_error_no_question": "В этом eVault не задан вопрос для восстановления. Без подтверждения личности восстановление невозможно.", + "recover_error_no_session": "Сессия проверки не вернула идентификатор. Попробуйте ещё раз.", + "recover_error_no_vault_url": "Нотариус не вернул URL хранилища.", + "recover_error_no_verification_url": "Сервер не вернул verificationUrl", + "recover_error_notary_identity": "Не удалось подтвердить личность нотариуса. Попробуйте ещё раз.", + "recover_error_notary_unreachable": "Не удалось связаться с нотариусом. Проверьте подключение.", + "recover_error_notary_unrecognised": "Этот код восстановления выдан не признанным нотариусом.", + "recover_error_qr_invalid": "Этот QR-код не является действительным кодом восстановления нотариуса.", + "recover_error_qr_not_notary": "Этот QR-код не является кодом восстановления нотариуса.", + "recover_error_question_malformed": "Вопрос для восстановления этого eVault отсутствует или имеет неверный формат.", + "recover_error_reenter_ename": "Введите свой eName ещё раз и попробуйте снова.", + "recover_error_registry_unreachable": "Не удалось связаться с реестром для проверки нотариуса.", + "recover_error_search": "Во время поиска что-то пошло не так. Попробуйте ещё раз.", + "recover_error_signature_invalid": "Подпись этого кода восстановления недействительна.", + "recover_error_store_failed": "Не удалось восстановить ваш eVault. Попробуйте ещё раз.", + "recover_forgot_answer": "Я забыл свой ответ", + "recover_forgot_ename": "Я забыл свой eName", + "recover_found_body": "Мы подтвердили вашу личность. Вот ваш прежний eVault — нажмите «Продолжить», чтобы восстановить доступ. Если задана парольная фраза восстановления, мы попросим подтвердить её перед продолжением.", + "recover_found_ename_label": "Ваш eName", + "recover_found_subtitle": "Проверьте данные подключения ниже", + "recover_found_title": "eVault найден", + "recover_home_heading_l1": "Уже есть", + "recover_home_heading_l2": "eVault?", + "recover_home_question": "Подтверждали ли вы личность при создании eVault?", + "recover_home_title": "Восстановить Цифровую Личность", + "recover_impossible_body": "Без вашего eName и без подтверждения личности восстановить eVault невозможно. eName — ваш уникальный идентификатор, и найти его без подтверждённой личности нельзя.", + "recover_impossible_title": "Восстановление невозможно", + "recover_loading_find_subtitle": "Ищем eVault, связанный с вашей личностью.", + "recover_loading_find_title": "Ищем ваш eVault", + "recover_loading_notary_subtitle": "Сверяем подпись кода восстановления с реестром.", + "recover_loading_notary_title": "Проверяем нотариуса", + "recover_loading_restore_subtitle": "Используем ваш код восстановления и загружаем данные.", + "recover_loading_restore_title": "Восстанавливаем ваш eVault", + "recover_loading_session_subtitle": "Готовим сессию восстановления.", + "recover_loading_session_title": "Подготовка проверки", + "recover_notary_body": "Без вашего ответа eVault нельзя восстановить автоматически. Зарегистрированный нотариус W3DS может лично подтвердить вашу личность с помощью доверенных свидетелей или других доказательств владения и разрешить восстановление от вашего имени.", + "recover_notary_scan_hint": "Наведите камеру на QR-код нотариуса", + "recover_notary_title": "Обратитесь к нотариусу W3DS", + "recover_path_notary_body": "Отсканируйте QR-код восстановления, выданный вам нотариусом.", + "recover_path_notary_title": "Я у нотариуса", + "recover_path_unverified_body": "Восстановите доступ по своему eName и контрольному вопросу, который вы задали при регистрации.", + "recover_path_unverified_title": "Нет, я не подтверждал документ", + "recover_path_verified_body": "Мы используем вашу подтверждённую личность, чтобы найти и подтвердить ваш прежний eVault.", + "recover_path_verified_title": "Да, я подтверждал документ", + "recover_restore_cta": "Восстановить", + "recover_step_subtitle_unverified": "Неподтверждённый ID", + "recover_step_title": "Восстановление", + "reveal_cta": "Раскрыть", + "reveal_note_body": "Это действие расшифрует ваш выбор локально. Отменить его нельзя, и результат будет виден на этом экране.", + "reveal_note_label": "Примечание:", + "reveal_poll_id_inline": "ID голосования: {id}", + "reveal_revealing": "Раскрытие...", + "reveal_review_body": "Проверьте запрос от следующего приложения.", + "reveal_scanned_l1": "Вы отсканировали", + "reveal_scanned_l2": "QR-код раскрытия голоса", + "reveal_selection_label": "Выбор", + "reveal_success_body": "Ваш выбор успешно получен.", + "reveal_success_title": "Голос расшифрован", + "scan_camera_permission_description": "Для сканирования QR-кодов разрешите доступ к камере в настройках устройства.", + "scan_hint": "Наведите камеру на код", + "scan_social_relation_label": "Описание отношений", + "scan_social_relation_placeholder": "Опишите, откуда вы знаете этого человека...", + "scan_social_request_sent": "Запрос отправлен", + "scan_social_review_body": "Перед продолжением проверьте личность ниже.", + "scan_social_scanned": "Вы отсканировали\nQR-код социальной связи", + "scan_social_sign_binding": "Подписать связь", + "scan_social_signing": "Подписание…", + "scan_social_success_body": "Вы подписали социальную связь личности. Вторая сторона поставит встречную подпись, чтобы завершить взаимную связь.", + "scan_title": "Сканировать QR-код", + "settings_app_version": "Версия приложения {version}", + "settings_biometric_login": "Вход по биометрии", + "settings_biometrics_unavailable": "Недоступно на этом устройстве", + "settings_external_link": "Внешняя ссылка", + "settings_language": "Язык", + "settings_logout": "Выйти", + "settings_logout_warning": "Внимание: при выходе это устройство будет отвязано от вашего eVault. Чтобы вернуть доступ, потребуется заново подтвердить личность и часть предоставленных связей.", + "settings_notifications": "Уведомления", + "settings_pin_code": "PIN-код", + "settings_privacy_policy": "Политика конфиденциальности", + "settings_tap_to_change": "Нажмите, чтобы изменить", + "settings_tap_to_configure": "Нажмите, чтобы настроить", + "settings_title": "Настройки", + "signing_blind_vote_submitted": "Слепой голос отправлен!", + "signing_message_label": "Сообщение", + "signing_message_signed": "Сообщение подписано!", + "signing_poll_title_label": "Название голосования", + "signing_review_subtitle": "Проверьте и подтвердите запрос от следующего приложения.", + "signing_scanned_blind_vote": "Вы отсканировали QR-код слепого голосования", + "signing_scanned_message": "Вы отсканировали QR-код подписи сообщения", + "signing_scanned_vote": "Вы отсканировали QR-код подписи голоса", + "signing_select_option": "Выберите вариант", + "signing_session_id_label": "ID сессии", + "signing_sign": "Подписать", + "signing_sign_vote": "Подписать голос", + "signing_signing": "Подписание...", + "signing_submit_blind_vote": "Отправить слепой голос", + "signing_submitting": "Отправка...", + "signing_success_subtitle": "Ваш запрос успешно обработан.", + "signing_vote_signed": "Голос подписан!", + "social_binding_contact_count": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} контакт", + "countPlural=few": "{count} контакта", + "countPlural=many": "{count} контактов", + "countPlural=other": "{count} контактов" + } + } + ], + "social_binding_empty_subtitle": "Новый уровень доверия", + "social_binding_full_list": "Полный список", + "social_binding_invite": "Пригласить", + "social_binding_preview_others": [ + { + "declarations": [ + "input names", + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{names} и ещё {count}", + "countPlural=few": "{names} и ещё {count}", + "countPlural=many": "{names} и ещё {count}", + "countPlural=other": "{names} и ещё {count}" + } + } + ], + "social_binding_title": "Социальная связь", + "social_bindings_empty_body": "Пригласите контакт с карточки вашего eName.", + "social_bindings_empty_title": "Социальных связей пока нет", + "social_bindings_page_title": "Социальные связи", + "social_details_awaiting": "Ожидает подтверждения", + "social_details_awaiting_suffix": "· Ожидает подтверждения", + "social_details_view_full_list": "Открыть полный список", + "social_drawer_counter_signing": "Завершаем взаимную связь…", + "social_drawer_error_fallback": "Не удалось завершить создание связи.", + "social_drawer_error_generic": "Что-то пошло не так.", + "social_drawer_error_title": "Что-то пошло не так", + "social_drawer_no_vault": "Активное хранилище не найдено.", + "social_drawer_qr_body": "Покажите этот код человеку, с которым хотите установить связь. Он отсканирует его из своего кошелька, чтобы подтвердить соединение.", + "social_drawer_qr_title": "Ваш QR-код", + "social_drawer_request_body": "хочет установить с вами социальную связь. Примите запрос, чтобы подтвердить связь.", + "social_drawer_request_title": "Запрос на социальную связь", + "social_drawer_someone": "Кто-то", + "social_drawer_success_body": "{name} подписал(а) вашу связь личности. Теперь в обоих eVault хранится взаимно подписанный документ о социальной связи.", + "social_drawer_success_title": "Связь установлена!", + "social_drawer_they_said": "Комментарий", + "social_drawer_your_contact": "Ваш контакт", + "social_role_received": "Получено", + "social_role_sent": "Отправлено", + "social_role_sent_received": "Отправлено и получено", + "splash_restore_cta": "Восстановить Цифровую Личность", + "tour_apps": "Откройте для себя приложения, работающие с вашим eVault, — их становится всё больше!", + "tour_binding_docs": "Связывайте свою реальную и цифровую личности разными способами. Это защищает вашу личность и усиливает контроль над данными.", + "tour_cta_alright": "Ясно", + "tour_cta_finish": "Завершить", + "tour_cta_got_it": "Понятно", + "tour_ename_p1": "Это ваш eName — уникальный постоянный идентификатор, который используется во всём цифровом мире. Он навсегда связан с вами настоящим.", + "tour_ename_p2": "Запишите свой eName — он может понадобиться для восстановления. Чтобы усилить ваш контроль над eName, на следующем шаге мы свяжем его с вами.", + "tour_evault": "Это ваш eVault — ваше суверенное хранилище данных. С этого момента все платформы будут читать и записывать данные о вас отсюда, под вашим контролем.", + "tour_scan": "Входите в любой сервис W3DS, сканируя QR-код. Не нужно создавать новые аккаунты — ваша Цифровая Личность и есть ваш суверенный аккаунт для всех платформ.", + "vote_poll_id_label": "ID голосования" +} diff --git a/infrastructure/eid-wallet/messages/uk.json b/infrastructure/eid-wallet/messages/uk.json new file mode 100644 index 000000000..55aa52be6 --- /dev/null +++ b/infrastructure/eid-wallet/messages/uk.json @@ -0,0 +1,658 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "auth_drawer_authenticating": "Автентифікація...", + "auth_drawer_pending_l1": "У вас є запит", + "auth_drawer_pending_l2": "на вхід", + "auth_drawer_review": "Перегляньте та підтвердьте, що ви надаєте доступ до своїх даних наступному застосунку", + "auth_drawer_scanned_l1": "Ви відсканували", + "auth_drawer_scanned_l2": "QR-код для входу", + "auth_guard_error": "Сталася непередбачена помилка. Перезапустіть застосунок.", + "binding_docs_about_aria": "Про зв’язувальні документи", + "binding_docs_title": "Зв’язувальні документи", + "biometrics_unavailable_error": "Біометрія недоступна на цьому пристрої.", + "biometrics_unlock_hint": "Розблоковуйте застосунок відбитком пальця або обличчям", + "biometrics_use": "Використовувати біометрію", + "camera_permission_description": "Щоб продовжити, надайте доступ до камери в налаштуваннях пристрою.", + "camera_permission_title": "Потрібен доступ до камери", + "common_accept": "Прийняти", + "common_add": "Додати", + "common_and": "та", + "common_back": "Назад", + "common_cancel": "Скасувати", + "common_close": "Закрити", + "common_confirm": "Підтвердити", + "common_continue": "Продовжити", + "common_decline": "Відхилити", + "common_done": "Готово", + "common_error": "Помилка", + "common_go_back": "Повернутися", + "common_loading": "Завантаження...", + "common_next": "Далі", + "common_off": "Вимк.", + "common_ok": "Ок", + "common_okay": "Добре", + "common_on": "Увімк.", + "common_open_settings": "Відкрити налаштування", + "common_privacy_policy": "Політикою конфіденційності", + "common_retry": "Спробувати ще раз", + "common_save": "Зберегти", + "common_saving": "Збереження…", + "common_scan": "Сканувати", + "common_something_went_wrong": "Щось пішло не так. Спробуйте ще раз.", + "common_try_again": "Спробувати ще раз", + "common_unknown": "Невідомо", + "copyable_copied": "Скопійовано!", + "copyable_copy_aria": "Скопіювати eName", + "edit_name_body": "Це ім’я показується на головному екрані. Ваше юридичне ім’я (з підтвердженого документа) та ваш eName не зміняться.", + "edit_name_label": "Відображуване ім’я", + "edit_name_title": "Змінити ім’я", + "epassport_add_binding_docs": "Додати зв’язувальні документи", + "epassport_enhance_trust": "Підвищити рівень довіри", + "epassport_missing_docs_body": "Вашу особу підтверджено локально, але у вашому eVault немає зв’язувальних документів, які це доводять. Додайте їх, щоб отримати повний рівень довіри.", + "epassport_no_pending_request": "Запитів на соціальний зв’язок, що очікують, не знайдено.", + "epassport_request_social_binding": "Запитати соціальний зв’язок", + "epassport_self_declared_body": "У вашому eVault є лише самозаявлений зв’язувальний документ. Підтвердьте свою особу, щоб підвищити рівень довіри.", + "epassport_social_from": "Від", + "epassport_social_qr_body": "Попросіть людину, якій ви довіряєте і яка має eID Wallet, відсканувати цей QR-код і підтвердити, що це ви.", + "epassport_social_qr_note": "Вона підпише соціальний зв’язок для вашої Цифрової Особистості — без доступу до ваших даних.", + "epassport_social_waiting": "Очікування підпису…", + "epassport_title": "ePassport", + "epassport_upgrade_available": "Доступне оновлення", + "evault_storage_percent_used": "{percent} використано", + "evault_storage_total_gb": "{total} ГБ загалом", + "evault_storage_used_gb": "{used} ГБ використано", + "history_title": "Історія", + "identity_date_of_birth": "Дата народження", + "identity_demo_id": "ДЕМО ID", + "identity_document_number": "Номер документа", + "identity_id_submitted": "Наданий документ", + "identity_name": "Ім’я", + "identity_passport_number": "Номер паспорта", + "identity_valid_from": "Дійсний з", + "identity_valid_until": "Дійсний до", + "identity_value_anonymous": "Анонімно — самозаява", + "identity_value_verified": "Підтверджено", + "identity_verified_id": "ПІДТВЕРДЖЕНИЙ ID", + "identity_verified_on": "Підтверджено", + "identity_your_ename": "Ваш eName", + "info_binding_p1": "Додавайте зв’язувальні документи, щоб посилити зв’язок між вашою Цифровою та Реальною Особистістю. Завантажуйте в eVault перевірювані артефакти — офіційні документи, фотографії чи підтвердження від друзів і рідних, — щоб за потреби довести право на свій eVault.", + "info_binding_p2": "На відміну від звичного підходу Web 2.0, де платформи змушують вас створювати обліковий запис і завантажувати дані до них, у W3DS ви маєте власний суверенний обліковий запис — вашу Цифрову Особистість — і самі вирішуєте, хто отримає доступ до ваших даних. Разом із суверенітетом приходить і відповідальність.", + "info_binding_p3": "За умовчанням ваша Цифрова Особистість пов’язана з Реальною через застосунок eID, тож якщо з телефоном щось станеться, ви можете втратити контроль над даними. Але якщо ваші особисті артефакти — документи, фотографії та соціальні підтвердження — зберігаються в eVault, ви зможете довести право на свою Цифрову Особистість і повернути контроль над даними.", + "info_binding_title": "Зв’язувальні документи", + "info_binding_why": "Чому це важливо:", + "info_evault_p1": "eVault — це ваше суверенне та захищене сховище. У ньому зберігаються всі ваші дані: фотографії, документи, дописи в соцмережах, повідомлення друзям тощо. Оскільки тепер дані зберігаються у вас, а не в платформ, ви легко можете переходити між сервісами.", + "info_evault_p2": "Наприклад, якщо вам розлюбився один месенджер, просто перейдіть в інший — усі ваші повідомлення, чати та друзі залишаться на місці, адже дані зберігаються у вас, а застосунок отримує лише тимчасовий дозвіл на доступ до них.", + "info_evault_title": "Що таке eVault?", + "knowledge_answer_label": "Відповідь", + "knowledge_hide_answer_aria": "Приховати відповідь", + "knowledge_question_label": "Запитання", + "knowledge_question_placeholder": "напр. Назва вулиці, де ви виросли", + "knowledge_sheet_body": "Поставте запитання, відповідь на яке знаєте лише ви. Порада: додайте нагадування про правильне написання відповіді.", + "knowledge_sheet_title": "Знання", + "knowledge_show_answer_aria": "Показати відповідь", + "kyc_checking_device": "Перевірка можливостей пристрою...", + "kyc_duplicate_body": "Цей документ уже прив’язаний до наявного eVault. Створити дублікат не можна — кожна людина має один підтверджений eVault.", + "kyc_duplicate_ename_label": "eName вашого наявного eVault", + "kyc_duplicate_hint": "Скористайтеся вказаним вище eName, щоб відновити доступ до наявного eVault.", + "kyc_duplicate_title": "Особу вже зареєстровано", + "kyc_hardware_check_failed": "Перевірка обладнання не вдалася: {reason}", + "kyc_hardware_check_timeout": "Перевірка можливостей обладнання перевищила 10 с. Перевірте adb logcat на помилки плагіна crypto-hw.", + "kyc_hardware_unavailable_body": "Апаратне підтвердження особи недоступне на цьому пристрої.", + "kyc_missing_session_id": "У результаті перевірки відсутній ідентифікатор сесії.", + "kyc_result_review_body": "Вашу перевірку розглядають вручну. Ми повідомимо, коли вона завершиться.", + "kyc_result_verified_body": "Вашу особу підтверджено. Рівень довіри вашого eVault буде підвищено.", + "kyc_start_error_title": "Не вдалося почати перевірку", + "kyc_upgrade_failed_short": "Оновлення не вдалося", + "kyc_upgrading": "Оновлення вашого eVault…", + "legal_id_document_number": "Номер документа", + "legal_id_empty_subtitle": "Будь-який офіційний документ", + "legal_id_title": "Офіційний документ", + "loggedin_connected_to": "Ви підключені до {platform}", + "loggedin_platform_fallback": "платформи", + "loggedin_return_prefix": "Ви можете повернутися до", + "loggedin_return_suffix": "і продовжити там", + "loggedin_title": "Ви увійшли!", + "login_biometric_fallback": "Введіть PIN-код", + "login_biometric_reason": "Спершу потрібно увійти за PIN-кодом", + "login_biometric_subtitle": "Пройдіть автентифікацію, щоб продовжити", + "login_biometric_title": "Вхід", + "login_clear_pin": "Очистити PIN-код", + "login_deeplink_pending_body": "Увійдіть, щоб продовжити.", + "login_deeplink_pending_title": "Очікується запит на автентифікацію.", + "login_forgot_pin": "Забули PIN-код?", + "login_pin_mismatch": "PIN-код не збігається, спробуйте ще раз.", + "login_recover_link": "Відновити eVault.", + "login_signing_in_subtitle": "Готуємо все потрібне. Це займе лише мить.", + "login_signing_in_title": "Виконуємо вхід", + "login_title": "Введіть PIN-код", + "main_edit_name_aria": "Змінити ім’я", + "main_edit_name_empty": "Введіть ім’я.", + "main_edit_name_failed": "Не вдалося зберегти нове ім’я. Спробуйте ще раз.", + "main_edit_name_no_vault": "eVault недоступний", + "main_edit_name_not_ready": "Гаманець не готовий.", + "main_ename_copied": "eName скопійовано в буфер обміну!", + "main_ename_copy_failed": "Не вдалося скопіювати eName", + "main_ename_show_qr_aria": "Показати QR-код", + "main_ename_title": "Ваш eName", + "main_ename_unverified": "Непідтверджений ID", + "main_ename_verified": "Підтверджений ID", + "main_evault_about_aria": "Про eVault", + "main_evault_available": "доступно", + "main_evault_size": "5 ГБ", + "main_evault_title": "Ваш eVault", + "main_greeting_afternoon": "Доброго дня", + "main_greeting_evening": "Доброго вечора", + "main_greeting_fallback": "Привіт", + "main_greeting_morning": "Доброго ранку", + "main_greeting_tour": "Вітаємо", + "main_notifications_aria": "Сповіщення", + "main_notifications_unread_aria": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "Сповіщення ({count} непрочитане)", + "countPlural=few": "Сповіщення ({count} непрочитані)", + "countPlural=many": "Сповіщення ({count} непрочитаних)", + "countPlural=other": "Сповіщення ({count} непрочитаних)" + } + } + ], + "main_profile_failed_body": "Не вдалося створити профіль у вашому eVault. Можливо, річ у проблемах із мережею або тимчасовій недоступності сервісу.", + "main_profile_failed_title": "Не вдалося створити профіль", + "main_profile_setup_body": "Створюємо ваш профіль в eVault. Це триватиме кілька хвилин...", + "main_profile_setup_title": "Налаштовуємо профіль вашого eVault", + "main_settings_aria": "Налаштування", + "marketplace_all_apps": "Усі застосунки", + "marketplace_category_finance": "Фінанси", + "marketplace_category_governance": "Врядування", + "marketplace_category_social": "Соціальні", + "marketplace_see_all_aria": "Переглянути всі застосунки", + "marketplace_title": "Маркетплейс застосунків", + "notif_clear_all": "Очистити все", + "notif_empty_body": "Ви все переглянули", + "notif_empty_title": "Немає сповіщень", + "notif_prompt_body": "Отримуйте сповіщення про нові повідомлення, запити на підпис та активність у вашому eVault.", + "notif_prompt_not_now": "Не зараз", + "notif_prompt_title": "Будьте в курсі", + "notif_time_days_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} д тому", + "countPlural=other": "{count} д тому" + } + } + ], + "notif_time_hours_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} год тому", + "countPlural=other": "{count} год тому" + } + } + ], + "notif_time_just_now": "Щойно", + "notif_time_minutes_ago": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} хв тому", + "countPlural=other": "{count} хв тому" + } + } + ], + "notifications_allow": "Дозволити сповіщення", + "notifications_disabled_hint": "Отримуйте сповіщення про активність у вашому eVault.", + "notifications_enabled_hint": "Ви отримуватимете сповіщення про нові повідомлення та запити.", + "onboarding_anon_body": "Вкажіть своє повне ім’я. Для інших воно вважатиметься непідтвердженим, доки ви не підкріпите його офіційним документом або соціальним зв’язком.", + "onboarding_anon_consent": "Продовжуючи, я підтверджую, що це моє ім’я і що я керую цією Цифровою Особистістю. Ця заява буде криптографічно підписана та збережена у вашому eVault як зв’язувальний документ.", + "onboarding_anon_dob_hint": "Зберігається лише на вашому пристрої — до підписаної заяви не входить.", + "onboarding_anon_dob_label": "Дата народження", + "onboarding_anon_name_label": "Повне ім’я", + "onboarding_anon_name_placeholder": "Введіть своє повне ім’я", + "onboarding_anon_optional": "(необов’язково)", + "onboarding_anon_submit": "Підтвердити та створити", + "onboarding_anon_title": "Поки що заявіть особу самостійно", + "onboarding_anonymous_provision_failed": "Не вдалося створити ваш самозаявлений eVault. Перевірте з’єднання та знову натисніть «Підтвердити та створити».", + "onboarding_back_to_epassport": "Назад до ePassport", + "onboarding_back_to_start": "На початок", + "onboarding_biometrics_body": "Розблоковуйте застосунок відбитком пальця або обличчям замість того, щоб щоразу вводити PIN-код.", + "onboarding_biometrics_enable": "Увімкнути біометрію", + "onboarding_biometrics_heading": "Швидше й безпечніше", + "onboarding_biometrics_skip": "Поки що пропустити", + "onboarding_biometrics_title": "Додати біометрію", + "onboarding_biometrics_unavailable": "Біометрія недоступна на цьому пристрої — ви можете продовжити, використовуючи лише PIN-код.", + "onboarding_create_cta": "Створити Цифрову Особистість", + "onboarding_duplicate_error": "Для цієї особи вже існує eVault. Створити дублікат не можна — відновіть доступ до наявного eVault.", + "onboarding_go_anonymous": "Продовжити анонімно", + "onboarding_hardware_error_body": "Ваш телефон не підтримує апаратні криптографічні ключі, які потрібні для підтверджених документів.", + "onboarding_hardware_error_hint": "Скористайтеся анонімним варіантом, щоб створити eVault.", + "onboarding_hardware_error_title": "Апаратний захист недоступний", + "onboarding_hero_ename": "— ваш унікальний постійний цифровий ідентифікатор, номер", + "onboarding_hero_epassport": "— ваші криптографічні ключі, що дають вам самостійність і контроль", + "onboarding_hero_evault": "— захищене сховище всіх ваших особистих даних. Ви вирішуєте, хто і як отримає до них доступ.", + "onboarding_hero_intro": "Ваша Цифрова Особистість складається з трьох основних елементів:", + "onboarding_hero_subtitle": "у просторі даних Web 3.0", + "onboarding_hero_title": "Ваша Цифрова Особистість", + "onboarding_kyc_body": "У просторі даних Web 3.0 особа пов’язана з реальністю. Ми починаємо з перевірки вашого справжнього паспорта — він стає основою для випуску захищеного ePassport. Водночас ми створюємо ваш eName — унікальний цифровий ідентифікатор — і ваш eVault для зберігання та захисту особистих даних.", + "onboarding_kyc_decision_failed": "Не вдалося отримати результат перевірки. Спробуйте ще раз.", + "onboarding_kyc_incomplete": "Перевірку не вдалося завершити.", + "onboarding_kyc_no_session": "Перевірка не повернула ідентифікатор сесії.", + "onboarding_kyc_start_failed": "Не вдалося почати перевірку. Спробуйте ще раз.", + "onboarding_kyc_title": "Ваша Цифрова Особистість починається зі справжнього вас", + "onboarding_loading_creating_subtitle": "Створюємо ваш eName і підписуємо зв’язувальний документ.", + "onboarding_loading_creating_title": "Створюємо ваш eVault", + "onboarding_loading_decision_subtitle": "Зачекайте — ми підтверджуємо результат.", + "onboarding_loading_decision_title": "Перевіряємо результат", + "onboarding_loading_hardware_subtitle": "Шукаємо підтримку апаратних ключів.", + "onboarding_loading_hardware_title": "Перевіряємо ваш пристрій", + "onboarding_loading_restoring_subtitle": "Завантажуємо вашу особу на цей пристрій.", + "onboarding_loading_restoring_title": "Відновлюємо ваш eVault", + "onboarding_loading_upgrading_subtitle": "Прив’язуємо підтверджену особу до вашого eVault.", + "onboarding_loading_upgrading_title": "Оновлюємо ваш eVault", + "onboarding_loading_verification_subtitle": "Відкриваємо захищену сесію з нашим партнером із перевірки документів.", + "onboarding_loading_verification_title": "Починаємо перевірку", + "onboarding_name_label": "Введіть своє ім’я", + "onboarding_name_placeholder": "Наприклад, Олекс", + "onboarding_name_required": "Введіть своє ім’я.", + "onboarding_name_title": "Як вас звати?", + "onboarding_new_subtitle": "Оберіть, як ви хочете підтвердити, що це ви.", + "onboarding_new_title": "Створіть свою Цифрову Особистість", + "onboarding_path_anonymous_body": "Почніть із самопідписаної заявленої особи — підтверджені та соціальні зв’язки можна додати згодом.", + "onboarding_path_anonymous_title": "Поки що заявити самостійно", + "onboarding_path_verified_body": "Скористайтеся справжнім документом, щоб прив’язати Цифрову Особистість до себе. Це дає найнадійніше підтвердження та спрощує відновлення.", + "onboarding_path_verified_title": "Підтвердити офіційним документом", + "onboarding_pin_create_title": "Створіть PIN-код", + "onboarding_pin_repeat_title": "Повторіть PIN-код", + "onboarding_pin_save_failed": "Не вдалося зберегти PIN-код. Спробуйте ще раз.", + "onboarding_privacy_link": "Політикою конфіденційності.", + "onboarding_provision_after_kyc_failed": "Не вдалося створити ваш eVault після підтвердження особи. Перевірте з’єднання та знову натисніть «Продовжити».", + "onboarding_provision_failed": "Не вдалося створити ваш eVault. Перевірте з’єднання та спробуйте ще раз.", + "onboarding_provision_incomplete": "Відповідь під час створення неповна. Спробуйте ще раз.", + "onboarding_provisioning_failed": "Не вдалося створити eVault", + "onboarding_provisioning_no_ids": "eVault створено, але uri/w3id не було повернено", + "onboarding_recover_existing": "Відновити наявний eVault", + "onboarding_recovery_failed": "Не вдалося відновити ваш eVault. Перевірте з’єднання та спробуйте ще раз.", + "onboarding_recovery_lost": "Дані відновлення втрачено. Почніть відновлення спочатку.", + "onboarding_restore_cta": "Відновити мою Цифрову Особистість", + "onboarding_result_duplicate_body": "Цей документ уже прив’язаний до наявного eVault. Відновіть той eVault, а не створюйте дублікат.", + "onboarding_result_duplicate_document": "Документ:", + "onboarding_result_duplicate_ename_label": "eName наявного eVault", + "onboarding_result_duplicate_title": "Особу вже зареєстровано", + "onboarding_result_failed_body": "Перевірку не вдалося завершити.", + "onboarding_result_failed_contact": "Якщо ви вважаєте, що це помилка, напишіть нам на", + "onboarding_result_failed_title": "Перевірку не пройдено", + "onboarding_result_review_body": "Вашу перевірку розглядають вручну. Ми повідомимо, коли вона завершиться.", + "onboarding_result_review_title": "На розгляді", + "onboarding_result_verified_body": "Вашу особу успішно підтверджено. Тепер ви можете створити свій eVault.", + "onboarding_result_verified_title": "Особу підтверджено", + "onboarding_result_verified_upgrade_body": "Вашу особу підтверджено. Рівень довіри вашого eVault буде підвищено.", + "onboarding_self_declare_instead": "Заявити самостійно", + "onboarding_step_counter": [ + { + "declarations": [ + "input step", + "input total", + "local totalPlural = total: plural" + ], + "selectors": [ + "totalPlural" + ], + "match": { + "totalPlural=one": "{step} з {total} кроку", + "totalPlural=few": "{step} з {total} кроків", + "totalPlural=many": "{step} з {total} кроків", + "totalPlural=other": "{step} з {total} кроків" + } + } + ], + "onboarding_terms_link": "Умовами використання", + "onboarding_terms_prefix": "Продовжуючи, ви погоджуєтеся з нашими", + "onboarding_upgrade_failed": "Оновлення не вдалося. Спробуйте ще раз.", + "onboarding_upgrade_no_vault": "Активний eVault для оновлення не знайдено.", + "open_message_prompt": "Відкрити цю розмову в", + "open_message_title": "Нове повідомлення", + "parameters_placeholder": "напр. народився 4 березня 1992 у Лісабоні, 1,78 м, карі очі", + "parameters_sheet_body": "дата й місце народження, зріст, колір очей та інші відмітні ознаки.", + "parameters_sheet_lead": "Особисті дані:", + "parameters_sheet_title": "Параметри", + "passphrase_confirm_label": "Підтвердьте парольну фразу", + "passphrase_confirm_placeholder": "Введіть парольну фразу ще раз", + "passphrase_error_empty": "Введіть парольну фразу.", + "passphrase_error_mismatch": "Парольні фрази не збігаються.", + "passphrase_error_requirements": "Парольна фраза не відповідає всім вимогам.", + "passphrase_error_save_failed": "Не вдалося зберегти парольну фразу. Спробуйте ще раз.", + "passphrase_existing_hint": "Парольну фразу для відновлення вже задано. Введіть нову нижче, щоб замінити її.", + "passphrase_new_hint": "Задайте парольну фразу, яка знадобиться під час відновлення eVault. Зберігається лише захищений хеш — саму фразу прочитати неможливо.", + "passphrase_new_label": "Нова парольна фраза", + "passphrase_new_placeholder": "Введіть парольну фразу", + "passphrase_req_length": "Щонайменше 12 символів", + "passphrase_req_lowercase": "Мала літера (a–z)", + "passphrase_req_number": "Цифра (0–9)", + "passphrase_req_special": "Спеціальний символ (!@#$…)", + "passphrase_req_uppercase": "Велика літера (A–Z)", + "passphrase_set_cta": "Задати парольну фразу", + "passphrase_success_body": "Вашу парольну фразу надійно збережено. Вона знадобиться під час відновлення eVault.", + "passphrase_success_title_set": "Парольну фразу задано!", + "passphrase_success_title_updated": "Парольну фразу оновлено!", + "passphrase_title": "Парольна фраза відновлення", + "passphrase_update_cta": "Оновити парольну фразу", + "personal_add_description": "Додати опис", + "personal_add_edit": "Додати / змінити", + "personal_add_photo": "Додати фото", + "personal_add_question": "Додати запитання", + "personal_biography_marks": "Біографічні позначки", + "personal_completed_aria": "Виконано", + "personal_delete_photo_aria": "Видалити фото", + "personal_edit_knowledge_aria": "Змінити знання", + "personal_edit_parameters_aria": "Змінити параметри", + "personal_edit_photo_aria": "Змінити фото", + "personal_empty_subtitle": "Позначки особистості", + "personal_error_knowledge_save": "Не вдалося зберегти контрольне запитання. Спробуйте ще раз.", + "personal_error_load": "Не вдалося завантажити особисті зв’язувальні документи.", + "personal_error_no_evault": "eVault недоступний.", + "personal_error_not_ready": "Гаманець не готовий", + "personal_error_parameters_save": "Не вдалося зберегти параметри. Спробуйте ще раз.", + "personal_error_photo_delete": "Не вдалося видалити фото. Спробуйте ще раз.", + "personal_error_photo_save": "Не вдалося зберегти фото. Спробуйте ще раз.", + "personal_error_wallet_state": "Не вдалося завантажити стан гаманця.", + "personal_intro": "Додайте унікальні особисті артефакти, якими володієте або про які знаєте лише ви", + "personal_knowledge_empty_title": "Унікальне знання", + "personal_knowledge_filled_title": "Особисте знання", + "personal_knowledge_subtitle": "Поставте запитання, відповідь на яке знаєте лише ви", + "personal_marks_achieved": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} з 3 позначок отримано", + "countPlural=few": "{count} з 3 позначок отримано", + "countPlural=many": "{count} з 3 позначок отримано", + "countPlural=other": "{count} з 3 позначок отримано" + } + } + ], + "personal_parameters_subtitle": "Особисті дані: дата й місце народження, зріст, колір очей та інші відмітні ознаки", + "personal_parameters_title": "Особисті параметри", + "personal_photo_files_uploaded": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} файл завантажено", + "countPlural=few": "{count} файли завантажено", + "countPlural=many": "{count} файлів завантажено", + "countPlural=other": "{count} файлів завантажено" + } + } + ], + "personal_photo_mark_fallback": "Фотопозначка", + "personal_photo_marks": "Фотопозначки", + "personal_photos_empty_title": "Відмітні фото", + "personal_photos_filled_title": "Особисті фото", + "personal_photos_subtitle": "Унікальні риси: обличчя, татуювання, родимки, шрами", + "personal_security_question": "Контрольне запитання", + "personal_title": "Особисте", + "photo_camera_permission_description": "Щоб зробити фотопозначку, надайте доступ до камери в налаштуваннях пристрою.", + "photo_capture": "Зняти", + "photo_description_label": "Опис", + "photo_description_placeholder": "Опишіть це фото", + "photo_discard_aria": "Видалити фото", + "photo_picked_from_gallery": "Вибрано з галереї", + "photo_sheet_add_title": "Додати фотопозначку", + "photo_sheet_edit_title": "Змінити фотопозначку", + "photo_source_camera": "Камера", + "photo_source_gallery": "Галерея", + "photo_take_from": "Джерело", + "photo_taken_from_camera": "Знято на камеру", + "pin_change_title": "Змінити PIN-код", + "pin_dots_aria": "Введення PIN-коду — 4 цифри", + "pin_error_mismatch": "PIN-коди не збігаються. Спробуйте ще раз.", + "pin_error_must_differ": "Новий PIN-код має відрізнятися від поточного.", + "pin_error_update_failed": "Не вдалося оновити PIN-код. Перевірте поточний PIN-код і спробуйте ще раз.", + "pin_error_verify_failed": "Не вдалося перевірити поточний PIN-код. Спробуйте ще раз.", + "pin_error_wrong_current": "Це не ваш поточний PIN-код. Спробуйте ще раз.", + "pin_step_current": "Введіть поточний PIN-код", + "pin_step_new": "Введіть новий PIN-код", + "pin_step_repeat": "Підтвердьте новий PIN-код", + "pin_success_body": "Ваш новий PIN-код активний. Використовуйте його під час наступного входу.", + "pin_success_title": "PIN-код змінено", + "platform_unknown_app": "Невідомий застосунок", + "privacy_title": "Конфіденційність", + "recover_answer_heading_l1": "Введіть відповідь", + "recover_answer_heading_l2": "на своє запитання", + "recover_answer_placeholder": "Ваша відповідь", + "recover_create_new": "Створити новий eVault", + "recover_ename_body": "Ми скористаємося вашим eName, щоб знайти ваш eVault, а потім попросимо відповісти на контрольне запитання, яке ви задали.", + "recover_ename_heading": "Введіть свій eName", + "recover_ename_label": "Ваш eName", + "recover_ename_placeholder": "напр. @4f2a9c1b-...", + "recover_error_answer_mismatch": "Відповідь не збігається.", + "recover_error_answer_required": "Введіть свою відповідь.", + "recover_error_answer_verify": "Не вдалося перевірити вашу відповідь. Спробуйте ще раз.", + "recover_error_camera_open": "Не вдалося відкрити камеру. Спробуйте ще раз.", + "recover_error_camera_permission": "Для сканування коду відновлення потрібен доступ до камери. Відкрийте цей застосунок у налаштуваннях пристрою та дозвольте доступ до камери.", + "recover_error_claim_failed": "Щось пішло не так під час використання коду.", + "recover_error_code_expired": "Термін дії цього коду відновлення минув. Попросіть нотаріуса видати новий.", + "recover_error_code_inconsistent": "Цей код відновлення внутрішньо суперечливий.", + "recover_error_code_malformed": "Цей код відновлення має хибний формат.", + "recover_error_code_missing_fields": "У цьому коді відновлення бракує обов’язкових полів.", + "recover_error_code_not_found": "Не вдалося знайти цей код відновлення.", + "recover_error_code_used": "Цей код відновлення вже використано.", + "recover_error_ename_not_found": "Не вдалося знайти такий eName. Перевірте його та спробуйте ще раз.", + "recover_error_ename_required": "Введіть свій eName.", + "recover_error_evault_unreachable": "Не вдалося зв’язатися з цим eVault. Перевірте з’єднання та спробуйте ще раз.", + "recover_error_generic": "Щось пішло не так. Спробуйте ще раз.", + "recover_error_generic_title": "Щось пішло не так", + "recover_error_liveness": "Не вдалося переконатися, що перед камерою жива людина. Спробуйте ще раз за доброго освітлення.", + "recover_error_liveness_title": "Перевірку на живу людину не пройдено", + "recover_error_no_evault": "Не вдалося знайти eVault, пов’язаний з вашою особою. Переконайтеся, що під час створення eVault ви пройшли підтвердження особи.", + "recover_error_no_match_title": "eVault не знайдено", + "recover_error_no_question": "У цьому eVault не задано запитання для відновлення. Без підтвердження особи відновлення неможливе.", + "recover_error_no_session": "Сесія перевірки не повернула ідентифікатор. Спробуйте ще раз.", + "recover_error_no_vault_url": "Нотаріус не повернув URL сховища.", + "recover_error_no_verification_url": "Сервер не повернув verificationUrl", + "recover_error_notary_identity": "Не вдалося підтвердити особу нотаріуса. Спробуйте ще раз.", + "recover_error_notary_unreachable": "Не вдалося зв’язатися з нотаріусом. Перевірте з’єднання.", + "recover_error_notary_unrecognised": "Цей код відновлення видано не визнаним нотаріусом.", + "recover_error_qr_invalid": "Цей QR-код не є дійсним кодом відновлення нотаріуса.", + "recover_error_qr_not_notary": "Цей QR-код не є кодом відновлення нотаріуса.", + "recover_error_question_malformed": "Запитання для відновлення цього eVault відсутнє або має хибний формат.", + "recover_error_reenter_ename": "Введіть свій eName ще раз і спробуйте знову.", + "recover_error_registry_unreachable": "Не вдалося зв’язатися з реєстром, щоб перевірити нотаріуса.", + "recover_error_search": "Під час пошуку щось пішло не так. Спробуйте ще раз.", + "recover_error_signature_invalid": "Підпис цього коду відновлення недійсний.", + "recover_error_store_failed": "Не вдалося відновити ваш eVault. Спробуйте ще раз.", + "recover_forgot_answer": "Я забув свою відповідь", + "recover_forgot_ename": "Я забув свій eName", + "recover_found_body": "Ми підтвердили вашу особу. Ось ваш попередній eVault — натисніть «Продовжити», щоб відновити доступ. Якщо задано парольну фразу відновлення, ми попросимо підтвердити її перед продовженням.", + "recover_found_ename_label": "Ваш eName", + "recover_found_subtitle": "Перегляньте дані підключення нижче", + "recover_found_title": "eVault знайдено", + "recover_home_heading_l1": "Уже маєте", + "recover_home_heading_l2": "eVault?", + "recover_home_question": "Чи підтверджували ви особу під час створення eVault?", + "recover_home_title": "Відновити Цифрову Особистість", + "recover_impossible_body": "Без вашого eName і без підтвердження особи відновити eVault неможливо. eName — ваш унікальний ідентифікатор, і знайти його без підтвердженої особи не можна.", + "recover_impossible_title": "Відновлення неможливе", + "recover_loading_find_subtitle": "Шукаємо eVault, пов’язаний з вашою особою.", + "recover_loading_find_title": "Шукаємо ваш eVault", + "recover_loading_notary_subtitle": "Звіряємо підпис коду відновлення з реєстром.", + "recover_loading_notary_title": "Перевіряємо нотаріуса", + "recover_loading_restore_subtitle": "Використовуємо ваш код відновлення та завантажуємо дані.", + "recover_loading_restore_title": "Відновлюємо ваш eVault", + "recover_loading_session_subtitle": "Готуємо сесію відновлення.", + "recover_loading_session_title": "Підготовка перевірки", + "recover_notary_body": "Без вашої відповіді eVault не можна відновити автоматично. Зареєстрований нотаріус W3DS може особисто підтвердити вашу особу за допомогою довірених свідків чи інших доказів володіння та дозволити відновлення від вашого імені.", + "recover_notary_scan_hint": "Наведіть камеру на QR-код нотаріуса", + "recover_notary_title": "Зверніться до нотаріуса W3DS", + "recover_path_notary_body": "Відскануйте QR-код відновлення, виданий вам нотаріусом.", + "recover_path_notary_title": "Я в нотаріуса", + "recover_path_unverified_body": "Відновіть доступ за своїм eName і контрольним запитанням, яке ви задали під час реєстрації.", + "recover_path_unverified_title": "Ні, я не підтверджував документ", + "recover_path_verified_body": "Ми скористаємося вашою підтвердженою особою, щоб знайти та підтвердити ваш попередній eVault.", + "recover_path_verified_title": "Так, я підтверджував документ", + "recover_restore_cta": "Відновити", + "recover_step_subtitle_unverified": "Непідтверджений ID", + "recover_step_title": "Відновлення", + "reveal_cta": "Розкрити", + "reveal_note_body": "Ця дія розшифрує ваш вибір локально. Скасувати її не можна, і результат буде видно на цьому екрані.", + "reveal_note_label": "Примітка:", + "reveal_poll_id_inline": "ID голосування: {id}", + "reveal_revealing": "Розкриття...", + "reveal_review_body": "Перегляньте запит від наступного застосунку.", + "reveal_scanned_l1": "Ви відсканували", + "reveal_scanned_l2": "QR-код розкриття голосу", + "reveal_selection_label": "Вибір", + "reveal_success_body": "Ваш вибір успішно отримано.", + "reveal_success_title": "Голос розшифровано", + "scan_camera_permission_description": "Для сканування QR-кодів надайте доступ до камери в налаштуваннях пристрою.", + "scan_hint": "Наведіть камеру на код", + "scan_social_relation_label": "Опис стосунків", + "scan_social_relation_placeholder": "Опишіть, звідки ви знаєте цю людину...", + "scan_social_request_sent": "Запит надіслано", + "scan_social_review_body": "Перед продовженням перегляньте особу нижче.", + "scan_social_scanned": "Ви відсканували\nQR-код соціального зв’язку", + "scan_social_sign_binding": "Підписати зв’язок", + "scan_social_signing": "Підписання…", + "scan_social_success_body": "Ви підписали соціальний зв’язок особи. Друга сторона поставить зустрічний підпис, щоб завершити взаємний зв’язок.", + "scan_title": "Сканувати QR-код", + "settings_app_version": "Версія застосунку {version}", + "settings_biometric_login": "Вхід за біометрією", + "settings_biometrics_unavailable": "Недоступно на цьому пристрої", + "settings_external_link": "Зовнішнє посилання", + "settings_language": "Мова", + "settings_logout": "Вийти", + "settings_logout_warning": "Увага: після виходу цей пристрій буде відв’язано від вашого eVault. Щоб повернути доступ, знадобиться заново підтвердити особу та частину наданих зв’язків.", + "settings_notifications": "Сповіщення", + "settings_pin_code": "PIN-код", + "settings_privacy_policy": "Політика конфіденційності", + "settings_tap_to_change": "Торкніться, щоб змінити", + "settings_tap_to_configure": "Торкніться, щоб налаштувати", + "settings_title": "Налаштування", + "signing_blind_vote_submitted": "Сліпий голос надіслано!", + "signing_message_label": "Повідомлення", + "signing_message_signed": "Повідомлення підписано!", + "signing_poll_title_label": "Назва голосування", + "signing_review_subtitle": "Перегляньте та підтвердьте запит від наступного застосунку.", + "signing_scanned_blind_vote": "Ви відсканували QR-код сліпого голосування", + "signing_scanned_message": "Ви відсканували QR-код підпису повідомлення", + "signing_scanned_vote": "Ви відсканували QR-код підпису голосу", + "signing_select_option": "Оберіть варіант", + "signing_session_id_label": "ID сесії", + "signing_sign": "Підписати", + "signing_sign_vote": "Підписати голос", + "signing_signing": "Підписання...", + "signing_submit_blind_vote": "Надіслати сліпий голос", + "signing_submitting": "Надсилання...", + "signing_success_subtitle": "Ваш запит успішно оброблено.", + "signing_vote_signed": "Голос підписано!", + "social_binding_contact_count": [ + { + "declarations": [ + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{count} контакт", + "countPlural=few": "{count} контакти", + "countPlural=many": "{count} контактів", + "countPlural=other": "{count} контактів" + } + } + ], + "social_binding_empty_subtitle": "Новий рівень довіри", + "social_binding_full_list": "Повний список", + "social_binding_invite": "Запросити", + "social_binding_preview_others": [ + { + "declarations": [ + "input names", + "input count", + "local countPlural = count: plural" + ], + "selectors": [ + "countPlural" + ], + "match": { + "countPlural=one": "{names} та ще {count}", + "countPlural=few": "{names} та ще {count}", + "countPlural=many": "{names} та ще {count}", + "countPlural=other": "{names} та ще {count}" + } + } + ], + "social_binding_title": "Соціальний зв’язок", + "social_bindings_empty_body": "Запросіть контакт із картки вашого eName.", + "social_bindings_empty_title": "Соціальних зв’язків поки немає", + "social_bindings_page_title": "Соціальні зв’язки", + "social_details_awaiting": "Очікує підтвердження", + "social_details_awaiting_suffix": "· Очікує підтвердження", + "social_details_view_full_list": "Відкрити повний список", + "social_drawer_counter_signing": "Завершуємо взаємний зв’язок…", + "social_drawer_error_fallback": "Не вдалося завершити створення зв’язку.", + "social_drawer_error_generic": "Щось пішло не так.", + "social_drawer_error_title": "Щось пішло не так", + "social_drawer_no_vault": "Активного сховища не знайдено.", + "social_drawer_qr_body": "Покажіть цей код людині, з якою хочете встановити зв’язок. Вона відсканує його зі свого гаманця, щоб підтвердити з’єднання.", + "social_drawer_qr_title": "Ваш QR-код", + "social_drawer_request_body": "хоче встановити з вами соціальний зв’язок. Прийміть запит, щоб підтвердити зв’язок.", + "social_drawer_request_title": "Запит на соціальний зв’язок", + "social_drawer_someone": "Хтось", + "social_drawer_success_body": "{name} підписав(ла) ваш зв’язок особи. Тепер в обох eVault зберігається взаємно підписаний документ про соціальний зв’язок.", + "social_drawer_success_title": "Зв’язок встановлено!", + "social_drawer_they_said": "Коментар", + "social_drawer_your_contact": "Ваш контакт", + "social_role_received": "Отримано", + "social_role_sent": "Надіслано", + "social_role_sent_received": "Надіслано та отримано", + "splash_restore_cta": "Відновити Цифрову Особистість", + "tour_apps": "Відкрийте для себе застосунки, що працюють із вашим eVault, — їх стає дедалі більше!", + "tour_binding_docs": "Пов’язуйте свою реальну та цифрову особистості різними способами. Це захищає вашу особу й посилює контроль над даними.", + "tour_cta_alright": "Ясно", + "tour_cta_finish": "Завершити", + "tour_cta_got_it": "Зрозуміло", + "tour_ename_p1": "Це ваш eName — унікальний постійний ідентифікатор, що використовується в усьому цифровому світі. Він назавжди пов’язаний зі справжнім вами.", + "tour_ename_p2": "Запишіть свій eName — він може знадобитися для відновлення. Щоб посилити ваш контроль над eName, на наступному кроці ми пов’яжемо його з вами.", + "tour_evault": "Це ваш eVault — ваше суверенне сховище даних. Відтепер усі платформи читатимуть і записуватимуть дані про вас звідси, під вашим контролем.", + "tour_scan": "Входьте до будь-якого сервісу W3DS, скануючи QR-код. Не потрібно створювати нові облікові записи — ваша Цифрова Особистість і є вашим суверенним обліковим записом для всіх платформ.", + "vote_poll_id_label": "ID голосування" +} diff --git a/infrastructure/eid-wallet/package.json b/infrastructure/eid-wallet/package.json index 2c830ea8b..9a419fc07 100644 --- a/infrastructure/eid-wallet/package.json +++ b/infrastructure/eid-wallet/package.json @@ -7,18 +7,19 @@ "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && npx @biomejs/biome check ./src", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "check": "npm run paraglide:compile && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && npx @biomejs/biome check ./src", + "check:watch": "npm run paraglide:compile && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "format": "npx @biomejs/biome format --write ./src", "check-format": "npx @biomejs/biome format ./src", "lint": "npx @biomejs/biome lint --write ./src", "check-lint": "npx @biomejs/biome lint ./src", "tauri": "tauri", - "test": "vitest run", - "storybook": "svelte-kit sync && storybook dev -p 6006", - "build-storybook": "storybook build", + "test": "npm run paraglide:compile && vitest run", + "storybook": "npm run paraglide:compile && svelte-kit sync && storybook dev -p 6006", + "build-storybook": "npm run paraglide:compile && storybook build", "build:apk": "npm run tauri android build -- --apk --target aarch64 --target armv7", - "build:aab": "npm run tauri android build -- --aab --target aarch64 --target armv7" + "build:aab": "npm run tauri android build -- --aab --target aarch64 --target armv7", + "paraglide:compile": "paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide --strategy localStorage preferredLanguage baseLocale" }, "license": "MIT", "dependencies": { @@ -29,6 +30,7 @@ "@fontsource-variable/roboto-condensed": "^5.2.8", "@hugeicons/core-free-icons": "^1.0.13", "@hugeicons/svelte": "^1.0.2", + "@inlang/paraglide-js": "^2.15.0", "@metastate-foundation/platform-icons": "workspace:*", "@tailwindcss/container-queries": "^0.1.1", "@tauri-apps/api": "^2.11.0", diff --git a/infrastructure/eid-wallet/project.inlang/settings.json b/infrastructure/eid-wallet/project.inlang/settings.json new file mode 100644 index 000000000..10dd996c6 --- /dev/null +++ b/infrastructure/eid-wallet/project.inlang/settings.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js" + ], + "plugin.inlang.messageFormat": { + "pathPattern": "./messages/{locale}.json" + }, + "baseLocale": "en", + "locales": ["en", "ru", "uk"] +} diff --git a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte index 536ec03a8..e23a2c609 100644 --- a/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte +++ b/infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte @@ -1,6 +1,7 @@ diff --git a/infrastructure/eid-wallet/src/lib/ui/PinDots/PinDots.svelte b/infrastructure/eid-wallet/src/lib/ui/PinDots/PinDots.svelte index 6d7e94fc0..ecc8a82b2 100644 --- a/infrastructure/eid-wallet/src/lib/ui/PinDots/PinDots.svelte +++ b/infrastructure/eid-wallet/src/lib/ui/PinDots/PinDots.svelte @@ -1,4 +1,5 @@ - +
{#if userData} @@ -619,8 +624,12 @@ onMount(async () => { > {#each Object.entries(docData) as [fieldName, value]}
-

{fieldName}

-

{value}

+

+ {identityFieldLabel(fieldName)} +

+

+ {identityFieldValue(String(value))} +

{/each}
@@ -633,29 +642,25 @@ onMount(async () => { class="mb-3 p-4 bg-emerald-50 border border-emerald-200 rounded-xl" >

- Upgrade available + {m.epassport_upgrade_available()}

- Your identity is verified locally but your eVault is - missing the binding documents to prove it. Add them now - to unlock the full trust level. + {m.epassport_missing_docs_body()}

- Add Binding Documents + {m.epassport_add_binding_docs()} {:else}

- Your eVault only contains a self-declared binding - document. Verify your identity to increase your trust - level. + {m.epassport_self_declared_body()}

- Enhance Trust Level + {m.epassport_enhance_trust()} {/if} @@ -669,7 +674,7 @@ onMount(async () => { class="w-full" callback={openSocialBindingDrawer} > - Request Social Binding + {m.epassport_request_social_binding()} {/if} @@ -689,37 +694,37 @@ onMount(async () => { > ✓ -

Binding Complete!

+

{m.social_drawer_success_title()}

- {socialBindingSignerName ?? "Someone"} has signed your identity binding. - Both eVaults now hold a mutually-signed social connection document. + {m.social_drawer_success_body({ + name: socialBindingSignerName ?? m.social_drawer_someone(), + })}

Done{m.common_done()} {:else if socialBindingCounterSigning}

- Completing mutual binding… + {m.social_drawer_counter_signing()}

{:else if socialBindingAwaitingConsent}
-

Social Connection Request

+

{m.social_drawer_request_title()}

{socialBindingSignerName ?? socialBindingSignerEname ?? - "Someone"} - wants to establish a social connection with you. Accept to confirm - the binding. + {m.social_drawer_request_body()}

-

From

+

{m.epassport_social_from()}

{socialBindingSignerName ?? socialBindingSignerEname}

@@ -731,7 +736,7 @@ onMount(async () => {
{#if typeof socialBindingPendingDocParsed?.data?.relation_description === "string" && socialBindingPendingDocParsed.data.relation_description}
-

Relationship Description

+

{m.scan_social_relation_label()}

{socialBindingPendingDocParsed.data.relation_description}

@@ -742,22 +747,20 @@ onMount(async () => { {/if}
Accept{m.common_accept()} Decline{m.common_decline()}
{:else}
-

Request Social Binding

+

{m.epassport_request_social_binding()}

- Ask a trusted person with an eID Wallet to scan this QR and - confirm it’s you.
- They will sign a social binding for your Digital Self – no access - to your data. + {m.epassport_social_qr_body()}
+ {m.epassport_social_qr_note()}

@@ -773,7 +776,7 @@ onMount(async () => { {#if socialBindingPolling}
-

Waiting for signature…

+

{m.epassport_social_waiting()}

{/if} @@ -786,7 +789,7 @@ onMount(async () => { class="w-full" callback={closeSocialBindingDrawer} > - Cancel + {m.common_cancel()} {/if}
@@ -822,19 +825,18 @@ onMount(async () => {

{kycStep === "checking-hw" - ? "Checking device capabilities..." + ? m.kyc_checking_device() : kycStep === "upgrading" - ? "Upgrading your eVault…" - : "Starting verification…"} + ? m.kyc_upgrading() + : m.onboarding_loading_verification_title()}

{:else if kycStep === "hw-error"}

- Hardware Security Not Available + {m.onboarding_hardware_error_title()}

- Your phone doesn't support hardware crypto keys, - which is a requirement for verified IDs. + {m.onboarding_hardware_error_body()}

{/if} @@ -846,7 +848,7 @@ onMount(async () => { class="w-full" callback={resetKyc} > - Cancel + {m.common_cancel()} {/if} @@ -864,7 +866,7 @@ onMount(async () => { class="text-sm text-black-500 underline" onclick={resetKyc} > - Cancel + {m.common_cancel()}
@@ -883,26 +885,23 @@ onMount(async () => { > ! -

Identity Already Registered

+

{m.kyc_duplicate_title()}

- This identity document is already linked to an existing eVault. - You can't create a duplicate — each person gets one verified - eVault. + {m.kyc_duplicate_body()}

{#if duplicateEName}

- Use the eName above to recover access to your existing - eVault instead. + {m.kyc_duplicate_hint()}

{/if}
- Got it + {m.tour_cta_got_it()}
@@ -929,15 +928,14 @@ onMount(async () => { > ✓ -

Identity Verified

+

{m.onboarding_result_verified_title()}

- Your identity has been verified. Your eVault trust level - will now be upgraded. + {m.kyc_result_verified_body()}

Continue{m.common_continue()}
{:else if diditResult === "in_review"} @@ -947,17 +945,16 @@ onMount(async () => { > ⏳ -

Under Review

+

{m.onboarding_result_review_title()}

- Your verification is being manually reviewed. You'll be - notified when it's complete. + {m.kyc_result_review_body()}

Close{m.common_close()}
{:else} @@ -967,20 +964,19 @@ onMount(async () => { > ✗ -

Verification Failed

+

{m.onboarding_result_failed_title()}

- {diditRejectionReason ?? - "Your verification could not be completed."} + {diditRejectionReason ?? m.onboarding_result_failed_body()}

Try Again{m.common_try_again()} Cancel{m.common_cancel()}
{/if} diff --git a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte index 6a05cadb5..f34692708 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte @@ -35,6 +35,8 @@ import { } from "$lib/stores/notifications"; import NotificationService from "$lib/services/NotificationService"; import { BottomSheet, ButtonAction, Toast } from "$lib/ui"; +import { m } from "$lib/paraglide/messages"; +import { getLocale } from "$lib/paraglide/runtime"; import * as Button from "$lib/ui/Button"; import { isPermissionGranted } from "@choochmeque/tauri-plugin-notifications-api"; import { openAppSettings } from "@tauri-apps/plugin-barcode-scanner"; @@ -72,7 +74,7 @@ import KycUpgradeOverlay from "./legacy/KycUpgradeOverlay.svelte"; // Seed component state from the module-scope cache so re-entry paints // instantly; loaders below refresh in-place. let userData: Record | undefined = $state(cachedUserData); -let greeting: string | undefined = $state(undefined); +let greetingHour = $state(undefined); let ename: string | undefined = $state(cachedEname); let profileCreationStatus: "idle" | "loading" | "success" | "failed" = $state("idle"); @@ -288,12 +290,12 @@ async function loadBindingDocuments(): Promise { // the next load picks the most-recent self doc by timestamp anyway. async function handleEditNameSave(newName: string): Promise { if (!globalState) { - editNameError = "Wallet not ready."; + editNameError = m.main_edit_name_not_ready(); return; } const trimmed = newName.trim(); if (!trimmed) { - editNameError = "Please enter a name."; + editNameError = m.main_edit_name_empty(); return; } if (trimmed === displayName) { @@ -307,7 +309,7 @@ async function handleEditNameSave(newName: string): Promise { try { const vault = await globalState.vaultController.vault; if (!vault?.uri || !vault?.ename) { - throw new Error("No eVault available"); + throw new Error(m.main_edit_name_no_vault()); } const ownerEname = vault.ename.startsWith("@") ? vault.ename @@ -365,7 +367,7 @@ async function handleEditNameSave(newName: string): Promise { editNameError = err instanceof Error ? err.message - : "Couldn't save your new name. Please try again."; + : m.main_edit_name_failed(); } finally { editNameSaving = false; } @@ -521,7 +523,11 @@ function formatDate(iso: string | undefined): string | undefined { if (!iso) return undefined; const d = new Date(iso); if (Number.isNaN(d.getTime())) return iso; - return d.toDateString(); + return d.toLocaleDateString(getLocale(), { + year: "numeric", + month: "short", + day: "numeric", + }); } // TODO: enrich the Legal ID card with document type, country, DOB and document @@ -558,7 +564,7 @@ function toLegalIdDoc(doc: ParsedBindingDoc): LegalIdDoc { (userData ? asString(userData["Document Number"]) : undefined); return { - title: title || "Legal ID", + title: title || m.legal_id_title(), name, dateOfBirth: dob, documentNumber, @@ -582,7 +588,18 @@ let tourOffset = $state(0); // instantly with last-known values while the background refresh runs. let pageReady = $state(hasEverLoaded); const tourActive = $derived(tourStep !== null); -const tourGreeting = $derived(tourActive ? "Hello" : (greeting ?? "Hi")); +const greeting = $derived( + greetingHour === undefined + ? undefined + : greetingHour > 17 + ? m.main_greeting_evening() + : greetingHour > 12 + ? m.main_greeting_afternoon() + : m.main_greeting_morning(), +); +const tourGreeting = $derived( + tourActive ? m.main_greeting_tour() : (greeting ?? m.main_greeting_fallback()), +); // Captured once on component init. Stays true for the lifetime of this // component instance; the module-scope flag flips immediately so any later @@ -806,13 +823,7 @@ onMount(() => { localStorage.removeItem(RECOVERY_SKIP_PROFILE_SETUP_KEY); } - const currentHour = new Date().getHours(); - greeting = - currentHour > 17 - ? "Good Evening" - : currentHour > 12 - ? "Good Afternoon" - : "Good Morning"; + greetingHour = new Date().getHours(); (async () => { let gs = getGlobalState(); @@ -925,10 +936,9 @@ async function refreshBindings(): Promise { {#if profileCreationStatus === "loading" && !skipProfileSetupGate}
-

Setting up your eVault profile

+

{m.main_profile_setup_title()}

- We're creating your profile in the eVault. This may take a few - moments... + {m.main_profile_setup_body()}

{:else if profileCreationStatus === "failed"} @@ -937,18 +947,17 @@ async function refreshBindings(): Promise { >

- Profile Setup Failed + {m.main_profile_failed_title()}

- We couldn't set up your eVault profile. This might be due to a - network issue or temporary service unavailability. + {m.main_profile_failed_body()}

- Try Again + {m.common_try_again()}
@@ -1085,7 +1094,7 @@ async function refreshBindings(): Promise { : { duration: 0 }} > (eVaultInfoOpen = true)} /> @@ -1162,7 +1171,7 @@ async function refreshBindings(): Promise { onsave={handleEditNameSave} /> - + {#snippet body()} { class="w-full h-auto rounded-2xl shrink-0" aria-hidden="true" /> -

- eVault is your sovereign and secure storage. It holds all your - data: photos, documents, social media posts, messages to friends, - and more. Since your data is now stored by you, not platforms, you - can easily switch between services. -

-

- For example, if you don't like one messenger, simply switch to - another, and all your messages, chats, and friends will still be - there, because your data is stored with you, and the app only gets - temporary permission to access it. -

+

{m.info_evault_p1()}

+

{m.info_evault_p2()}

{/snippet}
- + {#snippet body()} -

- Link binding documents to strengthen the connection between your - Digital and Real Selves. Upload verifiable artifacts to your eVault, - such as official documents, photos, or confirmations from friends - and family, so you can prove ownership of your eVault if needed. -

+

{m.info_binding_p1()}

-

Why it's important:

-

- Unlike the usual Web 2.0 approach, where platforms make you create - an account and upload your data to them, in W3DS, you have your own - sovereign account — your Digital Self — and you control who can - access your data. With sovereignty comes responsibility. -

-

- By default, your Digital Self is tied to your Real Self via the eID - App, so if anything happens to your phone, you may lose control over - your data. However, if your personal artifacts — documents, photos, - and social confirmations — are stored in your eVault, you can prove - ownership of your Digital Self and regain control over your data. -

+

{m.info_binding_why()}

+

{m.info_binding_p2()}

+

{m.info_binding_p3()}

{/snippet}
@@ -1220,10 +1203,9 @@ async function refreshBindings(): Promise { localStorage so it never re-appears on this device. -->
-

Stay in the loop

+

{m.notif_prompt_title()}

- Get notified about new messages, signing requests, and activity on - your eVault. + {m.notif_prompt_body()}

@@ -1235,7 +1217,7 @@ async function refreshBindings(): Promise { callback={handleNotifAllow} blockingClick > - Allow notifications + {m.notifications_allow()} { disabled={notifBusy} callback={handleNotifSkip} > - Not now + {m.notif_prompt_not_now()}
diff --git a/infrastructure/eid-wallet/src/routes/(app)/main/components/AppsMarketplace.svelte b/infrastructure/eid-wallet/src/routes/(app)/main/components/AppsMarketplace.svelte index 9b01c797a..a484bbb12 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/main/components/AppsMarketplace.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/main/components/AppsMarketplace.svelte @@ -1,10 +1,11 @@
-

Your eName

+

{m.main_ename_title()}

{#if verified} - Verified ID + {m.main_ename_verified()} {:else} - Unverified ID + {m.main_ename_unverified()} {/if}
@@ -55,10 +56,10 @@ async function copyEName() {

- {ename ?? "Loading..."}

@@ -474,21 +474,18 @@ async function handleUpgrade() { > ! -

Identity Already Registered

+

{m.kyc_duplicate_title()}

- This identity document is already linked to an existing eVault. - You can't create a duplicate — each person gets one verified - eVault. + {m.kyc_duplicate_body()}

{#if duplicateEName}

- Use the eName above to recover access to your existing - eVault instead. + {m.kyc_duplicate_hint()}

{/if}
@@ -497,7 +494,7 @@ async function handleUpgrade() { class="w-full" callback={resetKyc} > - Got it + {m.tour_cta_got_it()}
@@ -524,15 +521,14 @@ async function handleUpgrade() { > ✓ -

Identity Verified

+

{m.onboarding_result_verified_title()}

- Your identity has been verified. Your eVault trust level - will now be upgraded. + {m.kyc_result_verified_body()}

- Continue + {m.common_continue()}
{:else if diditResult === "in_review"} @@ -542,11 +538,10 @@ async function handleUpgrade() { > ⏳ -

Under Review

+

{m.onboarding_result_review_title()}

- Your verification is being manually reviewed. You'll be - notified when it's complete. + {m.kyc_result_review_body()}

- Close + {m.common_close()}
{:else} @@ -564,22 +559,21 @@ async function handleUpgrade() { > ✗ -

Verification Failed

+

{m.onboarding_result_failed_title()}

- {diditRejectionReason ?? - "Your verification could not be completed."} + {diditRejectionReason ?? m.onboarding_result_failed_body()}

- Try Again + {m.common_try_again()} - Cancel + {m.common_cancel()}
{/if} diff --git a/infrastructure/eid-wallet/src/routes/(app)/notifications/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/notifications/+page.svelte index 69f7e5c13..e238612d1 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/notifications/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/notifications/+page.svelte @@ -1,6 +1,8 @@ - + {#if notifications.length > 0}
{/if} {#if !loaded}
-

Loading...

+

{m.common_loading()}

{:else if notifications.length === 0}
-

No notifications

-

You're all caught up

+

{m.notif_empty_title()}

+

{m.notif_empty_body()}

{:else}
diff --git a/infrastructure/eid-wallet/src/routes/(app)/personal/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/personal/+page.svelte index c11f37ac8..503720682 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/personal/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/personal/+page.svelte @@ -1,6 +1,7 @@ {sheetTitle} - Description + {m.photo_description_label()} {#if description.length > PERSONAL_BINDING_MAX_LENGTH - 150} @@ -248,7 +251,7 @@ const sheetTitle = $derived(editing ? "Edit photo mark" : "Add photo mark");
{:else if mode === "capture"}
-

Taken from camera

+

{m.photo_taken_from_camera()}

- Capture + {m.photo_capture()}
{:else if mode === "preview" && pendingDataUrl}

{pendingSource === "camera" - ? "Taken from camera" - : "Picked from gallery"} + ? m.photo_taken_from_camera() + : m.photo_picked_from_gallery()}

@@ -279,7 +282,7 @@ const sheetTitle = $derived(editing ? "Edit photo mark" : "Add photo mark"); />
- Save + {m.common_save()}
{/if} @@ -321,6 +324,6 @@ const sheetTitle = $derived(editing ? "Edit photo mark" : "Add photo mark"); diff --git a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte index 0467e5d4d..6ca9c6f32 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte @@ -2,6 +2,7 @@ import { goto } from "$app/navigation"; import AppNav from "$lib/fragments/AppNav/AppNav.svelte"; import type { GlobalState } from "$lib/global"; +import { m } from "$lib/paraglide/messages"; import { getContext, onDestroy, onMount } from "svelte"; import type { SVGAttributes } from "svelte/elements"; import { get } from "svelte/store"; @@ -168,7 +169,7 @@ function handleSocialBindingOpenChange(value: boolean) { } - +

- Point the camera at the code + {m.scan_hint()}

diff --git a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/components/AuthDrawer.svelte b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/components/AuthDrawer.svelte index 337cdfb1f..dd499acb4 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/components/AuthDrawer.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/components/AuthDrawer.svelte @@ -1,4 +1,5 @@ @@ -102,7 +103,7 @@ const subtitle = $derived( type="button" onclick={onDecline} disabled={loading} - aria-label="Close" + aria-label={m.common_close()} class="w-9 h-9 rounded-full bg-gray-100 text-black-700 flex items-center justify-center active:opacity-80 disabled:opacity-40" > - Poll ID + {m.vote_poll_id_label()}
- Poll Title + {m.signing_poll_title_label()}
- Message + {m.signing_message_label()}
- Session Id + {m.signing_session_id_label()}
- Select Option + {m.signing_select_option()} {#each signingData?.pollDetails?.options || [] as option, index}
-

Recovery Passphrase {hasExistingPassphrase ? "Updated" : "Set"}!

+

+ {hasExistingPassphrase + ? m.passphrase_success_title_updated() + : m.passphrase_success_title_set()} +

- Your recovery passphrase has been securely stored. You will need it when recovering your eVault. + {m.passphrase_success_body()}

- Done + {m.common_done()} diff --git a/infrastructure/eid-wallet/src/routes/(app)/settings/pin/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/settings/pin/+page.svelte index 520937d3e..5c9aa1123 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/settings/pin/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/settings/pin/+page.svelte @@ -3,6 +3,7 @@ import { goto } from "$app/navigation"; import { keyboardInset } from "$lib/actions/keyboardInset"; import type { GlobalState } from "$lib/global"; import { runtime } from "$lib/global/runtime.svelte"; +import { m } from "$lib/paraglide/messages"; import { BottomSheet, ButtonAction, PinDots } from "$lib/ui"; import { CheckmarkCircle02Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/svelte"; @@ -26,10 +27,10 @@ const canSubmit = $derived(stepPin.length === 4); const stepTitle = $derived( step === "current" - ? "Enter your current PIN" + ? m.pin_step_current() : step === "new" - ? "Enter your new PIN" - : "Confirm your new PIN", + ? m.pin_step_new() + : m.pin_step_repeat(), ); async function advance() { @@ -42,21 +43,21 @@ async function advance() { const ok = await globalState.securityController.verifyPin(currentPin); if (!ok) { - error = "That's not your current PIN. Try again."; + error = m.pin_error_wrong_current(); currentPin = ""; return; } step = "new"; } catch (err) { console.error("Failed to verify current PIN:", err); - error = "Couldn't verify your current PIN. Try again."; + error = m.pin_error_verify_failed(); currentPin = ""; } finally { submitting = false; } } else if (step === "new") { if (newPin === currentPin) { - error = "Your new PIN must be different from your current PIN."; + error = m.pin_error_must_differ(); newPin = ""; return; } @@ -69,7 +70,7 @@ async function advance() { async function submit() { if (!globalState) return; if (repeatPin !== newPin) { - error = "PIN codes don't match. Try again."; + error = m.pin_error_mismatch(); repeatPin = ""; return; } @@ -84,8 +85,7 @@ async function submit() { } catch (err) { console.error("Failed to update PIN:", err); // Most failures here are wrong-current-PIN — bounce back to step 1. - error = - "Couldn't update your PIN. Check your current PIN and try again."; + error = m.pin_error_update_failed(); step = "current"; currentPin = ""; newPin = ""; @@ -114,7 +114,7 @@ $effect(() => { }); $effect(() => { - runtime.header.title = "Change PIN"; + runtime.header.title = m.pin_change_title(); // Step-aware back: walk back through internal steps before leaving the page. runtime.header.onback = () => { error = null; @@ -172,7 +172,7 @@ onMount(() => { callback={advance} blockingClick={step !== "new"} > - {step === "repeat" ? "Change PIN" : "Next"} + {step === "repeat" ? m.pin_change_title() : m.common_next()} @@ -203,16 +203,16 @@ onMount(() => { />
-

PIN code changed

+

{m.pin_success_title()}

- Your new PIN is now active. Use it the next time you sign in. + {m.pin_success_body()}

- Done + {m.common_done()} diff --git a/infrastructure/eid-wallet/src/routes/(app)/settings/privacy/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/settings/privacy/+page.svelte index 6133a2c22..7893ec226 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/settings/privacy/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/settings/privacy/+page.svelte @@ -1,8 +1,9 @@ diff --git a/infrastructure/eid-wallet/src/routes/(app)/social-bindings/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/social-bindings/+page.svelte index 5e82bee2c..164a068c0 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/social-bindings/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/social-bindings/+page.svelte @@ -1,6 +1,7 @@ - + {#if !loaded}
-

Loading…

+

{m.common_loading()}

{:else if contacts.length === 0}
-

No social bindings yet

+

{m.social_bindings_empty_title()}

- Invite a contact from your eName card. + {m.social_bindings_empty_body()}

{:else} @@ -160,7 +161,7 @@ const subtitle = $derived( {roleLabel(contact.role)} {#if contact.pending} · Awaiting confirmation{m.social_details_awaiting_suffix()} {/if}

diff --git a/infrastructure/eid-wallet/src/routes/(auth)/+layout.svelte b/infrastructure/eid-wallet/src/routes/(auth)/+layout.svelte index bbbc612f4..36863a451 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/+layout.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/+layout.svelte @@ -2,6 +2,7 @@ import { goto } from "$app/navigation"; import { page } from "$app/state"; import type { GlobalState } from "$lib/global"; +import { m } from "$lib/paraglide/messages"; import { getContext, onMount } from "svelte"; let { children } = $props(); @@ -82,7 +83,7 @@ onMount(async () => { class="flex h-screen w-screen items-center justify-center bg-background" >

- An unexpected error occurred. Please restart the application. + {m.auth_guard_error()}

{:else if !vaultExists} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/login/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/login/+page.svelte index 724448e3b..26985c8f6 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/login/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/login/+page.svelte @@ -2,6 +2,7 @@ import { goto } from "$app/navigation"; import { keyboardInset } from "$lib/actions/keyboardInset"; import type { GlobalState } from "$lib/global"; +import { m } from "$lib/paraglide/messages"; import { LoadingSheet, PinDots } from "$lib/ui"; import * as Button from "$lib/ui/Button"; import { continueAfterSuccessfulAuth } from "$lib/utils/postLogin"; @@ -38,12 +39,12 @@ let globalState: GlobalState | undefined = $state(undefined); const authOpts: AuthOptions = { allowDeviceCredential: false, - cancelTitle: "Cancel", + cancelTitle: m.common_cancel(), // iOS - fallbackTitle: "Please enter your PIN", + fallbackTitle: m.login_biometric_fallback(), // Android - title: "Login", - subtitle: "Please authenticate to continue", + title: m.login_biometric_title(), + subtitle: m.login_biometric_subtitle(), confirmationRequired: true, }; @@ -119,10 +120,7 @@ onMount(async () => { (await checkStatus()).isAvailable ) { try { - await authenticate( - "You must authenticate with PIN first", - authOpts, - ); + await authenticate(m.login_biometric_reason(), authOpts); isPostAuthLoading = true; await continueAfterSuccessfulAuth(gs); } catch (e) { @@ -145,15 +143,15 @@ onMount(async () => { class="h-dvh overflow-hidden px-[5vw] flex flex-col bg-white" style="padding-top: max(2svh, env(safe-area-inset-top)); padding-bottom: calc(max(16px, env(safe-area-inset-bottom)) + var(--kb-inset, 0px));" > - + {#if hasPendingDeepLink && !isPostAuthLoading}
- Authentication request pending. - Sign in to continue. + {m.login_deeplink_pending_title()} + {m.login_deeplink_pending_body()}
{/if} @@ -163,11 +161,11 @@ onMount(async () => { {#if isError}

- Forgot your pin? Recover your eVault.{m.login_recover_link()}

@@ -180,7 +178,7 @@ onMount(async () => { class="w-full uppercase tracking-wide" callback={clearPin} > - Clear PIN + {m.login_clear_pin()} @@ -189,6 +187,6 @@ onMount(async () => { user has visual context for the step they just completed. --> diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 293f9d0ad..91492d263 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -8,6 +8,7 @@ import { } from "$env/static/public"; import { Hero } from "$lib/fragments"; import { GlobalState } from "$lib/global"; +import { m } from "$lib/paraglide/messages"; import { pendingRecovery } from "$lib/stores/pendingRecovery"; import { ButtonAction, CopyableEName, LoadingSheet } from "$lib/ui"; import { capitalize, getCanonicalBindingDocString } from "$lib/utils"; @@ -93,35 +94,33 @@ let loadingPhase = $state(null); const loadingCopy = $derived( loadingPhase === "creating-evault" ? { - title: "Creating your eVault", - subtitle: - "Generating your eName and signing your binding document.", + title: m.onboarding_loading_creating_title(), + subtitle: m.onboarding_loading_creating_subtitle(), } : loadingPhase === "restoring-evault" ? { - title: "Restoring your eVault", - subtitle: "Loading your identity onto this device.", + title: m.onboarding_loading_restoring_title(), + subtitle: m.onboarding_loading_restoring_subtitle(), } : loadingPhase === "starting-verification" ? { - title: "Starting verification", - subtitle: "Opening a secure session with our ID partner.", + title: m.onboarding_loading_verification_title(), + subtitle: m.onboarding_loading_verification_subtitle(), } : loadingPhase === "fetching-decision" ? { - title: "Checking your verification", - subtitle: "Hang tight — we're confirming your result.", + title: m.onboarding_loading_decision_title(), + subtitle: m.onboarding_loading_decision_subtitle(), } : loadingPhase === "upgrading" ? { - title: "Upgrading your eVault", - subtitle: - "Linking your verified identity to your eVault.", + title: m.onboarding_loading_upgrading_title(), + subtitle: m.onboarding_loading_upgrading_subtitle(), } : loadingPhase === "checking-hardware" ? { - title: "Checking your device", - subtitle: "Looking for hardware-backed key support.", + title: m.onboarding_loading_hardware_title(), + subtitle: m.onboarding_loading_hardware_subtitle(), } : { title: "", subtitle: "" }, ); @@ -252,7 +251,7 @@ const advancePastBiometrics = async () => { const completeRecovery = async () => { const recovery = get(pendingRecovery); if (!recovery) { - recoveryError = "Recovery data lost. Please start recovery again."; + recoveryError = m.onboarding_recovery_lost(); return; } loadingPhase = "restoring-evault"; @@ -269,8 +268,7 @@ const completeRecovery = async () => { await goto("/main", { replaceState: true }); } catch (err) { console.error("[onboarding] recovery completion failed:", err); - recoveryError = - "Couldn't restore your eVault. Check your connection and try again."; + recoveryError = m.onboarding_recovery_failed(); loadingPhase = null; } }; @@ -386,8 +384,7 @@ const handleNameComplete = async (enteredName: string) => { await goto("/main", { replaceState: true }); } catch (err) { console.error("Failed to provision eVault:", err); - nameError = - "Couldn't create your eVault. Check your connection and try again."; + nameError = m.onboarding_provision_failed(); loadingPhase = null; } }; @@ -501,7 +498,7 @@ const handleKycNext = async () => { error = err instanceof Error ? err.message - : "Failed to start verification. Please try again."; + : m.onboarding_kyc_start_failed(); loadingPhase = null; setTimeout(() => { error = null; @@ -518,7 +515,7 @@ const handleDiditComplete = async (result: DiditCompleteResult) => { } if (!result.session?.sessionId) { - error = "Verification did not return a session ID."; + error = m.onboarding_kyc_no_session(); step = "kyc-panel"; return; } @@ -554,14 +551,14 @@ const handleDiditComplete = async (result: DiditCompleteResult) => { decision.reviews?.[0]?.comment ?? decision.id_verifications?.[0]?.warnings?.[0] ?.short_description ?? - "Verification could not be completed."; + m.onboarding_kyc_incomplete(); } loadingPhase = null; step = "verif-result"; } catch (err) { console.error("Failed to fetch Didit decision:", err); - error = "Failed to retrieve verification result. Please try again."; + error = m.onboarding_kyc_decision_failed(); loadingPhase = null; step = "kyc-panel"; setTimeout(() => { @@ -642,20 +639,17 @@ const handleProvision = async () => { if (result.duplicate) { await lookupDuplicateByDocument(); diditResult = "duplicate"; - error = - "An eVault already exists for this identity. You cannot create a duplicate — please reclaim your existing eVault instead."; + error = m.onboarding_duplicate_error(); loadingPhase = null; step = "verif-result"; return; } if (!result.success) { - throw new Error("Provisioning failed"); + throw new Error(m.onboarding_provisioning_failed()); } if (!result.uri || !result.w3id) { - throw new Error( - "Provisioning succeeded but did not return uri/w3id", - ); + throw new Error(m.onboarding_provisioning_no_ids()); } await globalState.vaultController.setVaultAndPersist({ @@ -670,7 +664,7 @@ const handleProvision = async () => { error = err instanceof Error ? err.message - : "We couldn’t create your eVault after identity verification. Check your connection, then tap Continue again."; + : m.onboarding_provision_after_kyc_failed(); loadingPhase = null; step = "verif-result"; setTimeout(() => { @@ -683,7 +677,7 @@ const handleProvision = async () => { const handleAnonymousSubmit = async () => { if (!anonName.trim()) { - error = "Please enter your name."; + error = m.onboarding_name_required(); setTimeout(() => { error = null; }, 4000); @@ -720,7 +714,7 @@ const handleAnonymousSubmit = async () => { "[Onboarding] Missing w3id/uri from anonymous provision result:", provisionResult, ); - error = "Provisioning response is incomplete. Please try again."; + error = m.onboarding_provision_incomplete(); loadingPhase = null; step = "anonymous-form"; return; @@ -809,8 +803,7 @@ const handleAnonymousSubmit = async () => { await goto("/main", { replaceState: true }); } catch (err) { console.error("Anonymous provisioning failed:", err); - error = - "We couldn’t create your self-declared eVault. Check your connection, then tap Confirm & Create again."; + error = m.onboarding_anonymous_provision_failed(); loadingPhase = null; step = "anonymous-form"; setTimeout(() => { @@ -824,7 +817,7 @@ const handleUpgrade = async () => { const vault = await globalState.vaultController.vault; const w3id = vault?.ename; if (!w3id) { - error = "No active eVault found for upgrade."; + error = m.onboarding_upgrade_no_vault(); return; } @@ -833,7 +826,7 @@ const handleUpgrade = async () => { diditDecision.session_id ?? diditDecision.session?.sessionId; if (!sessionId) { - error = "Missing session ID from verification result."; + error = m.kyc_missing_session_id(); return; } @@ -852,16 +845,14 @@ const handleUpgrade = async () => { }, ); if (!data.success) { - throw new Error(data.message ?? "Upgrade failed"); + throw new Error(data.message ?? m.kyc_upgrade_failed_short()); } loadingPhase = null; goto("/ePassport"); } catch (err) { console.error("[Upgrade] failed:", err); error = - err instanceof Error - ? err.message - : "Upgrade failed. Please try again."; + err instanceof Error ? err.message : m.onboarding_upgrade_failed(); loadingPhase = null; step = "verif-result"; setTimeout(() => { @@ -972,19 +963,19 @@ onMount(async () => {
{#snippet subtitle()} - Your Digital Self consists of three core elements:
- eName – your unique, permanent digital - identifier, a number + {m.onboarding_hero_intro()}
+ eName + {m.onboarding_hero_ename()}
- ePassport – your cryptographic keys, - enabling your agency and control + ePassport + {m.onboarding_hero_epassport()}
- eVault – the secure repository of all your - personal data. You will decide who can access it, and how. + eVault + {m.onboarding_hero_evault()}
{/snippet} - Your Digital Self
-

in Web 3.0 Data Space

+ {m.onboarding_hero_title()}
+

{m.onboarding_hero_subtitle()}

@@ -995,31 +986,31 @@ onMount(async () => { step = "new-evault"; }} > - Create Digital Self + {m.onboarding_create_cta()} goto("/recover")} > - Restore my Digital Self + {m.onboarding_restore_cta()}

- By continuing you agree to our
+ {m.onboarding_terms_prefix()}
Terms & Conditions{m.onboarding_terms_link()} - and + {m.common_and()} Privacy Policy.{m.onboarding_privacy_link()}

@@ -1028,9 +1019,9 @@ onMount(async () => { {:else if step === "new-evault"}
-

Create your Digital Self

+

{m.onboarding_new_title()}

- Choose how you want to prove it’s you. + {m.onboarding_new_subtitle()}

@@ -1039,12 +1030,10 @@ onMount(async () => { class="w-full rounded-2xl border border-gray-200 bg-gray-50 p-5 text-left hover:bg-gray-100 transition-colors active:bg-gray-200" >

- Verify with an official ID + {m.onboarding_path_verified_title()}

- Use a real-world ID to bind your Digital Self to you. - This gives the strongest proof and makes recovery - easier. + {m.onboarding_path_verified_body()}

@@ -1070,7 +1058,7 @@ onMount(async () => { step = "home"; }} > - Back + {m.common_back()} @@ -1078,12 +1066,10 @@ onMount(async () => {

- Self-declare your identity for now + {m.onboarding_anon_title()}

- Add your full name. Others will see it as unverified until - you support this claim with an official ID or social - binding. + {m.onboarding_anon_body()}

@@ -1100,21 +1086,23 @@ onMount(async () => { class="text-black-700 font-medium text-sm" for="anonName" > - Full Name * + {m.onboarding_anon_name_label()} *
{ class="border border-gray-200 w-full rounded-md font-medium my-1 p-3 bg-gray-50 focus:bg-white transition-colors" />

- Stored on your device only — not included in the signed - statement. + {m.onboarding_anon_dob_hint()}

- By continuing, I confirm this is my name and I control this - Digital Self. This statement will be cryptographically - signed and stored as a binding document on your eVault. + {m.onboarding_anon_consent()}

@@ -1144,7 +1129,7 @@ onMount(async () => { class="w-full" callback={handleAnonymousSubmit} > - Confirm & Create + {m.onboarding_anon_submit()} { error = null; }} > - Back + {m.common_back()} @@ -1185,27 +1170,20 @@ onMount(async () => { {#if showHardwareError}

- Hardware Security Not Available + {m.onboarding_hardware_error_title()}

- Your phone doesn't support hardware crypto keys, which - is a requirement for verified IDs. + {m.onboarding_hardware_error_body()}

- Please use the anonymous option to create an eVault - instead. + {m.onboarding_hardware_error_hint()}

{:else}

- Your Digital Self begins with the Real You + {m.onboarding_kyc_title()}

- In the Web 3.0 Data Space, identity is linked to - reality. We begin by verifying your real-world passport, - which serves as the foundation for issuing your secure - ePassport. At the same time, we generate your eName – a - unique digital identifier – and create your eVault to - store and protect your personal data. + {m.onboarding_kyc_body()}

{/if} @@ -1221,14 +1199,14 @@ onMount(async () => { error = null; }} > - Go Anonymous + {m.onboarding_go_anonymous()} {:else} - Next + {m.common_next()} {/if} { } }} > - Back + {m.common_back()} {/if} @@ -1269,7 +1247,7 @@ onMount(async () => { } }} > - Cancel + {m.common_cancel()}
@@ -1298,19 +1276,19 @@ onMount(async () => { > ✓ -

Identity Verified

+

{m.onboarding_result_verified_title()}

{upgradeMode - ? "Your identity has been verified. Your eVault trust level will now be upgraded." - : "Your identity has been successfully verified. You can now create your eVault."} + ? m.onboarding_result_verified_upgrade_body() + : m.onboarding_result_verified_body()}

- Continue + {m.common_continue()}
{:else if diditResult === "in_review"} @@ -1320,11 +1298,10 @@ onMount(async () => { > ⏳ -

Under Review

+

{m.onboarding_result_review_title()}

- Your verification is being manually reviewed. You'll be notified - when it's complete. + {m.onboarding_result_review_body()}

{ else step = "home"; }} > - {upgradeMode ? "Back to ePassport" : "Back to Start"} + {upgradeMode + ? m.onboarding_back_to_epassport() + : m.onboarding_back_to_start()}
{:else if diditResult === "duplicate"} @@ -1345,15 +1324,16 @@ onMount(async () => { > ! -

Identity Already Registered

+

+ {m.onboarding_result_duplicate_title()} +

- This identity document is already linked to an existing eVault. - Please recover that eVault instead of creating a duplicate. + {m.onboarding_result_duplicate_body()}

{#if duplicateDocumentNumber}

- Document: {duplicateDocumentNumber}

@@ -1361,12 +1341,12 @@ onMount(async () => { {#if duplicateExistingW3id} {/if}
goto("/recover")}> - Recover existing eVault + {m.onboarding_recover_existing()} { step = "home"; }} > - Back to Start + {m.onboarding_back_to_start()}
{:else} @@ -1385,19 +1365,18 @@ onMount(async () => { > ✗ -

Verification Failed

+

{m.onboarding_result_failed_title()}

- {diditRejectionReason ?? - "Your verification could not be completed."} + {diditRejectionReason ?? m.onboarding_result_failed_body()}

- If you believe this was a mistake, please contact us at + {m.onboarding_result_failed_contact()} info@metastate.foundation.

- Try Again + {m.common_try_again()} {#if !upgradeMode} { step = "anonymous-form"; }} > - Self-declare instead + {m.onboarding_self_declare_instead()} {/if} { else step = "home"; }} > - Back + {m.common_back()}
{/if} diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/steps/BiometricsSetup.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/steps/BiometricsSetup.svelte index 2ded884e3..28055c76b 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/steps/BiometricsSetup.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/steps/BiometricsSetup.svelte @@ -1,5 +1,6 @@