Add support for translations (#469)

* Reformat code with idea tool

* Pierwsza działająca wersja tłumaczeń

* Działa? I dobrze, bo ma działać

* Ćma szła i się potkła

* Ściął śmiałek źółty rząd pąków.
pull/498/head
Rafał Mikrut 2 years ago committed by GitHub
parent 5f774e03bd
commit 77a48ca6aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

354
Cargo.lock generated

@ -196,6 +196,21 @@ dependencies = [
"digest",
]
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.8.0"
@ -421,6 +436,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.0"
@ -499,10 +523,14 @@ dependencies = [
"futures",
"hamming",
"humansize",
"i18n-embed",
"i18n-embed-fl",
"image",
"img_hash",
"once_cell",
"rayon",
"rodio",
"rust-embed",
"serde",
"serde_json",
"tempfile",
@ -525,10 +553,14 @@ dependencies = [
"glib",
"gtk",
"humansize",
"i18n-embed",
"i18n-embed-fl",
"image",
"img_hash",
"once_cell",
"open",
"regex",
"rust-embed",
"trash",
"winapi",
]
@ -568,6 +600,16 @@ dependencies = [
"syn",
]
[[package]]
name = "dashmap"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
dependencies = [
"cfg-if",
"num_cpus",
]
[[package]]
name = "deflate"
version = "0.8.6"
@ -648,6 +690,15 @@ dependencies = [
"rustc_version",
]
[[package]]
name = "find-crate"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2"
dependencies = [
"toml",
]
[[package]]
name = "flate2"
version = "1.0.22"
@ -660,6 +711,50 @@ dependencies = [
"miniz_oxide 0.4.4",
]
[[package]]
name = "fluent"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61f69378194459db76abd2ce3952b790db103ceb003008d3d50d97c41ff847a7"
dependencies = [
"fluent-bundle",
"unic-langid",
]
[[package]]
name = "fluent-bundle"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd"
dependencies = [
"fluent-langneg",
"fluent-syntax",
"intl-memoizer",
"intl_pluralrules",
"rustc-hash",
"self_cell",
"smallvec",
"unic-langid",
]
[[package]]
name = "fluent-langneg"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94"
dependencies = [
"unic-langid",
]
[[package]]
name = "fluent-syntax"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78"
dependencies = [
"thiserror",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -1039,6 +1134,75 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
[[package]]
name = "i18n-config"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62affcd43abfb51f3cbd8736f9407908dc5b44fc558a9be07460bbfd104d983"
dependencies = [
"log",
"serde",
"serde_derive",
"thiserror",
"toml",
"unic-langid",
]
[[package]]
name = "i18n-embed"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8be76966dc82fc0c1fe50bac057170294594ab2a78a0e5d82f85227248a19a1"
dependencies = [
"fluent",
"fluent-langneg",
"fluent-syntax",
"i18n-embed-impl",
"intl-memoizer",
"lazy_static",
"locale_config",
"log",
"parking_lot",
"rust-embed",
"thiserror",
"unic-langid",
"walkdir",
]
[[package]]
name = "i18n-embed-fl"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c1d347d2f7f9f2f977385b43b204d59ebeb1b2f93ce73cd23622df2d2da1033"
dependencies = [
"dashmap",
"find-crate",
"fluent",
"fluent-syntax",
"i18n-config",
"i18n-embed",
"lazy_static",
"proc-macro-error",
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn",
"unic-langid",
]
[[package]]
name = "i18n-embed-impl"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0db2330e035808eb064afb67e6743ddce353763af3e0f2bdfc2476e00ce76136"
dependencies = [
"find-crate",
"i18n-config",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "id3"
version = "0.5.3"
@ -1097,11 +1261,31 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "intl-memoizer"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f"
dependencies = [
"type-map",
"unic-langid",
]
[[package]]
name = "intl_pluralrules"
version = "7.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf"
dependencies = [
"tinystr",
"unic-langid",
]
[[package]]
name = "itertools"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@ -1198,6 +1382,19 @@ dependencies = [
"winapi",
]
[[package]]
name = "locale_config"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
dependencies = [
"lazy_static",
"objc",
"objc-foundation",
"regex",
"winapi",
]
[[package]]
name = "lock_api"
version = "0.4.5"
@ -1225,6 +1422,15 @@ dependencies = [
"libc",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.4.1"
@ -1503,6 +1709,35 @@ dependencies = [
"syn",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "oboe"
version = "0.4.4"
@ -1541,6 +1776,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "open"
version = "2.0.2"
@ -1636,9 +1877,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.22"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
checksum = "d1a3ea4f0dd7f1f3e512cf97bf100819aa547f36a6eccac8dbaae839eb92363e"
[[package]]
name = "png"
@ -1712,9 +1953,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.32"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a"
dependencies = [
"unicode-xid",
]
@ -1851,6 +2092,40 @@ dependencies = [
"minimp3",
]
[[package]]
name = "rust-embed"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40377bff8cceee81e28ddb73ac97f5c2856ce5522f0b260b763f434cdfae602"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad22c7226e4829104deab21df575e995bfbc4adfad13a595e387477f238c1aec"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
@ -1938,6 +2213,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "self_cell"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
[[package]]
name = "semver"
version = "0.11.0"
@ -1958,18 +2239,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.130"
version = "1.0.131"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
version = "1.0.131"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2"
dependencies = [
"proc-macro2",
"quote",
@ -1987,6 +2268,19 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer",
"cfg-if",
"cpufeatures",
"digest",
"opaque-debug",
]
[[package]]
name = "shlex"
version = "0.1.1"
@ -2040,6 +2334,12 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.25"
@ -2176,6 +2476,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "tinystr"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1"
[[package]]
name = "tinyvec"
version = "1.5.1"
@ -2231,6 +2537,15 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622b09ce2fe2df4618636fb92176d205662f59803f39e70d1c333393082de96c"
[[package]]
name = "type-map"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46"
dependencies = [
"rustc-hash",
]
[[package]]
name = "typenum"
version = "1.14.0"
@ -2243,6 +2558,25 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unic-langid"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73328fcd730a030bdb19ddf23e192187a6b01cd98be6d3140622a89129459ce5"
dependencies = [
"unic-langid-impl",
]
[[package]]
name = "unic-langid-impl"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d"
dependencies = [
"serde",
"tinystr",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"

@ -11,6 +11,7 @@
- CLI frontend - for easy automation
- GUI frontend - uses modern GTK 3 and looks similar to FSlint
- No spying - Czkawka does not have access to the Internet, nor does it collect any user information or statistics
- Multilingual - app support multiple languages
- Multiple tools to use:
- Duplicates - Finds duplicates based on file name, size or hash
- Empty Folders - Finds empty folders with the help of an advanced algorithm
@ -131,6 +132,7 @@ You can help by creating:
- Pull Requests - implementing a new feature yourself or fixing bugs.
If the change is bigger, then it's a good idea to open a new issue to discuss changes.
- Documentation - There is an [instruction](instructions/Instruction.md) which you can improve.
- Translations - Instruction how to translate files is available [here](instructions/Translations.md)
You can also help by doing different things:
- Creating text articles - [LinuxUprising](https://www.linuxuprising.com/2021/03/find-and-remove-duplicate-files-similar.html) or [Ubunlog](https://ubunlog.com/en/czkawka-finds-and-removes-empty-and-broken-duplicate-files/)

@ -50,6 +50,11 @@ serde = "1.0.130"
bincode = "1.3.3"
serde_json = "1.0.72"
# Language
i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.6"
rust-embed = "6.2.0"
once_cell = "1.8.0"
[features]
default = []

@ -0,0 +1,13 @@
# (Required) The language identifier of the language used in the
# source code for gettext system, and the primary fallback language
# (for which all strings must be present) when using the fluent
# system.
fallback_language = "en"
# Use the fluent localization system.
[fluent]
# (Required) The path to the assets directory.
# The paths inside the assets directory should be structured like so:
# `assets_dir/{language}/{domain}.ftl`
assets_dir = "../i18n"

@ -18,5 +18,6 @@ pub mod common_extensions;
pub mod common_items;
pub mod common_messages;
pub mod common_traits;
pub mod localizer;
pub const CZKAWKA_VERSION: &str = env!("CARGO_PKG_VERSION");

@ -0,0 +1,34 @@
use i18n_embed::{
fluent::{fluent_language_loader, FluentLanguageLoader},
DefaultLocalizer, LanguageLoader, Localizer,
};
use once_cell::sync::Lazy;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "../i18n/"]
struct Localizations;
pub static LANGUAGE_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| {
let loader: FluentLanguageLoader = fluent_language_loader!();
loader.load_fallback_language(&Localizations).expect("Error while loading fallback language");
loader
});
#[macro_export]
macro_rules! fl {
($message_id:literal) => {{
i18n_embed_fl::fl!($crate::localizer::LANGUAGE_LOADER, $message_id)
}};
($message_id:literal, $($args:expr),*) => {{
i18n_embed_fl::fl!($crate::localizer::LANGUAGE_LOADER, $message_id, $($args), *)
}};
}
// Get the `Localizer` to be used for localizing this library.
pub fn localizer() -> Box<dyn Localizer> {
Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations))
}

@ -23,6 +23,7 @@ use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::{DebugPrint, PrintResults, SaveResults};
use crate::fl;
// TODO check for better values
pub const SIMILAR_VALUES: [[u32; 6]; 4] = [
@ -905,17 +906,17 @@ pub fn get_string_from_similarity(similarity: &Similarity, hash_size: u8) -> Str
#[cfg(debug_assertions)]
{
if *h <= SIMILAR_VALUES[index_preset][0] {
format!("Very High {}", *h)
format!("{} {}", fl!("core_similarity_very_high"), *h)
} else if *h <= SIMILAR_VALUES[index_preset][1] {
format!("High {}", *h)
format!("{} {}", fl!("core_similarity_high"), *h)
} else if *h <= SIMILAR_VALUES[index_preset][2] {
format!("Medium {}", *h)
format!("{} {}", fl!("core_similarity_medium"), *h)
} else if *h <= SIMILAR_VALUES[index_preset][3] {
format!("Small {}", *h)
format!("{} {}", fl!("core_similarity_small"), *h)
} else if *h <= SIMILAR_VALUES[index_preset][4] {
format!("Very Small {}", *h)
format!("{} {}", fl!("core_similarity_very_small"), *h)
} else if *h <= SIMILAR_VALUES[index_preset][5] {
format!("Minimal {}", *h)
format!("{} {}", fl!("core_similarity_minimal"), *h)
} else {
panic!();
}
@ -923,17 +924,17 @@ pub fn get_string_from_similarity(similarity: &Similarity, hash_size: u8) -> Str
#[cfg(not(debug_assertions))]
{
if *h <= SIMILAR_VALUES[index_preset][0] {
format!("Very High")
fl!("core_similarity_very_high")
} else if *h <= SIMILAR_VALUES[index_preset][1] {
format!("High")
fl!("core_similarity_high")
} else if *h <= SIMILAR_VALUES[index_preset][2] {
format!("Medium")
fl!("core_similarity_medium")
} else if *h <= SIMILAR_VALUES[index_preset][3] {
format!("Small")
fl!("core_similarity_small")
} else if *h <= SIMILAR_VALUES[index_preset][4] {
format!("Very Small")
fl!("core_similarity_very_small")
} else if *h <= SIMILAR_VALUES[index_preset][5] {
format!("Minimal")
fl!("core_similarity_minimal")
} else {
panic!();
}

@ -43,6 +43,12 @@ trash = "1.3.0"
# For moving files(why std::fs doesn't have such features)
fs_extra = "1.2.0"
# Language
i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.6"
rust-embed = "6.2.0"
once_cell = "1.8.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_core", "windef", "winerror", "wtypesbase", "winuser"] }

@ -0,0 +1,13 @@
# (Required) The language identifier of the language used in the
# source code for gettext system, and the primary fallback language
# (for which all strings must be present) when using the fluent
# system.
fallback_language = "en"
# Use the fluent localization system.
[fluent]
# (Required) The path to the assets directory.
# The paths inside the assets directory should be structured like so:
# `assets_dir/{language}/{domain}.ftl`
assets_dir = "../i18n"

@ -8,6 +8,7 @@ use glib::Receiver;
use gtk::prelude::*;
use humansize::{file_size_opts as options, FileSize};
use crate::fl;
use czkawka_core::duplicate::CheckingMethod;
use czkawka_core::same_music::MusicSimilarity;
use czkawka_core::similar_images;
@ -85,7 +86,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
match msg {
Message::Duplicates(df) => {
if df.get_stopped_search() {
entry_info.set_text("Searching for duplicates was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = df.get_information();
let text_messages = df.get_text_messages();
@ -94,32 +95,57 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
let duplicates_size: u64;
let duplicates_group: usize;
let fl_found = fl!("compute_found");
let fl_groups = fl!("compute_groups");
let fl_groups_which_took = fl!("compute_groups_which_took");
let fl_duplicated_files_in = fl!("compute_duplicated_files_in");
match df.get_check_method() {
CheckingMethod::Name => {
duplicates_number = information.number_of_duplicated_files_by_name;
duplicates_size = 0;
// duplicates_size = 0;
duplicates_group = information.number_of_groups_by_name;
entry_info.set_text(format!("Found {} files in {} groups which have same names.", duplicates_number, duplicates_group).as_str());
entry_info.set_text(format!("{} {} {} {} {}", fl_found, duplicates_number, fl_duplicated_files_in, duplicates_group, fl_groups).as_str());
}
CheckingMethod::Hash => {
duplicates_number = information.number_of_duplicated_files_by_hash;
duplicates_size = information.lost_space_by_hash;
duplicates_group = information.number_of_groups_by_hash;
entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str());
entry_info.set_text(
format!(
"{} {} {} {} {} {}.",
fl_found,
duplicates_number,
fl_duplicated_files_in,
duplicates_group,
fl_groups_which_took,
duplicates_size.file_size(options::BINARY).unwrap()
)
.as_str(),
);
}
CheckingMethod::Size => {
duplicates_number = information.number_of_duplicated_files_by_size;
duplicates_size = information.lost_space_by_size;
duplicates_group = information.number_of_groups_by_size;
entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str());
entry_info.set_text(
format!(
"{} {} {} {} {} {}.",
fl_found,
duplicates_number,
fl_duplicated_files_in,
duplicates_group,
fl_groups_which_took,
duplicates_size.file_size(options::BINARY).unwrap()
)
.as_str(),
);
}
CheckingMethod::None => {
panic!();
}
}
entry_info.set_text(format!("Found {} duplicates files in {} groups which took {}.", duplicates_number, duplicates_group, duplicates_size.file_size(options::BINARY).unwrap()).as_str());
// Create GUI
{
let list_store = get_list_store(&tree_view_duplicate_finder);
@ -192,10 +218,16 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
let values: [(u32, &dyn ToValue); 8] = [
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
(ColumnsDuplicates::SelectionButton as u32, &false),
(ColumnsDuplicates::Name as u32, &(format!("{} x {} ({} bytes)", vector.len(), size.file_size(options::BINARY).unwrap(), size))),
(ColumnsDuplicates::Name as u32, &(format!("{} x {} ({} {})", vector.len(), size.file_size(options::BINARY).unwrap(), size, fl!("general_bytes")))),
(
ColumnsDuplicates::Path as u32,
&(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)),
&(format!(
"{} ({} {}) {}",
((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(),
(vector.len() - 1) as u64 * *size as u64,
fl!("general_bytes"),
fl!("general_lost")
)),
),
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)),
@ -241,10 +273,16 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
let values: [(u32, &dyn ToValue); 8] = [
(ColumnsDuplicates::ActivatableSelectButton as u32, &false),
(ColumnsDuplicates::SelectionButton as u32, &false),
(ColumnsDuplicates::Name as u32, &(format!("{} x {} ({} bytes)", vector.len(), size.file_size(options::BINARY).unwrap(), size))),
(ColumnsDuplicates::Name as u32, &(format!("{} x {} ({} {})", vector.len(), size.file_size(options::BINARY).unwrap(), size, fl!("general_bytes")))),
(
ColumnsDuplicates::Path as u32,
&(format!("{} ({} bytes) lost", ((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(), (vector.len() - 1) as u64 * *size as u64)),
&(format!(
"{} ({} {}) {}",
((vector.len() - 1) as u64 * *size as u64).file_size(options::BINARY).unwrap(),
(vector.len() - 1) as u64 * *size as u64,
fl!("general_bytes"),
fl!("general_lost")
)),
),
(ColumnsDuplicates::Modification as u32, &"".to_string()), // No text in 3 column
(ColumnsDuplicates::ModificationAsSecs as u32, &(0)), // Not used here
@ -289,14 +327,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::EmptyFolders(ef) => {
if ef.get_stopped_search() {
entry_info.set_text("Searching for empty folders was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = ef.get_information();
let text_messages = ef.get_text_messages();
let empty_folder_number: usize = information.number_of_empty_folders;
entry_info.set_text(format!("Found {} empty folders.", empty_folder_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), empty_folder_number, fl!("compute_empty_folders")).as_str());
// Create GUI
{
@ -336,14 +374,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::EmptyFiles(vf) => {
if vf.get_stopped_search() {
entry_info.set_text("Searching for empty files was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = vf.get_information();
let text_messages = vf.get_text_messages();
let empty_files_number: usize = information.number_of_empty_files;
entry_info.set_text(format!("Found {} empty files.", empty_files_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), empty_files_number, fl!("compute_empty_files")).as_str());
// Create GUI
{
@ -384,14 +422,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::BigFiles(bf) => {
if bf.get_stopped_search() {
entry_info.set_text("Searching for big files was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = bf.get_information();
let text_messages = bf.get_text_messages();
let biggest_files_number: usize = information.number_of_real_files;
entry_info.set_text(format!("Found {} biggest files.", biggest_files_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), biggest_files_number, fl!("compute_biggest_files")).as_str());
// Create GUI
{
@ -409,7 +447,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
let (directory, file) = split_path(&file_entry.path);
let values: [(u32, &dyn ToValue); 7] = [
(ColumnsBigFiles::SelectionButton as u32, &false),
(ColumnsBigFiles::Size as u32, &(format!("{} ({} bytes)", size.file_size(options::BINARY).unwrap(), size))),
(ColumnsBigFiles::Size as u32, &(format!("{} ({} {})", size.file_size(options::BINARY).unwrap(), size, fl!("general_bytes")))),
(ColumnsBigFiles::Name as u32, &file),
(ColumnsBigFiles::Path as u32, &directory),
(ColumnsBigFiles::Modification as u32, &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())),
@ -434,14 +472,13 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::Temporary(tf) => {
if tf.get_stopped_search() {
entry_info.set_text("Searching for temporary files was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = tf.get_information();
let text_messages = tf.get_text_messages();
let temporary_files_number: usize = information.number_of_temporary_files;
entry_info.set_text(format!("Found {} temporary files.", temporary_files_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), temporary_files_number, fl!("compute_temporary_files")).as_str());
// Create GUI
{
@ -482,14 +519,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::SimilarImages(sf) => {
if sf.get_stopped_search() {
entry_info.set_text("Searching for similar images was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
//let information = sf.get_information();
let text_messages = sf.get_text_messages();
let base_images_size = sf.get_similar_images().len();
entry_info.set_text(format!("Found similar pictures for {} images.", base_images_size).as_str());
entry_info.set_text(format!("{} {} {} {}.", fl!("compute_found"), fl!("compute_duplicates_for"), base_images_size, fl!("compute_similar_image")).as_str());
// Create GUI
{
@ -563,14 +600,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::SimilarVideos(ff) => {
if ff.get_stopped_search() {
entry_info.set_text("Searching for similar videos was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
//let information = ff.get_information();
let text_messages = ff.get_text_messages();
let base_videos_size = ff.get_similar_videos().len();
entry_info.set_text(format!("Found similar videos for {} videos.", base_videos_size).as_str());
entry_info.set_text(format!("{} {} {} {}.", fl!("compute_found"), fl!("compute_duplicates_for"), base_videos_size, fl!("compute_similar_videos")).as_str());
// Create GUI
{
@ -640,14 +677,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::SameMusic(mf) => {
if mf.get_stopped_search() {
entry_info.set_text("Searching for same music was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = mf.get_information();
let text_messages = mf.get_text_messages();
let same_music_number: usize = information.number_of_duplicates_music_files;
entry_info.set_text(format!("Found {} duplicated music files.", same_music_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), same_music_number, fl!("compute_music_files")).as_str());
// Create GUI
{
@ -763,14 +800,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::InvalidSymlinks(ifs) => {
if ifs.get_stopped_search() {
entry_info.set_text("Searching for invalid symlink was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = ifs.get_information();
let text_messages = ifs.get_text_messages();
let invalid_symlinks: usize = information.number_of_invalid_symlinks;
entry_info.set_text(format!("Found {} invalid symlinks.", invalid_symlinks).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), invalid_symlinks, fl!("compute_symlinks")).as_str());
// Create GUI
{
@ -814,14 +851,14 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver<
}
Message::BrokenFiles(br) => {
if br.get_stopped_search() {
entry_info.set_text("Searching for broken files was stopped by user");
entry_info.set_text(&fl!("compute_stopped_by_user"));
} else {
let information = br.get_information();
let text_messages = br.get_text_messages();
let broken_files_number: usize = information.number_of_broken_files;
entry_info.set_text(format!("Found {} broken files.", broken_files_number).as_str());
entry_info.set_text(format!("{} {} {}.", fl!("compute_found"), broken_files_number, fl!("compute_broken_files")).as_str());
// Create GUI
{

@ -2,6 +2,7 @@ use std::collections::BTreeMap;
use std::fs;
use std::fs::Metadata;
use czkawka_core::fl;
use gtk::prelude::*;
use gtk::{Align, CheckButton, Dialog, ResponseType, TextView};
@ -103,7 +104,7 @@ pub async fn check_if_can_delete_files(check_button_settings_confirm_deletion: &
fn create_dialog_ask_for_deletion(window_main: &gtk::Window) -> (Dialog, CheckButton) {
let dialog = gtk::Dialog::builder().title("Delete confirmation").transient_for(window_main).modal(true).build();
let button_ok = dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let label: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete files?"));
let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time");
@ -123,7 +124,7 @@ fn create_dialog_ask_for_deletion(window_main: &gtk::Window) -> (Dialog, CheckBu
fn create_dialog_group_deletion(window_main: &gtk::Window) -> (Dialog, CheckButton) {
let dialog = gtk::Dialog::builder().title("Confirmation of deleting all files in group").transient_for(window_main).modal(true).build();
let button_ok = dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let label: gtk::Label = gtk::Label::new(Some("In some groups there are selected all records."));
let label2: gtk::Label = gtk::Label::new(Some("Are you sure that you want to delete them?"));

@ -5,6 +5,7 @@ use gtk::prelude::*;
use gtk::{Align, CheckButton, Dialog, ResponseType, TextView, TreeIter, TreePath};
use czkawka_core::duplicate::make_hard_link;
use czkawka_core::fl;
use crate::gui_data::GuiData;
use crate::help_functions::*;
@ -220,7 +221,7 @@ pub fn hardlink_symlink(tree_view: &gtk::TreeView, column_file_name: i32, column
fn create_dialog_non_group(window_main: &gtk::Window) -> Dialog {
let dialog = gtk::Dialog::builder().title("Invalid selection with some groups").transient_for(window_main).modal(true).build();
let button_ok = dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let label: gtk::Label = gtk::Label::new(Some("In some groups there is only 1 record selected and it will be ignored."));
let label2: gtk::Label = gtk::Label::new(Some("To be able to hard/sym link this files, at least 2 results in group needs to be selected."));
@ -324,7 +325,7 @@ pub async fn check_if_can_link_files(check_button_settings_confirm_link: &gtk::C
fn create_dialog_ask_for_linking(window_main: &gtk::Window) -> (Dialog, CheckButton) {
let dialog = gtk::Dialog::builder().title("Link confirmation").transient_for(window_main).modal(true).build();
let button_ok = dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let label: gtk::Label = gtk::Label::new(Some("Are you sure that you want to link this files?"));
let check_button: gtk::CheckButton = gtk::CheckButton::with_label("Ask next time");

@ -1,5 +1,6 @@
use std::path::{Path, PathBuf};
use czkawka_core::fl;
use gtk::prelude::*;
use gtk::{ResponseType, TreePath};
@ -64,7 +65,7 @@ fn move_things(tree_view: &gtk::TreeView, column_file_name: i32, column_path: i3
.modal(true)
.build();
chooser.add_button("Ok", ResponseType::Ok);
chooser.add_button("Close", ResponseType::Cancel);
chooser.add_button(&fl!("general_close_button"), ResponseType::Cancel);
chooser.set_select_multiple(false);
chooser.show_all();

@ -6,6 +6,7 @@ use glib::Sender;
use gtk::prelude::*;
use img_hash::{FilterType, HashAlg};
use crate::fl;
use czkawka_core::big_file::BigFile;
use czkawka_core::broken_files::BrokenFiles;
use czkawka_core::duplicate::{DuplicateFinder, HashType};
@ -137,7 +138,7 @@ pub fn connect_button_search(
button_settings.set_sensitive(false);
button_app_info.set_sensitive(false);
entry_info.set_text("Searching data, it may take a while, please wait...");
entry_info.set_text(&fl!("searching_for_data"));
// Resets progress bars
progress_bar_all_stages.set_fraction(0 as f64);

@ -0,0 +1,46 @@
use crate::language_functions::get_language_from_combo_box_text;
use crate::GuiData;
use gtk::prelude::*;
use i18n_embed::unic_langid::LanguageIdentifier;
// use i18n_embed::{DesktopLanguageRequester, Localizer};
pub fn connect_change_language(gui_data: &GuiData) {
change_language(gui_data);
let combo_box_settings_language = gui_data.settings.combo_box_settings_language.clone();
let gui_data = gui_data.clone();
combo_box_settings_language.connect_changed(move |_| {
change_language(&gui_data);
});
}
fn change_language(gui_data: &GuiData) {
let localizers = vec![("czkawka_gui", czkawka_core::localizer::localizer())];
let lang_short = get_language_from_combo_box_text(gui_data.settings.combo_box_settings_language.active_text().unwrap().to_string()).short_text;
let lang_identifier = vec![LanguageIdentifier::from_bytes(lang_short.as_bytes()).unwrap()];
// let available_languages = Localizer::available_languages();
// println!("{:?}", available_languages);
for (lib, localizer) in localizers {
if let Err(error) = localizer.select(&lang_identifier) {
eprintln!("Error while loadings languages for {} {:?}", lib, error);
}
}
gui_data.update_language();
// Try to use default OS
// let requested_languages = DesktopLanguageRequester::requested_languages();
// let localizers = vec![("czkawka_gui", crate::localizer::localizer())];
//
// println!("Requested Languages{:?}", requested_languages);
//
// let lang_identifier = LanguageIdentifier::from_bytes("pl".as_bytes());
// // let available_languages = Localizer::available_languages();
// // println!("{:?}", available_languages);
// for (lib, localizer) in localizers {
// if let Err(error) = localizer.select(&requested_languages) {
// eprintln!("Error while loadings languages for {} {:?}", lib, error);
// }
// }
}

@ -9,24 +9,11 @@ pub fn connect_notebook_tabs(gui_data: &GuiData) {
let buttons_array = gui_data.bottom_buttons.buttons_array.clone();
let notebook_main_clone = gui_data.main_notebook.notebook_main.clone();
let buttons_names = gui_data.bottom_buttons.buttons_names.clone();
let shared_upper_notebooks = gui_data.shared_upper_notebooks.clone();
let notebook_upper = gui_data.upper_notebook.notebook_upper.clone();
notebook_main_clone.connect_switch_page(move |_, _, number| {
let current_tab_in_main_notebook = to_notebook_main_enum(number);
// Buttons
set_buttons(&mut *shared_buttons.borrow_mut().get_mut(&current_tab_in_main_notebook).unwrap(), &buttons_array, &buttons_names);
// Upper notebook
{
for (index, upper_tab) in get_all_upper_tabs().iter().enumerate() {
if *shared_upper_notebooks.borrow_mut().get_mut(&current_tab_in_main_notebook).unwrap().get_mut(upper_tab).unwrap() {
notebook_upper.children().get(index).unwrap().show(); // TODO find alternative for children
} else {
notebook_upper.children().get(index).unwrap().hide();
}
}
}
});
}

@ -2,6 +2,7 @@ use gtk::prelude::*;
use gtk::{ResponseType, TreeIter, Window};
use regex::Regex;
use crate::fl;
use czkawka_core::common::Common;
use crate::gui_data::GuiData;
@ -218,21 +219,21 @@ fn popover_custom_select_unselect(popover: &gtk::Popover, window_main: &Window,
popover.popdown();
let window_title = match select_things {
false => "Unselect Custom",
true => "Select Custom",
false => fl!("popover_custom_mode_unselect"),
true => fl!("popover_custom_mode_select"),
};
// Dialog for select/unselect items
{
let dialog = gtk::Dialog::builder().title(window_title).transient_for(window_main).modal(true).build();
dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
let dialog = gtk::Dialog::builder().title(&window_title).transient_for(window_main).modal(true).build();
dialog.add_button(&fl!("general_ok_button"), ResponseType::Ok);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let check_button_path = gtk::CheckButton::builder().label("Path").build();
let check_button_name = gtk::CheckButton::builder().label("Name").build();
let check_button_rust_regex = gtk::CheckButton::builder().label("Regex Path + Name").build();
let check_button_path = gtk::CheckButton::builder().label(&fl!("popover_custom_regex_path_label")).build();
let check_button_name = gtk::CheckButton::builder().label(&fl!("popover_custom_regex_name_label")).build();
let check_button_rust_regex = gtk::CheckButton::builder().label(&fl!("popover_custom_regex_regex_label")).build();
let check_button_select_not_all_results = gtk::CheckButton::builder().label("Don't select all records in group").build();
let check_button_select_not_all_results = gtk::CheckButton::builder().label(&fl!("popover_custom_all_in_group_label")).build();
check_button_select_not_all_results.set_active(true);
let entry_path = gtk::Entry::new();
@ -244,21 +245,16 @@ fn popover_custom_select_unselect(popover: &gtk::Popover, window_main: &Window,
// Tooltips
{
let tooltip_path = "Allows to select records by its path.\n\nExample usage:\n/home/pimpek/rzecz.txt can be found with /home/pim*";
let tooltip_name = "Allows to select records by file names.\n\nExample usage:\n/usr/ping/pong.txt can be found with *ong*";
let tooltip_regex = "Allows to select records by specified Regex.\n\nWith this mode, searched text is Path with Name\n\nExample usage:\n/usr/bin/ziemniak.txt can be found with /ziem[a-z]+\n\nThis use default Rust regex implementation, so you can read more about it in https://docs.rs/regex.";
let tooltip_group_button = "Prevents from selecting all records in group.\n\n This is enabled by default, because in most of situations user don't want to delete both original and duplicates files, but want to leave at least one file.\n\nWarning: This setting don't work if already user selected all results in group manually.";
check_button_path.set_tooltip_text(Some(&fl!("popover_custom_path_check_button_entry_tooltip")));
entry_path.set_tooltip_text(Some(&fl!("popover_custom_path_check_button_entry_tooltip")));
check_button_path.set_tooltip_text(Some(tooltip_path));
entry_path.set_tooltip_text(Some(tooltip_path));
check_button_name.set_tooltip_text(Some(&fl!("popover_custom_name_check_button_entry_tooltip")));
entry_name.set_tooltip_text(Some(&fl!("popover_custom_name_check_button_entry_tooltip")));
check_button_name.set_tooltip_text(Some(tooltip_name));
entry_name.set_tooltip_text(Some(tooltip_name));
check_button_rust_regex.set_tooltip_text(Some(&fl!("popover_custom_regex_check_button_entry_tooltip")));
entry_rust_regex.set_tooltip_text(Some(&fl!("popover_custom_regex_check_button_entry_tooltip")));
check_button_rust_regex.set_tooltip_text(Some(tooltip_regex));
entry_rust_regex.set_tooltip_text(Some(tooltip_regex));
check_button_select_not_all_results.set_tooltip_text(Some(tooltip_group_button));
check_button_select_not_all_results.set_tooltip_text(Some(&fl!("popover_custom_not_all_check_button_tooltip")));
}
{
let label_regex_valid = label_regex_valid.clone();
@ -266,11 +262,11 @@ fn popover_custom_select_unselect(popover: &gtk::Popover, window_main: &Window,
let message;
let text_to_check = entry_rust_regex.text().to_string();
if text_to_check.is_empty() {
message = "";
message = "".to_string();
} else {
match Regex::new(&text_to_check) {
Ok(_) => message = "Regex is valid",
Err(_) => message = "Regex is invalid",
Ok(_) => message = fl!("popover_valid_regex"),
Err(_) => message = fl!("popover_invalid_regex"),
}
}
@ -280,7 +276,7 @@ fn popover_custom_select_unselect(popover: &gtk::Popover, window_main: &Window,
// let attribute = PangoAttrFontDesc { attr };
// attributes_list.insert(attribute);
// label_regex_valid.set_attributes(Some(&attributes_list));
label_regex_valid.set_text(message);
label_regex_valid.set_text(&message);
});
}

@ -1,6 +1,7 @@
use futures::StreamExt;
use gtk::prelude::*;
use crate::fl;
use czkawka_core::{big_file, broken_files, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, similar_videos, temporary};
use crate::gui_data::GuiData;
@ -41,7 +42,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.hide();
// progress_bar_all_stages.hide();
progress_bar_all_stages.set_fraction(0 as f64);
label_stage.set_text(format!("Scanned size of {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {} {}", fl!("progress_scanned"), fl!("progress_size"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
// Hash - first 1KB file
@ -57,9 +58,9 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(1, 1 + item.max_stage as u64);
}
label_stage.set_text(format!("Analyzed partial hash of {}/{} files", item.files_checked, item.files_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_analyzed_partial_hash"), item.files_checked, item.files_to_check, fl!("progress_files")).as_str());
}
// Hash - first 1MB of file or normal hash
// Hash - normal hash
2 => {
if item.files_to_check != 0 {
progress_bar_all_stages.set_fraction((2f64 + (item.files_checked) as f64 / item.files_to_check as f64) / (item.max_stage + 1) as f64);
@ -73,11 +74,7 @@ pub fn connect_progress_window(
taskbar_state.borrow().set_progress_value(2, 1 + item.max_stage as u64);
}
if item.checking_method == duplicate::CheckingMethod::Hash {
label_stage.set_text(format!("Analyzed full hash of {}/{} files", item.files_checked, item.files_to_check).as_str());
} else {
label_stage.set_text(format!("Analyzed hash of {}/{} files", item.files_checked, item.files_to_check).as_str());
}
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_analyzed_full_hash"), item.files_checked, item.files_to_check, fl!("progress_files")).as_str());
}
_ => {
panic!("Not available current_stage");
@ -88,14 +85,14 @@ pub fn connect_progress_window(
label_stage.show();
grid_progress_stages.hide();
label_stage.set_text(format!("Scanned name of {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {} {}", fl!("progress_scanned"), fl!("progress_name"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
duplicate::CheckingMethod::Size => {
label_stage.show();
grid_progress_stages.hide();
label_stage.set_text(format!("Scanned size {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {} {}", fl!("progress_scanned"), fl!("progress_size"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
duplicate::CheckingMethod::None => {
@ -112,7 +109,7 @@ pub fn connect_progress_window(
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_empty_files.next().await {
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
@ -124,7 +121,7 @@ pub fn connect_progress_window(
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_empty_folder.next().await {
label_stage.set_text(format!("Scanned {} folders", item.folders_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.folders_checked, fl!("progress_folders")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
@ -136,7 +133,7 @@ pub fn connect_progress_window(
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_big_files.next().await {
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
@ -153,7 +150,7 @@ pub fn connect_progress_window(
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(format!("Scanned {} files", item.music_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.music_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
@ -167,7 +164,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64);
}
label_stage.set_text(format!("Reading tags of {}/{} music files", item.music_checked, item.music_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_tags"), item.music_checked, item.music_to_check, fl!("progress_files")).as_str());
}
2 => {
if item.music_to_check != 0 {
@ -181,7 +178,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(2, (item.max_stage + 1) as u64);
}
label_stage.set_text(format!("Checking for duplicates of {}/{} music files", item.music_checked, item.music_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_checking"), item.music_checked, item.music_to_check, fl!("progress_files")).as_str());
}
_ => {
panic!();
@ -202,7 +199,7 @@ pub fn connect_progress_window(
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(format!("Scanned {} files", item.images_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.images_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
@ -218,7 +215,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64);
}
label_stage.set_text(format!("Hashing {}/{} image", item.images_checked, item.images_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_hashing"), item.images_checked, item.images_to_check, fl!("progress_files")).as_str());
}
_ => {
panic!();
@ -239,7 +236,7 @@ pub fn connect_progress_window(
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(format!("Scanned {} files", item.videos_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.videos_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
@ -255,7 +252,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64);
}
label_stage.set_text(format!("Hashing {}/{} video", item.videos_checked, item.videos_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_hashing"), item.videos_checked, item.videos_to_check, fl!("progress_files")).as_str());
}
_ => {
panic!();
@ -271,7 +268,7 @@ pub fn connect_progress_window(
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_temporary.next().await {
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
@ -283,7 +280,7 @@ pub fn connect_progress_window(
let taskbar_state = gui_data.taskbar_state.clone();
let future = async move {
while let Some(item) = futures_receiver_invalid_symlinks.next().await {
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
};
@ -300,7 +297,7 @@ pub fn connect_progress_window(
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(format!("Scanned {} files", item.files_checked).as_str());
label_stage.set_text(format!("{} {} {}", fl!("progress_scanned"), item.files_checked, fl!("progress_files")).as_str());
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
@ -314,7 +311,7 @@ pub fn connect_progress_window(
progress_bar_current_stage.set_fraction(0f64);
taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64);
}
label_stage.set_text(format!("Checking {}/{} files", item.files_checked, item.files_to_check).as_str());
label_stage.set_text(format!("{} {}/{} {}", fl!("progress_checking"), item.files_checked, item.files_to_check, fl!("progress_files")).as_str());
}
_ => {
panic!();

@ -3,6 +3,7 @@ use gtk::{ResponseType, TreeView, Window};
#[cfg(target_family = "windows")]
use czkawka_core::common::Common;
use czkawka_core::fl;
use crate::gui_data::GuiData;
use crate::help_functions::{get_dialog_box_child, get_list_store, ColumnsDirectory};
@ -12,8 +13,8 @@ pub fn connect_selection_of_directories(gui_data: &GuiData) {
{
let tree_view_included_directories = gui_data.upper_notebook.tree_view_included_directories.clone();
let window_main = gui_data.window_main.clone();
let buttons_manual_add_directory = gui_data.upper_notebook.buttons_manual_add_directory.clone();
buttons_manual_add_directory.connect_clicked(move |_| {
let buttons_manual_add_included_directory = gui_data.upper_notebook.buttons_manual_add_included_directory.clone();
buttons_manual_add_included_directory.connect_clicked(move |_| {
add_manually_directories(&window_main, &tree_view_included_directories);
});
}
@ -81,7 +82,7 @@ fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_i
let chooser = gtk::FileChooserDialog::builder().title(folders_to).action(gtk::FileChooserAction::SelectFolder).transient_for(window_main).modal(true).build();
chooser.add_button("Ok", ResponseType::Ok);
chooser.add_button("Close", ResponseType::Cancel);
chooser.add_button(&fl!("general_close_button"), ResponseType::Cancel);
chooser.set_select_multiple(true);
chooser.show_all();
@ -105,7 +106,7 @@ fn add_chosen_directories(window_main: &Window, tree_view: &TreeView, excluded_i
fn add_manually_directories(window_main: &Window, tree_view: &TreeView) {
let dialog = gtk::Dialog::builder().title("Add directory manually").transient_for(window_main).modal(true).build();
dialog.add_button("Ok", ResponseType::Ok);
dialog.add_button("Close", ResponseType::Cancel);
dialog.add_button(&fl!("general_close_button"), ResponseType::Cancel);
let entry: gtk::Entry = gtk::Entry::new();

@ -1,3 +1,4 @@
use crate::fl;
use gtk::prelude::*;
use gtk::{Builder, Window};
@ -20,11 +21,8 @@ impl GuiAbout {
about_dialog.set_transient_for(Some(window_main));
let button_repository: gtk::Button = builder.object("button_repository").unwrap();
button_repository.set_tooltip_text(Some("Link to repository page with source code."));
let button_donation: gtk::Button = builder.object("button_donation").unwrap();
button_donation.set_tooltip_text(Some("Link to donation page."));
let button_instruction: gtk::Button = builder.object("button_instruction").unwrap();
button_instruction.set_tooltip_text(Some("Link to instruction page."));
Self {
about_dialog,
@ -33,4 +31,13 @@ impl GuiAbout {
button_instruction,
}
}
pub fn update_language(&self) {
self.button_repository.set_tooltip_text(Some(&fl!("about_repository_button_tooltip")));
self.button_donation.set_tooltip_text(Some(&fl!("about_donation_button_tooltip")));
self.button_instruction.set_tooltip_text(Some(&fl!("about_instruction_button_tooltip")));
self.button_repository.set_label(&fl!("about_repository_button"));
self.button_donation.set_label(&fl!("about_donation_button"));
self.button_instruction.set_label(&fl!("about_instruction_button"));
}
}

@ -1,5 +1,7 @@
use crate::fl;
use crate::help_functions::get_custom_label_from_label_with_image;
use gtk::prelude::*;
use gtk::Widget;
use gtk::{Bin, Widget};
#[derive(Clone)]
pub struct GuiBottomButtons {
@ -26,22 +28,8 @@ impl GuiBottomButtons {
let buttons_hardlink: gtk::Button = builder.object("buttons_hardlink").unwrap();
let buttons_move: gtk::Button = builder.object("buttons_move").unwrap();
buttons_search.set_tooltip_text(Some("Start to search for files/folders"));
buttons_select.set_tooltip_text(Some("Selects records\nOnly selected files/folders can be later processed."));
buttons_delete.set_tooltip_text(Some("Delete selected files/folders"));
buttons_save.set_tooltip_text(Some("Save data about search to file"));
buttons_symlink.set_tooltip_text(Some(
"Creates symbolic links\nOnly works when at least 2 results in group are selected\nFirst is unchanged and second and later are symlinked to first",
));
buttons_hardlink.set_tooltip_text(Some("Creates hardlinks\nOnly works when at least 2 results in group are selected\nFirst is unchanged and second and later are hardlinked to first"));
buttons_move.set_tooltip_text(Some(
"Moves files to chosen folder\nIt copy all files to folder without preserving directory tree\nWhen trying to move 2 files with identical name to folder, second will fail and show error",
));
let buttons_show_errors: gtk::Button = builder.object("buttons_show_errors").unwrap();
buttons_show_errors.set_tooltip_text(Some("Show/Hide bottom error panel."));
let buttons_show_upper_notebook: gtk::Button = builder.object("buttons_show_upper_notebook").unwrap();
buttons_show_upper_notebook.set_tooltip_text(Some("Show/Hide upper notebook panel."));
let buttons_names = [
"search".to_string(),
@ -78,4 +66,24 @@ impl GuiBottomButtons {
buttons_array,
}
}
pub fn update_language(&self) {
get_custom_label_from_label_with_image(&self.buttons_search.clone().upcast::<Bin>()).set_text(&fl!("bottom_search_button"));
get_custom_label_from_label_with_image(&self.buttons_select.clone().upcast::<Bin>()).set_text(&fl!("bottom_select_button"));
get_custom_label_from_label_with_image(&self.buttons_delete.clone().upcast::<Bin>()).set_text(&fl!("bottom_delete_button"));
get_custom_label_from_label_with_image(&self.buttons_save.clone().upcast::<Bin>()).set_text(&fl!("bottom_save_button"));
get_custom_label_from_label_with_image(&self.buttons_symlink.clone().upcast::<Bin>()).set_text(&fl!("bottom_symlink_button"));
get_custom_label_from_label_with_image(&self.buttons_hardlink.clone().upcast::<Bin>()).set_text(&fl!("bottom_hardlink_button"));
get_custom_label_from_label_with_image(&self.buttons_move.clone().upcast::<Bin>()).set_text(&fl!("bottom_move_button"));
self.buttons_search.set_tooltip_text(Some(&fl!("bottom_search_button_tooltip")));
self.buttons_select.set_tooltip_text(Some(&fl!("bottom_select_button_tooltip")));
self.buttons_delete.set_tooltip_text(Some(&fl!("bottom_delete_button_tooltip")));
self.buttons_save.set_tooltip_text(Some(&fl!("bottom_save_button_tooltip")));
self.buttons_symlink.set_tooltip_text(Some(&fl!("bottom_symlink_button_tooltip")));
self.buttons_hardlink.set_tooltip_text(Some(&fl!("bottom_hardlink_button_tooltip")));
self.buttons_move.set_tooltip_text(Some(&fl!("bottom_move_button_tooltip")));
self.buttons_show_errors.set_tooltip_text(Some(&fl!("bottom_show_errors_tooltip")));
self.buttons_show_upper_notebook.set_tooltip_text(Some(&fl!("bottom_show_upper_notebook_tooltip")));
}
}

@ -24,7 +24,7 @@ use crate::gui_main_notebook::GuiMainNotebook;
use crate::gui_popovers::GuiPopovers;
use crate::gui_progress_dialog::GuiProgressDialog;
use crate::gui_settings::GuiSettings;
use crate::gui_upper_notepad::GuiUpperNotebook;
use crate::gui_upper_notebook::GuiUpperNotebook;
use crate::notebook_enums::*;
use crate::taskbar_progress::TaskbarProgress;
@ -52,9 +52,6 @@ pub struct GuiData {
// Buttons state
pub shared_buttons: Rc<RefCell<HashMap<NotebookMainEnum, HashMap<String, bool>>>>,
// Upper Notebook state
pub shared_upper_notebooks: Rc<RefCell<HashMap<NotebookMainEnum, HashMap<NotebookUpperEnum, bool>>>>,
// State of search results
pub shared_duplication_state: Rc<RefCell<DuplicateFinder>>,
pub shared_empty_folders_state: Rc<RefCell<EmptyFolder>>,
@ -91,6 +88,7 @@ impl GuiData {
let window_main: gtk::Window = builder.object("window_main").unwrap();
window_main.show_all();
window_main.set_title("Czkawka");
window_main.set_application(Some(application));
let main_notebook = GuiMainNotebook::create_from_builder(&builder);
@ -123,19 +121,6 @@ impl GuiData {
shared_buttons.borrow_mut().insert(i.clone(), temp_hashmap);
}
// Upper Notebook state
let shared_upper_notebooks: Rc<RefCell<_>> = Rc::new(RefCell::new(HashMap::<NotebookMainEnum, HashMap<NotebookUpperEnum, bool>>::new()));
for i in get_all_main_tabs().iter() {
let mut temp_hashmap: HashMap<NotebookUpperEnum, bool> = Default::default();
for j in get_all_upper_tabs().iter() {
temp_hashmap.insert(j.clone(), true);
}
shared_upper_notebooks.borrow_mut().insert(i.clone(), temp_hashmap);
}
// Some upper notebook tabs are disabled
*shared_upper_notebooks.borrow_mut().get_mut(&NotebookMainEnum::Temporary).unwrap().get_mut(&NotebookUpperEnum::AllowedExtensions).unwrap() = false;
// State of search results
let shared_duplication_state: Rc<RefCell<_>> = Rc::new(RefCell::new(DuplicateFinder::new()));
@ -176,7 +161,6 @@ impl GuiData {
header,
taskbar_state,
shared_buttons,
shared_upper_notebooks,
shared_duplication_state,
shared_empty_folders_state,
shared_empty_files_state,
@ -195,4 +179,15 @@ impl GuiData {
stop_receiver,
}
}
pub fn update_language(&self) {
self.main_notebook.update_language();
self.upper_notebook.update_language();
self.popovers.update_language();
self.bottom_buttons.update_language();
self.progress_window.update_language();
self.about.update_language();
self.header.update_language();
self.settings.update_language();
}
}

@ -1,3 +1,4 @@
use crate::fl;
use gtk::prelude::*;
#[derive(Clone)]
@ -11,9 +12,11 @@ impl GuiHeader {
let button_settings: gtk::Button = builder.object("button_settings").unwrap();
let button_app_info: gtk::Button = builder.object("button_app_info").unwrap();
button_settings.set_tooltip_text(Some("Opens settings dialog"));
button_app_info.set_tooltip_text(Some("Opens dialog with info about app"));
Self { button_settings, button_app_info }
}
pub fn update_language(&self) {
self.button_settings.set_tooltip_text(Some(&fl!("header_setting_button_tooltip")));
self.button_app_info.set_tooltip_text(Some(&fl!("header_about_button_tooltip")));
}
}

@ -1,7 +1,8 @@
use crate::fl;
use gtk::prelude::*;
use gtk::{EventControllerKey, TreeView};
use crate::notebook_enums::NUMBER_OF_NOTEBOOK_MAIN_TABS;
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
#[derive(Clone)]
pub struct GuiMainNotebook {
@ -93,6 +94,30 @@ pub struct GuiMainNotebook {
pub label_similar_images_minimal_similarity: gtk::Label,
pub label_duplicate_check_method: gtk::Label,
pub label_duplicate_hash_type: gtk::Label,
pub label_duplicate_size_bytes: gtk::Label,
pub label_duplicate_min_size: gtk::Label,
pub label_duplicate_max_size: gtk::Label,
pub label_big_shown_files: gtk::Label,
pub label_image_resize_algorithm: gtk::Label,
pub label_image_hash_type: gtk::Label,
pub label_image_hash_size: gtk::Label,
pub label_image_size_bytes: gtk::Label,
pub label_image_min_size: gtk::Label,
pub label_image_max_size: gtk::Label,
pub label_image_similarity: gtk::Label,
pub label_image_similarity_max: gtk::Label,
pub label_video_similarity: gtk::Label,
pub label_video_similarity_min: gtk::Label,
pub label_video_similarity_max: gtk::Label,
pub label_video_size_bytes: gtk::Label,
pub label_video_min_size: gtk::Label,
pub label_video_max_size: gtk::Label,
pub label_music_size_bytes: gtk::Label,
pub label_music_min_size: gtk::Label,
pub label_music_max_size: gtk::Label,
pub image_preview_similar_images: gtk::Image,
pub image_preview_duplicates: gtk::Image,
}
@ -181,12 +206,6 @@ impl GuiMainNotebook {
let radio_button_duplicates_size: gtk::RadioButton = builder.object("radio_button_duplicates_size").unwrap();
let radio_button_duplicates_hash: gtk::RadioButton = builder.object("radio_button_duplicates_hash").unwrap();
radio_button_duplicates_name.set_tooltip_text(Some("Finds files which have same name.\n\nThis mode not checking what file contain inside, so be carefully when using it."));
radio_button_duplicates_size.set_tooltip_text(Some("Finds files which have same size.\n\nThis mode not checking what file contain inside, so be carefully when using it."));
radio_button_duplicates_hash.set_tooltip_text(Some(
"Finds files which have the same content.\n\nThis mode hashes file and later compare this hashes to find duplicates.\n\nTool heavily uses cache, so second and further scans of same data should be a lot of faster that first.",
));
let scale_similarity_similar_images: gtk::Scale = builder.object("scale_similarity_similar_images").unwrap();
let scale_similarity_similar_videos: gtk::Scale = builder.object("scale_similarity_similar_videos").unwrap();
@ -194,10 +213,6 @@ impl GuiMainNotebook {
let radio_button_hash_type_crc32: gtk::RadioButton = builder.object("radio_button_hash_type_crc32").unwrap();
let radio_button_hash_type_xxh3: gtk::RadioButton = builder.object("radio_button_hash_type_xxh3").unwrap();
radio_button_hash_type_blake3.set_tooltip_text(Some("Blake3 is cryptographic hash function. It is used as default hash algorithm, because it is very fast."));
radio_button_hash_type_crc32.set_tooltip_text(Some("CRC32 is simple hash function. It should be faster than Blake3, but probably may have very rarely some collisions."));
radio_button_hash_type_xxh3.set_tooltip_text(Some("XXH3 is very similar in case of performance and hash quality to Blake3, so such modes can be easily used ."));
let radio_button_resize_algorithm_lanczos3: gtk::RadioButton = builder.object("radio_button_resize_algorithm_lanczos3").unwrap();
let radio_button_resize_algorithm_nearest: gtk::RadioButton = builder.object("radio_button_resize_algorithm_nearest").unwrap();
let radio_button_resize_algorithm_triangle: gtk::RadioButton = builder.object("radio_button_resize_algorithm_triangle").unwrap();
@ -215,15 +230,34 @@ impl GuiMainNotebook {
let radio_button_similar_hash_size_32: gtk::RadioButton = builder.object("radio_button_similar_hash_size_32").unwrap();
let radio_button_similar_hash_size_64: gtk::RadioButton = builder.object("radio_button_similar_hash_size_64").unwrap();
radio_button_similar_hash_size_8.set_tooltip_text(Some("Default hash size, with very high similarity it produce quite good results and don't save too much data too cache."));
radio_button_similar_hash_size_16.set_tooltip_text(Some("More precise than 8, so can be used to find very similar pictures, but create bigger cache entries."));
radio_button_similar_hash_size_32.set_tooltip_text(Some("Hash of this size provide very big similarity which is more than enough for most usages."));
radio_button_similar_hash_size_64.set_tooltip_text(Some("Paranoid mode, such tool create really big cache files and will catch almost same images."));
let check_button_image_ignore_same_size: gtk::CheckButton = builder.object("check_button_image_ignore_same_size").unwrap();
let label_similar_images_minimal_similarity: gtk::Label = builder.object("label_similar_images_minimal_similarity").unwrap();
let label_duplicate_check_method: gtk::Label = builder.object("label_duplicate_check_method").unwrap();
let label_duplicate_hash_type: gtk::Label = builder.object("label_duplicate_hash_type").unwrap();
let label_duplicate_size_bytes: gtk::Label = builder.object("label_duplicate_size_bytes").unwrap();
let label_duplicate_min_size: gtk::Label = builder.object("label_duplicate_min_size").unwrap();
let label_duplicate_max_size: gtk::Label = builder.object("label_duplicate_max_size").unwrap();
let label_big_shown_files: gtk::Label = builder.object("label_big_shown_files").unwrap();
let label_image_resize_algorithm: gtk::Label = builder.object("label_image_resize_algorithm").unwrap();
let label_image_hash_type: gtk::Label = builder.object("label_image_hash_type").unwrap();
let label_image_hash_size: gtk::Label = builder.object("label_image_hash_size").unwrap();
let label_image_size_bytes: gtk::Label = builder.object("label_image_size_bytes").unwrap();
let label_image_min_size: gtk::Label = builder.object("label_image_min_size").unwrap();
let label_image_max_size: gtk::Label = builder.object("label_image_max_size").unwrap();
let label_image_similarity: gtk::Label = builder.object("label_image_similarity").unwrap();
let label_image_similarity_max: gtk::Label = builder.object("label_image_similarity_max").unwrap();
let label_video_similarity: gtk::Label = builder.object("label_video_similarity").unwrap();
let label_video_similarity_min: gtk::Label = builder.object("label_video_similarity_min").unwrap();
let label_video_similarity_max: gtk::Label = builder.object("label_video_similarity_max").unwrap();
let label_video_size_bytes: gtk::Label = builder.object("label_video_size_bytes").unwrap();
let label_video_min_size: gtk::Label = builder.object("label_video_min_size").unwrap();
let label_video_max_size: gtk::Label = builder.object("label_video_max_size").unwrap();
let label_music_size_bytes: gtk::Label = builder.object("label_music_size_bytes").unwrap();
let label_music_min_size: gtk::Label = builder.object("label_music_min_size").unwrap();
let label_music_max_size: gtk::Label = builder.object("label_music_max_size").unwrap();
let image_preview_similar_images: gtk::Image = builder.object("image_preview_similar_images").unwrap();
let image_preview_duplicates: gtk::Image = builder.object("image_preview_duplicates").unwrap();
@ -296,6 +330,29 @@ impl GuiMainNotebook {
radio_button_similar_hash_size_64,
check_button_image_ignore_same_size,
label_similar_images_minimal_similarity,
label_duplicate_check_method,
label_duplicate_hash_type,
label_duplicate_size_bytes,
label_duplicate_min_size,
label_duplicate_max_size,
label_big_shown_files,
label_image_resize_algorithm,
label_image_hash_type,
label_image_hash_size,
label_image_size_bytes,
label_image_min_size,
label_image_max_size,
label_image_similarity,
label_image_similarity_max,
label_video_similarity,
label_video_similarity_min,
label_video_similarity_max,
label_video_size_bytes,
label_video_min_size,
label_video_max_size,
label_music_size_bytes,
label_music_min_size,
label_music_max_size,
image_preview_similar_images,
entry_duplicate_maximal_size,
entry_same_music_maximal_size,
@ -317,4 +374,133 @@ impl GuiMainNotebook {
self.tree_view_broken_files.clone(),
]
}
pub fn update_language(&self) {
self.check_button_music_title.set_label(&fl!("music_title_checkbox"));
self.check_button_music_artist.set_label(&fl!("music_artist_checkbox"));
self.check_button_music_album_title.set_label(&fl!("music_album_title_checkbox"));
self.check_button_music_album_artist.set_label(&fl!("music_album_artist_checkbox"));
self.check_button_music_year.set_label(&fl!("music_year_checkbox"));
self.check_button_music_approximate_comparison.set_label(&fl!("music_comparison_checkbox"));
self.radio_button_duplicates_name.set_label(&fl!("duplicate_mode_name_checkbox"));
self.radio_button_duplicates_size.set_label(&fl!("duplicate_mode_size_checkbox"));
self.radio_button_duplicates_hash.set_label(&fl!("duplicate_mode_hash_checkbox"));
self.radio_button_duplicates_name.set_tooltip_text(Some(&fl!("duplicate_mode_name_checkbox_tooltip")));
self.radio_button_duplicates_size.set_tooltip_text(Some(&fl!("duplicate_mode_size_checkbox_tooltip")));
self.radio_button_duplicates_hash.set_tooltip_text(Some(&fl!("duplicate_mode_hash_checkbox_tooltip")));
self.radio_button_hash_type_blake3.set_tooltip_text(Some(&fl!("duplicate_hash_checkbox_blake3")));
self.radio_button_hash_type_crc32.set_tooltip_text(Some(&fl!("duplicate_hash_checkbox_crc32")));
self.radio_button_hash_type_xxh3.set_tooltip_text(Some(&fl!("duplicate_hash_checkbox_xxh3")));
self.radio_button_similar_hash_size_8.set_tooltip_text(Some(&fl!("image_hash_checkbox_8")));
self.radio_button_similar_hash_size_16.set_tooltip_text(Some(&fl!("image_hash_checkbox_16")));
self.radio_button_similar_hash_size_32.set_tooltip_text(Some(&fl!("image_hash_checkbox_32")));
self.radio_button_similar_hash_size_64.set_tooltip_text(Some(&fl!("image_hash_checkbox_64")));
self.label_duplicate_check_method.set_label(&fl!("main_label_check_method"));
self.label_duplicate_hash_type.set_label(&fl!("main_label_hash_type"));
self.label_duplicate_size_bytes.set_label(&fl!("main_label_size_bytes"));
self.label_duplicate_min_size.set_label(&fl!("main_label_min_size"));
self.label_duplicate_max_size.set_label(&fl!("main_label_max_size"));
self.label_big_shown_files.set_label(&fl!("main_label_shown_files"));
self.label_image_resize_algorithm.set_label(&fl!("main_label_resize_algorithm"));
self.label_image_hash_type.set_label(&fl!("main_label_hash_type"));
self.label_image_hash_size.set_label(&fl!("main_label_hash_size"));
self.label_image_size_bytes.set_label(&fl!("main_label_size_bytes"));
self.label_image_min_size.set_label(&fl!("main_label_min_size"));
self.label_image_max_size.set_label(&fl!("main_label_max_size"));
self.label_image_similarity.set_label(&fl!("main_label_similarity"));
self.label_image_similarity_max.set_label(&fl!("core_similarity_very_high"));
self.label_video_similarity.set_label(&fl!("main_label_similarity"));
self.label_video_similarity_min.set_label(&fl!("core_similarity_minimal"));
self.label_video_similarity_max.set_label(&fl!("core_similarity_very_high"));
self.label_video_size_bytes.set_label(&fl!("main_label_size_bytes"));
self.label_video_min_size.set_label(&fl!("main_label_min_size"));
self.label_video_max_size.set_label(&fl!("main_label_max_size"));
self.label_music_size_bytes.set_label(&fl!("main_label_size_bytes"));
self.label_music_min_size.set_label(&fl!("main_label_min_size"));
self.label_music_max_size.set_label(&fl!("main_label_max_size"));
// Change name of main notebook tabs
let vec_children: Vec<gtk::Widget> = self.notebook_main.children();
for (main_enum, fl_thing) in [
(NotebookMainEnum::Duplicate as usize, fl!("main_notebook_duplicates")),
(NotebookMainEnum::EmptyDirectories as usize, fl!("main_notebook_empty_directories")),
(NotebookMainEnum::BigFiles as usize, fl!("main_notebook_big_files")),
(NotebookMainEnum::EmptyFiles as usize, fl!("main_notebook_empty_files")),
(NotebookMainEnum::Temporary as usize, fl!("main_notebook_temporary")),
(NotebookMainEnum::SimilarImages as usize, fl!("main_notebook_similar_images")),
(NotebookMainEnum::SimilarVideos as usize, fl!("main_notebook_similar_videos")),
(NotebookMainEnum::SameMusic as usize, fl!("main_notebook_same_music")),
(NotebookMainEnum::Symlinks as usize, fl!("main_notebook_symlinks")),
(NotebookMainEnum::BrokenFiles as usize, fl!("main_notebook_broken_files")),
] {
self.notebook_main.tab_label(&vec_children[main_enum]).unwrap().downcast::<gtk::Label>().unwrap().set_text(&fl_thing);
}
// Change names of columns
let names_of_columns = [
vec![fl!("main_tree_view_column_file_name"), fl!("main_tree_view_column_path"), fl!("main_tree_view_column_modification")], // Duplicates
vec![fl!("main_tree_view_column_folder_name"), fl!("main_tree_view_column_path"), fl!("main_tree_view_column_modification")], // Empty Folders
vec![
fl!("main_tree_view_column_size"),
fl!("main_tree_view_column_file_name"),
fl!("main_tree_view_column_path"),
fl!("main_tree_view_column_modification"),
], // Big files
vec![fl!("main_tree_view_column_file_name"), fl!("main_tree_view_column_path"), fl!("main_tree_view_column_modification")], // Empty files
vec![fl!("main_tree_view_column_file_name"), fl!("main_tree_view_column_path"), fl!("main_tree_view_column_modification")], // Temporary Files
vec![
fl!("main_tree_view_column_similarity"),
fl!("main_tree_view_column_size"),
fl!("main_tree_view_column_dimensions"),
fl!("main_tree_view_column_file_name"),
fl!("main_tree_view_column_path"),
fl!("main_tree_view_column_modification"),
], // Similar Images
vec![
fl!("main_tree_view_column_size"),
fl!("main_tree_view_column_file_name"),
fl!("main_tree_view_column_path"),
fl!("main_tree_view_column_modification"),
], // Similar Videos
vec![
fl!("main_tree_view_column_size"),
fl!("main_tree_view_column_file_name"),
fl!("main_tree_view_column_path"),
fl!("main_tree_view_column_title"),
fl!("main_tree_view_column_artist"),
fl!("main_tree_view_column_year"),
fl!("main_tree_view_column_album_title"),
fl!("main_tree_view_column_album_artist"),
fl!("main_tree_view_column_modification"),
], // Music Dupliactes
vec![
fl!("main_tree_view_column_symlink_file_name"),
fl!("main_tree_view_column_symlink_folder"),
fl!("main_tree_view_column_destination_path"),
fl!("main_tree_view_column_type_of_error"),
fl!("main_tree_view_column_modification"),
], // Invalid Symlinks
vec![
fl!("main_tree_view_column_file_name"),
fl!("main_tree_view_column_path"),
fl!("main_tree_view_column_type_of_error"),
fl!("main_tree_view_column_modification"),
], // Broken Files
];
for (notebook_index, tree_view) in self.get_main_tree_views().iter().enumerate() {
for (column_index, column) in tree_view.columns().iter().enumerate() {
if column_index == 0 {
continue; // Selection button
}
column.set_title(&names_of_columns[notebook_index][column_index - 1]);
}
}
}
}

@ -1,3 +1,4 @@
use crate::fl;
use gtk::prelude::*;
use gtk::Builder;
@ -82,4 +83,17 @@ impl GuiPopovers {
popover_right_click,
}
}
pub fn update_language(&self) {
self.buttons_popover_select_all.set_label(&fl!("popover_select_all"));
self.buttons_popover_unselect_all.set_label(&fl!("popover_unselect_all"));
self.buttons_popover_reverse.set_label(&fl!("popover_reverse"));
self.buttons_popover_select_all_except_oldest.set_label(&fl!("popover_select_all_except_oldest"));
self.buttons_popover_select_all_except_newest.set_label(&fl!("popover_select_all_except_newest"));
self.buttons_popover_select_one_oldest.set_label(&fl!("popover_select_one_oldest"));
self.buttons_popover_select_one_newest.set_label(&fl!("popover_select_one_newest"));
self.buttons_popover_select_custom.set_label(&fl!("popover_select_custom"));
self.buttons_popover_unselect_custom.set_label(&fl!("popover_unselect_custom"));
self.buttons_popover_select_all_images_except_biggest.set_label(&fl!("popover_select_all_images_except_biggest"));
self.buttons_popover_select_all_images_except_smallest.set_label(&fl!("popover_select_all_images_except_smallest"));
}
}

@ -1,5 +1,7 @@
use crate::fl;
use crate::help_functions::get_custom_label_from_label_with_image;
use gtk::prelude::*;
use gtk::{Builder, EventControllerKey, Window};
use gtk::{Bin, Builder, EventControllerKey, Window};
#[derive(Clone)]
pub struct GuiProgressDialog {
@ -9,6 +11,8 @@ pub struct GuiProgressDialog {
pub progress_bar_all_stages: gtk::ProgressBar,
pub label_stage: gtk::Label,
pub label_progress_current_stage: gtk::Label,
pub label_progress_all_stages: gtk::Label,
pub grid_progress_stages: gtk::Grid,
@ -23,11 +27,14 @@ impl GuiProgressDialog {
let window_progress: gtk::Dialog = builder.object("window_progress").unwrap();
window_progress.set_transient_for(Some(window_main));
window_progress.set_title("Czkawka");
let progress_bar_current_stage: gtk::ProgressBar = builder.object("progress_bar_current_stage").unwrap();
let progress_bar_all_stages: gtk::ProgressBar = builder.object("progress_bar_all_stages").unwrap();
let label_stage: gtk::Label = builder.object("label_stage").unwrap();
let label_progress_current_stage: gtk::Label = builder.object("label_progress_current_stage").unwrap();
let label_progress_all_stages: gtk::Label = builder.object("label_progress_all_stages").unwrap();
let grid_progress_stages: gtk::Grid = builder.object("grid_progress_stages").unwrap();
@ -39,9 +46,17 @@ impl GuiProgressDialog {
progress_bar_current_stage,
progress_bar_all_stages,
label_stage,
label_progress_current_stage,
label_progress_all_stages,
grid_progress_stages,
button_stop_in_dialog,
evk_button_stop_in_dialog,
}
}
pub fn update_language(&self) {
get_custom_label_from_label_with_image(&self.button_stop_in_dialog.clone().upcast::<Bin>()).set_text(&fl!("progress_stop_button"));
self.label_progress_current_stage.set_label(&fl!("progress_current_stage"));
self.label_progress_all_stages.set_label(&fl!("progress_all_stages"));
}
}

@ -1,3 +1,4 @@
use crate::fl;
use gtk::prelude::*;
use gtk::{Builder, Window};
@ -14,6 +15,8 @@ pub struct GuiSettings {
pub check_button_settings_show_text_view: gtk::CheckButton,
pub check_button_settings_use_cache: gtk::CheckButton,
pub check_button_settings_use_trash: gtk::CheckButton,
pub label_settings_general_language: gtk::Label,
pub combo_box_settings_language: gtk::ComboBoxText,
// Duplicates
pub check_button_settings_hide_hard_links: gtk::CheckButton,
@ -23,6 +26,8 @@ pub struct GuiSettings {
pub check_button_settings_show_preview_duplicates: gtk::CheckButton,
pub check_button_settings_duplicates_delete_outdated_cache: gtk::CheckButton,
pub button_settings_duplicates_clear_cache: gtk::Button,
pub label_settings_duplicate_minimal_size_cache: gtk::Label,
pub label_settings_duplicate_minimal_size_cache_prehash: gtk::Label,
// Similar Images
pub check_button_settings_show_preview_similar_images: gtk::CheckButton,
@ -60,15 +65,8 @@ impl GuiSettings {
let check_button_settings_show_text_view: gtk::CheckButton = builder.object("check_button_settings_show_text_view").unwrap();
let check_button_settings_use_cache: gtk::CheckButton = builder.object("check_button_settings_use_cache").unwrap();
let check_button_settings_use_trash: gtk::CheckButton = builder.object("check_button_settings_use_trash").unwrap();
check_button_settings_save_at_exit.set_tooltip_text(Some("Saves configuration to file when closing app."));
check_button_settings_load_at_start.set_tooltip_text(Some("Loading at start configuration from file.\n\nNot selecting this option will load default settings."));
check_button_settings_confirm_deletion.set_tooltip_text(Some("Shows confirmation dialog when clicking at delete button."));
check_button_settings_confirm_link.set_tooltip_text(Some("Shows confirmation dialog when clicking at hard/symlink button."));
check_button_settings_confirm_group_deletion.set_tooltip_text(Some("Shows dialog when trying to remove all records from group."));
check_button_settings_show_text_view.set_tooltip_text(Some("Shows error panel at bottom."));
check_button_settings_use_cache.set_tooltip_text(Some("Option to which allows to not use cache feature."));
check_button_settings_use_trash.set_tooltip_text(Some("When enabled it moves files to trash instead deleting them permanently."));
let label_settings_general_language: gtk::Label = builder.object("label_settings_general_language").unwrap();
let combo_box_settings_language: gtk::ComboBoxText = builder.object("combo_box_settings_language").unwrap();
// Duplicates
let check_button_settings_hide_hard_links: gtk::CheckButton = builder.object("check_button_settings_hide_hard_links").unwrap();
@ -78,53 +76,26 @@ impl GuiSettings {
let button_settings_duplicates_clear_cache: gtk::Button = builder.object("button_settings_duplicates_clear_cache").unwrap();
let check_button_duplicates_use_prehash_cache: gtk::CheckButton = builder.object("check_button_duplicates_use_prehash_cache").unwrap();
let entry_settings_prehash_cache_file_minimal_size: gtk::Entry = builder.object("entry_settings_prehash_cache_file_minimal_size").unwrap();
check_button_settings_hide_hard_links.set_tooltip_text(Some(
"Hides all files except one, if are points to same data(are hardlinked).\n\nE.g. in case where on disk there is 7 files which are hardlinked to specific data and one different file with same data but different inode, then in duplicate finder will be visible only one unique file and one file from hardlinked ones.",
));
entry_settings_cache_file_minimal_size.set_tooltip_text(Some(
"Allows to set minimal size of file, which will be cached.\n\nChoosing smaller value, will generate more records which will speedup search, but slowdown cache loading/saving.",
));
check_button_settings_show_preview_duplicates.set_tooltip_text(Some("Shows preview at right side, when selecting image file."));
check_button_settings_duplicates_delete_outdated_cache.set_tooltip_text(Some("Allows to delete outdated cache results which points to non-existent files.\n\nWhen enabled, app make sure when loading records, that all points to valid files and ignore broken ones.\n\nDisabling this option, will help to scan files on external drives, so cache entries about them will not be purged in next scan.\n\nIn case of having hundred of thousands records in cache, it is suggested to enable this option, to speedup cache loading and saving at start and end of scan."));
button_settings_duplicates_clear_cache.set_tooltip_text(Some("Manually clear cache from outdated entries.\n\nShould be used only if automatic clearing was disabled."));
check_button_duplicates_use_prehash_cache.set_tooltip_text(Some(
"Enables caching of prehash(hash computed from small part of file) which allows to earlier throw out non duplicated results.\n\nIt is disabled by default because can cause in some situations slowdowns.\n\nIt is heavily recommended to use it when scanning hundred of thousands or million files, because it can speedup search multiple times.",
));
let label_settings_duplicate_minimal_size_cache: gtk::Label = builder.object("label_settings_duplicate_minimal_size_cache").unwrap();
let label_settings_duplicate_minimal_size_cache_prehash: gtk::Label = builder.object("label_settings_duplicate_minimal_size_cache_prehash").unwrap();
// Similar Images
let check_button_settings_show_preview_similar_images: gtk::CheckButton = builder.object("check_button_settings_show_preview_similar_images").unwrap();
let check_button_settings_similar_images_delete_outdated_cache: gtk::CheckButton = builder.object("check_button_settings_similar_images_delete_outdated_cache").unwrap();
let button_settings_similar_images_clear_cache: gtk::Button = builder.object("button_settings_similar_images_clear_cache").unwrap();
check_button_settings_show_preview_similar_images.set_tooltip_text(Some("Shows preview at right side, when selecting image file."));
check_button_settings_similar_images_delete_outdated_cache.set_tooltip_text(Some("Allows to delete outdated cache results which points to non-existent files.\n\nWhen enabled, app make sure when loading records, that all points to valid files and ignore broken ones.\n\nDisabling this option, will help to scan files on external drives, so cache entries about them will not be purged in next scan.\n\nIn case of having hundred of thousands records in cache, it is suggested to enable this option, to speedup cache loading and saving at start and end of scan."));
button_settings_similar_images_clear_cache.set_tooltip_text(Some("Manually clear cache from outdated entries.\nShould be used only if automatic clearing was disabled."));
// Similar Videos
let check_button_settings_similar_videos_delete_outdated_cache: gtk::CheckButton = builder.object("check_button_settings_similar_videos_delete_outdated_cache").unwrap();
let button_settings_similar_videos_clear_cache: gtk::Button = builder.object("button_settings_similar_videos_clear_cache").unwrap();
check_button_settings_similar_videos_delete_outdated_cache.set_tooltip_text(Some("Allows to delete outdated cache results which points to non-existent files.\n\nWhen enabled, app make sure when loading records, that all points to valid files and ignore broken ones.\n\nDisabling this option, will help to scan files on external drives, so cache entries about them will not be purged in next scan.\n\nIn case of having hundred of thousands records in cache, it is suggested to enable this option, to speedup cache loading and saving at start and end of scan."));
button_settings_similar_videos_clear_cache.set_tooltip_text(Some("Manually clear cache from outdated entries.\nShould be used only if automatic clearing was disabled."));
// Saving/Loading/Resetting configuration
let button_settings_save_configuration: gtk::Button = builder.object("button_settings_save_configuration").unwrap();
let button_settings_load_configuration: gtk::Button = builder.object("button_settings_load_configuration").unwrap();
let button_settings_reset_configuration: gtk::Button = builder.object("button_settings_reset_configuration").unwrap();
button_settings_save_configuration.set_tooltip_text(Some("Save current settings configuration to file."));
button_settings_load_configuration.set_tooltip_text(Some("Load settings from file and replace current configuration with them."));
button_settings_reset_configuration.set_tooltip_text(Some("Reset current configuration to default one."));
let button_settings_open_cache_folder: gtk::Button = builder.object("button_settings_open_cache_folder").unwrap();
let button_settings_open_settings_folder: gtk::Button = builder.object("button_settings_open_settings_folder").unwrap();
button_settings_open_cache_folder.set_tooltip_text(Some(
"Opens folder where are stored txt files with cache.\n\nModifying them may cause to show invalid results but also modifying e.g. path may save time when moving big amount of files to different place.\n\nYou can copy this files between computers to save time on scanning again for files(of course if they have similar directory structure).\n\nIn case of problems with cache, this files can be removed, so app will automatically regenerate them.",
));
button_settings_open_settings_folder.set_tooltip_text(Some("Opens folder where Czkawka config are stored.\n\nModifying them, may cause to show."));
Self {
window_settings,
check_button_settings_save_at_exit,
@ -135,6 +106,8 @@ impl GuiSettings {
check_button_settings_show_text_view,
check_button_settings_use_cache,
check_button_settings_use_trash,
label_settings_general_language,
combo_box_settings_language,
check_button_settings_hide_hard_links,
entry_settings_cache_file_minimal_size,
entry_settings_prehash_cache_file_minimal_size,
@ -142,6 +115,8 @@ impl GuiSettings {
check_button_settings_show_preview_duplicates,
check_button_settings_duplicates_delete_outdated_cache,
button_settings_duplicates_clear_cache,
label_settings_duplicate_minimal_size_cache,
label_settings_duplicate_minimal_size_cache_prehash,
check_button_settings_show_preview_similar_images,
check_button_settings_similar_images_delete_outdated_cache,
button_settings_similar_images_clear_cache,
@ -154,4 +129,73 @@ impl GuiSettings {
button_settings_open_settings_folder,
}
}
pub fn update_language(&self) {
self.check_button_settings_save_at_exit.set_label(&fl!("settings_save_at_exit_button"));
self.check_button_settings_load_at_start.set_label(&fl!("settings_load_at_start_button"));
self.check_button_settings_confirm_deletion.set_label(&fl!("settings_confirm_deletion_button"));
self.check_button_settings_confirm_link.set_label(&fl!("settings_confirm_link_button"));
self.check_button_settings_confirm_group_deletion.set_label(&fl!("settings_confirm_group_deletion_button"));
self.check_button_settings_show_text_view.set_label(&fl!("settings_show_text_view_button"));
self.check_button_settings_use_cache.set_label(&fl!("settings_use_cache_button"));
self.check_button_settings_use_trash.set_label(&fl!("settings_use_trash_button"));
self.label_settings_general_language.set_label(&fl!("settings_language_label"));
self.check_button_settings_save_at_exit.set_tooltip_text(Some(&fl!("settings_save_at_exit_button_tooltip")));
self.check_button_settings_load_at_start.set_tooltip_text(Some(&fl!("settings_load_at_start_button_tooltip")));
self.check_button_settings_confirm_deletion.set_tooltip_text(Some(&fl!("settings_confirm_deletion_button_tooltip")));
self.check_button_settings_confirm_link.set_tooltip_text(Some(&fl!("settings_confirm_link_button_tooltip")));
self.check_button_settings_confirm_group_deletion.set_tooltip_text(Some(&fl!("settings_confirm_group_deletion_button_tooltip")));
self.check_button_settings_show_text_view.set_tooltip_text(Some(&fl!("settings_show_text_view_button_tooltip")));
self.check_button_settings_use_cache.set_tooltip_text(Some(&fl!("settings_use_cache_button_tooltip")));
self.check_button_settings_use_trash.set_tooltip_text(Some(&fl!("settings_use_trash_button_tooltip")));
self.label_settings_general_language.set_tooltip_text(Some(&fl!("settings_language_label_tooltip")));
self.check_button_settings_hide_hard_links.set_label(&fl!("settings_duplicates_hide_hard_link_button"));
self.check_button_settings_show_preview_duplicates.set_label(&fl!("settings_multiple_image_preview_checkbutton"));
self.check_button_settings_duplicates_delete_outdated_cache.set_label(&fl!("settings_multiple_delete_outdated_cache_checkbutton"));
self.button_settings_duplicates_clear_cache.set_label(&fl!("settings_multiple_clear_cache_button"));
self.check_button_duplicates_use_prehash_cache.set_label(&fl!("settings_duplicates_prehash_checkbutton"));
self.label_settings_duplicate_minimal_size_cache.set_label(&fl!("settings_duplicates_minimal_size_cache_label"));
self.label_settings_duplicate_minimal_size_cache_prehash.set_label(&fl!("settings_duplicates_minimal_size_cache_prehash_label"));
self.check_button_settings_hide_hard_links.set_tooltip_text(Some(&fl!("settings_duplicates_hide_hard_link_button_tooltip")));
self.entry_settings_cache_file_minimal_size.set_tooltip_text(Some(&fl!("settings_duplicates_minimal_size_entry_tooltip")));
self.check_button_settings_show_preview_duplicates.set_tooltip_text(Some(&fl!("settings_multiple_image_preview_checkbutton_tooltip")));
self.check_button_settings_duplicates_delete_outdated_cache
.set_tooltip_text(Some(&fl!("settings_multiple_delete_outdated_cache_checkbutton_tooltip")));
self.button_settings_duplicates_clear_cache.set_tooltip_text(Some(&fl!("settings_multiple_clear_cache_button_tooltip")));
self.check_button_duplicates_use_prehash_cache.set_tooltip_text(Some(&fl!("settings_duplicates_prehash_checkbutton_tooltip")));
self.entry_settings_prehash_cache_file_minimal_size.set_tooltip_text(Some(&fl!("settings_duplicates_prehash_minimal_entry_tooltip")));
self.check_button_settings_show_preview_similar_images.set_label(&fl!("settings_multiple_image_preview_checkbutton"));
self.check_button_settings_similar_images_delete_outdated_cache.set_label(&fl!("settings_multiple_delete_outdated_cache_checkbutton"));
self.button_settings_similar_images_clear_cache.set_label(&fl!("settings_multiple_clear_cache_button"));
self.check_button_settings_show_preview_similar_images.set_tooltip_text(Some(&fl!("settings_multiple_image_preview_checkbutton_tooltip")));
self.check_button_settings_similar_images_delete_outdated_cache
.set_tooltip_text(Some(&fl!("settings_multiple_delete_outdated_cache_checkbutton_tooltip")));
self.button_settings_similar_images_clear_cache.set_tooltip_text(Some(&fl!("settings_multiple_clear_cache_button_tooltip")));
self.check_button_settings_similar_videos_delete_outdated_cache.set_label(&fl!("settings_multiple_delete_outdated_cache_checkbutton"));
self.button_settings_similar_videos_clear_cache.set_label(&fl!("settings_multiple_clear_cache_button"));
self.check_button_settings_similar_videos_delete_outdated_cache
.set_tooltip_text(Some(&fl!("settings_multiple_delete_outdated_cache_checkbutton_tooltip")));
self.button_settings_similar_videos_clear_cache.set_tooltip_text(Some(&fl!("settings_multiple_clear_cache_button_tooltip")));
self.button_settings_save_configuration.set_label(&fl!("settings_saving_button"));
self.button_settings_load_configuration.set_label(&fl!("settings_loading_button"));
self.button_settings_reset_configuration.set_label(&fl!("settings_reset_button"));
self.button_settings_save_configuration.set_tooltip_text(Some(&fl!("settings_saving_button_tooltip")));
self.button_settings_load_configuration.set_tooltip_text(Some(&fl!("settings_loading_button_tooltip")));
self.button_settings_reset_configuration.set_tooltip_text(Some(&fl!("settings_reset_button_tooltip")));
self.button_settings_open_cache_folder.set_label(&fl!("settings_folder_cache_open"));
self.button_settings_open_settings_folder.set_label(&fl!("settings_folder_settings_open"));
self.button_settings_open_cache_folder.set_tooltip_text(Some(&fl!("settings_folder_cache_open_tooltip")));
self.button_settings_open_settings_folder.set_tooltip_text(Some(&fl!("settings_folder_settings_open_tooltip")));
}
}

@ -0,0 +1,121 @@
use crate::fl;
use crate::help_functions::get_custom_label_from_label_with_image;
use crate::notebook_enums::NotebookUpperEnum;
use gtk::prelude::*;
use gtk::{Bin, EventControllerKey, TreeView};
#[derive(Clone)]
pub struct GuiUpperNotebook {
pub notebook_upper: gtk::Notebook,
pub scrolled_window_included_directories: gtk::ScrolledWindow,
pub scrolled_window_excluded_directories: gtk::ScrolledWindow,
pub tree_view_included_directories: gtk::TreeView,
pub tree_view_excluded_directories: gtk::TreeView,
pub evk_tree_view_included_directories: gtk::EventControllerKey,
pub evk_tree_view_excluded_directories: gtk::EventControllerKey,
pub entry_excluded_items: gtk::Entry,
pub entry_allowed_extensions: gtk::Entry,
pub check_button_recursive: gtk::CheckButton,
pub buttons_manual_add_included_directory: gtk::Button,
pub buttons_add_included_directory: gtk::Button,
pub buttons_remove_included_directory: gtk::Button,
pub buttons_manual_add_excluded_directory: gtk::Button,
pub buttons_add_excluded_directory: gtk::Button,
pub buttons_remove_excluded_directory: gtk::Button,
pub label_excluded_items: gtk::Label,
pub label_allowed_extensions: gtk::Label,
}
impl GuiUpperNotebook {
pub fn create_from_builder(builder: &gtk::Builder) -> Self {
let notebook_upper: gtk::Notebook = builder.object("notebook_upper").unwrap();
let scrolled_window_included_directories: gtk::ScrolledWindow = builder.object("scrolled_window_included_directories").unwrap();
let scrolled_window_excluded_directories: gtk::ScrolledWindow = builder.object("scrolled_window_excluded_directories").unwrap();
let tree_view_included_directories: gtk::TreeView = TreeView::new();
let tree_view_excluded_directories: gtk::TreeView = TreeView::new();
let evk_tree_view_included_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_included_directories);
let evk_tree_view_excluded_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_excluded_directories);
let entry_allowed_extensions: gtk::Entry = builder.object("entry_allowed_extensions").unwrap();
let entry_excluded_items: gtk::Entry = builder.object("entry_excluded_items").unwrap();
let check_button_recursive: gtk::CheckButton = builder.object("check_button_recursive").unwrap();
let buttons_manual_add_included_directory: gtk::Button = builder.object("buttons_manual_add_included_directory").unwrap();
let buttons_add_included_directory: gtk::Button = builder.object("buttons_add_included_directory").unwrap();
let buttons_remove_included_directory: gtk::Button = builder.object("buttons_remove_included_directory").unwrap();
let buttons_manual_add_excluded_directory: gtk::Button = builder.object("buttons_manual_add_excluded_directory").unwrap();
let buttons_add_excluded_directory: gtk::Button = builder.object("buttons_add_excluded_directory").unwrap();
let buttons_remove_excluded_directory: gtk::Button = builder.object("buttons_remove_excluded_directory").unwrap();
let label_excluded_items: gtk::Label = builder.object("label_excluded_items").unwrap();
let label_allowed_extensions: gtk::Label = builder.object("label_allowed_extensions").unwrap();
Self {
notebook_upper,
scrolled_window_included_directories,
scrolled_window_excluded_directories,
tree_view_included_directories,
tree_view_excluded_directories,
evk_tree_view_included_directories,
evk_tree_view_excluded_directories,
entry_excluded_items,
entry_allowed_extensions,
check_button_recursive,
buttons_manual_add_included_directory,
buttons_add_included_directory,
buttons_remove_included_directory,
buttons_manual_add_excluded_directory,
buttons_add_excluded_directory,
buttons_remove_excluded_directory,
label_excluded_items,
label_allowed_extensions,
}
}
pub fn update_language(&self) {
self.check_button_recursive.set_label(&fl!("upper_recursive_button"));
self.check_button_recursive.set_tooltip_text(Some(&fl!("upper_recursive_button_tooltip")));
get_custom_label_from_label_with_image(&self.buttons_manual_add_included_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_manual_add_included_button"));
get_custom_label_from_label_with_image(&self.buttons_add_included_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_add_included_button"));
get_custom_label_from_label_with_image(&self.buttons_remove_included_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_remove_included_button"));
get_custom_label_from_label_with_image(&self.buttons_manual_add_excluded_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_manual_add_excluded_button"));
get_custom_label_from_label_with_image(&self.buttons_add_excluded_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_add_excluded_button"));
get_custom_label_from_label_with_image(&self.buttons_remove_excluded_directory.clone().upcast::<Bin>()).set_text(&fl!("upper_remove_excluded_button"));
self.buttons_manual_add_included_directory.set_tooltip_text(Some(&fl!("upper_manual_add_included_button_tooltip")));
self.buttons_add_included_directory.set_tooltip_text(Some(&fl!("upper_add_included_button_tooltip")));
self.buttons_remove_included_directory.set_tooltip_text(Some(&fl!("upper_remove_included_button_tooltip")));
self.buttons_manual_add_excluded_directory.set_tooltip_text(Some(&fl!("upper_manual_add_excluded_button_tooltip")));
self.buttons_add_excluded_directory.set_tooltip_text(Some(&fl!("upper_add_excluded_button_tooltip")));
self.buttons_remove_excluded_directory.set_tooltip_text(Some(&fl!("upper_remove_excluded_button_tooltip")));
self.label_allowed_extensions.set_tooltip_text(Some(&fl!("upper_allowed_extensions_tooltip")));
self.entry_allowed_extensions.set_tooltip_text(Some(&fl!("upper_allowed_extensions_tooltip")));
self.label_excluded_items.set_tooltip_text(Some(&fl!("upper_excluded_items_tooltip")));
self.entry_excluded_items.set_tooltip_text(Some(&fl!("upper_excluded_items_tooltip")));
self.label_excluded_items.set_label(&fl!("upper_excluded_items"));
self.label_allowed_extensions.set_label(&fl!("upper_allowed_extensions"));
let vec_children: Vec<gtk::Widget> = self.notebook_upper.children();
for (upper_enum, fl_thing) in [
(NotebookUpperEnum::ItemsConfiguration as usize, fl!("upper_notebook_items_configuration")),
(NotebookUpperEnum::ExcludedDirectories as usize, fl!("upper_notebook_excluded_directories")),
(NotebookUpperEnum::IncludedDirectories as usize, fl!("upper_notebook_included_directories")),
] {
self.notebook_upper.tab_label(&vec_children[upper_enum]).unwrap().downcast::<gtk::Label>().unwrap().set_text(&fl_thing);
}
}
}

@ -1,82 +0,0 @@
use gtk::prelude::*;
use gtk::{EventControllerKey, TreeView};
#[derive(Clone)]
pub struct GuiUpperNotebook {
pub notebook_upper: gtk::Notebook,
pub scrolled_window_included_directories: gtk::ScrolledWindow,
pub scrolled_window_excluded_directories: gtk::ScrolledWindow,
pub tree_view_included_directories: gtk::TreeView,
pub tree_view_excluded_directories: gtk::TreeView,
pub evk_tree_view_included_directories: gtk::EventControllerKey,
pub evk_tree_view_excluded_directories: gtk::EventControllerKey,
pub entry_excluded_items: gtk::Entry,
pub entry_allowed_extensions: gtk::Entry,
pub check_button_recursive: gtk::CheckButton,
pub buttons_manual_add_directory: gtk::Button,
pub buttons_add_included_directory: gtk::Button,
pub buttons_remove_included_directory: gtk::Button,
pub buttons_manual_add_excluded_directory: gtk::Button,
pub buttons_add_excluded_directory: gtk::Button,
pub buttons_remove_excluded_directory: gtk::Button,
}
impl GuiUpperNotebook {
pub fn create_from_builder(builder: &gtk::Builder) -> Self {
let notebook_upper: gtk::Notebook = builder.object("notebook_upper").unwrap();
let scrolled_window_included_directories: gtk::ScrolledWindow = builder.object("scrolled_window_included_directories").unwrap();
let scrolled_window_excluded_directories: gtk::ScrolledWindow = builder.object("scrolled_window_excluded_directories").unwrap();
let tree_view_included_directories: gtk::TreeView = TreeView::new();
let tree_view_excluded_directories: gtk::TreeView = TreeView::new();
let evk_tree_view_included_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_included_directories);
let evk_tree_view_excluded_directories: gtk::EventControllerKey = EventControllerKey::new(&tree_view_excluded_directories);
let entry_allowed_extensions: gtk::Entry = builder.object("entry_allowed_extensions").unwrap();
let entry_excluded_items: gtk::Entry = builder.object("entry_excluded_items").unwrap();
let check_button_recursive: gtk::CheckButton = builder.object("check_button_recursive").unwrap();
check_button_recursive.set_tooltip_text(Some("If selected, search also for files which are not placed directly under chosen folders"));
let buttons_manual_add_directory: gtk::Button = builder.object("buttons_manual_add_directory").unwrap();
let buttons_add_included_directory: gtk::Button = builder.object("buttons_add_included_directory").unwrap();
let buttons_remove_included_directory: gtk::Button = builder.object("buttons_remove_included_directory").unwrap();
let buttons_manual_add_excluded_directory: gtk::Button = builder.object("buttons_manual_add_excluded_directory").unwrap();
let buttons_add_excluded_directory: gtk::Button = builder.object("buttons_add_excluded_directory").unwrap();
let buttons_remove_excluded_directory: gtk::Button = builder.object("buttons_remove_excluded_directory").unwrap();
buttons_manual_add_directory.set_tooltip_text(Some("Allows to add directory name by hand"));
buttons_add_included_directory.set_tooltip_text(Some("Add new directory to search"));
buttons_remove_included_directory.set_tooltip_text(Some("Delete directory from search"));
buttons_manual_add_excluded_directory.set_tooltip_text(Some("Allows to add directory name by hand"));
buttons_add_excluded_directory.set_tooltip_text(Some("Add directory to be excluded in search"));
buttons_remove_excluded_directory.set_tooltip_text(Some("Delete directory from excluded list"));
Self {
notebook_upper,
scrolled_window_included_directories,
scrolled_window_excluded_directories,
tree_view_included_directories,
tree_view_excluded_directories,
evk_tree_view_included_directories,
evk_tree_view_excluded_directories,
entry_excluded_items,
entry_allowed_extensions,
check_button_recursive,
buttons_manual_add_directory,
buttons_add_included_directory,
buttons_remove_included_directory,
buttons_manual_add_excluded_directory,
buttons_add_excluded_directory,
buttons_remove_excluded_directory,
}
}
}

@ -541,3 +541,14 @@ pub fn clean_invalid_headers(model: &gtk::ListStore, column_color: i32) {
}
}
}
// TODO children are not available in GTK 4
pub fn get_custom_label_from_label_with_image(button: &gtk::Bin) -> gtk::Label {
let internal_box = button.child().unwrap().downcast::<gtk::Box>().unwrap();
for child in internal_box.children() {
if let Ok(t) = child.downcast::<gtk::Label>() {
return t;
}
}
panic!("Button doesn't have proper custom label child");
}

@ -18,6 +18,7 @@ use crate::create_tree_view::*;
use crate::delete_things;
use crate::gui_data::*;
use crate::help_functions::*;
use crate::language_functions::LANGUAGES_ALL;
use crate::notebook_enums::NotebookMainEnum;
use crate::opening_selecting_records::*;
@ -41,6 +42,14 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
buttons_hardlink.hide();
buttons_move.hide();
}
//// Initialize language combobox
{
let combo_box_settings_language = gui_data.settings.combo_box_settings_language.clone();
for lang in LANGUAGES_ALL {
combo_box_settings_language.append_text(lang.combo_box_text);
}
combo_box_settings_language.set_active(Some(0));
}
//// Initialize main scrolled view with notebook
{

@ -0,0 +1,26 @@
#[derive(Clone)]
pub struct Language {
pub combo_box_text: &'static str,
pub short_text: &'static str,
}
pub const LANGUAGES_ALL: [Language; 2] = [
Language {
combo_box_text: "English (en)",
short_text: "en",
},
Language {
combo_box_text: "Polski (pl)",
short_text: "pl",
},
];
pub fn get_language_from_combo_box_text(combo_box_text: String) -> Language {
for lang in LANGUAGES_ALL {
if lang.combo_box_text == combo_box_text {
return lang;
}
}
panic!("Not found proper text");
}

@ -16,6 +16,7 @@ use crate::connect_button_save::*;
use crate::connect_button_search::*;
use crate::connect_button_select::*;
use crate::connect_button_stop::*;
use crate::connect_change_language::*;
use crate::connect_duplicate_buttons::*;
use crate::connect_header_buttons::*;
use crate::connect_notebook_tabs::*;
@ -39,6 +40,7 @@ mod connect_button_save;
mod connect_button_search;
mod connect_button_select;
mod connect_button_stop;
mod connect_change_language;
mod connect_duplicate_buttons;
mod connect_header_buttons;
mod connect_notebook_tabs;
@ -57,9 +59,10 @@ mod gui_main_notebook;
mod gui_popovers;
mod gui_progress_dialog;
mod gui_settings;
mod gui_upper_notepad;
mod gui_upper_notebook;
mod help_functions;
mod initialize_gui;
mod language_functions;
mod notebook_enums;
mod opening_selecting_records;
mod saving_loading;
@ -101,6 +104,9 @@ fn main() {
reset_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors); // Fallback for invalid loading setting project
load_configuration(false, &gui_data.upper_notebook, &gui_data.settings, &gui_data.text_view_errors, &gui_data.scrolled_window_errors);
// Needs to run when entire GUI is initialized and
connect_change_language(&gui_data);
connect_button_delete(&gui_data);
connect_button_save(&gui_data);
connect_button_search(

@ -1,5 +1,5 @@
pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 10;
pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 4;
// pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 3;
// Needs to be updated when changed order of notebook tabs
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
@ -51,20 +51,18 @@ pub fn get_all_main_tabs() -> [NotebookMainEnum; NUMBER_OF_NOTEBOOK_MAIN_TABS] {
pub enum NotebookUpperEnum {
IncludedDirectories = 0,
ExcludedDirectories,
ExcludedItems,
AllowedExtensions,
ItemsConfiguration,
}
pub fn to_notebook_upper_enum(notebook_number: u32) -> NotebookUpperEnum {
match notebook_number {
0 => NotebookUpperEnum::IncludedDirectories,
1 => NotebookUpperEnum::ExcludedDirectories,
2 => NotebookUpperEnum::ExcludedItems,
3 => NotebookUpperEnum::AllowedExtensions,
_ => panic!("Invalid Upper Notebook Tab"),
}
}
pub fn get_all_upper_tabs() -> [NotebookUpperEnum; NUMBER_OF_NOTEBOOK_UPPER_TABS] {
[to_notebook_upper_enum(0), to_notebook_upper_enum(1), to_notebook_upper_enum(2), to_notebook_upper_enum(3)]
}
// pub fn to_notebook_upper_enum(notebook_number: u32) -> NotebookUpperEnum {
// match notebook_number {
// 0 => NotebookUpperEnum::IncludedDirectories,
// 1 => NotebookUpperEnum::ExcludedDirectories,
// 2 => NotebookUpperEnum::ItemsConfiguration,
// _ => panic!("Invalid Upper Notebook Tab"),
// }
// }
//
// pub fn get_all_upper_tabs() -> [NotebookUpperEnum; NUMBER_OF_NOTEBOOK_UPPER_TABS] {
// [to_notebook_upper_enum(0), to_notebook_upper_enum(1), to_notebook_upper_enum(2)]
// }

@ -3,13 +3,15 @@ use std::io::Write;
use std::path::Path;
use std::{env, fs};
use czkawka_core::fl;
use directories_next::ProjectDirs;
use gtk::prelude::*;
use gtk::{ScrolledWindow, TextView};
use crate::gui_settings::GuiSettings;
use crate::gui_upper_notepad::GuiUpperNotebook;
use crate::gui_upper_notebook::GuiUpperNotebook;
use crate::help_functions::*;
use crate::language_functions::{get_language_from_combo_box_text, LANGUAGES_ALL};
// TODO organize this better, add specific functions that will allow to load from files specific strings
const SAVE_FILE_NAME: &str = "czkawka_gui_config.txt";
@ -167,6 +169,11 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
data_to_save.push("--cache_prehash_minimal_file_size:".to_string());
let entry_settings_prehash_cache_file_minimal_size = settings.entry_settings_prehash_cache_file_minimal_size.clone();
data_to_save.push(entry_settings_prehash_cache_file_minimal_size.text().as_str().parse::<u64>().unwrap_or(0).to_string());
//// language
data_to_save.push("--language:".to_string());
let combo_box_settings_language = settings.combo_box_settings_language.clone();
data_to_save.push(get_language_from_combo_box_text(combo_box_settings_language.active_text().unwrap().to_string()).short_text.to_string());
}
// Creating/Opening config file
@ -194,7 +201,7 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
}
}
if data_saved {
add_text_to_text_view(&text_view_errors, format!("Saved configuration to file {}", config_file.display()).as_str());
add_text_to_text_view(&text_view_errors, format!("{} {}", fl!("saving_loading_saving_success"), config_file.display()).as_str());
} else {
add_text_to_text_view(&text_view_errors, format!("Failed to save configuration data to file {}", config_file.display()).as_str());
}
@ -225,6 +232,7 @@ enum TypeOfLoadedData {
DeleteCacheSimilarVideos,
UsePrehashCache,
CachePrehashMinimalSize,
Language,
}
pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNotebook, settings: &GuiSettings, text_view_errors: &TextView, scrolled_window_errors: &ScrolledWindow) {
@ -278,6 +286,7 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
let mut delete_outdated_cache_similar_videos: bool = false;
let mut use_prehash_cache: bool = false;
let mut cache_prehash_minimal_size: u64 = 0;
let mut short_language: String = "en".to_string();
let mut current_type = TypeOfLoadedData::None;
for (line_number, line) in loaded_data.replace("\r\n", "\n").split('\n').enumerate() {
@ -325,6 +334,8 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
current_type = TypeOfLoadedData::UsePrehashCache;
} else if line.starts_with("--cache_prehash_minimal_file_size") {
current_type = TypeOfLoadedData::CachePrehashMinimalSize;
} else if line.starts_with("--language") {
current_type = TypeOfLoadedData::Language;
} else if line.starts_with("--") {
current_type = TypeOfLoadedData::None;
add_text_to_text_view(
@ -553,6 +564,16 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
);
}
}
TypeOfLoadedData::Language => {
if LANGUAGES_ALL.iter().any(|e| e.short_text == line) {
short_language = line;
} else {
add_text_to_text_view(
&text_view_errors,
format!("Found invalid data in line {} \"{}\" isn't proper language value when loading file {:?}", line_number, line, config_file).as_str(),
);
}
}
}
}
}
@ -587,6 +608,15 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
let entry_allowed_extensions = upper_notebook.entry_allowed_extensions.clone();
entry_allowed_extensions.set_text(allowed_extensions.iter().map(|e| e.to_string() + ",").collect::<String>().as_str());
//// ComboText
{
for (index, lang) in LANGUAGES_ALL.iter().enumerate() {
if short_language == lang.short_text {
settings.combo_box_settings_language.set_active(Some(index as u32));
}
}
}
//// Buttons
settings.check_button_settings_load_at_start.set_active(loading_at_start);
settings.check_button_settings_save_at_exit.set_active(saving_at_exit);
@ -616,7 +646,7 @@ pub fn load_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb
}
if manual_execution {
add_text_to_text_view(&text_view_errors, format!("Properly loaded configuration from file {:?}", config_file).as_str());
add_text_to_text_view(&text_view_errors, format!("{} {:?}", &fl!("saving_loading_reset_configuration"), config_file).as_str());
}
} else {
add_text_to_text_view(&text_view_errors, "Failed to get home directory, so can't load file.");
@ -699,8 +729,9 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb
settings.check_button_settings_duplicates_delete_outdated_cache.set_active(true);
settings.check_button_duplicates_use_prehash_cache.set_active(false);
settings.entry_settings_prehash_cache_file_minimal_size.set_text("0");
settings.combo_box_settings_language.set_active(Some(0));
}
if manual_clearing {
add_text_to_text_view(&text_view_errors, "Current configuration was cleared.");
add_text_to_text_view(&text_view_errors, &fl!("saving_loading_reset_configuration"));
}
}

@ -158,7 +158,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkButton" id="buttons_manual_add_directory">
<object class="GtkButton" id="buttons_manual_add_included_directory">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
@ -442,40 +442,8 @@ Author: Rafał Mikrut
<object class="GtkBox" id="notebook_upper_excluded_items">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Excluded items must contains * wildcard and should be separated by commas.</property>
<attributes>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">This is slower than Excluded Directories, so use it carefully.</property>
<attributes>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@ -484,7 +452,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_excluded_items">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Excluded items</property>
@ -514,76 +482,6 @@ Author: Rafał Mikrut
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Excluded Items</property>
</object>
<packing>
<property name="position">2</property>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox" id="notebook_upper_allowed_extensions">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Allowed extensions must be separated by commas(by default all are available)</property>
<attributes>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Macros IMAGE, VIDEO, MUSIC, TEXT are available</property>
<attributes>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Usage example ".exe, IMAGE, VIDEO, .rar, 7z"</property>
<attributes>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@ -592,7 +490,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_allowed_extensions">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Allowed Extensions</property>
@ -623,17 +521,17 @@ Author: Rafał Mikrut
</child>
</object>
<packing>
<property name="position">3</property>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Allowed Extensions</property>
<property name="label" translatable="yes">Items Configuration</property>
</object>
<packing>
<property name="position">3</property>
<property name="position">2</property>
<property name="tab-fill">False</property>
</packing>
</child>
@ -666,7 +564,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="margin-top">2</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_duplicate_check_method">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Check method:</property>
@ -736,7 +634,7 @@ Author: Rafał Mikrut
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_duplicate_hash_type">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Hash type:</property>
@ -808,7 +706,7 @@ Author: Rafał Mikrut
<property name="margin-top">2</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_duplicate_size_bytes">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Size(bytes)</property>
@ -820,7 +718,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_duplicate_min_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Min:</property>
@ -847,7 +745,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_duplicate_max_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Max:</property>
@ -967,7 +865,7 @@ Author: Rafał Mikrut
<property name="margin-top">2</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_big_shown_files">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Number of shown files</property>
@ -1096,7 +994,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="margin-top">2</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_resize_algorithm">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Resize algorithm:</property>
@ -1200,7 +1098,7 @@ Author: Rafał Mikrut
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_hash_type">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Hash type:</property>
@ -1304,7 +1202,7 @@ Author: Rafał Mikrut
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_hash_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Hash size:</property>
@ -1391,7 +1289,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_size_bytes">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Size(bytes)</property>
@ -1403,7 +1301,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_min_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Min:</property>
@ -1430,7 +1328,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_max_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Max:</property>
@ -1485,7 +1383,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="margin-bottom">2</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_similarity">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Similarity </property>
@ -1497,7 +1395,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_image_similarity_max">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes"> Very High </property>
@ -1527,7 +1425,9 @@ Author: Rafał Mikrut
<object class="GtkLabel" id="label_similar_images_minimal_similarity">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes"> Minimal </property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="label" translatable="yes">Minimal</property>
</object>
<packing>
<property name="expand">False</property>
@ -1609,7 +1509,7 @@ Author: Rafał Mikrut
<property name="margin-top">2</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_size_bytes">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Size(bytes)</property>
@ -1621,7 +1521,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_min_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Min:</property>
@ -1648,7 +1548,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_max_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Max:</property>
@ -1689,7 +1589,7 @@ Author: Rafał Mikrut
<property name="margin-end">5</property>
<property name="margin-bottom">2</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_similarity">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Similarity </property>
@ -1701,7 +1601,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_similarity_max">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes"> Very High </property>
@ -1728,10 +1628,12 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_video_similarity_min">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes"> Minimal </property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="label" translatable="yes">Minimal</property>
</object>
<packing>
<property name="expand">False</property>
@ -1791,7 +1693,7 @@ Author: Rafał Mikrut
<property name="margin-top">2</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_music_size_bytes">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Size(bytes)</property>
@ -1803,7 +1705,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_music_min_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Min:</property>
@ -1830,7 +1732,7 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_music_max_size">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Max:</property>

@ -78,7 +78,8 @@ Author: Rafał Mikrut
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_progress_all_stages">
<property name="name">label_progress_all_stages</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">All stages: </property>
@ -102,7 +103,8 @@ Author: Rafał Mikrut
</packing>
</child>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_progress_current_stage">
<property name="name">label_progress_current_stage</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Current stage: </property>

@ -102,6 +102,42 @@ Author: Rafał Mikrut
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel" id="label_settings_general_language">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">10</property>
<property name="label" translatable="yes">Language</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="combo_box_settings_language">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="check_button_settings_load_at_start">
<property name="label" translatable="yes">Load configuration at start</property>
@ -114,7 +150,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="position">1</property>
</packing>
</child>
<child>
@ -129,7 +165,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
<child>
@ -144,7 +180,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
@ -159,7 +195,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
<child>
@ -174,7 +210,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
<property name="position">5</property>
</packing>
</child>
<child>
@ -189,7 +225,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
<property name="position">6</property>
</packing>
</child>
<child>
@ -204,7 +240,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
<property name="position">7</property>
</packing>
</child>
<child>
@ -219,7 +255,7 @@ Author: Rafał Mikrut
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
<property name="position">8</property>
</packing>
</child>
</object>
@ -334,12 +370,10 @@ Author: Rafał Mikrut
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-left">4</property>
<property name="margin-right">4</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_settings_duplicate_minimal_size_cache">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Minimal size of files in bytes saved to cache</property>
@ -405,12 +439,10 @@ Author: Rafał Mikrut
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-left">4</property>
<property name="margin-right">4</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<child>
<object class="GtkLabel">
<object class="GtkLabel" id="label_settings_duplicate_minimal_size_cache_prehash">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Minimal size of files in bytes saved to prehash cache</property>
@ -585,8 +617,6 @@ Author: Rafał Mikrut
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-left">3</property>
<property name="margin-right">3</property>
<property name="margin-start">3</property>
<property name="margin-end">3</property>
<property name="spacing">3</property>

@ -0,0 +1,13 @@
# (Required) The language identifier of the language used in the
# source code for gettext system, and the primary fallback language
# (for which all strings must be present) when using the fluent
# system.
fallback_language = "en"
# Use the fluent localization system.
[fluent]
# (Required) The path to the assets directory.
# The paths inside the assets directory should be structured like so:
# `assets_dir/{language}/{domain}.ftl`
assets_dir = "i18n"

@ -0,0 +1 @@
czkawka_gui.ftl

@ -0,0 +1,379 @@
# Core
core_similarity_very_high = Very High
core_similarity_high = High
core_similarity_medium = Medium
core_similarity_small = Small
core_similarity_very_small = Very Small
core_similarity_minimal = Minimal
# General
general_ok_button = Ok
general_close_button = Close
general_bytes = bytes
general_lost = lost
# Main window
music_title_checkbox = Title
music_artist_checkbox = Artist
music_album_title_checkbox = Album Title
music_album_artist_checkbox = Album Artist
music_year_checkbox = Year
music_comparison_checkbox = Approximate Comparison
duplicate_mode_name_checkbox = Name
duplicate_mode_size_checkbox = Size
duplicate_mode_hash_checkbox = Hash
duplicate_mode_name_checkbox_tooltip =
Finds files which have same name.
This mode not checking what file contain inside, so be carefully when using it.
duplicate_mode_size_checkbox_tooltip =
Finds files which have same size.
This mode not checking what file contain inside, so be carefully when using it.
duplicate_mode_hash_checkbox_tooltip =
Finds files which have the same content.
This mode hashes file and later compare this hashes to find duplicates.
Tool heavily uses cache, so second and further scans of same data should be a lot of faster that first.
duplicate_hash_checkbox_blake3 = Blake3 is cryptographic hash function. It is used as default hash algorithm, because it is very fast.
duplicate_hash_checkbox_crc32 = CRC32 is simple hash function. It should be faster than Blake3, but probably may have very rarely some collisions.
duplicate_hash_checkbox_xxh3 = XXH3 is very similar in case of performance and hash quality to Blake3, so such modes can be easily used.
image_hash_checkbox_8 = Default hash size, with very high similarity it produce quite good results and don't save too much data too cache.
image_hash_checkbox_16 = More precise than 8, so can be used to find very similar pictures, but create bigger cache entries.
image_hash_checkbox_32 = Hash of this size provide very big similarity which is more than enough for most usages.
image_hash_checkbox_64 = Paranoid mode, such tool create really big cache files and will catch almost same images.
main_notebook_duplicates = Duplicate Files
main_notebook_empty_directories = Empty Directories
main_notebook_big_files = Big Files
main_notebook_empty_files = Empty Files
main_notebook_temporary = Temporary Files
main_notebook_similar_images = Similar Images
main_notebook_similar_videos = Similar Videos
main_notebook_same_music = Music Duplicates
main_notebook_symlinks = Invalid Symlinks
main_notebook_broken_files = Broken Files
main_tree_view_column_file_name = File Name
main_tree_view_column_folder_name = Folder Name
main_tree_view_column_path = Path
main_tree_view_column_modification = Modification Date
main_tree_view_column_size = Size
main_tree_view_column_similarity = Similarity
main_tree_view_column_dimensions = Dimensions
main_tree_view_column_title = Title
main_tree_view_column_artist = Artist
main_tree_view_column_year = Year
main_tree_view_column_album_title = Album Title
main_tree_view_column_album_artist = Album Artist
main_tree_view_column_symlink_file_name = Symlink File Name
main_tree_view_column_symlink_folder = Symlnik Folder
main_tree_view_column_destination_path = Destination Path
main_tree_view_column_type_of_error = Type Of Error
main_label_check_method = Check method:
main_label_hash_type = Hash type:
main_label_hash_size = Hash size:
main_label_size_bytes = Size(bytes)
main_label_min_size = Min:
main_label_max_size = Max:
main_label_shown_files = Number of shown files:
main_label_resize_algorithm = Resize algorithm:
main_label_similarity = Similarity{" "}
# Upper window
upper_recursive_button = Recursive
upper_recursive_button_tooltip = If selected, search also for files which are not placed directly under chosen folders
upper_manual_add_included_button = Manual Add
upper_add_included_button = Add
upper_remove_included_button = Remove
upper_manual_add_excluded_button = Manual Add
upper_add_excluded_button = Add
upper_remove_excluded_button = Remove
upper_manual_add_included_button_tooltip = Allows to add directory name to search by hand
upper_add_included_button_tooltip = Add new directory to search
upper_remove_included_button_tooltip = Delete directory from search
upper_manual_add_excluded_button_tooltip = Allows to add excluded directory name by hand
upper_add_excluded_button_tooltip = Add directory to be excluded in search
upper_remove_excluded_button_tooltip = Delete directory from excluded
upper_notebook_items_configuration = Items Configuration
upper_notebook_excluded_directories = Excluded Directories
upper_notebook_included_directories = Included Directories
upper_allowed_extensions_tooltip =
Allowed extensions must be separated by commas(by default all are available)
Macros IMAGE, VIDEO, MUSIC, TEXT which adds multiple extensions at once are also available.
Usage example ".exe, IMAGE, VIDEO, .rar, 7z" - this means that image(e.g. jpg, png), video(e.g. avi, mp4), exe, rar and 7z files will be scanned.
upper_excluded_items_tooltip =
Excluded items must contains * wildcard and should be separated by commas.
This is slower than Excluded Directories, so use it carefully.
upper_excluded_items = Excluded Items:
upper_allowed_extensions = Allowed Extensions:
# Popovers
popover_select_all = Select all
popover_unselect_all = Unselect all
popover_reverse = Reverse Selection
popover_select_all_except_oldest = Select all except oldest
popover_select_all_except_newest = Select all except newest
popover_select_one_oldest = Select one oldest
popover_select_one_newest = Select one newest
popover_select_custom = Select custom
popover_unselect_custom = Unselect custom
popover_select_all_images_except_biggest = Select all except biggest
popover_select_all_images_except_smallest = Select all except smallest
popover_custom_path_check_button_entry_tooltip =
Allows to select records by its path.
Example usage:
/home/pimpek/rzecz.txt can be found with /home/pim*
popover_custom_name_check_button_entry_tooltip =
Allows to select records by file names.
Example usage:
/usr/ping/pong.txt can be found with *ong*
popover_custom_regex_check_button_entry_tooltip =
Allows to select records by specified Regex.
With this mode, searched text is Path with Name
Example usage:
/usr/bin/ziemniak.txt can be found with /ziem[a-z]+
This use default Rust regex implementation, so you can read more about it in https://docs.rs/regex.
popover_custom_not_all_check_button_tooltip =
Prevents from selecting all records in group.
This is enabled by default, because in most of situations user don't want to delete both original and duplicates files, but want to leave at least one file.
Warning: This setting don't work if already user selected all results in group manually.
popover_custom_regex_path_label = Path
popover_custom_regex_name_label = Name
popover_custom_regex_regex_label = Regex Path + Name
popover_custom_all_in_group_label = Don't select all records in group
popover_custom_mode_unselect = Unselect Custom
popover_custom_mode_select = Select Custom
popover_invalid_regex = Regex is invalid
popover_valid_regex = Regex is valid
# Bottom buttons
bottom_search_button = Search
bottom_select_button = Select
bottom_delete_button = Delete
bottom_save_button = Save
bottom_symlink_button = Symlink
bottom_hardlink_button = Hardlink
bottom_move_button = Move
bottom_search_button_tooltip = Start to search for files/folders
bottom_select_button_tooltip = Selects records. Only selected files/folders can be later processed.
bottom_delete_button_tooltip = Delete selected files/folders
bottom_save_button_tooltip = Save data about search to file
bottom_symlink_button_tooltip =
Creates symbolic links.
Only works when at least 2 results in group are selected.
First is unchanged and second and later are symlinked to first.
bottom_hardlink_button_tooltip =
Creates hardlinks.
Only works when at least 2 results in group are selected.
First is unchanged and second and later are hardlinked to first.
bottom_move_button_tooltip =
Moves files to chosen folder.
It copy all files to folder without preserving directory tree.
When trying to move 2 files with identical name to folder, second will fail and show error.
bottom_show_errors_tooltip = Show/Hide bottom error panel.
bottom_show_upper_notebook_tooltip = Show/Hide upper notebook panel.
# Progress Window
progress_stop_button = Stop
# About Window
about_repository_button_tooltip = Link to repository page with source code.
about_donation_button_tooltip = Link to donation page.
about_instruction_button_tooltip = Link to instruction page.
about_repository_button = Repository
about_donation_button = Donation
about_instruction_button = Instruction
# Header
header_setting_button_tooltip = Opens settings dialog.
header_about_button_tooltip = Opens dialog with info about app.
# Settings
## General
settings_save_at_exit_button_tooltip = Saves configuration to file when closing app.
settings_load_at_start_button_tooltip =
Loading at start configuration from file.
Not selecting this option will load default settings.
settings_confirm_deletion_button_tooltip = Shows confirmation dialog when clicking at delete button.
settings_confirm_link_button_tooltip = Shows confirmation dialog when clicking at hard/symlink button.
settings_confirm_group_deletion_button_tooltip = Shows dialog when trying to remove all records from group.
settings_show_text_view_button_tooltip = Shows error panel at bottom.
settings_use_cache_button_tooltip = Option to which allows to not use cache feature.
settings_use_trash_button_tooltip = When enabled it moves files to trash instead deleting them permanently.
settings_language_label_tooltip = Allows to choose language of interface from available ones.
settings_save_at_exit_button = Save configuration at exit
settings_load_at_start_button = Load configuration at start
settings_confirm_deletion_button = Show confirm dialog when deleting any files
settings_confirm_link_button = Show confirm dialog when hard/symlinks any files
settings_confirm_group_deletion_button = Show confirm dialog when deleting all files in group
settings_show_text_view_button = Show bottom text panel
settings_use_cache_button = Use cache
settings_use_trash_button = Move deleted files to trash
settings_language_label = Language
settings_multiple_delete_outdated_cache_checkbutton = Delete outdated cache entries automatically
settings_multiple_delete_outdated_cache_checkbutton_tooltip =
Allows to delete outdated cache results which points to non-existent files.
When enabled, app make sure when loading records, that all points to valid files and ignore broken ones.
Disabling this option, will help to scan files on external drives, so cache entries about them will not be purged in next scan.
In case of having hundred of thousands records in cache, it is suggested to enable this option, to speedup cache loading and saving at start and end of scan.
## Multiple - settings used in multiple tabs
settings_multiple_delete_outdated_cache_checkbutton = Delete outdated cache entries automatically
settings_multiple_delete_outdated_cache_checkbutton_tooltip =
Allows to delete outdated cache results which points to non-existent files.
When enabled, app make sure when loading records, that all points to valid files and ignore broken ones.
Disabling this option, will help to scan files on external drives, so cache entries about them will not be purged in next scan.
In case of having hundred of thousands records in cache, it is suggested to enable this option, to speedup cache loading and saving at start and end of scan.
settings_multiple_image_preview_checkbutton_tooltip = Shows preview at right side, when selecting image file.
settings_multiple_image_preview_checkbutton = Show image preview
settings_multiple_clear_cache_button_tooltip =
Manually clear cache from outdated entries.
Should be used only if automatic clearing was disabled.
settings_multiple_clear_cache_button = Remove outdated results from images cache
## Duplicates
settings_duplicates_hide_hard_link_button_tooltip =
Hides all files except one, if are points to same data(are hardlinked).
E.g. in case where on disk there is 7 files which are hardlinked to specific data and one different file with same data but different inode, then in duplicate finder will be visible only one unique file and one file from hardlinked ones.
settings_duplicates_minimal_size_entry_tooltip =
Allows to set minimal size of file, which will be cached.
Choosing smaller value, will generate more records which will speedup search, but slowdown cache loading/saving.
settings_duplicates_prehash_checkbutton_tooltip =
Enables caching of prehash(hash computed from small part of file) which allows to earlier throw out non duplicated results.
It is disabled by default because can cause in some situations slowdowns.
It is heavily recommended to use it when scanning hundred of thousands or million files, because it can speedup search multiple times.
settings_duplicates_prehash_minimal_entry_tooltip = Minimal size of cached entry.
settings_duplicates_hide_hard_link_button = Hide hard links(only Linux and MacOS)
settings_duplicates_prehash_checkbutton = Use prehash cache
settings_duplicates_minimal_size_cache_label = Minimal size of files in bytes saved to cache
settings_duplicates_minimal_size_cache_prehash_label = Minimal size of files in bytes saved to prehash cache
## Saving/Loading settings
settings_saving_button_tooltip = Save current settings configuration to file.
settings_loading_button_tooltip = Load settings from file and replace current configuration with them.
settings_reset_button_tooltip = Reset current configuration to default one.
settings_saving_button = Save configuration
settings_loading_button = Load configuration
settings_reset_button = Reset configuration
## Opening cache/config folders
settings_folder_cache_open_tooltip =
Opens folder where are stored txt files with cache.
Modifying them may cause to show invalid results but also modifying e.g. path may save time when moving big amount of files to different place.
You can copy this files between computers to save time on scanning again for files(of course if they have similar directory structure).
In case of problems with cache, this files can be removed, so app will automatically regenerate them.
settings_folder_settings_open_tooltip =
Opens folder where Czkawka config are stored.
Modifying them by hand, may cause to break your workflow.
settings_folder_cache_open = Open cache folder
settings_folder_settings_open = Open settings folder
# Compute results
compute_stopped_by_user = Searching was stopped by user
compute_found = Found
compute_duplicated_files_in = duplicated files in
compute_groups_which_took = groups which took
compute_groups = groups
compute_duplicates_for = duplicates for
compute_empty_folders = empty folders
compute_empty_files = empty files
compute_biggest_files = biggest files
compute_temporary_files = temporary files
compute_similar_image = images
compute_similar_videos = videos
compute_music_files = music files
compute_symlinks = invalid symlinks
compute_broken_files = broken files
# Progress window
progress_scanned = Scanned
progress_files = file
progress_folders = folders
progress_tags = Reading tags of
progress_hashing = Hashing
progress_checking = Checking
progress_size = size
progress_name = name
progress_analyzed_full_hash = Analyzed full hash of
progress_analyzed_partial_hash = Analyzed partial hash of
# Saving loading
saving_loading_saving_success = Saved configuration to file
saving_loading_reset_configuration = Current configuration was cleared.
saving_loading_loading_success = Properly loaded configuration from file
progress_current_stage = Current Stage:{" "}
progress_all_stages = All Stages:{" "}
# Other
searching_for_data = Searching data, it may take a while, please wait...

@ -0,0 +1 @@
czkawka_gui.ftl

@ -0,0 +1,366 @@
# Core
core_similarity_very_high = Bardzo Duże
core_similarity_high = Duże
core_similarity_medium = Średnie
core_similarity_small = Małe
core_similarity_very_small = Bardzo Małe
core_similarity_minimal = Minimalne
# Różne
general_ok_button = Ok
general_close_button = Zamknij
general_bytes = bajtów
general_lost = zaprzepaszczono
# Główne okno(środek)
music_title_checkbox = Tytuł
music_artist_checkbox = Wykonawca
music_album_title_checkbox = Tytuł Albumu
music_album_artist_checkbox = Wykonawca Albumu
music_year_checkbox = Rok
music_comparison_checkbox = Przybliżone Porównywanie
duplicate_mode_name_checkbox = Nazwa
duplicate_mode_size_checkbox = Rozmiar
duplicate_mode_hash_checkbox = Hash
duplicate_mode_name_checkbox_tooltip =
Służy do znajdowania plików o identycznych nazwach.
Ten tryb nie sprawdza zawartości pliku, dlatego należy uważać przy jego stosowaniu.
duplicate_mode_size_checkbox_tooltip =
Służy do znajdowania plików o identycznych rozmiarach.
Ten tryb nie sprawdza zawartości pliku, dlatego należy uważać przy jego stosowaniu.
duplicate_mode_hash_checkbox_tooltip =
Znajduje pliki z identyczną zawartością, bez względu na nazwę i rozszerzenie pliku.
W tym trybie, każdy plik jest hasowany a następnie każdy hash jest porównywany z innymi.
Ten tryb używa pamięci podręcznej do przechowywania raz obliczonych hashy, dlatego drugie i kolejne skanowanie, powinno być o wiele szybsze niż pierwsze.
duplicate_hash_checkbox_blake3 = Blake3 jest kryptograficzną funkcją haszującą. Z racji połączenia szybkości i niskiej ilości kolizji jest to domyślny tryb.
duplicate_hash_checkbox_crc32 = CRC32 to prosta funkcja haszująca. Powinna być szybsza niż Blake3, lecz bardzo rzadko może mogą wystąpić kolizje hashy.
duplicate_hash_checkbox_xxh3 = XXH3 zarówno pod względem jakości hashu jak i wydajności jest podobny do Blake3, dlatego te algorytmy mogą być używane wymiennie.
image_hash_checkbox_8 = Domyślna wielkość hasha, pozwala na wyszukanie obrazów od bardzo do minimalnie podobnych. Przy niższych poziomach podobieństwa, może grupować wiele niepodobnych obrazków.
image_hash_checkbox_16 = Bardziej precyzyjny od 8. Przydatny gdy ze względu na dużą ilość zdjęć i kolizji między hashami niższy hash wyświetla nieprawidłowe dane.
image_hash_checkbox_32 = Umożliwia wyszukiwanie niemal identycznych obrazów, różniących się niewielkimi szczegółami.
image_hash_checkbox_64 = Tryb predatora, tworzy ogromne hashe które porównywane, wczytywane i zapisywane znacznie dłużej od poprzedników. Z racji wad nie powinien być raczej stosowany.
main_notebook_duplicates = Duplikaty
main_notebook_empty_directories = Puste Katalogi
main_notebook_big_files = Duże Pliki
main_notebook_empty_files = Puste Pliki
main_notebook_temporary = Pliki Tymczasowe
main_notebook_similar_images = Podobne Obrazy
main_notebook_similar_videos = Podobne Wideo
main_notebook_same_music = Podobna Muzyka
main_notebook_symlinks = Niepoprawne Symlinki
main_notebook_broken_files = Zepsute Pliki
main_tree_view_column_file_name = Nazwa
main_tree_view_column_folder_name = Nazwa
main_tree_view_column_path = Ścieżka
main_tree_view_column_modification = Data Modyfikacji
main_tree_view_column_size = Rozmiar
main_tree_view_column_similarity = Podobieństwo
main_tree_view_column_dimensions = Wymiary
main_tree_view_column_title = Tytuł
main_tree_view_column_artist = Wykonawca
main_tree_view_column_year = Rok
main_tree_view_column_album_title = Tytuł Albumu
main_tree_view_column_album_artist = Wykonawca Albumu
main_tree_view_column_symlink_file_name = Nazwa Symlinka
main_tree_view_column_symlink_folder = Folder Symlinka
main_tree_view_column_destination_path = Docelowa Ścieżka
main_tree_view_column_type_of_error = Typ Błędu
main_label_check_method = Metoda sprawdzania:
main_label_hash_type = Typ hashu:
main_label_hash_size = Rozmiar hashu:
main_label_size_bytes = Rozmiar(bajty)
main_label_min_size = Min:
main_label_max_size = Max:
main_label_shown_files = Liczba wyświetlanych plików:
main_label_resize_algorithm = Algorytm zmiany rozmiaru:
main_label_similarity = Podobieństwo{" "}
# Górne okno
upper_recursive_button = Rekursywnie
upper_recursive_button_tooltip = Jeśli zaznaczony, szuka plików i folderów również w katalogach wewnątrz, nawet jeśli nie znajdują się one bezpośrednio w tym folderze.
upper_manual_add_included_button = Ręcznie Dodaj
upper_add_included_button = Dodaj
upper_remove_included_button = Usuń
upper_manual_add_excluded_button = Ręcznie Dodaj
upper_add_excluded_button = Dodaj
upper_remove_excluded_button = Usuń
upper_manual_add_included_button_tooltip = Pozwala ręcznie dodać foldery do skanowania
upper_add_included_button_tooltip = Dodaje wybrany folder do przeskanowania
upper_remove_included_button_tooltip = Usuwa zaznaczony folder z listy do przeskanowania
upper_manual_add_excluded_button_tooltip = Pozwala ręcznie dodać foldery do ignorowania
upper_add_excluded_button_tooltip = Dodaje wybrany folder do ignorowanych
upper_remove_excluded_button_tooltip = Usuwa zaznaczony folder z ignorowanych
upper_notebook_items_configuration = Konfiguracja Skanowania
upper_notebook_excluded_directories = Ignorowane Foldery
upper_notebook_included_directories = Przeszukiwane Foldery
upper_allowed_extensions_tooltip =
Dozwolone rozszerzenia muszą być oddzielone za pomocą przecinków - brak rozszerzeń oznacza ż wszystkie rozszerzenia są używane.
Makra IMAGE, VIDEO, MUSIC, TEXT które dodają rozrzerzenia w paczkach, również są wspierane
Przykładowe użycie ".exe, IMAGE, VIDEO, .rar, 7z" oznacza że obrazy(np. jpg, png), widea(np. avi, mp4) oraz pliki z roszerzeniami exe, rar i 7z będą przeskanowane
upper_excluded_items_tooltip =
Ignorowane obiekty mogą zawierać *(oznaczający dowolny ciąg znaków) i muszą być oddzielone za pomocą przecinków.
Działa o wiele wolniej niż Ignorowane Foldery, dlatego należy używać tego ostrożnie.
upper_excluded_items = Ignorowane Obiekty:
upper_allowed_extensions = Dozwolone Rozszerzenia:
# Zaznaczanie elementów
popover_select_all = Zaznacz wszystko
popover_unselect_all = Odznacz wszystko
popover_reverse = Odwróć zaznaczenie
popover_select_all_except_oldest = Zaznacz wszystkie oprócz najstarszego
popover_select_all_except_newest = Zaznacz wszystkie oprócz najnowszego
popover_select_one_oldest = Zaznacz jedno najstarsze
popover_select_one_newest = Zaznacz jedno najnowsze
popover_select_custom = Własne zaznaczanie
popover_unselect_custom = Własne odznaczanie
popover_select_all_images_except_biggest = Zaznacz wszystkie oprócz największego
popover_select_all_images_except_smallest = Zaznacz wszystkie oprócz najmniejszego
popover_custom_path_check_button_entry_tooltip =
Pozwala zaznaczać rekordy według ścieżki.
Przykładowe użycie:
/home/pimpek/rzecz.txt może zostać znalezione poprzez /home/pim*
popover_custom_name_check_button_entry_tooltip =
Pozwala zaznaczać rekordy według ścieżki.
Przykładowe użycie:
/usr/ping/pong.txt może zostać znalezione poprzez *ong*
popover_custom_regex_check_button_entry_tooltip =
Pozwala wyszukiwać rekordy za pomocą regexów.
W tym trybie przeszukiwanym tekstem jest pełna ścieżka(nazwa + ścieżka)
Example usage:
/usr/bin/ziemniak.txt może zostać znalezione with /ziem[a-z]+
Używana jest domyśla implementacja Rust regex o której użyciu można więcej przeczytać tutaj - https://docs.rs/regex.
popover_custom_not_all_check_button_tooltip =
Zapobiega przed zaznaczeniem wszystkich rekordów w danej grupie.
Tryb jest domyślnie aktywny, ponieważ w większości przypadków zaznaczenie wszystkich rekordów w grupie nie jest czymś czego oczekuje użytkownik.
Uwaga: To ustawienie nie powoduje pomija grupy w których to użytkownik wcześniej zaznaczył wszystkie rekordy ręcznie.
popover_custom_regex_path_label = Ścieżka
popover_custom_regex_name_label = Nazwa
popover_custom_regex_regex_label = Regex - Pełna ścieżka
popover_custom_all_in_group_label = Nie zaznaczaj wszystkich rekordów w grupie
popover_custom_mode_unselect = Własne odznaczanie
popover_custom_mode_select = Własne zaznaczanie
popover_invalid_regex = Regex jest niepoprawny
popover_valid_regex = Regex jest poprawny
# Przyciski na dole
bottom_search_button = Szukaj
bottom_select_button = Zaznacz
bottom_delete_button = Usuń
bottom_save_button = Zapisz
bottom_symlink_button = Symlink
bottom_hardlink_button = Hardlink
bottom_move_button = Przenieś
bottom_search_button_tooltip = Rozpocznij przeszukiwanie.
bottom_select_button_tooltip = Zaznacz elementy.
bottom_delete_button_tooltip = Usuń zaznaczone elementy.
bottom_save_button_tooltip = Zapisz informacje o skanowaniu.
bottom_symlink_button_tooltip =
Tworzy linki symboliczne.
Działa tylko jeśli przynajmniej 2 wyniki są zaznaczone w danej grupie.
Pierwszy zaznaczony nie jest modyfikowany, a drugi i kolejne są usuwane i tworzone linki symboliczne w ich miejscach.
bottom_hardlink_button_tooltip =
Tworzy twarde linki.
Działa tylko jeśli przynajmniej 2 wyniki są zaznaczone w danej grupie.
Pierwszy zaznaczony nie jest modyfikowany, a drugi i kolejne są usuwane i tworzone twarde linki w ich miejscach.
bottom_move_button_tooltip =
Przenosi pliki do podanej lokalizacji.
Kopiuje pliki bez zachowywania struktury katalogów.
Podczas próby skopiowania 2 plików z identycznymi nazwami, drugi nie zostanie przeniesiony i błąd zostanie wyświetlony.
bottom_show_errors_tooltip = Pokazuje/ukrywa dolny panel z informacjami.
bottom_show_upper_notebook_tooltip = Pokazuje/ukrywa górny panel.
# Progress Window
progress_stop_button = Stop
# About Window
about_repository_button_tooltip = Link do repozytorium z kodem źródłowym
about_donation_button_tooltip = Link do strony z dotacjami.
about_instruction_button_tooltip = Link do strony z instrukcją.
about_repository_button = Repozytorium
about_donation_button = Dotacje
about_instruction_button = Instrukcja(ENG)
# Header
header_setting_button_tooltip = Otwórz okno z ustawieniami programu.
header_about_button_tooltip = Otwórz okno z informacjami o programie.
# Settings
## General
settings_save_at_exit_button_tooltip = Zapisuje konfigurację programu podczas wychodzenia z niego.
settings_load_at_start_button_tooltip =
Ładowanie plików na starcie z plików.
Nie zaznaczenie tej opcji, spowoduje załadowanie domyślnych ustawień.
settings_confirm_deletion_button_tooltip = Wyświetla okno potwierdzające usuwanie plików.
settings_confirm_link_button_tooltip = Wyświetla okno potwierdzające usuwanie, gdy tworzone są hard/symlinki.
settings_confirm_group_deletion_button_tooltip = Wyświetla okno potwierdzające usuwanie, gdy wszystkie rekordy w danej grupie są zaznaczone.
settings_show_text_view_button_tooltip = Pokazuje na dole ekranu panel tekstowy.
settings_use_cache_button_tooltip = Umożliwia zapisywanie rekordów do pamięci podręcznej.
settings_use_trash_button_tooltip = Przenosi pliki do kosza zamiast usuwać je permanentnie.
settings_save_at_exit_button = Zapisuj konfigurację przy wyłączaniu
settings_load_at_start_button = Ładuj ustawienia na starcie z pliku
settings_confirm_deletion_button = Pokazuj okno potwierdzające usuwanie plików
settings_confirm_link_button = Pokazuj potwierdzenie usuwania hard/symlinków
settings_confirm_group_deletion_button = Pokazuj okno potwierdzające usuwanie wszystkich obiektów w grupie
settings_show_text_view_button = Pokazuj panel tekstowy na dole
settings_use_cache_button = Używaj pamięci podręcznej
settings_use_trash_button = Przenoś pliki do kosza
## Multiple - ustawienia wskazywane przez większość zakładek
settings_multiple_delete_outdated_cache_checkbutton = Usuwaj automatycznie nieaktualne rekordy z pamięci podręcznej
settings_multiple_delete_outdated_cache_checkbutton_tooltip =
Pozwala na automatyczne usuwanie rekordów, które wskazują na nieaktualne pliki.
W przypadku gdy pole jest zaznaczone, upewnij się, że wszystkie dyski zewnętrzne są podpięte by nie stracić zapisanych hashów z pamięci podręcznej.
Wyłączenie tej opcji spowoduje, że nawet przy skanowaniu odpiętych dysków, rekordy w pamięci podręcznej nie będą usuwane.
W przypadku posiadania dziesiątek czy setek tysięcy rekordów w pamięci podręcznej, zalecane jest zaznaczenie tej opcji, ponieważ przyspiesza to ładowanie i zapisywanie pamięci podręcznej.
settings_multiple_image_preview_checkbutton_tooltip = Pokazuje podgląd obrazów po ich zaznaczeniu po prawej stronie aplikacji.
settings_multiple_image_preview_checkbutton = Pokazuj podgląd obrazów
settings_multiple_clear_cache_button_tooltip =
Ręcznie czyści pamięć podręczną z nieaktualnych danych.
Opcja powinna być używana tylko gdy automatyczne czyszczenie pamięci podręcznej jest wyłączone.
settings_multiple_clear_cache_button = Usuń nieaktualne dane z pamięci podręcznej
## Duplicates
settings_duplicates_hide_hard_link_button_tooltip =
Ukrywa wszystkie pliki oprócz jednego, jeśli wskazują na dokładnie ten sam plik(to samo inode).
Przykładowo - gdy program znalazł 7 plików na dokładnie ten sam plik(to samo inode) a dodatkowo jeden na inny, to w wynikach wyszukiwania wyświetlą się jedynie 2 wyniki - jeden z pierwszej grupy i drugi z drugiej.
settings_duplicates_minimal_size_entry_tooltip =
Opcja umożliwia ustawienie minimalnej wielkości pliku, której hash będzie zapisywany do pamięci podręcznej.
Im mniejsza wartość, tym hash większej ilości plików będzie przechowywany w pamięci podręcznej, co przyspieszy wyszukiwanie plików lecz jednocześnie spowolni wczytywanie/zapisywanie hashu do pliku.
settings_duplicates_prehash_checkbutton_tooltip =
Umożliwia zapisywanie cząstkowego hashu do pamięci podręcznej, który umożliwia na wcześniejsze wyrzucenie plików z unikalnymi rozmiarami.
Domyślnie jest zablokowane, ponieważ może powodować spowolnione skanowanie w niektórych sytuacjach.
Jest mocno polecane osobom które skanują tylko i wyłącznie katalogi zawierające dziesiątki lub setki tysięcy lub nawet miliony plików, ponieważ może to wielokrotnie przyspieszyć proces skanowania.
settings_duplicates_prehash_minimal_entry_tooltip = Minimalny rozmiar pliku, którego cząstowy hash będzie zapisywany do pamięci podręcznej.
settings_duplicates_hide_hard_link_button = Ukrywaj twarde dowiązania(nie działa na Windowsie)
settings_duplicates_prehash_checkbutton = Używaj pamięci podręcznej dla hashy cząstkowych
settings_duplicates_minimal_size_cache_label = Wielkość pliku, od którego hash będzie zapisywany w pamięci podręcznej
settings_duplicates_minimal_size_cache_prehash_label = Wielkość pliku, od którego cząstkowy hash będzie zapisywany w pamięci podręcznej
## Saving/Loading settings
settings_saving_button_tooltip = Zapisuje aktualne ustawienia do pliku.
settings_loading_button_tooltip = Ładuje ustawienia z pliku.
settings_reset_button_tooltip = Resetuje aktualne ustawienia do domyślnie używanych przez aplikację.
settings_saving_button = Zapisanie ustawień
settings_loading_button = Załadowanie ustawień
settings_reset_button = Reset ustawień
## Opening cache/config folders
settings_folder_cache_open_tooltip =
Otwiera folder gdzie przechowywana jest pamięć podręczna aplikacji.
Jej ręczne modyfikowanie może powodować wyświetlanie niepoprawnych wyników lub jej uszkodzenie spowoduje koniecznośc ponownej generacji, lecz umożliwia też oszczędzenie czasu przy przesuwaniu większej ilości plików.
Można pliki kopiować pomiędzy komputerami by zaoszczędzić czas na hashowaniu plików(oczywiście tylko gdy dane są przechowywane w identycznej strukturze katalogów na komputerach).
settings_folder_settings_open_tooltip =
Otwiera folder gdzie Czkawka przechowuje ustawienia.
Ich ręczna zmiana, może spowodować różne błędy i kataklizmy, którym fiziologom się nie śniły.
settings_folder_cache_open = Otwórz folder pamięci podręcznej
settings_folder_settings_open = Otwórz folder ustawień
# Compute results
compute_stopped_by_user = Przeszukiwanie zostało zatrzymane przez użytkownika
compute_found = Znaleziono
compute_duplicated_files_in = duplikatów w
compute_groups_which_took = grupach, które zabrały
compute_groups = grup
compute_duplicates_for = duplikatów dla
compute_empty_folders = pustych folderów
compute_empty_files = pustych plików
compute_biggest_files = największych plików
compute_temporary_files = plików tymczasowych
compute_similar_image = obrazów
compute_similar_videos = plików wideo
compute_music_files = plików muzycznych
compute_symlinks = niepoprawnych linków symbolicznych
compute_broken_files = zepsutych plików
# Progress window
progress_scanned = Przeskanowano
progress_files = plików
progress_folders = folderów
progress_tags = Sczytano tagi z
progress_hashing = Przehashowano
progress_checking = Sprawdzono
progress_size = rozmiar
progress_name = nazwa
progress_analyzed_full_hash = Przeanalizowano pełny hash
progress_analyzed_partial_hash = Przeanalizowano częściowy hash
progress_current_stage = Aktualny Etap:{" "}
progress_all_stages = Wszystkie Etapy:{" "}
# Other
searching_for_data = Przeszukiwanie dysku, może to potrwać chwilę, proszę czekać...
# Saving loading
saving_loading_saving_success = Zapisano konfigurację do pliku
saving_loading_reset_configuration = Przywrócono domyślą konfigurację.
saving_loading_loading_success = Poprawnie załadowano konfigurację z pliku

@ -0,0 +1,67 @@
# Translations
New feature in Czkawka 4.0 is ability to translate interface of GTK app.
App use Fluent localization system - https://projectfluent.org/
Main/Default language is English, but also Polish is officially supported.
## How to translate Czkawka?
Base translatable strings are placed under `i18n/en/czkawka_gui.ftl` file.
`czkawka_core.ftl` is just a symlink which point to file from above(I had problems with splitting string into two separate crates)
Since such strings are heavily integrated into build system, so to check status of translation it is required to recompile Czkawka.
`czkawka_gui.ftl` file contains lines in this format:
`id_of_message` = `translated_string`
e.g.
```
upper_manual_add_included_button_tooltip = Allows to add directory name to search by hand
```
to create new folder with translations, it is required to create copy of `i18n/en` folder and give it name from [ISO 639-1 code standard](https://www.loc.gov/standards/iso639-2/php/code_list.php) - e.g. pl, en, ru, fr etc.
Next only translated strings needs to be changed
## Testing translation
### Replacing en folder
The simplest method is to remove `en` folder and replace it with needed one.
Next Czkawka needs to be compiled and run.
### Adding new translation
Recommended way to test translation, is to add it directly to Czkawka source code.
After creating proper and well named folder and translating string inside it, to be able to be able to choose this language file it is required to modify `czkawka_gui/src/language_functions.rs` file.
```rust
pub const LANGUAGES_ALL: [Language; 2] = [
Language {
combo_box_text: "English (en)",
short_text: "en",
},
Language {
combo_box_text: "Polski (pl)",
short_text: "pl",
},
];
```
The only thing which is required to change is `LANGUAGES_ALL` constant.
Number of items must be changed `[Language; 2]` -> `[Language; 3]`.
Next new record must be added to array.
`combo_box_text` must contains translated language name(so `Polski` is used instead `Polish`), to help find people to find their native(or not) language.
`short_text` is `ISO 639-1` code which need to match with county code and name of folder inside `i18n`.
```
Language {
combo_box_text: "Polski (pl)",
short_text: "pl",
},
```
Loading…
Cancel
Save