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

Localization "Index Patterns" tab #20525

Merged
merged 40 commits into from
Jul 30, 2018

Conversation

maryia-lapata
Copy link
Contributor

@maryia-lapata maryia-lapata commented Jul 6, 2018

It's integration "Index Patterns" tab and I18n engine
#19729

@maryia-lapata maryia-lapata added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc Project:i18n labels Jul 6, 2018
const I18nBrowser = require.requireActual('../../kbn-i18n/src/browser');
const I18nNode = require.requireActual('../../kbn-i18n/src/index');

module.exports = {

Choose a reason for hiding this comment

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

Note: workaround under current implementation (resolve client libraries for node env)

import { sectionTypes } from './section_keys';

export function translateSectionName(i18n, typeId) {
if (!typeId) {

Choose a reason for hiding this comment

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

I'd remove it and return empty string in default case


const intl = {
formatMessage: jest.fn().mockImplementation(({ defaultMessage }) => defaultMessage),
formatDate: jest.fn().mockImplementation(({ defaultMessage }) => defaultMessage),

Choose a reason for hiding this comment

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

  1. let's change default implementation if we really need these functions (formatDate for instance don't have defaultMessage)
  2. Or remove unnecessary properties at all and just change for tests contextType for Intl

@@ -53,7 +53,7 @@ export const IGNORE_FILE_GLOBS = [
* @type {Array}
*/
export const KEBAB_CASE_DIRECTORY_GLOBS = [
'packages/*',
'packages/!(__mocks__)',

Choose a reason for hiding this comment

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

why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

According to Jest, if the module you are mocking is a Node module, the mock should be placed in the __mocks__ directory. At the same time there is a rule in kibana in which files under packages should use kebab case.
Since mocking the @kbn/i18n module is a workaround, after merging the PR #20513 I will revert this change.


{this.renderDeleteConfirmationModal()}
</div>
<I18nProvider>

Choose a reason for hiding this comment

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

it's not root component, you don't need provider here. let's use Provider only in ReactDOM.render calls

now: jest.fn().mockImplementation(({ defaultMessage }) => defaultMessage),
};

export function shallowIntl(node, { context, childContextTypes, ...props } = {}) {

Choose a reason for hiding this comment

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

maybe let's rename to shallowWithIntl for more consistency?

Copy link
Contributor

@bmcconaghy bmcconaghy left a comment

Choose a reason for hiding this comment

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

This is coming along very nicely, just have a few concerns I've documented here, the primary one being creating a new object inside values each time (I only commented on this in one spot, but it happens a lot in this code).

id="kbn.management.createIndexPattern.emptyStateLabel.emptyStateDetail"
defaultMessage="{needToIndex} {learnHowLink} or {getStartedLink}"
values={{
needToIndex: (
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I would prefer the values object here to be declared as a constant above and then referenced here. This would make things easier to read, and would also prevent a new object being created with each rerender. See this for an explanation of why that might be bad: https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f

Choose a reason for hiding this comment

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

@bmcconaghy Basically, this is common pattern for avoiding creation of new object, but I would not say, that in this case, because:

  1. Moving such objects to constants will decrease readability of code in general
  2. Some of values are React components too and use props. So if we move values to constant outside component we will not get props, if we will create it inside render it will be the same one
  3. This case is envisaged by react-intl guys. And for avoiding rerendering they espacially use shallow compare for values props. (Here)[https://github.com/yahoo/react-intl/blob/master/src/components/message.js#L43]

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough on the performance point. I actually find the FormattedMessage nested in FormattedMessage harder to read personally, as I get lost in the multiple levels of nesting, so would still like to see the values defined outside of the FormattedMessage and then referenced there.

Copy link
Member

@azasypkin azasypkin Jul 26, 2018

Choose a reason for hiding this comment

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

It feels like the right solution for this readability problem would be integrating i18n into EUI components at some point, so that this:

<EuiTextColor color="subdued">
  <FormattedMessage
    id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel"
    defaultMessage="You'll need to index ....."
  />
</EuiTextColor>

can be changed to:

<EuiTextColor color="subdued" i18n-id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel">
	You'll need to index .....
</EuiTextColor>

We'll still have to use values to keep all parts of the single message together though (can be quite important for RTL languges).

But that's a bigger effort that spans several teams and i18n should prove itself in practice first.

<strong>
<FormattedMessage
id="kbn.management.createIndexPattern.step.status.matchAnyLabel.strongIndicesLabel"
defaultMessage="{allIndicesLength, plural, one {# index} other {# indices}}"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we could clean up the message here for the case when a single index exists. "any of your 1 index" sounds pretty silly. "any of your" should be made part of the conditional. I would suggest the messages should be: singular "...can match your index below" plural (remains the same)

You can match any of your <strong>{allIndices.length} indices</strong>, below.
<FormattedMessage
id="kbn.management.createIndexPattern.step.status.notMatchLabel.notMatchDetail"
defaultMessage="The index pattern you've entered doesn't match any indices. You can match any of your {strongIndices}, below."
Copy link
Contributor

Choose a reason for hiding this comment

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

same issue as above

@@ -31,8 +36,11 @@ export function extractTimeFields(fields) {
display: '───',
fieldName: '',
};
const noTimeFieldLabel = i18n.translate('kbn.management.createIndexPattern.stepTime.noTimeFieldOptionLabel', {
defaultMessage: 'I don\'t want to use the Time Filter'
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer that we use `` or "" for string delimiting if the string contains a ' character. Easier to read than using escaping.

Choose a reason for hiding this comment

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

@bmcconaghy Actually, I agree with you that it sometimes maybe better for readabilty (and we use it in react components), but there are points why we did it in such way.

  1. We have eslint rule: "Strings must use singlequote"
  2. Template string cannot be used, because this restriction is set by tool for extracting messages and verifying them

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess I can live with this as it is. Is there a possibility of modifying the tool so that template strings would work?

Choose a reason for hiding this comment

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

Basically there is possibility to do it, but babel creates quite hard AST with template strings, which is difficult to work with, so currently we have decided to use such approach

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we just decided not to complicate things for now. If we allow using template strings for i18n ID's and default messages, someone will try to use it as a template string with dynamic parameter some day and then we'll have troubles :/

toastNotifications.add(`'${this.indexPattern.title}' index pattern doesn't have a scripted field called '${fieldName}'`);
const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel',
{
defaultMessage: '\'{indexPatternTitle}\' index pattern doesn\'t have a scripted field called \'{fieldName}\'',
Copy link
Contributor

Choose a reason for hiding this comment

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

Again prefer other quotation marks here over escaping.

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Contributor

@jen-huang jen-huang left a comment

Choose a reason for hiding this comment

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

LGTM, I spot checked the changed files and ran branch locally and confirmed there were no functional regressions.

Copy link
Member

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

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

Looks good to me, just a couple of issues and a few nits/questions.

<FormattedMessage
id="kbn.management.createIndexPattern.step.status.notMatchLabel.notMatchDetail"
defaultMessage="The index pattern you've entered doesn't match any indices.
You can match {indicesLength, plural, one {your} other {any of your}} {strongIndices}, below."

This comment was marked as resolved.

characterList="\\\\, /, ?, \\", <, >, |"
data-test-subj="createIndexPatternStep1Header"
errors={
Array [
"An index pattern cannot contain spaces or the characters: \\\\, /, ?, \\", <, >, |",
"An index pattern cannot contain spaces or the characters: {characterList}",
Copy link
Member

Choose a reason for hiding this comment

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

issue: having exact chars in the snapshot like it was before is important, can you please tweak test so that it properly expands {characterList}?

Your index pattern can match any of your <strong>{allIndices.length} indices</strong>, below.
<FormattedMessage
id="kbn.management.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail"
defaultMessage="Your index pattern can match any of your {strongIndices}, below."
Copy link
Member

Choose a reason for hiding this comment

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

note: there is no need to change anything in this PR, but for the following PRs: parameter name and message id should rather reflect what this parameters/message means, not how it looks like visually (strongIndicies vs indexCount). It will help localizers to understand context better as well.

Your index pattern can match any of your <strong>{allIndices.length} indices</strong>, below.
<FormattedMessage
id="kbn.management.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail"
defaultMessage="Your index pattern can match any of your {strongIndices}, below."

This comment was marked as resolved.

}) => (
<EuiForm>
{ isVisible ?
<EuiFormRow
label={
<EuiFlexGroup gutterSize="xs" justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={false}>
<span>Time Filter field name</span>

This comment was marked as resolved.

target="_window"
href={getDocLink('scriptedFields.painless')}
>
<FormattedMessage id="common.ui.fieldEditor.syntax.defaultLabel.painlessLink" defaultMessage="Painless" />&nbsp;
Copy link
Member

Choose a reason for hiding this comment

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

note: same question/note about Painless here.

language: <EuiCode>{field.lang}</EuiCode>,
painlessLink: (
<EuiLink target="_window" href={getDocLink('scriptedFields.painless')}>
<FormattedMessage
Copy link
Member

Choose a reason for hiding this comment

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

note: same

@@ -296,16 +335,29 @@ export class FieldEditor extends PureComponent {
const { field, fieldTypeFormats, fieldFormatId, fieldFormatParams } = this.state;
const { fieldFormatEditors } = this.props.helpers;
const defaultFormat = fieldTypeFormats[0] && fieldTypeFormats[0].resolvedTitle;
const label = defaultFormat
Copy link
Member

Choose a reason for hiding this comment

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

question: likely I missed some related review comment from other folks, so just double checking: previously we had null if defaultFormat was not defined, now we render Format label: is that expected?

Choose a reason for hiding this comment

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

Actually this is the same. Maybe you missed <span> outside?

Copy link
Member

Choose a reason for hiding this comment

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

Ugh, my bad, sorry :/

toastNotifications.addDanger({
title: `Unknown field type ${spec.type}`,
text: `Field ${spec.name} in indexPattern ${indexPattern.title} is using an unknown field type.`
title: title,
Copy link
Member

Choose a reason for hiding this comment

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

nit: use shortcuts maybe?

title,
text

});

const warningText = i18n.translate('common.ui.indexPattern.warningText', {
defaultMessage: 'For more information, view the ["{title}" index pattern in management]({link})',
Copy link
Member

Choose a reason for hiding this comment

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

question: was there any agreement to change the way we display that link?

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Member

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

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

LGTM, but please wait for green CI.

@elasticmachine
Copy link
Contributor

💔 Build Failed

@yankouskia
Copy link

retest

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@yankouskia yankouskia merged commit 7063dbc into elastic:master Jul 30, 2018
@yankouskia yankouskia deleted the i18n-index-patterns branch July 30, 2018 18:33
LeanidShutau pushed a commit to LeanidShutau/kibana that referenced this pull request Aug 6, 2018
* Integrate i18n-engine into "Index Patterns" tab

* Adjusted unit tests for "Index Patterns" tab

* Localization of "Index patterns" section name

* Rename the function shallowIntl to shallowWithIntl, remove needless check for translation type id

* Refactoring of default message

* Localization for FieldEditor component

* Adjust unit tests for FieldEditor component

* Integrate i18n-engine into "Index Patterns" tab

* Adjusted unit tests for "Index Patterns" tab

* Localization of "Index patterns" section name

* Rename the function shallowIntl to shallowWithIntl, remove needless check for translation type id

* Refactoring of default message

* Localization for FieldEditor component

* Adjust unit tests for FieldEditor component

* Replace I18nContext to injectI18n according to changes in @kbn/i18n

* Fix broken saving form

* Adjust components importing according to changes in @kbn/i18n

* Formatting and refactoring

* Update ids

* Fix invalid HTML and refactoring

* Use i18n module instead of AngularJS service

* Localize scripting_syntax.js, refactoring

* Update message ids.

* fix plural form in status messages

* fix messages in status message, _field component

* move back span in time_field

* refactor enzyme helper for providing intl into context

* do not translate Painless

* test call params in formatMessage

* clear formatMessage mock after each test

Co-authored-by: maryia-lapata <[email protected]>
LeanidShutau added a commit that referenced this pull request Aug 6, 2018
* Integrate i18n-engine into "Index Patterns" tab

* Adjusted unit tests for "Index Patterns" tab

* Localization of "Index patterns" section name

* Rename the function shallowIntl to shallowWithIntl, remove needless check for translation type id

* Refactoring of default message

* Localization for FieldEditor component

* Adjust unit tests for FieldEditor component

* Integrate i18n-engine into "Index Patterns" tab

* Adjusted unit tests for "Index Patterns" tab

* Localization of "Index patterns" section name

* Rename the function shallowIntl to shallowWithIntl, remove needless check for translation type id

* Refactoring of default message

* Localization for FieldEditor component

* Adjust unit tests for FieldEditor component

* Replace I18nContext to injectI18n according to changes in @kbn/i18n

* Fix broken saving form

* Adjust components importing according to changes in @kbn/i18n

* Formatting and refactoring

* Update ids

* Fix invalid HTML and refactoring

* Use i18n module instead of AngularJS service

* Localize scripting_syntax.js, refactoring

* Update message ids.

* fix plural form in status messages

* fix messages in status message, _field component

* move back span in time_field

* refactor enzyme helper for providing intl into context

* do not translate Painless

* test call params in formatMessage

* clear formatMessage mock after each test

Co-authored-by: maryia-lapata <[email protected]>
@LeanidShutau
Copy link
Contributor

6.x/6.5: f6f4e68

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backported Project:i18n Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v6.5.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants