Создание плагинов

Механизм расширения Globalize (JavaScript library) строится вокруг идеи модульной локализации, где базовое ядро отвечает за работу с CLDR-данными, а дополнительные возможности подключаются через плагины. Плагины позволяют изолировать функциональность форматирования, парсинга и преобразования данных, не перегружая основной пакет и сохраняя предсказуемую архитектуру.

В основе системы лежит единый объект Globalize, который инкапсулирует доступ к локализованным операциям. Плагины подключаются как расширения этого объекта, добавляя новые методы или модифицируя поведение существующих через композицию.

Ключевые принципы:

  • изолированность функционала — каждый плагин решает одну задачу
  • явная регистрация зависимостей — подключение происходит вручную
  • работа поверх CLDR-данных — плагины не заменяют базовую модель локализации
  • отсутствие скрытых побочных эффектов

Такая модель делает систему предсказуемой при масштабировании и позволяет формировать минимальные сборки под конкретные задачи.

Базовый механизм расширения

Плагин в контексте Globalize представляет собой функцию, принимающую экземпляр Globalize и добавляющую к нему новый функционал.

function currencyPlugin(Globalize) {
  Globalize.prototype.formatCurrencyDetailed = function(value, currency) {
    return this.currencyFormatter(currency)(value);
  };
}

Регистрация выполняется вручную:

import Globalize from "globalize";

currencyPlugin(Globalize);

После подключения методы становятся частью прототипа и доступны через любой экземпляр:

const globalize = new Globalize("en");
globalize.formatCurrencyDetailed(1000, "USD");

Структура типичного плагина

Плагин обычно состоит из трёх частей:

  1. Проверка зависимостей
  2. Расширение прототипа
  3. Подключение внутренних вспомогательных функций

Пример расширенного шаблона:

function numberParserPlugin(Globalize) {
  if (!Globalize || !Globalize.formatNumber) {
    throw new Error("Globalize core or number module is missing");
  }

  function parseNumber(str) {
    return this.numberParser()(str);
  }

  Globalize.prototype.parseNumber = parseNumber;
}

Такая структура позволяет контролировать совместимость и предотвращать некорректное подключение.

Плагины форматирования

Наиболее распространённый тип расширений связан с форматированием данных. Globalize предоставляет базовые методы, но плагины позволяют объединять несколько операций или вводить новые форматы.

Расширенное форматирование дат

function dateTimePlugin(Globalize) {
  Globalize.prototype.formatDateTimeLong = function(date) {
    return this.formatDate(date, {
      datetime: "long"
    });
  };
}

Добавленный метод объединяет стандартную функциональность в более высокоуровневую операцию, что уменьшает дублирование кода в приложениях.

Плагины парсинга

Парсинг часто требует более сложной логики, чем форматирование, особенно при работе с пользовательским вводом.

function strictParsePlugin(Globalize) {
  Globalize.prototype.strictParseNumber = function(value) {
    const parsed = this.parseNumber(value);

    if (isNaN(parsed)) {
      throw new Error("Invalid number format");
    }

    return parsed;
  };
}

Подобные плагины усиливают контроль над данными, особенно в формах и интерфейсах ввода.

Комбинированные плагины

Некоторые расширения объединяют несколько типов операций, создавая более высокоуровневые абстракции.

function accountingPlugin(Globalize) {
  Globalize.prototype.formatAccounting = function(value, currency) {
    const formattedNumber = this.formatNumber(value, {
      minimumFractionDigits: 2
    });

    const formattedCurrency = this.currencyFormatter(currency)(value);

    return `${formattedCurrency} (${formattedNumber})`;
  };
}

Такие плагины формируют доменно-ориентированные инструменты поверх базовой интернационализации.

Управление зависимостями плагинов

При увеличении числа расширений возникает необходимость контроля порядка подключения.

function pluginA(Globalize) {
  Globalize.prototype.methodA = function() {};
}

function pluginB(Globalize) {
  if (!Globalize.prototype.methodA) {
    throw new Error("pluginA must be loaded before pluginB");
  }

  Globalize.prototype.methodB = function() {
    this.methodA();
  };
}

Зависимости между плагинами обычно не автоматизируются, что требует явного документирования порядка подключения.

Плагины и модульная сборка

При использовании сборщиков (Webpack, Rollup, Vite) плагины часто оформляются как отдельные модули:

// plugins/number-utils.js
export default function numberUtilsPlugin(Globalize) {
  Globalize.prototype.roundLocalized = function(value) {
    return Math.round(this.parseNumber(value));
  };
}

Импорт в приложении:

import Globalize from "globalize";
import numberUtilsPlugin from "./plugins/number-utils";

numberUtilsPlugin(Globalize);

Такой подход позволяет формировать библиотеку расширений как независимый слой над международной логикой.

Изоляция и расширяемость

Ключевым аспектом является отсутствие модификации исходного ядра. Плагины:

  • не изменяют внутренние структуры CLDR
  • не переопределяют базовые методы без необходимости
  • не нарушают обратную совместимость

При необходимости переопределения используется аккуратное сохранение оригинальной реализации:

function overrideFormatNumber(Globalize) {
  const original = Globalize.prototype.formatNumber;

  Globalize.prototype.formatNumber = function(value) {
    const result = original.call(this, value);
    return `[${result}]`;
  };
}

Организация библиотеки плагинов

В крупных проектах плагины группируются по функциональности:

  • числовые расширения
  • валютные операции
  • дата и время
  • валидация и парсинг
  • доменные утилиты

Каждая группа может иметь собственный входной модуль:

import currencyPlugins from "./plugins/currency/index.js";
import datePlugins from "./plugins/date/index.js";

currencyPlugins(Globalize);
datePlugins(Globalize);

Такая структура позволяет масштабировать локализацию без увеличения сложности основного кода.