diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..116d6852 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "inlang.vs-code-extension" + ] +} \ No newline at end of file diff --git a/backend/internal/dto/user_dto.go b/backend/internal/dto/user_dto.go index edce7790..82a7d555 100644 --- a/backend/internal/dto/user_dto.go +++ b/backend/internal/dto/user_dto.go @@ -9,18 +9,20 @@ type UserDto struct { FirstName string `json:"firstName"` LastName string `json:"lastName"` IsAdmin bool `json:"isAdmin"` + Locale *string `json:"locale"` CustomClaims []CustomClaimDto `json:"customClaims"` UserGroups []UserGroupDto `json:"userGroups"` LdapID *string `json:"ldapId"` } type UserCreateDto struct { - Username string `json:"username" binding:"required,username,min=2,max=50"` - Email string `json:"email" binding:"required,email"` - FirstName string `json:"firstName" binding:"required,min=1,max=50"` - LastName string `json:"lastName" binding:"required,min=1,max=50"` - IsAdmin bool `json:"isAdmin"` - LdapID string `json:"-"` + Username string `json:"username" binding:"required,username,min=2,max=50"` + Email string `json:"email" binding:"required,email"` + FirstName string `json:"firstName" binding:"required,min=1,max=50"` + LastName string `json:"lastName" binding:"required,min=1,max=50"` + IsAdmin bool `json:"isAdmin"` + Locale *string `json:"locale"` + LdapID string `json:"-"` } type OneTimeAccessTokenCreateDto struct { diff --git a/backend/internal/model/user.go b/backend/internal/model/user.go index 92043891..a2251b66 100644 --- a/backend/internal/model/user.go +++ b/backend/internal/model/user.go @@ -14,6 +14,7 @@ type User struct { FirstName string `sortable:"true"` LastName string `sortable:"true"` IsAdmin bool `sortable:"true"` + Locale *string LdapID *string CustomClaims []CustomClaim diff --git a/backend/internal/service/user_service.go b/backend/internal/service/user_service.go index 42507bba..8c63c260 100644 --- a/backend/internal/service/user_service.go +++ b/backend/internal/service/user_service.go @@ -153,6 +153,7 @@ func (s *UserService) CreateUser(input dto.UserCreateDto) (model.User, error) { Email: input.Email, Username: input.Username, IsAdmin: input.IsAdmin, + Locale: input.Locale, } if input.LdapID != "" { user.LdapID = &input.LdapID @@ -182,6 +183,7 @@ func (s *UserService) UpdateUser(userID string, updatedUser dto.UserCreateDto, u user.LastName = updatedUser.LastName user.Email = updatedUser.Email user.Username = updatedUser.Username + user.Locale = updatedUser.Locale if !updateOwnUser { user.IsAdmin = updatedUser.IsAdmin } diff --git a/backend/resources/migrations/postgres/20250320171311_user_locale.down.sql b/backend/resources/migrations/postgres/20250320171311_user_locale.down.sql new file mode 100644 index 00000000..6686c139 --- /dev/null +++ b/backend/resources/migrations/postgres/20250320171311_user_locale.down.sql @@ -0,0 +1 @@ +ALTER TABLE users DROP COLUMN locale; \ No newline at end of file diff --git a/backend/resources/migrations/postgres/20250320171311_user_locale.up.sql b/backend/resources/migrations/postgres/20250320171311_user_locale.up.sql new file mode 100644 index 00000000..99644e0c --- /dev/null +++ b/backend/resources/migrations/postgres/20250320171311_user_locale.up.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD COLUMN locale TEXT; \ No newline at end of file diff --git a/backend/resources/migrations/sqlite/20250320171311_user_locale.down.sql b/backend/resources/migrations/sqlite/20250320171311_user_locale.down.sql new file mode 100644 index 00000000..6686c139 --- /dev/null +++ b/backend/resources/migrations/sqlite/20250320171311_user_locale.down.sql @@ -0,0 +1 @@ +ALTER TABLE users DROP COLUMN locale; \ No newline at end of file diff --git a/backend/resources/migrations/sqlite/20250320171311_user_locale.up.sql b/backend/resources/migrations/sqlite/20250320171311_user_locale.up.sql new file mode 100644 index 00000000..99644e0c --- /dev/null +++ b/backend/resources/migrations/sqlite/20250320171311_user_locale.up.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD COLUMN locale TEXT; \ No newline at end of file diff --git a/frontend/messages/en.json b/frontend/messages/en.json new file mode 100644 index 00000000..4cd4e4ab --- /dev/null +++ b/frontend/messages/en.json @@ -0,0 +1,318 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "my_account": "My Account", + "logout": "Logout", + "english": "English", + "dutch": "Nederlands", + "confirm": "Confirm", + "key": "Key", + "value": "Value", + "remove_custom_claim": "Remove custom claim", + "add_custom_claim": "Add custom claim", + "add_another": "Add another", + "select_a_date": "Select a date", + "select_file": "Select File", + "profile_picture": "Profile Picture", + "profile_picture_is_managed_by_ldap_server": "The profile picture is managed by the LDAP server and cannot be changed here.", + "click_profile_picture_to_upload_custom": "Click on the profile picture to upload a custom one from your files.", + "image_should_be_in_format": "The image should be in PNG or JPEG format.", + "items_per_page": "Items per page", + "no_items_found": "No items found", + "search": "Search...", + "expand_card": "Expand card", + "copied": "Copied", + "click_to_copy": "Click to copy", + "something_went_wrong": "Something went wrong", + "go_back_to_home": "Go back to home", + "dont_have_access_to_your_passkey": "Don't have access to your passkey?", + "login_background": "Login background", + "logo": "Logo", + "login_code": "Login Code", + "create_a_login_code_to_sign_in_without_a_passkey_once": "Create a login code that the user can use to sign in without a passkey once.", + "one_hour": "1 hour", + "twelve_hours": "12 hours", + "one_day": "1 day", + "one_week": "1 week", + "one_month": "1 month", + "expiration": "Expiration", + "generate_code": "Generate Code", + "name": "Name", + "browser_unsupported": "Browser unsupported", + "this_browser_does_not_support_passkeys": "This browser doesn't support passkeys. Please or use a alternative sign in method.", + "an_unknown_error_occurred": "An unknown error occurred", + "authentication_process_was_aborted": "The authentication process was aborted", + "error_occurred_with_authenticator": "An error occurred with the authenticator", + "authenticator_does_not_support_discoverable_credentials": "The authenticator does not support discoverable credentials", + "authenticator_does_not_support_resident_keys": "The authenticator does not support resident keys", + "passkey_was_previously_registered": "This passkey was previously registered", + "authenticator_does_not_support_any_of_the_requested_algorithms": "The authenticator does not support any of the requested algorithms", + "authenticator_timed_out": "The authenticator timed out", + "critical_error_occurred_contact_administrator": "A critical error occurred. Please contact your administrator.", + "sign_in_to": "Sign in to {name}", + "client_not_found": "Client not found", + "client_wants_to_access_the_following_information": "{client} wants to access the following information:", + "do_you_want_to_sign_in_to_client_with_your_app_name_account": "Do you want to sign in to {client} with your {appName} account?", + "email": "Email", + "view_your_email_address": "View your email address", + "profile": "Profile", + "view_your_profile_information": "View your profile information", + "groups": "Groups", + "view_the_groups_you_are_a_member_of": "View the groups you are a member of", + "cancel": "Cancel", + "sign_in": "Sign in", + "try_again": "Try again", + "client_logo": "Client Logo", + "sign_out": "Sign out", + "do_you_want_to_sign_out_of_pocketid_with_the_account": "Do you want to sign out of Pocket ID with the account {username}?", + "sign_in_to_appname": "Sign in to {appName}", + "please_try_to_sign_in_again": "Please try to sign in again.", + "authenticate_yourself_with_your_passkey_to_access_the_admin_panel": "Authenticate yourself with your passkey to access the admin panel.", + "authenticate": "Authenticate", + "appname_setup": "{appName} Setup", + "please_try_again": "Please try again.", + "you_are_about_to_sign_in_to_the_initial_admin_account": "You're about to sign in to the initial admin account. Anyone with this link can access the account until a passkey is added. Please set up a passkey as soon as possible to prevent unauthorized access.", + "continue": "Continue", + "alternative_sign_in": "Alternative Sign In", + "if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "If you dont't have access to your passkey, you can sign in using one of the following methods.", + "use_your_passkey_instead": "Use your passkey instead?", + "email_login": "Email Login", + "enter_a_login_code_to_sign_in": "Enter a login code to sign in.", + "request_a_login_code_via_email": "Request a login code via email.", + "go_back": "Go back", + "an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system": "An email has been sent to the provided email, if it exists in the system.", + "enter_code": "Enter code", + "enter_your_email_address_to_receive_an_email_with_a_login_code": "Enter your email address to receive an email with a login code.", + "your_email": "Your email", + "submit": "Submit", + "enter_the_code_you_received_to_sign_in": "Enter the code you received to sign in.", + "code": "Code", + "invalid_redirect_url": "Invalid redirect URL", + "audit_log": "Audit Log", + "users": "Users", + "user_groups": "User Groups", + "oidc_clients": "OIDC Clients", + "api_keys": "API Keys", + "application_configuration": "Application Configuration", + "settings": "Settings", + "update_pocket_id": "Update Pocket ID", + "powered_by": "Powered by", + "see_your_account_activities_from_the_last_3_months": "See your account activities from the last 3 months.", + "time": "Time", + "event": "Event", + "approximate_location": "Approximate Location", + "ip_address": "IP Address", + "device": "Device", + "client": "Client", + "unknown": "Unknown", + "account_details_updated_successfully": "Account details updated successfully", + "profile_picture_updated_successfully": "Profile picture updated successfully. It may take a few minutes to update.", + "account_settings": "Account Settings", + "passkey_missing": "Passkey missing", + "please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Please add a passkey to prevent losing access to your account.", + "single_passkey_configured": "Single Passkey Configured", + "it_is_recommended_to_add_more_than_one_passkey": "It is recommended to add more than one passkey to avoid losing access to your account.", + "account_details": "Account Details", + "passkeys": "Passkeys", + "manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Manage your passkeys that you can use to authenticate yourself.", + "add_passkey": "Add Passkey", + "create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Create a one-time login code to sign in from a different device without a passkey.", + "create": "Create", + "first_name": "First name", + "last_name": "Last name", + "username": "Username", + "save": "Save", + "username_can_only_contain": "Username can only contain lowercase letters, numbers, underscores, dots, hyphens, and '@' symbols", + "sign_in_using_the_following_code_the_code_will_expire_in_minutes": "Sign in using the following code. The code will expire in 15 minutes.", + "or_visit": "or visit", + "added_on": "Added on", + "rename": "Rename", + "delete": "Delete", + "are_you_sure_you_want_to_delete_this_passkey": "Are you sure you want to delete this passkey?", + "passkey_deleted_successfully": "Passkey deleted successfully", + "delete_passkey_name": "Delete {passkeyName}", + "passkey_name_updated_successfully": "Passkey name updated successfully", + "name_passkey": "Name Passkey", + "name_your_passkey_to_easily_identify_it_later": "Name your passkey to easily identify it later.", + "create_api_key": "Create API Key", + "add_a_new_api_key_for_programmatic_access": "Add a new API key for programmatic access.", + "add_api_key": "Add API Key", + "manage_api_keys": "Manage API Keys", + "api_key_created": "API Key Created", + "for_security_reasons_this_key_will_only_be_shown_once": "For security reasons, this key will only be shown once. Please store it securely.", + "description": "Description", + "api_key": "API Key", + "close": "Close", + "name_to_identify_this_api_key": "Name to identify this API key.", + "expires_at": "Expires At", + "when_this_api_key_will_expire": "When this API key will expire.", + "optional_description_to_help_identify_this_keys_purpose": "Optional description to help identify this key's purpose.", + "name_must_be_at_least_3_characters": "Name must be at least 3 characters", + "name_cannot_exceed_50_characters": "Name cannot exceed 50 characters", + "expiration_date_must_be_in_the_future": "Expiration date must be in the future", + "revoke_api_key": "Revoke API Key", + "never": "Never", + "revoke": "Revoke", + "api_key_revoked_successfully": "API key revoked successfully", + "are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Are you sure you want to revoke the API key \"{apiKeyName}\"? This will break any integrations using this key.", + "last_used": "Last Used", + "actions": "Actions", + "images_updated_successfully": "Images updated successfully", + "general": "General", + "enable_email_notifications_to_alert_users_when_a_login_is_detected_from_a_new_device_or_location": "Enable email notifications to alert users when a login is detected from a new device or location.", + "ldap": "LDAP", + "configure_ldap_settings_to_sync_users_and_groups_from_an_ldap_server": "Configure LDAP settings to sync users and groups from an LDAP server.", + "images": "Images", + "update": "Update", + "email_configuration_updated_successfully": "Email configuration updated successfully", + "save_changes_question": "Save changes?", + "you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "You have to save the changes before sending a test email. Do you want to save now?", + "save_and_send": "Save and send", + "test_email_sent_successfully": "Test email sent successfully to your email address.", + "failed_to_send_test_email": "Failed to send test email. Check the server logs for more information.", + "smtp_configuration": "SMTP Configuration", + "smtp_host": "SMTP Host", + "smtp_port": "SMTP Port", + "smtp_user": "SMTP User", + "smtp_password": "SMTP Password", + "smtp_from": "SMTP From", + "smtp_tls_option": "SMTP TLS Option", + "email_tls_option": "Email TLS Option", + "skip_certificate_verification": "Skip Certificate Verification", + "this_can_be_useful_for_selfsigned_certificates": "This can be useful for self-signed certificates.", + "enabled_emails": "Enabled Emails", + "email_login_notification": "Email Login Notification", + "send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Send an email to the user when they log in from a new device.", + "allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Allows users to sign in with a login code sent to their email. This reduces the security significantly as anyone with access to the user's email can gain entry.", + "send_test_email": "Send test email", + "application_configuration_updated_successfully": "Application configuration updated successfully", + "application_name": "Application Name", + "session_duration": "Session Duration", + "the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "The duration of a session in minutes before the user has to sign in again.", + "enable_self_account_editing": "Enable Self-Account Editing", + "whether_the_users_should_be_able_to_edit_their_own_account_details": "Whether the users should be able to edit their own account details.", + "emails_verified": "Emails Verified", + "whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Whether the user's email should be marked as verified for the OIDC clients.", + "ldap_configuration_updated_successfully": "LDAP configuration updated successfully", + "ldap_disabled_successfully": "LDAP disabled successfully", + "ldap_sync_finished": "LDAP sync finished", + "client_configuration": "Client Configuration", + "ldap_url": "LDAP URL", + "ldap_bind_dn": "LDAP Bind DN", + "ldap_bind_password": "LDAP Bind Password", + "ldap_base_dn": "LDAP Base DN", + "user_search_filter": "User Search Filter", + "the_search_filter_to_use_to_search_or_sync_users": "The Search filter to use to search/sync users.", + "groups_search_filter": "Groups Search Filter", + "the_search_filter_to_use_to_search_or_sync_groups": "The Search filter to use to search/sync groups.", + "attribute_mapping": "Attribute Mapping", + "user_unique_identifier_attribute": "User Unique Identifier Attribute", + "the_value_of_this_attribute_should_never_change": "The value of this attribute should never change.", + "username_attribute": "Username Attribute", + "user_mail_attribute": "User Mail Attribute", + "user_first_name_attribute": "User First Name Attribute", + "user_last_name_attribute": "User Last Name Attribute", + "user_profile_picture_attribute": "User Profile Picture Attribute", + "the_value_of_this_attribute_can_either_be_a_url_binary_or_base64_encoded_image": "The value of this attribute can either be a URL, a binary or a base64 encoded image.", + "group_members_attribute": "Group Members Attribute", + "the_attribute_to_use_for_querying_members_of_a_group": "The attribute to use for querying members of a group.", + "group_unique_identifier_attribute": "Group Unique Identifier Attribute", + "group_name_attribute": "Group Name Attribute", + "admin_group_name": "Admin Group Name", + "members_of_this_group_will_have_admin_privileges_in_pocketid": "Members of this group will have Admin Privileges in Pocket ID.", + "disable": "Disable", + "sync_now": "Sync now", + "enable": "Enable", + "user_created_successfully": "User created successfully", + "create_user": "Create User", + "add_a_new_user_to_appname": "Add a new user to {appName}", + "add_user": "Add User", + "manage_users": "Manage Users", + "admin_privileges": "Admin Privileges", + "admins_have_full_access_to_the_admin_panel": "Admins have full access to the admin panel.", + "delete_firstname_lastname": "Delete {firstName} {lastName}", + "are_you_sure_you_want_to_delete_this_user": "Are you sure you want to delete this user?", + "user_deleted_successfully": "User deleted successfully", + "role": "Role", + "source": "Source", + "admin": "Admin", + "user": "User", + "local": "Local", + "toggle_menu": "Toggle menu", + "edit": "Edit", + "user_groups_updated_successfully": "User groups updated successfully", + "user_updated_successfully": "User updated successfully", + "custom_claims_updated_successfully": "Custom claims updated successfully", + "back": "Back", + "user_details_firstname_lastname": "User Details {firstName} {lastName}", + "manage_which_groups_this_user_belongs_to": "Manage which groups this user belongs to.", + "custom_claims": "Custom Claims", + "custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested.", + "user_group_created_successfully": "User group created successfully", + "create_user_group": "Create User Group", + "create_a_new_group_that_can_be_assigned_to_users": "Create a new group that can be assigned to users.", + "add_group": "Add Group", + "manage_user_groups": "Manage User Groups", + "friendly_name": "Friendly Name", + "name_that_will_be_displayed_in_the_ui": "Name that will be displayed in the UI", + "name_that_will_be_in_the_groups_claim": "Name that will be in the \"groups\" claim", + "delete_name": "Delete {name}", + "are_you_sure_you_want_to_delete_this_user_group": "Are you sure you want to delete this user group?", + "user_group_deleted_successfully": "User group deleted successfully", + "user_count": "User Count", + "user_group_updated_successfully": "User group updated successfully", + "users_updated_successfully": "Users updated successfully", + "user_group_details_name": "User Group Details {name}", + "assign_users_to_this_group": "Assign users to this group.", + "custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user_prioritized": "Custom claims are key-value pairs that can be used to store additional information about a user. These claims will be included in the ID token if the scope 'profile' is requested. Custom claims defined on the user will be prioritized if there are conflicts.", + "oidc_client_created_successfully": "OIDC client created successfully", + "create_oidc_client": "Create OIDC Client", + "add_a_new_oidc_client_to_appname": "Add a new OIDC client to {appName}.", + "add_oidc_client": "Add OIDC Client", + "manage_oidc_clients": "Manage OIDC Clients", + "one_time_link": "One Time Link", + "use_this_link_to_sign_in_once": "Use this link to sign in once. This is needed for users who haven't added a passkey yet or\n\t\t\t\thave lost it.", + "add": "Add", + "callback_urls": "Callback URLs", + "logout_callback_urls": "Logout Callback URLs", + "public_client": "Public Client", + "public_clients_do_not_have_a_client_secret_and_use_pkce_instead": "Public clients do not have a client secret and use PKCE instead. Enable this if your client is a SPA or mobile app.", + "pkce": "PKCE", + "public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange is a security feature to prevent CSRF and authorization code interception attacks.", + "name_logo": "{name} logo", + "change_logo": "Change Logo", + "upload_logo": "Upload Logo", + "remove_logo": "Remove Logo", + "are_you_sure_you_want_to_delete_this_oidc_client": "Are you sure you want to delete this OIDC client?", + "oidc_client_deleted_successfully": "OIDC client deleted successfully", + "authorization_url": "Authorization URL", + "oidc_discovery_url": "OIDC Discovery URL", + "token_url": "Token URL", + "userinfo_url": "Userinfo URL", + "logout_url": "Logout URL", + "certificate_url": "Certificate URL", + "enabled": "Enabled", + "disabled": "Disabled", + "oidc_client_updated_successfully": "OIDC client updated successfully", + "create_new_client_secret": "Create new client secret", + "are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.", + "generate": "Generate", + "new_client_secret_created_successfully": "New client secret created successfully", + "allowed_user_groups_updated_successfully": "Allowed user groups updated successfully", + "oidc_client_name": "OIDC Client {name}", + "client_id": "Client ID", + "client_secret": "Client secret", + "show_more_details": "Show more details", + "allowed_user_groups": "Allowed User Groups", + "add_user_groups_to_this_client_to_restrict_access_to_users_in_these_groups": "Add user groups to this client to restrict access to users in these groups. If no user groups are selected, all users will have access to this client.", + "favicon": "Favicon", + "light_mode_logo": "Light Mode Logo", + "dark_mode_logo": "Dark Mode Logo", + "background_image": "Background Image", + "language": "Language", + "reset_profile_picture_question": "Reset profile picture?", + "this_will_remove_the_uploaded_image_and_reset_the_profile_picture_to_default": "This will remove the uploaded image, and reset the profile picture to default. Do you want to continue?", + "reset": "Reset", + "reset_to_default": "Reset to default", + "profile_picture_has_been_reset": "Profile picture has been reset. It may take a few minutes to update.", + "select_the_language_you_want_to_use": "Select the language you want to use. Some languages may not be fully translated." +} diff --git a/frontend/messages/nl.json b/frontend/messages/nl.json new file mode 100644 index 00000000..3ddb3dbc --- /dev/null +++ b/frontend/messages/nl.json @@ -0,0 +1,313 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "my_account": "Mijn Account", + "logout": "Uitloggen", + "english": "English", + "dutch": "Nederlands", + "confirm": "Bevestigen", + "key": "Sleutel", + "value": "Waarde", + "remove_custom_claim": "Aangepaste claim verwijderen", + "add_custom_claim": "Aangepaste claim toevoegen", + "add_another": "Voeg nog een toe", + "select_a_date": "Selecteer een datum", + "select_file": "Selecteer bestand", + "profile_picture": "Profielfoto", + "profile_picture_is_managed_by_ldap_server": "De profielfoto wordt beheerd door de LDAP-server en kan hier niet worden gewijzigd.", + "click_profile_picture_to_upload_custom": "Klik op de profielfoto om een aangepaste foto uit uw bestanden te uploaden.", + "image_should_be_in_format": "De afbeelding moet in PNG- of JPEG-formaat zijn.", + "items_per_page": "Aantal per pagina", + "no_items_found": "Geen items gevonden", + "search": "Zoekopdracht...", + "expand_card": "Kaart uitbreiden", + "copied": "Gekopieerd", + "click_to_copy": "Klik om te kopiëren", + "something_went_wrong": "Er is iets misgegaan", + "go_back_to_home": "Ga terug naar huis", + "dont_have_access_to_your_passkey": "Hebt u geen toegang tot uw toegangscode?", + "login_background": "Inlogachtergrond", + "logo": "Logo", + "login_code": "Inlogcode", + "create_a_login_code_to_sign_in_without_a_passkey_once": "Maak een inlogcode aan waarmee de gebruiker zich eenmalig kan aanmelden zonder passkey.", + "one_hour": "1 uur", + "twelve_hours": "12 uur", + "one_day": "1 dag", + "one_week": "1 week", + "one_month": "1 maand", + "expiration": "Vervaldatum", + "generate_code": "Genereer code", + "name": "Naam", + "browser_unsupported": "Browser niet ondersteund", + "this_browser_does_not_support_passkeys": "Deze browser ondersteunt geen passkeys. Gebruik een alternatieve aanmeldmethode.", + "an_unknown_error_occurred": "Er is een onbekende fout opgetreden", + "authentication_process_was_aborted": "Het authenticatieproces is afgebroken", + "error_occurred_with_authenticator": "Er is een fout opgetreden met de authenticator", + "authenticator_does_not_support_discoverable_credentials": "De authenticator ondersteunt geen vindbare referenties", + "authenticator_does_not_support_resident_keys": "De authenticator ondersteunt geen residente sleutels", + "passkey_was_previously_registered": "Deze toegangscode is eerder geregistreerd", + "authenticator_does_not_support_any_of_the_requested_algorithms": "De authenticator ondersteunt geen van de gevraagde algoritmen", + "authenticator_timed_out": "De authenticator is verlopen", + "critical_error_occurred_contact_administrator": "Er is een kritieke fout opgetreden. Neem contact op met uw beheerder.", + "sign_in_to": "Meld u aan bij {name}", + "client_not_found": "Client niet gevonden", + "client_wants_to_access_the_following_information": "{client} wil toegang tot de volgende informatie:", + "do_you_want_to_sign_in_to_client_with_your_app_name_account": "Wilt u zich aanmelden bij {client} met uw {appName} account?", + "email": "E-mail", + "view_your_email_address": "Bekijk uw e-mailadres", + "profile": "Profiel", + "view_your_profile_information": "Bekijk uw profielgegevens", + "groups": "Groepen", + "view_the_groups_you_are_a_member_of": "Bekijk de groepen waarvan u lid bent", + "cancel": "Annuleren", + "sign_in": "Aanmelden", + "try_again": "Probeer het opnieuw", + "client_logo": "Client logo", + "sign_out": "Afmelden", + "do_you_want_to_sign_out_of_pocketid_with_the_account": "Wilt u zich afmelden bij Pocket ID met het account {username} ?", + "sign_in_to_appname": "Meld u aan bij {appName}", + "please_try_to_sign_in_again": "Probeer opnieuw in te loggen.", + "authenticate_yourself_with_your_passkey_to_access_the_admin_panel": "Verifieer uzelf met uw toegangscode om toegang te krijgen tot het beheerderspaneel.", + "authenticate": "Authenticeren", + "appname_setup": "{appName} Instellen", + "please_try_again": "Probeer het opnieuw.", + "you_are_about_to_sign_in_to_the_initial_admin_account": "U staat op het punt om in te loggen op het oorspronkelijke beheerdersaccount. Iedereen met deze link heeft toegang tot het account totdat er een passkey is toegevoegd. Stel zo snel mogelijk een passkey in om ongeautoriseerde toegang te voorkomen.", + "continue": "Doorgaan", + "alternative_sign_in": "Alternatieve aanmelding", + "if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods": "Als u geen toegang hebt tot uw toegangscode, kunt u zich op een van de volgende manieren aanmelden.", + "use_your_passkey_instead": "Wilt u in plaats daarvan uw toegangscode gebruiken?", + "email_login": "E-mail inloggen", + "enter_a_login_code_to_sign_in": "Voer een inlogcode in om in te loggen.", + "request_a_login_code_via_email": "Vraag een inlogcode aan via e-mail.", + "go_back": "Ga terug", + "an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system": "Er is een e-mail verzonden naar het opgegeven e-mailadres, indien dit in het systeem voorkomt.", + "enter_code": "Voer code in", + "enter_your_email_address_to_receive_an_email_with_a_login_code": "Voer uw e-mailadres in om een e-mail met een inlogcode te ontvangen.", + "your_email": "Uw e-mail", + "submit": "Indienen", + "enter_the_code_you_received_to_sign_in": "Voer de code in die u hebt ontvangen om in te loggen.", + "code": "Code", + "invalid_redirect_url": "Ongeldige omleidings-URL", + "audit_log": "Audit logboek", + "users": "Gebruikers", + "user_groups": "Gebruikersgroepen", + "oidc_clients": "OIDC-clients", + "api_keys": "API-sleutels", + "application_configuration": "Toepassingsconfiguratie", + "settings": "Instellingen", + "update_pocket_id": "Pocket-ID bijwerken", + "powered_by": "Aangedreven door", + "see_your_account_activities_from_the_last_3_months": "Bekijk uw accountactiviteiten van de afgelopen 3 maanden.", + "time": "Tijd", + "event": "Evenement", + "approximate_location": "Geschatte locatie", + "ip_address": "IP-adres", + "device": "Apparaat", + "client": "Cliënt", + "unknown": "Onbekend", + "account_details_updated_successfully": "Accountgegevens succesvol bijgewerkt", + "profile_picture_updated_successfully": "Profielfoto succesvol bijgewerkt. Het kan enkele minuten duren voordat de wijzigingen zichtbaar zijn.", + "account_settings": "Accountinstellingen", + "passkey_missing": "Passkey ontbreekt", + "please_provide_a_passkey_to_prevent_losing_access_to_your_account": "Voeg een passkey toe om te voorkomen dat u de toegang tot uw account verliest.", + "single_passkey_configured": "Eén enkele toegangscode geconfigureerd", + "it_is_recommended_to_add_more_than_one_passkey": "Het is raadzaam om meer dan één toegangscode toe te voegen om te voorkomen dat u de toegang tot uw account verliest.", + "account_details": "Accountgegevens", + "passkeys": "Toegangscodes", + "manage_your_passkeys_that_you_can_use_to_authenticate_yourself": "Beheer de toegangscodes waarmee u uzelf kunt verifiëren.", + "add_passkey": "Passkey toevoegen", + "create_a_one_time_login_code_to_sign_in_from_a_different_device_without_a_passkey": "Maak een eenmalige inlogcode aan om in te loggen vanaf een ander apparaat zonder passkey.", + "create": "Creëren", + "first_name": "Voornaam", + "last_name": "Achternaam", + "username": "Gebruikersnaam", + "save": "Opslaan", + "username_can_only_contain": "Gebruikersnaam mag alleen kleine letters, cijfers, onderstrepingstekens, punten, koppeltekens en '@'-symbolen bevatten", + "sign_in_using_the_following_code_the_code_will_expire_in_minutes": "Meld u aan met de volgende code. De code verloopt over 15 minuten.", + "or_visit": "of bezoek", + "added_on": "Toegevoegd op", + "rename": "Hernoemen", + "delete": "Verwijderen", + "are_you_sure_you_want_to_delete_this_passkey": "Weet u zeker dat u deze toegangscode wilt verwijderen?", + "passkey_deleted_successfully": "Passkey succesvol verwijderd", + "delete_passkey_name": "Verwijder {passkeyName}", + "passkey_name_updated_successfully": "Passkey naam succesvol bijgewerkt", + "name_passkey": "Naam Passkey", + "name_your_passkey_to_easily_identify_it_later": "Geef uw toegangscode een naam, zodat u deze later gemakkelijk kunt terugvinden.", + "create_api_key": "API-sleutel aanmaken", + "add_a_new_api_key_for_programmatic_access": "Voeg een nieuwe API-sleutel toe voor programmatische toegang.", + "add_api_key": "API-sleutel toevoegen", + "manage_api_keys": "API-sleutels beheren", + "api_key_created": "API-sleutel gemaakt", + "for_security_reasons_this_key_will_only_be_shown_once": "Om veiligheidsredenen wordt deze sleutel slechts één keer getoond. Bewaar hem veilig.", + "description": "Beschrijving", + "api_key": "API-sleutel", + "close": "Dichtbij", + "name_to_identify_this_api_key": "Naam om deze API-sleutel te identificeren.", + "expires_at": "Verloopt op", + "when_this_api_key_will_expire": "Wanneer deze API-sleutel verloopt.", + "optional_description_to_help_identify_this_keys_purpose": "Optionele beschrijving om het doel van deze sleutel te helpen identificeren.", + "name_must_be_at_least_3_characters": "Naam moet minimaal 3 tekens lang zijn", + "name_cannot_exceed_50_characters": "Naam mag niet langer zijn dan 50 tekens", + "expiration_date_must_be_in_the_future": "Vervaldatum moet in de toekomst liggen", + "revoke_api_key": "API-sleutel intrekken", + "never": "Nooit", + "revoke": "Herroepen", + "api_key_revoked_successfully": "API-sleutel succesvol ingetrokken", + "are_you_sure_you_want_to_revoke_the_api_key_apikeyname": "Weet u zeker dat u de API-sleutel \" {apiKeyName} \" wilt intrekken? Hiermee worden alle integraties die deze sleutel gebruiken, verbroken.", + "last_used": "Laatst gebruikt", + "actions": "Acties", + "images_updated_successfully": "Afbeeldingen succesvol bijgewerkt", + "general": "Algemeen", + "enable_email_notifications_to_alert_users_when_a_login_is_detected_from_a_new_device_or_location": "Schakel e-mailmeldingen in om gebruikers te waarschuwen wanneer er wordt ingelogd vanaf een nieuw apparaat of een nieuwe locatie.", + "ldap": "LDAP", + "configure_ldap_settings_to_sync_users_and_groups_from_an_ldap_server": "Configureer LDAP-instellingen om gebruikers en groepen vanaf een LDAP-server te synchroniseren.", + "images": "Afbeeldingen", + "update": "Update", + "email_configuration_updated_successfully": "E-mailconfiguratie succesvol bijgewerkt", + "save_changes_question": "Wijzigingen opslaan?", + "you_have_to_save_the_changes_before_sending_a_test_email_do_you_want_to_save_now": "U moet de wijzigingen opslaan voordat u een test-e-mail verzendt. Wilt u nu opslaan?", + "save_and_send": "Opslaan en verzenden", + "test_email_sent_successfully": "Test-e-mail succesvol verzonden naar uw e-mailadres.", + "failed_to_send_test_email": "Het is niet gelukt om een test-e-mail te versturen. Controleer de serverlogs voor meer informatie.", + "smtp_configuration": "SMTP-configuratie", + "smtp_host": "SMTP-host", + "smtp_port": "SMTP-poort", + "smtp_user": "SMTP-gebruiker", + "smtp_password": "SMTP-wachtwoord", + "smtp_from": "SMTP van", + "smtp_tls_option": "SMTP TLS-optie", + "email_tls_option": "E-mail TLS-optie", + "skip_certificate_verification": "Certificaatverificatie overslaan", + "this_can_be_useful_for_selfsigned_certificates": "Dit kan handig zijn voor zelfondertekende certificaten.", + "enabled_emails": "Ingeschakelde e-mails", + "email_login_notification": "E-mail-inlogmelding", + "send_an_email_to_the_user_when_they_log_in_from_a_new_device": "Stuur een e-mail naar de gebruiker wanneer deze zich aanmeldt vanaf een nieuw apparaat.", + "allow_users_to_sign_in_with_a_login_code_sent_to_their_email": "Hiermee kunnen gebruikers inloggen met een inlogcode die naar hun e-mail is gestuurd. Dit vermindert de beveiliging aanzienlijk, omdat iedereen met toegang tot de e-mail van de gebruiker toegang kan krijgen.", + "send_test_email": "Test-e-mail verzenden", + "application_configuration_updated_successfully": "Toepassingsconfiguratie succesvol bijgewerkt", + "application_name": "Toepassingsnaam", + "session_duration": "Sessieduur", + "the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again": "De duur van een sessie in minuten voordat de gebruiker zich opnieuw moet aanmelden.", + "enable_self_account_editing": "Zelf-accountbewerking inschakelen", + "whether_the_users_should_be_able_to_edit_their_own_account_details": "Of gebruikers hun eigen accountgegevens moeten kunnen bewerken.", + "emails_verified": "E-mails geverifieerd", + "whether_the_users_email_should_be_marked_as_verified_for_the_oidc_clients": "Of het e-mailadres van de gebruiker als geverifieerd moet worden gemarkeerd voor de OIDC-clients.", + "ldap_configuration_updated_successfully": "LDAP-configuratie succesvol bijgewerkt", + "ldap_disabled_successfully": "LDAP succesvol uitgeschakeld", + "ldap_sync_finished": "LDAP-synchronisatie voltooid", + "client_configuration": "Clientconfiguratie", + "ldap_url": "LDAP-URL", + "ldap_bind_dn": "LDAP Bind-DN", + "ldap_bind_password": "LDAP Bind-wachtwoord", + "ldap_base_dn": "LDAP-basis-DN", + "user_search_filter": "Gebruikerszoekfilter", + "the_search_filter_to_use_to_search_or_sync_users": "Het zoekfilter waarmee u gebruikers kunt zoeken/synchroniseren.", + "groups_search_filter": "Groepen Zoekfilter", + "the_search_filter_to_use_to_search_or_sync_groups": "Het zoekfilter waarmee u groepen kunt zoeken/synchroniseren.", + "attribute_mapping": "Attribuuttoewijzing", + "user_unique_identifier_attribute": "Gebruiker uniek identificatiekenmerk", + "the_value_of_this_attribute_should_never_change": "De waarde van dit kenmerk mag nooit veranderen.", + "username_attribute": "Gebruikersnaam Attribuut", + "user_mail_attribute": "Gebruikersmailkenmerk", + "user_first_name_attribute": "Gebruikersvoornaam Attribuut", + "user_last_name_attribute": "Gebruikersnaam Achternaam Attribuut", + "user_profile_picture_attribute": "Gebruikersprofielfoto-attribuut", + "the_value_of_this_attribute_can_either_be_a_url_binary_or_base64_encoded_image": "De waarde van dit kenmerk kan een URL, een binair bestand of een base64-gecodeerde afbeelding zijn.", + "group_members_attribute": "Groepsleden Attribuut", + "the_attribute_to_use_for_querying_members_of_a_group": "Het kenmerk dat gebruikt moet worden om leden van een groep te bevragen.", + "group_unique_identifier_attribute": "Groeps uniek identificatiekenmerk", + "group_name_attribute": "Groepsnaam Attribuut", + "admin_group_name": "Naam van beheerdersgroep", + "members_of_this_group_will_have_admin_privileges_in_pocketid": "Leden van deze groep hebben beheerdersrechten in Pocket ID.", + "disable": "Uitzetten", + "sync_now": "Nu synchroniseren", + "enable": "Inschakelen", + "user_created_successfully": "Gebruiker succesvol aangemaakt", + "create_user": "Gebruiker aanmaken", + "add_a_new_user_to_appname": "Voeg een nieuwe gebruiker toe aan {appName}", + "add_user": "Gebruiker toevoegen", + "manage_users": "Gebruikers beheren", + "admin_privileges": "Beheerdersrechten", + "admins_have_full_access_to_the_admin_panel": "Beheerders hebben volledige toegang tot het beheerderspaneel.", + "delete_firstname_lastname": "Verwijderen {firstName} {lastName}", + "are_you_sure_you_want_to_delete_this_user": "Weet u zeker dat u deze gebruiker wilt verwijderen?", + "user_deleted_successfully": "Gebruiker succesvol verwijderd", + "role": "Rol", + "source": "Bron", + "admin": "Beheerder", + "user": "Gebruiker", + "local": "Lokaal", + "toggle_menu": "Menu wisselen", + "edit": "Bewerking", + "user_groups_updated_successfully": "Gebruikersgroepen succesvol bijgewerkt", + "user_updated_successfully": "Gebruiker succesvol bijgewerkt", + "custom_claims_updated_successfully": "Aangepaste claims succesvol bijgewerkt", + "back": "Terug", + "user_details_firstname_lastname": "Gebruikersgegevens {firstName} {lastName}", + "manage_which_groups_this_user_belongs_to": "Beheer tot welke groepen deze gebruiker behoort.", + "custom_claims": "Aangepaste claims", + "custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user": "Aangepaste claims zijn sleutel-waardeparen die kunnen worden gebruikt om aanvullende informatie over een gebruiker op te slaan. Deze claims worden opgenomen in het ID-token als de scope 'profile' wordt aangevraagd.", + "user_group_created_successfully": "Gebruikersgroep succesvol aangemaakt", + "create_user_group": "Gebruikersgroep aanmaken", + "create_a_new_group_that_can_be_assigned_to_users": "Maak een nieuwe groep aan die aan gebruikers kan worden toegewezen.", + "add_group": "Groep toevoegen", + "manage_user_groups": "Gebruikersgroepen beheren", + "friendly_name": "Vriendelijke naam", + "name_that_will_be_displayed_in_the_ui": "Naam die in de gebruikersinterface wordt weergegeven", + "name_that_will_be_in_the_groups_claim": "Naam die in de claim 'groepen' zal staan", + "delete_name": "Verwijder {name}", + "are_you_sure_you_want_to_delete_this_user_group": "Weet u zeker dat u deze gebruikersgroep wilt verwijderen?", + "user_group_deleted_successfully": "Gebruikersgroep succesvol verwijderd", + "user_count": "Gebruikersaantal", + "user_group_updated_successfully": "Gebruikersgroep succesvol bijgewerkt", + "users_updated_successfully": "Gebruikers succesvol bijgewerkt", + "user_group_details_name": "Gebruikersgroepdetails {name}", + "assign_users_to_this_group": "Gebruikers aan deze groep toewijzen.", + "custom_claims_are_key_value_pairs_that_can_be_used_to_store_additional_information_about_a_user_prioritized": "Aangepaste claims zijn sleutel-waardeparen die kunnen worden gebruikt om aanvullende informatie over een gebruiker op te slaan. Deze claims worden opgenomen in het ID-token als de scope 'profile' wordt opgevraagd. Aangepaste claims die zijn gedefinieerd voor de gebruiker, krijgen prioriteit als er conflicten zijn.", + "oidc_client_created_successfully": "OIDC-client succesvol aangemaakt", + "create_oidc_client": "Maak een OIDC-client", + "add_a_new_oidc_client_to_appname": "Voeg een nieuwe OIDC-client toe aan {appName} .", + "add_oidc_client": "OIDC-client toevoegen", + "manage_oidc_clients": "OIDC-clients beheren", + "one_time_link": "Eenmalige link", + "use_this_link_to_sign_in_once": "Gebruik deze link om u eenmalig aan te melden. Dit is nodig voor gebruikers die nog geen passkey hebben toegevoegd of\nben het kwijt.", + "add": "Toevoegen", + "callback_urls": "Callback-URL's", + "logout_callback_urls": "Callback-URL's voor afmelden", + "public_client": "Publieke client", + "public_clients_do_not_have_a_client_secret_and_use_pkce_instead": "Publieke clients hebben geen client secret en gebruiken in plaats daarvan PKCE. Schakel dit in als uw client een SPA of mobiele app is.", + "pkce": "PKCE", + "public_key_code_exchange_is_a_security_feature_to_prevent_csrf_and_authorization_code_interception_attacks": "Public Key Code Exchange is een beveiligingsfunctie om CSRF- en autorisatiecode-onderscheppingsaanvallen te voorkomen.", + "name_logo": "{name} logo", + "change_logo": "Logo wijzigen", + "upload_logo": "Logo uploaden", + "remove_logo": "Logo verwijderen", + "are_you_sure_you_want_to_delete_this_oidc_client": "Weet u zeker dat u deze OIDC-client wilt verwijderen?", + "oidc_client_deleted_successfully": "OIDC-client succesvol verwijderd", + "authorization_url": "Autorisatie-URL", + "oidc_discovery_url": "OIDC-ontdekkings-URL", + "token_url": "Token-URL", + "userinfo_url": "Gebruikersinfo-URL", + "logout_url": "Uitlog-URL", + "certificate_url": "Certificaat-URL", + "enabled": "Ingeschakeld", + "disabled": "Uitgeschakeld", + "oidc_client_updated_successfully": "OIDC-client succesvol bijgewerkt", + "create_new_client_secret": "Nieuw clientgeheim aanmaken", + "are_you_sure_you_want_to_create_a_new_client_secret": "Weet u zeker dat u een nieuw client secret wilt aanmaken? De oude wordt ongeldig.", + "generate": "Genereren", + "new_client_secret_created_successfully": "Nieuw clientgeheim succesvol aangemaakt", + "allowed_user_groups_updated_successfully": "Toegestane gebruikersgroepen succesvol bijgewerkt", + "oidc_client_name": "OIDC-client {name}", + "client_id": "Client id", + "client_secret": "Client geheim", + "show_more_details": "Meer details weergeven", + "allowed_user_groups": "Toegestane gebruikersgroepen", + "add_user_groups_to_this_client_to_restrict_access_to_users_in_these_groups": "Voeg gebruikersgroepen toe aan deze client om de toegang tot gebruikers in deze groepen te beperken. Als er geen gebruikersgroepen zijn geselecteerd, hebben alle gebruikers toegang tot deze client.", + "favicon": "Favicon", + "light_mode_logo": "Lichte modus logo", + "dark_mode_logo": "Donkere modus logo", + "background_image": "Achtergrondfoto", + "language": "Taal", + "profile_picture_has_been_reset": "Profielfoto is gereset. Het kan enkele minuten duren voordat de wijzigingen zichtbaar zijn." +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8cdae40a..f4151c73 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "pocket-id-frontend", - "version": "0.39.0", + "version": "0.42.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pocket-id-frontend", - "version": "0.39.0", + "version": "0.42.1", "dependencies": { "@simplewebauthn/browser": "^13.1.0", "@tailwindcss/vite": "^4.0.0", @@ -25,6 +25,7 @@ "zod": "^3.24.1" }, "devDependencies": { + "@inlang/paraglide-js": "^2.0.0", "@internationalized/date": "^3.7.0", "@playwright/test": "^1.50.0", "@sveltejs/adapter-auto": "^4.0.0", @@ -747,6 +748,78 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inlang/paraglide-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.0.0.tgz", + "integrity": "sha512-ufe/k4tfBIQrJf6X1L+KGtvHYRhvDPX53m7vVe+IOYs0DkyR7RkBgwPBQb3kbXKpr5atCD+D2BDh/I7EpK5Clg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inlang/recommend-sherlock": "0.2.1", + "@inlang/sdk": "2.4.2", + "commander": "11.1.0", + "consola": "3.4.0", + "json5": "2.2.3", + "unplugin": "^2.1.2", + "urlpattern-polyfill": "^10.0.0" + }, + "bin": { + "paraglide-js": "bin/run.js" + } + }, + "node_modules/@inlang/paraglide-js/node_modules/@inlang/sdk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@inlang/sdk/-/sdk-2.4.2.tgz", + "integrity": "sha512-EqL32PcFHOlXWEg2o0nftSBZ376tSxuAhV8uTZoaq521AKSRMEvjTpVsJ9eS6ZJDCRiIXx7avtsdVNwkUntf8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lix-js/sdk": "0.4.2", + "@sinclair/typebox": "^0.31.17", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@inlang/paraglide-js/node_modules/@lix-js/sdk": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.4.2.tgz", + "integrity": "sha512-wrQQMAZzOxQEAssxUnajn7Djua98MlIzs+V6GdX51VN6b7iA3qvZJY4L9xEEMh0nRFvpAO3wOt7uBth9580pog==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@lix-js/server-api-schema": "0.1.1", + "dedent": "1.5.1", + "human-id": "^4.1.1", + "js-sha256": "^0.11.0", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=21" + } + }, + "node_modules/@inlang/paraglide-js/node_modules/@sinclair/typebox": { + "version": "0.31.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz", + "integrity": "sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inlang/recommend-sherlock": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz", + "integrity": "sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.3" + } + }, "node_modules/@internationalized/date": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.7.0.tgz", @@ -798,6 +871,13 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lix-js/server-api-schema": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@lix-js/server-api-schema/-/server-api-schema-0.1.1.tgz", + "integrity": "sha512-W1Z7KKOxAQ4Dag9V2wrDevHPh5rPk+icBUsxNfNCNB2tlPrKpba99562vcTCPoT03KXpihEbWutZNujCRtMA+g==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1214,6 +1294,16 @@ "integrity": "sha512-TJ7Al17j3+by5y2QkTLcF/oBVMbgXBhILVgi9PuwpxQVZZvGh5BFRzWbJPmZVNKpbRLjuMzFuRwR+tdFPqCkvA==", "optional": true }, + "node_modules/@sqlite.org/sqlite-wasm": { + "version": "3.48.0-build4", + "resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.48.0-build4.tgz", + "integrity": "sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "sqlite-wasm": "bin/index.js" + } + }, "node_modules/@sveltejs/adapter-auto": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-4.0.0.tgz", @@ -1909,6 +1999,13 @@ "@ark/util": "0.38.0" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2099,6 +2196,33 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2111,6 +2235,16 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -2119,6 +2253,13 @@ "node": ">= 0.6" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2173,6 +2314,21 @@ } } }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2490,6 +2646,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -2814,6 +2984,16 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -2826,6 +3006,16 @@ "node": ">= 0.4" } }, + "node_modules/human-id": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz", + "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2964,6 +3154,13 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-sha256": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.0.tgz", + "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3007,6 +3204,19 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3030,6 +3240,16 @@ "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", "dev": true }, + "node_modules/kysely": { + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3906,6 +4126,16 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "optional": true }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4094,6 +4324,18 @@ "source-map": "^0.6.0" } }, + "node_modules/sqlite-wasm-kysely": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/sqlite-wasm-kysely/-/sqlite-wasm-kysely-0.3.0.tgz", + "integrity": "sha512-TzjBNv7KwRw6E3pdKdlRyZiTmUIE0UttT/Sl56MVwVARl/u5gp978KepazCJZewFUnlWHz9i3NQd4kOtP/Afdg==", + "dev": true, + "dependencies": { + "@sqlite.org/sqlite-wasm": "^3.48.0-build2" + }, + "peerDependencies": { + "kysely": "*" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4548,6 +4790,20 @@ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "devOptional": true }, + "node_modules/unplugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.2.0.tgz", + "integrity": "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4557,12 +4813,33 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true, + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/valibot": { "version": "1.0.0-beta.11", "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.11.tgz", @@ -4687,6 +4964,13 @@ } } }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 557a52f6..eba0aff0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "zod": "^3.24.1" }, "devDependencies": { + "@inlang/paraglide-js": "^2.0.0", "@internationalized/date": "^3.7.0", "@playwright/test": "^1.50.0", "@sveltejs/adapter-auto": "^4.0.0", diff --git a/frontend/project.inlang/.gitignore b/frontend/project.inlang/.gitignore new file mode 100644 index 00000000..5e465967 --- /dev/null +++ b/frontend/project.inlang/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/frontend/project.inlang/project_id b/frontend/project.inlang/project_id new file mode 100644 index 00000000..1ff8aadf --- /dev/null +++ b/frontend/project.inlang/project_id @@ -0,0 +1 @@ +O2jvFph6P4Jpehf2BT \ No newline at end of file diff --git a/frontend/project.inlang/settings.json b/frontend/project.inlang/settings.json new file mode 100644 index 00000000..bf60cc91 --- /dev/null +++ b/frontend/project.inlang/settings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "baseLocale": "en", + "locales": [ + "en", + "nl" + ], + "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" + } +} \ No newline at end of file diff --git a/frontend/src/app.html b/frontend/src/app.html index befb926b..83bacbc4 100644 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -1,5 +1,5 @@ - +
diff --git a/frontend/src/hooks.server.ts b/frontend/src/hooks.server.ts index 2ff787dc..cead04c5 100644 --- a/frontend/src/hooks.server.ts +++ b/frontend/src/hooks.server.ts @@ -1,6 +1,8 @@ import { env } from '$env/dynamic/private'; import { ACCESS_TOKEN_COOKIE_NAME } from '$lib/constants'; +import { paraglideMiddleware } from '$lib/paraglide/server'; import type { Handle, HandleServerError } from '@sveltejs/kit'; +import { sequence } from '@sveltejs/kit/hooks'; import { AxiosError } from 'axios'; import { decodeJwt } from 'jose'; @@ -9,7 +11,16 @@ import { decodeJwt } from 'jose'; // this is still secure as process will just be undefined in the browser process.env.INTERNAL_BACKEND_URL = env.INTERNAL_BACKEND_URL ?? 'http://localhost:8080'; -export const handle: Handle = async ({ event, resolve }) => { +// Handle to use the paraglide middleware +const paraglideHandle: Handle = ({ event, resolve }) => { + return paraglideMiddleware(event.request, ({ locale }) => { + return resolve(event, { + transformPageChunk: ({ html }) => html.replace('%lang%', locale) + }); + }); +}; + +const authenticationHandle: Handle = async ({ event, resolve }) => { const { isSignedIn, isAdmin } = verifyJwt(event.cookies.get(ACCESS_TOKEN_COOKIE_NAME)); const isUnauthenticatedOnlyPath = event.url.pathname.startsWith('/login') || event.url.pathname.startsWith('/lc') @@ -43,6 +54,8 @@ export const handle: Handle = async ({ event, resolve }) => { return response; }; +export const handle: Handle = sequence(paraglideHandle, authenticationHandle); + export const handleError: HandleServerError = async ({ error, message, status }) => { if (error instanceof AxiosError) { message = error.response?.data.error || message; diff --git a/frontend/src/lib/components/advanced-table.svelte b/frontend/src/lib/components/advanced-table.svelte index 28113e6d..4a076469 100644 --- a/frontend/src/lib/components/advanced-table.svelte +++ b/frontend/src/lib/components/advanced-table.svelte @@ -11,6 +11,7 @@ import { ChevronDown } from 'lucide-svelte'; import type { Snippet } from 'svelte'; import Button from './ui/button/button.svelte'; + import { m } from '$lib/paraglide/messages'; let { items, @@ -93,7 +94,7 @@ 'relative z-50 mb-4 max-w-sm', items.data.length == 0 && searchValue == '' && 'hidden' )} - placeholder={'Search...'} + placeholder={m.search()} type="text" oninput={(e) => onSearch((e.target as HTMLInputElement).value)} /> @@ -102,7 +103,7 @@ {#if items.data.length === 0 && searchValue === ''}No items found
+{m.no_items_found()}
Items per page
+{m.items_per_page()}
- The profile picture is managed by the LDAP server and cannot be changed here. + {m.profile_picture_is_managed_by_ldap_server()}
{:else}- Click on the profile picture to upload a custom one from your files. + {m.click_profile_picture_to_upload_custom()}
-The image should be in PNG or JPEG format.
+{m.image_should_be_in_format()}
{/if}Browser unsupported
+{m.browser_unsupported()}
- This browser doesn't support passkeys. Please or use a alternative sign in method. + {m.this_browser_does_not_support_passkeys()}
diff --git a/frontend/src/lib/stores/user-store.ts b/frontend/src/lib/stores/user-store.ts index 19147c50..5f241f79 100644 --- a/frontend/src/lib/stores/user-store.ts +++ b/frontend/src/lib/stores/user-store.ts @@ -1,9 +1,13 @@ +import { setLocale } from '$lib/paraglide/runtime'; import type { User } from '$lib/types/user.type'; import { writable } from 'svelte/store'; const userStore = writableClient not found
+{m.client_not_found()}
{:else}{errorMessage}. @@ -93,34 +94,36 @@ {/if} {#if !authorizationRequired && !errorMessage}
- Do you want to sign in to {client.name} with your - {$appConfigStore.appName} account? + {@html m.do_you_want_to_sign_in_to_client_with_your_app_name_account({ + client: client.name, + appName: $appConfigStore.appName + })}
{:else if authorizationRequired}- {client.name} wants to access the following information: + {@html m.client_wants_to_access_the_following_information({ client: client.name })}
- {error}. Please try to sign in again. + {error}. {m.please_try_to_sign_in_again()}
{:else}- Authenticate yourself with your passkey to access the admin panel. + {m.authenticate_yourself_with_your_passkey_to_access_the_admin_panel()}
{/if}- If you dont't have access to your passkey, you can sign in using one of the following methods. + {m.if_you_do_not_have_access_to_your_passkey_you_can_sign_in_using_one_of_the_following_methods()}
- {error}. Please try again. + {error}. {m.please_try_again()}
{:else} -Enter the code you received to sign in.
+{m.enter_the_code_you_received_to_sign_in()}
{/if}- {error}. Please try again. + {error}. {m.please_try_again()}
- An email has been sent to the provided email, if it exists in the system. + {m.an_email_has_been_sent_to_the_provided_email_if_it_exists_in_the_system()}
- {error}. Please try again. + {error}. {m.please_try_again()}
{:else}- You're about to sign in to the initial admin account. Anyone with this link can access the - account until a passkey is added. Please set up a passkey as soon as possible to prevent - unauthorized access. + {m.you_are_about_to_sign_in_to_the_initial_admin_account()}
-- Do you want to sign out of Pocket ID with the account {$userStore?.username}? + {@html m.do_you_want_to_sign_out_of_pocketid_with_the_account({ username: $userStore?.username ?? '' })}
- Powered by Pocket ID toast.success('Account details updated successfully'))
+ .then(() => toast.success(m.account_details_updated_successfully()))
.catch((e) => {
axiosErrorToast(e);
success = false;
@@ -51,9 +53,7 @@
async function updateProfilePicture(image: File) {
await userService
.updateCurrentUsersProfilePicture(image)
- .then(() =>
- toast.success('Profile picture updated successfully. It may take a few minutes to update.')
- )
+ .then(() => toast.success(m.profile_picture_updated_successfully()))
.catch(axiosErrorToast);
}
@@ -72,24 +72,22 @@
or visit {m.or_visit()} {passkey.name}
- Added on {new Date(passkey.createdAt).toLocaleDateString()}
+ {m.added_on()} {new Date(passkey.createdAt).toLocaleDateString()}
{apiKeyResponse.apiKey.name}
{#if apiKeyResponse.apiKey.description} -{apiKeyResponse.apiKey.description}
{/if} -