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

Implement new UI for switching languages #12544

Closed
wants to merge 6 commits into from
Closed

Conversation

jsnajdr
Copy link
Member

@jsnajdr jsnajdr commented Mar 27, 2017

This is a PR for my trial project described in my post on the i18n P2 blog (internal ref: pxLjZ-3EJ-p2).

The main part of the effort is implementing a new language picker component (internal ref: p4TIVU-5np-p2).

A big task with many subtasks:

  • Implement a LanguageChooser component intended to replace the existing LanguageSelector. Its design is based on the SitesDropdown component.
  • Implement a LanguageChooserModal dialog that opens after clicking the "Change" link in the LanguageChooser. The design is based on EditorMediaModal. A tab bar with language groups and search, filtered list of languages to choose from, and a button bar with "Cancel" and "Select" buttons.
  • Use the new LanguageChooser on the /me/account page.
  • Use the LanguageChooser on the my-sites/site-settings/form-general page. This will need several improvements to the component:
    • In addition to valueLink prop, support also a value/onChange variant. Or get rid of the valueLink in me/account/main.jsx. That might be more future-proof, as valueLink is deprecated. (valueLink is being removed in PR Removed usages of valueLink from client/me/account #12729)
    • Support the disabled state
    • Support hooking telemetry (eventTracker) into the component
  • Support a "placeholder" state in LanguageChooser. It's displayed when settings data is being loaded.
  • Highlight the currently selected language in LanguageChooserModal
  • Add a README.md for the new components
  • Learn how unit tests are written in Calypso and write a testing suite (are we testing actions and reducers, or also UI rendering? What about integration (e2e) tests?
  • Display the explanation text side-by-side with the LanguageChooser (if the viewport is wide enough) abandoned, displaying under the component for consistency.
  • Create a LanguageSidebarChooser component that will be displayed in sidebars
  • Add a "Suggested Languages" list to LanguageChooserModal. The suggestions will be based on the browser language settings.
    • Get the language list from navigator.languages
    • For browsers that don't support navigator.languages (it's a new experimental API, supported only by Chrome and Firefox atm, according to MDN, find some fallback - probably some server REST API endpoint that reads the Accept-Language header. Decided to support only navigator.languages now and maybe make /locale-guesser smarter sometime in future.
    • As a last-resort fallback, use geolocation for suggestions. Investigate the /locale-guesser API endpoint. Result: using geolocation to select the default tab.
  • Group the language list into territories (Europe, Asia, Americas, ...), like the Facebook language picker does
    • Use the CLDR data for that. Decide whether to hardcode the data into the config/_shared.json file, or whether to query it online (see below)
    • Investigate the wp-cldr plugin. Does it have REST API? Can we detect if it's installed and query it? (It should be available on all WordPress.com sites). Result: hardcoding the data into JS code (it's not that big). Might load the data with AsyncLoad in future.
  • Support searching for a language by multiple names (Czech, Čeština, Tschechisch, ...). CLDR has all the translations.
    • How big will the translation data be? Decide whether to support only popular languages, or all.
    • Use the same data to display a tooltip over the language name that translates the name into the current language. The language name in the list is always self-referential (English, Deutsch, Čeština). Facebook dialog does this.
  • Tune the CSS styling of the modal. Right now, the styles depend on precise pixel sizes. Vertical flex should make the styling simpler and more reliable. Do all supported browser have good-enough vertical flex support?
  • Fine-tune the responsivity of the modal dialog (size, column sizes and count)
  • When a language name is too long and doesn't fit into the column, add a "fade-out" effect to make the clipping look good. (turns out this is not needed when the column count is responsive -- there's always enough room for all existing language names)
  • Clean up the language list data in config/_shared.json. There are a few errors. (moved this task to an independent PR: Update/normalize language names #12714)
    • Don't include the language slug in the language name. Convert en - English to English.

A related task that will probably be an independent PR: avoid reloading the whole page after a language is switched. Just trigger a React rerender with the new language. (Moved to #13712)

  • Does the localize HOC from i18n-calypso support this? Will the value of the injected translate property change?
  • Will all components properly rerender when translate props changes? Or will it be blocked by some shouldComponentUpdate implementation? Or a wrong/missing componentWillReceiveProps?
  • Does something that's not managed by React need to change on language switch? Like CSS styles or other assets?
  • Decide what directory should the new components be in. Is it client/components, or client/blocks or client/components/form? Result: It should be client/component - it's a "dumb" component that only renders what it's passed in props. To be eligible to be a block, it would need to connect to the app state by itself.
  • Consider removing the current LanguageSelector component and replace it completely with the LanguageChooser, maybe even reusing the name.

The LanguageChooser uses the lib/user-settings module that uses a legacy, event-based approach to data. Converting this module to Redux would be great.

  • Create a Redux state slice for user settings and provide appropriate action creators and selectors as the new API (happens in a separate PR: Reduxify the user-settings module (/me/settings endpoint) #12819)
  • Convert the existing lib/user-settings into a thin wrapper over the Redux API
  • Migrate all usages of lib/user-settings
  • Remove the legacy lib/user-settings module

@akirk
Copy link
Member

akirk commented Mar 27, 2017

I have tried it out on my machine: great progress! (Please tell us when you're ready for UI feedback :) ) Does the list represent the priority sequence in which you plan to implement the other points?

Re the Content-Language header: I would suggest not to do a work-around for missing navigator.languages support (for now; btw, it's available in Opera as it's Chrome based). Ultimately we can integrate the Content-Language reporting into locale-guesser to avoid an additional request round trip.

It would be great if you could provide screenshots of the current implementation state, it's both great for documenting the progress as well as it allows others to quickly peak at the current stage.

@jsnajdr
Copy link
Member Author

jsnajdr commented Mar 27, 2017

I have tried it out on my machine: great progress! (Please tell us when you're ready for UI feedback :) ) Does the list represent the priority sequence in which you plan to implement the other points?

The list is in a rather random order - it's a memory dump where I wanted to write things down before I forget them. I believe that all or almost all of them need to be implemented before the feature is shippable. Is there anything that you think is likely to spark some longer discussion and that should be implemented sooner rather than later?

It would be great if you could provide screenshots of the current implementation state, it's both great for documenting the progress as well as it allows others to quickly peak at the current stage.

Here is a screenshot of the state as of today:

language-chooser-03-27

It shows a part of the my/account form with the LanguageChooser and also the SitesDropdown for comparison. On the right, there is the LanguageChooserModal dialog.

A design question for @folletto: when I see the LanguageChooser and SitesDropdown next to each other, I feel they don't fit together very well. The "English" and "Change" labels are big and bold, while the text in the SitesDropdown looks more subtle. I tried to change the font weight and sizes slightly, and the result is in the bottom left. I like it more. What do you think?

@folletto
Copy link
Contributor

I tried to change the font weight and sizes slightly, and the result is in the bottom left. I like it more. What do you think?

A step back for the rationale: it was bold to match the button styling, not the site dropdown styling.

I agree there's a mismatch there tho, as the site dropdown doesn't adjust weight to align with buttons, so it's probably something to be reviewed more broadly as there's an existing incoherence there.

Given we're "in between", I'm ok with either option. If you feel the normal weight one is better, go for it. :)

} ),
}

constructor( props ) {
Copy link
Member

Choose a reason for hiding this comment

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

Looks like you could use ESNext property initialisers instead of this constructor.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

@@ -0,0 +1,127 @@
import React, { PureComponent } from 'react';
Copy link
Member

Choose a reason for hiding this comment

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

Missing an External dependencies docblock

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

@jsnajdr jsnajdr force-pushed the add/language-chooser branch from d7815ed to 728ad4e Compare March 28, 2017 21:05
},
{
action: 'confirm',
label: translate( 'Select Language' ),
Copy link

@a8ci18n a8ci18n Mar 28, 2017

Choose a reason for hiding this comment

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

Hi! I've found a possible matching string that has already been translated 60 times:
translate( 'Select a language below' ) ES Score: 10
See 1 additional suggestion in the PR translation status page

Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).

@jsnajdr
Copy link
Member Author

jsnajdr commented Mar 28, 2017

Today's update:

  • added a language button into the sidebar footer
  • cleaned up the language chooser modal:
    • highlight the selected language in the dialog
    • save and close the dialog only after clicking the confirmation button

sidebar-button-and-selection

New problem: in order to be able to react to changes in the user settings, and to do that without using legacy components like the observe mixin, we'll need to move the user-settings module functionality (fetching, getting, updating, saving) to a Redux state subtree with appropriate actions, reducers and selectors. Quite a big task.

As a rather ugly temporary workaround, I now subscribe to userSettings' change event in LanguageButton's componentDidMount/componentWillUnmount.

@jsnajdr jsnajdr force-pushed the add/language-chooser branch from 728ad4e to f8bcedb Compare March 30, 2017 17:46
@jsnajdr
Copy link
Member Author

jsnajdr commented Mar 30, 2017

Added a list of suggested languages:

suggested-languages

It's based on browser preferences, i.e., on navigator.languages. If the browser doesn't support this feature, the suggested list is not displayed at all.

What remains to be done on this feature:

  • make it responsive - in a narrow viewport, the list overflows and is not pretty.
  • make the selection highlight box the same size in both the language list and the selected language list. Now the heights are different, for some strange reasons.
  • test on Safari (Calypso in devel mode often crashes it)
  • test on IE

@folletto What do you think are best options for making the suggested language list responsive? Show limited number of suggestions on one row and hide the ones that would overflow? Convert the list into a popup menu when the viewport width is small? (SectionNav does exactly this with tabs, maybe we can reuse it)

@matticbot matticbot added the [Size] XL Probably needs to be broken down into multiple smaller issues label Mar 30, 2017
</div>
</div>
<LanguageChooserModal
isVisible={ this.state.open }
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the LanguageChooserModal do anything if it's not visible or own the visibility in some sense? If not, we might take the isVisible out of it and check it here to simplify the component and avoid creating it at all when it's not visible.

Copy link
Member Author

Choose a reason for hiding this comment

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

The LanguageChooserModal internally uses the <Dialog> component which owns the visibility state. It's supposed to be used in a 'declarative' way - just unconditionally render a <Dialog isVisible={...}/> and it will figure out whether to render something or not.

Before this feature is ready to merge, I'll need to do some performance tuning on this: to avoid creating the whole dialog contents in cases where it's not going to be rendered anyway.

@jsnajdr
Copy link
Member Author

jsnajdr commented Apr 3, 2017

Latest update: while the user settings are being fetched, all the language chooser buttons show a placeholder with the 'loading' status:

settings-placeholder

My next steps will be breaking this big PR into smaller ones that can be independently reviewed and merged.

@jsnajdr jsnajdr force-pushed the add/language-chooser branch from aacd47a to 3174adf Compare April 3, 2017 09:22
@jsnajdr
Copy link
Member Author

jsnajdr commented Apr 3, 2017

Rebased this PR to latest master, where #12714 just got merged.

jsnajdr added a commit that referenced this pull request Apr 3, 2017
Removed usages of valueLink and checkedLink from client/me/account/main.jsx
and replaced them with value/checked/onChange properties.

Also, stopped using valueLink method from me/form-base and the LinkedStateMixin.
Replaced them with methods on the Account class that directly work with the
userSettings module and the component state.

This will come handy when Reduxifying the component - all the method calls will
be straithforwardly replaced with selectors and action dispatches.

It also comes handy for PR #12544 that introduces a new LanguageChooser component.
This component won't have to support the dual API with both value/onChange and
valueLink, but will need to support just one.

After this PR, doing the same change in other client/me subdirectories should follow.
@jsnajdr jsnajdr force-pushed the add/language-chooser branch from 3174adf to 2a60256 Compare April 3, 2017 15:13
@jsnajdr
Copy link
Member Author

jsnajdr commented Apr 3, 2017

Current status:

@akirk @folletto @ehg I guess I'm ready for a design review and code review of the new language picker. There are currently 5 commits in this branch that I indend to merge as separate PRs.

The first version of the chooser dialog will have two tabs with "Popular Languages" and "All Languages", there will be no suggested languages and no division by territory. These will be followups after the basic version is accepted and merged.

I'll be now working on Reduxization of the lib/user-settings module. Although it will be quite a big change, it won't affect the language picker code very much.

@folletto
Copy link
Contributor

folletto commented Apr 3, 2017

There are currently 5 commits in this branch that I indend to merge as separate PRs.

Ok go ahead for the separate PRs.

In general the design looks good.

I've just a secondary note that the "button" should be entirely clickable, and should highlight similar to the standard buttons on hover, not just "Change". Sorry if it wasn't clear from the mockups.

@jsnajdr jsnajdr force-pushed the add/language-chooser branch from 2a60256 to 6cad6b8 Compare April 5, 2017 06:23
jsnajdr added a commit that referenced this pull request Apr 5, 2017
Removed usages of valueLink and checkedLink from client/me/account/main.jsx
and replaced them with value/checked/onChange properties.

Also, stopped using valueLink method from me/form-base and the LinkedStateMixin.
Replaced them with methods on the Account class that directly work with the
userSettings module and the component state.

This will come handy when Reduxifying the component - all the method calls will
be straithforwardly replaced with selectors and action dispatches.

It also comes handy for PR #12544 that introduces a new LanguageChooser component.
This component won't have to support the dual API with both value/onChange and
valueLink, but will need to support just one.

After this PR, doing the same change in other client/me subdirectories should follow.
@jsnajdr jsnajdr force-pushed the add/language-chooser branch from 6cad6b8 to 474716b Compare April 5, 2017 10:26
jsnajdr added a commit that referenced this pull request Apr 7, 2017
Removed usages of valueLink and checkedLink from client/me/account/main.jsx
and replaced them with value/checked/onChange properties.

Also, stopped using valueLink method from me/form-base and the LinkedStateMixin.
Replaced them with methods on the Account class that directly work with the
userSettings module and the component state.

This will come handy when Reduxifying the component - all the method calls will
be straithforwardly replaced with selectors and action dispatches.

It also comes handy for PR #12544 that introduces a new LanguageChooser component.
This component won't have to support the dual API with both value/onChange and
valueLink, but will need to support just one.

After this PR, doing the same change in other client/me subdirectories should follow.
@folletto
Copy link
Contributor

folletto commented Apr 7, 2017

Ok, looks good:

cap-

jsnajdr added a commit that referenced this pull request Apr 13, 2017
Removed usages of valueLink and checkedLink from client/me/account/main.jsx
and replaced them with value/checked/onChange properties.

Also, stopped using valueLink method from me/form-base and the LinkedStateMixin.
Replaced them with methods on the Account class that directly work with the
userSettings module and the component state.

This will come handy when Reduxifying the component - all the method calls will
be straithforwardly replaced with selectors and action dispatches.

It also comes handy for PR #12544 that introduces a new LanguageChooser component.
This component won't have to support the dual API with both value/onChange and
valueLink, but will need to support just one.

After this PR, doing the same change in other client/me subdirectories should follow.
jsnajdr added a commit that referenced this pull request Apr 13, 2017
Removed usages of valueLink and checkedLink from client/me/account/main.jsx
and replaced them with value/checked/onChange properties.

Also, stopped using valueLink method from me/form-base and the LinkedStateMixin.
Replaced them with methods on the Account class that directly work with the
userSettings module and the component state.

This will come handy when Reduxifying the component - all the method calls will
be straithforwardly replaced with selectors and action dispatches.

It also comes handy for PR #12544 that introduces a new LanguageChooser component.
This component won't have to support the dual API with both value/onChange and
valueLink, but will need to support just one.

After this PR, doing the same change in other client/me subdirectories should follow.
@jsnajdr jsnajdr force-pushed the add/language-chooser branch from b597d56 to 94cb718 Compare April 14, 2017 10:44
},
{
action: 'confirm',
label: translate( 'Select Language' ),
Copy link

Choose a reason for hiding this comment

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

Hi! I've found a possible matching string that has already been translated 60 times:
translate( 'Select a language below' ) ES Score: 10
See 1 additional suggestion in the PR translation status page

Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).

@jsnajdr jsnajdr force-pushed the add/language-chooser branch 2 times, most recently from 6cdbc0a to 01b5936 Compare April 17, 2017 08:42
@yoavf
Copy link
Contributor

yoavf commented Apr 20, 2017

Suggestion: use the Autonym Font for the language names to prevent ܕܥܒܪܸܝܛ

screen shot 2017-04-20 at 11 30 12

jsnajdr added 6 commits April 20, 2017 16:31
Added a new LanguagePicker component which can be used as a form element
to change the interface or site language.

On click, the component opens a LanguagePickerModal dialog with UI
suitable for finding and selecting one of 135+ languages.
When dispatching saveUserSettings, optionally add custom onSuccess and
onFailure actions. These will be dispatched instead of the default ones
(i.e., the initiator action with meta attached).
Created a LanguageButton component that shows the interface language
in every sidebar (shown next to the Help button) and allows to change
the language on click.
Display list of suggested languages based on 'navigator.languages', i.e.,
on browser settings. If the 'navigator.languages' feature is missing from
the browser, detect that fact and don't show the suggested list in that case.
@jsnajdr jsnajdr force-pushed the add/language-chooser branch from 01b5936 to 5ab51cb Compare April 20, 2017 14:40
@jsnajdr
Copy link
Member Author

jsnajdr commented Apr 20, 2017

Suggestion: use the Autonym Font for the language names to prevent ܕܥܒܪܸܝܛ

Looks like a great idea, thanks! I'll definitely try the font out. I'm wondering how the font glyph look like design-wise. Also, I'm a bit worried that the project is explicitly marked as unmaintained.

@yoavf do you have any direct experience with the font? Have used it on any project?

@jsnajdr
Copy link
Member Author

jsnajdr commented Apr 20, 2017

Update: using the new Redux state/user-settings module to implement the sidebar button. Works very well, except there are some problems reacting to success/error response after saving the new language. Will blog about it.

@yoavf
Copy link
Contributor

yoavf commented Apr 20, 2017

Also, I'm a bit worried that the project is explicitly marked as unmaintained.
@yoavf do you have any direct experience with the font? Have used it on any project?

Nope, no personal experience. I was thinking it was used on Wikipedia, but I've just checked and this doesn't seem to be the case. Feel free to ignore it then :)

@jsnajdr
Copy link
Member Author

jsnajdr commented May 7, 2017

Closing this PR as all related changes were moved to separate smaller PRs under the Language Picker Project

@jsnajdr jsnajdr closed this May 7, 2017
@jsnajdr jsnajdr deleted the add/language-chooser branch May 7, 2017 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
i18n OSS Citizen [Size] XL Probably needs to be broken down into multiple smaller issues Translator
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants