Angular: i18n: ํ…œํ”Œ๋ฆฟ ์™ธ๋ถ€์—์„œ ๋ฒˆ์—ญ ๋ฌธ์ž์—ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์— ๋งŒ๋“  2016๋…„ 09์›” 07์ผ  ยท  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
  • ๋ธŒ๋ผ์šฐ์ €: [์ „์ฒด]
  • ์–ธ์–ด: [ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ 2.0.2 | ES5 | ์‹œ์Šคํ…œJS]

@vicb

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์€ ์ด๊ฒƒ์ด ๊ตฌํ˜„๋  ๋•Œ๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์ฝ”๋“œ์—์„œ ๋ฒˆ์—ญ๋œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฉ”์‹œ์ง€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ, ์—ฌ๊ธฐ์—์„œ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” OOTB ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ng2-translate์—์„œ Angular2 i18n์œผ๋กœ ์ „ํ™˜ํ–ˆ์œผ๋ฉฐ ๋ฒˆ์—ญ์„ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์‰ฝ์Šต๋‹ˆ๋‹ค(ng2-translate๋Š” IMO์— ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋จ)
์ด ๋‹จ๊ณ„์—์„œ๋Š” ๋‚ด ์„œ๋น„์Šค์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฒˆ์—ญํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•๋„ ์—†์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋””์ž์ธ ์‚ฌ์–‘์„ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: Google ๋ฌธ์„œ๋„๊ตฌ์—์„œ).

๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ๋‚˜์—ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋นจ๋ฆฌ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์žˆ์–ด.

_.('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 ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ (string-) ์†์„ฑ์— ๋Œ€ํ•ด @i18n() ์™€ ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ๋Ÿฐ ๋‹ค์Œ @Input() ๊ฐ€ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ฒˆ์—ญ๋œ ๊ฐ’์œผ๋กœ ์ฑ„์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฒˆ์—ญ๋˜์ง€ ์•Š์€ ๊ฐ’์„ ์ฝ”๋“œ์—์„œ ์‰ฝ๊ฒŒ ์ถ”์ถœํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธ์ˆ˜์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

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

๋ฒˆ์—ญ ๋Œ€์ƒ์ด ์—†์„ ๋•Œ ์†Œ์Šค๋ฅผ ์†์„ฑ์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ „์ฒด ๊ตญ์ œํ™” ์ฃผ๊ธฐ์ธ IMO์—์„œ ํ•„์ˆ˜ ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค.

๋‚ด ๊ฐ€๊ฒŒ์—์„œ ์šฐ๋ฆฌ๋Š” ๋ฒˆ์—ญ์ž๋ฅผ ์œ„ํ•œ ์‚ฌ์ „ ํŒŒ์ผ์— ๋„ฃ์„ ํ‘œ์‹œ๋œ ํ…์ŠคํŠธ๋ฅผ ์ฐพ๋Š” ๋ชจ๋“  ์œ ํ˜•์˜ ์†Œ์Šค ํŒŒ์ผ์„ ํฌ๋กค๋งํ•˜๋Š” "ng-xi18n - like" ๋„๊ตฌ(xgettext์˜ ํ™•์žฅ์ž)์— ์ต์ˆ™ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” HTML ํ…œํ”Œ๋ฆฟ์˜ ๊นจ๋—ํ•˜๊ณ  ์‰ฌ์šด i18n ๋งˆํฌ์—…์„ ์ข‹์•„ํ•˜๊ณ  Typescript ์ฝ”๋“œ์—์„œ๋„ ๊ฐ™์€ ๊ฒƒ์„ ๊ธฐ๋Œ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

@vicb ๊ท€ํ•˜์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€ ์™ธ์—๋„ TS ์ฝ”๋“œ์—์„œ ๋ณด๊ฐ„๋œ ๋ฌธ์ž์—ด์˜ ํ˜„์ง€ํ™”๋ฅผ ์ง€์›ํ•  ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ง€์›ํ•˜๋ ค๋ฉด TS ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ํšจํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋ ๊นŒ์š”?

์ด๊ฒƒ์€ Angular 2๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฒˆ์—ญ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” ์ฃผ์š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. HTML์— ์ €์žฅ๋˜์ง€ ์•Š์€ ์ผ๋ถ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์—์„œ ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ฅผ ํ†ตํ•ด ๋˜๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ TRANSLATIONS์— ๋Œ€ํ•ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฒˆ์—ญํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ ์ ˆํ•œ ๋ฌธ์ž์—ด์„ ํ‘œ์‹œํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋™์•ˆ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ์ œํ•œ ๋•Œ๋ฌธ์— ng-translate์™€ ๊ฐ™์€ ๊ฒƒ์œผ๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‚ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์„œ๋น„์Šค์— ๋นˆ 'lang' ๊ฐœ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ div์˜ ๋ชจ๋“  ๋ฒ”์œ„๋ฅผ ์ฝ๊ณ  ํ•ด๋‹น ๊ฐœ์ฒด์— ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ์ง€์‹œ๋ฌธ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ˆจ๊ฒจ์ง„ ์†์„ฑ์ด ์žˆ๋Š” ํŽ˜์ด์ง€ ํ•˜๋‹จ์˜ ํ…œํ”Œ๋ฆฟ์— ๋ชจ๋“  ๋ฌธ์ž์—ด์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ…œํ”Œ๋ฆฟ ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋ฌธ์ž์—ด์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด๊ธฐ ํ‰ํ•˜๊ณ  ๋™์ผํ•œ ID๋กœ ํ•ญ๋ชฉ์„ ์‰ฝ๊ฒŒ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—†๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋‚ซ์Šต๋‹ˆ๋‹ค.

์„œ๋น„์Šค

@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 ์— ID๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: 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 of 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์ด ์—†์–ด๋„ ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : 4.0.0-๋ฒ ํƒ€์˜ ํ˜„์žฌ @angular/compiler-cli NPM ํŒจํ‚ค์ง€์—๋Š” @angular/tsc-wrapped ์˜ ์ž˜๋ชป๋œ ์ข…์†์„ฑ ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค. 0.4.2๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ 0.5.0์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @vicb ์ด๊ฑฐ ์‰ฝ๊ฒŒ ๊ณ ์ณ์ง€๋‚˜์š”? ์•„๋‹ˆ๋ฉด ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@fredrikredflag ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค! ๊ทธ๋ฆฌ๊ณ  AOT๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

@ghidoz AOT๋Š” ๋˜ ๋‹ค๋ฅธ ์ด์•ผ๊ธฐ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋ชจ๋“  ๋ฒˆ์—ญ์„ ๋ฏธ๋ฆฌ ์ปดํŒŒ์ผํ•˜์—ฌ ํ‚ค๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ngc ๋Š” ๋ชจ๋“  i18n ๋ฅผ ์˜ฌ๋ฐ”๋ฅธ ๋ฒˆ์—ญ์œผ๋กœ ๋Œ€์ฒดํ•˜๋ฏ€๋กœ ์ด๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ngc ์—์„œ ๊ตฌ๋ฌธ ๋ถ„์„๋œ ๋ฒˆ์—ญ์„ ํฌํ•จํ•˜๋Š” ๋…ธ์ถœ๋œ ์˜ต์…˜/์†์„ฑ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. TRANSLATION ํ† ํฐ์— ์—ฌ์ „ํžˆ ์ œ๊ณตํ•˜๋Š” xlt ํŒŒ์ผ์„ ๊ฐ€์ ธ์™€์„œ JIT์™€ ๋™์ผํ•œ ๋™์  ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ 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 ๊ตฌ์กฐ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„ ๋ฒˆ์—ญ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ผ ๋ฒ„์ „์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์žˆ๊ณ  ๋Ÿฐํƒ€์ž„์— ํ™•์ธ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ค๋Š˜๋‚  ํ…œํ”Œ๋ฆฟ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ •์  ๋ฒˆ์—ญ์„ ์ง€์›ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด์€ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋Œ€์ฒด๋˜๊ณ  ์„ฑ๋Šฅ์€ ๋” ์ข‹์ง€๋งŒ ๋กœ์ผ€์ผ๋‹น ํ•˜๋‚˜์˜ ์•ฑ ๋ฒ„์ „,
  • ๋‚˜์ค‘์— ํ…œํ”Œ๋ฆฟ์—์„œ __(...) ๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๊ฒƒ์€ 2.3์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ TS ๋ณ€ํ™˜๊ธฐ๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ์ด์ „์— ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

/cc @ocombe

__() ๋Š” ์•„์ง ์ด๋ฆ„์ด ์—†๋Š” ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. (๊ทธ๋ฆฌ๊ณ  ๋ฉ”์„œ๋“œ๋Š” ์‹ค์ œ๋กœ __ ๊ฐ€ ์•„๋‹ˆ๊ฒ ์ฃ ?)

ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ •์  ๋ฒˆ์—ญ์— ๋Œ€ํ•œ ์ข‹์€ ์•„์ด๋””์–ด์ด๋ฉฐ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ์š” __() ๋Š” ์ด๋ฆ„์ด ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค :)

๋ฒˆ์—ญ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€๋งŒ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์„ ํ˜ธํ•˜๋Š” ๊ฒฝ์šฐ import {__ as olivier} from '@angular/core' ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

eeeeeeeh ์ž์ฒด ์„ค๋ช…์ด ์•„๋‹™๋‹ˆ๋‹ค. :D
๊ทธ๊ฒƒ์€ ๋งค์šฐ ์‚ฌ์ ์ธ ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

์ €๋„ ___ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. :) ์„œ๋น„์Šค๊ฐ€ ๋  ๊ฑฐ๋ผ๊ณ  ์ƒ์ƒํ–ˆ๋‚˜์š”?
์–ด์จŒ๋“  ๋ฐœ์ „ํ•˜๋Š” ๋ชจ์Šต์ด ๋ณด๊ธฐ ์ข‹๋„ค์š” ๐Ÿ‘

์ข‹์•„์š” __()! :D ๋งค์šฐ gettext-y์ด๋ฉฐ ์งง์Šต๋‹ˆ๋‹ค.

JS ์„ธ๊ณ„์—์„œ๋Š” @ocombes ng2-translate์— ๋Œ€ํ•œ ๊ฒฝํ—˜๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ this._translateService.instant()๋กœ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋ฉด ์—ฌ๊ธฐ์— ์ œ์•ˆ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ์งง์€ ๋Œ€์•ˆ์— ๋น„ํ•ด ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ๊ฐ€ ๋‹ค์†Œ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

ng2 ๋ฒˆ์—ญ ์„œ๋น„์Šค์˜ ์ด๋ฆ„์„ __ ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. :)

์‚ฌ์‹ค, ๋‚˜๋Š” DI ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜๋กœ ์–ด๋–ป๊ฒŒ ๋ž˜ํ•‘ํ•˜๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. - ์–ด์จŒ๋“ , ์‹ ๊ฒฝ์“ฐ์ง€ ๋งˆ์„ธ์š”. ๊ทธ๊ฒƒ์€ ์ด ๋ฌธ์ œ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค:-) ์ œ ์˜๊ฒฌ์€ __๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ +1์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ ์–ด๋„ PHP ์„ธ๊ณ„์—์„œ๋Š” ๋‹ค๋ฅธ ๋ฒˆ์—ญ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ข‹์•„, ์•„๋งˆ๋„ ___๊ฐ€ ๊ดœ์ฐฎ๊ณ  "this.translationService.getTranslation()"๋ณด๋‹ค ํ›จ์”ฌ ์งง์Šต๋‹ˆ๋‹ค.
์˜ˆ, ์›ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

__(...) i18n(...) $๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

์ด๋ฆ„์— ๋Œ€ํ•œ ๋…ผ์Ÿ์„ ์ค‘๋‹จํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๊ฒŒ ์š”์ ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”.

monday = __('Monday', {description: 'First day of the week', id: 'firstDatOfWeek'}); ๊ฐ€ ์žˆ๋Š” @vicb ๋Š” 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>

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ ์—ฌ์ „ํžˆ ์ง€๊ธˆ๊นŒ์ง€ ๊ฐ€์žฅ ๊นจ๋—ํ•œ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ts title ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณง ๋””์ž์ธ ๋ฌธ์„œ๊ฐ€ ๋‚˜์˜ฌ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค :-)

์ด๊ฒƒ์€ ๊ฐ€์žฅ ๊ธฐ๋Œ€๋˜๋Š” ๊ธฐ๋Šฅ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค

์ข‹์€ ์†Œ์‹์ด๋„ค์š”. @ocombe ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋””์ž์ธ ๋ฌธ์„œ๋Š” https://goo.gl/jQ6tQf ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋“  ํ”ผ๋“œ๋ฐฑ์„ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ฌ์ฝคํ•œ, ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ์ฝ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค!

@ocombe ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

๋ฌธ์„œ๋ฅผ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ฆ„๋‹ค์šด ์š”์•ฝ.

ts ํŒŒ์ผ์—์„œ ๋ฌธ์ž์—ด์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ •๋ง ๋ฉ‹์ง„ ์ผ์ž…๋‹ˆ๋‹ค.

Angular4์—์„œ Typescript ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ์–ธ์ œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฑฐ์˜ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์ด ์ œํ•œ์— ๋ถ€๋”ช์ณค๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธฐ๋Šฅ์€ ์ด๋ฏธ ๋ช‡ ๊ฐœ์›” ๋™์•ˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ–ˆ์œผ๋ฉฐ ์ ์–ด๋„ 3/6๊ฐœ์›”์ด ๋” ์ง€๋‚˜๊ธฐ ์ „์—๋Š” ์ด ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ…œํ”Œ๋ฆฟ์— Angular i18n์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฒˆ์—ญ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ngx-translate๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ์€ ์ง€๊ธˆ ์ €๋งŒ์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฒƒ์„ i18n์— ๋ณ‘ํ•ฉํ•˜๋ ค๋Š” ๋ชฉํ‘œ๋Š” ๋ถ„๋ช…ํžˆ ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ๋„ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ i18n์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•œ๋‹ค๋Š” ์ธก๋ฉด์—์„œ ๋‹จ์ˆœํ™”๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ด ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ˜„์žฌ์˜ ngx-translate ๊ตฌํ˜„๊ณผ ๋น„๊ตํ•˜์—ฌ ์‹ค์ œ๋กœ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ๊นŒ์š”?

๋‚ด๊ฐ€ ์ง€๊ธˆ ์ดํ•ดํ•˜๋Š” ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด ์œ ์ผํ•œ ๋ณด๋„ˆ์Šค๋Š” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฌธ์ž์—ด์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ํ˜„์žฌ ํฐ ์ œํ•œ ์‚ฌํ•ญ์€ ๋ณต์ˆ˜ํ™”์ž…๋‹ˆ๋‹ค. ์ „์ฒด ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ๋ฆด๋ฆฌ์Šคํ•  ๋•Œ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. xliff์™€ xmb๊ฐ€ ๋ชจ๋‘ ์ด๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๋Š” i18n ๊ด€๋ จ ํ‹ฐ์ผ“์„ ๋งŽ์ด ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ž‘๋™ํ•˜๋Š” ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ngx-translate๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๋˜ ํ•˜๋‚˜์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

@ocombe ์ƒ์„ธํ•œ ์„ค๊ณ„ ๋ฌธ์„œ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด ๊ธฐ๋Šฅ ์š”์ฒญ์— ๋Œ€ํ•œ ์ •๋ง ์ข‹์€ ์†”๋ฃจ์…˜์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ๋””์ž์ธ์€ ๋‚ด๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ: ์„ค๊ณ„๋Š” JIT ๋ชจ๋“œ์šฉ I18N ์„œ๋น„์Šค์™€ AOT ๋ชจ๋“œ์šฉ TS 2.2.x Transformer์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€ํ™˜๊ธฐ๊ฐ€ ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ์ •์  ๋ณ€ํ™˜์œผ๋กœ ๋Œ€์ฒดํ•˜๊ณ  I18N ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๋‚˜๋จธ์ง€ ์ฐธ์กฐ๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ?

@Thommas Angular 4 ๋Š” TypeScript 2.1(์ฆ‰, ์—…๊ทธ๋ ˆ์ด๋“œ ํ•ด์•ผ ํ•จ)์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” Angular 2 ๋˜๋Š” 4์—์„œ ์ตœ์‹  ๋ฒ„์ „์˜ TypeScript(์˜ˆ: 2.2.1)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ngx-translate์— ๋Œ€ํ•œ ์„ฑ๋Šฅ ํ–ฅ์ƒ ์ธก๋ฉด์—์„œ AOT๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. AOT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋“์ด์ง€๋งŒ ์ฐจ์ด๋ฅผ ๋Š๋ผ์ง€ ๋ชปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. JIT(AOT ์—†์Œ)์—์„œ๋Š” ์ด๋“์ด ์—†์Šต๋‹ˆ๋‹ค(์‹ค์ œ๋กœ get ์˜ต์ €๋ฒ„๋ธ” ๋˜๋Š” ๋™๊ธฐ์‹ instant ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์˜ต์ €๋ฒ„๋ธ” ๋น„์šฉ์ด ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋ณด๋‹ค ๋น„์Œ‰๋‹ˆ๋‹ค).
์—ฌ๊ธฐ ์ฝ”๋“œ์—์„œ i18n์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Angular i18n(AOT ๋ฐ JIT์—์„œ)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‹ค์ œ๋กœ ๋ˆˆ์— ๋ณด์ด๋Š” ์ด๋“์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๋ฒˆ์—ญ์„ ์‚ฌ์šฉํ• ์ˆ˜๋ก ๋” ๋งŽ์€ ๊ฒƒ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณต์ˆ˜ํ™”๊ฐ€ ํ…œํ”Œ๋ฆฟ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ํ…œํ”Œ๋ฆฟ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@schmuli Angular๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์‹œ๊ฐ„์€ AOT๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์„œ๋น„์Šค ํ˜ธ์ถœ์ด ์ฝ”๋“œ์—์„œ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ AOT๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์„œ๋น„์Šค ํ˜ธ์ถœ์€ ์ •์  ๋ณ€ํ™˜์œผ๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค(์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋งŒ ๋™์  ์ƒํƒœ๋กœ ์œ ์ง€๋จ). I18n ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ• ์ง€ ์—ฌ๋ถ€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. I18n ์„œ๋น„์Šค๋Š” ํ–ฅํ›„ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ ์ž‘์„ฑ์„ ์‹œ์ž‘ํ•˜๋ฉด ๋ณ€ํ™˜๊ธฐ๋กœ ๋ฌด์—‡์ด ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@ocombe ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ์ถ”๊ฐ€ DI ์ฃผ์ž…์„ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š” ํ•œ ์ฝ”๋“œ๋ฅผ ๋‚จ๊ฒจ๋‘๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์œ ์Šค ์ผ€์ด์Šค๋ฅผ ์ƒ๊ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(์ด๊ฒƒ์ด ์‹ค์ œ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ?).

์•ž์œผ๋กœ ์„œ๋น„์Šค๊ฐ€ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ธ€๊ณผ ์‚ฌ์šฉ์ž์˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ์•„์˜ˆ ์‚ญ์ œํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ AOT์—์„œ ํ˜„์žฌ ๋กœ์ผ€์ผ์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๋Ÿฌ ์–ธ์–ด๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋ฒ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๋”ฐ๋ผ์„œ ์š”์ฒญ์— ํฌํ•จํ•  ํ˜„์žฌ ๋กœ์บ˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•ญ์ƒ ์ž„์‹œ๋กœ ๋ฒˆ์—ญ๋œ ๋ฌธ์ž์—ด์„ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@diego0020 ์ด๋ฏธ ๋กœ์ผ€์ผ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”์–ด์—์„œ LOCALE_ID ๋ฅผ ์ฃผ์ž…ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@ocombe ๋ณต์ˆ˜ํ™”๋Š” xliff๋กœ ๊ตฌํ˜„๋˜์ง€ ์•Š์œผ๋ฉฐ Google ์™ธ๋ถ€์˜ ๋ˆ„๊ตฌ๋„ xmb์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋‹จ์„œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ฐธ์กฐ: https://github.com/angular/angular/issues/13780

์–ด์จŒ๋“ , ์ง€๊ธˆ ๋‹น์žฅ ์šฐ๋ฆฌ์˜ i18n ๊ตฌํ˜„์„ ์ฐจ๋‹จํ•˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ngx-translate with pluralization pipe๋Š” ์ง€๊ธˆ ๋‹น์žฅ์€ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ”๋ผ๊ฑด๋Œ€ ๋ชจ๋“  ๊ฒƒ์ด NG4์—์„œ ๋” ์ข‹์•„ ๋ณด์ด๊ณ  ๋ฌธ์„œ์— ๊ฐœ์„  ์‚ฌํ•ญ์ด ๋ฐ˜์˜๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”.

@Thommas ICU with xliff๋Š” ๊ณง ์ˆ˜์ •๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค: https://github.com/angular/angular/pull/15068 ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ๋ฒ•์„ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด https://angular.io/docs/ ๋ฌธ์„œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ETA๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ng4.0.0 ๋ฆด๋ฆฌ์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋“ค์—ˆ์ง€๋งŒ ์•„๋‹ˆ์š”! ๊ฐ์‚ฌ ํ•ด์š”

์ฐธ์กฐ @ocombe

์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ๋””์ž์ธ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณ ๋ คํ•ด์•ผ ํ•  ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์‚ฌํ•ญ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋„์„œ๊ด€์ด ์ž์ฒด ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•), ...
์ด๊ฒƒ์€ 4.2์—์„œ ์˜ˆ์ƒ๋˜์ง€๋งŒ ๋ณด์žฅ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

ok ๊ฐ์‚ฌ ํ•ฉ๋‹ˆ๋‹ค @ocombe , ๋‘ ๊ฐ€์ง€ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์‹ค์ œ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด๊ฐ„์ด ํฌํ•จ๋œ ํ…œํ”Œ๋ฆฟ์˜ ํ…์ŠคํŠธ๋ฅผ ๋ฒˆ์—ญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    <span i18n>This is {{myValue}}</span>
  1. ์‹ค์ œ๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์งˆ๋ฌธํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.
    Could not mark an element as translatable inside a translatable section

@istiti

  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 ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ์ฐพ๊ธฐ๊ฐ€ ์ •๋ง ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

@istiti

  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๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ๋•์…˜์—์„œ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋„๋ก ๋‚ด miniApp์— ์•ฝ๊ฐ„์˜ ๋ฌธ์ž์—ด๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!!

P/S: Martin Roob์˜ 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 ๋Œ€๋žต์ ์ธ ์ถ”์ •์€ ์–ธ์ œ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๊นŒ?

์ข‹์€ ๊ธฐ๋Šฅ btw :)

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๊นŒ์ง€ ๋ณด๋ฅ˜๋˜๋ฏ€๋กœ 4.2๊ฐ€ ์•„๋‹ˆ๋ผ 4.3์—๋„ ์ ์šฉ๋˜๊ธฐ๋ฅผ ํฌ๋งํ•ฉ๋‹ˆ๋‹ค.

๋ˆ„๊ตฌ๋“ ์ง€ ๋‹ค์Œ ์˜ˆ์—์„œ [title]๊ณผ ๊ฐ™์ด param ๊ฐ’์—์„œ i18n์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ฆ‰, HELLO๋ผ๋Š” ๋‹จ์–ด์— ๋ฒˆ์—ญ์„ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

๋ฌธ์•ˆ ์ธ์‚ฌ

์…˜

HELLO๊ฐ€ HTML ํ…œํ”Œ๋ฆฟ์— ์ž…๋ ฅํ•˜๋Š” ๋ฌธ์ž์—ด์ผ ๊ฒฝ์šฐ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
```html

````
๋ฌธ์„œ์— ์ด์— ๋Œ€ํ•œ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ๋ณด์„ธ์š”: https://angular.io/docs/ts/latest/cookbook/i18n.html#! #translate-attributes

๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ฌธ์ž์—ด ์†์„ฑ์— ๋ฐ”์ธ๋”ฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ด ๊ธฐ๋Šฅ์„ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ๋ฒˆ์—ญ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋‚ด๊ฐ€ ์•„๋Š” ํ•œ).

@์˜ค์ฝค๋ฒ 

์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ๋””์ž์ธ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณ ๋ คํ•ด์•ผ ํ•  ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์‚ฌํ•ญ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋„์„œ๊ด€์ด ์ž์ฒด ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•), ...

์ด๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ๋„ ์ด ๊ธฐ๋Šฅ์˜ ์ผ๋ถ€์ด๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ท€ํ•˜์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œํ•˜๋Š” ๋™์•ˆ 1๊ฐœ์˜ XLIFF ํŒŒ์ผ๋งŒ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์–ธ์–ด๋ฅผ ๋ฒˆ์—ญํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ๋นŒ๋“œํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋„ค ์ €๋„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ์ด๊ฒƒ์€ ์˜์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ฒญ์ค‘์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ํ”„๋กœ์ ํŠธ์— ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๊ทธ๊ฒƒ์€ ํ™•์‹คํžˆ ์šฐ๋ฆฌ๊ฐ€ ์ง€์›ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒ€์€ ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค :-)

๋Œ€์ƒ์ด ๋  ๋ฒ„์ „์— ๋Œ€ํ•œ ์˜ˆ์ƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์•ฝ 4.3 ์ผ์ง€๋„ ๋ชจ๋ฅธ๋‹ค๋Š” ๊ฒƒ์„ ์–ด๋”˜๊ฐ€์—์„œ ์ฝ์—ˆ๋‹ค.

ํ•„์š”ํ•œ ๋ฆฌํŒฉํ† ๋ง(๋ฐ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ) ๋•Œ๋ฌธ์— v5 ์ด์ „์—๋Š” ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์™€์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„์•„ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…ใ…์•… ์–ธ์–ด. v5๊ฐ€ ์–ธ์ œ์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”

@์˜ค์ฝค๋ฒ 

@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 ๋นŒ๋“œ ์‹œ๊ฐ„์œผ๋กœ ์ธํ•ด ์†์ƒ์ด ์—„๊ฒฉํ•˜๊ฒŒ ์ตœ์†Œํ™”๋ฉ๋‹ˆ๋‹ค.

ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ์š”... ์ด ๋ณ€๊ฒฝ์š”์ฒญ/๋ณ€๊ฒฝ์ด ๊ณต์‹ํ™” ๋˜๋Š” ๊ฑด๊ฐ€์š”?
์—ฌ๊ธฐ์— ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์ง€๋งŒ ๋ฒˆ์—ญ์€ ํ…œํ”Œ๋ฆฟ์—๋งŒ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
redux, ์‚ฌ์šฉ์ž ์ •์˜ treeview ๊ตฌ์„ฑ ์š”์†Œ ๋“ฑ ... ๋ชจ๋‘ ํ…œํ”Œ๋ฆฟ์ด ์•„๋‹Œ ์ฝ”๋“œ์˜ ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๊ฐœ์ฒด์—์„œ ์ƒ์„ฑ๋จ

๊ณต์‹์ ์ด๋ฉฐ ๊ณง ์ถœ์‹œ๋  ์˜ˆ์ •์ด์ง€๋งŒ ๋จผ์ € ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ํฌ๊ฒŒ ๋ณ€๊ฒฝํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— 4.3์—์„œ๋Š” ์ค€๋น„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฑฐ๋‚˜ ๊ณ„ํš ์ค‘์ธ ์ •ํ™•ํ•œ ๋ฒ„์ „์ด ๋ฌด์—‡์ธ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? 4.3.1, 4.3.2 ... 4.3.X ?

4.x ๋ธŒ๋žœ์น˜์—๋Š” ๋” ์ด์ƒ ๋ฉ”์ด์ €/๋งˆ์ด๋„ˆ ๋ฒ„์ „์ด ์—†์Šต๋‹ˆ๋‹ค(ํŒจ์น˜๋งŒ: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md). ์ฆ‰, 5.x์šฉ์ด ๋ฉ๋‹ˆ๋‹ค. , ์–ด๋Š ๊ฒƒ์ด ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์—ฌ์ „ํžˆ 5.x์— ํฌํ•จ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๊นŒ? ๋ฒ ํƒ€์—์„œ๋Š” ์•ˆ๋ณด์ด๋„ค์š”. ๊ฐ์‚ฌ ํ•ด์š”

v5.x๊ฐ€ ์•„๋‹Œ v50.x์— ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‚

5.x ์˜ˆ, ํ•˜์ง€๋งŒ 5.0์—๋Š” ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฅด์ฅฌ. 3 aoรปt 2017 ร  12:56, vltr [email protected] a รฉcrit :

v5.x๊ฐ€ ์•„๋‹Œ v50.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ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋‹น์žฅ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค lol :+1: ๋†€๋ผ์šด ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! :)

ํ˜„์žฌ ์„ค๊ณ„ ๋ฌธ์„œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ AOT ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž๋Š” ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค์–‘ํ•œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์–ธ์–ด์— ๋Œ€ํ•œ ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ–ˆ๋Š”๊ฐ€?

์ด๊ฒƒ์€ ์ข‹์€ ์ง€์ ์ž…๋‹ˆ๋‹ค @gms1.
๋‚˜๋Š” ์ด๊ฒƒ์„ ์—ฌ๊ธฐ์—์„œ ์‹œํ—˜ํ–ˆ๋‹ค.
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž๋Š” i18n ํƒœ๊ทธ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ " ngfactories "๋กœ ์ปดํŒŒ์ผํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค(ng-conf 2017์—์„œ Jason Aden์˜ ์—ฐ์„ค ์ฐธ์กฐ). ๊ทธ๋Ÿฌ๋ฉด ๋ฒˆ์—ญ ํƒœ๊ทธ๊ฐ€ ๋Œ€์ฒด๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ng xi18n ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ node_modules ํด๋”์˜ ํŒŒ์ผ์— ๋Œ€ํ•œ xliff์˜ ๋ฒˆ์—ญ๋„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ์œ ์šฉํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„ i18n ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋””์ž์ธ ๋ฌธ์„œ์—์„œ ์ธ์šฉ:

AOT์˜ ๊ฒฝ์šฐ ์†Œ์Šค ์ฝ”๋“œ๋Š” ์„œ๋น„์Šค ํ˜ธ์ถœ์„ ์ •์  ๋ฒˆ์—ญ์œผ๋กœ ๋Œ€์ฒดํ•˜๋„๋ก ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด TypeScript ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด Angular(AOT) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ ํ˜•์‹์œผ๋กœ ์ถœํŒ๋œ๋‹ค๋ฉด ์ด๊ฒƒ์€ ๋ฌด์—‡์„ ์˜๋ฏธํ• ๊นŒ์š”? ์ด ๋ฌธ์„œ์—์„œ .metadata.json์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ตœ์ข… ์ฝ”๋“œ๋กœ ์ปดํŒŒ์ผํ•ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. @jasonaden ์ด ์—ฌ๊ธฐ์—์„œ ์–ธ๊ธ‰ํ•œ ๋‚ด์šฉ์„ ์ฐธ์กฐํ•˜์„ธ์š”. ์ด๊ฒƒ์€ ๋˜ํ•œ i18n ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฒˆ์—ญ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

@gms1 ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด :

์šฐ๋ฆฌ๋Š” ๋””์ž์ธ ๋ฌธ์„œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ด์ „ ๋ฒ„์ „์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ–ˆ๊ณ  ์•„๋งˆ๋„ ์šฐ๋ฆฌ๊ฐ€ ๋๋‚ด๊ฒŒ ๋  ๊ตฌํ˜„์€ ์•„๋‹ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  AOT ์ปดํŒŒ์ผ๋Ÿฌ๋Š” v5์— ๋Œ€ํ•ด ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ๋ณ€๊ฒฝ๋˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ "aot-ready" ์ฝ”๋“œ๋ฅผ ๊ฒŒ์‹œํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
i18n์˜ ๊ฒฝ์šฐ ์ด๋ฅผ ์ตœ๋Œ€ํ•œ ์‰ฝ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒˆ์—ญ ํŒŒ์ผ์„ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์›ํ•˜๋Š” ๊ฒฝ์šฐ ์žฌ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ถ”๊ฐ€ ์–ธ์–ด

์ด ์„ค๋ช…์— ๋Œ€ํ•ด @ocombe ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

@ocombe ์ด๊ฒƒ์€ ngx-translate์˜ ๊ธฐ๋Šฅ์„ ๊ฐ๋„ ์ž์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ?

@montreal91 ngx-translate์˜ ์–ด๋–ค ๋ถ€๋ถ„๋„ Angular๋กœ ๊ตฌํ˜„๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ œ lib๋Š” ๋งค์šฐ ์ˆœ์ง„ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ "๋Œ€๋ถ€๋ถ„" ์ž‘๋™ํ•˜์ง€๋งŒ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ›จ์”ฌ ๋” ํšจ์œจ์ ์ด๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, angular๋Š” ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค(์ตœ์ข… ๊ตฌํ˜„์ด ๋‹ค๋ฅผ์ง€๋ผ๋„).

์ด๊ฒƒ์€ (https://github.com/PointInside/ng2-toastr) ๊ธฐ๋ฐ˜์˜ UI ์•Œ๋ฆผ ์‹œ์Šคํ…œ์—์„œ ์ž‘์—…ํ•˜๋Š” ๋™์•ˆ์˜ ์ ‘๊ทผ ๋ฐฉ์‹(FLUX)์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์•Œ๋ฆผ ๋‚ด์šฉ์ด Angular i18n ์‹œ์Šคํ…œ(xi18n)์—์„œ ๊ด€๋ฆฌํ•  ํ…œํ”Œ๋ฆฟ์ด ์•„๋‹Œ ์„œ๋น„์Šค ํ˜ธ์ถœ์— ์ •์˜๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ _working_ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ ์กฐ๊ฐ์—์„œ ์•„์ด๋””์–ด๋ฅผ _์ถ”์ถœ_ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค :)

์–ด๋”˜๊ฐ€์—

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

์•Œ๋ฆผ ๊ตฌ์„ฑ ์š”์†Œ.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;
            }
        }
    }
}

์•Œ๋ฆผ ๊ตฌ์„ฑ ์š”์†Œ.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 ๋ชจ๋“ˆ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์–ธ์ œ ํ†ตํ•ฉ๋ฉ๋‹ˆ๊นŒ?

์ด ๊ธฐ๋Šฅ์€ ์•ต๊ทค๋Ÿฌ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํŒ€์€ ๊ด€์‹ฌ์ด ์ ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ž‘์—…์ด๋‚˜ PR ๋˜๋Š” ์ปค๋ฐ‹์ฒ˜๋Ÿผ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค:- (. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋ชจ๋“  ๋ฒˆ์—ญ ํ”„๋ ˆ์ž„์›Œํฌ์— ์žˆ๋Š” ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•˜๋Š” ์ด ๊ธฐ๋Šฅ ์š”์ฒญ์€ ์ด์ œ 1๋…„์ด ๋„˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•„์ˆ˜ ๊ธฐ๋Šฅ์ด ๋„์ฐฉํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ ์–ด๋„ 5.x์—์„œ๋Š”...

์–˜๋“ค์•„ ์นจ์ฐฉํ•ด๋ผ AOT ์ปดํŒŒ์ผ๋Ÿฌ์— ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ฆฌ์„์€ ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. @ocombe ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

"์•„๋งˆ๋„ 5.x์— ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. @vicb ๋Š” ๋งˆ์นจ๋‚ด ์ด๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ์ปดํŒŒ์ผ๋Ÿฌ์— ๋Œ€ํ•œ ๋งˆ์ง€๋ง‰ ๋ณ€๊ฒฝ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค."

์˜ˆ, ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์ธ ๋Ÿฐํƒ€์ž„ i18n์„ ์ž‘์—… ์ค‘์ž…๋‹ˆ๋‹ค.
๋Ÿฐํƒ€์ž„ i18n์€ ๋‹ค์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์–ธ์–ด์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ๋ฒˆ๋“ค, AOT ์ปดํŒŒ์ผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” i18n์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‚˜์ค‘์— ๋Ÿฐํƒ€์ž„์— ์–ธ์–ด๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ๋Ÿฐํƒ€์ž„์— ๋ฒˆ์—ญ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฝ”๋“œ ๋‚ด๋ถ€์˜ ๋ฒˆ์—ญ์— ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค(์™œ๋ƒํ•˜๋ฉด ๋ฒˆ์—ญ์„ ์œ„ํ•œ ๋Ÿฐํƒ€์ž„ ํŒŒ์„œ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค...).
์ด๊ฒƒ์ด ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์Œ ์šฐ์„  ์ˆœ์œ„๋Š” ์ฝ”๋“œ ๋‚ด๋ถ€์˜ ๋ฒˆ์—ญ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ typescript ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์ „์—๋Š” ๋Ÿฐํƒ€์ž„ i18n์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค(5.0์—์„œ ์ˆ˜ํ–‰๋จ).

์–ด๋–ค 5.x ๋ฒ„์ „์— ์–ด๋–ค i18n์ด ๊ฐœ์„ ๋ ์ง€ ์•„์‹ญ๋‹ˆ๊นŒ? 5.0.0 ์ž์ฒด์™€ ํ•จ๊ป˜ ์ถœ์‹œ๋˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

5.0:

  • intl API๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ƒˆ๋กœ์šด i18n ํŒŒ์ดํ”„(๋‚ ์งœ/์ˆซ์ž/๋ฐฑ๋ถ„์œจ/ํ†ตํ™”)๋Š” ์ด์ œ ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— 20๊ฐ€์ง€ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐํƒ€ ๊ฐœ์„  ์‚ฌํ•ญ(๋กœ์ผ€์ผ ๋งค๊ฐœ๋ณ€์ˆ˜, ์ƒˆ๋กœ์šด ์ถ”๊ฐ€ ํ˜•์‹, ๋ฐ์ดํŠธ ํŒŒ์ดํ”„, ...)
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด i18n API ํ•จ์ˆ˜: https://next.angular.io/api?query=getlocale
  • CLI์™€์˜ ๋” ๋‚˜์€ ํ†ตํ•ฉ

5.1 ๋˜๋Š” 5.2(์˜ˆ๊ธฐ์น˜ ์•Š์€ ์ฐจ๋‹จ๊ธฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ):

  • ๋Ÿฐํƒ€์ž„ i18n

5.x:

  • i18n ์ฝ”๋“œ ๋ฒˆ์—ญ(๋‹จ์ˆœํ•œ ํ…œํ”Œ๋ฆฟ์ด ์•„๋‹˜)

๊ทธ๋ฆฌ๊ณ  ์ถ”๊ฐ€ํ•  ์˜ˆ์ •์ด์ง€๋งŒ ์•„์ง ๊ฒฐ์ •๋˜์ง€ ์•Š์€ ๊ธฐํƒ€ ์‚ฌํ•ญ(https://github.com/angular/angular/issues/16477์„ ํŒ”๋กœ์šฐํ•  ์ˆ˜ ์žˆ์Œ).

์กฐ๊ธˆ ๋Šฆ์—ˆ์ง€๋งŒ TS ํŒŒ์ผ์—์„œ i18n ์ง€์›์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์ฃผ์„ ๊ตฌ๋ฌธ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? (๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์œ„์—์„œ๋„ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค)

์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
@i18n (id='message1')
message1 = "๋ฒˆ์—ญํ•ด์•ผ ํ•  ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.";

@i18n (id='๋™์  ๋ฉ”์‹œ์ง€')
dynamicMessage = "์ด๊ฒƒ์€ {0}์ด(๊ฐ€) ํฌํ•จ๋œ ๋™์  ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.";

dynamicMessage์— ๋Œ€ํ•œ ์ฃผ์„์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ฆ„์ด format ์ธ ์ด ๋ฌธ์ž์—ด ์ธ์Šคํ„ด์Šค์— ์ฃผ์„์„ ํ†ตํ•ด ํ•จ์ˆ˜๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
var finalMessage = dynamicMessage.format('๊ฐ’1')

๋ช…๋ช…๋œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋“ฑ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๋น„์Šทํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ข‹์€ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ 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. ๋ฐฑ์—”๋“œ๋Š” ๋ฒˆ์—ญํ•˜๋ ค๋Š” ํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  2. ํ˜„์žฌ/์ฃผ์š” ์–ธ์–ด๋กœ ํ‘œ์‹œํ•˜๋Š” ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ๊ต์ฒด/(๋˜๋Š” ํ˜„์žฌ ์ ‘๊ทผ ๋ฐฉ์‹์ธ ๋ฐฑ์—”๋“œ์—์„œ ๋‹ค์šด๋กœ๋“œ). (๋ชจ๋“  ๊ฒƒ์„ ๊ต์ฒดํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ์ง€๋งŒ ๊ฐ„๋‹จํ•œ ๋ ˆ์ด๋ธ”์„ ํ‘œ์‹œํ•  ๋•Œ๋งˆ๋‹ค ๋‘ ๊ฐœ์˜ ํ‚ค๋ฅผ ์ฐพ์„ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค).
  3. ์ง„์ •ํ•œ ๋™์  ํ…์ŠคํŠธ๋งŒ ๋Œ€์ฒด ๋ฐ/๋˜๋Š” ๋ฐฑ์—”๋“œ์— ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ๊ฐํ•ด ๋ณด์„ธ์š”. ํ‘œ์‹œํ•  ๋™์  ํ…์ŠคํŠธ๊ฐ€ ์ •๋ง ์žˆ๋‹ค๋ฉด ๋ฐฑ์—”๋“œ์—์„œ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ณ  "๋™์  ํ…์ŠคํŠธ"์˜ ๋ณต์‚ฌ๋ณธ์ด ์ •๋ง๋กœ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ•ญ์ƒ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ ์ƒ๊ฐ์—๋Š” ๋” ์ด์ƒ ์ด ๋ฌธ์ œ๋ฅผ ๋…ผ์˜ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ i18n์—์„œ ํ’€ํƒ€์ž„์œผ๋กœ ์ผํ•˜๋Š” ์‚ฌ๋žŒ(Olivier Combe)์ด ์žˆ์Šต๋‹ˆ๋‹ค. AOT๋Š” ๋งค์šฐ ํŠน๋ณ„ํ•˜๋ฉฐ ์ด ๋ฌธ์ œ๋ฅผ ๊ฐ€๋Šฅ์— ๊ฐ€๊น๊ฒŒ ๋งŒ๋“ค๊ธฐ๊นŒ์ง€ ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณง ๋™์  ๋ฒˆ์—ญ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. ๋” ์ด์ƒ ๊ฐ ์–ธ์–ด๋ฅผ ๋ณ„๋„๋กœ ๊ตฌ์ถ•ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค! ์ด ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ๋‚˜์ค‘์— ์ฝ”๋“œ ๋‚ด์—์„œ ๋ฒˆ์—ญ(์ด ๋ฌธ์ œ)์„ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ์•ž์œผ๋กœ ๋ฐ˜๋…„์ด ๊ฑธ๋ฆด ๊ฒƒ์ด๋ผ๊ณ  ๋งํ–ˆ๋‹ค.

๊ด€์‹ฌ์ด ์žˆ์œผ์‹œ๋ฉด 07.11.17์˜ Angular Connect์—์„œ Angular์—์„œ i18n์˜ ํ˜„์žฌ์™€ ๋ฏธ๋ž˜์— ๋Œ€ํ•œ ์—ฐ์„ค์„ ํ™•์ธํ•˜์„ธ์š”. https://youtu.be/DWet6RvhHWI?t=21m12s

์ด๊ฒƒ์€ typescript ํƒœ๊ทธ๊ฐ€ ์ง€์ •๋œ ํ…œํ”Œ๋ฆฟ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ข‹์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค...

์ด๊ฒƒ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ƒ„์ƒˆ๊ฐ€๋‚ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋งค๋‹ฌ ํ•œ ๋ฒˆ ๋ฐฉ๋ฌธํ•˜์—ฌ ์ง„ํ–‰ ์ƒํ™ฉ์„ ํ™•์ธํ•˜๊ณ  ๊ธฐ๋Œ€์น˜๊ฐ€ ๋‚ฎ์•„์ ธ ์‹ค๋ง์„ ๋ฉˆ์ท„์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ํ…œํ”Œ๋ฆฟ์—์„œ์™€ ๊ฐ™์ด ์ฝ”๋“œ์—์„œ ๋ฌธ์ž์—ด ๋ฒˆ์—ญ์— ๋Œ€ํ•ด ๋™์ผํ•œ ์˜ต์…˜์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด ์ฝ”๋“œ๋Š” ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ ๋ถ€์กฑ์œผ๋กœ ์ธํ•ด ์ˆจ๊ฒจ์ง„ ๋ฒˆ์—ญ๋œ ํ…œํ”Œ๋ฆฟ ๋ฌธ์ž์—ด๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๊ฒฐ๊ตญ ์„œ๋น„์Šค ๋˜๋Š” ์ฃผ์„์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ์ถ”๊ฐ€๋กœ ๋ฐ€๋ฆฌ์ดˆ๊ฐ€ ์†Œ์š”๋˜๋Š”์ง€ ์—ฌ๋ถ€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ ๋ฌธ์ž์—ด์„ ์„ ํƒํ•  ๋•Œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ์ด๋ฏธ ๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค . ์œ ์ผํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์€ ์ฝ”๋“œ๊ฐ€ ๊ตฌ๋ฌธ ๋ถ„์„๋˜๊ณ  ๊ด€๋ จ ๋ฌธ์ž์—ด์ด ๋‚ด ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜ ๋ฒˆ์—ญ๊ณผ ๋™์ผํ•œ ํ˜•์‹์˜ ๋™์ผํ•œ ํŒŒ์ผ๋กœ ๋๋‚˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@eliasre ์ฝ”๋“œ ๋ฒˆ์—ญ์ด ๊ธ‰ํ•œ ๊ฒฝ์šฐ https://github.com/ngx-translate/i18n-polyfill ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์ด ๊ฐ™์„ ๊ฒƒ์ด๋ผ๋Š” ์•ฝ์†์€ ์—†์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์•„๋งˆ๋„ ๋‹ค๋ฅผ ๊ฒƒ์ž…๋‹ˆ๋‹ค(์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์—), ์ง€๊ธˆ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์— ์ œํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค... ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉํ•  ์•ฑ์— ~80ko๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค ๊ทธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์œผ๋ ค๋ฉด ngx-translate๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ocombe ์‚ฌ์šฉํ•  ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋Œ€ํ•œ ๊ฒฐ์ •์„ ๊ธฐ๋‹ค๋ฆด ๋•Œ ๊ฐœ๋ฐœ ์ผ์ •์— ๋”ฐ๋ผ ์ถ”์ ํ•˜๊ณ  ๊ณ„ํšํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง„ํ–‰ ์ƒํ™ฉ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ œ๊ณตํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์€ ๋งค์šฐ ๋„์›€์ด๋˜๊ณ  ๊ฐ์‚ฌ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค

@eliasre ๊ตฌ๊ธ€์ด ํ•œ๋ฒˆ์— ์ข‹์€ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ญ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋„ ๋ณ€ํ•จ์—†์ด. ์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๋‚œํ•œ @ocombe ๋ฅผ ๊ดด๋กญํžˆ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๊ทธ๋Š” ๋งค์šฐ ์—ด์‹ฌํžˆ ์ผํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค!
๊ณ„์† ํ•ด! :)

์ œ๊ฐ€ ์ด ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์‚ฌ๋žŒ์ด ์•„๋‹ˆ๊ณ  ํœด์ผ์ด๋ผ ๋” ์•Œ๊ฒŒ ๋˜๋Š”๋Œ€๋กœ ์•Œ๋ ค๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค

@ocombe ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

@ocombe ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์—ฌ๊ธฐ์—์„œ ํฌ๊ฒŒ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ง€๋‚œ ๋ช‡ ๋‹ฌ ๋™์•ˆ ๋Ÿฐํƒ€์ž„ i18n์„ ๊ฐ„์ ˆํžˆ ๊ธฐ๋‹ค๋ ธ๊ณ  ๋งˆ์ง€๋ง‰ ๋นŒ๋“œ ETA๋Š” 5.2์˜€์Šต๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ๋œ ETA๋ฅผ ์—ฌ๊ธฐ์—์„œ ์•Œ๋ ค ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋ˆ์งˆ๊ธฐ๊ฒŒ ํ•ด์„œ ๋ฏธ์•ˆํ•˜์ง€๋งŒ 20๊ฐœ ์–ธ์–ด๋กœ ๋นŒ๋“œํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ๋กœ์„œ๋Š” ์—„์ฒญ๋‚˜๊ฒŒ ๋Š๋ฆฝ๋‹ˆ๋‹ค.

Angular 5.2๊ฐ€ ๋‚˜์™”๊ณ  ๋ถˆํ–‰ํžˆ๋„ i18n ๊ณผ ๊ด€๋ จ๋œ ๊ฒƒ์„ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. i18n์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ๋…ธ๋ ฅ์— ๋Œ€ํ•ด ๋งŽ์ด & thx ๋งŽ์ด!

@ocombe ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ์ด ์•„๋‹™๋‹ˆ๋‹ค... ์ด ๋Œ“๊ธ€์˜ YouTube ๋งํฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”: https://github.com/angular/angular/issues/11405#issuecomment -343933617

๊ณ„ํš์€ ์ง€์†์ ์œผ๋กœ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ถœ์‹œ ๋‚ ์งœ๋ฅผ ์ค„ ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒƒ์ด ์šฐ์„  ์ˆœ์œ„๋ฅผ ์–ป๊ฑฐ๋‚˜ ํ•„์ˆ˜๊ฐ€ ๋˜์–ด ๋‚ ์งœ๋ฅผ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ๊ธฐ๋‹ค๋ ค์ฃผ์‹  ์—ฌ๋Ÿฌ๋ถ„๊ป˜ ์–ผ๋งˆ๋‚˜ ์‹ค๋ง์Šค๋Ÿฌ์šด์ง€ ์ž˜ ์•Œ๊ณ  ์žˆ์œผ๋ฉฐ ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ตœ์„ ์„ ๋‹คํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋‚ด์ผ i18n ๋ฐฑ๋กœ๊ทธ/๊ณ„ํš์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ธฐ ์œ„ํ•œ ํšŒ์˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์†Œ์‹์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

@ocombe ์ด๋ฒˆ๋‹ฌ ์— i18n ์ถœ์‹œ๋˜๋ฉด ์ˆ˜์ œ๋งฅ์ฃผ 24ํŒฉ ์‚ฌ์ค„๊ฒŒ

Angular Elements ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ง€์›์ด ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ๋ฌป๋Š”๋‹ค๋ฉด ๋…์ผ ๋งฅ์ฃผ 24๋ณ‘๊ณผ 24๋ณ‘์„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ •๋ณด๋ฅผ ์–ป์ง€ ๋ชปํ•˜๋Š” ์  ์žฅ.

@ocombe ๊ฐ’๋น„์‹ผ ์ˆ˜์ œ ๋งฅ์ฃผ 72๋ณ‘์„ ๊ตฌ์ž…ํ•˜๊ณ  ๊ฐœ๋ฐœ ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ ํ–‰๋ณตํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ƒ์— ํ•œ ๋ฒˆ๋ฟ์ธ ๋“œ๋ฌธ ๊ธฐํšŒ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์ด๊ฒƒ์„ ์„ฑ์ทจํ•œ๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ์˜ ์•ฝ์†์„ ์ดํ–‰ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค ์นœ๊ตฌ.

@MickL Angualr Elments, ๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ SPA๊ฐ€ ์•„๋‹Œ ํŽ˜์ด์ง€๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ๊ฐ๋„ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ธฐ๋ณธ ์š”์†Œ(์ž์ฒด ์œ„์ ฏ์œผ๋กœ๋„ ์‚ฌ์šฉ)๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ค ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ชจ๋‘๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” 2๊ฐœ์˜ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ์ƒํƒœ๊ฐ€ ๋ฌด์—‡์ด๋ฉฐ ์–ธ์ œ ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋Š” ์•„๋ฌด๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค...

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋งˆ์ง€๋ง‰ 27๋ณ‘์˜ ๋งฅ์ฃผ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ๋‹ค๊ณ  ์•ฝ์†ํ•œ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๋“ค์„ ์…€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!
http://www.99-bottles-of-beer.net/language-javascript-1948.html

@ocombe ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค : ์ข‹์•„ํ•˜๋Š” ๋ธŒ๋žœ๋“œ ์ด๋ฆ„์„ ์ง€์ •ํ•˜์„ธ์š” :D

ํŽธ์ง‘ : ๋ˆ„๊ตฐ๊ฐ€ beerbounty :p๋ผ๋Š” eth bounty์™€ ์œ ์‚ฌํ•œ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์•ฝ์†๋Œ€๋กœ ์•ฝ๊ฐ„์˜ ์—…๋ฐ์ดํŠธ: ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ v6์—์„œ ๋Ÿฐํƒ€์ž„ i18n์„ ์ถœ์‹œํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์งง์„ ๊ฒƒ์ด๊ณ  ์•„๋งˆ๋„ ๋งˆ์ง€๋ง‰ ๋ฆด๋ฆฌ์Šค ์ค‘ ํ•˜๋‚˜์— ์ถ”๊ฐ€๋  ๊ฒƒ์ด๋ฉฐ ํ”Œ๋ž˜๊ทธ ๋’ค์— ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋Ÿฐํƒ€์ž„ i18n์€ ์ฝ”๋“œ ๋ฒˆ์—ญ๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๊ฒƒ์ด ์–ด์จŒ๋“  ํ…œํ”Œ๋ฆฟ์—์„œ๋„ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(๋™์ผํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ).
๋‹ค๋งŒ, ์„œ๋น„์Šค๊ฐ€ 100% ์ค€๋น„๋ ์ง€๋Š” ๋ฏธ์ง€์ˆ˜์ด๋ฉฐ, ์ถœ์‹œ ์งํ›„ ์ค‘๋‹จ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์˜ณ์€ ์„ ํƒ์ด๋ผ๊ณ  ํŒ๋‹จ๋˜๋ฉด ์—ฐ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ๋Ÿฐํƒ€์ž„ i18n์„ ๋”ฐ๋ฅผ ๊ฒƒ์ด๋ฉฐ(์ด๊ฒƒ์ด ์šฐ๋ฆฌ์˜ ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค) ํ”Œ๋ž˜๊ทธ ๋’ค์— ์žˆ์„ ๊ฒƒ์ด๊ณ  ์–ด์จŒ๋“  ์•„๋ฌด ๊ฒƒ๋„ ๊นจ๋œจ๋ฆฌ์ง€ ์•Š์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆด๋ฆฌ์Šคํ•˜๊ธฐ ์œ„ํ•ด ์ฃผ ๋ฒ„์ „์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ œ๋•Œ ๊ณต๊ฐœํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ:

  • ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•œ ๊ฒฝ์šฐ(๊ฐœ๋ฐœ ๋ฐฉ์‹์„ ์•Œ๊ณ  ์žˆ์Œ)
  • ์šฐ๋ฆฌ๊ฐ€ ์–ด๋”˜๊ฐ€๋ฅผ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๋‚ด๋ถ€ ๊ตฌ๊ธ€ ์•ฑ์„ ๋ง๊ฐ€๋œจ๋ฆฐ๋‹ค๋ฉด
  • ์ตœ์šฐ์„  ๊ณผ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์ดˆ์ ์„ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ์˜์กดํ•˜๋Š” ์ƒˆ๋กœ์šด ๊ฒƒ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์ฐจ๋‹จ๋˜๊ฑฐ๋‚˜ ์ง€์—ฐ๋œ ๊ฒฝ์šฐ(๋Ÿฐํƒ€์ž„ i18n์€ ํŒ€์˜ ๋‹ค๋ฅธ ๊ตฌ์„ฑ์›์ด ์ž‘์—… ์ค‘์ธ ์ฃผ์š” ๋‚ด๋ถ€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„)
  • 3๋…„ ๋™์•ˆ PascalPrecht์˜ ๋ฒˆ์—ญ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์˜จ AngularJS ์ˆ˜์„ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.
  • ๋‚˜๋ฅผ ํฅ๋ถ„์‹œ์ผฐ๋‹ค. ์•ต๊ทค๋Ÿฌ2 ์‹ ์ธ. ์ˆœ์ง„ํ•˜๊ฒŒ ํƒ์ƒ‰ https://angular.io/guide/i18n
  • i18n์„ ๋‚ด ์ „๋ฌธ ํ”„๋กœ์ ํŠธ์— ์„ฑ๊ณต์ ์œผ๋กœ ํ†ตํ•ฉ
  • 100+kb xlf ํŒŒ์ผ๋กœ ํฌํŒ…ํ•˜๋Š” ๋ชจ๋“  ํ”„๋ก ํŠธ ์—”๋“œ ํ•˜๋“œ ์ฝ”๋”ฉ ๋ ˆ์ด๋ธ”์„ ์–ด์ง€๋Ÿฝํžˆ๋Š” ๋ฐ ํ•˜๋ฃจ ์ข…์ผ ์†Œ๋น„
  • ng ์„œ๋น„์Šค ๋‚ด์—์„œ ์›์‹œ ๋ ˆ์ด๋ธ”์„ ๋ฒˆ์—ญํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ๊ตฌ๊ธ€์—์„œ ์ฐพ์•„๋ณด๋ฉด ์—ฌ๊ธฐ ์žˆ์–ด
  • Angular 6 ์‹œ๋Œ€ ์ด์ „์—๋Š” ํ•ด๊ฒฐ์ฑ…์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„๋‚ด์‹ญ์‹œ์˜ค.
  • ๋‚˜ rn
    mfw

@Macadoshis ์ง€๊ธˆ์€ ๋‚ด polyfill ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/ngx-translate/i18n-polyfill

@Macadoshis ๋Š” ์ด์ œ alpha.46 ์ดํ›„๋กœ ์šฐ๋ฆฌ๊ฐ€ ๊ฒช์—ˆ๋˜ ์ผ์„ ์ƒ์ƒํ•ด ๋ณด์„ธ์š”! ;)

i18n-polyfill @ocombe ๋ฅผ ์•Œ๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฒˆ์—ญ ํ‚ค์˜ ๋น„๋™๊ธฐ ๋กœ๋“œ๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ngx-translate ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
TRANSLATIONS ์ œ๊ณต์ž๋ฅผ ์œ„ํ•œ i18n-polyfill ํŒฉํ† ๋ฆฌ๋Š” ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ์ด์ „์— ์•Œ๋ ค์ง„ ๊ณ ์ • ๋กœ์ผ€์ผ์˜ ๋™๊ธฐํ™” ์›์‹œ ๋กœ๋”ฉ๋งŒ ์ง€์›ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// 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 ๋‹น์‹ ์ด ์ž‘์„ฑํ•œ ํด๋ฆฌํ•„์ด ์ถœ์‹œ๋˜๋Š” ๊ฒƒ์— ์–ผ๋งˆ๋‚˜ ๊ฐ€๊น์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๊ฐ€ ์•Œ๊ณ  ์žˆ๊ฑฐ๋‚˜ ์ค€๋น„ํ•ด์•ผ ํ•  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋˜ํ•œ ๋ฒ„์ „ 6์—์„œ ๋ฆด๋ฆฌ์Šค๋˜๋Š” i18n์˜ ๊ธฐ๋Šฅ ๋ชฉ๋ก๊ณผ i18n์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์ง€๊ธˆ์€ ์ฝ”๋“œ ๋ฒˆ์—ญ ์„œ๋น„์Šค์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋‹ค์Œ ์ฃผ์— ์ž‘์—…ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(์ €๋Š” ๋งˆ์šดํ‹ด ๋ทฐ๋กœ ์—ฌํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค). ๋‚ด๊ฐ€ ์•„๋Š” ๊ฒƒ์€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํด๋กœ์ € ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ goog.getMsg ์™€ ์œ ์‚ฌํ•  ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค(ํ˜„์žฌ Google์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—): https://github.com/google/closure-library /blob/db9bc1a2e71d4b6ee8f57eebe37eb0c6494e9d7e/closure/goog/base.js#L2379 -L2387 ์ด๋Š” ๋‚ด ํด๋ฆฌํ•„๊ณผ๋„ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

v6์—์„œ ์šฐ๋ฆฌ๋Š” ๋Ÿฐํƒ€์ž„ i18n์„ ์ถœ์‹œํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค: ๋ชจ๋“  ๋กœ์ผ€์ผ์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ๋ฒˆ๋“ค, ๋Ÿฐํƒ€์ž„์— ํ•ด์„๋œ ๋ฒˆ์—ญ, ์‹œ๊ฐ„์ด ์žˆ๋‹ค๋ฉด ์ฝ”๋“œ ๋ฒˆ์—ญ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๊ณง ๋‚˜์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค). ์ „ํˆฌ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š์€ ์ƒˆ ๋ Œ๋”๋Ÿฌ(ng-ivy๋ผ๊ณ  ํ•จ)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ชจ๋“  ๊ฒƒ์ด ํ”Œ๋ž˜๊ทธ ๋’ค์— ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ ๋งˆ์›Œ! @ocombe ... ์ •๋ง ์ข‹์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!
ํ…œํ”Œ๋ฆฟ ๋ฒˆ์—ญ์„ ์œ„ํ•œ ๊ตฌ๋ฌธ์— ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ์— ๋ฒˆ์—ญ์„ ์ถ”๊ฐ€ํ•  ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ช‡ ์ฃผ ์•ˆ์— ์™„์ „ํžˆ ๋‹ค์‹œ ํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”, ํ…œํ”Œ๋ฆฟ ๊ตฌ๋ฌธ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์ข‹์€ ์†Œ์‹์„ ์•Œ๋ ค์ค€ @ocombe ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋งค์šฐ ์œ ๋งํ•ฉ๋‹ˆ๋‹ค. v6๊ณผ ํ•จ๊ป˜ ์ถœ์‹œ๋  ng-ivy ๋ Œ๋”๋Ÿฌ์—์„œ ์–ด๋–ค ์ข…๋ฅ˜์˜ ํ”„๋กœ๋•์…˜ ์ค€๋น„๋ฅผ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ „ํˆฌ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ํ”„๋กœ๋•์…˜ ์‚ฌ์šฉ์„ ์œ„ํ•ด ์ค€๋น„๋˜๊ณ  ๊ฑฐ์˜ ์ตœ์‹  ๋ฒ„์ „์˜ ๋ชจ๋“  ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋งž์Šต๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์—์„œ ์ง„ํ–‰ ์ƒํ™ฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/angular/angular/issues/21706
๋ชจ๋“  ๊ฒƒ์ด v6์— ๋Œ€ํ•ด ์ค€๋น„๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”Œ๋ž˜๊ทธ ์•„๋ž˜์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— v6 ๋ฆด๋ฆฌ์Šค ํ›„์—๋„ ๊ณ„์† ์ง„ํ–‰ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€ ๋˜๋Š” ๊ทธ ๋ฐ–์˜ ๊ฒƒ์€ ์•„๋‹˜)
์†”์งํžˆ ๊ทธ ๋ชจ๋“  ๊ฒƒ๋“ค์ด ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค :D
๋‚˜๋Š” cli์˜ hello world ์•ฑ์ด ์ด๋ฏธ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ƒˆ ๋ Œ๋”๋Ÿฌ์˜ ์ตœ์ ํ™”์—์„œ ์ด์ ์„ ์–ป์œผ๋ ค๋ฉด ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค ์ค‘ ์ผ๋ถ€๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๋ชจ๋“  ๊ฒƒ์„ ํ™•์ธํ•˜์ง€ ์•Š๊ณ ๋„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ฆ‰, ์ƒ์‚ฐ ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ์•„์ง ์ œํ’ˆ์— ๋ฒ ํŒ…ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๋‚ด๋ถ€ Google ์•ฑ์—์„œ๋Š” ํ…Œ์ŠคํŠธ๋˜์ง€ ์•Š์œผ๋ฉฐ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ์ฃผ์š” ๋ณ€๊ฒฝ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ ๋ Œ๋”๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž์˜ ์žฌ๋Ÿ‰์— ๋”ฐ๋ผ ์œ„ํ—˜์„ ๊ฐ์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

v6-beta4์— ์ด ์ค‘ ํ•˜๋‚˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์•„๋‹ˆ์š”. ์ด ๋กœ๋“œ๋งต ์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. ์ด ๊ธฐ๋Šฅ์€ i18n ๋Ÿฐํƒ€์ž„์— ์˜ํ•ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ @ocombe ?

๋Ÿฐํƒ€์ž„ i18n์˜ ์ฒซ ๋ฒˆ์งธ PR์ด ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  Hello World ๋ฐ๋ชจ ์•ฑ๊ณผ ํ•จ๊ป˜ ๋งˆ์Šคํ„ฐ์— ๋ณ‘ํ•ฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„์— ์ž‘๋™ํ•˜๋ฉฐ ์•„์ง ์„œ๋น„์Šค๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ์ด๋ก ์ ์œผ๋กœ ์ฝ”๋“œ ๋ฒˆ์—ญ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
์ง€๊ธˆ์€ ๋งค์šฐ ์ตœ์†Œํ•œ์˜ ์ง€์›(์ •์  ๋ฌธ์ž์—ด)์ด๋ฉฐ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(๋‹ค์Œ ์ฃผ์— ์ถ”์ถœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ ๋‹ค์Œ ์ž๋ฆฌ ํ‘œ์‹œ์ž์™€ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ๋™์  ๋ฌธ์ž์—ด).
๊ทธ ํ›„ ์ฝ”๋“œ ๋ฒˆ์—ญ ์„œ๋น„์Šค๋ฅผ ํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.
์ƒˆ ๊ธฐ๋Šฅ์ด ์™„๋ฃŒ๋˜๋ฉด ๋งˆ์Šคํ„ฐ์— ๋ณ‘ํ•ฉ๋˜๋ฏ€๋กœ ์ƒˆ ์ „๊ณต์„ ๊ธฐ๋‹ค๋ฆด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

@ocombe i heart i18n ๊ธฐ๋Šฅ์€ ์ด๋ฏธ v4.3์— ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!! ๋„ˆ๋ฌด ๋งŽ์€ ๋ฆด๋ฆฌ์Šค๊ฐ€ ์žˆ์ง€๋งŒ i18n์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ์—†์Šต๋‹ˆ๋‹ค. Angular ํŒ€ ๊ด€๋ฆฌ์ž๊ฐ€ ๋” ๋งŽ์€ ์ž‘์—…/๊ฐœ๋ฐœ์ž๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ํ˜ผ์ž ๋˜๋Š” ๋‘ ๋ช…์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด i 18n ๊ธฐ๋Šฅ์€ Angular๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ์•ฑ/๋Œ€ํ˜• ์•ฑ์œผ๋กœ ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋นŒ๋“œ๋˜๋Š” ํ•„์ˆ˜ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ด ๋‘ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์€ ๋Œ€ํ˜• ์•ฑ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”

@ocombe ์—๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ง์€ ๊ทธ๊ฐ€ ์ด ๊ธฐ๋Šฅ์— ์Ÿ๋Š” ๋ชจ๋“  ๋…ธ๋ ฅ์— ๋Œ€ํ•ด ๊ฐ์‚ฌํ•˜๋‹ค๋Š” ๋ง๋ฟ์ž…๋‹ˆ๋‹ค. ๋” ์ด์ƒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์—†๋‹ค๋ฉด ๊ทธ๊ฐ€ ์š”์ฒญํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ๋†”๋‘์„ธ์š”. ์ถœ์‹œ๋˜๋ฉด ํ›„ํšŒํ•˜์ง€ ์•Š์„ ๊ฑฐ์—์š”.

์ฐธ๊ณ ๋กœ...

json ํŒŒ์ผ์— ์ €์žฅ๋œ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ง€์›์„ ํฌํ•จํ•˜์—ฌ ์›๋ž˜ Aurelia์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐœ๋ฐœ๋œ ๋ฌธ์ž์—ด ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์œ„ํ•œ ๋Œ€์ฒด ๋„๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. 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 ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ๊ฐ€ ์–ผ๋งˆ ๋™์•ˆ ์—ด๋ ค ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. HTML๊ณผ ๊ตฌ์„ฑ ์š”์†Œ ์ฝ”๋“œ ํ…์ŠคํŠธ๋ฅผ ๋ชจ๋‘ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ Angular์—์„œ ๋‹ค๊ตญ์–ด ์‚ฌ์ดํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ๋Œ€ํ•œ ์ฃผ์š” ๊ด€์‹ฌ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
ocombe ๋ชจ๋“  ๊ตฌ๋…์ž์—๊ฒŒ ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”. 2018๋…„ 5์›”์ด ์ฝ”์•ž์ธ ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์˜ ์นœ์ ˆํ•œ ๊ธฐ์—ฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

@ocombe ์ด ๋Ÿฐํƒ€์ž„ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Ivy๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์ด์ „ ์—”์ง„์—์„œ๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

๋‹ด์Ÿ์ด๋ฉ๊ตด๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์•„์ง ๋ฏธ์™„์„ฑ์ด๋ผ ์‚ฌ์šฉ๋ถˆ๊ฐ€

@ocombe ์˜ ๋ชจ๋“  ๋…ธ๋ ฅ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•ด ๋ง์”€ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

Ivy๋Š” ํ˜„์žฌ ์‹œํ—˜ํŒ ์ƒํƒœ์—์„œ ์ปดํŒŒ์ผ๋Ÿฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Angular 6์—์„œ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ƒˆ๋กœ์šด 18n ๊ธฐ๋Šฅ์„ ํ˜„์žฌ Ivy ์‹œํ—˜ํŒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•„์ง๊นŒ์ง€๋Š” ์•„๋‹ˆ์ง€๋งŒ, ๋‚˜๋Š” ์ข‹์€ ์ง„์ „์„ ์ด๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์ง€๊ธˆ ์ด ์ผ์— ๋Œ€ํ•ด ํ’€ํƒ€์ž„์œผ๋กœ ์ผํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค). ๋งˆ์Šคํ„ฐ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฉด ์—ฌ๊ธฐ์— ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฒŒ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@ocombe ์ •๋ง ๊ฐ์‚ฌ ํ•ฉ๋‹ˆ๋‹ค! ๋‹น์‹ ์˜ ๋…ธ๋ ฅ์œผ๋กœ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ํ˜œํƒ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋ชจ๋‘๋Š” ๊ทธ๊ฒƒ์„ ํฌ๊ฒŒ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@ocombe ts์˜ ์ •์  ๋ฒˆ์—ญ์€ ์•„์ง ๊ณ„ํš ์ค‘์ž…๋‹ˆ๊นŒ? typescript ๋ณ€ํ™˜์œผ๋กœ ์ปดํŒŒ์ผ ํƒ€์ž„ ํ‘œํ˜„์‹ ๊ต์ฒด๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ง€์ • ts ๋ณ€ํ™˜์„ ์ถ”์ถœํ•˜์ง€ ์•Š๊ณ  ng build ํŒŒ์ดํ”„๋ผ์ธ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@TinyMan ์ด ๋ฌด์Šจ ๋ง์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ ์‹œ๊ฐ„์— ๋ฒˆ์—ญ์„ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ธ๊ฐ€์š”(์ง€๊ธˆ์ฒ˜๋Ÿผ), ์•„๋‹ˆ๋ฉด ts ์ฝ”๋“œ์—์„œ ๋ฒˆ์—ญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ธ๊ฐ€์š”(์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ…œํ”Œ๋ฆฟ ๋ฒˆ์—ญ ์ œ์™ธ)?

@ocombe ๋‚ด ๋ง์€ ts์—์„œ ๋ฒˆ์—ญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์„œ๋น„์Šค๋‚˜ DI/๋Ÿฐํƒ€์ž„ ๋ฒˆ์—ญ์„ ํ†ตํ•ด์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ ํƒ€์ž„ ๋ฒˆ์—ญ์„ ์˜๋ฏธํ•˜์ง€๋งŒ typescript์šฉ์ž…๋‹ˆ๋‹ค. 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 !"),
}

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ (in fr)๊ณผ ๊ฐ™์ด ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

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 ์—ฌ๊ธฐ์—๋„ ๊ฐ์‚ฌ ์ธ์‚ฌ๋ฅผ ์ „ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์ด ์ผ์„ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋งค์šฐ ๊ฐ์‚ฌํ•˜๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ ์ œ ์ผ์— ์—„์ฒญ๋‚˜๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ: ํ…์ŠคํŠธ๋ฅผ ์ฐพ์„ ๋•Œ ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ์ž์—ด์„ ์–ป๊ธฐ ์œ„ํ•ด ๋Ÿฐํƒ€์ž„์— xlf๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•œ ์„ธํŠธ์˜ ๋ฒˆ๋“ค ํŒŒ์ผ๋งŒ ๋งŒ๋“œ๋Š” AOT ์ปดํŒŒ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋”ฐ๋ผ์„œ ๋ณธ์งˆ์ ์œผ๋กœ ์–ธ์–ด๋‹น 1๊ฐœ์˜ xlf ํŒŒ์ผ๊ณผ 5๊ฐœ ๋˜๋Š” 6๊ฐœ์˜ ๋ฒˆ๋“ค ํŒŒ์ผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ 10๊ฐœ ์–ธ์–ด์™€ AOT ์ปดํŒŒ์ผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ 50๊ฐœ ์ด์ƒ์˜ ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์–ธ์–ด๋‹น ๋ฒˆ๋“ค ํŒŒ์ผ ์„ธํŠธ...

๋‚˜๋Š” ๊ทธ๋Ÿฐ ๋…ธ๋ ฅ์ด๋‚˜ ๋ณต์žก์„ฑ์„ ๋ชจ๋ฅด์ง€๋งŒ 1 ์„ธํŠธ์˜ ํŒŒ์ผ ๋งŒ ์žˆ์œผ๋ฉด ์ปดํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ, ๊ทธ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ivy, ๋Ÿฐํƒ€์ž„ i18n์œผ๋กœ ํ•  ์ผ์ž…๋‹ˆ๋‹ค.
์•ฑ์„ ํ•œ ๋ฒˆ ๋ฒˆ๋“คํ•˜๊ณ  ๋Ÿฐํƒ€์ž„์— ๋ฒˆ์—ญ์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค(๋ฒˆ์—ญ์„ ์ง€์—ฐ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Œ).

@๊ทธ๋ ‡๊ตฌ๋‚˜ . ์ด๋‹ค. ๋ฏฟ์„ ์ˆ˜์—†๋Š”.

๋ฏฟ์„ ์ˆ˜ ์—†์„ ์ •๋„๋กœ ํ–‰๋ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!

์™ธ๋ถ€ ํ…œํ”Œ๋ฆฟ์„ ๋ฒˆ์—ญํ•  ์ˆ˜ ์—†๋Š” i18n ๊ธฐ๋Šฅ์€ ๋‚˜์—๊ฒŒ ์™„์ „ํžˆ ์“ธ๋ชจ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

@ocombe ์•ˆ๋…•ํ•˜์„ธ์š” ์˜ฌ๋ฆฌ๋น„์—!
์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ฐ์‚ฌ ํ•ด์š”!

์™„๋ฃŒ๋˜๋ฉด Angular 7(2018๋…„ 9์›”/10์›”)๋กœ ์˜ˆ์ •๋œ Ivy๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Angular 7์—์„œ๋Š” ์ด ๋ฌธ์ œ๊ฐ€ 2๋…„ ๋œ LOL์ด ๋ฉ๋‹ˆ๋‹ค.
์–ด์จŒ๋“  Ivy๋Š” ์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๊ฐ€์žฅ ์ง€์—ฐ์‹œํ‚จ ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค...

@ocombe , ๋“ฃ๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ ์ˆœ์ „ํžˆ ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋กค๋งํ•œ ๋ ˆ๊ฑฐ์‹œ i18n ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. JS์—์„œ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ ์šฐ๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ๊ฐ„๋‹จํ•œ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์„ ๊ทน๋„๋กœ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  • ๋™์  ๊ตฌ์„ฑ ์š”์†Œ
  • ์ผ๋ถ€ ํ˜„์ง€ํ™”๋œ ํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ํƒ€์‚ฌ ์„œ๋น„์Šค์™€ ํ†ตํ•ฉ
  • ๋™์  ํ™•์ธ ๋ชจ๋‹ฌ ํ‘œ์‹œ
  • ์šฐ๋ฆฌ API๋Š” types ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๋งฅ๋ฝ์—์„œ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ๋™์ ์œผ๋กœ ์ง€์—ญํ™”ํ•ด์•ผ ํ•˜๋ฉฐ ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.
  • Angular ํŒ€์ด ์ œ์•ˆํ•œ ๋Œ€๋กœ TitleService ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์ง€ํ™”๋œ ํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค!

Angular ํŒ€์ด ํ˜„์žฌ ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค...

์•ˆ๋…•ํ•˜์„ธ์š” @vincentjames501 ,
์šฐ๋ฆฌ ํšŒ์‚ฌ์—์„œ๋„ ์ง€๊ธˆ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์ด ํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ๋„ˆ๋ฌด ๋ฒˆ๊ฑฐ๋กœ์›Œ์„œ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์ด์ „์— ์–ธ๊ธ‰ํ•œ i18n-polyfill ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๊ณ  ์ง€๊ธˆ๊นŒ์ง€ ์ž˜ ์ž‘๋™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ์œ ์ผํ•œ ๋‹จ์ ์€ ์•ฑ ๋ฒˆ๋“ค์˜ ํฌ๊ธฐ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์„ธ ๊ฐœ์˜ ๋ฒˆ์—ญ ํŒŒ์ผ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๊ฐ ๋ฒˆ๋“ค์€ ๊ทธ ์•ˆ์— ๊ทธ๊ฒƒ๋“ค์„ ๋ชจ๋‘ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์‚ฌ์šฉํ•˜๋Š” ๋ฒˆ์—ญ๋งŒ์œผ๋กœ ๋ฒˆ๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค). ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ชจ๋“  ๊ฒƒ์€ Ivy๊ฐ€ ์ถœ์‹œ๋˜๋ฉด ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ผ๋Š” ์„ฑ๊ฐ€์‹  ์ผ์ž…๋‹ˆ๋‹ค.
๊ฑด๋ฐฐ,

๋ฒˆ์—ญ ๋งต์„ ํฌํ•จํ•˜๊ณ  ๊ฐ ์–ธ์–ด์˜ environment.ts ํŒŒ์ผ์— ๋‹ค์‹œ ๋‚ด๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ ์—†์ด ์ž‘๋™ํ•˜๊ณ  ๋ชจ๋“  ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉฐ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฐ€์ง„ ์œ ์ผํ•œ ๋ฌธ์ œ๋Š” evey ์‚ฌ์ดํŠธ๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ์–ธ์–ด์— ๋Œ€ํ•ด ๋™์ผํ•œ ์„œ๋น„์Šค ์ž‘์—…์ž๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์œผ๋ฉฐ ๋ˆ„๊ตฐ๊ฐ€ ์–ธ์–ด๋ฅผ ์ „ํ™˜ํ•˜๋ฉด ๋‚ด ์‚ฌ์ดํŠธ์—์„œ ๊ทธ๊ฐ€ ์ด๋ฏธ ํ‘ธ์‹œ ์•Œ๋ฆผ์— ๋“ฑ๋ก๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค...

@ocombe Angular 6์— ๋Œ€ํ•œ ์†Œ์‹์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ Angular v6์—๋Š” ์—†์Šต๋‹ˆ๋‹ค. v7์šฉ์œผ๋กœ ์˜ˆ์ •๋˜์–ด ์žˆ๋Š” Ivy์— ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

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

์ด ๊ธฐ๋Šฅ์ด ์ถœ์‹œ๋œ๋‹ค๋ฉด ํ˜„์žฌ์˜ i18n API์™€ ํฐ ๋ณ€ํ™”๊ฐ€ ์—†์„๊นŒ์š”? ์ง€๊ธˆ i18n์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด Angular 7์ด ์ถœ์‹œ๋  ๋•Œ ์ƒˆ๋กœ์šด i18n API๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์—…๋ฐ์ดํŠธ ์–ธ์ œ ๋Ÿฐํƒ€์ž„ ๋ฐ ๋™์  ๋ฒˆ์—ญ ์ง€์›์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋Ÿฐํƒ€์ž„ ๋ฒˆ์—ญ์ด ์™„๋ฃŒ๋˜๊ณ  ๋ณ‘ํ•ฉ๋˜์ง€๋งŒ(ivy๋กœ) ์ปดํŒŒ์ผ๋Ÿฌ ์ธก์ด ์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” ์ง€๊ธˆ ICU ํ‘œํ˜„์„ ์—ฐ๊ตฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์•„์ง ๋™์  ๋ฒˆ์—ญ(์„œ๋น„์Šค) ์ฝ”๋”ฉ์„ ์‹œ์ž‘ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์•„๋งˆ๋„ ICU ํ‘œํ˜„์‹ ํ›„์— ํ•  ๋‹ค์Œ ์ž‘์—…์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@vincentjames501 ICU ํ‘œํ˜„์‹๊ณผ ํ•จ๊ป˜ i18n-polyfill์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์—†์Šต๋‹ˆ๋‹ค.

@ocombe , ๋Ÿฐํƒ€์ž„๊ณผ ๋™์  ๋ฒˆ์—ญ์˜ ์ฐจ์ด์ ์„ ๋ช…ํ™•ํžˆ ํ•ด์ฃผ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•„๋งˆ๋„ ๊ณต์‹์ ์ธ ๋ช…์นญ์€ ์—†์ง€๋งŒ ๋‚ด๊ฐ€ ๋ณด๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋Ÿฐํƒ€์ž„: ๋ฒˆ์—ญ์€ ๋Ÿฐํƒ€์ž„์— ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ํ˜„์žฌ์™€ ๊ฐ™์ด ๋นŒ๋“œ ์ค‘์—๋Š” ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์œ ํ˜•์˜ ๋ฒˆ์—ญ(ํ…œํ”Œ๋ฆฟ ๋˜๋Š” ์ฝ”๋“œ)์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ๋™์ ์ด๋ž€ ๋Ÿฐํƒ€์ž„ ์‹œ ๋ฒˆ์—ญํ•  ๋‚ด์šฉ๋งŒ ์•Œ๊ณ  ๋นŒ๋“œ ์‹œ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ "์ฝ”๋“œ ๋‚ด" ๋ฒˆ์—ญ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ICU ํ‘œํ˜„์‹์ด ๋ณ€์ˆ˜์— ์˜์กดํ•œ๋‹ค๋Š” ์ ์—์„œ ๋™์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ€์ด์Šค ์ˆ˜๊ฐ€ ์œ ํ•œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋“œ ์‹œ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋ณ€ํ™˜์„ ์—ฌ์ „ํžˆ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๊ฐœ๋ฐœ ์ค‘์ธ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— i18n ์ง€์›์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์—ฐ๊ธฐํ–ˆ์ง€๋งŒ ๋ฆด๋ฆฌ์Šค์— ๊ฐ€๊นŒ์›Œ์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด Angular 7์—์„œ ์ตœ์ข…์ ์ธ ๊ฒƒ์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”? ์•„๋‹ˆ๋ฉด ๋ฒˆ์—ญ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@andrei-tatar i18n์€ Angular 2 ์ดํ›„๋กœ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์œ ์ผํ•œ ๋‹จ์ :

  • ์ฝ”๋“œ ๋ฒˆ์—ญ ์—†์Œ(์ด๋ฒˆ ๋ฌธ์ œ) -> ํ•„์š”ํ•œ ๊ฒฝ์šฐ i18n-polyfill์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • AOT(๊ถŒ์žฅ)๋ฅผ ๋นŒ๋“œํ•  ๊ฒฝ์šฐ ์–ธ์–ด๋ณ„๋กœ ์•ฑ์„ ๋ณ„๋„๋กœ ๋นŒ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ ์•ฑ์€ ๋ณ„๋„๋กœ ๋นŒ๋“œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์–ด๋ฅผ ์ „ํ™˜ํ•  ๋•Œ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ๋‘ ์ง€์ ์— ๋Œ€ํ•ด์„œ๋Š” @ngx-translate๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Angular์˜ ๋‚ด์žฅ i18n๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ ์ดํ›„ ์—…๋ฐ์ดํŠธ์—๋Š” ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ฆฌํ•„์˜ ๊ฒฝ์šฐ ์—…๋ฐ์ดํŠธ๋Š” ์•„๋งˆ๋„ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@์˜ค์ฝค๋ฒ 

Angular i18n ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด๋ถ€ ์—ฐ์‚ฐ์ž๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•

[email protected]>์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

@shobhit12345 https://github.com/shobhit12345

์šฐ๋ฆฌ๋Š” ngSwitch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋ฉ”์‹œ์ง€๋ฅผ ํ…œํ”Œ๋ฆฟํ™”ํ•˜๋ฏ€๋กœ i18n-tag๋ฅผ ๋‹ค์Œ์— ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฐœ๋ณ„์ ์œผ๋กœ.

์ˆจ๋‹ค๋ณด์—ฌ ์ฃผ๋‹ค์—ญ์‚ฌ

์šฐ๋ฆฌ๋Š” ๋ˆ„๋ฝ๋œ ๋™์  ๋ฒˆ์—ญ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ด ๋ฐฉ๋ฒ•์„ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
์กฐ๊ธˆ๋งŒ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋†€๋ผ์šด ์–‘์˜ ํ…์ŠคํŠธ๋ฅผ ๋‹ค์Œ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ…œํ”Œ๋ฆฟ์—์„œ ์ด๋Ÿฐ ์‹์œผ๋กœ. ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์€ ๋ฉ”์‹œ์ง€ ๋ฐฐ์—ด์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด๊ฒƒ์„ ngFor ๋ฐ ngSwitch์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ…œํ”Œ๋ฆฟํ™”ํ•ฉ๋‹ˆ๋‹ค.
์ด ๊ฐ™์€:

TS

๋ฉ”์‹œ์ง€ = [ '์ด๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค', '์ด๊ฒƒ์€ ๋‘ ๋ฒˆ์งธ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค' ]

HTML


i18n="@@firstMesssage">์ฒซ ๋ฒˆ์งธ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.
i18n="@@secondMesssage">๋‘ ๋ฒˆ์งธ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.

๋‹ค์†Œ ์žฅํ™ฉํ•˜์ง€๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/angular/angular/issues/11405#issuecomment-415731284 ,
๋˜๋Š” ์Šค๋ ˆ๋“œ ์Œ์†Œ๊ฑฐ
https://github.com/notifications/unsubscribe-auth/AGwM6jcWIpwtGxhkH1fwnVXNagRxmMnoks5uT-LxgaJpZM4J2pkr
.

์™„๋ฃŒ๋˜๋ฉด Angular 7(2018๋…„ 9์›”/10์›”)๋กœ ์˜ˆ์ •๋œ Ivy๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฒŒ์จ 10์›”์ž…๋‹ˆ๋‹ค. 10์›” ๋ง๊นŒ์ง€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

https://is-angular-ivy-ready.firebaseapp.com ์— ๋”ฐ๋ฅด๋ฉด @lizzymendivil Ivy๋Š” 65% ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉฐ 30์ผ ๋งŒ์— ์™„๋ฃŒ๋  ๊ฒƒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ, ์•„์ด๋น„๋Š” ํ•œ ๋‹ฌ ์•ˆ์— ๋๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@ocombe ๋‹น์‹ ๋งŒ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž ๊ธ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "์–ธ์ œ ์™„๋ฃŒ๋˜์—ˆ๋‚˜์š”?" ์ฝ”๋ฉ˜ํŠธ

@ocombe Ivy๋Š” ์ด์ œ ๋Œ€๋žต 94%๊ฐ€ ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฐ๋ง์ฏค์—๋Š” ์ค€๋น„๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ธฐ๋Šฅ์ด ์ค€๋น„๋˜์–ด ์žˆ๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์—†๋Š” ๊ฒƒ(= ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•จ)์€ ๋งค์šฐ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„ ์ˆ˜์ • ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@ocombe i18n์ด Angular 8๋ณด๋‹ค ๋จผ์ € ๋‚˜์™”๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฏฟ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ธฐ๋Šฅ์ด ์ค€๋น„๋˜์–ด ์žˆ๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์—†๋Š” ๊ฒƒ(= ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•จ)์€ ๋งค์šฐ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„ ์ˆ˜์ • ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ค, ์‹ ์†ํ•œ ๋‹ต๋ณ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

Angular์—์„œ I18N ์ง€์›์„ ์œ„ํ•ด "ํ…œํ”Œ๋ฆฟ ๋ฒˆ์—ญ"๊ณผ ํ•จ๊ป˜ "์ฝ”๋“œ ๋ฒˆ์—ญ" ๋ถ€๋ถ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ด์•ผ ํ•  ๋•Œ(์—ฐ๋ง์— ๋งˆ์ง€๋ง‰ ๋ช‡ ๊ฐ€์ง€ ์˜๊ฒฌ ์ฐธ์กฐ) ์—…๋ฐ์ดํŠธ @ocombe ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๋Š” Angular I18n ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ngx-translate-polyfill์„ ํด๋Ÿฝํ™”ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ https://github.com/biesbjerg/ngx-translate-extract CLI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด xlf ํŒŒ์ผ์„ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐ xlf ์ง€์›์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. .

๊ฐ์‚ฌ ํ•ด์š” !

@์•„๋ฒ ์ฝฉ๊ฒŒ

ngSwitch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋ฉ”์‹œ์ง€๋ฅผ ํ…œํ”Œ๋ฆฟํ™”ํ•˜๋ฏ€๋กœ i18n ํƒœ๊ทธ๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์†Œ ์žฅํ™ฉํ•˜์ง€๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

์ œ์•ˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๊ฐ€์žฅ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ œ ์งˆ๋ฌธ์€ ๋ฐฐ์—ด์— 10๊ฐœ ์ด์ƒ๊ณผ ๊ฐ™์ด "๋งŽ์€" ๊ฐ’์ด ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ์ด ๊ตฌํ˜„์„ ๊ณ„์† ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ? ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ์ปค์งˆ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ทธ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค๊ณผ ํ•จ๊ป˜ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด์ง€๋งŒ ์™œ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šค์œ„์น˜์™€ i18n ํƒœ๊ทธ์ธ ์ž‘์€ i18n ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋ฐ์ด๋น„๋“œ

๋ด 23. 1์›” 2019 ํด. 19.24 skrev Andrew Bissada [email protected] :

@์•„๋ฒ ์ฝฉ๊ฒŒ

ngSwitch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋ฉ”์‹œ์ง€๋ฅผ ํ…œํ”Œ๋ฆฟํ™”ํ•˜๋ฏ€๋กœ i18n ํƒœ๊ทธ๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์†Œ ์žฅํ™ฉํ•˜์ง€๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

์ œ์•ˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๊ฐ€์žฅ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ œ ์งˆ๋ฌธ์€ ๋ฐฐ์—ด์— 10๊ฐœ ์ด์ƒ๊ณผ ๊ฐ™์ด "๋งŽ์€" ๊ฐ’์ด ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ์ด ๊ตฌํ˜„์„ ๊ณ„์† ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ? ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ์ปค์งˆ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ๋ณด๊ฑฐ๋‚˜ ์Šค๋ ˆ๋“œ๋ฅผ ์Œ์†Œ๊ฑฐํ•˜์„ธ์š”.

Validator ํด๋ž˜์Šค์—์„œ i18n-polifills๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•. i18n ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ์€๋ฐ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

//์ปดํฌ๋„ท์—์„œ
this.crForm= this.fb.group({
์‚ฌ์šฉ์ž ์ด๋ฆ„: [''],
์ „์ž๋น„๋ฐ€๋ฒˆํ˜ธ: [''],
}, { ๊ฒ€์ฆ์ธ: ์ƒˆ๋กœ์šด AccValidator(this.i18n).validate()}
);

//๊ฒ€์ฆ๊ธฐ

import { AbstractControl, ValidationErrors, FormGroup, FormControl } from '@angular/forms';
'@ngx-translate/i18n-polyfill'์—์„œ { I18n } ๊ฐ€์ ธ์˜ค๊ธฐ;
๋‚ด๋ณด๋‚ด๊ธฐ ํด๋ž˜์Šค AccValidator{
์ƒ์„ฑ์ž(i18n:I18n)
{

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

์˜ค๋ฅ˜ ์•„๋ž˜์— ์ ์ 

RROR ์˜ค๋ฅ˜: ์žกํžˆ์ง€ ์•Š์Œ(์•ฝ์† ์ค‘): TypeError: i18n์€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
TypeError: i18n์€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
FormGroup.eval์—์„œ [๊ฒ€์ฆ์ธ์œผ๋กœ] (acc-validator.ts:9)
FormGroup.AbstractControl._runValidator์—์„œ(forms.js:3433)
FormGroup.AbstractControl.updateValueAndValidity(forms.js:3387)์—์„œ
์ƒˆ FormGroup์—์„œ(forms.js:4326)
FormBuilder.group์—์„œ(forms.js:7864)

@์˜ค์ฝค๋ฒ 

.ts ํŒŒ์ผ์—์„œ const์™€ ํ•จ๊ป˜ i18n-polyfills๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

๋‚ด๋ณด๋‚ด๊ธฐ const ์šฉ์–ด ๋ชจ๋ธ= () => [
{
์ œ๋ชฉ: 'ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ',
ํ™œ์„ฑ: ์‚ฌ์‹ค,
๋ฐ์ดํ„ฐ: [

        [
            {
                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, ์„ ํƒ, ์˜๋ฃŒ {Medical} ์น˜๊ณผ {Dental} ์˜๋ฃŒ ๋ฐ ์น˜๊ณผ {Medical & Dental} ์น˜๋ช…์  ๋ฐ ์น˜๊ณผ {Catastrophic & Dental} ์น˜๋ช…์  {Catastrophic} }
{VAR_SELECT, ์„ ํƒ, ์˜๋ฃŒ {Medical} ์น˜๊ณผ {Dental} ์˜๋ฃŒ### ๋ฐ ์น˜๊ณผ {Medical y Dental}
์น˜๋ช…์  ### & ์น˜๊ณผ{Catastrophic y Dental} ์น˜๋ช…์  {Catastrophic} }

ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ์žˆ๋Š” ICU ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ณ€ํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@ocombe i18n-polyfill์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋™ ๊ฒฝ๋กœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚ด๋ณด๋‚ด๊ธฐ const ๊ฒฝ๋กœ: ๊ฒฝ๋กœ = [
{
๊ธธ: '',
๊ตฌ์„ฑ ์š”์†Œ: ํ™ˆ ๊ตฌ์„ฑ ์š”์†Œ,
๋ฐ์ดํ„ฐ: {
์ œ๋ชฉ: '์ง‘',
์ด๋™ ๊ฒฝ๋กœ: 'ํ™ˆ'
}
}
]

@์˜ค์ฝค๋ฒ 

.ts ํŒŒ์ผ์—์„œ const์™€ ํ•จ๊ป˜ i18n-polyfills๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

๋‚ด๋ณด๋‚ด๊ธฐ const ์šฉ์–ด ๋ชจ๋ธ= () => [
{
์ œ๋ชฉ: 'ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ',
ํ™œ์„ฑ: ์‚ฌ์‹ค,
๋ฐ์ดํ„ฐ: [

        [
            {
                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({ ๊ฐ’: '์ด๋ฆ„', id: '์ด๋ฆ„' }),
}
๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ์ž์— I18n ํด๋ฆฌํ•„์„ ์ฃผ์ž…ํ•˜์‹ญ์‹œ์˜ค.
๊ฐœ์ธ i18n: I18n
ts ํŒŒ์ผ์—์„œ ๋ฒˆ์—ญ์„ ์‚ฌ์šฉํ•  ๋•Œ ํ•ด๋‹น ts ํŒŒ์ผ์„ ๋ฒˆ์—ญํ•˜๋ ค๋ฉด ngx-extractor ๋ฐ xliffmerge๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. https://www.npmjs.com/package/ngx-i18nsupport

@ JanneHarju
์ž‘๋™ํ•˜์ง€ ์•Š๊ณ  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
  }
}

@ JanneHarju
์˜ˆ, ๋™์ผํ•œ ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ xlf ํŒŒ์ผ์—์„œ .ts ๋ฉ”์‹œ์ง€๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ const๋Š” ๋‹ค๋ฅธ .ts ํŒŒ์ผ์— ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๋ณด๋‚ด๊ธฐ const ์šฉ์–ด ๋ชจ๋ธ= () => [
{
}

i18n์„ const์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์žˆ๋Š”๋ฐ ๊ฐ’์„ ์ถ”์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

provider์™€ ๊ฐ™์€ const ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

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

์ฝ”๋“œ๊ฐ€ ๊นจ์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ํฌ์ธํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋นต ๋ถ€์Šค๋Ÿฌ๊ธฐ๋ฅผ ๋ฒˆ์—ญํ•˜๋Š” ๋ฐฉ๋ฒ•

const ๊ฒฝ๋กœ: ๊ฒฝ๋กœ = [
{
๊ฒฝ๋กœ: './enroll-new.component',
๊ตฌ์„ฑ ์š”์†Œ: EnrollNewComponent,
๋ฐ์ดํ„ฐ: {
์ด๋™ ๊ฒฝ๋กœ: '๋“ฑ๋ก'
},
}
]

์ด ์Šค๋ ˆ๋“œ๋ฅผ i18n-polyfill ๋˜๋Š” ๊ธฐํƒ€ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ง€์› ์Šค๋ ˆ๋“œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? i18n-polyfill์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์ €์žฅ์†Œ์—์„œ ๋ฌธ์ œ๋ฅผ ์ œ๊ธฐํ•˜์‹ญ์‹œ์˜ค.
@ocombe ์ด ์ฃผ์ œ๋ฅผ ์ž ๊ธ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฑฐ์˜ ๋ชจ๋“  ์ค‘์š”ํ•œ ๊ฒƒ์„ ๋‹ค๋ฃจ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด ์ฃผ์ œ์—์„œ ์–ธ๊ธ‰ํ•œ i18n ์ง€์›์„ ์ถœ์‹œํ•  Angular ๋ฒ„์ „์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์˜ˆ, ์ง€๊ธˆ์€ ์ž ๊ฒจ ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ์˜ตํŠธ์ธ ๋ฒ ํƒ€๋กœ v8์—์„œ ์•„์ด๋น„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ด์‹ฌํžˆ ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„ i18n์€ google ํด๋กœ์ €(google์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ํ†ตํ•ด ๋””๋ฒ„๊ทธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋งค์šฐ ํฐ ๋ณ€ํ™”์ž…๋‹ˆ๋‹ค). ๋‹ค๋ฅธ ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ i18n์œผ๋กœ ์•„์ด๋น„๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฒˆ์—ญ์„ ๋กœ๋“œํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์•ฑ์€ ์•ฑ์„ ์ฝ”๋”ฉํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ ์›๋ž˜ ์–ธ์–ด๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
์‹ค์ œ๋กœ ๋ฒˆ์—ญํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋Ÿฐํƒ€์ž„ ์„œ๋น„์Šค๋Š” ํ˜„์žฌ ๋ฒˆ์—ญ๋˜์ง€ ์•Š์€ ํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ชจ๋‘ ๊ธฐ์กด ์ฝ”๋“œ๋กœ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ๋ฆด๋ฆฌ์Šค ์ดํ›„๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. v8์ด ๋‚˜์˜ค๋ฉด ์ž‘์—…ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ €์˜ ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ƒˆ๋กœ์šด ์†Œ์‹์ด ์žˆ์œผ๋ฉด ์—…๋ฐ์ดํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด ์Šค๋ ˆ๋“œ์˜ ์ž ๊ธˆ์„ ํ•ด์ œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ์ƒˆ๋กœ์šด $localize ํƒœ๊ทธ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ

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

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ปดํŒŒ์ผ ํƒ€์ž„(๋˜๋Š” ๋Ÿฐํƒ€์ž„)์— ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” Hello {$name}! ์— ๋Œ€ํ•œ ๋ฒˆ์—ญ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฌธ์„œํ™”๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ).

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰