core icon indicating copy to clipboard operation
core copied to clipboard

/assets/i18n/en.json NOT FOUND

Open ellenchristine opened this issue 6 years ago • 24 comments

screen shot 2018-05-20 at 11 00 43 pm

I realize this is a common issue and have been scouring this repo's support tickets and Stackoverflow looking for why I can't get this working. None of the many suggestions I've tried have worked. I'm confused because my setup is simple and in no way (that I can see) different from the example code setup shared in this repo.

I'm using Angular 5.1.0 along with Angular CLI 1.7. Webpack and ngx-translate versions are as follows:

    "@ngx-translate/core": "^9.1.1",
    "@ngx-translate/http-loader": "^2.0.1",
    "webpack": "~3.8.1"

http://localhost:4200/src/assets/i18n/en.json resolves to the file correctly in the browser, so the file is in the correct location for the default configuration outlined in the ngx-translate README.

Here are the relevant files:

app.component.ts

import { ActivatedRoute } from '@angular/router';
import { Component, ElementRef, HostListener, OnInit, ViewChild, AfterViewInit, ErrorHandler } from '@angular/core';
import {TranslateService} from '@ngx-translate/core';

/*
 * Main app component that houses all views.
 */
@Component({
  selector: 'app-comp',
  templateUrl: './app.component.html'
})

export class AppComponent {

  store: any;

  constructor(private route: ActivatedRoute, private translate: TranslateService) {
    // translate.addLangs(['en', 'fr']);
    translate.setDefaultLang('en');
  }
}

app.module.ts

import { MaterialModule } from './material.module';
import { BrowserModule, Title } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpModule } from '@angular/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { RootComponent } from './root.component';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app.routing';

import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from '../db/in-memory-data.service';

import { AppInterceptor } from './_core/app.interceptor';
import { FooterComponent } from './_core/footer/footer.component';
import { HeaderComponent } from './_core/header/header.component';
import { DataService } from './_core/data.service';
import { DataResolver } from './_core/data.resolver';

import { environment } from '../environments/environment';
import { AppGuard } from './app.guard';

import { MessageService } from './message.service';
import { GatewayService } from './shared/gateway.service';
import { WindowRefService } from './window-ref.service';

/*
* Main module for the app that boostraps everything.
*/
@NgModule({
    imports: [
        BrowserModule,
        HttpClientModule,
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useFactory: HttpLoaderFactory,
            deps: [HttpClient]
          }
        }),
        HttpModule,
        FormsModule,
        AppRoutingModule,
        BrowserAnimationsModule,
        InMemoryWebApiModule.forRoot(InMemoryDataService, { dataEncapsulation: false }) // Remove to use real HTTP calls
    ],
    declarations: [
        RootComponent,
        HeaderComponent,
        AppComponent,
        FooterComponent
    ],
    providers: [
        AppGuard,
        DataService,
        DataResolver,
        MessageService,
        GatewayService,

        WindowRefService,
        {
            provide: HTTP_INTERCEPTORS,
            useClass: AppInterceptor,
            multi: true,
        }
    ],
    bootstrap: [RootComponent]
})

export class AppModule { }

// required for AOT compilation
export function HttpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(http);
}

I've tried all the common solutions, including using the CopyWebpackPlugin to try to resolve the webpack bundling, adding the i18n directory to the assets list in angular-cli.json, and explicitly passing my path to TranslateHttpLoader like so:

return new TranslateHttpLoader(http, "./assets/i18n/", ".json");

None of these approaches have worked.

Is there something very basic I'm missing in my setup? I feel like I've just been looking at it too long at this point. :/

ellenchristine avatar May 21 '18 04:05 ellenchristine

Check your angular cli configuration, I'm pretty sure the mistake comes from here.

You can look in apps > prefix and add its value before ./assets/i18n/.

rsaenen avatar May 22 '18 07:05 rsaenen

if you are using the cli, you may need to include it in the paths folder in angular-cli.json

cryptoplastic avatar May 22 '18 11:05 cryptoplastic

@ellenchristine in your angular-cli the prefix and assets should refer to the paths as shown below.

"assets": [
        "assets",
        "favicon.png"
      ],
 "prefix": "app"

Then refer it like this in your root module

export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

JayaKrishnaNamburu avatar May 23 '18 06:05 JayaKrishnaNamburu

I had the same problem, the InMemoryDataService intercepts your requests to the real server. To fix this you can set passThruUnknownUrl: true like this: InMemoryDataService, {dataEncapsulation: false, passThruUnknownUrl: true}

I also had this issue using webpack 4. It turned out that json files had to be copied to the dist folder along with the rest of the compilation, so I used copy-webpack-plugin for that. In my webpack config:

const CopyWebpackPlugin = require('copy-webpack-plugin');
...
  plugins: [
    new CopyWebpackPlugin([
      { from: helpers.root('src'), to: helpers.root('dist') }
    ]),
  ],

It solved the problem and json files are loaded correctly now. At least when using dev server...

k-majick avatar Jun 02 '18 20:06 k-majick

I have the same Problem. With Angular Version 6.

But there isn't a angular-cli.json File. So I add the path in the angualr.json

"projects": { "navigatorWebClient": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "gue", "schematics": { "@schematics/angular:component": { "styleext": "scss" } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/navigatorWebClient", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets", "src/assets/i18n" ], "styles": [ "src/styles.scss" ], "scripts": [] },

But the Error isn't disappear

My ngx-translate-Version is

"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",

best regards McGurk

NickDerSchlitzerMcGurk avatar Jul 19 '18 09:07 NickDerSchlitzerMcGurk

I have the same problem with the version of angular 6 and 7 if someone knows how to solve them?

I only have problems with the construction and deployment on the server

When used in my premises everything works correctly

Hansel03 avatar Jan 25 '19 21:01 Hansel03

it works for me

https://stackoverflow.com/questions/44756251/json-language-files-are-not-found-ngx-translate-angular-cli/51121032#51121032

Hansel03 avatar Jan 29 '19 13:01 Hansel03

You can use you own loader, this one works with SSR too:

import { translationFr } from 'assets/i18n/fr';
import { of, Observable } from 'rxjs';
import { TranslateLoader as NgxTranslateLoader } from '@ngx-translate/core';

const TRANSLATIONS = {
    fr: translationFr
};

export class TranslateLoader implements NgxTranslateLoader {

    public getTranslation(lang: string): Observable<any> {
        return of(TRANSLATIONS[lang]);
    }
}

export function translateFactory() {
    return new TranslateLoader();
}

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { translateFactory } from '@shared/services/translate-loader.service';
import { TranslateLoader, TranslateModule as NgxTranslateModule, TranslateService } from '@ngx-translate/core';

@NgModule({
    imports: [
        HttpClientModule,
        NgxTranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: translateFactory
            }
        })
    ],
    exports: [ NgxTranslateModule ]
})

export class TranslateModule {
    constructor(translate: TranslateService, inputFileService: InputFileService) {
        translate.addLangs(['fr']);
        translate.setDefaultLang('fr');
    }
}

Why not use a typescript file instead of json? :)

Example: src > assets >i18n > fr.ts

export const translationFr = {
 // my translations
};

rsaenen avatar Jan 29 '19 14:01 rsaenen

I had the same problem, the InMemoryDataService intercepts your requests to the real server. To fix this you can set passThruUnknownUrl: true like this: InMemoryDataService, {dataEncapsulation: false, passThruUnknownUrl: true}

Worked for me, if I disabled InMemoryDataService would work but not when enabled so the passThruUnknownUrl config property did the trick.

packetstracer avatar Feb 18 '19 10:02 packetstracer

I had the same problem, the InMemoryDataService intercepts your requests to the real server. To fix this you can set passThruUnknownUrl: true like this: InMemoryDataService, {dataEncapsulation: false, passThruUnknownUrl: true}

It works

pookdeveloper avatar Aug 19 '19 15:08 pookdeveloper

try this 2 option..

export const environment = { production: true, appRootPrefix: '/<<Your project name>>' };

export function createTranslateLoader(http: HttpClient) { return new TranslateHttpLoader(http, './assets/i18n/', '.json'); }

udhayaganesh85 avatar Feb 07 '20 18:02 udhayaganesh85

Worked for me too. return new TranslateHttpLoader(http, "/BASEHREF/assests/i18n", ".json");

Aprajita-96 avatar Apr 01 '20 19:04 Aprajita-96

@pookdeveloper thanks, worked for me

vandnagarg avatar May 01 '20 10:05 vandnagarg

I had the same problem, Is there any way to solve it now

aganyc avatar Jun 24 '20 07:06 aganyc

Worked for me too. return new TranslateHttpLoader(http, "/BASEHREF/assests/i18n", ".json");

@Aprajita-96 How did you solve it

aganyc avatar Jun 24 '20 08:06 aganyc

At the moment, the only thing that worked for me is to change the .json extension of the files to .txt. Then put this in the module (for local DEV I keep the json files, else I would have to copy each time if I would like to check translations):

export function httpTranslateLoader(http: HttpClient) {
  if (environment.production == true)
  {
    return new TranslateHttpLoader(http, "./assets/i18n/", ".txt");
  }
  else
  {
    return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
  }
}

If I tried to enter the url of the json file in the browser, it didn't work, now if i try this with the txt file in the same folder it works. So the .json file are intercepted. I have a MSAL http interceptor which I cannot just remove. Its not the best solution, but it works, if I can find a better way, I would love to. Now after each deploy to production, I need to copy these translation files to txt.

mderaeve avatar Aug 20 '20 13:08 mderaeve

I spent few hours to figure this issue out, but it finally works. Want to share it, hope this will fix your issue as well. step 1: added below code in the src folder -> web.config file: [src/web.config] <staticContent> <mimeMap fileExtension=".json" mimeType="application/json" /> </staticContent>

Example of src/Web.config file:

    <!-- for mutil-language to get static json files from assets i18n folder -->
     ****<staticContent>
        <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>****

</system.webServer>

step 2: In the app.module.ts, added the below code

// The TranslateHttpLoader uses HttpClient to load translations, which means that you have to import the HttpClientModule from @angular/common/http before the TranslateModule: // import TranslateModule and execute the translateHttpLoaderFactory function

export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './assets/i18n/', '.json'); }

step 3: add "src/web.config" and "src/assets/i18n" under in the angular.json file the path is "projects" => "Project Name" => "architect" => "build" => "options" => "assets" object => add "src/assets/i18n" and "src/web.config"

kcrystalchen avatar Feb 03 '21 03:02 kcrystalchen

I had this problem after building using ng build --prod --base-href=/my-path/

I ended using a similar solution to @mderaeve , saving the i18n folder path in my environment.ts and enviornment.ts.prod files. This is my loader at app.module.ts

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, environment.I18N_FOLDER, ".json");
}

I hope this helps

zolastro avatar Feb 23 '21 16:02 zolastro

none of options worked for me. I have my .json files in src/assets/labels folder and my angular-cli.json also had src/assets folder. In interceptor I had to do this intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { const newreq = request.clone({ url: this.baseUrl + request.url, }); if (request.url.includes('.json')) { return next.handle(request); } return next.handle(newreq); } }

hope it helps someone

sardapv avatar Apr 01 '21 15:04 sardapv

I have same error but didn't get any solution , I am using angular 10 and my ngx-translate version is

"@ngx-translate/core": "^11.0.1", "@ngx-translate/http-loader": "^4.0.0",

And I have already made export function of httpLoaderFactory(), after then having error . Because of that I am not able to have object value. If anyone has any idea, plz suggest here

nex1dhu avatar Apr 29 '21 11:04 nex1dhu

Worked for me. readFileSync(dist/test-seo-project/browser/assets/i18n/${lang}.json, 'utf8')));

fozel44 avatar Jul 11 '21 20:07 fozel44

After hours of searching and useless tries I decided to write custom loader that loads JSON files by dynamic import:

export default class LanguageLoader implements TranslateLoader {
  public getTranslation(language: string): Observable<{ [key: string]: string }> {
    return from(import('./i18n/' + language + '.json'));
  }
}

Then in AppModule:

TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        provide: TranslateLoader,
        useClass: LanguageLoader,
      },
    }),

That's all, i18n files loads as modules, not by HTTP, @ngx-translate/http-loader can be removed from dependencies.

Don't forget to add "resolveJsonModule": true in tsconfig.json, or if you want to use ts\js file instead of json, move object with translations into it and export this object by default, than use: return from(import('./i18n/' + language)).pipe(pluck('default')); or some other logic that depends of your situation.

maestart avatar Sep 02 '23 07:09 maestart

After hours of searching and useless tries I decided to write custom loader that loads JSON files by dynamic import:

export default class LanguageLoader implements TranslateLoader {
  public getTranslation(language: string): Observable<{ [key: string]: string }> {
    return from(import('./i18n/' + language + '.json'));
  }
}

Then in AppModule:

TranslateModule.forRoot({
      defaultLanguage: 'en',
      loader: {
        provide: TranslateLoader,
        useClass: LanguageLoader,
      },
    }),

That's all, i18n files loads as modules, not by HTTP, @ngx-translate/http-loader can be removed from dependencies.

Don't forget to add "resolveJsonModule": true in tsconfig.json, or if you want to use ts\js file instead of json, move object with translations into it and export this object by default, than use: return from(import('./i18n/' + language)).pipe(pluck('default')); or some other logic that depends of your situation.

Hi, i tried your method but iam getting this error "./src/app/app.module.ts:20:16-54 - Error: Module not found: Error: Can't resolve './i18n'" am i missing some step? I didn't understand what you mean by "return from(import('./i18n/' + language)).pipe(pluck('default'));", thanks!

renatolopeslatitudde avatar Nov 30 '23 23:11 renatolopeslatitudde