복잡한뇌구조마냥

[Angular] Text Management/Translation (Text 관리 및 번역) 본문

FE/Angular

[Angular] Text Management/Translation (Text 관리 및 번역)

지금해냥 2023. 11. 21. 09:23

❗️Problem

  1. Angular에서 Text를 관리하는 방법
    1. 일반적으로 사용하는 Text관리 방법은 무엇인가?
    2. LiveStudio 내에서 사용하는 모든 Text를 일괄적으로 관리하는 방법이 필요하다.
  2. Text들을 Translation하는 방법
    1. Angular에서 지원하는 traslation은 무엇이고, 어떤 라이브러리들이 있는가?
    2. LiveStudio에 적용하기에 가장 효과적인 방법은 무엇인가?

⚠️ Text 관리방법

⭐️ 일반적 Text 관리 방법

 

1. String을 이용한 Text 관리

공식 문서 :

String - JavaScript | MDN

const string1 = "A string primitive";
const string2 = 'Also a string primitive';
const string3 = `Yet another string primitive`;
const string4 = new String("A String object");

2. Service를 활용한 Text 관리

  • Service에 text 객체를 만들어 함수를 통해 매칭되는 text를 교체하는 방식

3. Server를 활용한 Text 관리

  • 서버에서 언어별 리소스 교체

⭐️ File을 이용한 Text 관리

공식 문서 : Angular

ARB:

Flutter ARB file (.arb) - Localizely

XLIFF: https://en.wikipedia.org/wiki/XLIFF

 

XLIFF - Wikipedia

From Wikipedia, the free encyclopedia Computer file format XLIFF (XML Localization Interchange File Format) is an XML-based bitext format created to standardize the way localizable data are passed between and among tools during a localization process and a

en.wikipedia.org

XMB: https://filext.com/file-extension/XMB

⭐️ JSON을 이용한 Text 관리

공식 문서:

JSON으로 작업하기 - Web 개발 학습하기 | MDN

공식 문서:

Internationalization - Mozilla | MDN

예제 자료:

GitHub - workshopper/how-to-npm: A module to teach you how to module.

 

{
  "squadName": "Super hero squad",
  "homeTown": "Metro City",
  "formed": 2016,
  "secretBase": "Super tower",
  "active": true,
  "members": [
    {
      "name": "Molecule Man",
      "age": 29,
      "secretIdentity": "Dan Jukes",
      "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
    },
    {
      "name": "Madame Uppercut",
      "age": 39,
      "secretIdentity": "Jane Wilson",
      "powers": [
        "Million tonne punch",
        "Damage resistance",
        "Superhuman reflexes"
      ]
    },
    {
      "name": "Eternal Flame",
      "age": 1000000,
      "secretIdentity": "Unknown",
      "powers": [
        "Immortality",
        "Heat Immunity",
        "Inferno",
        "Teleportation",
        "Interdimensional travel"
      ]
    }
  ]
}

⭐️Angular i18n(Internationalization)을 이용한 Text 관리

공식 문서 : Angular

예제 자료:

GitHub - StephenFluin/i18n-sample: A sample of internationalization with Angular 2 RC 6

  1. HTML의 Text가 필요한 각각의 태그에 i18n 속성을 @@접두사를 사용하여 정의

2./locale/messages.${locale}.xlf형식의 파일을 생성 - 언어마다 파일 생성
각 id의 요소로 i18n 태그에 매칭되는 값을 작성하여 번역되는 내용을 표시

3. 두 요소 모두 동일한 사용자 정의 ID로 정의되어있어 동일한 번역으로 동작

장점 : text를 변경해도 id를 변경하지 않기 때문에 번역을 업데이트 하기 위한 추가 단계를 수행할 필요 없음.
단점: 텍스트를 변경하면 새로 변경된 원본 텍스트와 동기화 되지 않을 수 있음.
( 첫번째 작성된 원본은 유지 해야함 - 위의 예제의 경우 최상단 Hello가 유지되야 동작함.)

 

⚠️ Translate 방법

i18n이란 (국제화, Internationalization)

참고 자료: https://www.freecodecamp.org/news/how-to-implement-localization-in-angular-using-i18n-tools-a88898b1a0d0/
참고 자료 : https://velog.io/@youngjjjjj/i18n%EA%B3%BC-l10n%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
참고 자료: https://miaow-miaow.tistory.com/32

 

i18n 이 뭔가요? SW 국제화가 뭔가요? 현지화가 뭔가요?

목표: Internationalization (i18n) 파악하기 요약 i18n 은 Internationalization 의 축약형임 SW국제화란 국제적으로 통용되는 SW를 설계하고 개발하는 과정 SW현지화란 현지(Locale) IT 환경에 적합하도록 SW 를 개

miaow-miaow.tistory.com

 

I18n국제화라고도 하며, 앱이 전 세계 사용자에게 도달 범위를 확장하기 위해 다양한 언어를 지원하도록 만드는 프로세스입니다.

1. 소프트웨어의 국제화

  • 언어별 번역
    -> 국제화의 가장 큰 의미이다.
  • 문자 인코딩 설정
    -> 초기에 문자를 표현하는 대표적인 방식은 ASCII 인코딩 방식이었으나, 한글이나 한자 같은 문자는 2개 이상의 특수 문자를 합쳐서 표현하곤 했는데, 이러한 방식은 비정상적이고 그에 따라 문자가 깨지거나 제대로 표현하지 못하여 2~4바이트 공간에 여유롭게 문자를 할당하고자 나온 방식이 Unicode이다. Unicode 자체는 1바이트로 표현이 가능한 영문자도 2바이트 이상의 공간을 사용하여 메모리 낭비가 심하여 이를 가변 길이 문자 인코딩 방식으로 나온 것이 UTF-8이다.
  • 문자열 치환 방법
    1. Server Side (서버에서 언어별 리소스 교체)
    2. Client Side (클라이언트에서 언어별 리소스 교체)
    • Client Side가 Server Side보다 많은 경우에서 좋은 방법이다. 왜냐하면 리소스 캐시와 선호 언어 설정 등이 가능하기 때문이다.

2. 디자인의 국제화

소스 코드의 변경 없이도 다양한 언어 / 지역을 지원할 수 있도록 처리해야한다.
왜냐하면 언어 / 지역별로 가독성이 적절해야하고, 번역으로 인해 문자열의 길이가 길어질 수 있기 때문이다. (ex 국제화 -> internationalization)

3. 리소스의 국제화

언어 / 지역에 맞춰 가장 적절한 리소스를 준비해야한다.

4. 고려할 사항 정리

 

요소

설명

목적

유니코드
세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준 각 언어와 문자 체계에 따른 충돌 문제 해결
리소스 외부화 및 관리
이미지, 바이너리 코드, 소스 코드 등으로부터 리소스를 분리(외부화)하는 것 프로그램의 수정 없이 다국어 지원이 가능하도록 하기 위함
Locale 대응
날짜/시간 형식, 달력, 통화 기호, 문자열 정렬 순서 등 국제화 라이브러리를 이용하여 다수의 Locale에 유연하게 대응하기 위함
Localizability
다국어로 번역될 경우 사용자 인터페이스에 미치는 영향을 분석하는 것 UI가 구성한 의도에 맞게 언어별로 처리할 수 있는지 확인하기 바람

📚 l10n이란 (현지화, Localiztion)

l10n이란 특정 목표 시장(국가)의 문화 및 기타 요구 사항을 충족시키는 작업

1. LTR / RTL (쓰기 방향의 차이)

-> 일부 중동 국가에서는 표기방식을 오른쪽에서 왼쪽으로 읽음. 그에 따라 UI와 HTML 코드 수정이 필요해짐.

2. 숫자, 날짜 및 시간 형식

-> 나라마다 화폐(콤마), 날짜 표현 방식이 다 다름.

3. 문자열 정렬 방법

-> 나라마다 알파벳을 정렬하는 방법이 다름 (ex 발음의 강세가 표현된 글자) Collation 참고

4. 개인 이름 및 주소 형식 처리 등

-> 나라마다 개인 이름 및 주소 형식이 다름.

⭐️라이브러리

참고 문서: https://phrase.com/blog/posts/the-best-javascript-i18n-libraries/
참고 문서: https://crowdin.com/blog/2023/03/20/angular-localization-and-i18n

 

A Guide to Angular Localization and i18n — Crowdin

Learn how to use i18n in Angular and how to automate Angular localization, instead of copy-pasting text strings.

crowdin.com

 

 
LibraryFramework supportDocumentationUpdatesDownloads/weekBundle size (minified)Advanced featuresNotes
i18next
  • React (first-party)
  • Next.js (first-party)
  • Vue (first-party)
  • Angular (third-party)
  • jQuery (first-party)
  • Many more…
⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️⭐️ 350만 56.3KB
[14.8KB gzip]
✅ 복합 복수형
✅ 숫자
✅ 날짜(+ 상대)
✅ TypeScript
✅ 메시지 추출
✅ ICU 구문
메시지 추출 및 ICU 지원은 자사 추가 기능을 통한 선택 사항입니다.
FormatJS
  • React (first-party, react-intl)
  • Vue (first-party)
⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️⭐️ 120만 62.8KB
[17.8KB gzip]
✅ 복합 복수형
✅ 숫자
✅ 날짜(+ 상대)
✅ TypeScript
✅ 메시지 추출
✅ ICU 구문
최고 수준의 ICU 메시지 구문 지원.
vue-i18n Vue (third-party) ⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️ 984K 63.8KB
[18.9KB gzip]
🟡 복합 복수형
(참고 사항 참조)
✅ 숫자
✅ 날짜
✅ TypeScript
❌ 메시지 추출
❌ ICU 구문
복잡한 복수형에 대한 고유한 논리를 제공해야 합니다.
@angular/
localize
Angular (first-party) ⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️⭐️ 766K 4.6KB
[1.9KB gzip]
✅ 복합 복수형
✅ 숫자
✅ 날짜
✅ TypeScript
✅ 메시지 추출
✅ ICU 구문
 
Globalize (See Notes) ⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️ 198K 71.1kB
[22.2kB gzip]
(참고 참조)
✅ 복합 복수형
✅ 숫자
✅ 날짜(+ 상대)
✅ TypeScript
❌ 메시지 추출
✅ ICU 구문
  • 프레임워크 타사 통합이 오래된 것 같습니다.
  • 모듈형 아키텍처: 필요한 기능을 선택하고 선택하세요. 여기의 번들 크기는 포함된 모든 모듈을 반영할 수 있습니다.
Polyglot
  • React (third-party)
  • Vue (third-party
⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️ 184K 35.5kB
[10.5kB gzip]
✅ 복합 복수형
❌ 숫자
❌ 날짜
❌ TypeScript
❌ 메시지 추출
❌ ICU 구문
  • 번역 메시지에만 집중합니다.
  • 라이브러리는 간단하므로 최소한의 업데이트도 괜찮을 수 있습니다.
jQuery.i18n jQuery (third-party) ⭐️⭐️⭐️⭐️ ⭐️⭐️⭐️ 해당 없음
(참고 사항 참조)
1.1kB
[0.7kB gzip]
(참고 사항 참조)
✅ 복합 복수형
❌ 숫자
❌ 날짜
❌ TypeScript
❌ 메시지 추출
❌ ICU 구문
  • 번역 메시지에만 집중합니다.
  • 라이브러리는 간단하므로 최소한의 업데이트도 괜찮을 수 있습니다.
  • 일반 설치는 NPM을 통한 것이 아니므로 다운로드 통계가 정확하지 않습니다.
  • Bundlephobia 번들 크기에는 핵심 jQuery 라이브러리가 포함됩니다. 여기서는 제외됩니다.

1. @angular/localize

공식 문서 : https://angular.io/api/localize

사용 방법 :

  • ng build --localize CLI에 자동으로 Locale 데이터가 포함됨
  • import '@angular/common/locales/global/ko'; 를 통해 필요한 곳에서 가져옴

  • const message = $localize`Hello, World!`; 
    <h1 i18n>Hello, World!</h1>
  • $localize를 선언하여 단어를 i18n으로 번역하는 식으로도 사용 가능

장점 : angular 내부에 정해져서 나오는 값이 있음, 용량이 낮음

단점 : 지정하는 방식이 쉽지않음, 사용 예제가 많이 없음.

2. ngx-translate

공식 문서 : https://github.com/ngx-translate/core
참고 자료 : https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular-app-with-ngx-translate
참고 자료: https://gogomalibu.tistory.com/150

사용 방법

  1. 모듈 설치
    > npm install @ngx-translate/core --save 
  2. > npm install @ngx-translate/http-loader --save 
  3. app.module.ts 에 추가
  4. @NgModule({ declarations: [AppComponent, ... 이외에 사용하는 여러 컴포넌트들], imports: [ BrowserModule, ReactiveFormsModule, ... TranslateModule.forRoot({ useDefaultLang: true, defaultLanguage: 'ko', loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] } }) ], bootstrap: [AppComponent] }) export class AppModule { } export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './assets/locale/', '.json'); }
  5. 언어 별 json 파일 생성
    ex ) assets/i18n/ko.json
  6. { "btn": { "create": "추가", "update": "수정", "save": "저장", "cancel": "취소", "delete": "삭제" }, "placeholder": { "search-menu": "메뉴 검색" } }
  7. component 에서 translate 사용하기
    constructor(private translate: TranslateService) {
         ...
    }
    
     
    
    this.translate.get('btn.create').subscribe((res: string) => {
        console.log(res);
    });
  8. <li (click)="edit()">{{ 'btn.update' | translate }}</li>

3. i18next

공식 문서: https://www.i18next.com/
참고 자료 : https://phrase.com/blog/posts/angular-l10n-with-i18next/
참고 자료 : https://github.com/Romanchuk/angular-i18next
예제 자료: https://github.com/Romanchuk/angular-i18next-demo/tree/master
예제 자료: ​https://romanchuk.github.io/angular-i18next/

사용방법:

<div>{{ 'test' | i18next }}</div>
<div>{{ 'test' | i18next: { count: 5, nsSeparator: '#' } }}</div>

플러그인

import { I18NextModule, ITranslationService, I18NEXT_SERVICE } from 'angular-i18next';
//  import Backend from 'i18next-xhr-backend'; //for i18next < 20.0.0
import HttpApi from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

...

i18next.use(HttpApi)
       .use(LanguageDetector)
       .init(i18nextOptions)

i18n 초기화

export function appInit(i18next: ITranslationService) {
    return () => i18next.init();
}

export function localeIdFactory(i18next: ITranslationService)  {
    return i18next.language;
}

export const I18N_PROVIDERS = [
{
    provide: APP_INITIALIZER,
    useFactory: appInit,
    deps: [I18NEXT_SERVICE],
    multi: true
},
{
    provide: LOCALE_ID,
    deps: [I18NEXT_SERVICE],
    useFactory: localeIdFactory
}];

라우팅 경로 변경으로 언어 설정

export class AppComponent implements OnInit  {
  constructor(private router: Router,
              private title: Title,
              @Inject(I18NEXT_SERVICE) private i18NextService: ITranslationService) {
      // page title subscription
      // https://toddmotto.com/dynamic-page-titles-angular-2-router-events#final-code
      this.router.events
        .filter(event => event instanceof NavigationEnd)
        .map(() => this.router.routerState.root)
        .map(route => {
          while (route.firstChild) route = route.firstChild;
          return route;
        })
        .filter(route => route.outlet === 'primary')
        .mergeMap(route => route.data)
        .subscribe((event) => this.updatePageTitle(event['title']));
  }

  ngOnInit() {
    this.i18NextService.events.languageChanged.subscribe(lang => {
      let root = this.router.routerState.root;
      if (root != null && root.firstChild != null) {
        let data: any = root.firstChild.data;
        this.updatePageTitle(data && data.value && data.value.title);
      }
    });
  }

  updatePageTitle(title: string): void {
    let newTitle = title || 'application_title';
    this.title.setTitle(newTitle);
  }
}

4. FormatJS

공식 문서: https://formatjs.io/

참고 자료: https://phrase.com/blog/posts/react-i18n-format-js/#how-do-i-localize-my-app-with-react-intl

사용 방법:

  1. 번역 파일
  2. // src/lang/en-US.json { "app.title": "Yomtaba", "app.tagline": "recipe of the day" } 코드 언어: JSON / 주석이 포함된 JSON ( json ) // src/lang/ar-EG.json { "app.title": "يومتابا", "app.tagline": "وصفة اليوم" }
  3. 컴포넌트에서 사용
  4. export default function Recipe(){ const intl = useIntl(); return ( <main> <h2> <FormattedMessage id="recipe..title" /> </h2> </main> ) }

5. jQuery.i18n

참고 자료: https://github.com/wikimedia/jquery.i18n

  1. 번역 파일
  2. { "@metadata": { "authors": [ "Alice", "David", "Santhosh" ], "last-updated": "2012-09-21", "locale": "en", "message-documentation": "qqq", "AnotherMetadata": "AnotherMedatadataValue" }, "en": { "appname-title": "Example Application", "appname-sub-title": "An example application with jquery.i18n", "appname-header-introduction": "Introduction", "appname-about": "About this application", "appname-footer": "Footer text" }, "ml": { "appname-title": "അപ്ലിക്കേഷന്‍ ഉദാഹരണം", "appname-sub-title": "jquery.i18n ഉപയോഗിച്ചുള്ള അപ്ലിക്കേഷന്‍ ഉദാഹരണം", "appname-header-introduction": "ആമുഖം", "appname-about": "ഈ അപ്ലിക്കേഷനെപ്പറ്റി", "appname-footer": "അടിക്കുറിപ്പു്" } }
  3. jquery로 호출 - 특정 단어 또는 파일로 참조 가능
  4. $.i18n().load( { en: { 'message-hello': 'Hello World', 'message-welcome': 'Welcome' }, hi: 'i18n/messages-hi.json', // Messages for Hindi de: 'i18n/messages-de.json' } );

6. angular-translate

공식 문서: https://angular-translate.github.io/
참고 자료: https://github.com/angular-translate/angular-translate
예제 자료: https://angular-translate.github.io/docs/#/guide/05_using-translate-directive

index.html

<body>
    <div ng-controller="Ctrl">
      <p>{{ 'HEADLINE' | translate }}</p>
      <img src="mylogo.png" translate-attr="{ alt: 'LOGO' }"></img>
      <p>{{ 'PARAGRAPH' | translate }}</p>
    
      <p translate>PASSED_AS_TEXT</p>
      <p translate="PASSED_AS_ATTRIBUTE"></p>
      <p translate>{{ 'PASSED_AS_INTERPOLATION' }}</p>
      <p translate="{{ 'PASSED_AS_INTERPOLATION' }}"></p>
    </div>
  </body>

script.js

var translations = {
  HEADLINE: 'What an awesome module!',
  PARAGRAPH: 'Srsly!',
  LOGO: 'My cool logo',
  PASSED_AS_TEXT: 'Hey there! I\'m passed as text value!',
  PASSED_AS_ATTRIBUTE: 'I\'m passed as attribute value, cool ha?',
  PASSED_AS_INTERPOLATION: 'Beginners! I\'m interpolated!'
};
 
var app = angular.module('myApp', ['pascalprecht.translate']);
 
app.config(['$translateProvider', function ($translateProvider) {
  // add translation table
  $translateProvider
    .translations('en', translations)
    .preferredLanguage('en');
}]);
 
app.controller('Ctrl', ['$scope', function ($scope) {
 
}]);

⭐️Angular에서 사용 가능한 Library

  1. @angular/localize
    1. 장점
      • Angular에서 제공하는 내용을 사용할 수 있음
      • 용량이 작음
    2. 단점
      • 사용하기위한 연구가 필요함.
      • 다른 라이브러리로 변경이 어려움 (JSON 형식이 아님)
      • 사용 예제가 많이 없음
      • 언어별로 프로젝트가 따로 빌드된다는 얘기가 있
  2. I18next
    1. 장점
      • JSON 형식
      • 다수의 프레임 워크에서 사용하는 라이브러리임
      • 지원하는 항목이 많음
      • 다양한 옵션으로 커스터마이징 가능
    2. 단점
      • Angular용 i18next는 i18next 자체 제작이 아님
      • 대부분 예제는 리액트임
      • Angular 최신용 버전이 아직 개발 단계임
      • 언어 변경 시에 깜빡임 현상이 일어남
  3. @ngx-translate
    1. 장점
      • JSON 형식
      • Angular 적용이 편함
      • 그나마 최근에 업데이트가 되었음
      • 언어 변경 시 깜빡임 없음
    2. 단점
      • 최근 Angular 16용으로 구축됨
  4. angular-translate
    1. 장점
      • JSON 형식
      • Angular 적용이 편함
      • 언어 변경 시 깜빡임 없음
    2. 단점
      • 적용하기 전에 사전작업이 필요
      • 최신 업데이트가 없음
      • 자료가 많이 없음

결론

현재 LiveStudio에 적용에는 @ngx-translate 를 적용하는게 유리하다고 판단됨.

LIST