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 json
nous utiliserons la méthode MDE. L'approche se divise en trois étapes principales :
- Conception d'un méta-modèle représentant l'internationalisation
- Création d'un importateur de fichiers de propriétés
- 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 :

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 commentaire
, nouvelle ligne
et 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.