4

I need to set up global head in Nuxt for my app, which some subpages will overwrite. Those global head needs to contain translated data.

I created seoHead.js file with code:

import Vue from "vue";

export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign);

export default {
  title: $t("seoGlobal.title"),
  meta: [
    { charset: "utf-8" },
    { name: "viewport", content: "width=device-width, initial-scale=1" },
    {
      hid: "description",
      name: "description",
      content: $t("seoGlobal.description"),
    },
    {
      hid: "ogSiteName",
      name: "og:site_name",
      content: "Test Page",
    },
    {
      hid: "ogTitle",
      name: "og:title",
      content: $t("seoGlobal.ogTitle"),
    },
    (...)
  ],
};

I import and use this data in my index.vue and other pages like this:

import seoHead from "~/constants/seoHead";

export default {
  head() {
    const metaI18n = this.$nuxtI18nSeo();
    const currentPath = process.env.LP_URL + this.$router.currentRoute.fullPath;
    return {
      ...seoHead,
      meta: [
        {
          hid: "ogLocale",
          name: "og:locale",
          content: metaI18n.meta[0].content,
        },
        {
          hid: "ogLocaleAlternate",
          name: "og:locale:alternate",
          content: metaI18n.meta[1].content,
        },
        {
          hid: "ogUrl",
          name: "og:url",
          content: currentPath,
        },
      ],
    };
  },
(...)

Unfortunately, I am facing Cannot read property '$options' of undefined error. It's strange for me, because I already used export const $t = (sign) => Vue.prototype.$nuxt.$options.i18n.t(sign); code in another js file. Anyone know why this error appears? You know the best way to translate global head options?

BobiDaHombre
  • 193
  • 1
  • 4
  • 19
  • I'm not too acquainted with Nuxt, but your error messages seems to indicate a race condition: `seoHead` is used before Nuxt's setup is complete, so `$nuxt` has not been defined (injected) yet when it is accessed in `$t`. Can you rule out that this is the case here? – dr_barto Feb 20 '21 at 15:33
  • @dr_barto It could be. I'm not so experienced in Nuxt lifecycle :/ – BobiDaHombre Feb 22 '21 at 21:47
  • Please check if you import `seoHead.js` somewhere else, and try to remove that import if you find any. It's unlikely, but .. well :) – dr_barto Feb 23 '21 at 10:45
  • Only in described file I imported `seoHead.js` – BobiDaHombre Feb 23 '21 at 13:36
  • Maybe this workaround works for you: delay the execution of `$t` by changing `seoHead.js` to export a function which simply returns the object you are currently exporting. Then, in `index.vue`, just change the line `...seoHead` to `...seoHead()`. – dr_barto Feb 23 '21 at 14:07
  • @dr_barto It works – BobiDaHombre Feb 23 '21 at 22:10
  • @dr_barto Can You give your response as answer, not comment? So I will sign It as problem resolver and You will get bouty :) – BobiDaHombre Feb 28 '21 at 10:48

2 Answers2

4

As discussed in the comments, there seems to be a timing issue with the Nuxt lifecycle and your component: at the time your component seoHead.js is imported, Nuxt has not yet injected its $nuxt object into Vue. So an easy workaround would be to delay the execution of your $t function (which accesses $nuxt):

  1. Change your component to export a function which returns the object, instead of directly exporting the object:
export default function() {
  return {
    title: $t("seoGlobal.title"),
    // ...
  }
}
  1. In index.vue, change your head function to call seoHead when spreading it:
return {
  ...seoHead(),
  // ...

This way, the code which accesses $nuxt will be executed later -- not when seoHead is imported, but only when the head function is executed. At this time, the Nuxt lifecycle hopefully has finished its startup work and the required object is in place.


As I said, this is merely a workaround; if you would be calling head immediately in index.vue, the same error would appear. So unless you find out a proper way to integrate into the Nuxt lifecycle, I suggest to also put a safeguard into your translation function:

const $t = (sign) => Vue.prototype.$nuxt 
  ? Vue.prototype.$nuxt.$options.i18n.t(sign)
  : sign

This will return the i18n key if the required infrastructure is not yet in place. Not great, but better than an exception ;)

Alternatively you might be able to directly import your i18n functionality, without going through Nuxt at all; this way you wouldn't have any dependency on the infrastructure at all -- much better.

dr_barto
  • 5,723
  • 3
  • 26
  • 47
0

I think what you basically need here is a mixin.

export default {
  title: $t("seoGlobal.title"),
  meta: this.computedMeta,
  computed:{
    computedMeta(){
      return [....] // this contains the array of objects in meta
   }
  }
  methods:{
   yourMethod(sign){
     return this.$nuxt.$options.i18n.t(sign);
   }
  }
};

then just import it as a mixin in whatever file you need.

tony19
  • 125,647
  • 18
  • 229
  • 307
Bhaskar
  • 1,838
  • 1
  • 16
  • 29