Utilisateur:Botomatik/mise à jour de la liste des langues au format JSON/code
Apparence
Code python utilisant le framework Pywikibot (version core) pour mettre à jour MediaWiki:Gadget-translation editor.js/langues.json, qui est la liste utilisée par l’outil d’ajout de traductions. La liste des langues écrite en Lua est utilisée comme base pour la mise à jour. Le résultat de la mise à jour est écrit dans la page Utilisateur:Botomatik/mise à jour de la liste des langues au format JSON.
Actuellement, ce code est exécuté chaque mois.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import codecs
import re
import json
import datetime
import pywikibot
test = True # Pour tester le script (ne sauvegarde rien)
site = pywikibot.Site('fr', 'wiktionary')
page_lua = u'Module:langues/data'
page_sortie = u'Utilisateur:Botomatik/mise à jour de la liste des langues au format JSON'
page_json = u'MediaWiki:Gadget-translation editor.js/langues.json'
def sortkey(str):
key = str.lower()
key = re.sub( u'[àáâãäå]', u'a', key )
key = re.sub( u'[æ]', u'ae', key )
key = re.sub( u'[çćċč]', u'c', key )
key = re.sub( u'[ĉ]', u'cx', key )
key = re.sub( u'[èéêë]', u'e', key )
key = re.sub( u'[ĝ]', u'gx', key )
key = re.sub( u'[ĥ]', u'hx', key )
key = re.sub( u'[ìíîï]', u'i', key )
key = re.sub( u'[ĵ]', u'jx', key )
key = re.sub( u'[ñ]', u'n', key )
key = re.sub( u'[òóôõö]', u'o', key )
key = re.sub( u'[œ]', u'oe', key )
key = re.sub( u'[òóôõö]', u'o', key )
key = re.sub( u'[ŝ]', u'sx', key )
key = re.sub( u'[ùúûü]', u'u', key )
key = re.sub( u'[ŭ]', u'ux', key )
key = re.sub( u'[ýÿ]', u'y', key )
key = re.sub( u'[\'’)(]', u'', key )
key = re.sub( u'[-\/]', u' ', key )
return key
def tuple_to_json(my_list):
'''
Prend une liste de tuples et retourne un string au format json
* Utilise la fonction sortkey()
* Les strings de la liste ne doivent pas contenir de caractère "
'''
my_list = sorted(my_list, key=lambda elt: sortkey(elt[1]))
res = u'{'
for elt in my_list:
res += u'"' + elt[0] + u'":"' + elt[1] + u'",'
res = res[:len(res)-1] # on enlève la dernière virgule
res += u'}'
return res
def diff_listes_json(nouvelle_liste):
'''Prend deux listes de langues au format JSON et les compare
Le résultat de la comparaison est retourné sous forme de chaine
'''
liste_actuelle = pywikibot.Page(site, page_json).text
liste_actuelle = json.loads(liste_actuelle)
nouvelle_liste = json.loads(nouvelle_liste)
langues_retirees = []
langues_ajoutees = []
langues_modifiees = []
redirections_retirees = []
redirections_ajoutees = []
redirections_modifiees = []
# Ajouts/retraits dans le champs "redirections" ?
redirects_actu = None
redirects_new = None
if u'redirects' in liste_actuelle:
redirects_actu = liste_actuelle[u'redirects']
del liste_actuelle[u'redirects']
if u'redirects' in nouvelle_liste:
redirects_new = nouvelle_liste[u'redirects']
del nouvelle_liste[u'redirects']
for code in liste_actuelle:
if code not in nouvelle_liste:
langues_retirees.append(code + u' : ' + liste_actuelle[code])
if code in nouvelle_liste and liste_actuelle[code] != nouvelle_liste[code]:
langues_modifiees.append(code + u' : ' + liste_actuelle[code] + u' → ' + nouvelle_liste[code])
for code in nouvelle_liste:
if code not in liste_actuelle:
langues_ajoutees.append(code + u' : ' + nouvelle_liste[code])
for code in redirects_actu:
if code not in redirects_new:
redirections_retirees.append(code + u' : ' + redirects_actu[code])
if code in redirects_new and redirects_actu[code] != redirects_new[code]:
redirections_modifiees.append(code + u' : ' + redirects_actu[code] + u' → ' + redirects_new[code])
for code in redirects_new:
if code not in redirects_actu:
redirections_ajoutees.append(code + u' : ' + redirects_new[code])
if len(langues_ajoutees) == 0 and len(langues_retirees) == 0 and \
len(redirections_ajoutees) == 0 and len(redirections_retirees) == 0 \
and len(langues_modifiees) == 0 and len(redirections_modifiees):
return u''
res = u'%s langue(s) retirée(s) :\n* %s' \
% (len(langues_retirees), u'\n* '.join(langues_retirees))
res += u'\n\n%s langue(s) ajoutée(s) :\n* %s' \
% (len(langues_ajoutees), u'\n* '.join(langues_ajoutees))
res += u'\n\n%s langue(s) modifiée(s) :\n* %s' \
% (len(langues_modifiees), u'\n* '.join(langues_modifiees))
res += u'\n\n%s redirection(s) retirée(s) :\n* %s' \
% (len(redirections_retirees), u'\n* '.join(redirections_retirees))
res += u'\n\n%s redirection(s) ajoutée(s) :\n* %s' \
% (len(redirections_ajoutees), u'\n* '.join(redirections_ajoutees))
res += u'\n\n%s redirection(s) modifiée(s) :\n* %s' \
% (len(redirections_modifiees), u'\n* '.join(redirections_modifiees))
return res
def erreur(msg):
'''
écrit un message d'erreur sur la page de sortie
'''
Page_sortie = pywikibot.Page(site, page_sortie)
if test:
pywikibot.output(msg)
else:
sauvegarde(Page_sortie, msg, summary=u'Mise à jour non réalisée suite à une erreur')
def maj_liste():
Page_sortie = pywikibot.Page(site, page_sortie)
Page_lua = pywikibot.Page(site, page_lua)
# La liste des langues se trouve entre ces deux marqueurs
marqueur_debut_langues = u'-- Langues\n'
marqueur_fin_langues = u'-- Fin langues\n'
# La liste des redirections de langues se trouve entre ces deux marqueurs
marqueur_debut_redirections = u'-- Redirections de langues\n'
marqueur_fin_redirections = u'-- Fin redirections de langues\n'
try:
contenu = Page_lua.text
except pywikibot.NoPage:
erreur(u'Erreur lors de la \'\'\'mise à jour du %s\'\'\' : la page'
u'%s n\'existe pas.' % (date_actuelle, page_lua))
return
except pywikibot.IsRedirectPage:
erreur(u'Erreur lors de la \'\'\'mise à jour du %s\'\'\' : la page'
u'%s n\'existe pas.' % (date_actuelle, page_lua))
return
date_actuelle = datetime.datetime.utcnow()
date_actuelle = date_actuelle.strftime('%d/%m/%Y')
######################################
############## LANGUES ###############
######################################
# On extrait de la page la liste des langues en se basant sur
# les marqueurs précédemment déclarés
pos_marqueur_debut = contenu.find(marqueur_debut_langues)
pos_marqueur_fin = contenu.find(marqueur_fin_langues)
# On génère une erreur si ces marqueurs n'ont pas été trouvé
if pos_marqueur_debut == -1 or pos_marqueur_fin == -1:
erreur(u'\'\'\'Mise à jour du %s\'\'\' abandonnée : le format de la liste des langues en Lua'
u' n\'a pas été reconnu (au moins un des marqueurs %s ou %s manque)'
% (date_actuelle, marqueur_debut_langues, marqueur_fin_langues))
return
contenu_langues = contenu[pos_marqueur_debut:pos_marqueur_fin]
# On récupère toutes les lignes de la liste principale dans un tableau python
liste_langues = []
R = re.compile(ur'l\[\'([^\']+?)\'\] = \{ nom = \'([^\']+?)\'[, ][ }]')
for langue in R.findall(contenu_langues):
liste_langues.append(langue)
######################################
######################################
###### REDIRECTIONS DE LANGUES #######
######################################
# On extrait de la page la liste des redirections de langues
# en se basant sur les marqueurs précédemment déclarés
pos_marqueur_debut = contenu.find(marqueur_debut_redirections)
pos_marqueur_fin = contenu.find(marqueur_fin_redirections)
# On génère une erreur si ces marqueurs n'ont pas été trouvé
if pos_marqueur_debut == -1 or pos_marqueur_fin == -1:
erreur(u'\'\'\'Mise à jour du %s\'\'\' abandonnée : le format de la liste des redirections'
u' de langues en Lua n\'a pas été reconnu (au moins un des marqueurs %s ou %s manque)'
% (date_actuelle, marqueur_debut_redirections, marqueur_fin_redirections))
return
contenu_redirections = contenu[pos_marqueur_debut:pos_marqueur_fin]
liste_redirections_langues = []
R = re.compile(ur'l\[\'([^\']+?)\'\] = l\[\'([^\']+?)\'\]')
for langue in R.findall(contenu_redirections):
liste_redirections_langues.append(langue)
######################################
######################################
## MISE EN FORME JSON ET SAUVEGARDE ##
######################################
redirections_json = tuple_to_json(liste_redirections_langues)
langues_json = tuple_to_json(liste_langues)
contenu = langues_json[:len(langues_json)-1] + u',"redirects":' + redirections_json + u'}'
diff = diff_listes_json(contenu)
contenu = u'\'\'\'Mise à jour du %s\'\'\'\n\n' % date_actuelle + \
diff + u'\n\n=== Code à mettre dans la page [[%s]] ===\n\n' \
% page_json + contenu
if not Page_sortie.exists() or contenu != Page_sortie.text:
sauvegarde(Page_sortie, contenu, summary=u'Mise à jour automatique de la liste')
else:
sauvegarde(Page_sortie, u'\'\'\'Mise à jour du %s\'\'\' : aucun changement de la'
u'liste des langues depuis la dernière mise à jour' % date_actuelle,
summary=u'Aucune mise à jour nécessaire')
# adapté d'un script de JackPotte
def sauvegarde(PageCourante, Contenu, summary=None):
pagename = PageCourante.title()
modif = "o"
if test:
if PageCourante.exists() and len(Contenu) <= 5000:
pywikibot.showDiff(PageCourante.text, Contenu)
elif len(Contenu) > 5000:
pywikibot.output(u'Début du contenu :')
pywikibot.output(Contenu[:2000])
pywikibot.output(u'\nFin du contenu :')
pywikibot.output(Contenu[-1000:])
else:
pywikibot.output(Contenu)
modif = pywikibot.inputChoice(u"Sauvegarder ?",
["oui", "non"], ["o", "n"], default="n")
if modif == "o":
try:
PageCourante.put(Contenu, summary, minorEdit=False)
except pywikibot.IsRedirectPage:
pywikibot.output(u"IsRedirectPage en sauvegarde")
return
except pywikibot.LockedPage:
pywikibot.output(u"LockedPage en sauvegarde")
return
except pywikibot.EditConflict:
pywikibot.output(u"EditConflict en sauvegarde")
return
except pywikibot.ServerError:
pywikibot.output(u"ServerError en sauvegarde")
return
except pywikibot.BadTitle:
pywikibot.output(u"BadTitle en sauvegarde")
return
except AttributeError:
pywikibot.output(u"AttributeError en sauvegarde")
return
else:
pywikibot.output(u"Non modifié (pas de changement ou clic de l'utilisateur)")
if __name__ == '__main__':
try:
maj_liste()
finally:
pywikibot.stopme()