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 :
Should probably report an error in prod(in addition to whatever behavior you suggest)/fail in dev?
Imo the key name is less bad than an empty string, I have been on broken sites/apps where I could complete my flow in part thanks to the variable names in the template. But that's a nitpick.
Ok, I note the suggestion, I'll try to implement it this week end, something like the onMissingKey is working :
frenchkiss.onMissingVariable((value,key,lang)=>{// report itsendReport(`variable "${value}" in ${lang}->${key} is missing.`);// the value you want to use insteadreturn`[${value}]`;});
I already did some tests with it working using an object mapping to values, but it doesn’t work well with nested expressions.
With nested expressions, you can’t really pre-cache objects and it will execute all the possible branches code before doing the resolution leading to performance issue.
With nested expressions you can have functions for some branches and strings for some. :v
Don't know about performance, but it is usually very compact, and you just need one helper:
Not really so compact if you transpile it to ES5.
Here is an example of a complete solution (if I don't miss a thing ?).
The translation :
Updated: {minutes, plural,
easteregg {never}
=0 {just now}
=1 {one minute ago}
other {
{minutes} minutes ago by {gender, select,
male {male}
female {female}
other {other}
}
}
}
The global functions
// Global SELECTfunctiongetBranchData(branch,prop,params,getPluralCategory,onMissingVariable,key,language){vardata=branch.hasOwnProperty(prop)?branch[prop]:branch.other;// fallback to 'others'returntypeofdata==="function"?data(params,getPluralCategory,onMissingVariable,key,language):data;}// Global PLURALfunctiongetBranchPluralData(branch,prop,params,getPluralCategory,onMissingVariable,key,language,){varcategory=getPluralCategory&&getPluralCategory(params[prop]);vardata;if(branch.hasOwnProperty(prop)){// direct assignmentdata=branch[prop];}elseif(category&&branch.hasOwnProperty(category)){// category check (easter egg)data=branch[category];}else{// default to otherdata=branch.other;}returntypeofdata==="function"?data(params,getPluralCategory,onMissingVariable,key,language):data;}// Global InterpolationfunctionhandleInterpolation(params,prop,onMissingVariable,key,language){return!params.hasOwnProperty(prop)?onMissingVariable(prop,key,language):typeofparams[prop]==="number"?params[prop]:params[prop]||"";}
The generated function demo:
functionfunctionGenerator(){// Closure to avoid re-defining branches at each callvarbranchA={0:"just now",1:"one minute ago",other:function(params,getPluralCategory,onMissingVariable,key,language){return(handleInterpolation(params,"minutes",onMissingVariable,key,language)+" minutes ago by "+getBranchData(branchB,params.gender,params,getPluralCategory,onMissingVariable,key,language));}};varbranchB={male:"male",female:"female",other:"other"};returnfunction(params,getPluralCategory,onMissingVariable,key,language){return("Updated: "+getBranchPluralData(branchA,params.minutes,params,getPluralCategory,onMissingVariable,key,language));};}varfn=functionGenerator();fn({minutes:5,gender:"male"});
I'll probably do a branch to see if it's a good candidate.
With a little more work of the compiler, there are things that could make the function shorter:
Can you clarify to me what the
(a||(a=="0"?0:""))
is doing?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 :I'm not well-versed in
i18n
, is that the expected behavior ofpet, select, other{{pet}}
? Empty string for entirely missing key?Can I suggest this way of inlining
selects
or will it hit performance?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):Depend of the i18n libs, some are printing undefined, some others are keeping
"{variable}"
in translation.As for me, I think it's a better user experience to have an empty string than a variable name (else the website seems broken).
Should probably report an error in prod(in addition to whatever behavior you suggest)/fail in dev?
Imo the key name is less bad than an empty string, I have been on broken sites/apps where I could complete my flow in part thanks to the variable names in the template. But that's a nitpick.
Ok, I note the suggestion, I'll try to implement it this week end, something like the
onMissingKey
is working :Just saw your comment about SELECT optimization.
I already did some tests with it working using an object mapping to values, but it doesn’t work well with nested expressions.
With nested expressions, you can’t really pre-cache objects and it will execute all the possible branches code before doing the resolution leading to performance issue.
With nested expressions you can have functions for some branches and strings for some. :v
Don't know about performance, but it is usually very compact, and you just need one helper:
Not really so compact if you transpile it to ES5.
Here is an example of a complete solution (if I don't miss a thing ?).
The translation :
The global functions
The generated function demo:
I'll probably do a branch to see if it's a good candidate.
should probably be an object, passed by reference instead of individually through arguments?