@@ -221,23 +226,23 @@
Keeper
@@ -251,23 +256,23 @@
Nordpass
@@ -288,20 +293,14 @@
Nordpass
-
- Delete account
-
+
-
- Are you sure you want to delete your account? All of your data will be permanently removed from server forever. This action cannot be undone.
-
+
-
+
diff --git a/index.html b/index.html
index 1271a80..b026f85 100644
--- a/index.html
+++ b/index.html
@@ -9,6 +9,7 @@
+
@@ -71,7 +72,7 @@
diff --git a/js/default-functions.js b/js/default-functions.js
index 3b691e4..aad03ac 100644
--- a/js/default-functions.js
+++ b/js/default-functions.js
@@ -50,17 +50,32 @@ function toggleMenu(){
}
function changeTheme(){
- if(localStorage.theme == 0){
- document.getElementById("css-theme").href = "css/themes/light.css";
- document.getElementById("theme-link").innerText = "Theme (Light)";
- document.getElementById("theme-link-mobile").innerText = "Theme (Light)";
- localStorage.theme = 1;
- }else{
- document.getElementById("css-theme").href = "css/themes/dark.css";
- document.getElementById("theme-link").innerText = "Theme (Dark)";
- document.getElementById("theme-link-mobile").innerText = "Theme (Dark)";
- localStorage.theme = 0;
+ switch(localStorage.theme){
+ case "dark":
+ document.getElementById("css-theme").href = "css/themes/light.css";
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ localStorage.theme = "light";
+ break;
+ default:
+ document.getElementById("css-theme").href = "css/themes/dark.css";
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ localStorage.theme = "dark";
+ break;
+ }
+}
+
+function changeLanguage(){
+ switch(localStorage.lang){
+ case "en":
+ localStorage.lang = "sl";
+ break;
+ default:
+ localStorage.lang = "en";
+ break;
}
+ location.reload();
}
function copyToClipboard(text){
@@ -80,33 +95,6 @@ function copyToClipboard(text){
document.body.removeChild(textArea);
}
-const errors = {
- "0": "Successful",
- "1": "Username is invalid!",
- "2": "Password is incorrect!",
- "3": "Something went wrong while inserting data to database!",
- "4": "Username is already registered!",
- "5": "Password must be between 8 and 255 characters long and have at least one letter, one number and one special character!",
- "6": "Email is invalid!",
- "7": "Username doesn't exist!",
- "8": "You don't have any saved password.",
- "9": "Domain is invalid!",
- "10": "User does not own this password!",
- "11": "Something went wrong while deleting data from database!",
- "12": "Username must be between 6 and 30 characters long and can only contains letters, numbers and dots!",
- "13": "Something went wrong while updating data in database!",
- "14": "Json is invalid!",
- "15": "This server can't accept more users!",
- "16": "You have reached maximum amount of stored passwords!",
- "400": "Action was not provided in POST!",
- "401": "Action is invalid!",
- "403": "You didn't provide all required values in POST.",
- "404": "Can't connect into API.",
- "429": "You are sending too many requests! Please wait some time before executing this action.",
- "505": "Something went wrong while connecting to database!",
- "999": "You don't have permission to use this endpoint."
-}
-
function downloadTxt(exportTxt, exportName){
let dataStr = "data:text/plain;charset=utf-8," + encodeURIComponent(exportTxt);
let downloadAnchorNode = document.createElement('a');
diff --git a/js/export.js b/js/export.js
index 5be9b66..b3d3b37 100644
--- a/js/export.js
+++ b/js/export.js
@@ -1,5 +1,54 @@
check_login();
+document.getElementById("passwords-link").innerText = lang[localStorage.lang]["passwords"];
+document.getElementById("import-export-link").innerText = lang[localStorage.lang]["import_export"];
+document.getElementById("signout-link").innerText = lang[localStorage.lang]["signout"];
+
+document.getElementById("passwords-link-mobile").innerText = lang[localStorage.lang]["passwords"];
+document.getElementById("import-export-link-mobile").innerText = lang[localStorage.lang]["import_export"];
+document.getElementById("signout-link-mobile").innerText = lang[localStorage.lang]["signout"];
+
+switch(localStorage.theme){
+ case "light":
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ break;
+ default:
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ break;
+}
+
+switch(localStorage.lang){
+ case "sl":
+ document.getElementById("lang-link").innerText = "Language (Slovenian)";
+ document.getElementById("lang-link-mobile").innerText = "Language (Slovenian)";
+ break;
+ default:
+ document.getElementById("lang-link").innerText = "Language (English)";
+ document.getElementById("lang-link-mobile").innerText = "Language (English)";
+ break;
+}
+
+document.getElementById("passky-backup-btn-text").innerText = lang[localStorage.lang]["backup"];
+
+document.getElementById("passky-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("lastpass-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("bitwarden-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("dashline-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("onepassword-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("keeper-import-btn-text").innerText = lang[localStorage.lang]["import"];
+document.getElementById("nordpass-import-btn-text").innerText = lang[localStorage.lang]["import"];
+
+document.getElementById("passky-export-btn-text").innerText = lang[localStorage.lang]["export"];
+document.getElementById("lastpass-export-btn-text").innerText = lang[localStorage.lang]["export"];
+document.getElementById("dashline-export-btn-text").innerText = lang[localStorage.lang]["export"];
+document.getElementById("onepassword-export-btn-text").innerText = lang[localStorage.lang]["export"];
+document.getElementById("keeper-export-btn-text").innerText = lang[localStorage.lang]["export"];
+document.getElementById("nordpass-export-btn-text").innerText = lang[localStorage.lang]["export"];
+
+document.getElementById("dialog-button-cancel").innerText = lang[localStorage.lang]["cancel"];
+
function import_passky(){
check_login();
@@ -196,7 +245,7 @@ function import_data(passwords){
if(xhr.readyState === 4){
if(xhr.status != 200){
- changeDialog(0, "Server is unreachable!");
+ changeDialog(0, lang[localStorage.lang]["server_unreachable"]);
show('dialog');
return;
}
@@ -204,23 +253,23 @@ function import_data(passwords){
var json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- changeDialog(0, "Server is unreachable!");
+ changeDialog(0, lang[localStorage.lang]["server_unreachable"]);
show('dialog');
return;
}
if(json['error'] != 0){
- changeDialog(0, errors[json['error']]);
+ changeDialog(0, errors[localStorage.lang][json['error']]);
show('dialog');
return;
}
if(json['error'] == 0){
if(json['import_error'] == 0){
- changeDialog(3, json['import_success'] + " passwords has been successfully imported!");
+ changeDialog(3, lang[localStorage.lang]["import_success"].replace("{success_number}", json['import_success']));
show('dialog');
}else{
- changeDialog(3, json['import_success'] + " passwords has been successfully imported, but " + json['import_error'] + " passwords has not been imported!");
+ changeDialog(3, lang[localStorage.lang]["import_errors"].replace("{success_number}", json['import_success']).replace("{error_number}", json['import_error']));
show('dialog');
}
}
@@ -240,19 +289,19 @@ function changeDialog(style, text, text2){
document.getElementById('dialog-text').innerHTML = "
";
document.getElementById('dialog-button').className = "primaryButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Import";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["import"];
switch(text){
case 0:
- document.getElementById('dialog-title').innerText = "Import from Passky";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["import_from"].replace("{name}","Passky");
document.getElementById('dialog-button').onclick = () => import_passky();
break;
case 1:
- document.getElementById('dialog-title').innerText = "Import from Lastpass";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["import_from"].replace("{name}","Lastpass");
document.getElementById('dialog-button').onclick = () => import_lastpass();
break;
case 2:
- document.getElementById('dialog-title').innerText = "Import from Bitwarden";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["import_from"].replace("{name}","Bitwarden");
document.getElementById('dialog-button').onclick = () => import_bitwarden();
break;
}
@@ -262,11 +311,11 @@ function changeDialog(style, text, text2){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "ERROR";
- document.getElementById('dialog-text').innerText = "Data in import is invalid!";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["error"];
+ document.getElementById('dialog-text').innerText = lang[localStorage.lang]["import_invalid"];
document.getElementById('dialog-button').className = "dangerButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Try again";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["try_again"];
document.getElementById('dialog-button').onclick = () => changeDialog(text, text2);
break;
case 3:
@@ -274,11 +323,11 @@ function changeDialog(style, text, text2){
document.getElementById('dialog-icon').className = "mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "SUCCESS";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["success"];
document.getElementById('dialog-text').innerText = text;
document.getElementById('dialog-button').className = "successButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Okay";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["okay"];
document.getElementById('dialog-button').onclick = () => refreshPasswords();
break;
default:
@@ -286,11 +335,11 @@ function changeDialog(style, text, text2){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "ERROR";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["error"];
document.getElementById('dialog-text').innerText = text;
document.getElementById('dialog-button').className = "dangerButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Okay";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["okay"];
document.getElementById('dialog-button').onclick = () => hide('dialog');
break;
}
@@ -312,6 +361,14 @@ document.getElementById("theme-link-mobile").addEventListener("click", () => {
changeTheme();
});
+document.getElementById("lang-link").addEventListener("click", () => {
+ changeLanguage();
+});
+
+document.getElementById("lang-link-mobile").addEventListener("click", () => {
+ changeLanguage();
+});
+
document.getElementById("main-menu-toggle-btn").addEventListener("click", () => {
toggleMenu();
});
diff --git a/js/header.js b/js/header.js
index 75ac8c2..f0c239e 100644
--- a/js/header.js
+++ b/js/header.js
@@ -1,7 +1,11 @@
-if(localStorage.theme == null || typeof(localStorage.theme) == 'undefined') localStorage.theme = 0;
+if(localStorage.theme == null || typeof(localStorage.theme) == 'undefined') localStorage.theme = "dark";
+if(localStorage.lang == null || typeof(localStorage.lang) == 'undefined') localStorage.lang = "en";
-if(localStorage.theme == 0){
- document.getElementById("css-theme").href = "css/themes/dark.css";
-}else{
- document.getElementById("css-theme").href = "css/themes/light.css";
+if(!(localStorage.theme == "dark" || localStorage.theme == "light")) localStorage.theme = "dark";
+if(!(localStorage.lang == "en" || localStorage.lang == "sl")) localStorage.lang = "en";
+
+switch(localStorage.theme){
+ case "light":
+ document.getElementById("css-theme").href = "css/themes/light.css";
+ break;
}
\ No newline at end of file
diff --git a/js/lang.js b/js/lang.js
new file mode 100644
index 0000000..a64674e
--- /dev/null
+++ b/js/lang.js
@@ -0,0 +1,165 @@
+const lang = {
+ "en": {
+ "server": "Server",
+ "website": "Website",
+ "username": "Username",
+ "email": "Email",
+ "password": "Password",
+ "signin": "Sign in",
+ "signup": "Sign up",
+ "signout": "Sign out",
+ "okay": "Okay",
+ "add": "Add",
+ "change": "Change",
+ "use": "Use",
+ "copy": "Copy",
+ "cancel": "Cancel",
+ "try_again": "Try again",
+ "success": "SUCCESS",
+ "error": "ERROR",
+ "delete": "Delete",
+ "import": "Import",
+ "import_from": "Import from {name}",
+ "import_invalid": "Data in import is invalid!",
+ "import_success": "{success_number} passwords has been successfully imported!",
+ "import_errors": "{success_number} passwords has been successfully imported, but {error_number} passwords has not been imported!",
+ "backup": "Backup",
+ "export": "Export",
+ "passwords": "Passwords",
+ "import_export": "Import & Export",
+ "theme": "Theme",
+ "search": "Search",
+ "length": "Length",
+ "add_password": "Add password",
+ "add_password_success": "Password has been added successfully",
+ "change_password_success": "Password has been changed successfully",
+ "remove_password_success": "Password has been removed successfully",
+ "edit_password": "Edit password",
+ "password_generator": "Password Generator",
+ "delete_password": "Delete password",
+ "delete_password_confirmation": "Are you sure you want to delete your password? Your password will be permanently removed from server forever. This action cannot be undone.",
+ "delete_account": "Delete account",
+ "delete_account_info": "Once you delete your account, you will lose all data associated with it.",
+ "delete_account_confirmation": "Are you sure you want to delete your account? All of your data will be permanently removed from server forever. This action cannot be undone.",
+ "url_invalid": "Server url is invalid!",
+ "server_unreachable": "Server is unreachable!",
+ "registration_completed": "Registration is completed!",
+ "dont_have_account_link": "Don't have account yet? Sign up here.",
+ "already_have_account_link": "Already have account? Sign in here.",
+ "username_validation": "Username must be between 3 and 255 character long and can't contain spaces!",
+ "username_validation2": "Username can't contains provided special characters: ' \" \\",
+ "password_validation": "Password must be between 8 and 255 character long and can't contain spaces!",
+ "password_validation2": "Password can't contains provided special characters: ' \" \\",
+ "website_validation": "Website much be between 5 and 255 character long and can't contain spaces!",
+ "website_validation2": "Website can't contains provided special characters: ' \" \\"
+ },
+ "sl": {
+ "server": "Strežnik",
+ "website": "Spletna stran",
+ "username": "Uporabniško ime",
+ "email": "E-naslov",
+ "password": "Geslo",
+ "signin": "Vpis",
+ "signup": "Prijava",
+ "signout": "Odjava",
+ "okay": "Okay",
+ "add": "Dodaj",
+ "change": "Spremeni",
+ "use": "Uporabi",
+ "copy": "Kopiraj",
+ "cancel": "Prekliči",
+ "try_again": "Poskusite znova",
+ "success": "USPEH",
+ "error": "NAPAKA",
+ "delete": "Izbriši",
+ "import": "Uvozi",
+ "import_from": "Uvozi iz {name}",
+ "import_invalid": "Podatki pri uvozu so neveljavni!",
+ "import_success": "{success_number} gesla so bila uspešno uvožena! ",
+ "import_errors": "{success_number} gesel je bilo uspešno uvoženih, {error_number} gesel pa ni bilo uvoženih!",
+ "backup": "Rezerva",
+ "export": "Izvoz",
+ "passwords": "Gesla",
+ "import_export": "Uvoz in Izvoz",
+ "theme": "Tema",
+ "search": "Iskanje",
+ "length": "Dolžina",
+ "add_password": "Dodaj geslo",
+ "add_password_success": "Geslo je bilo uspešno dodano",
+ "change_password_success": "Geslo je bilo uspešno spremenjeno",
+ "remove_password_success": "Geslo je bilo uspešno odstranjeno",
+ "edit_password": "Uredi geslo",
+ "password_generator": "Generator gesel",
+ "delete_password": "Izbriši geslo",
+ "delete_password_confirmation": "Ali ste prepričani, da želite izbrisati geslo? Vaše geslo bo za vedno odstranjeno s strežnika. Tega dejanja ni mogoče razveljaviti.",
+ "delete_account": "Izbriši račun",
+ "delete_account_info": "Ko izbrišete račun, boste izgubili vse podatke, povezane z njim.",
+ "delete_account_confirmation": "Ali ste prepričani, da želite izbrisati svoj račun? Vsi vaši podatki bodo za vedno odstranjeni s strežnika. Tega dejanja ni mogoče razveljaviti.",
+ "url_invalid": "URL strežnika ni veljaven!",
+ "server_unreachable": "Strežnik je nedosegljiv!",
+ "registration_completed": "Registracija je končana!",
+ "dont_have_account_link": "Še nimate računa? Prijavite se tukaj.",
+ "already_have_account_link": "Že imate račun? Prijavite se tukaj.",
+ "username_validation": "Uporabniško ime mora biti dolgo med 3 in 255 znaki in ne sme vsebovati presledkov!",
+ "username_validation2": "Uporabniško ime ne more vsebovati predvidenih posebnih znakov: ' \" \\",
+ "password_validation": "Geslo mora biti dolgo med 8 in 255 znaki in ne sme vsebovati presledkov!",
+ "password_validation2": "Geslo ne more vsebovati predvidenih posebnih znakov: ' \" \\",
+ "website_validation": "Spletno mesto mora biti dolgo med 5 in 255 znaki in ne sme vsebovati presledkov!",
+ "website_validation2": "Spletno mesto ne more vsebovati predvidenih posebnih znakov: ' \" \\"
+ }
+}
+
+const errors = {
+ "en": {
+ "0": "Successful",
+ "1": "Username is invalid!",
+ "2": "Password is incorrect!",
+ "3": "Something went wrong while inserting data to database!",
+ "4": "Username is already registered!",
+ "5": "Password must be between 8 and 255 characters long and have at least one letter, one number and one special character!",
+ "6": "Email is invalid!",
+ "7": "Username doesn't exist!",
+ "8": "You don't have any saved password.",
+ "9": "Domain is invalid!",
+ "10": "User does not own this password!",
+ "11": "Something went wrong while deleting data from database!",
+ "12": "Username must be between 6 and 30 characters long and can only contains letters, numbers and dots!",
+ "13": "Something went wrong while updating data in database!",
+ "14": "Json is invalid!",
+ "15": "This server can't accept more users!",
+ "16": "You have reached maximum amount of stored passwords!",
+ "400": "Action was not provided in POST!",
+ "401": "Action is invalid!",
+ "403": "You didn't provide all required values in POST.",
+ "404": "Can't connect into API.",
+ "429": "You are sending too many requests! Please wait some time before executing this action.",
+ "505": "Something went wrong while connecting to database!",
+ "999": "You don't have permission to use this endpoint."
+ },
+ "sl": {
+ "0": "Uspešno",
+ "1": "Uporabniško ime je neveljavno!",
+ "2": "Geslo je napačno!",
+ "3": "Med vstavljanjem podatkov v bazo podatkov je prišlo do napake!",
+ "4": "Uporabniško ime je že registrirano!",
+ "5": "Geslo mora biti dolgo med 8 in 255 znaki in mora vsebovati vsaj eno črko, eno številko in en poseben znak!",
+ "6": "E-pošta je neveljavna!",
+ "7": "Uporabniško ime ne obstaja!",
+ "8": "Nimate shranjenega gesla.",
+ "9": "Domena je neveljavna!",
+ "10": "Uporabnik ni lastnik tega gesla!",
+ "11": "Med brisanjem podatkov iz baze podatkov je prišlo do napake!",
+ "12": "Uporabniško ime mora biti dolgo med 6 in 30 znakov in lahko vsebuje samo črke, številke in pike!",
+ "13": "Med posodabljanjem podatkov v bazi je prišlo do napake!",
+ "14": "Json je neveljaven!",
+ "15": "Ta strežnik ne more sprejeti več uporabnikov!",
+ "16": "Dosegli ste največjo količino shranjenih gesel!",
+ "400": "Akcija ni bila zagotovljena v POST-u!",
+ "401": "Dejanje je neveljavno!",
+ "403": "V POST niste navedli vseh zahtevanih vrednosti. ",
+ "404": "Ne morem se povezati z API-jem.",
+ "429": "Pošiljate preveč zahtev! Počakajte nekaj časa, preden izvedete to dejanje. ",
+ "505": "Med povezovanjem z bazo podatkov je prišlo do napake!",
+ "999": "Nimate dovoljenja za uporabo te točke."
+ }
+}
\ No newline at end of file
diff --git a/js/login.js b/js/login.js
index cb1d48f..562933f 100644
--- a/js/login.js
+++ b/js/login.js
@@ -3,6 +3,15 @@ if(localStorage.url !== null && typeof(localStorage.url) !== 'undefined' && loca
if(localStorage.url !== null && typeof(localStorage.url) !== 'undefined') document.getElementById('passky-server').value = localStorage.url;
if(localStorage.username !== null && typeof(localStorage.username) !== 'undefined') document.getElementById('username').value = localStorage.username;
+//Languages
+document.getElementById("passky-server").placeholder = lang[localStorage.lang]["server"];
+document.getElementById("username").placeholder = lang[localStorage.lang]["username"];
+document.getElementById("password").placeholder = lang[localStorage.lang]["password"];
+document.getElementById("btn_signin").innerText = lang[localStorage.lang]["signin"];
+document.getElementById("error-dialog-modal-title").innerText = lang[localStorage.lang]["error"];
+document.getElementById("dont_have_account_link").innerText = lang[localStorage.lang]["dont_have_account_link"];
+document.getElementById("error-dialog-okay").innerText = lang[localStorage.lang]["okay"];
+
document.getElementById("login_form").addEventListener("submit", e => {
e.preventDefault();
onBtnClick();
@@ -21,19 +30,19 @@ function onBtnClick(){
if(url.length == 0 || username.length == 0 || password.length == 0) return;
if(!/^[a-z0-9.]{6,30}$/i.test(username)){
- setText('error-dialog-modal-text', "Username must be between 6 and 30 characters long and can only contains letters, numbers and dots!");
+ setText('error-dialog-modal-text', errors[localStorage.lang]["12"]);
show('error-dialog');
return;
}
if(!/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,255}$/i.test(password)){
- setText('error-dialog-modal-text', "Password must be between 8 and 255 characters long and have at least one letter, one number and one special character!");
+ setText('error-dialog-modal-text', errors[localStorage.lang]["5"]);
show('error-dialog');
return;
}
if(!validURL(url)){
- setText('error-dialog-modal-text', "Server url is invalid!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["url_invalid"]);
show('error-dialog');
return;
}
@@ -49,20 +58,20 @@ function onBtnClick(){
if(xhr.readyState === 4){
if(xhr.status != 200){
- setText('error-dialog-modal-text', "Server is unreachable!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["server_unreachable"]);
show('error-dialog');
return;
}
var json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- setText('error-dialog-modal-text', "Server is unreachable!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["server_unreachable"]);
show('error-dialog');
return;
}
if(json['error'] != 0 && json['error'] != 8){
- setText('error-dialog-modal-text', errors[json['error']]);
+ setText('error-dialog-modal-text', errors[localStorage.lang][json['error']]);
show('error-dialog');
return;
}
diff --git a/js/passwords.js b/js/passwords.js
index b801080..05a29f7 100644
--- a/js/passwords.js
+++ b/js/passwords.js
@@ -1,3 +1,42 @@
+document.getElementById("passwords-link").innerText = lang[localStorage.lang]["passwords"];
+document.getElementById("import-export-link").innerText = lang[localStorage.lang]["import_export"];
+document.getElementById("signout-link").innerText = lang[localStorage.lang]["signout"];
+
+document.getElementById("passwords-link-mobile").innerText = lang[localStorage.lang]["passwords"];
+document.getElementById("import-export-link-mobile").innerText = lang[localStorage.lang]["import_export"];
+document.getElementById("signout-link-mobile").innerText = lang[localStorage.lang]["signout"];
+
+switch(localStorage.theme){
+ case "light":
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Light)";
+ break;
+ default:
+ document.getElementById("theme-link").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ document.getElementById("theme-link-mobile").innerText = lang[localStorage.lang]["theme"] + " (Dark)";
+ break;
+}
+
+switch(localStorage.lang){
+ case "sl":
+ document.getElementById("lang-link").innerText = "Language (Slovenian)";
+ document.getElementById("lang-link-mobile").innerText = "Language (Slovenian)";
+ break;
+ default:
+ document.getElementById("lang-link").innerText = "Language (English)";
+ document.getElementById("lang-link-mobile").innerText = "Language (English)";
+ break;
+}
+
+document.getElementById("search").placeholder = lang[localStorage.lang]["search"];
+document.getElementById("add-password-btn").innerText = lang[localStorage.lang]["add_password"];
+
+document.getElementById("delete-account-title").innerText = lang[localStorage.lang]["delete_account"];
+document.getElementById("delete-account-text").innerText = lang[localStorage.lang]["delete_account_info"];
+document.getElementById("delete-account-btn").innerText = lang[localStorage.lang]["delete_account"];
+
+document.getElementById("dialog-button-cancel").innerText = lang[localStorage.lang]["cancel"];
+
function displayPasswords(){
let html_passwords = "";
@@ -53,9 +92,7 @@ function displayPasswords(){
show('dialog');
});
}
-
}
-
}
displayPasswords();
@@ -94,6 +131,14 @@ document.getElementById("theme-link-mobile").addEventListener("click", () => {
changeTheme();
});
+document.getElementById("lang-link").addEventListener("click", () => {
+ changeLanguage();
+});
+
+document.getElementById("lang-link-mobile").addEventListener("click", () => {
+ changeLanguage();
+});
+
document.getElementById("main-menu-toggle-btn").addEventListener("click", () => {
toggleMenu();
});
@@ -152,11 +197,11 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "Delete account";
- document.getElementById('dialog-text').innerText = "Are you sure you want to delete your account? All of your data will be permanently removed from server forever. This action cannot be undone.";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["delete_account"];
+ document.getElementById('dialog-text').innerText = lang[localStorage.lang]["delete_account_confirmation"];
document.getElementById('dialog-button').className = "dangerButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Delete";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["delete"];
document.getElementById('dialog-button').onclick = () => deleteAccount();
break;
case 2:
@@ -164,11 +209,11 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "ERROR";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["error"];
document.getElementById('dialog-text').innerText = text;
document.getElementById('dialog-button').className = "dangerButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Try again";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["try_again"];
document.getElementById('dialog-button').onclick = () => changeDialog(0);
break;
case 3:
@@ -176,15 +221,15 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "SUCCESS";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["success"];
- let message = "Password has been added successfully";
+ let message = lang[localStorage.lang]["add_password_success"];
switch(text){
case 1:
- message = "Password has been changed successfully";
+ message = lang[localStorage.lang]["change_password_success"];
break;
case 2:
- message = "Password has been removed successfully";
+ message = lang[localStorage.lang]["remove_password_success"];
break;
}
document.getElementById('dialog-text').innerText = message;
@@ -192,7 +237,7 @@ function changeDialog(style, text){
document.getElementById('dialog-button-cancel').style.display = 'none';
document.getElementById('dialog-button').className = "successButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Okay";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["okay"];
document.getElementById('dialog-button').onclick = () => refreshPasswords();
break;
case 4:
@@ -202,12 +247,12 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "Edit password";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["edit_password"];
- document.getElementById('dialog-text').innerHTML = "
";
+ document.getElementById('dialog-text').innerHTML = "
";
document.getElementById('dialog-button').className = "primaryButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Change";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["change"];
document.getElementById('dialog-button').onclick = () => editPassword(e_data[0]);
document.getElementById('btn-password-generator').onclick = () => changeDialog(5, text);
@@ -223,9 +268,9 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "Password Generator";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["password_generator"];
- document.getElementById('dialog-text').innerHTML = "
A-Z
0-9
!@#$%?&*
Length
";
+ document.getElementById('dialog-text').innerHTML = "
A-Z
0-9
!@#$%?&*
" + lang[localStorage.lang]["length"] + "
";
document.getElementById('dialog-button').className = "primaryButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
@@ -251,16 +296,16 @@ function changeDialog(style, text){
}
if(pg_data[0] == null){
- document.getElementById('dialog-button').innerText = "Copy";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["copy"];
document.getElementById('dialog-button').onclick = () => copyToClipboard(document.getElementById('generated-password').innerText);
}else if(pg_data[0] == "-1"){
- document.getElementById('dialog-button').innerText = "Use";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["use"];
document.getElementById('dialog-button').onclick = () => {
text = pg_data[0] + " " + pg_data[1] + " " + pg_data[2] + " " + document.getElementById('generated-password').innerText;
changeDialog(0, text);
}
}else{
- document.getElementById('dialog-button').innerText = "Use";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["use"];
document.getElementById('dialog-button').onclick = () => {
text = pg_data[0] + " " + pg_data[1] + " " + pg_data[2] + " " + document.getElementById('generated-password').innerText;
changeDialog(4, text);
@@ -276,11 +321,11 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "Delete password";
- document.getElementById('dialog-text').innerText = "Are you sure you want to delete your password? Your password will be permanently removed from server forever. This action cannot be undone.";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["delete_password"];
+ document.getElementById('dialog-text').innerText = lang[localStorage.lang]["delete_password_confirmation"];
document.getElementById('dialog-button').className = "dangerButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Delete";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["delete"];
document.getElementById('dialog-button').onclick = () => deletePassword(text);
break;
default:
@@ -288,12 +333,12 @@ function changeDialog(style, text){
document.getElementById('dialog-icon').className = "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10";
document.getElementById('dialog-icon').innerHTML = "
";
- document.getElementById('dialog-title').innerText = "Add password";
+ document.getElementById('dialog-title').innerText = lang[localStorage.lang]["add_password"];
- document.getElementById('dialog-text').innerHTML = "
";
+ document.getElementById('dialog-text').innerHTML = "
";
document.getElementById('dialog-button').className = "primaryButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm";
- document.getElementById('dialog-button').innerText = "Add";
+ document.getElementById('dialog-button').innerText = lang[localStorage.lang]["add"];
document.getElementById('dialog-button').onclick = () => addPassword();
if(text != null){
@@ -317,6 +362,8 @@ function changeDialog(style, text){
}
function addPassword(){
+ check_login();
+
const website = document.getElementById("website").value;
const username = document.getElementById("username").value;
let password = document.getElementById("password").value;
@@ -324,37 +371,32 @@ function addPassword(){
if(website.length == 0 || username.length == 0 || password.length == 0) return;
if(!(username.length >= 3 && username.length <= 255) || username.includes(" ")){
- changeDialog(2, "Username must be between 3 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["username_validation"]);
return;
}
if(username.includes("'") || username.includes('"') || username.includes("\\")){
- changeDialog(2, "Username can't contains provided special characters: ' \" \\");
+ changeDialog(2, lang[localStorage.lang]["username_validation2"]);
return;
}
if(!(password.length >= 8 && password.length <= 255) || password.includes(" ")){
- changeDialog(2, "Password must be between 8 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["password_validation"]);
return;
}
if(password.includes("'") || password.includes('"') || password.includes("\\")){
- changeDialog(2, "Password can't contains provided special characters: ' \" \\");
+ changeDialog(2, lang[localStorage.lang]["password_validation2"]);
return;
}
if(!(website.length >= 5 && website.length <= 255) || website.includes(" ")){
- changeDialog(2, "Website much be between 5 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["website_validation"]);
return;
}
if(website.includes("'") || website.includes('"') || website.includes("\\")){
- changeDialog(2, "Website can't contains provided special characters: ' \" \\");
- return;
- }
-
- if(localStorage.url === null || typeof(localStorage.url) === 'undefined' || localStorage.username === null || typeof(localStorage.username) === 'undefined' || localStorage.password === null || typeof(localStorage.password) === 'undefined'){
- changeDialog(2, "Session has expired please sign in again!");
+ changeDialog(2, lang[localStorage.lang]["website_validation2"]);
return;
}
@@ -371,19 +413,19 @@ function addPassword(){
if(xhr.readyState === 4){
if(xhr.status != 200){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
const json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
if(json['error'] != 0){
- changeDialog(2, errors[json['error']]);
+ changeDialog(2, errors[localStorage.lang][json['error']]);
return;
}
@@ -395,6 +437,8 @@ function addPassword(){
}
function editPassword(password_id){
+ check_login();
+
const website = document.getElementById("website").value;
const username = document.getElementById("username").value;
let password = document.getElementById("password").value;
@@ -402,37 +446,32 @@ function editPassword(password_id){
if(password_id.length == 0 || website.length == 0 || username.length == 0 || password.length == 0) return;
if(!(username.length >= 3 && username.length <= 255) || username.includes(" ")){
- changeDialog(2, "Username must be between 3 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["username_validation"]);
return;
}
if(username.includes("'") || username.includes('"') || username.includes("\\")){
- changeDialog(2, "Username can't contains provided special characters: ' \" \\");
+ changeDialog(2, lang[localStorage.lang]["username_validation2"]);
return;
}
if(!(password.length >= 8 && password.length <= 255) || password.includes(" ")){
- changeDialog(2, "Password must be between 8 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["password_validation"]);
return;
}
if(password.includes("'") || password.includes('"') || password.includes("\\")){
- changeDialog(2, "Password can't contains provided special characters: ' \" \\");
+ changeDialog(2, lang[localStorage.lang]["password_validation2"]);
return;
}
if(!(website.length >= 5 && website.length <= 255) || website.includes(" ")){
- changeDialog(2, "Website much be between 5 and 255 character long and can't contain spaces!");
+ changeDialog(2, lang[localStorage.lang]["website_validation"]);
return;
}
if(website.includes("'") || website.includes('"') || website.includes("\\")){
- changeDialog(2, "Website can't contains provided special characters: ' \" \\");
- return;
- }
-
- if(localStorage.url === null || typeof(localStorage.url) === 'undefined' || localStorage.username === null || typeof(localStorage.username) === 'undefined' || localStorage.password === null || typeof(localStorage.password) === 'undefined'){
- changeDialog(2, "Session has expired please sign in again!");
+ changeDialog(2, lang[localStorage.lang]["website_validation2"]);
return;
}
@@ -449,19 +488,19 @@ function editPassword(password_id){
if(xhr.readyState === 4){
if(xhr.status != 200){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
const json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
if(json['error'] != 0){
- changeDialog(2, errors[json['error']]);
+ changeDialog(2, errors[localStorage.lang][json['error']]);
return;
}
@@ -484,19 +523,19 @@ function deletePassword(password_id){
if(xhr.readyState === 4){
if(xhr.status != 200){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
const json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- changeDialog(2, "Server is unreachable!");
+ changeDialog(2, lang[localStorage.lang]["server_unreachable"]);
return;
}
if(json['error'] != 0){
- changeDialog(2, errors[json['error']]);
+ changeDialog(2, errors[localStorage.lang][json['error']]);
return;
}
diff --git a/js/register.js b/js/register.js
index c79f1d0..d47a8cb 100644
--- a/js/register.js
+++ b/js/register.js
@@ -1,5 +1,14 @@
if(localStorage.url !== null && typeof(localStorage.url) !== 'undefined') document.getElementById('passky-server').value = localStorage.url;
+document.getElementById("passky-server").placeholder = lang[localStorage.lang]["server"];
+document.getElementById("username").placeholder = lang[localStorage.lang]["username"];
+document.getElementById("email").placeholder = lang[localStorage.lang]["email"];
+document.getElementById("password").placeholder = lang[localStorage.lang]["password"];
+document.getElementById("btn-dialog").innerText = lang[localStorage.lang]["okay"];
+document.getElementById("error-dialog-modal-title").innerText = lang[localStorage.lang]["error"];
+document.getElementById("btn_signup").innerText = lang[localStorage.lang]["signup"];
+document.getElementById("already_have_account_link").innerText = lang[localStorage.lang]["already_have_account_link"];
+
document.getElementById("signup-form").addEventListener("submit", e => {
e.preventDefault();
onBtnClick();
@@ -19,25 +28,25 @@ function onBtnClick(){
if(url.length == 0 || username.length == 0 || email.length == 0 || password.length == 0) return;
if(!/^[a-z0-9.]{6,30}$/i.test(username)){
- setText('error-dialog-modal-text', "Username must be between 6 and 30 characters long and can only contains letters, numbers and dots!");
+ setText('error-dialog-modal-text', errors[localStorage.lang]["12"]);
show('error-dialog');
return;
}
if(!/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,255}$/i.test(password)){
- setText('error-dialog-modal-text', "Password must be between 8 and 255 characters long and have at least one letter, one number and one special character!");
+ setText('error-dialog-modal-text', errors[localStorage.lang]["5"]);
show('error-dialog');
return;
}
if(!validEmail(email)){
- setText('error-dialog-modal-text', "Email is invalid!");
+ setText('error-dialog-modal-text', errors[localStorage.lang]["6"]);
show('error-dialog');
return;
}
if(!validURL(url)){
- setText('error-dialog-modal-text', "Server url is invalid!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["url_invalid"]);
show('error-dialog');
return;
}
@@ -53,7 +62,7 @@ function onBtnClick(){
if(xhr.readyState === 4){
if(xhr.status != 200){
- setText('error-dialog-modal-text', "Server is unreachable!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["server_unreachable"]);
show('error-dialog');
return;
}
@@ -61,13 +70,13 @@ function onBtnClick(){
var json = JSON.parse(xhr.responseText);
if(typeof json['error'] === 'undefined'){
- setText('error-dialog-modal-text', "Server is unreachable!");
+ setText('error-dialog-modal-text', lang[localStorage.lang]["server_unreachable"]);
show('error-dialog');
return;
}
if(json['error'] != 0){
- setText('error-dialog-modal-text', errors[json['error']]);
+ setText('error-dialog-modal-text', errors[localStorage.lang][json['error']]);
show('error-dialog');
return;
}
@@ -75,8 +84,8 @@ function onBtnClick(){
localStorage.url = url;
localStorage.username = username;
- setText('error-dialog-modal-title', "SUCCESS");
- setText('error-dialog-modal-text', "Registration is completed!");
+ setText('error-dialog-modal-title', lang[localStorage.lang]["success"]);
+ setText('error-dialog-modal-text', lang[localStorage.lang]["registration_completed"]);
document.getElementById('dialog-icon').className = "mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100";
document.getElementById('dialog-icon').innerHTML = "
";
document.getElementById('btn-dialog').className = "successButton inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium sm:text-sm"
diff --git a/passwords.html b/passwords.html
index b94721f..50d10a1 100644
--- a/passwords.html
+++ b/passwords.html
@@ -9,6 +9,7 @@
+
@@ -23,15 +24,18 @@
-
+
Passwords
-
+
Import & Export
Theme
+
+ Language
+
Sign out
@@ -61,9 +65,10 @@
@@ -84,11 +89,11 @@
-
+
Delete your account
-
+
Once you delete your account, you will lose all data associated with it.
diff --git a/register.html b/register.html
index 92f0e50..c8c3bf6 100644
--- a/register.html
+++ b/register.html
@@ -9,6 +9,7 @@
+
@@ -73,10 +74,10 @@