-
-
Notifications
You must be signed in to change notification settings - Fork 56
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
Fully add multi-language capability to blip #473
Conversation
Procedure: - surround all text to be translated with __() - npm run update-translations will update the .po files in translations/ - Use appropriate software to add translations - npm run build-translations will transform the .po files into .json Then the webpack script takes care of generating a separate index.[xx].html and bundle.[xx].js for each language in dist. For now, the server only serves index.en.html
Set default language to French (pending a per-user setting) and add translations for the navbar
- Move the loading of translations out of dependencies/i18n - Change languages.json from [languageCode] to {languageCode: language} - Move the language setting out of bootstrap.js and into core/language - Add language selection in userprofile to change language - Language selection is only client-side, not yet stored server-side
If the user hasn't yet set a language in their settings, use the browser's language instead.
Not yet using react-i18next. i18next allows to keep things minimal, react-i18next would introduce decorators and extracting t from props. I am still using i18n-extract to extract translations, next step is using i18next-parser
- Sort translation keys in the JSON - Translate the front page - Remove unneeded dependencies - Fix stuff
The weekly/trends chart have also been updated from "MMM D" to "D MMM" in French
Translations are now extracted from blip's two submodules. That way they don't need the extra-tooling, only i18next as a dependency. Furthermore, they can prefix their translatable strings with 'viz|' or 'tideline|' to use a different namespace and separate their translations from blip's translation.
It gets confused by translate() calls in viz/tideline
Thanks @coyotte508 We're currently having our company-wide offsite this week. I should be available to dive into reviewing this (and the other corresponding PRs) next week. |
@coyotte508 Just to clarify: This seems to fully replace the #468 PR, correct? I haven't gone through it in-depth yet, but at a glance it seems that this one encompasses everything from it. |
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.
Thanks for putting this all together! Looks good 👍
I do have a number of small changes requested, but overall a very clean PR.
The one main change I allude to in one of the review comments is that we'd like to have any translation-related UI changes, such as the language select on the user profile form, be enabled only by a feature flag (set via an envirionment variable).
Here are the local additions I made as a POC to illustrate the approach I recommend:
config.app.js
/* global __I18N_ENABLED__ */
module.exports {
// ...
I18N_ENABLED: booleanFromText(__I18N_ENABLED__, false),
};
config.webpack.js
var defineEnvPlugin = new webpack.DefinePlugin({
// ...
__I18N_ENABLED__: JSON.stringify(process.env.I18N_ENABLED || false),
});
webpack.config.js
var defineEnvPlugin = new webpack.DefinePlugin({
// ...
__I18N_ENABLED__: JSON.stringify(process.env.I18N_ENABLED || false),
});
Then, we can opt-in to show any translation-related UI elements via the config.app.js
export
import config from './config';
config.I18N_ENABLED && showStuff();
@@ -190,7 +191,7 @@ var Weekly = React.createClass({ | |||
|
|||
componentWillReceiveProps:function (nextProps) { | |||
if (this.props.loading && !nextProps.loading) { | |||
this.refs.chart.rerenderChart(); | |||
this.refs.chart.getWrappedInstance().rerenderChart(); |
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 errors out because the WeeklyChart
class above is not wrapped with the translate
HOC.
I'd suggest that we wrap the WeeklyChart
class for consistency with the other views. We then need to ensure all calls to methods on this.refs.chart
are prececeded by getWrappedInstance()
Currently, there are two places where this has not been done:
- In
componentDidMount
- In
handleClickOneDay
/* The following is for the translation extracter */ | ||
// t('year', {context: 'timeago'});t('years', {context: 'timeago'}); | ||
// t('month', {context: 'timeago'});t('months', {context: 'timeago'}); | ||
// t('week', {context: 'timeago'});t('minutes', {context: 'timeago'}); |
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.
Should this be weeks
here instead of minutes
?
@@ -15,6 +15,8 @@ | |||
|
|||
import React, { Component } from 'react'; | |||
import _ from 'lodash'; | |||
import { translate, Trans } from 'react-i18next'; | |||
import i18next from '../../core/language'; |
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.
Unused import
app/pages/patientnew/patientnew.js
Outdated
import { bindActionCreators } from 'redux'; | ||
|
||
import _ from 'lodash'; | ||
import sundial from 'sundial'; | ||
import { validateForm } from '../../core/validation'; | ||
import i18next from '../../core/language'; |
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.
Unused import
app/pages/userprofile/userprofile.js
Outdated
return [ | ||
{name: 'fullName', label: t('Full name'), type: 'text'}, | ||
{name: 'username', label: t('Email'), type: 'email'}, | ||
{name: 'lang', label: t('Language'), type: 'select', items: [ |
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.
Recommend that this be only displayed when enabled by a feature flag. Also, I ran this by our designer, and he'd prefer the language select as the last form input.
Here's what I've done locally as a POC:
const inputs = [
{name: 'fullName', label: t('Full name'), type: 'text'},
{name: 'username', label: t('Email'), type: 'email'},
{name: 'password', label: t('Password'), type: 'password'},
{name: 'passwordConfirm', label: t('Confirm password'), type: 'password'}
];
const langInput = {
name: 'lang', label: t('Language'),
type: 'select', items: [
{value: 'en', label: 'English'},
{value: 'fr', label: 'Français'},
],
placeholder: t('Select language...'),
};
config.I18N_ENABLED && inputs.push(langInput);
return inputs;
I'll add additional comments to the main thread re: using a feature flag to enable i18n.
package.json
Outdated
@@ -83,11 +87,13 @@ | |||
"devDependencies": { | |||
"babel-eslint": "6.1.2", | |||
"babel-plugin-rewire": "1.0.0-rc-6", | |||
"babel-plugin-transform-decorators-legacy": "^1.3.4", |
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.
Version needs to be locked down
package.json
Outdated
"chai": "3.5.0", | ||
"chromedriver": "2.23.1", | ||
"eslint": "2.13.1", | ||
"eslint-plugin-react": "5.2.2", | ||
"gitbook-cli": "2.3.0", | ||
"i18next-parser": "^1.0.0-beta9", |
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.
Version needs to be locked down
app/pages/userprofile/userprofile.js
Outdated
fullName: formValues.fullName, | ||
// This seems to be the best place to put language. Preferences and Settings | ||
// both refer to a patient id, but language doesn't have anything to do with patients | ||
language: formValues.lang |
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.
I've spoken with our backend engineer responsible for our data model, and he's requested that the appropriate language code be stored in the preferences
object as displayLanguageCode
app/pages/app/app.js
Outdated
@@ -418,6 +419,10 @@ export function mapStateToProps(state) { | |||
if (state.blip.loggedInUserId === state.blip.currentPatientInViewId) { | |||
userIsCurrentPatient = true; | |||
} | |||
|
|||
if (user && user.profile && user.profile.language) { | |||
i18next.changeLanguage(user.profile.language); |
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 will need to be changed once the language key is stored in preferences.displayLanguageCode
app/pages/app/app.js
Outdated
@@ -418,6 +419,10 @@ export function mapStateToProps(state) { | |||
if (state.blip.loggedInUserId === state.blip.currentPatientInViewId) { | |||
userIsCurrentPatient = true; | |||
} | |||
|
|||
if (user && user.profile && user.profile.language) { |
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.
Recommend using _.get
here:
if (_.get(user, 'profile.language')) {
...
}
I just changed the base to a new This will allow us to get these PR's merged a bit quicker, and will also allow us to create some staging builds on our side so our QA team can smoke test this before we merge into master. |
Thank you. I'm taking note of everything and hope to have the PR ready soon. Since the base has been locked down to the current state of master, I will also fix the current conflicts. |
- I18N_ENABLED environment variable to enable language selection in the GUI - Bugs with `getWrappedInstance()` in the weekly chart - Move language to preferences.displayLanguageCode - Remove unused imports
@cbwebdevelopment Changes were made to this PR, as well as tidepool-org/viz#102 and tidepool-org/tideline#331. |
As language is now stored in preferences, the user needs to be fetched before generating the pdf, so that the web worker can have language information.
const hasDiabetesData = _.get(nextState, 'processedPatientData.diabetesData.length'); | ||
|
||
// Ahead-Of-Time pdf generation for non-blocked print popup. | ||
// Whenever patientData is processed or the chartType changes, such as after a refresh | ||
// we check to see if we need to generate a new pdf to avoid stale data | ||
if (patientDataProcessed && hasDiabetesData && !pdfGenerating && !pdfGenerated) { | ||
if (userFetched && patientDataProcessed && hasDiabetesData && !pdfGenerating && !pdfGenerated) { |
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.
I'm curious. Were you running into any issues not having this check here? I can't recall anything from the user object being leveraged in the PDFs.
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.
It's to load preferences and the language. When the language information was stored in profile.language
there were no issues as it's loaded with the patient, but the preferences are loaded later and as such preferences.displayLanguageCode
.
Without userFetched
, the generated pdf on a page reload doesn't take into account the language, the user would have to go to their profile and back to the data.
It all looks good to me. I just have the one question about the need for the Also, it would be good to track that change in a separate PR. If you do move it to a separate PR, I can approve this one right away. Nice work :) We really appreciate it. |
Thank you :) I removed the last commit with |
Ahh makes sense.
You can leave it in if you’d like. I didn’t realize it was related to the translation.
Separate PR is fine as well if it’s already prepared. I’ll approve it at the same time.
…On Apr 30, 2018, 6:26 PM -0400, coyotte508 ***@***.***>, wrote:
Thank you :)
I removed the last commit with userFetched, I'm going to make it in a separate PR.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Okay, added the commit back. |
LGTM 👍 |
This is a follow-up to #468, with a lot more changes as every translatable string is flagged. Keys are used where html content is concerned, see 4e3b42d
This PR, along with the corresponding PRs in viz and tideline would allow multilanguage capabilities right now.