JSON files are not loading in ng2-translate with webpack - javascript

I'm trying to implement ng2-translate i18n.
dashboard.component.ts
import { Component } from '#angular/core';
import {TranslateService} from 'ng2-translate';
#Component({
    selector: 'dashboard-page',
    template:`<div>
      <h2>{{ 'HOME.TITLE' | translate }}</h2>
      <label>
        {{ 'HOME.SELECT' | translate }}
        <select #langSelect (change)="translate.use(langSelect.value)">
          <option *ngFor="let lang of translate.getLangs()" [value]="lang" [selected]="lang === translate.currentLang">{{ lang }}</option>
        </select>
      </label>
    </div>`
    
})
export class DashboardComponent {
constructor(private translate: TranslateService) {
translate.addLangs(["en", "fr"]);
translate.setDefaultLang('en');
let browserLang = translate.getBrowserLang();
translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');
}
}
Path of this file is src/main/app/dashboard/dashboard.component.ts
Path of the 2 JSON files- en.json & fr.json is src/main/app/assets/i18n.
I have included TranslateModule in app.module.ts
But when I run the app, I'm getting en.json file not found-404 error. I'm using webpack and in webpack.common.js I have preloader for JSON like this
preLoaders:[
    {
        test: /\.json$/,
        exclude: /node_modules/,
        loader: 'json-loader'
    }
]
Still I'm getting JSON file not found error.
And from the examples I was following, I din't understand in which file the path assests\i18n.json is to be mentioned.

I have encountered this same issue. Webpack only include files which are 'require'-ed, so unless there is a require('./path/to/file.json') the file is not included. Furthermore, by doing so would mean that the file will also become hashed, and thus the file will not be recognized by the ng2-translate util.
I came around this issue by using the CopyWebpackPlugin (see https://github.com/kevlened/copy-webpack-plugin) By adding the following config to my webpack.config.js file
var CopyWebpackPlugin = require('copy-webpack-plugin');
...
plugins: [
new CopyWebpackPlugin([ { from: 'src/assets/i18n', to: 'assets/i18n' } ])
]
I also configured the Translate module as following because my resources were found under the /assets/i18n folder, rather than the default /i18n folder.
In app.translate.ts (note the export of the function, this is required for AoT)
export function createTranslateLoader(http: Http) {
return new TranslateStaticLoader(http, 'assets/i18n', '.json');
}
export const AppTranslateModule: ModuleWithProviders = TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [ Http ]
});
And in my app.module.ts as follows
#NgModule({
imports: [ AppTranslateModule, ... ],
...
})
export class AppModule {
}
Note: To the time of writing, the ng2-translate webpack example is broken. In fact there is an issue open for this https://github.com/ocombe/ng2-translate/issues/325

Change
new CopyWebpackPlugin([ { from: 'src/assets/i18n', to: 'assets/i18n' } ])
to
new CopyWebpackPlugin({ patterns: [ { from: './src/assets/i18n', to: 'assets/i18n' } ] }),

Related

Cypress: import modules via alias

in my project i am using cypress with plain javascript. i am facing the challenge of importing the modules (page objects) via aliases instead of spaghetti code like ../../../../folder/page.js.
I don't use typescript or react.js and don't have a src folder/directory.
my tests run locally in the browser or via a docker image (pipeline).
I would like to transform from this:
import { LoginPage } from "../../pages/loginPage.js";
to something like this:
import { LoginPage } from "#Pages/loginPage.js";
but I always get an error:
Error: Webpack Compilation Error
./cypress/e2e/accountOverview/accountOverviewPageTest.spec.js
Module not found: Error: Can't resolve 'Pages/loginPage.js' in 'C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview'
resolve 'Pages/loginPage.js' in 'C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview'
Parsed request is a module
using description file: C:\Users\User\automated_frontend_tests\automated_frontend_tests\package.json (relative path: ./cypress/e2e/accountOverview)
Field 'browser' doesn't contain a valid alias configuration
Looked for and couldn't find the file at the following paths:
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\accountOverview\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\e2e\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\cypress\node_modules]
[C:\Users\node_modules]
[C:\node_modules]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js]
[C:\Users\User\node_modules\Pages\loginPage.js]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.js]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.js]
[C:\Users\User\node_modules\Pages\loginPage.js.js]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.json]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.json]
[C:\Users\User\node_modules\Pages\loginPage.js.json]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\node_modules\Pages\loginPage.js.jsx]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\node_modules\Pages\loginPage.js.mjs]
[C:\Users\User\automated_frontend_tests\automated_frontend_tests\node_modules\Pages\loginPage.js.coffee]
[C:\Users\User\automated_frontend_tests\node_modules\Pages\loginPage.js.coffee]
[C:\Users\User\node_modules\Pages\loginPage.js.coffee]
# ./cypress/e2e/accountOverview/accountOverviewPageTest.spec.js 5:17-46
I have tried several solutions, including:
//webpack.config.js
module.exports = {
resolve: {
alias: {
"#pages": path.resolve(__dirname, "cypress/pages/*"),
},
},
};
//testspec file
import { LoginPage } from "#pages/loginPage.js";
const loginPage = new LoginPage();
#Uzair Khan:
I tried your solution, but it still didn't work. The error message remains the same. It seems that the IDE does not search in the correct folder, but only in ...\node_modules\#page\loginPage.js which makes no sense.
If I enter const loginPage = new LoginPage(), the module LoginPage() cannot be found by the IDE either. Something is wrong with the solution. Do I still have to install any packages via NPM?
In your webpack.config.js file add resolve.alias which you want to make alias. It looks like something this below:
resolve: {
alias: {
'#page': path.resolve(__dirname, '{path you want to make alias}')
}
}
Since you are using cypress, you have to update the resolve path in cypress.config.js. Here is mine cypress.config.js
import { defineConfig } from 'cypress'
import webpack from '#cypress/webpack-preprocessor'
import preprocessor from '#badeball/cypress-cucumber-preprocessor'
import path from 'path'
export async function setupNodeEvents (on, config) {
// This is required for the preprocessor to be able to generate JSON reports after each run, and more,
await preprocessor.addCucumberPreprocessorPlugin(on, config)
on(
'file:preprocessor',
webpack({
webpackOptions: {
resolve: {
extensions: ['.ts', '.js', '.mjs'],
alias: {
'#page': path.resolve('cypress/support/pages/')
}
},
module: {
rules: [
{
test: /\.feature$/,
use: [
{
loader: '#badeball/cypress-cucumber-preprocessor/webpack',
options: config
}
]
}
]
}
}
})
)
// Make sure to return the config object as it might have been modified by the plugin.
return config
}
And import in other file via that alias you set in cypress.config.js. Here is mine for example:
import page from '#page/visit.js'
const visit = new page()
When('I visit duckduckgo.com', () => {
visit.page()
})
I think both answers are nearly there, this is what I have for src files:
const webpack = require('#cypress/webpack-preprocessor')
...
module.exports = defineConfig({
...
e2e: {
setupNodeEvents(on, config) {
...
// #src alias
const options = {
webpackOptions: {
resolve: {
alias: {
'#src': path.resolve(__dirname, './src')
},
},
},
watchOptions: {},
}
on('file:preprocessor', webpack(options))
...
path.resolve() resolves a relative path into an absolute one, so you need to start the 2nd param with ./ or ../.
Also, don't use wildcard * in the path, you just need a single folder that will be substituted for the alias in the import statement.
If in doubt, check the folder returned (in the terminal)
module.exports = defineConfig({
...
e2e: {
setupNodeEvents(on, config) {
const pagesFolder = path.resolve(__dirname, './cypress/pages')
console.log('pagesFolder', pagesFolder)

Enable CORS in Angular frontend

I have a microfrontend running on port 4200, and the other one on 4201. I tried splitting up the translation files and would like to load both of the applications translations, so I wrote a custom loader that is making an http request to port 4201:
export const scope = function(http: HttpClient) {
const loader = ['en', 'de'].reduce((acc: any, lang: string) => {
acc[lang] = () => firstValueFrom(http.get(`http://localhost:4201/assets/i18n/fields/${lang}.json`));
return acc;
}, {});
return {scope: 'fields', loader: loader}
};
#NgModule({
declarations: [RootComponent],
imports: [
CommonModule,
RootRoutingModule,
FormsModule,
SharedModule.forRemote(environment),
TranslocoModule
],
providers: [
{
provide: TRANSLOCO_SCOPE,
deps: [HttpClient],
useFactory: scope
}
]
})
export class RootModule { }
Both applications are javacript frontends, hence CORS blocks it. How can I ignore cores in the frontend?
https://levelup.gitconnected.com/fixing-cors-errors-with-angular-cli-proxy-e5e0ef143f85
This article helped me. It is a workaround to enable CORS in the frontend. But be warned this is just a workaround and in my case it was neccessary because I was loading translation files from one microfrontend to the app shell.

Angular: Weird if statement behaviour in app.module.ts

we recently experienced weird behaviour in our app.module.ts. We were using environment.ts and environemnt.prod.ts file to include/exclude specific library in imports array of the module(library should be excluded for production build). It looked something like this:
import { environment } from '../environments/environment'
//
#NgModule({
//
imports: [
CommonModule,
BrowserModule,
environment.production ? [] : libraryXXX,
HttpClientModule,
FormsModule
],
we found out after days of barren investigation that libraryXXX is included in build every time, even with --prod flag. We tested what's the problem - the value from environment.ts/prod.ts file was read correctly, but for whatever reason comparision always returned false. What I mean by always: replacing above fragment with:
environment.production == true ? [] : libraryXXX
or
environment.production == false ? [] : libraryXXX
did not change a thing - library WAS ALWAYS included. Like the if statement was broken(?). Extracting it to variable didn't change a thing. We ended up doing semi-hacky solution like:
environment.ts
import { libraryXXX } from 'whatever'
export const environment = {
production: false,
libraryXXX: libraryXXX
}
environment.prod.ts
export const environment = {
production: true,
libraryXXX: []
}
and simply referening to environment.libraryXXX in app.module.ts. But out of the curiosity - can anyone explain to me why simple if statement failed? Since it was app.module.ts I could not debug it, or even see console output, to know what's going on. Anyone has an idea?
This will work.
import { environment } from '../environments/environment'
const targetModules = [
CommonModule,
BrowserModule,
HttpClientModule,
FormsModule
];
if (environment.production) {
targetModules.push(libraryXXX);
}
//
#NgModule({
//
imports: targetModules,
//
What you can do:
You can import both libraries, the prod and the mock version.
Then you can decide (environment.production) which of both your will provide:
providers: [
{
provide: DbTrassenanfrageStatusService,
useClass: environment.production ? XyzMockService : XyzService
}
]
If you are talking about modules:
Give this a try:
const exports = [];
if (environment.production === true) {
exports.push(ModuleXyyyz);
console.info('FactoryModule: ModuleXyyyz;');
} else {
console.info('FactoryModule: nothing;');
}
#NgModule({
imports: [
ModuleXyyyz
],
exports
})
export class FactoryModule {
}
Then import FactoryModule in your app module.
To 'choose' the environment.prod.ts config, just build or start it via --prod flag:
ng serve --prod
ng build --prod
See the angular cli doc for more information (--prod , --configuration, ...)
If you have an environment.*.ts like this:
export const environment = {
production: true,
env: 'prod',
version: '{BUILD_VERSION}',
commitHash: '{COMMIT_HASH}',
showVersionIndicator: false,
routerTracing: false,
...then you can print out a field like version at startup (in your app component):
console.info('Version: ', environment.version);

Angular 2 Snackbar - Global Duration Config

I can set the duration of a snackbar message like so
let config = new MdSnackBarConfig();
config.duration = 5000;
this.snackBar.open(element.text, 'OK', config);
However I need to set the duration for multiple snackbars and would rather not have to pass in the config each time.
Can I somehow set a global duration config?
Thanks!
I know this post is from a few years ago but for future reference i'm going to answer this anyway. Hoping I help someone who comes across this post like I did.
You can now inject the MatSnackBar with default options for modules by using the providers in your #NgModule:
import { MatSnackBarModule, MAT_SNACK_BAR_DEFAULT_OPTIONS } from '#angular/material';
#NgModule({
declarations: [],
imports: [
MatSnackBarModule
],
exports: [
MatSnackBarModule
],
providers: [
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 2500 } }
]
})
Source: Material Angular doc's
What we've done is included an external app.config.ts file at the module level and include it where we need it. This is an example of what's in the file.
export class Config {
static apiUrl = "api/";
static token = "";
static snackBarDurration = 5000;
......
}
Then, all you have to do is declare it in your module and then import it in the component or service in which you want to use it. Here is an example.
import { Injectable } from "#angular/core";
import { Config } from "../../app.config";
#Injectable()
export class SnackBarService {
.... // declare your snackbar here
constructor() { }
showSnackBar(elementText: string){
let config = new MdSnackBarConfig();
config.duration = Config.snackBarDurration; // Here is your change
this.snackBar.open(elementText, 'OK', config);
}
}
I know it's not solution for a global configuration, but to
make invocation more compact I declared config in params:
this.snackBar.open(elementText, 'OK', { duration: 3000 });

Google plus comment box integration with Angular2 app

I was trying to integrate google plus comment box into my MEAN 2.0 website by following this link. I configured few things as per angular2 way but not sure if that is the correct way to do that. Please guide me to integrate it as not much help i found on internet for this.
index.html
added below link to index.html
<script src="https://apis.google.com/js/plusone.js"></script>
app.ts
declare let gapi:any;
#Component({
selector: 'blogComment',
template: `
<div class="g-commentcount" data-href="blog/"></div>
<div id="{{commentId}}"></div>
`
})
export class CommentComponent /*implements OnInit */{
commentId : string = "comments";
constructor() {
console.log("CommentComponent const");
this.embedComment();
}
/*ngOnInit(){
}*/
embedComment() {
gapi.comments.render(this.commentId, {
href: window.location,
width: '624',
first_party_property: 'BLOGGER',
view_type: 'FILTERED_POSTMOD'
});
}
}
Here is another component in the same app.ts file which is mapped to "blc" router.
#Component({
providers: [CommentComponent],
template : `
<blogComment></blogComment>
`
})
export class BlogComponent{
constructor(public comment: CommentComponent) {
console.log("BlogComponent const");
}
}
Router configuration
const appRoutes: Routes = [
...
{ path: 'blc', component: BlogComponent },
];
const appRoutingProviders: any[] = [
];
const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
and finally included everything in NgModule like below.
let declarationArr : Array<any>= [
BlogHomeComponent, ckeditorClass, AuthApp,
BlogNotFoundComponent, BlogComponent, BlogListComponent,
NewBlogComponent, CommentComponent
];
#NgModule({
imports: [ BrowserModule, HttpModule, CKEditorModule, FormsModule, routing ],
declarations: declarationArr,
providers: [ appRoutingProviders ],
bootstrap: [ BlogHomeComponent ]
})
export class app{}
const platform = platformBrowserDynamic();
platform.bootstrapModule(app);
but the comment box is not at all loading into the browser.
UPDATE
I tried the same using normal html and js.
It is coming properly in UI with a warning::
'//# sourceURL' and '//# sourceMappingURL' are deprecated, please use '//# sourceURL=' and '//# sourceMappingURL=' instead.
cb=gapi.loaded_1:1
'//# sourceURL' and '//# sourceMappingURL' are deprecated, please use '//# sourceURL=' and '//# sourceMappingURL=' instead.
When tries to comment something, in console it throws below error.
cb=gapi.loaded_1:138 POST https://apis.google.com/u/0/wm/1/_/sharebox/linkpreview/?soc-app=103&cid=0&soc-platform=1&hl=en&f.sid=712313642&_reqid=253999&rt=j 400 ()
And when tries to share that it throws error in UI saying::
"Something went wrong"
[NOTE] : I am in localhost. Is that the root cause? Would it get resolved if hosted?

Categories