Angular: i18n: возможность использовать строки перевода вне шаблона.

Созданный на 7 сент. 2016  ·  204Комментарии  ·  Источник: angular/angular

Я отправляю ... (отметьте один знаком "x")

[x] feature request

Текущее поведение
https://github.com/angular/angular/issues/9104#issuecomment-244909246

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

Ожидаемое/желаемое поведение
Иметь возможность переводить строки, используемые в любом месте кода, с помощью API.

Воспроизведение проблемы

Каково ожидаемое поведение?
Я имею в виду использование $translate.instant для демонстрации реальных вариантов использования:

  • Пользовательский визуализированный текст:
if (data._current_results === data._total) {
                content = this.$translate.instant('CLIPPINGS__LIST__SUMMARY_ALL', {'num': data._current_results});
            } else {
                if (undefined === data._total) {
                    data._total = '...';
                }

                content = this.$translate.instant('CLIPPINGS__LIST__SUMMARY', {
                    'num': data._current_results,
                    'total': data._total
                });
            }

            // Put 'mentions' first
            data = angular.merge({}, {
                mentions: mentions
            }, data);

            _.each(data, (value:number, key:string):void => {
                if (value) {
                    details += value + ' ' + this.$translate.instant('CLIPPINGS__LIST__SUMMARY_TYPE_' + key) + ', ';
                }
            });

            if (details) {
                details = '(' + _.trim(details, ', ') + ')';
            }

            content = content.replace(':details', details);

Еще примеры:

  • Получение имени файла изображения из экспортированного изображения HTML-отчета:
getExportImageName(hideExtension:boolean):string {
        let fileName:string;

        fileName = this.$translate.instant('D_CHART_FACET_authors__EXPORT_FILENAME', {
            'profileName': this.ExportService.GetProfileName(),
            'period': this.ExportService.GetPeriodString(this.SearchFilter.GetPeriodFromInterval())
        });

        if (!Boolean(hideExtension)) {
            fileName += '.png';
        }

        return fileName;
    }
  • Иногда вы переводите, иногда используете данные модели (в шаблоне они могут быть очень подробными):
private _getTitle():string {
        if (this.inShareColumn) {
            return this.$translate.instant('COMPARISONS__SHARE_COLUMN_share_of_voice_TITLE');
        } else if (this.inTotalsColumn) {
            return this.$translate.instant('COMPARISONS__TOTAL_COLUMN_share_of_voice_TITLE');
        } else {
            return _.get<string>(this.group, 'profileName', '');
        }
    }
  • Использование стороннего плагина диаграммы (Highcharts)
this.chart = new Highcharts.Chart(<any>{
            title: {
                text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone').toUpperCase(),
            },
            xAxis: {
                title: {
                    text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone_xaxis')
                }
            },
            yAxis: {
                min: 0,
                title: {
                    text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone_yaxis')
                }
            },
            plotOptions: {
                scatter: {
                    tooltip: {
                        headerFormat: '<b>{point.key}</b><br>',
                        pointFormat: '{point.y} ' + this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_mentions')
                    }
                }
            }
        });
  • Чтобы настроить переменные конфигурации и отобразить текст без каналов, поскольку это не всегда переведенная строка
this.config = {
            requiredList: true,
            bannedList: false,
            allowSpaces: false,
            allowComma: false,
            colorsType: false,
            defaultEnterAction: 'required',
            requiredTooltip: this.$translate.instant('D_CLIPPING_TAGS__REQUIRED_TOOLTIP'),
            bannedTooltip: this.$translate.instant('D_CLIPPING_TAGS__BANNED_TOOLTIP')
        };
  • Чтобы установить window.title :) :
SetWindowTitle(title:string) {
        if (!!title) {
            this.$window.document.title = this.$translate.instant(title);
        }
    }
  • Пользовательское форматирование даты:
dateHuman(date:Date):string {
        return date.getDate() + ' ' + this.$translate.instant('GLOBAL_CALENDAR_MONTH_' + date.getMonth())
            + ' ' + date.getFullYear();
    }
  • Сортировка вещей на основе переведенных значений:
// Sort types
            tmpTypes = _.sortBy(tmpTypes, (type:string):string => {
                // 'MISC' at the end
                if ('MISC' === type) {
                    return 'zzzzz';
                }

                return this.$translate.instant('FACET_phrases2__TYPE_' + type);
            });
GetSortedLanguages():IFacetLangDetectedCommonServiceLanguageObject[] {
        // We have to sort by translated languages!
        return _.sortBy(_.map(this.facetOptions, (item:string):any => {
            return {
                key: item,
                label: this.$translate.instant('FACET_langDetected_' + item),
                cssStyle: (_.includes(['english', 'catalan', 'spanish', 'french', 'italian'], item))
                    ? {'font-weight': 'bold'} : null,
                flag: _.get(this.lutFlags, item, null)
            };
        }), (item):string => {
            return item.label.toLowerCase();
        });
    }
  • Экспорт необработанных данных в CSV или Excel с переведенными значениями:
getDataExportStacked(inputData:any):any {
        let exportData = angular.copy(inputData);

        if (angular.isArray(exportData) && exportData.length) {
            exportData[0].name = this.$translate.instant('CLIPPINGS__CHARTS_volume_TITLE');

            exportData[0].data = _.map(exportData[0].data, (inputDataItem:any):any => {
                return {
                    'label': inputDataItem.association.profileName,
                    'value': inputDataItem.value
                };
            });
        }

        return exportData;
    }
  • Установите строки конфигурации для сторонних плагинов:
UpdateCalendarStrings():void {
        Highcharts.setOptions({
            lang: {
                months: [
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_January'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_February'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_March'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_April'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_May'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_June'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_July'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_August'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_September'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_October'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_November'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_December')
                ],
                shortMonths: [
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jan'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Feb'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Mar'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Apr'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_May'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jun'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jul'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Aug'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Sep'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Oct'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Nov'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Dec')
                ],
                weekdays: [
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Sunday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Monday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Tuesday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Wednesday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Thursday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Friday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Saturday')
                ]
            }
        });
    }


Какова мотивация / вариант использования для изменения поведения?
Иметь возможность переводить строки вне шаблонов.

Расскажите, пожалуйста, о вашей среде:

  • Угловая версия: 2.0.0-rc.6
  • Браузер: [все]
  • Язык: [TypeScript 2.0.2 | ЭС5 | SystemJS]

@викб

i18n feature high

Самый полезный комментарий

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

Все 204 Комментарий

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

@ Mattes83 Вы пробовали так?

<p [hidden]="!alertManagerRowForm.controls.sendTo.hasError('validateEmail')" class="help-error">
    {{ 'ALERTMANAGER__FORM__FIELD__sendTo__ERROR__validateEmail' | translate }}
</p>

:confused: В документации рассказывается, как приятно иметь сообщения об ошибках в коде, а поддержка перевода требует чего-либо в шаблоне. Похоже, что есть потребность в общении.

@marcalj Я знаю этот способ ... но мне нужно иметь локализованные строки в моих файлах ts.
@manklu я полностью согласен

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

Да, то же самое здесь, я только что перешел с ng2-translate на Angular2 i18n, так как предпочитаю использовать модули OOTB, и извлекать переводы намного проще (ng2-translate требует больше времени, IMO)
На данном этапе я не могу переводить сообщения об ошибках, выдаваемые моими службами. Нет обходного пути.

Если кто-то хочет начать спецификацию дизайна, это было бы полезно (например, в Google Docs).

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

_.('static text');
_.('with {{ parameter }}', {parameter: "parameter" });
_.plural(count, {'few': '...'});
_.select(on, {'value': '...'});

Привет, ребята, отличный запрос функции :+1:

Есть ли какой-либо предлагаемый обходной путь для перевода текстов *.ts?

@fbobbio Я создавал скрытые элементы в шаблоне, например.
<span class="translation" #trans-foo i18n>foo</span> .

Свяжите их, используя:
@ViewChild('trans-foo) transFoo : ElementRef; .

Затем получить переведенное значение
transFoo.nativeElement.textContent .

Выглядит отсталым, но работает для моих нужд.

Поскольку ng-xi18n уже обрабатывает весь TS-код, почему бы не реализовать декоратор вроде @i18n() для (строковых) свойств? Затем они могут быть заполнены переведенным значением, например, @Input() используется с односторонней привязкой данных.
Если непереведенное значение не может быть легко извлечено из кода, просто поместите его в аргумент следующим образом:

@i18n( {
  source : 'Untranslated value',
  description: 'Some details for the translator'
} )
public set translatedProperty( value : string ) {
   this._translatedProperty = value;
}

и передать источник в свойство, когда нет цели перевода.

Это важный пункт во всем цикле интернационализации, ИМО.

В моем магазине мы привыкли к инструменту типа ng-xi18n (расширение xgettext), который просматривает все типы исходных файлов в поисках помеченного текста для помещения в файлы словарей для переводчиков.

Мне нравится чистая и простая разметка i18n в HTML-шаблонах, и я ожидал того же от кода Typescript.

@vicb В дополнение к вашим вариантам использования я думаю о возможности поддержки локализации интерполированной строки в коде TS. Однако, вероятно, потребуется переписать код TS для поддержки такого сценария. Будет ли это правильным подходом?

Это основная особенность, которая мешает нам использовать готовый подход к переводу предложений Angular 2. У нас есть много компонентов, управляемых метаданными, чьи ключи исходят из некоторых метаданных, не хранящихся в HTML. Если бы мы могли переводить через конвейер или программно в соответствии с доступными TRANSLATIONS, мы могли бы заставить эти компоненты отображать правильные строки.

В то же время мы ограничены чем-то вроде ng-translate из-за этого ограничения.

Я решил эту проблему, добавив пустой объект lang в службу, используемую в моем приложении. Затем я применяю директиву, которая считывает весь диапазон в div и сохраняет значение в этом объекте. Я помещаю всю свою строку в шаблон внизу страницы со скрытым свойством. Затем строка становится доступной из шаблона или компонента. Это уродливо, и вы можете легко перезаписать запись с тем же идентификатором. Но это лучше, чем ничего.

ОКАЗАНИЕ УСЛУГ

@Injectable()
export class AppService {

    //Language string object.
    private _lang:Object = new Object();
    get lang():Object {
        return this._lang;
    }
}

ДИРЕКТИВА

@Directive({
    selector: '[lang]'
})
export class LangDirective implements OnInit {

    constructor(
        public element: ElementRef,
        public app: AppService) {
    }

    ngOnInit() {
        let ele = this.element.nativeElement;
        for (var i = 0; i < ele.children.length; i++) {
            let id = ele.children[i].getAttribute('id');
            let value = ele.children[i].innerHTML;
            this.app.lang[id]=value;
        }
    }
}

ШАБЛОН

<button>{{app.lang.myButtonText}}</button>
<div lang hidden >
    <span id="myButtonText" i18n="Test Button">Testing</span>
</div>

Привет @lvlbmeunier

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

<p *ngFor="let d of dataEntry">{{app.lang[d.name]}}</p>
<div lang hidden >
<span id="{{d.name}}" *ngFor="let d of dataEntry" i18n>{{d.name}}</span>
</div>

Эти новые ключи не отображаются в моих файлах xliff. Можно ли добиться этого с помощью вашего решения?

Я никогда не пробовал, но я почти уверен, что сборка файла xliff не запускает код. Наличие динамического значения в i18n противоречило бы концепции. Если вы точно знаете все имена, которые будут в вашем списке, все они должны быть объявлены независимо, а не в цикле for.

Добавление ключей вручную работает, но нецелесообразно. В моем случае я получаю сотни текстовых ключей, нуждающихся в переводе из API.

Вы можете запустить свой код, взять исходный код и скопировать его в файл. Создание файла x18n основано на статическом файле.

С помощью 4.0.0-beta вы можете назначить идентификатор i18n , например, mainTitle:

<span i18n="title@@mainTitle">

При этом мы можем, по крайней мере, для компилятора JIT создать фиктивный компонент (его не нужно добавлять в html приложения, только модуль приложения) со всеми нашими «дополнительными» переводами.

Для начала добавим провайдеров не только в компилятор, но и в модуль приложения:

// bootstrap.ts
getTranslationProviders().then(providers => {
    const options = { providers };
    // here we pass "options.providers" to "platformBrowserDynamic" as extra providers.
    // otherwise when we inject the token TRANSLATIONS it will be empty. The second argument of
   // "bootstrapModule" will assign the providers to the compiler and not our AppModule
    platformBrowserDynamic(<Provider[]>options.providers).bootstrapModule(AppModule, options);
});

Затем мы создадим фиктивный компонент для размещения наших дополнительных переводов, не забудьте добавить компонент в declarations из AppModule . Это сделано для того, чтобы ng-xi18n мог найти html (я думаю) и добавить его в файл перевода.

//tmpI18N.ts
import {Component} from '@angular/core';

@Component({
    selector: 'tmpI18NComponent',
    moduleId: module.id,
    templateUrl: 'tmp.i18n.html'
})
export class TmpI18NComponent {
}

Добавьте наши переводы в tmp.i18n.html :

<!-- tmp.i18n.html -->
<span i18n="test@@mainTitle">
    test {{something}}
</span>

Теперь мы можем создать сервис, куда мы сможем получать наши переводы:

import {Injectable, Inject, TRANSLATIONS} from '@angular/core';
import {I18NHtmlParser, HtmlParser, Xliff} from '@angular/compiler';

@Injectable()
export class I18NService {
    private _source: string;
    private _translations: {[name: string]: any};

    constructor(
        @Inject(TRANSLATIONS) source: string
    ) {
        let xliff = new Xliff();
        this._source = source;
        this._translations = xliff.load(this._source, '');
    }

    get(key: string, interpolation: any[] = []) {
        let parser = new I18NHtmlParser(new HtmlParser(), this._source);
        let placeholders = this._getPlaceholders(this._translations[key]);
        let parseTree = parser.parse(`<div i18n="@@${key}">content ${this._wrapPlaceholders(placeholders).join(' ')}</div>`, 'someI18NUrl');

        return this._interpolate(parseTree.rootNodes[0]['children'][0].value, this._interpolationWithName(placeholders, interpolation));
    }

    private _getPlaceholders(nodes: any[]): string[] {
        return nodes
            .filter((node) => node.hasOwnProperty('name'))
            .map((node) => `${node.name}`);
    }

    private _wrapPlaceholders(placeholders: string[]): string[] {
        return placeholders
            .map((node) => `{{${node}}}`);
    }

    private _interpolationWithName(placeholders: string[], interpolation: any[]): {[name: string]: any} {
        let asObj = {};

        placeholders.forEach((name, index) => {
            asObj[name] = interpolation[index];
        });

        return asObj;
    }

    private _interpolate(pattern: string, interpolation: {[name: string]: any}) {
        let compiled = '';
        compiled += pattern.replace(/{{(\w+)}}/g, function (match, key) {
            if (interpolation[key] && typeof interpolation[key] === 'string') {
                match = match.replace(`{{${key}}}`, interpolation[key]);
            }
            return match;
        });

        return compiled;
    }
}

Теперь мы можем сделать что-то вроде:

export class AppComponent {

    constructor(i18nService: I18NService) {
        // Here we pass value that should be interpolated in our tmp template as a array and 
        // not an object. This is due to the fact that interpolation in the translation files (xlf for instance)
        // are not named. They will have names such as `<x id="INTERPOLATION"/>
        // <x id="INTERPOLATION_1"/>`. And so on.
        console.log(i18nService.get('mainTitle', ['magic']));
    }
}

Это хакерский обходной путь. Но, по крайней мере, мы можем использовать файл перевода, получить по ключу, интерполировать и не иметь скрытого html в нашем приложении.

ПРИМЕЧАНИЕ. Текущий пакет NPM @angular/compiler-cli версии 4.0.0-beta имеет неправильную версию зависимостей @angular/tsc-wrapped . Это указывает на 0.4.2, должно быть 0.5.0. @vicb это легко исправить? Или стоит ждать следующего релиза?

@fredrikredflag Потрясающе! А как же АОТ?

@ghidoz AOT — это отдельная история. Что мы хотели бы сделать, так это предварительно скомпилировать все переводы, чтобы мы могли получить их по ключу. Но поскольку ngc заменит все i18n правильным переводом, мы не сможем его использовать. Не удается найти открытые параметры/свойства, содержащие проанализированные переводы из ngc . Мы могли бы использовать тот же динамический подход, что и для JIT, извлекая файл xlt таким образом, по-прежнему предоставляя его на токене TRANSLATION . Однако это идет вразрез с целью AOT.

НЕ ДЕЛАЙТЕ ЭТОГО ДЛЯ ЛЮБЫХ ПРОИЗВОДСТВЕННЫХ ПРИЛОЖЕНИЙ .

/// bootstrap.aot.ts
function fetchLocale() {
    const locale = 'sv';
    const noProviders: Object[] = [];

    const translationFile = `./assets/locale/messages.${locale}.xlf`;
    return window['fetch'](translationFile)
        .then(resp => resp.text())
        .then( (translations: string ) => [
            { provide: TRANSLATIONS, useValue: translations },
            { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
            { provide: LOCALE_ID, useValue: locale }
        ])
        .catch(() => noProviders);
}

fetchLocale().then(providers => {
    const options = { providers };
    platformBrowser(<Provider[]>options.providers).bootstrapModuleFactory(AppModuleNgFactory);
});

Текущие размышления о том, как это реализовать:

@Component()
class MyComp {
  // description, meaning and id are constants
  monday = __('Monday', {description?, meaning?, id?});
}
  • поскольку мы не могли повлиять на структуру DOM с помощью такой конструкции, мы могли бы поддерживать переводы во время выполнения — была бы единственная версия двоичного файла, и разрешение происходило бы во время выполнения,
  • мы также можем поддерживать статические переводы, как мы это делаем сегодня для шаблонов — строки будут заменены во время компиляции, лучше производительность, но одна версия приложения для каждой локали,
  • мы могли бы, вероятно, позже поддерживать __(...) в шаблонах,
  • это будет реализовано с помощью преобразователя TS, доступного в версии 2.3 — у нас, вероятно, был прототип раньше.

/cc @ocombe

Я предполагаю, что __() предназначен для метода, у которого еще нет имени (и этот метод на самом деле не будет __ , верно?)

Это хорошая идея для статических переводов, которые вы можете использовать в своих классах, и я думаю, что их довольно просто реализовать.

Нет, __() — это имя, тебе не нравится :)

Оно обычно используется в фреймворках перевода, но вы сможете import {__ as olivier} from '@angular/core' , если предпочитаете другое имя!

эээээх это не очень понятно :D
Это похоже на очень личную функцию

Мне тоже не нравится название метода ___ :) Я представлял, что это будет сервис?
В любом случае, приятно видеть прогресс 👍

Мне нравиться __()! :D Очень геттекстовый и короткий.

В мире JS у меня есть опыт работы только с @ocombes ng2-translate, где пометка всего текста с помощью this._translateService.instant() делает код несколько труднее для чтения по сравнению с более короткой альтернативой, такой как предложенная здесь.

ничто не мешает вам переименовать службу перевода ng2 в __ , вы знаете :)

На самом деле, я понятия не имею, как обернуть метод службы DI в простую функцию - в любом случае, неважно, это выходит за рамки этой проблемы :-) Мой комментарий был просто +1 за использование __, как это хорошо известно, если вы' я когда-либо использовал другие фреймворки перевода, по крайней мере, в мире PHP.

хорошо, может быть, ___ подходит, лучше, чем "this.translationService.getTranslation()", намного короче.
И да, вы можете переименовать его, если хотите.

Как насчет i18n(...) вместо __(...) ?

Пожалуйста, прекратите споры о названии, это не главное. Спасибо.

@vicb с monday = __('Monday', {description: 'First day of the week', id: 'firstDatOfWeek'}); можно ли разрешить по id, т.е.:

__('@<strong i="8">@firstDatOfWeek</strong>') // Monday

Также будет ли Monday локальным для класса, который он определил, или его можно будет разрешить из любого места? Я думаю об общих переводах, таких как «закрыть», «открыть» и т. д.

Мне было интересно, какой на данный момент лучший обходной путь, который вы, ребята, рекомендуете использовать с AOT , пока официальный выпуск не поддержит его?

С уважением,
Шон

Angular 2 Кухонная раковина: http://ng2.javascriptninja.io
и источник @ https://github.com/born2net/Angular-kitchen-sink

@vicb есть новости, там ^

Пока эта функция не реализована, я использую функцию перевода атрибутов .

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

@Component({
    selector: 'app-sandbox',
    templateUrl: 'sandbox.html'
})
export class SandboxComponent implements OnInit {
    @Input()
    public title: string;

    constructor() {
    }

    ngOnInit() {
        console.log('Translated title ', this.title);
    }
}

Из шаблона родительского компонента:

<app-sandbox i18n-title title="Sandbox"></app-sandbox>

Это обходной путь, но, тем не менее, я думаю, что на данный момент он самый чистый. Это дает вам доступ к переведенным title в пределах ts .

Я начинаю работать над этой функцией, ожидайте дизайн-документ в ближайшее время :-)

это будет самая ожидаемая функция

Это хорошие новости. Спасибо @ocombe .

Документ с дизайном доступен здесь: https://goo.gl/jQ6tQf
Любая обратная связь приветствуется, спасибо.

мило, скоро прочитаю!

Спасибо @ocombe

Я прочитал документ. Красивое резюме.

Возможность извлечь строку из файлов ts звучит потрясающе.

Я не уверен, когда обновление Typescript будет доступно для Angular4.

Это означает, что эта функция, которая уже должна быть доступна в течение нескольких месяцев, потому что почти все столкнулись с этим ограничением, не смогут использовать это решение, по крайней мере, еще 3/6 месяцев.

Возможно, сейчас я не единственный, кто использует ngx-translate для управления переводами в моих контроллерах, в то время как я полагаюсь на angular i18n для шаблонов.

Цель слить все в i18n явно велика.

Но помимо упрощения с точки зрения понимания того, как реализовать i18n в среде angular, действительно ли этот подход повысит производительность по сравнению с текущей реализацией ngx-translate?

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

Также большим ограничением сейчас является множественное число, пожалуйста, убедитесь, что оно работает правильно, когда вы выпускаете полное обновление. Я прочитал много билетов, связанных с i18n, где xliff и xmb не обработали бы это правильно. Это еще один случай, когда мне нужно вернуться к ngx-translate, чтобы предоставить работающее решение.

@ocombe Спасибо за подробный документ по дизайну, похоже, это действительно хорошее решение для этого запроса функции. Текущий дизайн относится к вариантам использования, которые я пытаюсь решить.

Один вопрос: в проекте говорится о службе I18N для режима JIT и преобразователе TS 2.2.x для режима AOT. Правильно ли я предполагаю, что преобразователь заменит вызов метода службы на статическую трансляцию, а также удалит все оставшиеся ссылки на службу I18N?

@Thommas Angular 4 будет использовать TypeScript 2.1 (что означает, что вам придется обновиться), но на самом деле вы уже можете использовать любую более позднюю версию TypeScript (например, 2.2.1) с Angular 2 или 4.

С точки зрения прироста производительности по сравнению с ngx-translate это зависит от того, используете ли вы AOT или нет. Если вы используете AOT, то это выигрыш, но вы, вероятно, не увидите разницы. В JIT (без AOT) не будет никакого выигрыша (на самом деле это зависит от того, используете ли вы наблюдаемый get или синхронный метод instant , наблюдаемый стоит больше, чем простой вызов функции).
Я говорю об i18n в вашем коде здесь. Если мы говорим о шаблонах, то есть реальный видимый выигрыш, если вы используете Angular i18n (в AOT и JIT), потому что он не использует привязки. Чем больше переводов вы используете, тем больше вы получаете.

Я прослежу, чтобы множественное число работало точно так же, как и для шаблонов. Есть ли сейчас какие-либо проблемы с этим в шаблонах?

@schmuli единственный раз, когда Angular может заменить ваш код, — это когда вы используете AOT. Если вы этого не сделаете, то служебные вызовы в вашем коде останутся прежними.
Но если вы используете AOT, то вызов службы будет заменен статическим переводом (только переменные, которые вы можете использовать, останутся динамическими). Я не уверен, удалим ли мы ссылки на сервис I18n, потому что в будущем его можно будет использовать для других целей, мне нужно будет посмотреть, что возможно с преобразователем, когда я начну писать код. Вы думаете о прецеденте, где это может быть проблемой?

@ocombe Я не могу придумать вариант использования, в котором оставление кода было бы проблемой, если только мы не рассмотрим дополнительную инъекцию DI, которая не будет использоваться (это реальная проблема?).

Учитывая то, что вы написали о том, что служба может быть использована для других целей в будущем, и возможность возникновения ошибок при изменении кода пользователя, я бы сказал, что, вероятно, лучше вообще избегать удаления кода.

Возможно, было бы полезно использовать сервис для получения текущей локали в AOT. Рассмотрим, например, случай, когда у вас есть сервер, который может возвращать текст на нескольких языках, поэтому вам потребуется текущая локаль для включения в запрос. Однако вы всегда можете использовать фиктивную переведенную строку в качестве обходного пути.

@diego0020 diego0020 вы уже можете получить локаль, просто введите LOCALE_ID из ядра

@ocombe Множественное число не реализовано с xliff, и никто за пределами Google не знает, как использовать его с xmb. См. также: https://github.com/angular/angular/issues/13780 .

В любом случае, ничто не блокирует нашу реализацию i18n прямо сейчас, ngx-translate с конвейером множественного числа пока подойдет. Будем надеяться, что в NG4 все будет выглядеть лучше, и в документации будут отражены улучшения. Спасибо.

@Thommas ICU с xliff скоро будет исправлено: https://github.com/angular/angular/pull/15068 , и если вы хотите знать, как его использовать, это в документации: https://angular.io/docs/ ts/latest/cookbook/i18n.html#! #мощность

Пожалуйста, извините, Есть ли ETA? Потому что я слышал, что он будет доступен в версии ng4.0.0, но нет! Спасибо

Копия @ocombe

Мы все еще работаем над дизайном, есть много неожиданных вещей, которые нужно учитывать (например, как библиотеки могут выпускать собственные переводы),...
Ожидайте этого для 4.2, но это не гарантируется.

хорошо, спасибо @ocombe , у меня есть два вопроса, пожалуйста:

  1. На самом деле мы можем перевести текст в шаблоне, который включает интерполяцию, например:
    <span i18n>This is {{myValue}}</span>
  1. Я спрашиваю, потому что на самом деле я не могу извлечь, я не знаю, почему я получаю эту ошибку:
    Could not mark an element as translatable inside a translatable section

@истити

  1. Да, ты можешь.
  2. вам нужно обратить внимание на расположение вашей директивы i18n, она должна быть размещена непосредственно на элементе, содержащем текст, а не на каких-либо других элементах того же уровня.
    Например:
    <div i18n><span i18n>my text</span></div> - это нехорошо
    <div><span i18n>my text</span></div> - это хорошо

@royiHalp
Спасибо

  1. Хорошо, как перевести с интерполяцией?
  2. При извлечении ngc я получаю файл, строку и фрагмент кода, но у меня нет i18n, завернутого в другой i18n.
    Очень сложно найти, у кого из моих родителей случайно есть атрибут i18n

@истити

  1. вы делаете это, как и любой другой элемент, просто добавляете директиву i18n, как вы это делали:
    <span i18n>This is {{myValue}}</span>
    результат в файле messages.xlf будет таким:
    <source>This is <x id="INTERPOLATION"/></source>
    теперь, когда вы переводите его на разные языки, вы должны поместить <x id="INTERPOLATION"/> в правильное место в предложении, чтобы помочь другим понять ваш смысл, вы можете добавить описание к директиве i18n следующим образом:
  1. по моему опыту ошибка Could not mark an element as translatable inside a translatable section такова, как я объяснил, я помню, что если я внимательно прочитаю ошибку, я смогу заметить, в каком файле у меня проблема.

@fredrikredflag Огромное спасибо!

Ваш код очень полезен! Мне просто нужно было исправить одну проблему, потому что кажется, что в настоящее время xliff.load возвращает другой объект, поэтому this._translations необходимо настроить на:

const loaded = xliff.load(this._source, '');
this._translations = loaded['i18nNodesByMsgId'] ? loaded['i18nNodesByMsgId'] : {};

и небольшая проверка в методе get , если мы запрашиваем несуществующий ключ:

const placeholders = this._getPlaceholders(this._translations[key] ? this._translations[key] : []);

Кроме того, я думаю, что пустой компонент i18n был встряхнут или что-то в этом роде, поэтому мне пришлось включить строки в соответствующие шаблоны компонентов с помощью:

<span hidden i18n="@@MY_STRING_1">String 1</span>
<span hidden i18n="@@MY_STRING_2">String 2</span>

К счастью, мне нужно всего несколько строк для моего мини-приложения, чтобы оно отлично работало в продакшене с AoT.
Спасибо еще раз!!!

P/S: на данный момент необходимо использовать инструмент xliffmerge Мартина Рооба, а также его TinyTranslator B-)

Я использую компиляцию AoT, и мой проект поддерживает два языка: английский и русский. Я нашел временное решение проблемы, используя конфигурацию среды.

Файл environments/environment.ts содержит:

import { messagesEn } from '../messages/messages-en';

export const environment = {
  production: false
};

export const messages = messagesEn;

Также есть еще два файла environment.prod-en.ts и environment.prod-ru.ts следующего содержания:

import { messagesEn } from '../messages/messages-en';

export const environment = {
  production: true
};

export const messages = messagesEn;

И для русского:

import { messagesRu } from '../messages/messages-ru';

export const environment = {
  production: true
};

export const messages = messagesRu;

Каждый файл сообщения может содержать что-то вроде этого:

export const messages = {
  MessageKey: 'Translation',
  AnotherMessageKey: 'Translation',
  Group: {
    MessageKey: 'Translation',
    AnotherMessageKey: 'Translation',
  }
};

В моем коде (компонентах, службах и т. д.) я просто импортирую сообщения:

import { messages } from '../../environments/environment';

И используйте их:

alert(messages.MessageKey);

В .angular-cli.json я указал следующие среды для производства:

"environments": {
  "dev": "environments/environment.ts",
  "prod-en": "environments/environment.prod-en.ts",
  "prod-ru": "environments/environment.prod-ru.ts"
}

Оно работает!

@alex-chuev Вы пробовали это с JIT?

@ocombe какая-нибудь приблизительная оценка, когда это будет доступно?

Отличная функция кстати :)

Это отложено до тех пор, пока не будут внесены изменения в компилятор, поэтому не для 4.2, я все еще надеюсь сделать это для 4.3.

кто-нибудь знает, как реализовать i18n в значениях параметров, например, в [title] в следующем примере:
так другими словами добавь перевод к слову ПРИВЕТ

С Уважением

Шон

Если HELLO — это просто строка, которую вы вводите в HTML-шаблон, вы можете сделать следующее:
```html

````
В документации есть такой пример. Посмотрите здесь: https://angular.io/docs/ts/latest/cookbook/i18n.html#! #translate-атрибуты

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

@ocombe

Мы все еще работаем над дизайном, есть много неожиданных вещей, которые нужно учитывать (например, как библиотеки могут выпускать собственные переводы),...

Это очень важно. Я надеюсь, что это тоже часть этой функции. Потому что на данный момент я не вижу, как сторонняя библиотека может предоставить переводы для вашего приложения. Во время сборки вы можете указать только 1 файл XLIFF, и, похоже, вам нужно предварительно собрать свою библиотеку для вашего языка, чтобы иметь возможность ее переводить.

Ага, я тоже этого жду! Это ОЧЕНЬ важно для проектов, предназначенных для неанглоязычной аудитории!

Это определенно то, что мы хотим поддерживать, команда работает над рефакторингом компилятора, который позволит нам это сделать :-)

Есть ли оценка, для какой версии она будет предназначена? Я где-то читал, что это может быть около 4,3?

Боюсь, что из-за необходимости рефакторинга (и критических изменений) это будет не раньше v5.

Чоооо 😳 О, нет, я жду эту функцию для 4.2, о которой вы сказали, и теперь она для v5 ☹️ Я думал, что для v5 будет динамическое изменение языка, а не выпуск для каждой версии, но в любом случае надеюсь, что это будет один день, даже с 36 тысячами разных сборок для каждой версии. язык. Мне просто интересно, когда будет v5? Спасибо

@ocombe

@istiti Я сказал, что это не гарантированная дата ;-)
График выпуска находится здесь: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md .
Окончательный выпуск v5 — 2017–09–18, но до этого будут бета-версии и RC.

Есть ли какие-либо изменения для создания одного файла локали для каждого компонента? означает создание фрагментов messages.xlf , например: messages.{component}.{locale}.xlf и, например, только messages.{component}.xlf для языка по умолчанию.

Еще нет

Ущерб строго минимальный из-за времени сборки @ocombe

Я в замешательстве... Является ли этот запрос на изменение/изменение официальным или нет?
Здесь такая же проблема, переводы просто не применяются только к шаблонам.
Имея избыточность, пользовательские компоненты древовидной структуры и т. д., все они сгенерированы из объектов javascript В КОДЕ, а не для шаблона.

Это официально, и это будет, но сначала нам пришлось внести другие глубокие изменения в компилятор, поэтому он не был готов для 4.3.

Известно ли, в какой именно версии эта функция будет доступна/планируется? 4.3.1, 4.3.2... 4.3.Х?

Для ветки 4.x больше нет основной/младшей версии (только патчи: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md), что означает, что это будет для 5.x , не уверен, какой.

Ожидается ли, что это все еще попадет в 5.x? Я не вижу его в бета-версиях. Спасибо

Может быть в v50.x не v5.x 😂

5.х да, но в 5.0 скорее всего не будет

Le jeu. 3 августа 2017 г., 12:56, [email protected] , запись:

Может быть в v50.x не v5.x 😂


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/angular/angular/issues/11405#issuecomment-319936876 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AAQMorXMbyI8l6K3QA4jmXEKawiEC46xks5sUad0gaJpZM4J2pkr
.

Привет , @ocombe. Я очень заинтересован в том, чтобы заставить это работать, а то, как сейчас работает компилятор, делает эту задачу более сложной. У вас есть какая-то ясность относительно того, как выглядит временная шкала, или это все же не 5.0, а какая-то 5.x?

@arackow , скорее всего, это будет в 5.x, @vicb работает над последними изменениями в компиляторе, которые, наконец, сделают это возможным

@ocombe ... есть ли какой-нибудь проектный документ, описывающий концепцию решения для строк вне шаблонов? Мы находимся на этапе разработки проекта, и было бы здорово это знать, чтобы мы могли как-то подготовить наше временное решение, и позже было бы намного проще переключиться на окончательный синтаксис Angular.

У нас был дизайн-документ, но он был основан на предыдущей версии компилятора, и, вероятно, это не та реализация, которую мы в конечном итоге сделаем. Мы сделаем новый общедоступный дизайн-документ, как только у нас будет лучшее представление о новой реализации.

@ocombe Мне нужно добавить +1 к этой функции. серьезная потребность в этом прямо сейчас, лол :+1: Спасибо, ребята, за создание потрясающих инструментов! :)

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

Это хороший момент @ gms1.
Я тестировал это здесь .
Как автору библиотеки вам нужно только добавить теги i18n.
Вы не должны компилировать свою библиотеку в « ngfactories » (см. выступление Джейсона Адена на ng-conf 2017), поэтому тег перевода не будет заменен. Таким образом, когда вы запускаете команду ng xi18n , вы также получаете перевод в xliff для файлов в вашей папке node_modules.

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

цитата из проектной документации:

Для AOT исходный код преобразуется для замены вызовов службы статическими переводами. Для этого мы будем использовать преобразователь TypeScript.

Итак, что бы это значило, если бы библиотека angular (AOT) обычно публиковалась в транспилированном виде? Я не нашел ссылок на .metadata.json в этом документе.

Вы не должны компилировать свою библиотеку в окончательный код, а подготавливать ее для компиляции разработчиком с использованием вашего кода. Посмотрите, что @jasonaden упоминает здесь . Это также означает, что вы можете сделать свою библиотеку переводимой, добавив тег i18n.

@ gms1 , как я уже сказал:

У нас был дизайн-документ, но он был основан на предыдущей версии компилятора, и, вероятно, это не та реализация, которую мы в конечном итоге сделаем.

И компилятор AOT сильно изменен для v5, библиотекам должно быть проще публиковать «готовый к aot» код.
Для i18n мы также хотим сделать это как можно более простым/гибким, это, вероятно, будет что-то вроде: библиотеки могут публиковать файлы перевода, которые вы можете использовать, но которые вы также можете переопределить, если хотите, и вы должны быть в состоянии предоставить дополнительные языки, если библиотека не поддерживает их по умолчанию

Спасибо @ocombe за это разъяснение!

@ocombe Означает ли это, что функции ngx-translate будут доступны в самом angular?

@ montreal91 ни одна из частей ngx-translate не может быть реализована как есть в angular, у моей библиотеки очень наивный подход, она работает «в основном», но мы хотим быть намного эффективнее с фреймворком.
При этом angular будет предоставлять аналогичные функции (даже если окончательная реализация будет другой).

Это мой подход (FLUX), пока я работаю над системой уведомлений пользовательского интерфейса на основе (https://github.com/PointInside/ng2-toastr). Проблема в том, что содержимое уведомления определяется в сервисном вызове, а не в шаблоне, которым управляет система angular i18n (xi18n).

Это не то, что мне бы хотелось, но это _рабочее_ решение. Вы можете _извлечь_ идею из следующих фрагментов кода. Надеюсь, поможет :)

в любом месте

// this call in any other component, service... 
// "info" method parameter is the "id" of the HTML element in template NotificationComponent.html
this.notificationActionCreator.success("myMessage");

NotificationComponent.ts

@Component({
    selector: 'notification-cmp',
    templateUrl: '../../public/html/NotificationComponent.html'
})
export class NotificationComponent implements OnInit, OnDestroy, AfterViewInit {

    notificationMap: Map<string, any> = new Map();
    subscription: Subscription;

    constructor(private toastr: ToastsManager,
                private vcr: ViewContainerRef,
                private store: NotificationStore,
                private elementRef: ElementRef) {

        this.toastr.setRootViewContainerRef(vcr);
    }

    ngOnInit() {
        this.subscription = this.store.payload
            .subscribe((payload: NotificationStorePayload) => this.handleStorePayload(payload));
    }

    ngOnDestroy(): void {
        this.store.destroy();
        if (null != this.subscription) {
            this.subscription.unsubscribe();
        }
    }

    ngAfterViewInit(): void {
        this.elementRef.nativeElement.querySelectorAll("div[notification-title][notification-text]")
            .forEach(el => this.notificationMap.set(el.id, {
                    title: el.attributes["notification-title"].value,
                    text: el.attributes["notification-text"].value,
                })
            );
    }

    handleStorePayload(payload: NotificationStorePayload): void {

        if (null != payload.action) {
            let notification = this.notificationMap.get(payload.notification.id);

            switch (payload.notification.type) {
                case NotificationType.SUCCESS:
                    this.toastr.success(notification.text, notification.title);
                    break;
                case NotificationType.INFO:
                    this.toastr.info(notification.text, notification.title);
                    break;
                case NotificationType.WARNING:
                    this.toastr.warning(notification.text, notification.title);
                    break;
                case NotificationType.ERROR:
                    this.toastr.error(notification.text, notification.title);
                    break;
            }
        }
    }
}

NotificationComponent.html

<div hidden
     id="myMessage"
     i18n-notification-title="@@notificationTitleMyMessage"
     i18n-notification-text="@@notificationTextMyMessage"
     notification-title="Greeting"
     notification-text="Hello world"></div>

<div hidden
     id="error"
     i18n-notification-title="@@notificationTitleError"
     i18n-notification-text="@@notificationTextError"
     notification-title="Error"
     notification-text="Something went wrong!"></div>

Теперь, когда Angular 5 выпущен, есть ли у нас какие-либо изменения, когда будут интегрированы изменения в модуле i18n?

Похоже, что эта функция зависит от изменений в компиляторе angular, но команды, ответственные за компилятор, кажутся менее заинтересованными. Это не похоже на задачу, PR или коммит :- (. Извините за высказывание, но этот запрос функции, который описывает очень базовую функциональность, присутствующую в любой другой платформе перевода, уже больше года. Я дал надеюсь, что эта важная функция появится, по крайней мере, для 5.x...

Ребята сохраняйте спокойствие. Это не глупо реализовать в компиляторе AOT. Имейте немного доверия, @ocombe сказал:

"скорее всего это будет в 5.x, @vicb работает над последними изменениями в компиляторе, которые, наконец, сделают это возможным"

Да, прямо сейчас мы работаем над средой выполнения i18n, что является первым шагом.
i18n во время выполнения означает: один пакет для всех языков, AOT-скомпилированные библиотеки могут использовать i18n и, возможно, позже возможность смены языка во время выполнения. Это также означает, что мы можем выполнять переводы во время выполнения, что необходимо для переводов внутри кода (потому что нам нужен анализатор времени выполнения для переводов и т. д.).
Как только это будет сделано, следующим приоритетом станут переводы внутри кода.

Но мы не могли сделать i18n во время выполнения, пока не изменили компилятор для использования преобразователей машинописного текста (что было сделано для версии 5.0).

Есть идеи, какая версия 5.x будет иметь какие улучшения i18n? Что-нибудь выпускается с самим 5.0.0?

5.0:

  • новые каналы i18n (дата/число/процент/валюта), которые не используют intl API, исправлено около 20 ошибок, потому что теперь они работают одинаково во всех браузерах + некоторые другие улучшения (параметр локали, новые дополнительные форматы, параметр часового пояса для финиковая трубка, ...)
  • новая API-функция i18n для библиотек и компонентов: https://next.angular.io/api?query=getlocale
  • лучшая интеграция с cli

5.1 или 5.2 (если нет неожиданного блокировщика):

  • время выполнения i18n

5.х:

  • Переводы кода i18n (не только шаблон)

И другие вещи, которые мы добавим по ходу, но еще не решены (вы можете следить за https://github.com/angular/angular/issues/16477).

Просто любопытные мысли, хотя я немного опоздал, просто учитывая поддержку i18n в файле TS, почему бы нам не подумать о синтаксисе аннотаций? (Я обнаружил, что кто-то упомянул об этом выше)

Примером может быть:
@i18n (id='message1')
message1 = "Это сообщение нужно перевести";

@i18n (id='dynamicMessage')
dynamicMessage = "Это динамическое сообщение с {0}";

С аннотацией для dynamicMessage мы можем внедрить функцию через аннотацию в этот экземпляр строки, имя которой — format , затем мы можем использовать, как показано ниже:
var finalMessage = dynamicMessage.format('value1')

Подобный подход может быть возможен для заботы об именованных параметрах и т. д.

Я предполагаю, что вопрос не в том, как сделать хороший опыт разработчика. Вопрос в компиляции.

Также что произойдет, если вы измените message1 на другую строку? Тогда все переменные i18n всегда должны быть константами. Я не думаю, что использование переменных вообще сработает. Например, в Symfony есть служба-переводчик с функцией перевода, которая в синтаксисе JS будет работать следующим образом: let translated = this.translator.trans('Hello %name%', [{'%name%': nameVariable}]); , что приведет к: <source>Hello %name%</source> <target>Bonjour %name%</target>

@MickL смысл текущего перевода -aot в том, чтобы сделать минимальную и эффективную программу. Поэтому подхода к динамическому переводу пока не существует.
Я твердо верю, что текущий подход действительно хорош в том смысле, что мы не используем службу динамики для перевода строк. Это означает, что если вы знаете, что какой-то текст статичен, пожалуйста, переведите его таким образом, не используя службу.

Проблема с динамическим переводом проста, если вы собираетесь переводить строку каждый раз, когда вы ее показываете. Это не очень хороший способ,
Почему?

  1. Потому что у вас в памяти есть словарь нескольких языков, когда вы им не пользуетесь.
  2. Каждый раз, когда вы показываете динамический текст, вам нужно перейти к карте и найти ключ, а затем найти языковой перевод. КАЖДЫЙ РАЗ, потому что у вас есть «основной язык».

С моей точки зрения, будущее решение должно быть:

  1. Backend дает вам текст, который вы хотите перевести.
  2. Замените/(или загрузите из бэкэнда, что является текущим подходом) каждый текст, который вы показываете на текущем/основном языке. (заменить все получится вовремя, но вам не нужно находить два ключа каждый раз, когда вы хотите показать простую метку).
  3. Только действительно динамический текст может быть заменен и/или запрошен на серверной части.

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

На мой взгляд, нет необходимости больше обсуждать этот вопрос. На самом деле есть парень (Оливье Комб), который ПОЛНОСТЬЮ работает над i18n. AOT очень особенный, и нужно было проделать много работы, прежде чем сделать эту проблему хотя бы близкой к возможной. Скоро у нас будут динамические переводы: больше не нужно создавать каждый язык отдельно! Когда это будет сделано, позже у нас будут переводы внутри кода (этот выпуск). Он сказал, что дорога до решения этого вопроса, надеюсь, займет полгода.

Если вам интересно, ознакомьтесь с его выступлением на Angular Connect от 07.11.17 о настоящем и будущем i18n в Angular: https://youtu.be/DWet6RvhHWI?t=21m12s

Это пахнет хорошим вариантом использования для строк шаблона с тегами машинописного текста...

Это вообще запах. Я посещаю эту ветку раз в месяц, чтобы проверить прогресс, и перестал разочаровываться из-за заниженных ожиданий. Единственное, чего хотят разработчики, — это иметь те же возможности перевода строк в коде, что и в шаблонах. Мой код пронизан скрытыми переведенными строками шаблонов из-за отсутствия функциональности. Будет ли это в конечном итоге достигнуто с помощью службы или аннотаций, не имеет значения, и не имеет значения, если это займет дополнительную миллисекунду. Я уже что- то наблюдаю за изменениями, когда выбираю строку из кода. Единственное требование состоит в том, чтобы код анализировался, а соответствующие строки оказывались в тех же файлах с тем же форматом, что и мои переводы на основе шаблонов.

@eliasre , вы можете попробовать https://github.com/ngx-translate/i18n-polyfill , если вы спешите с переводом кода
никаких обещаний, что это будет то же самое, хотя на самом деле это, вероятно, будет по-другому (например, проще в использовании), есть ограничения на то, что возможно прямо сейчас ... и это добавит ~ 80ko к вашему приложению для использования эта библиотека

Вы можете использовать ngx-translate, если не хотите ждать

@ocombe , не могли бы вы предоставить обновленную информацию о прогрессе, чтобы мы могли отслеживать и планировать в соответствии со сроками разработки, когда ждем решения о том, какие плагины или фреймворки использовать? было бы очень полезно и ценно

@eliasre Я думаю, что Google хочет сразу найти хорошее решение. Без нарушения изменения в будущем. Я согласен, что это занимает гораздо больше времени, чем мы думаем.

Не беспокойте бедного @ocombe , он очень, ОЧЕНЬ усердно работает!
Так держать! :)

Я не тот, кто работает над этой функцией, и сейчас каникулы, я дам вам знать, как только узнаю больше

спасибо @ocombe

спасибо @ocombe , здесь будут очень признательны за любые обновления. Я отчаянно ждал запуска i18n в течение последних нескольких месяцев, и последняя сборка ETA была 5.2. Не могли бы вы сообщить нам, как только у вас появится обновленное ETA?

Извините за настойчивость, но сборка для 20 языков на данный момент оказывается мучительно медленной.

Поскольку Angular 5.2 вышел, и, к сожалению, я не смог найти ничего, связанного с i18n (или я что-то упустил из виду?) ... - @ocombe , может быть, вы могли бы сообщить нам о плане выпуска? Большое спасибо и большое спасибо за ваши усилия по i18n!

@ocombe не тот парень, которого мы здесь ждем... посмотрите ссылку на YouTube в этом комментарии: https://github.com/angular/angular/issues/11405#issuecomment -343933617

Планировка постоянно развивается. Всякий раз, когда я называю возможную дату выпуска, оказывается, что что-то другое получает приоритет или становится обязательным, и это снова сдвигает дату. Я знаю, как это разочаровывает всех, кто ждет этой функции, и я делаю все возможное, чтобы повысить приоритет.
У нас завтра встреча, чтобы обсудить отставание/планирование i18n, я дам вам знать, если узнаю что-нибудь новое.

@ocombe , если ты выпустишь i18n в этом месяце, я куплю тебе 24 упаковки крафтового пива

Я добавлю 24 бутылки немецкого пива и еще 24 бутылки, если вы спросите, что делает Angular Elements и поддержка библиотек. Черт, не получать информацию о том, что происходит, ужасно.

@ocombe у вас есть редкая возможность раз в жизни приобрести 72 бутылки дорогого крафтового пива и порадовать сообщество разработчиков. Мы выполним наши обещания, если ты выполнишь это, мой друг.

@MickL Angualr Elments, насколько я понимаю, позволит нам создавать не-SPA-страницы и использовать угловые компоненты в качестве нативных элементов (в том числе и как собственные виджеты)

Да, я знаю. Это еще 2 функции, которых все ждут, но никто не знает, в каком статусе и когда их ожидать...

Если только кто-то пообещает добавить последние 27 бутылок пива, мы можем начать их обратный отсчет!
http://www.99-bottles-of-beer.net/language-javascript-1948.html

Я добавлю их, @ocombe : назовите свой любимый бренд :D

Редактировать: кто-то создаст сервис, похожий на eth bounty, под названием пивобаунти: p

Как и было обещано, небольшое обновление: мы все еще стремимся выпустить рантайм i18n в v6, что дает нам 5 недель. Он будет коротким, возможно, его добавят в одном из последних релизов, и он будет за флагом.
Среда выполнения i18n должна поставляться с переводами кода, потому что в любом случае она будет работать и для шаблонов (в ней должен использоваться тот же механизм).
При этом нет уверенности, что сервис будет готов на 100%, и мы можем отложить его, чтобы убедиться, что мы не сломаем его сразу после его выпуска, если мы считаем, что это правильный выбор. Но в любом случае он будет следовать i18n во время выполнения (это наша дорожная карта), и нам не нужна основная версия для его выпуска, потому что он будет за флагом и в любом случае не должен ничего ломать).

Что могло помешать нам выпустить его вовремя:

  • если мы наткнемся на неожиданную проблему (вы знаете, как работает разработка)
  • если это сломает внутренние приложения Google, потому что мы где-то напортачили
  • если появится что-то первоочередное, и нам придется переключить внимание
  • если одна из новых вещей, от которых он зависит, заблокирована или задержана (время выполнения i18n зависит от некоторых серьезных внутренних изменений, над которыми работают другие члены команды)
  • Старший разработчик angularJS, использует библиотеку перевода PascalPrecht в течение 3 лет.
  • Взволновал меня. Новичок в Angular 2. Наивный просмотр https://angular.io/guide/i18n
  • Успешная интеграция i18n в мой профессиональный проект
  • Целый день возился со всеми жестко закодированными метками внешнего интерфейса, портируя их в файл xlf размером более 100 КБ.
  • При необходимости перевода необработанных меток в службах ng
  • Глядя на это в Google, будь здесь
  • Узнайте, что решения не существует до того, как Angular 6 возрастет.
  • меня р-н
    mfw

@Macadoshis , вы можете использовать мою библиотеку polyfill: https://github.com/ngx-translate/i18n-polyfill

@Macadoshis, теперь представьте, через что мы прошли со времен alpha.46! ;)

Спасибо, что указали мне на i18n-polyfill @ocombe , но я выберу ngx-translate , так как он поддерживает асинхронную загрузку ключей перевода.
Фабрика i18n-polyfill для поставщика TRANSLATIONS , по-видимому, поддерживает только синхронную необработанную загрузку фиксированной локали, известной до начальной загрузки.

// sync loading
return require(`raw-loader!../locale/messages.${locale}.xlf`);
// @ngx-translate/i18n-polyfill/esm5/ngx-translate-i18n-polyfill.js
Tokenizer.prototype._advance = function () {
    //...
    this._index++;
    // "this._input" needs to be a string and can't handle a Promise or an Observable
    this._peek = this._index >= this._length ? $EOF : this._input.charCodeAt(this._index);
    this._nextPeek = this._index + 1 >= this._length ? $EOF : this._input.charCodeAt(this._index + 1);
}

@ocombe , насколько полифилл, который вы написали, близок к тому, что выпускается? Что-то, о чем мы должны знать или к чему готовиться? Кроме того, не могли бы вы перечислить список функций i18n, которые будут выпущены в версии 6, и как проходит тестирование i18n?

У меня пока нет более подробной информации о службе перевода кода, мы поработаем над ней, вероятно, на следующей неделе (я еду в Маунтин-Вью). Все, что я знаю, это то, что за сценой это будет похоже на goog.getMsg из библиотеки закрытия (поскольку это то, что Google сейчас использует внутри): https://github.com/google/closure-library /blob/db9bc1a2e71d4b6ee8f57eebe37eb0c6494e9d7e/closure/goog/base.js#L2379 -L2387, который также похож на мой полифилл.

В версии 6 мы выпустим рантайм i18n: один пакет для всех локалей, переводы, решаемые во время выполнения, и, возможно, переводы кода, если у нас будет время (иначе это произойдет вскоре после этого). Все это будет скрыто флагом, потому что для этого требуется использовать новый рендерер (называемый ng-ivy), который не будет проходить боевые испытания.

Спасибо! @ocombe ... звучит очень красиво!
Будут ли критические изменения в синтаксисе перевода шаблонов? Я думаю о добавлении переводов в наш проект сейчас, но не хочу полностью переделывать его через несколько недель.

Нет, синтаксис шаблона будет таким же

Спасибо @ocombe за отличные новости, это очень многообещающе. Какую готовность к производству мы можем ожидать от средства визуализации ng-ivy, которое будет выпущено с v6? Я понимаю, что он не будет протестирован в бою, но он все равно будет готов к использованию в производстве и будет работать во всех основных браузерах, близких к последней версии, верно?

Вы можете следить за прогрессом здесь: https://github.com/angular/angular/issues/21706 .
Я не думаю, что все будет готово для версии 6, поскольку она находится под флагом, что мы будем продолжать работать над этим даже после выпуска версии 6 (это не критическое изменение или что-то в этом роде).
Честно говоря, я не уверен, что все это :D
Я знаю, что приложение hello world из cli уже работает.
Я думаю, что некоторые из этих вещей необходимы, чтобы извлечь выгоду из оптимизации нового рендерера, но, вероятно, он может работать без проверки всего.
При этом это также означает, что он не будет готов к производству, пока не ставьте на него свой продукт. Он не будет тестироваться во внутренних приложениях Google, и нам может потребоваться внести некоторые критические изменения, чтобы исправить ситуацию. Использование нового рендерера на ваше усмотрение и на свой страх и риск

Есть ли что-то из этого в v6-beta4?

Нет, это не так. Проверьте эту дорожную карту , эта функция заблокирована средой выполнения i18n.

обновляет @ocombe ?

Первый PR для среды выполнения i18n был объединен с мастером вместе с демонстрационным приложением hello world, которое мы будем использовать для тестирования функций. Он работает во время выполнения и теоретически поддерживает переводы кода, даже если для него еще нет службы.
На данный момент это очень минимальная поддержка (статические строки), мы работаем над добавлением новых функций (на следующей неделе я сделаю извлечение, а затем динамическую строку с заполнителями и переменными).
После этого мы выполним услугу по переводу кода.
Как только новая функция будет завершена, она будет объединена с мастером, вам не придется ждать нового майора.

@ocombe i heart Функции i18n уже должны быть здесь, в версии 4.3 !! Столько релизов, а на i18n ничего. Может ли менеджер команды angular выделить больше работ / разработчиков, я могу понять, что вы один или два разработчика не можете двигаться вперед быстро, эта функция i 18n является обязательной функцией, чтобы притворяться, что angular является бизнес-приложением / большим приложением с быстрой сборкой, конечно эти две функции являются наиболее важными для большого приложения, вы так не думаете? Спасибо

Я думаю, единственное, что мы можем сказать @ocombe , это поблагодарить его за все усилия, которые он вкладывает в эту функцию. Я уверен, что если разработчиков больше нет, то не потому, что он их не просил. Просто дайте ему это сделать, я уверен, что мы не пожалеем, когда он выйдет.

Просто для справки...

У меня есть альтернативный инструмент для импорта и экспорта строк, изначально разработанный для использования с Aurelia, который включает поддержку строк, хранящихся в файлах json — это очень удобно, так как Webpack позволяет напрямую импортировать json файлы в ваши файлы ts , предоставляя вашему коду легкий доступ к этим строкам.

Этот инструмент также работает с шаблонами Angular и имеет множество других полезных функций — используйте его, если хотите, или не стесняйтесь заимствовать идеи для улучшения инструментов Angular. На его основе также есть загрузчик Webpack — см. ссылку в документации.

https://www.npmjs.com/package/gulp-translate

У нас есть более простая проблема, и я не уверен, нужна ли нам предстоящая функция (или полифилл от @ocombe).

Мы определяем структуру всех реактивных форм с помощью констант, в которых задаем свойства каждого элемента формы. Например:

loginForm = [
  {
    type: 'email',
    placeholder: 'EMAILPLACEHOLDER' // "Your email"
  },
  {
    type: 'password,
    placeholder: 'PASSWORDPLACEHOLDER' // "Your password"
  }
];

В настоящее время мы используем ngx-translate , поэтому в шаблоне мы переводим строки следующим образом:

<input *ngFor="let ele of loginForm" [type]="ele.type" [placeholder]="ele.placeholder | translate">

Теперь мы хотели бы перейти на Angular i18n. Однако, поскольку не все наши строки находятся в шаблоне, кажется, что мы не можем использовать Angular i18n из коробки.

Однако наша ситуация выглядит проще, чем та, в которой переводы нужно получать во время выполнения. Все наши тексты предопределены в константах и ​​могут быть заменены во время компиляции, как это делает x18n в настоящее время для строк в шаблонах.

Например, у нас может быть более сложная строка, подобная следующей:

placeholder: 'I18N:description|meaning@<strong i="16">@PASSWORDPLACEHOLDER</strong>:Your password'

Во время компиляции строка может быть заменена на:

placeholder: 'Your password'

Это что-то, что можно было бы рассмотреть для реализации?

вы определенно можете сделать это с помощью i18n во время выполнения, вы можете использовать новый сервис i18n в канале, например, для преобразования ваших заполнителей в их переводы.

Я заметил, что эта ветка была открыта в течение некоторого времени, она демонстрирует большой интерес к разработке многоязычных сайтов в Angular простым способом, тесно обращаясь как с текстами HTML, так и с кодом компонентов.
ocombe, пожалуйста, не забудьте отправить всем подписчикам уведомление, когда это будет сделано — я так понял, что это не за горами к маю 2018 года. И спасибо за ваш добрый вклад!

@ocombe , мы должны использовать Ivy, чтобы иметь возможность использовать эти службы времени выполнения, или он будет работать и со старым движком?

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

Спасибо за всю вашу тяжелую работу @ocombe !

Что-нибудь известно о том, как скоро мы сможем использовать эти новые функции?

Ivy можно включить в angular 6 с помощью флага компилятора прямо сейчас, в состоянии перед выпуском. Можно ли в настоящее время использовать эти новые функции 18n в предварительной версии Ivy?

Пока нет, но я делаю хорошие успехи (прямо сейчас работаю над этим полный рабочий день). Я опубликую обновление здесь, как только оно будет доступно в мастере для тестирования.

большое спасибо @ocombe ! Так много людей получают пользу от вашего упорного труда. Мы все это очень ценим!

@ocombe Статические переводы в ts все еще планируются? Я имею в виду замену выражения времени компиляции, вероятно, с преобразованием машинописного текста.
Если нет, сможем ли мы подключить пользовательское преобразование ts к конвейеру ng build без извлечения ?

Я не уверен, что понимаю, что вы имеете в виду @TinyMan ? Вы имеете в виду возможность объединять переводы во время сборки (как сейчас) или возможность использовать переводы в коде ts (кроме переводов шаблонов, которые у нас уже есть)?

@ocombe Я имею в виду возможность использовать перевод в ts, но не через службу или перевод DI / во время выполнения. Я имею в виду перевод времени компиляции, но для машинописного текста. Как препроцессор C. Я думал, что это было запланировано в соответствии с комментарием vicb :

  • мы также можем поддерживать статические переводы, как мы это делаем сегодня для шаблонов — строки будут заменены во время компиляции, лучше производительность, но одна версия приложения для каждой локали,

Например, я хочу иметь возможность писать:

export const Notifications = {
    newComment: i18n("New comment notification@@newComment", "New comment on your story !"),
    newStory: i18n("New story notification@@newStory", "{{0}} wrote a new story !"),
}

И затем это преобразуется во что-то вроде (на фр.):

export const Notifications = {
    newComment: "Un nouveau commentaire a été ajouté a votre article !",
    newStory: "{{0}} a écrit un nouvel article !",
}

В настоящее время для этой цели я использую ngx-translate с настраиваемым маркером для извлечения ( i18n в этом примере), и когда мне нужно отобразить сообщение, я должен вызвать this.translate.instant(Notifications.newStory, ["TinyMan"]) , который выполняет перевод + интерполяция. Я имею в виду, что нам нужно иметь возможность написать Notifications.newComment без вызова службы перевода. И для интерполяции строк у нас может быть метод интерполяции, который выполняет только ICU и интерполяцию (строка шаблона уже будет переведена).

Notification.newStory // {{0}} a écrit un nouvel article, static string, no runtime translation
template(Notification.newStory, "TinyMan") // TinyMan a écrit un nouvel article !

Здесь мы просто избавляемся от HTTP-запроса перевода и накладных расходов на обслуживание.

надеюсь понятно?

То, что вы описываете, действительно входит в дорожную карту i18n.
На данный момент https://github.com/ngx-translate/i18n-polyfill подойдет.

@TinyMan Я еще не уверен, будет ли это через службу или глобальную функцию. Оба варианта возможны, но сервис также имеет много преимуществ: вы можете сделать его моком для тестов или заменить его своим, вы также можете изменить его поведение для каждого модуля/компонента.
Я знаю, что внутри Google будет использовать Closure i18n (через goog.getMsg ), которая является глобальной функцией, и эта функция, скорее всего, будет заменена службой во время компиляции на основе глобального флага. Я попытаюсь посмотреть, можно ли этот флаг также использовать извне, но я не понимаю, почему бы и нет. Но если вы используете это, это будет для шаблонов и переводов кода.

@ocombe Я тоже хочу поблагодарить вас. Я очень ценю работу, которую вы делаете над этим, что будет невероятно полезно для меня в моей работе. Один вопрос: есть ли способ или _будет ли_ способ выполнить компиляцию AOT, которая создает только один набор файлов пакетов, которые при поиске текста ссылаются на xlf во время выполнения, чтобы получить правильную строку?

так что, по сути, вам понадобится 1 файл xlf для каждого языка плюс 5 или 6 файлов пакетов. Прямо сейчас, если у нас есть 10 языков и компиляция AOT, это более 50 файлов: набор файлов пакетов для каждого языка...

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

да, это то, что мы будем делать с плющом, время выполнения i18n
свяжите свое приложение один раз и загрузите переводы во время выполнения (вы можете лениво загружать переводы)

@ocombe это. является. невероятный.

Это делает меня невероятно счастливым. СПАСИБО!

Без возможности перевода внешних шаблонов функция i18n для меня совершенно бесполезна.

@ocombe Привет, Оливье!
Любые обновления?

Спасибо!

Если это будет сделано, это не имеет значения, так как нам нужно дождаться завершения Ivy, что запланировано для Angular 7 (сентябрь/октябрь 2018 г.)

К Angular 7 этой проблеме будет два года LOL.
В любом случае именно Айви задержала эту новую функцию больше всего...

@ocombe , приятно это слышать. В настоящее время мы застряли с использованием устаревшей службы i18n, которую мы развернули с нуля исключительно по этой причине. Из-за невозможности сделать это в JS нам чрезвычайно сложно сделать несколько простых вещей:

  • Динамические компоненты
  • Интеграция со сторонними сервисами, где мы должны предоставить локализованный текст для
  • Отображение динамических модальных форм подтверждения
  • Наш API возвращает ошибку types . В нашем контексте нам нужно динамически локализовать эти ошибки, и подход, основанный на шаблонах, будет неудобным.
  • Мы хотим использовать TitleService , как предлагает команда Angular, но нет возможности предоставить локализованный текст!

Мне любопытно, как команда Angular справляется с этим в настоящее время...

Привет @vincentjames501 ,
В нашей компании мы пытались сделать то же, что и вы сейчас, но это было очень хлопотно, поэтому в итоге мы использовали i18n-polyfill, упомянутый ранее в этой теме, и пока он отлично работает.
Единственный недостаток, который у нас есть, это размер пакетов нашего приложения. У нас есть три файла перевода, и каждый пакет содержит их все внутри (мы не придумали, как сгенерировать пакет только с используемым переводом). Но все это просто неприятности, которые, как мы надеемся, будут решены, когда Айви уйдет.
Ваше здоровье,

Я включил карту перевода и реэкспортировал ее в файл environment.ts для каждого языка. Он работает без проблем, не входит во все пакеты и не требует внешней библиотеки. Единственная проблема, с которой я столкнулся, заключается в том, что, поскольку каждый сайт отличается, я не могу иметь одного и того же работника службы для всех языков, и если кто-то переключает языки, мой сайт не может определить, зарегистрирован ли он уже для получения push-уведомлений или нет...

@ocombe есть новости об угловом 6?

Его не будет в Angular v6, как объяснялось выше. Мы зависим от Ivy, который планируется для v7.

@ocombe , могу я предложить вам заблокировать эту ветку, чтобы только команда могла предоставлять значимые обновления, когда это уместно, и мы избегали повторяющихся вопросов, на которые вы продолжаете отвечать?

Мой хак для использования с текущим Angular использует ng-template и программно создает встроенное представление:

<ng-template #messagetotranslate i18n>This message should be translated</ng-template>

а затем в файле компонента ts:

@ViewChild('messagetotranslate') messagetotranslate: TemplateRef<any>;

createTranslatedMessage(): string {
  return this.messagetotranslate.createEmbeddedView({}).rootNodes[0].textContent;
}

Метод createTranslatedMessage возвращает переведенное сообщение. Хотя я использую шаблон для объявления сообщения, которое не является оптимальным, это позволяет инструменту перевода CLI зарегистрировать его в файлах xlf, и у меня есть способ программно получить переведенное сообщение для использования вне шаблонов.

Надеюсь, API будет работать и для маршрутов! Например

export const routes: Routes = [
 {
  path: '',
  component: HomeComponent,
  data: {
   title: i18n('Home'),
   breadcrumb: i18n('Home')
  }
 }
]

Если эта функция будет выпущена, будут ли существенные изменения по сравнению с текущим API i18n? Вы бы порекомендовали мне начать свой проект с i18n сейчас или мне следует подождать нового i18n Api, когда выйдет Angular 7?

Любое обновление. Когда мы получим поддержку во время выполнения и динамического перевода?

Переводы во время выполнения сделаны и объединены (с ivy), но сторона компилятора еще не закончена.
Сейчас я работаю над выражениями в отделении интенсивной терапии.
Я еще не начал программировать динамические переводы (сервис), но это, вероятно, следующее, что я сделаю после выражений ICU.

@vincentjames501 Можем ли мы использовать i18n-polyfills с выражением ICU? У меня нет решения, как это реализовать

@ocombe , не могли бы вы пояснить разницу между временем выполнения и динамическим переводом?

официальной деноминации, вероятно, нет, но как я это вижу:

  • время выполнения: переводы разрешаются во время выполнения, то есть не во время сборки (как мы делаем сейчас). Это относится ко всем типам переводов (шаблонов или в коде)
  • динамический означает, что вы знаете только то, что хотите перевести во время выполнения, и вы не можете сделать это во время сборки. В основном это относится к переводам «в коде» с использованием службы. Я предполагаю, что вы могли бы считать выражения ICU динамическими в том смысле, что они зависят от переменной, но вы все равно можете вычислить все возможные переводы во время сборки, потому что количество случаев конечно.

Я отложил добавление поддержки i18n в текущий проект, который мы разрабатываем, но мы приближаемся к выпуску, есть идеи, будет ли это окончательным в angular 7? Или мне следует рассмотреть другие способы добавления переводов?

@andrei-tatar i18n отлично работает с Angular 2. Единственные недостатки:

  • Нет перевода кода (эта проблема) -> Если вам это нужно, используйте i18n-polyfill
  • Если вы создаете AOT (рекомендуется), приложение должно быть создано для каждого языка отдельно.
  • Поскольку каждое приложение создается отдельно, при переключении языка приходится перезагружать страницу.

Вместо последних двух пунктов вы можете использовать @ngx-translate. Но он работает иначе, чем встроенный в Angular i18n, поэтому более позднее обновление может занять некоторое время. Для полифилла обновление будет не раз, скорее всего, без критических изменений.

@ocombe

Как мы можем обрабатывать условный оператор, используя функцию Angular i18n

https://github.com/shobhit12345

Мы используем ngSwitch для шаблонизации всех сообщений, поэтому мы можем прикреплять теги i18n к
их по отдельности.

СкрыватьПоказыватьИстория

Мы часто используем этот метод, чтобы обойти отсутствующие динамические переводы.
Если немного подумать, удивительное количество текста может быть выражено в
таким образом в шаблонах. Общий шаблон состоит в том, чтобы иметь массив сообщений,
а затем используйте это с ngFor и ngSwitch для шаблона сообщений,
что-то вроде этого:

тс

messages = ['это первое сообщение', 'это второе сообщение']

HTML


i18n="@@firstMesssage">Это первое сообщение
i18n="@@secondMesssage">Это второе сообщение

Это несколько многословно - но это работает!


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/angular/angular/issues/11405#issuecomment-415731284 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AGwM6jcWIpwtGxhkH1fwnVXNagRxmMnoks5uT-LxgaJpZM4J2pkr
.

Если это будет сделано, это не имеет значения, так как нам нужно дождаться завершения Ivy, что запланировано для Angular 7 (сентябрь/октябрь 2018 г.)

Уже октябрь. Как вы думаете, появятся ли новые функции к концу октября?

@lizzymendivil согласно https://is-angular-ivy-ready.firebaseapp.com Ivy завершена на 65% и вряд ли будет завершена всего за 30 дней.

Да, плющ не будет готов за один месяц.

@ocombe , не могли бы вы заблокировать это, чтобы только вы могли публиковать обновления. немного раздражает получать все уведомления обо всех "когда это будет сделано?" Комментарии

@ocombe кажется, что Ivy сейчас примерно на 94%, как вы думаете, это может быть готово к концу года?

Я так не думаю. Быть готовым к функциональности и свободным от ошибок (= пригодным для использования) — это совсем другое. Сейчас мы в основном работаем над исправлением ошибок.

@ocombe можем ли мы поверить, что i18n появился раньше angular 8?

Я так не думаю. Быть готовым к функциональности и свободным от ошибок (= пригодным для использования) — это совсем другое. Сейчас мы в основном работаем над исправлением ошибок.

Хорошо, спасибо за оперативный ответ, очень признателен.

Любое обновление @ocombe о том, когда мы должны ожидать (конец года, который я вижу в последних нескольких комментариях), часть «Перевод кода» доступна вместе с «Переводом шаблона» для поддержки I18N с Angular? Мы думали объединить ngx-translate-polyfill для того же вместе с функцией Angular I18n, но там также кажется, что поддержка xlf недоступна для слияния существующего файла xlf с использованием https://github.com/biesbjerg/ngx-translate-extract CLI .

Спасибо !

@Абеконге

Мы используем ngSwitch для шаблонизации всех сообщений, поэтому мы можем прикреплять к ним теги i18n по отдельности.
Это несколько многословно - но это работает!

Спасибо за предложение! Это кажется самым простым для понимания. Мой вопрос: вы все еще используете эту реализацию в ситуациях, когда массив имеет «много» значений, например 10 или более? Похоже, код станет очень громоздким.

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

Дэйвид

День 23. янв. 2019 кл. 19.24 skrev Эндрю Биссада уведомления[email protected] :

@Абеконге

Мы используем ngSwitch для шаблонизации всех сообщений, поэтому мы можем прикреплять к ним теги i18n по отдельности.
Это несколько многословно - но это работает!

Спасибо за предложение! Это кажется самым простым для понимания. Мой вопрос: вы все еще используете эту реализацию в ситуациях, когда массив имеет «много» значений, например 10 или более? Похоже, код станет очень громоздким.


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите ветку.

Как использовать i18n-polifills в классах Validator. Я не могу использовать скрытое сообщение валидатора через сервис i18n.

//В компоненте
this.crForm= this.fb.group({
имя пользователя: [''],
электронный пароль: [''],
}, { валидатор: новый AccValidator(this.i18n).validate()}
);

//Валидатор

импортировать { AbstractControl, ValidationErrors, FormGroup, FormControl } из '@angular/forms';
импортировать {I18n} из '@ngx-translate/i18n-polyfill';
класс экспорта AccValidator{
конструктор (i18n:I18n)
{

}
validate() {       
    return (group: FormGroup): createAccountError => {
        if (group) {
            this.i18n("test");
}}}

получение ошибки ниже

Ошибка RROR: Uncaught (в обещании): TypeError: i18n не является функцией
TypeError: i18n не является функцией
в FormGroup.eval [в качестве валидатора] (acc-validator.ts:9)
в FormGroup.AbstractControl._runValidator (forms.js:3433)
в FormGroup.AbstractControl.updateValueAndValidity (forms.js:3387)
в новой группе форм (forms.js:4326)
в FormBuilder.group (forms.js:7864)

@ocombe

Как использовать i18n-polyfills с const в файлах .ts

экспортировать const glossayModel= () => [
{
заголовок: 'тестовые данные',
активно: правда,
данные: [

        [
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'Past Due',
                data: "test data."
            }

]]}];


{VAR_SELECT, выберите, Медицинский {Медицинский} Стоматологический {Стоматологический} Медицинский и стоматологический {Медицинский и стоматологический} Катастрофический и стоматологический {Катастрофический и стоматологический} Катастрофический {Катастрофический} }
{VAR_SELECT, выберите, Medical {Medical} Dental {Dental} Medical### & Dental {Medical y Dental}
Катастрофический ### и Стоматологический {Катастрофический и Стоматологический} Катастрофический {Катастрофический} }

Когда я использую выражение ICU со специальным символом, оно не преобразуется.

@ocombe Как обращаться с панировочными сухарями с помощью i18n-polyfills?

экспортировать постоянные маршруты: Routes = [
{
дорожка: '',
компонент: HomeComponent,
данные: {
название: 'Дом',
хлебная крошка: «Дом»
}
}
]

@ocombe

Как использовать i18n-polyfills с const в файлах .ts

экспортировать const glossayModel= () => [
{
заголовок: 'тестовые данные',
активно: правда,
данные: [

        [
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'Past Due',
                data: "test data."
            }

]]}];

Вы можете использовать вот так
{
данные: 'тестовые данные',
название: this.i18n({значение: 'Имя', идентификатор: 'имя'}),
}
введите полифилл I18n в конструктор компонентов, подобный этому
частный i18n: I18n
При использовании переводов в ts-файле вам нужно использовать ngx-extractor и xliffmerge, чтобы перевести эти ts-файлы. https://www.npmjs.com/package/ngx-i18nsupport

@ ЯннеХарью
он не работает, не получает данные в файле xlf.

Вот мой скрипт перевода:
"translate-i18n": "ng xi18n --output-path locale && ngx-extractor -i src/**/*.ts projects/**/*.ts -f xlf -o src/locale/messages.xlf && xliffmerge --profile xliffmerge.json fi en",

а вот xliffmerge.json

{
  "xliffmergeOptions": {
    "srcDir": "src/locale",
    "genDir": "src/locale",
    "i18nFile": "messages.xlf",
    "defaultLanguage": "en",
    "useSourceAsTarget": true
  }
}

@ ЯннеХарью
Да, я использую ту же конфигурацию и могу извлекать сообщения .ts в файл xlf.

Но const у меня есть в разных файлах .ts

экспортировать const glossayModel= () => [
{
}

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

Что делать, если вы используете константные значения, такие как provider.

{
    provide: glossayModel,
    useFactory: () => glossayModel()
}

код может быть сломан, но вы, возможно, поймете.

как перевести хлебные крошки

константные маршруты: Маршруты = [
{
путь: './enroll-new.component',
компонент: EnrollNewComponent,
данные: {
хлебная крошка: «Регистрация»
},
}
]

Можете ли вы, люди, перестать использовать эту тему в качестве темы поддержки для i18n-polyfill или других проблем? если у вас есть вопрос относительно i18n-polyfill, задайте вопрос в этом репозитории.
@ocombe , может быть, вы можете закрыть эту тему? почти все важное должно быть охвачено.
в какой угловой версии вы планируете выпустить поддержку i18n, упомянутую в этой теме?

Да, пока заблокирован.
Мы прилагаем все усилия, чтобы плющ был доступен с v8 в качестве добровольной бета-версии. Среду выполнения i18n можно будет использовать с закрытием Google (то, что Google использует внутри), что позволит нам отладить его (это очень большое изменение). Для всех остальных вы сможете протестировать ivy с помощью i18n, но не сможете загружать переводы. Приложение будет работать с исходным языком, используемым для написания кода приложения.
Служба среды выполнения, необходимая для фактического перевода, в настоящее время возвращает непереведенный текст. Поскольку мы все работаем над исправлением ошибок в существующем коде, новые функции будут ограничены после выпуска. Мы поработаем над этим, как только выйдет v8, это должно быть моей первой задачей.
Я добавлю обновление и разблокирую эту тему, как только у нас появятся новости.

Как бы то ни было, новый тег $localize , над которым мы работаем, можно использовать программно.

Например

const name = 'World';
$localize `Hello ${name}:name!`;

А затем сможет предоставить переводы для Hello {$name}! , которые можно заменить во время компиляции (или во время выполнения).

Это теперь доступно (если не задокументировано).

Была ли эта страница полезной?
0 / 5 - 0 рейтинги