Adding a language to Tableau Server

If you find yourself embedding Tableau Server but serving areas with languages that are not part of the standard set provided by default, it is possible to add support for additional language.

DISCLAIMER: Not supported by Tableau whatsoever, may break at any time, may void your warranty, proceed with caution!!!.

Updated 2018-05-09: New instructions for Tableau Server 10.5. A few things moved but it all works like before.

Adding a New Language

There are two parts to Tableau Server that are visible to the end user (only one when you fully embed):

  • vizportalclient: the UI of Tableau Server
  • vizqlserver: Draws all of the vizes that are embedded in an iframe.

These instructions will add a language to vizqlserver, but we’ll also do some work on vizportalclient to make sure everything is in order.

There are three steps to adding a language:

  1. Adding an entry for the language into the Repository
  2. Duplicating an existing language’s files and modifying
  3. Adjusting the JavaScript files of Tableau Server to make the language available

Adding an entry for the language into the Repository

Inside the Tableau Server PostgreSQL Repository, there is a table called language_prefs. If you SELECT * this, you’ll find the languages that appear in the Language selection box for each user. Tableau Server also uses this table on startup to determine which languages exist in the server.

To add a Russian language pack:

INSERT INTO language_prefs VALUES

The values for the row are:

  1. The lowercase version of the language code (‘ru’ for Russian). This is how the language will be identified in other places throughout the Tableau Server code
  2. The name that will be visible in the drop-down selector in the Tableau Server UI
  3. An integer that determines the order the languages appear in the selector box for each user. The default pattern goes up by 100 each time, and there are 8 original languages, so our first new language is 900 and we’ll just increment from there. I suppose you could rearrange the existing languages to put your new one to the top.
  4. The fourth value is the help file link pattern, which we’ll leave pointed to the English help, because that’s one thing we’re not going to take into our own hands for translation.
  5. The last value is the language_locale code, with language lower-case and locale uppercase. ‘ru_RU’ in this case.

If you just tried this with the readonly user, you received a message that you don’t have privileges. That user isn’t named “readonly” for nothing. To do this warranty voiding action, you’ll have to find a user with admin rights, which might be mentioned in various blog posts. If you can find the user and its password, you are qualified to continue.

At this point, when you restart Tableau Server it will try and look for the Russian language files. They don’t exist yet, so we better create some.

Duplicating an existing language’s files and modifying

Note: You’ll want to copy all of the custom files you create before you do an upgrade, then put them back in place afterward, checking that no new values have been added to the jsstrings files for the supported languages. You also should keep a copy of the original vizportalMinLibs.js and messageformat_locales.js (and anything else you change) that you can substitute back in place so nothing gets messed up when you upgrade.

Note 2: In 10.0+, every content file has an equivalent .gz file which will be read if it exists. You can rename all of these with “.old” at the end so that the Apache server will ignore them. Or you can gzip your modified files to replace them. You also MUST follow these steps to disable server-side caching so that your new files will be delivered. There are also min.js versions of almost every JavaScript file. These are almost impossible to modify, so what you can do is change their names (and move somewhere safe) and then save the non-minified version with the .min.js ending. I supposed you could minify the files as well but that’s beyond me.

Note 3 (10.5): In 10.5, the server-side caching seems to be less strong that before, so you may not need to disable it. However, the system is definitely looking for the min.js versions of the files, so make sure you do the duplication mentioned at the end of Note 2.

vizqlserver files

As mentioned earlier, the files that are involved in the actual display of a Viz (and web edit) come from vizqlserver. The JavaScript files that include those strings live in the directory (or its equivalent):

C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizqlserver\public\v_{versionnumber}\javascripts\

In this directory you’ll find a set of files named “jsstrings_”. Open up “jsstrings_en.js” and you’ll find a JavaScript object with keys and text that clearly line up with every bit of text found in the viz iframe. We can use this as our template for translation. Save As a copy as “jsstrings_ru.js”, and then modify something you’ll see immediately once all the changes are in place. I suggest “ToolbarDownload:” or “ToolbarEdit:” as good candidates.

Eventually you’ll want to translate all of these strings so that the end user gets the desired experience. This takes care of vizqlserver — the jsstrings file controls it all.

vizportalclient files

Now let’s do some work on vizportalclient just to make sure the server doesn’t balk when it looks for a language. Let’s look in

C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public

Notice that there are directories for each language. Let’s copy the ‘en‘ folder and rename that copy ‘ru‘.

Earlier than 10.5: If you compare the files in each of the directories, you’ll notice that they are all identical, with placeholders where the translated text goes. This is convenient and means there is no danger in just replicating the ‘en’ folder for each new language we add.

10.5: The files themselves actually have the real values for quite a few of the words in the HTML files themselves. If you remove (or rename) the .gz version of a file, the web server will use the basic HTML version. You can change the text directly (remember to only change text that is between the tags, and not any of the attributes of the HTML tags.

The next directory to make changes to varies between versions, so follow the correct instructions:

Earlier than 10.5:

C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public\loc

you’ll find “__.json” files like “en.json” which include most of the strings that are used in the Tableau Server UI. Let’s just copy en.json and rename is “ru.json”. You could translate these later if you needed to, but for now let’s leave them in English so we can still navigate when we test our new language.


C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public\localize

you’ll find “messages.language_locale.js” files like “messages_en_US.js” which include most of the strings that are used in the Tableau Server UI. Let’s just copy en.js and rename is “ru.js”. You could translate these later if you needed to, but for now let’s leave them in English so we can still navigate when we test our new language.


There is a basic set of language_locale information around times, calendar dates, numbers, etc. in

C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public\locales

which do not need any changes — the codes for almost every locale are already here and ready.

Adjusting the JavaScript files of Tableau Server to make the language available

The actual JavaScript files that compose the functional “Tableau Server” application code have references that actually direct the correct localized content to be loaded. These also vary a bit depending on the version:

Before 10.5:

There are two more files we need to change to enable the new language, and we make the same change to both of them:

C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public\vizportalLibs.js
C:\Program Files{ (x86)}\Tableau\Tableau Server\{version}\vizportalclient\public\messageformat_locales.js

In later version (10.2 for sure, probably earlier), vizportalLibs.js is replaced by vizportalMinLib.js, but it has the same section to edit.

Each has a section that looks like:{return n===1?”one”:”other”}
MessageFormat.locale.en=function(n){return n===1?”one”:”other”}{return n===1?”one”:”other”}{return n===0||n==1?”one”:”other”}
MessageFormat.locale.ja=function(n){return “other”}
MessageFormat.locale.ko=function(n){return “other”}{return n===1?”one”:”other”}
MessageFormat.locale.zh=function(n){return “other”}

We want to add a line recognizing our new locale:{return n===1?”one”:”other”}

I’m duplicating the English options, but it might make sense to use that of Chinese or Korean on languages in other character sets. I’m not entirely sure what this does, but it seems to affect pluralizations in the angular.js framework underneath. We’re not concerned here with vizportal so much so I just want everything my vizportal to show in English for the time being.


In 10.5, the JavaScript code that controls the language direction has moved to vizportal.js. Make sure to remove the min.js version, and then after you’ve made your changes to the original vizportal.js, save a copy of the changed file as vizportal.min.js.

It’s a big file, so the best way I have found is to search for the following terms:

  • messageLocaleMap
  • GettingStartedNotifications.prototype.getLocalizedSiteIntroLink
  • this.server.sessionLanguage

For messageLocaleMap, add the language code as the key and the language_LOCALE pair as the value:

var messageLocaleMap = {
de: 'de_DE',
en: 'en_US',
es: 'es_ES',
fr: 'fr_FR',
ga: 'ga_IE',
ja: 'ja_JP',
ko: 'ko_KR',
pt: 'pt_BR',
zh: 'zh_CN',
ru: 'ru_RU'

For GettingStartedNotifications.prototype.getLocalizedSiteIntroLink, simply add a case with a link similar to the others:

GettingStartedNotifications.prototype.getLocalizedSiteIntroLink = function () {
switch (this.ServerService.sessionLanguage()) {
case 'en':
return '//';
case 'zh':
return '//';
case 'fr':
return '//';
case 'de':
return '//';
case 'ja':
return '//';
case 'ko':
return '//';
case 'pt':
return '//';
case 'es':
return '//';
case 'ru':
return '//';
return '//';

For this.server.sessionLanguage, add to the case statement (this time with language-locale, all lowercase):

HelpService.prototype.helpUrlLanguage = function () {
switch (this.server.sessionLanguage()) {
case "de": return "de-de";
case "en": return "en-us";
case "es": return "es-es";
case "fr": return "fr-fr";
case "ja": return "ja-jp";
case "ko": return "ko-kr";
case "pt": return "pt-br";
case "zh": return "zh-cn";
case "ru": return "ru-ru";
default: return 'en-us';

Restart the Server and See if you have succeeded!

At this point, you’ve set up enough to restart the server and see your new language be available. Every time you update the language file, you may need to clear your browser cache to see the changes. You do not have to restart server — the JSON strings are actually brought into the browser fresh from the server with a browser cache refresh (at least in the vizqlserver process).


Enabling A NEW Language For a User

Each user in Tableau has language and locale preference settings. You can see your own using My Account Settings

account settings

or set them for any user you can admin using the Site Users page. By default these are set to “Unspecified”.

unspecified language locale

When these are “Unspecifed”, Tableau Server will try and use the locale settings in the browser to determine which language to use. However, this functionality is hard-coded and not changed by adding our new language in the repository. Each language that is not officially supported has its own default that it goes to (most of them default to en_US surprise surprise).

So to make our new language work, we have to specifically select it in the list.

new russian language

That’s kind of a pain for every user, particularly in embedded environments. There’s currently no way to set Language and Locale for a user via the REST API. If we trust ourselves enough, it is possible to set this via the repository. In the user_prefs table, each system_user_id that has ever had settings set has an entry, with language_id and locale_id fields. These match up to the language and locales that we put in the language_prefs table in the beginning. You can match the system_user_ids with the visible Tableau usernames by joining the system_users table and looking at the column. If you feel confident in updating the repository, you can do an update to the user_prefs table to set languages programmatically.

FROM user_prefs up
JOIN system_users su on up.system_user_id =
WHERE = '{username}'

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s