Database
 sql >> Baza danych >  >> RDS >> Database

Projektowanie baz danych dla aplikacji wielojęzycznych

Chociaż niektóre systemy oprogramowania są używane przez ograniczoną liczbę użytkowników mówiących tym samym językiem, większość organizacji musi ujednolicić i scentralizować swoje aplikacje, aby mogły być używane przez osoby posługujące się różnymi językami na całym świecie. Wielojęzyczne bazy danych stanowią dodatkowy poziom trudności w projektowaniu i wdrażaniu modeli danych. W tym artykule proponujemy kilka sposobów radzenia sobie z tym wyzwaniem.

Jakie informacje musimy przechowywać w wielu językach?

Na pozór wszystkie informacje w ciągach mogą wydawać się wiarygodne do przetłumaczenia na wiele języków. Jednak zwykle tak nie jest. Informacje dotyczące klienta, takie jak CompanyName lub Adres może być przetłumaczone, ale może to nie być dobry pomysł.

Weźmy na przykład klienta biznesowego z Wielkiej Brytanii o nazwie „Riverside Trucks” z biurem przy „123 Upper Castle Road”. Nie chcesz, aby użytkownik hiszpańskojęzyczny wydrukował i wysłał list do „Camiones Orilla” znajdującego się pod adresem „123 Calle Castillo Superior”. Royal Mail (usługa pocztowa Wielkiej Brytanii) go nie znajdzie! Prawdopodobnie chcesz przetłumaczyć tylko kolumny zawierające informacje opisowe, a nie nazwy własne.

Projektując system do obsługi tłumaczeń, nie zawsze wiadomo z góry, które kolumny można tłumaczyć, a które nie wymagają tłumaczenia. Wybór elastycznego podejścia pozwala zaoszczędzić dużo czasu na projektowaniu i rozwoju. Zapoznaj się z artykułem „Jak zaprojektować system przystosowany do lokalizacji”, aby zobaczyć kilka przykładów.

Jakie podejścia bierzemy pod uwagę?

W tym artykule opisujemy trzy podejścia do projektowania wielojęzycznych baz danych. Zaczynamy od najprostszej, która nie jest tak elastyczna, a następnie przechodzimy do rozważenia innych opcji, wyjaśniając zalety i wady każdego z nich.

Zarówno składnia, jak i modele baz danych (dostępne w internetowym narzędziu do modelowania danych Vertabelo) użyte w tym artykule dotyczą programu SQL Server. Można je jednak łatwo dostosować do dowolnego silnika bazy danych.

Podejście 1:tworzenie dodatkowych kolumn do przechowywania przetłumaczonej treści

Jest to najprostsze podejście do wdrożenia, choć niezbyt elastyczne. Polega na dodaniu kolumny dla każdej kolumny i języka, którego potrzebujemy w naszym systemie, jak pokazano na poniższym diagramie Vertabelo:

Chociaż może się to wydawać bardzo prostym rozwiązaniem, ma pewne wady. Wyjaśnimy poniżej.

Wada:złożoność kodu

Takie podejście sprawia, że ​​kod jest bardziej złożony. Wymaga to albo napisania innego zapytania dla każdego języka, albo użycia CASE skonstruować, aby pobrać tłumaczenie dla odpowiedniego języka w oparciu o konfigurację użytkownika. Zobacz na przykład następujący kod:

SELECT ProductID,
    CASE @Language WHEN ‘ES’ THEN ProductName_ES
                   WHEN ‘DE’ THEN ProductName_DE
                   WHEN ‘FR’ THEN ProductName_FR
                   ELSE ProductName
    END AS ProductName,
    CASE @Language WHEN ‘ES’ THEN ProductDescription_ES
                   WHEN ‘DE’ THEN ProductDescription_DE
                   WHEN ‘FR’ THEN ProductDescription_FR
                   ELSE ProductDescription
    END AS ProductDescription,
    Price,
    Weight,
    ProductCategoryID
FROM Product
WHERE …

Uwaga: W tym przykładzie używamy zmiennej @Language, aby zachować język, którego chcemy używać. Możesz rozważyć użycie SESSION_CONTEXT() (lub kontekstu aplikacji w Oracle) do ustawienia i odczytania języka dla każdego użytkownika.

Wada:brak elastyczności

Takiemu podejściu brakuje elastyczności. Jeśli musimy zaimplementować nowy język, musimy zmodyfikować nasz model danych, dodając kolumnę dla nowego języka dla każdej możliwej do przetłumaczenia kolumny w naszym systemie. Musimy również utworzyć nowe zapytanie językowe dla każdej tabeli (lub edytować istniejące, dodając nowy CASE WHEN klauzula, która używa nowego języka dla każdej kolumny, którą można przetłumaczyć).

Con:Wyzwania w obsłudze nieznanych informacji

Wyobraź sobie to:użytkownik dodaje produkt, ale nie wie, jak go przetłumaczyć, a przetłumaczone kolumny pozostawia puste. Użytkownicy mówiący w tych językach zobaczą NULL lub puste informacje w kolumnach, które mogą być wymagane.

Podejście 2:izolowanie kolumn, które można przetłumaczyć w osobnej tabeli

W tym podejściu kolumny w tabeli są grupowane w kolumny, które można przetłumaczyć i których nie można przetłumaczyć. Kolumny, których nie można przetłumaczyć, pozostają w oryginalnej tabeli. Natomiast te, które można przetłumaczyć, znajdują się w osobnej tabeli, z kluczem obcym do oryginalnej tabeli i wskaźnikiem języka. Zobacz poniżej:

Diagram pokazuje oryginalne tabele (bez danych do przetłumaczenia) w kolorze białym. Tabele zawierające tłumaczenia są w kolorze jasnoniebieskim, a główna tabela zawierająca informacje o języku jest w kolorze żółtym.

Ma to ogromne zalety w zakresie elastyczności w porównaniu z używaniem wielu kolumn, jak omówiono wcześniej. Ta metoda nie wymaga zmiany modelu danych, gdy potrzebny jest nowy język. Ponadto składnia zapytań o informacje jest prostsza:

SELECT p.ProductID,
    pt.ProductName,
    pt.ProductDescription,
    p.Price,
    p.Weight,
    p.ProductCategoryID
FROM Product p
LEFT JOIN ProductTranslation pt ON pt.ProductID = p.ProductID
                               AND pt.LanguageID = @Language
WHERE …

Jednak nadal istnieją pewne wady, które omówimy poniżej.

Con:Wyzwania, gdy dodatkowe kolumny wymagają tłumaczenia

Jeśli musimy przekonwertować kolumnę, której nie można przetłumaczyć, na kolumnę, którą można przetłumaczyć (lub odwrotnie), musimy zmodyfikować nasz model danych, przenosząc kolumnę z jednej tabeli do drugiej. Zwykle oznacza to większe koszty po wdrożeniu i użytkowaniu systemu.

Con:Wyzwania w obsłudze nieznanych informacji

Podobnie jak w przypadku pierwszego podejścia, podejście to wiąże się z wyzwaniami, gdy mamy do czynienia z nieznanymi informacjami. Ponownie, jeśli użytkownik doda produkt, ale nie wie, jak go przetłumaczyć i pozostawi przetłumaczone kolumny puste, użytkownicy mówiący tymi językami zobaczą NULL lub puste informacje w kolumnach, które mogą być wymagane. Ponadto zapytanie wymaga LEFT JOIN w przypadku, gdy tłumaczenie na język bieżącego użytkownika nie zostało jeszcze utworzone, tak że dane, których nie można przetłumaczyć, są nadal wyświetlane.

Podejście 3:Dodawanie podsystemu tłumaczeń

Tłumaczenie można uznać za cechę całkowicie niezależną od modelu danych wymagającego tłumaczenia. W idealnym systemie możemy włączyć lub wyłączyć translację dla dowolnej kolumny bez konieczności modyfikacji modelu danych. Niestety łatwiej to powiedzieć niż zrobić.

Przedstawiamy metodę, która nie ma wpływu na istniejący model danych i jest całkowicie elastyczna. Chociaż zwiększa to złożoność w momencie wykonywania zapytań o dane, nie wymaga żadnych dodatkowych zmian w modelu danych z wyjątkiem kilku tabel. Może to być świetny wybór, jeśli chcesz dodać możliwość przechowywania tłumaczeń do istniejącego modelu danych.

Rzućmy okiem na model i zobaczmy, jak działa:

Pierwszą rzeczą, którą należy zauważyć, jest to, że oryginalny model danych nie zawiera żadnych zmian. Ponadto nie ma bezpośredniego związku między tym modelem a podsystemem tłumaczenia.

Podsystem tłumaczeniowy zawiera mały słownik danych z tabelami i kolumnami wymagającymi tłumaczenia. Ten słownik danych można modyfikować, po prostu dodając/usuwając wiersze bez zmiany modelu danych. Tłumaczenia są przechowywane w osobnej tabeli, a każda wartość jest identyfikowana przez następujące 3 kolumny:

  • Identyfikator kolumny :jednoznacznie identyfikuje kolumnę (i tabelę), którą tłumaczymy.
  • Identyfikator klucza :Przechowuje identyfikator (klucz podstawowy) określonego wiersza, który tłumaczymy.
  • Identyfikator języka :Identyfikuje język tłumaczenia.

Taka konstrukcja umożliwia wprowadzanie i przechowywanie danych w oryginalnych tabelach, dodając tłumaczenia tylko wtedy, gdy jest to wymagane. Przetłumaczone informacje są używane podczas pobierania danych, zachowując oryginalne dane (w oryginalnym języku) nietknięte.

Dane można odpytywać przy użyciu bardziej złożonej składni niż w powyższych przykładach. Wymaga dodatkowego JOIN dla każdej kolumny, którą można przetłumaczyć, jak pokazano poniżej:

SELECT p.ProductID,
    ISNULL(t1.TranslationValue, p.ProductName) AS ProductName,
    ISNULL(t2.TranslationValue, p.ProductDescription) AS ProductDescription,
    p.Price,
    p.Weight,
    p.ProductCategoryID
FROM Product p
LEFT JOIN Translation t1 ON t1.ColumnID = <>
                       AND t1.Key = p.ProductID
                       AND t1.LanguageID = @Language
LEFT JOIN Translation t2 ON t2.ColumnID = <>
                       AND t2.Key = p.ProductID
                       AND t2.LanguageID = @Language
WHERE …;

Uwaga:<> ” i „<> ” należy zastąpić identyfikatorami kolumn, które mają zostać przetłumaczone, jako przechowywane w ColumnInformation stół. Rozważ generowanie widoków tłumaczenia dla każdej tabeli wymagającej tłumaczenia, aby ukryć złożoność sprzężeń dla użytkowników końcowych. Możesz nawet zautomatyzować ten krok za pomocą skryptu, który generuje każdy widok. Ten skrypt może wysyłać zapytania do słownika danych bazy danych, aby wybrać tabele i kolumny oraz dodać logikę tłumaczenia dla kolumn, które istnieją w ColumnInformation tabela.

Dodatkowa wskazówka nr 1

Możesz także uprościć składnię. Zastąp każde JOIN wywołaniem funkcji, która obsługuje (i ukrywa) aspekt tłumaczenia, jak pokazano poniżej:

SELECT p.ProductID,
    ISNULL(fn_translate(‘Product’,‘ProductName’,ProductID), p.ProductName)
         AS ProductName,
    ISNULL(fn_translate(‘Product’,‘ProductDescription’,ProductID),
         p.ProductDescription) AS ProductName,
    p.Price,
    p.Weight,
    p.ProductCategoryID
FROM Product p
WHERE …;

Funkcja może odczytać żądany język z kontekstu lub możesz go dodać jako dodatkowy parametr. W tym przykładzie funkcja używa nazw tabeli i kolumn podanych jako parametry oraz klawisza wiersza (również podanego jako parametr) w celu wyszukania i zwrócenia żądanego tłumaczenia.

Wywołanie funkcji ma dodatkowy wpływ na wydajność ze względu na przełączanie kontekstu między SQL a językiem proceduralnym. Jednak może to być prostsze rozwiązanie dla baz danych lub tabel, w których pozwala na to ilość tłumaczonych danych.

Oba przykłady — ten z JOIN i ten z funkcją — wykorzystują funkcję ISNULL() SQL Server. Tak więc, jeśli tłumaczenie na żądany język nie istnieje, nadal wyświetla oryginalną wartość zapisaną w kolumnach ProductName i ProductDescription zamiast pustych lub NULL.

Uwagi ogólne

Trzecie podejście jest zwykle najlepsze do realizacji większych projektów. Pozwala to na elastyczność zarówno przy projektowaniu, jak i po uruchomieniu systemu. Istnieją jednak szczególne względy, które mogą sprawić, że inne podejścia będą przydatne. Niezależnie od wyboru, rozważ następujące kwestie, aby zaoszczędzić czas zarówno podczas projektowania, jak i rozwoju/wdrażania.

Dodaj warstwę abstrakcji

Jak wspomniano wcześniej, rozważ tworzenie widoków, które dbają o logikę tłumaczenia, np. wybierając jedną kolumnę spośród wielu kolumn tłumaczeniowych lub łącząc się z określonymi wierszami. Dzięki temu konkretne szczegóły implementacji są ukryte przed programistami. Po prostu używają tych widoków, zamiast konstruować złożone zdania SQL za każdym razem, gdy potrzebują dostępu do tabeli z możliwymi do przetłumaczenia informacjami.

Użyj kontekstu do filtrowania danych

Jak wspomniano w pierwszym przykładzie, rozważ użycie funkcji kontekstowych dostępnych w większości aparatów baz danych. Używaj ich do przechowywania informacji o języku użytkownika po zalogowaniu się do systemu, a następnie automatycznie filtruj wyniki w widokach, które zajmują się tłumaczeniem.

Automatyzacja

Nowoczesne systemy mogą mieć setki, a nawet tysiące stołów. Poświęć trochę czasu na zautomatyzowanie generowania widoków tłumaczenia, zamiast pisania zapytań jeden po drugim. Dojście do działającego skryptu może zająć trochę czasu, ale zawsze możesz utworzyć nowe widoki lub odtworzyć istniejące w mniej niż sekundę!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Różnica między SQL a NoSQL

  2. 11 typowych instrukcji SQL z podstawowymi przykładami

  3. Część 3 – Klienci, rozmowy telefoniczne i spotkania

  4. Testowanie warstwy ODBC

  5. Dlaczego korzystanie z testów jednostkowych to świetna inwestycja w architekturę wysokiej jakości