A few months ago, I’ve started a journey on building a side project. It’s a Vue2 PWA (progressive web app) which leverages Vuetify — a material design component framework — for developing web pages layout & UI elements with beauty & ease. At the time when I decided to add localization support to the web app, I couldn’t find out a suitable boilerplate for my need. That’s why I try to did it myself, with vue-i18n from Kazupon (now managed by intlify organization).
First things first, let’s list some characteristics of the target template:
- It should be scalable by allow placing locale translations both in global language files and in Vue SFC modules;
- It should allow i18n translation usage outside Vue components (i.e. the place where Vue instance is NOT available);
- The prefered locale should be persistent after page refresh;
- Implementing i18n in new Vue SFC should be easy because developers would throw the boilerplate away if they have to add a bunch lines of code to enable i18n.
Quite enough? Let’s get started!
Here’s my development environments:
- NodeJS version 12.3.1;
- VueCLI version 3.9.3.
For the sake of brevity, I will omit some trivial tasks (such as how to create Vue PWA project, how to add a npm package, etc).
For Github page URL compliance, I have to set
vue.config.js file to match Github repository’s name. In this case, to access the web app from localhost, you must use the URL
http://localhost:8080/demo-webapp-vuetify-i18n. This is quite inconvenience if you don’t host the web app’s distribution at Github, so you could remove this configuration in order to access via usual URL
Layout & Routing
The web app has a main layout
HomeLayout.vue, which allows user to switch locale with an upper right text button. The bottom navigation will direct user to a desired child components(recent page or favorites page). The child page’s content will be loaded into the area between a top app bar and the bottom navigation menu.
Here’s what the routes path look like:
As you can see, the login page is a independent component — named
LoginPage.vue — , i.e. its content does not get injected into home layout. User is unable to change locale here because the switch button will not be presented.
Nothing much to consider here, Vuex store is the first name that comes to mind when we need to centrally store the web app’s current locale state.
Please note that Vuex state is not persistent across a browser refresh, so I decided to use VuexPersist to save/load that state to/from browser’s local storage.
This is the most interesting part that would make the boilerplate to be useful for developers… or totally not if we don’t craft it carefully ^^.
Firstly, the home layout shows a locale text button and allows user clicking to change the locale. When user click that button, the logical processing steps should be:
- The current locale will be changed to user’s chosen value and saved to Vuex;
- The i18n instance will need to be informed about new locale value and takes action according to;
- And last but not least, on Vue components’
createdhook, they need to be able to get locale value of the previous session and start a new life cycle with that value.
Secondly, we could observe that step #1 is only applied to home layout where the locale button’s placed while the two later steps would happen to any Vue component in the web app. Therefore, we need a method to encapsulate that two logical steps.
Finally, Vue Mixins is the chosen method. In a nutshell, It’s a kind of inheritance in VueJS. You can read more here.
The mixins code would look like:
localeMixin usage in home layout:
And in login page:
If you check
Recent Vue component, you may see the missing of
localeMixin. The reason is that these components are used as nested routes of the
HomeLayout component (a kind of child-parent relationship).
Fortunately, VueI18n has already had support adding locale messages within Vue SFC — via
<i18n> custom block. Hence, beside global files for common locale messages, we also have places for component-related locale messages.
This separation would help us to keep the global locale files as small as possible while more and more components are added to the project’s code base. That’s why we will get scalability naturally.
So far, you may get the main idea behind the scene (I hope so). All other details will be revealed when you discover the Github code base.
Thanks for reading! Feel free to follow me for further posts.
Happy Coding \(^_^)/