None of the "common" solutions to the problem work well for me:
- The css-based solution (white-space: pre-line) requires adding the style to each translated element where a line break is needed. It clutters up the code and personally I'd like to have a clear separation between the text and the styles.
- As mentioned above, the v-html-based solution might be dangerous, especially if you have multiple people working on the locale messages.
- I use global .json files for storing the locale messages and .yaml format is not an option for me.
That being said, I don't think there is a perfect solution to the problem and maybe this is where the vue-i18n can be improved.
But for my use case I found a pretty good solution: I created a custom wrapper around component, that allows me to:
- move the text into the new line by adding a {br} placeholder (inspired by @GeekyMonkey)
- create styled paragraphs from the list of locale messages by passing the 'paragraph-class' prop to the custom wrapper. It's important for me since I don't just want to move the text to the new line, sometimes I want the paragraphs to have the same customizable distance between them
I18nCustom.vue:
<template>
<div>
<i18n
v-bind="$attrs"
v-on="$listeners"
:class="paragraphClass"
v-for="idx in (Array.isArray(paragraphs) ? paragraphs : [paragraphs]).length"
:key="`${path}.${idx - 1}`"
:path="Array.isArray(paragraphs) ? `${path}.${idx - 1}` : path"
>
<template v-for="(_, name) in $slots" v-slot:[name]>
<slot :name="name"/>
</template>
<template #br>
<br>
</template>
</i18n>
</div>
</template>
<script>
export default {
data: () => ({
paragraphs: null
}),
props: {
path: {
type: String,
required: true
},
paragraphClass: {
type: String,
default: ''
},
},
mounted() {
this.paragraphs = this.$t(this.path)
}
};
</script>
How to use it:
You can use the wrapper in the same way you would you the element: all the props and slots are supported
en.json
{
"paragraphsNewLine": "line1{br}line2{br}line3{slot-example}{br}",
"slotExample": "slot",
"styledParagraphs": [
"paragraph1",
"paragraph2",
"paragraph3"
],
}
In the components:
<!-- new line example -->
new line example:
<i18n-custom
tag="p"
path="paragraphsNewLine"
>
<template #slot-example>
<b>
{{ $t('slotExample') }}
</b>
</template>
</i18n-custom>
<!-- styled paragraphs example -->
styled paragraphs example:
<i18n-custom
tag="p"
path="styledParagraphs"
paragraph-class="mb-3"
/>
The results:
the results
v-html
orv-text
for this purpose – Gentes