setDefaultLang ngx-translate. Получить ошибку Исключение: вызов модуля узла завершился ошибкой: неожиданный токен в JSON в позиции 0

Я новичок в Angular и начинаю создавать новый проект со следующими характеристиками. Извините, если объяснение недостаточно ясное. Я более чем рад предоставить больше информации, но не хочу, чтобы через весь мой проект оставалась не относящаяся к делу информация.

я использую

  • Visual Studio 2015
  • ЯДРО ASPNET
  • Услуги AspNetCore.Angular
  • ngx-translate

Я следил за примерами и инструкциями, приведенными в [https://github.com/ngx-translate/corevisible[1pting

Мой код работает должным образом, так как я могу переводить на 4 языка и использовать директиву pipe в нескольких компонентах внутри маршрутизатора. Это означает, что мои файлы json загружаются и имеют правильную структуру. Я видел много отчетов, в которых была ошибка в файлах json, но это не мой случай.

Однако моя проблема в том, что я не могу добавить строки, которые устанавливают язык и язык по умолчанию, которые будут использоваться в конструкторе.

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
    selector: 'app',
    template: require('./app.component.html'),
    styles: [require('./app.component.css')]
})
export class AppComponent {
    constructor(private translate: TranslateService) {

        
        translate.addLangs(["en", "fr", "es", "de"]);
        //Error shows up when uncommenting any of the next two lines
        //translate.setDefaultLang('en');
        //translate.use('en');

    }
}

Всякий раз, когда я раскомментирую эти строки, я получаю сообщение об ошибке

Исключение: вызов модуля узла завершился ошибкой: SyntaxError: неожиданный токен в JSON в позиции 0 в JSON.parse ()

Если я прокомментирую эти строки, мое приложение запускается без проблем, и единственная деталь заключается в том, что язык еще не настроен. Я могу вручную выбрать его в раскрывающемся списке, и тогда все будет работать должным образом.

Вот html файл

<div id="MainContainer" class='container-fluid'>
    <div class='row'>
        <label>
          {{ "SELECT" | translate }}<br />
          <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>
</div>

Вот мой модуль приложения

import { NgModule }                 from '@angular/core';
import { UniversalModule }          from 'angular2-universal'; // this automatically imports BrowserModule, HttpModule, and JsonpModule too.
import { Http }                     from '@angular/http';
import { FormsModule }              from '@angular/forms'; // <-- ngModel lives here
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader }      from '@ngx-translate/http-loader';

// main Routing
import { AppRoutingModule }         from './routers/app-routing.module';


// own Services
import { ImgService }               from './services/img.service';

// own components
import { AppComponent }             from './components/app/app.component';
import { NavMenuComponent }         from './components/nav-menu/nav-menu.component';
import { CompleteSystemComponent }  from './components/complete-system/complete-system.component';
import { VehicleComponent }         from './components/vehicle/vehicle.component';
import { RobotComponent }           from './components/robot/robot.component';
import { MapComponent }             from './components/map/map.component';
import { StatusBarComponent }       from './components/status-bar/status-bar.component';
import { RobotCameraComponent }     from './components/robot-camera/robot-camera.component';
import { ImageProcessingComponent } from './components/image-processing/image-processing.component';
import { Station1Component }        from './components/station1/station1.component';
import { Station2Component }        from './components/station2/station2.component';


//AoT requires an exported function for factories
export function HttpLoaderFactory(http: Http) {
    //return new TranslateHttpLoader(http, '/i18n/', '.json');
    //return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
    return new TranslateHttpLoader(http);
}


@NgModule({
    imports: [
        UniversalModule, // must be first import. This automatically imports BrowserModule, HttpModule, and JsonpModule too.
        FormsModule,
        AppRoutingModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [Http]
            }
        }),

    ],
    declarations: [
        AppComponent,
        NavMenuComponent,
        RobotComponent,
        VehicleComponent,
        CompleteSystemComponent,
        MapComponent,
        StatusBarComponent,
        RobotCameraComponent,
        ImageProcessingComponent,
        Station1Component,
        Station2Component
    ],
    providers: [
        ImgService
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

Буду признателен, если кто-нибудь подскажет, что попробовать. Пока это то, что я пытался решить проблему

  • Переместите определение языка по умолчанию и используйте его в ngOnInit (не удалось так же)
  • Переместите определение языка по умолчанию и используйте функцию, вызываемую кнопкой (работает без проблем)
  • Попробуйте переместить определение языка по умолчанию и использовать в ngAfterViewInit () и ngAfterViewChecked ().

Я подозреваю, что проблема в том, что файлы json не были загружены из каталога wwwroot или что служба не может найти их там при запуске приложения. После запуска приложение находит их без проблем и все работает как положено.

Еще раз спасибо за ваши комментарии и дайте мне знать, если дополнительная информация поможет отладить эту проблему


person Miguel Angel Meza Martínez    schedule 04.07.2017    source источник


Ответы (2)


Наконец-то мне удалось решить почти 80% этой проблемы (я тоже новичок в angular и хотел бы увидеть лучшее решение).

  1. Обновите все пакеты до последней версии (для меня это angular 4.3.4).

  2. Перейдите на HttpClient, как в документации (https://github.com/ngx-translate/core)

Вот мой app.module.shared.ts файл:

import { NgModule,Inject } from '@angular/core';
import { RouterModule,Router } from '@angular/router';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { HttpModule } from '@angular/http';

import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

import { AppComponent } from './components/app/app.component'
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from './components/counter/counter.component';

export function HttpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(http);
}

export const sharedConfig: NgModule = {
    bootstrap: [ AppComponent ],
    declarations: [
        AppComponent,
        NavMenuComponent,
        CounterComponent,
        FetchDataComponent,
        HomeComponent,
    ],
    imports: [
        HttpClientModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [HttpClient]
            }
        }),
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', component: CounterComponent },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
};

И вот самое интересное. Единственная проблема заключается в том, что перевод пользовательского интерфейса выполняется в браузере, что плохо для SEO. Я обновлю, если что-то выясню.

app.component.ts файл:

import { Component, OnInit, Inject } from '@angular/core';

import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

import { TranslateService } from '@ngx-translate/core';

@Component({
    selector: 'app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    isBrowser: boolean;


    constructor( @Inject(PLATFORM_ID) platformId: Object ,@Inject('ORIGIN_URL') originUrl: string, private translate: TranslateService) {
        this.isBrowser = isPlatformBrowser(platformId);

        if (this.isBrowser) {
            translate.setDefaultLang('en');
            translate.use('en');
        }

    }
    changeLang(lang: string) {
        this.translate.use(lang);
    }
}

На данный момент это решило проблему, и если вы найдете лучшее решение, которое не пропустит SEO, поделитесь им :).

person Abdo    schedule 11.08.2017

У меня была такая же проблема, вот как я ее решил:

1) Предоставьте словарь для просмотра:

public async Task<IActionResult> Index()
{
    var serverData = new IndexViewModel
    {
        Vocabulary = await GetUserLanguage()
    };

    return View(serverData);
}

Запас слов:

public class Vocabulary
{
    public String Language { get; set; }

    public Object Translations { get; set; }
}

GetUserLanguage ():

private async Task<Vocabulary> GetUserLanguage()
    {
        // Get lang form request headers
        StringValues langs;
        HttpContext.Request.Headers.TryGetValue("Accept-Language", out langs);

        if(langs.Count == 0)
        {
            return null;
        }

        var langsArr = langs.ToArray();

        for(var i = 0; i < langsArr.Length; i++)
        {
            var lang = langsArr[i];

            if (lang.Contains("-"))
            {
                langsArr[i] = lang.Split("-")[0];
            }

            if (lang.Contains("_"))
            {
                langsArr[i] = lang.Split("_")[0];
            }
        }

        langsArr = langsArr == null
            ? new String[] { "en" }
            : langsArr;

        Vocabulary vocabulary = null;

        foreach (var userLang in langsArr)
        {
            var path = $"{_hostingEnvironment.WebRootPath}/assets/i18n/{userLang}.json";
            FileInfo fileInfo = new FileInfo(path);

            if (fileInfo.Exists)
            {
                vocabulary = new Vocabulary
                {
                    Language = userLang,
                    Translations = await System.IO.File.ReadAllTextAsync(path)
                };

                break;
            }
        }

        return vocabulary;
    }

2) Отправьте модель на boot.server.

Index.cshtml:

<app asp-prerender-module="ClientApp/dist/main-server" asp-prerender-data="@JavaScriptHelper.Json(Model)">Loading...</app>

JavaScriptHelper.Json ():

public static string Json(object obj)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new JsonConverter[]
            {
                new StringEnumConverter(),
            },
            StringEscapeHandling = StringEscapeHandling.EscapeHtml
        };

        return JsonConvert.SerializeObject(obj, settings);
    }

Передача данных из MVC в Angular2 описана здесь

В boot.server.ts вы можете получить доступ к переданным данным сервера через params.data: // Imports

declare var global: any;

enableProdMode();

export default createServerRenderer(params => {
    let serverData = JSON.parse(params.data);
    serverData.vocabulary.translations = 
JSON.parse(serverData.vocabulary.translations);

global.serverData = serverData;

// ...

return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
    const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
    const state = moduleRef.injector.get(PlatformState);
    const zone = moduleRef.injector.get(NgZone);

return new Promise<RenderResult>((resolve, reject) => {
        zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
        appRef.isStable.first(isStable => isStable).subscribe(() => {
            // Because 'onStable' fires before 'onError', we have to delay slightly before
            // completing the request in case there's an error to report
            setImmediate(() => {
                resolve({
                    html: state.renderToString(),

                    globals: {
                        serverData: serverData
                    }
                });
                moduleRef.destroy();
            });
        });
    });

Объект global доступен во время предварительной отрисовки в среде узла.

globals: { serverData: serverData } данные передаются объекту окна, доступному в браузере.

3) Установите язык по умолчанию в app.component.ts: объявите var serverData: any;

@Component({
    selector: 'app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor(private translate: TranslateService, private http: Http, globalService: GlobalService, @Inject(PLATFORM_ID) platformId: Object) {
    let isBrowser = isPlatformBrowser(platformId);

    let lang = '';
    let translations = { };

    if (!isBrowser) {
        lang = serverData.vocabulary.language;
        translations = serverData.vocabulary.translations;
    } else {
        lang = (window as any).serverData.vocabulary.language;
        translations = (window as any).serverData.vocabulary.translations;
    }

    translate.setTranslation(lang, translations);
    translate.setDefaultLang(lang);
    translate.use(lang);
    }
}
person Nazir Temirov    schedule 18.09.2017