Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate mt field error to custom i18n #357

Merged
merged 8 commits into from
Nov 6, 2024
Merged
5 changes: 5 additions & 0 deletions .changeset/rude-shoes-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shopware-ag/meteor-component-library": patch
---

Improve accessibility of mt-field-error
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,6 @@ export const VisualTestError: MtProgressBarStory = {
detail: "Error while sending variants",
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

const errorMessage = canvas.getByLabelText("Error message");

expect(errorMessage).toBeDefined();
expect(errorMessage.innerText).toContain("Error while sending variants");
},
};

export const VisualTestLabel: MtProgressBarStory = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,106 +1,82 @@
<template>
<mt-text
v-if="!!error"
as="span"
size="2xs"
color="color-text-critical-default"
v-if="!!error"
class="mt-field__error"
aria-label="Error message"
>
<mt-icon name="solid-exclamation-circle" />
{{ errorMessage }}
<mt-icon name="solid-exclamation-circle" size="0.75rem" aria-hidden="true" />

<span>{{ errorMessage }}</span>
</mt-text>
</template>

<script lang="ts">
import { defineComponent } from "vue";
<script setup lang="ts">
import { computed } from "vue";
import MtIcon from "../../../icons-media/mt-icon/mt-icon.vue";
import MtText from "@/components/content/mt-text/mt-text.vue";
import { useI18n } from "@/composables/useI18n";

export default defineComponent({
name: "MtFieldError",
const props = defineProps<{
error?: Record<string, any> | null;
}>();

i18n: {
messages: {
en: {
"mt-field-error": {
FRAMEWORK__MISSING_PRIVILEGE_ERROR: "Missing permissions",
FRAMEWORK__DELETE_RESTRICTED: "Deletion failed",
INVALID_MEDIA_URL: "Please enter a valid URL to upload a file.",
CONTENT__MISSING_RULE_TYPE_EXCEPTION: "You must choose a type for this rule.",
CONTENT__INVALID_CATEGORY_TYPE_AS_ENTRY_POINT:
"The type can not be assigned while category is an entry point.",
SHOPWARE_INVALID_IP: "Please enter a valid IP address.",
INVALID_URL: "Please enter a valid url.",
INVALID_MAIL: "Please enter a valid email address.",
FRAMEWORK__RATE_LIMIT_EXCEEDED:
"Too many requests. Please wait {seconds} seconds before trying again.",
DUPLICATED_URL: "This URL is already in use. Please choose another URL.",
"c1051bb4-d103-4f74-8988-acbcafc7fdc3": "This field must not be empty.",
},
},
de: {
"mt-field-error": {
FRAMEWORK__MISSING_PRIVILEGE_ERROR: "Fehlende Berechtigungen",
FRAMEWORK__DELETE_RESTRICTED: "Löschen fehlgeschlagen",
INVALID_MEDIA_URL: "Bitte gib eine gültige URL ein, um eine Datei hochzuladen.",
CONTENT__MISSING_RULE_TYPE_EXCEPTION: "Du musst einen Typ für diese Regel auswählen.",
CONTENT__INVALID_CATEGORY_TYPE_AS_ENTRY_POINT:
"Dieser Typ kann nicht gewählt werden, während die Kategorie als Einstiegspunkt festgelegt ist.",
SHOPWARE_INVALID_IP: "Bitte gib eine gültige IP-Adresse ein.",
INVALID_URL: "Bitte gib eine gültige URL ein.",
INVALID_MAIL: "Bitte gib eine gültige E-Mail-Adresse ein.",
FRAMEWORK__RATE_LIMIT_EXCEEDED:
"Zu viele Anfragen. Bitte warten Sie {seconds} Sekunden, bevor Sie es erneut versuchen.",
DUPLICATED_URL: "Diese URL wird bereits genutzt. Bitte wähle eine andere Domain.",
"c1051bb4-d103-4f74-8988-acbcafc7fdc3": "Dieses Feld darf nicht leer sein",
},
},
},
},
const errorMessage = computed(() => {
if (!props.error) return "";

components: {
"mt-icon": MtIcon,
"mt-text": MtText,
},
const translation = t(props.error.code, props.error.parameters || {});
const noTranslationFound = translation === props.error.code;

props: {
error: {
type: Object,
required: false,
default: null,
},
},

computed: {
errorMessage(): string {
if (!this.error) {
return "";
}

const translationKey = `mt-field-error.${this.error.code}`;
const translation = this.$tc(translationKey, 1, this.error.parameters || {});
return noTranslationFound ? props.error.detail : translation;
});

if (translation === translationKey) {
return this.error.detail;
}
return translation;
const { t } = useI18n({
messages: {
en: {
"mt-field-error": {
FRAMEWORK__MISSING_PRIVILEGE_ERROR: "Missing permissions",
FRAMEWORK__DELETE_RESTRICTED: "Deletion failed",
INVALID_MEDIA_URL: "Please enter a valid URL to upload a file.",
CONTENT__MISSING_RULE_TYPE_EXCEPTION: "You must choose a type for this rule.",
CONTENT__INVALID_CATEGORY_TYPE_AS_ENTRY_POINT:
"The type can not be assigned while category is an entry point.",
SHOPWARE_INVALID_IP: "Please enter a valid IP address.",
INVALID_URL: "Please enter a valid url.",
INVALID_MAIL: "Please enter a valid email address.",
FRAMEWORK__RATE_LIMIT_EXCEEDED:
"Too many requests. Please wait {seconds} seconds before trying again.",
DUPLICATED_URL: "This URL is already in use. Please choose another URL.",
"c1051bb4-d103-4f74-8988-acbcafc7fdc3": "This field must not be empty.",
},
},
de: {
"mt-field-error": {
FRAMEWORK__MISSING_PRIVILEGE_ERROR: "Fehlende Berechtigungen",
FRAMEWORK__DELETE_RESTRICTED: "Löschen fehlgeschlagen",
INVALID_MEDIA_URL: "Bitte gib eine gültige URL ein, um eine Datei hochzuladen.",
CONTENT__MISSING_RULE_TYPE_EXCEPTION: "Du musst einen Typ für diese Regel auswählen.",
CONTENT__INVALID_CATEGORY_TYPE_AS_ENTRY_POINT:
"Dieser Typ kann nicht gewählt werden, während die Kategorie als Einstiegspunkt festgelegt ist.",
SHOPWARE_INVALID_IP: "Bitte gib eine gültige IP-Adresse ein.",
INVALID_URL: "Bitte gib eine gültige URL ein.",
INVALID_MAIL: "Bitte gib eine gültige E-Mail-Adresse ein.",
FRAMEWORK__RATE_LIMIT_EXCEEDED:
"Zu viele Anfragen. Bitte warten Sie {seconds} Sekunden, bevor Sie es erneut versuchen.",
DUPLICATED_URL: "Diese URL wird bereits genutzt. Bitte wähle eine andere Domain.",
"c1051bb4-d103-4f74-8988-acbcafc7fdc3": "Dieses Feld darf nicht leer sein",
},
},
},
});
</script>

<style lang="scss">
<style scoped>
.mt-field__error {
display: flex;
align-items: center;
gap: 4px;
margin-top: 4px;

#meteor-icon-kit__solid-exclamation-circle {
width: 12px;
height: 12px;
color: var(--color-icon-critical-default);
}
color: var(--color-icon-critical-default);
}
</style>
Loading