I'm starting a new website with Nuxt and I'm currently setting it to be multilingual (french and english)
I followed this tutorial to setup the translation and the language switcher, and got the following:
nuxt.config.js (relevant part)
['nuxt-i18n', {
detectBrowserLanguage: {
useCookie: true,
alwaysRedirect: true
},
strategy: 'prefix_except_default',
defaultLocale: 'fr',
parsePages: false,
seo: true,
pages: {
about: {
en: '/about-us',
fr: '/a-propos'
},
portfolio: {
en: '/projects',
fr: '/portfolio'
}
},
locales: [
{
code: 'en',
iso: 'en-US',
name: 'English',
file: 'en-US.js'
},
{
code: 'fr',
iso: 'fr-FR',
name: 'Français',
file: 'fr-FR.js'
}
],
lazy: true,
langDir: 'lang/'
}]
navbar.vue
<nav class="header">
<div class="logo">
<nuxt-link :to="localePath('index')">
<img src="https://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28">
</nuxt-link>
</div>
<div class="links">
<nuxt-link :to="localePath('about')">
{{ $t('navbar.about') }}
</nuxt-link>
<nuxt-link :to="localePath('blog')">
Blog
</nuxt-link>
<nuxt-link :to="localePath('portfolio')">
Portfolio
</nuxt-link>
<nuxt-link :to="localePath('contact')">
Contact
</nuxt-link>
<span>|</span>
<nuxt-link v-if="$i18n.locale === 'fr'" :to="switchLocalePath('en')">
English
</nuxt-link>
<nuxt-link v-else :to="switchLocalePath('fr')">
Français
</nuxt-link>
{{ $i18n.locale }}
</div>
</nav>
Here is my directory structure (if that can help)
layouts/
front.vue
navbar.vue
pages/
index.vue
about.vue
blog.vue
portfolio.vue
contact.vue
The navbar.vue file is called inside front.vue, which is my layout.
The problems are the following:
On any page, when I try to click the languageSwitcher link, I get redirected to its english version (ie: /a-propos becomes /en/about-us), however the other links will bring me back to the french version.
{{ $i18n.locale }} keeps displaying fr
I tried the following block of code:
<template>
...
<nuxt-link
v-for="locale in availableLocales"
key="locale.code"
:to="switchLocalePath(locale.code)"
>
{{ locale.name }}
</nuxt-link>
...
</template
<script>
export default {
computed: {
availableLocales () {
return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale)
}
}
}
</script>
And it only displays english, while it should display me both english and french.
What have I done wrong, or what am I missing?
This worked for me, using vue-select and availableLocales of Nuxt-$i18n, hope it helps:
<template>
<div>
<client-only>
<b-navbar>
<div class="container">
<b-navbar-brand
class="navbar-brand-custom mr-2"
:to="localePath('index')"
:title="title">
<div class="d-flex flex-row order-2 order-lg-3 ml-auto text-capitalize">
<b-navbar-nav class="d-flex flex-row">
<!-- Language menu -->
<v-select
v-model="selected"
v-for="(lang, index) in availableLocales"
:key="index"
:value="lang.code"
:searchable="false"
#input="onChange"
class="vue-select-custom"
></v-select>
<!-- Navbar menu -->
<b-nav-item-dropdown
id="menu-links"
right
no-caret
role="manu"
class="ml-0"
menu-class="animated fadeIn text-right menu-links rounded-0"
>
<span class="dropdown-menu-arrow"></span>
<template
v-slot:button-content
style="height:42px"
>
</b-nav-item-dropdown>
</b-navbar-nav>
</div>
</div>
</b-navbar>
</client-only>
<script>
export default {
data() {
return {
selected: this.$i18n.locale
}
},
computed: {
availableLocales() {
return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale);
},
},
.....
methods: {
onChange(locale) {
var language = locale.toLocaleLowerCase();
this.$i18n.setLocaleCookie(language)
this.$router.replace(this.switchLocalePath(language));
},
....
}
}
this is due to alwaysRedirect: true, set it to false
Related
I would like to translate the titles that are passed to my component via props. However I assume because my strings are being passed via props they are not being translated like the rest of my code. Below you will find my current 2 components that I am working with:
Parent Component:
`<setting-section
:title="$t('Random Text 1')"
:description="$t('Random Text 2')"
>`
In the Child:
`<template>
<div class="flex grid w-full">
<div class="divider mr-4 mt-5" />
<div class="header col-2">
<div class="title text-primary">{{ title }}</div>
<div class="description text-xs">{{ description }}</div>
</div>
<div class="flex col-10" v-if="!isLoading">
<slot />
</div>
<div class="flex col-10" v-else>
<Skeleton height="5rem" />
</div>
</div>
</template>
<script>
export default {
name: 'Menu',
props: {
title: {
type: String,
default: '',
},
description: {
type: String,
default: '',
},
},
};
</script>`
How ever if I do add the below variation it obviously wont work.
`<template>
<div class="flex grid w-full">
<div class="header col-2">
<div class="title text-primary">{{ $t('title')}} </div>
<div class="description text-xs">{{ description }}</div>
</div>
</div>
</template>`
Your both the solutions should work as we always configured VueI18n at global level. Hence, translation literals always accessible from any nested component.
Live Demo as per both the use cases :
Vue.component('child-one', {
props: ['childmsg'],
template: '<p>{{ childmsg }}</p>'
});
Vue.component('child-two', {
template: `<p>{{ $t('message') }}</p>`
});
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: 'ja',
fallbackLocale: 'en',
messages: {
"ja": {
"message": "こんにちは、世界"
},
"en": {
"message": "Hello World"
}
}
});
new Vue({
el: "#app",
i18n,
data() {
return {
locale: "ja"
}
},
watch: {
locale(newLocale) {
this.$i18n.locale = newLocale;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.8/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-i18n#8.8.2/dist/vue-i18n.min.js"></script>
<main id="app">
<div>
<label><input type="radio" value="ja" v-model="locale" />Japanese</label>
<label><input type="radio" value="en" v-model="locale" />English</label>
</div>
<h3>Passing translated string from parent</h3>
<child-one :childmsg="$t('message')"></child-one>
<h3>Transaltions happens in child component itself</h3>
<child-two></child-two>
</main>
I'm starting at Vue Js, my problem is that my b-button is not shown in my table and I don't understand why.
Here is my HTML code:
<div id="listlocales">
<div class="overflow-auto">
<b-button size ="sm" href="{% url 'newLocal'}" variant="outline-primary"> Nuevo Local</b-button>
<br></br>
<b-table
id="my-table"
striped responsive="sm"
:items="items"
:fields="fields"
:per-page="recordsPerPage"
:current-page="currentPage">
<template #cell(actions)='data'>
<b-button size="sm" variant="primary" #click="getLocales()"> Editar </b-button>
<b-button size="sm" variant="danger" href="{% url 'newLocal' %}"> Eliminar </b-button>
</template>
</b-table>
<b-pagination
v-model="currentPage"
:total-rows="totalPages"
:per-page="recordsPerPage"
aria-controls="my-table"
></b-pagination>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.21/dist/vue.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
And here is my script Vue code:
<script>
const listloc = new Vue({
el: '#listlocales',
data: {
items: [],
currentPage: 1,
totalPages: 0,
recordsPerPage: 10,
isLoading: false,
fields: [
{ key: 'id', label: 'ID' },
{ key: 'descripcion', label: 'Descripcion' },
{ key: 'clave', label: 'Clave' },
{ key: 'responsable', label: 'Responsable' },
{ key: 'actions', label: ''}
]
}, ...
});
</script>
</body>
</html>
I tried to use v-slot instead cell but isn't working anyway... Can someone help me for solving this issue.
The v-slot directive, that Boostrap is using, was introduced in Vue version 2.6.0. To fix your issue you have to upgrade your Vue version
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.0/dist/vue.js"></script>
I'm completely new to VueJS and am trying to create a project tile list with different data values per tile. I use Vue CLI. I created a component which is my template for one project tile.
component TheProjectTile.vue :
<template>
<router-link to="{{ project.url }}">
<div
class="row project-container"
style="background-color: {{ project.backgroundcolor }};"
v-scrollanimation
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img src="#/assets/img/{{ project.image }}" alt="{{ project.title }}" />
</div>
</div>
</router-link>
</template>
<script type="text/javascript">
export default {
props: { project: Object },
data() {
return {}
}
}
</script>
Then I have my View on my Vue CLI application where I want to render the project tiles and where I want to give the data to the tiles:
View where the projects should be shown
<template>
<div id="projekte">
<section class="container">
<div id="projects">
<projectlist v-for="project in projects" :project="project" />
</div>
</section>
</div>
</template>
<script>
import TheProjectTile from './components/TheProjectTile'
export default {
components: {
projectlist: TheProjectTile
},
data() {
return {
projects: [
{
url: '/projekte/client1',
backgroundcolor: '#005ca9',
title: 'Website client 1',
img: 'client1.png'
},
{
url: '/projekte/client2',
backgroundcolor: '#c10b25',
title: 'Website client 2',
img: 'client2.png'
}
]
}
}
}
</script>
What do I need to change that it works? :/
Please take a look at following snippet:
You need to bind data with v-bind or :,
in v-for loop you need key
Vue.component('projectList', {
template: `
<a :to="project.url">
<div
class="row project-container"
:style="{'background-color': project.backgroundcolor}"
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img :src="'#/assets/img/'+project.image" :alt="project.title" />
</div>
</div>
</a>
`,
props: { project: Object },
})
new Vue({
el: '#demo',
data() {
return {
projects: [{url: '/projekte/client1', backgroundcolor: '#005ca9', title: 'Website client 1', img: 'client1.png'}, {url: '/projekte/client2', backgroundcolor: '#c10b25', title: 'Website client 2', img: 'client2.png'}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div id="projekte">
<section class="container">
<div id="projects">
<!-- 👇 key -->
<project-list v-for="(project, index) in projects" :key="index" :project="project" />
</div>
</section>
</div>
</div>
I will create a menu with jump marks for accessibility that is only visible when the tab key on the keyboard is clicked.
How can I implement this in Vuetify? is there a way to use something like #click for this?
This is my html code for the menu:
<template>
<div class="m-block-tab-jump-sections" data-module="tab-jump-sections" v-on:click.tab="onClick">
<div class="jump-sections js-sections h-break-in">
<a href="#tab-jump-section--metamenu" class="jump-link" title="" target="" tabindex="50">
zur Top-Navigation
</a>
</div>
</div>
</template>
In order to capture the tab on the entire page, you may need to look at putting the following on the app element:
v-on:keydown.tab='handleTab'
Now you can open a menu or do other actions in the handler.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
showMenu: false,
clickcount: 0,
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' },
],
}),
methods: {
handleTab(event) {
this.showMenu = true;
}
}
})
<div id="app" v-on:keydown.tab='handleTab'>
<v-app id="inspire">
<div class="text-center">
<v-menu offset-y v-model='showMenu'>
<template v-slot:activator="{ on }">
<v-btn
color="primary"
dark
v-on:focus='handleTab'
>
Dropdown
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in items"
:key="index"
#click=""
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
<v-text-field></v-text-field>
<v-text-field></v-text-field>
<v-text-field></v-text-field>
<v-text-field></v-text-field>
</v-app>
</div>
Here is a sample:
I'm creating a basic MTG Deckbuilder using Vue.Js. I'm trying to have the user type the card name into an input box then when the button is clicked, the deck list is update with the card name. Currently,the list add's a blank element for the card instead of the card name. Any ideas?
app.Vue:
<template>
<div id="app">
<deckBuilder #addCard="addCard" :title="title" :card="card" :deck="deck" />
</div>
</template>
<script>
import deckBuilder from './components/deckBuilder'
export default {
name: 'app',
components: {
deckBuilder,
},
data: () => ({
title: 'MTG Deck Builder',
card: {
name: '',
},
deck:[],
}),
methods: {
addCard: function(event,) {
this.deck.push(this.card.name);
},
},
}
</script>
deckBuilder.Vue:
<template>
<div>
<h1>{{ title }}</h1>
<input v-model="card.name" placeholder="Type a Card Name" />
<p> the card is: {{ card.name }}
<button #click="addCard">Add!</button>
<h2>Deck</h2>
<ul>
<li v-for="item in deck">{{ item.card }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'deckBuilder',
props: ['title', 'card', 'deck'],
methods: {
addCard() {
this.$emit('addCard')
}
},
}
</script>
Because you push string item instead of object
this.deck.push(this.card.name);
Correct template will be {{ item }}, not {{ item.card }}
This is because you are not emitting any data in your $emit
Try this,
In deckbuilder.vue
addCard() {
this.$emit('addCard',this.card.name);
}
In app.vue
addCard: function(cardName){
this.deck.push(cardName);
}
In html, v-for should be this way
<li v-for="item in deck">{{ item }}</li>
Try This
<!-- Menu Content -->
<ul class="nav-list" style="overflow: visible;">
<!-- Items -->
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<nuxt-link :to="menuItem.link" :class="menuItem.class">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<!-- Link Name -->
<span class="links_name">{{ menuItem.name }}</span>
</nuxt-link>
</li>
</span>
</ul>
<script>
export default {
name: 'SidebarMenu',
menuItems: {
type: Array,
default: () => [
{
link: '/',
name: '_home',
icon: 'bx-home',
class: '',
},
{
link: '/blog',
name: '_blog',
icon: 'bx-edit',
class: '',
},
{
link: '/projects',
name: '_projects',
icon: 'bx-code',
class: ''
},
{
link: '/about',
name: '_about',
icon: 'bx-user',
class: ''
},
],
},
}
</script>