Selaa lähdekoodia

Improve Project Manager auto-translation

kobewi 4 kuukautta sitten
vanhempi
commit
e6edf3b3b3

+ 63 - 59
editor/gui/editor_file_dialog.cpp

@@ -262,9 +262,13 @@ void EditorFileDialog::_notification(int p_what) {
 			set_translation_domain(SNAME("godot.editor"));
 		} break;
 
-		case NOTIFICATION_THEME_CHANGED:
-		case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
 		case NOTIFICATION_TRANSLATION_CHANGED: {
+			update_filters();
+			[[fallthrough]];
+		}
+
+		case NOTIFICATION_THEME_CHANGED:
+		case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
 			_update_icons();
 			invalidate();
 		} break;
@@ -434,12 +438,12 @@ void EditorFileDialog::update_dir() {
 		case FILE_MODE_OPEN_FILE:
 		case FILE_MODE_OPEN_FILES:
 			file->set_text("");
-			set_ok_button_text(TTR("Open"));
+			set_ok_button_text(TTRC("Open"));
 			break;
 		case FILE_MODE_OPEN_ANY:
 		case FILE_MODE_OPEN_DIR:
 			file->set_text("");
-			set_ok_button_text(TTR("Select Current Folder"));
+			set_ok_button_text(TTRC("Select Current Folder"));
 			break;
 		case FILE_MODE_SAVE_FILE:
 			// FIXME: Implement, or refactor to avoid duplication with set_mode
@@ -663,7 +667,7 @@ void EditorFileDialog::_action_pressed() {
 		// First check we're not having an empty name.
 		String file_name = file_text.strip_edges().get_file();
 		if (file_name.is_empty()) {
-			error_dialog->set_text(TTR("Cannot save file with an empty filename."));
+			error_dialog->set_text(TTRC("Cannot save file with an empty filename."));
 			error_dialog->popup_centered(Size2(250, 80) * EDSCALE);
 			return;
 		}
@@ -677,7 +681,7 @@ void EditorFileDialog::_action_pressed() {
 		}
 
 		if (file_name.begins_with(".")) { // Could still happen if typed manually.
-			error_dialog->set_text(TTR("Cannot save file with a name starting with a dot."));
+			error_dialog->set_text(TTRC("Cannot save file with a name starting with a dot."));
 			error_dialog->popup_centered(Size2(250, 80) * EDSCALE);
 			return;
 		}
@@ -713,11 +717,11 @@ void EditorFileDialog::_item_selected(int p_item) {
 
 		if (mode != FILE_MODE_SAVE_FILE) {
 			// FILE_MODE_OPEN_ANY can alternate this text depending on what's selected.
-			set_ok_button_text(TTR("Open"));
+			set_ok_button_text(TTRC("Open"));
 		}
 	} else if (mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) {
 		file->set_text("");
-		set_ok_button_text(TTR("Select This Folder"));
+		set_ok_button_text(TTRC("Select This Folder"));
 	}
 
 	get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -750,7 +754,7 @@ void EditorFileDialog::_items_clear_selection(const Vector2 &p_pos, MouseButton
 	switch (mode) {
 		case FILE_MODE_OPEN_FILE:
 		case FILE_MODE_OPEN_FILES:
-			set_ok_button_text(TTR("Open"));
+			set_ok_button_text(TTRC("Open"));
 			get_ok_button()->set_disabled(!item_list->is_anything_selected());
 			break;
 
@@ -758,7 +762,7 @@ void EditorFileDialog::_items_clear_selection(const Vector2 &p_pos, MouseButton
 		case FILE_MODE_OPEN_DIR:
 			file->set_text("");
 			get_ok_button()->set_disabled(false);
-			set_ok_button_text(TTR("Select Current Folder"));
+			set_ok_button_text(TTRC("Select Current Folder"));
 			break;
 
 		case FILE_MODE_SAVE_FILE:
@@ -824,10 +828,10 @@ void EditorFileDialog::_item_list_item_rmb_clicked(int p_item, const Vector2 &p_
 	}
 
 	if (single_item_selected) {
-		item_menu->add_icon_item(theme_cache.action_copy, TTR("Copy Path"), ITEM_MENU_COPY_PATH);
+		item_menu->add_icon_item(theme_cache.action_copy, TTRC("Copy Path"), ITEM_MENU_COPY_PATH);
 	}
 	if (allow_delete) {
-		item_menu->add_icon_item(theme_cache.action_delete, TTR("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
+		item_menu->add_icon_item(theme_cache.action_delete, TTRC("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
 	}
 
 #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
@@ -835,14 +839,14 @@ void EditorFileDialog::_item_list_item_rmb_clicked(int p_item, const Vector2 &p_
 	if (single_item_selected) {
 		item_menu->add_separator();
 		Dictionary item_meta = item_list->get_item_metadata(p_item);
-		String item_text = item_meta["dir"] ? TTR("Open in File Manager") : TTR("Show in File Manager");
+		String item_text = item_meta["dir"] ? TTRC("Open in File Manager") : TTRC("Show in File Manager");
 		item_menu->add_icon_item(theme_cache.filesystem, item_text, ITEM_MENU_SHOW_IN_EXPLORER);
 	}
 #endif
 	if (single_item_selected) {
 		Dictionary item_meta = item_list->get_item_metadata(p_item);
 		if (item_meta["bundle"]) {
-			item_menu->add_icon_item(theme_cache.open_folder, TTR("Show Package Contents"), ITEM_MENU_SHOW_BUNDLE_CONTENT);
+			item_menu->add_icon_item(theme_cache.open_folder, TTRC("Show Package Contents"), ITEM_MENU_SHOW_BUNDLE_CONTENT);
 		}
 	}
 
@@ -871,13 +875,13 @@ void EditorFileDialog::_item_list_empty_clicked(const Vector2 &p_pos, MouseButto
 	item_menu->reset_size();
 
 	if (can_create_dir) {
-		item_menu->add_icon_item(theme_cache.folder, TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD_OR_CTRL | Key::N);
+		item_menu->add_icon_item(theme_cache.folder, TTRC("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD_OR_CTRL | Key::N);
 	}
-	item_menu->add_icon_item(theme_cache.reload, TTR("Refresh"), ITEM_MENU_REFRESH, Key::F5);
+	item_menu->add_icon_item(theme_cache.reload, TTRC("Refresh"), ITEM_MENU_REFRESH, Key::F5);
 #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
 	// Opening the system file manager is not supported on the Android and web editors.
 	item_menu->add_separator();
-	item_menu->add_icon_item(theme_cache.filesystem, TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+	item_menu->add_icon_item(theme_cache.filesystem, TTRC("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
 #endif
 
 	item_menu->set_position(item_list->get_screen_position() + p_pos);
@@ -1446,28 +1450,28 @@ void EditorFileDialog::set_file_mode(FileMode p_mode) {
 	mode = p_mode;
 	switch (mode) {
 		case FILE_MODE_OPEN_FILE:
-			set_ok_button_text(TTR("Open"));
-			set_title(TTR("Open a File"));
+			set_ok_button_text(TTRC("Open"));
+			set_title(TTRC("Open a File"));
 			can_create_dir = false;
 			break;
 		case FILE_MODE_OPEN_FILES:
-			set_ok_button_text(TTR("Open"));
-			set_title(TTR("Open File(s)"));
+			set_ok_button_text(TTRC("Open"));
+			set_title(TTRC("Open File(s)"));
 			can_create_dir = false;
 			break;
 		case FILE_MODE_OPEN_DIR:
-			set_ok_button_text(TTR("Open"));
-			set_title(TTR("Open a Directory"));
+			set_ok_button_text(TTRC("Open"));
+			set_title(TTRC("Open a Directory"));
 			can_create_dir = true;
 			break;
 		case FILE_MODE_OPEN_ANY:
-			set_ok_button_text(TTR("Open"));
-			set_title(TTR("Open a File or Directory"));
+			set_ok_button_text(TTRC("Open"));
+			set_title(TTRC("Open a File or Directory"));
 			can_create_dir = true;
 			break;
 		case FILE_MODE_SAVE_FILE:
-			set_ok_button_text(TTR("Save"));
-			set_title(TTR("Save a File"));
+			set_ok_button_text(TTRC("Save"));
+			set_title(TTRC("Save a File"));
 			can_create_dir = true;
 			break;
 	}
@@ -1538,14 +1542,14 @@ void EditorFileDialog::_make_dir_confirm() {
 	const String stripped_dirname = makedirname->get_text().strip_edges();
 
 	if (stripped_dirname.is_empty()) {
-		error_dialog->set_text(TTR("The path specified is invalid."));
+		error_dialog->set_text(TTRC("The path specified is invalid."));
 		error_dialog->popup_centered(Size2(250, 50) * EDSCALE);
 		makedirname->set_text(""); // Reset label.
 		return;
 	}
 
 	if (dir_access->dir_exists(stripped_dirname)) {
-		error_dialog->set_text(TTR("Could not create folder. File with that name already exists."));
+		error_dialog->set_text(TTRC("Could not create folder. File with that name already exists."));
 		error_dialog->popup_centered(Size2(250, 50) * EDSCALE);
 		makedirname->set_text(""); // Reset label.
 		return;
@@ -1562,7 +1566,7 @@ void EditorFileDialog::_make_dir_confirm() {
 			EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
 		}
 	} else {
-		error_dialog->set_text(TTR("Could not create folder."));
+		error_dialog->set_text(TTRC("Could not create folder."));
 		error_dialog->popup_centered(Size2(250, 50) * EDSCALE);
 	}
 	makedirname->set_text(""); // reset label
@@ -1705,7 +1709,7 @@ void EditorFileDialog::_update_icons() {
 void EditorFileDialog::_favorite_selected(int p_idx) {
 	Error change_dir_result = dir_access->change_dir(favorites->get_item_metadata(p_idx));
 	if (change_dir_result != OK) {
-		error_dialog->set_text(TTR("Favorited folder does not exist anymore and will be removed."));
+		error_dialog->set_text(TTRC("Favorited folder does not exist anymore and will be removed."));
 		error_dialog->popup_centered(Size2(250, 50) * EDSCALE);
 
 		bool res = (access == ACCESS_RESOURCES);
@@ -2376,7 +2380,7 @@ EditorFileDialog::EditorFileDialog() {
 	vbc = memnew(VBoxContainer);
 	add_child(vbc);
 
-	set_title(TTR("Save a File"));
+	set_title(TTRC("Save a File"));
 
 	ED_SHORTCUT("file_dialog/go_back", TTRC("Go Back"), KeyModifierMask::ALT | Key::LEFT);
 	ED_SHORTCUT("file_dialog/go_forward", TTRC("Go Forward"), KeyModifierMask::ALT | Key::RIGHT);
@@ -2405,15 +2409,15 @@ EditorFileDialog::EditorFileDialog() {
 	dir_prev = memnew(Button);
 	dir_prev->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_prev->set_accessibility_name(TTRC("Previous"));
-	dir_prev->set_tooltip_text(TTR("Go to previous folder."));
+	dir_prev->set_tooltip_text(TTRC("Go to previous folder."));
 	dir_next = memnew(Button);
 	dir_next->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_next->set_accessibility_name(TTRC("Next"));
-	dir_next->set_tooltip_text(TTR("Go to next folder."));
+	dir_next->set_tooltip_text(TTRC("Go to next folder."));
 	dir_up = memnew(Button);
 	dir_up->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_up->set_accessibility_name(TTRC("Parent Folder"));
-	dir_up->set_tooltip_text(TTR("Go to parent folder."));
+	dir_up->set_tooltip_text(TTRC("Go to parent folder."));
 
 	pathhb->add_child(dir_prev);
 	pathhb->add_child(dir_next);
@@ -2423,7 +2427,7 @@ EditorFileDialog::EditorFileDialog() {
 	dir_next->connect(SceneStringName(pressed), callable_mp(this, &EditorFileDialog::_go_forward));
 	dir_up->connect(SceneStringName(pressed), callable_mp(this, &EditorFileDialog::_go_up));
 
-	Label *l = memnew(Label(TTR("Path:")));
+	Label *l = memnew(Label(TTRC("Path:")));
 	l->set_focus_mode(Control::FOCUS_NONE);
 	l->set_theme_type_variation("HeaderSmall");
 	pathhb->add_child(l);
@@ -2439,7 +2443,7 @@ EditorFileDialog::EditorFileDialog() {
 	refresh = memnew(Button);
 	refresh->set_theme_type_variation(SceneStringName(FlatButton));
 	refresh->set_accessibility_name(TTRC("Refresh Files"));
-	refresh->set_tooltip_text(TTR("Refresh files."));
+	refresh->set_tooltip_text(TTRC("Refresh files."));
 	refresh->connect(SceneStringName(pressed), callable_mp(this, &EditorFileDialog::update_file_list));
 	pathhb->add_child(refresh);
 
@@ -2447,7 +2451,7 @@ EditorFileDialog::EditorFileDialog() {
 	favorite->set_theme_type_variation(SceneStringName(FlatButton));
 	favorite->set_toggle_mode(true);
 	favorite->set_accessibility_name(TTRC("(Un)favorite Folder"));
-	favorite->set_tooltip_text(TTR("(Un)favorite current folder."));
+	favorite->set_tooltip_text(TTRC("(Un)favorite current folder."));
 	favorite->connect(SceneStringName(pressed), callable_mp(this, &EditorFileDialog::_favorite_pressed));
 	pathhb->add_child(favorite);
 
@@ -2465,7 +2469,7 @@ EditorFileDialog::EditorFileDialog() {
 	makedir = memnew(Button);
 	makedir->set_theme_type_variation(SceneStringName(FlatButton));
 	makedir->set_accessibility_name(TTRC("Create Folder"));
-	makedir->set_tooltip_text(TTR("Create a new folder."));
+	makedir->set_tooltip_text(TTRC("Create a new folder."));
 	makedir->connect(SceneStringName(pressed), callable_mp(this, &EditorFileDialog::_make_dir));
 	pathhb->add_child(makedir);
 
@@ -2499,7 +2503,7 @@ EditorFileDialog::EditorFileDialog() {
 	HBoxContainer *fav_hb = memnew(HBoxContainer);
 	fav_vb->add_child(fav_hb);
 
-	l = memnew(Label(TTR("Favorites:")));
+	l = memnew(Label(TTRC("Favorites:")));
 	l->set_focus_mode(Control::FOCUS_NONE);
 	l->set_theme_type_variation("HeaderSmall");
 	fav_hb->add_child(l);
@@ -2533,7 +2537,7 @@ EditorFileDialog::EditorFileDialog() {
 	recent->set_allow_reselect(true);
 	recent->set_theme_type_variation("ItemListSecondary");
 	recent->set_accessibility_name(TTRC("Recent"));
-	rec_vb->add_margin_child(TTR("Recent:"), recent, true);
+	rec_vb->add_margin_child(TTRC("Recent:"), recent, true);
 	recent->connect(SceneStringName(item_selected), callable_mp(this, &EditorFileDialog::_recent_selected));
 
 	VBoxContainer *item_vb = memnew(VBoxContainer);
@@ -2550,7 +2554,7 @@ EditorFileDialog::EditorFileDialog() {
 	HBoxContainer *lower_hb = memnew(HBoxContainer);
 	lower_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 
-	l = memnew(Label(TTR("Directories & Files:")));
+	l = memnew(Label(TTRC("Directories & Files:")));
 	l->set_focus_mode(Control::FOCUS_NONE);
 	l->set_theme_type_variation("HeaderSmall");
 	l->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -2562,7 +2566,7 @@ EditorFileDialog::EditorFileDialog() {
 	show_hidden->set_toggle_mode(true);
 	show_hidden->set_pressed(is_showing_hidden_files());
 	show_hidden->set_accessibility_name(TTRC("Show Hidden Files"));
-	show_hidden->set_tooltip_text(TTR("Toggle the visibility of hidden files."));
+	show_hidden->set_tooltip_text(TTRC("Toggle the visibility of hidden files."));
 	show_hidden->connect(SceneStringName(toggled), callable_mp(this, &EditorFileDialog::set_show_hidden_files));
 	lower_hb->add_child(show_hidden);
 
@@ -2578,7 +2582,7 @@ EditorFileDialog::EditorFileDialog() {
 	mode_thumbnails->set_pressed(display_mode == DISPLAY_THUMBNAILS);
 	mode_thumbnails->set_button_group(view_mode_group);
 	mode_thumbnails->set_accessibility_name(TTRC("View as Thumbnails"));
-	mode_thumbnails->set_tooltip_text(TTR("View items as a grid of thumbnails."));
+	mode_thumbnails->set_tooltip_text(TTRC("View items as a grid of thumbnails."));
 	lower_hb->add_child(mode_thumbnails);
 
 	mode_list = memnew(Button);
@@ -2588,7 +2592,7 @@ EditorFileDialog::EditorFileDialog() {
 	mode_list->set_pressed(display_mode == DISPLAY_LIST);
 	mode_list->set_button_group(view_mode_group);
 	mode_list->set_accessibility_name(TTRC("View as List"));
-	mode_list->set_tooltip_text(TTR("View items as a list."));
+	mode_list->set_tooltip_text(TTRC("View items as a list."));
 	lower_hb->add_child(mode_list);
 
 	lower_hb->add_child(memnew(VSeparator));
@@ -2596,26 +2600,26 @@ EditorFileDialog::EditorFileDialog() {
 	file_sort_button = memnew(MenuButton);
 	file_sort_button->set_flat(false);
 	file_sort_button->set_theme_type_variation("FlatMenuButton");
-	file_sort_button->set_tooltip_text(TTR("Sort files"));
+	file_sort_button->set_tooltip_text(TTRC("Sort files"));
 	file_sort_button->set_accessibility_name(TTRC("Sort Files"));
 
 	show_search_filter_button = memnew(Button);
 	show_search_filter_button->set_theme_type_variation(SceneStringName(FlatButton));
 	show_search_filter_button->set_toggle_mode(true);
 	show_search_filter_button->set_pressed(false);
-	show_search_filter_button->set_tooltip_text(TTR("Toggle the visibility of the filter for file names."));
+	show_search_filter_button->set_tooltip_text(TTRC("Toggle the visibility of the filter for file names."));
 	show_search_filter_button->set_accessibility_name(TTRC("Show Search Filters"));
 	show_search_filter_button->connect(SceneStringName(toggled), callable_mp(this, &EditorFileDialog::set_show_search_filter));
 	lower_hb->add_child(show_search_filter_button);
 
 	PopupMenu *p = file_sort_button->get_popup();
 	p->connect(SceneStringName(id_pressed), callable_mp(this, &EditorFileDialog::_file_sort_popup));
-	p->add_radio_check_item(TTR("Sort by Name (Ascending)"), static_cast<int>(FileSortOption::FILE_SORT_NAME));
-	p->add_radio_check_item(TTR("Sort by Name (Descending)"), static_cast<int>(FileSortOption::FILE_SORT_NAME_REVERSE));
-	p->add_radio_check_item(TTR("Sort by Type (Ascending)"), static_cast<int>(FileSortOption::FILE_SORT_TYPE));
-	p->add_radio_check_item(TTR("Sort by Type (Descending)"), static_cast<int>(FileSortOption::FILE_SORT_TYPE_REVERSE));
-	p->add_radio_check_item(TTR("Sort by Last Modified"), static_cast<int>(FileSortOption::FILE_SORT_MODIFIED_TIME));
-	p->add_radio_check_item(TTR("Sort by First Modified"), static_cast<int>(FileSortOption::FILE_SORT_MODIFIED_TIME_REVERSE));
+	p->add_radio_check_item(TTRC("Sort by Name (Ascending)"), static_cast<int>(FileSortOption::FILE_SORT_NAME));
+	p->add_radio_check_item(TTRC("Sort by Name (Descending)"), static_cast<int>(FileSortOption::FILE_SORT_NAME_REVERSE));
+	p->add_radio_check_item(TTRC("Sort by Type (Ascending)"), static_cast<int>(FileSortOption::FILE_SORT_TYPE));
+	p->add_radio_check_item(TTRC("Sort by Type (Descending)"), static_cast<int>(FileSortOption::FILE_SORT_TYPE_REVERSE));
+	p->add_radio_check_item(TTRC("Sort by Last Modified"), static_cast<int>(FileSortOption::FILE_SORT_MODIFIED_TIME));
+	p->add_radio_check_item(TTRC("Sort by First Modified"), static_cast<int>(FileSortOption::FILE_SORT_MODIFIED_TIME_REVERSE));
 	p->set_item_checked(0, true);
 	lower_hb->add_child(file_sort_button);
 
@@ -2643,7 +2647,7 @@ EditorFileDialog::EditorFileDialog() {
 	preview_vb = memnew(VBoxContainer);
 	preview_hb->add_child(preview_vb);
 	CenterContainer *prev_cc = memnew(CenterContainer);
-	preview_vb->add_margin_child(TTR("Preview:"), prev_cc);
+	preview_vb->add_margin_child(TTRC("Preview:"), prev_cc);
 	preview = memnew(TextureRect);
 	prev_cc->add_child(preview);
 	preview_vb->hide();
@@ -2652,7 +2656,7 @@ EditorFileDialog::EditorFileDialog() {
 	filter_hb->add_child(memnew(Label(RTR("Filter:"))));
 	filter_box = memnew(LineEdit);
 	filter_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-	filter_box->set_placeholder(TTR("Filter"));
+	filter_box->set_placeholder(TTRC("Filter"));
 	filter_box->set_accessibility_name(TTRC("Filename Filter"));
 	filter_hb->add_child(filter_box);
 	filter_hb->set_visible(false);
@@ -2660,7 +2664,7 @@ EditorFileDialog::EditorFileDialog() {
 
 	file_box = memnew(HBoxContainer);
 
-	l = memnew(Label(TTR("File:")));
+	l = memnew(Label(TTRC("File:")));
 	l->set_focus_mode(Control::FOCUS_NONE);
 	l->set_theme_type_variation("HeaderSmall");
 	file_box->add_child(l);
@@ -2702,19 +2706,19 @@ EditorFileDialog::EditorFileDialog() {
 	add_child(dep_remove_dialog);
 
 	global_remove_dialog = memnew(ConfirmationDialog);
-	global_remove_dialog->set_text(TTR("Remove the selected files? For safety only files and empty directories can be deleted from here. (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently."));
+	global_remove_dialog->set_text(TTRC("Remove the selected files? For safety only files and empty directories can be deleted from here. (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently."));
 	global_remove_dialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorFileDialog::_delete_files_global));
 	add_child(global_remove_dialog);
 
 	makedialog = memnew(ConfirmationDialog);
-	makedialog->set_title(TTR("Create Folder"));
+	makedialog->set_title(TTRC("Create Folder"));
 	VBoxContainer *makevb = memnew(VBoxContainer);
 	makedialog->add_child(makevb);
 
 	makedirname = memnew(LineEdit);
 	makedirname->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
 	makedirname->set_accessibility_name(TTRC("Name"));
-	makevb->add_margin_child(TTR("Name:"), makedirname);
+	makevb->add_margin_child(TTRC("Name:"), makedirname);
 	add_child(makedialog);
 	makedialog->register_text_enter(makedirname);
 	makedialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorFileDialog::_make_dir_confirm));

+ 65 - 64
editor/project_manager.cpp

@@ -105,6 +105,13 @@ void ProjectManager::_notification(int p_what) {
 		} break;
 
 		case NOTIFICATION_TRANSLATION_CHANGED: {
+			// TRANSLATORS: This refers to the application where users manage their Godot projects.
+			SceneTree::get_singleton()->get_root()->set_title(GODOT_VERSION_NAME + String(" - ") + TTR("Project Manager", "Application"));
+
+			const String line1 = TTR("You don't have any projects yet.");
+			const String line2 = TTR("Get started by creating a new one,\nimporting one that exists, or by downloading a project template from the Asset Library!");
+			empty_list_message->set_text(vformat("[center][b]%s[/b] %s[/center]", line1, line2));
+
 			_titlebar_resized();
 		} break;
 
@@ -417,10 +424,10 @@ void ProjectManager::_update_list_placeholder() {
 
 	const int network_mode = EDITOR_GET("network/connection/network_mode");
 	if (network_mode == EditorSettings::NETWORK_OFFLINE) {
-		empty_list_open_assetlib->set_text(TTR("Go Online and Open Asset Library"));
+		empty_list_open_assetlib->set_text(TTRC("Go Online and Open Asset Library"));
 		empty_list_online_warning->set_visible(true);
 	} else {
-		empty_list_open_assetlib->set_text(TTR("Open Asset Library"));
+		empty_list_open_assetlib->set_text(TTRC("Open Asset Library"));
 		empty_list_online_warning->set_visible(false);
 	}
 
@@ -452,7 +459,7 @@ void ProjectManager::_run_project_confirm() {
 	for (int i = 0; i < selected_list.size(); ++i) {
 		const String &selected_main = selected_list[i].main_scene;
 		if (selected_main.is_empty()) {
-			_show_error(TTR("Can't run project: Project has no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category."));
+			_show_error(TTRC("Can't run project: Project has no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category."));
 			continue;
 		}
 
@@ -460,7 +467,7 @@ void ProjectManager::_run_project_confirm() {
 
 		// `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://".
 		if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
-			_show_error(TTR("Can't run project: Assets need to be imported first.\nPlease edit the project to trigger the initial import."));
+			_show_error(TTRC("Can't run project: Assets need to be imported first.\nPlease edit the project to trigger the initial import."));
 			continue;
 		}
 
@@ -571,10 +578,10 @@ void ProjectManager::_open_selected_projects_check_warnings() {
 		if (config_version == GODOT4_CONFIG_VERSION - 1 && ProjectSettings::CONFIG_VERSION == GODOT4_CONFIG_VERSION) { // Conversion from Godot 3 to 4.
 			full_convert_button->show();
 			ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by Godot 3.x, and needs to be converted for Godot 4.x.\n\nProject path: %s\n\nYou have three options:\n- Convert only the configuration file (\"project.godot\"). Use this to open the project without attempting to convert its scenes, resources and scripts.\n- Convert the entire project including its scenes, resources and scripts (recommended if you are upgrading).\n- Do nothing and go back.\n\nWarning: If you select a conversion option, you won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
-			ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot Only"));
+			ask_update_settings->get_ok_button()->set_text(TTRC("Convert project.godot Only"));
 		} else {
 			ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by an older engine version, and needs to be converted for this version.\n\nProject path: %s\n\nDo you want to convert it?\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
-			ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
+			ask_update_settings->get_ok_button()->set_text(TTRC("Convert project.godot"));
 		}
 		ask_update_settings->popup_centered(popup_min_size);
 		ask_update_settings->get_cancel_button()->grab_focus(); // To prevent accidents.
@@ -696,7 +703,7 @@ void ProjectManager::_erase_project() {
 	if (selected_list.size() >= 2) {
 		confirm_message = vformat(TTR("Remove %d projects from the list?"), selected_list.size());
 	} else {
-		confirm_message = TTR("Remove this project from the list?");
+		confirm_message = TTRC("Remove this project from the list?");
 	}
 
 	erase_ask_label->set_text(confirm_message);
@@ -705,7 +712,7 @@ void ProjectManager::_erase_project() {
 }
 
 void ProjectManager::_erase_missing_projects() {
-	erase_missing_ask->set_text(TTR("Remove all missing projects from the list?\nThe project folders' contents won't be modified."));
+	erase_missing_ask->set_text(TTRC("Remove all missing projects from the list?\nThe project folders' contents won't be modified."));
 	erase_missing_ask->popup_centered();
 }
 
@@ -936,24 +943,24 @@ void ProjectManager::_apply_project_tags() {
 void ProjectManager::_set_new_tag_name(const String p_name) {
 	create_tag_dialog->get_ok_button()->set_disabled(true);
 	if (p_name.is_empty()) {
-		tag_error->set_text(TTR("Tag name can't be empty."));
+		tag_error->set_text(TTRC("Tag name can't be empty."));
 		return;
 	}
 
 	if (p_name.contains_char(' ')) {
-		tag_error->set_text(TTR("Tag name can't contain spaces."));
+		tag_error->set_text(TTRC("Tag name can't contain spaces."));
 		return;
 	}
 
 	for (const String &c : forbidden_tag_characters) {
 		if (p_name.contains(c)) {
-			tag_error->set_text(vformat(TTR("These characters are not allowed in tags: %s."), String(" ").join(forbidden_tag_characters)));
+			tag_error->set_text(vformat(TTRC("These characters are not allowed in tags: %s."), String(" ").join(forbidden_tag_characters)));
 			return;
 		}
 	}
 
 	if (p_name.to_lower() != p_name) {
-		tag_error->set_text(TTR("Tag name must be lowercase."));
+		tag_error->set_text(TTRC("Tag name must be lowercase."));
 		return;
 	}
 
@@ -1237,9 +1244,6 @@ ProjectManager::ProjectManager() {
 		OS::get_singleton()->set_low_processor_usage_mode(true);
 	}
 
-	// TRANSLATORS: This refers to the application where users manage their Godot projects.
-	SceneTree::get_singleton()->get_root()->set_title(GODOT_VERSION_NAME + String(" - ") + TTR("Project Manager", "Application"));
-
 	SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
 
 	// Initialize UI.
@@ -1328,7 +1332,7 @@ ProjectManager::ProjectManager() {
 
 		quick_settings_button = memnew(Button);
 		quick_settings_button->set_flat(true);
-		quick_settings_button->set_text(TTR("Settings"));
+		quick_settings_button->set_text(TTRC("Settings"));
 		right_hbox->add_child(quick_settings_button);
 		quick_settings_button->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_show_quick_settings));
 
@@ -1348,7 +1352,7 @@ ProjectManager::ProjectManager() {
 	{
 		local_projects_vb = memnew(VBoxContainer);
 		local_projects_vb->set_name("LocalProjectsTab");
-		_add_main_view(MAIN_VIEW_PROJECTS, TTR("Projects"), Ref<Texture2D>(), local_projects_vb);
+		_add_main_view(MAIN_VIEW_PROJECTS, TTRC("Projects"), Ref<Texture2D>(), local_projects_vb);
 
 		// Project list's top bar.
 		{
@@ -1357,33 +1361,33 @@ ProjectManager::ProjectManager() {
 			local_projects_vb->add_child(hb);
 
 			create_btn = memnew(Button);
-			create_btn->set_text(TTR("Create"));
+			create_btn->set_text(TTRC("Create"));
 			create_btn->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTRC("New Project"), KeyModifierMask::CMD_OR_CTRL | Key::N));
 			create_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_new_project));
 			hb->add_child(create_btn);
 
 			import_btn = memnew(Button);
-			import_btn->set_text(TTR("Import"));
+			import_btn->set_text(TTRC("Import"));
 			import_btn->set_shortcut(ED_SHORTCUT("project_manager/import_project", TTRC("Import Project"), KeyModifierMask::CMD_OR_CTRL | Key::I));
 			import_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_import_project));
 			hb->add_child(import_btn);
 
 			scan_btn = memnew(Button);
-			scan_btn->set_text(TTR("Scan"));
+			scan_btn->set_text(TTRC("Scan"));
 			scan_btn->set_shortcut(ED_SHORTCUT("project_manager/scan_projects", TTRC("Scan Projects"), KeyModifierMask::CMD_OR_CTRL | Key::S));
 			scan_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_scan_projects));
 			hb->add_child(scan_btn);
 
-			loading_label = memnew(Label(TTR("Loading, please wait...")));
+			loading_label = memnew(Label(TTRC("Loading, please wait...")));
 			loading_label->set_accessibility_live(DisplayServer::AccessibilityLiveMode::LIVE_ASSERTIVE);
 			loading_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 			loading_label->hide();
 			hb->add_child(loading_label);
 
 			search_box = memnew(LineEdit);
-			search_box->set_placeholder(TTR("Filter Projects"));
+			search_box->set_placeholder(TTRC("Filter Projects"));
 			search_box->set_accessibility_name(TTRC("Filter Projects"));
-			search_box->set_tooltip_text(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+			search_box->set_tooltip_text(TTRC("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
 			search_box->set_clear_button_enabled(true);
 			search_box->connect(SceneStringName(text_changed), callable_mp(this, &ProjectManager::_on_search_term_changed));
 			search_box->connect(SceneStringName(text_submitted), callable_mp(this, &ProjectManager::_on_search_term_submitted));
@@ -1391,7 +1395,7 @@ ProjectManager::ProjectManager() {
 			hb->add_child(search_box);
 
 			sort_label = memnew(Label);
-			sort_label->set_text(TTR("Sort:"));
+			sort_label->set_text(TTRC("Sort:"));
 			sort_label->set_focus_mode(Control::FOCUS_NONE);
 			hb->add_child(sort_label);
 
@@ -1403,10 +1407,10 @@ ProjectManager::ProjectManager() {
 			filter_option->connect(SceneStringName(item_selected), callable_mp(this, &ProjectManager::_on_order_option_changed));
 			hb->add_child(filter_option);
 
-			filter_option->add_item(TTR("Last Edited"));
-			filter_option->add_item(TTR("Name"));
-			filter_option->add_item(TTR("Path"));
-			filter_option->add_item(TTR("Tags"));
+			filter_option->add_item(TTRC("Last Edited"));
+			filter_option->add_item(TTRC("Name"));
+			filter_option->add_item(TTRC("Path"));
+			filter_option->add_item(TTRC("Tags"));
 		}
 
 		// Project list and its sidebar.
@@ -1435,15 +1439,12 @@ ProjectManager::ProjectManager() {
 				empty_list_placeholder->hide();
 				project_list_panel->add_child(empty_list_placeholder);
 
-				RichTextLabel *empty_list_message = memnew(RichTextLabel);
+				empty_list_message = memnew(RichTextLabel);
 				empty_list_message->set_use_bbcode(true);
 				empty_list_message->set_fit_content(true);
 				empty_list_message->set_h_size_flags(SIZE_EXPAND_FILL);
 				empty_list_message->add_theme_style_override(CoreStringName(normal), memnew(StyleBoxEmpty));
 
-				const String line1 = TTR("You don't have any projects yet.");
-				const String line2 = TTR("Get started by creating a new one,\nimporting one that exists, or by downloading a project template from the Asset Library!");
-				empty_list_message->set_text(vformat("[center][b]%s[/b] %s[/center]", line1, line2));
 				empty_list_placeholder->add_child(empty_list_message);
 
 				FlowContainer *empty_list_actions = memnew(FlowContainer);
@@ -1451,19 +1452,19 @@ ProjectManager::ProjectManager() {
 				empty_list_placeholder->add_child(empty_list_actions);
 
 				empty_list_create_project = memnew(Button);
-				empty_list_create_project->set_text(TTR("Create New Project"));
+				empty_list_create_project->set_text(TTRC("Create New Project"));
 				empty_list_create_project->set_theme_type_variation("PanelBackgroundButton");
 				empty_list_actions->add_child(empty_list_create_project);
 				empty_list_create_project->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_new_project));
 
 				empty_list_import_project = memnew(Button);
-				empty_list_import_project->set_text(TTR("Import Existing Project"));
+				empty_list_import_project->set_text(TTRC("Import Existing Project"));
 				empty_list_import_project->set_theme_type_variation("PanelBackgroundButton");
 				empty_list_actions->add_child(empty_list_import_project);
 				empty_list_import_project->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_import_project));
 
 				empty_list_open_assetlib = memnew(Button);
-				empty_list_open_assetlib->set_text(TTR("Open Asset Library"));
+				empty_list_open_assetlib->set_text(TTRC("Open Asset Library"));
 				empty_list_open_assetlib->set_theme_type_variation("PanelBackgroundButton");
 				empty_list_actions->add_child(empty_list_open_assetlib);
 				empty_list_open_assetlib->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_open_asset_library_confirmed));
@@ -1473,7 +1474,7 @@ ProjectManager::ProjectManager() {
 				empty_list_online_warning->set_custom_minimum_size(Size2(220, 0) * EDSCALE);
 				empty_list_online_warning->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
 				empty_list_online_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-				empty_list_online_warning->set_text(TTR("Note: The Asset Library requires an online connection and involves sending data over the internet."));
+				empty_list_online_warning->set_text(TTRC("Note: The Asset Library requires an online connection and involves sending data over the internet."));
 				empty_list_placeholder->add_child(empty_list_online_warning);
 			}
 
@@ -1489,7 +1490,7 @@ ProjectManager::ProjectManager() {
 			project_list_sidebar->add_child(open_btn_container);
 
 			open_btn = memnew(Button);
-			open_btn->set_text(TTR("Edit"));
+			open_btn->set_text(TTRC("Edit"));
 			open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTRC("Edit Project"), KeyModifierMask::CMD_OR_CTRL | Key::E));
 			open_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_open_selected_projects_check_recovery_mode));
 			open_btn->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -1512,25 +1513,25 @@ ProjectManager::ProjectManager() {
 			open_btn_container->set_custom_minimum_size(Size2(120, open_btn->get_combined_minimum_size().y));
 
 			run_btn = memnew(Button);
-			run_btn->set_text(TTR("Run"));
+			run_btn->set_text(TTRC("Run"));
 			run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTRC("Run Project"), KeyModifierMask::CMD_OR_CTRL | Key::R));
 			run_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_run_project));
 			project_list_sidebar->add_child(run_btn);
 
 			rename_btn = memnew(Button);
-			rename_btn->set_text(TTR("Rename"));
+			rename_btn->set_text(TTRC("Rename"));
 			// The F2 shortcut isn't overridden with Enter on macOS as Enter is already used to edit a project.
 			rename_btn->set_shortcut(ED_SHORTCUT("project_manager/rename_project", TTRC("Rename Project"), Key::F2));
 			rename_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_rename_project));
 			project_list_sidebar->add_child(rename_btn);
 
 			manage_tags_btn = memnew(Button);
-			manage_tags_btn->set_text(TTR("Manage Tags"));
-			manage_tags_btn->set_shortcut(ED_SHORTCUT("project_manager/project_tags", TTR("Manage Tags"), KeyModifierMask::CMD_OR_CTRL | Key::T));
+			manage_tags_btn->set_text(TTRC("Manage Tags"));
+			manage_tags_btn->set_shortcut(ED_SHORTCUT("project_manager/project_tags", TTRC("Manage Tags"), KeyModifierMask::CMD_OR_CTRL | Key::T));
 			project_list_sidebar->add_child(manage_tags_btn);
 
 			erase_btn = memnew(Button);
-			erase_btn->set_text(TTR("Remove"));
+			erase_btn->set_text(TTRC("Remove"));
 			erase_btn->set_shortcut(ED_SHORTCUT("project_manager/remove_project", TTRC("Remove Project"), Key::KEY_DELETE));
 			erase_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_project));
 			project_list_sidebar->add_child(erase_btn);
@@ -1540,7 +1541,7 @@ ProjectManager::ProjectManager() {
 			project_list_sidebar->add_child(filler);
 
 			erase_missing_btn = memnew(Button);
-			erase_missing_btn->set_text(TTR("Remove Missing"));
+			erase_missing_btn->set_text(TTRC("Remove Missing"));
 			erase_missing_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_missing_projects));
 			project_list_sidebar->add_child(erase_missing_btn);
 		}
@@ -1550,14 +1551,14 @@ ProjectManager::ProjectManager() {
 	if (AssetLibraryEditorPlugin::is_available()) {
 		asset_library = memnew(EditorAssetLibrary(true));
 		asset_library->set_name("AssetLibraryTab");
-		_add_main_view(MAIN_VIEW_ASSETLIB, TTR("Asset Library"), Ref<Texture2D>(), asset_library);
+		_add_main_view(MAIN_VIEW_ASSETLIB, TTRC("Asset Library"), Ref<Texture2D>(), asset_library);
 		asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
 	} else {
 		VBoxContainer *asset_library_filler = memnew(VBoxContainer);
 		asset_library_filler->set_name("AssetLibraryTab");
-		Button *asset_library_toggle = _add_main_view(MAIN_VIEW_ASSETLIB, TTR("Asset Library"), Ref<Texture2D>(), asset_library_filler);
+		Button *asset_library_toggle = _add_main_view(MAIN_VIEW_ASSETLIB, TTRC("Asset Library"), Ref<Texture2D>(), asset_library_filler);
 		asset_library_toggle->set_disabled(true);
-		asset_library_toggle->set_tooltip_text(TTR("Asset Library not available (due to using Web editor, or because SSL support disabled)."));
+		asset_library_toggle->set_tooltip_text(TTRC("Asset Library not available (due to using Web editor, or because SSL support disabled)."));
 	}
 
 	// Footer bar.
@@ -1589,18 +1590,18 @@ ProjectManager::ProjectManager() {
 		scan_dir->set_previews_enabled(false);
 		scan_dir->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
 		scan_dir->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
-		scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
+		scan_dir->set_title(TTRC("Select a Folder to Scan")); // Must be after mode or it's overridden.
 		scan_dir->set_current_dir(EDITOR_GET("filesystem/directories/default_project_path"));
 		add_child(scan_dir);
 		scan_dir->connect("dir_selected", callable_mp(project_list, &ProjectList::find_projects));
 
 		erase_missing_ask = memnew(ConfirmationDialog);
-		erase_missing_ask->set_ok_button_text(TTR("Remove All"));
+		erase_missing_ask->set_ok_button_text(TTRC("Remove All"));
 		erase_missing_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
 		add_child(erase_missing_ask);
 
 		erase_ask = memnew(ConfirmationDialog);
-		erase_ask->set_ok_button_text(TTR("Remove"));
+		erase_ask->set_ok_button_text(TTRC("Remove"));
 		erase_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_project_confirm));
 		add_child(erase_ask);
 
@@ -1613,24 +1614,24 @@ ProjectManager::ProjectManager() {
 		// Comment out for now until we have a better warning system to
 		// ensure users delete their project only.
 		//delete_project_contents = memnew(CheckBox);
-		//delete_project_contents->set_text(TTR("Also delete project contents (no undo!)"));
+		//delete_project_contents->set_text(TTRC("Also delete project contents (no undo!)"));
 		//erase_ask_vb->add_child(delete_project_contents);
 
 		multi_open_ask = memnew(ConfirmationDialog);
-		multi_open_ask->set_ok_button_text(TTR("Edit"));
+		multi_open_ask->set_ok_button_text(TTRC("Edit"));
 		multi_open_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_open_selected_projects));
 		add_child(multi_open_ask);
 
 		multi_run_ask = memnew(ConfirmationDialog);
-		multi_run_ask->set_ok_button_text(TTR("Run"));
+		multi_run_ask->set_ok_button_text(TTRC("Run"));
 		multi_run_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_run_project_confirm));
 		add_child(multi_run_ask);
 
 		open_recovery_mode_ask = memnew(ConfirmationDialog);
 		open_recovery_mode_ask->set_min_size(Size2(550, 70) * EDSCALE);
 		open_recovery_mode_ask->set_autowrap(true);
-		open_recovery_mode_ask->add_button(TTR("Edit normally"))->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_on_recovery_mode_popup_open_normal));
-		open_recovery_mode_ask->set_ok_button_text(TTR("Edit in Recovery Mode"));
+		open_recovery_mode_ask->add_button(TTRC("Edit normally"))->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_on_recovery_mode_popup_open_normal));
+		open_recovery_mode_ask->set_ok_button_text(TTRC("Edit in Recovery Mode"));
 		open_recovery_mode_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_on_recovery_mode_popup_open_recovery));
 		add_child(open_recovery_mode_ask);
 
@@ -1641,13 +1642,13 @@ ProjectManager::ProjectManager() {
 		if (ed_swap_cancel_ok == 0) {
 			ed_swap_cancel_ok = DisplayServer::get_singleton()->get_swap_cancel_ok() ? 2 : 1;
 		}
-		full_convert_button = ask_update_settings->add_button(TTR("Convert Full Project"), ed_swap_cancel_ok != 2);
+		full_convert_button = ask_update_settings->add_button(TTRC("Convert Full Project"), ed_swap_cancel_ok != 2);
 		full_convert_button->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_full_convert_button_pressed));
 		add_child(ask_update_settings);
 
 		ask_full_convert_dialog = memnew(ConfirmationDialog);
 		ask_full_convert_dialog->set_autowrap(true);
-		ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3 to work in Godot 4.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
+		ask_full_convert_dialog->set_text(TTRC("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3 to work in Godot 4.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
 		ask_full_convert_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ProjectManager::_perform_full_project_conversion));
 		add_child(ask_full_convert_dialog);
 
@@ -1657,7 +1658,7 @@ ProjectManager::ProjectManager() {
 		add_child(project_dialog);
 
 		error_dialog = memnew(AcceptDialog);
-		error_dialog->set_title(TTR("Error"));
+		error_dialog->set_title(TTRC("Error"));
 		add_child(error_dialog);
 
 		about_dialog = memnew(EditorAbout);
@@ -1668,19 +1669,19 @@ ProjectManager::ProjectManager() {
 	{
 		tag_manage_dialog = memnew(ConfirmationDialog);
 		add_child(tag_manage_dialog);
-		tag_manage_dialog->set_title(TTR("Manage Project Tags"));
+		tag_manage_dialog->set_title(TTRC("Manage Project Tags"));
 		tag_manage_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_apply_project_tags));
 		manage_tags_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_manage_project_tags));
 
 		VBoxContainer *tag_vb = memnew(VBoxContainer);
 		tag_manage_dialog->add_child(tag_vb);
 
-		Label *label = memnew(Label(TTR("Project Tags")));
+		Label *label = memnew(Label(TTRC("Project Tags")));
 		tag_vb->add_child(label);
 		label->set_theme_type_variation("HeaderMedium");
 		label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
 
-		label = memnew(Label(TTR("Click tag to remove it from the project.")));
+		label = memnew(Label(TTRC("Click tag to remove it from the project.")));
 		tag_vb->add_child(label);
 		label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
 
@@ -1690,12 +1691,12 @@ ProjectManager::ProjectManager() {
 
 		tag_vb->add_child(memnew(HSeparator));
 
-		label = memnew(Label(TTR("All Tags")));
+		label = memnew(Label(TTRC("All Tags")));
 		tag_vb->add_child(label);
 		label->set_theme_type_variation("HeaderMedium");
 		label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
 
-		label = memnew(Label(TTR("Click tag to add it to the project.")));
+		label = memnew(Label(TTRC("Click tag to add it to the project.")));
 		tag_vb->add_child(label);
 		label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
 
@@ -1709,13 +1710,13 @@ ProjectManager::ProjectManager() {
 
 		create_tag_dialog = memnew(ConfirmationDialog);
 		tag_manage_dialog->add_child(create_tag_dialog);
-		create_tag_dialog->set_title(TTR("Create New Tag"));
+		create_tag_dialog->set_title(TTRC("Create New Tag"));
 		create_tag_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_create_new_tag));
 
 		tag_vb = memnew(VBoxContainer);
 		create_tag_dialog->add_child(tag_vb);
 
-		Label *info = memnew(Label(TTR("Tags are capitalized automatically when displayed.")));
+		Label *info = memnew(Label(TTRC("Tags are capitalized automatically when displayed.")));
 		tag_vb->add_child(info);
 
 		new_tag_name = memnew(LineEdit);

+ 1 - 0
editor/project_manager.h

@@ -126,6 +126,7 @@ class ProjectManager : public Control {
 	// Project list.
 
 	VBoxContainer *empty_list_placeholder = nullptr;
+	RichTextLabel *empty_list_message = nullptr;
 	Button *empty_list_create_project = nullptr;
 	Button *empty_list_import_project = nullptr;
 	Button *empty_list_open_assetlib = nullptr;

+ 50 - 46
editor/project_manager/project_dialog.cpp

@@ -83,7 +83,7 @@ void ProjectDialog::_validate_path() {
 	_set_message("", MESSAGE_SUCCESS, INSTALL_PATH);
 
 	if (project_name->get_text().strip_edges().is_empty()) {
-		_set_message(TTR("It would be a good idea to name your project."), MESSAGE_ERROR);
+		_set_message(TTRC("It would be a good idea to name your project."), MESSAGE_ERROR);
 		return;
 	}
 
@@ -119,7 +119,7 @@ void ProjectDialog::_validate_path() {
 
 			unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io);
 			if (!pkg) {
-				_set_message(TTR("Invalid \".zip\" project file; it is not in ZIP format."), MESSAGE_ERROR);
+				_set_message(TTRC("Invalid \".zip\" project file; it is not in ZIP format."), MESSAGE_ERROR);
 				unzClose(pkg);
 				return;
 			}
@@ -147,7 +147,7 @@ void ProjectDialog::_validate_path() {
 			}
 
 			if (ret == UNZ_END_OF_LIST_OF_FILE) {
-				_set_message(TTR("Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."), MESSAGE_ERROR);
+				_set_message(TTRC("Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."), MESSAGE_ERROR);
 				unzClose(pkg);
 				return;
 			}
@@ -159,30 +159,30 @@ void ProjectDialog::_validate_path() {
 			create_dir->hide();
 			install_path_container->hide();
 
-			_set_message(TTR("Valid project found at path."), MESSAGE_SUCCESS);
+			_set_message(TTRC("Valid project found at path."), MESSAGE_SUCCESS);
 		} else {
 			create_dir->hide();
 			install_path_container->hide();
 
-			_set_message(TTR("Please choose a \"project.godot\", a directory with one, or a \".zip\" file."), MESSAGE_ERROR);
+			_set_message(TTRC("Please choose a \"project.godot\", a directory with one, or a \".zip\" file."), MESSAGE_ERROR);
 			return;
 		}
 	}
 
 	if (target_path.is_relative_path()) {
-		_set_message(TTR("The path specified is invalid."), MESSAGE_ERROR, target_path_input_type);
+		_set_message(TTRC("The path specified is invalid."), MESSAGE_ERROR, target_path_input_type);
 		return;
 	}
 
 	if (target_path.get_file() != OS::get_singleton()->get_safe_dir_name(target_path.get_file())) {
-		_set_message(TTR("The directory name specified contains invalid characters or trailing whitespace."), MESSAGE_ERROR, target_path_input_type);
+		_set_message(TTRC("The directory name specified contains invalid characters or trailing whitespace."), MESSAGE_ERROR, target_path_input_type);
 		return;
 	}
 
 	String working_dir = d->get_current_dir();
 	String executable_dir = OS::get_singleton()->get_executable_path().get_base_dir();
 	if (target_path == working_dir || target_path == executable_dir) {
-		_set_message(TTR("Creating a project at the engine's working directory or executable directory is not allowed, as it would prevent the project manager from starting."), MESSAGE_ERROR, target_path_input_type);
+		_set_message(TTRC("Creating a project at the engine's working directory or executable directory is not allowed, as it would prevent the project manager from starting."), MESSAGE_ERROR, target_path_input_type);
 		return;
 	}
 
@@ -194,7 +194,7 @@ void ProjectDialog::_validate_path() {
 #endif
 	String documents_dir = OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS);
 	if (target_path == home_dir || target_path == documents_dir) {
-		_set_message(TTR("You cannot save a project at the selected path. Please create a subfolder or choose a new path."), MESSAGE_ERROR, target_path_input_type);
+		_set_message(TTRC("You cannot save a project at the selected path. Please create a subfolder or choose a new path."), MESSAGE_ERROR, target_path_input_type);
 		return;
 	}
 
@@ -202,24 +202,24 @@ void ProjectDialog::_validate_path() {
 	if (mode == MODE_NEW || mode == MODE_INSTALL || (mode == MODE_IMPORT && target_path_input_type == InputType::INSTALL_PATH)) {
 		if (create_dir->is_pressed()) {
 			if (!d->dir_exists(target_path.get_base_dir())) {
-				_set_message(TTR("The parent directory of the path specified doesn't exist."), MESSAGE_ERROR, target_path_input_type);
+				_set_message(TTRC("The parent directory of the path specified doesn't exist."), MESSAGE_ERROR, target_path_input_type);
 				return;
 			}
 
 			if (d->dir_exists(target_path)) {
 				// The path is not necessarily empty here, but we will update the message later if it isn't.
-				_set_message(TTR("The project folder already exists and is empty."), MESSAGE_SUCCESS, target_path_input_type);
+				_set_message(TTRC("The project folder already exists and is empty."), MESSAGE_SUCCESS, target_path_input_type);
 			} else {
-				_set_message(TTR("The project folder will be automatically created."), MESSAGE_SUCCESS, target_path_input_type);
+				_set_message(TTRC("The project folder will be automatically created."), MESSAGE_SUCCESS, target_path_input_type);
 			}
 		} else {
 			if (!d->dir_exists(target_path)) {
-				_set_message(TTR("The path specified doesn't exist."), MESSAGE_ERROR, target_path_input_type);
+				_set_message(TTRC("The path specified doesn't exist."), MESSAGE_ERROR, target_path_input_type);
 				return;
 			}
 
 			// The path is not necessarily empty here, but we will update the message later if it isn't.
-			_set_message(TTR("The project folder exists and is empty."), MESSAGE_SUCCESS, target_path_input_type);
+			_set_message(TTRC("The project folder exists and is empty."), MESSAGE_SUCCESS, target_path_input_type);
 		}
 
 		// Check if the directory is empty. Not an error, but we want to warn the user.
@@ -240,7 +240,7 @@ void ProjectDialog::_validate_path() {
 			d->list_dir_end();
 
 			if (!is_folder_empty) {
-				_set_message(TTR("The selected path is not empty. Choosing an empty folder is highly recommended."), MESSAGE_WARNING, target_path_input_type);
+				_set_message(TTRC("The selected path is not empty. Choosing an empty folder is highly recommended."), MESSAGE_WARNING, target_path_input_type);
 			}
 		}
 	}
@@ -497,8 +497,8 @@ void ProjectDialog::ok_pressed() {
 	if (!is_folder_empty) {
 		if (!nonempty_confirmation) {
 			nonempty_confirmation = memnew(ConfirmationDialog);
-			nonempty_confirmation->set_title(TTR("Warning: This folder is not empty"));
-			nonempty_confirmation->set_text(TTR("You are about to create a Godot project in a non-empty folder.\nThe entire contents of this folder will be imported as project resources!\n\nAre you sure you wish to continue?"));
+			nonempty_confirmation->set_title(TTRC("Warning: This folder is not empty"));
+			nonempty_confirmation->set_text(TTRC("You are about to create a Godot project in a non-empty folder.\nThe entire contents of this folder will be imported as project resources!\n\nAre you sure you wish to continue?"));
 			nonempty_confirmation->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectDialog::_nonempty_confirmation_ok_pressed));
 			add_child(nonempty_confirmation);
 		}
@@ -512,7 +512,7 @@ void ProjectDialog::ok_pressed() {
 		if (create_dir->is_pressed()) {
 			Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 			if (!d->dir_exists(path) && d->make_dir(path) != OK) {
-				_set_message(TTR("Couldn't create project directory, check permissions."), MESSAGE_ERROR);
+				_set_message(TTRC("Couldn't create project directory, check permissions."), MESSAGE_ERROR);
 				return;
 			}
 		}
@@ -548,14 +548,14 @@ void ProjectDialog::ok_pressed() {
 
 		Error err = ProjectSettings::get_singleton()->save_custom(path.path_join("project.godot"), initial_settings, Vector<String>(), false);
 		if (err != OK) {
-			_set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
+			_set_message(TTRC("Couldn't create project.godot in project path."), MESSAGE_ERROR);
 			return;
 		}
 
 		// Store default project icon in SVG format.
 		Ref<FileAccess> fa_icon = FileAccess::open(path.path_join("icon.svg"), FileAccess::WRITE, &err);
 		if (err != OK) {
-			_set_message(TTR("Couldn't create icon.svg in project path."), MESSAGE_ERROR);
+			_set_message(TTRC("Couldn't create icon.svg in project path."), MESSAGE_ERROR);
 			return;
 		}
 		fa_icon->store_string(get_default_project_icon());
@@ -596,7 +596,7 @@ void ProjectDialog::ok_pressed() {
 
 			unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io);
 			if (!pkg) {
-				dialog_error->set_text(TTR("Error opening package file, not in ZIP format."));
+				dialog_error->set_text(TTRC("Error opening package file, not in ZIP format."));
 				dialog_error->popup_centered();
 				return;
 			}
@@ -627,7 +627,7 @@ void ProjectDialog::ok_pressed() {
 			}
 
 			if (ret == UNZ_END_OF_LIST_OF_FILE) {
-				_set_message(TTR("Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."), MESSAGE_ERROR);
+				_set_message(TTRC("Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."), MESSAGE_ERROR);
 				unzClose(pkg);
 				return;
 			}
@@ -635,7 +635,7 @@ void ProjectDialog::ok_pressed() {
 			if (create_dir->is_pressed()) {
 				Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 				if (!d->dir_exists(path) && d->make_dir(path) != OK) {
-					_set_message(TTR("Couldn't create project directory, check permissions."), MESSAGE_ERROR);
+					_set_message(TTRC("Couldn't create project directory, check permissions."), MESSAGE_ERROR);
 					return;
 				}
 			}
@@ -772,8 +772,8 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
 		// Name and path are set in `ProjectManager::_rename_project`.
 		project_path->set_editable(false);
 
-		set_title(TTR("Rename Project"));
-		set_ok_button_text(TTR("Rename"));
+		set_title(TTRC("Rename Project"));
+		set_ok_button_text(TTRC("Rename"));
 
 		create_dir->hide();
 		project_status_rect->hide();
@@ -812,8 +812,8 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
 		edit_check_box->show();
 
 		if (mode == MODE_IMPORT) {
-			set_title(TTR("Import Existing Project"));
-			set_ok_button_text(TTR("Import"));
+			set_title(TTRC("Import Existing Project"));
+			set_ok_button_text(TTRC("Import"));
 
 			name_container->hide();
 			install_path_container->hide();
@@ -822,8 +822,8 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
 
 			// Project path dialog is also opened; no need to change focus.
 		} else if (mode == MODE_NEW) {
-			set_title(TTR("Create New Project"));
-			set_ok_button_text(TTR("Create"));
+			set_title(TTRC("Create New Project"));
+			set_ok_button_text(TTRC("Create"));
 
 			name_container->show();
 			install_path_container->hide();
@@ -834,7 +834,7 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
 			callable_mp(project_name, &LineEdit::select_all).call_deferred();
 		} else if (mode == MODE_INSTALL) {
 			set_title(TTR("Install Project:") + " " + zip_title);
-			set_ok_button_text(TTR("Install"));
+			set_ok_button_text(TTRC("Install"));
 
 			project_name->set_text(zip_title);
 
@@ -862,6 +862,10 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
 
 void ProjectDialog::_notification(int p_what) {
 	switch (p_what) {
+		case NOTIFICATION_TRANSLATION_CHANGED: {
+			_renderer_selected();
+		} break;
+
 		case NOTIFICATION_THEME_CHANGED: {
 			create_dir->set_button_icon(get_editor_theme_icon(SNAME("FolderCreate")));
 			project_browse->set_button_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
@@ -892,7 +896,7 @@ ProjectDialog::ProjectDialog() {
 	vb->add_child(name_container);
 
 	Label *l = memnew(Label);
-	l->set_text(TTR("Project Name:"));
+	l->set_text(TTRC("Project Name:"));
 	name_container->add_child(l);
 
 	project_name = memnew(LineEdit);
@@ -906,12 +910,12 @@ ProjectDialog::ProjectDialog() {
 	project_path_container->add_child(pphb_label);
 
 	l = memnew(Label);
-	l->set_text(TTR("Project Path:"));
+	l->set_text(TTRC("Project Path:"));
 	l->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	pphb_label->add_child(l);
 
 	create_dir = memnew(CheckButton);
-	create_dir->set_text(TTR("Create Folder"));
+	create_dir->set_text(TTRC("Create Folder"));
 	create_dir->set_pressed(true);
 	pphb_label->add_child(create_dir);
 	create_dir->connect(SceneStringName(toggled), callable_mp(this, &ProjectDialog::_create_dir_toggled));
@@ -929,7 +933,7 @@ ProjectDialog::ProjectDialog() {
 	vb->add_child(install_path_container);
 
 	l = memnew(Label);
-	l->set_text(TTR("Project Installation Path:"));
+	l->set_text(TTRC("Project Installation Path:"));
 	install_path_container->add_child(l);
 
 	HBoxContainer *iphb = memnew(HBoxContainer);
@@ -947,7 +951,7 @@ ProjectDialog::ProjectDialog() {
 	pphb->add_child(project_status_rect);
 
 	project_browse = memnew(Button);
-	project_browse->set_text(TTR("Browse"));
+	project_browse->set_text(TTRC("Browse"));
 	project_browse->connect(SceneStringName(pressed), callable_mp(this, &ProjectDialog::_browse_project_path));
 	pphb->add_child(project_browse);
 
@@ -957,7 +961,7 @@ ProjectDialog::ProjectDialog() {
 	iphb->add_child(install_status_rect);
 
 	install_browse = memnew(Button);
-	install_browse->set_text(TTR("Browse"));
+	install_browse->set_text(TTRC("Browse"));
 	install_browse->connect(SceneStringName(pressed), callable_mp(this, &ProjectDialog::_browse_install_path));
 	iphb->add_child(install_browse);
 
@@ -971,7 +975,7 @@ ProjectDialog::ProjectDialog() {
 	renderer_container = memnew(VBoxContainer);
 	vb->add_child(renderer_container);
 	l = memnew(Label);
-	l->set_text(TTR("Renderer:"));
+	l->set_text(TTRC("Renderer:"));
 	renderer_container->add_child(l);
 	HBoxContainer *rshc = memnew(HBoxContainer);
 	renderer_container->add_child(rshc);
@@ -994,7 +998,7 @@ ProjectDialog::ProjectDialog() {
 
 	Button *rs_button = memnew(CheckBox);
 	rs_button->set_button_group(renderer_button_group);
-	rs_button->set_text(TTR("Forward+"));
+	rs_button->set_text(TTRC("Forward+"));
 #ifndef RD_ENABLED
 	rs_button->set_disabled(true);
 #endif
@@ -1006,7 +1010,7 @@ ProjectDialog::ProjectDialog() {
 	}
 	rs_button = memnew(CheckBox);
 	rs_button->set_button_group(renderer_button_group);
-	rs_button->set_text(TTR("Mobile"));
+	rs_button->set_text(TTRC("Mobile"));
 #ifndef RD_ENABLED
 	rs_button->set_disabled(true);
 #endif
@@ -1018,7 +1022,7 @@ ProjectDialog::ProjectDialog() {
 	}
 	rs_button = memnew(CheckBox);
 	rs_button->set_button_group(renderer_button_group);
-	rs_button->set_text(TTR("Compatibility"));
+	rs_button->set_text(TTRC("Compatibility"));
 #if !defined(GLES3_ENABLED)
 	rs_button->set_disabled(true);
 #endif
@@ -1041,7 +1045,7 @@ ProjectDialog::ProjectDialog() {
 	rvb->add_child(renderer_info);
 
 	rd_not_supported = memnew(Label);
-	rd_not_supported->set_text(vformat(TTR("RenderingDevice-based methods not available on this GPU:\n%s\nPlease use the Compatibility renderer."), RenderingServer::get_singleton()->get_video_adapter_name()));
+	rd_not_supported->set_text(vformat(TTRC("RenderingDevice-based methods not available on this GPU:\n%s\nPlease use the Compatibility renderer."), RenderingServer::get_singleton()->get_video_adapter_name()));
 	rd_not_supported->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
 	rd_not_supported->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
 	rd_not_supported->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
@@ -1051,7 +1055,7 @@ ProjectDialog::ProjectDialog() {
 	_renderer_selected();
 
 	l = memnew(Label);
-	l->set_text(TTR("The renderer can be changed later, but scenes may need to be adjusted."));
+	l->set_text(TTRC("The renderer can be changed later, but scenes may need to be adjusted."));
 	// Add some extra spacing to separate it from the list above and the buttons below.
 	l->set_custom_minimum_size(Size2(0, 40) * EDSCALE);
 	l->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
@@ -1062,12 +1066,12 @@ ProjectDialog::ProjectDialog() {
 	default_files_container = memnew(HBoxContainer);
 	vb->add_child(default_files_container);
 	l = memnew(Label);
-	l->set_text(TTR("Version Control Metadata:"));
+	l->set_text(TTRC("Version Control Metadata:"));
 	default_files_container->add_child(l);
 	vcs_metadata_selection = memnew(OptionButton);
 	vcs_metadata_selection->set_custom_minimum_size(Size2(100, 20));
-	vcs_metadata_selection->add_item(TTR("None"), (int)EditorVCSInterface::VCSMetadata::NONE);
-	vcs_metadata_selection->add_item(TTR("Git"), (int)EditorVCSInterface::VCSMetadata::GIT);
+	vcs_metadata_selection->add_item(TTRC("None"), (int)EditorVCSInterface::VCSMetadata::NONE);
+	vcs_metadata_selection->add_item(TTRC("Git"), (int)EditorVCSInterface::VCSMetadata::GIT);
 	vcs_metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
 	default_files_container->add_child(vcs_metadata_selection);
 	Control *spacer = memnew(Control);
@@ -1083,7 +1087,7 @@ ProjectDialog::ProjectDialog() {
 	vb->add_child(spacer2);
 
 	edit_check_box = memnew(CheckBox);
-	edit_check_box->set_text(TTR("Edit Now"));
+	edit_check_box->set_text(TTRC("Edit Now"));
 	edit_check_box->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
 	edit_check_box->set_pressed(true);
 	vb->add_child(edit_check_box);

+ 14 - 8
editor/project_manager/project_list.cpp

@@ -293,11 +293,11 @@ void ProjectListItemControl::set_is_missing(bool p_missing) {
 		project_icon->set_modulate(Color(1, 1, 1, 0.5));
 
 		explore_button->set_button_icon(get_editor_theme_icon(SNAME("FileBroken")));
-		explore_button->set_tooltip_text(TTR("Error: Project is missing on the filesystem."));
+		explore_button->set_tooltip_text(TTRC("Error: Project is missing on the filesystem."));
 	} else {
 #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
 		explore_button->set_button_icon(get_editor_theme_icon(SNAME("Load")));
-		explore_button->set_tooltip_text(TTR("Show in File Manager"));
+		explore_button->set_tooltip_text(TTRC("Show in File Manager"));
 #else
 		// Opening the system file manager is not supported on the Android and web editors.
 		explore_button->hide();
@@ -407,7 +407,7 @@ ProjectListItemControl::ProjectListItemControl() {
 		last_edited_info = memnew(Label);
 		last_edited_info->set_name("LastEditedInfo");
 		last_edited_info->set_mouse_filter(Control::MOUSE_FILTER_PASS);
-		last_edited_info->set_tooltip_text(TTR("Last edited timestamp"));
+		last_edited_info->set_tooltip_text(TTRC("Last edited timestamp"));
 		last_edited_info->set_modulate(Color(1, 1, 1, 0.5));
 		path_hb->add_child(last_edited_info);
 
@@ -451,6 +451,13 @@ bool ProjectList::project_feature_looks_like_version(const String &p_feature) {
 
 void ProjectList::_notification(int p_what) {
 	switch (p_what) {
+		case NOTIFICATION_TRANSLATION_CHANGED: {
+			if (is_ready()) {
+				// FIXME: Technically this only needs to update some dynamic texts, not the whole list.
+				update_project_list();
+			}
+		} break;
+
 		case NOTIFICATION_PROCESS: {
 			// Load icons as a coroutine to speed up launch when you have hundreds of projects.
 			if (_icon_load_index < _projects.size()) {
@@ -626,7 +633,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
 			unsupported_features.push_back("3.x");
 			project_version = "3.x";
 		} else {
-			unsupported_features.push_back("Unknown version");
+			unsupported_features.push_back(TTR("Unknown version"));
 		}
 	}
 
@@ -647,7 +654,6 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
 	} else {
 		grayed = true;
 		missing = true;
-		print_line("Project is missing: " + conf);
 	}
 
 	for (const String &tag : tags) {
@@ -818,14 +824,14 @@ void ProjectList::find_projects(const String &p_path) {
 void ProjectList::find_projects_multiple(const PackedStringArray &p_paths) {
 	if (!scan_progress && is_inside_tree()) {
 		scan_progress = memnew(AcceptDialog);
-		scan_progress->set_title(TTR("Scanning"));
-		scan_progress->set_ok_button_text(TTR("Cancel"));
+		scan_progress->set_title(TTRC("Scanning"));
+		scan_progress->set_ok_button_text(TTRC("Cancel"));
 
 		VBoxContainer *vb = memnew(VBoxContainer);
 		scan_progress->add_child(vb);
 
 		Label *label = memnew(Label);
-		label->set_text(TTR("Scanning for projects..."));
+		label->set_text(TTRC("Scanning for projects..."));
 		vb->add_child(label);
 
 		ProgressBar *progress = memnew(ProgressBar);

+ 12 - 12
editor/project_manager/quick_settings_dialog.cpp

@@ -179,7 +179,7 @@ void QuickSettingsDialog::_add_setting_control(const String &p_text, Control *p_
 #ifndef ANDROID_ENABLED
 void QuickSettingsDialog::_language_selected(int p_id) {
 	const String selected_language = language_option_button->get_item_metadata(p_id);
-	_set_setting_value("interface/editor/editor_language", selected_language, true);
+	_set_setting_value("interface/editor/editor_language", selected_language);
 }
 #endif
 
@@ -222,7 +222,7 @@ void QuickSettingsDialog::_set_setting_value(const String &p_setting, const Vari
 			if (ed_swap_cancel_ok == 0) {
 				ed_swap_cancel_ok = DisplayServer::get_singleton()->get_swap_cancel_ok() ? 2 : 1;
 			}
-			restart_required_button = add_button(TTR("Restart Now"), ed_swap_cancel_ok != 2);
+			restart_required_button = add_button(TTRC("Restart Now"), ed_swap_cancel_ok != 2);
 			restart_required_button->connect(SceneStringName(pressed), callable_mp(this, &QuickSettingsDialog::_request_restart));
 		}
 	}
@@ -260,8 +260,8 @@ void QuickSettingsDialog::_bind_methods() {
 }
 
 QuickSettingsDialog::QuickSettingsDialog() {
-	set_title(TTR("Quick Settings"));
-	set_ok_button_text(TTR("Close"));
+	set_title(TTRC("Quick Settings"));
+	set_ok_button_text(TTRC("Close"));
 
 	VBoxContainer *main_vbox = memnew(VBoxContainer);
 	add_child(main_vbox);
@@ -291,7 +291,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				language_option_button->set_item_metadata(i, lang_value);
 			}
 
-			_add_setting_control(TTR("Language"), language_option_button);
+			_add_setting_control(TTRC("Language"), language_option_button);
 		}
 #endif
 
@@ -306,9 +306,9 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				theme_option_button->add_item(theme_value, i);
 			}
 
-			_add_setting_control(TTR("Interface Theme"), theme_option_button);
+			_add_setting_control(TTRC("Interface Theme"), theme_option_button);
 
-			custom_theme_label = memnew(Label(TTR("Custom preset can be further configured in the editor.")));
+			custom_theme_label = memnew(Label(TTRC("Custom preset can be further configured in the editor.")));
 			custom_theme_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
 			custom_theme_label->set_custom_minimum_size(Size2(220, 0) * EDSCALE);
 			custom_theme_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
@@ -329,7 +329,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				scale_option_button->add_item(scale_value, i);
 			}
 
-			_add_setting_control(TTR("Display Scale"), scale_option_button);
+			_add_setting_control(TTRC("Display Scale"), scale_option_button);
 		}
 
 		// Network mode options.
@@ -343,7 +343,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				network_mode_option_button->add_item(network_mode_value, i);
 			}
 
-			_add_setting_control(TTR("Network Mode"), network_mode_option_button);
+			_add_setting_control(TTRC("Network Mode"), network_mode_option_button);
 		}
 
 		// Engine version update mode options.
@@ -357,7 +357,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				engine_version_update_mode_button->add_item(engine_version_update_mode_value, i);
 			}
 
-			_add_setting_control(TTR("Engine Version Update Mode"), engine_version_update_mode_button);
+			_add_setting_control(TTRC("Engine Version Update Mode"), engine_version_update_mode_button);
 		}
 
 		// Project directory naming options.
@@ -371,7 +371,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 				directory_naming_convention_button->add_item(directory_naming_convention, i);
 			}
 
-			_add_setting_control(TTR("Directory Naming Convention"), directory_naming_convention_button);
+			_add_setting_control(TTRC("Directory Naming Convention"), directory_naming_convention_button);
 		}
 
 		_update_current_values();
@@ -379,7 +379,7 @@ QuickSettingsDialog::QuickSettingsDialog() {
 
 	// Restart required panel.
 	{
-		restart_required_label = memnew(Label(TTR("Settings changed! The project manager must be restarted for changes to take effect.")));
+		restart_required_label = memnew(Label(TTRC("Settings changed! The project manager must be restarted for changes to take effect.")));
 		restart_required_label->set_custom_minimum_size(Size2(560, 0) * EDSCALE);
 		restart_required_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
 		restart_required_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);