DEV Community

Cover image for Speed-up your internationalization calls up to 5-1000 times

Speed-up your internationalization calls up to 5-1000 times

Vincent Thibault on February 28, 2019

Context It all started two years ago. I was working on a new PWA for a big social network written from scratch that needed a i18n module...
Collapse
 
qm3ster profile image
Mihail Malo

I assume it would be more code on the wire if you server-rendered these functions?
Have your considered rendering them inside a Service Worker and returning the .js file?

Collapse
 
vince_tblt profile image
Vincent Thibault

Interesting idea to do it on the server-side/service-worker/build-tool !

Yet I'm not sure there is much gain, the generated function weighs more than the string representation. And it will mean for every update of the library you'll have to re-generate all your functions in case of signature mismatch (and possible fixes on the generated function).

But yeah, it would also be possible with this method to remove the compiler from the code and gain some extra bytes :)

By the way, here is how to extract the function if needed :

import { locale, set, t, cache } from 'frenchkiss';

locale('en');
set('en', {
  test: 'Check my {pet, select, cat{evil cat} dog{good boy} other{{pet}}} :D',
});

t('test'); // generate it
console.log(cache.en.test.toString()); // extract it

// =>
// function anonymous(a,f
// /*``*/) {
// var p=a||{};return "Check my "+(p["pet"]=="cat"?"evil cat":p["pet"]=="dog"?"good // boy":(p["pet"]||(p["pet"]=="0"?0:"")))+" :D"
// }
// */
Collapse
 
qm3ster profile image
Mihail Malo

It's more about the fact that the browser can store the parsed and even potentially optimized function in cache, not just the string form, when you go through normal pathways.
new Function() is rather esoteric, and means it will definitely do a parse per instantiation, as well as cause some deoptimization around the instantiation.
Furthermore, using the library as is requires 'unsafe-eval' CSP directive on your entire page, which you otherwise might be able to avoid.

Collapse
 
qm3ster profile image
Mihail Malo • Edited
var p=a||{};return "Check my "+(p["pet"]=="cat"?"evil cat":p["pet"]=="dog"?"good boy":(p["pet"]||(p["pet"]=="0"?0:"")))+" :D"

With a little more work of the compiler, there are things that could make the function shorter:

var p=a||{},a=p.pet;return "Check my "+(a=="cat"?"evil cat":a=="dog"?"good boy":a||(a=="0"?0:""))+" :D"

Can you clarify to me what the (a||(a=="0"?0:"")) is doing?

Thread Thread
 
vince_tblt profile image
Vincent Thibault

Yeah some optimizations can definitively cleanup the generated function. I just wanted to avoid spending much time (and file size) just to prettify the output.

The var p=a||{}; for example can be removed in case of raw string (that's not actually the case).

About the (a||(a=="0"?0:"")), it's actually to avoid printing "undefined", "null" in a translation, but keep "0" working :

// 'test' : 'Value: {value} !'

t('test'); // 'Variable:  !'
t('test', { value: undefined ); // 'Value:  !'
t('test', { value: null ); // 'Value:  !'
t('test', { value: 'test' ); // 'Value: test !'
t('test', { value: 0 ); // 'Value: 0 !'
Thread Thread
 
qm3ster profile image
Mihail Malo

I'm not well-versed in i18n, is that the expected behavior of pet, select, other{{pet}}? Empty string for entirely missing key?