-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Localization "Index Patterns" tab #20525
Conversation
packages/__mocks__/@kbn/i18n.js
Outdated
const I18nBrowser = require.requireActual('../../kbn-i18n/src/browser'); | ||
const I18nNode = require.requireActual('../../kbn-i18n/src/index'); | ||
|
||
module.exports = { |
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.
Note: workaround under current implementation (resolve client libraries for node env)
import { sectionTypes } from './section_keys'; | ||
|
||
export function translateSectionName(i18n, typeId) { | ||
if (!typeId) { |
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'd remove it and return empty string in default case
|
||
const intl = { | ||
formatMessage: jest.fn().mockImplementation(({ defaultMessage }) => defaultMessage), | ||
formatDate: jest.fn().mockImplementation(({ defaultMessage }) => defaultMessage), |
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.
- let's change default implementation if we really need these functions (
formatDate
for instance don't havedefaultMessage
) - Or remove unnecessary properties at all and just change for tests
contextType
forIntl
@@ -53,7 +53,7 @@ export const IGNORE_FILE_GLOBS = [ | |||
* @type {Array} | |||
*/ | |||
export const KEBAB_CASE_DIRECTORY_GLOBS = [ | |||
'packages/*', | |||
'packages/!(__mocks__)', |
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.
why?
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.
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> |
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 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 } = {}) { |
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.
maybe let's rename to shallowWithIntl
for more consistency?
…heck for translation type id
2e53185
to
463490f
Compare
50d5ac9
to
f186b43
Compare
…heck for translation type id
…a/kibana into i18n-index-patterns
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 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: ( |
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 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
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.
@bmcconaghy Basically, this is common pattern for avoiding creation of new object, but I would not say, that in this case, because:
- Moving such objects to constants will decrease readability of code in general
- 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
- 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]
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.
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.
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 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}}" |
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 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." |
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.
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' |
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 would prefer that we use `` or "" for string delimiting if the string contains a ' character. Easier to read than using escaping.
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.
@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.
- We have eslint rule: "Strings must use singlequote"
- Template string cannot be used, because this restriction is set by tool for extracting messages and verifying them
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 guess I can live with this as it is. Is there a possibility of modifying the tool so that template strings would work?
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.
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
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, 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}\'', |
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.
Again prefer other quotation marks here over escaping.
💚 Build Succeeded |
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.
LGTM, I spot checked the changed files and ran branch locally and confirmed there were no functional regressions.
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 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.
This comment was marked as resolved.
Sorry, something went wrong.
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}", |
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.
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." |
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.
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.
This comment was marked as resolved.
Sorry, something went wrong.
}) => ( | ||
<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.
This comment was marked as resolved.
Sorry, something went wrong.
target="_window" | ||
href={getDocLink('scriptedFields.painless')} | ||
> | ||
<FormattedMessage id="common.ui.fieldEditor.syntax.defaultLabel.painlessLink" defaultMessage="Painless" /> |
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.
note: same question/note about Painless
here.
language: <EuiCode>{field.lang}</EuiCode>, | ||
painlessLink: ( | ||
<EuiLink target="_window" href={getDocLink('scriptedFields.painless')}> | ||
<FormattedMessage |
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.
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 |
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.
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?
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.
Actually this is the same. Maybe you missed <span>
outside?
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.
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, |
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.
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})', |
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.
question: was there any agreement to change the way we display that link?
💚 Build Succeeded |
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.
LGTM, but please wait for green CI.
💔 Build Failed |
retest |
💚 Build Succeeded |
* 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]>
* 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]>
6.x/6.5: f6f4e68 |
It's integration "Index Patterns" tab and I18n engine
#19729