Show how many files will be deleted/moved (#514)
* Print proper character(\) in Windows when printing files * Show how many files will be moved/deleted. Don't show dialog when 0 files is selected
This commit is contained in:
parent
71c2e01ce4
commit
878550446d
11 changed files with 151 additions and 46 deletions
|
@ -1,10 +1,12 @@
|
|||
## Version 4.0.0 - ?
|
||||
- Multithread support for collecting files to check(2/3x on 4 thread processor) - [#502](https://github.com/qarmin/czkawka/pull/502), [#504](https://github.com/qarmin/czkawka/pull/504)
|
||||
- Add Polish and Italian translation - [#469](https://github.com/qarmin/czkawka/pull/469), [#508](https://github.com/qarmin/czkawka/pull/508)
|
||||
- Add support for finding similar videos - [#460](https://github.com/qarmin/czkawka/pull/460)
|
||||
- GUI code refactoring(could fix some bugs) - [#462](https://github.com/qarmin/czkawka/pull/462)
|
||||
- Fixed crash when trying to hard/symlink 0 files - [#462](https://github.com/qarmin/czkawka/pull/462)
|
||||
- GTK 4 compatibility improvements for future change of toolkit - [#467](https://github.com/qarmin/czkawka/pull/467), [#468](https://github.com/qarmin/czkawka/pull/468), [#473](https://github.com/qarmin/czkawka/pull/473), [#474](https://github.com/qarmin/czkawka/pull/474)
|
||||
- GTK 4 compatibility improvements for future change of toolkit - [#467](https://github.com/qarmin/czkawka/pull/467), [#468](https://github.com/qarmin/czkawka/pull/468), [#473](https://github.com/qarmin/czkawka/pull/473), [#474](https://github.com/qarmin/czkawka/pull/474), [#503](https://github.com/qarmin/czkawka/pull/503), [#505](https://github.com/qarmin/czkawka/pull/505)
|
||||
- Change minimal supported OS to Ubuntu 20.04(needed by GTK) - [#468](https://github.com/qarmin/czkawka/pull/468)
|
||||
- Increased performance when using image previews - [#468](https://github.com/qarmin/czkawka/pull/468)
|
||||
- Increased performance by avoiding creating unnecessary image previews - [#468](https://github.com/qarmin/czkawka/pull/468)
|
||||
- Improved performance due caching hash of broken/not supported images/videos = [#471](https://github.com/qarmin/czkawka/pull/471)
|
||||
- Option to not remove cache from non existent files(e.g. from unplugged pendrive) - [#472](https://github.com/qarmin/czkawka/pull/472)
|
||||
- Add multiple tooltips with helpful messages - [#472](https://github.com/qarmin/czkawka/pull/472)
|
||||
|
@ -13,6 +15,9 @@
|
|||
- Remove support for finding zeroed files - [#461](https://github.com/qarmin/czkawka/pull/461)
|
||||
- Remove HashMB mode - [#476](https://github.com/qarmin/czkawka/pull/476)
|
||||
- Approximate comparison of music - [#483](https://github.com/qarmin/czkawka/pull/483)
|
||||
- Enable column sorting for simple treeview - [#487](https://github.com/qarmin/czkawka/pull/487)
|
||||
- Allow to hide upper panel - [#491](https://github.com/qarmin/czkawka/pull/491)
|
||||
- Make UI take less space - [#500](https://github.com/qarmin/czkawka/pull/500)
|
||||
|
||||
## Version 3.3.1 - 22.11.2021r
|
||||
- Fix crash when moving buttons [#457](https://github.com/qarmin/czkawka/pull/457)
|
||||
|
|
|
@ -41,31 +41,31 @@ pub async fn delete_things(gui_data: GuiData) {
|
|||
let preview_path = gui_data.preview_path.clone();
|
||||
|
||||
let text_view_errors = gui_data.text_view_errors.clone();
|
||||
if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main).await {
|
||||
return;
|
||||
}
|
||||
|
||||
let nb_number = notebook_main.current_page().unwrap();
|
||||
let tree_view = &main_tree_views[nb_number as usize];
|
||||
let nb_object = &NOTEBOOKS_INFOS[nb_number as usize];
|
||||
|
||||
let (number_of_selected_items, number_of_selected_groups) = check_how_much_elements_is_selected(tree_view, nb_object.column_color, nb_object.column_selection);
|
||||
|
||||
// Nothing is selected
|
||||
if number_of_selected_items == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if !check_if_can_delete_files(&check_button_settings_confirm_deletion, &window_main, number_of_selected_items, number_of_selected_groups).await {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(column_color) = nb_object.column_color {
|
||||
if !check_button_settings_confirm_group_deletion.is_active() || !check_if_deleting_all_files_in_group(tree_view, column_color, nb_object.column_selection, &window_main, &check_button_settings_confirm_group_deletion).await {
|
||||
tree_remove(
|
||||
&tree_view.clone(),
|
||||
nb_object.column_name,
|
||||
nb_object.column_path,
|
||||
column_color,
|
||||
nb_object.column_selection,
|
||||
&check_button_settings_use_trash,
|
||||
&text_view_errors,
|
||||
);
|
||||
tree_remove(tree_view, nb_object.column_name, nb_object.column_path, column_color, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors);
|
||||
}
|
||||
} else {
|
||||
if nb_number == NotebookMainEnum::EmptyDirectories as u32 {
|
||||
empty_folder_remover(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors);
|
||||
empty_folder_remover(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors);
|
||||
} else {
|
||||
basic_remove(&tree_view.clone(), nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors);
|
||||
basic_remove(tree_view, nb_object.column_name, nb_object.column_path, nb_object.column_selection, &check_button_settings_use_trash, &text_view_errors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,9 +82,9 @@ pub async fn delete_things(gui_data: GuiData) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn check_if_can_delete_files(check_button_settings_confirm_deletion: >k::CheckButton, window_main: >k::Window) -> bool {
|
||||
pub async fn check_if_can_delete_files(check_button_settings_confirm_deletion: >k::CheckButton, window_main: >k::Window, number_of_selected_items: u64, number_of_selected_groups: u64) -> bool {
|
||||
if check_button_settings_confirm_deletion.is_active() {
|
||||
let (confirmation_dialog_delete, check_button) = create_dialog_ask_for_deletion(window_main);
|
||||
let (confirmation_dialog_delete, check_button) = create_dialog_ask_for_deletion(window_main, number_of_selected_items, number_of_selected_groups);
|
||||
|
||||
let response_type = confirmation_dialog_delete.run_future().await;
|
||||
if response_type == gtk::ResponseType::Ok {
|
||||
|
@ -102,12 +102,19 @@ pub async fn check_if_can_delete_files(check_button_settings_confirm_deletion: &
|
|||
true
|
||||
}
|
||||
|
||||
fn create_dialog_ask_for_deletion(window_main: >k::Window) -> (Dialog, CheckButton) {
|
||||
fn create_dialog_ask_for_deletion(window_main: >k::Window, number_of_selected_items: u64, number_of_selected_groups: u64) -> (Dialog, CheckButton) {
|
||||
let dialog = gtk::Dialog::builder().title(&fl!("delete_title_dialog")).transient_for(window_main).modal(true).build();
|
||||
let button_ok = dialog.add_button(&fl!("general_ok_button"), ResponseType::Ok);
|
||||
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
|
||||
|
||||
let label: gtk::Label = gtk::Label::new(Some(&fl!("delete_question_label")));
|
||||
let label2: gtk::Label = match number_of_selected_groups {
|
||||
0 => gtk::Label::new(Some(&fl!("delete_items_label", generate_translation_hashmap(vec![("items", number_of_selected_items.to_string())])))),
|
||||
_ => gtk::Label::new(Some(&fl!(
|
||||
"delete_items_groups_label",
|
||||
generate_translation_hashmap(vec![("items", number_of_selected_items.to_string()), ("groups", number_of_selected_groups.to_string())])
|
||||
))),
|
||||
};
|
||||
let check_button: gtk::CheckButton = gtk::CheckButton::with_label(&fl!("dialogs_ask_next_time"));
|
||||
check_button.set_active(true);
|
||||
check_button.set_halign(Align::Center);
|
||||
|
@ -116,7 +123,10 @@ fn create_dialog_ask_for_deletion(window_main: >k::Window) -> (Dialog, CheckBu
|
|||
|
||||
let internal_box = get_dialog_box_child(&dialog);
|
||||
internal_box.add(&label);
|
||||
internal_box.add(&label2);
|
||||
internal_box.add(&check_button);
|
||||
internal_box.set_margin(5);
|
||||
check_button.set_margin_top(5);
|
||||
|
||||
dialog.show_all();
|
||||
(dialog, check_button)
|
||||
|
@ -227,7 +237,7 @@ pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, co
|
|||
|
||||
// We must check if folder is really empty or contains only other empty folders
|
||||
let mut error_happened = false;
|
||||
let mut folders_to_check: Vec<String> = vec![format!("{}/{}", path, name)];
|
||||
let mut folders_to_check: Vec<String> = vec![get_full_name_from_path_name(&path, &name)];
|
||||
let mut current_folder: String;
|
||||
let mut next_folder: String;
|
||||
'dir: while !folders_to_check.is_empty() {
|
||||
|
@ -275,14 +285,14 @@ pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, co
|
|||
|
||||
if !error_happened {
|
||||
if !use_trash {
|
||||
match fs::remove_dir_all(format!("{}/{}", path, name)) {
|
||||
match fs::remove_dir_all(get_full_name_from_path_name(&path, &name)) {
|
||||
Ok(_) => {
|
||||
model.remove(&iter);
|
||||
}
|
||||
Err(_inspected) => error_happened = true,
|
||||
}
|
||||
} else {
|
||||
match trash::delete(format!("{}/{}", path, name)) {
|
||||
match trash::delete(get_full_name_from_path_name(&path, &name)) {
|
||||
Ok(_) => {
|
||||
model.remove(&iter);
|
||||
}
|
||||
|
@ -291,7 +301,7 @@ pub fn empty_folder_remover(tree_view: >k::TreeView, column_file_name: i32, co
|
|||
}
|
||||
}
|
||||
if error_happened {
|
||||
messages += &fl!("delete_folder_failed", generate_translation_hashmap(vec![("dir", format!("{}/{}", path, name))]));
|
||||
messages += &fl!("delete_folder_failed", generate_translation_hashmap(vec![("dir", get_full_name_from_path_name(&path, &name))]));
|
||||
messages += "\n";
|
||||
}
|
||||
}
|
||||
|
@ -332,23 +342,23 @@ pub fn basic_remove(tree_view: >k::TreeView, column_file_name: i32, column_pat
|
|||
let path = model.value(&iter, column_path).get::<String>().unwrap();
|
||||
|
||||
if !use_trash {
|
||||
match fs::remove_file(format!("{}/{}", path, name)) {
|
||||
match fs::remove_file(get_full_name_from_path_name(&path, &name)) {
|
||||
Ok(_) => {
|
||||
model.remove(&iter);
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", format!("{}/{}", path, name)), ("reason", e.to_string())])).as_str();
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", get_full_name_from_path_name(&path, &name)), ("reason", e.to_string())])).as_str();
|
||||
messages += "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match trash::delete(format!("{}/{}", path, name)) {
|
||||
match trash::delete(get_full_name_from_path_name(&path, &name)) {
|
||||
Ok(_) => {
|
||||
model.remove(&iter);
|
||||
}
|
||||
Err(e) => {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", format!("{}/{}", path, name)), ("reason", e.to_string())])).as_str();
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", get_full_name_from_path_name(&path, &name)), ("reason", e.to_string())])).as_str();
|
||||
messages += "\n";
|
||||
}
|
||||
}
|
||||
|
@ -410,12 +420,12 @@ pub fn tree_remove(tree_view: >k::TreeView, column_file_name: i32, column_path
|
|||
vec_file_name.dedup();
|
||||
for file_name in vec_file_name {
|
||||
if !use_trash {
|
||||
if let Err(e) = fs::remove_file(format!("{}/{}", path.clone(), file_name.clone())) {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", format!("{}/{}", path, file_name)), ("reason", e.to_string())])).as_str();
|
||||
if let Err(e) = fs::remove_file(get_full_name_from_path_name(&path, &file_name)) {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", get_full_name_from_path_name(&path, &file_name)), ("reason", e.to_string())])).as_str();
|
||||
messages += "\n";
|
||||
}
|
||||
} else if let Err(e) = trash::delete(format!("{}/{}", path.clone(), file_name.clone())) {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", format!("{}/{}", path, file_name)), ("reason", e.to_string())])).as_str();
|
||||
} else if let Err(e) = trash::delete(get_full_name_from_path_name(&path, &file_name)) {
|
||||
messages += fl!("delete_file_failed", generate_translation_hashmap(vec![("name", get_full_name_from_path_name(&path, &file_name)), ("reason", e.to_string())])).as_str();
|
||||
messages += "\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ pub fn hardlink_symlink(tree_view: >k::TreeView, column_file_name: i32, column
|
|||
if model.path(¤t_iter).unwrap() == selected_rows[current_selected_index] {
|
||||
let file_name = model.value(¤t_iter, column_file_name).get::<String>().unwrap();
|
||||
let path = model.value(¤t_iter, column_path).get::<String>().unwrap();
|
||||
let full_file_path = format!("{}/{}", path, file_name);
|
||||
let full_file_path = get_full_name_from_path_name(&path, &file_name);
|
||||
|
||||
if current_symhardlink_data.is_some() {
|
||||
vec_tree_path_to_remove.push(model.path(¤t_iter).unwrap());
|
||||
|
|
|
@ -31,6 +31,12 @@ pub fn connect_button_move(gui_data: &GuiData) {
|
|||
let tree_view = &main_tree_views[nb_number as usize];
|
||||
let nb_object = &NOTEBOOKS_INFOS[nb_number as usize];
|
||||
|
||||
let (number_of_selected_items, _number_of_selected_groups) = check_how_much_elements_is_selected(tree_view, nb_object.column_color, nb_object.column_selection);
|
||||
|
||||
// Nothing is selected
|
||||
if number_of_selected_items == 0 {
|
||||
return;
|
||||
}
|
||||
move_things(
|
||||
tree_view,
|
||||
nb_object.column_name,
|
||||
|
@ -174,7 +180,7 @@ fn move_files_common(selected_rows: &[TreePath], model: >k::ListStore, column_
|
|||
let file_name = model.value(&iter, column_file_name).get::<String>().unwrap();
|
||||
let path = model.value(&iter, column_path).get::<String>().unwrap();
|
||||
|
||||
let thing = format!("{}/{}", path, file_name);
|
||||
let thing = get_full_name_from_path_name(&path, &file_name);
|
||||
let destination_file = destination_folder.join(file_name);
|
||||
if Path::new(&thing).is_dir() {
|
||||
if let Err(e) = fs_extra::dir::move_dir(&thing, &destination_file, &fs_extra::dir::CopyOptions::new()) {
|
||||
|
|
|
@ -401,11 +401,8 @@ fn popover_custom_select_unselect(popover: >k::Popover, window_main: &Window,
|
|||
let is_selected = model.value(&iter, column_button_selection as i32).get::<bool>().unwrap();
|
||||
let path = model.value(&iter, column_path).get::<String>().unwrap();
|
||||
let name = model.value(&iter, column_file_name).get::<String>().unwrap();
|
||||
#[cfg(not(target_family = "windows"))]
|
||||
let character = "/";
|
||||
#[cfg(target_family = "windows")]
|
||||
let character = "\\";
|
||||
let path_and_name = format!("{}{}{}", path, character, name);
|
||||
|
||||
let path_and_name = get_full_name_from_path_name(&path, &name);
|
||||
|
||||
let mut need_to_change_thing: bool = false;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::{ListStore, TextView, Widget};
|
||||
use gtk::{ListStore, TextView, TreeView, Widget};
|
||||
|
||||
use czkawka_core::big_file::BigFile;
|
||||
use czkawka_core::broken_files::BrokenFiles;
|
||||
|
@ -19,6 +19,11 @@ use czkawka_core::{fl, invalid_symlinks};
|
|||
|
||||
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
|
||||
|
||||
#[cfg(not(target_family = "windows"))]
|
||||
pub const CHARACTER: char = '/';
|
||||
#[cfg(target_family = "windows")]
|
||||
pub const CHARACTER: char = '\\';
|
||||
|
||||
pub const KEY_DELETE: u32 = 119;
|
||||
pub const KEY_ENTER: u32 = 36;
|
||||
pub const KEY_SPACE: u32 = 65;
|
||||
|
@ -470,6 +475,14 @@ pub fn get_notebook_object_from_tree_view(tree_view: >k::TreeView) -> &Noteboo
|
|||
&NOTEBOOKS_INFOS[nb_enum as usize]
|
||||
}
|
||||
|
||||
pub fn get_full_name_from_path_name(path: &str, name: &str) -> String {
|
||||
let mut string = String::with_capacity(path.len() + name.len() + 1);
|
||||
string.push_str(path);
|
||||
string.push(CHARACTER);
|
||||
string.push_str(name);
|
||||
string
|
||||
}
|
||||
|
||||
// After e.g. deleting files, header may become orphan or have one child, so should be deleted in this case
|
||||
pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32) {
|
||||
// Remove only child from header
|
||||
|
@ -541,6 +554,52 @@ pub fn clean_invalid_headers(model: >k::ListStore, column_color: i32) {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn check_how_much_elements_is_selected(tree_view: &TreeView, column_color: Option<i32>, column_selection: i32) -> (u64, u64) {
|
||||
let mut number_of_selected_items: u64 = 0;
|
||||
let mut number_of_selected_groups: u64 = 0;
|
||||
|
||||
let model = get_list_store(tree_view);
|
||||
|
||||
let mut is_item_currently_selected_in_group: bool = false;
|
||||
|
||||
// First iter
|
||||
if let Some(iter) = model.iter_first() {
|
||||
if let Some(column_color) = column_color {
|
||||
assert_eq!(model.value(&iter, column_color).get::<String>().unwrap(), HEADER_ROW_COLOR); // First element should be header
|
||||
|
||||
loop {
|
||||
if !model.iter_next(&iter) {
|
||||
break;
|
||||
}
|
||||
|
||||
if model.value(&iter, column_color).get::<String>().unwrap() == HEADER_ROW_COLOR {
|
||||
is_item_currently_selected_in_group = false;
|
||||
} else {
|
||||
if model.value(&iter, column_selection).get::<bool>().unwrap() {
|
||||
number_of_selected_items += 1;
|
||||
|
||||
if !is_item_currently_selected_in_group {
|
||||
number_of_selected_groups += 1;
|
||||
}
|
||||
is_item_currently_selected_in_group = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loop {
|
||||
if !model.iter_next(&iter) {
|
||||
break;
|
||||
}
|
||||
|
||||
if model.value(&iter, column_selection).get::<bool>().unwrap() {
|
||||
number_of_selected_items += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(number_of_selected_items, number_of_selected_groups)
|
||||
}
|
||||
|
||||
pub fn get_custom_label_from_button_with_image(button: >k::Bin) -> gtk::Label {
|
||||
let internal_box = button.child().unwrap().downcast::<gtk::Box>().unwrap();
|
||||
|
|
|
@ -673,7 +673,7 @@ fn show_preview(tree_view: &TreeView, text_view_errors: &TextView, check_button_
|
|||
let path = tree_model.value(&tree_model.iter(&tree_path).unwrap(), column_path).get::<String>().unwrap();
|
||||
let name = tree_model.value(&tree_model.iter(&tree_path).unwrap(), column_name).get::<String>().unwrap();
|
||||
|
||||
let file_name = format!("{}/{}", path, name);
|
||||
let file_name = get_full_name_from_path_name(&path, &name);
|
||||
let file_name = file_name.as_str();
|
||||
|
||||
if let Some(extension) = Path::new(file_name).extension() {
|
||||
|
|
|
@ -80,9 +80,7 @@ fn common_open_function(tree_view: >k::TreeView, column_name: i32, column_path
|
|||
|
||||
let end_path = match opening_mode {
|
||||
OpenMode::OnlyPath => path,
|
||||
OpenMode::PathAndName => {
|
||||
format!("{}/{}", path, name)
|
||||
}
|
||||
OpenMode::PathAndName => get_full_name_from_path_name(&path, &name),
|
||||
};
|
||||
|
||||
open::that_in_background(&end_path);
|
||||
|
@ -96,11 +94,9 @@ fn common_open_function(tree_view: >k::TreeView, column_name: i32, column_path
|
|||
fn handle_tree_keypress(tree_view: >k::TreeView, key_code: u32, name_column: i32, path_column: i32, mark_column: i32) {
|
||||
match key_code {
|
||||
KEY_ENTER => {
|
||||
// Enter
|
||||
common_open_function(tree_view, name_column, path_column, OpenMode::PathAndName);
|
||||
}
|
||||
KEY_SPACE => {
|
||||
// Space
|
||||
common_mark_function(tree_view, mark_column);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -424,6 +424,9 @@ delete_all_files_in_group_label1 = In some groups there are selected all records
|
|||
delete_all_files_in_group_label2 = Are you sure that you want to delete them?
|
||||
delete_folder_failed = Failed to remove folder {$dir} because folder doesn't exists, you don't have permissions or isn't empty.
|
||||
|
||||
delete_items_label = { $items } files will be removed.
|
||||
delete_items_groups_label = { $items } files from { $groups } groups will be removed.
|
||||
|
||||
hardlink_failed = Failed to hardlink
|
||||
hard_sym_invalid_selection_title_dialog = Invalid selection with some groups
|
||||
hard_sym_invalid_selection_label_1 = In some groups there is only 1 record selected and it will be ignored.
|
||||
|
|
|
@ -367,6 +367,8 @@ delete_all_files_in_group_title = Potwierdzenie usunięcia wszystkich plików w
|
|||
delete_all_files_in_group_label1 = W niektórych grupach zaznaczono wszystkie rekordy.
|
||||
delete_all_files_in_group_label2 = Czy na pewno je usunąć?
|
||||
delete_folder_failed = Nie udało się usunąć folderu { $name } ponieważ nie istnieje, uprawnienia nie są wystarczające lub nie jest pusty.
|
||||
delete_items_label = { $items } plików zostanie usuniętych.
|
||||
delete_items_groups_label = { $items } plików z { $groups } grup będzie usuniętych.
|
||||
hardlink_failed = Nie udało się utworzyć twardego dowiązania
|
||||
hard_sym_invalid_selection_title_dialog = Niepoprawne zaznaczenie w niektórych grupach
|
||||
hard_sym_invalid_selection_label_1 = W niektórych grupach zaznaczono tylko 1 rekord który zostanie zignorowany.
|
||||
|
|
|
@ -63,4 +63,31 @@ Next new record must be added to array.
|
|||
combo_box_text: "Polski (Polish)",
|
||||
short_text: "pl",
|
||||
},
|
||||
```
|
||||
```
|
||||
|
||||
# Validating translation offline
|
||||
When trying to translate objects offline, due renames, adding and removing elements, may happen that translations will contain outdated entries.
|
||||
|
||||
To help find such keywords, special python script can be used.
|
||||
|
||||
To be able to use it, be sure that you are directly inside main `czkawka` folder.
|
||||
Next, be sure that your language is available in array/list and also in i18n folder and then run python script `python3 misc/translation_test.py`.
|
||||
Then results should be visible in console:
|
||||
```
|
||||
Checking pl language
|
||||
Missing keyword - duplicate_mode_name_combo_box
|
||||
Missing keyword - duplicate_mode_size_combo_box
|
||||
Missing keyword - duplicate_mode_hash_combo_box
|
||||
Missing keyword - settings_language_label_tooltip
|
||||
Missing keyword - settings_language_label
|
||||
Unused keyword - duplicate_mode_name_checkbox
|
||||
Unused keyword - duplicate_mode_size_checkbox
|
||||
Unused keyword - duplicate_mode_hash_checkbox
|
||||
Unused keyword - duplicate_mode_name_checkbox_tooltip
|
||||
Unused keyword - duplicate_mode_size_checkbox_tooltip
|
||||
Unused keyword - duplicate_mode_hash_checkbox_tooltip
|
||||
```
|
||||
`Missing keyword` means that some keywords exists in base translations and texts needs to be translated.
|
||||
`Unused keyword` means that keyword is no longer used. It can be renamed or entirely removed from file.
|
||||
|
||||
When script will not print anything except "Checking language", then this means that translation file have exactly same keys as base one.
|
Loading…
Add table
Reference in a new issue