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

[CCR] i18n feedback #30028

Merged
merged 8 commits into from
Feb 15, 2019
Merged

[CCR] i18n feedback #30028

merged 8 commits into from
Feb 15, 2019

Conversation

cjcenizal
Copy link
Contributor

@cjcenizal cjcenizal commented Feb 5, 2019

Addresses feedback from #27936 (review).

jscodeshift

I used jscodeshift to convert from intl.formatMessage to i18n.translate. I installed the tool and used this command to apply the codemod:

jscodeshift -t=path/to/intlFormatMessageToi18nTranslate.js /path/to/kibana/x-pack/plugins/cross_cluster_replication/public/app

Codemod

Here's the contents of intlFormatMessageToi18nTranslate.js:

export default function transformer(file, api) {
  const j = api.jscodeshift;
  const root = j(file.source);
  const intlCalls = root.find(j.CallExpression, {
    callee: {
      object: {
        name: 'intl'
      },
      property: {
        name: 'formatMessage'
      }
    }
  });

  intlCalls.forEach(({ node }) => {
    node.callee.object.name = 'i18n';
    node.callee.property.name = 'translate';

    const id = node.arguments[0].properties.find(prop => {
      return prop.key.name === 'id';
    }).value.value;

    const defaultMessageNode = node.arguments[0].properties.find(prop => {
      return prop.key.name === 'defaultMessage';
    });

    const defaultMessage = typeof defaultMessageNode.value.value === 'string'
      ? defaultMessageNode.value.value
      : defaultMessageNode.value.quasis[0].value.raw;

    const values = node.arguments[1];

    const args = [
      j.property(
        'init',
        j.identifier('defaultMessage'),
        j.literal(defaultMessage)
      )
    ];

    if (!!values) {
      args.push(j.property(
        'init',
        j.identifier('values'),
        values
      ));
    }

    const config = j.objectExpression(args);
    node.arguments = [`'${id}'`, config];
  });

  return root.toSource();
};

Resources

@cjcenizal cjcenizal added Project:i18n Feature:CCR and Remote Clusters Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more labels Feb 5, 2019
@elasticmachine
Copy link
Contributor

Pinging @elastic/es-ui

@sebelga
Copy link
Contributor

sebelga commented Feb 5, 2019

I would not have mixed the i18n changes requested with the huge refactor for a future deprecation of inject18n one day before FF. It is very hard to review and we have very little time to test and discover anything that might have been left. Is there a way we could have 2 PRs and only merge before FF the i18n issue and not the implementation?

I guess you double checked with @jen-huang and we don't have any opened PR on our feature branch to avoid conflict nightmare 😊

Note: don't misunderstand me, I think this jscodeshift is awesome and you did an amazing job with it (very nice resources!), just that it seems like a lot of changes at this stage.

@cjcenizal
Copy link
Contributor Author

cjcenizal commented Feb 5, 2019

@sebelga To make the review easier to manage you can set GitHub to ignore whitespace. Here's a quick link to the diff with whitepsace ignored: https://github.com/elastic/kibana/pull/30028/files?w=1. Does this help?

For any open PRs, we'll resolve merge conflicts either on this branch or on the other -- I'll be happy to take on that responsibility. 😄

@cjcenizal cjcenizal changed the base branch from feature/ccr to master February 5, 2019 22:33
@elasticmachine
Copy link
Contributor

💔 Build Failed

Copy link
Contributor

@maryia-lapata maryia-lapata 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 I'd like to ask to replace double quotes with single quotes for defaultMessage values in i18n.translate just to be consistent.

Thank you for jscodeshift!

const errorMsg = i18n.translate(
'xpack.crossClusterReplication.autoFollowPatternForm.leaderIndexPatternError.duplicateMessage',
{
defaultMessage: "Duplicate leader index pattern aren't allowed."
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just to be consistent

Suggested change
defaultMessage: "Duplicate leader index pattern aren't allowed."
defaultMessage: `Duplicate leader index pattern aren't allowed.`

placeholder={i18n.translate(
'xpack.crossClusterReplication.autoFollowPatternForm.fieldLeaderIndexPatternsPlaceholder',
{
defaultMessage: "Type and then hit ENTER"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
defaultMessage: "Type and then hit ENTER"
defaultMessage: 'Type and then hit ENTER'

Copy link
Contributor

Choose a reason for hiding this comment

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

@mayya-sharipova on your previous comment you suggested the ` character and there the ' 😊 Which one should be use best?

const title = i18n.translate(
'xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewTitle',
{
defaultMessage: "Index name examples"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
defaultMessage: "Index name examples"
defaultMessage: 'Index name examples'

Copy link
Contributor

Choose a reason for hiding this comment

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

Apparently the single quote.

@@ -18,7 +19,7 @@ import routing from '../services/routing';
import { resumeFollowerIndex } from '../store/actions';
import { arrify } from '../../../common/services/utils';

class Provider extends PureComponent {
class FollowerIndexResumeProviderUi extends PureComponent {
Copy link
Contributor

Choose a reason for hiding this comment

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

We used Ui (or Component) postfix to differ the initial component and the wrapper: ComponentName = injectI18n(ComponentNameUi).
Since we are getting rid of injectI18n, we can remove Ui at the end of class name.
But it's up to you, you can leave it as well.

) : i18n.translate(
'xpack.crossClusterReplication.unfollowLeaderIndex.confirmModal.unfollowMultipleTitle',
{
defaultMessage: `Unfollow {count} leader indices?`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
defaultMessage: `Unfollow {count} leader indices?`,
defaultMessage: 'Unfollow {count} leader indices?',

Copy link
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

LGTM! Great job on this. It was indeed much easier to review without the white spacing. 😊

placeholder={i18n.translate(
'xpack.crossClusterReplication.autoFollowPatternForm.fieldLeaderIndexPatternsPlaceholder',
{
defaultMessage: "Type and then hit ENTER"
Copy link
Contributor

Choose a reason for hiding this comment

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

@mayya-sharipova on your previous comment you suggested the ` character and there the ' 😊 Which one should be use best?

const title = i18n.translate(
'xpack.crossClusterReplication.autoFollowPatternForm.indicesPreviewTitle',
{
defaultMessage: "Index name examples"
Copy link
Contributor

Choose a reason for hiding this comment

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

Apparently the single quote.

follower index is synchronized with the leader index; when the timeout has elapsed, the
poll for operations will return to the follower so that it can update some statistics, and
then the follower will immediately attempt to read from the leader again.`
defaultMessage: 'The maximum time to wait for new operations on the remote cluster when the ' +
Copy link
Contributor

Choose a reason for hiding this comment

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

@maryia-lapata The fact that we can't use template literals for multiple lines, is it because the translators don't have the text wrapped in their translation tool? It seems like going backward for us 😊 (as template literals were brought to solve this concatenating problem)

@maryia-lapata
Copy link
Contributor

@sebelga we added backtick strings support to avoid escaping single quotes in defaultMessage. The concatenation of static strings is preferable because backtick strings will insert a \n for every line break and this won't work in places where this \n will actually be rendered (e.g. because of using the translated string in console.log or a <pre> tag).

So the choice path is the following:

  • we use backtick strings in JS in case defaultMessage contains single quotes ':
    i18n.translate('someId', { defaultMessage: `This's a label` })
  • we use single quotes in JS otherwise:
    i18n.translate('someId', { defaultMessage: 'This is a label' })
  • we use double quotes in JSX and HTML:
    <FormattedMessage id="someId" defaultMessage="This is a label"/>
    <span i18n-id="someId" i18n-default-message="This is a label"></span>

Sorry if my comments misled you :)

@sebelga
Copy link
Contributor

sebelga commented Feb 8, 2019

Ok thanks @maryia-lapata for the explanation. Why not use backtick strings in JS everywhere (apart from multiline)?

Aso, would something like this be ok?

defaultMessage: ['Some very long text',
'that should wrap on multiple lines',
'like this text here'].join(' ')

@maryia-lapata
Copy link
Contributor

@sebelga it should be taken into account that all labels are extracted into JSON file to pass it to vendors.i18n validation tool validates and extracts IDs, default messages and descriptions only if they are defined statically and together, otherwise it will fail. The defaultMessage has limitation: it must be string literals, template literals w/o expressions or string-only concatenation expressions, anything else is not allowed. That's why [...].join(' ') won't work.

Since expressions aren't allowed in template literals (

`Hello ${name}`
), I would recommend using backtick strings only for strings with single quotes (for which they were allowed) and not confusing others that such string can be a real template literal (in case someone will need to change label without diving into i18n engine and ICU format).
Anyway it's allowed to use backticks for all labels in defaultMessage.

@sebelga
Copy link
Contributor

sebelga commented Feb 8, 2019

Perfect, thanks @maryia-lapata for clarifying!

@cjcenizal
Copy link
Contributor Author

Thanks for the reviews @maryia-lapata and @sebelga! Maryia, I've removed the use of double quotes; thanks for catching that.

@elasticmachine
Copy link
Contributor

💔 Build Failed

@cjcenizal
Copy link
Contributor Author

Retest

@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

@maryia-lapata
Copy link
Contributor

@cjcenizal there was changes in i18n tool in #30378, so now build fails when there are unused translations in zh-CN.json file (which was added as well). I guess it's caused by renaming IDs.
The following command should fix unused translations:

$ node scripts/i18n_check.js --fix

@cjcenizal
Copy link
Contributor Author

Thanks @maryia-lapata! I'll try that.

@cjcenizal
Copy link
Contributor Author

@maryia-lapata I removed a few unused Chinese translations. Can you take a look and let me know if this looks right to you?

@elasticmachine
Copy link
Contributor

💔 Build Failed

@cjcenizal
Copy link
Contributor Author

Retest

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@cjcenizal cjcenizal merged commit 1d2a6fa into elastic:master Feb 15, 2019
@cjcenizal cjcenizal deleted the ccr/i18n-feedback branch February 15, 2019 01:37
cjcenizal added a commit to cjcenizal/kibana that referenced this pull request Feb 15, 2019
* Remove unused Chinese translations.
cjcenizal added a commit that referenced this pull request Feb 15, 2019
* Remove unused Chinese translations.
@cjcenizal cjcenizal added the non-issue Indicates to automation that a pull request should not appear in the release notes label May 7, 2019
@elasticmachine
Copy link
Contributor

💔 Build Failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:CCR and Remote Clusters non-issue Indicates to automation that a pull request should not appear in the release notes Project:i18n Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more v7.2.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants