diff --git a/src/unstable/Picocrypt.go b/src/unstable/Picocrypt.go index 2ede78a..cfc1e76 100644 --- a/src/unstable/Picocrypt.go +++ b/src/unstable/Picocrypt.go @@ -37,6 +37,7 @@ import ( "image/color" "archive/zip" "encoding/hex" + "encoding/json" "path/filepath" "runtime/debug" @@ -60,25 +61,40 @@ import ( "github.com/AllenDang/giu" // Reed-Solomon - "github.com/HACKERALERT/infectious" // v0.0.0-20210730231340-8af02cb9ed0a + "github.com/HACKERALERT/infectious" // v0.0.0-20210818221523-92bdec168696 // Helpers + "github.com/cloudfoundry-attic/jibber_jabber" "github.com/HACKERALERT/clipboard" // v0.1.5-0.20210716140604-61d96bf4fc94 "github.com/HACKERALERT/dialog" // v0.0.0-20210716143851-223edea1d840 - "github.com/HACKERALERT/browser" // v0.0.0-20210730230128-85901a8dd82f + "github.com/HACKERALERT/browser" // v0.0.0-20210818221535-991cc324ab76 "github.com/HACKERALERT/zxcvbn-go" // v0.0.0-20210730224720-b29e9dba62c2 ) var version = "v1.17" -//go:embed NotoSans-Regular.ttf +//go:embed font.ttf var font []byte + //go:embed sdelete64.exe var sdelete64bytes []byte + //go:embed icon.png var iconBytes []byte +//go:embed strings.json +var localeBytes []byte + +type locale struct{ + iso string + data []string +} + +var locales []locale +var selectedLocale = "en" + + // Languages var languages = []string{ "English", @@ -132,7 +148,7 @@ var passwordState = giu.InputTextFlagsPassword var passwordStateLabel = "Show" var cPassword string // Confirm password text entry string variable var keyfilePath string -var keyfileLabel = "Use a keyfile" +var keyfileLabel = "Keyfile" var metadata string var metadataPrompt = "Metadata (optional):" var metadataState = giu.InputTextFlagsNone @@ -205,7 +221,7 @@ func startUI(){ // The tab bar, which contains different tabs for different functions giu.TabBar().TabItems( // Main file encryption/decryption tab - giu.TabItem("Main").Layout( + giu.TabItem(s("Encryption")).Layout( // Update 'tab' to indicate that this is the active tab giu.Custom(func(){ if giu.IsItemActive(){ @@ -216,22 +232,22 @@ func startUI(){ // Password generator modal giu.Custom(func(){ if showGenpass{ - giu.PopupModal("Generate password:").Layout( + giu.PopupModal(s("Generate password:")).Layout( giu.Row( - giu.Label("Length: "), + giu.Label(s("Length:")), giu.SliderInt("",&genpassLength,4,64).Size(-0.0000001), ), - giu.Checkbox("Uppercase",&genpassUpper), - giu.Checkbox("Lowercase",&genpassLower), - giu.Checkbox("Numbers",&genpassNums), - giu.Checkbox("Symbols",&genpassSymbols), - giu.Checkbox("Copy to clipboard",&genpassCopy), + giu.Checkbox(s("Uppercase"),&genpassUpper), + giu.Checkbox(s("Lowercase"),&genpassLower), + giu.Checkbox(s("Numbers"),&genpassNums), + giu.Checkbox(s("Symbols"),&genpassSymbols), + giu.Checkbox(s("Copy to clipboard"),&genpassCopy), giu.Row( - giu.Button("Cancel").Size(100,0).OnClick(func(){ + giu.Button(s("Cancel")).Size(100,0).OnClick(func(){ giu.CloseCurrentPopup() showGenpass = false }), - giu.Button("Generate").Size(100,0).OnClick(func(){ + giu.Button(s("Generate")).Size(100,0).OnClick(func(){ tmp := genPassword() password = tmp cPassword = tmp @@ -242,7 +258,7 @@ func startUI(){ }), ), ).Build() - giu.OpenPopup("Generate password:") + giu.OpenPopup(s("Generate password:")) giu.Update() } }), @@ -250,14 +266,14 @@ func startUI(){ // Confirm overwrite with a modal giu.Custom(func(){ if showConfirmation{ - giu.PopupModal("Warning:").Layout( - giu.Label("Output already exists. Overwrite?"), + giu.PopupModal(s("Warning:")).Layout( + giu.Label(s("Output already exists. Overwrite?")), giu.Row( - giu.Button("No").Size(100,0).OnClick(func(){ + giu.Button(s("No")).Size(100,0).OnClick(func(){ giu.CloseCurrentPopup() showConfirmation = false }), - giu.Button("Yes").Size(100,0).OnClick(func(){ + giu.Button(s("Yes")).Size(100,0).OnClick(func(){ giu.CloseCurrentPopup() showConfirmation = false showProgress = true @@ -272,7 +288,7 @@ func startUI(){ }), ), ).Build() - giu.OpenPopup("Warning:") + giu.OpenPopup(s("Warning:")) giu.Update() } }), @@ -290,7 +306,7 @@ func startUI(){ // Progress bar giu.Row( giu.ProgressBar(progress).Size(280,0).Overlay(progressInfo), - giu.Button("Cancel").Size(58,0).OnClick(func(){ + giu.Button(s("Cancel")).Size(58,0).OnClick(func(){ working = false }), ), @@ -303,21 +319,21 @@ func startUI(){ // Label listing the input files and a button to clear them giu.Row( - giu.Label(inputLabel), + giu.Label(s(inputLabel)), giu.Row( giu.Dummy(-58,0), - giu.Button("Clear").Size(50,0).OnClick(resetUI), - giu.Tooltip("Clear all input files and reset UI state."), + giu.Button(s("Clear")).Size(50,0).OnClick(resetUI), + giu.Tooltip(s("Clear all input files and reset UI state.")), ), ), // Allow user to choose a custom output path and/or name - giu.Label("Save output as:"), + giu.Label(s("Save output as:")), giu.Row( giu.InputText(&outputEntry).Size(outputWidth/dpi), giu.Label(orLabel), - giu.Button("Choose").OnClick(func(){ - file,_ := dialog.File().Title("Save output as...").Save() + giu.Button(s("Choose")).OnClick(func(){ + file,_ := dialog.File().Title(s("Save output as...")).Save() // Return if user canceled the file dialog if file==""{ @@ -338,52 +354,52 @@ func startUI(){ outputEntry = file }).Size(64,0), - giu.Tooltip("Select a custom name and path to save the output as."), + giu.Tooltip(s("Select a custom name and path to save the output as.")), ), // Prompt for password giu.Row( - giu.Label("Password:"), + giu.Label(s("Password:")), giu.Custom(func(){ if mode!="decrypt"{ giu.Row( - giu.Button("Generate").OnClick(func(){ + giu.Button(s("Generate")).OnClick(func(){ showGenpass = true }), - giu.Tooltip("Use this to generate a cryptographically secure password."), + giu.Tooltip(s("Use this to generate a cryptographically secure password.")), - giu.Button("Copy").OnClick(func(){ + giu.Button(s("Copy")).OnClick(func(){ clipboard.WriteAll(password) }), - giu.Tooltip("Copies the contents of the password field into your clipboard."), + giu.Tooltip(s("Copies the contents of the password field into your clipboard.")), ).Build() } }), - giu.Button("Paste").OnClick(func(){ + giu.Button(s("Paste")).OnClick(func(){ tmp,_ := clipboard.ReadAll() password = tmp cPassword = tmp passwordStrength = zxcvbn.PasswordStrength(password,nil).Score giu.Update() }), - giu.Tooltip("Paste your clipboard content into the password fields."), + giu.Tooltip(s("Paste your clipboard content into the password fields.")), - giu.Button("Clear").OnClick(func(){ + giu.Button(s("Clear")).OnClick(func(){ password = "" cPassword = "" }), - giu.Tooltip("Clear both password fields."), + giu.Tooltip(s("Clear both password fields.")), giu.Button(passwordStateLabel).OnClick(func(){ if passwordState==giu.InputTextFlagsPassword{ passwordState = giu.InputTextFlagsNone - passwordStateLabel = "Hide" + passwordStateLabel = s("Hide") }else{ passwordState = giu.InputTextFlagsPassword - passwordStateLabel = "Show" + passwordStateLabel = s("Show") } }), - giu.Tooltip("Click to toggle the password state."), + giu.Tooltip(s("Click to toggle the password state.")), ), giu.Row( giu.InputText(&password).Size(300/dpi).Flags(passwordState).OnChange(func(){ @@ -438,9 +454,9 @@ func startUI(){ }), giu.Custom(func(){ if keyfile&&mode=="encrypt"{ - giu.Button("Clear").OnClick(func(){ + giu.Button(s("Clear")).OnClick(func(){ keyfile = false - keyfileLabel = "Use keyfile(s)" + keyfileLabel = s("Keyfile") keyfilePath = "" }).Build() } @@ -451,7 +467,7 @@ func startUI(){ // Prompt to confirm password giu.Custom(func(){ if mode!="decrypt"{ - giu.Label("Confirm password:").Build() + giu.Label(s("Confirm password:")).Build() giu.Row( giu.InputText(&cPassword).Size(300/dpi).Flags(passwordState), giu.Custom(func(){ @@ -479,42 +495,42 @@ func startUI(){ }), // Optional metadata - giu.Label(metadataPrompt), + giu.Label(s(metadataPrompt)), giu.InputText(&metadata).Size(-0.0000001).Flags(metadataState), giu.Custom(func(){ if mode!=""{ - giu.Label("Advanced options:").Build() + giu.Label(s("Advanced options:")).Build() } }), // Advanced options can be enabled with checkboxes giu.Custom(func(){ if mode=="encrypt"{ - giu.Checkbox("Shred temporary files",&shredTemp).Build() - giu.Tooltip("Use this to shred temporary zip archives and volumes used by Picocrypt.").Build() + giu.Checkbox(s("Shred temporary files"),&shredTemp).Build() + giu.Tooltip(s("Use this to shred temporary zip archives and volumes used by Picocrypt.")).Build() - giu.Checkbox("Use fast mode",&fast).OnChange(func(){ + giu.Checkbox(s("Use fast mode"),&fast).OnChange(func(){ paranoid = false }).Build() - giu.Tooltip("Uses BLAKE2b instead of SHA3 with less Argon2; faster, but less secure.").Build() + giu.Tooltip(s("Uses BLAKE2b instead of SHA3 with less Argon2; faster, but less secure.")).Build() - giu.Checkbox("Use paranoid mode",¶noid).OnChange(func(){ + giu.Checkbox(s("Use paranoid mode"),¶noid).OnChange(func(){ fast = false }).Build() - giu.Tooltip("Cascades Serpent with XChaCha20 plus high Argon2; highly secure, but slower.").Build() + giu.Tooltip(s("Uses Serpent and high Argon2; highly secure, but slower.")).Build() giu.Row( - giu.Checkbox("Encode with Reed-Solomon",&reedsolo), - giu.Tooltip("Reed-Solomon can detect and fix corrupted data."), + giu.Checkbox(s("Encode with Reed-Solomon"),&reedsolo), + giu.Tooltip(s("Reed-Solomon can detect and fix corrupted data.")), giu.Button("?").Size(24,25).OnClick(func(){ browser.OpenURL(rsWikipedia) }), ).Build() giu.Row( - giu.Checkbox("Split output into chunks of",&split), - giu.Tooltip("Use this to split the output file into chunks."), + giu.Checkbox(s("Split output into chunks of"),&split), + giu.Tooltip(s("Use this to split the output file into chunks.")), giu.InputText(&splitSize).Size(50).Flags(giu.InputTextFlagsCharsDecimal).OnChange(func(){ if splitSize==""{ split = false @@ -527,15 +543,15 @@ func startUI(){ giu.Dummy(0,1).Build() }else if mode=="decrypt"{ - giu.Checkbox("Keep decrypted output even if it's corrupted or modified",&keep).Build() - giu.Tooltip("Tells Picocrypt to always keep decrypted outputs.").Build() + giu.Checkbox(s("Keep decrypted output even if it's corrupted or modified"),&keep).Build() + giu.Tooltip(s("Tells Picocrypt to always keep decrypted outputs.")).Build() - giu.Checkbox("Delete the input file(s) after decryption",&deleteEncrypted).Build() - giu.Tooltip("Removes the encrypted Picocrypt volume (and chunks).").Build() + giu.Checkbox(s("Delete the input file(s) after decryption"),&deleteEncrypted).Build() + giu.Tooltip(s("Removes the encrypted Picocrypt volume (and chunks).")).Build() giu.Dummy(0,112).Build() }else{ giu.Dummy(0,67).Build() - giu.Label(" No files selected yet.").Build() + giu.Label(s(" No files selected yet.")).Build() giu.Dummy(0,68).Build() } }), @@ -543,12 +559,12 @@ func startUI(){ // Start button giu.Button("Start").Size(-0.0000001,35).OnClick(func(){ if mode=="encrypt"&&password!=cPassword{ - _status = "Passwords don't match." + _status = s("Passwords don't match.") _status_color = color.RGBA{0xff,0x00,0x00,255} return } if keyfile&&keyfilePath==""{ - _status = "Please select a keyfile." + _status = s("Please select a keyfile.") _status_color = color.RGBA{0xff,0x00,0x00,255} return } @@ -584,20 +600,20 @@ func startUI(){ ), // File checksum generator tab - giu.TabItem("Checksum").Layout( + giu.TabItem(s("Checksum")).Layout( giu.Custom(func(){ if giu.IsItemActive(){ tab = 1 } }), - giu.Label("Toggle the hashes you would like to generate and drop a file here."), + giu.Label(s("Toggle the hashes you would like to generate and drop a file here.")), // MD5 giu.Row( giu.Checkbox("MD5:",&md5_selected), giu.Dummy(-58,0), - giu.Button("Copy##md5").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##md5").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_md5) }), ), @@ -609,7 +625,7 @@ func startUI(){ giu.Row( giu.Checkbox("SHA1:",&sha1_selected), giu.Dummy(-58,0), - giu.Button("Copy##sha1").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##sha1").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_sha1) }), ), @@ -621,7 +637,7 @@ func startUI(){ giu.Row( giu.Checkbox("SHA256:",&sha256_selected), giu.Dummy(-58,0), - giu.Button("Copy##sha256").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##sha256").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_sha256) }), ), @@ -633,7 +649,7 @@ func startUI(){ giu.Row( giu.Checkbox("SHA3-256:",&sha3_256_selected), giu.Dummy(-58,0), - giu.Button("Copy##sha3_256").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##sha3_256").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_sha3_256) }), ), @@ -645,7 +661,7 @@ func startUI(){ giu.Row( giu.Checkbox("BLAKE2b:",&blake2b_selected), giu.Dummy(-58,0), - giu.Button("Copy##blake2b").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##blake2b").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_blake2b) }), ), @@ -657,7 +673,7 @@ func startUI(){ giu.Row( giu.Checkbox("BLAKE2s:",&blake2s_selected), giu.Dummy(-58,0), - giu.Button("Copy##blake2s").Size(50,0).OnClick(func(){ + giu.Button(s("Copy")+"##blake2s").Size(50,0).OnClick(func(){ clipboard.WriteAll(cs_blake2s) }), ), @@ -666,7 +682,7 @@ func startUI(){ ), // Input entry for validating a checksum - giu.Label("Validate a checksum:"), + giu.Label(s("Validate a checksum:")), giu.InputText(&cs_validate).Size(-0.0000001).OnChange(func(){ md5_color = color.RGBA{0x10,0x10,0x10,255} sha1_color = color.RGBA{0x10,0x10,0x10,255} @@ -694,25 +710,25 @@ func startUI(){ }), // Progress bar - giu.Label("Progress:"), + giu.Label(s("Progress:")), giu.ProgressBar(cs_progress).Size(-0.0000001,0), ), // File shredder tab - giu.TabItem("Shredder").Layout( + giu.TabItem(s("Shredder")).Layout( giu.Custom(func(){ if giu.IsItemActive(){ tab = 2 } }), - giu.Label("Drop file(s) and folder(s) here to shred them."), + giu.Label(s("Drop file(s) and folder(s) here to shred them.")), giu.Custom(func(){ if runtime.GOOS=="darwin"{ - giu.Label("Number of passes: Not supported on macOS").Build() + giu.Label(s("Number of passes: Not supported on macOS")).Build() }else{ giu.Row( - giu.Label("Number of passes:"), + giu.Label(s("Number of passes:")), giu.InputText(&shredPasses).Size(16).Flags(giu.InputTextFlagsCharsDecimal), ).Build() } @@ -720,9 +736,9 @@ func startUI(){ giu.Dummy(0,-50), giu.Row( giu.ProgressBar(shredProgress).Overlay(shredOverlay).Size(-65,0), - giu.Button("Cancel").Size(58,0).OnClick(func(){ + giu.Button(s("Cancel")).Size(58,0).OnClick(func(){ stopShredding = true - shredding = "Ready." + shredding = s("Ready.") shredProgress = 0 shredOverlay = "" }), @@ -736,29 +752,29 @@ func startUI(){ ), // About tab - giu.TabItem("About").Layout( + giu.TabItem(s("About")).Layout( giu.Custom(func(){ if giu.IsItemActive(){ tab = 3 } }), - giu.Label("Picocrypt "+version+", created by Evan Su (https://evansu.cc)."), - giu.Label("Released under a GNU GPL v3 License."), - giu.Label("A warm thank you to all the people listed below."), - giu.Label("Patrons:"), + giu.Label(fmt.Sprintf(s("Picocrypt %s, created by Evan Su (https://evansu.cc/)."),version)), + giu.Label(s("Released under a GNU GPL v3 License.")), + giu.Label(s("A warm thank you to all the people listed below.")), + giu.Label(s("Patrons:")), giu.Label(" - Frederick Doe"), - giu.Label("Donators:"), + giu.Label(s("Donators:")), giu.Label(" - jp26"), giu.Label(" - W.Graham"), giu.Label(" - N. Chin"), giu.Label(" - Manjot"), giu.Label(" - Phil P."), giu.Label(" - E. Zahard"), - giu.Label("Translators"), + giu.Label(s("Translators:")), giu.Label(" - umitseyhan75 (Turkish)"), giu.Label(" - digitalblossom (German)"), giu.Label(" - maguszeal (Brazilian Portuguese)"), - giu.Label("Other"), + giu.Label(s("Other:")), giu.Label(" - Fuderal for setting up Picocrypt's Discord server"), giu.Label(" - u/greenreddits for constant feedback and support"), giu.Label(" - u/Tall_Escape for helping me test Picocrypt"), @@ -771,7 +787,7 @@ func startUI(){ // Handle files dropped into Picocrypt by user func onDrop(names []string){ - _status = "Ready." + _status = s("Ready.") recombine = false if tab==0{ // Clear variables @@ -784,7 +800,7 @@ func onDrop(names []string){ resetUI() // Hide the ".pcv" label - orLabel = "or" + orLabel = s("or") outputWidth = 370 // There's only one dropped item @@ -795,13 +811,13 @@ func onDrop(names []string){ if stat.IsDir(){ mode = "encrypt" folders++ - inputLabel = "1 folder selected." + inputLabel = s("1 folder selected.") // Add the folder onlyFolders = append(onlyFolders,names[0]) // Set 'outputEntry' to 'Encrypted' - outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted") + outputEntry = filepath.Join(filepath.Dir(names[0]),s("Encrypted")) // Show the ".zip.pcv" file extension orLabel = ".zip.pcv or" @@ -823,12 +839,12 @@ func onDrop(names []string){ if strings.HasSuffix(names[0],".pcv")||isSplit{ var err error mode = "decrypt" - inputLabel = name+" (will decrypt)" - metadataPrompt = "Metadata (read-only):" + inputLabel = name+s(" (will decrypt)") + metadataPrompt = s("Metadata (read-only):") metadataState = giu.InputTextFlagsReadOnly if isSplit{ - inputLabel = name+" (will recombine and decrypt)" + inputLabel = name+s(" (will recombine and decrypt)") ind := strings.Index(names[0],".pcv") names[0] = names[0][:ind] outputEntry = names[0] @@ -850,14 +866,14 @@ func onDrop(names []string){ fin.Read(tmp) if string(tmp[:5])=="v1.13"{ resetUI() - _status = "Please use Picocrypt v1.13 to decrypt this file." + _status = s("Please use Picocrypt v1.13 to decrypt this file.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() return } if valid,_:=regexp.Match(`^v\d\.\d{2}.{10}0?\d+`,tmp);!valid&&!isSplit{ resetUI() - _status = "This doesn't seem to be a Picocrypt volume." + _status = s("This doesn't seem to be a Picocrypt volume.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() return @@ -871,7 +887,7 @@ func onDrop(names []string){ tmp,_ = rsDecode(rs5,tmp) if string(tmp)=="v1.14"||string(tmp)=="v1.15"||string(tmp)=="v1.16"{ resetUI() - _status = "Please use Picocrypt v1.16 to decrypt this file." + _status = s("Please use Picocrypt v1.16 to decrypt this file.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() return @@ -889,33 +905,33 @@ func onDrop(names []string){ for i:=0;i1{ - inputLabel = fmt.Sprintf("1 file and %d folders selected.",folders) + inputLabel = fmt.Sprintf(s("1 file and %d folders selected."),folders) }else if folders==1&&files>1{ - inputLabel = fmt.Sprintf("%d files and 1 folder selected.",files) + inputLabel = fmt.Sprintf(s("%d files and 1 folder selected."),files) }else if folders==1&&files==1{ - inputLabel = "1 file and 1 folder selected." + inputLabel = s("1 file and 1 folder selected.") }else{ - inputLabel = fmt.Sprintf("%d files and %d folders selected.",files,folders) + inputLabel = fmt.Sprintf(s("%d files and %d folders selected."),files,folders) } } // Set 'outputEntry' to 'Encrypted' - outputEntry = filepath.Join(filepath.Dir(names[0]),"Encrypted") + outputEntry = filepath.Join(filepath.Dir(names[0]),s("Encrypted")) } // If there are folders that were dropped, recusively add all files into 'allFiles' @@ -996,7 +1012,7 @@ func onDrop(names []string){ // Start encryption/decryption func work(){ // Set some variables - status = "Starting..." + status = s("Starting...") working = true padded := false var salt []byte @@ -1012,7 +1028,7 @@ func work(){ // Set the output file based on mode if mode=="encrypt"{ - status = "Combining files..." + status = s("Combining files...") // "Tar" files into a zip archive with a compression level of 0 (store) if len(allFiles)>1||len(onlyFolders)>0{ @@ -1033,7 +1049,7 @@ func work(){ w.Close() file.Close() os.Remove(inputFile) - _status = "Operation cancelled by user." + _status = s("Operation cancelled by user.") _status_color = color.RGBA{0xff,0xff,0xff,255} return } @@ -1066,7 +1082,7 @@ func work(){ } if recombine{ - status = "Recombining file..." + status = s("Recombining file...") total := 0 if strings.HasSuffix(inputFile,".pcv"){ @@ -1114,7 +1130,7 @@ func work(){ // XChaCha20's max message size is 256 GiB if total>256*1073741824{ - _status = "Total size is larger than 256 GiB, XChaCha20's limit." + _status = s("Total size is larger than 256 GiB, XChaCha20's limit.") _status_color = color.RGBA{0xff,0x00,0x00,255} return } @@ -1125,7 +1141,7 @@ func work(){ // If encrypting, generate values; If decrypting, read values from file if mode=="encrypt"{ - status = "Generating values..." + status = s("Generating values...") giu.Update() fout,_ = os.OpenFile( outputFile, @@ -1215,7 +1231,7 @@ func work(){ var err9 error var err10 error - status = "Reading values..." + status = s("Reading values...") giu.Update() version := make([]byte,15) fin.Read(version) @@ -1270,7 +1286,7 @@ func work(){ if keep{ kept = true }else{ - _status = "The header is corrupt and the input file cannot be decrypted." + _status = s("The header is corrupt and the input file cannot be decrypted.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() return @@ -1278,7 +1294,7 @@ func work(){ } } - status = "Deriving key..." + status = s("Deriving key...") progress = 0 progressInfo = "" giu.Update() @@ -1315,7 +1331,7 @@ func work(){ } if !working{ - _status = "Operation cancelled by user." + _status = s("Operation cancelled by user.") _status_color = color.RGBA{0xff,0xff,0xff,255} fin.Close() fout.Close() @@ -1370,9 +1386,9 @@ func work(){ }else{ fin.Close() if !keyCorrect{ - _status = "The provided password is incorrect." + _status = s("The provided password is incorrect.") }else{ - _status = "The provided keyfile is incorrect." + _status = s("The provided keyfile is incorrect.") } _status_color = color.RGBA{0xff,0x00,0x00,255} key = nil @@ -1421,7 +1437,7 @@ func work(){ for{ if !working{ - _status = "Operation cancelled by user." + _status = s("Operation cancelled by user.") _status_color = color.RGBA{0xff,0xff,0xff,255} fin.Close() fout.Close() @@ -1491,7 +1507,7 @@ func work(){ if keep{ kept = true }else{ - _status = "The input file is too corrupted to decrypt." + _status = s("The input file is too corrupted to decrypt.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() fout.Close() @@ -1513,7 +1529,7 @@ func work(){ if keep{ kept = true }else{ - _status = "The input file is too corrupted to decrypt." + _status = s("The input file is too corrupted to decrypt.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() fout.Close() @@ -1529,7 +1545,7 @@ func work(){ if keep{ kept = true }else{ - _status = "The input file is too corrupted to decrypt." + _status = s("The input file is too corrupted to decrypt.") _status_color = color.RGBA{0xff,0x00,0x00,255} fin.Close() fout.Close() @@ -1570,7 +1586,7 @@ func work(){ } progressInfo = fmt.Sprintf("%.2f%%",progress*100) - status = fmt.Sprintf("Working at %.2f MB/s (ETA: %s)",speed,humanize(eta)) + status = fmt.Sprintf(s("Working at %.2f MB/s (ETA: %s)"),speed,humanize(eta)) giu.Update() } @@ -1600,7 +1616,7 @@ func work(){ // Split files into chunks if split{ var splitted []string - status = "Splitting file..." + status = s("Splitting file...") stat,_ := os.Stat(outputFile) size := stat.Size() finished := 0 @@ -1629,7 +1645,7 @@ func work(){ if !working{ fin.Close() fout.Close() - _status = "Operation cancelled by user." + _status = s("Operation cancelled by user.") _status_color = color.RGBA{0xff,0xff,0xff,255} // If user cancels, remove the unfinished files @@ -1660,7 +1676,7 @@ func work(){ fin.Close() if shredTemp{ progressInfo = "" - status = "Shredding temporary files..." + status = s("Shredding temporary files...") shred([]string{outputFile}[:],false) }else{ os.Remove(outputFile) @@ -1676,7 +1692,7 @@ func work(){ if len(allFiles)>1||len(onlyFolders)>0{ if shredTemp{ progressInfo = "" - status = "Shredding temporary files..." + status = s("Shredding temporary files...") giu.Update() shred([]string{outputEntry+".zip"}[:],false) }else{ @@ -1704,10 +1720,10 @@ func work(){ // If user chose to keep a corrupted/modified file, let them know if kept{ - _status = "The input file is corrupted and/or modified. Please be careful." + _status = s("The input file is corrupted and/or modified. Please be careful.") _status_color = color.RGBA{0xff,0xff,0x00,255} }else{ - _status = "Completed." + _status = s("Completed.") _status_color = color.RGBA{0x00,0xff,0x00,255} } @@ -1715,12 +1731,12 @@ func work(){ working = false kept = false key = nil - status = "Ready." + status = s("Ready.") } // This function is run if an issue occurs during decryption func broken(){ - _status = "The input file is either corrupted or intentionally modified." + _status = s("The input file is either corrupted or intentionally modified.") _status_color = color.RGBA{0xff,0x00,0x00,255} if recombine{ os.Remove(inputFile) @@ -1749,22 +1765,22 @@ func generateChecksums(file string){ cs_validate = "" if md5_selected{ - cs_md5 = "Calculating..." + cs_md5 = s("Calculating...") } if sha1_selected{ - cs_sha1 = "Calculating..." + cs_sha1 = s("Calculating...") } if sha256_selected{ - cs_sha256 = "Calculating..." + cs_sha256 = s("Calculating...") } if sha3_256_selected{ - cs_sha3_256 = "Calculating..." + cs_sha3_256 = s("Calculating...") } if blake2b_selected{ - cs_blake2b = "Calculating..." + cs_blake2b = s("Calculating...") } if blake2s_selected{ - cs_blake2s = "Calculating..." + cs_blake2s = s("Calculating...") } // Create the checksum objects @@ -1842,7 +1858,7 @@ func shred(names []string,separate bool){ // 'separate' is true if this function is being called from the encryption/decryption tab if separate{ - shredOverlay = "Shredding..." + shredOverlay = s("Shredding...") } // Walk through directories to get the total number of files for statistics @@ -1995,7 +2011,7 @@ func shred(names []string,separate bool){ } // Clear UI state - shredding = "Completed." + shredding = s("Completed.") shredProgress = 0 shredOverlay = "" } @@ -2015,17 +2031,17 @@ func shredUpdate(separate bool){ // Reset the UI to a clean state with nothing selected or checked func resetUI(){ mode = "" - inputLabel = "Drag and drop file(s) and folder(s) into this window." + inputLabel = s("Drag and drop file(s) and folder(s) into this window.") outputEntry = "" - orLabel = "or" + orLabel = s("or") outputWidth = 370 password = "" cPassword = "" - keyfileLabel = "Use a keyfile" + keyfileLabel = s("Use a keyfile") keyfilePath = "" keyfile = false metadata = "" - metadataPrompt = "Metadata (optional):" + metadataPrompt = s("Metadata (optional):") metadataState = giu.InputTextFlagsNone shredTemp = false keep = false @@ -2037,7 +2053,7 @@ func resetUI(){ paranoid = false progress = 0 progressInfo = "" - _status = "Ready." + _status = s("Ready.") _status_color = color.RGBA{0xff,0xff,0xff,255} giu.Update() } @@ -2125,7 +2141,56 @@ func genPassword() string{ return string(tmp) } +func s(term string) string{ + for _,i := range locales{ + if i.iso==selectedLocale{ + for _,j := range locales{ + if j.iso=="en"{ + for k,l := range j.data{ + if l==term{ + return i.data[k] + } + } + } + } + + } + } + return term +} + func main(){ + // Parse locales + var obj map[string]json.RawMessage + json.Unmarshal(localeBytes,&obj) + for i := range obj{ + var tmp []string + json.Unmarshal(obj[i],&tmp) + locales = append(locales,locale{ + iso:i, + data:tmp, + }) + } + + // Check system locale + for _,i := range locales{ + tmp,err := jibber_jabber.DetectIETF() + if err==nil{ + if strings.HasPrefix(tmp,i.iso){ + selectedLocale = i.iso + } + } + } + + inputLabel = s("Drag and drop file(s) and folder(s) into this window.") + orLabel = s("or") + status = s("Ready.") + _status = s("Ready.") + shredding = s("Ready.") + passwordStateLabel = s("Show") + keyfileLabel = s("Keyfile") + metadataPrompt = s("Metadata (optional):") + // Create a temporary file to store sdelete64.exe sdelete64,_ := os.CreateTemp("","sdelete64.*.exe") sdelete64path = sdelete64.Name() @@ -2143,7 +2208,7 @@ func main(){ v.Body.Close() if err==nil{ if string(body[:5])!=version{ - _status = "A newer version is available." + _status = s("A newer version is available.") _status_color = color.RGBA{0,255,0,255} } } @@ -2164,7 +2229,7 @@ func main(){ window.SetDropCallback(onDrop) window.SetCloseCallback(func() bool{ // Disable closing window if a Picocrypt is working to prevent temporary files - if working||(shredding!="Ready."&&shredding!="Completed."){ + if working||(shredding!=s("Ready.")&&shredding!=s("Completed.")){ return false } return true