-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
i18n: add i18n for LighthouseError messages #6457
Conversation
@@ -173,7 +173,7 @@ class GatherRunner { | |||
const insecureDescriptions = explanations | |||
.filter(exp => exp.securityState === 'insecure') | |||
.map(exp => exp.description); | |||
errorDef.message += ` ${insecureDescriptions.join(' ')}`; | |||
errorDef.substitute = `${insecureDescriptions.join(' ')}`; |
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 join
seems like it could be a problem. Are these descriptions localized by chrome?
lighthouse-core/lib/lh-error.js
Outdated
@@ -24,7 +59,7 @@ class LighthouseError extends Error { | |||
super(errorDefinition.code); | |||
this.name = 'LHError'; | |||
this.code = errorDefinition.code; | |||
this.friendlyMessage = errorDefinition.message; | |||
this.friendlyMessage = str_(errorDefinition.message, errorDefinition); |
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.
@patrickhulce @brendankenny is this what you had in mind?
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.
perfect 👌
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.
What if the second argument to the LHError
constructor becomes the replacement values? I feel like it would be conceptually easier to understand without having all of it on the first argument and
const err = new LHError(
LHError.errors.PROTOCOL_TIMEOUT,
protocolMethod: `${method}`,
);
reject(err);
is a lot easier to understand at a glance than
const err = new LHError({
...LHError.errors.PROTOCOL_TIMEOUT,
protocolMethod: `${method}`,
});
reject(err);
I was going to say ideally we'd do this but the existing properties
second arg makes that a problem, but I think it's actually fine. The only place we ever use that argument is in this file for fromProtocolMessage()
, and we use it for protocolMethod
and protocolError
, one of which is already an icu argument name :)
What if properties
just did both? It puts its properties on the error object (as it does now), and it gets passed into str_
(as errorDefinition
is doing here).
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 later on we should do stricter type checking...if you use a string that needs a replacement, you should have to provide the replacement
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.
love the new naming, thanks so much @exterkamp!
lighthouse-core/lib/lh-error.js
Outdated
@@ -24,7 +59,7 @@ class LighthouseError extends Error { | |||
super(errorDefinition.code); | |||
this.name = 'LHError'; | |||
this.code = errorDefinition.code; | |||
this.friendlyMessage = errorDefinition.message; | |||
this.friendlyMessage = str_(errorDefinition.message, errorDefinition); |
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.
perfect 👌
@@ -1059,7 +1062,8 @@ describe('GatherRunner', function() { | |||
config: new Config({}), | |||
}).then(artifacts => { | |||
assert.equal(artifacts.LighthouseRunWarnings.length, 1); | |||
assert.ok(/unable.*load the page/.test(artifacts.LighthouseRunWarnings[0])); | |||
expect(artifacts.LighthouseRunWarnings[0]) |
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.
at this stage don't we want to assert that the string itself has already gone through the i18n process and is just a normal string?
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 it was already doing that? I might not get what you're implying. I made the check more accurate since the regex was a little plain.
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.
well I mean that toBeDisplayString
does the whole getFormatted
dance for you, so I'm thinkin' we want at least one test that checks if our code is using getFormatted
at all the right places.
but maybe I'm misunderstanding or we haven't decided to have the strings in artifacts be pre-resolved yet and the test you added in runner-test
is good enough for now?
hope that makes more sense
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.
Oh I think I get what you're saying, we should check that the translation did actually get filled in and we don't expose any un-translated strings to the user, right?
I think that the test in runner captures the only new place we have translation. Everything here is translated at the same time all other lhr strings are. Do we have some coverage for that/should we add some for these new strings?
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 exactly. I was somewhat wondering outloud if the artifacts
is one new place we should do the translation.
lighthouse-core/lib/lh-error.js
Outdated
@@ -24,7 +59,7 @@ class LighthouseError extends Error { | |||
super(errorDefinition.code); | |||
this.name = 'LHError'; | |||
this.code = errorDefinition.code; | |||
this.friendlyMessage = errorDefinition.message; | |||
this.friendlyMessage = str_(errorDefinition.message, errorDefinition); |
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.
What if the second argument to the LHError
constructor becomes the replacement values? I feel like it would be conceptually easier to understand without having all of it on the first argument and
const err = new LHError(
LHError.errors.PROTOCOL_TIMEOUT,
protocolMethod: `${method}`,
);
reject(err);
is a lot easier to understand at a glance than
const err = new LHError({
...LHError.errors.PROTOCOL_TIMEOUT,
protocolMethod: `${method}`,
});
reject(err);
I was going to say ideally we'd do this but the existing properties
second arg makes that a problem, but I think it's actually fine. The only place we ever use that argument is in this file for fromProtocolMessage()
, and we use it for protocolMethod
and protocolError
, one of which is already an icu argument name :)
What if properties
just did both? It puts its properties on the error object (as it does now), and it gets passed into str_
(as errorDefinition
is doing here).
lighthouse-core/lib/lh-error.js
Outdated
@@ -24,7 +59,7 @@ class LighthouseError extends Error { | |||
super(errorDefinition.code); | |||
this.name = 'LHError'; | |||
this.code = errorDefinition.code; | |||
this.friendlyMessage = errorDefinition.message; | |||
this.friendlyMessage = str_(errorDefinition.message, errorDefinition); |
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 later on we should do stricter type checking...if you use a string that needs a replacement, you should have to provide the replacement
lighthouse-core/lib/lh-error.js
Outdated
lhrRuntimeError: true, | ||
errorDetails: 'No Failure Description Loaded.', |
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.
do we want defaults for these? What happens if you don't provide them? Throwing if you don't provide one seems ideal
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 the ICU message translator throws. With a 'value that wasn't replaced', good point, we probably do want to throw in order to avoid a silent lack of real replacement.
ready for review? |
Not ready to review yet 😄 should land #6579 first and then merge those changes in and update to i18n that new error! |
Should be g2g, ptal |
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 % nits!
errorDef.message += ` ${netErr}.`; | ||
return new LHError( | ||
LHError.errors.FAILED_DOCUMENT_REQUEST, | ||
{errorDetails: `${netErr}`} |
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.
do these still need to be in string templates?
const UIStrings = { | ||
/** Error message explaining that the Lighthouse run was not able to collect screenshots through Chrome.*/ | ||
didntCollectScreenshots: `Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse.`, | ||
/** Error message explaining that the network trace was not able to be recorded for the Lighthouse run. */ |
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 for some of these descriptions we should include for the translators the distinction of whether it was something weird that retrying should fix, or something that the user needs to fix and try again? I'm thinking a stock explanation.
This is an error message that was because of certain user conditions they must fix before retrying.
vs.
This is an error message that was because of irregularities with Lighthouse that should be fixed by trying again.
just spitballin'
lhrRuntimeError: true, | ||
}, | ||
/* Used when security error prevents page load. */ | ||
/* Used when security error prevents page load. | ||
* Requires an additional `securityMessages` field for translation. |
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 feel like we're going to forget to update these if they ever change, but I'm not sure what to do about 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.
Well the current plan is that if we change them, then there will be a ton of errors thrown from str_ because it is missing the required substitution fields. But I'm not sure that's a long term strategy.
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.
we could maybe figure out something with typescript, but I can't think of a way without keeping a manual list of error codes that will require an extra field.
@exterkamp would you want to do that? or wait on it.
main issue with
there will be a ton of errors thrown from str_
is we need to make sure error cases are getting hit in unit tests and that the unit tests aren't testing for any throw, since str_
errors would fit that bill
lighthouse-core/test/runner-test.js
Outdated
} catch (err) { | ||
assert.equal(err.code, LHError.errors.PROTOCOL_TIMEOUT.code); | ||
assert.ok(/^Waiting for DevTools protocol.*Method: Method.Failure/.test(err.friendlyMessage), | ||
'should have prevented run'); |
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 have a localized error message
:)
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.
Oh I see now my comment was confusing! I was suggesting to change the failure message to should have a localized error message
not to change the test :)
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.
Hold up a sec, maybe we forgot something for LR? Travis is unhappy with runLighthouseInLR https://travis-ci.org/GoogleChrome/lighthouse/builds/460924770#L1067
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!
lighthouse-core/test/runner-test.js
Outdated
} catch (err) { | ||
assert.equal(err.code, LHError.errors.PROTOCOL_TIMEOUT.code); | ||
assert.ok(/^Waiting for DevTools protocol.*Method: Method.Failure/.test(err.friendlyMessage), | ||
'should have prevented run'); |
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.
Oh I see now my comment was confusing! I was suggesting to change the failure message to should have a localized error message
not to change the test :)
Co-Authored-By: exterkamp <[email protected]>
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
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.
really liking this last form for the LHError
constructor.
Mostly some style nits and two bigger questions left from me
lighthouse-core/gather/driver.js
Outdated
const asyncTimeout = setTimeout((_ => { | ||
const err = new LHError( | ||
LHError.errors.PROTOCOL_TIMEOUT, | ||
{protocolMethod: `${method}`} |
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.
can drop the template string.
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.
optional style nit: a lot of these new LHError()
lines could also fit on one line now. Was it intentional breaking them up over 4? I feel like they're more readable on one, but understand if you feel otherwise
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.
Personally I like splitting complex constructors into lines, and with it all on one line it skirts the line of es-lint yelling that the lines are too long. I feel like 4 lines is more readable than crammed onto 1.
@@ -24,7 +57,7 @@ class LighthouseError extends Error { | |||
super(errorDefinition.code); | |||
this.name = 'LHError'; | |||
this.code = errorDefinition.code; | |||
this.friendlyMessage = errorDefinition.message; | |||
this.friendlyMessage = str_(errorDefinition.message, properties); |
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.
🎉
lhrRuntimeError: true, | ||
}, | ||
/* Used when security error prevents page load. */ | ||
/* Used when security error prevents page load. | ||
* Requires an additional `securityMessages` field for translation. |
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.
we could maybe figure out something with typescript, but I can't think of a way without keeping a manual list of error codes that will require an extra field.
@exterkamp would you want to do that? or wait on it.
main issue with
there will be a ton of errors thrown from str_
is we need to make sure error cases are getting hit in unit tests and that the unit tests aren't testing for any throw, since str_
errors would fit that bill
const connectionError = new LHError( | ||
LHError.errors.FAILED_DOCUMENT_REQUEST, | ||
{errorDetails: 'Bad connection req'} | ||
); |
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.
what happens with the parsedResult.runtimeError.message.includes
check below? Are they expected to be localized by that point? Can we assert that? (and can we check that the errorDetails
replacement worked)?
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 that is what the includes checks, that the runtime message in the end is the same as the orig friendly msg post a round of translation since it is outside of the Runner.run which translates errors before it exits. It uses the includes instead of equal b/c LR appends the msg to the friendly msg which may not be desired? It's the first I'm really seeing 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.
I had noticed that runLighthouseInLR
doesn't run i18n on its generated output, hence the question, but the new err.friendlyMessage = i18n.getFormatted(err.friendlyMessage, settings.locale);
line in runner.js
translates the error friendlyMessage
before it gets back to runLighthouseInLR
, so localization is good to go!
if (!mainRecord) { | ||
errorDef = LHError.errors.NO_DOCUMENT_REQUEST; | ||
return new LHError(LHError.errors.NO_DOCUMENT_REQUEST); |
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.
🎉
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.
Digging it. small tweaks but I like the overall.
Added paulirish's suggestions for i18n strings. Co-Authored-By: exterkamp <[email protected]>
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!
Summary
Adds i18n strings for LighthouseError messages. Adds support for substituting in values into an error message through i18n UIString.
Related Issues/PRs
fixes: #6441