Stratégies efficaces pour la localisation dans .NET [fermé]


121

Je développe l'interface utilisateur pour une application .NET MVC qui nécessitera la localisation internationale de tout le contenu dans un proche avenir. Je connais très bien .NET en général, mais je n’ai jamais eu un projet qui nécessitait une attention aussi importante sur l’accessibilité internationale.

Le projet est initialement réalisé en anglais. Quelles mesures dois-je prendre à ce stade pour faciliter la mise en œuvre de la localisation à l'avenir?


2
Bonne question! Je suis confronté à une situation similaire et j'aimerais beaucoup que les experts interviennent à ce sujet.

Quelqu'un at-il de bonnes normes pour la gestion des ressources? La valeur localisée peut également inclure des images et pas seulement des chaînes.

1
S'agit-il d'une interface utilisateur WPF / silverlight ou de Winforms? D'après mon expérience (limitée), l'expérience WinForms en matière de localisation est beaucoup plus simple que WPF / Silverlight.
Pete Stensønes

1
Si vous finissez par le stockage de vos chaînes localisées dans la base de données, au lieu des fichiers de ressources, vous pouvez jeter un oeil à cette discussion: stackoverflow.com/questions/2458615/...

1
@Pete, @smartcaveman a déclaré qu'il "développait l'interface utilisateur pour une application .NET MVC", donc ...
BrunoSalvino

Réponses:


74

Vous développez l'application ASP.Net MVC, n'est-ce pas? D'autres réponses semblent être spécifiques aux applications de bureau. Laissez-moi capturer des choses communes:

Détection de la localisation

Il est très important que votre application détecte correctement les paramètres régionaux de l'utilisateur. Dans les applications de bureau, CultureInfo.CurrentCulture contient les paramètres régionaux de mise en forme préférés (ceux qui doivent être utilisés pour formater les nombres, les dates, les devises, etc.), tandis que CultureInfo.CurrentUICulture contient les paramètres régionaux préférés de l'interface utilisateur (ceux qui doivent être utilisés pour afficher les messages localisés). . Pour les applications Web, vous devez définir les deux cultures sur auto (pour détecter automatiquement les paramètres régionaux à partir de l'en-tête AcceptLanguage), sauf si vous souhaitez implémenter un workflow de détection de paramètres régionaux sophistiqué (par exemple, prendre en charge le changement de langue à la demande).

Externaliser des chaînes

Toutes les chaînes doivent provenir de ressources, c’est-à-dire des fichiers Resx. Dans Winforms App, il est facilement réalisable en définissant la propriété de formulaire Localizable sur true. Vous auriez également besoin d'externaliser (malheureusement) manuellement les chaînes provenant de vos modèles. C'est aussi relativement simple. Dans Asp.Net, vous devez tout externaliser manuellement ...

Layouts

Vous devez absolument permettre l'expansion des chaînes. Dans le monde Winforms, il est possible d’atteindre l’aide de TableLayoutPanel, qui doit être utilisé pour s’assurer que la disposition s’ajuste automatiquement pour prendre en charge un texte plus long. Dans le monde Web, vous avez un peu de chance. Vous devrez peut-être implémenter un mécanisme de localisation CSS - un moyen de modifier (remplacer) les définitions CSS. Cela permettrait aux gens de la localisation de modifier les problèmes de style à la demande. Assurez-vous que chaque élément HTML dans la page rendue a un identifiant unique - cela permettra de le cibler avec précision.

Problèmes spécifiques à la culture

Évitez d'utiliser des graphiques, des couleurs et des sons qui pourraient être spécifiques à la culture occidentale. Si vous en avez vraiment besoin, veuillez fournir un moyen de localisation. Évitez les graphiques sensibles à la direction (cela poserait un problème lorsque vous essayez de localiser en arabe ou en hébreu). En outre, ne supposez pas que le monde entier utilise les mêmes numéros (c.-à-d. Que ce n'est pas vrai pour l'arabe).

ToString () et Parse ()

Veillez à toujours transmettre CultureInfo lorsque vous appelez ToString (), sauf si cela n'est pas pris en charge. De cette façon, vous commentez vos intentions. Par exemple: si vous utilisez un nombre en interne et que, pour une raison quelconque, vous devez le convertir en chaîne, utilisez:

int i = 42;
var s = i.ToString(CultureInfo.InvariantCulture);

Pour les numéros à afficher pour l'utilisateur:

var s = i.ToString(CultureInfo.CurrentCulture); // formatting culture used

La même chose s'applique à Parse (), TryParse () et même à ParseExact () - certains bugs peuvent être introduits sans l'utilisation appropriée de CultureInfo. C’est parce qu’une pauvre âme de Microsoft, pleine de bonnes intentions, a décidé qu’il était judicieux de traiter CultureInfo.CurrentCulture comme celui par défaut (il serait utilisé si vous ne transmettez rien), après tout, quand quelqu'un utilise ToString ( ) il / elle veut l'afficher à l'utilisateur, non? Ce n’est pas toujours le cas - essayez par exemple de stocker le numéro de version de votre application dans une base de données, puis convertissez-le en instance de la classe Version. Bonne chance.

Dates et fuseaux horaires

Veillez à toujours stocker et instancier DateTime au format UTC (utilisez DateTime.UtcNow à la place de DateTime.Now). Convertissez-le en heure locale au format local en affichant:

DateTime now = DateTime.UtcNow;
var s = now.ToLocalTime().ToString(CultureInfo.CurrentCulture);

Si vous devez envoyer des e-mails avec la référence de temps dans le corps, veillez à inclure les informations de fuseau horaire - incluez l'offset UTC et la liste des villes:

DateTime someDate; // i.e. from database
var formattedDate = String.Format("{0} {1}", 
             someDate.ToLocaleTime().ToString(CultureInfo.CurrentCulture),
             TimeZoneInfo.Local.DisplayName);

Messages composés

Vous avez déjà été averti de ne pas concaténer des chaînes. Au lieu de cela, vous utiliseriez probablement String.Format () comme indiqué ci-dessus. Cependant, je dois dire que vous devriez minimiser l'utilisation de messages composés. C’est parce que les règles de grammaire cible sont assez souvent différentes et que les traducteurs peuvent donc avoir besoin non seulement de réorganiser la phrase (ceci sera résolu en utilisant des espaces réservés et String.Format ()), mais également de traduire la phrase entière de manière différente en fonction de ce qui sera substitué. Laisse moi te donner quelques exemples:

// Multiple plural forms
English: 4 viruses found.
Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów.

// Conjugation
English: Program encountered incorrect character | Application encountered incorrect character.
Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.

Autres problèmes de concaténation

La concaténation n'est pas limitée aux chaînes. Évitez de combiner les contrôles, par exemple:

Rappelez-moi à nouveau dans [zone de texte avec numéro] jours.

Cela devrait être repensé pour ressembler à ceci: Rappelez-moi à nouveau dans ce nombre de jours: [zone de texte].

Encodage des caractères et des polices

Toujours sauvegarder, transférer, quel que soit le texte au format Unicode (c.-à-d. UTF-8). Ne codez pas les polices en dur - La localisation devra peut-être les modifier et le mécanisme de secours par défaut des polices sera désactivé (dans le cas de Winforms). N'oubliez pas d'autoriser les caractères "étranges" dans la plupart des champs (nom d'utilisateur).

Tester

Vous aurez probablement besoin d'implémenter une pseudo traduction, c'est-à-dire créer des ressources pour la culture allemande et copier vos chaînes en anglais en ajoutant un préfixe et un suffixe. Vous pouvez également utiliser des espaces réservés pour détecter facilement les chaînes composées. La pseudo-traduction a pour but de détecter les problèmes de localisation tels que les chaînes codées en dur, les problèmes de mise en page et l'utilisation excessive de messages composés.


5
En ce qui concerne les messages composés - je devais faire des formes plurielles plusieurs fois. J'ai étendu String.Formatpour qu'il puisse prendre en charge cette syntaxe géniale: "There {0:was|were} {0} {0:virus|viruses} found."chaque langue peut charger ses propres règles, donc vous pouvez le faire. "Znaleziono {0} {0:wirusy|wirusów}." La source est sur GitHub: github.com/scottrippey/SmartFormat/wiki
Scott Rippey Le

2
@Scott Rippey Avez-vous remarqué que l'exemple polonais se lisait comme suit: "Znaleziono 4 wirusy. OR Znaleziono 5 wirusów." <- Le polonais, comme beaucoup d’autres langues, a plus de deux formes plurielles et les règles permettant de les distinguer peuvent également être complexes. Ici, je dois quitter le polonais puisque je ne le parle pas, mais dans ma langue, le pluriel pour 101 éléments est le même que pour 1 élément. Vous pouvez voir comment GNU gettext s’attaque à ce problème: gnu.org/s/hello/manual/gettext/Plural-forms.html
gregopet Le

2
@gregopet Mon exemple polonais était artificiel, parce que je ne le parle pas, mais c'est exactement ce que fait le projet SmartFormat. Voici un meilleur exemple: "{0} {0:plik|pliki|plików}". Le formateur a une règle polonaise qui détermine lequel des 3 formulaires à utiliser et détermine correctement les cas particuliers. Je travaille actuellement sur l'ajout de règles supplémentaires, l' gettextarticle s'avérera donc très utile, merci.
Scott Rippey

Pour la pseudo-localisation, j'ai construit un outil de pseudolocalisation en ligne gratuit sur pseudolocalize.com
JerSchneid

74

Quelques éléments de base à prendre en compte:

Externaliser toutes les ressources de chaîne

Toutes vos ressources doivent être contenues dans des fichiers externes pouvant être transférés pour la localisation. N'oubliez pas les messages d'erreur, si vous souhaitez également les localiser.

Prévoyez un espace suffisant pour l'expansion de la chaîne

Dans certaines langues, par exemple, les chaînes ont tendance à être 30% plus longues (comme le grec) par exemple. Veillez donc à concevoir votre interface utilisateur de manière à ce que les chaînes puissent se développer si nécessaire. Voici un exemple assez extrême pour le français:

Ok -> Accepter (français - extension de 400%)

Je recommanderais de faire une sorte de pseudo traduction comme point de départ ( http://en.wikipedia.org/wiki/Pseudolocalization ). Vous pouvez également traduire vos ressources via Google Translate ou Bing. Cela vous donnera une bonne indication de ce à quoi les traductions réelles ressembleront.

Attention au texte en images

Si vous utilisez des images dans votre application, assurez-vous qu'elles ne contiennent pas de texte, car elles ne peuvent évidemment pas être traduites.

Ne jamais coder les chemins d'accès aux dossiers Windows

Évident, mais je l'ai vu dans le passé. Par exemple, C:\Program Filesest traduit sur certaines versions internationales de Windows, par exemple C:\Programmesur un système d’exploitation allemand.

Évitez d'utiliser des termes spécifiques aux paramètres régionaux

Par exemple, si vous demandez à quelqu'un son "lycée" sur un formulaire, cela n'a pas beaucoup de sens en Europe occidentale.

Éviter de créer des chaînes via la concaténation de chaînes

Par exemple, cela semble inoffensif:

strWelcome = ReadExternalString("Welcome"); 
strMessage = strWelcome + ", " + UserName;

Cependant, l'ordre des mots sur le japonais, par exemple, serait différent, de sorte que cela risque de ne pas avoir de sens.

Paramètres heure / date

Assurez-vous toujours d’obtenir le format heure / date du système d’exploitation.


@ Jimmy C, comment construisez-vous des chaînes pour une cohérence logique indépendante du langage?
smartcaveman

14
@Smart faites quelque chose dans votre ressource comme "{0}, {1}" puis, lorsque vous la localisez, utilisez string.format et transmettez le message d'accueil et le nom d'utilisateur. De plus, cela vous donne l'avantage d'avoir la "vitesse actuelle {0} est {1} {2}" et vous pouvez passer en "Moteur", "50" et "MPH", et lorsque vous traduisez votre phrase, vous pouvez vous déplacer { 0} etc autour de là où ils ont un sens dans cette langue
taylonr

4
Bonne liste JimmyC. "Ne jamais coder en dur les chemins d'accès aux dossiers Windows" m'a rappelé "Toujours utiliser Path.Combine" au lieu de la concaténation de chaînes pour les chemins Windows.

@ Jimmy-C Excellente réponse!

1
Environment.GetFolderPath peut être utilisé pour obtenir des chemins d'accès valides vers des chemins d'accès communs tels que Mes documents sans dépendre du nom anglais de ces dossiers.
Crippledsmurf

24

Considérations spéciales pour les langues asiatiques

En plus de toutes les bonnes réponses déjà ici, quelques vigilance pour les langues asiatiques:

Attention aux différentes longueurs de texte

Le texte en chinois et en coréen a tendance à être beaucoup plus court que le texte anglais équivalent (étant donné que vous avez généralement besoin de moins de caractères en bloc pour écrire la même chose), de sorte qu'une page peut paraître vide en chinois mais pleine en allemand ... Ce que vous devez faire certains dimensionnement dynamique ici pour bien paraître.

Cependant, le texte japonais a tendance à être beaucoup plus long, voire plus long que le texte anglais équivalent en termes de nombre de caractères.

Méfiez-vous de la disposition de base et du look "glissé vers le haut"

Les caractères asiatiques sont généralement disposés sur la ligne de base , ce qui n'inclut pas les descendeurs (c.-à-d. La partie inférieure de y, g, q, j, etc.) Lorsque vous formatez un élément d'écran - généralement des boutons - avec du texte à l'intérieur, et si le texte n’est que des langues asiatiques (c’est-à-dire qu’il n’ya pas d’alphabets occidentaux), le texte semblera alors être décalé vers le haut.

Formatage des nombres et des unités numériques localisées

Traitez le formatage des nombres différemment. Différents pays asiatiques ont différentes façons de formater les nombres. Même avec les devises. Par exemple, en Asie de l’Est, 10 000 (wan) est une unité commune. En Inde, 100 000 (lakhs) sont courants.

Monnaies locales

Les monnaies de certains pays ont beaucoup de zéros et aucune virgule décimale (par exemple, le Japon, l'Indonésie, l'Italie), tandis que d'autres ont jusqu'à deux chiffres après la virgule.

Méfiez-vous des différents ordres de mots

L'ordre des mots peut ne pas toujours être le même. Il est préférable d’utiliser {0}, {1}, etc. dans le formatage de la chaîne plutôt que dans l’ordre des mots codé en dur si votre chaîne provient d’une combinaison de données différentes.

Utiliser le tri spécifique à l'environnement local

Le tri est différent selon les langues et les paramètres régionaux. Vous devez toujours vous fier au tri spécifique du système d'exploitation.

Soyez très prudent avec les caractères pleine largeur / demi-largeur

Attention aux différences entre les caractères "pleine largeur" ​​et "demi-largeur". Les crochets, la ponctuation, etc. peuvent avoir des versions "pleine largeur" ​​différentes de l'ASCII standard. Si vous effectuez une recherche ou un fractionnement de chaîne en fonction de ces lettres, vous devez d'abord convertir tous les symboles pleine largeur en équivalents demi-largeur.

Une période n'est pas un point ... une virgule n'est pas une virgule ...

Faites attention aux pièges de saisie de données - par exemple, en chinois, une période n'est pas un point ".". Une virgule est pleine largeur, pas ",". N'essayez pas de rechercher la ponctuation occidentale si l'utilisateur qui saisit les données peut activer accidentellement l'IME en langue asiatique.

Les numéros de téléphone

Ne supposez rien dans le formatage du numéro de téléphone. Il n'y a pas toujours d'indicatif régional, etc., et il peut être formaté différemment. Habituellement, définissez une chaîne de format par pays.

Ne présumez pas que les gens n'auront qu'un seul numéro de téléphone portable, un seul numéro de fax, etc. Ce n'est pas ainsi en Asie.

Adresses - plus dense que vous ne le pensez

Pour les adresses, n'assumez rien . Il ne peut pas toujours y avoir un code postal. Les codes postaux peuvent ne pas toujours être des chiffres. Un pays peut ne pas avoir de provinces / états. Un pays peut n'être qu'une grande ville (par exemple, Singapour). Pour certains pays asiatiques, la plus petite unité d'une maison peut être "Pièce X, Unité Y, Section Z, Étage A, Bloc B, Groupe C, Domaine D". En général, soyez très libéral quant au nombre de champs et au nombre de caractères autorisés dans les adresses.

Salutations

Les salutations ne se limitent pas à M., Mme etc. Bien que vous utilisiez probablement "M" et "F" pour le sexe sans danger, nous ne sommes pas encore si bizarres ...


1
Le dernier paragraphe m'a fait sourire.
BoltClock

Oh, nous (les gars), nous n'avions même pas encore commencé ... Nous n'avons pu que gratter la surface :) Si nous devions parler de problèmes spécifiques tels que l'assistance GB18030, notre publication serait trop longue pour que SO puisse la gérer :) Merci pour votre note en tout cas, j'ai raté pas mal d'éléments.
Paweł Dyda

À propos du dernier, je crois que le Royaume-Uni accepte maintenant officiellement «Autre» en tant que sexe. Pensez transgenres.
Bart Friederichs

11

Certaines étapes de base consistent à s’assurer que toute chaîne affichée à l’écran n’est pas un littéral dans votre code. Si vous utilisez Winforms, chaque formulaire aura une ressource d'interface utilisateur. Pour les dialogues, les rapports, etc., assurez-vous d’utiliser les fichiers de ressources du projet.

Donc, au lieu de "Échec de l'envoi" dans votre code, vous pourriez avoir quelque chose comme Ressources.UploadFailed

De cette façon, vous pouvez créer un nouveau fichier de ressources pour chaque langue que vous utilisez (et .Net vous aidera dans ce cas.) Et disposer de la chaîne localisée dans chaque fichier.

EDIT J'ai oublié de mentionner que lorsque vous faites votre interface utilisateur, assurez-vous de ne pas simplement fourrer des choses là-dedans. Selon les langues que vous localisez, l'immobilier peut poser problème. J'ai travaillé sur un projet dans lequel l'allemand et le portugais étaient les deux plus gros contrevenants à la croissance des chaînes. Si nous n'étions pas prudents en anglais, le français et l'italien exploseraient en allemand.


1
De mon expérience L10n, le russe est le pire des cas. Toutefois, dans WinForms, si vous utilisez correctement TableLayoutPanels, vous pouvez gérer la croissance de chaînes de manière élégante.
Paweł Dyda Le

Oui, mon expérience était limitée à 7 langues: anglais, allemand, portugais, italien, français, espagnol et japonais. Mais je peux voir la Russie d' être mauvais car ils ont tendance à avoir beaucoup de suffixes et préfixes
taylonr

9

Je vous suggère d'exécuter FXCop ou Visual Studio Code Analysis (ils sont pratiquement identiques) sur vos assemblys.

Ils sont efficaces pour détecter le code .NET qui n'utilise pas les surcharges orientées sur la culture appropriées, comme celui-ci: CA1305: Spécifiez IFormatProvider .

Je dois ajouter que ces outils sont également frustrants, car ils détectent généralement des millions de problèmes dans votre code. Néanmoins, même si vous ne respectez pas chacune des règles, vous devez en apprendre beaucoup.


S'agit-il de la valeur par défaut ou dois-je spécifier un paramètre pour rechercher des règles spécifiques à la mondialisation?
smartcaveman

@smartcaveman - c'est le défaut (hmm .. en fait, certaines personnes pensent qu'il y a beaucoup de règles par défaut dans ces outils :-)
Simon Mourier Le

7

En plus de la manière spécifique de charger des ressources, je voudrais vous assurer de commencer par tester une version pseudo-localisée. Sinon, vous ne remarquerez probablement pas les endroits où les considérations d'internationalisation ont été omises jusqu'à la fin.


Pour un moyen rapide et facile de pseudolocaliser, j'ai créé un outil en ligne gratuit sur pseudolocalize.com
JerSchneid

6

En plus de tous les autres conseils utiles, voici quelques-uns qui manquent:

Tenez compte du fait que certains pays utilisent plusieurs langues. Par exemple, au Canada, un utilisateur s'attendrait à pouvoir basculer facilement entre l'anglais et le français.

Si vous posez à l'utilisateur une question qui n'attend qu'une réponse à une lettre, ne vous attendez pas à ce qu'il appuie sur la touche "Y" pour dire Oui.

Soyez très conscient dans les procédures stockées que les dates dans la base de données SQL sont au format USA

Le placement de chaînes de texte dans la base de données vous permet d'ajouter ultérieurement des langues supplémentaires sans redéploiement.

Lorsque vous envoyez des fichiers texte écrits pour traduction, incluez toujours une description du contexte pour vous assurer que le traducteur sélectionne le mot correct. Par exemple, sans contexte, vous pourriez traduire "pitch:" en quelque chose qui a trait au son ou à un lieu sur lequel vous jouez au football

Les étiquettes d'adresse doivent toujours être converties. Province au Canada, État en Amérique, Comté au Royaume-Uni


5

Vous devez considérer:

  1. Routage multilingue

  2. Déplacer toutes les chaînes de caractères dans le fichier de ressources

Un exemple pour une propriété:

Modèle:

[Display(Name = <Resource for display name>.<field for this property>)]
[Required(ErrorMessage = <Resource for error message>.<field for this validate message>)]
public string TestProperty { get; set; }

Vue:

@Html.LabelFor(m=>m.TestProperty)
@Html.EditorFor(m => m.TestProperty)
@Html.ValidationMessageFor(m => m.TestProperty)

5

Voici quelque chose qui n'est pas mentionné dans le reste des réponses.

En fonction de la complexité de votre application et de sa localisation, il est vivement conseillé de mettre en œuvre un autre fournisseur de ressources et de conserver les ressources localisées dans une base de données. Avec le schéma de localisation ASP.NET par défaut, toutes les ressources sont conservées dans des fichiers RESX, qui:

  1. Sont une douleur dans le cul à éditer dans Visual Studio
  2. Limitez la distribution et la gestion des ressources localisées une fois l'application compilée / expédiée / exécutée.

En tant que cas d'utilisation possible, envisagez de fournir des modules linguistiques pour votre application et la possibilité d'importer et d'exporter des langues via l'interface utilisateur. Les fichiers RESX ne seraient pas utiles ici.

Dans de tels scénarios, un fournisseur de ressources alternatif est très utile. Plus d'informations sur la mise en œuvre peuvent être trouvées ici . Bien entendu, il s'agit d'un cas rare, plus courant dans les applications d'entreprise, mais toujours valable.


1
Merci d’avoir pris le temps de parcourir ces excellentes réponses tout en apportant quelque chose de nouveau et d’utile.
smartcaveman

+1; J'ai construit une application Web complète dans Asp.NET et nous avons fini par faire des traductions via la base de données. De nouvelles fonctionnalités ont souvent été ajoutées, mais comme nos traducteurs n'étaient pas des experts de la terminologie particulière utilisée, nous avons pu traiter rapidement les e-mails de clients en colère du type "Pourquoi utilisez-vous le mot Y pour X qui est manifestement faux?".
gregopet

3

Le plus important est de gérer le contenu dans différentes langues. J'ai moi-même développé quelques sites web et la gestion du contenu dans différentes langues est le plus gros défi.

J'utilise la base de données pour stocker les ressources / contenu. Cela me donne la possibilité d'ajouter le support linguistique que je souhaite. J'ai implémenté la logique du retour à la langue anglaise si une ressource dans une langue particulière n'est pas trouvée.

Vous pouvez ensuite utiliser un traducteur pour convertir la valeur en anglais dans n’importe quelle langue.


2

Résumé des éléments à prendre en compte dans l'internationalisation:

  • Toutes les informations doivent être internationalisées. Prenez en compte le fait que les graphiques peuvent contenir des informations que nous souhaitons internationaliser.

  • La taille des champs ou des chaînes dépend de la langue car cela peut nous causer des problèmes.

  • L'ordre des mots dépend de la langue que nous sommes, donc un ordre dans une langue sera le même dans une autre.

  • Nous devons tenir compte du fait que le format de la date changera d’une langue à l’autre


1

Faites le test de la dinde :

L’internationalisation des logiciels est difficile dans le meilleur des cas , mais j’ai toujours été étonnée de voir combien de fois un pays en particulier faisait l’objet de discussions sur des problèmes d’internationalisation: la Turquie ...

Si vous vous souciez de la localisation ou de l'internationalisation, forcez votre code à s'exécuter sous les paramètres régionaux turcs dès que raisonnablement possible . C'est un puissant indicateur pour votre code qui tourne dans la plupart des cultures et des lieux, mais pas du tout.

Si votre site / programme fonctionne correctement avec un client turc, vous pouvez être sûr qu'il fonctionnera sur la plupart des autres plates-formes.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.