chore: make vue global components and layouts localizable ()

This commit is contained in:
Philipp Fischbeck 2022-08-15 23:55:51 +02:00 committed by GitHub
parent 7af48d51be
commit ba15006bb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 193 additions and 153 deletions

@ -28,7 +28,7 @@
:prepend-inner-icon="$globals.icons.search"
background-color="primary lighten-1"
color="white"
placeholder="Press '/'"
:placeholder="$t('search.search-hint')"
>
</v-text-field>
</div>

@ -8,7 +8,9 @@
<v-list-item-content>
<v-list-item-title> {{ $auth.user.fullName }}</v-list-item-title>
<v-list-item-subtitle>
<NuxtLink class="favorites-link" :to="`/user/${$auth.user.id}/favorites`"> Favorite Recipes </NuxtLink>
<NuxtLink class="favorites-link" :to="`/user/${$auth.user.id}/favorites`">
{{ $t("user.favorite-recipes") }}
</NuxtLink>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>

@ -22,14 +22,14 @@
@blur="on.blur"
>
<v-icon>{{ $globals.icons.contentCopy }}</v-icon>
{{ icon ? "" : "Copy" }}
{{ icon ? "" : $t("general.copy") }}
</v-btn>
</template>
<span>
<v-icon left dark>
{{ $globals.icons.clipboardCheck }}
</v-icon>
<slot> {{ $t("general.copied") }}! </slot>
<slot> {{ $t("general.copied_message") }} </slot>
</span>
</v-tooltip>
</template>
@ -42,7 +42,7 @@ export default defineComponent({
props: {
copyText: {
type: String,
default: "Default Copy Text",
required: true,
},
color: {
type: String,
@ -81,10 +81,9 @@ export default defineComponent({
show,
copyToolTip,
textToClipboard,
}
};
},
});
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>

@ -129,7 +129,9 @@
</div>
<v-card-actions>
<v-spacer />
<BaseButton small @click="value[inputField.varName].push(getTemplate(inputField.items))"> New </BaseButton>
<BaseButton small @click="value[inputField.varName].push(getTemplate(inputField.items))">
{{ $t("general.new") }}
</BaseButton>
</v-card-actions>
</div>
</v-col>

@ -1,14 +1,13 @@
<template>
<v-alert border="left" colored-border type="warning" elevation="2" :icon="$globals.icons.alert">
<b>Experimental Feature</b>
<div>This page contains experimental or still-baking features. Please excuse the mess.</div>
<b>{{ $t("banner-experimental.title") }}</b>
<div>{{ $t("banner-experimental.description") }}</div>
<div v-if="issue != ''" class="py-2">
<a :href="issue" target="_blank"> Track our progress here</a>
<a :href="issue" target="_blank">{{ $t("banner-experimental.issue-link-text") }}</a>
</div>
</v-alert>
</template>
<script lang="ts">
export default {
props: {
@ -19,4 +18,4 @@ export default {
},
},
};
</script>
</script>

@ -109,40 +109,40 @@ export default defineComponent({
},
},
setup(props) {
const { $globals } = useContext();
const { $globals, i18n } = useContext();
const buttonOptions = {
create: {
text: "Create",
text: i18n.t("general.create"),
icon: $globals.icons.createAlt,
color: "success",
},
update: {
text: "Update",
text: i18n.t("general.update"),
icon: $globals.icons.edit,
color: "success",
},
save: {
text: "Save",
text: i18n.t("general.save"),
icon: $globals.icons.save,
color: "success",
},
edit: {
text: "Edit",
text: i18n.t("general.edit"),
icon: $globals.icons.edit,
color: "info",
},
delete: {
text: "Delete",
text: i18n.t("general.delete"),
icon: $globals.icons.delete,
color: "error",
},
cancel: {
text: "Cancel",
text: i18n.t("general.cancel"),
icon: $globals.icons.close,
color: "grey",
},
download: {
text: "Download",
text: i18n.t("general.download"),
icon: $globals.icons.download,
color: "info",
},
@ -189,13 +189,11 @@ export default defineComponent({
return buttonStyles.defaults;
});
const api = useUserApi();
function downloadFile() {
api.utils.download(props.downloadUrl);
}
return {
btnAttrs,
btnStyle,

@ -1,4 +1,3 @@
<template>
<v-card
color="background"
@ -30,7 +29,7 @@ export default defineComponent({
props: {
title: {
type: String,
default: "Place Holder",
required: true,
},
icon: {
type: String,

@ -102,6 +102,7 @@ export default defineComponent({
},
submitText: {
type: String,
// TODO Figure out how to localize this default value
default: () => "Create",
},
keepOpen: {

@ -1,4 +1,4 @@
<template>
<template>
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-btn color="primary" v-bind="{ ...attrs, ...$attrs }" :class="btnClass" :disabled="disabled" v-on="on">
@ -94,6 +94,7 @@ export default defineComponent({
btnText: {
type: String,
required: false,
// TODO Figure out how to localize this default value
default: "Actions",
},
},
@ -115,7 +116,7 @@ export default defineComponent({
function setValue(v: MenuItem) {
context.emit(INPUT_EVENT, v.value);
activeObj.value = v;
activeObj.value = v;
}
return {
@ -127,6 +128,3 @@ export default defineComponent({
},
});
</script>

@ -20,7 +20,7 @@ export default defineComponent({
},
text: {
type: String,
default: "Link",
required: true,
},
icon: {
type: String,
@ -28,4 +28,4 @@ export default defineComponent({
},
},
});
</script>
</script>

@ -37,7 +37,7 @@
<slot name="button-row"> </slot>
</v-card-actions>
<div class="mx-2 clip-width">
<v-text-field v-model="search" :label="$tc('search.search')"></v-text-field>
<v-text-field v-model="search" :label="$t('search.search')"></v-text-field>
</div>
<v-data-table
v-model="selected"
@ -57,12 +57,12 @@
:buttons="[
{
icon: $globals.icons.edit,
text: 'Edit',
text: $t('general.edit'),
event: 'edit',
},
{
icon: $globals.icons.delete,
text: 'Delete',
text: $t('general.delete'),
event: 'delete',
},
]"
@ -77,7 +77,7 @@
<template #icon>
{{ $globals.icons.download }}
</template>
{{ $tc("general.download") }}
{{ $t("general.download") }}
</BaseButton>
</v-card-actions>
</div>

@ -1,5 +1,5 @@
<template>
<v-text-field v-model="inputVal" label="Color">
<v-text-field v-model="inputVal" :label="$t('general.color')">
<template #prepend>
<v-btn class="elevation-0" small height="30px" width="30px" :color="inputVal || 'grey'" @click="setRandomHex">
<v-icon color="white">
@ -63,4 +63,4 @@ export default defineComponent({
};
},
});
</script>
</script>

@ -3,7 +3,7 @@
<v-text-field
v-model.number="quantity"
hide-details
label="Qty"
:label="$t('form.quantity-label-abbreviated')"
:min="min"
:max="max"
type="number"
@ -21,10 +21,6 @@ import { computed, defineComponent } from "@nuxtjs/composition-api";
export default defineComponent({
name: "VInputNumber",
props: {
label: {
type: String,
default: "Qty",
},
min: {
type: Number,
default: 0,
@ -61,4 +57,4 @@ export default defineComponent({
};
},
});
</script>
</script>

@ -5,7 +5,7 @@
:buttons="[
{
icon: previewState ? $globals.icons.edit : $globals.icons.eye,
text: previewState ? $tc('general.edit') : 'Preview Markdown',
text: previewState ? $t('general.edit') : $t('markdown-editor.preview-markdown-button-label'),
event: 'toggle',
},
]"

@ -25,7 +25,7 @@
</template>
<script lang="ts">
import { defineComponent, useRouter } from "@nuxtjs/composition-api";
import { defineComponent, useContext, useRouter } from "@nuxtjs/composition-api";
import { ReportSummary } from "~/types/api-types/reports";
export default defineComponent({
@ -38,13 +38,14 @@ export default defineComponent({
setup(_, context) {
const router = useRouter();
const { i18n } = useContext();
const headers = [
{ text: "Category", value: "category" },
{ text: "Name", value: "name" },
{ text: "Timestamp", value: "timestamp" },
{ text: "Status", value: "status" },
{ text: "Delete", value: "actions" },
{ text: i18n.t("category.category"), value: "category" },
{ text: i18n.t("general.name"), value: "name" },
{ text: i18n.t("general.timestamp"), value: "timestamp" },
{ text: i18n.t("general.status"), value: "status" },
{ text: i18n.t("general.delete"), value: "actions" },
];
function handleRowClick(item: ReportSummary) {

@ -20,7 +20,8 @@
"portfolio": "Portfolio",
"production": "Production",
"support": "Support",
"version": "Version"
"version": "Version",
"unknown-version": "unknown"
},
"asset": {
"assets": "Assets",
@ -44,7 +45,8 @@
"category-updated": "Category updated",
"uncategorized-count": "Uncategorized {count}",
"create-a-category": "Create a Category",
"category-name": "Category Name"
"category-name": "Category Name",
"category": "Category"
},
"events": {
"apprise-url": "Apprise URL",
@ -65,7 +67,7 @@
"close": "Close",
"confirm": "Confirm",
"confirm-delete-generic": "Are you sure you want to delete this?",
"copied": "Copied",
"copied_message": "Copied!",
"create": "Create",
"created": "Created",
"custom": "Custom",
@ -150,7 +152,10 @@
"delete-with-name": "Delete {name}",
"confirm-delete-generic-with-name": "Are you sure you want to delete this {name}?",
"organizer": "Organizer",
"transfer": "Transfer"
"transfer": "Transfer",
"copy": "Copy",
"color": "Color",
"timestamp": "Timestamp"
},
"group": {
"are-you-sure-you-want-to-delete-the-group": "Are you sure you want to delete <b>{groupName}<b/>?",
@ -241,7 +246,9 @@
"view-scraped-data": "View Scraped Data",
"trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines",
"trim-prefix-description": "Trim first character from each line",
"split-by-numbered-line-description": "Attempts to split a paragraph by matching '1)' or '1.' patterns"
"split-by-numbered-line-description": "Attempts to split a paragraph by matching '1)' or '1.' patterns",
"import-by-url": "Import a recipe by URL",
"create-manually": "Create a recipe manually"
},
"page": {
"404-page-not-found": "404 Page not found",
@ -254,7 +261,9 @@
"page-update-failed": "Page update failed",
"page-updated": "Page updated",
"pages-update-failed": "Pages update failed",
"pages-updated": "Pages updated"
"pages-updated": "Pages updated",
"404-not-found": "404 Not Found",
"an-error-occurred": "An error occurred"
},
"recipe": {
"add-key": "Add Key",
@ -357,7 +366,8 @@
"search": "Search",
"search-mealie": "Search Mealie (press /)",
"search-placeholder": "Search...",
"tag-filter": "Tag Filter"
"tag-filter": "Tag Filter",
"search-hint": "Press '/'"
},
"settings": {
"add-a-new-theme": "Add a New Theme",
@ -425,7 +435,9 @@
"theme-name-is-required": "Theme Name is required.",
"theme-saved": "Theme Saved",
"theme-updated": "Theme updated",
"warning": "Warning"
"warning": "Warning",
"light-mode": "Light Mode",
"dark-mode": "Dark Mode"
},
"token": {
"active-tokens": "ACTIVE TOKENS",
@ -484,7 +496,13 @@
"site-settings": "Site Settings",
"tags": "Tags",
"toolbox": "Toolbox",
"language": "Language"
"language": "Language",
"maintenance": "Maintenance",
"background-tasks": "Background Tasks",
"parser": "Parser",
"developer": "Developer",
"cookbook": "Cookbook",
"create-cookbook": "Create a new cookbook"
},
"signup": {
"error-signing-up": "Error Signing Up",
@ -572,7 +590,8 @@
"you-are-not-allowed-to-create-a-user": "You are not allowed to create a user",
"you-are-not-allowed-to-delete-this-user": "You are not allowed to delete this user",
"enable-advanced-content": "Enable Advanced Content",
"enable-advanced-content-description": "Enables advanced features like Recipe Scaling, API keys, Webhooks, and Data Management. Don't worry, you can always change this later"
"enable-advanced-content-description": "Enables advanced features like Recipe Scaling, API keys, Webhooks, and Data Management. Don't worry, you can always change this later",
"favorite-recipes": "Favorite Recipes"
},
"language-dialog": {
"translated": "translated",
@ -624,5 +643,21 @@
"default-30-days": "Default 30 Days",
"expires-at": "Expires At",
"recipe-link-copied-message": "Recipe link copied to clipboard"
},
"banner-experimental": {
"title": "Experimental Feature",
"description": "This page contains experimental or still-baking features. Please excuse the mess.",
"issue-link-text": "Track our progress here"
},
"form": {
"quantity-label-abbreviated": "Qty"
},
"markdown-editor": {
"preview-markdown-button-label": "Preview Markdown"
},
"demo": {
"info_message_with_version": "This is a Demo for version: {version}",
"demo_username": "Username: {username}",
"demo_password": "Password: {password}"
}
}

@ -6,7 +6,7 @@
:top-link="topLinks"
:bottom-links="bottomLinks"
:user="{ data: true }"
secondary-header="Developer"
:secondary-header="$t('sidebar.developer')"
:secondary-links="developerLinks"
/>
@ -77,17 +77,17 @@ export default defineComponent({
{
icon: $globals.icons.wrench,
to: "/admin/maintenance",
title: "Maintenance",
title: i18n.t("sidebar.maintenance"),
},
{
icon: $globals.icons.check,
to: "/admin/background-tasks",
title: "Background Tasks",
title: i18n.t("sidebar.background-tasks"),
},
{
icon: $globals.icons.slotMachine,
to: "/admin/parser",
title: "Parser",
title: i18n.t("sidebar.parser"),
},
];

@ -4,7 +4,9 @@
<v-banner v-if="isDemo" sticky>
<div class="text-center">
<b> This is a Demo for version: {{ version }} </b> | Username: changeme@email.com | Password: demo
<b> {{ $t("demo.info_message_with_version", { version: version }) }} </b> |
{{ $t("demo.demo_username", { username: "changeme@email.com" }) }} |
{{ $t("demo.demo_password", { password: "demo" }) }}
</div>
</v-banner>
@ -17,7 +19,7 @@
</template>
<script lang="ts">
import { computed, defineComponent } from "@nuxtjs/composition-api";
import { computed, defineComponent, useContext } from "@nuxtjs/composition-api";
import TheSnackbar from "~/components/Layout/TheSnackbar.vue";
import { useAppInfo } from "~/composables/api";
export default defineComponent({
@ -27,7 +29,8 @@ export default defineComponent({
const isDemo = computed(() => appInfo?.value?.demoStatus || false);
const version = computed(() => appInfo?.value?.version || "unknown");
const { i18n } = useContext();
const version = computed(() => appInfo?.value?.version || i18n.t("about.unknown-version"));
return {
appInfo,

@ -6,7 +6,7 @@
v-model="sidebar"
absolute
:top-link="topLinks"
secondary-header="Cookbooks"
:secondary-header="$t('sidebar.cookbooks')"
secondary-header-link="/group/cookbooks"
:secondary-links="cookbookLinks || []"
:bottom-links="isAdmin ? bottomLink : []"
@ -57,7 +57,9 @@
{{ $vuetify.theme.dark ? $globals.icons.weatherSunny : $globals.icons.weatherNight }}
</v-icon>
</v-list-item-icon>
<v-list-item-title> {{ $vuetify.theme.dark ? "Light Mode" : "Dark Mode" }} </v-list-item-title>
<v-list-item-title>
{{ $vuetify.theme.dark ? $t("settings.theme.light-mode") : $t("settings.theme.dark-mode") }}
</v-list-item-title>
</v-list-item>
</template>
</AppSidebar>
@ -89,7 +91,7 @@ export default defineComponent({
middleware: "auth",
setup() {
const { cookbooks } = useCookbooks();
const { $globals, $auth, $vuetify } = useContext();
const { $globals, $auth, $vuetify, i18n } = useContext();
const isAdmin = computed(() => $auth.user?.admin);
@ -113,83 +115,83 @@ export default defineComponent({
};
});
});
return { cookbookLinks, isAdmin, languageDialog, toggleDark, sidebar };
},
data() {
return {
createLinks: [
{
icon: this.$globals.icons.link,
title: "Import",
subtitle: "Import a recipe by URL",
to: "/recipe/create/url",
restricted: true,
},
{ divider: true },
{
icon: this.$globals.icons.edit,
title: "Create",
subtitle: "Create a recipe manually",
to: "/recipe/create/new",
restricted: true,
},
{ divider: true },
{
icon: this.$globals.icons.pages,
title: "Cookbook",
subtitle: "Create a new cookbook",
to: "/group/cookbooks",
restricted: true,
},
],
bottomLink: [
{
icon: this.$globals.icons.cog,
title: this.$t("general.settings"),
to: "/admin/site-settings",
restricted: true,
},
],
topLinks: [
{
icon: this.$globals.icons.calendarMultiselect,
title: this.$t("meal-plan.meal-planner"),
to: "/group/mealplan/planner",
restricted: true,
},
{
icon: this.$globals.icons.formatListCheck,
title: this.$t("shopping-list.shopping-lists"),
to: "/shopping-lists",
restricted: true,
},
{
icon: this.$globals.icons.viewModule,
to: "/recipes/all",
title: this.$t("sidebar.all-recipes"),
},
{
icon: this.$globals.icons.search,
to: "/search",
title: this.$t("sidebar.search"),
},
{
icon: this.$globals.icons.tags,
to: "/recipes/categories",
title: this.$t("sidebar.categories"),
},
{
icon: this.$globals.icons.tags,
to: "/recipes/tags",
title: this.$t("sidebar.tags"),
},
{
icon: this.$globals.icons.potSteam,
to: "/recipes/tools",
title: "Tools",
},
],
};
const createLinks = [
{
icon: $globals.icons.link,
title: i18n.t("general.import"),
subtitle: i18n.t("new-recipe.import-by-url"),
to: "/recipe/create/url",
restricted: true,
},
{ divider: true },
{
icon: $globals.icons.edit,
title: i18n.t("general.create"),
subtitle: i18n.t("new-recipe.create-manually"),
to: "/recipe/create/new",
restricted: true,
},
{ divider: true },
{
icon: $globals.icons.pages,
title: i18n.t("sidebar.cookbook"),
subtitle: i18n.t("sidebar.create-cookbook"),
to: "/group/cookbooks",
restricted: true,
},
];
const bottomLink = [
{
icon: $globals.icons.cog,
title: i18n.t("general.settings"),
to: "/admin/site-settings",
restricted: true,
},
];
const topLinks = [
{
icon: $globals.icons.calendarMultiselect,
title: i18n.t("meal-plan.meal-planner"),
to: "/group/mealplan/planner",
restricted: true,
},
{
icon: $globals.icons.formatListCheck,
title: i18n.t("shopping-list.shopping-lists"),
to: "/shopping-lists",
restricted: true,
},
{
icon: $globals.icons.viewModule,
to: "/recipes/all",
title: i18n.t("sidebar.all-recipes"),
},
{
icon: $globals.icons.search,
to: "/search",
title: i18n.t("sidebar.search"),
},
{
icon: $globals.icons.tags,
to: "/recipes/categories",
title: i18n.t("sidebar.categories"),
},
{
icon: $globals.icons.tags,
to: "/recipes/tags",
title: i18n.t("sidebar.tags"),
},
{
icon: $globals.icons.potSteam,
to: "/recipes/tools",
title: i18n.t("tool.tools"),
},
];
return { cookbookLinks, createLinks, bottomLink, topLinks, isAdmin, languageDialog, toggleDark, sidebar };
},
});
</script>

@ -39,9 +39,15 @@ export default defineComponent({
},
},
setup(props) {
useMeta({ title: props.error.statusCode === 404 ? "404 Not Found" : "An error occurred" });
const { $globals, i18n } = useContext();
useMeta({
title:
props.error.statusCode === 404
? (i18n.t("page.404-not-found") as string)
: (i18n.t("page.an-error-occurred") as string),
});
const buttons = [
{ icon: $globals.icons.home, to: "/", text: i18n.t("general.home") },
{ icon: $globals.icons.primary, to: "/recipes/all", text: i18n.t("page.all-recipes") },
@ -50,7 +56,7 @@ export default defineComponent({
return {
buttons,
}
};
},
// Needed for useMeta
head: {},
@ -67,4 +73,3 @@ p {
font-size: 200px;
}
</style>