Merge pull request 'merge: assets-refactor' (#125) from assets-refactor into master

Reviewed-on: kherel/selfprivacy.org.app#125
Reviewed-by: Inex Code <inex.code@selfprivacy.org>
pull/126/head
Inex Code 2022-10-04 13:35:40 +03:00
commit 571e32ecff
43 changed files with 712 additions and 865 deletions

View File

@ -2,9 +2,10 @@
"test": "en-test",
"locale": "en",
"basis": {
"_comment": "Basic interface elements",
"providers": "Providers",
"providers_title": "Your Data Center",
"services": "Services",
"services_title": "Your personal, private and independent services.",
"users": "Users",
"more": "More",
"next": "Next",
@ -29,41 +30,38 @@
"wait": "Wait",
"remove": "Remove",
"apply": "Apply",
"done": "Done"
"done": "Done",
"continue": "Continue"
},
"more": {
"_comment": "'More' tab",
"more_page": {
"configuration_wizard": "Setup wizard",
"about_project": "About us",
"about_app": "About application",
"about_application": "About",
"onboarding": "Onboarding",
"create_ssh_key": "Create SSH key",
"generate_key": "Generate key",
"generate_key_text": "You can generate ssh key",
"console": "Console",
"remove": "Remove",
"enable": "Enable",
"ok": "ok",
"continue": "Continue",
"ssh_key_exist_text": "You have generated ssh key",
"yes_delete": "Yes, delete my SSH key",
"share": "Share",
"copy_buffer": "Copy to buffer",
"copied_ssh": "SSH copied to clipboard",
"delete_ssh_text": "Delete SSH key?",
"about_app_page": {
"application_version_text": "Application version v.{}",
"api_version_text": "Server API version v.{}"
},
"settings": {
"title": "Application settings",
"1": "Dark Theme",
"2": "Change your the app theme",
"3": "Reset app config",
"4": "Reset api keys and root user",
"5": "Delete Server",
"6": "This removes the Server. It will be no longer accessible"
}
"application_settings": "Application settings"
},
"console_page": {
"title": "Console",
"waiting": "Waiting for initialization..."
},
"about_us_page": {
"title": "About us"
},
"about_application_page": {
"title": "About",
"application_version_text": "Application version v.{}",
"api_version_text": "Server API version v.{}"
},
"application_settings": {
"title": "Application settings",
"dark_theme_title": "Dark theme",
"dark_theme_description": "Switch your application theme",
"reset_config_title": "Reset application config",
"reset_config_description": "Reset api keys and root user",
"delete_server_title": "Delete server",
"delete_server_description": "This removes your server. It will be no longer accessible"
},
"ssh": {
"title": "SSH keys",
@ -73,248 +71,179 @@
"subtitle_with_keys": "{} keys",
"subtitle_without_keys": "No keys",
"no_key_name": "Unnamed key",
"root": {
"title": "These are superuser keys",
"subtitle": "Owners of these keys get full access to the server and can do anything on it. Only add your own keys to the server."
},
"root_title": "These are superuser keys",
"root_subtitle": "Owners of these keys get full access to the server and can do anything on it. Only add your own keys to the server.",
"input_label": "Public ED25519 or RSA key"
},
"onboarding": {
"_comment": "Onboarding pages",
"page1_title": "Digital independence, available to all of us",
"page1_text": "Mail, VPN, Messenger, social network and much more on your private server, under your control.",
"page2_title": "SelfPrivacy — it's not a cloud, but your personal datacenter",
"page2_text": "SelfPrivacy works only with your provider accounts: Hetzner, Cloudflare, Backblaze. If you do not own those, we'll help you to create them"
},
"providers": {
"_comment": "'Providers' tab",
"page_title": "Your Data Center",
"server": {
"card_title": "Server",
"status": "Status — Good",
"bottom_sheet": {
"1": "It's a virtual computer, where all your services live.",
"2": "General information",
"3": "Location"
},
"chart": {
"month": "Month",
"day": "Day",
"hour": "Hour",
"cpu_title": "CPU Usage",
"network_title": "Network Usage",
"in": "In",
"out": "Out"
},
"resource_usage": "Resource usage",
"settings": {
"allow_autoupgrade": "Allow auto-upgrade",
"allow_autoupgrade_hint": "Allow automatic packages upgrades on server",
"reboot_after_upgrade": "Reboot after upgrade",
"reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server",
"server_timezone": "Server timezone",
"select_timezone": "Select timezone"
},
"info": {
"server_id": "Server ID",
"status": "Status",
"cpu": "CPU",
"ram": "Memory",
"disk": "Disk local",
"monthly_cost": "Monthly cost",
"location": "Location",
"core_count": {
"one": "{} core",
"other": "{} cores"
}
}
},
"domain": {
"card_title": "Domain",
"status": "Status — Good",
"bottom_sheet": {
"1": "It's your personal internet address that will point to the server and other services of yours."
},
"screen_title": "Domain and DNS",
"states": {
"ok": "Records are OK",
"error": "Problems found",
"error_subtitle": "Tap here to fix them",
"refreshing": "Refreshing status...",
"uninitialized": "Data is not retrieved yet"
},
"record_description": {
"root": "Root domain",
"api": "SelfPrivacy API",
"cloud": "File cloud",
"git": "Git server",
"meet": "Video conference",
"social": "Social network",
"password": "Password manager",
"vpn": "VPN",
"mx": "MX record",
"dmarc": "DMARC record",
"spf": "SPF record",
"dkim": "DKIM key"
},
"cards": {
"services": {
"title": "Services",
"subtitle": "Type “A” records required for each service."
},
"email": {
"title": "Email",
"subtitle": "Records necessary for secure email exchange."
}
}
},
"backup": {
"card_title": "Backup",
"status": "Status — Good",
"bottom_sheet": {
"1": "Will save your day in case of incident: hackers attack, server deletion, etc.",
"2": "3Gb/10Gb, last backup was yesterday {}"
},
"reuploadKey": "Force reupload key",
"reuploadedKey": "Key reuploaded",
"initialize": "Initialize",
"waitingForRebuild": "You will be able to create your first backup in a few minutes.",
"restore": "Restore from backup",
"no_backups": "There are no backups yet",
"create_new": "Create a new backup",
"creating": "Creating a new backup: {}%",
"restoring": "Restoring from backup",
"error_pending": "Server returned error, check it below",
"restore_alert": "You are about to restore from backup created on {}. All current data will be lost. Are you sure?",
"refresh": "Refresh status",
"refetchBackups": "Refetch backup list",
"refetchingList": "In a few minutes list will be updated"
},
"storage": {
"card_title": "Server Storage",
"status_ok": "Disk usage is OK",
"status_error": "Low disk space",
"disk_usage": "{} used",
"disk_total": "{} total · {}",
"gb": "{} GB",
"mb": "{} MB",
"kb": "{} KB",
"extend_volume_button": "Extend volume",
"extending_volume_title": "Extending volume",
"extending_volume_description": "Resizing volume will allow you to store more data on your server without extending the server itself. Volume can only be extended: shrinking is not possible.",
"extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by Hetzner. Server will be rebooted after resizing.",
"extending_volume_error": "Couldn't initialize volume extending.",
"size": "Size",
"euro": "Euro",
"data_migration_title": "Data migration",
"data_migration_notice": "During migration all services will be turned off.",
"start_migration_button": "Start migration",
"migration_process": "Migrating...",
"migration_done": "Finish"
"resource_chart": {
"month": "Month",
"day": "Day",
"hour": "Hour",
"cpu_title": "CPU Usage",
"network_title": "Network Usage",
"in": "In",
"out": "Out"
},
"server": {
"card_title": "Server",
"description": "All your services live here",
"general_information": "General information",
"resource_usage": "Resource usage",
"allow_autoupgrade": "Allow auto-upgrade",
"allow_autoupgrade_hint": "Allow automatic packages upgrades on server",
"reboot_after_upgrade": "Reboot after upgrade",
"reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server",
"server_timezone": "Server timezone",
"select_timezone": "Select timezone",
"server_id": "Server ID",
"status": "Status",
"cpu": "CPU",
"ram": "Memory",
"disk": "Disk local",
"monthly_cost": "Monthly cost",
"location": "Location",
"core_count": {
"one": "{} core",
"other": "{} cores"
}
},
"record": {
"root": "Root domain",
"api": "SelfPrivacy API",
"cloud": "File cloud",
"git": "Git server",
"meet": "Video conference",
"social": "Social network",
"password": "Password manager",
"vpn": "VPN",
"mx": "MX record",
"dmarc": "DMARC record",
"spf": "SPF record",
"dkim": "DKIM key"
},
"domain": {
"card_title": "Domain",
"screen_title": "Domain and DNS",
"ok": "Records are OK",
"error": "Problems found",
"error_subtitle": "Tap here to fix them",
"refreshing": "Refreshing status...",
"uninitialized": "Data is not retrieved yet",
"services_title": "Services",
"services_subtitle": "Type “A” records required for each service.",
"email_title": "Email",
"email_subtitle": "Records necessary for secure email exchange."
},
"backup": {
"card_title": "Backup",
"description": "Will save your day in case of incident: hackers attack, server deletion, etc.",
"reupload_key": "Force reupload key",
"reuploaded_key": "Key reuploaded",
"initialize": "Initialize",
"waiting_for_rebuild": "You will be able to create your first backup in a few minutes.",
"restore": "Restore from backup",
"no_backups": "There are no backups yet",
"create_new": "Create a new backup",
"creating": "Creating a new backup: {}%",
"restoring": "Restoring from backup",
"error_pending": "Server returned error, check it below",
"restore_alert": "You are about to restore from backup created on {}. All current data will be lost. Are you sure?",
"refresh": "Refresh status",
"refetch_backups": "Refetch backup list",
"refetching_list": "In a few minutes list will be updated"
},
"storage": {
"card_title": "Server Storage",
"status_ok": "Disk usage is OK",
"status_error": "Low disk space",
"disk_usage": "{} used",
"disk_total": "{} total · {}",
"gb": "{} GB",
"mb": "{} MB",
"kb": "{} KB",
"extend_volume_button": "Extend volume",
"extending_volume_title": "Extending volume",
"extending_volume_description": "Resizing volume will allow you to store more data on your server without extending the server itself. Volume can only be extended: shrinking is not possible.",
"extending_volume_price_info": "Price includes VAT and is estimated from pricing data provided by Hetzner. Server will be rebooted after resizing.",
"extending_volume_error": "Couldn't initialize volume extending.",
"size": "Size",
"euro": "Euro",
"data_migration_title": "Data migration",
"data_migration_notice": "During migration all services will be turned off.",
"start_migration_button": "Start migration",
"migration_process": "Migrating...",
"migration_done": "Finish"
},
"not_ready_card": {
"_comment": "Card shown when user skips initial setup",
"1": "Please finish application setup using ",
"2": "@:more.configuration_wizard",
"3": " for further work",
"begin": "Please finish application setup using ",
"insertion": "@:more.configuration_wizard",
"end": " for further work",
"in_menu": "Server is not set up yet. Please finish setup using setup wizard for further work."
},
"services": {
"_comment": "Services",
"title": "Your personal, private and independent services.",
"service_page": {
"open_in_browser": "Open in browser",
"restart": "Restart service",
"disable": "Disable service",
"enable": "Enable service",
"move": "Move to another volume",
"uses": "Uses {usage} on {volume}"
},
"mail": {
"title": "E-Mail",
"subtitle": "E-Mail for company and family.",
"login_info": "Use username and password from users tab. IMAP port is 143 with STARTTLS, SMTP port is 587 with STARTTLS.",
"bottom_sheet": {
"1": "To connect to the mailserver, please use {} domain alongside with username and password, that you created. Also feel free to invite",
"2": "new users"
}
},
"messenger": {
"title": "Messenger",
"subtitle": "Telegram or Signal not so private as Delta.Chat that uses your private server.",
"login_info": "Use the same username and password as for e-mail.",
"bottom_sheet": {
"1": "For connection, please use {} domain and credentials that you created."
}
},
"password_manager": {
"title": "Password Manager",
"subtitle": "Base of your security. Bitwarden will help you to create, store and move passwords between devices, as well as input them, when requested using autocompletion.",
"login_info": "You will have to create an account on the website.",
"bottom_sheet": {
"1": "You can connect to the service and create a user via this link:"
}
},
"video": {
"title": "Videomeet",
"subtitle": "Zoom and Google Meet are good, but Jitsi Meet is a worth alternative that also gives you confidence that you're not being listened.",
"login_info": "No account needed.",
"bottom_sheet": {
"1": "Using Jitsi as simple as just visiting this link:"
}
},
"cloud": {
"title": "Cloud Storage",
"subtitle": "Do not allow cloud services to read your data by using NextCloud.",
"login_info": "Login is admin, password is the same as with your main user. Create new accounts in Nextcloud interface.",
"bottom_sheet": {
"1": "You can connect and create a new user here:"
}
},
"social_network": {
"title": "Social Network",
"subtitle": "It's hard to believe, but it became possible to create your own social network, with your own rules and target audience.",
"login_info": "You will have to create an account on the website.",
"bottom_sheet": {
"1": "You can connect and create new social user here:"
}
},
"git": {
"title": "Git Server",
"subtitle": "Private alternative to the Github, that belongs to you, but not a Microsoft.",
"login_info": "You will have to create an account on the website. First user will become an admin.",
"bottom_sheet": {
"1": "You can connect and create a new user here:"
}
},
"vpn": {
"title": "VPN Server",
"subtitle": "Private VPN server",
"bottom_sheet": {
"1": "Openconnect VPN Server. Engine for secure and scalable VPN infrastructure"
}
},
"page": {
"up_and_running": "Up and running",
"resource_usage": "Resource usage",
"disk_used": "{} of disk space used",
"users": "Users",
"controlled_by": "Controlled by {}",
"apps": "Apps",
"settings": "Settings and maintenance"
"service_page": {
"open_in_browser": "Open in browser",
"restart": "Restart service",
"disable": "Disable service",
"enable": "Enable service",
"move": "Move to another volume",
"uses": "Uses {usage} on {volume}",
"status": {
"active": "Up and running",
"inactive": "Stopped",
"failed": "Failed to start",
"off": "Disabled",
"activating": "Activating",
"deactivating": "Deactivating",
"reloading": "Restarting"
}
},
"mail": {
"title": "E-Mail",
"subtitle": "E-Mail for company and family.",
"login_info": "Use username and password from users tab. IMAP port is 143 with STARTTLS, SMTP port is 587 with STARTTLS."
},
"password_manager": {
"title": "Password Manager",
"subtitle": "Base of your security. Bitwarden will help you to create, store and move passwords between devices, as well as input them, when requested using autocompletion.",
"login_info": "You will have to create an account on the website."
},
"video": {
"title": "Videomeet",
"subtitle": "Zoom and Google Meet are good, but Jitsi Meet is a worth alternative that also gives you confidence that you're not being listened.",
"login_info": "No account needed."
},
"cloud": {
"title": "Cloud Storage",
"subtitle": "Do not allow cloud services to read your data by using NextCloud.",
"login_info": "Login is admin, password is the same as with your main user. Create new accounts in Nextcloud interface."
},
"social_network": {
"title": "Social Network",
"subtitle": "It's hard to believe, but it became possible to create your own social network, with your own rules and target audience.",
"login_info": "You will have to create an account on the website."
},
"git": {
"title": "Git Server",
"subtitle": "Private alternative to the Github, that belongs to you, but not a Microsoft.",
"login_info": "You will have to create an account on the website. First user will become an admin."
},
"vpn": {
"title": "VPN Server",
"subtitle": "Private VPN server"
},
"users": {
"_comment": "'Users' tab",
"add_new_user": "Add a first user",
"new_user": "New user",
"delete_user": "Delete user",
"not_ready": "Please connect server, domain and DNS in the Providers tab, to be able to add a first user",
"nobody_here": "Nobody here",
"login": "Login",
"onboarding": "Onboarding",
"console": "Console",
"new_user_info_note": "New user will automatically be granted an access to all of the services",
"delete_confirm_question": "Are you sure?",
"reset_password": "Reset password",
@ -327,38 +256,34 @@
"could_not_delete_user": "Couldn't delete user",
"could_not_add_ssh_key": "Couldn't add SSH key",
"email_login": "Email login",
"no_sso_notice": "Only email and SSH accounts are created for this user. Single Sign On for all services is coming soon."
"no_ssh_notice": "Only email and SSH accounts are created for this user. Single Sign On for all services is coming soon."
},
"initializing": {
"_comment": "initializing page",
"1": "Connect a server",
"2": "A place where your data and SelfPrivacy services will reside:",
"connect_to_server": "Connect a server",
"place_where_data": "A place where your data and SelfPrivacy services will reside:",
"how": "How to obtain API token",
"hetzner_bad_key_error": "Hetzner API key is invalid",
"cloudflare_bad_key_error": "Cloudflare API key is invalid",
"backblaze_bad_key_error": "Backblaze storage information is invalid",
"3": "Connect CloudFlare",
"4": "To manage your domain's DNS",
"5": "CloudFlare API Token",
"6": "Connect Backblaze storage",
"7": "No connected domains at the moment",
"8": "Loading domains list",
"9": "Found more than one domain. For your own security, please be asked to delete unnecessary domains",
"10": "Save domain",
"connect_cloudflare": "Connect CloudFlare",
"manage_domain_dns": "To manage your domain's DNS",
"cloudflare_api_token": "CloudFlare API Token",
"connect_backblaze_storage": "Connect Backblaze storage",
"no_connected_domains": "No connected domains at the moment",
"loading_domain_list": "Loading domain list",
"found_more_domains": "Found more than one domain. For your own security, please be asked to delete unnecessary domains",
"save_domain": "Save domain",
"final": "Final step",
"11": "Create server",
"create_server": "Create server",
"what": "What does it mean?",
"13": "Server rebooted. Waiting for the last verification...",
"14": "Server started. It will be validated and rebooted now...",
"15": "Server created. DNS checks and server boot in progress...",
"16": "Until the next check: ",
"17": "Check",
"18": "How to obtain Hetzner API Token:'",
"19": "1 Go via this link ",
"20": "\n",
"21": "One more restart to apply your security certificates.",
"22": "Create master account",
"23": "Enter a nickname and strong password",
"server_rebooted": "Server rebooted. Waiting for the last verification...",
"server_started": "Server started. It will be validated and rebooted now...",
"server_created": "Server created. DNS checks and server boot in progress...",
"until_the_next_check": "Until the next check: ",
"check": "Check",
"one_more_restart": "One more restart to apply your security certificates.",
"create_master_account": "Create master account",
"enter_nickname_and_password": "Enter a nickname and strong password",
"finish": "Everything is initialized",
"checks": "Checks have been completed \n{} out of {}"
},
@ -451,19 +376,16 @@
"generation_error": "Couldn't generate a recovery key. {}"
},
"modals": {
"_comment": "messages in modals",
"1": "Server with such name, already exist.",
"1_1": "Unexpected error during placement from the provider side.",
"2": "Destroy server and create a new one?",
"2_2": "Try again?",
"3": "Are you sure?",
"4": "Purge all authentication keys?",
"5": "Yes, purge all my tokens",
"6": "Delete the server and volume?",
"7": "Yes",
"8": "Remove task",
"9": "Reboot",
"10": "You cannot use this API for domains with such TLD.",
"already_exists": "Such server already exists.",
"unexpected_error": "Unexpected error during placement from the provider side.",
"destroy_server": "Destroy the server and create a new one?",
"try_again": "Try again?",
"are_you_sure": "Are you sure?",
"purge_all_keys": "Purge all authentication keys?",
"purge_all_keys_confirm": "Yes, purge all my tokens",
"delete_server_volume": "Delete the server and volume?",
"reboot": "Reboot",
"you_cant_use_this_api": "You cannot use this API for domains with such TLD.",
"yes": "Yes",
"no": "No"
},
@ -471,27 +393,26 @@
"sec": "{} sec"
},
"jobs": {
"_comment": "Jobs list",
"title": "Jobs list",
"start": "Start",
"empty": "No jobs",
"createUser": "Create user",
"deleteUser": "Delete user",
"serviceTurnOff": "Turn off",
"serviceTurnOn": "Turn on",
"jobAdded": "Job added",
"runJobs": "Run jobs",
"rebootSuccess": "Server is rebooting",
"rebootFailed": "Couldn't reboot the server. Check the app logs.",
"configPullFailed": "Failed to pull configuration upgrade. Started software upgrade anyways.",
"upgradeSuccess": "Server upgrade started",
"upgradeFailed": "Failed to upgrade server",
"upgradeServer": "Upgrade server",
"rebootServer": "Reboot server",
"create_user": "Create user",
"delete_user": "Delete user",
"service_turn_off": "Turn off",
"service_turn_on": "Turn on",
"job_added": "Job added",
"run_jobs": "Run jobs",
"reboot_success": "Server is rebooting",
"reboot_failed": "Couldn't reboot the server. Check the app logs.",
"config_pull_failed": "Failed to pull configuration upgrade. Started software upgrade anyways.",
"upgrade_success": "Server upgrade started",
"upgrade_failed": "Failed to upgrade server",
"upgrade_server": "Upgrade server",
"reboot_server": "Reboot server",
"create_ssh_key": "Create SSH key for {}",
"delete_ssh_key": "Delete SSH key for {}",
"server_jobs": "Jobs on the server",
"resetUserPassword": "Reset password of user"
"reset_user_password": "Reset password of user"
},
"validations": {
"required": "Required.",

View File

@ -2,9 +2,10 @@
"test": "ru-test",
"locale": "ru",
"basis": {
"_comment": "базовые элементы интерфейса",
"providers": "Провайдеры",
"providers_title": "Ваш Дата Центр",
"services": "Сервисы",
"services_title": "Ваши личные, приватные и независимые сервисы.",
"users": "Пользователи",
"more": "Ещё",
"next": "Далее",
@ -29,41 +30,38 @@
"wait": "Загрузка",
"remove": "Удалить",
"apply": "Подать",
"done": "Готово"
"done": "Готово",
"continue": "Продолжить"
},
"more": {
"_comment": "вкладка ещё",
"more_page": {
"configuration_wizard": "Мастер Подключения",
"about_project": "О проекте SelfPrivacy",
"about_app": "О приложении",
"about_application": "О приложении",
"onboarding": "Приветствие",
"console": "Консоль",
"create_ssh_key": "Создать ssh ключ",
"generate_key": "Сгенерировать ключ",
"generate_key_text": "Вы сможете сгенерировать ключ",
"remove": "Отключить",
"enable": "Включить",
"ok": "ok",
"continue": "Продолжить",
"ssh_key_exist_text": "У Вас уже есть сгенерированный ssh ключ",
"yes_delete": "Да, удалить",
"share": "Поделиться",
"copy_buffer": "Копировать в буфер",
"copied_ssh": "SSH ключ cкопирован в буфер",
"delete_ssh_text": "Удалить SSH ключ?",
"about_app_page": {
"application_version_text": "Версия приложения v.{}",
"api_version_text": "Версия API сервера v.{}"
},
"settings": {
"title": "Настройки приложения",
"1": "Тёмная тема",
"2": "Сменить цветовую тему.",
"3": "Сброс настроек",
"4": "Сбросить API ключи а также root пользвателя.",
"5": "Удалить сервер",
"6": "Действие приведет к удалению сервера. После этого он будет недоступен."
}
"application_settings": "Настройки приложения"
},
"console_page": {
"title": "Консоль",
"waiting": "Ждём инициализации..."
},
"about_us_page": {
"title": "О проекте SelfPrivacy"
},
"about_application_page": {
"title": "О приложении",
"application_version_text": "Версия приложения v.{}",
"api_version_text": "Версия API сервера v.{}"
},
"application_settings": {
"title": "Настройки приложения",
"dark_theme_title": "Тёмная тема",
"dark_theme_description": "Сменить цветовую тему.",
"reset_config_title": "Сброс настроек",
"reset_config_description": "Сбросить API ключи а также root пользвателя.",
"delete_server_title": "Удалить сервер",
"delete_server_description": "Действие приведет к удалению сервера. После этого он будет недоступен."
},
"ssh": {
"title": "SSH ключи",
@ -73,285 +71,213 @@
"subtitle_with_keys": "Ключей: {}",
"subtitle_without_keys": "Ключей нет",
"no_key_name": "Безымянный ключ",
"root": {
"title": "Это ключи суперпользователя",
"subtitle": "Владельцы указанных здесь ключей получают полный доступ к данным и настройкам сервера. Добавляйте исключительно свои ключи."
},
"root_title": "Это ключи суперпользователя",
"root_subtitle": "Владельцы указанных здесь ключей получают полный доступ к данным и настройкам сервера. Добавляйте исключительно свои ключи.",
"input_label": "Публичный ED25519 или RSA ключ"
},
"onboarding": {
"_comment": "страницы онбординга",
"page1_title": "Цифровая независимость доступна каждому",
"page1_text": "Почта, VPN, Мессенджер, социальная сеть и многое другое на Вашем личном сервере, под Вашим полным контролем.",
"page2_title": "SelfPrivacy — это не облако, а Ваш личный дата-центр",
"page2_text": "SelfPrivacy работает только с вашими сервис-провайдерами: Hetzner, Cloudflare, Backblaze. Если у Вас нет учётных записей, мы поможем их создать."
},
"providers": {
"_comment": "вкладка провайдеры",
"page_title": "Ваш Дата-центр",
"server": {
"card_title": "Сервер",
"status": "Статус — в норме",
"bottom_sheet": {
"1": "Это виртуальный компьютер на котором работают все Ваши сервисы.",
"2": "Общая информация",
"3": "Размещение"
},
"chart": {
"month": "Месяц",
"day": "День",
"hour": "Час",
"cpu_title": "Использование процессора",
"network_title": "Использование сети",
"in": "Получено",
"out": "Отправлено"
},
"settings": {
"allow_autoupgrade": "Разрешить авто-обноления",
"allow_autoupgrade_hint": "Разрешить автоматичесую установку обновлений на сервер",
"reboot_after_upgrade": "Перезагружать после обновлений",
"reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений",
"server_timezone": "Часовой пояс сервера",
"select_timezone": "Выберите часовой пояс"
},
"info": {
"server_id": "ID сервера",
"status": "Статус",
"cpu": "Процессор",
"ram": "Операивная память",
"disk": "Диск",
"monthly_cost": "Ежемесячная стоимость",
"location": "Размещение",
"core_count": {
"one": "{} ядро",
"two": "{} ядра",
"few": "{} ядра",
"many": "{} ядер",
"other": "{} ядер"
}
}
},
"domain": {
"card_title": "Домен",
"status": "Статус — в норме",
"bottom_sheet": {
"1": "Это ваш личный адрес в интернете, который будет указывать на сервер и другие ваши сервисы."
},
"screen_title": "Домен и DNS",
"states": {
"ok": "Записи в норме",
"error": "Обнаружены проблемы",
"error_subtitle": "Нажмите здесь, чтобы исправить",
"refreshing": "Обновление данных...",
"uninitialized": "Данные ещё не получены"
},
"record_description": {
"root": "Корневой домен",
"api": "SelfPrivacy API",
"cloud": "Файловое облако",
"git": "Git сервер",
"meet": "Видеоконференции",
"social": "Социальная сеть",
"password": "Менеджер паролей",
"vpn": "VPN",
"mx": "MX запись",
"dmarc": "DMARC запись",
"spf": "SPF запись",
"dkim": "DKIM ключ"
},
"cards": {
"services": {
"title": "Сервисы",
"subtitle": "Записи типа “A” необходимые для работы сервисов."
},
"email": {
"title": "Электронная почта",
"subtitle": "Записи необходимые для безопасного обмена электронной почтой."
}
}
},
"backup": {
"card_title": "Резервное копирование",
"status": "Статус — в норме",
"bottom_sheet": {
"1": "Выручит Вас в любой ситуации: хакерская атака, удаление сервера и т.д.",
"2": "Использовано 3Gb из бесплатых 10Gb. Последнее копирование была сделано вчера в {}."
},
"reuploadKey": "Принудительно обновить ключ",
"reuploadedKey": "Ключ на сервере обновлён",
"initialize": "Настроить",
"waitingForRebuild": "Через несколько минут можно будет создать первую копию.",
"restore": "Восстановить из копии",
"no_backups": "Резервных копий пока нет",
"create_new": "Создать новую копию",
"creating": "Создание копии: {}%",
"restoring": "Восстановление из копии",
"error_pending": "Сервер вернул ошибку: проверьте её ниже.",
"restore_alert": "Вы собираетесь восстановить из копии созданной {}. Все текущие данные будут потеряны. Вы уверены?",
"refresh": "Обновить статус",
"refetchBackups": "Обновить список копий",
"refetchingList": "Через несколько минут список будет обновлён"
},
"storage": {
"card_title": "Хранилище",
"status_ok": "Проблем на диске не обнаружено",
"status_error": "Заканчивается место на диске",
"disk_usage": "{} использовано",
"disk_total": "{} всего · {}",
"gb": "{} GB",
"mb": "{} MB",
"kb": "{} KB",
"extend_volume_button": "Расширить хранилище",
"extending_volume_title": "Расширение хранилища",
"extending_volume_description": "Изменение размера хранилища позволит вам держать больше данных на вашем сервере без расширения самого сервера. Объем можно только увеличить: уменьшить нельзя.",
"extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных Hetzner. Сервер будет перезагружен во время процесса.",
"extending_volume_error": "Не удалось начать расширение хранилища.",
"size": "Размер",
"euro": "Евро",
"data_migration_title": "Миграция данных",
"data_migration_notice": "На время миграции данных все сервисы будут выключены.",
"start_migration_button": "Начать миграцию",
"migration_process": "Мигрируем...",
"migration_done": "Завершить"
"resource_chart": {
"month": "Месяц",
"day": "День",
"hour": "Час",
"cpu_title": "Использование процессора",
"network_title": "Использование сети",
"in": "Получено",
"out": "Отправлено"
},
"server": {
"card_title": "Сервер",
"description": "Это виртуальный компьютер на котором работают все Ваши сервисы.",
"general_information": "Общая информация",
"resource_usage": "Потребление ресурсов",
"allow_autoupgrade": "Разрешить авто-обноления",
"allow_autoupgrade_hint": "Разрешить автоматичесую установку обновлений на сервер",
"reboot_after_upgrade": "Перезагружать после обновлений",
"reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений",
"server_timezone": "Часовой пояс сервера",
"select_timezone": "Выберите часовой пояс",
"server_id": "ID сервера",
"status": "Статус",
"cpu": "Процессор",
"ram": "Оперативная память",
"disk": "Диск",
"monthly_cost": "Ежемесячная стоимость",
"location": "Размещение",
"core_count": {
"one": "{} ядро",
"two": "{} ядра",
"few": "{} ядра",
"many": "{} ядер",
"other": "{} ядер"
}
},
"record": {
"root": "Корневой домен",
"api": "SelfPrivacy API",
"cloud": "Файловое облако",
"git": "Git сервер",
"meet": "Видеоконференции",
"social": "Социальная сеть",
"password": "Менеджер паролей",
"vpn": "VPN",
"mx": "MX запись",
"dmarc": "DMARC запись",
"spf": "SPF запись",
"dkim": "DKIM ключ"
},
"domain": {
"card_title": "Домен",
"screen_title": "Домен и DNS",
"ok": "Записи в норме",
"error": "Обнаружены проблемы",
"error_subtitle": "Нажмите здесь, чтобы исправить",
"refreshing": "Обновление данных...",
"uninitialized": "Данные ещё не получены",
"services_title": "Сервисы",
"services_subtitle": "Записи типа “A” необходимые для работы сервисов.",
"email_title": "Электронная почта",
"email_subtitle": "Записи необходимые для безопасного обмена электронной почтой."
},
"backup": {
"card_title": "Резервное копирование",
"description": "Выручит Вас в любой ситуации: хакерская атака, удаление сервера и т.д.",
"reupload_key": "Принудительно обновить ключ",
"reuploaded_key": "Ключ на сервере обновлён",
"initialize": "Настроить",
"waiting_for_rebuild": "Через несколько минут можно будет создать первую копию.",
"restore": "Восстановить из копии",
"no_backups": "Резервных копий пока нет",
"create_new": "Создать новую копию",
"creating": "Создание копии: {}%",
"restoring": "Восстановление из копии",
"error_pending": "Сервер вернул ошибку: проверьте её ниже.",
"restore_alert": "Вы собираетесь восстановить из копии созданной {}. Все текущие данные будут потеряны. Вы уверены?",
"refresh": "Обновить статус",
"refetch_backups": "Обновить список копий",
"refetching_list": "Через несколько минут список будет обновлён"
},
"storage": {
"card_title": "Хранилище",
"status_ok": "Проблем на диске не обнаружено",
"status_error": "Заканчивается место на диске",
"disk_usage": "{} использовано",
"disk_total": "{} всего · {}",
"gb": "{} GB",
"mb": "{} MB",
"kb": "{} KB",
"extend_volume_button": "Расширить хранилище",
"extending_volume_title": "Расширение хранилища",
"extending_volume_description": "Изменение размера хранилища позволит вам держать больше данных на вашем сервере без расширения самого сервера. Объем можно только увеличить: уменьшить нельзя.",
"extending_volume_price_info": "Цена включает НДС и рассчитана на основе данных о ценах, предоставленных Hetzner. Сервер будет перезагружен во время процесса.",
"extending_volume_error": "Не удалось начать расширение хранилища.",
"size": "Размер",
"euro": "Евро",
"data_migration_title": "Миграция данных",
"data_migration_notice": "На время миграции данных все сервисы будут выключены.",
"start_migration_button": "Начать миграцию",
"migration_process": "Мигрируем...",
"migration_done": "Завершить"
},
"not_ready_card": {
"_comment": "Карточка показывающая когда человек скипнул настройку, на карте текст из 3 блоков, средний содержит ссыку на мастер подключения",
"1": "Завершите настройку приложения используя ",
"2": "@:more.configuration_wizard",
"3": " для продолжения работы",
"begin": "Завершите настройку приложения используя ",
"insertion": "@:more.configuration_wizard",
"end": " для продолжения работы",
"in_menu": "Сервер ещё не настроен, воспользуйтесь мастером подключения."
},
"services": {
"_comment": "Вкладка сервисы",
"title": "Ваши личные, приватные и независимые сервисы:",
"service_page": {
"open_in_browser": "Открыть в браузере",
"restart": "Перезапустить сервис",
"disable": "Выключить сервис",
"enable": "Включить сервис",
"move": "Переместить на другой диск",
"uses": "Использует {usage} на {volume}"
},
"mail": {
"title": "Почта",
"subtitle": "Электронная почта для семьи или компании.",
"login_info": "Используйте логин и пароль из вкладки пользователей. IMAP порт: 143, STARTTLS. SMTP порт: 587, STARTTLS.",
"bottom_sheet": {
"1": "Для подключения почтового ящика используйте {} и профиль, который Вы создали. Так же приглашайте",
"2": "новых пользователей."
}
},
"messenger": {
"title": "Мессенджер",
"subtitle": "Telegram и Signal не так приватны, как Delta.Chat — он использует Ваш личный сервер.",
"login_info": "Используйте те же логин и пароль, что и для почты.",
"bottom_sheet": {
"1": "Для подключения используйте {} и логин пароль, который Вы создали."
}
},
"password_manager": {
"title": "Менеджер паролей",
"subtitle": "Это фундамент Вашей безопасности. Создавать, хранить, копировать пароли между устройствами и вбивать их в формы поможет Bitwarden.",
"login_info": "Аккаунт нужно создать на сайте.",
"bottom_sheet": {
"1": "Подключиться к серверу и создать пользователя можно по адресу:."
}
},
"video": {
"title": "Видеоконференция",
"subtitle": "Jitsi meet — отличный аналог Zoom и Google meet который помимо удобства ещё и гарантирует Вам защищённые высококачественные видеоконференции.",
"login_info": "Аккаунт не требуется.",
"bottom_sheet": {
"1": "Для использования просто перейдите по ссылке:."
}
},
"cloud": {
"title": "Файловое облако",
"subtitle": "Не позволяйте облачным сервисам просматривать ваши данные. Используйте NextCloud — надёжный дом для всех Ваших данных.",
"login_info": "Логин администратора: admin, пароль такой же как у основного пользователя. Создавайте новых пользователей в интерфейсе администратора NextCloud.",
"bottom_sheet": {
"1": "Подключиться к серверу и создать пользователя можно по адресу:."
}
},
"social_network": {
"title": "Социальная сеть",
"subtitle": "Сложно поверить, но стало возможным создать свою собственную социальную сеть, со своими правилами и аудиторией.",
"login_info": "Аккаунт нужно создать на сайте.",
"bottom_sheet": {
"1": "Подключиться к серверу и создать пользователя можно по адресу:."
}
},
"git": {
"title": "Git-сервер",
"subtitle": "Приватная альтернатива Github, которая принадлежит вам, а не Microsoft.",
"login_info": "Аккаунт нужно создать на сайте. Первый зарегистрированный пользователь становится администратором.",
"bottom_sheet": {
"1": "Подключиться к серверу и создать пользователя можно по адресу:."
}
},
"vpn": {
"title": "VPN сервер",
"subtitle": "Закрытый VPN сервер",
"bottom_sheet": {
"1": "Создать подключиться к VPN-серверу. Движок для безопасной и масштабируемой инфраструктуры VPN"
}
},
"page": {
"up_and_running": "Запущен и работает",
"resource_usage": "Потребление ресурсов",
"disk_used": "{} использовано места на диске",
"users": "Пользователи",
"controlled_by": "Контролируется {}",
"apps": "Приложения",
"settings": "Настройки"
}
"service_page": {
"open_in_browser": "Открыть в браузере",
"restart": "Перезапустить сервис",
"disable": "Выключить сервис",
"enable": "Включить сервис",
"move": "Переместить на другой диск",
"uses": "Использует {usage} на {volume}"
},
"mail": {
"title": "Почта",
"subtitle": "Электронная почта для семьи или компании.",
"login_info": "Используйте логин и пароль из вкладки пользователей. IMAP порт: 143, STARTTLS. SMTP порт: 587, STARTTLS."
},
"password_manager": {
"title": "Менеджер паролей",
"subtitle": "Это фундамент Вашей безопасности. Создавать, хранить, копировать пароли между устройствами и вбивать их в формы поможет Bitwarden.",
"login_info": "Аккаунт нужно создать на сайте."
},
"video": {
"title": "Видеоконференция",
"subtitle": "Jitsi meet — отличный аналог Zoom и Google meet который помимо удобства ещё и гарантирует Вам защищённые высококачественные видеоконференции.",
"login_info": "Аккаунт не требуется."
},
"cloud": {
"title": "Файловое облако",
"subtitle": "Не позволяйте облачным сервисам просматривать ваши данные. Используйте NextCloud — надёжный дом для всех Ваших данных.",
"login_info": "Логин администратора: admin, пароль такой же как у основного пользователя. Создавайте новых пользователей в интерфейсе администратора NextCloud."
},
"social_network": {
"title": "Социальная сеть",
"subtitle": "Сложно поверить, но стало возможным создать свою собственную социальную сеть, со своими правилами и аудиторией.",
"login_info": "Аккаунт нужно создать на сайте."
},
"git": {
"title": "Git-сервер",
"subtitle": "Приватная альтернатива Github, которая принадлежит вам, а не Microsoft.",
"login_info": "Аккаунт нужно создать на сайте. Первый зарегистрированный пользователь становится администратором."
},
"vpn": {
"title": "VPN сервер",
"subtitle": "Закрытый VPN сервер"
},
"users": {
"_comment": "'Users' tab",
"add_new_user": "Добавьте первого пользователя.",
"new_user": "Новый пользователь",
"delete_user": "Удалить пользователя",
"not_ready": "Подключите сервер, домен и DNS в разделе Провайдеры чтобы добавить первого пользователя",
"nobody_here": "Здесь будут отображаться пользователи.",
"login": "Логин",
"onboarding": "Приветствие",
"console": "Консоль разработчика",
"new_user_info_note": "Новый пользователь автоматически получит доступ ко всем сервисам.",
"delete_confirm_question": "Вы действительно хотите удалить учетную запись?",
"reset_password": "Сбросить пароль",
"account": "Учетная запись",
"send_registration_data": "Поделиться реквизитами"
"send_registration_data": "Поделиться реквизитами",
"could_not_fetch_users": "Не удалось получить пользователей",
"could_not_fetch_description": "Проверьте интернет соединение и попробуйте снова",
"refresh_users": "Обновить список пользователей",
"could_not_create_user": "Не удалось создать пользователя",
"could_not_delete_user": "Не удалось стереть пользователя",
"could_not_add_ssh_key": "Не удалось создать SSH ключить",
"email_login": "Авторизация по Email",
"no_ssh_notice": "Для этого пользователя созданы только SSH и Email аккаунты. Единая авторизация для всех сервисов ещё не реализована."
},
"initializing": {
"_comment": "initializing page",
"1": "Подключите сервер",
"2": "Здесь будут жить наши данные и SelfPrivacy-сервисы",
"connect_to_server": "Подключите сервер",
"place_where_data": "Здесь будут жить наши данные и SelfPrivacy-сервисы",
"how": "Как получить API Token",
"hetzner_bad_key_error": "Hetzner API ключ неверен",
"cloudflare_bad_key_error": "Cloudflare API ключ неверен",
"backblaze_bad_key_error": "Информация о Backblaze хранилище неверна",
"3": "Подключите CloudFlare",
"4": "Для управления DNS вашего домена",
"5": "CloudFlare API Token",
"6": "Подключите облачное хранилище Backblaze",
"7": "На данный момент подлюченных доменов нет",
"8": "Загружаем список доменов",
"9": "Найдено больше одного домена, для вашей безопастности, просим Вам удалить не нужные домены",
"10": "Сохранить домен",
"connect_cloudflare": "Подключите CloudFlare",
"manage_domain_dns": "Для управления DNS вашего домена",
"cloudflare_api_token": "CloudFlare API Token",
"connect_backblaze_storage": "Подключите облачное хранилище Backblaze",
"no_connected_domains": "На данный момент подлюченных доменов нет",
"loading_domain_list": "Загружаем список доменов",
"found_more_domains": "Найдено больше одного домена, для вашей безопастности, просим Вам удалить не нужные домены",
"save_domain": "Сохранить домен",
"final": "Последний шаг",
"11": "Создать сервер",
"create_server": "Создать сервер",
"what": "Что это значит?",
"13": "Сервер презагружен, ждем последнюю проверку.",
"14": "Cервер запущен, сейчас он будет проверен и перезагружен.",
"15": "Cервер создан, идет проверка ДНС адресов и запуск сервера.",
"16": "До следующей проверки: ",
"17": "Проверка",
"18": "Как получить Hetzner API Token:'",
"19": "1 Переходим по ссылке ",
"20": "\n2 Заходим в созданный нами проект. Если такового нет - значит создаём.\n3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).\n4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.\n5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же Вы используете мобильную версию сайта - в нижнем правом углу Вы увидите красный плюсик. Нажимаем на эту кнопку.\n6 В поле Description даём нашему токену название (это может быть любое название, которое Вам нравиться, сути оно не меняет.",
"21": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности",
"22": "Создайте главную учетную запись",
"23": "Введите никнейм и сложный пароль",
"server_rebooted": "Сервер презагружен, ждем последнюю проверку.",
"server_started": "Cервер запущен, сейчас он будет проверен и перезагружен.",
"server_created": "Cервер создан, идет проверка ДНС адресов и запуск сервера.",
"until_the_next_check": "До следующей проверки: ",
"check": "Проверка",
"one_more_restart": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности",
"create_master_account": "Создайте главную учетную запись",
"enter_nickname_and_password": "Введите никнейм и сложный пароль",
"finish": "Всё инициализировано.",
"checks": "Проверок выполнено: \n{} / {}"
},
@ -444,19 +370,16 @@
"generation_error": "Не удалось сгенерировать ключ. {}"
},
"modals": {
"_comment": "messages in modals",
"1": "Сервер с таким именем уже существует.",
"1.1": "Непредвиденная ошибка при создании со стороны провайдера.",
"2": "Уничтожить сервер и создать новый?",
"2.2": "Попробовать ещё раз?",
"3": "Подтвердите",
"4": "Сбросить все ключи?",
"5": "Да, сбросить",
"6": "Удалить сервер и диск?",
"7": "Да, удалить",
"8": "Удалить задачу",
"9": "Перезагрузить",
"10": "API не поддерживает домены с таким TLD.",
"already_exists": "Такой сервер уже существует.",
"unexpected_error": "Непредвиденная ошибка со стороны провайдера.",
"destroy_server": "Уничтожить сервер и создать новый?",
"try_again": "Попробовать ещё раз?",
"are_you_sure": "Вы уверены?",
"purge_all_keys": "Стереть все ключи авторизации?",
"purge_all_keys_confirm": "Да, стереть все ключи!",
"delete_server_volume": "Удалить сервер и хранилище?",
"reboot": "Перезагрузить",
"you_cant_use_this_api": "Нельзя использовать этот API для доменом с подобным TLD.",
"yes": "Да",
"no": "Нет"
},
@ -464,27 +387,26 @@
"sec": "{} сек"
},
"jobs": {
"_comment": "Jobs list",
"title": "Задачи",
"start": "Начать выполенение",
"empty": "Пусто.",
"createUser": "Создать пользователя",
"deleteUser": "Удалить пользователя",
"serviceTurnOff": "Остановить",
"serviceTurnOn": "Запустить",
"jobAdded": "Задача добавленна",
"runJobs": "Запустите задачи",
"rebootSuccess": "Сервер перезагружается",
"rebootFailed": "Не удалось перезагрузить сервер, проверьте логи",
"configPullFailed": "Не удалось обновить конфигурацию сервера. Обновление ПО запущено.",
"upgradeSuccess": "Запущено обновление сервера",
"upgradeFailed": "Обновить сервер не вышло",
"upgradeServer": "Обновить сервер",
"rebootServer": "Перезагрузить сервер",
"create_user": "Создать пользователя",
"delete_user": "Удалить пользователя",
"service_turn_off": "Остановить",
"service_turn_on": "Запустить",
"job_added": "Задача добавленна",
"run_jobs": "Запустите задачи",
"reboot_success": "Сервер перезагружается",
"reboot_failed": "Не удалось перезагрузить сервер, проверьте логи",
"config_pull_failed": "Не удалось обновить конфигурацию сервера. Обновление ПО запущено.",
"upgrade_success": "Запущено обновление сервера",
"upgrade_failed": "Обновить сервер не вышло",
"upgrade_server": "Обновить сервер",
"reboot_server": "Перезагрузить сервер",
"create_ssh_key": "Создать SSH ключ для {}",
"delete_ssh_key": "Удалить SSH ключ для {}",
"server_jobs": "Задачи на сервере",
"resetUserPassword": "Сбросить пароль пользователя"
"reset_user_password": "Сбросить пароль пользователя"
},
"validations": {
"required": "Обязательное поле.",

View File

@ -13,6 +13,7 @@ class Localization extends StatelessWidget {
supportedLocales: const [Locale('ru'), Locale('en')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
useFallbackTranslations: true,
saveLocale: false,
useOnlyLangCode: true,
child: child!,

View File

@ -51,55 +51,55 @@ extension ServiceTypesExt on ServiceTypes {
String get title {
switch (this) {
case ServiceTypes.mailserver:
return 'services.mail.title'.tr();
return 'mail.title'.tr();
case ServiceTypes.bitwarden:
return 'services.password_manager.title'.tr();
return 'password_manager.title'.tr();
case ServiceTypes.jitsi:
return 'services.video.title'.tr();
return 'video.title'.tr();
case ServiceTypes.nextcloud:
return 'services.cloud.title'.tr();
return 'cloud.title'.tr();
case ServiceTypes.pleroma:
return 'services.social_network.title'.tr();
return 'social_network.title'.tr();
case ServiceTypes.gitea:
return 'services.git.title'.tr();
return 'git.title'.tr();
case ServiceTypes.ocserv:
return 'services.vpn.title'.tr();
return 'vpn.title'.tr();
}
}
String get subtitle {
switch (this) {
case ServiceTypes.mailserver:
return 'services.mail.subtitle'.tr();
return 'mail.subtitle'.tr();
case ServiceTypes.bitwarden:
return 'services.password_manager.subtitle'.tr();
return 'password_manager.subtitle'.tr();
case ServiceTypes.jitsi:
return 'services.video.subtitle'.tr();
return 'video.subtitle'.tr();
case ServiceTypes.nextcloud:
return 'services.cloud.subtitle'.tr();
return 'cloud.subtitle'.tr();
case ServiceTypes.pleroma:
return 'services.social_network.subtitle'.tr();
return 'social_network.subtitle'.tr();
case ServiceTypes.gitea:
return 'services.git.subtitle'.tr();
return 'git.subtitle'.tr();
case ServiceTypes.ocserv:
return 'services.vpn.subtitle'.tr();
return 'vpn.subtitle'.tr();
}
}
String get loginInfo {
switch (this) {
case ServiceTypes.mailserver:
return 'services.mail.login_info'.tr();
return 'mail.login_info'.tr();
case ServiceTypes.bitwarden:
return 'services.password_manager.login_info'.tr();
return 'password_manager.login_info'.tr();
case ServiceTypes.jitsi:
return 'services.video.login_info'.tr();
return 'video.login_info'.tr();
case ServiceTypes.nextcloud:
return 'services.cloud.login_info'.tr();
return 'cloud.login_info'.tr();
case ServiceTypes.pleroma:
return 'services.social_network.login_info'.tr();
return 'social_network.login_info'.tr();
case ServiceTypes.gitea:
return 'services.git.login_info'.tr();
return 'git.login_info'.tr();
case ServiceTypes.ocserv:
return '';
}

View File

@ -135,7 +135,7 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
} else {
await api.uploadBackblazeConfig(bucket);
emit(state.copyWith(isInitialized: true, preventActions: false));
getIt<NavigationService>().showSnackBar('providers.backup.reuploadedKey');
getIt<NavigationService>().showSnackBar('backup.reuploaded_key');
}
}
@ -173,8 +173,7 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
Future<void> forceUpdateBackups() async {
emit(state.copyWith(preventActions: true));
await api.forceBackupListReload();
getIt<NavigationService>()
.showSnackBar('providers.backup.refetchingList'.tr());
getIt<NavigationService>().showSnackBar('backup.refetching_list'.tr());
emit(state.copyWith(preventActions: false));
}

View File

@ -30,7 +30,7 @@ class JobsCubit extends Cubit<JobsState> {
newJobsList.addAll(jobsState.clientJobList);
}
newJobsList.add(job);
getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
getIt<NavigationService>().showSnackBar('jobs.job_added'.tr());
emit(JobsStateWithJobs(newJobsList));
}
@ -53,7 +53,7 @@ class JobsCubit extends Cubit<JobsState> {
removeJob(removingJob.id);
} else {
newJobsList.add(job);
getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
getIt<NavigationService>().showSnackBar('jobs.job_added'.tr());
emit(JobsStateWithJobs(newJobsList));
}
}
@ -67,7 +67,7 @@ class JobsCubit extends Cubit<JobsState> {
newJobsList.any((final el) => el is CreateSSHKeyJob);
if (!isExistInJobList) {
newJobsList.add(job);
getIt<NavigationService>().showSnackBar('jobs.jobAdded'.tr());
getIt<NavigationService>().showSnackBar('jobs.job_added'.tr());
emit(JobsStateWithJobs(newJobsList));
}
}
@ -76,9 +76,9 @@ class JobsCubit extends Cubit<JobsState> {
emit(JobsStateLoading());
final bool isSuccessful = await api.reboot();
if (isSuccessful) {
getIt<NavigationService>().showSnackBar('jobs.rebootSuccess'.tr());
getIt<NavigationService>().showSnackBar('jobs.reboot_success'.tr());
} else {
getIt<NavigationService>().showSnackBar('jobs.rebootFailed'.tr());
getIt<NavigationService>().showSnackBar('jobs.reboot_failed'.tr());
}
emit(JobsStateEmpty());
}
@ -89,12 +89,12 @@ class JobsCubit extends Cubit<JobsState> {
final bool isSuccessful = await api.upgrade();
if (isSuccessful) {
if (!isPullSuccessful) {
getIt<NavigationService>().showSnackBar('jobs.configPullFailed'.tr());
getIt<NavigationService>().showSnackBar('jobs.config_pull_failed'.tr());
} else {
getIt<NavigationService>().showSnackBar('jobs.upgradeSuccess'.tr());
getIt<NavigationService>().showSnackBar('jobs.upgrade_success'.tr());
}
} else {
getIt<NavigationService>().showSnackBar('jobs.upgradeFailed'.tr());
getIt<NavigationService>().showSnackBar('jobs.upgrade_failed'.tr());
}
emit(JobsStateEmpty());
}

View File

@ -51,8 +51,7 @@ class DnsRecordsCubit
_getDesiredDnsRecords(domain.domainName, ipAddress, dkimPublicKey);
final List<DesiredDnsRecord> foundRecords = [];
for (final DesiredDnsRecord record in desiredRecords) {
if (record.description ==
'providers.domain.record_description.dkim') {
if (record.description == 'record.dkim') {
final DnsRecord foundRecord = records.firstWhere(
(final r) => r.name == record.name && r.type == record.type,
orElse: () => DnsRecord(
@ -146,61 +145,61 @@ class DnsRecordsCubit
DesiredDnsRecord(
name: domainName,
content: ipAddress,
description: 'providers.domain.record_description.root',
description: 'record.root',
),
DesiredDnsRecord(
name: 'api.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.api',
description: 'record.api',
),
DesiredDnsRecord(
name: 'cloud.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.cloud',
description: 'record.cloud',
),
DesiredDnsRecord(
name: 'git.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.git',
description: 'record.git',
),
DesiredDnsRecord(
name: 'meet.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.meet',
description: 'record.meet',
),
DesiredDnsRecord(
name: 'social.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.social',
description: 'record.social',
),
DesiredDnsRecord(
name: 'password.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.password',
description: 'record.password',
),
DesiredDnsRecord(
name: 'vpn.$domainName',
content: ipAddress,
description: 'providers.domain.record_description.vpn',
description: 'record.vpn',
),
DesiredDnsRecord(
name: domainName,
content: domainName,
description: 'providers.domain.record_description.mx',
description: 'record.mx',
type: 'MX',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: '_dmarc.$domainName',
content: 'v=DMARC1; p=none',
description: 'providers.domain.record_description.dmarc',
description: 'record.dmarc',
type: 'TXT',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: domainName,
content: 'v=spf1 a mx ip4:$ipAddress -all',
description: 'providers.domain.record_description.spf',
description: 'record.spf',
type: 'TXT',
category: DnsRecordsCategory.email,
),
@ -208,7 +207,7 @@ class DnsRecordsCubit
DesiredDnsRecord(
name: 'selector._domainkey.$domainName',
content: dkimPublicKey,
description: 'providers.domain.record_description.dkim',
description: 'record.dkim',
type: 'TXT',
category: DnsRecordsCategory.email,
),

View File

@ -86,7 +86,7 @@ class ApiProviderVolumeCubit
if (!resized) {
getIt<NavigationService>().showSnackBar(
'providers.storage.extending_volume_error'.tr(),
'storage.extending_volume_error'.tr(),
);
emit(state.copyWith(isResizing: false));
return false;

View File

@ -250,8 +250,8 @@ class ServerInstallationRepository {
final NavigationService nav = getIt.get<NavigationService>();
nav.showPopUpDialog(
BrandAlert(
title: 'modals.1'.tr(),
contentText: 'modals.2'.tr(),
title: 'modals.already_exists'.tr(),
contentText: 'modals.destroy_server'.tr(),
actions: [
ActionButton(
text: 'basis.delete'.tr(),
@ -291,11 +291,11 @@ class ServerInstallationRepository {
final NavigationService nav = getIt.get<NavigationService>();
nav.showPopUpDialog(
BrandAlert(
title: 'modals.1_1'.tr(),
contentText: 'modals.2_2'.tr(),
title: 'modals.unexpected_error'.tr(),
contentText: 'modals.try_again'.tr(),
actions: [
ActionButton(
text: 'modals.7'.tr(),
text: 'modals.yes'.tr(),
isRed: true,
onPressed: () async {
ServerHostingDetails? serverDetails;
@ -353,9 +353,9 @@ class ServerInstallationRepository {
nav.showPopUpDialog(
BrandAlert(
title: e.response!.data['errors'][0]['code'] == 1038
? 'modals.10'.tr()
: 'providers.domain.states.error'.tr(),
contentText: 'modals.6'.tr(),
? 'modals.you_cant_use_this_api'.tr()
: 'domain.states.error'.tr(),
contentText: 'modals.delete_server_volume'.tr(),
actions: [
ActionButton(
text: 'basis.delete'.tr(),

View File

@ -28,11 +28,11 @@ class DiskSize {
if (byte < 1024) {
return '${byte.toStringAsFixed(0)} ${tr('bytes')}';
} else if (byte < 1024 * 1024) {
return 'providers.storage.kb'.tr(args: [kibibyte.toStringAsFixed(1)]);
return 'storage.kb'.tr(args: [kibibyte.toStringAsFixed(1)]);
} else if (byte < 1024 * 1024 * 1024) {
return 'providers.storage.mb'.tr(args: [mebibyte.toStringAsFixed(1)]);
return 'storage.mb'.tr(args: [mebibyte.toStringAsFixed(1)]);
} else {
return 'providers.storage.gb'.tr(args: [gibibyte.toStringAsFixed(1)]);
return 'storage.gb'.tr(args: [gibibyte.toStringAsFixed(1)]);
}
}
}

View File

@ -30,7 +30,7 @@ class RebuildServerJob extends ClientJob {
class CreateUserJob extends ClientJob {
CreateUserJob({
required this.user,
}) : super(title: '${"jobs.createUser".tr()} ${user.login}');
}) : super(title: '${"jobs.create_user".tr()} ${user.login}');
final User user;
@ -41,7 +41,7 @@ class CreateUserJob extends ClientJob {
class ResetUserPasswordJob extends ClientJob {
ResetUserPasswordJob({
required this.user,
}) : super(title: '${"jobs.resetUserPassword".tr()} ${user.login}');
}) : super(title: '${"jobs.reset_user_password".tr()} ${user.login}');
final User user;
@ -52,7 +52,7 @@ class ResetUserPasswordJob extends ClientJob {
class DeleteUserJob extends ClientJob {
DeleteUserJob({
required this.user,
}) : super(title: '${"jobs.deleteUser".tr()} ${user.login}');
}) : super(title: '${"jobs.delete_user".tr()} ${user.login}');
final User user;
@ -78,7 +78,7 @@ class ServiceToggleJob extends ToggleJob {
required this.needToTurnOn,
}) : super(
title:
'${needToTurnOn ? "jobs.serviceTurnOn".tr() : "jobs.serviceTurnOff".tr()} ${type.title}',
'${needToTurnOn ? "jobs.service_turn_on".tr() : "jobs.service_turn_off".tr()} ${type.title}',
);
final bool needToTurnOn;

View File

@ -43,7 +43,7 @@ class JobsContent extends StatelessWidget {
const SizedBox(height: 80),
BrandButton.rised(
onPressed: () => context.read<JobsCubit>().upgradeServer(),
text: 'jobs.upgradeServer'.tr(),
text: 'jobs.upgrade_server'.tr(),
),
const SizedBox(height: 10),
BrandButton.text(
@ -51,8 +51,8 @@ class JobsContent extends StatelessWidget {
final NavigationService nav = getIt<NavigationService>();
nav.showPopUpDialog(
BrandAlert(
title: 'jobs.rebootServer'.tr(),
contentText: 'modals.3'.tr(),
title: 'jobs.reboot_server'.tr(),
contentText: 'modals.are_you_sure'.tr(),
actions: [
ActionButton(
text: 'basis.cancel'.tr(),
@ -60,13 +60,13 @@ class JobsContent extends StatelessWidget {
ActionButton(
onPressed: () =>
{context.read<JobsCubit>().rebootServer()},
text: 'modals.9'.tr(),
text: 'modals.reboot'.tr(),
)
],
),
);
},
title: 'jobs.rebootServer'.tr(),
title: 'jobs.reboot_server'.tr(),
),
];
}

View File

@ -19,7 +19,7 @@ class NotReadyCard extends StatelessWidget {
text: TextSpan(
children: [
TextSpan(
text: 'not_ready_card.1'.tr(),
text: 'not_ready_card.begin'.tr(),
style: const TextStyle(color: BrandColors.white),
),
WidgetSpan(
@ -32,7 +32,7 @@ class NotReadyCard extends StatelessWidget {
),
),
child: Text(
'not_ready_card.2'.tr(),
'not_ready_card.insertion'.tr(),
style: body1Style.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
@ -44,7 +44,7 @@ class NotReadyCard extends StatelessWidget {
),
),
TextSpan(
text: 'not_ready_card.3'.tr(),
text: 'not_ready_card.end'.tr(),
style: const TextStyle(color: BrandColors.white),
),
],

View File

@ -17,12 +17,12 @@ class ServerStorageListItem extends StatelessWidget {
@override
Widget build(final BuildContext context) => ConsumptionListItem(
title: 'providers.storage.disk_usage'.tr(
title: 'storage.disk_usage'.tr(
args: [
volume.sizeUsed.toString(),
],
),
subtitle: 'providers.storage.disk_total'.tr(
subtitle: 'storage.disk_total'.tr(
args: [
volume.sizeTotal.toString(),
volume.displayName,

View File

@ -46,8 +46,8 @@ class _BackupDetailsState extends State<BackupDetails>
return BrandHeroScreen(
heroIcon: BrandIcons.save,
heroTitle: 'providers.backup.card_title'.tr(),
heroSubtitle: 'providers.backup.bottom_sheet.1'.tr(),
heroTitle: 'backup.card_title'.tr(),
heroSubtitle: 'backup.description'.tr(),
children: [
if (isReady && !isBackupInitialized)
BrandButton.rised(
@ -56,10 +56,10 @@ class _BackupDetailsState extends State<BackupDetails>
: () async {
await context.read<BackupsCubit>().createBucket();
},
text: 'providers.backup.initialize'.tr(),
text: 'backup.initialize'.tr(),
),
if (backupStatus == BackupStatusEnum.initializing)
BrandText.body1('providers.backup.waitingForRebuild'.tr()),
BrandText.body1('backup.waiting_for_rebuild'.tr()),
if (backupStatus != BackupStatusEnum.initializing &&
backupStatus != BackupStatusEnum.noKey)
OutlinedCard(
@ -77,14 +77,14 @@ class _BackupDetailsState extends State<BackupDetails>
Icons.add_circle_outline_rounded,
),
title: Text(
'providers.backup.create_new'.tr(),
'backup.create_new'.tr(),
style: Theme.of(context).textTheme.headline6,
),
),
if (backupStatus == BackupStatusEnum.backingUp)
ListTile(
title: Text(
'providers.backup.creating'.tr(
'backup.creating'.tr(
args: [(backupProgress * 100).round().toString()],
),
style: Theme.of(context).textTheme.headline6,
@ -97,7 +97,7 @@ class _BackupDetailsState extends State<BackupDetails>
if (backupStatus == BackupStatusEnum.restoring)
ListTile(
title: Text(
'providers.backup.restoring'.tr(
'backup.restoring'.tr(
args: [(backupProgress * 100).round().toString()],
),
style: Theme.of(context).textTheme.headline6,
@ -113,7 +113,7 @@ class _BackupDetailsState extends State<BackupDetails>
color: Theme.of(context).colorScheme.error,
),
title: Text(
'providers.backup.error_pending'.tr(),
'backup.error_pending'.tr(),
style: Theme.of(context).textTheme.headline6,
),
),
@ -135,7 +135,7 @@ class _BackupDetailsState extends State<BackupDetails>
Icons.refresh,
),
title: Text(
'providers.backup.restore'.tr(),
'backup.restore'.tr(),
style: Theme.of(context).textTheme.headline6,
),
),
@ -147,7 +147,7 @@ class _BackupDetailsState extends State<BackupDetails>
leading: const Icon(
Icons.error_outline,
),
title: Text('providers.backup.no_backups'.tr()),
title: Text('backup.no_backups'.tr()),
),
if (backups.isNotEmpty)
Column(
@ -161,10 +161,8 @@ class _BackupDetailsState extends State<BackupDetails>
getIt<NavigationService>();
nav.showPopUpDialog(
BrandAlert(
title:
'providers.backup.restoring'.tr(),
contentText:
'providers.backup.restore_alert'.tr(
title: 'backup.restoring'.tr(),
contentText: 'backup.restore_alert'.tr(
args: [backup.time.toString()],
),
actions: [
@ -200,7 +198,7 @@ class _BackupDetailsState extends State<BackupDetails>
children: [
ListTile(
title: Text(
'providers.backup.refresh'.tr(),
'backup.refresh'.tr(),
),
onTap: refreshing
? null
@ -215,7 +213,7 @@ class _BackupDetailsState extends State<BackupDetails>
),
ListTile(
title: Text(
'providers.backup.refetchBackups'.tr(),
'backup.refetch_backups'.tr(),
),
onTap: preventActions
? null
@ -230,7 +228,7 @@ class _BackupDetailsState extends State<BackupDetails>
),
ListTile(
title: Text(
'providers.backup.reuploadKey'.tr(),
'backup.reupload_key'.tr(),
),
onTap: preventActions
? null

View File

@ -28,7 +28,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
bool isError = false;
switch (dnsState) {
case DnsRecordsStatus.uninitialized:
description = 'providers.domain.states.uninitialized'.tr();
description = 'domain.states.uninitialized'.tr();
icon = const Icon(
Icons.refresh,
size: 24.0,
@ -36,7 +36,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false;
break;
case DnsRecordsStatus.refreshing:
description = 'providers.domain.states.refreshing'.tr();
description = 'domain.states.refreshing'.tr();
icon = const Icon(
Icons.refresh,
size: 24.0,
@ -44,7 +44,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false;
break;
case DnsRecordsStatus.good:
description = 'providers.domain.states.ok'.tr();
description = 'domain.states.ok'.tr();
icon = const Icon(
Icons.check_circle_outline,
size: 24.0,
@ -52,8 +52,8 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false;
break;
case DnsRecordsStatus.error:
description = 'providers.domain.states.error'.tr();
subtitle = 'providers.domain.states.error_subtitle'.tr();
description = 'domain.states.error'.tr();
subtitle = 'domain.states.error_subtitle'.tr();
icon = const Icon(
Icons.error_outline,
size: 24.0,
@ -93,7 +93,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
hasBackButton: true,
headerTitle: '',
heroIcon: BrandIcons.globe,
heroTitle: 'providers.domain.screen_title'.tr(),
heroTitle: 'domain.screen_title'.tr(),
heroSubtitle: 'not_ready_card.in_menu'.tr(),
children: const [],
);
@ -107,7 +107,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
hasBackButton: true,
heroSubtitle: domain,
heroIcon: BrandIcons.globe,
heroTitle: 'providers.domain.screen_title'.tr(),
heroTitle: 'domain.screen_title'.tr(),
children: <Widget>[
_getStateCard(dnsCubit.dnsState, () {
context.read<DnsRecordsCubit>().fix();
@ -115,13 +115,13 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
const SizedBox(height: 16.0),
ListTile(
title: Text(
'providers.domain.cards.services.title'.tr(),
'domain.services_title'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
subtitle: Text(
'providers.domain.cards.services.subtitle'.tr(),
'domain.services_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
),
@ -160,13 +160,13 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
const SizedBox(height: 16.0),
ListTile(
title: Text(
'providers.domain.cards.email.title'.tr(),
'domain.email_title'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary,
),
),
subtitle: Text(
'providers.domain.cards.email.subtitle'.tr(),
'domain.email_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
),

View File

@ -6,16 +6,17 @@ import 'package:selfprivacy/ui/components/brand_text/brand_text.dart';
import 'package:package_info/package_info.dart';
import 'package:easy_localization/easy_localization.dart';
class InfoPage extends StatelessWidget {
const InfoPage({final super.key});
class AboutApplicationPage extends StatelessWidget {
const AboutApplicationPage({final super.key});
@override
Widget build(final BuildContext context) => SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child:
BrandHeader(title: 'more.about_app'.tr(), hasBackButton: true),
child: BrandHeader(
title: 'about_application_page.title'.tr(),
hasBackButton: true),
),
body: ListView(
padding: paddingH15V0,
@ -24,14 +25,14 @@ class InfoPage extends StatelessWidget {
FutureBuilder(
future: _packageVersion(),
builder: (final context, final snapshot) => BrandText.body1(
'more.about_app_page.application_version_text'
'about_application_page.application_version_text'
.tr(args: [snapshot.data.toString()]),
),
),
FutureBuilder(
future: _apiVersion(),
builder: (final context, final snapshot) => BrandText.body1(
'more.about_app_page.api_version_text'
'about_application_page.api_version_text'
.tr(args: [snapshot.data.toString()]),
),
),

View File

@ -4,8 +4,8 @@ import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class AboutPage extends StatelessWidget {
const AboutPage({final super.key});
class AboutUsPage extends StatelessWidget {
const AboutUsPage({final super.key});
@override
Widget build(final BuildContext context) => SafeArea(
@ -13,7 +13,7 @@ class AboutPage extends StatelessWidget {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'more.about_project'.tr(),
title: 'about_us_page.title'.tr(),
hasBackButton: true,
),
),

View File

@ -30,7 +30,7 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'more.settings.title'.tr(),
title: 'application_settings.title'.tr(),
hasBackButton: true,
),
),
@ -46,8 +46,9 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
children: [
Flexible(
child: _TextColumn(
title: 'more.settings.1'.tr(),
value: 'more.settings.2'.tr(),
title: 'application_settings.dark_theme_title'.tr(),
value:
'application_settings.dark_theme_description'.tr(),
hasWarning: false,
),
),
@ -70,8 +71,9 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
children: [
Flexible(
child: _TextColumn(
title: 'more.settings.3'.tr(),
value: 'more.settings.4'.tr(),
title: 'application_settings.reset_config_title'.tr(),
value: 'application_settings.reset_config_description'
.tr(),
hasWarning: false,
),
),
@ -91,11 +93,11 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
showDialog(
context: context,
builder: (final _) => BrandAlert(
title: 'modals.3'.tr(),
contentText: 'modals.4'.tr(),
title: 'modals.are_you_sure'.tr(),
contentText: 'modals.purge_all_keys'.tr(),
actions: [
ActionButton(
text: 'modals.5'.tr(),
text: 'modals.purge_all_keys_confirm'.tr(),
isRed: true,
onPressed: () {
context
@ -135,8 +137,8 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
children: [
Flexible(
child: _TextColumn(
title: 'more.settings.5'.tr(),
value: 'more.settings.6'.tr(),
title: 'application_settings.delete_server_title'.tr(),
value: 'application_settings.delete_server_description'.tr(),
hasWarning: false,
),
),
@ -151,11 +153,11 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
showDialog(
context: context,
builder: (final _) => BrandAlert(
title: 'modals.3'.tr(),
contentText: 'modals.6'.tr(),
title: 'modals.are_you_sure'.tr(),
contentText: 'modals.delete_server_volume'.tr(),
actions: [
ActionButton(
text: 'modals.7'.tr(),
text: 'modals.yes'.tr(),
isRed: true,
onPressed: () async {
showDialog(

View File

@ -1,5 +1,6 @@
import 'dart:collection';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/get_it_config.dart';
@ -35,8 +36,11 @@ class _ConsoleState extends State<Console> {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(53),
child: Column(
children: const [
BrandHeader(title: 'Console', hasBackButton: true)
children: [
BrandHeader(
title: 'console_page.title'.tr(),
hasBackButton: true,
),
],
),
),
@ -90,12 +94,12 @@ class _ConsoleState extends State<Console> {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: const [
Text('Waiting for initialisation'),
SizedBox(
children: [
Text('console_page.waiting'.tr()),
const SizedBox(
height: 16,
),
CircularProgressIndicator(),
const CircularProgressIndicator(),
],
);
}

View File

@ -17,10 +17,10 @@ import 'package:selfprivacy/ui/pages/root_route.dart';
import 'package:selfprivacy/ui/pages/users/users.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:selfprivacy/ui/pages/more/about/about.dart';
import 'package:selfprivacy/ui/pages/more/about_us.dart';
import 'package:selfprivacy/ui/pages/more/app_settings/app_setting.dart';
import 'package:selfprivacy/ui/pages/more/console/console.dart';
import 'package:selfprivacy/ui/pages/more/info/info.dart';
import 'package:selfprivacy/ui/pages/more/console.dart';
import 'package:selfprivacy/ui/pages/more/about_application.dart';
class MorePage extends StatelessWidget {
const MorePage({final super.key});
@ -48,7 +48,7 @@ class MorePage extends StatelessWidget {
children: [
if (isReady && usesBinds != null && !usesBinds)
_MoreMenuItem(
title: 'providers.storage.start_migration_button'.tr(),
title: 'storage.start_migration_button'.tr(),
iconData: Icons.drive_file_move_outline,
goTo: ServicesMigrationPage(
diskStatus: context
@ -70,12 +70,12 @@ class MorePage extends StatelessWidget {
.toList(),
isMigration: true,
),
subtitle: 'providers.storage.data_migration_notice'.tr(),
subtitle: 'storage.data_migration_notice'.tr(),
accent: true,
),
if (!isReady)
_MoreMenuItem(
title: 'more.configuration_wizard'.tr(),
title: 'more_page.configuration_wizard'.tr(),
iconData: Icons.change_history_outlined,
goTo: const InitializingPage(),
subtitle: 'not_ready_card.in_menu'.tr(),
@ -83,7 +83,7 @@ class MorePage extends StatelessWidget {
),
if (isReady)
_MoreMenuItem(
title: 'more.create_ssh_key'.tr(),
title: 'more_page.create_ssh_key'.tr(),
iconData: Ionicons.key_outline,
goTo: const UserDetails(
login: 'root',
@ -102,28 +102,28 @@ class MorePage extends StatelessWidget {
title: 'devices.main_screen.header'.tr(),
),
_MoreMenuItem(
title: 'more.settings.title'.tr(),
title: 'more_page.application_settings'.tr(),
iconData: Icons.settings_outlined,
goTo: const AppSettingsPage(),
),
_MoreMenuItem(
title: 'more.about_project'.tr(),
title: 'more_page.about_project'.tr(),
iconData: BrandIcons.engineer,
goTo: const AboutPage(),
goTo: const AboutUsPage(),
),
_MoreMenuItem(
title: 'more.about_app'.tr(),
title: 'more_page.about_application'.tr(),
iconData: BrandIcons.fire,
goTo: const InfoPage(),
goTo: const AboutApplicationPage(),
),
if (!isReady)
_MoreMenuItem(
title: 'more.onboarding'.tr(),
title: 'more_page.onboarding'.tr(),
iconData: BrandIcons.start,
goTo: const OnboardingPage(nextPage: RootPage()),
),
_MoreMenuItem(
title: 'more.console'.tr(),
title: 'more_page.console'.tr(),
iconData: BrandIcons.terminal,
goTo: const Console(),
),

View File

@ -64,7 +64,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'providers.page_title'.tr(),
title: 'basis.providers_title'.tr(),
),
),
body: ListView(
@ -77,10 +77,10 @@ class _ProvidersPageState extends State<ProvidersPage> {
_Card(
state: getServerStatus(),
icon: BrandIcons.server,
title: 'providers.server.card_title'.tr(),
title: 'server.card_title'.tr(),
subtitle: diskStatus.isDiskOkay
? 'providers.storage.status_ok'.tr()
: 'providers.storage.status_error'.tr(),
? 'storage.status_ok'.tr()
: 'storage.status_error'.tr(),
onTap: () => Navigator.of(context)
.push(materialRoute(const ServerDetailsScreen())),
),
@ -88,7 +88,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
_Card(
state: getDnsStatus(),
icon: BrandIcons.globe,
title: 'providers.domain.screen_title'.tr(),
title: 'domain.screen_title'.tr(),
subtitle: appConfig.isDomainSelected
? appConfig.serverDomain!.domainName
: '',
@ -106,10 +106,8 @@ class _ProvidersPageState extends State<ProvidersPage> {
? StateType.stable
: StateType.uninitialized,
icon: BrandIcons.save,
title: 'providers.backup.card_title'.tr(),
subtitle: isBackupInitialized
? 'providers.backup.card_subtitle'.tr()
: '',
title: 'backup.card_title'.tr(),
subtitle: isBackupInitialized ? 'backup.card_subtitle'.tr() : '',
onTap: () => Navigator.of(context)
.push(materialRoute(const BackupDetails())),
),

View File

@ -17,7 +17,7 @@ class _Chart extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'providers.server.chart.cpu_title'.tr(),
'resource_chart.cpu_title'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
@ -50,7 +50,7 @@ class _Chart extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'providers.server.chart.network_title'.tr(),
'resource_chart.network_title'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color:
Theme.of(context).colorScheme.onSurfaceVariant,
@ -59,12 +59,12 @@ class _Chart extends StatelessWidget {
const Spacer(),
Legend(
color: Theme.of(context).colorScheme.primary,
text: 'providers.server.chart.in'.tr(),
text: 'resource_chart.in'.tr(),
),
const SizedBox(width: 5),
Legend(
color: Theme.of(context).colorScheme.tertiary,
text: 'providers.server.chart.out'.tr(),
text: 'resource_chart.out'.tr(),
),
],
),
@ -111,9 +111,9 @@ class _Chart extends StatelessWidget {
}
},
titles: [
'providers.server.chart.month'.tr(),
'providers.server.chart.day'.tr(),
'providers.server.chart.hour'.tr()
'resource_chart.month'.tr(),
'resource_chart.day'.tr(),
'resource_chart.hour'.tr()
],
),
const SizedBox(height: 8),

View File

@ -51,7 +51,7 @@ class NetworkChart extends StatelessWidget {
res.add(
LineTooltipItem(
'${timeShown ? '' : DateFormat('HH:mm dd.MM.yyyy').format(date)} ${spot.barIndex == 0 ? 'providers.server.chart.in'.tr() : 'providers.server.chart.out'.tr()} ${DiskSize(byte: value.toInt()).toString()}',
'${timeShown ? '' : DateFormat('HH:mm dd.MM.yyyy').format(date)} ${spot.barIndex == 0 ? 'resource_chart.in'.tr() : 'resource_chart.out'.tr()} ${DiskSize(byte: value.toInt()).toString()}',
TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,

View File

@ -70,7 +70,7 @@ class _ServerDetailsScreenState extends State<ServerDetailsScreen>
if (!isReady) {
return BrandHeroScreen(
heroIcon: BrandIcons.server,
heroTitle: 'providers.server.card_title'.tr(),
heroTitle: 'server.card_title'.tr(),
heroSubtitle: 'not_ready_card.in_menu'.tr(),
children: const [],
);
@ -80,8 +80,8 @@ class _ServerDetailsScreenState extends State<ServerDetailsScreen>
create: (final context) => context.read<ServerDetailsCubit>()..check(),
child: BrandHeroScreen(
heroIcon: BrandIcons.server,
heroTitle: 'providers.server.card_title'.tr(),
heroSubtitle: 'providers.server.bottom_sheet.1'.tr(),
heroTitle: 'server.card_title'.tr(),
heroSubtitle: 'server.description'.tr(),
children: [
StorageCard(
diskStatus: context.watch<ApiServerVolumeCubit>().state.diskStatus,
@ -90,7 +90,7 @@ class _ServerDetailsScreenState extends State<ServerDetailsScreen>
const _ServerSettings(),
const Divider(height: 32),
Text(
'providers.server.resource_usage'.tr(),
'server.resource_usage'.tr(),
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),

View File

@ -34,7 +34,7 @@ class _ServerSettingsState extends State<_ServerSettings> {
onChanged: (final switched) {
if (didSomethingChange == false) {
context.read<JobsCubit>().addJob(
RebuildServerJob(title: 'jobs.upgradeServer'.tr()),
RebuildServerJob(title: 'jobs.upgrade_server'.tr()),
);
}
context
@ -51,9 +51,9 @@ class _ServerSettingsState extends State<_ServerSettings> {
didSomethingChange = true;
});
},
title: Text('providers.server.settings.allow_autoupgrade'.tr()),
title: Text('server.allow_autoupgrade'.tr()),
subtitle: Text(
'providers.server.settings.allow_autoupgrade_hint'.tr(),
'server.allow_autoupgrade_hint'.tr(),
),
activeColor: Theme.of(context).colorScheme.primary,
),
@ -62,7 +62,7 @@ class _ServerSettingsState extends State<_ServerSettings> {
onChanged: (final switched) {
if (didSomethingChange == false) {
context.read<JobsCubit>().addJob(
RebuildServerJob(title: 'jobs.upgradeServer'.tr()),
RebuildServerJob(title: 'jobs.upgrade_server'.tr()),
);
}
context
@ -79,21 +79,21 @@ class _ServerSettingsState extends State<_ServerSettings> {
didSomethingChange = true;
});
},
title: Text('providers.server.settings.reboot_after_upgrade'.tr()),
title: Text('server.reboot_after_upgrade'.tr()),
subtitle: Text(
'providers.server.settings.reboot_after_upgrade_hint'.tr(),
'server.reboot_after_upgrade_hint'.tr(),
),
activeColor: Theme.of(context).colorScheme.primary,
),
ListTile(
title: Text('providers.server.settings.server_timezone'.tr()),
title: Text('server.server_timezone'.tr()),
subtitle: Text(
serverDetailsState.serverTimezone.toString(),
),
onTap: () {
if (didSomethingChange == false) {
context.read<JobsCubit>().addJob(
RebuildServerJob(title: 'jobs.upgradeServer'.tr()),
RebuildServerJob(title: 'jobs.upgrade_server'.tr()),
);
}
setState(() {

View File

@ -18,7 +18,7 @@ class _TextDetails extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'providers.server.bottom_sheet.2'.tr(),
'server.general_information'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
@ -27,34 +27,33 @@ class _TextDetails extends StatelessWidget {
ListTileOnSurfaceVariant(
leadingIcon: Icons.numbers_outlined,
title: data.id.toString(),
subtitle: 'providers.server.info.server_id'.tr(),
subtitle: 'server.server_id'.tr(),
),
ListTileOnSurfaceVariant(
leadingIcon: Icons.mode_standby_outlined,
title: data.status.toString().split('.')[1].capitalize(),
subtitle: 'providers.server.info.status'.tr(),
subtitle: 'server.status'.tr(),
),
ListTileOnSurfaceVariant(
leadingIcon: Icons.memory_outlined,
title: 'providers.server.info.core_count'
.plural(data.serverType.cores),
subtitle: 'providers.server.info.cpu'.tr(),
title: 'server.core_count'.plural(data.serverType.cores),
subtitle: 'server.cpu'.tr(),
),
ListTileOnSurfaceVariant(
leadingIcon: Icons.memory_outlined,
title: '${data.serverType.memory.toString()} GB',
subtitle: 'providers.server.info.ram'.tr(),
subtitle: 'server.ram'.tr(),
),
ListTileOnSurfaceVariant(
leadingIcon: Icons.euro_outlined,
title: data.serverType.prices[1].monthly.toStringAsFixed(2),
subtitle: 'providers.server.info.monthly_cost'.tr(),
subtitle: 'server.monthly_cost'.tr(),
),
// Server location
ListTileOnSurfaceVariant(
leadingIcon: Icons.location_on_outlined,
title: '${data.location.city}, ${data.location.country}',
subtitle: 'providers.server.info.location'.tr(),
subtitle: 'server.location'.tr(),
),
],
),

View File

@ -50,7 +50,7 @@ class _SelectTimezoneState extends State<SelectTimezone> {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'providers.server.settings.select_timezone'.tr(),
title: 'server.select_timezone'.tr(),
hasBackButton: true,
),
),

View File

@ -53,7 +53,7 @@ class _MigrationProcessPageState extends State<MigrationProcessPage> {
if (job.finishedAt != null) const SizedBox(height: 16),
if (job.finishedAt != null)
FilledButton(
title: 'providers.storage.migration_done'.tr(),
title: 'storage.migration_done'.tr(),
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()),
@ -65,7 +65,7 @@ class _MigrationProcessPageState extends State<MigrationProcessPage> {
}
return BrandHeroScreen(
hasBackButton: false,
heroTitle: 'providers.storage.migration_process'.tr(),
heroTitle: 'storage.migration_process'.tr(),
heroSubtitle: subtitle,
children: [
BrandLinearIndicator(

View File

@ -100,7 +100,7 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
child: Column(
children: [
BrandHeader(
title: 'providers.storage.data_migration_title'.tr(),
title: 'storage.data_migration_title'.tr(),
hasBackButton: true,
),
Padding(
@ -158,13 +158,13 @@ class _ServicesMigrationPageState extends State<ServicesMigrationPage> {
Padding(
padding: const EdgeInsets.all(8.0),
child: InfoBox(
text: 'providers.storage.data_migration_notice'.tr(),
text: 'storage.data_migration_notice'.tr(),
isWarning: true,
),
),
const SizedBox(height: 16),
FilledButton(
title: 'providers.storage.start_migration_button'.tr(),
title: 'storage.start_migration_button'.tr(),
onPressed: () {
if (widget.isMigration) {
context.read<ServerJobsCubit>().migrateToBinds(

View File

@ -57,9 +57,8 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
if (!snapshot.hasData) {
return BrandHeroScreen(
hasBackButton: true,
heroTitle: 'providers.storage.extending_volume_title'.tr(),
heroSubtitle:
'providers.storage.extending_volume_description'.tr(),
heroTitle: 'storage.extending_volume_title'.tr(),
heroSubtitle: 'storage.extending_volume_description'.tr(),
children: const [
SizedBox(height: 16),
Center(
@ -84,8 +83,8 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
return BrandHeroScreen(
hasBackButton: true,
heroTitle: 'providers.storage.extending_volume_title'.tr(),
heroSubtitle: 'providers.storage.extending_volume_description'.tr(),
heroTitle: 'storage.extending_volume_title'.tr(),
heroSubtitle: 'storage.extending_volume_description'.tr(),
children: [
const SizedBox(height: 16),
Row(
@ -104,7 +103,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
decoration: InputDecoration(
border: const OutlineInputBorder(),
errorText: _isError ? ' ' : null,
labelText: 'providers.storage.size'.tr(),
labelText: 'storage.size'.tr(),
),
),
),
@ -120,7 +119,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
decoration: InputDecoration(
border: const OutlineInputBorder(),
errorText: _isError ? ' ' : null,
labelText: 'providers.storage.euro'.tr(),
labelText: 'storage.euro'.tr(),
),
),
),
@ -140,7 +139,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
),
const SizedBox(height: 16),
FilledButton(
title: 'providers.storage.extend_volume_button.title'.tr(),
title: 'storage.extend_volume_button.title'.tr(),
onPressed: _isError
? null
: () {
@ -169,7 +168,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
),
),
const SizedBox(height: 16),
Text('providers.storage.extending_volume_price_info'.tr()),
Text('storage.extending_volume_price_info'.tr()),
const SizedBox(height: 16),
],
);

View File

@ -32,14 +32,14 @@ class _ServerStoragePageState extends State<ServerStoragePage> {
if (!isReady) {
return BrandHeroScreen(
hasBackButton: true,
heroTitle: 'providers.storage.card_title'.tr(),
heroTitle: 'storage.card_title'.tr(),
children: const [],
);
}
return BrandHeroScreen(
hasBackButton: true,
heroTitle: 'providers.storage.card_title'.tr(),
heroTitle: 'storage.card_title'.tr(),
children: [
// ...sections,
...widget.diskStatus.diskVolumes
@ -101,7 +101,7 @@ class ServerStorageSection extends StatelessWidget {
if (volume.isResizable) ...[
const SizedBox(height: 16),
BrandOutlinedButton(
title: 'providers.storage.extend_volume_button.title'.tr(),
title: 'storage.extend_volume_button.title'.tr(),
onPressed: () => Navigator.of(context).push(
materialRoute(
ExtendingVolumePage(

View File

@ -65,14 +65,14 @@ class StorageCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'providers.storage.card_title'.tr(),
'storage.card_title'.tr(),
style: Theme.of(context).textTheme.titleLarge,
),
if (state != StateType.uninitialized)
Text(
diskStatus.isDiskOkay
? 'providers.storage.status_ok'.tr()
: 'providers.storage.status_error'.tr(),
? 'storage.status_ok'.tr()
: 'storage.status_error'.tr(),
style: Theme.of(context).textTheme.bodyLarge,
),
],

View File

@ -74,7 +74,7 @@ class _ServicePageState extends State<ServicePage> {
onTap: () => _launchURL(service.url),
leading: const Icon(Icons.open_in_browser),
title: Text(
'services.service_page.open_in_browser'.tr(),
'service_page.open_in_browser'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
subtitle: Text(
@ -92,7 +92,7 @@ class _ServicePageState extends State<ServicePage> {
},
leading: const Icon(Icons.restart_alt_outlined),
title: Text(
'services.service_page.restart'.tr(),
'service_page.restart'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
enabled: !serviceDisabled && !serviceLocked,
@ -110,8 +110,8 @@ class _ServicePageState extends State<ServicePage> {
leading: const Icon(Icons.power_settings_new),
title: Text(
serviceDisabled
? 'services.service_page.enable'.tr()
: 'services.service_page.disable'.tr(),
? 'service_page.enable'.tr()
: 'service_page.disable'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
enabled: !serviceLocked,
@ -132,11 +132,11 @@ class _ServicePageState extends State<ServicePage> {
),
leading: const Icon(Icons.drive_file_move_outlined),
title: Text(
'services.service_page.move'.tr(),
'service_page.move'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
subtitle: Text(
'services.service_page.uses'.tr(
'service_page.uses'.tr(
namedArgs: {
'usage': service.storageUsage.used.toString(),
'volume': context
@ -188,79 +188,79 @@ class ServiceStatusCard extends StatelessWidget {
Widget build(final BuildContext context) {
switch (status) {
case ServiceStatus.active:
return const FilledCard(
return FilledCard(
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.check_circle_outline,
size: 24,
),
title: Text('Up and running'),
title: Text('service_page.status.active'.tr()),
),
);
case ServiceStatus.inactive:
return const FilledCard(
return FilledCard(
tertiary: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.stop_circle_outlined,
size: 24,
),
title: Text('Stopped'),
title: Text('service_page.status.inactive'.tr()),
),
);
case ServiceStatus.failed:
return const FilledCard(
return FilledCard(
error: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.error_outline,
size: 24,
),
title: Text('Failed to start'),
title: Text('service_page.status.failed'.tr()),
),
);
case ServiceStatus.off:
return const FilledCard(
return FilledCard(
tertiary: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.power_settings_new,
size: 24,
),
title: Text('Disabled'),
title: Text('service_page.status.off'.tr()),
),
);
case ServiceStatus.activating:
return const FilledCard(
return FilledCard(
tertiary: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.restart_alt_outlined,
size: 24,
),
title: Text('Activating'),
title: Text('service_page.status.activating'.tr()),
),
);
case ServiceStatus.deactivating:
return const FilledCard(
return FilledCard(
tertiary: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.restart_alt_outlined,
size: 24,
),
title: Text('Deactivating'),
title: Text('service_page.status.deactivating'.tr()),
),
);
case ServiceStatus.reloading:
return const FilledCard(
return FilledCard(
tertiary: true,
child: ListTile(
leading: Icon(
leading: const Icon(
Icons.restart_alt_outlined,
size: 24,
),
title: Text('Restarting'),
title: Text('service_page.status.reloading'.tr()),
),
);
}

View File

@ -67,7 +67,7 @@ class _ServicesPageState extends State<ServicesPage> {
child: ListView(
padding: paddingH15V0,
children: [
BrandText.body1('services.title'.tr()),
BrandText.body1('basis.services_title'.tr()),
const SizedBox(height: 24),
if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)],
...ServiceTypes.values
@ -218,7 +218,7 @@ class _Card extends StatelessWidget {
sigmaY: 2,
),
child: BrandText.h2(
'jobs.runJobs'.tr(),
'jobs.run_jobs'.tr(),
textAlign: TextAlign.center,
),
),

View File

@ -154,9 +154,9 @@ class InitializingPage extends StatelessWidget {
width: 150,
),
const SizedBox(height: 10),
BrandText.h2('initializing.1'.tr()),
BrandText.h2('initializing.connect_to_server'.tr()),
const SizedBox(height: 10),
BrandText.body2('initializing.2'.tr()),
BrandText.body2('initializing.place_where_data'.tr()),
const Spacer(),
CubitFormTextField(
formFieldCubit: context.read<ProviderFormCubit>().apiKey,
@ -211,16 +211,16 @@ class InitializingPage extends StatelessWidget {
width: 150,
),
const SizedBox(height: 10),
BrandText.h2('initializing.3'.tr()),
BrandText.h2('initializing.connect_cloudflare'.tr()),
const SizedBox(height: 10),
BrandText.body2('initializing.4'.tr()),
BrandText.body2('initializing.manage_domain_dns'.tr()),
const Spacer(),
CubitFormTextField(
formFieldCubit: context.read<DnsProviderFormCubit>().apiKey,
textAlign: TextAlign.center,
scrollPadding: const EdgeInsets.only(bottom: 70),
decoration: InputDecoration(
hintText: 'initializing.5'.tr(),
hintText: 'initializing.cloudflare_api_token'.tr(),
),
),
const Spacer(),
@ -260,7 +260,7 @@ class InitializingPage extends StatelessWidget {
height: 50,
),
const SizedBox(height: 10),
BrandText.h2('initializing.6'.tr()),
BrandText.h2('initializing.connect_backblaze_storage'.tr()),
const SizedBox(height: 10),
const Spacer(),
CubitFormTextField(
@ -321,16 +321,17 @@ class InitializingPage extends StatelessWidget {
const SizedBox(height: 30),
BrandText.h2('basis.domain'.tr()),
const SizedBox(height: 10),
if (state is Empty) BrandText.body2('initializing.7'.tr()),
if (state is Empty)
BrandText.body2('initializing.no_connected_domains'.tr()),
if (state is Loading)
BrandText.body2(
state.type == LoadingTypes.loadingDomain
? 'initializing.8'.tr()
? 'initializing.loading_domain_list'.tr()
: 'basis.saving'.tr(),
),
if (state is MoreThenOne)
BrandText.body2(
'initializing.9'.tr(),
'initializing.found_more_domains'.tr(),
),
if (state is Loaded) ...[
const SizedBox(height: 10),
@ -387,7 +388,7 @@ class InitializingPage extends StatelessWidget {
BrandButton.rised(
onPressed: () =>
context.read<DomainSetupCubit>().saveDomain(),
text: 'initializing.10'.tr(),
text: 'initializing.save_domain'.tr(),
),
],
const SizedBox(
@ -411,9 +412,10 @@ class InitializingPage extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BrandText.h2('initializing.22'.tr()),
BrandText.h2('initializing.create_master_account'.tr()),
const SizedBox(height: 10),
BrandText.body2('initializing.23'.tr()),
BrandText.body2(
'initializing.enter_nickname_and_password'.tr()),
const Spacer(),
CubitFormTextField(
formFieldCubit: context.read<RootUserFormCubit>().userName,
@ -477,12 +479,14 @@ class InitializingPage extends StatelessWidget {
const Spacer(flex: 2),
BrandText.h2('initializing.final'.tr()),
const SizedBox(height: 10),
BrandText.body2('initializing.11'.tr()),
BrandText.body2('initializing.create_server'.tr()),
const Spacer(),
BrandButton.rised(
onPressed:
isLoading ? null : appConfigCubit.createServerAndSetDnsRecords,
text: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(),
text: isLoading
? 'basis.loading'.tr()
: 'initializing.create_server'.tr(),
),
],
),
@ -498,16 +502,16 @@ class InitializingPage extends StatelessWidget {
late int doneCount;
late String? text;
if (state.isServerResetedSecondTime) {
text = 'initializing.13'.tr();
text = 'initializing.server_rebooted'.tr();
doneCount = 3;
} else if (state.isServerResetedFirstTime) {
text = 'initializing.21'.tr();
text = 'initializing.one_more_restart'.tr();
doneCount = 2;
} else if (state.isServerStarted) {
text = 'initializing.14'.tr();
text = 'initializing.server_started'.tr();
doneCount = 1;
} else if (state.isServerCreated) {
text = 'initializing.15'.tr();
text = 'initializing.server_created'.tr();
doneCount = 0;
}
return Builder(
@ -542,14 +546,14 @@ class InitializingPage extends StatelessWidget {
if (!state.isLoading)
Row(
children: [
BrandText.body2('initializing.16'.tr()),
BrandText.body2('initializing.until_the_next_check'.tr()),
BrandTimer(
startDateTime: state.timerStart!,
duration: state.duration!,
)
],
),
if (state.isLoading) BrandText.body2('initializing.17'.tr()),
if (state.isLoading) BrandText.body2('initializing.check'.tr()),
],
),
);

View File

@ -73,7 +73,7 @@ class RecoverByNewDeviceKeyInput extends StatelessWidget {
),
const SizedBox(height: 16),
FilledButton(
title: 'more.continue'.tr(),
title: 'basis.continue'.tr(),
onPressed: formCubitState.isSubmitting
? null
: () =>

View File

@ -83,7 +83,7 @@ class RecoverByOldToken extends StatelessWidget {
),
const SizedBox(height: 16),
FilledButton(
title: 'more.continue'.tr(),
title: 'basis.continue'.tr(),
onPressed: formCubitState.isSubmitting
? null
: () => context.read<RecoveryDeviceFormCubit>().trySubmit(),

View File

@ -44,7 +44,7 @@ class RecoverByRecoveryKey extends StatelessWidget {
),
const SizedBox(height: 16),
FilledButton(
title: 'more.continue'.tr(),
title: 'basis.continue'.tr(),
onPressed: formCubitState.isSubmitting
? null
: () => context.read<RecoveryDeviceFormCubit>().trySubmit(),

View File

@ -38,7 +38,7 @@ class RecoveryConfirmCloudflare extends StatelessWidget {
formFieldCubit: context.read<DnsProviderFormCubit>().apiKey,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: 'initializing.5'.tr(),
labelText: 'initializing.cloudflare_api_token'.tr(),
),
),
const SizedBox(height: 16),

View File

@ -45,7 +45,7 @@ class RecoveryHetznerConnected extends StatelessWidget {
),
const SizedBox(height: 16),
FilledButton(
title: 'more.continue'.tr(),
title: 'basis.continue'.tr(),
onPressed: formCubitState.isSubmitting
? null
: () => context.read<ProviderFormCubit>().trySubmit(),

View File

@ -127,7 +127,7 @@ class SelectDomainToRecover extends StatelessWidget {
),
const SizedBox(height: 16),
FilledButton(
title: 'more.continue'.tr(),
title: 'basis.continue'.tr(),
onPressed: formCubitState.isSubmitting
? null
: () =>

View File

@ -25,8 +25,8 @@ class UserDetails extends StatelessWidget {
if (user.type == UserType.root) {
return BrandHeroScreen(
hasBackButton: true,
heroTitle: 'ssh.root.title'.tr(),
heroSubtitle: 'ssh.root.subtitle'.tr(),
heroTitle: 'ssh.root_title'.tr(),
heroSubtitle: 'ssh.root_subtitle'.tr(),
children: [
_SshKeysCard(user: user),
],
@ -64,7 +64,7 @@ class UserDetails extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(16.0),
child: InfoBox(
text: 'users.no_sso_notice'.tr(),
text: 'users.no_ssh_notice'.tr(),
isWarning: true,
),
),