mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-27 08:14:30 -04: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:
		| @@ -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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user