Angular tilidagi dinamik tarjimalar mumkin

Dangasa yuklangan tarjimalarni amalga oshirish uchun amaliy qo'llanma

Agar siz Angular tilida internatsionalizatsiya (yoki qisqacha "i18n") bilan shug'ullangan bo'lsangiz yoki uni amalga oshirish arafasida bo'lsangiz, siz ajoyib "rasmiy qo'llanma" ga amal qilishingiz mumkin, disk raskadrovka yoki tanlash qiyin bo'lishi mumkin bo'lgan uchinchi tomon paketlaridan foydalaning. men quyida tasvirlab beradigan muqobil yo'l.

i18n-dan foydalanishda keng tarqalgan tuzoqlardan biri bu katta tarjima fayllari hajmi va ilovangizning ayrim qismlarini qiziquvchan ko'zlardan yashirish uchun ularni bo'lishning mumkin emasligi. Angular o'rnatilgan dastur kabi ba'zi echimlar haqiqatan ham kuchli va SEO-ga mos keladi, lekin juda ko'p tayyorgarlikni talab qiladi va rivojlanish rejimida tezda tillarni almashtirishni qo'llab-quvvatlamaydi (bu hech bo'lmaganda 9-versiyada "muammolarni keltirib chiqargan"); "ngx-translate" kabi boshqa echimlar bir nechta paketlarni o'rnatishni talab qiladi va hali ham bitta tilni ajratishni qo'llab-quvvatlamaydi (yangilanish: aslida ngx-translate buni qo'llab-quvvatlaydi).

Hamma narsani qo'llab-quvvatlaydigan va hammaga mos keladigan bu murakkab xususiyat uchun "sehrli tayoqcha" mavjud bo'lmasa-da, bu sizning ehtiyojlaringizga mos keladigan tarjimalarni amalga oshirishning yana bir usuli.
Kirish bilan kifoya, men bu amaliy bo'lishiga va'da berdim. hidoyat, shuning uchun to'g'ridan-to'g'ri unga o'taylik.

Asoslarni tayyorlash

Birinchi qadam, ilovada ishlatiladigan tillar turini yaratishdir:

export type LanguageCode = 'en' | 'de';

Sevimli burchak xususiyatlaridan biri bu biz uchun juda ko'p ish qiladigan qaramlik in'ektsiyasi - keling, undan ehtiyojlarimiz uchun foydalanaylik. Shuningdek, ushbu qo‘llanma uchun NgRx-dan foydalanib, narsalarni biroz yaxshilashni xohlayman, lekin agar siz uni loyihangizda ishlatmasangiz, uni oddiy BehaviorSubject bilan almashtiring.

NgRx bilan keyingi rivojlanishni osonlashtiradigan ixtiyoriy qadam sifatida DI zavodlari uchun tur yarating:

export type Ti18nFactory<Part> = (store: Store) => Observable<Part>;

Tarjima fayllarini yaratish

Umumiy qatorlar

Faraz qilaylik, bizda ilovada foydalanmoqchi bo'lgan bir nechta asosiy satrlar mavjud. “OK” yoki “Orqaga” tugmalari kabi ma’lum modul, funksiya yoki kutubxonaga hech qachon aloqador bo‘lmagan oddiy, ammo keng tarqalgan narsalar.
Biz bu satrlarni “yadro” moduliga joylashtiramiz va buni oddiy interfeysdan boshlaymiz. Bu bizga tarjimalarda biron bir qatorni unutmaslikka yordam beradi:

export interface I18nCore {
  errorDefault: string;
  language: string;
}

Shunchaki tushunarli bo'lishi uchun, ushbu interfeys barcha satrlarning haqiqatda tarjima qilinishini kafolatlamaydi, ammo "lang" fayllaringizga biron bir qatorni qo'shishni unutib qo'ysangiz, TypeScript kompilyatori (va sizning IDE) "TS2741" xatosini keltirib chiqaradi.

Interfeys va ushbu parcha uchun dasturga o'tadigan bo'lsak, men bu holda libs/core/src/lib/i18n/lang-en.lang.ts bo'ladigan fayl yo'lining namunasini taqdim etishim juda muhim:

export const lang: I18nCore = {
  errorDefault: 'An error has occurred',
  language: 'Language',
};

Kodlarning takrorlanishini kamaytirish va ishlab chiqish jarayonidan maksimal darajada foydalanish uchun biz DI zavodini ham yaratamiz. Mana NgRx dan foydalangan holda ishlaydigan misol (yana bu mutlaqo ixtiyoriy, buning uchun BehaviorSubject dan foydalanishingiz mumkin):

export const I18N_CORE =
  new InjectionToken<Observable<I18nCore>>('I18N_CORE');

export const i18nCoreFactory: Ti18nFactory<I18nCore> =
  (store: Store): Observable<I18nCore> => 
    (store as Store<LocalePartialState>).pipe(
      select(getLocaleLanguageCode),
      distinctUntilChanged(),
      switchMap((code: LanguageCode) =>
        import(`./lang-${code}.lang`)
          .then((l: { lang: I18nCore }) => l.lang)
      ),
    );

export const i18nCoreProvider: FactoryProvider = {
  provide: I18N_CORE,
  useFactory: i18nCoreFactory,
  deps: [Store],
};

Shubhasiz, getLocaleLanguageCode selektori do'kondan til kodini tanlaydi.

Tarjima fayllarini kompilyatsiyangizga qo'shishni unutmang, chunki ular to'g'ridan-to'g'ri havola qilinmaydi, shuning uchun avtomatik ravishda kiritilmaydi. Buning uchun tegishli "tsconfig" ni ("main.ts" ro'yxatini ko'rsatadigan) toping va "include" qatoriga quyidagilarni qo'shing:

"../../libs/core/src/lib/i18n/*.lang.ts"

Esda tutingki, bu yerdagi fayl yoʻli joker belgini oʻz ichiga oladi, shunda barcha tarjimalaringiz bir vaqtning oʻzida kiritiladi. Bundan tashqari, ta'mga ko'ra, men shunga o'xshash fayllarga prefiks qo'yishni yaxshi ko'raman, bu misol nomi ([prefix]-[langCode].lang.ts) nima uchun juda g'alati ko'rinishini tushuntiradi.

Modulga xos qatorlar

Keling, har qanday modul uchun ham xuddi shunday qilamiz, shuning uchun brauzerda tarjimalar qanday qilib alohida yuklanishini ko'rishimiz mumkin. Oddiy bo'lishi uchun ushbu modul "tab1" deb nomlanadi.

Yana interfeysdan boshlang:

export interface I18nTab1 {
  country: string;
}

Ushbu interfeysni amalga oshiring:

export const lang: I18nTab1 = {
  country: 'Country',
};

Tarjimalaringizni kompilyatsiyaga kiriting:

"../../libs/tab1/src/lib/i18n/*.lang.ts"

Va ixtiyoriy ravishda avvalgisiga o'xshash, ammo boshqa interfeysga ega bo'lgan DI zavodini yarating.

Tarjimalarni taqdim etish

“Asosiy” tarjimalar faqat AppModule roʻyxatida koʻrsatilishi uchun men provayderlar sonini kamaytirishni afzal koʻraman:

providers: [i18nCoreProvider],

Boshqa har qanday tarjima faqat tegishli modullarda taqdim etilishi kerak - dangasa yuklangan xususiyat modullarida yoki agar siz SCAM namunasiga amal qilsangiz, komponent modullarida:

@NgModule({
  declarations: [TabComponent],
  imports: [CommonModule, ReactiveFormsModule],
  providers: [i18nTab1Provider],
})
export class TabModule {}

Bundan tashqari, bu erga ob'ektlar qo'shish o'rniga oldindan tayyorlangan FactoryProviders-dan foydalanishning nafisligiga e'tibor bering.

Tokenlarni component.ts ichiga kiriting:

constructor(
  @Inject(I18N_CORE)
  public readonly i18nCore$: Observable<I18nCore>,
  @Inject(I18N_TAB1)
  public readonly i18nTab1$: Observable<I18nTab1>,
) {}

Va nihoyat, component.html ni ng-konteyner va oddiy ngIf iborasi bilan o'rab oling:

<ng-container *ngIf="{
    core: i18nCore$ | async,
    tab1: i18nTab1$ | async
  } as i18n">
    <p>{{ i18n.core?.language }}</p>
    <p>{{ i18n.tab1?.country }}: n/a</p>
</ng-container>

Natijani tekshirish

Keling, buni ishga tushiramiz va bu haqiqatan ham ishlayotganligini va eng muhimi, bu tarjimalar qanday yuklanishini ko'rib chiqamiz. Men ikkita dangasa yuklangan Angular modullaridan iborat oddiy demo ilovasini yaratdim, shuning uchun siz u bilan klonlashingiz va tajriba qilishingiz mumkin. Ammo hozircha, DevTools-ning haqiqiy skrinshotlari:

Foyda

  • Ushbu yechim yordamida siz o'zingizning tarjimalaringizni kerakli tarzda bir nechta fayllarga bo'lishingiz mumkin, lekin majbur emassiz;
  • Bu reaktiv, ya'ni to'g'ri amalga oshirilganda u foydalanuvchilarga uzluksiz tajriba beradi;
  • Bu sizdan Angular bilan birga bo'lmagan narsalarni o'rnatishingizni talab qilmaydi;
  • U osongina tuzatiladi va to'liq moslashtiriladi, chunki u to'g'ridan-to'g'ri loyihangizda amalga oshiriladi;
  • U murakkab mahalliy ruxsatlarni qo'llab-quvvatlaydi, masalan, brauzer tili bilan bog'liq, avtorizatsiyadan keyin foydalanuvchi hisobidan mintaqaviy sozlamalarni olish va foydalanuvchi tomonidan belgilangan til bilan bekor qilish - va bularning barchasi bitta sahifani qayta yuklamasdan;
  • Shuningdek, u zamonaviy IDE-larda kodni to'ldirishni qo'llab-quvvatlaydi.

Kamchiliklari

  • Ushbu tarjima fayllari aktivlarga kiritilmagani uchun, ular aslida ko'chirilishi kerak, bu esa qurish vaqtini biroz oshiradi;
  • Tarjimalaringizni mahalliylashtirish platformasi bilan almashish uchun sizdan maxsus yordamchi dastur yaratishingiz yoki uchinchi tomon yechimidan foydalanishingizni talab qiladi;
  • To'g'ri server tomonida ko'rsatilmagan holda qidiruv tizimlari bilan yaxshi ishlamasligi mumkin.

GitHub

"Ushbu omborda" mavjud bo'lgan to'liq ishlaydigan misol bilan tajriba o'tkazing.
Ijobiy bo'ling va ajoyib ilovalar yarating!