mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-25 08:09:41 +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:
parent
754d4c3937
commit
f8b8680b45
55 changed files with 695 additions and 393 deletions
|
@ -8,9 +8,11 @@
|
|||
<RecipeOrganizerSelector v-model="inputCategories" selector-type="categories" />
|
||||
<RecipeOrganizerSelector v-model="inputTags" selector-type="tags" />
|
||||
|
||||
<!-- TODO Make this localizable -->
|
||||
{{ inputDay === "unset" ? "This rule will apply to all days" : `This rule applies on ${inputDay}s` }}
|
||||
{{ inputEntryType === "unset" ? "for all meal types" : ` and for ${inputEntryType} meal types` }}
|
||||
<!-- TODO: proper pluralization of inputDay -->
|
||||
{{ $t('meal-plan.this-rule-will-apply', {
|
||||
dayCriteria: inputDay === "unset" ? $t('meal-plan.to-all-days') : $t('meal-plan.on-days', [inputDay]),
|
||||
mealTypeCriteria: inputEntryType === "unset" ? $t('meal-plan.for-all-meal-types') : $t('meal-plan.for-type-meal-types', [inputEntryType])
|
||||
}) }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div v-if="preferences">
|
||||
<BaseCardSectionTitle title="General Preferences"></BaseCardSectionTitle>
|
||||
<v-checkbox v-model="preferences.privateGroup" class="mt-n4" label="Private Group"></v-checkbox>
|
||||
<BaseCardSectionTitle :title="$tc('group.general-preferences')"></BaseCardSectionTitle>
|
||||
<v-checkbox v-model="preferences.privateGroup" class="mt-n4" :label="$t('group.private-group')"></v-checkbox>
|
||||
<v-select
|
||||
v-model="preferences.firstDayOfWeek"
|
||||
:prepend-icon="$globals.icons.calendarWeekBegin"
|
||||
|
@ -11,7 +11,7 @@
|
|||
:label="$t('settings.first-day-of-week')"
|
||||
/>
|
||||
|
||||
<BaseCardSectionTitle class="mt-5" title="Group Recipe Preferences"></BaseCardSectionTitle>
|
||||
<BaseCardSectionTitle class="mt-5" :title="$tc('group.group-recipe-preferences')"></BaseCardSectionTitle>
|
||||
<template v-for="(_, key) in preferences">
|
||||
<v-checkbox
|
||||
v-if="labels[key]"
|
||||
|
@ -38,12 +38,12 @@ export default defineComponent({
|
|||
const { i18n } = useContext();
|
||||
|
||||
const labels = {
|
||||
recipePublic: "Allow users outside of your group to see your recipes",
|
||||
recipeShowNutrition: "Show nutrition information",
|
||||
recipeShowAssets: "Show recipe assets",
|
||||
recipeLandscapeView: "Default to landscape view",
|
||||
recipeDisableComments: "Disable recipe comments from users in your group",
|
||||
recipeDisableAmount: "Disable organizing recipe ingredients by units and food",
|
||||
recipePublic: i18n.tc("group.allow-users-outside-of-your-group-to-see-your-recipes"),
|
||||
recipeShowNutrition: i18n.tc("group.show-nutrition-information"),
|
||||
recipeShowAssets: i18n.tc("group.show-recipe-assets"),
|
||||
recipeLandscapeView: i18n.tc("group.default-to-landscape-view"),
|
||||
recipeDisableComments: i18n.tc("group.disable-users-from-commenting-on-recipes"),
|
||||
recipeDisableAmount: i18n.tc("group.disable-organizing-recipe-ingredients-by-units-and-food"),
|
||||
};
|
||||
|
||||
const allDays = [
|
||||
|
@ -96,4 +96,4 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<v-icon left>
|
||||
{{ $globals.icons.chefHat }}
|
||||
</v-icon>
|
||||
<v-list-item-title>{{ "Last Made" }}</v-list-item-title>
|
||||
<v-list-item-title>{{ $t('general.last-made') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<div class="d-flex justify-center flex-wrap">
|
||||
<BaseButton :small="$vuetify.breakpoint.smAndDown" @click="madeThisDialog = true">
|
||||
<template #icon> {{ $globals.icons.chefHat }} </template>
|
||||
I Made This
|
||||
{{ $t('recipe.made-this') }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
<div class="d-flex justify-center flex-wrap">
|
||||
|
@ -63,7 +63,7 @@
|
|||
<v-icon left>
|
||||
{{ $globals.icons.calendar }}
|
||||
</v-icon>
|
||||
Last Made {{ value ? new Date(value+"Z").toLocaleDateString($i18n.locale) : $t("general.never") }}
|
||||
{{ $t('recipe.last-made-date', { date: value ? new Date(value+"Z").toLocaleDateString($i18n.locale) : $t("general.never") } ) }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -25,12 +25,10 @@
|
|||
</v-card-actions>
|
||||
<AdvancedOnly>
|
||||
<v-card v-if="isEditForm" flat class="ma-2 mb-2">
|
||||
<v-card-title> API Extras </v-card-title>
|
||||
<v-card-title> {{ $t('recipe.api-extras') }} </v-card-title>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-card-text>
|
||||
Recipes extras are a key feature of the Mealie API. They allow you to create custom json key/value pairs
|
||||
within a recipe to reference from 3rd part applications. You can use these keys to contain information to
|
||||
trigger automation or custom messages to relay to your desired device.
|
||||
{{ $t('recipe.api-extras-description') }}
|
||||
<v-row v-for="(_, key) in recipe.extras" :key="key" class="mt-1">
|
||||
<v-col cols="8">
|
||||
<v-text-field v-model="recipe.extras[key]" dense :label="key">
|
||||
|
@ -45,7 +43,7 @@
|
|||
</v-card-text>
|
||||
<v-card-actions class="d-flex">
|
||||
<div style="max-width: 200px">
|
||||
<v-text-field v-model="apiNewKey" label="Message Key"></v-text-field>
|
||||
<v-text-field v-model="apiNewKey" :label="$t('recipe.message-key')"></v-text-field>
|
||||
</div>
|
||||
<BaseButton create small class="ml-5" @click="createApiExtra" />
|
||||
</v-card-actions>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<template #icon>
|
||||
{{ $globals.icons.foods }}
|
||||
</template>
|
||||
Parse
|
||||
{{ $t('recipe.parse') }}
|
||||
</BaseButton>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -53,7 +53,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import draggable from "vuedraggable";
|
||||
import { computed, defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent, ref, useContext } from "@nuxtjs/composition-api";
|
||||
import { usePageState, usePageUser } from "~/composables/recipe-page/shared-state";
|
||||
import { NoUndefinedField } from "~/lib/api/types/non-generated";
|
||||
import { Recipe } from "~/lib/api/types/recipe";
|
||||
|
@ -75,6 +75,7 @@ export default defineComponent({
|
|||
setup(props) {
|
||||
const { user } = usePageUser();
|
||||
const { imageKey } = usePageState(props.recipe.slug);
|
||||
const { i18n } = useContext();
|
||||
|
||||
const drag = ref(false);
|
||||
|
||||
|
@ -95,11 +96,11 @@ export default defineComponent({
|
|||
|
||||
const parserToolTip = computed(() => {
|
||||
if (props.recipe.settings.disableAmount) {
|
||||
return "Enable ingredient amounts to use this feature";
|
||||
return i18n.t("recipe.enable-ingredient-amounts-to-use-this-feature");
|
||||
} else if (hasFoodOrUnit.value) {
|
||||
return "Recipes with units or foods defined cannot be parsed.";
|
||||
return i18n.t("recipe.recipes-with-units-or-foods-defined-cannot-be-parsed");
|
||||
}
|
||||
return "Parse ingredients";
|
||||
return i18n.t("recipe.parse-ingredients");
|
||||
});
|
||||
|
||||
function addIngredient(ingredients: Array<string> | null = null) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
:disable-amount="recipe.settings.disableAmount"
|
||||
/>
|
||||
<div v-if="!isEditMode && recipe.tools && recipe.tools.length > 0">
|
||||
<h2 class="mb-2 mt-4">Required Tools</h2>
|
||||
<h2 class="mb-2 mt-4">{{ $t('tool.required-tools') }}</h2>
|
||||
<v-list-item v-for="(tool, index) in recipe.tools" :key="index" dense>
|
||||
<v-checkbox
|
||||
v-model="recipe.tools[index].onHand"
|
||||
|
|
|
@ -135,15 +135,15 @@
|
|||
event: 'open',
|
||||
children: [
|
||||
{
|
||||
text: 'Toggle Section',
|
||||
text: $tc('recipe.toggle-section'),
|
||||
event: 'toggle-section',
|
||||
},
|
||||
{
|
||||
text: 'Link Ingredients',
|
||||
text: $tc('recipe.link-ingredients'),
|
||||
event: 'link-ingredients',
|
||||
},
|
||||
{
|
||||
text: 'Merge Above',
|
||||
text: $tc('recipe.merge-above'),
|
||||
event: 'merge-above',
|
||||
},
|
||||
{
|
||||
|
@ -152,7 +152,7 @@
|
|||
},
|
||||
{
|
||||
icon: previewStates[index] ? $globals.icons.edit : $globals.icons.eye,
|
||||
text: previewStates[index] ? 'Edit Markdown' : 'Preview Markdown',
|
||||
text: previewStates[index] ? $tc('recipe.edit-markdown') : $tc('markdown-editor.preview-markdown-button-label'),
|
||||
event: 'preview-step',
|
||||
},
|
||||
],
|
||||
|
@ -188,7 +188,7 @@
|
|||
:preview.sync="previewStates[index]"
|
||||
:display-preview="false"
|
||||
:textarea="{
|
||||
hint: 'Attach images by dragging & dropping them into the editor',
|
||||
hint: $t('recipe.attach-images-hint'),
|
||||
persistentHint: true,
|
||||
}"
|
||||
/>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
<!-- Recipe Tools Edit -->
|
||||
<v-card v-if="isEditForm" class="mt-2">
|
||||
<v-card-title class="py-2"> Required Tools </v-card-title>
|
||||
<v-card-title class="py-2"> {{ $t('tool.required-tools') }} </v-card-title>
|
||||
<v-divider class="mx-2" />
|
||||
<v-card-text class="pt-0">
|
||||
<RecipeOrganizerSelector v-model="recipe.tools" selector-type="tools" />
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{{ toastAlert.text }}
|
||||
|
||||
<template #action="{ attrs }">
|
||||
<v-btn text v-bind="attrs" @click="toastAlert.open = false"> Close </v-btn>
|
||||
<v-btn text v-bind="attrs" @click="toastAlert.open = false"> {{ $t('general.close') }} </v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
<v-snackbar
|
||||
|
|
|
@ -106,8 +106,9 @@ export default defineComponent({
|
|||
},
|
||||
submitText: {
|
||||
type: String,
|
||||
// TODO Figure out how to localize this default value
|
||||
default: () => "Create",
|
||||
default: function () {
|
||||
return this.$t("general.create");
|
||||
}
|
||||
},
|
||||
keepOpen: {
|
||||
default: false,
|
||||
|
@ -117,6 +118,8 @@ export default defineComponent({
|
|||
setup(props, context) {
|
||||
const dialog = computed<boolean>({
|
||||
get() {
|
||||
// @ts-expect-error - props inference doesn't work here for some reason
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
|
|
|
@ -94,8 +94,9 @@ export default defineComponent({
|
|||
btnText: {
|
||||
type: String,
|
||||
required: false,
|
||||
// TODO Figure out how to localize this default value
|
||||
default: "Actions",
|
||||
default: function () {
|
||||
return this.$t("general.actions");
|
||||
}
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue