В Angular-проектах библиотека Globalize подключается через npm как обычная зависимость и требует дополнительной настройки CLDR-данных для корректной локализации чисел, дат и валют.
Установка выполняется стандартной командой:
npm install globalize cldr-data
Дополнительно часто требуется установка вспомогательных пакетов для работы с CLDR:
npm install cldrjs
После установки формируется базовая инфраструктура, в которой Globalize не работает «из коробки» — ему требуется загрузка локализационных данных и регистрация форматов.
Globalize опирается на Unicode CLDR (Common Locale Data Repository). Без загрузки этих данных форматирование остаётся неполным.
В Angular-проекте данные обычно подключаются вручную в одном из
bootstrap-файлов (например, main.ts или отдельном
i18n.ts).
Пример подключения базового набора:
import * as Globalize from "globalize";
import likelySubtags from "cldr-data/supplemental/likelySubtags";
import numberingSystems from "cldr-data/supplemental/numberingSystems";
import enNumbers from "cldr-data/main/en/numbers";
import enCurrencies from "cldr-data/main/en/currencies";
import enCaGregorian from "cldr-data/main/en/ca-gregorian";
import enTimeZoneNames from "cldr-data/main/en/timeZoneNames";
Globalize.load(
likelySubtags,
numberingSystems,
enNumbers,
enCurrencies,
enCaGregorian,
enTimeZoneNames
);
Globalize.locale("en");
При увеличении числа поддерживаемых локалей структура расширяется:
добавляются соответствующие наборы main/<locale>.
Angular-архитектура предполагает централизованное управление зависимостями через сервисы. Globalize целесообразно инкапсулировать в единый сервис, обеспечивающий форматирование чисел, дат и валют.
Создание сервиса:
import { Injectable } from "@angular/core";
import * as Globalize from "globalize";
@Injectable({
providedIn: "root"
})
export class I18nService {
private globalize = Globalize;
setLocale(locale: string): void {
this.globalize.locale(locale);
}
formatNumber(value: number): string {
return this.globalize.numberFormatter()(value);
}
formatCurrency(value: number, currency: string): string {
return this.globalize.currencyFormatter(currency)(value);
}
formatDate(value: Date): string {
return this.globalize.dateFormatter()(value);
}
}
Такой слой изолирует библиотеку от компонентов Angular и упрощает замену реализации при необходимости.
Компоненты получают доступ к форматированию через DI:
import { Component } from "@angular/core";
import { I18nService } from "./i18n.service";
@Component({
selector: "app-dashboard",
template: `
<div>{{ price }}</div>
<div>{{ date }}</div>
`
})
export class DashboardComponent {
price: string;
date: string;
constructor(private i18n: I18nService) {
this.price = this.i18n.formatCurrency(1250, "USD");
this.date = this.i18n.formatDate(new Date());
}
}
Форматирование выполняется на уровне бизнес-логики, а не шаблона, что снижает нагрузку на Angular change detection при сложных выражениях.
Для декларативного использования в шаблонах создаётся pipe-обёртка.
import { Pipe, PipeTransform } from "@angular/core";
import * as Globalize from "globalize";
@Pipe({
name: "gNumber",
pure: true
})
export class NumberPipe implements PipeTransform {
transform(value: number): string {
return Globalize.numberFormatter()(value);
}
}
import { Pipe, PipeTransform } from "@angular/core";
import * as Globalize from "globalize";
@Pipe({
name: "gCurrency",
pure: true
})
export class CurrencyPipe implements PipeTransform {
transform(value: number, currency: string): string {
return Globalize.currencyFormatter(currency)(value);
}
}
<div>{{ 1500 | gNumber }}</div>
<div>{{ 1500 | gCurrency:'EUR' }}</div>
Pipe обеспечивает лаконичность шаблонов, но требует осторожности при массовом использовании из-за возможной повторной инициализации форматтеров.
Динамическое переключение локали требует обновления состояния Globalize и повторного пересчёта отображаемых значений.
Расширение сервиса:
setLocale(locale: string): void {
this.globalize.locale(locale);
}
Дополнительно применяется реактивный подход через
BehaviorSubject:
import { BehaviorSubject } from "rxjs";
private locale$ = new BehaviorSubject<string>("en");
setLocale(locale: string): void {
this.globalize.locale(locale);
this.locale$.next(locale);
}
getLocale() {
return this.locale$.asObservable();
}
Компоненты подписываются на изменения и обновляют данные при смене языка интерфейса.
При большом количестве локалей загрузка всех CLDR данных в bundle
приводит к увеличению размера сборки. Используется динамическая
подгрузка через import().
async loadLocale(locale: string): Promise<void> {
const [
numbers,
currencies,
caGregorian,
timeZoneNames
] = await Promise.all([
import(`cldr-data/main/${locale}/numbers`),
import(`cldr-data/main/${locale}/currencies`),
import(`cldr-data/main/${locale}/ca-gregorian`),
import(`cldr-data/main/${locale}/timeZoneNames`)
]);
Globalize.load(numbers, currencies, caGregorian, timeZoneNames);
Globalize.locale(locale);
}
Такой подход уменьшает initial bundle size и переносит нагрузку на runtime.
Angular содержит встроенный DatePipe, однако Globalize
предоставляет более консистентное поведение в мульти-региональных
приложениях.
Пример форматирования даты через Globalize:
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
formatter(new Date());
Сопоставление форматов:
short — минимальное отображениеmedium — стандартноеlong — расширенноеfull — максимально подробноеИспользование Globalize позволяет унифицировать форматирование вне зависимости от Angular шаблонов.
Форматирование валют в Globalize учитывает правила конкретной локали:
const usdFormatter = Globalize.currencyFormatter("USD");
usdFormatter(1234.56);
Поддерживается:
Для Angular-приложений финансового профиля целесообразно централизовать форматтеры и избегать их пересоздания.
Создание форматтеров Globalize является относительно дорогой операцией. В Angular-приложениях применяется кэширование:
private numberFormatter = Globalize.numberFormatter();
private currencyFormatter = Globalize.currencyFormatter("USD");
format(value: number): string {
return this.numberFormatter(value);
}
Также учитывается:
Для корректной работы локализации Globalize должен быть настроен до
вызова bootstrapApplication или
platformBrowserDynamic.
Пример структуры main.ts:
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import "./i18n/globalize-init";
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
Файл globalize-init.ts содержит всю загрузку CLDR и
установку дефолтной локали.
При работе с ReactiveFormsModule форматирование часто
применяется на уровне отображения, а не хранения значения.
Пример преобразования отображаемого значения:
this.form.get("price")?.valueChanges.subscribe(value => {
const formatted = this.i18n.formatCurrency(value, "USD");
});
Хранение остаётся в числовом виде, что упрощает валидацию и серверную обработку.
При отсутствии данных CLDR для выбранной локали используется fallback:
Globalize.locale(["fr", "en"]);
Система пытается применить французскую локаль, а при отсутствии данных переходит на английскую.
Такой механизм повышает устойчивость приложения в многоязычных средах и снижает вероятность runtime-ошибок форматирования.