diff --git a/package-lock.json b/package-lock.json index c53d535..af2db25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,12 @@ "electron-is-dev": "^2.0.0", "electron-packager": "^15.5.1", "file-saver": "^2.0.5", + "i18next": "^22.4.5", + "i18next-browser-languagedetector": "^7.0.1", + "i18next-http-backend": "^2.1.0", "react": "^18.1.0", "react-dom": "^18.1.0", + "react-i18next": "^12.1.1", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", @@ -1803,11 +1807,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", + "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" @@ -5444,6 +5448,14 @@ "yarn": ">=1" } }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8542,6 +8554,14 @@ "node": ">= 12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -8681,6 +8701,44 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "22.4.5", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.5.tgz", + "integrity": "sha512-Kc+Ow0guRetUq+kv02tj0Yof9zveROPBAmJ8UxxNODLVBRSwsM4iD0Gw3BEieOmkWemF6clU3K1fbnCuTqiN2Q==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.20.6" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz", + "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==", + "dependencies": { + "@babel/runtime": "^7.19.4" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.0.tgz", + "integrity": "sha512-rTVhhFrpnZJnNvCCdC6RjhFPk0S6mJ2VAix93vbDD19ixlrSJtoNqkk49wvR10PImBSsuGJf35gMQwn2mjer6A==", + "dependencies": { + "cross-fetch": "3.1.5" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -10808,6 +10866,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -12935,6 +13031,27 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-i18next": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", + "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", + "dependencies": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 19.0.0", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -13271,9 +13388,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -15219,6 +15336,14 @@ "node": ">= 0.8" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -17370,11 +17495,11 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", + "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", "requires": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" } }, "@babel/runtime-corejs3": { @@ -20060,6 +20185,14 @@ "cross-spawn": "^7.0.1" } }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -22335,6 +22468,14 @@ } } }, + "html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "requires": { + "void-elements": "3.1.0" + } + }, "html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -22431,6 +22572,30 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, + "i18next": { + "version": "22.4.5", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.5.tgz", + "integrity": "sha512-Kc+Ow0guRetUq+kv02tj0Yof9zveROPBAmJ8UxxNODLVBRSwsM4iD0Gw3BEieOmkWemF6clU3K1fbnCuTqiN2Q==", + "requires": { + "@babel/runtime": "^7.20.6" + } + }, + "i18next-browser-languagedetector": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz", + "integrity": "sha512-Pa5kFwaczXJAeHE56CHG2aWzFBMJNUNghf0Pm4SwSrEMps/PTKqW90EYWlIvhuYStf3Sn1K0vw+gH3+TLdkH1g==", + "requires": { + "@babel/runtime": "^7.19.4" + } + }, + "i18next-http-backend": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.1.0.tgz", + "integrity": "sha512-rTVhhFrpnZJnNvCCdC6RjhFPk0S6mJ2VAix93vbDD19ixlrSJtoNqkk49wvR10PImBSsuGJf35gMQwn2mjer6A==", + "requires": { + "cross-fetch": "3.1.5" + } + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -24004,6 +24169,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -25411,6 +25605,15 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "react-i18next": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", + "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", + "requires": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -25669,9 +25872,9 @@ } }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { "version": "0.15.0", @@ -27143,6 +27346,11 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index e9fc6f1..2663b46 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,12 @@ "electron-is-dev": "^2.0.0", "electron-packager": "^15.5.1", "file-saver": "^2.0.5", + "i18next": "^22.4.5", + "i18next-browser-languagedetector": "^7.0.1", + "i18next-http-backend": "^2.1.0", "react": "^18.1.0", "react-dom": "^18.1.0", + "react-i18next": "^12.1.1", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", diff --git a/public/locales/en/books.json b/public/locales/en/books.json new file mode 100644 index 0000000..4b05695 --- /dev/null +++ b/public/locales/en/books.json @@ -0,0 +1,81 @@ +{ + "edit": "Edit details", + "delete": "Delete book", + "bookId": "Book ID", + "isbn": "ISBN", + "isbn10": "ISBN-10", + "isbn13": "ISBN-13", + "totalQuantity": "Total quantity", + "availableQuantity": "Available quantity", + "librarySection": "Library Section", + "title": "Title", + "titlePlaceholder": "The Parent's Dook about Bullying", + "subtitle": "Subtitle", + "subtitlePlaceholder": "Changing the Course of Your Child's Life", + "authors": "Author(s)", + "authorsPlaceholder": "William Voors", + "author": "Author", + "publisher": "Publisher", + "publisherPlaceholder": "Hazelden Publishing", + "edition": "Edition", + "editionPlaceholder": "1", + "year": "Year", + "yearOfPub": "Year of publication", + "yearOfPubPlaceholder": "2000", + "language": "Language", + "languagePlaceholder": "English", + "tagsCommaSep": "Tags (comma separated)", + "tagsPlaceholder": "family, relationships", + "tags": "Tags", + "notes": "Additional notes", + "notesPlaceholder": "Additional information", + "totalCopies": "Total copies", + "availableCopies": "Available copies", + "retailPrice": "Retail price", + "retailPlaceholder": "10.99", + "libraryPrice": "Library price", + "libraryPlaceholder": "6.99", + "currencySymbol": "$", + "section": "Section in library", + "image": "Image link", + "additionalNotes": "Additional notes", + "currentLoans": "Current loans", + "noLoans": "No outstanding loans found", + "loanerId": "Loaner ID", + "fullName": "Full name", + "copies": "Copies", + "borrowDate": "Borrow date", + "dueDate": "Due date", + "missingFilter": "Searching requires a filter", + "searchBy": "Search by", + "noFilter": "No Filter", + "searchTerm": "Search term", + "searchTermPlaceholder": "Your search term goes here", + "search": "Search", + "notFound": "No books found", + "by": "by {{authors}}", + "section:": "Section: {{section}}", + "enterIsbn": "Enter ISBN before searching!", + "detailsNotFound": "Details not found! Please fill manually.", + "detailsPopulated": "Details populated! You may edit them accordingly.", + "preFill": "Pre-fill using ISBN", + "add": "Add book", + "editBook": "Edit book", + "update": "Update", + "deleteResp": { + "200": "Book deleted successfully", + "404": "Book not found", + "400": "Cannot delete book with outstanding loans", + "unspecific": "Something went wrong" + }, + "createResp": { + "200": "Book added successfully", + "400": "{{errorMessage}}", + "unspecific": "Something went wrong" + }, + "updateResp": { + "200": "Book updated successfully", + "400": "{{errorMessage}}", + "unspecific": "Something went wrong" + } +} \ No newline at end of file diff --git a/public/locales/en/common.json b/public/locales/en/common.json new file mode 100644 index 0000000..53eea04 --- /dev/null +++ b/public/locales/en/common.json @@ -0,0 +1,43 @@ +{ + "loginHeader": "Login to BudLib", + "emailPlaceholder": "Enter Email Address...", + "passwordPlaceholder": "Password", + "loginButton": "Login", + "appName": "BudLib", + "profile": "Profile", + "logout": "Logout", + "cancel": "Cancel", + "clear": "Clear", + "admin": "Admin", + "books": "Books", + "loaners": "Loaners", + "heading": "Home", + "transact": "Transact", + "borrowBooks": "Borrow books", + "returnBooks": "Return books", + "extendBooks": "Extend books", + "pastTransactions": "Past transactions", + "database": "Database", + "searchBooks": "Search books", + "addBook": "Add a book", + "searchLoaners": "Search loaners", + "addLoaner": "Add a loaner", + "dashboard": "Dashboard", + "dashboardHome": "Dashboard home", + "librarianManagement": "Librarian management", + "expiredSession": "Your session has expired. Please login again.", + "alert": "Alert", + "confirmLogout": "Are you sure you want to logout?", + "footer": "BudLib OpenSource Library System", + "pageNotFound": "Page not found", + "backToHome": "Back to home", + "PARENT_LIBRARY": "Parent Library", + "FACULTY_LIBRARY": "Faculty Library", + "CLASS_SETS": "Class Sets", + "CHILDREN_LIBRARY": "Children Library", + "BORROW": "Borrow", + "RETURN": "Return", + "EXTEND": "Extend", + "ADMIN": "Admin", + "FACULTY": "Faculty" +} \ No newline at end of file diff --git a/public/locales/en/dashboard.json b/public/locales/en/dashboard.json new file mode 100644 index 0000000..063d321 --- /dev/null +++ b/public/locales/en/dashboard.json @@ -0,0 +1,65 @@ +{ + "uniqueTitles": "Unique titles", + "totalLoaners": "Lotal loaners", + "totalCopies": "Total copies of all titles", + "totalOutstanding": "Total outstanding copies", + "exportBooks": "Export all books", + "exportLoaners": "Export all loaners", + "exportLoans": "Export all outstanding loans", + "exportTransactions": "Export all transactions", + "librarianManagement": "Librarian management", + "librarianManagementDesc": "Add or update librarian or faculty", + "importBooks": "Import books", + "importBooksDesc": "Import books from CSV", + "importLoaners": "Import loaners", + "importLoanersDesc": "Import loaners from CSV", + "overdueLoans": "Overdue loans", + "noOverdueLoans": "No overdue loans", + "loaner": "Loaner", + "book": "Book", + "copies": "Copies", + "dueDate": "Due date", + "upcomingDueDates": "Upcoming due dates", + "noUpcomingDueDates": "No upcoming due date until next week", + "cannotReadFile": "Uploaded file cannot be read", + "booksRes": { + "200": "{{responseMessage}}", + "unspecific": "Something went wrong" + }, + "loanersRes": { + "200": "{{responseMessage}}", + "unspecific": "Something went wrong" + }, + "bookImportNote": "Note: The recommended file format during import is CSV. Please make sure that the file is in the correct format. A sample file can be downloaded from <2>this link. The mandatory fields are title, isbn_10 or isbn_13, library_section, totalQuantity, and availableQuantity.", + "loanerImportNote": "Note: The recommended file format during import is CSV. Please make sure that the file is in the correct format. A sample file can be downloaded from <2>this link. The mandatory fields are isStudent and firstName.", + "noFile": "No file uploaded", + "headerInFile": "Header in File", + "databaseCategory": "Database Category", + "notUsed": "not used", + "title": "title", + "subtitle": "subtitle", + "authors": "authors", + "publisher": "publisher", + "edition": "edition", + "year": "year", + "language": "language", + "isbn_10": "isbn_10", + "isbn_13": "isbn_13", + "librarySection": "library section", + "totalQuantity": "total quantity", + "availableQuantity": "available quantity", + "imageLink": "image link", + "notes": "notes", + "priceRetail": "price retail", + "priceLibrary": "price library", + "schoolId": "school ID", + "email": "email", + "isStudent": "is student", + "salutation": "salutation", + "firstName": "first name", + "middleName": "middle name", + "lastName": "last name", + "motherName": "mother's name", + "fatherName": "father's name", + "upload": "Upload File" +} \ No newline at end of file diff --git a/public/locales/en/librarians.json b/public/locales/en/librarians.json new file mode 100644 index 0000000..0106353 --- /dev/null +++ b/public/locales/en/librarians.json @@ -0,0 +1,45 @@ +{ + "addLibrarian": "Add new librarian", + "backToDashboard": "Back to dashboard", + "notFound": "No other librarians found", + "details": "Details", + "librarianId": "Librarian ID", + "username": "Username", + "email": "Email", + "role": "Role", + "firstName": "First Name", + "middleName": "Middle Name", + "lastName": "Last Name", + "createPassword": "Create password", + "confirmPassword": "Confirm password", + "changePassword": "Change password", + "editDetails": "Edit details", + "delete": "Delete Librarian", + "add": "Add Librarian", + "edit": "Edit Librarian", + "update": "Update", + "deleteResp": { + "200": "Librarian deleted successfully", + "403": "{{errorMessage}}", + "404": "Librarian not found", + "unspecific": "Something went wrong" + }, + "createResp": { + "200": "Librarian added successfully", + "400": "{{errorMessage}}", + "unspecific": "Something went wrong" + }, + "updateResp": { + "200": "Librarian updated successfully", + "400": "{{errorMessage}}", + "404": "Librarian not found", + "unspecific": "Something went wrong" + }, + "passUpdateResp": { + "200": "Password updated successfully", + "400": "{{errorMessage}}", + "404": "Librarian not found", + "unspecific": "Something went wrong" + }, + "passwordMismatch": "Password don't match" +} \ No newline at end of file diff --git a/public/locales/en/loaners.json b/public/locales/en/loaners.json new file mode 100644 index 0000000..4f09ff3 --- /dev/null +++ b/public/locales/en/loaners.json @@ -0,0 +1,74 @@ +{ + "searchLoaners": "Search loaners", + "missingFilter": "Searching requires a filter", + "searchBy": "Search by", + "noFilter": "No filter", + "id": "ID", + "parentName": "Parent's Name", + "searchTerm": "Search term", + "searchTermPlaceholder": "Your search term goes here", + "search": "Search", + "notFound": "No loaners found", + "loanerId": "Loaner ID", + "schoolId": "School ID", + "employeeId": "Employee ID", + "name": "Name", + "firstName": "First Name", + "firstNamePlaceholder": "John", + "middleName": "Middle Name", + "middleNamePlaceholder": "Michael", + "lastName": "Last Name", + "lastNamePlaceholder": "Doe", + "email": "Email", + "emailPlaceholder": "john.doe@waldorf.ca", + "fatherName": "Father's name", + "fatherNamePlaceholder": "Michael Jake Doe", + "motherName": "Mother's name", + "motherNamePlaceholder": "Emily Doe", + "type": "Type", + "loanerType": "Loaner Type", + "salutation": "Salutation", + "totalOutstanding": "Total outstanding", + "borrowedBooks": "Borrowed books", + "student": "Student", + "faculty": "Faculty", + "deleteResp": { + "200": "Loaner deleted successfully", + "404": "Loaner not found", + "400": "Cannot delete loaner with outstanding books", + "unspecific": "Something went wrong" + }, + "createResp": { + "200": "Loaner added successfully", + "400": "Loaner already exists", + "unspecific": "Something went wrong" + }, + "updateResp": { + "200": "Loaner updated successfully", + "404": "Loaner not found", + "400": "Loaner already exists", + "unspecific": "Something went wrong" + }, + "editDetails": "Edit details", + "deleteLoaner": "Delete loaner", + "details": "Details", + "loans": "Loans", + "bookIsbn": "Book ISBN", + "bookTitle": "Book title", + "copies": "Copies", + "borrowDate": "Borrow date", + "dueDate": "Due date", + "history": "History", + "transactionNumber": "Trn No", + "transactionDate": "Date", + "transactionTime": "Time", + "transactionType": "Type", + "mr": "Mr", + "ms": "Ms", + "miss": "Miss", + "mrs": "Mrs", + "dr": "Dr", + "add": "Add loaner", + "editLoaner": "Edit Loaner", + "update": "Update" +} \ No newline at end of file diff --git a/public/locales/en/transactions.json b/public/locales/en/transactions.json new file mode 100644 index 0000000..294da5a --- /dev/null +++ b/public/locales/en/transactions.json @@ -0,0 +1,61 @@ +{ + "notFound": "No transactions found", + "booksNotFound": "No books found", + "emptyCart": "Empty cart", + "noCopies": "No copies availabile", + "noMoreCopies": "No more copies availabile", + "noBooksInCart": "No books in cart to borrow", + "noMoreCopiesReturn": "No more copies to return", + "noBooksInCartReturn": "No books in cart to return", + "noBooksToExtend": "No books for providing extension", + "noLoans": "No outstanding loans", + "alreadyInCart": "Book already in cart", + "noBooksInCartToExtend": "No books in cart for providing extension", + "trnNo": "Trn No", + "date": "Date", + "time": "Time", + "type": "Type", + "loaner": "Loaner", + "removed": "", + "transactionId#": "Transaction ID: {{id}}", + "": "", + "": "", + "details": "Details", + "transactionId": "Transaction ID", + "transactionType": "Transaction type", + "transactionDate": "Transaction date", + "transactionTime": "Transaction time", + "coordinatorId": "Coordinator's ID", + "coordinatorName": "Coordinator's full name", + "coordinatorEmail": "Coordinator's email", + "loanerType": "Loaner type", + "loanerId": "Loaner ID", + "loanerSchoolId": "Loaner's school ID", + "loanerEmployeeId": "Loaner's employee ID", + "loanerName": "Loaner's full name", + "loanerEmail": "Loaner's email", + "transactedBooks": "Transacted books", + "title": "Title", + "copies": "Copies", + "outstandingBooks": "Outstanding books", + "borrowDate": "Borrow date", + "dueDate": "Due date", + "returnDate": "Return date", + "newDueDate": "New due date", + "oldDueDate": "Old due date", + "titlesInCart": "Titles in the cart", + "qty": "Qty", + "add": "Add", + "borrowBooks": "Borrow books - select loaner", + "returnBooks": "Return books - select loaner", + "extendLoans": "Provide extension - select loaner", + "extendLoan": "Provide Extension", + "select": "Select", + "completeTransaction": "Complete transaction", + "completeRes": { + "200": "Transaction completed successfully", + "400": "{{errorMessage}}", + "404": "{{errorMessage}}", + "unspecific": "Something went wrong" + } +} \ No newline at end of file diff --git a/src/components/BatchExport.js b/src/components/BatchExport.js index 9d5d64f..b5cfd7c 100644 --- a/src/components/BatchExport.js +++ b/src/components/BatchExport.js @@ -1,7 +1,10 @@ import React from 'react'; import { downloadCall } from '../helpers/downloadCall'; +import { useTranslation } from 'react-i18next'; const BatchExport = () => { + const { t } = useTranslation('dashboard'); + const exportBooks = () => { downloadCall('/api/dashboard/batch/export/books', 'budlib_books_export.csv'); }; @@ -23,28 +26,28 @@ const BatchExport = () => {
diff --git a/src/components/BookAddForm.js b/src/components/BookAddForm.js index 2435e73..b2314aa 100644 --- a/src/components/BookAddForm.js +++ b/src/components/BookAddForm.js @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { postCall } from '../helpers/postCall'; +import { useTranslation } from 'react-i18next'; function get_book_details(isbn_number) { let isbn_number_formatted = isbn_number.trim().replaceAll('-', ''); @@ -14,6 +15,8 @@ function get_book_details(isbn_number) { } const BookAddForm = () => { + const { t } = useTranslation('books'); + let navigate = useNavigate(); let defaultImg = `${process.env.PUBLIC_URL + '/images/no_image_book_v2.jpg'}`; @@ -45,7 +48,7 @@ const BookAddForm = () => { let isbnSearchInput = document.getElementById('formIsbn'); if (isbnSearchInput.value === '') { - messageSpan.innerHTML = 'Enter ISBN before searching!'; + messageSpan.innerHTML = t('enterIsbn'); messageSpan.setAttribute('display', 'inline'); messageSpan.className = 'px-4 text-danger'; } else { @@ -54,11 +57,11 @@ const BookAddForm = () => { const fetchedDetails = await get_book_details(isbnSearchInput.value); if (fetchedDetails['totalItems'] === 0) { - messageSpan.innerHTML = 'Details not found! Please fill manually.'; + messageSpan.innerHTML = t('detailsNotFound'); messageSpan.setAttribute('display', 'inline'); messageSpan.className = 'px-4 text-danger'; } else { - messageSpan.innerHTML = 'Details populated! You may edit them accordingly.'; + messageSpan.innerHTML = t('detailsPopulated'); messageSpan.setAttribute('display', 'inline'); messageSpan.className = 'px-4 text-success'; @@ -131,9 +134,13 @@ const BookAddForm = () => { // } postCall('/api/books', sendDetails).then((result) => { - window.alert(result['data']['message']); + const status = result['status']; + window.alert(t( + [`createResp.${status}`, 'createResp.unspecific'], + {errorMessage: result['data']['message']} + )); - if (result['status'] === 200) { + if (status === 200) { window.location.reload(); } }); @@ -148,7 +155,7 @@ const BookAddForm = () => {
- +
@@ -178,7 +185,7 @@ const BookAddForm = () => {
- + { />
- + {
- + { />
- + {
- +
- $ + {t('currencySymbol')}
{
- +
- $ + {t('currencySymbol')}
{
- +
- +
{
- + { @@ -360,12 +367,12 @@ const BookAddForm = () => { />
- + { @@ -377,12 +384,12 @@ const BookAddForm = () => {
- + { @@ -391,12 +398,12 @@ const BookAddForm = () => { />
- + { @@ -408,12 +415,12 @@ const BookAddForm = () => {
- + { @@ -422,12 +429,12 @@ const BookAddForm = () => { />
- + { @@ -436,12 +443,12 @@ const BookAddForm = () => { />
- + { @@ -453,12 +460,12 @@ const BookAddForm = () => {
- + { @@ -471,13 +478,13 @@ const BookAddForm = () => {
- +