From 1e5edc7434a07f44f539983e3a9c993ef63b3f38 Mon Sep 17 00:00:00 2001
From: sephrat <34862846+sephrat@users.noreply.github.com>
Date: Thu, 29 Apr 2021 18:22:45 +0200
Subject: [PATCH] More localization (#358)
* Translate missing items on About page
* Localize import summary dialog
* Make site menu translation reactive
* Localize import options
* Include semi colon in string
* Move API texts to frontend + better status codes
* Provide feedback to user when no meal is planned
* Fix API tests after latest rework
* Add warning for API changes in changelog
* Refactor API texts handling
* Refactor API texts handling #2
* Better API feedback
* Rearrange strings hierarchy
* Add messages upon recipe updated
* Fix 'recipe effected' typo
* Remove snackbar usage in backend
* Translate toolbox
* Provide feedback for tags CRUD
* Fix messed up merge
* Translate sign-up form
* Better feedback for sign-up CRUD
* Refactor log-in API texts handling
* No error message when user is not authenticated
* Remove unimportant console log
---
docs/docs/changelog/v0.5.0.md | 7 +-
frontend/src/api/api-utils.js | 92 ++++------
frontend/src/api/backup.js | 16 +-
frontend/src/api/category.js | 82 ++++++---
frontend/src/api/groups.js | 56 ++++--
frontend/src/api/mealplan.js | 30 +++-
frontend/src/api/migration.js | 10 +-
frontend/src/api/recipe.js | 79 ++++++---
frontend/src/api/signUps.js | 21 ++-
frontend/src/api/siteSettings.js | 48 +++--
frontend/src/api/themes.js | 27 ++-
frontend/src/api/upload.js | 15 +-
frontend/src/api/users.js | 72 +++++---
.../FormHelpers/CategoryTagSelector.vue | 2 +-
.../components/ImportSummaryDialog/index.vue | 44 +++--
frontend/src/components/Login/LoginForm.vue | 12 +-
frontend/src/components/Login/SignUpForm.vue | 32 ++--
.../components/MealPlan/MealPlanEditor.vue | 5 +-
.../src/components/MealPlan/MealPlanNew.vue | 11 +-
.../Recipe/Parts/Helpers/ImageUploadBtn.vue | 7 +-
.../components/Recipe/RecipeEditor/index.vue | 2 +-
.../components/Recipe/RecipeViewer/index.vue | 4 +-
.../components/UI/Buttons/TheUploadBtn.vue | 6 +-
frontend/src/components/UI/TheRecipeFab.vue | 18 +-
frontend/src/components/UI/TheSiteMenu.vue | 12 +-
frontend/src/locales/messages/en-US.json | 167 ++++++++++++++----
frontend/src/pages/Admin/About/index.vue | 4 +-
.../Admin/Backup/AvailableBackupCard.vue | 18 +-
.../src/pages/Admin/Backup/ImportOptions.vue | 2 +-
.../src/pages/Admin/Backup/NewBackupCard.vue | 9 +-
.../src/pages/Admin/ManageUsers/GroupCard.vue | 11 +-
.../Admin/ManageUsers/GroupDashboard.vue | 11 +-
.../Admin/ManageUsers/TheSignUpTable.vue | 15 +-
.../pages/Admin/ManageUsers/TheUserTable.vue | 29 ++-
.../src/pages/Admin/ManageUsers/index.vue | 4 +-
.../src/pages/Admin/MealPlanner/index.vue | 7 +-
.../pages/Admin/Migration/MigrationCard.vue | 7 +-
frontend/src/pages/Admin/Profile/index.vue | 20 ++-
.../pages/Admin/Settings/CreatePageDialog.vue | 14 +-
.../Admin/Settings/CustomPageCreator.vue | 5 +-
.../pages/Admin/Settings/HomePageSettings.vue | 7 +-
frontend/src/pages/Admin/Theme/ThemeCard.vue | 10 +-
frontend/src/pages/Admin/Theme/index.vue | 12 +-
.../ToolBox/CategoryTagEditor/BulkAssign.vue | 6 +-
.../CategoryTagEditor/RemoveUnused.vue | 2 +-
.../Admin/ToolBox/CategoryTagEditor/index.vue | 11 +-
frontend/src/pages/Admin/ToolBox/index.vue | 2 +-
frontend/src/pages/MealPlan/Planner.vue | 5 +-
frontend/src/pages/MealPlan/ThisWeek.vue | 4 +
frontend/src/pages/Recipe/NewRecipe.vue | 2 +-
frontend/src/pages/Recipe/ViewRecipe.vue | 19 +-
frontend/src/pages/SearchPage/index.vue | 2 +-
frontend/src/routes/meal.js | 16 +-
mealie/routes/backup_routes.py | 59 +++----
mealie/routes/groups/crud.py | 27 +--
mealie/routes/mealplans/crud.py | 36 ++--
mealie/routes/migration_routes.py | 18 +-
mealie/routes/recipe/category_routes.py | 20 ++-
mealie/routes/recipe/recipe_assets.py | 17 +-
mealie/routes/recipe/recipe_crud_routes.py | 10 +-
mealie/routes/recipe/tag_routes.py | 8 +-
mealie/routes/site_settings/custom_pages.py | 6 +-
mealie/routes/site_settings/site_settings.py | 3 -
mealie/routes/theme_routes.py | 19 +-
mealie/routes/users/auth.py | 7 +-
mealie/routes/users/crud.py | 47 +++--
mealie/routes/users/sign_up.py | 33 ++--
mealie/routes/utility_routes.py | 9 +-
mealie/schema/snackbar.py | 26 ---
tests/integration_tests/test_group_routes.py | 16 +-
tests/integration_tests/test_meal_routes.py | 2 +-
.../integration_tests/test_settings_routes.py | 2 +-
72 files changed, 890 insertions(+), 606 deletions(-)
delete mode 100644 mealie/schema/snackbar.py
diff --git a/docs/docs/changelog/v0.5.0.md b/docs/docs/changelog/v0.5.0.md
index 252a8568ab3c..5db08118ba78 100644
--- a/docs/docs/changelog/v0.5.0.md
+++ b/docs/docs/changelog/v0.5.0.md
@@ -17,6 +17,8 @@
- Fixes #281 - Slow Handling of Large Sets of Recipes
## Features and Improvements
+- 'Dinner this week' shows a warning when no meal is planned yet
+- 'Dinner today' shows a warning when no meal is planned yet
### General
- New Toolbox Page!
@@ -37,4 +39,7 @@
### Behind the Scenes
- Unified Sidebar Components
-- Refactor UI components to fit Vue best practices (WIP)
\ No newline at end of file
+- Refactor UI components to fit Vue best practices (WIP)
+- The API returns more consistent status codes
+- The API returns error code instead of error text when appropriate
+ - ⚠️ May cause side-effects if you were directly consuming the API
\ No newline at end of file
diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js
index 47868d0f7eb7..0e42f23337dc 100644
--- a/frontend/src/api/api-utils.js
+++ b/frontend/src/api/api-utils.js
@@ -1,75 +1,57 @@
const baseURL = "/api/";
import axios from "axios";
-import utils from "@/utils";
import { store } from "../store";
+import utils from "@/utils";
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${store.getters.getToken}`;
-function processResponse(response) {
- try {
- utils.notify.show(response.data.snackbar.text, response.data.snackbar.type);
- } catch (err) {
- return;
+function handleError(error, getText) {
+ if(getText) {
+ utils.notify.error(getText(error.response));
}
+ return false;
+}
+function handleResponse(response, getText) {
+ if(response && getText) {
+ const successText = getText(response);
+ utils.notify.success(successText);
+ }
+ return response;
+}
- return;
+function defaultErrorText(response) {
+ return response.statusText;
+}
+
+function defaultSuccessText(response) {
+ return response.statusText;
}
const apiReq = {
- post: async function(url, data) {
- let response = await axios.post(url, data).catch(function(error) {
- if (error.response) {
- processResponse(error.response);
- return error.response;
- }
- });
- processResponse(response);
- return response;
+ post: async function(url, data, getErrorText = defaultErrorText, getSuccessText) {
+ const response = await axios.post(url, data).catch(function(error) { handleError(error, getErrorText) });
+ return handleResponse(response, getSuccessText);
+ },
+
+ put: async function(url, data, getErrorText = defaultErrorText, getSuccessText) {
+ const response = await axios.put(url, data).catch(function(error) { handleError(error, getErrorText) });
+ return handleResponse(response, getSuccessText);
+ },
+
+ patch: async function(url, data, getErrorText = defaultErrorText, getSuccessText) {
+ const response = await axios.patch(url, data).catch(function(error) { handleError(error, getErrorText) });
+ return handleResponse(response, getSuccessText);
},
- put: async function(url, data) {
- let response = await axios.put(url, data).catch(function(error) {
- if (error.response) {
- processResponse(error.response);
- return response;
- } else return;
- });
- processResponse(response);
- return response;
- },
- patch: async function(url, data) {
- let response = await axios.patch(url, data).catch(function(error) {
- if (error.response) {
- processResponse(error.response);
- return response;
- } else return;
- });
- processResponse(response);
- return response;
+ get: function(url, data, getErrorText = defaultErrorText) {
+ return axios.get(url, data).catch(function(error) { handleError(error, getErrorText) });
},
- get: async function(url, data) {
- let response = await axios.get(url, data).catch(function(error) {
- if (error.response) {
- processResponse(error.response);
- return response;
- } else return;
- });
- processResponse(response);
- return response;
- },
-
- delete: async function(url, data) {
- let response = await axios.delete(url, data).catch(function(error) {
- if (error.response) {
- processResponse(error.response);
- return response;
- }
- });
- processResponse(response);
- return response;
+ delete: async function(url, data, getErrorText = defaultErrorText, getSuccessText = defaultSuccessText ) {
+ const response = await axios.delete(url, data).catch( function(error) { handleError(error, getErrorText) } );
+ return handleResponse(response, getSuccessText);
},
async download(url) {
diff --git a/frontend/src/api/backup.js b/frontend/src/api/backup.js
index b6afd6e98bb2..d95dd6d27bb4 100644
--- a/frontend/src/api/backup.js
+++ b/frontend/src/api/backup.js
@@ -1,6 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import { store } from "@/store";
+import i18n from '@/i18n.js';
const backupBase = baseURL + "backups/";
@@ -40,7 +41,12 @@ export const backupAPI = {
* @param {string} fileName
*/
async delete(fileName) {
- await apiReq.delete(backupURLs.deleteBackup(fileName));
+ return apiReq.delete(
+ backupURLs.deleteBackup(fileName),
+ null,
+ function() { return i18n.t('settings.backup.unable-to-delete-backup'); },
+ function() { return i18n.t('settings.backup.backup-deleted'); }
+ );
},
/**
* Creates a backup on the serve given a set of options
@@ -48,8 +54,12 @@ export const backupAPI = {
* @returns
*/
async create(options) {
- let response = apiReq.post(backupURLs.createBackup, options);
- return response;
+ return apiReq.post(
+ backupURLs.createBackup,
+ options,
+ function() { return i18n.t('settings.backup.error-creating-backup-see-log-file'); },
+ function(response) { return i18n.t('settings.backup.backup-created-at-response-export_path', {path: response.data.export_path}); }
+ );
},
/**
* Downloads a file from the server. I don't actually think this is used?
diff --git a/frontend/src/api/category.js b/frontend/src/api/category.js
index 8c2219e58f4f..ed0e3752465c 100644
--- a/frontend/src/api/category.js
+++ b/frontend/src/api/category.js
@@ -1,6 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import { store } from "@/store";
+import i18n from '@/i18n.js';
const prefix = baseURL + "categories";
@@ -22,29 +23,44 @@ export const categoryAPI = {
return response.data;
},
async create(name) {
- let response = await apiReq.post(categoryURLs.getAll, { name: name });
- store.dispatch("requestCategories");
- return response.data;
+ const response = await apiReq.post(
+ categoryURLs.getAll,
+ { name: name },
+ function() { return i18n.t('category.category-creation-failed'); },
+ function() { return i18n.t('category.category-created'); }
+ );
+ if(response) {
+ store.dispatch("requestCategories");
+ return response.data;
+ }
},
async getRecipesInCategory(category) {
let response = await apiReq.get(categoryURLs.getCategory(category));
return response.data;
},
async update(name, newName, overrideRequest = false) {
- let response = await apiReq.put(categoryURLs.updateCategory(name), {
- name: newName,
- });
- if (!overrideRequest) {
+ const response = await apiReq.put(
+ categoryURLs.updateCategory(name),
+ { name: newName },
+ function() { return i18n.t('category.category-update-failed'); },
+ function() { return i18n.t('category.category-updated'); }
+ );
+ if (response && !overrideRequest) {
store.dispatch("requestCategories");
+ return response.data;
}
- return response.data;
},
async delete(category, overrideRequest = false) {
- let response = await apiReq.delete(categoryURLs.deleteCategory(category));
- if (!overrideRequest) {
+ const response = await apiReq.delete(
+ categoryURLs.deleteCategory(category),
+ null,
+ function() { return i18n.t('category.category-deletion-failed'); },
+ function() { return i18n.t('category.category-deleted'); }
+ );
+ if (response && !overrideRequest) {
store.dispatch("requestCategories");
}
- return response.data;
+ return response;
},
};
@@ -68,28 +84,48 @@ export const tagAPI = {
return response.data;
},
async create(name) {
- let response = await apiReq.post(tagURLs.getAll, { name: name });
- store.dispatch("requestTags");
- return response.data;
+ const response = await apiReq.post(
+ tagURLs.getAll,
+ { name: name },
+ function() { return i18n.t('tag.tag-creation-failed'); },
+ function() { return i18n.t('tag.tag-created'); }
+ );
+ if(response) {
+ store.dispatch("requestTags");
+ return response.data;
+ }
},
async getRecipesInTag(tag) {
let response = await apiReq.get(tagURLs.getTag(tag));
return response.data;
},
async update(name, newName, overrideRequest = false) {
- let response = await apiReq.put(tagURLs.updateTag(name), { name: newName });
+ const response = await apiReq.put(
+ tagURLs.updateTag(name),
+ { name: newName },
+ function() { return i18n.t('tag.tag-update-failed'); },
+ function() { return i18n.t('tag.tag-updated'); }
+ );
- if (!overrideRequest) {
- store.dispatch("requestTags");
+ if(response) {
+ if (!overrideRequest) {
+ store.dispatch("requestTags");
+ }
+ return response.data;
}
-
- return response.data;
},
async delete(tag, overrideRequest = false) {
- let response = await apiReq.delete(tagURLs.deleteTag(tag));
- if (!overrideRequest) {
- store.dispatch("requestTags");
+ const response = await apiReq.delete(
+ tagURLs.deleteTag(tag),
+ null,
+ function() { return i18n.t('tag.tag-deletion-failed'); },
+ function() { return i18n.t('tag.tag-deleted'); }
+ );
+ if(response) {
+ if (!overrideRequest) {
+ store.dispatch("requestTags");
+ }
+ return response.data;
}
- return response.data;
},
};
diff --git a/frontend/src/api/groups.js b/frontend/src/api/groups.js
index 7f67a16de531..011c3d104fc6 100644
--- a/frontend/src/api/groups.js
+++ b/frontend/src/api/groups.js
@@ -1,5 +1,6 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
+import i18n from '@/i18n.js';
const groupPrefix = baseURL + "groups";
const groupsURLs = {
@@ -10,25 +11,58 @@ const groupsURLs = {
update: id => `${groupPrefix}/${id}`,
};
+function deleteErrorText(response) {
+ switch(response.data.detail) {
+ case 'GROUP_WITH_USERS':
+ return i18n.t('group.cannot-delete-group-with-users');
+
+ case 'GROUP_NOT_FOUND':
+ return i18n.t('group.group-not-found');
+
+ case 'DEFAULT_GROUP':
+ return i18n.t('group.cannot-delete-default-group');
+
+ default:
+ return i18n.t('group.group-deletion-failed');
+ }
+}
+
export const groupAPI = {
async allGroups() {
let response = await apiReq.get(groupsURLs.groups);
return response.data;
},
- async create(name) {
- let response = await apiReq.post(groupsURLs.create, { name: name });
- return response.data;
+ create(name) {
+ return apiReq.post(
+ groupsURLs.create,
+ { name: name },
+ function() { return i18n.t('group.user-group-creation-failed'); },
+ function() { return i18n.t('group.user-group-created'); }
+ );
},
- async delete(id) {
- let response = await apiReq.delete(groupsURLs.delete(id));
- return response.data;
+ delete(id) {
+ return apiReq.delete(
+ groupsURLs.delete(id),
+ null,
+ deleteErrorText,
+ function() { return i18n.t('group.group-deleted'); }
+ );
},
async current() {
- let response = await apiReq.get(groupsURLs.current);
- return response.data;
+ const response = await apiReq.get(
+ groupsURLs.current,
+ null,
+ null);
+ if(response) {
+ return response.data;
+ }
},
- async update(data) {
- let response = await apiReq.put(groupsURLs.update(data.id), data);
- return response.data;
+ update(data) {
+ return apiReq.put(
+ groupsURLs.update(data.id),
+ data,
+ function() { return i18n.t('group.error-updating-group'); },
+ function() { return i18n.t('settings.group-settings-updated'); }
+ );
},
};
diff --git a/frontend/src/api/mealplan.js b/frontend/src/api/mealplan.js
index 172fc9339726..ff51da61e511 100644
--- a/frontend/src/api/mealplan.js
+++ b/frontend/src/api/mealplan.js
@@ -1,5 +1,6 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
+import i18n from '@/i18n.js';
const prefix = baseURL + "meal-plans/";
@@ -15,9 +16,13 @@ const mealPlanURLs = {
};
export const mealplanAPI = {
- async create(postBody) {
- let response = await apiReq.post(mealPlanURLs.create, postBody);
- return response;
+ create(postBody) {
+ return apiReq.post(
+ mealPlanURLs.create,
+ postBody,
+ function() { return i18n.t('meal-plan.mealplan-creation-failed')},
+ function() { return i18n.t('meal-plan.mealplan-created'); }
+ );
},
async all() {
@@ -35,14 +40,21 @@ export const mealplanAPI = {
return response;
},
- async delete(id) {
- let response = await apiReq.delete(mealPlanURLs.delete(id));
- return response;
+ delete(id) {
+ return apiReq.delete(mealPlanURLs.delete(id),
+ null,
+ function() { return i18n.t('meal-plan.mealplan-deletion-failed'); },
+ function() { return i18n.t('meal-plan.mealplan-deleted'); }
+ );
},
- async update(id, body) {
- let response = await apiReq.put(mealPlanURLs.update(id), body);
- return response;
+ update(id, body) {
+ return apiReq.put(
+ mealPlanURLs.update(id),
+ body,
+ function() { return i18n.t('meal-plan.mealplan-update-failed'); },
+ function() { return i18n.t('meal-plan.mealplan-updated'); }
+ );
},
async shoppingList(id) {
diff --git a/frontend/src/api/migration.js b/frontend/src/api/migration.js
index e09c07cd96a5..5d967c56c110 100644
--- a/frontend/src/api/migration.js
+++ b/frontend/src/api/migration.js
@@ -1,6 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import { store } from "../store";
+import i18n from '@/i18n.js';
const migrationBase = baseURL + "migrations";
@@ -17,8 +18,13 @@ export const migrationAPI = {
return response.data;
},
async delete(folder, file) {
- let response = await apiReq.delete(migrationURLs.delete(folder, file));
- return response.data;
+ const response = await apiReq.delete(
+ migrationURLs.delete(folder, file),
+ null,
+ function() { return i18n.t('general.file-folder-not-found'); },
+ function() { return i18n.t('migration.migration-data-removed'); }
+ );
+ return response;
},
async import(folder, file) {
let response = await apiReq.post(migrationURLs.import(folder, file));
diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js
index 3dd8c1a6f8dc..b11a73ddb3b7 100644
--- a/frontend/src/api/recipe.js
+++ b/frontend/src/api/recipe.js
@@ -1,7 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import { store } from "../store";
-import { router } from "../main";
+import i18n from '@/i18n.js';
const prefix = baseURL + "recipes/";
@@ -26,9 +26,12 @@ export const recipeAPI = {
* @returns {string} Recipe Slug
*/
async createByURL(recipeURL) {
- let response = await apiReq.post(recipeURLs.createByURL, {
- url: recipeURL,
- });
+ const response = await apiReq.post(
+ recipeURLs.createByURL,
+ { url: recipeURL },
+ function() { return i18n.t('recipe.recipe-creation-failed'); },
+ function() { return i18n.t('recipe.recipe-created'); }
+ );
store.dispatch("requestRecentRecipes");
return response;
@@ -43,7 +46,12 @@ export const recipeAPI = {
},
async create(recipeData) {
- let response = await apiReq.post(recipeURLs.create, recipeData);
+ const response = await apiReq.post(
+ recipeURLs.create,
+ recipeData,
+ function() { return i18n.t('recipe.recipe-creation-failed'); },
+ function() { return i18n.t('recipe.recipe-created'); }
+ );
store.dispatch("requestRecentRecipes");
return response.data;
},
@@ -53,14 +61,24 @@ export const recipeAPI = {
return response.data;
},
- async updateImage(recipeSlug, fileObject) {
- const fd = new FormData();
- fd.append("image", fileObject);
- fd.append("extension", fileObject.name.split(".").pop());
- let response = apiReq.put(recipeURLs.updateImage(recipeSlug), fd);
- return response;
- },
+ updateImage(recipeSlug, fileObject, overrideSuccessMsg = false) {
+ const formData = new FormData();
+ formData.append("image", fileObject);
+ formData.append("extension", fileObject.name.split(".").pop());
+ let successMessage = null;
+ if(!overrideSuccessMsg) {
+ successMessage = function() { return overrideSuccessMsg ? null : i18n.t('recipe.recipe-image-updated'); };
+ }
+
+ return apiReq.put(
+ recipeURLs.updateImage(recipeSlug),
+ formData,
+ function() { return i18n.t('general.image-upload-failed'); },
+ successMessage
+ );
+ },
+
async createAsset(recipeSlug, fileObject, name, icon) {
const fd = new FormData();
fd.append("file", fileObject);
@@ -70,17 +88,27 @@ export const recipeAPI = {
let response = apiReq.post(recipeURLs.createAsset(recipeSlug), fd);
return response;
},
-
- async updateImagebyURL(slug, url) {
- const response = apiReq.post(recipeURLs.updateImage(slug), { url: url });
- return response;
+
+ updateImagebyURL(slug, url) {
+ return apiReq.post(
+ recipeURLs.updateImage(slug),
+ { url: url },
+ function() { return i18n.t('general.image-upload-failed'); },
+ function() { return i18n.t('recipe.recipe-image-updated'); }
+ );
},
async update(data) {
- console.log(data)
- let response = await apiReq.put(recipeURLs.update(data.slug), data);
- store.dispatch("patchRecipe", response.data);
- return response.data.slug; // ! Temporary until I rewrite to refresh page without additional request
+ let response = await apiReq.put(
+ recipeURLs.update(data.slug),
+ data,
+ function() { return i18n.t('recipe.recipe-update-failed'); },
+ function() { return i18n.t('recipe.recipe-updated'); }
+ );
+ if(response) {
+ store.dispatch("patchRecipe", response.data);
+ return response.data.slug; // ! Temporary until I rewrite to refresh page without additional request
+ }
},
async patch(data) {
@@ -89,10 +117,13 @@ export const recipeAPI = {
return response.data;
},
- async delete(recipeSlug) {
- await apiReq.delete(recipeURLs.delete(recipeSlug));
- store.dispatch("requestRecentRecipes");
- router.push(`/`);
+ delete(recipeSlug) {
+ return apiReq.delete(
+ recipeURLs.delete(recipeSlug),
+ null,
+ function() { return i18n.t('recipe.unable-to-delete-recipe'); },
+ function() { return i18n.t('recipe.recipe-deleted'); }
+ );
},
async allSummary(start = 0, limit = 9999) {
diff --git a/frontend/src/api/signUps.js b/frontend/src/api/signUps.js
index 91b982caa113..8500a0cb97a4 100644
--- a/frontend/src/api/signUps.js
+++ b/frontend/src/api/signUps.js
@@ -1,5 +1,6 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
+import i18n from '@/i18n.js';
const signUpPrefix = baseURL + "users/sign-ups";
@@ -16,15 +17,25 @@ export const signupAPI = {
return response.data;
},
async createToken(data) {
- let response = await apiReq.post(signUpURLs.createToken, data);
+ let response = await apiReq.post(
+ signUpURLs.createToken,
+ data,
+ function() { return i18n.t('signup.sign-up-link-creation-failed'); },
+ function() { return i18n.t('signup.sign-up-link-created'); }
+ );
return response.data;
},
async deleteToken(token) {
- let response = await apiReq.delete(signUpURLs.deleteToken(token));
- return response.data;
+ return await apiReq.delete(signUpURLs.deleteToken(token),
+ null,
+ function() { return i18n.t('signup.sign-up-token-deletion-failed'); },
+ function() { return i18n.t('signup.sign-up-token-deleted'); }
+ );
},
async createUser(token, data) {
- let response = await apiReq.post(signUpURLs.createUser(token), data);
- return response.data;
+ return apiReq.post(signUpURLs.createUser(token), data,
+ function() { return i18n.t('user.you-are-not-allowed-to-create-a-user'); },
+ function() { return i18n.t('user.user-created'); }
+ );
},
};
diff --git a/frontend/src/api/siteSettings.js b/frontend/src/api/siteSettings.js
index 1b511e8b33f8..f5c234af7cfe 100644
--- a/frontend/src/api/siteSettings.js
+++ b/frontend/src/api/siteSettings.js
@@ -1,6 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import { store } from "@/store";
+import i18n from '@/i18n.js';
const settingsBase = baseURL + "site-settings";
@@ -19,9 +20,16 @@ export const siteSettingsAPI = {
},
async update(body) {
- let response = await apiReq.put(settingsURLs.updateSiteSettings, body);
- store.dispatch("requestSiteSettings");
- return response.data;
+ const response = await apiReq.put(
+ settingsURLs.updateSiteSettings,
+ body,
+ function() { return i18n.t('settings.settings-update-failed'); },
+ function() { return i18n.t('settings.settings-updated'); }
+ );
+ if(response) {
+ store.dispatch("requestSiteSettings");
+ }
+ return response;
},
async getPages() {
@@ -34,23 +42,39 @@ export const siteSettingsAPI = {
return response.data;
},
- async createPage(body) {
- let response = await apiReq.post(settingsURLs.customPages, body);
- return response.data;
+ createPage(body) {
+ return apiReq.post(
+ settingsURLs.customPages,
+ body,
+ function() { return i18n.t('page.page-creation-failed'); },
+ function() { return i18n.t('page.new-page-created'); }
+ );
},
async deletePage(id) {
- let response = await apiReq.delete(settingsURLs.customPage(id));
- return response.data;
+ return await apiReq.delete(
+ settingsURLs.customPage(id),
+ null,
+ function() { return i18n.t('page.page-deletion-failed'); },
+ function() { return i18n.t('page.page-deleted'); });
},
- async updatePage(body) {
- let response = await apiReq.put(settingsURLs.customPage(body.id), body);
- return response.data;
+ updatePage(body) {
+ return apiReq.put(
+ settingsURLs.customPage(body.id),
+ body,
+ function() { return i18n.t('page.page-update-failed'); },
+ function() { return i18n.t('page.page-updated'); }
+ );
},
async updateAllPages(allPages) {
- let response = await apiReq.put(settingsURLs.customPages, allPages);
+ let response = await apiReq.put(
+ settingsURLs.customPages,
+ allPages,
+ function() { return i18n.t('page.pages-update-failed'); },
+ function() { return i18n.t('page.pages-updated'); }
+ );
return response;
},
};
diff --git a/frontend/src/api/themes.js b/frontend/src/api/themes.js
index d29568216890..321091754387 100644
--- a/frontend/src/api/themes.js
+++ b/frontend/src/api/themes.js
@@ -1,5 +1,6 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
+import i18n from '@/i18n.js';
const prefix = baseURL + "themes";
@@ -23,21 +24,31 @@ export const themeAPI = {
},
async create(postBody) {
- let response = await apiReq.post(settingsURLs.createTheme, postBody);
- return response.data;
+ return await apiReq.post(
+ settingsURLs.createTheme,
+ postBody,
+ function() { return i18n.t('settings.theme.error-creating-theme-see-log-file'); },
+ function() { return i18n.t('settings.theme.theme-saved'); });
},
- async update(themeName, colors) {
+ update(themeName, colors) {
const body = {
name: themeName,
colors: colors,
};
- let response = await apiReq.put(settingsURLs.updateTheme(themeName), body);
- return response.data;
+ return apiReq.put(
+ settingsURLs.updateTheme(themeName),
+ body,
+ function() { return i18n.t('settings.theme.error-updating-theme'); },
+ function() { return i18n.t('settings.theme.theme-updated'); });
},
- async delete(themeName) {
- let response = await apiReq.delete(settingsURLs.deleteTheme(themeName));
- return response.data;
+ delete(themeName) {
+ return apiReq.delete(
+ settingsURLs.deleteTheme(themeName),
+ null,
+ function() { return i18n.t('settings.theme.error-deleting-theme'); },
+ function() { return i18n.t('settings.theme.theme-deleted'); }
+ );
},
};
diff --git a/frontend/src/api/upload.js b/frontend/src/api/upload.js
index d5475080ecb2..14ac790f8a3f 100644
--- a/frontend/src/api/upload.js
+++ b/frontend/src/api/upload.js
@@ -1,15 +1,16 @@
import { apiReq } from "./api-utils";
+import i18n from '@/i18n.js';
export const utilsAPI = {
// import { api } from "@/api";
- async uploadFile(url, fileObject) {
+ uploadFile(url, fileObject) {
console.log("API Called");
- let response = await apiReq.post(url, fileObject, {
- headers: {
- "Content-Type": "multipart/form-data",
- },
- });
- return response.data;
+ return apiReq.post(
+ url,
+ fileObject,
+ function() { return i18n.t('general.failure-uploading-file'); },
+ function() { return i18n.t('general.file-uploaded'); }
+ );
},
};
diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js
index b312e463f9dd..edf85bc3a9e8 100644
--- a/frontend/src/api/users.js
+++ b/frontend/src/api/users.js
@@ -1,6 +1,7 @@
import { baseURL } from "./api-utils";
import { apiReq } from "./api-utils";
import axios from "axios";
+import i18n from '@/i18n.js';
const authPrefix = baseURL + "auth";
const userPrefix = baseURL + "users";
@@ -17,13 +18,23 @@ const usersURLs = {
resetPassword: id => `${userPrefix}/${id}/reset-password`,
};
+function deleteErrorText(response) {
+ switch(response.data.detail) {
+ case 'SUPER_USER':
+ return i18n.t('user.error-cannot-delete-super-user');
+
+ default:
+ return i18n.t('user.you-are-not-allowed-to-delete-this-user');
+ }
+}
export const userAPI = {
async login(formData) {
- let response = await apiReq.post(authURLs.token, formData, {
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- },
- });
+ let response = await apiReq.post(
+ authURLs.token,
+ formData,
+ function() { return i18n.t('user.incorrect-username-or-password'); },
+ function() { return i18n.t('user.user-successfully-logged-in'); }
+ );
return response;
},
async refresh() {
@@ -36,9 +47,13 @@ export const userAPI = {
let response = await apiReq.get(usersURLs.users);
return response.data;
},
- async create(user) {
- let response = await apiReq.post(usersURLs.users, user);
- return response.data;
+ create(user) {
+ return apiReq.post(
+ usersURLs.users,
+ user,
+ function() { return i18n.t('user.user-creation-failed'); },
+ function() { return i18n.t('user.user-created'); }
+ );
},
async self() {
let response = await apiReq.get(usersURLs.self);
@@ -48,20 +63,37 @@ export const userAPI = {
let response = await apiReq.get(usersURLs.userID(id));
return response.data;
},
- async update(user) {
- let response = await apiReq.put(usersURLs.userID(user.id), user);
- return response.data;
+ update(user) {
+ return apiReq.put(
+ usersURLs.userID(user.id),
+ user,
+ function() { return i18n.t('user.user-update-failed'); },
+ function() { return i18n.t('user.user-updated'); }
+ );
},
- async changePassword(id, password) {
- let response = await apiReq.put(usersURLs.password(id), password);
- return response.data;
+ changePassword(id, password) {
+ return apiReq.put(
+ usersURLs.password(id),
+ password,
+ function() { return i18n.t('user.existing-password-does-not-match'); },
+ function() { return i18n.t('user.password-updated'); }
+ );
},
- async delete(id) {
- let response = await apiReq.delete(usersURLs.userID(id));
- return response.data;
+
+ delete(id) {
+ return apiReq.delete(
+ usersURLs.userID(id),
+ null,
+ deleteErrorText,
+ function() { return i18n.t('user.user-deleted'); }
+ );
},
- async resetPassword(id) {
- let response = await apiReq.put(usersURLs.resetPassword(id));
- return response.data;
+ resetPassword(id) {
+ return apiReq.put(
+ usersURLs.resetPassword(id),
+ null,
+ function() { return i18n.t('user.password-reset-failed'); },
+ function() { return i18n.t('user.password-has-been-reset-to-the-default-password'); }
+ );
},
};
diff --git a/frontend/src/components/FormHelpers/CategoryTagSelector.vue b/frontend/src/components/FormHelpers/CategoryTagSelector.vue
index c31f0a017389..5266990865df 100644
--- a/frontend/src/components/FormHelpers/CategoryTagSelector.vue
+++ b/frontend/src/components/FormHelpers/CategoryTagSelector.vue
@@ -90,7 +90,7 @@ export default {
computed: {
inputLabel() {
if (!this.showLabel) return null;
- return this.tagSelector ? this.$t('recipe.tags') : this.$t('recipe.categories');
+ return this.tagSelector ? this.$t('tag.tags') : this.$t('recipe.categories');
},
activeItems() {
let ItemObjects = [];
diff --git a/frontend/src/components/ImportSummaryDialog/index.vue b/frontend/src/components/ImportSummaryDialog/index.vue
index 5088e1491950..ef069ddab225 100644
--- a/frontend/src/components/ImportSummaryDialog/index.vue
+++ b/frontend/src/components/ImportSummaryDialog/index.vue
@@ -7,7 +7,7 @@
mdi-import
{{ $t("general.options") }}:
+{{ $t("general.options") }}
{{ $t("general.templates") }}:
+{{ $t("general.templates") }}