Migration des fichiers d'internationalisation

Drapeau mondial international

Pendant mon doctorat. projet de migration, Je considère la migration de plusieurs aspects de l'interface graphique : Visuel, Comportemental et Métier. Ces éléments sont les principaux. Lorsque parfaitement considéré, vous pouvez migrer le front-end de n'importe quelle application. Mais, il nous manque d'autres choses 😄 Par exemple, comment migrer les fichiers i18N ? Dans ce post, je vais présenter comment construire un outil de migration simple pour migrer les fichiers I18N de... .propriétés (utilisé par Java) à .json (utilisé par Angular).

Fichiers I18N

Tout d'abord, voyons notre source et notre cible. En tant que source, j'ai plusieurs .propriétés fichiers, y compris I18N pour un projet Java. Chaque fichier possède un ensemble de clé/valeur et des commentaires. Par exemple, le EditerMessages_fr.properties est le suivant :

##########
# Page : Editer
##########

pageTitle=Editer
classerDemande=Demandeur
classerDiffusion=Diffusion
classerPar=Classer Par

Et sa version arabe EditerMessages_ar.properties

#########
# Page : Éditeur
#########

pageTitle=تحرير
classerDemande=طلب
classerDiffusion=بث
classerPar=تصنيف حسب

En tant que cible, j'ai besoin un seul fichier JSON par langue. Ainsi, le fichier pour la traduction française ressemble à ceci :

{
    "EditerMessages" : {
        "classerDemande" : "Demande",
        "classerDiffusion" : "Diffusion",
        "classerPar" : "Classer Par",
        pageTitle" : "Editer", { "pageTitle" : "Editer".
    }
}

Et la version arabe :

{
    "EditerMessages" : {
        "classerDemande" : "طلب",
        "classerDiffusion" : "بث",
        "classerPar" : "تصنيف حسب",
        "pageTitle" : "تحرير"
    },
}

Pour effectuer la transformation à partir du .propriétés pour jsonnous utiliserons la méthode MDE. L'approche se divise en trois étapes principales :

  1. Conception d'un méta-modèle représentant l'internationalisation
  2. Création d'un importateur de fichiers de propriétés
  3. Création d'un exportateur JSON

Méta-modèle d'internationalisation

Les fichiers I18N sont simples. Ils consistent en un ensemble de clés/valeurs. Chaque valeur est associée à une langue. Et chaque fichier peut être associé à un espace de noms. Par exemple, dans l'exemple d'introduction, l'espace de nom de toutes les entrées est "EditerMessages". J'ai conçu un méta-modèle pour représenter tous ces concepts :

I18N Méta-modèle
Métamodèle I18N

Une fois que le méta-modèle est conçu, nous devons créer un importateur qui prend .propriétés en entrée et produit un modèle.

Importateur de propriétés

Pour produire un modèle, je cherche d'abord une .propriétés sans grand succès. J'ai donc décidé de créer mon propre analyseur. A partir d'un fichier correctement formaté, l'analyseur me fournit les entrées I18N. Ensuite, en itérant sur cette collection, je construis un modèle I18N.

Analyseur I18N

Pour implémenter l'analyseur syntaxique, j'ai utilisé le Projet PetitParser2. Ce projet vise à faciliter la création de nouveaux parsers. D'abord, j'ai téléchargé la dernière version de Mooseet j'ai installé PetitParser en utilisant la commande fournie dans le Readme du dépôt :

Metacello nouveau
    baseline : 'PetitParser2' ;
    repository : 'github://kursjan/petitparser2' ;
    charger.

Dans mon image Moose, j'ai créé un nouveau parser. Pour ce faire, j'ai étendu le PP2CompositeNode classe.

PP2CompositeNode << #CS18NPropertiesParser
    slots : { } ;
    package : 'Casino-18N-Model-PropertyImporter' (paquet : 'Casino-18N-Model-PropertyImporter')

Ensuite, j'ai défini les règles d'analyse. En utilisant PetitParser2, chaque règle correspond à une méthode.

D'abord, commencer est le point d'entrée.

début
    paires fin

paires analyse les entrées du fichier .propriétés des fichiers.

paires
    ^ comment optional starLazy, pair , ((newline / comment) star , pair ==> [ :token | token second ]) star , (newline/comment) star ==> [ :token |
      ((OrderedCollection with : token second)
           addAll : jeton troisième ;
           vous-même) asArray ]

La première partie de cette méthode (avant ==>) correspond à la règle analysée. La deuxième partie (après ==>), à la production.

La première partie essaie d'analyser un ou plusieurs éléments suivants commentaire. Ensuite, il analyse un paire suivi d'une liste de commentairenouvelle ligneet paire.

Cet analyseur n'est évidemment pas parfait et nécessiterait quelques améliorations. Néanmoins, il fonctionne pour notre contexte. La deuxième partie produit une collection (c'est-à-dire une liste) des paire.

Construire le modèle I18N

Maintenant que nous pouvons analyser un fichier, nous pouvons construire un modèle I18N. Pour ce faire, nous allons d'abord analyser chaque fichier .propriétés fichier. Pour chaque fichier, nous extrayons le langue et la espace de noms en fonction du nom du fichier. Ainsi, EditerMessages_fr.properties est le fichier pour le fr la langue et le EditerMessages espace de noms. Ensuite, pour chaque entrée de fichier, nous instancions une entrée dans notre modèle à l'intérieur de l'espace de noms et avec la langue correcte attachée.

importString : aString
    (parser parse : aString) do : [ :keyValue |
        (self model allWithType : CS18NEntry) asOrderedCollection
            détecter : [ :entry |
                "rechercher une clé existante dans le fichier"
                entrée nom clé = cléValeur clé ]
            ifOne : [ :entry |
                "Si une entrée existe déjà (dans une autre langue par exemple)"
                entry addValue : ((self createInModel : CS18NValue)
                    nom : keyValue valeur ;
                    langue : currentLanguage ;
                    vous-même) ]
            ifNone : [
                "Si aucune entrée n'existe"
                (self createInModel : CS18NEntry)
                    namespace : currentNamespace ;
                    key : ((self createInModel : CS18NKey)
                        nom : keyValue clé ;
                        vous-même) ;
                    addValue : ((self createInModel : CS18NValue)
                        nom : keyValue valeur ;
                        langue : currentLanguage ;
                        vous-même) ;
                    vous-même ] ]

Après avoir effectué l'importation, nous obtenons un modèle avec, pour chaque espace de nom, plusieurs entrées. Chaque entrée a une clé et plusieurs valeurs. Chaque valeur est attachée à la langue.

Exportateur JSON

Pour effectuer l'exportation JSON, j'ai utilisé la fonction Projet NeoJSON. NeoJSON permet de créer un encodeur personnalisé. Pour l'exportation, nous choisissons d'abord une langue. Ensuite, nous construisons un dictionnaire avec tous les espaces de noms :

rootDic := Dictionnaire new.
    (modèle allWithType : CS18NNamespace)
        select : [ :namespace | namespace namespace isNil ]
        thenDo : [ :namespace | rootDic at : namespace name put : namespace ].

Pour exporter un espace de nom (c'est-à-dire, a CS18NNamespace), je définis un encodeur personnalisé :

writter pour : CS18NNamespace customDo : [ :mapper |
    mapper encoder : [ :namespace | (self constructNamespace : namespace) asDictionary
        ]
    ].
constructNamespace : aNamespace
    | dic
    dic := Dictionnaire nouveau.
    aNamespace containables do : [ :containable |
        (containable isKindOf : CS18NNamespace)
            ifTrue : [ dic at : nom de containable put : (self constructNamespace : containable) ]
            ifFalse : [ "devrait être une CS18NEntry"
                dic at : containable key name put : (containable values detect : [ :value | value language = langue ] ifOne : [ :value | value name ] ifNone : [ '' ]) ] ].
    ^ dic

L'encodeur personnalisé consiste à convertir un Espace de nommage en un dictionnaire d'entrées avec les clés des entrées et leurs valeurs dans la langue sélectionnée.

Effectuer la migration

Une fois que mon importateur et mon exportateur sont conçus, je peux effectuer la migration. Pour ce faire, j'utilise un petit script. Il crée un modèle de l'I18N, importe plusieurs .propriétés dans le modèle, et exporte les entrées du fichier arabe dans un fichier JSON.

"Créer un modèle"
i18nModel := CS18NModel new.

"Créer un importateur"
importer := CS18NPropertiesImporter new.
importer model : i18nModel.

"Importer toutes les entrées du dossier "
('D:devmyProject' asFileReference allChildrenMatching : '*.properties') do : [ :fileRef |
    self record : fileRef absolutePath basename.
    importateur importFile : fileRef.
].

"exporter le fichier arabe JSON I18N".
D:/myFile-ar.json' asFileReference writeStreamDo : [ :stream |
    CS18NPropertiesExporter nouveau
        modèle : importateur modèle ;
        stream : stream ;
        language : ((importer model allWithType : CS18NLanguage) detect : [ :lang | lang shortName = 'ar' ]) ;
        export
]

Ressource

Le méta-modèle, l'importateur et l'exportateur sont disponibles gratuitement sur le site Web de la Commission européenne. GitHub.

Plus ...

Retour en haut