diff --git a/conf/messages.en b/conf/messages.en index bb7a0f1..dbe668c 100644 --- a/conf/messages.en +++ b/conf/messages.en @@ -1,151 +1,3 @@ -<<<<<<< HEAD -#Perfiles -error.E0100= E0100: Se esperaba impactar sobre 1 solo registro y se impactaron {0}. -error.E0101= E0101: Perfil no encontrado. -error.E0102= E0102: Error al insertar el motivo de rechazo. -error.E0103= E0103: Algunos perfiles no se pudieron actualizar. -error.E0104= E0104: No se puede pasar del estado {0} al estado {1}. -error.E0105= E0105: Perfil inexistente: {0}. -error.E0106= E0106: No se puede actualizar un perfil en estado {0}. -error.E0107= E0107: Código debe ser único para cada perfil. -error.E0108= E0108: El genetista responsable debe ser siempre el mismo para {0}. -error.E0109= E0109: No existe el perfil. -error.E0110= E0110: El perfil seleccionado no tiene análisis cargados. -error.E0111= E0111: El perfil está asociado a otro perfil. No pueden agregarse más análisis. -error.E0112= E0112: No se pueden agregar análisis a un perfil con coincidencias confirmadas o pendientes. -error.E0113= E0113: No existe un perfil con el código: {0}. -error.E0114= E0114: Error en imagen. -error.E0115= E0115: El perfil {0} no es coincidente con la evidencia. -error.E0116= E0116: No se puede realizar la asociación, ya existe un perfil asociado. -error.E0117= E0117: No se pudo cambiar información del perfil. -error.E0118= E0118: El perfil {0} está participando de un escenario pendiente. -error.E0119= E0119: No se pudo agregar el perfil. -error.E0120= E0120: La cantidad de individuos en la población de interés ({0}) tiene que ser mayor a la cantidad de perfiles evaluados ({1}). -error.E0121= E0121: Error realizando traza de tipo {0} para el perfil {1}. -error.E0122= E0122: Error al importar el perfil {0}. -error.E0123= E0123: Valor de Alelo/s inválidos. -error.E0124= E0124: Alelos {0} duplicados. -error.E0125= E0125: El perfil {0} está asociado a un caso. -error.E0126= E0126: El perfil {0} está asociado a un pedigri activo o en construcción. -error.E0127= E0127: El perfil {0} no puede ser eliminado. -error.E0128= E0128: El perfil {0} está asociado a un escenario de pedigri pendiente. -error.E0129= E0129: El perfil {0} tiene matches de MPI/DVI pendientes. -error.E0130= E0130: El perfil {0} se encuentra en un pedigri con matches pendientes. -error.E0131= E0131: Error realizando traza de tipo {0} para el pedigree {1}. - - -#Pedigree -error.E0200= E0200: No existe usuario de GeneMapper: {0}. -error.E0201= E0201: El pedigrí no tiene asociada una base de frecuencias. -error.E0202= E0202: No se pueden agregar análisis a un perfil que está participando de un pedigrí activo o validado. -error.E0203= E0203: No se encontraron perfiles para importar. -error.E0204= E0204: El usuario no tiene permisos para confirmar la coincidencia. -error.E0205= E0205: No se puede desasociar el perfíl. -error.E0206= E0206: Hubo un error al guardar la agrupación. -error.E0207= E0207: Los perfiles {0} están asociados a pedigris activos o en construcción. -error.E0208= E0208: El perfil {0} está asociado a pedigris activos o en construcción. -error.E0209= E0209: Los perfiles {0} tienen coincidencias pendientes. -error.E0210= E0210: El perfil {0} tiene coincidencias pendientes. -error.E0211= E0211: El caso contiene pedigris activos. -error.E0212= E0212: El pédigri {0} no tiene personas desaparecidas/desconocidas. Configurando el pédigri en modo construcción para poder modificarlo. - -#Carga Masiva -error.E0301= E0301: Error importando el lote. -error.E0302= E0302: El formato de las líneas no coincide con la cabecera. -error.E0303= E0303: No se puede importar el perfil. -error.E0304= E0304: Cannnot detele this!!!!. -error.E0305= E0305: Faltan parámetros en la cabecera del archivo. -error.E0306= E0306: El perfil ''{0}'' está pendiente de aprobación en el lote #{1}. -error.E0307= E0307: La posicion de alguna de las variaciones no pertenece al rango. -error.E0308= E0308: Los rangos deben estar entre 1 y 16569. -error.E0309= E0309: El limite superior debe ser mayor al inferior del rango. -error.E0310= E0310: El perfil no puede tener mas de 4 rangos. -error.E0311= E0311: La variacion no pertenece a D-loop (1-576, 16024-16569). -error.E0312= E0312: El rango no pertenece a D-loop(1-576, 16024-16569). -error.E0313= E0313: La base no corresponde a la posicion : {0}. -error.E0314= E0314: Posicion {0} no existente. -error.E0315= E0315: El perfil ya tiene un análisis mitocondrial. -error.E0316= E0316: El Kit ''{0}'' No existe en la base de datos. -# -error.E0400= E0400: No se pueden cambiar los valores {0} por {1}. -error.E0500= E0500: Error al actualizar la configuración el motivo. - -#Configuraciones -error.E0600= E0600: No existe la categoría {0}. -error.E0610= E0610: No están configuradas las opciones estadísticas por defecto. -error.E0611= E0611: Rango invalido o inexistente en las Frecuencias Mínimas [{0}]. -error.E0612= E0612: Frecuencias mal formadas {0}. -error.E0630= E0630: Error inesperado en la base de datos. -error.E0640= E0640: Alias {0} duplicado. -error.E0641= E0641: No existe el usuario. -error.E0642= E0642: El usuario no tiene permisos para descartar la coincidencia. -error.E0643= E0643: El usuario {0} no tiene permisos para modificar el pedigrí. -error.E0644= E0644: El usuario {0} no tiene permisos para dar la baja. -error.E0645= E0645: El usuario no tiene permisos sobre el escenario. -error.E0646= E0646: No se puede pasar el usuario del estado {0} al estado {1}. -error.E0650= E0650: El responsable ''{0}'' no es un usuario genetista del sistema. -error.E0654= E0654: Existen usuarios asociados al rol. -error.E0660= E0660: Actualización de categoría incorrecta: se actualizaron {0} registros. -error.E0661= E0661: La categoría debe ser siempre la misma para {0}. -error.E0662= E0662: El asignado {0} no coincide. -error.E0663= E0663: La categoría del perfil {0} no coincide con {1}. -error.E0664= E0664: Id o nombre de categoría duplicado. -error.E0665= E0665: No se puede borrar la categoría porque esta relacionada con otras categorías. -error.E0666= E0666: No existe la categoría. -error.E0667= E0667: La categoría de {0} no puede asociarse. -error.E0670= E0670: Id o nombre de grupo duplicado. -error.E0671= E0671: No se puede borrar el grupo porque tiene categorías asociadas. -error.E0680= E0680: El marcador ''{0}'' no esta definido en el sistema. -error.E0681= E0681: El marcador ''{0}'' no pertenece al kit ''{1}''. -error.E0682= E0682: Marcadores {0} no contenidos en kit. -error.E0683= E0683: El análisis debe contener al menos {0} marcadores. -error.E0684= E0684: El análisis no puede contener marcadores con más de {0} alelos. -error.E0685= E0685: El análisis no puede contener más de {0} marcadores con trisomías. -error.E0686= E0686: Marcador {0} invalido. {1}. -error.E0687= E0687: No se puede eliminar el marcador {0} ya que está ligado a otro marcador. -error.E0688= E0688: Id de marcador: {0} duplicado. -error.E0689= E0689: Uno o mas Marcadores [{0}] no fue encontrado en el sistema. -error.E0690= E0690: El kit debe ser siempre el mismo para {0}. -error.E0691= E0691: El kit ''{0}'' no esta definido en el sistema. -error.E0692= E0692: No existe el kit {0}. -error.E0693= E0693: No se puede eliminar el marcador {0} ya que está incluido en algún kit. -error.E0694= E0694: Id de kit: {0} duplicado. -error.E0695= E0695: No se puede eliminar el kit {0} ya que se está utilizando en un perfil. -error.E0696= E0696: No se puede eliminar el kit {0} ya que se está utilizando en un lote de carga masiva. -error.E0697= E0697: El parámetro representativo no puede ser mayor a la cantidad de marcadores. -error.E0698= E0698: El analisis no contiene al menos 1 de los marcadores requeridos. - -#Interconexión -error.E0701= E0701: Error al actualizar la configuración de instancia inferior. -error.E0702= E0702: Error de conexión. -error.E0707= E0707: No se pudo conectar. -error.E0708= E0708: No se pudo guardar la url debido a que no tiene conectividad. -error.E0710= E0710: No se pudo notificar el estado a la instancia inferior. -error.E0720= E0720: La instancia superior ya guardó la conexión. -error.E0721= E0721: No está mapeada la categoría de la instancia superior. -error.E0722= E0722: No está configurada instancia superior. -error.E0723= E0723: Error de conexión con la instancia superior. -error.E0724= E0724: La instancia superior rechazo el perfil. -error.E0725= E0725: El perfil no pertenece a una categoría que se pueda replicar hacia la instancia superior. -error.E0726= E0726: No se puede confirmar ni descartar un match que no pertenece a la instancia actual. -error.E0727= E0727: El perfil no puede ser modificado porque es de otro laboratorio. -error.E0728= E0728: El perfil no puede ser modificado porque fue replicado a instancia superior. -error.E0729= E0729: El perfil no es editable. -error.E0730= E0730: Tiempo agotado. -# -error.E0802= E0802: La sesión es inválida o ha expirado. -error.E0803= E0803: Token inválido. -error.E0900= E0900: No existe el perfil {0}. -error.E0901= E0901: Nombre ya utilizado. -error.E0902= E0902: La coincidencia está siendo utilizada en un escenario pendiente. -error.E0930= E0930: La transición de {0} a {1} no es válida. -error.E0940= E0940: No existe código global. * -error.E0950= E0950: Ocurrió un error borrando las coincidencias. -error.E0951= E0951: No se pudo obtener imagen del perfil {0} debido a que el token es inválido o ha expirado. -error.E0960= E0960: Inconsistencia entre el tamaño de la cabecera [{0}] y el resto de las filas [{1}]. -error.E1000= E1000: Actualización no permitida. -error.E2000= E2000: No se encontraron perfiles con los filtros seleccionados. -======= #Profiles error.E0100= E0100: It was expected to hit with only one registry and hit {0}. error.E0101= E0101: Profile not found. @@ -180,7 +32,6 @@ error.E0129= E0129: Profile{0} has pending MPI/DVI matches. error.E0130= E0130: Profile {0} is in a pedigree with pending matches. error.E0131= E0131: Error making trace of type {0} for pedigree {1}. - #Pedigree error.E0200= E0200: There is no GeneMapper user:{0}. error.E0201= E0201: Pegigree has not a frequency base associated. @@ -194,6 +45,7 @@ error.E0208= E0208: Profile {0} is associated with active or under construction error.E0209= E0209: Profiles {0} have pending matches. error.E0210= E0210: Profile {0} has pending matches. error.E0211= E0211: The case contains active pedigrees. +error.E0212= E0212: The pedigree {0} do not has missing persons. Configuring pedigre en building mode. #Bulk upload error.E0301= E0301: Error importing the batch. @@ -206,12 +58,13 @@ error.E0307= E0307: The position of some of the variations does not belong to th error.E0308= E0308: Ranges must be between 1 and 16569. error.E0309= E0309: The upper limit must be greater than the range loweest. error.E0310= E0310: Profile cannot have more than 4 ranges. -error.E03011= E0311: Variation does not belong to D-loop (1-576, 16024-16569). -error.E03012= E0312: Range does not belong to D-loop(1-576, 16024-16569). +error.E0311= E0311: Variation does not belong to D-loop (1-576, 16024-16569). +error.E0312= E0312: Range does not belong to D-loop(1-576, 16024-16569). error.E0313= E0313: The base does not belong to the position : {0}. error.E0314= E0314: Position {0} not existent. error.E0315= E0315: The profile already has a mitochondrial analysis. -# +error.E0316= E0316: Kit ''{0}'' does no exists in database. + error.E0400= E0400: Values{0} cannot be changed for {1}. error.E0500= E0500: Error updating motive setup. @@ -258,6 +111,7 @@ error.E0694= E0694: Kit {0} Id duplicated. error.E0695= E0695: Kit {0} cannot be deleted beacause it is being used in a profile. error.E0696= E0696: Kit {0} cannot be deleted because it is being used in a bulk upload batch. error.E0697= E0697: The representative parameter cannot be greater than the number of loci. +error.E0698= E0698: Analysis does not have at least one required marker. #Interconnection error.E0701= E0701: Error updating inferior instance settings. @@ -265,7 +119,7 @@ error.E0702= E0702: Connection error. error.E0707= E0707: Could not be connected. error.E0708= E0708: The url could not be saved because there is not connectivity. error.E0710= E0710: The status to the inferior instance could not be notidfied. -error.E0720= E0720: The superior instance has already saved the connection. +error.E0720= E0720: The superior instance has already saved the connection. error.E0721= E0721: Category of the superior instance is not mapped. error.E0722= E0722: Superior instance is not setup. error.E0723= E0723: Connection error with the superior instance. @@ -276,7 +130,7 @@ error.E0727= E0727: Profile could not be updated because it belongs to another l error.E0728= E0728: Profile cannot be updated because it was replicated to a superior instance. error.E0729= E0729: The profile is not editable. error.E0730= E0730: Time out. -# + error.E0802= E0802: The session is invalid or has expired. error.E0803= E0803: Invalid token. error.E0900= E0900: Profile {0} does not exist. @@ -290,10 +144,8 @@ error.E0960= E0960: Inconsistency between the header size [{0}] and the rest of error.E1000= E1000: Update not allowed. error.E2000= E2000: No profiles found with the selected filters. - # Wait a moment start.wait= Wait a moment please #Inbox -inbox.theuserpending = The user: {0} is pending for approval. ->>>>>>> origin/Internationalization +inbox.theuserpending= The user: {0} is pending for approval. diff --git a/conf/messages.es b/conf/messages.es index 014e17e..1dd341d 100644 --- a/conf/messages.es +++ b/conf/messages.es @@ -32,7 +32,6 @@ error.E0129= E0129: El perfil {0} tiene matches de MPI/DVI pendientes. error.E0130= E0130: El perfil {0} se encuentra en un pedigri con matches pendientes. error.E0131= E0131: Error realizando traza de tipo {0} para el pedigree {1}. - #Pedigree error.E0200= E0200: No existe usuario de GeneMapper: {0}. error.E0201= E0201: El pedigrí no tiene asociada una base de frecuencias. @@ -65,9 +64,6 @@ error.E0313= E0313: La base no corresponde a la posicion : {0}. error.E0314= E0314: Posicion {0} no existente. error.E0315= E0315: El perfil ya tiene un análisis mitocondrial. error.E0316= E0316: El Kit ''{0}'' No existe en la base de datos. -# -error.E0400= E0400: No se pueden cambiar los valores {0} por {1}. -error.E0500= E0500: Error al actualizar la configuración el motivo. #Configuraciones error.E0600= E0600: No existe la categoría {0}. @@ -131,7 +127,10 @@ error.E0727= E0727: El perfil no puede ser modificado porque es de otro laborato error.E0728= E0728: El perfil no puede ser modificado porque fue replicado a instancia superior. error.E0729= E0729: El perfil no es editable. error.E0730= E0730: Tiempo agotado. -# + +# Miscelaneos +error.E0400= E0400: No se pueden cambiar los valores {0} por {1}. +error.E0500= E0500: Error al actualizar la configuración el motivo. error.E0802= E0802: La sesión es inválida o ha expirado. error.E0803= E0803: Token inválido. error.E0900= E0900: No existe el perfil {0}. @@ -148,5 +147,5 @@ error.E2000= E2000: No se encontraron perfiles con los filtros seleccionados. # Wait a moment start.wait= Espere un momemto por favor. -#Inbox -inbox.theuserpending = El usuario: {0} esta pendiente de aprobación +# Inbox +inbox.theuserpending= El usuario: {0} esta pendiente de aprobación diff --git a/utils/compare_messages.py b/utils/compare_messages.py new file mode 100644 index 0000000..4f89637 --- /dev/null +++ b/utils/compare_messages.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +# pylint: disable=missing-module-docstring + +import argparse +import sys +from typing import Mapping, Optional, Dict +from enum import Enum +import re + +# pylint: disable=missing-module-docstring +# pylint: disable=missing-function-docstring +# pylint: disable=bad-indentation + +def load_messages(file: str) -> Mapping: + line_pattern = r"(^[^=]+)=(.+)$" + result = {} + with open(file, "r", encoding="utf-8") as fin: + for line in fin: + line = line.strip() + if not line or line.startswith("#"): + continue + if m := re.match(line_pattern, line): + result[m.group(1)] = m.group(2) + return result + +class Action(Enum): + """A class to represent actions""" + COMPARE_SAME_LANG = 1 + COMPARE_DIFF_LANG = 2 + MERGE = 3 + +def validate_action(argument: str) -> Optional[Action]: + if argument.lower() == "merge": + return Action.MERGE + if argument.lower() == "compare-same-language": + return Action.COMPARE_SAME_LANG + if argument.lower() == "compare-diff-language": + return Action.COMPARE_DIFF_LANG + return None + +def compare_same_language(messages1:Mapping, messages2: Mapping) -> Dict: + keys1 = set(messages1.keys()) + keys2 = set(messages2.keys()) + results = { + "not_in_messages1" : [], + "not_in_messages2" : [], + "different_values" : [], + } + for k in keys1.union(keys2): + if k not in keys1: + results["not_in_messages1"].append(k) + if k not in keys2: + results["not_in_messages2"].append(k) + if k in keys1 and k in keys2: + value1 = messages1[k] + value2 = messages2[k] + if value1 != value2: + results["different_values"].append(k) + return results + +def compare_diff_language(messages1: Mapping, messages2: Mapping) -> Dict: + keys1 = set(messages1.keys()) + keys2 = set(messages2.keys()) + results = { + "not_in_messages1" : [], + "not_in_messages2" : [], + } + for k in keys1.union(keys2): + if k not in keys1: + results["not_in_messages1"].append(k) + if k not in keys2: + results["not_in_messages2"].append(k) + return results + +def merge(messages1:Mapping, messages2:Mapping) -> Mapping: + keys1 = set(messages1.keys()) + keys2 = set(messages2.keys()) + results = {} + for k in keys1.union(keys2): + if k not in keys1: + results[k] = messages2[k] + if k not in keys2: + results[k] = messages1[k] + if k in keys1 and k in keys2: + results[k] = messages1[k] + return results + +def print_merge_results(results:Mapping): + for k in sorted(results.keys()): + print(f"{k}={results[k]}") + +def print_compare_results(results:Mapping): + results_types = sorted(results.keys()) + titles = { + "not_in_messages1": "Keys not found in messages file 1:", + "not_in_messages2": "Keys not found in messages file 2:", + "different_values": "Keys with different values:" + } + for r_type in results_types: + print(titles[r_type]) + for line in sorted(results[r_type]): + print(f"[{line}]") + +def main(): + """ + Compare two json files of translations. + """ + parser = argparse.ArgumentParser( + description = "Json translations comparison tool", + usage = ( + 'python3 generate_topt_token.py --action ACTION ' + '--messages1 FILE --messages2 FILE\n\n' + 'Actions allowed are compare-same-language, compare-diff-language and merge.\n' + ' - compare-same-language is intended to use to compare two version of the \n' + ' same translation file in the same language. Checks for absences of keys \n' + ' in both files, and for differences of values.\n' + ' - compare-diff-language is intended to use to compare two version of the \n' + ' same translation file in different languages. Checks for absences of keys.\n' + ' assumes that values are always different\n' + ' - merge is intended to use to merge two version of the \n' + ' same translation file in the same language. Takes the keys from both files.\n' + ' taking file 1 precedence over file 2 when keys is present in both files.\n' + ) + ) + parser.add_argument( + '--action', + type=str, + required=True, + help='What to do with the json files' + ) + parser.add_argument( + '--messages1', + type=str, + required=True, + help='The path to the first messages file' + ) + parser.add_argument( + '--messages2', + type=str, + required=True, + help='The path to the second messages file' + ) + args = parser.parse_args() + action = validate_action(args.action) + if not action: + sys.exit("We need an action to do something.") + json1 = load_messages(args.messages1) + json2 = load_messages(args.messages2) + if not json1 or not json2: + sys.exit( + "Provided file is not a valid json file. " + "Please provide a valid json file." + ) + if action == Action.COMPARE_SAME_LANG: + print("Running compare same") + results = compare_same_language(json1, json2) + print_compare_results(results) + if action == Action.COMPARE_DIFF_LANG: + print("Running compare diff") + results = compare_diff_language(json1, json2) + print_compare_results(results) + if action == Action.MERGE: + print("Running merge") + results = merge(json1, json2) + print_merge_results(results) + +if __name__ == "__main__": + main() + +# Tests +# Requires pytest module. +# Run as: +# pytest utils/generate_totp_token.py +def test_compare_json_with_identical_data(): + messages1 = { + "key1": "value1" + } + messages2 = { + "key1" : "value1" + } + results = compare_same_language(messages1, messages2) + assert len(results["not_in_messages1"]) == 0 + assert len(results["not_in_messages2"]) == 0 + assert len(results["different_values"]) == 0 + +def test_compare_json_with_different_data_1(): + messages1 = { + "key1": "value1" + } + messages2 = { + "key1" : "value2", + } + results = compare_same_language(messages1, messages2) + assert len(results["not_in_messages1"]) == 0 + assert len(results["not_in_messages2"]) == 0 + assert len(results["different_values"]) == 1 + assert results["different_values"][0] == "key1" + +def test_compare_json_with_different_data_2(): + messages1 = { + "key1" : "value1", + } + messages2 = { + "key2" : "value2", + } + results = compare_same_language(messages1, messages2) + assert len(results["not_in_messages1"]) == 1 + assert results["not_in_messages1"][0] == "key2" + assert len(results["not_in_messages2"]) == 1 + assert results["not_in_messages2"][0] == "key1" + assert len(results["different_values"]) == 0 + +def test_merge_case_1(): + messages1 = { + "key1": "value1", + "key2": "value2", + "key4": "value4a" + } + messages2 = { + "key1": "value1", + "key3": "value3", + "key4": "value4b" + } + expected = { + "key1": "value1", + "key2": "value2", + "key3": "value3", + "key4": "value4a", + } + result = merge(messages1, messages2) + assert result == expected diff --git a/utils/compare_translation.py b/utils/compare_translation.py index 75133c2..1ba0f55 100644 --- a/utils/compare_translation.py +++ b/utils/compare_translation.py @@ -20,8 +20,8 @@ def load_json_file(file: str) -> Mapping: class Action(Enum): """A class to represent actions""" COMPARE_SAME_LANG = 1 - COMPARE_DIFF_LANG = 1 - MERGE = 2 + COMPARE_DIFF_LANG = 2 + MERGE = 3 def validate_action(argument: str) -> Optional[Action]: if argument.lower() == "merge":