2008-11-24 11 views
7

Eine vollständig internationalisierte Anwendung ist eine Notwendigkeit, wenn Sie weltweit verkaufen möchten. In Java verwenden wir Ressourcenbündel und das löst Dinge für statische Codeseiten.Wie internationalisieren Sie Text in der Datenbank?

Aber was machen Sie mit Text, der in der Datenbank gespeichert ist? Beginnend mit statischen Definitionen bis hin zu vom Benutzer modifizierbaren Objekten, endend mit vom Benutzer eingegebenen Daten.

Angenommen, Sie haben eine Datenbank, die von Benutzern mit unterschiedlichen Locales verwendet wird - wie gehen Sie damit um? Wie weit internationalisieren Sie? Wo zeichnest du die Linie? Welche Problemumgehung kann verhindern, dass Benutzer Text in einer Sprache erhalten, die sie nicht verstehen?

Antwort

6

Speichern Sie keinen systemgenerierten Text in der Datenbank. Speichern Sie stattdessen einen Code (z. B. eine Nachrichtennummer) und internationalisieren Sie ihn dann auf der GUI-Ebene. Stellen Sie sicher, dass der einzige Text, der direkt aus der Datenbank kommt, ein Text ist, den der Benutzer selbst eingibt. Stellen Sie sicher, dass Ihre Datenbank Unicode-Text akzeptiert.

0

Statische Daten sind am einfachsten Ich würde eine Übersetzungstabelle erstellen, also stellen Sie sich eine UserStatus-Tabelle mit einer StatusId, TranslationToken vor, dann hat die TranslationTable ein Token, eine Sprache und Text.

Oder similary Sie könnten einfach das Token für die Anwendung zur Verarbeitung mit Ihren Ressourcen-Dateien zurückgeben.

Wie für Benutzer Eingabedaten ist dies sehr viel komplexer. Sie müssen Unicode-Zeichen mindestens akzeptieren, aber dann wird die Frage Sortieren und Vergleichen. Sortierung ist die größte. Vieles, was Sie tun können, hängt von Ihrer Anwendung ab. Wenn Ihre Datenbank also nur eine einzige Sprache unterstützen muss (Stellen Sie sich vor, Ihre Anwendung wurde an Ihre Kunden verteilt), dann ist die Sortierung ein Problem, da Sie sie zur Installationszeit festlegen können.

Wenn Sie jedoch mehrere Sprachen in einer einzigen Datenbank unterstützen müssen, müssen Sie die Sortierung richtig handhaben. Der einzige Weg, den wir gefunden haben, um die Kollatierung im laufenden Betrieb zu ändern, bestand darin, sie innerhalb unserer Abfragen zu setzen, und das benötigte dynamische sql wurde erzeugt. In diesem Beispiel speichern Sie Russisch, Englisch und Polnisch in einem Feld in derselben Tabelle.

Wir haben nie etwas über die lateinischen und kyrillischen Sortierungen hinaus erforscht, aber ich stelle mir vor, dass die asiatischen Sprachen gleich funktionieren würden.

0

Wir verwenden XML-Datei für unser System. Die Datei enthält Schlüsselzuordnungen zu bestimmten Teilen unserer Module. Auf diese Weise können wir schnell XPath zum Abrufen von Informationen verwenden. Wir haben 1 Datei für jede Sprache (wir unterstützen momentan 2 Sprachen, aber das Hinzufügen einer Sprache ist sehr einfach, kopieren Sie einfach die Datei). Diese Lösung ist nicht perfekt, hat aber einige Vorteile:

  1. Nicht in der Datenbank.
  2. Kann von einer Person außerhalb der Programmierung bearbeitet werden.
  3. Einfach in mehreren Ansichten implementiert werden (wir haben WinForm und WebForm).
1

Welche Abhilfe können die Benutzer verhindern Text in einer Sprache empfangen sie nicht verstehen?

Das wäre nur ein Problem für Benutzer eingegebene Daten.Wenn Sie also verhindern möchten, dass andere Benutzer Inhalte in einer Sprache sehen, die sie möglicherweise nicht verstehen, speichern Sie den Gebietsschema-Code zusammen mit dem Inhalt und zeigen Sie diesen Inhalt nur für alle Personen mit derselben Gebietsschema/Benutzer-ausgewählten Sprache an.

Auf der anderen Seite könnten die Benutzer mehrere Sprachen kennen, also würde ich sie nicht daran hindern, Inhalte zu sehen, ich würde einfach einen Hinweis hinzufügen wie "Dieser Inhalt ist nicht in der Sprache Ihrer Wahl verfügbar, ..." und dann angezeigt der Inhalt in der verfügbaren Sprache. Auf diese Weise erhöhen Sie die Wahrscheinlichkeit, dass der Benutzer einen Inhalt erhält, den er verstehen kann.

2

Erstens, seien Sie sich der Einschränkungen sehr bewusst. Für von Benutzern erstellte Inhalte betrachten Sie Community-Übersetzungen (unberechenbar), maschinelle Übersetzungen (unzuverlässig) oder bezahlte menschliche Übersetzer (teuer!), Wenn Sie Dinge lokalisieren möchten, die Ihre Benutzer in Ihre Anwendung eingeben. Sie können Ihre Benutzer bitten, zwei Versionen anzugeben - eine für Ihre Standardkultur (Englisch?) Und eine für ihre lokalisierte Kultur, sodass Sie eine Fallback-Übersetzung für andere Benutzer bereitstellen können.

Zweitens, seien Sie bereit für einige extrem lange Datenbankmigrationen ... Wenn Sie vier Spalten Text in einer Excel-Tabelle haben, haben Sie plötzlich mit dem Einfügen jedes Wertes in Ihr Übersetzungssystem, Abrufen der lokalisierten ID, und speichert dann , dass in der Tabelle, die Sie tatsächlich importieren - und SELECT * geben Sie nur Phrasen-IDs, die Sie zurück in Strings auflösen müssen, indem Sie sie gegen Ihre Übersetzungstabellen lokalisieren.

Das heißt - Sie können viele der Lookup-Tabellen, Dropdown-Listen usw., die von der Datenbank in einem typischen Projekt gesteuert werden, lokalisieren. Andere Kommentare haben bereits das Speichern von StringId-Werten in der Datenbank erwähnt, die auf externe Ressourcendateien oder Tabellenkalkulationen verweisen. Wenn Sie jedoch ALLE lokalisierten Texte in der Datenbank neben den Daten selbst speichern möchten, ist dieser Ansatz möglicherweise hilfreich.

Wir haben eine Tabelle namens Phrase verwendet, die die ID und den Standardinhalt (Englisch) für jeden Text in Ihrer Anwendung enthält.

Ihre anderen Tabellen am Ende wie folgt aussehen:

CREATE TABLE ProductType (
    Id int primary key, 
    NamePhraseId int, -- link to the Phrase containing the name of this product type. 
    DescriptionPhraseId int 
) 

Erstellen Sie eine zweite Tabelle Kultur, die die spezifischen und neutrale Kulturen enthält unterstützen Sie. Für Bonuspunkte implementieren Sie diese Tabelle als selbstreferenziellen Baum (jeder Culture-Datensatz enthält eine nullbare ParentCultureCode-Referenz), sodass Sie von bestimmten Kulturen ("fr-CA" für kanadisches Französisch) auf neutrale Kulturen ("fr") zurückgreifen können wenn keine regionale Lokalisierung vorhanden), auf Ihre invariant/Standardkultur (in der Regel ‚en‘, weil es so weit gesprochen)

Ihre aktuellen Übersetzungen in einer LocalizedPhrase Tabelle, die wie folgt aussieht:

CREATE TABLE LocalizedPhrase (
    PhraseId int primary key, 
    CultureCode varchar(8) primary key, 
    Content nvarchar(255) -- the actual localized content 
) 
können Sie Erweitern Sie dieses Modell, wenn Sie männlich/weiblich-spezifische Lokalisierungen angeben möchten:

CREATE TABLE GenderedLocalizedPhrase (
    PhraseId int primary key, 
    CultureCode varchar(8) primary key, 
    GenderCode char(1) primary key, -- 'm', 'f' or '?' - links to Gender table 
    Content nvarchar(255) 
) 

Sie sollten dieses gesamte Tabellendiagramm im Speicher zwischenspeichern und Ihre Abfrage-/Join-Strategien entsprechend ändern. Das Zwischenspeichern der Lokalisierungen innerhalb von Phrasenklassen und das Überschreiben der ToString() - Methode für das Phrase-Objekt zur Überprüfung der aktuellen Thread-Kultur ist ein Ansatz. Wenn Sie das Zeug in Ihre Fragen versuchen und tun, werden Sie eine erhebliche Leistungskosten entstehen und jede Abfrage wird am Ende wie folgt suchen:

-- assume @MyCulture contains the culture code ('ca-FR') that we are looking for: 
SELECT 
    Product.Id, 
    Product.Name, 

    COALESCE(ProductStatusLocalizedPhrase.Content, ProductStatusPhrase.Content) as ProductStatus, 
    COALESCE(ProductTypeLocalizedPhrase.Content, ProductTypePhrase.Content) as ProductType, 
    FROM Product 

    INNER JOIN ProductStatus ON Product.StatusId = ProductStatus.Id 
    INNER JOIN Phrase as ProductStatusPhrase ON ProductStatus.NamePhraseId = Phrase.Id 
    LEFT JOIN LocalizedPhrase as ProductStatusLocalizedPhrase 
     ON ProductStatus.NamePhraseId = ProductStatusLocalizedPhrase.Id and CultureCode = @MyCulture 

    INNER JOIN ProductType ON Product.TypeId = ProductType.Id 
    INNER JOIN Phrase as ProductTypePhrase ON ProductType.NamePhraseId = Phrase.Id 
    LEFT JOIN LocalizedPhrase as ProductTypeLocalizedPhrase 
     ON ProductType.NamePhraseId = ProductTypeLocalizedPhrase.Id and CultureCode = @MyCulture 
1

Wir sind viel Text in unserer Datenbank zu ändern „zu sein Schlüssel: Standardtext "und dann den" Schlüssel "in unseren Übersetzungsdateien.Dies umfasst den gesamten Text, den der Kunde nicht in der Datenbank ändert (z. B. eine "Gutschrift"). Wenn der Kunde den Text ändert, kann er einfach den Schlüssel entfernen, damit er immer einen Wert erhält.

Unser System hat ein paar Tabellen, die Konfigurationsdaten enthalten, die die oben genannten Tabellen benötigen, die nur Text enthalten. Die Kundeneingabe ist kein Problem, wenn jeder Kunde nur eine einzige Sprache benötigt.

1

Angenommen, Sie haben eine Tabelle haben:

create table countries (
    country_id int primary key, 
    short_name text not null unique, 
    official_name text not null unique, 
    iso_code char(2) not null unique 
); 

insert into countries values (12, 'Algeria', 'The People''s Democratic Republic of Algeria' 'DZ'); 

Dann Sie eine Übersetzungstabelle zu erstellen:

create table countries_t (
    country_id int not null references countries(country_id), 
    short_name text not null, 
    official_name text not null, 
    locale varchar(5) not null, 

    primary key (country_id, locale) 
); 

insert into countries_t values 
(12, 'Algérie', 'la République algérienne démocratique et populaire', 'fr'), 
(12, 'Algerien', 'Demokratische Volksrepublik Algerien', 'de-DE'); 

eine Ansicht erstellen, die Daten zurück auf der Grundlage einer user - defined Session-Variablen. Im Folgenden finden Sie PostgreSQL-spezifische, aber Ihre Datenbank könnte benutzerdefinierte Session-Variablen, sonst Verwendung Temptabelle unterstützen:

create view countries_i18n as 
    select 
    a.country_id, 
    coalesce(c.short_name, b.short_name, a.short_name) as short_name, --default to countries.name if translation not found 
    coalesce(c.official_name, b.official_name, a.official_name) as official_name 
    countries.iso_code 
    from countries a 
    left join countries_t b on b.id = a.id and b.locale = current_setting('my_custom_guc.locale') 
    left join countries_t c on c.id = a.id and c.locale = left(current_setting('my_custom_guc.locale'), 2); --fall-back to 2-letter locale 

Abfrage die Tabelle in Deutsch als gesprochen in Deutschland:

SET my_custom_guc.language_code = 'de-DE'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algerien Demokratische ... 

Abfrage die Tabelle in kanadischem Französisch (zurück zu generic Französisch) fällt:

SET my_custom_guc.locale= 'fr-CA'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algérie  la République ... 

Abfrage der Tabelle auf Spanisch (es gibt keine Übersetzung, gibt English):

SET my_custom_guc.language_code = 'es'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algeria The People's D ... 
Verwandte Themen