Localize the Vue Minimal Site Sample

Introduction

This tutorial discusses how to display a localized version of the Vue minimal site sample. The goal of this exercise is to modify the application so that it can support multiple languages at the same time and allow users to switch between them easily. The languages are not defined in the application code; rather, they are determined by what is downloaded from the server at build time.

What This Tutorial Includes

This tutorial includes the following:

What This Tutorial Does Not Include

This is what this tutorial does not include:

The Original Vue Minimal Site Sample

If you’re unfamiliar with the application discussed in this tutorial, we recommend that you first have a look at the original, English-only version running on the demo site.

You can find the source code for the original application on GitHub.

For an in-depth look at the English-only application and how it was written, have a look at the tutorial.

How the Untranslated Vue Minimal Site Sample Works

The existing sample is a simple three-page application. It has a home page, a Contact Us page, and a People page.

Structure of the Untranslated Minimal Site Sample Data

The minimal site sample uses the following Oracle Content Management asset types:

The single-language minimal site sample application consists of the following assets and relationships:

This application code uses predefined slugs as identifiers to reference pages or data sections that need special handling. The people page is built using a different asset type than the home and contact-us pages, but the code uses its slug as a way to distinguish it.

How the Untranslated Minimal Site Sample Loads Data from the Oracle Content Management Server

The Vue minimal site sample uses two methods to load data: REST calls to Oracle Content Management via the Content SDK and POST calls to the GraphQL endpoint of Oracle Content Management using the cross-fetch library. One quirk in the application is that all pages loaded by entering an explicit URL are rendered on the server side, while all pages loaded by clicking a link will be loaded and rendered by code running in the client web browser.

Changes Needed to Create a Localized Copy of the Application

Structure of the Localized Asset Data

No changes are needed to the Oracle Content Management asset data types. All the visible translated text can be stored in assets using the existing types.

For the purpose of this exercise, an automated tool was used to create translations of the base data into Canadian French, Spanish (Spain), and Simplified Chinese. This data may have some inaccuracies due to a lack of context in the automated process, but will suffice for this exercise.

As mentioned in the introduction, each translated locale was given its own complete asset tree which can be processed independently of the source language. For example, the English asset tree looks like this:

   MinimalMainGraphQL (slug: minimalmaingraphql)
      Home-Page (slug: home)
            Home-Announcement
            Home-Section1
            Home-Section2
      Contact-Us-Page (slug: contact-us)
            ContactUs-Announcement
            ContactUs-Section1
            ContactUs-Section2
      People-Page (slug: people)
            People-Announcement
            List-of-Person-Assets

and the Spanish one looks like this (note the appended ’_es’ locale in the slugs):

   MinimalMainGraphQL-ES (slug: minimalmaingraphql_es)
      Home-Page-ES (slug: home_es)
            Home-Announcement-ES
            Home-Section1-ES
            Home-Section2-ES
      Contact-Us-Page-ES (slug: contact-us_es)
            ContactUs-Announcement-ES
            ContactUs-Section1-ES
            ContactUs-Section2-ES
      People-Page-ES (slug: people_es)
            People-Announcement-ES
            List-of-Person-Assets-ES

Note how the slugs of the MinimalMain and Page assets share a common root across languages. This is for the following reasons:

Code Modifications Needed to Display a Localized Vue Minimal Site Sample

The only visible change in the application is to add a locale switching control in the page header. (See the description of the Header.vue file below). Since all translations are published on the same channel token, there’s no need to support multiple channels for data acquisition.

Below are some of the source code changes required to support multiple locales.

/src/router/index.js

The routes used for the Home, Contact-Us, and People pages now optionally contain the locale of the pages as well as the slug of the default English pages. The slugs for pages in other languages is now constructed based on the language passed in and the default language page slug.

path: '/page/:lang?/:slug'

/src/scripts/services.js

This set of utility functions performs the calls to the Content SDK to retrieve server data for the application. Originally, it was built on the idea that there would be one MinimalMain asset that would contain the references to all the pages that the application should know about. This is no longer the case with localization, as each language has its own MinimalMain asset that contains a list of localized pages. Rather than rework the application to support multiple lists of pages, it was decided to have the application get the list of all MinimalMain assets that have a slug starting with “minimalmaingraphql” and then load each one in turn. The list of all pages defined in each MinimalMain instance is then merged into one list and passed into the application for processing.

New functions

getAllMains — Gets a list of all the MinimalMain assets on the server that have a slug starting with “minimalmaingraphql.” Each localized copy of the data has its own MinimalMain asset that matches this pattern. Since the list of these assets is not hard-coded in the client, it’s not necessary to maintain a list of predefined locales to display. Instead, the application can determine this information based on the list of MinimalMain assets that the server returns to it.

  const data = await client.getItems({
    q: '(type eq "MinimalMain" AND slug sw "minimalmaingraphql")',
  });

Modified functions

fetchOceMinimalMain — It now calls getAllMains and loads each one of the returned slugs in turn. It then merges the page lists from all the returned assets into one asset and returns it. Previously it would load one asset only by slug name and return that. The footer logo and header logo are still derived from the first MinimalMain asset loaded so if these were localized, the code would not currently handle them being displayed differently for each language. Instead, the application would have to be modified to manage the set of all MinimalMain assets.

/src/components/Header.vue

The only UI change made in this component is to add a selection box to choose which language should be displayed. This serves two purposes: when a new language is selected, it will change the menu to display only the links for the pages in the new locale, and then it will reload the current page in the new locale. For example, if the user is viewing the French home page and then selects Chinese, it will remove the French page links, display the Chinese page links, and then navigate to the Chinese home page. The data now keeps track of the current language and all the available languages.

Modified functions

created — This function now initializes the default language from the route parameter set in the url. It used to select the first language defined in the list. It also creates an array of available languages. The page slug is now constructed based on the language and the slug passed in the url.

onLanguageChange — This is the callback for the language dropdown selector. It causes the page menu to update to display the pages for the newly selected language. It also checks the current page and loads its equivalent in the new language.

template — The template now includes the UI for rendering the languages dropdown.

<div id="language">
  Language
  <select v-model="language" @change="onLanguageChange($event)">
    <option :key="lang" :value="lang"  v-for="(lang) in languages">
      {{lang}}
    </option>
  </select>
</div>

/src/pages/Page.vue

Modified functions

created and beforeRouteUpdate — These functions now also consider the language parameter that’s passed in and creates the page slug to be fetched accordingly.

created() {
  // get data passed in on the URL
  this.lang = this.$route.params.lang;
  const { slug } = this.$route.params;
  this.slug = this.lang === 'en' || this.lang === '' || !this.lang ? slug : `${slug}_${this.lang.split('-')[0]}`;

  ...
}

/src/styles/styles.css

Add a style used to hide languages that are not in use.

Views of the Localized Sample Site

Here are a few images showing different pages in varying locales. Note that there is text in the header and footer of each page that is untranslated. This is because the text is part of an image, not free text. It would have been possible to create localized versions of the image as well if this was intended to be a production site.

The Spanish home page:

The Spanish home page

The French People page:

The French People page

The Chinese home page:

The Chinese home page