Kibana Globalization - Phase 1#7545
Conversation
|
Jenkins standing by to test this. If you aren't a maintainer, you can ignore this comment. Someone with commit access, please review this and clear it for Jenkins to run; then say 'jenkins, test it'. |
|
@Bargs, @epixa, @srl295, @shikhasriva: First draft of i18n core plugin. |
src/plugins/i18n/server/i18n.js
Outdated
There was a problem hiding this comment.
unix - may need to rewrite or use another module
There was a problem hiding this comment.
@srl295, good point, thanks. I was having issue previously but may have been that I was using the asynchronous version of 'mkdirp' in a synchronous fashion. I have updated the code now to use 'mkdirp.sync' and is working as expected.
|
@hickeyma I read through the code in the PR. Before I jump into feedback, let me make sure I understand everything correctly. I've written up some notes with my understanding of the API (both JS module and HTTP) thus far: Module API
I'm guessing HTTP API/api/i18n/translations/{plugin} - returns JSON translations based on plugin name and accept header I will add one general note. I'm worried about loading translations per plugin. A plugin might provide a very small piece of a page. For instance, the Visualize page which displays all the visualization types available could be displaying content from many different plugins. So if we're loading translations by plugin, it might take more than 10 round trips to the server to get all of the translations for that page. Unless we end up finding that these translation bundles are huge, I think it makes more sense to load an entire language, for all plugins, in one go. |
|
@Bargs Thanks for the notes; good synopsis. Module APIGood description of the APIs. Additionally,
HTTP APIThis is good feedback that a plugin may not provide all code to a page or multiple pages. If this is the case then it makes sense to have an API which returns all translations bundled for all plugins. I will add this API. |
Probably not, we can always add it if we realize we need it later. Also, btw a PR (#7457) just got merged that gives plugins a dedicated data directory for writing to the filesystem. I think you'll find that helpful in this plugin. |
|
I question the value of the HTTP API at all: can we not just have the kibana server grab translations for the current bundles on load and serve them on the initial request? |
|
@epixa are you suggesting all language translations get built directly into each JS bundle? |
|
No, I think we could serve the current language of the user as javascript in either the html or as a separate js file. In the same way that we serve up details about kibana itself in |
|
I suppose inlining the translations (like |
|
We need the translations when the contents are loading anyway, otherwise we can't translate things like the loading screen or the global error handler (not the angular notifier handler, the more global one). So at the very least, those translations will need to be served up with the HTML. We shouldn't optimize for the experience of switching languages, and I'd prefer to outright eliminate any overhead in maintaining that experience by requiring a page reload. For the vast majority of installs, there will only be a single language configured. Most Kibana installs are private to a company, and most companies either have no use at all for supporting multiple languages or won't be interested in the ongoing burden of maintaining a multiple language install. There are exceptions, of course, but we should be optimizing for the most common usage. |
|
(jumping in midstream…) |
|
But I think that language selection needs to happen during the initial load of the application one way or another, otherwise we can't translate the two screens I mentioned above. I agree that most of the translations can be loaded separately, but at least those translations need to be applied when the initial html is created on the server, so we're already going to need to do language determination at that time. As for a separate request for translations, that really needs to happen during the initial load window (when you see the "one moment please" screen), which means that cannot be initiated from the client-side JS bundles themselves. It must either be embedded into the HTML (which is really only ideal for the very few strings that exist in the global context of the main html) or linked as a script tag along with the other bundles: https://github.com/elastic/kibana/blob/master/src/ui/views/ui_app.jade#L48-L53 |
That's what I thought would happen for initial content. |
@epixa Yeah I see the miscommunication now. When I wrote "HTTP API" in my summary comment, I didn't mean "an API that can only be called via XHR". As I mentioned in this comment, the translations can be served by Hapi just like the static bundles are served by Hapi currently. |
|
A couple more thoughts:
|
|
First draft of an example translation plugin structure: https://github.com/Bargs/management-es At first glance I thought this might work at installation time without any modifications, but upon further inspection I've realized the plugin installer doesn't initialize the plugins, it only creates the js/css bundles. I think we should make it work at install time, so I need to give this some more thought. |
|
So I think we have a couple options.
I'm leaning towards the second option. I think it would be pretty easy to implement and should avoid a lot of complexity at server startup time. What do you think @epixa? |
|
@Bargs I like the example translation plugin structure. I am interested to know more about the "additional plugin lifecycle hook" ! :-) FYI: I have refactored the i18n plugin:
|
|
Unless someone just outright hates the idea of adding an install-time hook to the server boot process that can be enabled in the plugin installer, I'm going to work on a prototype for it. It's a little weird adding it to the KbnServer constructor, but I think it's better than inventing a totally separate mechanism right now. |
|
Here's a rough prototype of what I'm thinking: #7613 |
|
Can one of the admins verify this patch? |
|
@hickeyma to follow up on your question from IRC, you'll want to replace my mock registration here with your actual i18n module. My idea is that within the install hook, plugins can register helper functions (like |
|
@Bargs I thought the mock registration provided some hooks back into the actual call to registerTranslations. Thanks for setting me straight. It worked as expected when I made the change as you suggested. |
|
As promised, here's my first round of feedback. This probably looks like a massive list, but a lot of it is just coding convention stuff to make things more consistent with the rest of Kibana. This list might not be totally comprehensive either, but I wanted to get you some feedback asap so you're not blocked.
|
Moving the i18n module into a class so as to encapsulate the registered translations which means there can be different and distinct instances per process. This is to accomodate the user case where there might be multiple Kibana server instances in a process and the localization should be at the server level.
Message starting with 'Give me a moment...' is no longer part of loading message folowing a rebase with master.
- Update after following review: elastic#7545 (review) - Also, fix syntax mess following rebase with master of src/optimize/index.js
|
jenkins, test it |
|
Code LGTM, let's see what Jenkins thinks! |
|
jenkins, test this |
|
🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 |
|
Hooray!
|
|
Awesome and yes this is just the beginning... but a great start. Looking forward to next steps |
|
Very exciting. Great job on this! |
|
Can one of the admins verify this patch? |
|
great stuff! |
|
Great! |

Phase 1
Purpose
Decide Language for Translation Algorithm
I18n Class
Manages the language translations for Kibana
Responsible for loading translated content per language
The translations file are JSON files with a flat keyspace, where the keys are unique. This uniqueness between translation plugins could be achieved by prefixing the keys with the plugin name. The key signifies the translation ID which would be referenced in translatable files (like JS, HTML etc.).
The key value is the translation string
Example translation JSON file
en.json{ "UI-WELCOME_MESSAGE": "Loading Kibana", "UI-LOADING_MESSAGE": "Give me a moment here. I'm loading a whole bunch of code. Don't worry, all this good stuff will be cached up for next time!", "UI-WELCOME_ERROR": "Kibana did not load properly. Check the server output for more information." }UiI18n Class
I18nclass)accept-language headerto BCP 47 tagsDeliverable
(https://github.com/elastic/kibana/blob/master/src/ui/views/ui_app.jade)
I18nunit testsi18n(<key>)function in the Jade template. A tool can then be used to find such pattern and extract the keys to file.