Przejdź do treści
DedicatedPHP Kontakt

Internacjonalizacja aplikacji PHP bez duplikowania

Przewodnik po oddzielaniu języka, formatów i treści od reguł biznesowych podczas przygotowywania aplikacji PHP na różne rynki.

Schemat redakcyjny aplikacji PHP oddzielającej język, formaty regionalne, strefę czasową i reguły biznesowe

Internacjonalizacja aplikacji PHP nie polega wyłącznie na tłumaczeniu przycisków i komunikatów. Aplikacja przygotowana na wiele języków lub rynków musi oddzielać język, formaty regionalne, strefę czasową, walutę, treść i polityki biznesowe. Gdy te warstwy są mieszane, każda ekspansja może stać się funkcjonalnym rozgałęzieniem trudnym do testowania i utrzymania.

Co zmienia się podczas działania w wielu językach i na wielu rynkach

Co zmienia się podczas działania w wielu językach i na wielu rynkach — guía visual de DedicatedPHP

Język określa sposób wyrażania tekstu. Ustawienia regionalne, czyli locale, definiują konwencje prezentacji, takie jak separator dziesiętny, kolejność dat czy grupowanie tysięcy. Ustawienia regionalne mogą zawierać region, na przykład es-ES lub fr-CA, ale ten region nie powinien zastępować rynku, podmiotu prawnego, miejsca zamieszkania, polityki handlowej ani kraju operacyjnego.

Warto także rozróżniać konteksty, które często występują razem, lecz nie oznaczają tego samego:

  • Strefa czasowa: interpretuje harmonogramy, terminy, planowanie i zakończenia działań operacyjnych.
  • Waluta: identyfikuje kwotę transakcji lub cennika; nie wynika z języka.
  • Organizacja lub podmiot prawny: może określać podatki, uprawnienia, fakturowanie lub retencję danych.
  • Rynek: może warunkować katalog, logistykę, metody płatności lub dostępne kanały.
  • Preferencje użytkownika: wybrany język, ustawienia regionalne i strefa czasowa, które mogą różnić się od konfiguracji firmowej.

Osoba może używać interfejsu po angielsku, pracować w europejskiej strefie czasowej i zarządzać organizacją fakturującą w innej walucie. Sprowadzenie tej rzeczywistości do jednej zmiennej locale tworzy ukryte decyzje.

Kosztowny błąd: traktowanie języka jako reguły biznesowej

Zły sygnał pojawia się, gdy kod podejmuje decyzje domenowe na podstawie języka interfejsu: if ($locale === 'es'). Taki warunek może zacząć się od wyświetlania innej etykiety, a skończyć na naliczaniu podatków, ukrywaniu metody płatności lub zmianie zatwierdzenia.

Właściwe pytanie brzmi: „jaka dana lub polityka wyjaśnia tę różnicę?”. Jeśli zależy ona od podmiotu prawnego, należy odwołać się do tego podmiotu. Jeśli wynika z polityki handlowej, powinna istnieć identyfikowalna i wersjonowalna polityka. Jeśli wpływa wyłącznie na reprezentację, należy do granicy wejścia lub wyjścia.

Język tłumaczy doświadczenie; sam w sobie nie autoryzuje, nie oblicza ani nie definiuje zachowania domeny.

Co powinno pozostać w domenie

Domena powinna pracować ze stabilnymi pojęciami i wartościami kanonicznymi. Zamówienie potrzebuje ilości, kwot, pozycji, statusów i reguł obliczeń; nie musi wiedzieć, czy kwota zostanie wyświetlona jako 1,234.50 czy 1.234,50. Polityka kwalifikowalności powinna otrzymywać jawne atrybuty, a nie odczytywać prezentację użytkownika.

  • Domena: niezmienniki, stany, obliczenia, autoryzacje biznesowe, polityki i zdarzenia.
  • Aplikacja: przypadki użycia, ładowanie kontekstu, koordynacja i wybór polityk.
  • Adaptery wejściowe: formularze, nagłówki, API lub pliki; walidacja i normalizacja.
  • Adaptery wyjściowe: tłumaczenie, serializacja oraz formatowanie dat, kwot i jednostek.

W PHP należy unikać bezpośredniego odwoływania się przez encje i centralne serwisy do sesji, nagłówków HTTP, zmiennych środowiskowych lub globalnych ustawień regionalnych procesu. Te zależności sprawiają, że ten sam przypadek użycia zachowuje się inaczej zależnie od kanału lub chwili wykonania.

Projektowanie jawnego i ograniczonego kontekstu

ExecutionContext może obejmować identyfikator organizacji, aktora, ustawienia regionalne prezentacji i preferowaną strefę czasową. Każde pole powinno mieć jasną semantykę. Waluta operacji powinna jednak być częścią kwoty lub zastosowanej polityki cenowej, a nie mutowalnej globalnej preferencji.

Kontekst należy rozwiązywać na granicy każdego kanału. Żądanie webowe może używać zapisanej preferencji lub kontrolowanej negocjacji; API powinno otrzymywać jawne i udokumentowane pola; proces kolejkowy musi utrwalać wymagane identyfikatory podczas tworzenia. Zadanie asynchroniczne nie powinno zakładać, że odziedziczy sesję, użytkownika ani strefę czasową.

Treść tłumaczalna i dane operacyjne

Teksty interfejsu, szablony komunikacji i treści redakcyjne mają inny cykl życia niż dane operacyjne. Używaj stabilnych i semantycznych kluczy, na przykład billing.invoice.overdue, zamiast tekstu źródłowego. Dzięki temu można zmienić redakcję bez psucia kodu, testów ani integracji.

Treść zarządzalna wymaga publikacji: tłumaczenie może istnieć jako szkic, być zatwierdzone lub opublikowane. Zdefiniuj fallback: żądany język, język bazowy organizacji oraz, gdy to właściwe, widoczny i kontrolowany brak. Alternatywne tłumaczenie może być akceptowalne dla wewnętrznej notatki, lecz niekoniecznie dla komunikacji kontraktowej.

Nie duplikuj kompletnego rekordu operacyjnego dla każdego języka, chyba że dana jest zlokalizowana. Produkt może mieć tłumaczalną nazwę i opis, podczas gdy identyfikator, waga, status i reguły dostępności pozostają wspólne. Jeśli istnieje rzeczywista różnica handlowa, modeluj ją jako wariant lub politykę, a nie jako tłumaczenie.

Daty, kwoty, jednostki i zaokrąglenia

Przechowuj punkty w czasie w sposób jednoznaczny i zachowuj strefę czasową, gdy znaczenie jest lokalne. „Spotkanie zaczyna się o 09:00” wymaga znajomości strefy, w której je zdefiniowano; „zdarzenie nastąpiło o tej godzinie” wymaga chwili absolutnej. Zmiany czasu sezonowego powodują godziny nieistniejące lub powtarzające się, dlatego dane wejściowe muszą być walidowane, a przyjęte rozstrzygnięcie powinno zostać zapisane, gdy ma to zastosowanie.

Dla pieniędzy przechowuj liczbę całkowitą w jednostkach podrzędnych wraz z kodem waluty, ale nie zakładaj dwóch miejsc dziesiętnych. Skala lub wykładnik wynika z metadanych waluty mających zastosowanie do operacji. Niektóre waluty używają skali innej niż dwa, a wymagania historyczne lub sieci płatniczej mogą wymagać zachowania obowiązującej skali albo wersji użytej reguły.

final class Money {
    public function __construct(
        public readonly int $minorUnits,
        public readonly string $currency,
        public readonly int $scale
    ) {}
}

Skala pozwala prawidłowo interpretować jednostki podrzędne, ale nie zastępuje polityki zaokrąglania. Zdefiniuj punkt zaokrąglania, stosowany tryb i regułę gotówkową, gdy istnieje, ponieważ zaokrąglanie kasowe może różnić się od księgowego. Unikaj float, zlokalizowanych formatów podczas obliczeń oraz niejawnych konwersji.

Ten sam wzorzec stosuje się do miar: zachowuj oryginalną jednostkę, gdy ma znaczenie operacyjne, normalizuj ją, gdy wymagają tego obliczenia, i konwertuj wyłącznie podczas wprowadzania lub prezentacji. Formularz powinien wskazywać jednostkę i dozwolony format; nie powinien zgadywać, czy 1,500 oznacza półtora czy tysiąc pięćset.

Architektura przepływów wejścia i wyjścia

Rozdzielenie warstw powinno być widoczne w pełnym i powtarzalnym przepływie:

  1. Pobranie kontekstu i danych wejściowych: uzyskanie organizacji, aktora, kanału, ustawień regionalnych, strefy czasowej i otrzymanej wartości.
  2. Walidacja dozwolonego formatu: sprawdzenie pól wymaganych, składni, jednostki, waluty, strefy czasowej i ograniczeń kanału.
  3. Normalizacja do wartości kanonicznych: przekształcenie zlokalizowanego tekstu w jednoznaczne kwoty, daty, jednostki i identyfikatory.
  4. Wykonanie przypadku użycia domeny: zastosowanie jawnych reguł i polityk do wartości kanonicznych.
  5. Tłumaczenie i formatowanie wyjścia: wybór opublikowanych komunikatów i reprezentowanie wartości dla odbiorcy lub kontraktu API.

API może zdecydować o przyjmowaniu wyłącznie formatów kanonicznych, takich jak daty z jawną strefą oraz strukturyzowane kwoty. Formularz dla człowieka może przyjmować formaty zlokalizowane, pod warunkiem że jego parser jest jawny. W obu przypadkach domena otrzymuje tę samą stabilną reprezentację.

Konfigurowalna polityka czy odrębna reguła biznesowa

Wariacja jest zwykle konfigurowalna, jeśli współdzieli proces i zmienia deklarowalne parametry, takie jak limit, lista świąt lub metoda obliczeń zdefiniowana przez konfigurację. Ta konfiguracja wymaga schematu, wersji, właściciela i testów.

Różnica ujawnia odrębną regułę, gdy zmienia niezmienniki, stany, odpowiedzialności, źródła danych lub konsekwencje prawne. W takim przypadku ukrywanie jej w opcjach tworzy nieprzejrzystą konfigurację. Modeluj politykę za pomocą jawnego interfejsu albo odrębnego przepływu, jeśli proces rzeczywiście jest inny. Celem nie jest wymuszanie jednej abstrakcji, lecz uniknięcie duplikowania całej aplikacji z powodu zlokalizowanej różnicy.

Testy i lista kontrolna

Testy i lista kontrolna — guía visual de DedicatedPHP

Testy powinny weryfikować obliczenia i reprezentację. Zmiana języka lub ustawień regionalnych nie powinna zmieniać sumy, autoryzacji ani polityki handlowej, chyba że stanowi o tym jawny wymóg.

  • Testuj daty przy zmianach czasu, z godzinami niejednoznacznymi i nieistniejącymi.
  • Uwzględnij kwoty zerowe, ujemne, różne skale, zaokrąglanie księgowe i gotówkowe.
  • Sprawdzaj dozwolone zlokalizowane dane wejściowe oraz odrzucanie niejednoznacznych formatów.
  • Weryfikuj fallback, brak opublikowanej treści i interpolowane zmienne.
  • Uruchamiaj zadania asynchroniczne bez sesji, używając wyłącznie utrwalonego kontekstu.
  • Testuj kontrakty API z wartościami kanonicznymi i metadanymi formatu, gdy są potrzebne.

Przed otwarciem języka lub rynku zidentyfikuj, co rzeczywiście się zmienia, rozdziel źródła prawdy, przejrzyj reguły walutowe i czasowe oraz aktywuj dostępność stopniowo, gdy działanie wymaga kontrolowanej walidacji. Ta dyscyplina pozwala rozwijać aplikację bez przekształcania każdego rynku w równoległą wersję produktu.

Chcesz zastosować te pomysły w swoim projekcie?Omówmy Twoją platformę PHP.
Zobacz powiązaną usługę