-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Init I18n before Notifications start #23902
Conversation
…ialized in CoreSystem
src/core/public/core_system.ts
Outdated
const injectedMetadata = this.injectedMetadata.start(); | ||
this.i18nService.start({ injectedMetadata }); |
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.
Initialization of i18n engine should be before Notifications start.
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 like we don't need src/ui/public/chrome/api/translations.js
anymore, can you please remove it (including its usage in src/ui/public/chrome/chrome.js
)?
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.
And I believe usage of i18n.init
in src/ui/ui_render/bootstrap/app_bootstrap.js
(and hence usage of await server.getUiTranslations()
in src/ui/ui_render/ui_render_mixin.js
) isn't not needed anymore as well. Can you please double check and remove everything redundant where possible? With this we'll have just 2 places where we init i18n
- one for server and one for client.
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.
@azasypkin sure.
Done.
src/core/public/i18n/i18n_service.ts
Outdated
injectedMetadata: InjectedMetadataStartContract; | ||
} | ||
export class I18nService { | ||
public start({ injectedMetadata }: Deps) { |
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 method isn't actually a start method, but I named as start
to be consistent with other services.
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 at some point we'll do more than just i18n.init
, so I'm +1 for consistency.
@@ -28,7 +27,4 @@ import { | |||
uiModules.get('i18n') | |||
.provider('i18n', I18nProvider) | |||
.filter('i18n', i18nFilter) | |||
.directive('i18nId', i18nDirective) | |||
.config((i18nProvider) => { | |||
i18nProvider.init(metadata.translations); |
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 removed initialization of i18n
from here, because it will be already initialized at very beginning of loading application (https://github.com/elastic/kibana/pull/23902/files#diff-ac3204e754680bbed67c8193da8cc11bR103)
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, just a bunch of nits here and there.
@spalger could you please let us know if this PR looks good to you (it touches CoreSystem)?
packages/kbn-i18n/src/index.ts
Outdated
@@ -22,3 +22,4 @@ import * as loader from './loader'; | |||
|
|||
export const i18n = i18nCore; | |||
export const i18nLoader = loader; | |||
export { PlainMessages } from './messages'; |
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: We'll eventually rename PlainMessages
to something that is clearer in one of the upcoming PRs (I believe there is one is ready for review already).
src/core/public/i18n/i18n_service.ts
Outdated
injectedMetadata: InjectedMetadataStartContract; | ||
} | ||
export class I18nService { | ||
public start({ injectedMetadata }: Deps) { |
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 at some point we'll do more than just i18n.init
, so I'm +1 for consistency.
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
const mockI18n = jest.fn(); |
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: same nit about new lines here as well, + new line before beforeEach
, it
etc.
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
const mockI18n = jest.fn(); |
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: maybe mockI18nInit
to make it clearer what we actually mock.
const i18nService = new I18nService(); | ||
expect(mockI18n).not.toHaveBeenCalled(); | ||
i18nService.start({ injectedMetadata }); | ||
expect(mockI18n.mock.calls).toMatchSnapshot(); |
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: for such small snapshots I'd better use toMatchInlineSnapshot
or even better something like this:
expect(mockI18nInit).toHaveBeenCalledTimes(1);
expect(mockI18nInit).toHaveBeenCalledWith(translations);
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.
Thank you, done.
src/core/public/core_system.ts
Outdated
const injectedMetadata = this.injectedMetadata.start(); | ||
this.i18nService.start({ injectedMetadata }); |
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 like we don't need src/ui/public/chrome/api/translations.js
anymore, can you please remove it (including its usage in src/ui/public/chrome/chrome.js
)?
src/core/public/core_system.ts
Outdated
const injectedMetadata = this.injectedMetadata.start(); | ||
this.i18nService.start({ injectedMetadata }); |
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.
And I believe usage of i18n.init
in src/ui/ui_render/bootstrap/app_bootstrap.js
(and hence usage of await server.getUiTranslations()
in src/ui/ui_render/ui_render_mixin.js
) isn't not needed anymore as well. Can you please double check and remove everything redundant where possible? With this we'll have just 2 places where we init i18n
- one for server and one for client.
…pBootstrap were changed
💚 Build Succeeded |
src/core/public/i18n/i18n_service.ts
Outdated
|
||
export class I18nService { | ||
public start({ injectedMetadata }: Deps) { | ||
i18n.init(injectedMetadata.getLegacyMetadata().translations); |
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 took me a while to track this down and figure out how everything was taking advantage of the translations without consuming the new platform at all, turns out it's because we are just using new platform constructs to store the translations in @kbn/i18n
module. Based on this I don't think the I18nService
is necessary, and I don't really think this does what we want for the new platform.
I'm down to move this to the new platform, but if we are going to do that then we should be instantiating something that will wrap the translations
, and exposing that on the I18nService
start contract, not by caching the state in @kbn/i18n
.
In order to address https://github.com/elastic/kibana/pull/23603/files#r225105739 all we would really need to do is move the call to i18n.init()
out of an angular .config()
function, and we can just do that by adding it to src/ui/public/i18n/index.js
for now until we want to move @kbn/i18n
fully to the new platform:
diff --git a/src/ui/public/chrome/chrome.js b/src/ui/public/chrome/chrome.js
index cfae977feb..fe0cc3011f 100644
--- a/src/ui/public/chrome/chrome.js
+++ b/src/ui/public/chrome/chrome.js
@@ -21,6 +21,7 @@ import _ from 'lodash';
import angular from 'angular';
import { metadata } from '../metadata';
+import '../i18n';
import '../state_management/global_state';
import '../config';
import '../notify';
diff --git a/src/ui/public/i18n/index.js b/src/ui/public/i18n/index.js
index 5def86410e..1f4b435f61 100644
--- a/src/ui/public/i18n/index.js
+++ b/src/ui/public/i18n/index.js
@@ -18,12 +18,16 @@
*/
import { uiModules } from 'ui/modules';
+import { metadata } from 'ui/metadata';
+import { i18n } from '@kbn/i18n';
import {
I18nProvider,
i18nFilter,
i18nDirective,
} from '@kbn/i18n/angular';
+i18n.init(metadata.translations);
+
uiModules.get('i18n')
.provider('i18n', I18nProvider)
.filter('i18n', i18nFilter)
(or something like that)
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.
@spalger The main reason for this PR is that Notifications template is rendered earlier than i18n
is initialized with specified locale.
It's important because to make labels, passing in Notifications, translatable we should wrap Notifications template by I18nProvider
https://github.com/elastic/kibana/pull/22757/files#diff-53c9b70520405921f846a26c104aeb23R40 which is used to setup the i18n context for a tree. And in the case when we setup the locale in src/ui/public/i18n/index.js
, the i18n context for Notifications will be defined with a default locale not counting the data specified in src/ui/public/i18n/index.js
.
Here the order of files loading:
That's why I placed i18n
initialization just before Notifications template is rendered.
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.
Okay, I didn't see that we were going to start consuming <I18nProvider />
from the new platform. In that case, can we just move the init() call to the entry file so it's initialized before any other code is run? I just don't want to have an i18n service in the new platform unless it's useful, and I don't think this version is really there.
diff --git a/src/ui/ui_bundles/app_entry_template.js b/src/ui/ui_bundles/app_entry_template.js
index 764e70eaa1..a74ef61848 100644
--- a/src/ui/ui_bundles/app_entry_template.js
+++ b/src/ui/ui_bundles/app_entry_template.js
@@ -33,10 +33,15 @@ import 'whatwg-fetch';
import 'abortcontroller-polyfill';
import 'childnode-remove-polyfill';
+import { i18n } from '@kbn/i18n';
import { CoreSystem } from '__kibanaCore__'
+const injectedMetadata = JSON.parse(document.querySelector('kbn-injected-metadata').getAttribute('data'));
+i18n.init(injectedMetadata.legacyMetadata.translations);
+
new CoreSystem({
- injectedMetadata: JSON.parse(document.querySelector('kbn-injected-metadata').getAttribute('data')),
+ injectedMetadata: injectedMetadata,
rootDomElement: document.body,
requireLegacyFiles: () => {
${bundle.getRequires().join('\n ')}
💚 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 don't have any translations to test, but the logic looks good!
@spalger I've checked this code with translations. |
* Init I18n before Notifications start * Remove i18n initialization in AngularJS since it will be already initialized in CoreSystem * Remove unused translationsApi * Remove redundant i18n.init invocation * Remove i18n tests since i18n.init was removed and input params for AppBootstrap were changed * Move i18n initialization to the entry file.
* Init I18n before Notifications start * Remove i18n initialization in AngularJS since it will be already initialized in CoreSystem * Remove unused translationsApi * Remove redundant i18n.init invocation * Remove i18n tests since i18n.init was removed and input params for AppBootstrap were changed * Move i18n initialization to the entry file.
Issue: Since Notifications are rendered before i18n engine initializing with specified locale, labels in Notifications are not localized with the specified locale, they are displayed in default locale.
Solution: initialize i18n engine before Notifications are rendered.
Fixed: #23903
With this fix there will be no need for wrapping constants with translated labels into a function in client code. Like I'm trying to make translations to work here and here
In addition I found out that these, these and these translations are currently broken without this fix.