ngx-translate / core

The internationalization (i18n) library for Angular
MIT License
4.51k stars 574 forks source link

/assets/i18n/en.json NOT FOUND #853

Open ellenchristine opened 6 years ago

ellenchristine commented 6 years ago
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. :/

rsaenen commented 6 years ago

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/.

cryptoplastic commented 6 years ago

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

JayaKrishnaNamburu commented 6 years ago

@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');
}
e455a81e-d3ba-41a2-bc6d-7aafb1d9a5cd commented 6 years ago

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}

k-majick commented 6 years ago

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...

NickDerSchlitzerMcGurk commented 6 years ago

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

Hansel03 commented 5 years ago

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 commented 5 years ago

it works for me

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

rsaenen commented 5 years ago

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
};
packetstracer commented 5 years ago

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.

pookdeveloper commented 5 years ago

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

udhayaganesh85 commented 4 years ago

try this 2 option..

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

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

Aprajita-96 commented 4 years ago

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

vandnagarg commented 4 years ago

@pookdeveloper thanks, worked for me

aganyc commented 4 years ago

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

aganyc commented 4 years ago

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

@Aprajita-96 How did you solve it

mderaeve commented 4 years ago

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.

kcrystalchen commented 3 years ago

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>****

Example of src/Web.config file: <?xml version="1.0" encoding="UTF-8"?>

**** ****

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"

zolastro commented 3 years ago

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

sardapv commented 3 years ago

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

nex1dhu commented 3 years ago

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

fozel44 commented 3 years ago

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

maestart commented 1 year ago

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.

renatolopeslatitudde commented 10 months ago

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!

vaimeo commented 3 weeks ago

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 thanks!!