Generator-jhipster: Page titles are not translated the first time

Created on 2 Feb 2017  路  12Comments  路  Source: jhipster/generator-jhipster

Steps to reproduce:

Login to https://jhipster-4-demo.herokuapp.com/ with user/user.

Click on Entities > Blog and notice how the page title is translation-not-found[blogApp.blog.home.title].

translation-not-found-blog

Refresh your browser and it renders properly.

translation-found-after-refresh

Click on Entities > Entry and see the same behavior.

translation-not-found-entry

minor angular

All 12 comments

This looks like an asynchronous issue, maybe related to Observable in TranslatePartialLoader when it combines partial translations for newly visited entity page with already loaded transaltions.

I replaced ng-jhipster MissingTranslationHandler by mine which logs on console.

I get many missing translations logged (twice per menu item) when I go from an entity page to home page even though the page displays correctly.
Also in the log below, you can see the request to get the json translation.


Console output

XHR finished loading: GET "http://localhost:9000/i18n/en/home.json".
missing-i18n.ts:5 missing translation footer
missing-i18n.ts:5 missing translation footer
missing-i18n.ts:5 missing translation global.menu.account.main
missing-i18n.ts:5 missing translation global.menu.account.main
missing-i18n.ts:5 missing translation global.title
missing-i18n.ts:5 missing translation global.title
missing-i18n.ts:5 missing translation global.menu.home
missing-i18n.ts:5 missing translation global.menu.home
missing-i18n.ts:5 missing translation global.menu.language
missing-i18n.ts:5 missing translation global.menu.language
missing-i18n.ts:5 missing translation global.ribbon.dev
missing-i18n.ts:5 missing translation global.ribbon.dev
missing-i18n.ts:5 missing translation global.menu.entities.main
missing-i18n.ts:5 missing translation global.menu.entities.main
missing-i18n.ts:5 missing translation global.menu.entities.rankingList
missing-i18n.ts:5 missing translation global.menu.entities.rankingList
missing-i18n.ts:5 missing translation global.menu.entities.tournamentType
missing-i18n.ts:5 missing translation global.menu.entities.tournamentType
missing-i18n.ts:5 missing translation global.menu.entities.tournament
missing-i18n.ts:5 missing translation global.menu.entities.tournament
missing-i18n.ts:5 missing translation global.menu.entities.countryMedal
missing-i18n.ts:5 missing translation global.menu.entities.countryMedal
missing-i18n.ts:5 missing translation global.menu.entities.medal
missing-i18n.ts:5 missing translation global.menu.entities.medal
missing-i18n.ts:5 missing translation global.menu.entities.doubleMatch
missing-i18n.ts:5 missing translation global.menu.entities.doubleMatch
missing-i18n.ts:5 missing translation global.menu.entities.singleMatch
missing-i18n.ts:5 missing translation global.menu.entities.singleMatch
missing-i18n.ts:5 missing translation global.menu.entities.player
missing-i18n.ts:5 missing translation global.menu.entities.player
missing-i18n.ts:5 missing translation global.menu.entities.ratingMovement
missing-i18n.ts:5 missing translation global.menu.entities.ratingMovement
missing-i18n.ts:5 missing translation global.menu.entities.tournamentPlayer
missing-i18n.ts:5 missing translation global.menu.entities.tournamentPlayer
missing-i18n.ts:5 missing translation global.menu.entities.rating
missing-i18n.ts:5 missing translation global.menu.entities.rating
missing-i18n.ts:5 missing translation global.menu.admin.database
missing-i18n.ts:5 missing translation global.menu.admin.database
missing-i18n.ts:5 missing translation global.menu.admin.main
missing-i18n.ts:5 missing translation global.menu.admin.main
missing-i18n.ts:5 missing translation global.menu.admin.userManagement
missing-i18n.ts:5 missing translation global.menu.admin.userManagement
missing-i18n.ts:5 missing translation global.menu.admin.metrics
missing-i18n.ts:5 missing translation global.menu.admin.metrics
missing-i18n.ts:5 missing translation global.menu.admin.health
missing-i18n.ts:5 missing translation global.menu.admin.health
missing-i18n.ts:5 missing translation global.menu.admin.configuration
missing-i18n.ts:5 missing translation global.menu.admin.configuration
missing-i18n.ts:5 missing translation global.menu.admin.audits
missing-i18n.ts:5 missing translation global.menu.admin.audits
missing-i18n.ts:5 missing translation global.menu.admin.logs
missing-i18n.ts:5 missing translation global.menu.admin.logs
missing-i18n.ts:5 missing translation global.menu.account.settings
missing-i18n.ts:5 missing translation global.menu.account.settings
missing-i18n.ts:5 missing translation global.menu.account.password
missing-i18n.ts:5 missing translation global.menu.account.password
missing-i18n.ts:5 missing translation global.menu.account.logout
missing-i18n.ts:5 missing translation global.menu.account.logout
missing-i18n.ts:5 missing translation global.menu.admin.apidocs
missing-i18n.ts:5 missing translation global.menu.admin.apidocs
XHR finished loading: GET "http://localhost:9000/i18n/en/global.json".

One way to simplify our TranslateLoader and to avoid partial async loading would be to merge all our i18n JSON files per language, this way we would load all translations at once.

I have been able to do it using webpack core json-loader and a plugin: merge-jsons-webpack-plugin

~~~js
const MergeJsonWebpackPlugin = require("merge-jsons-webpack-plugin");

...

            {   
                // Load i18n files
                test: /\.json$/,
                loader: 'json-loader',
                include: path.resolve('./src/main/webapp/i18n')
            },

...

        // Merge i18n files per language
        new MergeJsonWebpackPlugin({
            'output': {
                'groupBy':[
                    { 
                        'pattern': './src/main/webapp/i18n/en/*.json', 
                        'fileName' : './target/www/i18n/en.json'
                    },
                    { 
                        'pattern': './src/main/webapp/i18n/fr/*.json', 
                        'fileName' : './target/www/i18n/fr.json'
                    },
                ]        
            }
        }),

~~~

I am also investigating an alternative with #5072.

I think I found why pageTitle is not translated first time.

pageTitle is set on NavigationEnd event so before reaching the entity component, the location for translations related to this entity is added in the constructor of the component using jhiLanguageService.setLocations() so it's too late.

A solution for this would be to call jhiLanguageService.setLocations() in a CanActivate guard but I prefer to go with my proposition to use webpack merging json files because it will simplify things and be more performant too.

@deepu105 as you coded the TranslatePartialLoader, what's your opinion?

Yes another caveat of ng router as we used to do it in ui router resolve b4
and worked well.

Also ok to serve a merged json if possible but it would be nice to keep the
files separated for dev else it will endup becoming a single huge file

Thanks & regards,
Deepu

I tried to define a componentless parent route where to add the resolve. It worked fine except for popup routes where I could not remove the auxilliary route from url upon closing the modal. This looks like a bug of the router in ApplyRedirects, I may try to add a unit test to report the issue.

One way to simplify our TranslateLoader and to avoid partial async loading would be to merge all >our i18n JSON files per language, this way we would load all translations at once.

This should probably solve one problem I had. From entity A dialog (non modal page) open a modal dialog for (a new) entity B - that causes the non modal page texts (under the popup) to change to "translation not found"...

I solved it by adding locations for both entities, ie:

jhiLanguageService.setLocations(['A', 'B']);

Good point, we already had to add more locations for social signin for same reason: a view aggregates messages from several i18n files (different entities or different features).

While your case could probably easily be addressed at generation time because we know all entities related to the current entity and so could call setLocations() with correct list, it's very likely that we cannot guess what kind of aggregations our users will build so we could make their life simpler by having a full i18n bundle per language.

@mraible This is not happening in the current build. I believe this can be closed.

Tested with JHipster v4.0.8 via https://github.com/mraible/jhipster4-demo and it appears to be fixed.

@gmarziou Is it possible to implement this solution in the existing JHipster project? I have successfully combined JSON files using configuration you provided, but it still searches for the translation files by component name..
I also removed from the webpack.common.js under CopyWebpackPlugin line { from: './src/main/webapp/i18n', to: 'i18n' }.

I get: http://localhost:9000/i18n/en/global.json 404 (Not Found) error, and like that for every translation file..

It is really annoying because I am using nested components and translation only loads for the last imported component.. For parent component I get translation-not-found error.. So, I have to use combined file..

Have you checked #5689 ?

@gmarziou Didn't see that.. :) It took me a few hours to solve conflicts but after upgrade everything works fine.. Thanks..! :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

marcelinobadin picture marcelinobadin  路  3Comments

pascalgrimaud picture pascalgrimaud  路  4Comments

DanielFran picture DanielFran  路  3Comments

chegola picture chegola  路  4Comments

Steven-Garcia picture Steven-Garcia  路  3Comments