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", "test": "en-test",
"locale": "en", "locale": "en",
"basis": { "basis": {
"_comment": "Basic interface elements",
"providers": "Providers", "providers": "Providers",
"providers_title": "Your Data Center",
"services": "Services", "services": "Services",
"services_title": "Your personal, private and independent services.",
"users": "Users", "users": "Users",
"more": "More", "more": "More",
"next": "Next", "next": "Next",
@ -29,41 +30,38 @@
"wait": "Wait", "wait": "Wait",
"remove": "Remove", "remove": "Remove",
"apply": "Apply", "apply": "Apply",
"done": "Done" "done": "Done",
"continue": "Continue"
}, },
"more": { "more_page": {
"_comment": "'More' tab",
"configuration_wizard": "Setup wizard", "configuration_wizard": "Setup wizard",
"about_project": "About us", "about_project": "About us",
"about_app": "About application", "about_application": "About",
"onboarding": "Onboarding", "onboarding": "Onboarding",
"create_ssh_key": "Create SSH key", "create_ssh_key": "Create SSH key",
"generate_key": "Generate key",
"generate_key_text": "You can generate ssh key",
"console": "Console", "console": "Console",
"remove": "Remove", "application_settings": "Application settings"
"enable": "Enable", },
"ok": "ok", "console_page": {
"continue": "Continue", "title": "Console",
"ssh_key_exist_text": "You have generated ssh key", "waiting": "Waiting for initialization..."
"yes_delete": "Yes, delete my SSH key", },
"share": "Share", "about_us_page": {
"copy_buffer": "Copy to buffer", "title": "About us"
"copied_ssh": "SSH copied to clipboard", },
"delete_ssh_text": "Delete SSH key?", "about_application_page": {
"about_app_page": { "title": "About",
"application_version_text": "Application version v.{}", "application_version_text": "Application version v.{}",
"api_version_text": "Server API version v.{}" "api_version_text": "Server API version v.{}"
}, },
"settings": { "application_settings": {
"title": "Application settings", "title": "Application settings",
"1": "Dark Theme", "dark_theme_title": "Dark theme",
"2": "Change your the app theme", "dark_theme_description": "Switch your application theme",
"3": "Reset app config", "reset_config_title": "Reset application config",
"4": "Reset api keys and root user", "reset_config_description": "Reset api keys and root user",
"5": "Delete Server", "delete_server_title": "Delete server",
"6": "This removes the Server. It will be no longer accessible" "delete_server_description": "This removes your server. It will be no longer accessible"
}
}, },
"ssh": { "ssh": {
"title": "SSH keys", "title": "SSH keys",
@ -73,248 +71,179 @@
"subtitle_with_keys": "{} keys", "subtitle_with_keys": "{} keys",
"subtitle_without_keys": "No keys", "subtitle_without_keys": "No keys",
"no_key_name": "Unnamed key", "no_key_name": "Unnamed key",
"root": { "root_title": "These are superuser keys",
"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.",
"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" "input_label": "Public ED25519 or RSA key"
}, },
"onboarding": { "onboarding": {
"_comment": "Onboarding pages",
"page1_title": "Digital independence, available to all of us", "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.", "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_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" "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": { "resource_chart": {
"_comment": "'Providers' tab", "month": "Month",
"page_title": "Your Data Center", "day": "Day",
"server": { "hour": "Hour",
"card_title": "Server", "cpu_title": "CPU Usage",
"status": "Status — Good", "network_title": "Network Usage",
"bottom_sheet": { "in": "In",
"1": "It's a virtual computer, where all your services live.", "out": "Out"
"2": "General information", },
"3": "Location" "server": {
}, "card_title": "Server",
"chart": { "description": "All your services live here",
"month": "Month", "general_information": "General information",
"day": "Day", "resource_usage": "Resource usage",
"hour": "Hour", "allow_autoupgrade": "Allow auto-upgrade",
"cpu_title": "CPU Usage", "allow_autoupgrade_hint": "Allow automatic packages upgrades on server",
"network_title": "Network Usage", "reboot_after_upgrade": "Reboot after upgrade",
"in": "In", "reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server",
"out": "Out" "server_timezone": "Server timezone",
}, "select_timezone": "Select timezone",
"resource_usage": "Resource usage", "server_id": "Server ID",
"settings": { "status": "Status",
"allow_autoupgrade": "Allow auto-upgrade", "cpu": "CPU",
"allow_autoupgrade_hint": "Allow automatic packages upgrades on server", "ram": "Memory",
"reboot_after_upgrade": "Reboot after upgrade", "disk": "Disk local",
"reboot_after_upgrade_hint": "Reboot without prompt after applying changes on server", "monthly_cost": "Monthly cost",
"server_timezone": "Server timezone", "location": "Location",
"select_timezone": "Select timezone" "core_count": {
}, "one": "{} core",
"info": { "other": "{} cores"
"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"
} }
}, },
"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": { "not_ready_card": {
"_comment": "Card shown when user skips initial setup", "begin": "Please finish application setup using ",
"1": "Please finish application setup using ", "insertion": "@:more.configuration_wizard",
"2": "@:more.configuration_wizard", "end": " for further work",
"3": " for further work",
"in_menu": "Server is not set up yet. Please finish setup using setup wizard for further work." "in_menu": "Server is not set up yet. Please finish setup using setup wizard for further work."
}, },
"services": { "service_page": {
"_comment": "Services", "open_in_browser": "Open in browser",
"title": "Your personal, private and independent services.", "restart": "Restart service",
"service_page": { "disable": "Disable service",
"open_in_browser": "Open in browser", "enable": "Enable service",
"restart": "Restart service", "move": "Move to another volume",
"disable": "Disable service", "uses": "Uses {usage} on {volume}",
"enable": "Enable service", "status": {
"move": "Move to another volume", "active": "Up and running",
"uses": "Uses {usage} on {volume}" "inactive": "Stopped",
}, "failed": "Failed to start",
"mail": { "off": "Disabled",
"title": "E-Mail", "activating": "Activating",
"subtitle": "E-Mail for company and family.", "deactivating": "Deactivating",
"login_info": "Use username and password from users tab. IMAP port is 143 with STARTTLS, SMTP port is 587 with STARTTLS.", "reloading": "Restarting"
"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"
} }
}, },
"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": { "users": {
"_comment": "'Users' tab",
"add_new_user": "Add a first user", "add_new_user": "Add a first user",
"new_user": "New user", "new_user": "New user",
"delete_user": "Delete 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", "not_ready": "Please connect server, domain and DNS in the Providers tab, to be able to add a first user",
"nobody_here": "Nobody here", "nobody_here": "Nobody here",
"login": "Login", "login": "Login",
"onboarding": "Onboarding",
"console": "Console",
"new_user_info_note": "New user will automatically be granted an access to all of the services", "new_user_info_note": "New user will automatically be granted an access to all of the services",
"delete_confirm_question": "Are you sure?", "delete_confirm_question": "Are you sure?",
"reset_password": "Reset password", "reset_password": "Reset password",
@ -327,38 +256,34 @@
"could_not_delete_user": "Couldn't delete user", "could_not_delete_user": "Couldn't delete user",
"could_not_add_ssh_key": "Couldn't add SSH key", "could_not_add_ssh_key": "Couldn't add SSH key",
"email_login": "Email login", "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": { "initializing": {
"_comment": "initializing page", "connect_to_server": "Connect a server",
"1": "Connect a server", "place_where_data": "A place where your data and SelfPrivacy services will reside:",
"2": "A place where your data and SelfPrivacy services will reside:",
"how": "How to obtain API token", "how": "How to obtain API token",
"hetzner_bad_key_error": "Hetzner API key is invalid", "hetzner_bad_key_error": "Hetzner API key is invalid",
"cloudflare_bad_key_error": "Cloudflare API key is invalid", "cloudflare_bad_key_error": "Cloudflare API key is invalid",
"backblaze_bad_key_error": "Backblaze storage information is invalid", "backblaze_bad_key_error": "Backblaze storage information is invalid",
"3": "Connect CloudFlare", "connect_cloudflare": "Connect CloudFlare",
"4": "To manage your domain's DNS", "manage_domain_dns": "To manage your domain's DNS",
"5": "CloudFlare API Token", "cloudflare_api_token": "CloudFlare API Token",
"6": "Connect Backblaze storage", "connect_backblaze_storage": "Connect Backblaze storage",
"7": "No connected domains at the moment", "no_connected_domains": "No connected domains at the moment",
"8": "Loading domains list", "loading_domain_list": "Loading domain list",
"9": "Found more than one domain. For your own security, please be asked to delete unnecessary domains", "found_more_domains": "Found more than one domain. For your own security, please be asked to delete unnecessary domains",
"10": "Save domain", "save_domain": "Save domain",
"final": "Final step", "final": "Final step",
"11": "Create server", "create_server": "Create server",
"what": "What does it mean?", "what": "What does it mean?",
"13": "Server rebooted. Waiting for the last verification...", "server_rebooted": "Server rebooted. Waiting for the last verification...",
"14": "Server started. It will be validated and rebooted now...", "server_started": "Server started. It will be validated and rebooted now...",
"15": "Server created. DNS checks and server boot in progress...", "server_created": "Server created. DNS checks and server boot in progress...",
"16": "Until the next check: ", "until_the_next_check": "Until the next check: ",
"17": "Check", "check": "Check",
"18": "How to obtain Hetzner API Token:'", "one_more_restart": "One more restart to apply your security certificates.",
"19": "1 Go via this link ", "create_master_account": "Create master account",
"20": "\n", "enter_nickname_and_password": "Enter a nickname and strong password",
"21": "One more restart to apply your security certificates.",
"22": "Create master account",
"23": "Enter a nickname and strong password",
"finish": "Everything is initialized", "finish": "Everything is initialized",
"checks": "Checks have been completed \n{} out of {}" "checks": "Checks have been completed \n{} out of {}"
}, },
@ -451,19 +376,16 @@
"generation_error": "Couldn't generate a recovery key. {}" "generation_error": "Couldn't generate a recovery key. {}"
}, },
"modals": { "modals": {
"_comment": "messages in modals", "already_exists": "Such server already exists.",
"1": "Server with such name, already exist.", "unexpected_error": "Unexpected error during placement from the provider side.",
"1_1": "Unexpected error during placement from the provider side.", "destroy_server": "Destroy the server and create a new one?",
"2": "Destroy server and create a new one?", "try_again": "Try again?",
"2_2": "Try again?", "are_you_sure": "Are you sure?",
"3": "Are you sure?", "purge_all_keys": "Purge all authentication keys?",
"4": "Purge all authentication keys?", "purge_all_keys_confirm": "Yes, purge all my tokens",
"5": "Yes, purge all my tokens", "delete_server_volume": "Delete the server and volume?",
"6": "Delete the server and volume?", "reboot": "Reboot",
"7": "Yes", "you_cant_use_this_api": "You cannot use this API for domains with such TLD.",
"8": "Remove task",
"9": "Reboot",
"10": "You cannot use this API for domains with such TLD.",
"yes": "Yes", "yes": "Yes",
"no": "No" "no": "No"
}, },
@ -471,27 +393,26 @@
"sec": "{} sec" "sec": "{} sec"
}, },
"jobs": { "jobs": {
"_comment": "Jobs list",
"title": "Jobs list", "title": "Jobs list",
"start": "Start", "start": "Start",
"empty": "No jobs", "empty": "No jobs",
"createUser": "Create user", "create_user": "Create user",
"deleteUser": "Delete user", "delete_user": "Delete user",
"serviceTurnOff": "Turn off", "service_turn_off": "Turn off",
"serviceTurnOn": "Turn on", "service_turn_on": "Turn on",
"jobAdded": "Job added", "job_added": "Job added",
"runJobs": "Run jobs", "run_jobs": "Run jobs",
"rebootSuccess": "Server is rebooting", "reboot_success": "Server is rebooting",
"rebootFailed": "Couldn't reboot the server. Check the app logs.", "reboot_failed": "Couldn't reboot the server. Check the app logs.",
"configPullFailed": "Failed to pull configuration upgrade. Started software upgrade anyways.", "config_pull_failed": "Failed to pull configuration upgrade. Started software upgrade anyways.",
"upgradeSuccess": "Server upgrade started", "upgrade_success": "Server upgrade started",
"upgradeFailed": "Failed to upgrade server", "upgrade_failed": "Failed to upgrade server",
"upgradeServer": "Upgrade server", "upgrade_server": "Upgrade server",
"rebootServer": "Reboot server", "reboot_server": "Reboot server",
"create_ssh_key": "Create SSH key for {}", "create_ssh_key": "Create SSH key for {}",
"delete_ssh_key": "Delete SSH key for {}", "delete_ssh_key": "Delete SSH key for {}",
"server_jobs": "Jobs on the server", "server_jobs": "Jobs on the server",
"resetUserPassword": "Reset password of user" "reset_user_password": "Reset password of user"
}, },
"validations": { "validations": {
"required": "Required.", "required": "Required.",

View File

@ -2,9 +2,10 @@
"test": "ru-test", "test": "ru-test",
"locale": "ru", "locale": "ru",
"basis": { "basis": {
"_comment": "базовые элементы интерфейса",
"providers": "Провайдеры", "providers": "Провайдеры",
"providers_title": "Ваш Дата Центр",
"services": "Сервисы", "services": "Сервисы",
"services_title": "Ваши личные, приватные и независимые сервисы.",
"users": "Пользователи", "users": "Пользователи",
"more": "Ещё", "more": "Ещё",
"next": "Далее", "next": "Далее",
@ -29,41 +30,38 @@
"wait": "Загрузка", "wait": "Загрузка",
"remove": "Удалить", "remove": "Удалить",
"apply": "Подать", "apply": "Подать",
"done": "Готово" "done": "Готово",
"continue": "Продолжить"
}, },
"more": { "more_page": {
"_comment": "вкладка ещё",
"configuration_wizard": "Мастер Подключения", "configuration_wizard": "Мастер Подключения",
"about_project": "О проекте SelfPrivacy", "about_project": "О проекте SelfPrivacy",
"about_app": "О приложении", "about_application": "О приложении",
"onboarding": "Приветствие", "onboarding": "Приветствие",
"console": "Консоль", "console": "Консоль",
"create_ssh_key": "Создать ssh ключ", "create_ssh_key": "Создать ssh ключ",
"generate_key": "Сгенерировать ключ", "application_settings": "Настройки приложения"
"generate_key_text": "Вы сможете сгенерировать ключ", },
"remove": "Отключить", "console_page": {
"enable": "Включить", "title": "Консоль",
"ok": "ok", "waiting": "Ждём инициализации..."
"continue": "Продолжить", },
"ssh_key_exist_text": "У Вас уже есть сгенерированный ssh ключ", "about_us_page": {
"yes_delete": "Да, удалить", "title": "О проекте SelfPrivacy"
"share": "Поделиться", },
"copy_buffer": "Копировать в буфер", "about_application_page": {
"copied_ssh": "SSH ключ cкопирован в буфер", "title": "О приложении",
"delete_ssh_text": "Удалить SSH ключ?", "application_version_text": "Версия приложения v.{}",
"about_app_page": { "api_version_text": "Версия API сервера v.{}"
"application_version_text": "Версия приложения v.{}", },
"api_version_text": "Версия API сервера v.{}" "application_settings": {
}, "title": "Настройки приложения",
"settings": { "dark_theme_title": "Тёмная тема",
"title": "Настройки приложения", "dark_theme_description": "Сменить цветовую тему.",
"1": "Тёмная тема", "reset_config_title": "Сброс настроек",
"2": "Сменить цветовую тему.", "reset_config_description": "Сбросить API ключи а также root пользвателя.",
"3": "Сброс настроек", "delete_server_title": "Удалить сервер",
"4": "Сбросить API ключи а также root пользвателя.", "delete_server_description": "Действие приведет к удалению сервера. После этого он будет недоступен."
"5": "Удалить сервер",
"6": "Действие приведет к удалению сервера. После этого он будет недоступен."
}
}, },
"ssh": { "ssh": {
"title": "SSH ключи", "title": "SSH ключи",
@ -73,285 +71,213 @@
"subtitle_with_keys": "Ключей: {}", "subtitle_with_keys": "Ключей: {}",
"subtitle_without_keys": "Ключей нет", "subtitle_without_keys": "Ключей нет",
"no_key_name": "Безымянный ключ", "no_key_name": "Безымянный ключ",
"root": { "root_title": "Это ключи суперпользователя",
"title": "Это ключи суперпользователя", "root_subtitle": "Владельцы указанных здесь ключей получают полный доступ к данным и настройкам сервера. Добавляйте исключительно свои ключи.",
"subtitle": "Владельцы указанных здесь ключей получают полный доступ к данным и настройкам сервера. Добавляйте исключительно свои ключи."
},
"input_label": "Публичный ED25519 или RSA ключ" "input_label": "Публичный ED25519 или RSA ключ"
}, },
"onboarding": { "onboarding": {
"_comment": "страницы онбординга",
"page1_title": "Цифровая независимость доступна каждому", "page1_title": "Цифровая независимость доступна каждому",
"page1_text": "Почта, VPN, Мессенджер, социальная сеть и многое другое на Вашем личном сервере, под Вашим полным контролем.", "page1_text": "Почта, VPN, Мессенджер, социальная сеть и многое другое на Вашем личном сервере, под Вашим полным контролем.",
"page2_title": "SelfPrivacy — это не облако, а Ваш личный дата-центр", "page2_title": "SelfPrivacy — это не облако, а Ваш личный дата-центр",
"page2_text": "SelfPrivacy работает только с вашими сервис-провайдерами: Hetzner, Cloudflare, Backblaze. Если у Вас нет учётных записей, мы поможем их создать." "page2_text": "SelfPrivacy работает только с вашими сервис-провайдерами: Hetzner, Cloudflare, Backblaze. Если у Вас нет учётных записей, мы поможем их создать."
}, },
"providers": { "resource_chart": {
"_comment": "вкладка провайдеры", "month": "Месяц",
"page_title": "Ваш Дата-центр", "day": "День",
"server": { "hour": "Час",
"card_title": "Сервер", "cpu_title": "Использование процессора",
"status": "Статус — в норме", "network_title": "Использование сети",
"bottom_sheet": { "in": "Получено",
"1": "Это виртуальный компьютер на котором работают все Ваши сервисы.", "out": "Отправлено"
"2": "Общая информация", },
"3": "Размещение" "server": {
}, "card_title": "Сервер",
"chart": { "description": "Это виртуальный компьютер на котором работают все Ваши сервисы.",
"month": "Месяц", "general_information": "Общая информация",
"day": "День", "resource_usage": "Потребление ресурсов",
"hour": "Час", "allow_autoupgrade": "Разрешить авто-обноления",
"cpu_title": "Использование процессора", "allow_autoupgrade_hint": "Разрешить автоматичесую установку обновлений на сервер",
"network_title": "Использование сети", "reboot_after_upgrade": "Перезагружать после обновлений",
"in": "Получено", "reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений",
"out": "Отправлено" "server_timezone": "Часовой пояс сервера",
}, "select_timezone": "Выберите часовой пояс",
"settings": { "server_id": "ID сервера",
"allow_autoupgrade": "Разрешить авто-обноления", "status": "Статус",
"allow_autoupgrade_hint": "Разрешить автоматичесую установку обновлений на сервер", "cpu": "Процессор",
"reboot_after_upgrade": "Перезагружать после обновлений", "ram": "Оперативная память",
"reboot_after_upgrade_hint": "Автоматически перезагружать сервер после применения обновлений", "disk": "Диск",
"server_timezone": "Часовой пояс сервера", "monthly_cost": "Ежемесячная стоимость",
"select_timezone": "Выберите часовой пояс" "location": "Размещение",
}, "core_count": {
"info": { "one": "{} ядро",
"server_id": "ID сервера", "two": "{} ядра",
"status": "Статус", "few": "{} ядра",
"cpu": "Процессор", "many": "{} ядер",
"ram": "Операивная память", "other": "{} ядер"
"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": "Завершить"
} }
}, },
"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": { "not_ready_card": {
"_comment": "Карточка показывающая когда человек скипнул настройку, на карте текст из 3 блоков, средний содержит ссыку на мастер подключения", "begin": "Завершите настройку приложения используя ",
"1": "Завершите настройку приложения используя ", "insertion": "@:more.configuration_wizard",
"2": "@:more.configuration_wizard", "end": " для продолжения работы",
"3": " для продолжения работы",
"in_menu": "Сервер ещё не настроен, воспользуйтесь мастером подключения." "in_menu": "Сервер ещё не настроен, воспользуйтесь мастером подключения."
}, },
"services": { "service_page": {
"_comment": "Вкладка сервисы", "open_in_browser": "Открыть в браузере",
"title": "Ваши личные, приватные и независимые сервисы:", "restart": "Перезапустить сервис",
"service_page": { "disable": "Выключить сервис",
"open_in_browser": "Открыть в браузере", "enable": "Включить сервис",
"restart": "Перезапустить сервис", "move": "Переместить на другой диск",
"disable": "Выключить сервис", "uses": "Использует {usage} на {volume}"
"enable": "Включить сервис", },
"move": "Переместить на другой диск", "mail": {
"uses": "Использует {usage} на {volume}" "title": "Почта",
}, "subtitle": "Электронная почта для семьи или компании.",
"mail": { "login_info": "Используйте логин и пароль из вкладки пользователей. IMAP порт: 143, STARTTLS. SMTP порт: 587, STARTTLS."
"title": "Почта", },
"subtitle": "Электронная почта для семьи или компании.", "password_manager": {
"login_info": "Используйте логин и пароль из вкладки пользователей. IMAP порт: 143, STARTTLS. SMTP порт: 587, STARTTLS.", "title": "Менеджер паролей",
"bottom_sheet": { "subtitle": "Это фундамент Вашей безопасности. Создавать, хранить, копировать пароли между устройствами и вбивать их в формы поможет Bitwarden.",
"1": "Для подключения почтового ящика используйте {} и профиль, который Вы создали. Так же приглашайте", "login_info": "Аккаунт нужно создать на сайте."
"2": "новых пользователей." },
} "video": {
}, "title": "Видеоконференция",
"messenger": { "subtitle": "Jitsi meet — отличный аналог Zoom и Google meet который помимо удобства ещё и гарантирует Вам защищённые высококачественные видеоконференции.",
"title": "Мессенджер", "login_info": "Аккаунт не требуется."
"subtitle": "Telegram и Signal не так приватны, как Delta.Chat — он использует Ваш личный сервер.", },
"login_info": "Используйте те же логин и пароль, что и для почты.", "cloud": {
"bottom_sheet": { "title": "Файловое облако",
"1": "Для подключения используйте {} и логин пароль, который Вы создали." "subtitle": "Не позволяйте облачным сервисам просматривать ваши данные. Используйте NextCloud — надёжный дом для всех Ваших данных.",
} "login_info": "Логин администратора: admin, пароль такой же как у основного пользователя. Создавайте новых пользователей в интерфейсе администратора NextCloud."
}, },
"password_manager": { "social_network": {
"title": "Менеджер паролей", "title": "Социальная сеть",
"subtitle": "Это фундамент Вашей безопасности. Создавать, хранить, копировать пароли между устройствами и вбивать их в формы поможет Bitwarden.", "subtitle": "Сложно поверить, но стало возможным создать свою собственную социальную сеть, со своими правилами и аудиторией.",
"login_info": "Аккаунт нужно создать на сайте.", "login_info": "Аккаунт нужно создать на сайте."
"bottom_sheet": { },
"1": "Подключиться к серверу и создать пользователя можно по адресу:." "git": {
} "title": "Git-сервер",
}, "subtitle": "Приватная альтернатива Github, которая принадлежит вам, а не Microsoft.",
"video": { "login_info": "Аккаунт нужно создать на сайте. Первый зарегистрированный пользователь становится администратором."
"title": "Видеоконференция", },
"subtitle": "Jitsi meet — отличный аналог Zoom и Google meet который помимо удобства ещё и гарантирует Вам защищённые высококачественные видеоконференции.", "vpn": {
"login_info": "Аккаунт не требуется.", "title": "VPN сервер",
"bottom_sheet": { "subtitle": "Закрытый VPN сервер"
"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": "Настройки"
}
}, },
"users": { "users": {
"_comment": "'Users' tab",
"add_new_user": "Добавьте первого пользователя.", "add_new_user": "Добавьте первого пользователя.",
"new_user": "Новый пользователь", "new_user": "Новый пользователь",
"delete_user": "Удалить пользователя",
"not_ready": "Подключите сервер, домен и DNS в разделе Провайдеры чтобы добавить первого пользователя", "not_ready": "Подключите сервер, домен и DNS в разделе Провайдеры чтобы добавить первого пользователя",
"nobody_here": "Здесь будут отображаться пользователи.", "nobody_here": "Здесь будут отображаться пользователи.",
"login": "Логин", "login": "Логин",
"onboarding": "Приветствие",
"console": "Консоль разработчика",
"new_user_info_note": "Новый пользователь автоматически получит доступ ко всем сервисам.", "new_user_info_note": "Новый пользователь автоматически получит доступ ко всем сервисам.",
"delete_confirm_question": "Вы действительно хотите удалить учетную запись?", "delete_confirm_question": "Вы действительно хотите удалить учетную запись?",
"reset_password": "Сбросить пароль", "reset_password": "Сбросить пароль",
"account": "Учетная запись", "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": { "initializing": {
"_comment": "initializing page", "connect_to_server": "Подключите сервер",
"1": "Подключите сервер", "place_where_data": "Здесь будут жить наши данные и SelfPrivacy-сервисы",
"2": "Здесь будут жить наши данные и SelfPrivacy-сервисы",
"how": "Как получить API Token", "how": "Как получить API Token",
"hetzner_bad_key_error": "Hetzner API ключ неверен", "hetzner_bad_key_error": "Hetzner API ключ неверен",
"cloudflare_bad_key_error": "Cloudflare API ключ неверен", "cloudflare_bad_key_error": "Cloudflare API ключ неверен",
"backblaze_bad_key_error": "Информация о Backblaze хранилище неверна", "backblaze_bad_key_error": "Информация о Backblaze хранилище неверна",
"3": "Подключите CloudFlare", "connect_cloudflare": "Подключите CloudFlare",
"4": "Для управления DNS вашего домена", "manage_domain_dns": "Для управления DNS вашего домена",
"5": "CloudFlare API Token", "cloudflare_api_token": "CloudFlare API Token",
"6": "Подключите облачное хранилище Backblaze", "connect_backblaze_storage": "Подключите облачное хранилище Backblaze",
"7": "На данный момент подлюченных доменов нет", "no_connected_domains": "На данный момент подлюченных доменов нет",
"8": "Загружаем список доменов", "loading_domain_list": "Загружаем список доменов",
"9": "Найдено больше одного домена, для вашей безопастности, просим Вам удалить не нужные домены", "found_more_domains": "Найдено больше одного домена, для вашей безопастности, просим Вам удалить не нужные домены",
"10": "Сохранить домен", "save_domain": "Сохранить домен",
"final": "Последний шаг", "final": "Последний шаг",
"11": "Создать сервер", "create_server": "Создать сервер",
"what": "Что это значит?", "what": "Что это значит?",
"13": "Сервер презагружен, ждем последнюю проверку.", "server_rebooted": "Сервер презагружен, ждем последнюю проверку.",
"14": "Cервер запущен, сейчас он будет проверен и перезагружен.", "server_started": "Cервер запущен, сейчас он будет проверен и перезагружен.",
"15": "Cервер создан, идет проверка ДНС адресов и запуск сервера.", "server_created": "Cервер создан, идет проверка ДНС адресов и запуск сервера.",
"16": "До следующей проверки: ", "until_the_next_check": "До следующей проверки: ",
"17": "Проверка", "check": "Проверка",
"18": "Как получить Hetzner API Token:'", "one_more_restart": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности",
"19": "1 Переходим по ссылке ", "create_master_account": "Создайте главную учетную запись",
"20": "\n2 Заходим в созданный нами проект. Если такового нет - значит создаём.\n3 Наводим мышкой на боковую панель. Она должна раскрыться, показав нам пункты меню. Нас интересует последний — Security (с иконкой ключика).\n4 Далее, в верхней части интерфейса видим примерно такой список: SSH Keys, API Tokens, Certificates, Members. Нам нужен API Tokens. Переходим по нему.\n5 В правой части интерфейса, нас будет ожидать кнопка Generate API token. Если же Вы используете мобильную версию сайта - в нижнем правом углу Вы увидите красный плюсик. Нажимаем на эту кнопку.\n6 В поле Description даём нашему токену название (это может быть любое название, которое Вам нравиться, сути оно не меняет.", "enter_nickname_and_password": "Введите никнейм и сложный пароль",
"21": "Сейчас будет дополнительная перезагрузка для активации сертификатов безопастности",
"22": "Создайте главную учетную запись",
"23": "Введите никнейм и сложный пароль",
"finish": "Всё инициализировано.", "finish": "Всё инициализировано.",
"checks": "Проверок выполнено: \n{} / {}" "checks": "Проверок выполнено: \n{} / {}"
}, },
@ -444,19 +370,16 @@
"generation_error": "Не удалось сгенерировать ключ. {}" "generation_error": "Не удалось сгенерировать ключ. {}"
}, },
"modals": { "modals": {
"_comment": "messages in modals", "already_exists": "Такой сервер уже существует.",
"1": "Сервер с таким именем уже существует.", "unexpected_error": "Непредвиденная ошибка со стороны провайдера.",
"1.1": "Непредвиденная ошибка при создании со стороны провайдера.", "destroy_server": "Уничтожить сервер и создать новый?",
"2": "Уничтожить сервер и создать новый?", "try_again": "Попробовать ещё раз?",
"2.2": "Попробовать ещё раз?", "are_you_sure": "Вы уверены?",
"3": "Подтвердите", "purge_all_keys": "Стереть все ключи авторизации?",
"4": "Сбросить все ключи?", "purge_all_keys_confirm": "Да, стереть все ключи!",
"5": "Да, сбросить", "delete_server_volume": "Удалить сервер и хранилище?",
"6": "Удалить сервер и диск?", "reboot": "Перезагрузить",
"7": "Да, удалить", "you_cant_use_this_api": "Нельзя использовать этот API для доменом с подобным TLD.",
"8": "Удалить задачу",
"9": "Перезагрузить",
"10": "API не поддерживает домены с таким TLD.",
"yes": "Да", "yes": "Да",
"no": "Нет" "no": "Нет"
}, },
@ -464,27 +387,26 @@
"sec": "{} сек" "sec": "{} сек"
}, },
"jobs": { "jobs": {
"_comment": "Jobs list",
"title": "Задачи", "title": "Задачи",
"start": "Начать выполенение", "start": "Начать выполенение",
"empty": "Пусто.", "empty": "Пусто.",
"createUser": "Создать пользователя", "create_user": "Создать пользователя",
"deleteUser": "Удалить пользователя", "delete_user": "Удалить пользователя",
"serviceTurnOff": "Остановить", "service_turn_off": "Остановить",
"serviceTurnOn": "Запустить", "service_turn_on": "Запустить",
"jobAdded": "Задача добавленна", "job_added": "Задача добавленна",
"runJobs": "Запустите задачи", "run_jobs": "Запустите задачи",
"rebootSuccess": "Сервер перезагружается", "reboot_success": "Сервер перезагружается",
"rebootFailed": "Не удалось перезагрузить сервер, проверьте логи", "reboot_failed": "Не удалось перезагрузить сервер, проверьте логи",
"configPullFailed": "Не удалось обновить конфигурацию сервера. Обновление ПО запущено.", "config_pull_failed": "Не удалось обновить конфигурацию сервера. Обновление ПО запущено.",
"upgradeSuccess": "Запущено обновление сервера", "upgrade_success": "Запущено обновление сервера",
"upgradeFailed": "Обновить сервер не вышло", "upgrade_failed": "Обновить сервер не вышло",
"upgradeServer": "Обновить сервер", "upgrade_server": "Обновить сервер",
"rebootServer": "Перезагрузить сервер", "reboot_server": "Перезагрузить сервер",
"create_ssh_key": "Создать SSH ключ для {}", "create_ssh_key": "Создать SSH ключ для {}",
"delete_ssh_key": "Удалить SSH ключ для {}", "delete_ssh_key": "Удалить SSH ключ для {}",
"server_jobs": "Задачи на сервере", "server_jobs": "Задачи на сервере",
"resetUserPassword": "Сбросить пароль пользователя" "reset_user_password": "Сбросить пароль пользователя"
}, },
"validations": { "validations": {
"required": "Обязательное поле.", "required": "Обязательное поле.",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,11 +28,11 @@ class DiskSize {
if (byte < 1024) { if (byte < 1024) {
return '${byte.toStringAsFixed(0)} ${tr('bytes')}'; return '${byte.toStringAsFixed(0)} ${tr('bytes')}';
} else if (byte < 1024 * 1024) { } 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) { } else if (byte < 1024 * 1024 * 1024) {
return 'providers.storage.mb'.tr(args: [mebibyte.toStringAsFixed(1)]); return 'storage.mb'.tr(args: [mebibyte.toStringAsFixed(1)]);
} else { } 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 { class CreateUserJob extends ClientJob {
CreateUserJob({ CreateUserJob({
required this.user, required this.user,
}) : super(title: '${"jobs.createUser".tr()} ${user.login}'); }) : super(title: '${"jobs.create_user".tr()} ${user.login}');
final User user; final User user;
@ -41,7 +41,7 @@ class CreateUserJob extends ClientJob {
class ResetUserPasswordJob extends ClientJob { class ResetUserPasswordJob extends ClientJob {
ResetUserPasswordJob({ ResetUserPasswordJob({
required this.user, required this.user,
}) : super(title: '${"jobs.resetUserPassword".tr()} ${user.login}'); }) : super(title: '${"jobs.reset_user_password".tr()} ${user.login}');
final User user; final User user;
@ -52,7 +52,7 @@ class ResetUserPasswordJob extends ClientJob {
class DeleteUserJob extends ClientJob { class DeleteUserJob extends ClientJob {
DeleteUserJob({ DeleteUserJob({
required this.user, required this.user,
}) : super(title: '${"jobs.deleteUser".tr()} ${user.login}'); }) : super(title: '${"jobs.delete_user".tr()} ${user.login}');
final User user; final User user;
@ -78,7 +78,7 @@ class ServiceToggleJob extends ToggleJob {
required this.needToTurnOn, required this.needToTurnOn,
}) : super( }) : super(
title: 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; final bool needToTurnOn;

View File

@ -43,7 +43,7 @@ class JobsContent extends StatelessWidget {
const SizedBox(height: 80), const SizedBox(height: 80),
BrandButton.rised( BrandButton.rised(
onPressed: () => context.read<JobsCubit>().upgradeServer(), onPressed: () => context.read<JobsCubit>().upgradeServer(),
text: 'jobs.upgradeServer'.tr(), text: 'jobs.upgrade_server'.tr(),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
BrandButton.text( BrandButton.text(
@ -51,8 +51,8 @@ class JobsContent extends StatelessWidget {
final NavigationService nav = getIt<NavigationService>(); final NavigationService nav = getIt<NavigationService>();
nav.showPopUpDialog( nav.showPopUpDialog(
BrandAlert( BrandAlert(
title: 'jobs.rebootServer'.tr(), title: 'jobs.reboot_server'.tr(),
contentText: 'modals.3'.tr(), contentText: 'modals.are_you_sure'.tr(),
actions: [ actions: [
ActionButton( ActionButton(
text: 'basis.cancel'.tr(), text: 'basis.cancel'.tr(),
@ -60,13 +60,13 @@ class JobsContent extends StatelessWidget {
ActionButton( ActionButton(
onPressed: () => onPressed: () =>
{context.read<JobsCubit>().rebootServer()}, {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( text: TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: 'not_ready_card.1'.tr(), text: 'not_ready_card.begin'.tr(),
style: const TextStyle(color: BrandColors.white), style: const TextStyle(color: BrandColors.white),
), ),
WidgetSpan( WidgetSpan(
@ -32,7 +32,7 @@ class NotReadyCard extends StatelessWidget {
), ),
), ),
child: Text( child: Text(
'not_ready_card.2'.tr(), 'not_ready_card.insertion'.tr(),
style: body1Style.copyWith( style: body1Style.copyWith(
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -44,7 +44,7 @@ class NotReadyCard extends StatelessWidget {
), ),
), ),
TextSpan( TextSpan(
text: 'not_ready_card.3'.tr(), text: 'not_ready_card.end'.tr(),
style: const TextStyle(color: BrandColors.white), style: const TextStyle(color: BrandColors.white),
), ),
], ],

View File

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

View File

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

View File

@ -28,7 +28,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
bool isError = false; bool isError = false;
switch (dnsState) { switch (dnsState) {
case DnsRecordsStatus.uninitialized: case DnsRecordsStatus.uninitialized:
description = 'providers.domain.states.uninitialized'.tr(); description = 'domain.states.uninitialized'.tr();
icon = const Icon( icon = const Icon(
Icons.refresh, Icons.refresh,
size: 24.0, size: 24.0,
@ -36,7 +36,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false; isError = false;
break; break;
case DnsRecordsStatus.refreshing: case DnsRecordsStatus.refreshing:
description = 'providers.domain.states.refreshing'.tr(); description = 'domain.states.refreshing'.tr();
icon = const Icon( icon = const Icon(
Icons.refresh, Icons.refresh,
size: 24.0, size: 24.0,
@ -44,7 +44,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false; isError = false;
break; break;
case DnsRecordsStatus.good: case DnsRecordsStatus.good:
description = 'providers.domain.states.ok'.tr(); description = 'domain.states.ok'.tr();
icon = const Icon( icon = const Icon(
Icons.check_circle_outline, Icons.check_circle_outline,
size: 24.0, size: 24.0,
@ -52,8 +52,8 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
isError = false; isError = false;
break; break;
case DnsRecordsStatus.error: case DnsRecordsStatus.error:
description = 'providers.domain.states.error'.tr(); description = 'domain.states.error'.tr();
subtitle = 'providers.domain.states.error_subtitle'.tr(); subtitle = 'domain.states.error_subtitle'.tr();
icon = const Icon( icon = const Icon(
Icons.error_outline, Icons.error_outline,
size: 24.0, size: 24.0,
@ -93,7 +93,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
hasBackButton: true, hasBackButton: true,
headerTitle: '', headerTitle: '',
heroIcon: BrandIcons.globe, heroIcon: BrandIcons.globe,
heroTitle: 'providers.domain.screen_title'.tr(), heroTitle: 'domain.screen_title'.tr(),
heroSubtitle: 'not_ready_card.in_menu'.tr(), heroSubtitle: 'not_ready_card.in_menu'.tr(),
children: const [], children: const [],
); );
@ -107,7 +107,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
hasBackButton: true, hasBackButton: true,
heroSubtitle: domain, heroSubtitle: domain,
heroIcon: BrandIcons.globe, heroIcon: BrandIcons.globe,
heroTitle: 'providers.domain.screen_title'.tr(), heroTitle: 'domain.screen_title'.tr(),
children: <Widget>[ children: <Widget>[
_getStateCard(dnsCubit.dnsState, () { _getStateCard(dnsCubit.dnsState, () {
context.read<DnsRecordsCubit>().fix(); context.read<DnsRecordsCubit>().fix();
@ -115,13 +115,13 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
ListTile( ListTile(
title: Text( title: Text(
'providers.domain.cards.services.title'.tr(), 'domain.services_title'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith( style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
), ),
), ),
subtitle: Text( subtitle: Text(
'providers.domain.cards.services.subtitle'.tr(), 'domain.services_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium, style: Theme.of(context).textTheme.labelMedium,
), ),
), ),
@ -160,13 +160,13 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
ListTile( ListTile(
title: Text( title: Text(
'providers.domain.cards.email.title'.tr(), 'domain.email_title'.tr(),
style: Theme.of(context).textTheme.headlineSmall!.copyWith( style: Theme.of(context).textTheme.headlineSmall!.copyWith(
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
), ),
), ),
subtitle: Text( subtitle: Text(
'providers.domain.cards.email.subtitle'.tr(), 'domain.email_subtitle'.tr(),
style: Theme.of(context).textTheme.labelMedium, 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:package_info/package_info.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
class InfoPage extends StatelessWidget { class AboutApplicationPage extends StatelessWidget {
const InfoPage({final super.key}); const AboutApplicationPage({final super.key});
@override @override
Widget build(final BuildContext context) => SafeArea( Widget build(final BuildContext context) => SafeArea(
child: Scaffold( child: Scaffold(
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(52), preferredSize: const Size.fromHeight(52),
child: child: BrandHeader(
BrandHeader(title: 'more.about_app'.tr(), hasBackButton: true), title: 'about_application_page.title'.tr(),
hasBackButton: true),
), ),
body: ListView( body: ListView(
padding: paddingH15V0, padding: paddingH15V0,
@ -24,14 +25,14 @@ class InfoPage extends StatelessWidget {
FutureBuilder( FutureBuilder(
future: _packageVersion(), future: _packageVersion(),
builder: (final context, final snapshot) => BrandText.body1( 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()]), .tr(args: [snapshot.data.toString()]),
), ),
), ),
FutureBuilder( FutureBuilder(
future: _apiVersion(), future: _apiVersion(),
builder: (final context, final snapshot) => BrandText.body1( 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()]), .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:easy_localization/easy_localization.dart';
import 'package:selfprivacy/ui/components/brand_md/brand_md.dart'; import 'package:selfprivacy/ui/components/brand_md/brand_md.dart';
class AboutPage extends StatelessWidget { class AboutUsPage extends StatelessWidget {
const AboutPage({final super.key}); const AboutUsPage({final super.key});
@override @override
Widget build(final BuildContext context) => SafeArea( Widget build(final BuildContext context) => SafeArea(
@ -13,7 +13,7 @@ class AboutPage extends StatelessWidget {
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(52), preferredSize: const Size.fromHeight(52),
child: BrandHeader( child: BrandHeader(
title: 'more.about_project'.tr(), title: 'about_us_page.title'.tr(),
hasBackButton: true, hasBackButton: true,
), ),
), ),

View File

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

View File

@ -1,5 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
@ -35,8 +36,11 @@ class _ConsoleState extends State<Console> {
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(53), preferredSize: const Size.fromHeight(53),
child: Column( child: Column(
children: const [ children: [
BrandHeader(title: 'Console', hasBackButton: true) BrandHeader(
title: 'console_page.title'.tr(),
hasBackButton: true,
),
], ],
), ),
), ),
@ -90,12 +94,12 @@ class _ConsoleState extends State<Console> {
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: const [ children: [
Text('Waiting for initialisation'), Text('console_page.waiting'.tr()),
SizedBox( const SizedBox(
height: 16, 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/ui/pages/users/users.dart';
import 'package:selfprivacy/utils/route_transitions/basic.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/app_settings/app_setting.dart';
import 'package:selfprivacy/ui/pages/more/console/console.dart'; import 'package:selfprivacy/ui/pages/more/console.dart';
import 'package:selfprivacy/ui/pages/more/info/info.dart'; import 'package:selfprivacy/ui/pages/more/about_application.dart';
class MorePage extends StatelessWidget { class MorePage extends StatelessWidget {
const MorePage({final super.key}); const MorePage({final super.key});
@ -48,7 +48,7 @@ class MorePage extends StatelessWidget {
children: [ children: [
if (isReady && usesBinds != null && !usesBinds) if (isReady && usesBinds != null && !usesBinds)
_MoreMenuItem( _MoreMenuItem(
title: 'providers.storage.start_migration_button'.tr(), title: 'storage.start_migration_button'.tr(),
iconData: Icons.drive_file_move_outline, iconData: Icons.drive_file_move_outline,
goTo: ServicesMigrationPage( goTo: ServicesMigrationPage(
diskStatus: context diskStatus: context
@ -70,12 +70,12 @@ class MorePage extends StatelessWidget {
.toList(), .toList(),
isMigration: true, isMigration: true,
), ),
subtitle: 'providers.storage.data_migration_notice'.tr(), subtitle: 'storage.data_migration_notice'.tr(),
accent: true, accent: true,
), ),
if (!isReady) if (!isReady)
_MoreMenuItem( _MoreMenuItem(
title: 'more.configuration_wizard'.tr(), title: 'more_page.configuration_wizard'.tr(),
iconData: Icons.change_history_outlined, iconData: Icons.change_history_outlined,
goTo: const InitializingPage(), goTo: const InitializingPage(),
subtitle: 'not_ready_card.in_menu'.tr(), subtitle: 'not_ready_card.in_menu'.tr(),
@ -83,7 +83,7 @@ class MorePage extends StatelessWidget {
), ),
if (isReady) if (isReady)
_MoreMenuItem( _MoreMenuItem(
title: 'more.create_ssh_key'.tr(), title: 'more_page.create_ssh_key'.tr(),
iconData: Ionicons.key_outline, iconData: Ionicons.key_outline,
goTo: const UserDetails( goTo: const UserDetails(
login: 'root', login: 'root',
@ -102,28 +102,28 @@ class MorePage extends StatelessWidget {
title: 'devices.main_screen.header'.tr(), title: 'devices.main_screen.header'.tr(),
), ),
_MoreMenuItem( _MoreMenuItem(
title: 'more.settings.title'.tr(), title: 'more_page.application_settings'.tr(),
iconData: Icons.settings_outlined, iconData: Icons.settings_outlined,
goTo: const AppSettingsPage(), goTo: const AppSettingsPage(),
), ),
_MoreMenuItem( _MoreMenuItem(
title: 'more.about_project'.tr(), title: 'more_page.about_project'.tr(),
iconData: BrandIcons.engineer, iconData: BrandIcons.engineer,
goTo: const AboutPage(), goTo: const AboutUsPage(),
), ),
_MoreMenuItem( _MoreMenuItem(
title: 'more.about_app'.tr(), title: 'more_page.about_application'.tr(),
iconData: BrandIcons.fire, iconData: BrandIcons.fire,
goTo: const InfoPage(), goTo: const AboutApplicationPage(),
), ),
if (!isReady) if (!isReady)
_MoreMenuItem( _MoreMenuItem(
title: 'more.onboarding'.tr(), title: 'more_page.onboarding'.tr(),
iconData: BrandIcons.start, iconData: BrandIcons.start,
goTo: const OnboardingPage(nextPage: RootPage()), goTo: const OnboardingPage(nextPage: RootPage()),
), ),
_MoreMenuItem( _MoreMenuItem(
title: 'more.console'.tr(), title: 'more_page.console'.tr(),
iconData: BrandIcons.terminal, iconData: BrandIcons.terminal,
goTo: const Console(), goTo: const Console(),
), ),

View File

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

View File

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

View File

@ -51,7 +51,7 @@ class NetworkChart extends StatelessWidget {
res.add( res.add(
LineTooltipItem( 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( TextStyle(
color: Theme.of(context).colorScheme.onSurface, color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

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

View File

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

View File

@ -18,7 +18,7 @@ class _TextDetails extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Text( child: Text(
'providers.server.bottom_sheet.2'.tr(), 'server.general_information'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
@ -27,34 +27,33 @@ class _TextDetails extends StatelessWidget {
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.numbers_outlined, leadingIcon: Icons.numbers_outlined,
title: data.id.toString(), title: data.id.toString(),
subtitle: 'providers.server.info.server_id'.tr(), subtitle: 'server.server_id'.tr(),
), ),
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.mode_standby_outlined, leadingIcon: Icons.mode_standby_outlined,
title: data.status.toString().split('.')[1].capitalize(), title: data.status.toString().split('.')[1].capitalize(),
subtitle: 'providers.server.info.status'.tr(), subtitle: 'server.status'.tr(),
), ),
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.memory_outlined, leadingIcon: Icons.memory_outlined,
title: 'providers.server.info.core_count' title: 'server.core_count'.plural(data.serverType.cores),
.plural(data.serverType.cores), subtitle: 'server.cpu'.tr(),
subtitle: 'providers.server.info.cpu'.tr(),
), ),
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.memory_outlined, leadingIcon: Icons.memory_outlined,
title: '${data.serverType.memory.toString()} GB', title: '${data.serverType.memory.toString()} GB',
subtitle: 'providers.server.info.ram'.tr(), subtitle: 'server.ram'.tr(),
), ),
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.euro_outlined, leadingIcon: Icons.euro_outlined,
title: data.serverType.prices[1].monthly.toStringAsFixed(2), title: data.serverType.prices[1].monthly.toStringAsFixed(2),
subtitle: 'providers.server.info.monthly_cost'.tr(), subtitle: 'server.monthly_cost'.tr(),
), ),
// Server location // Server location
ListTileOnSurfaceVariant( ListTileOnSurfaceVariant(
leadingIcon: Icons.location_on_outlined, leadingIcon: Icons.location_on_outlined,
title: '${data.location.city}, ${data.location.country}', 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( appBar: PreferredSize(
preferredSize: const Size.fromHeight(52), preferredSize: const Size.fromHeight(52),
child: BrandHeader( child: BrandHeader(
title: 'providers.server.settings.select_timezone'.tr(), title: 'server.select_timezone'.tr(),
hasBackButton: true, 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) const SizedBox(height: 16),
if (job.finishedAt != null) if (job.finishedAt != null)
FilledButton( FilledButton(
title: 'providers.storage.migration_done'.tr(), title: 'storage.migration_done'.tr(),
onPressed: () { onPressed: () {
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(
materialRoute(const RootPage()), materialRoute(const RootPage()),
@ -65,7 +65,7 @@ class _MigrationProcessPageState extends State<MigrationProcessPage> {
} }
return BrandHeroScreen( return BrandHeroScreen(
hasBackButton: false, hasBackButton: false,
heroTitle: 'providers.storage.migration_process'.tr(), heroTitle: 'storage.migration_process'.tr(),
heroSubtitle: subtitle, heroSubtitle: subtitle,
children: [ children: [
BrandLinearIndicator( BrandLinearIndicator(

View File

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

View File

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

View File

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

View File

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

View File

@ -74,7 +74,7 @@ class _ServicePageState extends State<ServicePage> {
onTap: () => _launchURL(service.url), onTap: () => _launchURL(service.url),
leading: const Icon(Icons.open_in_browser), leading: const Icon(Icons.open_in_browser),
title: Text( title: Text(
'services.service_page.open_in_browser'.tr(), 'service_page.open_in_browser'.tr(),
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
subtitle: Text( subtitle: Text(
@ -92,7 +92,7 @@ class _ServicePageState extends State<ServicePage> {
}, },
leading: const Icon(Icons.restart_alt_outlined), leading: const Icon(Icons.restart_alt_outlined),
title: Text( title: Text(
'services.service_page.restart'.tr(), 'service_page.restart'.tr(),
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
enabled: !serviceDisabled && !serviceLocked, enabled: !serviceDisabled && !serviceLocked,
@ -110,8 +110,8 @@ class _ServicePageState extends State<ServicePage> {
leading: const Icon(Icons.power_settings_new), leading: const Icon(Icons.power_settings_new),
title: Text( title: Text(
serviceDisabled serviceDisabled
? 'services.service_page.enable'.tr() ? 'service_page.enable'.tr()
: 'services.service_page.disable'.tr(), : 'service_page.disable'.tr(),
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
enabled: !serviceLocked, enabled: !serviceLocked,
@ -132,11 +132,11 @@ class _ServicePageState extends State<ServicePage> {
), ),
leading: const Icon(Icons.drive_file_move_outlined), leading: const Icon(Icons.drive_file_move_outlined),
title: Text( title: Text(
'services.service_page.move'.tr(), 'service_page.move'.tr(),
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
subtitle: Text( subtitle: Text(
'services.service_page.uses'.tr( 'service_page.uses'.tr(
namedArgs: { namedArgs: {
'usage': service.storageUsage.used.toString(), 'usage': service.storageUsage.used.toString(),
'volume': context 'volume': context
@ -188,79 +188,79 @@ class ServiceStatusCard extends StatelessWidget {
Widget build(final BuildContext context) { Widget build(final BuildContext context) {
switch (status) { switch (status) {
case ServiceStatus.active: case ServiceStatus.active:
return const FilledCard( return FilledCard(
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.check_circle_outline, Icons.check_circle_outline,
size: 24, size: 24,
), ),
title: Text('Up and running'), title: Text('service_page.status.active'.tr()),
), ),
); );
case ServiceStatus.inactive: case ServiceStatus.inactive:
return const FilledCard( return FilledCard(
tertiary: true, tertiary: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.stop_circle_outlined, Icons.stop_circle_outlined,
size: 24, size: 24,
), ),
title: Text('Stopped'), title: Text('service_page.status.inactive'.tr()),
), ),
); );
case ServiceStatus.failed: case ServiceStatus.failed:
return const FilledCard( return FilledCard(
error: true, error: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.error_outline, Icons.error_outline,
size: 24, size: 24,
), ),
title: Text('Failed to start'), title: Text('service_page.status.failed'.tr()),
), ),
); );
case ServiceStatus.off: case ServiceStatus.off:
return const FilledCard( return FilledCard(
tertiary: true, tertiary: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.power_settings_new, Icons.power_settings_new,
size: 24, size: 24,
), ),
title: Text('Disabled'), title: Text('service_page.status.off'.tr()),
), ),
); );
case ServiceStatus.activating: case ServiceStatus.activating:
return const FilledCard( return FilledCard(
tertiary: true, tertiary: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.restart_alt_outlined, Icons.restart_alt_outlined,
size: 24, size: 24,
), ),
title: Text('Activating'), title: Text('service_page.status.activating'.tr()),
), ),
); );
case ServiceStatus.deactivating: case ServiceStatus.deactivating:
return const FilledCard( return FilledCard(
tertiary: true, tertiary: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.restart_alt_outlined, Icons.restart_alt_outlined,
size: 24, size: 24,
), ),
title: Text('Deactivating'), title: Text('service_page.status.deactivating'.tr()),
), ),
); );
case ServiceStatus.reloading: case ServiceStatus.reloading:
return const FilledCard( return FilledCard(
tertiary: true, tertiary: true,
child: ListTile( child: ListTile(
leading: Icon( leading: const Icon(
Icons.restart_alt_outlined, Icons.restart_alt_outlined,
size: 24, 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( child: ListView(
padding: paddingH15V0, padding: paddingH15V0,
children: [ children: [
BrandText.body1('services.title'.tr()), BrandText.body1('basis.services_title'.tr()),
const SizedBox(height: 24), const SizedBox(height: 24),
if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)], if (!isReady) ...[const NotReadyCard(), const SizedBox(height: 24)],
...ServiceTypes.values ...ServiceTypes.values
@ -218,7 +218,7 @@ class _Card extends StatelessWidget {
sigmaY: 2, sigmaY: 2,
), ),
child: BrandText.h2( child: BrandText.h2(
'jobs.runJobs'.tr(), 'jobs.run_jobs'.tr(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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