1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-05 13:35:23 +02:00

Localize hard-coded texts (#2044)

* feat(lang): localize some views

* feat(lang): an attempt at localizing vuetify (WIP)

* feat(lang): localized some more screens

* feat(lang): localized some more screens again

* feat(lang): hack to localize vuetify

* feat(lang): localize data management pages

* fix linting errors

---------

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
sephrat 2023-01-29 02:39:51 +01:00 committed by GitHub
parent 754d4c3937
commit f8b8680b45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 695 additions and 393 deletions

View file

@ -4,10 +4,8 @@
<template #header>
<v-img max-height="100" max-width="100" :src="require('~/static/svgs/manage-cookbooks.svg')"></v-img>
</template>
<template #title> Cookbooks </template>
Cookbooks are another way to organize recipes by creating cross sections of recipes and tags. Creating a cookbook
will add an entry to the side-bar and all the recipes with the tags and categories chosen will be displayed in the
cookbook.
<template #title> {{ $t('cookbook.cookbooks') }} </template>
{{ $t('cookbook.description') }}
</BasePageTitle>
<BaseButton create @click="actions.createOne()" />
@ -34,35 +32,34 @@
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-card-text v-if="cookbooks">
<v-text-field v-model="cookbooks[index].name" label="Cookbook Name"></v-text-field>
<v-textarea v-model="cookbooks[index].description" auto-grow :rows="2" label="Description"></v-textarea>
<v-text-field v-model="cookbooks[index].name" :label="$t('cookbook.cookbook-name')"></v-text-field>
<v-textarea v-model="cookbooks[index].description" auto-grow :rows="2" :label="$t('recipe.description')"></v-textarea>
<RecipeOrganizerSelector v-model="cookbooks[index].categories" selector-type="categories" />
<RecipeOrganizerSelector v-model="cookbooks[index].tags" selector-type="tags" />
<RecipeOrganizerSelector v-model="cookbooks[index].tools" selector-type="tools" />
<v-switch v-model="cookbooks[index].public" hide-details single-line>
<template #label>
Public Cookbook
{{ $t('cookbook.public-cookbook') }}
<HelpIcon small right class="ml-2">
Public Cookbooks can be shared with non-mealie users and will be displayed on your groups page.
{{ $t('cookbook.public-cookbook-description') }}
</HelpIcon>
</template>
</v-switch>
<div class="mt-4">
<h3 class="text-subtitle-1 d-flex align-center mb-0 pb-0">
Filter Options
{{ $t('cookbook.filter-options') }}
<HelpIcon right small class="ml-2">
When require all is selected the cookbook will only include recipes that have all of the items
selected. This applies to each subset of selectors and not a cross section of the selected items.
{{ $t('cookbook.filter-options-description') }}
</HelpIcon>
</h3>
<v-switch v-model="cookbooks[index].requireAllCategories" class="mt-0" hide-details single-line>
<template #label> Require All Categories </template>
<template #label> {{ $t('cookbook.require-all-categories') }} </template>
</v-switch>
<v-switch v-model="cookbooks[index].requireAllTags" hide-details single-line>
<template #label> Require All Tags </template>
<template #label> {{ $t('cookbook.require-all-tags') }} </template>
</v-switch>
<v-switch v-model="cookbooks[index].requireAllTools" hide-details single-line>
<template #label> Require All Tools </template>
<template #label> {{ $t('cookbook.require-all-tools') }} </template>
</v-switch>
</div>
</v-card-text>

View file

@ -4,8 +4,8 @@
<template #header>
<v-img max-height="175" max-width="175" :src="require('~/static/svgs/manage-recipes.svg')"></v-img>
</template>
<template #title> Data Management </template>
Select which data set you want to make changes to.
<template #title> {{ $t('data-pages.data-management') }} </template>
{{ $t('data-pages.data-management-description') }}
<BannerExperimental class="mt-5"></BannerExperimental>
<template #content>
<div>
@ -13,28 +13,7 @@
:btn-text="buttonText"
mode="link"
rounded
:items="[
{
text: 'Recipes',
value: 'new',
to: '/group/data/recipes',
},
{
text: 'Foods',
value: 'url',
to: '/group/data/foods',
},
{
text: 'Units',
value: 'new',
to: '/group/data/units',
},
{
text: 'Labels',
value: 'new',
to: '/group/data/labels',
},
]"
:items="DATA_TYPE_OPTIONS"
>
</BaseOverflowButton>
</div>
@ -49,7 +28,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, useRoute } from "@nuxtjs/composition-api";
import { computed, defineComponent, useContext, useRoute } from "@nuxtjs/composition-api";
export default defineComponent({
props: {
@ -59,13 +38,37 @@ export default defineComponent({
},
},
setup() {
const { i18n } = useContext();
const buttonLookup: { [key: string]: string } = {
recipes: "Recipes",
foods: "Foods",
units: "Units",
labels: "Labels",
recipes: i18n.tc("general.recipes"),
foods: i18n.tc("general.foods"),
units: i18n.tc("general.units"),
labels: i18n.tc("data-pages.labels.labels"),
};
const DATA_TYPE_OPTIONS = [
{
text: i18n.t("general.recipes"),
value: "new",
to: "/group/data/recipes",
},
{
text: i18n.t("general.foods"),
value: "url",
to: "/group/data/foods",
},
{
text: i18n.t("general.units"),
value: "new",
to: "/group/data/units",
},
{
text: i18n.t("data-pages.labels.labels"),
value: "new",
to: "/group/data/labels",
},
];
const route = useRoute();
const buttonText = computed(() => {
@ -75,15 +78,18 @@ export default defineComponent({
return buttonLookup[last];
}
return "Select Data";
return i18n.tc("data-pages.select-data");
});
return {
buttonText,
DATA_TYPE_OPTIONS
};
},
head: {
title: "Data Management",
head() {
return {
title: this.$tc("data-pages.data-management"),
};
},
});
</script>

View file

@ -1,13 +1,13 @@
<template>
<div>
<!-- Merge Dialog -->
<BaseDialog v-model="mergeDialog" :icon="$globals.icons.foods" title="Combine Food" @confirm="mergeFoods">
<BaseDialog v-model="mergeDialog" :icon="$globals.icons.foods" :title="$t('data-pages.foods.combine-food')" @confirm="mergeFoods">
<v-card-text>
<div>
{{ $t("data-pages.foods.merge-dialog-text") }}
</div>
<v-autocomplete v-model="fromFood" return-object :items="foods" item-text="name" label="Source Food" />
<v-autocomplete v-model="toFood" return-object :items="foods" item-text="name" label="Target Food" />
<v-autocomplete v-model="fromFood" return-object :items="foods" item-text="name" :label="$t('data-pages.foods.source-food')" />
<v-autocomplete v-model="toFood" return-object :items="foods" item-text="name" :label="$t('data-pages.foods.target-food')" />
<template v-if="canMerge && fromFood && toFood">
<div class="text-center">
@ -32,7 +32,7 @@
v-model="locale"
:items="locales"
item-text="name"
label="Select Language"
:label="$t('data-pages.select-language')"
class="my-3"
hide-details
outlined
@ -58,7 +58,7 @@
<BaseDialog
v-model="createDialog"
:icon="$globals.icons.foods"
title="Create Food"
:title="$t('data-pages.foods.create-food')"
:submit-text="$tc('general.save')"
@submit="createFood"
>
@ -67,17 +67,17 @@
<v-text-field
v-model="createTarget.name"
autofocus
label="Name"
:label="$t('general.name')"
:rules="[validators.required]"
></v-text-field>
<v-text-field v-model="createTarget.description" label="Description"></v-text-field>
<v-text-field v-model="createTarget.description" :label="$t('recipe.description')"></v-text-field>
<v-autocomplete
v-model="createTarget.labelId"
clearable
:items="allLabels"
item-value="id"
item-text="name"
label="Food Label"
:label="$t('data-pages.foods.food-label')"
>
</v-autocomplete>
</v-form> </v-card-text
@ -87,21 +87,21 @@
<BaseDialog
v-model="editDialog"
:icon="$globals.icons.foods"
title="Edit Food"
:title="$t('data-pages.foods.edit-food')"
:submit-text="$tc('general.save')"
@submit="editSaveFood"
>
<v-card-text v-if="editTarget">
<v-form ref="domEditFoodForm">
<v-text-field v-model="editTarget.name" label="Name" :rules="[validators.required]"></v-text-field>
<v-text-field v-model="editTarget.description" label="Description"></v-text-field>
<v-text-field v-model="editTarget.name" :label="$t('general.name')" :rules="[validators.required]"></v-text-field>
<v-text-field v-model="editTarget.description" :label="$t('recipe.description')"></v-text-field>
<v-autocomplete
v-model="editTarget.labelId"
clearable
:items="allLabels"
item-value="id"
item-text="name"
label="Food Label"
:label="$t('data-pages.foods.food-label')"
>
</v-autocomplete>
</v-form> </v-card-text
@ -121,7 +121,7 @@
</BaseDialog>
<!-- Recipe Data Table -->
<BaseCardSectionTitle :icon="$globals.icons.foods" section title="Food Data"> </BaseCardSectionTitle>
<BaseCardSectionTitle :icon="$globals.icons.foods" section :title="$tc('data-pages.foods.food-data')"> </BaseCardSectionTitle>
<CrudTable
:table-config="tableConfig"
:headers.sync="tableHeaders"
@ -154,7 +154,7 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, ref, computed } from "@nuxtjs/composition-api";
import { defineComponent, onMounted, ref, computed, useContext } from "@nuxtjs/composition-api";
import type { LocaleObject } from "@nuxtjs/i18n";
import { validators } from "~/composables/use-validators";
import { useUserApi } from "~/composables/api";
@ -168,28 +168,29 @@ export default defineComponent({
components: { MultiPurposeLabel },
setup() {
const userApi = useUserApi();
const { i18n } = useContext();
const tableConfig = {
hideColumns: true,
canExport: true,
};
const tableHeaders = [
{
text: "Id",
text: i18n.tc("general.id"),
value: "id",
show: false,
},
{
text: "Name",
text: i18n.tc("general.name"),
value: "name",
show: true,
},
{
text: "Description",
text: i18n.tc("recipe.description"),
value: "description",
show: true,
},
{
text: "Label",
text: i18n.tc("shopping-list.label"),
value: "label",
show: true,
},
@ -297,7 +298,7 @@ export default defineComponent({
const seedDialog = ref(false);
const locale = ref("");
const { locales: LOCALES, locale: currentLocale, i18n } = useLocales();
const { locales: LOCALES, locale: currentLocale } = useLocales();
onMounted(() => {
locale.value = currentLocale.value;

View file

@ -1,7 +1,7 @@
<template>
<div>
<!-- Create New Dialog -->
<BaseDialog v-model="state.createDialog" title="New Label" :icon="$globals.icons.tags" @submit="createLabel">
<BaseDialog v-model="state.createDialog" :title="$t('data-pages.labels.new-label')" :icon="$globals.icons.tags" @submit="createLabel">
<v-card-text>
<MultiPurposeLabel :label="createLabelData" />
@ -16,7 +16,7 @@
<BaseDialog
v-model="state.editDialog"
:icon="$globals.icons.tags"
title="Edit Label"
:title="$t('data-pages.labels.edit-label')"
:submit-text="$tc('general.save')"
@submit="editSaveLabel"
>
@ -57,7 +57,7 @@
v-model="locale"
:items="locales"
item-text="name"
label="Select Language"
:label="$t('data-pages.select-language')"
class="my-3"
hide-details
outlined
@ -80,7 +80,7 @@
</BaseDialog>
<!-- Recipe Data Table -->
<BaseCardSectionTitle :icon="$globals.icons.tags" section title="Labels"> </BaseCardSectionTitle>
<BaseCardSectionTitle :icon="$globals.icons.tags" section :title="$tc('data-pages.labels.labels')"> </BaseCardSectionTitle>
<CrudTable
:table-config="tableConfig"
:headers.sync="tableHeaders"
@ -103,7 +103,7 @@
<template #button-bottom>
<BaseButton @click="seedDialog = true">
<template #icon> {{ $globals.icons.database }} </template>
Seed
{{ $t('data-pages.seed') }}
</BaseButton>
</template>
</CrudTable>
@ -111,7 +111,7 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, reactive, ref } from "@nuxtjs/composition-api";
import { defineComponent, onMounted, reactive, ref, useContext } from "@nuxtjs/composition-api";
import type { LocaleObject } from "@nuxtjs/i18n";
import { validators } from "~/composables/use-validators";
import { useUserApi } from "~/composables/api";
@ -124,18 +124,19 @@ export default defineComponent({
components: { MultiPurposeLabel },
setup() {
const userApi = useUserApi();
const { i18n } = useContext();
const tableConfig = {
hideColumns: true,
canExport: true,
};
const tableHeaders = [
{
text: "Id",
text: i18n.t("general.id"),
value: "id",
show: false,
},
{
text: "Name",
text: i18n.t("general.name"),
value: "name",
show: true,
},
@ -205,7 +206,7 @@ export default defineComponent({
const seedDialog = ref(false);
const locale = ref("");
const { locales: LOCALES, locale: currentLocale, i18n } = useLocales();
const { locales: LOCALES, locale: currentLocale } = useLocales();
onMounted(() => {
locale.value = currentLocale.value;

View file

@ -3,12 +3,12 @@
<!-- Export Purge Confirmation Dialog -->
<BaseDialog
v-model="purgeExportsDialog"
title="Purge Exports"
:title="$t('data-pages.recipes.purge-exports')"
color="error"
:icon="$globals.icons.alertCircle"
@confirm="purgeExports()"
>
<v-card-text> Are you sure you want to delete all export data? </v-card-text>
<v-card-text> {{ $t('data-pages.recipes.are-you-sure-you-want-to-delete-all-export-data') }} </v-card-text>
</BaseDialog>
<!-- Base Dialog Object -->
@ -18,7 +18,7 @@
width="650px"
:icon="dialog.icon"
:title="dialog.title"
submit-text="Submit"
:submit-text="$t('general.submit')"
@submit="dialog.callback"
>
<v-card-text v-if="dialog.mode == MODES.tag">
@ -28,7 +28,7 @@
<RecipeOrganizerSelector v-model="toSetCategories" selector-type="categories" />
</v-card-text>
<v-card-text v-else-if="dialog.mode == MODES.delete">
<p class="h4">Are you sure you want to delete the following recipes? This action cannot be undone.</p>
<p class="h4">{{ $t('data-pages.recipes.confirm-delete-recipes') }}</p>
<v-card outlined>
<v-virtual-scroll height="400" item-height="25" :items="selected">
<template #default="{ item }">
@ -42,7 +42,7 @@
</v-card>
</v-card-text>
<v-card-text v-else-if="dialog.mode == MODES.export">
<p class="h4">The following recipes ({{ selected.length }}) will be exported.</p>
<p class="h4">{{ $t('data-pages.recipes.the-following-recipes-selected-length-will-be-exported', [selected.length]) }}</p>
<v-card outlined>
<v-virtual-scroll height="400" item-height="25" :items="selected">
<template #default="{ item }">
@ -56,20 +56,19 @@
</v-card>
</v-card-text>
<v-card-text v-else-if="dialog.mode == MODES.updateSettings" class="px-12">
<p>Settings chosen here, excluding the locked option, will be applied to all selected recipes.</p>
<p>{{ $t('data-pages.recipes.settings-chosen-explanation') }}</p>
<div class="mx-auto">
<RecipeSettingsSwitches v-model="recipeSettings" />
</div>
<p class="text-center mb-0">
<i>{{ selected.length }} recipe(s) settings will be updated.</i>
<i>{{ $t('data-pages.recipes.selected-length-recipe-s-settings-will-be-updated', [selected.length]) }}</i>
</p>
</v-card-text>
</BaseDialog>
<section>
<!-- Recipe Data Table -->
<BaseCardSectionTitle :icon="$globals.icons.primary" title="Recipe Data">
Use this section to manage the data associated with your recipes. You can perform several bulk actions on your
recipes including exporting, deleting, tagging, and assigning categories.
<BaseCardSectionTitle :icon="$globals.icons.primary" :title="$tc('data-pages.recipes.recipe-data')">
{{ $t('data-pages.recipes.recipe-data-description') }}
</BaseCardSectionTitle>
<v-card-actions class="mt-n5 mb-1">
<v-menu offset-y bottom nudge-bottom="6" :close-on-content-click="false">
@ -78,12 +77,12 @@
<v-icon left>
{{ $globals.icons.cog }}
</v-icon>
Columns
{{ $t('data-pages.columns') }}
</v-btn>
</template>
<v-card>
<v-card-title class="py-2">
<div>Recipe Columns</div>
<div>{{ $t('data-pages.recipes.recipe-columns') }}</div>
</v-card-title>
<v-divider class="mx-2"></v-divider>
<v-card-text class="mt-n5">
@ -113,7 +112,7 @@
>
</BaseOverflowButton>
<p v-if="selected.length > 0" class="text-caption my-auto ml-5">Selected: {{ selected.length }}</p>
<p v-if="selected.length > 0" class="text-caption my-auto ml-5">{{ $tc('general.selected-count', selected.length) }}</p>
</v-card-actions>
<v-card>
<RecipeDataTable v-model="selected" :loading="loading" :recipes="allRecipes" :show-headers="headers" />
@ -134,7 +133,7 @@
<template #icon>
{{ $globals.icons.database }}
</template>
Export All
{{ $t('general.export-all') }}
</BaseButton>
</v-card-actions>
</v-card>
@ -142,9 +141,8 @@
<section class="mt-10">
<!-- Downloads Data Table -->
<BaseCardSectionTitle :icon="$globals.icons.database" section title="Data Exports">
This section provides links to available exports that are ready to download. These exports do expire, so be sure
to grab them while they're still available.
<BaseCardSectionTitle :icon="$globals.icons.database" section :title="$tc('data-pages.recipes.data-exports')">
{{ $t('data-pages.recipes.data-exports-description') }}
</BaseCardSectionTitle>
<v-card-actions class="mt-n5 mb-1">
<BaseButton delete @click="purgeExportsDialog = true"> </BaseButton>
@ -182,7 +180,7 @@ export default defineComponent({
setup() {
const { getAllRecipes, refreshRecipes } = useRecipes(true, true);
const { $globals } = useContext();
const { $globals, i18n } = useContext();
const selected = ref<Recipe[]>([]);
@ -204,39 +202,39 @@ export default defineComponent({
});
const headerLabels = {
id: "Id",
owner: "Owner",
tags: "Tags",
categories: "Categories",
tools: "Tools",
recipeYield: "Recipe Yield",
dateAdded: "Date Added",
id: i18n.t("general.id"),
owner: i18n.t("general.owner"),
tags: i18n.t("tag.tags"),
categories: i18n.t("recipe.categories"),
tools: i18n.t("tool.tools"),
recipeYield: i18n.t("recipe.recipe-yield"),
dateAdded: i18n.t("general.date-added"),
};
const actions: MenuItem[] = [
{
icon: $globals.icons.database,
text: "Export",
text: i18n.tc("export.export"),
event: "export-selected",
},
{
icon: $globals.icons.tags,
text: "Tag",
text: i18n.tc("data-pages.recipes.tag"),
event: "tag-selected",
},
{
icon: $globals.icons.tags,
text: "Categorize",
text: i18n.tc("data-pages.recipes.categorize"),
event: "categorize-selected",
},
{
icon: $globals.icons.cog,
text: "Update Settings",
text: i18n.tc("data-pages.recipes.update-settings"),
event: "update-settings",
},
{
icon: $globals.icons.delete,
text: "Delete",
text: i18n.tc("general.delete"),
event: "delete-selected",
},
];
@ -352,7 +350,7 @@ export default defineComponent({
const dialog = reactive({
state: false,
title: "Tag Recipes",
title: i18n.t("data-pages.recipes.tag-recipes"),
mode: MODES.tag,
tag: "",
callback: () => {
@ -364,11 +362,11 @@ export default defineComponent({
function openDialog(mode: MODES) {
const titles: Record<MODES, string> = {
[MODES.tag]: "Tag Recipes",
[MODES.category]: "Categorize Recipes",
[MODES.export]: "Export Recipes",
[MODES.delete]: "Delete Recipes",
[MODES.updateSettings]: "Update Settings",
[MODES.tag]: i18n.tc("data-pages.recipes.tag-recipes"),
[MODES.category]: i18n.tc("data-pages.recipes.categorize-recipes"),
[MODES.export]: i18n.tc("data-pages.recipes.export-recipes"),
[MODES.delete]: i18n.tc("data-pages.recipes.delete-recipes"),
[MODES.updateSettings]: i18n.tc("data-pages.recipes.update-settings"),
};
const callbacks: Record<MODES, () => Promise<void>> = {
@ -420,7 +418,7 @@ export default defineComponent({
},
head() {
return {
title: "Recipe Data",
title: this.$tc("data-pages.recipes.recipe-data"),
};
},
});

View file

@ -1,23 +1,25 @@
<template>
<div>
<!-- Merge Dialog -->
<BaseDialog v-model="mergeDialog" :icon="$globals.icons.units" title="Combine Unit" @confirm="mergeUnits">
<BaseDialog v-model="mergeDialog" :icon="$globals.icons.units" :title="$t('data-pages.units.combine-unit')" @confirm="mergeUnits">
<v-card-text>
Combining the selected units will merge the Source Unit and Target Unit into a single unit. The
<strong> Source Unit will be deleted </strong> and all of the references to the Source Unit will be updated to
point to the Target Unit.
<i18n path="data-pages.units.combine-unit-description">
<template #source-unit-will-be-deleted>
<strong> {{ $t('data-pages.recipes.source-unit-will-be-deleted') }} </strong>
</template>
</i18n>
<v-autocomplete v-model="fromUnit" return-object :items="units" item-text="id" label="Source Unit">
<v-autocomplete v-model="fromUnit" return-object :items="units" item-text="id" :label="$t('data-pages.units.source-unit')">
<template #selection="{ item }"> {{ item.name }}</template>
<template #item="{ item }"> {{ item.name }} </template>
</v-autocomplete>
<v-autocomplete v-model="toUnit" return-object :items="units" item-text="id" label="Target Unit">
<v-autocomplete v-model="toUnit" return-object :items="units" item-text="id" :label="$t('data-pages.units.target-unit')">
<template #selection="{ item }"> {{ item.name }}</template>
<template #item="{ item }"> {{ item.name }} </template>
</v-autocomplete>
<template v-if="canMerge && fromUnit && toUnit">
<div class="text-center">Merging {{ fromUnit.name }} into {{ toUnit.name }}</div>
<div class="text-center">{{ $t('data-pages.units.merging-unit-into-unit', [fromUnit.name, toUnit.name]) }}</div>
</template>
</v-card-text>
</BaseDialog>
@ -26,7 +28,7 @@
<BaseDialog
v-model="createDialog"
:icon="$globals.icons.units"
title="Create Unit"
:title="$t('data-pages.units.create-unit')"
:submit-text="$tc('general.save')"
@submit="createUnit"
>
@ -35,13 +37,13 @@
<v-text-field
v-model="createTarget.name"
autofocus
label="Name"
:label="$t('general.name')"
:rules="[validators.required]"
></v-text-field>
<v-text-field v-model="createTarget.abbreviation" label="Abbreviation"></v-text-field>
<v-text-field v-model="createTarget.description" label="Description"></v-text-field>
<v-checkbox v-model="createTarget.fraction" hide-details label="Display as Fraction"></v-checkbox>
<v-checkbox v-model="createTarget.useAbbreviation" hide-details label="Use Abbreviation"></v-checkbox>
<v-text-field v-model="createTarget.abbreviation" :label="$t('data-pages.units.abbreviation')"></v-text-field>
<v-text-field v-model="createTarget.description" :label="$t('data-pages.units.description')"></v-text-field>
<v-checkbox v-model="createTarget.fraction" hide-details :label="$t('data-pages.units.display-as-fraction')"></v-checkbox>
<v-checkbox v-model="createTarget.useAbbreviation" hide-details :label="$t('data-pages.units.use-abbreviation')"></v-checkbox>
</v-form>
</v-card-text>
</BaseDialog>
@ -50,17 +52,17 @@
<BaseDialog
v-model="editDialog"
:icon="$globals.icons.units"
title="Edit Unit"
:title="$t('data-pages.units.edit-unit')"
:submit-text="$tc('general.save')"
@submit="editSaveUnit"
>
<v-card-text v-if="editTarget">
<v-form ref="domEditUnitForm">
<v-text-field v-model="editTarget.name" label="Name" :rules="[validators.required]"></v-text-field>
<v-text-field v-model="editTarget.abbreviation" label="Abbreviation"></v-text-field>
<v-text-field v-model="editTarget.description" label="Description"></v-text-field>
<v-checkbox v-model="editTarget.fraction" hide-details label="Display as Fraction"></v-checkbox>
<v-checkbox v-model="editTarget.useAbbreviation" hide-details label="Use Abbreviation"></v-checkbox>
<v-text-field v-model="editTarget.name" :label="$t('general.name')" :rules="[validators.required]"></v-text-field>
<v-text-field v-model="editTarget.abbreviation" :label="$t('data-pages.units.abbreviation')"></v-text-field>
<v-text-field v-model="editTarget.description" :label="$t('data-pages.units.description')"></v-text-field>
<v-checkbox v-model="editTarget.fraction" hide-details :label="$t('data-pages.units.display-as-fraction')"></v-checkbox>
<v-checkbox v-model="editTarget.useAbbreviation" hide-details :label="$t('data-pages.units.use-abbreviation')"></v-checkbox>
</v-form>
</v-card-text>
</BaseDialog>
@ -93,7 +95,7 @@
v-model="locale"
:items="locales"
item-text="name"
label="Select Language"
:label="$t('data-pages.select-language')"
class="my-3"
hide-details
outlined
@ -116,7 +118,7 @@
</BaseDialog>
<!-- Recipe Data Table -->
<BaseCardSectionTitle :icon="$globals.icons.units" section title="Unit Data"> </BaseCardSectionTitle>
<BaseCardSectionTitle :icon="$globals.icons.units" section :title="$tc('data-pages.units.unit-data')"> </BaseCardSectionTitle>
<CrudTable
:table-config="tableConfig"
:headers.sync="tableHeaders"
@ -155,7 +157,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, ref } from "@nuxtjs/composition-api";
import { computed, defineComponent, onMounted, ref, useContext } from "@nuxtjs/composition-api";
import type { LocaleObject } from "@nuxtjs/i18n";
import { validators } from "~/composables/use-validators";
import { useUserApi } from "~/composables/api";
@ -167,38 +169,39 @@ import { VForm } from "~/types/vuetify";
export default defineComponent({
setup() {
const userApi = useUserApi();
const { i18n } = useContext();
const tableConfig = {
hideColumns: true,
canExport: true,
};
const tableHeaders = [
{
text: "Id",
text: i18n.t("general.id"),
value: "id",
show: false,
},
{
text: "Name",
text: i18n.t("general.name"),
value: "name",
show: true,
},
{
text: "Abbreviation",
text: i18n.t("data-pages.units.abbreviation"),
value: "abbreviation",
show: true,
},
{
text: "Use Abbv.",
text: i18n.t("data-pages.units.use-abbv"),
value: "useAbbreviation",
show: true,
},
{
text: "Description",
text: i18n.t("data-pages.units.description"),
value: "description",
show: false,
},
{
text: "Fraction",
text: i18n.t("data-pages.units.fraction"),
value: "fraction",
show: true,
},
@ -304,7 +307,7 @@ export default defineComponent({
const seedDialog = ref(false);
const locale = ref("");
const { locales: LOCALES, locale: currentLocale, i18n } = useLocales();
const { locales: LOCALES, locale: currentLocale } = useLocales();
onMounted(() => {
locale.value = currentLocale.value;

View file

@ -4,16 +4,16 @@
<template #header>
<v-img max-height="100" max-width="100" :src="require('~/static/svgs/manage-group-settings.svg')"></v-img>
</template>
<template #title> Group Settings </template>
These items are shared within your group. Editing one of them will change it for the whole group!
<template #title> {{ $t('profile.group-settings') }} </template>
{{ $t('profile.group-description') }}
</BasePageTitle>
<section v-if="group">
<BaseCardSectionTitle class="mt-10" title="Group Preferences"></BaseCardSectionTitle>
<BaseCardSectionTitle class="mt-10" :title="$tc('group.group-preferences')"></BaseCardSectionTitle>
<v-checkbox
v-model="group.preferences.privateGroup"
class="mt-n4"
label="Private Group"
:label="$t('group.private-group')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-select
@ -28,45 +28,44 @@
</section>
<section v-if="group">
<BaseCardSectionTitle class="mt-10" title="Default Recipe Preferences">
These are the default settings when a new recipe is created in your group. These can be changed for individual
recipes in the recipe settings menu.
<BaseCardSectionTitle class="mt-10" :title="$tc('group.default-recipe-preferences')">
{{ $t('group.default-recipe-preferences-description') }}
</BaseCardSectionTitle>
<v-checkbox
v-model="group.preferences.recipePublic"
class="mt-n4"
label="Allow users outside of your group to see your recipes"
:label="$t('group.allow-users-outside-of-your-group-to-see-your-recipes')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-checkbox
v-model="group.preferences.recipeShowNutrition"
class="mt-n4"
label="Show nutrition information"
:label="$t('group.show-nutrition-information')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-checkbox
v-model="group.preferences.recipeShowAssets"
class="mt-n4"
label="Show recipe assets"
:label="$t('group.show-recipe-assets')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-checkbox
v-model="group.preferences.recipeLandscapeView"
class="mt-n4"
label="Default to landscape view"
:label="$t('group.default-to-landscape-view')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-checkbox
v-model="group.preferences.recipeDisableComments"
class="mt-n4"
label="Disable users from commenting on recipes"
:label="$t('group.disable-users-from-commenting-on-recipes')"
@change="groupActions.updatePreferences()"
></v-checkbox>
<v-checkbox
v-model="group.preferences.recipeDisableAmount"
class="mt-n4"
label="Disable organizing recipe ingredients by units and food"
:label="$t('group.disable-organizing-recipe-ingredients-by-units-and-food')"
@change="groupActions.updatePreferences()"
></v-checkbox>
</section>

View file

@ -35,25 +35,25 @@
<v-date-picker v-model="newMeal.date" :first-day-of-week="firstDayOfWeek" no-title @input="pickerMenu = false"></v-date-picker>
</v-menu>
<v-card-text>
<v-select v-model="newMeal.entryType" :return-object="false" :items="planTypeOptions" label="Entry Type">
<v-select v-model="newMeal.entryType" :return-object="false" :items="planTypeOptions" :label="$t('recipe.entry-type')">
</v-select>
<v-autocomplete
v-if="!dialog.note"
v-model="newMeal.recipeId"
label="Meal Recipe"
:label="$t('meal-plan.meal-recipe')"
:items="allRecipes"
item-text="name"
item-value="id"
:return-object="false"
></v-autocomplete>
<template v-else>
<v-text-field v-model="newMeal.title" label="Meal Title"> </v-text-field>
<v-textarea v-model="newMeal.text" rows="2" label="Meal Note"> </v-textarea>
<v-text-field v-model="newMeal.title" :label="$t('meal-plan.meal-title')"> </v-text-field>
<v-textarea v-model="newMeal.text" rows="2" :label="$t('meal-plan.meal-note')"> </v-textarea>
</template>
</v-card-text>
<v-card-actions class="my-0 py-0">
<v-switch v-model="dialog.note" class="mt-n3" label="Note Only"></v-switch>
<v-switch v-model="dialog.note" class="mt-n3" :label="$t('meal-plan.note-only')"></v-switch>
</v-card-actions>
</v-card-text>
</BaseDialog>
@ -71,8 +71,8 @@
</div>
</div>
<div class="d-flex align-center justify-space-between">
<v-switch v-model="edit" label="Editor"></v-switch>
<ButtonLink :icon="$globals.icons.calendar" to="/group/mealplan/settings" text="Settings" />
<v-switch v-model="edit" :label="$t('meal-plan.editor')"></v-switch>
<ButtonLink :icon="$globals.icons.calendar" to="/group/mealplan/settings" :text="$tc('general.settings')" />
</div>
<v-row class="">
<v-col
@ -174,7 +174,7 @@
:buttons="[
{
icon: $globals.icons.diceMultiple,
text: 'Random Meal',
text: $tc('meal-plan.random-meal'),
event: 'random',
children: [
{
@ -185,19 +185,19 @@
{
icon: $globals.icons.diceMultiple,
text: 'Lunch',
text: $tc('meal-plan.lunch'),
event: 'randomLunch',
},
],
},
{
icon: $globals.icons.potSteam,
text: 'Random Dinner',
text: $tc('meal-plan.random-dinner'),
event: 'randomDinner',
},
{
icon: $globals.icons.bowlMixOutline,
text: 'Random Side',
text: $tc('meal-plan.random-side'),
event: 'randomSide',
},
{

View file

@ -4,20 +4,15 @@
<template #header>
<v-img max-height="100" max-width="100" :src="require('~/static/svgs/manage-cookbooks.svg')"></v-img>
</template>
<template #title> Meal Plan Rules </template>
You can create rules for auto selecting recipes for you meal plans. These rules are used by the server to
determine the random pool of recipes to select from when creating meal plans. Note that if rules have the same
day/type constraints then the categories of the rules will be merged. In practice, it's unnecessary to create
duplicate rules, but it's possible to do so.
<template #title> {{ $t('meal-plan.meal-plan-rules') }} </template>
{{ $t('meal-plan.meal-plan-rules-description') }}
</BasePageTitle>
<v-card>
<v-card-title class="headline"> New Rule </v-card-title>
<v-card-title class="headline"> {{ $t('meal-plan.new-rule') }} </v-card-title>
<v-divider class="mx-2"></v-divider>
<v-card-text>
When creating a new rule for a meal plan you can restrict the rule to be applicable for a specific day of the
week and/or a specific type of meal. To apply a rule to all days or all meal types you can set the rule to "Any"
which will apply it to all the possible values for the day and/or meal type.
{{ $t('meal-plan.new-rule-description') }}
<GroupMealPlanRuleForm
class="mt-2"
@ -33,13 +28,13 @@
</v-card>
<section>
<BaseCardSectionTitle class="mt-10" title="Recipe Rules" />
<BaseCardSectionTitle class="mt-10" :title="$tc('meal-plan.recipe-rules')" />
<div>
<div v-for="(rule, idx) in allRules" :key="rule.id">
<v-card class="my-2 left-border">
<v-card-title class="headline pb-1">
{{ rule.day === "unset" ? "Applies to all days" : `Applies on ${rule.day}s` }}
{{ rule.entryType === "unset" ? "for all meal types" : ` for ${rule.entryType} meal types` }}
{{ rule.day === "unset" ? $t('meal-plan.applies-to-all-days') : $t('meal-plan.applies-on-days', [rule.day]) }}
{{ rule.entryType === "unset" ? $t('meal-plan.for-all-meal-types') : $t('meal-plan.for-type-meal-types', [rule.entryType]) }}
<span class="ml-auto">
<BaseButtonGroup
:buttons="[
@ -91,7 +86,7 @@
</template>
<script lang="ts">
import { defineComponent, ref, useAsync } from "@nuxtjs/composition-api";
import { defineComponent, ref, useAsync, useContext } from "@nuxtjs/composition-api";
import { useUserApi } from "~/composables/api";
import { PlanRulesCreate, PlanRulesOut } from "~/lib/api/types/meal-plan";
import GroupMealPlanRuleForm from "~/components/Domain/Group/GroupMealPlanRuleForm.vue";
@ -182,8 +177,10 @@ export default defineComponent({
toggleEditState,
};
},
head: {
title: "Meal Plan Settings",
head() {
return {
title: this.$tc("meal-plan.meal-plan-settings"),
};
},
});
</script>

View file

@ -4,13 +4,18 @@
<template #header>
<v-img max-height="125" max-width="125" :src="require('~/static/svgs/manage-members.svg')"></v-img>
</template>
<template #title> Manage Members </template>
Manage the permissions of the members in your groups. <b> Manage </b> allows the user to access the
data-management page <b> Invite </b> allows the user to generate invitation links for other users. Group owners
cannot change their own permissions.
<template #title> {{ $t('group.manage-members') }} </template>
<i18n path="group.manage-members-description">
<template #manage>
<b>{{ $t('group.manage') }}</b>
</template>
<template #invite>
<b>{{ $t('group.invite') }}</b>
</template>
</i18n>
</BasePageTitle>
<v-container class="mt-4 d-flex justify-start">
<v-btn outlined rounded to="/user/profile/edit"> Looking to Update Your Profile? </v-btn>
<v-btn outlined rounded to="/user/profile/edit"> {{ $t('group.looking-to-update-your-profile') }} </v-btn>
</v-container>
<v-data-table
:headers="headers"
@ -24,7 +29,7 @@
<UserAvatar :user-id="item.id" />
</template>
<template #item.admin="{ item }">
{{ item.admin ? "Admin" : "User" }}
{{ item.admin ? $t('user.admin') : $t('user.user') }}
</template>
<template #item.manage="{ item }">
<div class="d-flex justify-center">
@ -85,9 +90,9 @@ export default defineComponent({
{ text: i18n.t("user.username"), value: "username" },
{ text: i18n.t("user.full-name"), value: "fullName" },
{ text: i18n.t("user.admin"), value: "admin" },
{ text: "Manage", value: "manage", sortable: false, align: "center" },
{ text: "Organize", value: "organize", sortable: false, align: "center" },
{ text: "Invite", value: "invite", sortable: false, align: "center" },
{ text: i18n.t("group.manage"), value: "manage", sortable: false, align: "center" },
{ text: i18n.t("settings.organize"), value: "organize", sortable: false, align: "center" },
{ text: i18n.t("group.invite"), value: "invite", sortable: false, align: "center" },
];
async function refreshMembers() {
@ -116,7 +121,7 @@ export default defineComponent({
},
head() {
return {
title: "Members",
title: this.$t("profile.members"),
};
},
});

View file

@ -4,7 +4,7 @@
<template #header>
<v-img max-height="200" max-width="200" class="mb-2" :src="require('~/static/svgs/data-reports.svg')"></v-img>
</template>
<template #title> Report </template>
<template #title> {{ $t('group.report') }} </template>
</BasePageTitle>
<v-container v-if="report">
<BaseCardSectionTitle :title="report.name"> </BaseCardSectionTitle>