-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Gutenberg: Load Jetpack block translations in Calypso synchronously #28304
Conversation
@@ -42,6 +48,36 @@ function registerDataPlugins( userId ) { | |||
use( plugins.controls ); | |||
} | |||
|
|||
export const jetpackBlocki18n = ( context, next ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about calling this function here https://github.com/Automattic/wp-calypso/blob/master/client/gutenberg/editor/init.js#L25 before the extensions are loaded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I think I'll pass because:
- We need access to the state, in order to fetch the user's current locale.
- For the suggested approach, we need to pause the flow and continue after translations are loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could pass the state (or part of it) to initGutenberg
from controller, but I agree that we shouldn't do it here because of your second point.
const languageFileUrl = | ||
'https://widgets.wp.com/languages/jetpack-gutenberg-blocks/' + localeSlug + '.json'; | ||
|
||
request.get( languageFileUrl ).end( ( error, response ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor terminology nit, this isn't a synchronous call (as laid out in the title and description of the PR), as it doesn't block the browser UI while it's inflight. That said, we should not block the browser UI by using a true synchronous request, so this is perfectly fine, unless you're expecting it to block the browser...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good point, this is really sync-ish, because we don't prevent browser from loading anything, but in the same time we won't call next()
until the translations request is finished.
94fbc60
to
42bf6e5
Compare
42bf6e5
to
795e97e
Compare
Rebased. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, and tests well. While it'd be nice to have some more general-purpose solution in Gutenberg (see WordPress/gutenberg#12232), this is a reasonable solution for now. 🚢
As discussed on a video call with some Luna and Poseidon folks earlier today, we'll actually follow @sirreal's suggestion and use a similar pattern to fetch block visibility data (from @roccotripaldi's endpoint (D21225-code)). /cc @enejb
I'd hold off merging for now - I prefer getting approval from @Automattic/i18n and @Automattic/lannister before going ahead with this one. |
const languageFileUrl = | ||
'https://widgets.wp.com/languages/jetpack-gutenberg-blocks/' + localeSlug + '.json'; | ||
|
||
request.get( languageFileUrl ).end( ( error, response ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we shouldn't need to pull in superagent
here and instead could consider using the data layer…
import { requestHttpData, waitForData } from 'state/data-layer/http-data';
import { rawHttp } from 'state/data-getters';
waitForData( {
translations: requestHttpData(
'jetpack-gutenberg-translations',
rawHttp( {
method: 'GET',
url: `https://widgets.wp.com/languages/jetpack-gutenberg-blocks/${ localeSlug }.json`,
} ),
{ fromApi: () => ( { body } ) => [ [ 'jetpack-gutenberg-translations', body ] ] }
)
} ).then( ( { translations: { state, data } ) => {
if ( state === 'failure' ) {
debug( `Encountered an error loading locale file for ${ localeSlug }. Falling back to English.` );
}
// could still be expired data in the system
if ( data ) {
setLocaleData( data, 'jetpack' );
}
next();
} );
granted, that's more code, but it's inspectable in our dev tools and comes with freshness and auto-retry policies and you can fake the data in testing easily enough. if you are interested I'd be happy to create a helper function in state/data-getters
which cuts down on the overhead for doing a basic raw HTTP request
waitForData( {
translations: getAtURL( `https://widgets.wp.com/…` ),
} ).then( ( { translations: { state, data } } ) => {
if ( 'failure' === state ) {
debug( '…' );
}
if ( data ) {
setLocaleData( data.body, 'jetpack' );
}
next();
} );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^^ in case you are interested…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is lovely, thanks @dmsnell ❤️
I've implemented your suggestion in this PR, and it's ready for another look.
See #28304 In this patch we're adding a small helper to be used to get raw information from a given URL though a `GET` request. The way we'd use this is inside of the `waitForData()` function. This is meant to obscure the global http-data ID so that the user doesn't need to worry about it. ```js waitForData( { planets: getAtURL( 'https://swapi.co/api/planets/' ), } ).then( ( { planets } ) => { console.log( planets.data ); } ); ```
2acd7cf
to
373bd5b
Compare
See #28304 In this patch we're adding a small helper to be used to get raw information from a given URL though a `GET` request. The way we'd use this is inside of the `waitForData()` function. This is meant to obscure the global http-data ID so that the user doesn't need to worry about it. ```js waitForData( { planets: getAtURL( 'https://swapi.co/api/planets/' ), } ).then( ( { planets } ) => { console.log( planets.data ); } ); ```
See #28304 In this patch we're adding a small helper to be used to get raw information from a given URL though a `GET` request. The way we'd use this is inside of the `waitForData()` function. This is meant to obscure the global http-data ID so that the user doesn't need to worry about it. ```js waitForData( { planets: getAtURL( 'https://swapi.co/api/planets/' ), } ).then( ( { planets } ) => { console.log( planets.data ); } ); ```
This is currently blocked by #28867. |
See #28304 In this patch we're adding a small helper to be used to get raw information from a given URL though a `GET` request. The way we'd use this is inside of the `waitForData()` function. This is meant to obscure the global http-data ID so that the user doesn't need to worry about it. ```js waitForData( { planets: getAtURL( 'https://swapi.co/api/planets/' ), } ).then( ( { planets } ) => { console.log( planets.data ); } ); ```
See #28304 In this patch we're adding a small helper to be used to get raw information from a given URL though a `GET` request. The way we'd use this is inside of the `waitForData()` function. This is meant to obscure the global http-data ID so that the user doesn't need to worry about it. ```js waitForData( { planets: requestFromUrl( 'https://swapi.co/api/planets/' ), } ).then( ( { planets } ) => { console.log( planets.data ); } ); ```
373bd5b
to
685a69b
Compare
Rebased |
const localeSlug = getCurrentLocaleSlug( state ); | ||
|
||
// We don't need to localize English | ||
if ( localeSlug === 'en' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to use config( 'i18n_default_locale_slug' )
here
Merging. Thanks Marin, Dennis, et al |
Note that this is affected by the bug fixed in #29043 |
Thanks for landing this one @ockham! 🙇 |
We already have a working i18n system for Jetpack blocks that works well in wp-admin of Jetpack sites. However, currently, we don't serve those translations for Jetpack blocks to Calypso. This means that any of the Jetpack blocks aren't being localized.
This isn't straightforward, because those translations are managed at WP.org, and Calypso's translations are served by WP.com. So what we're already doing on the WP.com side is:
So, currently we'll have the translations available at URLs like: https://widgets.wp.com/languages/jetpack-gutenberg-blocks/bg.json
Next we need to actually pass these to Calypso, so blocks can be translated.
However, it's worth to mention that asynchronously loading those translations has some challenges we don't have solutions for:
We can register blocks without translations, then after translations are loaded, unregister and register them again with translations, however theoretically this will break those blocks in cases where they're needed while we're doing this re-registration. Even though we'll need to come up with a totally different mechanism for registering blocks, this is an alternative approach that is probably worth experimenting with.
So, this PR suggests that we load the translations synchronously, and we instantiate the editor after that. This way we'll only have to register the blocks once, and at that time they'll actually be translated already. The downside with this approach is that the first time translations are loaded, it might cause a little delay before initializing the editor. Any further initialization should be quick, as the translations file will already be available in the browser cache.
Changes proposed in this Pull Request
Testing instructions
npm start
.:site:
is one of your sites.:site:
is one of your sites.https://widgets.wp.com/languages/jetpack-gutenberg-blocks/*
are made in attempt to load i18n files for blocks.Note
This is currently blocked by #28867.