Skip to content
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

🌐✨First pass at internationalizing amp-story #14051

Merged
merged 16 commits into from Mar 23, 2018

Conversation

newmuis
Copy link
Contributor

@newmuis newmuis commented Mar 16, 2018

This PR adds a simple service that swaps strings out depending on the lang attribute of the nearest ancestor. This service is currently in the amp-story extension, but could, in theory, be moved to src/.

The big problem with this is that it builds all strings for all languages into the binary that uses them. This won't scale to a large number of strings or languages. Ideally (I think?), we would have a way to build separate bundles based on the languages used, which we could dynamically fetch. That becomes an interesting UX problem, since there could be a delay before we have the strings.

Fixes #13556.

Loosely based on https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Internationalization

@newmuis
Copy link
Contributor Author

newmuis commented Mar 16, 2018

/cc @calebcordry

* document. If unspecified, will use the document-level language, if
* one exists, or the default otherwise.
*/
getMessage(messageId, opt_elementToUse) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the new styleguide asks for elementToUse = undefined instead

src/services.js Outdated
* @param {!Window} win
* @return {?Promise<?../extensions/amp-story/0.1/messages.MessageService>}
*/
static messageServiceForOrNull(win) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since no other extension is planning on using this service, we have no risk of race conditions. Could we just get it from the synchronous messageService method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget about me 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Also, this isn't stories-specific, so in theory, other people could use this for their strings too (/cc @cathyxz, does lightbox gallery have strings?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, don't have strings on lightbox gallery (yet), but we may end up with aria strings in all components for accessibility.

Copy link
Member

@alanorozco alanorozco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM although the format is a little verbose.

I think tables / ids should be built from source, akin to:

msg('Hi, I'm a message.')

...in plain English so that we can automatically invalidate stale translations, etc. The build step would then create pointers to unique strings and all that.

I don't think this is urgent, but I thought it might be worth putting out there.

@@ -335,6 +334,7 @@ div.i-amphtml-story-top {
margin: auto!important;
color:#fff!important;
box-sizing: initial !important;
text-transform: uppercase!important;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: space

*/
getLanguageCodesForElement_(element) {
const languageEl = closest(element, el => el.hasAttribute('lang'));
const languageCode = languageEl ? languageEl.getAttribute('lang') : null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can probably fallback to empty string here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAttribute can return null if the attribute is not present, so I felt null was more consistent; languageCode is either the value of the lang attribute, or null if there wasn't one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

@alanorozco alanorozco changed the title First pass at internationalizing amp-story ✨First pass at internationalizing amp-story Mar 16, 2018
Copy link

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by bikeshed: "Message" is confusing since it's also a verb. Recommend "I18n" or "LocalizedStrings".

@newmuis
Copy link
Contributor Author

newmuis commented Mar 19, 2018

@choumx Done
@alanorozco I think you're right that's a better end goal, but we need a build step for that, and we don't currently have it. This, at least, gets all the messages in a centralized place, so other refactors will be easier (i.e. they won't need to rip strings out that ended up in CSS somehow). Also, if we allow multiple langs in the same doc, the build step becomes very complicated 😄

@newmuis
Copy link
Contributor Author

newmuis commented Mar 21, 2018

Fixed type errors, renamed "messages" (and all related names) to "localized strings", and added the ability to create pseudo-locales, which will help us out for testing. We can expand pseudo-locale supoprt in a separate future PR, but this at least lets you verify that the string(s) you are using are indeed being passed through the LocalizationService, and are not hard-coded.

@newmuis newmuis changed the title ✨First pass at internationalizing amp-story 🌐✨First pass at internationalizing amp-story Mar 22, 2018
Copy link
Contributor

@gmajoulet gmajoulet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

},
[LocalizedStringId.AMP_STORY_SHARING_CLIPBOARD_FAILURE_TEXT]: {
string: ':(',
description: 'String shown in a toast to inform the user that a link ' +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: a translator would probably not know what a toast is

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

*
* Next ID: 22
*
* @const @enum {string}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious: any reason why we want strings instead of numbers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😦

Yeah. We directly use these as object keys in the _locales/*.js files, and object keys have to be strings. If you let this be @enum {number} they get coerced to strings when used as keys, but then you get all kinds of nasty type errors when you try to use Object.keys because they're all strings, but anything that was accepting an ID is expecting a number.

@newmuis newmuis merged commit fabd75e into ampproject:master Mar 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants