Closed davidsteinberger closed 7 years ago
I agree that we need something like this.
I solved this at my office by doing stuff like the below:
app-localize-behavior
__onRequestResponse
to wait till everything is loadedIn the element being translated
Polymer( {
// ...
behaviors: [
window.app.behaviors.localizer( [ 'core', 'other', 'feature' ] ),
],
// ...
} );
Helpers.js
class Helper {
isObject( source ) {
const nonNullObject = source && typeof source === 'object';
const toString = Object.prototype.toString.call( source );
return nonNullObject && toString === '[object Object]';
}
mergeObjects( target, ...sources ) {
if ( !sources.length ) return target;
const source = sources.shift();
const helpers = this;
if ( this.isObject( target ) && this.isObject( source ) ) {
Object.keys( source ).forEach( function eachKey( key ) {
if ( helpers.isObject( source[ key ] ) ) {
if ( !target[ key ] ) {
Object.assign( target, { [ key ]: {} } );
}
helpers.mergeObjects( target[ key ], source[ key ] );
} else {
Object.assign( target, { [ key ]: source[ key ] } );
}
} );
}
return this.mergeObjects( target, ...sources );
}
}
localizer.js
window.app.behaviors = window.app.behaviors || {};
window.app.behaviors.localizerImpl = function localizerImpl( features ) {
if ( !Array.isArray( features ) ) features = [ features ];
return {
properties: {
resourcesLeftToLoad: {
type: Number,
value: features.length,
},
},
__onRequestResponse: function __onRequestResponse( event ) {
this._tempResources = window.app.helper.mergeObjects( this._tempResources || {}, event.response );
if ( this.resourcesLeftToLoad !== 1 ) {
this.resourcesLeftToLoad -= 1;
} else {
this.resources = this._tempResources;
this.fire( 'app-localize-resources-loaded', event, { bubbles: this.bubbleEvent } );
}
},
attached: function attached() {
const component = this;
// ... determine language to load ...
features.forEach( function eachFilter( feature ) {
const url = 'http://google.com'; // build your url
component.loadResources( url );
} );
},
};
};
window.app.behaviors.localizer = function localizer( features ) {
return [ Polymer.AppLocalizeBehavior, window.app.behaviors.localizerImpl( features ) ];
};
@notwaldorf: This could easily be adopted into the main repo. If you let me know your browser targets I can polyfill the needed methods and open a PR.
I hit this too, but for the apps I'm building, the simpler changes from #110 were the only changes to AppLocalizeBehavior that were needed to achieve this.
With those changes, I'm able to pass a mergeResources
callback to loadResources
as the preprocessor
parameter, which merges the newly fetched resources into the existing resources that have been fetched (both for other languages and for other pages, since it's a SPA).
You can also listen for the app-localize-resources-loaded
event to do any additional bookkeeping needed once the resources have been updated (e.g. notifying Polymer about any deep paths that have changed).
That said, even though the changes from #110 are sufficient for this (as well as being more generally useful), I think there is still room for the AppLocalizeBehavior to offer a more ergonomic API for this use case.
To that end, I just pushed https://github.com/jab/app-localize-behavior/commit/b9bb3b1 to explore another idea: This adds two more optional parameters to loadResources
: language
, and merge
. If the language
parameter is supplied, the resources that have just been fetched are assigned into resources.language
rather than into resources
. And if you pass merge = true
, the new resources are merged into resources
rather than clobbering them. (This uses Object.assign, but you can also pass your own merge function instead of true
and that will be used instead, in case you need deep merge.)
This is quite a bit more ergonomic for our apps than what I described in my previous comment. It's also a better fit for us than @JonathanWolfe's solution, since each loadResources
call remains independent of any others, and doesn't need to know or care whether any other resources have been loaded yet. This way, when we have a request in flight for the resources for the global nav elements at the same time we have a request in flight for the current page's, whichever one finishes first will result in that part of the UI getting displayed immediately, without having to wait for the other one to finish.
I pushed a small demo of an app that uses this up to https://uproxy.github.io/uproxy.org/ in case anyone wants to take a peek.
I also just submitted these changes for consideration in #111, in case it's easier to look at this more holistically.
Description
As a developer it would be great if
app-localize-behavior
would support loading multiple locale/json files. That would allow devs to split the locales into multiple files and prevent duplicated translations across components.IMO that could be as achieved by having
__onRequestResponse()
merge the response into theresources
object, instead of replacing it.I'd be happy to work on a PR for that. What do you think?