Schéma multilingue approprié, ou exagéré?

8

MISE À JOUR 2 : En fait, j'ai fini par utiliser cela, et c'est génial après quelques ajustements. Voici mon article sur sa conception actuelle et en action: http://tim.hithlonde.com/2013/lemon-schema-works/

Je crée une application Web et je veux qu'elle prenne en charge plusieurs langues. Cette structure a deux composantes:

  1. Connexion des paramètres régionaux ('anglais', 'Deutch', etc.) avec des termes, et ayant une pierre de rosette connectant les termes et les termes dans une langue spécifique.
  2. Regroupement des termes par page. Je ne veux pas dire, SELECT term1, term2, etc. à travers les 30+ termes dont je pourrais avoir besoin sur une page. Je veux demander par la page à laquelle ils sont connectés.

Voici ma structure de table proposée (notez que tous les id ont des relations / index entre eux pour faire des requêtes très efficaces):

Diagramme de schéma

  * locale
      * id
      * value //English, Deutch, etc//
  * terms
    * id
    * value //In English//
  * page 
    * id
    * value //Think add entry, menu//
  * page_group //group all terms to a page, for easy pulling//
    * id
    * page.id
    * term.id
  * rosetta
    * id
    * locale.id
    * term.id
    * value //french word for amount, description, etc//

Cela permettra des requêtes comme:

SELECT localization.value,
        terms.value
FROM localization
INNER JOIN terms ON terms.id=localization.termid
INNER JOIN page_group ON page_group.termid=localization.termid
INNER JOIN page ON page.id=page_group.pageid
INNER JOIN locale ON locale.id=localization.localeid
WHERE page.value='add_entry' AND locale.id=custlangid
ORDER BY terms.id

Je n'ai qu'à demander deux articles; l'ID de langue dont j'ai besoin et la page dont j'ai besoin. Il servira tous les termes, dans la langue spécifiée, qui font partie du groupe de termes de cette page.

Je pense que c'est une très bonne structure, mais j'aimerais avoir des commentaires.

MISE À JOUR : Pour clarifier, nous ne parlons que de la localisation des composants de l' interface utilisateur . (étiquettes, navigation, texte utile) Toutes les informations saisies par l'utilisateur seront stockées en unicode, pas dans ce schéma.

MISE À JOUR 2 : J'ai fini par l'utiliser, et c'est génial. Voici mon article sur son design actuel et en action: http://tim.hithlonde.com/2013/lemon-schema-works/

Tim Habersack
la source
1
Normalement (d'après ce que j'ai vu), la localisation se fait via des modèles du côté Web des choses. Quel genre de choses cherchez-vous à localiser du côté de la base de données?
Philᵀᴹ
Je veux localiser toutes les étiquettes, le menu de navigation et tout texte utile (avertissements, etc.) Mon raisonnement pour récupérer ceci à partir de db est, je ne veux pas cette logique dans mes modèles. Dans mes modèles, je veux avoir <?php echo $term['term_in_english'];?>Je m'efforce d'une solide approche MVC.
Tim Habersack

Réponses:

6

Nous avons fait beaucoup de cela, et les utilisateurs (administratifs) ont été autorisés à corriger les traductions en direct. (Vous voudrez peut-être toujours une couche de mise en cache, mais je ne veux absolument pas piloter cela avec une vraie base de données et non des fichiers de ressources - cela vous donne une tonne de puissance pour interroger et trouver des choses qui doivent être traduites, etc.). Je pense que votre schéma est probablement très bien, donc je vais juste vous transmettre quelques trucs que nous avons appris dans l'espoir qu'il soit utile.

Une chose que vous avez omise est les phrases avec des points d'insertion. Dans l'exemple ci-dessous, l'ordre est inversé et la langue est toujours l'anglais, mais cela pourrait très facilement être deux langues différentes - faites semblant que ce ne sont que deux langues qui mettent normalement les choses dans un ordre différent.

Hello, <username> you have <x> points!

You've got <x> points to spend, <username>!

Dans notre pre-.NET, nous avions une routine qui faisait l'insertion pour que les phrases ressemblent à ceci:

Hello, {0:username} you have {1:points} points!

You've got {1:points} points to spend, {0:username}!

Ce serait évidemment simplement utilisé dans votre code comme <%= String.Format(phrase, username, points); %>ou similaire

Ce qui a un peu aidé le traducteur. Mais .NET String.FOrmat ne prend pas en charge les commentaires dans la chaîne de format, malheureusement.

Comme vous le dites, vous ne voudriez pas gérer cela dans votre php avec une conscience locale ou des méta-phrases.

Donc, ce que nous avions était un tableau de phrases maître:

phraseid, anglais, informations supplémentaires

et une table localisée:

phraseid, localeid, traduction

Vous avez également supposé avec INNER JOINS que les versions localisées existaient - nous avions tendance à les laisser de côté jusqu'à ce qu'elles soient traduites, de sorte que la requête de votre part ne finirait par ne rien retourner au début (pas même la valeur par défaut)

Si une traduction n'existait pas, la nôtre par défaut était l'anglais, puis se repliait sur le code fourni (dans le cas où la base de données n'avait pas l'ID, et il était également clair d'après le code quelle phrase l'identifiant "TXT_LNG_WRNNG_INV_LOW" essayait réellement d'obtenir ) - donc l'équivalent de cette requête est ce que nous avons utilisé:

SELECT COALESCE(localized.translation, phrase.english, @fallback)
FROM DUAL
LEFT JOIN phrase
    ON phrase.phraseid = @phraseid
LEFT JOIN localized
    ON localized.phraseid = phrase.phraseid
    AND localized.localeid = @localeid

De toute évidence, vous pourriez obtenir toutes les choses en même temps en utilisant votre système de page.

Nous avions tendance à ne pas lier les choses à la page car elles étaient beaucoup réutilisées entre les pages (et pas seulement dans les fragments de page ou les contrôles), mais c'est très bien.

Dans le cas de nos applications natives Windows, nous avons utilisé la réflexion et un fichier de mappage du contrôle à la balise de traduction afin que la traduction ne nécessite pas de recompilation (dans les applications pré.NET, nous devions baliser les contrôles à l'aide de la balise ou d'une autre spéciale Propriétés). C'est probablement un peu plus problématique en PHP ou ASP.NET MVC, mais possible en ASP.NET où il existe un modèle de page côté serveur complet.

Pour les tests, vous pouvez évidemment rechercher très facilement les traductions manquantes. Pour trouver des endroits qui doivent être étiquetés, traduisez le dictionnaire de phrases entier en utilisant le latin-porc ou le klingon ou quelque chose comme remplacer chaque caractère non-espace par? - l'anglais devrait se démarquer et vous faire savoir que du texte brut nu s'est glissé dans votre HTML.

Cade Roux
la source
Merci pour ça! Je n'avais pas pensé aux points d'insertion. Je ne pense pas que mon application en aura réellement, mais il est bon de le garder à l'esprit. Merci également pour les commentaires sur le schéma. J'ai fait de la conception de base de données depuis un certain temps maintenant, mais sans un bon ensemble de pairs pour comparer les notes, cela me rend parfois incertain que je me dirige dans la bonne direction. :)
Tim Habersack
0

Les traductions sont généralement effectuées par des sociétés spécialisées externes. En tant que tel, ce serait compliqué de gérer le contenu traduit dans une base de données. Il vaut mieux les gérer dans des "bundles" ou des fichiers de propriétés via une sorte de fonctionnalité linguistique offerte par votre plateforme. Pour y parvenir, dans la base de données, il vous suffit de placer un mnémonique pour la chaîne. Ensuite, en fonction de la langue souhaitée, vous recherchez dans le bundle. par exemple.

Data:
Employee_Status = empl_status.active

language Bundles:
Employee.us:  
  empl_status.active=Active

Employee.es
  empl_status.active=<spanish translation goes here>

To get the localized content:
    String status = getLocalizedContent("Employee","empl_status.active", "us");
    String status = getLocalizedContent("Employee","empl_status.active", "es");
    String status = getLocalizedContent("Employee","empl_status.active");
srini.venigalla
la source
Je suis confus, car nous parlons de la même chose. Je vais construire l'équivalent de votre getLocalizedContent. Sauf au niveau du contrôleur, je demanderai tous les termes connectés à une page et la langue dans laquelle je le veux. Cette fonction appellera la requête que j'ai décrite ci-dessus et fera un peu de magie pour que je récupère un tableau associatif, où la clé sera le mnémonique, et la valeur sera le terme. Le nombre de termes d'interface utilisateur sera petit (<100), donc je ne vois pas que ce soit un problème de gestion dans une base de données. Je vais probablement créer une interface simple pour saisir les termes traduits et les pages de regroupement.
Tim Habersack
0

Créez simplement 3 tables

1.) Maître de langue (LangId, LangName)

2.) Maître des ressources (ResourceMasterId, TableId, ColumnId, ColumnName)

3.) Détails des ressources (ResourceMasterId, LangId, Value)

clé composite (ResourceMasterId, LangId) sur les détails de la ressource

Bhavik Jani
la source