In a client project we're using Vue to build a configurator embedded in Drupal Commerce. To make it multilingual we had to decide, how to handle translations and where to provide a UI to translate them.
As we're big fans of Drupal and its translation capabilities, our favourite option was to translate the Vue component strings right inside the Drupal Localization / Translation UI.
To be able to do that, we needed to bring Drupal.t() to Vue. Similar logic should be possible for React & Svelte with the same results!
Here's how you can pass the Drupal object containing the t() function to Vue as global property, so it can be used just like this in the components:
{{ Drupal.t('Add to cart') }}
(Note: This must be "Drupal.t()" and you can't use the shorter "t()" sadly, as Drupal would not recognize this as translation string on the page otherwise, see details below to understand why!
Here's the Drupal Vue initialization code providing the Drupal JavaScript object:
/**
* @file
* Birapa Commerce behaviors.
*/
(function (Drupal) {
Drupal.behaviors.myConfiguratorModule = {
attach(context, settings) {
once('vue-app-init', '#app', context).forEach((app) => {
// Mount the Vue app:
const vueApp = Vue.createApp({});
// Register our Configurator component as <configurator />.
// It's available as global variable from the loaded
// app/dist/configurator.umd.min.js library file.
vueApp.component('configurator', Configurator);
// Provide the Drupal object to Vue (to be able to use Drupal.t()):
vueApp.config.globalProperties.Drupal = Drupal;
vueApp.mount(app);
});
},
};
})(Drupal, once, drupalSettings);
So as a result you have the power of Drupal localization available in Vue (React / Svelte) and you can use the Drupal translation UI! Great!
Take care with Vite minification
Ensure to have Drupal.t() in the build result as string, otherwise Drupal won't be able to catch up the translation strings!
You may not beed minification in Vue, if you leave the minification to the asset / libraries system in Drupal! That will ensure Drupal.t() is handled correctly.
How it works
Drupals locale module has a genius functionality to scan the JavaScript assets (libraries) on the page for Drupal.t() calls:
/**
* Variable generated by Drupal that holds all translated strings from PHP.
*
* Content of this variable is automatically created by Drupal when using the
* Interface Translation module. It holds the translation of strings used on
* the page.
*
* This variable is used to pass data from the backend to the frontend. Data
* contained in `drupalSettings` is used during behavior initialization.
*
* @global
*
* @var {object} drupalTranslations
*/
/**
* Translates strings to the page language, or a given language.
*
* See the documentation of the server-side t() function for further details.
*
* @param {string} str
* A string containing the English text to translate.
* @param {Object.<string, string>} [args]
* An object of replacements pairs to make after translation. Incidences
* of any key in this array are replaced with the corresponding value.
* See {@link Drupal.formatString}.
* @param {object} [options]
* Additional options for translation.
* @param {string} [options.context='']
* The context the source string belongs to.
*
* @return {string}
* The formatted string.
* The translated string.
*/
Drupal.t = function (str, args, options) {
options = options || {};
options.context = options.context || '';
// Fetch the localized version of the string.
if (
typeof drupalTranslations !== 'undefined' &&
drupalTranslations.strings &&
drupalTranslations.strings[options.context] &&
drupalTranslations.strings[options.context][str]
) {
str = drupalTranslations.strings[options.context][str];
}
if (args) {
str = Drupal.formatString(str, args);
}
return str;
};
https://git.drupalcode.org/project/drupal/-/blob/11.x/core/misc/drupal.js#L368
The JS parsing for Drupal.t() is done in locale.module:
// Load the JavaScript file.
$file = file_get_contents($filepath);
// Match all calls to Drupal.t() in an array.
// Note: \s also matches newlines with the 's' modifier.
preg_match_all('~
[^\w]Drupal\s*\.\s*t\s* # match "Drupal.t" with whitespace
\(\s* # match "(" argument list start
(' . LOCALE_JS_STRING . ')\s* # capture string argument
(?:,\s*' . LOCALE_JS_OBJECT . '\s* # optionally capture str args
(?:,\s*' . LOCALE_JS_OBJECT_CONTEXT . '\s*) # optionally capture context
?)? # close optional args
[,\)] # match ")" or "," to finish
~sx', $file, $t_matches);
https://git.drupalcode.org/project/drupal/-/blob/11.x/core/modules/locale/locale.module#L1085
Take care, window.drupalTranslations only contains translation from the current page, determined from the assets on this page! It doesn't contain all translation strings Drupal knows about (which is good)!
So ensure your assets (e.g. your Vue build) can be parsed and is attached via libraries, otherwise it won't work.
You can check the available resulting strings by
console.log(window.drupalTranslations.strings);
Bonus
By the way, if you even need it more globally (might be evil ;)) then you can also pass the window object to Vue:
app.config.globalProperties.window = window
https://github.com/vuejs/vue-next-webpack-preview/issues/15
Are you planning a Configurator in Drupal + Vue?
Or maybe something similar?
Then the webks.de & DROWL.de Team is a good choice and investment for development support & consulting! Feel free to contact us!