Angular: i18n: Capaz de usar strings de tradução fora de um modelo

Criado em 7 set. 2016  ·  204Comentários  ·  Fonte: angular/angular

Estou enviando um ... (marque um com "x")

[x] feature request

Comportamento atual
https://github.com/angular/angular/issues/9104#issuecomment -244909246

Eu não acho que seja possível, como eu disse antes só funciona com texto estático, não vai analisar texto no código js, ​​apenas templates

Comportamento esperado/desejado
Ser capaz de traduzir strings usadas em qualquer lugar do código, usando uma API.

Reprodução do problema

Qual é o comportamento esperado?
Estou referenciando o uso de $translate.instant para expor casos de uso reais:

  • Texto renderizado personalizado:
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);

Mais exemplos:

  • Obtendo o nome do arquivo da imagem da imagem exportada de um relatório renderizado em 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;
    }
  • Às vezes você está traduzindo, às vezes usa dados de modelo (pode ser muito detalhado em um modelo):
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', '');
        }
    }
  • Usando um plug-in de gráfico de terceiros (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')
                    }
                }
            }
        });
  • Para configurar variáveis ​​de configuração e renderizar o texto sem pipes, pois nem sempre é uma string traduzida
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')
        };
  • Para definir window.title :) :
SetWindowTitle(title:string) {
        if (!!title) {
            this.$window.document.title = this.$translate.instant(title);
        }
    }
  • Formatação de data personalizada:
dateHuman(date:Date):string {
        return date.getDate() + ' ' + this.$translate.instant('GLOBAL_CALENDAR_MONTH_' + date.getMonth())
            + ' ' + date.getFullYear();
    }
  • Classifique as coisas com base nos valores traduzidos:
// 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();
        });
    }
  • Exporte dados brutos para CSV ou Excel com valores traduzidos:
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;
    }
  • Defina strings de configuração para plugins de terceiros:
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')
                ]
            }
        });
    }


Qual é a motivação/caso de uso para mudar o comportamento?
Ser capaz de traduzir strings fora dos templates.

Por favor, conte-nos sobre o seu ambiente:

  • Versão angular: 2.0.0-rc.6
  • Navegador: [todos]
  • Idioma: [TypeScript 2.0.2 | ES5 | SystemJS]

@vicb

i18n feature high

Comentários muito úteis

Eu acho que isso é um verdadeiro showtopper, i18n não está pronto para uso até que isso seja implementado.
Por exemplo, não consigo definir mensagens de validação traduzidas no código

Todos 204 comentários

Eu acho que isso é um verdadeiro showtopper, i18n não está pronto para uso até que isso seja implementado.
Por exemplo, não consigo definir mensagens de validação traduzidas no código

@ Mattes83 Você tentou dessa maneira?

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

:confused: A documentação diz como é bom ter mensagens de erro no código e o suporte à tradução requer qualquer coisa no template. Parece que há mais necessidade de comunicação.

@marcalj Eu sei dessa maneira... mas preciso ter strings localizadas nos meus arquivos ts.
@manklu concordo plenamente

Eu acho que isso é um verdadeiro showtopper, i18n não está pronto para uso até que isso seja implementado.
Por exemplo, não consigo definir mensagens de validação traduzidas no código

Sim, o mesmo aqui, acabei de mudar de ng2-translate para Angular2 i18n, pois prefiro usar módulos OOTB e é muito mais fácil extrair traduções (ng2-translate é mais demorado IMO)
Nesta fase, não consigo traduzir as mensagens de erro levantadas pelos meus serviços. Nenhuma solução alternativa também.

Se alguém quiser iniciar uma especificação de design, seria útil (ou seja, no Google Docs).

Precisaria listar todos os casos. Pensando rapidamente sobre isso, vejo a necessidade de

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

Olá pessoal, ótima solicitação de recurso :+1:

Existe alguma solução sugerida para traduzir textos *.ts?

@fbobbio O que tenho feito é criar elementos ocultos no template, ex.
<span class="translation" #trans-foo i18n>foo</span> .

Vincule-os usando:
@ViewChild('trans-foo) transFoo : ElementRef; .

Em seguida, recupere o valor traduzido
transFoo.nativeElement.textContent .

Parece retardado, mas funciona para as minhas necessidades.

Como o ng-xi18n já processa todo o código TS, por que não implementar um decorador como @i18n() para (string-)properties? Estes podem então ser preenchidos com o valor traduzido, como @Input() é usado com vinculação de dados unidirecional.
Se o valor não traduzido não puder ser facilmente extraído do código, basta colocá-lo no argumento da seguinte forma:

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

e alimente a origem na propriedade quando não houver destino de tradução.

Este é um item essencial em todo o ciclo de internacionalização, IMO.

Na minha loja, estamos acostumados a uma ferramenta "ng-xi18n - like" (uma extensão para xgettext) que rastreia todos os tipos de arquivos de origem procurando por texto marcado para colocar em arquivos de dicionário para os tradutores.

Adoro a marcação i18n limpa e fácil nos modelos HTML e esperava o mesmo para o código Typescript.

@vicb Além de seus casos de uso, estou pensando na possibilidade de oferecer suporte à localização de string interpolada no código TS. No entanto, é provável que seja necessário reescrever o código TS para dar suporte a esse cenário. Será uma abordagem válida?

Esse é o principal recurso que nos impede de usar a abordagem pronta para uso para a tradução que o Angular 2 oferece. Temos muitos componentes orientados a metadados cujas chaves vêm de alguns metadados não armazenados em HTML. Se pudéssemos traduzir via pipe ou programaticamente em relação às TRANSLATIONS disponíveis, poderíamos fazer com que esses componentes mostrassem as strings apropriadas.

Enquanto isso, estamos limitados a algo como ng-translate por causa dessa limitação.

A maneira como resolvi esse problema foi adicionando um objeto 'lang' vazio em um serviço usado em todo o meu aplicativo. Em seguida, aplico uma diretiva que lê todo o intervalo em uma div e armazeno o valor nesse objeto. Coloco toda a minha string em um modelo na parte inferior da página com uma propriedade oculta. A string é então acessível a partir do modelo ou do componente. É feio e você pode facilmente substituir uma entrada com o mesmo id. Mas é melhor que nada.

SERVIÇO

@Injectable()
export class AppService {

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

DIRETORIA

@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;
        }
    }
}

MODELO

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

Olá @lvlbmeunier

Obrigado por fornecer esta sugestão para uma solução alternativa enquanto aguardamos a implementação oficial. Tentei implementar sua solução, mas não consigo fazer com que as chaves de tradução dinâmicas sejam reconhecidas. Eu estava tentando fazer assim:

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

Essas novas chaves não aparecem nos meus arquivos xliff. É possível conseguir isso com sua solução?

Eu nunca tentei, mas tenho quase certeza de que a compilação do arquivo xliff não executa código. Ter valor dinâmico em i18n seria contrário ao conceito. Se você souber com certeza todos os nomes que estariam em sua lista, todos eles devem ser declarados independentemente e não em um loop for.

Adicionar as chaves manualmente funciona, mas é impraticável. No meu caso, recebo centenas de chaves de texto que precisam de tradução de uma API.

Você pode executar seu código e pegar a fonte e copiá-la para um arquivo. A geração do arquivo x18n é baseada em arquivo estático.

Com 4.0.0-beta você pode atribuir um id a i18n , por exemplo mainTitle:

<span i18n="title@@mainTitle">

Com isso podemos, pelo menos para o compilador JIT, criar um Component fictício (não precisa ser adicionado ao html do aplicativo, apenas o módulo do aplicativo) com todas as nossas traduções "extras".

Para começar, adicionaremos os provedores não apenas ao compilador, mas também ao módulo do aplicativo:

// 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);
});

Então vamos criar um componente fictício para abrigar nossas traduções extras, não se esqueça de adicionar o componente a declarations de AppModule . Isso é para que ng-xi18n possa encontrar o html (eu acho) e adicioná-lo ao arquivo de tradução.

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

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

Adicione nossas traduções a tmp.i18n.html :

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

Agora podemos criar um serviço onde podemos buscar nossas traduções:

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;
    }
}

Agora podemos fazer algo como:

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']));
    }
}

Esta é uma solução hacky. Mas pelo menos podemos alavancar o arquivo de tradução, obter por chave, interpolar e não precisar ter um html oculto em nossa aplicação.

NOTA: o atual pacote NPM @angular/compiler-cli do 4.0.0-beta tem uma versão de dependência incorreta de @angular/tsc-wrapped . Aponta para 0.4.2 deve ser 0.5.0. @vicb isso é facilmente corrigido? Ou devemos esperar pelo próximo lançamento?

@fredrikredflag Incrível! E o AOT?

@ghidoz AOT é outra história. O que gostaríamos de fazer é pré-compilar todas as traduções para que possamos obtê-las por chave. Mas como o ngc substituirá todos os i18n pela tradução correta, não podemos aproveitá-lo. Não é possível encontrar nenhuma opção/propriedade exposta que contenha as traduções analisadas de ngc . Poderíamos usar a mesma abordagem dinâmica do JIT, buscando o arquivo xlt dessa forma ainda fornecendo-o no token TRANSLATION . No entanto, isso vai contra o propósito da AOT.

NÃO FAÇA ISSO PARA NENHUM APP DE PRODUÇÃO .

/// 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);
});

Pensamento atual sobre como implementar isso:

@Component()
class MyComp {
  // description, meaning and id are constants
  monday = __('Monday', {description?, meaning?, id?});
}
  • como não poderíamos afetar a estrutura DOM com tal construção, poderíamos suportar traduções em tempo de execução - haveria uma única versão do binário e a resolução aconteceria em tempo de execução,
  • também podemos oferecer suporte a traduções estáticas como fazemos hoje para modelos - as strings seriam substituídas em tempo de compilação, melhor desempenho, mas uma versão do aplicativo por localidade,
  • provavelmente poderíamos suportar __(...) em modelos em algum momento posterior,
  • isso seria implementado através de um transformador TS disponível a partir de 2.3 - provavelmente poderíamos ter um protótipo antes.

/cc @ocombe

Suponho que __() é para um método que ainda não tem nome (e o método não seria realmente __ , certo?)

É uma boa ideia para traduções estáticas que você pode usar em suas classes e bastante simples de implementar, eu acho.

Não __() é o nome, você não gosta :)

É comumente usado em estruturas de tradução - mas você poderá import {__ as olivier} from '@angular/core' se preferir outro nome!

eeeeeh não é muito auto explicativo :D
Parece uma função muito privada

Também não gosto do nome do método ___ :) Imaginava que seria um serviço?
De qualquer forma, é bom ver o progresso 👍

Eu gosto __()! :D Muito gettext-y e é curto.

No mundo JS, só tenho experiência com @ocombes ng2-translate, onde marcar todo o texto com this._translateService.instant() torna o código um pouco mais difícil de ler em comparação com uma alternativa mais curta, como proposta aqui.

nada impede você de renomear o serviço de tradução ng2 __ você sabe :)

Na verdade, não tenho ideia de como envolver um método de serviço DI em uma função simples - de qualquer maneira, não importa, isso está além do escopo deste problema :-) Meu comentário foi apenas um +1 para usar __ como é bem conhecido se você ' Já usei outros frameworks de tradução, pelo menos no mundo PHP.

ok, talvez ___ seja bom, melhor que "this.translationService.getTranslation()", muito mais curto.
E sim, você pode renomeá-lo se quiser.

Que tal i18n(...) em vez de __(...) ?

Por favor, pare o debate sobre o nome, esse não é o ponto. Obrigado.

@vicb com monday = __('Monday', {description: 'First day of the week', id: 'firstDatOfWeek'}); será possível resolvê-lo por id, ou seja:

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

Além disso, Monday seria local para a classe definida ou seria possível resolver de qualquer lugar? Estou pensando em traduções comuns como "fechar", "abrir" etc.

Eu queria saber qual é a melhor solução atualmente que vocês recomendam usar com AOT até que o lançamento oficial o suporte?

Cumprimentos,
Sean

Pia de cozinha angular 2: http://ng2.javascriptninja.io
e source@ https://github.com/born2net/Angular-kitchen-sink

@vicb alguma novidade, por lá ^

Até que esse recurso seja implementado, estou usando o recurso de tradução de atributos .

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);
    }
}

Do modelo de componente pai:

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

É uma solução alternativa, mas ainda assim, acho que é a mais limpa até agora. Dá-lhe acesso ao title traduzido dentro de ts .

Estou começando a trabalhar neste recurso, espere um documento de design em breve :-)

este será o recurso mais esperado

Isso é uma boa notícia. Obrigado @ocombe .

O documento de design está disponível aqui: https://goo.gl/jQ6tQf
Qualquer feedback é apreciado, obrigado.

querida, estarei lendo o mais rápido possível!

Obrigado @ocombe

Eu li o documento. Belo resumo.

Ser capaz de extrair strings de arquivos ts parece incrível.

Não tenho certeza de quando a atualização do Typescript estará disponível para Angular4.

Isso significa que esse recurso que já deve estar disponível há meses, porque praticamente todo mundo se deparou com essa limitação não poderá usar essa solução antes de pelo menos 3/6 meses.

Eu posso não ser o único agora que usa ngx-translate para gerenciar traduções em meus controladores enquanto confio em angular i18n para os modelos.

O objetivo de mesclar tudo no i18n é obviamente ótimo.

Mas, além da simplificação em termos de compreensão de como implementar o i18n na estrutura angular, essa abordagem realmente aumentará o desempenho em comparação com a implementação atual do ngx-translate?

Pelo que entendi agora, o único bônus seria poder extrair strings dos controladores.

Além disso, uma grande limitação agora é a pluralização, por favor, certifique-se de que está funcionando corretamente quando você liberar toda a atualização. Eu li muitos tickets relacionados ao i18n em que xliff e xmb não lidariam com isso corretamente. Este é mais um caso em que preciso voltar ao ngx-translate para fornecer uma solução funcional.

@ocombe Obrigado pelo documento de design detalhado, parece uma solução muito boa para esta solicitação de recurso. O design atual aborda os casos de uso que estou tentando resolver.

Uma pergunta: O projeto fala de um serviço I18N para modo JIT, e um Transformador TS 2.2.x para modo AOT. Estou correto ao assumir que o transformador substituirá a chamada ao método de serviço por uma tradução estática e também removerá todas as referências restantes ao serviço I18N?

@Thommas Angular 4 usará o TypeScript 2.1 (o que significa que você terá que atualizar), mas você já pode usar qualquer versão mais recente do TypeScript (2.2.1, por exemplo) com o Angular 2 ou 4.

Em termos de ganho de desempenho em relação ao ngx-translate, depende se você usa AOT ou não. Se você usar AOT, é um ganho, mas provavelmente não verá a diferença. No JIT (sem AOT) não haverá nenhum ganho (na verdade depende se você usar o get observável ou o método síncrono instant , o observável custa mais do que uma simples chamada de função).
Estou falando de i18n em seu código aqui. Se estamos falando sobre os templates, então há um ganho real visível se você estiver usando o Angular i18n (em AOT e JIT) porque ele não usa ligações. Quanto mais traduções você usa, mais você ganha.

Vou garantir que a pluralização funcione exatamente da mesma forma que para os modelos. Existe algum problema agora com ele nos modelos?

@schmuli a única vez que o Angular pode substituir seu código é quando você usa o AOT. Caso contrário, as chamadas de serviço permanecerão as mesmas em seu código.
Mas se você usar AOT, a chamada de serviço será substituída por uma tradução estática (somente as variáveis ​​que você usar permanecerão dinâmicas). Não tenho certeza se vamos remover as referências ao serviço I18n, porque ele pode ser usado para outras coisas no futuro, terei que ver o que é possível com o transformador assim que começar a escrever o código. Você está pensando em um caso de uso em que isso seria um problema?

@ocombe Não consigo pensar em um caso de uso em que deixar o código seria um problema, a menos que consideremos uma injeção extra de DI que não será usada (isso é um problema real?).

Considerando o que você escreveu que o serviço pode ser usado para outras coisas no futuro e o potencial de erros introduzidos pela alteração do código do usuário, eu diria que provavelmente é melhor evitar a remoção total do código.

Talvez seja útil usar o serviço para obter a localidade atual no AOT. Considere, por exemplo, o caso em que você tem um servidor que pode retornar texto em vários idiomas, portanto, você precisará incluir a localidade atual na solicitação. No entanto, você sempre pode usar uma string traduzida fictícia como uma solução alternativa.

@diego0020 você já pode obter a localidade, basta injetar LOCALE_ID do núcleo

@ocombe Pluralization não é implementado com xliff e ninguém fora do google tem alguma idéia de como usá-lo com xmb. Veja também: https://github.com/angular/angular/issues/13780

De qualquer forma, nada está bloqueando nossa implementação i18n agora ngx-translate com um canal de pluralização fará por enquanto. Espero que tudo fique melhor no NG4 e a documentação reflita as melhorias. Obrigado.

@Thommas ICU com xliff será corrigido em breve: https://github.com/angular/angular/pull/15068 e se quiser saber como usar, está nos documentos: https://angular.io/docs/ ts/latest/cookbook/i18n.html#! #cardinalidade

Por favor, desculpe, existe algum ETA? Porque eu ouvi que estará disponível na versão ng4.0.0, mas não! Obrigado

Cc @ocombe

Ainda estamos trabalhando no design, há muitas coisas inesperadas a serem levadas em consideração (como como as bibliotecas podem enviar suas próprias traduções), ...
Espere isso para 4.2, mas não é garantido.

ok obrigado @ocombe , tenho duas perguntas por favor:

  1. Na verdade, podemos traduzir texto em modelo que inclua interpolação, como:
    <span i18n>This is {{myValue}}</span>
  1. Pergunto porque na verdade não consigo extrair, não sei porque recebo esse erro:
    Could not mark an element as translatable inside a translatable section

@istiti

  1. sim você pode.
  2. você precisa prestar atenção na localização da sua diretiva i18n, ela deve ser colocada diretamente no elemento que contém o texto, não em nenhum outro irmão.
    por exemplo:
    <div i18n><span i18n>my text</span></div> - isso não é bom
    <div><span i18n>my text</span></div> - isso é bom

@royiHalp
Obrigado

  1. Ok, como traduzir com interpolação?
  2. Ao extrair ngc, obtenha-me arquivo e linha e trecho de código, mas não tenho i18n envolvido em outro i18n
    Isso é realmente difícil de encontrar qual dos meus pais acidentalmente i18n atributo

@istiti

  1. você faz isso como qualquer outro elemento, basta adicionar a diretiva i18n como você fez:
    <span i18n>This is {{myValue}}</span>
    o resultado no arquivo messages.xlf será:
    <source>This is <x id="INTERPOLATION"/></source>
    agora, ao traduzi-lo para diferentes localidades, você deve colocar o <x id="INTERPOLATION"/> no lugar correto na frase, para ajudar os outros a entender seu significado, você pode adicionar uma descrição à diretiva i18n assim:
  1. pela minha experiência o erro Could not mark an element as translatable inside a translatable section é como eu expliquei, lembro que se eu ler o erro com atenção posso perceber em qual arquivo estou com o problema.

@fredrikredflag Muito obrigado!

Seu código é super útil! Eu só tive que corrigir um problema porque parece que xliff.load retorna um objeto diferente hoje em dia, então this._translations precisa ser ajustado para:

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

e uma validação menor no método get se pedirmos uma chave inexistente:

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

Além disso, acho que o componente i18n vazio foi abalado em árvore ou algo assim, então tive que incluir as strings nos modelos de componentes correspondentes com:

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

Por sorte, eu só preciso de uma pequena quantidade de strings para o meu miniApp, então ele funciona muito bem em produção com AoT.
Obrigado novamente!!!

P/S: a ferramenta xliffmerge de Martin Roob é de uso obrigatório no momento, e seu TinyTranslator também B-)

Eu uso a compilação AoT e meu projeto suporta dois idiomas: inglês e russo. Encontrei uma solução temporária para o problema usando a configuração do ambiente.

O arquivo environments/environment.ts contém:

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

export const environment = {
  production: false
};

export const messages = messagesEn;

Também existem outros dois arquivos environment.prod-en.ts e environment.prod-ru.ts com o próximo conteúdo:

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

export const environment = {
  production: true
};

export const messages = messagesEn;

E para russo:

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

export const environment = {
  production: true
};

export const messages = messagesRu;

Cada arquivo de mensagem pode conter algo assim:

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

No meu código (componentes, serviços, etc) eu apenas importo mensagens:

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

E use-os:

alert(messages.MessageKey);

Em .angular-cli.json eu especifiquei os próximos ambientes para produção:

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

Funciona!

@alex-chuev Você já tentou isso com JIT?

@ocombe alguma estimativa aproximada de quando isso estaria disponível?

Ótimo recurso btw :)

Está em espera até que sejam feitas alterações no compilador, então não para 4.2, ainda espero fazer isso para 4.3

alguém sabe como implementar i18n em valores de param por exemplo em [title] no exemplo a seguir:
então, em outras palavras, adicione tradução à palavra HELLO

Saudações

Sean

Se HELLO for apenas uma string que você digita no modelo HTML, você pode fazer o seguinte:
```html

````
A documentação tem um exemplo disso. Veja aqui: https://angular.io/docs/ts/latest/cookbook/i18n.html#! #translate-attributes

Se você precisar vincular a uma propriedade de string no componente, precisará aguardar esse recurso ou implementar uma maneira personalizada de tradução (que eu saiba).

@ocombe

Ainda estamos trabalhando no design, há muitas coisas inesperadas a serem levadas em consideração (como como as bibliotecas podem enviar suas próprias traduções), ...

Isso é muito importante. Espero que faça parte desse recurso também. Porque no momento não vejo como a biblioteca de terceiros pode fornecer traduções para seu aplicativo. Durante a compilação, você pode especificar apenas 1 arquivo XLIFF, e parece que você precisa pré-compilar sua biblioteca para que seu idioma tenha a capacidade de traduzi-la.

Sim, estou esperando por isso também! Isso é MUITO importante para projetos destinados a públicos que não falam inglês!

É definitivamente algo que queremos apoiar, a equipe está trabalhando na refatoração do compilador que nos permitirá fazer isso :-)

Existe uma estimativa para qual versão será direcionada? Eu li em algum lugar que pode ser em torno de 4,3?

Por causa da refatoração (e mudanças de quebra) necessárias, não será antes da v5, temo

Uau 😳 Oh não, estou esperando esse recurso para 4.2 que você disse e agora é para v5 ☹️ Eu estava pensando que a v5 será dinâmica mudando de idioma não liberando cada versão mas de qualquer forma espero que seja um dia mesmo com 36k build diferente para cada Língua. Eu só quero saber para quando é v5? Obrigado

@ocombe

@istiti eu disse que não era uma data garantida ;-)
O cronograma de lançamento está aqui: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md
A versão final da v5 é 2017-09-18, mas haverá betas e RCs antes

Há alguma alteração para criar um arquivo de localidade para cada componente? significa, criar pedaços de messages.xlf , por exemplo: messages.{component}.{locale}.xlf e por exemplo apenas messages.{component}.xlf para o idioma padrão.

Ainda não

Danmage é estrito minimu devido ao tempo de construção @ocombe

Estou confuso... Este pedido de alteração/alteração é oficial ou não?
Tendo o mesmo problema aqui, as traduções simplesmente não se aplicam apenas aos modelos.
Tendo redux, componentes de visualização em árvore personalizados etc... todos gerados a partir de objetos javascript IN CODE, não por template

É oficial e está chegando, mas tivemos que fazer outras mudanças profundas no compilador primeiro, e é por isso que ele não estava pronto para o 4.3

Sabe-se em qual versão exata esse recurso estará disponível / está planejado? 4.3.1, 4.3.2 ... 4.3.X ?

Não há mais versão principal/secundária para o branch 4.x (somente patches: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md) o que significa que isso será para 5.x , não tenho certeza de qual.

Isso ainda é esperado para entrar em 5.x? Não consigo ver nos betas. Obrigado

Pode estar em v50.x não em v5.x 😂

5.x sim, mas provavelmente não será em 5.0

Le jeu. 3 de outubro de 2017 às 12:56, vltr [email protected] um écrit :

Pode estar em v50.x não em v5.x 😂


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/angular/angular/issues/11405#issuecomment-319936876 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AAQMorXMbyI8l6K3QA4jmXEKawiEC46xks5sUad0gaJpZM4J2pkr
.

Oi @ocombe Estou muito interessado no processo para fazer isso funcionar e a maneira como o compilador funciona atualmente torna isso uma tarefa mais difícil. Você tem alguma clareza sobre a aparência da linha do tempo ou isso ainda não é 5.0, mas sim 5.x?

@arackow provavelmente estará em 5.x, @vicb está trabalhando nas últimas mudanças no compilador que finalmente tornarão isso possível

@ocombe ... existe algum documento de design que descreva um conceito da solução para strings fora dos modelos? Estamos em uma fase de desenvolvimento do projeto onde seria ótimo conhecê-lo, para que pudéssemos preparar de alguma forma nossa solução temporária e depois seria muito mais fácil mudar para a sintaxe final do Angular.

Tínhamos um documento de design, mas era baseado na versão anterior do compilador e provavelmente não é a implementação que acabaremos fazendo. Faremos um novo documento de design público assim que tivermos uma ideia melhor sobre a nova implementação

@ocombe eu tenho que marcar com +1 esse recurso. necessidade séria disso agora lol :+1: Obrigado a vocês por fazerem ferramentas incríveis! :)

Pelo que entendi do documento de design atual, um autor de uma biblioteca AOT precisaria fornecer as traduções para todos os idiomas exigidos pelos vários aplicativos que estão usando essa biblioteca.
Será que entendi isso corretamente?

Este é um bom ponto @gms1.
Eu testei isso aqui .
Como autor de biblioteca, você só precisa adicionar as tags i18n.
Você não deve compilar sua biblioteca para " ngfactories " (veja a palestra de Jason Aden em ng-conf 2017), então a tag de tradução não será substituída. Desta forma, quando você executar o comando ng xi18n , você também obterá uma tradução no xliff para os arquivos em sua pasta node_modules.

Portanto, não, você não precisa fornecer traduções, mas adicionar tags i18n com significados úteis.

citado do documento de design:

Para AOT, o código-fonte é transformado para substituir as chamadas de serviço por traduções estáticas. Para fazer isso, usaremos um transformador TypeScript.

Então, o que isso significaria se uma biblioteca angular (AOT) fosse publicada geralmente na forma transpilada? Não encontrei nenhuma referência a .metadata.json neste documento

Você não deve compilar sua biblioteca para o código final, mas prepará-la para ser compilada pelo desenvolvedor usando seu código. Veja o que @jasonaden menciona aqui . Isso também significa que você pode tornar sua biblioteca traduzível adicionando a tag i18n.

@gms1 como eu disse:

Tínhamos um documento de design, mas era baseado na versão anterior do compilador e provavelmente não é a implementação que acabaremos fazendo.

E o compilador AOT está sendo alterado extensivamente para a v5, deve ser mais fácil para as libs publicarem código "aot-ready".
Para i18n, queremos tornar isso o mais fácil/flexível possível, provavelmente será algo como: bibliotecas podem publicar arquivos de tradução que você pode usar, mas que você também pode substituir se preferir, e você deve poder fornecer idiomas adicionais também se a biblioteca não suportar por padrão

Obrigado @ocombe por este esclarecimento!

@ocombe Isso significa que os recursos do ngx-translate estarão disponíveis no próprio angular?

@ montreal91 nenhuma das partes do ngx-translate pode ser implementada como está em angular, minha lib tem uma abordagem muito ingênua, funciona "principalmente", mas queremos ser muito mais eficientes com o framework.
Dito isto, o angular fornecerá recursos semelhantes (mesmo que a implementação final seja diferente).

Esta é a minha abordagem (FLUX) enquanto estou trabalhando em um sistema de notificação de interface do usuário baseado em (https://github.com/PointInside/ng2-toastr). O problema é que o conteúdo da notificação é definido na chamada de serviço ao invés de um template a ser gerenciado pelo sistema angular i18n (xi18n)

Não é o que eu gostaria, mas é uma solução _funcionando_. Você pode _extrair_ a ideia dos seguintes fragmentos de código. Espero que ajude :)

qualquer lugar

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

Agora que o Angular 5 foi lançado, temos algum retorno sobre quando as mudanças no módulo i18n serão integradas?

Parece que esse recurso depende de alterações no compilador angular, mas as equipes responsáveis ​​pelo compilador parecem menos interessadas. Não parece que há uma tarefa ou um PR ou commits:- (. Desculpe por desabafar, mas esta solicitação de recurso que descreve uma funcionalidade muito básica presente em todos os outros frameworks de tradução agora tem mais de um ano. Eu dei espero que esse recurso essencial chegue. Pelo menos para 5.x...

Pessoal fiquem tranquilos. Não é uma coisa boba implementar em um compilador AOT. Tenha um pouco de confiança, @ocombe disse:

"provavelmente será em 5.x, @vicb está trabalhando nas últimas alterações no compilador que finalmente tornarão isso possível"

Sim, estamos trabalhando no tempo de execução i18n agora, que é o primeiro passo.
Runtime i18n significa: um pacote para todos os idiomas, bibliotecas compiladas AOT podem usar i18n e talvez mais tarde a capacidade de alterar o idioma em tempo de execução. Isso também significa que podemos fazer traduções em tempo de execução, o que é necessário para traduções dentro do código (porque precisamos de um analisador de tempo de execução para traduções, etc...).
Feito isso, a próxima prioridade serão as traduções dentro do código.

Mas não podíamos fazer o runtime i18n antes de mudarmos o compilador para usar transformadores typescript (o que foi feito para 5.0)

Alguma idéia de qual versão 5.x terá quais melhorias i18n? Alguma coisa sendo lançada com o próprio 5.0.0?

5.0:

  • novos pipes i18n (data/número/porcentagem/moeda) que não usam a API intl que corrigiu algo como 20 bugs porque agora eles funcionam da mesma forma em todos os navegadores + algumas outras melhorias (parâmetro de localidade, novos formatos adicionais, parâmetro de fuso horário para o tubo de data, ...)
  • nova função de API i18n para bibliotecas e componentes: https://next.angular.io/api?query=getlocale
  • melhor integração com o cli

5.1 ou 5.2 (se não houver bloqueador inesperado):

  • tempo de execução i18n

5.x:

  • traduções de código i18n (não apenas modelo)

E outras coisas que adicionaremos ao longo do caminho, mas ainda não decididas (você pode seguir https://github.com/angular/angular/issues/16477).

Apenas pensamentos curiosos, embora eu esteja um pouco atrasado, apenas considerando o suporte a i18n em um arquivo TS, por que não pensamos na sintaxe da anotação? (Achei que alguém mencionou isso acima também)

Exemplo seria:
@i18n (id='mensagem1')
message1 = "Esta é uma mensagem que precisa ser traduzida";

@i18n (id='dynamicMessage')
dynamicMessage = "Esta é uma mensagem dinâmica com {0}";

Com a anotação para dynamicMessage, podemos injetar uma função através de anotação para esta instância de string, cujo nome é format , então podemos usar como abaixo:
var mensagem final = dynamicMessage.format('value1')

Uma abordagem semelhante pode ser possível para cuidar de parâmetros nomeados , etc.

Acho que a questão não é como fazer uma boa experiência de desenvolvedor. A questão é sobre a compilação.

Além disso, o que acontece se você alterar message1 para outra string? Todas as variáveis ​​i18n precisam ser sempre constantes então. Eu não acho que usar variáveis ​​​​funcionaria. Por exemplo, o Symfony tem um serviço de tradução com uma função de tradução que funcionaria assim na sintaxe JS: let translated = this.translator.trans('Hello %name%', [{'%name%': nameVariable}]); que resultará em: <source>Hello %name%</source> <target>Bonjour %name%</target>

@MickL o ponto da tradução -aot atual é fazer um programa mínimo e eficiente. É por isso que ainda não existe uma abordagem para tradução dinâmica.
Acredito firmemente que a abordagem atual é muito boa, no sentido de que não estamos usando o serviço de dinâmica para traduzir strings. Isso significa que, se você souber que algum texto é estático, traduza dessa maneira sem usar um serviço.

O problema com a tradução dinâmica é simples, ou seja, se você vai traduzir uma string toda vez que a estiver mostrando. Não é uma maneira muito boa,
Por quê?

  1. Porque você tem um dicionário de vários idiomas na memória quando não está usando.
  2. Toda vez que você está mostrando um texto dinâmico, você precisa ir ao mapa e encontrar uma chave e, em seguida, encontrar a tradução do idioma. TODAS AS VEZES porque você tem um "idioma principal".

Do meu ponto de vista, a solução futura deve ser:

  1. O backend fornece o texto que você deseja traduzir.
  2. Substitua/(ou baixe do backend que é a abordagem atual) todo texto que você está mostrando no idioma atual/principal. (substitua tudo, ganhe tempo, mas você não precisa encontrar duas chaves toda vez que quiser mostrar um rótulo simples).
  3. Apenas texto verdadeiramente dinâmico pode ser substituído e/ou solicitado ao backend.

Pense nisso, se você realmente tem texto dinâmico para mostrar, você pode recebê-lo do backend, e se você realmente precisa de uma cópia desse "texto dinâmico", você sempre pode usar o cache para isso.

Na minha opinião, não há mais necessidade de discutir este assunto. Na verdade tem um cara (Olivier Combe) trabalhando FULLTIME no i18n. AOT é muito especial e muito trabalho teve que ser feito antes de tornar essa questão ainda mais próxima possível. Em breve teremos traduções dinâmicas: Não há mais necessidade de construir cada idioma separadamente! Quando isso for feito, teremos traduções dentro do código (essa questão) mais tarde. Ele disse que o caminho até que esse problema seja resolvido, espero, leve meio ano a partir de agora.

Se você estiver interessado, confira o discurso dele no Angular Connect em 07.11.17 sobre o presente e o futuro do i18n em Angular: https://youtu.be/DWet6RvhHWI?t=21m12s

Isso cheira a um bom caso de uso para strings de modelo marcadas com texto datilografado ...

Isso cheira em geral. Eu visito este tópico uma vez por mês para verificar o progresso e parei de me decepcionar por causa das expectativas baixas. A única coisa que os desenvolvedores querem é ter as mesmas opções para tradução de strings no código e nos templates. Meu código está cheio de strings de modelo traduzidas ocultas devido a essa falta de funcionalidade. Se isso eventualmente é realizado com um serviço ou anotações é irrelevante e não importa se leva um milissegundo extra. Já estou observando algo para mudanças quando estou escolhendo uma string do código. O único requisito é que o código seja analisado e as strings relevantes acabem nos mesmos arquivos com o mesmo formato que minhas traduções baseadas em modelo.

@eliasre você pode tentar https://github.com/ngx-translate/i18n-polyfill se estiver com pressa para tradução de código
sem promessas de que será o mesmo, na verdade provavelmente será diferente (como mais fácil de usar), há limitações para o que é possível agora ... e adicionará ~ 80ko ao seu aplicativo para usar essa lib

Você pode usar ngx-translate se não quiser esperar

@ocombe você se importaria de fornecer atualizações sobre o progresso para que possamos acompanhar e planejar de acordo com os cronogramas de desenvolvimento ao aguardar decisões sobre quais plug-ins ou estruturas usar? seria muito útil e apreciado

@eliasre Acho que o google quer fazer uma boa solução de uma só vez. Sem quebrar mudanças no futuro. Concordo que está demorando muito mais do que pensamos.

Não incomode o pobre @ocombe , ele está trabalhando muito, MUITO duro!
Mantem! :)

Não sou eu quem está trabalhando nesse recurso, e é o feriado de fim de ano. Avisarei assim que souber mais

obrigado @ocombe

obrigado @ocombe , qualquer atualização seria muito apreciada aqui. Eu estive esperando desesperadamente pelo tempo de execução i18n nos últimos meses, e o último ETA de compilação foi 5.2. Você pode nos informar assim que tiver um ETA atualizado aqui?

Desculpe por ser tão persistente, mas construir para 20 idiomas acaba sendo terrivelmente lento no momento.

Como o Angular 5.2 saiu e infelizmente não consegui encontrar nada relacionado ao i18n (ou esqueci de algo?) ... - @ocombe talvez você possa nos atualizar sobre o plano de lançamento? Thx muito & thx muito para o seu esforço em i18n!

@ocombe não é o cara que estamos esperando aqui... confira o link do youtube neste comentário: https://github.com/angular/angular/issues/11405#issuecomment -343933617

O planejamento está em constante evolução. Sempre que eu dou uma data provável de lançamento, acontece que outra coisa obtém a prioridade ou se torna necessária e muda a data mais uma vez. Eu sei como é decepcionante para todos vocês que estão esperando por esse recurso, e estou fazendo tudo o que posso para aumentar a prioridade.
Temos uma reunião amanhã para discutir o backlog/planejamento do i18n, avisarei se tiver algo novo.

@ocombe se você lançar o i18n esse mês eu compro um pacote de 24 cervejas artesanais

Adicionarei 24 garrafas de cerveja alemã e outras 24 garrafas se você perguntar o que o Angular Elements e o suporte da biblioteca estão fazendo. Porra, não obter informações do que está acontecendo é horrível.

@ocombe , você tem essa rara oportunidade única na vida de adquirir 72 garrafas de cerveja artesanal cara e deixar a comunidade de desenvolvimento feliz. Cumpriremos nossas promessas se você realizar essas coisas, meu amigo.

@MickL Angualr Elments, pelo que entendi, nos permitirá construir páginas não SPA e usar componentes angulares como elementos nativos (como self-widgets também)

Sim eu sei. Esses são outros 2 recursos que todos estão esperando, mas ninguém sabe qual é o status e quando esperar...

Se alguém prometer adicionar as últimas 27 garrafas de cerveja, podemos começar a contar!
http://www.99-bottles-of-beer.net/language-javascript-1948.html

Vou adicioná-los, @ocombe : nomeie sua marca favorita :D

Edit: alguém cria um serviço semelhante ao eth bounty chamado beerbounty: p

Como prometido, uma pequena atualização: ainda pretendemos lançar o runtime i18n na v6, o que nos dá 5 semanas. Será curto, provavelmente será adicionado em um dos últimos lançamentos e estará atrás de uma bandeira.
Runtime i18n deve vir com traduções de código, porque é assim que funcionará para templates também (deveria usar o mesmo mecanismo).
Dito isto, não é certo que o serviço esteja 100% pronto, e podemos adiá-lo para garantir que não o quebraremos logo após o lançamento, se acharmos que é a escolha certa. Mas ele seguirá o tempo de execução i18n em qualquer caso (esse é nosso roteiro), e não precisamos de uma versão principal para lançá-lo porque estará atrás de um sinalizador e não deve quebrar nada de qualquer maneira).

O que poderia nos impedir de liberá-lo a tempo:

  • se nos depararmos com um problema inesperado (você sabe como funciona o desenvolvimento)
  • se ele quebrar os aplicativos internos do google porque erramos em algum lugar
  • se algo de prioridade máxima aparecer e tivermos que mudar nosso foco
  • se uma das coisas novas das quais depende estiver bloqueada ou atrasada (o tempo de execução do i18n depende de algumas mudanças internas importantes nas quais outros membros da equipe estão trabalhando)
  • Desenvolvedor angularJS sênior, usa a lib de tradução do PascalPrecht há 3 anos.
  • Excitou-me. Novato em Angular 2. Navegando ingenuamente https://angular.io/guide/i18n
  • Integrando com sucesso o i18n no meu projeto profissional
  • Passar um dia inteiro mexendo com todos os rótulos codificados de front-end, portando-os para um arquivo xlf de 100+kb
  • Na necessidade de traduzir rótulos brutos em serviços ng
  • Procurando no google, esteja aqui
  • Descubra que não há solução antes das 6 idades do Angular .
  • eu rn
    mfw

@Macadoshis você pode usar minha lib polyfill por enquanto: https://github.com/ngx-translate/i18n-polyfill

@Macadoshis agora imagine o que passamos desde alpha.46 ! ;)

Obrigado por apontar o i18n-polyfill para mim @ocombe , mas vou usar o ngx-translate , pois ele suporta o carregamento assíncrono das chaves de tradução.
A fábrica de i18n-polyfill para o provedor TRANSLATIONS parece oferecer suporte apenas ao carregamento bruto de sincronização de uma localidade fixa conhecida antes do bootstrap.

// 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 quão próximo está o polyfill que você escreveu do que está sendo lançado? Algo que devemos estar cientes ou nos prepararmos? Além disso, você se importaria de listar uma lista dos recursos do i18n que estão sendo lançados na versão 6 e como estão os testes com o i18n?

Não tenho mais detalhes sobre o serviço de tradução de código por enquanto, provavelmente trabalharemos nele na próxima semana (estou viajando para Mountain View). Tudo o que sei é que nos bastidores será semelhante a goog.getMsg da biblioteca de fechamento (já que é o que o google está usando internamente por enquanto): https://github.com/google/closure-library /blob/db9bc1a2e71d4b6ee8f57eebe37eb0c6494e9d7e/closure/goog/base.js#L2379 -L2387 que também é semelhante ao meu polyfill.

Na v6, lançaremos o runtime i18n: um pacote para todas as localidades, traduções resolvidas em tempo de execução e talvez traduções de código se tivermos tempo (caso contrário, virá logo depois). Tudo isso estará atrás de uma bandeira porque requer o uso do novo renderizador (chamado ng-ivy) que não será testado em batalha.

THX! @ocombe ... isso soa muito bem!
Haverá mudanças significativas na sintaxe para tradução de templates? Estou pensando em adicionar traduções ao nosso projeto agora - mas não quero refazê-lo completamente em algumas semanas.

Não, a sintaxe do modelo será a mesma

Obrigado @ocombe pela ótima notícia, isso é extremamente promissor. Que tipo de prontidão de produção podemos esperar do renderizador ng-ivy que seria lançado com a v6? Eu entendo que não será testado em batalha, mas ainda estaria pronto para uso em produção e funcionaria em todos os principais navegadores de versão quase atual, certo?

Você pode acompanhar o progresso aqui: https://github.com/angular/angular/issues/21706
Eu não acho que tudo estará pronto para a v6, já que está sob uma bandeira, continuaremos progredindo mesmo após o lançamento da v6 (não é uma mudança de ruptura nem nada)
Sinceramente não sei o que são essas coisas :D
Eu sei que um aplicativo hello world do cli já está funcionando.
Eu acho que algumas dessas coisas são necessárias para se beneficiar das otimizações do novo renderizador, mas provavelmente pode funcionar sem ter tudo verificado
Dito isto, também significa que não estará pronto para produção, não aposte seu produto nele ainda. Ele não será testado em aplicativos internos do Google e talvez precisemos fazer algumas alterações importantes para corrigir coisas. O uso do novo renderizador fica a seu critério e por sua conta e risco

Isso está presente no v6-beta4?

Não, não é. Verifique este roteiro , este recurso está bloqueado pelo tempo de execução do i18n.

atualizações @ocombe ?

O primeiro PR para o runtime i18n foi mesclado no master, juntamente com um aplicativo de demonstração hello world que usaremos para testar os recursos. Ele funciona em tempo de execução e suporta teoricamente traduções de código, mesmo que ainda não haja serviço para isso.
Por enquanto, é um suporte mínimo (strings estáticas), estamos trabalhando para adicionar novos recursos (farei a extração funcionar na próxima semana e, em seguida, string dinâmica com espaços reservados e variáveis).
Depois disso faremos o serviço de tradução de código.
Assim que um novo recurso é concluído, ele é mesclado ao mestre, você não terá que esperar por um novo major.

@ocombe i heart i18n recursos já devem estar aqui na v4.3 !! Tantos lançamentos, mas nada no i18n. O gerente de equipe angular pode alocar mais trabalhos / desenvolvedores nele, posso entender você sozinho ou dois desenvolvedores não podem avançar rapidamente, esse recurso i 18n é o recurso obrigatório para fingir que o angular é um aplicativo de negócios / aplicativo grande com construção rápida, é claro esses dois recursos são os mais importantes para aplicativos grandes, você não acha? Obrigado

Acho que a única coisa que podemos dizer ao @ocombe é agradecer a ele por todo o esforço que ele está colocando nesse recurso. Tenho certeza de que se não houver mais desenvolvedores não é porque ele não os pediu. Apenas deixe-o fazer, tenho certeza que não vamos nos arrepender quando for lançado.

Somente para referência...

Eu tenho uma ferramenta alternativa para importar e exportar strings, originalmente desenvolvida para uso com Aurelia, que inclui suporte para strings armazenadas em arquivos json - é bastante útil, pois o Webpack permite importar diretamente json em seus arquivos ts , dando ao seu código acesso fácil a essas strings.

Essa ferramenta também funciona com modelos Angular e possui vários outros recursos úteis - use-o se quiser ou sinta-se à vontade para emprestar ideias para melhorar as ferramentas Angular. Há também um carregador Webpack baseado nisso - veja o link nos documentos.

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

Temos um problema mais simples e não tenho certeza se precisamos do próximo recurso (ou do polyfill de @ocombe).

Definimos a estrutura de todas as formas reativas com constantes, nas quais definimos as propriedades de cada elemento do formulário. Por exemplo:

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

Atualmente usamos ngx-translate , então no template traduzimos strings assim:

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

Agora gostaríamos de migrar para o Angular i18n. No entanto, como nem todas as nossas strings estão em um modelo, parece que não podemos usar o Angular i18n pronto para uso.

Nossa situação parece mais simples do que aquela em que as traduções precisam ser recuperadas em tempo de execução. Todos os nossos textos são pré-definidos em constantes, e podem ser substituídos em tempo de compilação, assim como x18n atualmente faz para strings em templates.

Por exemplo, poderíamos ter uma string mais complexa como a seguinte

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

Em tempo de compilação, a string pode ser substituída por:

placeholder: 'Your password'

Isso é algo que pode ser considerado para implementação?

você definitivamente poderia fazer isso com o tempo de execução i18n, você poderia usar o novo serviço i18n em um pipe, por exemplo, para transformar seus espaços reservados em suas traduções

Percebo que este tópico está aberto há algum tempo, mostra o grande interesse em desenvolver sites multilíngue em Angular de maneira simples, abordando de perto tanto textos HTML quanto de código componente.
ocombe, por favor, não se esqueça de enviar um alerta a todos os assinantes quando isso for feito - eu entendi que está chegando em maio de 2018. E obrigado por suas contribuições gentis!

@ocombe devemos usar o Ivy para poder usar esses serviços de tempo de execução ou funcionará com o mecanismo antigo também?

será apenas com ivy, que você não pode usar por enquanto, pois não está finalizado

Obrigado por todo o seu trabalho duro @ocombe !

Alguma palavra sobre quando podemos usar esses novos recursos?

A Ivy pode ser habilitada no angular 6 com um sinalizador do compilador agora, em um estado de pré-lançamento. Esses novos recursos de 18n podem ser usados ​​usando o pré-lançamento da Ivy neste momento?

Ainda não, mas estou fazendo um bom progresso (trabalhando em tempo integral nisso agora). Vou postar uma atualização aqui assim que estiver disponível no master para testar

muito obrigado @ocombe ! Tantas pessoas estão se beneficiando de seu trabalho duro. Todos nós agradecemos muito!

@ocombe As traduções estáticas em ts ainda estão planejadas? Quero dizer, substituição de expressão em tempo de compilação, provavelmente com transformação datilografada.
Se não, seremos capazes de conectar a transformação ts personalizada no pipeline ng build sem extrair ?

Não tenho certeza de entender o que você quer dizer com @TinyMan ? Você quer dizer ser capaz de mesclar traduções em tempo de compilação (como está agora), ou ser capaz de usar traduções em código ts (além das traduções de templates que já temos)?

@ocombe , quero dizer, poder usar a tradução em ts, mas não por meio de um serviço ou tradução de DI / tempo de execução. Quero dizer tradução em tempo de compilação, mas para texto datilografado. Como o pré-processador C. Eu pensei que foi planejado de acordo com o comentário vicb :

  • também podemos oferecer suporte a traduções estáticas como fazemos hoje para modelos - as strings seriam substituídas em tempo de compilação, melhor desempenho, mas uma versão do aplicativo por localidade,

Por exemplo, eu quero ser capaz de escrever:

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 !"),
}

E então isso é transpilado para algo como (in fr):

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

Atualmente para isso uso ngx-translate com um marcador personalizado para a extração ( i18n neste exemplo), e quando preciso exibir a mensagem tenho que chamar this.translate.instant(Notifications.newStory, ["TinyMan"]) que faz a tradução + a interpolação. O que quero dizer é que precisaríamos ser capazes de escrever Notifications.newComment sem chamar o serviço de tradução. E para interpolação de strings poderíamos ter um método de interpolação que faça apenas o ICU e a interpolação (a string do template já estaria traduzida)

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

Aqui, apenas nos livramos da solicitação HTTP de traduções e da sobrecarga de serviço.

espero que esclareça?

O que você descreve está realmente no roteiro para i18n.
No momento, https://github.com/ngx-translate/i18n-polyfill fará o trabalho.

@TinyMan Ainda não tenho certeza se será por meio de um serviço ou de uma função global. Ambos são possíveis, mas um serviço também tem muitas vantagens: você pode zombar dele para testes, ou substituí-lo pelo seu próprio, você também pode alterar seu comportamento para cada módulo/componente
Eu sei que internamente o Google usará Closure i18n (via goog.getMsg ) que é uma função global, e a função provavelmente será substituída pelo serviço durante a compilação com base em um sinalizador global. Vou tentar ver se esse sinalizador também pode ser usado externamente, mas não vejo porque não. Mas se você usar isso, será para modelos e traduções de código

@ocombe Eu quero agradecer aqui também. Eu super aprecio o trabalho que você está fazendo nisso, que será incrivelmente útil para mim no meu trabalho. Uma pergunta: existe uma maneira, ou _haverá_ uma maneira, de fazer a compilação AOT que faz apenas um conjunto de arquivos de pacote que, ao procurar por texto, referencia o xlf em tempo de execução para obter a string correta?

então, em essência, você precisaria de 1 arquivo xlf por idioma mais os 5 ou 6 arquivos de pacote. No momento, se tivermos 10 idiomas e compilação AOT, são mais de 50 arquivos: um conjunto de arquivos de pacote por idiomas...

Não sei o esforço ou a complexidade de algo assim, mas seria bom ter uma compilação mas com apenas 1 conjunto de arquivos.

sim, é isso que faremos com ivy, runtime i18n
agrupar seu aplicativo uma vez e carregar as traduções em tempo de execução (você pode carregar as traduções com preguiça)

@ocombe isso. é. incrível.

Isso me deixa tão inacreditavelmente feliz. OBRIGADA!

Sem a capacidade de traduzir modelos externos, o recurso i18n é completamente inútil para mim.

@ocombe Olá Olivier!
Alguma atualização?

Obrigado!

Se for feito, não importa, pois temos que esperar que Ivy esteja completo, que está programado para Angular 7 (setembro/outubro de 2018)

Por Angular 7 esta edição terá dois anos LOL.
De qualquer forma, Ivy foi o que mais atrasou esse novo recurso ...

@ocombe , é ótimo ouvir isso. Atualmente, estamos presos usando um serviço i18n herdado que lançamos desde o início puramente por esse motivo. Não poder fazer isso em JS torna extremamente difícil fazer algumas coisas simples para nós:

  • Componentes dinâmicos
  • Integração com serviços de terceiros onde temos que fornecer algum texto localizado para
  • Mostrando modais de confirmação dinâmica
  • Nossa API retorna o erro types . Em nosso contexto, precisamos localizar dinamicamente esses erros e uma abordagem orientada por modelo seria complicada.
  • Queremos usar o TitleService como sugere a equipe do Angular, mas não há como fornecer texto localizado!

Estou meio curioso como a equipe Angular lida com isso atualmente ...

Olá @vincentjames501 ,
Em nossa empresa, tentamos fazer o mesmo que você está fazendo agora, mas foi muito problemático, então acabamos usando o i18n-polyfill mencionado anteriormente neste tópico, e até agora está funcionando muito bem.
A única desvantagem que temos é o tamanho dos pacotes do nosso aplicativo. Temos três arquivos de tradução, e cada pacote contém todos eles dentro (não descobrimos uma maneira de gerar o pacote apenas com a tradução que ele usa). Mas tudo isso são apenas incômodos que esperamos que sejam resolvidos quando Ivy sair.
Saúde,

Incluí um mapa de tradução e o reexportei no arquivo environment.ts de cada idioma. Funciona sem problemas, não está incluído em todos os pacotes e não requer uma biblioteca externa. O único problema que tenho é que, como cada site é diferente, não posso ter o mesmo service worker para todos os idiomas e, se alguém mudar de idioma, meu site não pode dizer se ele já está registrado para notificações push ou não ...

@ocombe alguma novidade no angular 6?

Não será em Angular v6, conforme explicado acima. Dependemos de Ivy que está planejada para v7.

@ocombe posso sugerir que você bloqueie este tópico, para que apenas a equipe possa fornecer atualizações significativas quando apropriado e evitarmos as perguntas repetitivas que você continua respondendo?

Meu hack para uso com o Angular atual é usar um ng-template e criar a view incorporada programaticamente:

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

e depois no arquivo ts do componente:

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

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

O método createTranslatedMessage retorna a mensagem traduzida. Embora eu esteja usando o modelo para declarar a mensagem que não é ideal, isso possibilita que a ferramenta de tradução da CLI a registre nos arquivos xlf, e tenho uma maneira de obter a mensagem traduzida programaticamente para uso em modelos externos.

Espero que a API funcione para as rotas também! Por exemplo

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

Se esse recurso for lançado, haveria uma mudança significativa em relação à API i18n atual? Você recomendaria que eu iniciasse meu projeto com o i18n agora ou devo esperar pela nova i18n Api quando o Angular 7 for lançado?

Alguma atualização Quando teremos suporte para tradução dinâmica e em tempo de execução?

As traduções em tempo de execução são feitas e mescladas (com ivy), mas o lado do compilador ainda não está concluído.
Estou trabalhando em expressões de UTI agora.
Ainda não comecei a codificar as traduções dinâmicas (serviço), mas provavelmente é a próxima coisa que farei depois das expressões ICU.

@vincentjames501 Podemos usar i18n-polyfills com expressão ICU? Não tenho solução para implementar isso

@ocombe , você pode esclarecer a diferença entre o tempo de execução e as traduções dinâmicas?

provavelmente não há denominação oficial, mas do jeito que eu vejo é:

  • runtime: as traduções são resolvidas em tempo de execução, ou seja, não durante a compilação (como fazemos atualmente). Aplica-se a todos os tipos de traduções (modelos ou em código)
  • dynamic significa que você só sabe o que deseja traduzir em tempo de execução e não pode fazê-lo em tempo de compilação. Aplica-se principalmente a traduções "em código", usando um serviço. Eu acho que você poderia considerar as expressões ICU dinâmicas no sentido de que elas dependem de uma variável, mas você ainda pode calcular todas as traduções possíveis em tempo de construção porque o número de casos é finito.

Adiei a adição de suporte i18n ao projeto atual que estamos desenvolvendo, mas estamos chegando perto do lançamento, alguma ideia se isso será final no angular 7? Ou devo considerar outras formas de adicionar traduções?

@andrei-tatar i18n está funcionando perfeitamente desde Angular 2. As únicas desvantagens:

  • Sem traduções de código (este problema) -> Se você precisar, use i18n-polyfill
  • Se você criar AOT (recomendado), o aplicativo deve ser criado para cada idioma separadamente
  • Como cada aplicativo é construído separadamente, ao alternar o idioma, você precisa recarregar a página

Para os dois últimos pontos, você pode usar @ngx-translate. Mas funciona de maneira diferente do i18n integrado do Angular, portanto, uma atualização posterior pode levar algum tempo. Para o polyfill, a atualização não será demorada, provavelmente sem alterações importantes.

@ocombe

Como podemos lidar com o operador condicional usando o recurso Angular i18n

[email protected]> escreveu:

@shobhit12345 https://github.com/shobhit12345

Usamos o ngSwitch para modelar todas as mensagens, para que possamos anexar tags i18n a
eles individualmente.

EsconderMostrarHistória

Usamos muito esse método para contornar as traduções dinâmicas ausentes.
Com um pouco de reflexão, uma quantidade surpreendente de texto pode ser expressa em
desta forma nos modelos. Um padrão comum é ter uma matriz de mensagens,
e, em seguida, use isso com ngFor e ngSwitch para modelar as mensagens,
algo assim:

ts

mensagens = [ 'esta é a primeira mensagem', 'esta é a segunda mensagem' ]

html


i18n="@@firstMesssage">Esta é a primeira mensagem
i18n="@@secondMesssage">Esta é a segunda mensagem

É um pouco verboso - mas funciona!


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/angular/angular/issues/11405#issuecomment-415731284 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AGwM6jcWIpwtGxhkH1fwnVXNagRxmMnoks5uT-LxgaJpZM4J2pkr
.

Se for feito, não importa, pois temos que esperar que Ivy esteja completo, que está programado para Angular 7 (setembro/outubro de 2018)

Já é outubro. Você acha que teremos os novos recursos até o final de outubro?

@lizzymendivil de acordo com https://is-angular-ivy-ready.firebaseapp.com Ivy está 65% concluída e parece improvável que seja concluída em apenas 30 dias

Sim, a hera não será concluída em um mês.

@ocombe você pode bloquear isso para que apenas você possa postar atualizações. é um pouco chato receber todas as notificações de todos os "quando é feito?" comentários

@ocombe parece que Ivy está agora em aproximadamente 94%, você acha que isso pode estar pronto até o final do ano?

Acho que não. Estar pronto para recursos e livre de bugs (= utilizável) é muito diferente. Estamos trabalhando principalmente para consertar as coisas agora.

@ocombe podemos acreditar que o i18n veio antes do angular 8?

Acho que não. Estar pronto para recursos e livre de bugs (= utilizável) é muito diferente. Estamos trabalhando principalmente para consertar as coisas agora.

Ok, obrigado pela pronta resposta, muito apreciado.

Alguma atualização @ocombe que até quando devemos esperar (Fim do ano, vejo nos últimos comentários) a parte "Tradução de código" disponível junto com "Tradução de modelo" para suporte a I18N com Angular? Pensamos em juntar ngx-translate-polyfill para o mesmo junto com o recurso Angular I18n, mas também parece que o suporte xlf não está disponível para mesclar o arquivo xlf existente usando https://github.com/biesbjerg/ngx-translate-extract CLI .

Obrigado !

@Abekonge

Usamos o ngSwitch para modelar todas as mensagens, para que possamos anexar tags i18n a elas individualmente.
É um pouco verboso - mas funciona!

Obrigado pela sugestão! Parece o mais fácil de entender. Minha pergunta é, você ainda usa essa implementação em situações em que o array tem muitos valores, como 10 ou mais? Parece que o código ficaria muito volumoso.

Não sei se temos algum com tantos, mas por que não. Se as mensagens são usadas em vários lugares, fazemos pequenos componentes i18n que são basicamente apenas o switch e as tags i18n.

Davi

Den 23. jan. 2019 k. 19.24 skrev Andrew Bissada [email protected] :

@Abekonge

Usamos o ngSwitch para modelar todas as mensagens, para que possamos anexar tags i18n a elas individualmente.
É um pouco verboso - mas funciona!

Obrigado pela sugestão! Parece o mais fácil de entender. Minha pergunta é, você ainda usa essa implementação em situações em que o array tem muitos valores, como 10 ou mais? Parece que o código ficaria muito volumoso.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou silencie a conversa.

Como usar i18n-polifills nas classes do Validador. Não consigo usar a mensagem do validador secreto por meio do serviço i18n.

//No componentenet
this.crForm= this.fb.group({
nome do usuário: [''],
Senha eletrônica: [''],
}, { validador: new AccValidator(this.i18n).validate()}
);

//Validador

import { AbstractControl, ValidationErrors, FormGroup, FormControl } de '@angular/forms';
importe { I18n } de '@ngx-translate/i18n-polyfill';
export class AccValidator{
construtor(i18n:I18n)
{

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

ficando abaixo do erro

Erro RROR: Não capturado (em promessa): TypeError: i18n não é uma função
TypeError: i18n não é uma função
em FormGroup.eval [como validador] (acc-validator.ts:9)
em FormGroup.AbstractControl._runValidator (forms.js:3433)
em FormGroup.AbstractControl.updateValueAndValidity (forms.js:3387)
no novo FormGroup (forms.js:4326)
em FormBuilder.group (forms.js:7864)

@ocombe

Como usar i18n-polyfills com const em arquivos .ts

export const glossayModel= () => [
{
título: 'dados de teste',
ativo: verdadeiro,
dados: [

        [
            {
                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, select, Médico {Medical} Odontológico {Dental} Médico e Odontológico {Medical & Dental} Catastrófico e Odontológico {Catastrophic & Dental} Catastrófico {Catastrophic} }
{VAR_SELECT, select, Medical {Medical} Dental {Dental} Medical### & Dental {Medical y Dental}
Catastrófica ### & Dental{Catastrophic y Dental} Catastrophic {Catastrophic} }

Quando estou usando a expressão ICU com caractere especial, não está convertendo.

@ocombe Como lidar com migalhas de pão usando i18n-polyfills?

export const rotas: Rotas = [
{
caminho: '',
componente: HomeComponent,
dados: {
título: 'Casa',
pão ralado: 'Casa'
}
}
]

@ocombe

Como usar i18n-polyfills com const em arquivos .ts

export const glossayModel= () => [
{
título: 'dados de teste',
ativo: verdadeiro,
dados: [

        [
            {
                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."
            }

]]}];

Você pode usar assim
{
dados: 'dados de teste',
título: this.i18n({ valor: 'Nome', id: 'nome' }),
}
injetar polyfill I18n no construtor de componentes como este
privado i18n: I18n
Ao usar traduções no arquivo ts, você precisa usar ngx-extractor e xliffmerge para traduzir esses arquivos ts. https://www.npmjs.com/package/ngx-i18nsupport

@ Janne Harju
não está funcionando, não está obtendo os dados no arquivo xlf.

Aqui está o meu script de tradução:
"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",

e aqui está xliffmerge.json

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

@ Janne Harju
Sim, estou usando a mesma configuração e capaz de extrair mensagens .ts no arquivo xlf.

Mas const eu tenho em diferentes arquivos .ts

export const glossayModel= () => [
{
}

estou importando em componente, quando estou tentando usar i18n com const, não está extraindo os valores.

E se você usar valores const como provedor.

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

o código pode estar quebrado, mas talvez você ganhe ponto.

como traduzir breadcrumbs

const rotas: Rotas = [
{
caminho: './enroll-new.component',
componente: InscreverNovoComponente,
dados: {
breadcrumb: 'Inscrição'
},
}
]

vocês podem parar de usar este tópico como um tópico de suporte para i18n-polyfill ou outros problemas? se você tiver uma pergunta sobre o i18n-polyfill, levante um problema nesse repositório.
@ocombe talvez você possa bloquear este tópico? praticamente tudo o que é importante deve ser coberto.
qual é a versão angular que você planeja liberar o suporte i18n mencionado neste tópico?

Sim, bloqueado por enquanto.
Estamos trabalhando duro para ter o ivy disponível com a v8 como uma versão beta opcional. O tempo de execução i18n será utilizável com o fechamento do google (o que o google usa internamente), o que nos permitirá depurá-lo (é uma mudança muito grande). Para todos os outros, você poderá testar o ivy com o i18n, mas não poderá carregar as traduções. O aplicativo será executado com o idioma original usado para codificar o aplicativo.
O serviço de tempo de execução necessário para traduzir atualmente retorna o texto não traduzido. Como estamos todos trabalhando na correção de bugs com o código existente, os novos recursos serão limitados após o lançamento. Trabalharemos nisso assim que a v8 for lançada, deve ser minha primeira tarefa.
Vou adicionar uma atualização e desbloquear este tópico assim que tivermos algumas novidades.

Pelo que vale a nova tag $localize que estamos trabalhando pode ser usada programaticamente.

Por exemplo

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

E então poderá fornecer traduções para Hello {$name}! que podem ser substituídas em tempo de compilação (ou tempo de execução).

Isso agora está disponível (se não documentado).

Esta página foi útil?
0 / 5 - 0 avaliações