Localize more dates and texts (#341)

* Localize more dates and texts

* Adapt source language to 4-letter code for VS code

* Make page titles more reactive to language change

* Translate missing text + fix missed refactoring

* Fix missed page titles refactoring

* Translate nutrition view

* Translate Image upload vue

* Fix default text being defined twice in upload btn
This commit is contained in:
sephrat 2021-04-23 08:13:00 +02:00 committed by GitHub
parent 048d3d5469
commit 80f8806604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 65 additions and 125 deletions

View File

@ -10,7 +10,7 @@
"python.testing.pytestArgs": ["tests"], "python.testing.pytestArgs": ["tests"],
"cSpell.enableFiletypes": ["!javascript", "!python"], "cSpell.enableFiletypes": ["!javascript", "!python"],
"i18n-ally.localesPaths": "frontend/src/locales/messages", "i18n-ally.localesPaths": "frontend/src/locales/messages",
"i18n-ally.sourceLanguage": "en", "i18n-ally.sourceLanguage": "en-US",
"i18n-ally.enabledFrameworks": ["vue"], "i18n-ally.enabledFrameworks": ["vue"],
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",
"cSpell.words": ["performant"], "cSpell.words": ["performant"],

View File

@ -3,7 +3,7 @@
<v-card-title class=" headline"> <v-card-title class=" headline">
{{ $t("meal-plan.create-a-new-meal-plan") }} {{ $t("meal-plan.create-a-new-meal-plan") }}
<v-btn color="info" class="ml-auto" @click="setQuickWeek()"> <v-btn color="info" class="ml-auto" @click="setQuickWeek()">
<v-icon left>mdi-calendar-minus</v-icon> Quick Week <v-icon left>mdi-calendar-minus</v-icon> {{$t('meal-plan.quick-week')}}
</v-btn> </v-btn>
</v-card-title> </v-card-title>
@ -110,7 +110,6 @@ export default {
this.meals.push({ this.meals.push({
slug: "empty", slug: "empty",
date: this.getDate(i), date: this.getDate(i),
dateText: this.getDayText(i),
}); });
} }
}, },
@ -193,10 +192,6 @@ export default {
); );
return dateText; return dateText;
}, },
getDayText(index) {
const dateObj = this.processTime(index);
return utils.getDateAsText(dateObj);
},
getDate(index) { getDate(index) {
const dateObj = this.processTime(index); const dateObj = this.processTime(index);
return utils.getDateAsPythonDate(dateObj); return utils.getDateAsPythonDate(dateObj);

View File

@ -3,10 +3,10 @@
<v-dialog v-model="dialog" width="650"> <v-dialog v-model="dialog" width="650">
<v-card> <v-card>
<v-card-title class="headline"> <v-card-title class="headline">
Shopping List {{$t('meal-plan.shopping-list')}}
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text color="accent" @click="group = !group"> <v-btn text color="accent" @click="group = !group">
Group (Beta) {{$t('meal-plan.group')}}
</v-btn> </v-btn>
</v-card-title> </v-card-title>
<v-divider></v-divider> <v-divider></v-divider>

View File

@ -3,13 +3,13 @@
<v-menu offset-y top nudge-top="6" :close-on-content-click="false"> <v-menu offset-y top nudge-top="6" :close-on-content-click="false">
<template v-slot:activator="{ on, attrs }"> <template v-slot:activator="{ on, attrs }">
<v-btn color="accent" dark v-bind="attrs" v-on="on"> <v-btn color="accent" dark v-bind="attrs" v-on="on">
Image {{$t('recipe.image')}}
</v-btn> </v-btn>
</template> </template>
<v-card width="400"> <v-card width="400">
<v-card-title class="headline flex mb-0"> <v-card-title class="headline flex mb-0">
<div> <div>
Recipe Image {{$t('recipe.recipe-image')}}
</div> </div>
<TheUploadBtn <TheUploadBtn
class="ml-auto" class="ml-auto"
@ -22,7 +22,7 @@
</v-card-title> </v-card-title>
<v-card-text class="mt-n5"> <v-card-text class="mt-n5">
<div> <div>
<v-text-field label="URL" class="pt-5" clearable v-model="url"> <v-text-field :label="$t('general.url')" class="pt-5" clearable v-model="url">
<template v-slot:append-outer> <template v-slot:append-outer>
<v-btn <v-btn
class="ml-2" class="ml-2"
@ -30,7 +30,7 @@
@click="getImageFromURL" @click="getImageFromURL"
:loading="loading" :loading="loading"
> >
Get {{$t('general.get')}}
</v-btn> </v-btn>
</template> </template>
</v-text-field> </v-text-field>
@ -46,7 +46,6 @@ const REFRESH_EVENT = "refresh";
const UPLOAD_EVENT = "upload"; const UPLOAD_EVENT = "upload";
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn"; import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
import { api } from "@/api"; import { api } from "@/api";
// import axios from "axios";
export default { export default {
components: { components: {
TheUploadBtn, TheUploadBtn,
@ -55,7 +54,6 @@ export default {
slug: String, slug: String,
}, },
data: () => ({ data: () => ({
items: [{ title: "Upload Image" }, { title: "From URL" }],
url: "", url: "",
loading: false, loading: false,
}), }),

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-if="valueNotNull || edit"> <div v-if="valueNotNull || edit">
<h2 class="my-4">Nutrition</h2> <h2 class="my-4">{{$t('recipe.nutrition')}}</h2>
<div v-if="edit"> <div v-if="edit">
<div v-for="(item, key, index) in value" :key="index"> <div v-for="(item, key, index) in value" :key="index">
<v-text-field <v-text-field
@ -45,14 +45,14 @@ export default {
return { return {
labels: { labels: {
calories: { calories: {
label: "Calories", label: this.$t('recipe.calories'),
suffix: "calories", suffix:this.$t('recipe.calories-suffix'),
}, },
fatContent: { label: "Fat Content", suffix: "grams" }, fatContent: { label: this.$t('recipe.fat-content'), suffix: this.$t('recipe.grams') },
fiberContent: { label: "Fiber Content", suffix: "grams" }, fiberContent: { label: this.$t('recipe.fiber-content'), suffix: this.$t('recipe.grams') },
proteinContent: { label: "Protein Content", suffix: "grams" }, proteinContent: { label: this.$t('recipe.protein-content'), suffix: this.$t('recipe.grams') },
sodiumContent: { label: "Sodium Content", suffix: "milligrams" }, sodiumContent: { label: this.$t('recipe.sodium-content'), suffix: this.$t('recipe.milligrams') },
sugarContent: { label: "Sugar Content", suffix: "grams" }, sugarContent: { label: this.$t('recipe.sugar-content'), suffix: this.$t('recipe.grams') },
}, },
}; };
}, },

View File

@ -23,7 +23,7 @@ export default {
default: true, default: true,
}, },
url: String, url: String,
text: { default: "Upload" }, text: String,
icon: { default: "mdi-cloud-upload" }, icon: { default: "mdi-cloud-upload" },
fileName: { default: "archive" }, fileName: { default: "archive" },
textBtn: { textBtn: {

View File

@ -3,5 +3,11 @@
"month": "short", "month": "short",
"day": "numeric", "day": "numeric",
"weekday": "long" "weekday": "long"
},
"medium": {
"month": "long",
"day": "numeric",
"weekday": "long",
"year": "numeric"
} }
} }

View File

@ -56,7 +56,9 @@
"thursday": "Thursday", "thursday": "Thursday",
"friday": "Friday", "friday": "Friday",
"saturday": "Saturday", "saturday": "Saturday",
"about": "About" "about": "About",
"get": "Get",
"url": "URL"
}, },
"page": { "page": {
"home-page": "Home Page", "home-page": "Home Page",
@ -122,7 +124,9 @@
"create-a-new-meal-plan": "Create a New Meal Plan", "create-a-new-meal-plan": "Create a New Meal Plan",
"start-date": "Start Date", "start-date": "Start Date",
"end-date": "End Date", "end-date": "End Date",
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans" "only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans",
"quick-week": "Quick Week",
"group": "Group (Beta)"
}, },
"recipe": { "recipe": {
"description": "Description", "description": "Description",
@ -150,7 +154,19 @@
"key-name-required": "Key Name Required", "key-name-required": "Key Name Required",
"no-white-space-allowed": "No White Space Allowed", "no-white-space-allowed": "No White Space Allowed",
"delete-recipe": "Delete Recipe", "delete-recipe": "Delete Recipe",
"delete-confirmation": "Are you sure you want to delete this recipe?" "delete-confirmation": "Are you sure you want to delete this recipe?",
"nutrition": "Nutrition",
"calories": "Calories",
"calories-suffix": "calories",
"fat-content": "Fat Content",
"fiber-content": "Fiber Content",
"protein-content": "Protein Content",
"sodium-content": "Sodium Content",
"sugar-content": "Sugar Content",
"grams": "grams",
"milligrams": "milligrams",
"recipe-image": "Recipe Image",
"image": "Image"
}, },
"search": { "search": {
"search-mealie": "Search Mealie", "search-mealie": "Search Mealie",
@ -238,7 +254,8 @@
"custom-pages": "Custom Pages", "custom-pages": "Custom Pages",
"new-page": "New Page", "new-page": "New Page",
"edit-page": "Edit Page", "edit-page": "Edit Page",
"page-name": "Page Name" "page-name": "Page Name",
"remove-existing-entries-matching-imported-entries": "Remove existing entries matching imported entries"
}, },
"migration": { "migration": {
"recipe-migration": "Recipe Migration", "recipe-migration": "Recipe Migration",

View File

@ -27,7 +27,7 @@
<div class="text-truncate"> <div class="text-truncate">
<strong>{{ backup.name }}</strong> <strong>{{ backup.name }}</strong>
</div> </div>
<div class="text-truncate">{{ readableTime(backup.date) }}</div> <div class="text-truncate">{{ $d(new Date(backup.date), "medium") }}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@ -40,7 +40,6 @@
<script> <script>
import ImportDialog from "./ImportDialog"; import ImportDialog from "./ImportDialog";
import { api } from "@/api"; import { api } from "@/api";
import utils from "@/utils";
export default { export default {
props: { props: {
backups: Array, backups: Array,
@ -57,14 +56,10 @@ export default {
}, },
methods: { methods: {
openDialog(backup) { openDialog(backup) {
this.selectedDate = this.readableTime(backup.date); this.selectedDate = backup.date;
this.selectedName = backup.name; this.selectedName = backup.name;
this.$refs.import_dialog.open(); this.$refs.import_dialog.open();
}, },
readableTime(timestamp) {
let date = new Date(timestamp);
return utils.getDateAsText(date);
},
async importBackup(data) { async importBackup(data) {
this.$emit("loading"); this.$emit("loading");
let response = await api.backups.import(data.name, data); let response = await api.backups.import(data.name, data);

View File

@ -26,7 +26,7 @@
<div> <div>
<strong>{{ backup.name }}</strong> <strong>{{ backup.name }}</strong>
</div> </div>
<div>{{ readableTime(backup.date) }}</div> <div>{{ $d(new Date(backup.date), "medium") }}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@ -39,7 +39,6 @@
<script> <script>
import ImportDialog from "./ImportDialog"; import ImportDialog from "./ImportDialog";
import { api } from "@/api"; import { api } from "@/api";
import utils from "@/utils";
export default { export default {
props: { props: {
backups: Array, backups: Array,
@ -56,14 +55,10 @@ export default {
}, },
methods: { methods: {
openDialog(backup) { openDialog(backup) {
this.selectedDate = this.readableTime(backup.date); this.selectedDate = backup.date;
this.selectedName = backup.name; this.selectedName = backup.name;
this.$refs.import_dialog.open(); this.$refs.import_dialog.open();
}, },
readableTime(timestamp) {
let date = new Date(timestamp);
return utils.getDateAsText(date);
},
async importBackup(data) { async importBackup(data) {
this.$emit("loading"); this.$emit("loading");
let response = await api.backups.import(data.name, data); let response = await api.backups.import(data.name, data);

View File

@ -19,7 +19,7 @@
</v-toolbar-items> </v-toolbar-items>
</v-toolbar> </v-toolbar>
<v-card-title> {{ name }} </v-card-title> <v-card-title> {{ name }} </v-card-title>
<v-card-subtitle class="mb-n3"> {{ date }} </v-card-subtitle> <v-card-subtitle class="mb-n3"> {{ $d(new Date(date), "medium") }} </v-card-subtitle>
<v-divider></v-divider> <v-divider></v-divider>
<v-card-text> <v-card-text>
@ -29,7 +29,7 @@
<v-checkbox <v-checkbox
dense dense
label="Remove existing entries matching imported entries" :label="$t('settings.remove-existing-entries-matching-imported-entries')"
v-model="forceImport" v-model="forceImport"
></v-checkbox> ></v-checkbox>
</v-card-text> </v-card-text>

View File

@ -32,7 +32,7 @@
<strong>{{ migration.name }}</strong> <strong>{{ migration.name }}</strong>
</div> </div>
<div class="text-truncate"> <div class="text-truncate">
{{ readableTime(migration.date) }} {{ $d(new Date(migration.date), "medium") }}
</div> </div>
</v-col> </v-col>
</v-row> </v-row>
@ -67,7 +67,6 @@
<script> <script>
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn"; import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
import utils from "@/utils";
import { api } from "@/api"; import { api } from "@/api";
import MigrationDialog from "./MigrationDialog"; import MigrationDialog from "./MigrationDialog";
export default { export default {
@ -98,10 +97,6 @@ export default {
// this.$emit("imported", response.successful, response.failed); // this.$emit("imported", response.successful, response.failed);
this.loading = false; this.loading = false;
}, },
readableTime(timestamp) {
let date = new Date(timestamp);
return utils.getDateAsText(date);
},
}, },
}; };
</script> </script>

View File

@ -112,10 +112,6 @@ export default {
generateKey(name, index) { generateKey(name, index) {
return utils.generateUniqueKey(name, index); return utils.generateUniqueKey(name, index);
}, },
formatDate(timestamp) {
let dateObject = new Date(timestamp);
return utils.getDateAsTextAlt(dateObject);
},
getImage(image) { getImage(image) {
return api.recipes.recipeTinyImage(image); return api.recipes.recipeTinyImage(image);
}, },

View File

@ -8,7 +8,6 @@ import ManageUsers from "@/pages/Admin/ManageUsers";
import Settings from "@/pages/Admin/Settings"; import Settings from "@/pages/Admin/Settings";
import About from "@/pages/Admin/About"; import About from "@/pages/Admin/About";
import { store } from "../store"; import { store } from "../store";
import i18n from '@/i18n.js';
export const adminRoutes = { export const adminRoutes = {
path: "/admin", path: "/admin",
@ -27,7 +26,7 @@ export const adminRoutes = {
path: "profile", path: "profile",
component: Profile, component: Profile,
meta: { meta: {
title: i18n.t('settings.profile'), title: "settings.profile",
}, },
}, },
@ -35,49 +34,49 @@ export const adminRoutes = {
path: "backups", path: "backups",
component: Backup, component: Backup,
meta: { meta: {
title: i18n.t('settings.backup-and-exports'), title: "settings.backup-and-exports",
}, },
}, },
{ {
path: "themes", path: "themes",
component: Theme, component: Theme,
meta: { meta: {
title: i18n.t('general.themes'), title: "general.themes",
}, },
}, },
{ {
path: "meal-planner", path: "meal-planner",
component: MealPlanner, component: MealPlanner,
meta: { meta: {
title: i18n.t('meal-plan.meal-planner'), title: "meal-plan.meal-planner",
}, },
}, },
{ {
path: "migrations", path: "migrations",
component: Migration, component: Migration,
meta: { meta: {
title: i18n.t('settings.migrations'), title: "settings.migrations",
}, },
}, },
{ {
path: "manage-users", path: "manage-users",
component: ManageUsers, component: ManageUsers,
meta: { meta: {
title: i18n.t('settings.manage-users'), title: "settings.manage-users",
}, },
}, },
{ {
path: "settings", path: "settings",
component: Settings, component: Settings,
meta: { meta: {
title: i18n.t('settings.site-settings'), title: "settings.site-settings",
}, },
}, },
{ {
path: "about", path: "about",
component: About, component: About,
meta: { meta: {
title: i18n.t('general.about'), title: "general.about",
}, },
}, },
], ],

View File

@ -1,4 +1,3 @@
import i18n from "@/i18n.js";
import SearchPage from "@/pages/SearchPage"; import SearchPage from "@/pages/SearchPage";
import HomePage from "@/pages/HomePage"; import HomePage from "@/pages/HomePage";
@ -9,7 +8,7 @@ export const generalRoutes = [
path: "/search", path: "/search",
component: SearchPage, component: SearchPage,
meta: { meta: {
title: i18n.t("search.search"), title: "search.search",
}, },
}, },
]; ];

View File

@ -9,6 +9,7 @@ import VueRouter from "vue-router";
import VueI18n from "@/i18n"; import VueI18n from "@/i18n";
import Vuetify from "@/plugins/vuetify"; import Vuetify from "@/plugins/vuetify";
import Vue from "vue"; import Vue from "vue";
import i18n from '@/i18n.js';
export const routes = [ export const routes = [
...generalRoutes, ...generalRoutes,
@ -34,8 +35,8 @@ router.afterEach(to => {
const title = await to.meta.title(to); const title = await to.meta.title(to);
document.title = title + TITLE_SUFFIX; document.title = title + TITLE_SUFFIX;
} else { } else {
document.title = to.meta.title document.title = i18n.t(to.meta.title)
? to.meta.title + TITLE_SUFFIX ? i18n.t(to.meta.title) + TITLE_SUFFIX
: DEFAULT_TITLE; : DEFAULT_TITLE;
} }
}); });

View File

@ -1,6 +1,5 @@
import Planner from "@/pages/MealPlan/Planner"; import Planner from "@/pages/MealPlan/Planner";
import ThisWeek from "@/pages/MealPlan/ThisWeek"; import ThisWeek from "@/pages/MealPlan/ThisWeek";
import i18n from "@/i18n.js";
import { api } from "@/api"; import { api } from "@/api";
export const mealRoutes = [ export const mealRoutes = [
@ -8,14 +7,14 @@ export const mealRoutes = [
path: "/meal-plan/planner", path: "/meal-plan/planner",
component: Planner, component: Planner,
meta: { meta: {
title: i18n.t("meal-plan.meal-planner"), title: "meal-plan.meal-planner",
}, },
}, },
{ {
path: "/meal-plan/this-week", path: "/meal-plan/this-week",
component: ThisWeek, component: ThisWeek,
meta: { meta: {
title: i18n.t("meal-plan.dinner-this-week"), title: "meal-plan.dinner-this-week",
}, },
}, },
{ {

View File

@ -9,45 +9,6 @@ const notifyHelpers = {
info: "notify-info-color", info: "notify-info-color",
}; };
const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const monthsShort = [
"Jan",
"Feb",
"March",
"April",
"May",
"June",
"July",
"Aug",
"Sept",
"Oct",
"Nov",
"Dec",
];
export default { export default {
getImageURL(image) { getImageURL(image) {
return `/api/recipes/${image}/image?image_type=small`; return `/api/recipes/${image}/image?image_type=small`;
@ -56,22 +17,6 @@ export default {
const uniqueKey = `${item}-${index}`; const uniqueKey = `${item}-${index}`;
return uniqueKey; return uniqueKey;
}, },
getDateAsText(dateObject) {
const dow = days[dateObject.getUTCDay()];
const month = months[dateObject.getUTCMonth()];
const day = dateObject.getUTCDate();
// const year = dateObject.getFullYear();
return `${dow}, ${month} ${day}`;
},
getDateAsTextAlt(dateObject) {
const dow = days[dateObject.getUTCDay()];
const month = monthsShort[dateObject.getUTCMonth()];
const day = dateObject.getUTCDate();
// const year = dateObject.getFullYear();
return `${dow}, ${month} ${day}`;
},
getDateAsPythonDate(dateObject) { getDateAsPythonDate(dateObject) {
const month = dateObject.getUTCMonth() + 1; const month = dateObject.getUTCMonth() + 1;
const day = dateObject.getUTCDate(); const day = dateObject.getUTCDate();