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 • 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?

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

Can I suggest this way of inlining selects or will it hit performance?

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

If you do manage to get rid of new Function, you could do things like this though (n being a helper shared by all functions for all locales):

const n=x=>typeof x==="string"?x:"",
g=(c,x)=>c[x]||n(a)
// Elsewhere...
const c={cat:"evil cat",dog:"good boy"},
out=({pet:a}={},f)=>`Check my ${g(c,a)} :D`