Nuxt
Using the package in Nuxt raises one problem a plain Vue app doesn't have. The server renders the page before anything runs in the browser, and the server doesn't know which language the visitor chose. If the server renders "English" in the language switcher and the browser then reads the cookie and changes it to "Français", Vue reports a hydration mismatch and the switcher visibly flickers.
The Nuxt module solves that, and saves you the setup from Installation at the same time.
Adding the module
npm install @ken_de_nigerian/vue-google-translate-widget// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@ken_de_nigerian/vue-google-translate-widget/nuxt'],
googleTranslate: {
defaultLanguage: 'en',
includedLanguages: ['en', 'fr', 'yo', 'ig', 'ha', 'ar'],
},
})That's the whole setup. Use the components anywhere, without importing them:
<!-- app.vue -->
<template>
<header>
<span v-no-translate class="logo">Lagos Eats</span>
<GoogleTranslateButton />
</header>
<NuxtPage />
</template>What the module does
- Registers the components and composable for auto-import:
GoogleTranslateWidget,GoogleTranslateButton,useGoogleTranslateandvNoTranslate. - Adds the stylesheet to every page. Turn this off with
css: falseif you style the components yourself. - Applies your
googleTranslateoptions to every component and composable, exactly as the plugin does in a plain Vue app. - Renders the visitor's language on the server. A small plugin reads the
googtranscookie during the server render (and?lang=, if you enable shareable links) and passes it to the components, so the HTML the server sends already says "Français". The browser agrees when it hydrates, so there's no mismatch and no flicker. - Registers
v-no-translateglobally. Nuxt's auto-imports reach scripts, not template directives, so the module registers it for you. On the server it renders onlytranslate="no"; thenotranslateclass is added in the browser after hydration. Rendering the class on the server would make Vue report a class mismatch, because Vue compares the wholeclassattribute when it hydrates.
The translation itself still happens in the browser: the server always sends the page's original text. That's the nature of machine translation in the browser, and How Translation Works explains what it means for search engines.
How this is tested
Every change to the package builds a real Nuxt app (tests/fixtures/nuxt-app/) on Nuxt 3 and Nuxt 4, starts it, and checks the HTML its server sends: that the components are auto-imported, the stylesheet arrives, the cookie's language is rendered, ?lang= takes priority over the cookie, two visitors with different languages requesting pages at the same time each get their own language, and the directive renders translate="no" without a class.
Options
googleTranslate takes every configuration option whose value can be written in nuxt.config (strings, numbers, booleans, arrays), plus two of its own:
| Option | Default | |
|---|---|---|
css | true | Add the components' stylesheet to every page |
plugin | true | Register the plugin that applies your options and renders the visitor's language on the server |
Functions can't be written in nuxt.config, so provider, cache and onTranslate aren't available here. See below for how to set them.
Shareable links
A reader who shares a recipe in French probably wants the person they send it to see it in French too. Turn on the lang query parameter:
googleTranslate: {
queryParameter: 'lang',
}Now https://lagoseats.example/recipes/jollof?lang=fr opens in French, on the server and in the browser, even for someone who has never visited. As readers switch languages, the parameter is kept in sync with history.replaceState, so it doesn't add entries to the back button. ?lang= takes priority over the cookie.
Why there are no hreflang tags or /fr/ URLs
Both tell search engines "a French version of this page exists at this URL". With translation in the browser, it doesn't: the server sends English. Advertising translations the HTML doesn't contain can hurt how search engines treat your site, so the module deliberately doesn't generate them. For real multilingual SEO you need translations rendered on the server, which is a job for vue-i18n.
Providers, onTranslate and other functions
To translate with DeepL or another provider, or to send analytics events, you need to pass functions, which nuxt.config can't hold. Turn off the module's plugin and register your own. The module still handles auto-imports and the stylesheet:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@ken_de_nigerian/vue-google-translate-widget/nuxt'],
googleTranslate: { plugin: false },
})// plugins/translate.ts
import { createGoogleTranslate, endpointProvider, vNoTranslate } from '@ken_de_nigerian/vue-google-translate-widget'
export default defineNuxtPlugin(nuxtApp => {
// Render the visitor's language on the server, as the built-in plugin would.
const saved = useCookie('googtrans', { decode: (value: string) => value }).value
nuxtApp.vueApp.use(
createGoogleTranslate({
defaultLanguage: 'en',
includedLanguages: ['en', 'fr', 'yo', 'ig', 'ha', 'ar'],
provider: endpointProvider({ url: '/api/translate' }),
onTranslate: event => console.log('language changed', event),
initialLanguage: saved?.split('/')[2] || undefined,
}),
)
nuxtApp.vueApp.directive('no-translate', vNoTranslate)
})The /api/translate route that goes with this is in Server Handlers.
Troubleshooting
- Hydration warnings after a reload in another language. Make sure the plugin is registered (
plugin: true, the default), or that your own plugin passesinitialLanguageas above. v-no-translate"failed to resolve directive". You turned the module's plugin off and your own plugin doesn't register the directive. AddnuxtApp.vueApp.directive('no-translate', vNoTranslate).- No styles. Check
cssisn'tfalse, or import@ken_de_nigerian/vue-google-translate-widget/style.cssyourself.
More in Troubleshooting.