The Complete Guide to Build a Full Blown Multilanguage Website with Nuxt.js
This guide is for beginners and professionals who want to build a full-blown multilanguage website using Nuxt.js. With this step by step guide, you will get a dynamic Nuxt.js website running on a Vercel (previously ZEIT now) server, using an API for the multilanguage content.
If you are in a hurry you can download the whole project (nuxtblok.now.sh) at Github https://github.com/storyblok/nuxtjs-multilanguage-website
Basic understanding of Nuxt.js
The CLI of now.sh for hosting
An account on Storyblok.com to manage content
If not done yet install NodeJS, NPM, and NPX.
We will start by initializing the project with the Nuxt.js create app template. Navigate through the guide and choose the following options:
package manager of your choice
no UI Framework
no custom server framework
no modules needed
choose Universal rendering mode (SSR)
npx create-nuxt-app mywebsite // yarn create nuxt-app mywebsite cd mywebsite npm run dev // yarn dev
Nuxt.js starts its server on port 3000 by default so after running npm run dev (yarn dev) open your browser at http://localhost:3000.
As we will use SCSS to organize our CSS we also need to install the sass-loader.
npm install --save-dev sass-loader node-sass css-loader // yarn add -D sass-loader node-sass css-loader
To track the changes we make over the time we will also initialize the git repository.
// Initialize git git init && git add . && git commit -m 'init'
Build a skeleton
We will start to build the skeleton for your website. In the end, you will have a header, a main and a footer section and some useful global utility CSS classes.
Global SCSS in Nuxt.js
In the first step we installed the SCSS loader so let's create some global stylings and define SCSS variables. We will create a folder for styling general HTML tags
assets/scss/elements/ and one for our utility component
assets/ --| scss/ -----| elements/ --------| body.scss --------| ... -----| components/ --------| util.scss --------| ... --| styles.scss
Create the file
assets/scss/styles.scss and add the following content.
Instead of putting the stylings of all HTML elements in one file I prefer to make separate files to keep the project structured and scalable. Create the file
assets/scss/elements/body.scss to define the base font stylings.
In the components folder, we manage the global SCSS components and helper classes. Create the file
assets/scss/components/util.scss to define the global utility classes.
Add a google font to Nuxt.js
In the file
body.scss, we defined the font as Zilla Slab. As this is not a system font we need to add it to the head section of our document. Open the Nuxt.js configuration file (
nuxt.config.js ) and add the font stylesheet to the head section.
Define the default layout
Now that we have our SCSS in place we need to add it to the project. Make sure you have installed the sass loader in step one and replace the code of file
layouts/default.vue with the following code.
You will see an error that the components
BottomFooter.vue don't exist. So let's create them.
Create the header component
Create a file
./components/TopHeader.vue with the following code. Notice the attribute
lang="scss" in the style tag, which allows you to use SCSS code in the style section of the Vue.js single file component.
Create the footer component
BottomFooter.vue to your
At this moment, the website should look similar to the following screenshot. In the next step, I'll show you how to create the homepage with a teaser and a feature section.
Now let's commit that to git. See my GitHub commit for reference.
$ git add . && git commit -m 'creates the skeleton'
Build a homepage
Install the Storyblok Nuxt.js module
The Storyblok module will install
$storyblok on the Vue instance.
$ npm install storyblok-nuxt --save // yarn add -D storyblok-nuxt
After installing the module you need to initialize it with the preview token of your Storyblok space. Signup or Login at app.storyblok.com and create a new space.
Add the following to your
nuxt.config.js file and replace
PREVIEW_TOKEN with your preview token.
Update the homepage component
Now replace the default content of
pages/index.vue with following:
The asyncData method will load a JSON that defines which components we will render on the homepage. After this update, your website should look similar to the following screenshot.
Creating the homepage components
To render the full homepage we will need to create some components. Add the file
components.js with following content into the
Nuxt.js doesn't pick up the files in plugins folder automatically so we need to add the
components.js to the
Then create the Vue components inside the
After the reload of http://localhost:3000/ you should see the following design.
You can see created components in the source code using the Vue.js devtools.
Create your first block in Storyblok
We just loaded the demo content of Storyblok (added by default at the creation of the new space) and now we will extend the teaser component with interactive slides.
Setup of the Nuxt.js environment preview
At first, we need to connect your Nuxt.js environment to the Storyblok visual composer by inserting your development host
http://localhost:3000/ in the default environment location. To do so, open Settings and insert
http://localhost:3000/ in the default environment location. Don't forget to save the changes.
You can also define multiple preview links for the Storyblok visual composer. We will cover this topic later by the deployment of the website.
Now you can go to the Content section of Storyblok and open the Home page of our website. At first, you will see an error. This is caused by resolving the URL path, as the website we opened is called
/home, Nuxt.js doesn't know that this is homepage (index.html).
IMPORTANT: You have to change the real path field to
/ (see screenshot) otherwise, you will get a error
This page could not be found from Nuxt.js.
Don't forget to save your changes in the top right corner. After this change, you should see the preview of your page in the left part of the application.
Let's define the schema of a new slide block/component
Follow this video which explains how to create a new block.
After updating the schema and adding the content to Storyblok we will need to add the Vue.js component for the slide into the Nuxt.js project. Create
components/Slide.vue with the following content.
Don't forget to add the new component to your
component.js file, otherwise the component will not be registered in Vue.
Of course, we don't want to show all the slides at once. So let's extend the
Teaser.vue with some logic to show the dot navigation. You can use any Vue.js slider plugin for a more advanced slider but let's keep it simple here.
After updating all the mentioned files you should see the following result.
Extending the feature component
Every feature component currently only has a title. Let's extend the feature component/block with a description text and icon.
Now you can use the visual composer and click directly on the
Feature 1. As you hover with your mouse above the visual composer, you should see a dashed border around the clickable components/blocks. If you click/select on one of the components you should see a green highlight around that component. The right panel should show the content of the selected component.
Now we need to define two new fields in the Feature component. Click on the
Define schema button in the top right corner of the right panel and add a field named
description of the type textarea, and a field named
icon of the type image.
Open the feature component (
components/Feature.vue) and extend it with the new fields as well as some basic SCSS style.
You should have a fully editable homepage at this moment. Feel free to experiment with the content and see how the live visual editor behaves.
Build a navigation menu
To build a dynamic navigation menu you have several possibilities. One is to create a global content item that contains the global configurations. Another method is to use the Links API to generate the navigation automatically from your content tree. We will implement the first method in this tutorial.
We are creating a multilanguage website, so we create a global configuration for each language. Let's start with creating a folder for the English language named
Navigate back to the content section of your space and create a new folder by clicking the button in the top right corner. Name the folder
en and don't change the slug of the folder.
Create global settings
Inside the folder
en we create a new content entry/item called
Settings with the new content type
settings. Click on
+ Entry in the top right corner. Fill the inputs according to the following screen and create
settings component. This settings item will contain all the navigation items and other global configurations of our website.
Change the real path in the config of Settings to
/ and create the schema for the main navigation defining the field
main_navi with the type
Blocks. After changing the real path don't forget to reload the website to update the preview section of the application.
Add a block for the nav item name
nav_item with the schema containing a filed
name of the type
Text and a filed
link of the type
Link. At the end your
Settings content item should look like this on the following screenshot:
Getting global settings with the Vuex store
Nuxt.js comes with built-in support for Vuex and we will use it to retrieve and store the configuration of the navigation as well as the current language. To initialize Vuex in Nuxt.js you have to only create a
index.js file in your
store folder. Copy & paste the following code into the
store/index.js and save the file.
After dispatching the action
loadSettings in the middleware of the Nuxt.js, we will have the navigation items available at
Add a middleware
middleware in Nuxt.js allows you to define a function that runs before rendering the page. The function can be asynchronous and return a Promise so it is ideal for loading our settings from the API. Create it by adding the following code into the
Additionally, the middleware needs to be registered in the
Access the data in the TopHeader component
$store.state.settings.main_navi we can now easily access the navigation items and loop over them to render the navigation in
components/TopHeader.vue. Replace the template part of the
TopHeader.vue with the following code.
At this moment you should be able to edit the navigation using the Settings in Storyblok. You can add new navigation items or edit current ones. After saving, the preview should be reloaded and the changes should be visible on your screen similar to the following screenshot.
Build a blog section
A common task when creating a website is to develop an overview page of collections like news, blog posts or products. In our example, we will create a simple blog post. In Nuxt.js you can define dynamic routes creating folders with the underscore prepended
_ and Nuxt will automatically resolve them to Vue.js routes.
Our final URL should look like
/:language/blog/:slug so we will need to create the following folder structure in our Nuxt.js project.
pages/ --| _language/ -----| blog/ --------| _slug.vue --------| index.vue --| index.vue
Add a blog detail page
We start with the blog detail page at
pages/_language/blog/_slug.vue which will fetch the content from the Storyblok API and then render the blog post with markdown using
marked as a parser.
So first we will need to install the markdown parser.
$ npm install marked --save // yarn add -D marked
Then we will create the file
pages/_language/blog/_slug.vue for the dynamic route of the blog posts.
Create the overview page
To list the blog posts we will create a route on
/:language/blog simply by saving the file
index.vue into the blog folder.
Storyblok API can list all content items of a specific folder with the parameter
starts_with. The number of content items you get back is by default 25, but you can change that with the
per_page parameter and jump to the other pages with the
Create the blog content in Storyblok
After creating the Vue.js components for showing the blog we need to create a new folder in Storyblok to create the blog pages.
Create the folder
en/blog and choose
blog as default content type of this folder.
Create the blog article
Go inside the blog folder and create a new content item/entry and it will now automatically choose blog as a content type.
Add the schema fields
name (Text) and
body (Markdown) to the blog component and create any demo content like on this screenshot. You should be able to see a live preview during the editing of your content.
If you navigate to http://localhost:3000/en/blog you should also see a listing of your blog posts similar to the following screenshot.
Build a sitemap
To generate a sitemap or navigation tree with Nuxt.js of all your pages we will call Storyblok´s links API. The API includes the parent-child relationships through the
parent_id and therefore we just need to generate a tree using a computed property. Create
pages/_language/sitemap.vue file with the following code.
components/SitemapItem.vue component for the sitemap nodes, which will be used to generate the children of the sitemap tree.
Don't add to register the new SitemapItem component to your
At the end, we should have the following page.
Adding another language
With Storyblok you have two options to make multi-language projects - a field-level translation and multi-tree translation. Field level translation is a good decision if you have most of your content translated. Consider using the multi-tree translation if the content tree is different in every language. If you are not sure what to choose read our guide about i18n.
Publish the content
Don't forget to publish your content because we are going to deploy with published content. You can do it on each content item in the top right corner or globally in the content tree,
Deployment to Vercel
You have multiple options for the deployment of your website/application to live or preview environment. One of the easiest ways is to use Vercel (previously Now.sh) and deploy using the command line.
We will use Vercel which was previously known as ZEIT now. First, create an account on Vercel and install their desktop application. Then, create a now.json file with the following content and change
ACCOUNT_NAME to your account name.
Don't forget to also define
You can now test your Now.sh setup by writing
now whoami into the command line, which should return your account name. If it all works correctly you can run the deployment by simple running
now command in your terminal.
You will get a unique URL which you can then link via
now alias to your custom domain.
IMPORTANT: For the deployment of the Nuxt.js application on the Now.sh v2 you need to use
@nuxtjs/now-builder provided by Nuxt.js core team.
It's incredibly easy to build a full-blown website with Nuxt.js and it comes with a great ecosystem. I really like the way Nuxt.js abstracts common tasks you normally do in the Webpack configuration. It feels a little bit like Ruby on Rails where conventions go over configuration. For big projects, these conventions make it easy to onboard new team members and make the projects a lot more maintainable.