adbrosaci / vue-lang-router

Vue language routing with (optional) localized URLs.
MIT License
66 stars 8 forks source link

Link text which is dynamically added isn't translated #2

Closed deRaaf closed 4 years ago

deRaaf commented 4 years ago

Hello! Great plugin. I seem to have one problem with it though.

I have nav where I dynamically add the nav items to, like so:

<localized-link :to="item.link">
  <v-list-item-icon>
    <v-icon>{{ item.icon }}</v-icon>
  </v-list-item-icon>

  <v-list-item-content>
    <v-list-item-title>
       {{ item.title }}
     </v-list-item-title>
  </v-list-item-content>
</localized-link>

When using a localized-link component the URLs are translated, but the link text isn't. I setup the plugin exactly like the documentation.

radek-altof commented 4 years ago

Hey @deRaaf, perhaps you just forgot to use the VueI18n translate function? Instead of {{ item.title }} you would use {{ $t(item.title) }}.

https://github.com/adbrosaci/vue-lang-router#how-to-use http://kazupon.github.io/vue-i18n/started.html

Let me know how it goes.

deRaaf commented 4 years ago

Hi @radek-altof I tried that, sorry I should've mentioned this. If I do this I get the same result and i18n throws a warning. Value of key 'Dashboard' is not a string! and Cannot translate the value of keypath 'Dashboard'. Use the value of keypath as default.

radek-altof commented 4 years ago

@deRaaf That's the warning that i18n throws when you're missing a translation for the given key. Either you don't have "Dashboard" defined in your translations, or you're passing the translations wrong somehow.

{
  "Dashboard": "This is dashboard",
}

I'm afraid I can't help you further unless you provide a more complete example.

deRaaf commented 4 years ago

@radek-altof Yes, the thing is I have defined it, as you can see below.

This is what I have: (For context, I'm using Vuetify nav drawer)

The nav

<template>
    <v-navigation-drawer
      app
      floating
      color="#F5F7F8"
      :mini-variant.sync="this.toggleMini"
      width="240"
      v-model="this.mobileToggle"
      :permanent="$vuetify.breakpoint.mdOnly"
      :temporary="$vuetify.breakpoint.mdAndDown"
      v-show="user"
      >

      <v-list
        nav
      >
        <v-list-group
          v-for="item in items"
          :key="item.title"
          link
        >
          <template v-slot:activator>
            <localized-link :to="item.link">
              <v-list-item-icon>
                <v-icon>{{ item.icon }}</v-icon>
              </v-list-item-icon>

              <v-list-item-content>
                <v-list-item-title>
                  {{ item.title }}
                </v-list-item-title>
              </v-list-item-content>
            </localized-link>
          </template>

          <v-list-item
            v-for="sublink in item.sublinks"
            :key="sublink.title"
            link
          >
            <v-list-item-title>{{ sublink.title }}</v-list-item-title>
          </v-list-item>
        </v-list-group>
        <v-list-item
          link
          :class="{'hide': $vuetify.breakpoint.mdAndUp, 'bottom-nav': $vuetify.breakpoint.smAndDown}">
          <localized-link :to="'profiel'">
            <v-list-item-icon>
              <v-icon>person</v-icon>
            </v-list-item-icon>

            <v-list-item-content>
              <v-list-item-title>
                Naam
              </v-list-item-title>
              <v-list-item-subtitle>
                {{ $t('global.manage_profile') }}
              </v-list-item-subtitle>
            </v-list-item-content>
            </localized-link>
          </v-list-item>
        <v-list-item
          link
          :class="{'hide': $vuetify.breakpoint.mdAndUp, 'bottom-nav': $vuetify.breakpoint.smAndDown}">
          <localized-link :to="'uitloggen'">
            <v-list-item-icon>
              <v-icon>exit_to_app</v-icon>
            </v-list-item-icon>

            <v-list-item-content>
              <v-list-item-title>
                {{ $t('global.logout') }}
              </v-list-item-title>
            </v-list-item-content>
            </localized-link>
          </v-list-item>
      </v-list>
    </v-navigation-drawer>
</template>

<script>
export default {
  data() {
    return {
      user: null,
      // translations go in lang/localized-urls
      items: [
        { title: 'Dashboard', icon: 'dashboard', link: '/' },
        {
          title: 'Personen',
          icon: 'people',
          link: 'personen',
          sublinks: [
            {
              title: 'subitem 1',
              link: 'subitem1',
            },
            {
              title: 'subitem 2',
              link: 'subitem2',
            },
          ],
        },
        { title: 'Organisatie', icon: 'business_center', link: 'organisatie' },
        { title: 'Toegang', icon: 'https', link: 'toegang' },
        { title: 'Bezoekers', icon: 'perm_contact_calendar', link: 'bezoekers' },
        {
          title: 'Meldingen',
          icon: 'announcement',
          link: 'meldingen',
          sublinks: [
            {
              title: 'subitem 1',
              link: 'subitem1',
            },
            {
              title: 'subitem 2',
              link: 'subitem2',
            },
          ],
        },
        { title: 'Reserveringen', icon: 'event', link: 'reserveringen' },
        { title: 'Monitors', icon: 'multiline_chart', link: 'monitors' },
        { title: 'Rapportages', icon: 'bar_chart', link: 'rapportages' },
        { title: 'Systeeminstellingen', icon: 'settings', link: 'systeeminstellingen' },
      ],
    };
  },
};
</script>

The router

import Vue from 'vue';
import LangRouter from 'vue-lang-router'; // vue language router instead of vue router
import Dashboard from '../views/Dashboard.vue';

import translations from '../lang/translations/index';
import localizedURLs from '../lang/localized-urls';

Vue.use(LangRouter, {
  defaultLanguage: 'nl',
  translations,
  localizedURLs,
});

const routes = [
  {
    path: '/login',
    name: 'Login',
    component: () => import(/* webpackChunkName: "login" */ '../views/Login.vue'),
  },
  {
    path: '/',
    name: 'Dashboard',
    component: Dashboard,
  },
  {
    path: '/personen',
    name: 'People',
    meta: { breadCrumb: 'Personen' },
    // route level code-splitting
    // this generates a separate chunk (people.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "people" */ '../views/People.vue'),
  },
  {
    path: '/organisatie',
    name: 'Organisation',
    meta: { breadCrumb: 'Organisatie' },
    component: () => import(/* webpackChunkName: "organisations" */ '../views/Organisation.vue'),
  },
  {
    path: '/toegang',
    name: 'Access',
    meta: { breadCrumb: 'Toegang' },
    component: () => import(/* webpackChunkName: "access" */ '../views/Access.vue'),
  },
  {
    path: '/bezoekers',
    name: 'Visitors',
    meta: { breadCrumb: 'Bezoekers' },
    component: () => import(/* webpackChunkName: "visitors" */ '../views/Visitors.vue'),
  },
  {
    path: '/meldingen',
    name: 'incidents',
    meta: { breadCrumb: 'Meldingen' },
    component: () => import(/* webpackChunkName: "alerts" */ '../views/Incidents.vue'),
  },
  {
    path: '/reserveringen',
    name: 'Reservations',
    meta: { breadCrumb: 'Reservering' },
    component: () => import(/* webpackChunkName: "reservations" */ '../views/Reservations.vue'),
  },
  {
    path: '/monitors',
    name: 'Monitors',
    meta: { breadCrumb: 'Monitors' },
    component: () => import(/* webpackChunkName: "monitors" */ '../views/Monitors.vue'),
  },
  {
    path: '/rapportages',
    name: 'Reports',
    meta: { breadCrumb: 'Rapportages' },
    component: () => import(/* webpackChunkName: "reports" */ '../views/Reports.vue'),
  },
  {
    path: '/systeeminstellingen',
    name: 'Settings',
    meta: { breadCrumb: 'Systeemsinstellingen' },
    component: () => import(/* webpackChunkName: "settings" */ '../views/Settings.vue'),
  },
  {
    path: '/profiel',
    name: 'Profile',
    meta: { breadCrumb: 'Profiel' },
    component: () => import(/* webpackChunkName: "profile" */ '../views/Profile.vue'),
  },
  { path: '*', redirect: { path: '/' } },
];

const router = new LangRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});

export default router;

localized-urls/en.json

{
    "dashboard": "dashboard",
    "personen": "people",
    "organisatie": "organisation",
    "toegang": "access",
    "bezoekers": "visitors",
    "meldingen": "incidents",
    "reserveringen": "reservations",
    "monitors": "monitors",
    "rapportages": "reports",
    "systeeminstellingen": "system settings"
}

{{ $t('global.manage_profile') }} does work because I defined it in lang/translations/*.json

radek-altof commented 4 years ago

@deRaaf The question remains the same. Do you have "Dashboard" key (and "Personen", "Organisatie", etc.) defined in your translations? You will then use it the same way as {{ $t('global.manage_profile') }}, so {{ $t(item.title) }}.

You posted file with URL localization - but that only translates link URLs. Any text translation needs to go to the translations file in lang/translations/*.json.

deRaaf commented 4 years ago

My apologies, it seems I misunderstood the doc. I added the translations and the links are translated now, thank you.