Implementing Multilingual Content using Directus and Nuxt
Directus comes with built-in support for creating multilingual content. In this post, you'll learn how to create multilingual content and access it using your Nuxt application.
Before You Start
You will need:
- A Directus project with admin access.
- Fundamental understanding of Nuxt concepts.
- Optional but recommended: Familiarity with data modeling in Directus.
Set Up Your Directus Project
Create a Collection
Create a new collection called posts with the following fields:
title
(Type: Input)content
(Type: Markdown)slug
(Type: Input)
Edit Public Policy
So that Nuxt can access the posts
collection without needing to authenticate navigate to Settings -> Access Policies -> Public
and under posts
set a public policy for read
.
Configure CORS
You may need set your content security policy to allow access to your Nuxt project. For example if you are self-hosting, or in development, and using Docker, then this is achieved by updating your docker-compose.yml
file as follows:
environment:
CONTENT_SECURITY_POLICY_DIRECTIVES__FRAME_SRC: your-website-url
Replace
your-website-url
with your Nuxt URL and the port. eg. If your Nuxt URL ishttp://localhost:3000
, replaceyour-website-url
withlocalhost:3000
.
Set Up Your Nuxt Project
Initialize Your Project
Create a new Nuxt project using Nuxi:
npx nuxi@latest init directus-multilingual
cd directus-multilingual
Inside your Nuxt project, install the Directus SDK package by running:
npm install @directus/sdk
Configuring Nuxt
With Nuxt installed with the Directus SDK you can now configure our project to connect to Directus.
Create a .env
file with the Directus URL:
API_URL="http://0.0.0.0:8055"
Add a type definition for your new environment variable by creating an env.d.ts
file with the following content:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly API_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Depending on your project configuration and if you are in development or production you may need to configure a Nuxt proxy to allow access between your Nuxt application and Directus in your nuxt.config.ts
:
routeRules: {
"/directus/**": { proxy: `${import.meta.env.API_URL}/**` },
},
This will allow your Nuxt application to access Directus via your Nuxt URL, eg. http://localhost:3000/directus
Define a Directus Schema
TypeScript needs to know what the structure of the Directus data is. To achieve this create a directus.d.ts
file in the root of our project which defines our schema:
/// <reference types="@directus/extensions/api.d.ts" />
interface DirectusSchema {
posts: Post[];
posts_translations: PostTranslation[];
}
interface Post {
id: number;
title: string;
content: string;
slug?: string;
}
interface PostTranslation {
id: number;
title: string;
content: string;
languages_code: string;
posts_id: number;
}
Create a Directus plugin
Create a Nuxt plugin to streamline accessing Directus throughout your application. Create a new file plugins/directus.ts
Copy and paste in the code below, replace the your-website-url
with your Nuxt URL and port:
import { createDirectus, rest, readItems } from "@directus/sdk";
const directus = createDirectus<DirectusSchema>(
"http://your-website-url/directus",
).with(rest());
export default defineNuxtPlugin(() => {
return {
provide: { directus, readItems },
};
});
Set Up Content Translations
Add a field to the posts
collection of type Translations keeping all the default settings.
This will create two new collections, languages
and posts_translations
The posts_translations
collection is required to retrieve the translation from Nuxt so make this public by navigating to Settings -> Access Policies -> Public and adding posts_translations
with read
permissions.
Open the posts_translations
collection, and add the fields title
and content
with their corresponding types (matching the ones listed above).
Create post content with the according translations in 3 languages (hint: use Google Translate).
title
: "Becoming a productive rabbit"content
:
Rabbits are known for their quickness and agility, but did you know they can also be incredibly productive? Here are a few tips to help you become the most productive rabbit you can be:
Set clear goals. Determine what you want to achieve and make a plan to reach your goals.
Use your natural abilities. Rabbits are quick, so use that speed to your advantage by completing tasks quickly and efficiently.
Stay organized. Keep your burrow neat and tidy so you can quickly find what you need when you need it.
Take breaks. Despite their reputation for being quick, rabbits need breaks too. Take short hops to stretch your legs and rest your mind.
Surround yourself with positive influences. Make friends with other productive rabbits and learn from their habits.
By following these tips, you'll be well on your way to becoming the most productive rabbit you can be. So, get hopping and get things done!
slug
: "becoming-a-productive-rabbit"
Click on the "Translations" interface and select the language you want to add the translation for. Below is a translation in French, Italian and Portuguese but you can add as many additional languages as you like.
French Translation
title
: "Devenir un lapin productif"content
:
Les lapins sont connus pour leur rapidité et leur agilité, mais saviez-vous qu'ils peuvent aussi être incroyablement productifs ? Voici quelques conseils pour vous aider à devenir le lapin le plus productif possible :
Fixez-vous des objectifs clairs. Déterminez ce que vous voulez accomplir et établissez un plan pour atteindre vos objectifs.
Utilisez vos capacités naturelles. Les lapins sont rapides, alors utilisez cette vitesse à votre avantage en accomplissant les tâches rapidement et efficacement.
Restez organisé. Gardez votre terrier propre et rangé afin de pouvoir trouver rapidement ce dont vous avez besoin quand vous en avez besoin.
Faites des pauses. Malgré leur réputation d'être rapides, les lapins ont aussi besoin de pauses. Faites de petits sauts pour vous dégourdir les jambes et reposer votre esprit.
Entourez-vous d'influences positives. Faites-vous des amis avec d'autres lapins productifs et apprenez de leurs habitudes.
En suivant ces conseils, vous serez sur la bonne voie pour devenir le lapin le plus productif possible. Alors, sautez et faites avancer les choses !
Italian Translation
title
: "Diventare un coniglio produttivo"content
:
I conigli sono noti per la loro rapidità e agilità, ma sapevi che possono anche essere incredibilmente produttivi? Ecco alcuni suggerimenti per aiutarti a diventare il coniglio più produttivo possibile:
Fissa obiettivi chiari. Determina cosa vuoi ottenere e fai un piano per raggiungerli.
Usa le tue abilità naturali. I conigli sono veloci, quindi usa questa velocità a tuo vantaggio completando i compiti in modo rapido ed efficiente.
Sii organizzato. Tieni la tua tana pulita e in ordine in modo da trovare rapidamente ciò di cui hai bisogno quando ne hai bisogno.
Fai delle pause. Nonostante la loro reputazione di essere veloci, anche i conigli hanno bisogno di pause. Fai dei piccoli salti per sgranchirti le gambe e riposare la mente.
Circondati di influenze positive. Fai amicizia con altri conigli produttivi e impara dalle loro abitudini.
Seguendo questi suggerimenti, sarai sulla buona strada per diventare il coniglio più produttivo possibile. Quindi, salta e fai le cose!
Portugeuse Translation
title
: "Tornando-se um coelho produtivo"content
:
Os coelhos são conhecidos por sua rapidez e agilidade, mas você sabia que eles também podem ser incrivelmente produtivos? Aqui estão algumas dicas para ajudar você a se tornar o coelho mais produtivo que você pode ser:
Estabeleça metas claras. Determine o que você quer alcançar e faça um plano para atingir suas metas.
Use suas habilidades naturais. Os coelhos são rápidos, então use essa velocidade a seu favor completando tarefas de forma rápida e eficiente.
Mantenha-se organizado. Mantenha sua toca limpa e arrumada para que você possa encontrar rapidamente o que precisa quando precisar.
Faça pausas. Apesar de sua reputação de serem rápidos, os coelhos também precisam de pausas. Dê pequenos saltos para esticar as pernas e descansar a mente.
Cerque-se de influências positivas. Faça amizade com outros coelhos produtivos e aprenda com seus hábitos.
Seguindo essas dicas, você estará no caminho certo para se tornar o coelho mais produtivo que você pode ser. Então, comece a pular e faça as coisas!
Note the "Translations" column showing the number of translations available for each post.
Set Up Language-Based Dynamic Routing
To map each language and collection with a unique URL use Nuxt's dynamic routing feature. Open app.vue
and replace the code with the following:
<template>
<div>
<NuxtRouteAnnouncer />
<NuxtPage />
</div>
</template>
Create a a new file and folder structure pages/[lang]/[slug].vue
. Add the following code the file that will retrieve a post based on the slug:
<script setup lang="ts">
const { $directus, $readItems } = useNuxtApp()
const route = useRoute()
const post: Ref<Post | null> = ref(null)
const { data, error } = await useAsyncData('post', async () => {
const slugParam = Array.isArray(route.params.slug) ? route.params.slug[0] : route.params.slug
return $directus.request($readItems('posts', {
filter: {
slug: { _eq: slugParam }
},
fields: ['id', 'title', 'content', 'slug'],
limit: 1
}))
})
if (error.value || data.value === null) {
console.error(error)
throw createError({
statusCode: 404,
statusMessage: "Post not found"
})
}
post.value = data.value[0]
</script>
<template>
<div v-if="post">
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
</div>
<div v-else>Loading...</div>
</template>
Start your Nuxt project by running npm run dev
and navigate to http://localhost:3000/en-US/becoming-a-productive-rabbit
. You should see your post content displayed.
In order to dynamically change the language of the post we also need to request the post by the lang
parameter supplied in the URL. Replace your [slug].vue
file with the following:
<script setup lang="ts">
const { $directus, $readItems } = useNuxtApp()
const route = useRoute()
const post: Ref<Post | null> = ref(null)
const { data, error } = await useAsyncData('post', async () => {
const slugParam = Array.isArray(route.params.slug) ? route.params.slug[0] : route.params.slug
const languageCode = Array.isArray(route.params.lang) ? route.params.lang[0] : route.params.lang
return await $directus.request($readItems('posts', {
filter: {
slug: { _eq: slugParam },
},
fields: ['id', 'title', 'content'],
limit: 1
})).then(data => {
if (languageCode === 'en-US') {
return data
}
return $directus.request($readItems('posts_translations', {
filter: {
posts_id: { _eq: data[0].id },
languages_code: { _eq: languageCode }
},
fields: ['id', 'title', 'content'],
limit: 1
}))
})
})
if (error.value || data.value === null || data.value.length === 0) {
console.error(error)
throw createError({
statusCode: 404,
statusMessage: "Post not found"
})
}
post.value = data.value[0]
</script>
<template>
<div v-if="post">
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
</div>
<div v-else>Loading...</div>
</template>
Navigate to http://localhost:3000/fr-FR/becoming-a-productive-rabbit
to see the French translation of the post.
The default language in this example is en-US, navigate to http://localhost:3000/en-US/becoming-a-productive-rabbit
and confirm you see the English version of the post (even though we haven't specifically added a translation).
If we try to navigate to a language we haven't added a translation for, eg. http://localhost:3000/es-ES/becoming-a-productive-rabbit
we will see a 404 error.
Summary
In this post, you learned how to create multilingual content in Directus and access it using a Nuxt application. Using Nuxt's dynamic routing the same content can be retrieved based on the language requested in a URL.