Compare commits
3 Commits
b31644553e
...
4e1dfbdbcd
Author | SHA1 | Date |
---|---|---|
Miguel | 4e1dfbdbcd | |
Miguel | 689bd20333 | |
Miguel | f329d30a38 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
This texts are for an HMI industrial machine. Preserve the next words without translation: TILTER, ON, OFF, HMI, STOP, SD, USB, PLC, PID, FF, VFD, +A, +B, +CG, +D, +E, UPS, EMD, Pack, TableTop, Air, DCS, SKID, ALLEN BRADLEY, CPU, DANFOSS, Vetromeccanica, mBar, m/sec, mm, EEPROM, Ethernet, FIFO, PDF, RAM.
|
|
|
@ -0,0 +1 @@
|
||||||
|
from .funciones_base import *
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,51 @@
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# Diccionario de idiomas
|
||||||
|
IDIOMAS = {
|
||||||
|
0: ("Italian", "it-IT"),
|
||||||
|
1: ("English", "en-GB"),
|
||||||
|
2: ("Portuguese", "pt-PT"),
|
||||||
|
3: ("Spanish", "es-ES"),
|
||||||
|
4: ("Russian", "ru-RU"),
|
||||||
|
5: ("French", "fr-FR"),
|
||||||
|
6: ("German", "de-DE"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def mostrar_idiomas():
|
||||||
|
print("Selecciona el idioma de destino:")
|
||||||
|
for numero, (nombre, _) in IDIOMAS.items():
|
||||||
|
print(f"{numero}: {nombre}")
|
||||||
|
|
||||||
|
def transformar_texto(texto):
|
||||||
|
if pd.isnull(texto):
|
||||||
|
return texto
|
||||||
|
# Sustituir [[digits]] por <>
|
||||||
|
texto_transformado = re.sub(r'\[\[digits\]\]', '<>', texto)
|
||||||
|
# Sustituir cualquier <...> por <#>
|
||||||
|
texto_transformado = re.sub(r'<.*?>', '<#>', texto_transformado)
|
||||||
|
return texto_transformado
|
||||||
|
|
||||||
|
|
||||||
|
def save_dataframe_with_retries(df, output_path, max_retries=5, retry_delay=5):
|
||||||
|
"""
|
||||||
|
Guarda un DataFrame en un archivo Excel, reintentando si el archivo está en uso.
|
||||||
|
|
||||||
|
:param df: El DataFrame a guardar.
|
||||||
|
:param output_path: La ruta del archivo donde se guardará el DataFrame.
|
||||||
|
:param max_retries: El número máximo de reintentos en caso de error.
|
||||||
|
:param retry_delay: El tiempo de espera (en segundos) entre cada reintento.
|
||||||
|
"""
|
||||||
|
retries = 0
|
||||||
|
while retries < max_retries:
|
||||||
|
try:
|
||||||
|
df.to_excel(output_path, index=False)
|
||||||
|
print("Archivo guardado exitosamente.")
|
||||||
|
return
|
||||||
|
except PermissionError as e:
|
||||||
|
print(f"Error de permiso: {e}. Por favor cierre el archivo. Reintentando en {retry_delay} segundos...")
|
||||||
|
retries += 1
|
||||||
|
time.sleep(retry_delay)
|
||||||
|
|
||||||
|
print(f"No se pudo guardar el archivo después de {max_retries} intentos.")
|
|
@ -2,6 +2,7 @@ import pandas as pd
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from manejoArchivos import select_file
|
from manejoArchivos import select_file
|
||||||
|
import funciones_comunes
|
||||||
|
|
||||||
def es_columna_tipo_xxYY(columna):
|
def es_columna_tipo_xxYY(columna):
|
||||||
# Verificar si la columna es del tipo "xx-YY" usando una expresión regular
|
# Verificar si la columna es del tipo "xx-YY" usando una expresión regular
|
||||||
|
@ -22,7 +23,7 @@ def preprocesar_importacion(df_importacion):
|
||||||
# Sustituir en las demás columnas del tipo "xx-YY"
|
# Sustituir en las demás columnas del tipo "xx-YY"
|
||||||
for columna in df_importacion.columns:
|
for columna in df_importacion.columns:
|
||||||
if columna != 'it-IT' and es_columna_tipo_xxYY(columna):
|
if columna != 'it-IT' and es_columna_tipo_xxYY(columna):
|
||||||
df_importacion.at[index, columna] = sustituir_digitos(fila[columna])
|
df_importacion.at[index, columna] = funciones_comunes.transformar_texto(sustituir_digitos(fila[columna]))
|
||||||
|
|
||||||
# Guardar la clave sustituida
|
# Guardar la clave sustituida
|
||||||
df_importacion.at[index, 'it-IT'] = clave_sustituida
|
df_importacion.at[index, 'it-IT'] = clave_sustituida
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
from manejoArchivos import select_file
|
from manejoArchivos import select_file
|
||||||
|
import funciones_comunes
|
||||||
def transformar_texto(texto):
|
|
||||||
# Sustituir [[digits]] por <>
|
|
||||||
texto_transformado = re.sub(r'\[\[digits\]\]', '<>', texto)
|
|
||||||
# Sustituir cualquier <...> por <#>
|
|
||||||
texto_transformado = re.sub(r'<.*?>', '<#>', texto_transformado)
|
|
||||||
return texto_transformado
|
|
||||||
|
|
||||||
def exportar_para_traduccion(archivo_maestro):
|
def exportar_para_traduccion(archivo_maestro):
|
||||||
if not os.path.exists(archivo_maestro):
|
if not os.path.exists(archivo_maestro):
|
||||||
|
@ -25,10 +18,10 @@ def exportar_para_traduccion(archivo_maestro):
|
||||||
|
|
||||||
# Transformar las demás columnas
|
# Transformar las demás columnas
|
||||||
for columna in df_maestro.columns[1:]:
|
for columna in df_maestro.columns[1:]:
|
||||||
df_export[columna] = df_maestro[columna].apply(lambda x: transformar_texto(str(x)) if pd.notnull(x) else x)
|
df_export[columna] = df_maestro[columna].apply(lambda x: funciones_comunes.transformar_texto(str(x)) if pd.notnull(x) else x)
|
||||||
|
|
||||||
# Guardar el archivo exportado
|
# Guardar el archivo exportado
|
||||||
ruta_export = os.path.join(os.path.dirname(archivo_maestro), '.\\data\\2_master_export2translate.xlsx')
|
ruta_export = os.path.join(os.path.dirname(archivo_maestro), '2_master_export2translate.xlsx')
|
||||||
df_export.to_excel(ruta_export, index=False)
|
df_export.to_excel(ruta_export, index=False)
|
||||||
print(f"Archivo exportado para traducción: {ruta_export}")
|
print(f"Archivo exportado para traducción: {ruta_export}")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import funciones_comunes
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
from manejoArchivos import select_file
|
||||||
|
|
||||||
|
def configurar_logger(ruta_log):
|
||||||
|
os.makedirs(".\\data", exist_ok=True)
|
||||||
|
logger = logging.getLogger('.\\data\\importacion_logger')
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
fh = logging.FileHandler(ruta_log, encoding='utf-8')
|
||||||
|
fh.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter('%(asctime)s - %(message)s')
|
||||||
|
fh.setFormatter(formatter)
|
||||||
|
logger.addHandler(fh)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
def revertir_transformaciones(texto, digitos, secciones):
|
||||||
|
# Revertir <> a [[digits]]
|
||||||
|
for digito in digitos:
|
||||||
|
texto = texto.replace('<>', digito, 1)
|
||||||
|
# Revertir <#> a <...> usando las secciones originales
|
||||||
|
for seccion in secciones:
|
||||||
|
texto = texto.replace('<#>', f'<{seccion}>', 1)
|
||||||
|
return texto
|
||||||
|
|
||||||
|
def importar_traduccion(archivo_maestro, archivo_traduccion, target_lang_code, nivel_afinidad_minimo):
|
||||||
|
if not os.path.exists(archivo_maestro):
|
||||||
|
print("El archivo maestro no existe.")
|
||||||
|
return
|
||||||
|
|
||||||
|
master_col = target_lang_code
|
||||||
|
translated_col = f"{target_lang_code} Translated"
|
||||||
|
affinity_col = f"{target_lang_code} Affinity"
|
||||||
|
|
||||||
|
df_maestro = pd.read_excel(archivo_maestro)
|
||||||
|
df_traduccion = pd.read_excel(archivo_traduccion)
|
||||||
|
|
||||||
|
# Configurar el logger
|
||||||
|
directorio = os.path.dirname(archivo_maestro)
|
||||||
|
nombre_log = os.path.join(directorio, 'importacion_traduccion.log')
|
||||||
|
logger = configurar_logger(nombre_log)
|
||||||
|
|
||||||
|
# Iterar sobre las filas del archivo de traducción para actualizar el maestro
|
||||||
|
for index, fila in df_traduccion.iterrows():
|
||||||
|
clave = fila[df_maestro.columns[0]]
|
||||||
|
if clave in df_maestro[df_maestro.columns[0]].values:
|
||||||
|
# Comprobar afinidad y valores no nulos/vacíos
|
||||||
|
if fila[affinity_col] >= nivel_afinidad_minimo and pd.notnull(fila[translated_col]) and fila[translated_col] != "":
|
||||||
|
valor_traducido = fila[translated_col]
|
||||||
|
valor_original = df_maestro.loc[df_maestro[df_maestro.columns[0]] == clave, master_col].values[0]
|
||||||
|
|
||||||
|
if str(valor_original) != str(valor_traducido):
|
||||||
|
df_maestro.loc[df_maestro[df_maestro.columns[0]] == clave, master_col] = valor_traducido
|
||||||
|
logger.info(f'Fila {index}, Columna {translated_col}: "{valor_original}" actualizado a "{valor_traducido}"')
|
||||||
|
|
||||||
|
# Guardar el archivo maestro actualizado
|
||||||
|
funciones_comunes.save_dataframe_with_retries(df_maestro,output_path=archivo_maestro)
|
||||||
|
print(f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}. Detalles de los cambios en {nombre_log}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
archivo_maestro = ".\\data\\1_hmi_master_translates.xlsx"
|
||||||
|
archivo_traduccion = ".\\data\\3_master_export2translate_translated.xlsx"
|
||||||
|
|
||||||
|
nivel_afinidad_minimo = input("Introduce el nivel minimo de afinidad para importar (presiona Enter para usar el valor por defecto 0.5): ")
|
||||||
|
nivel_afinidad_minimo = float(nivel_afinidad_minimo) if nivel_afinidad_minimo else 0.5
|
||||||
|
|
||||||
|
funciones_comunes.mostrar_idiomas()
|
||||||
|
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
|
||||||
|
if seleccion_idioma not in funciones_comunes.IDIOMAS:
|
||||||
|
print("Selección inválida.")
|
||||||
|
else:
|
||||||
|
target_lang, target_lang_code = funciones_comunes.IDIOMAS[seleccion_idioma]
|
||||||
|
importar_traduccion(archivo_maestro, archivo_traduccion, target_lang_code, nivel_afinidad_minimo )
|
|
@ -5,50 +5,17 @@ import re
|
||||||
import logging
|
import logging
|
||||||
from openai_api_key import openai_api_key
|
from openai_api_key import openai_api_key
|
||||||
from google_api_key import google_api_key
|
from google_api_key import google_api_key
|
||||||
from x2_master_export2translate import transformar_texto
|
|
||||||
import ollama
|
import ollama
|
||||||
import json
|
import json
|
||||||
from google.cloud import translate_v2 as translate
|
from google.cloud import translate_v2 as translate
|
||||||
from google.oauth2 import service_account
|
from google.oauth2 import service_account
|
||||||
import html
|
import html
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import time
|
import funciones_comunes
|
||||||
|
|
||||||
openai_client = OpenAI(api_key=openai_api_key())
|
openai_client = OpenAI(api_key=openai_api_key())
|
||||||
GOOGLE_APPLICATION_CREDENTIALS = "translate-431108-020c17463fbb.json"
|
GOOGLE_APPLICATION_CREDENTIALS = "translate-431108-020c17463fbb.json"
|
||||||
|
|
||||||
# Diccionario de idiomas
|
|
||||||
IDIOMAS = {
|
|
||||||
1: ("English", "en-GB"),
|
|
||||||
2: ("Portuguese", "pt-PT"),
|
|
||||||
3: ("Spanish", "es-ES"),
|
|
||||||
4: ("Russian", "ru-RU"),
|
|
||||||
5: ("French", "fr-FR"),
|
|
||||||
6: ("German", "de-DE"),
|
|
||||||
}
|
|
||||||
|
|
||||||
def save_dataframe_with_retries(df, output_path, max_retries=5, retry_delay=5):
|
|
||||||
"""
|
|
||||||
Guarda un DataFrame en un archivo Excel, reintentando si el archivo está en uso.
|
|
||||||
|
|
||||||
:param df: El DataFrame a guardar.
|
|
||||||
:param output_path: La ruta del archivo donde se guardará el DataFrame.
|
|
||||||
:param max_retries: El número máximo de reintentos en caso de error.
|
|
||||||
:param retry_delay: El tiempo de espera (en segundos) entre cada reintento.
|
|
||||||
"""
|
|
||||||
retries = 0
|
|
||||||
while retries < max_retries:
|
|
||||||
try:
|
|
||||||
df.to_excel(output_path, index=False)
|
|
||||||
print("Archivo guardado exitosamente.")
|
|
||||||
return
|
|
||||||
except PermissionError as e:
|
|
||||||
print(f"Error de permiso: {e}. Reintentando en {retry_delay} segundos...")
|
|
||||||
retries += 1
|
|
||||||
time.sleep(retry_delay)
|
|
||||||
|
|
||||||
print(f"No se pudo guardar el archivo después de {max_retries} intentos.")
|
|
||||||
|
|
||||||
|
|
||||||
def configurar_logger():
|
def configurar_logger():
|
||||||
logger = logging.getLogger("translate_logger")
|
logger = logging.getLogger("translate_logger")
|
||||||
|
@ -87,12 +54,6 @@ def google_translate(text, target_language):
|
||||||
logger = configurar_logger()
|
logger = configurar_logger()
|
||||||
|
|
||||||
|
|
||||||
def mostrar_idiomas():
|
|
||||||
print("Selecciona el idioma de destino:")
|
|
||||||
for numero, (nombre, _) in IDIOMAS.items():
|
|
||||||
print(f"{numero}: {nombre}")
|
|
||||||
|
|
||||||
|
|
||||||
def read_system_prompt():
|
def read_system_prompt():
|
||||||
try:
|
try:
|
||||||
with open(".\\data\\system_prompt.txt", "r", encoding="utf-8") as file:
|
with open(".\\data\\system_prompt.txt", "r", encoding="utf-8") as file:
|
||||||
|
@ -169,7 +130,7 @@ def affinity_batch_openai(texts_dict):
|
||||||
"Evaluate the semantic similarity between the following table of pairs of texts in json format on a scale from 0 to 1. "
|
"Evaluate the semantic similarity between the following table of pairs of texts in json format on a scale from 0 to 1. "
|
||||||
"Return the similarity scores for every row in JSON format as a list of numbers, without any additional text or formatting."
|
"Return the similarity scores for every row in JSON format as a list of numbers, without any additional text or formatting."
|
||||||
)
|
)
|
||||||
original_list = [transformar_texto(key) for key in texts_dict.keys()]
|
original_list = [funciones_comunes.transformar_texto(key) for key in texts_dict.keys()]
|
||||||
re_translated_list = list(texts_dict.values())
|
re_translated_list = list(texts_dict.values())
|
||||||
|
|
||||||
request_payload = json.dumps(
|
request_payload = json.dumps(
|
||||||
|
@ -243,7 +204,7 @@ def main(file_path, target_lang_code, target_lang, traducir_todo, batch_size=10)
|
||||||
if source_translated_col in df.columns
|
if source_translated_col in df.columns
|
||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
processed_text = transformar_texto(source_text)
|
processed_text = funciones_comunes.transformar_texto(source_text)
|
||||||
|
|
||||||
if traducir_todo:
|
if traducir_todo:
|
||||||
if texto_requiere_traduccion(processed_text):
|
if texto_requiere_traduccion(processed_text):
|
||||||
|
@ -353,7 +314,7 @@ def main(file_path, target_lang_code, target_lang, traducir_todo, batch_size=10)
|
||||||
output_path = os.path.join(
|
output_path = os.path.join(
|
||||||
os.path.dirname(file_path), "3_master_export2translate_translated.xlsx"
|
os.path.dirname(file_path), "3_master_export2translate_translated.xlsx"
|
||||||
)
|
)
|
||||||
save_dataframe_with_retries(df,output_path=output_path)
|
funciones_comunes.save_dataframe_with_retries(df,output_path=output_path)
|
||||||
logger.info(f"Archivo traducido guardado en: {output_path}")
|
logger.info(f"Archivo traducido guardado en: {output_path}")
|
||||||
print(f"Archivo traducido guardado en: {output_path}")
|
print(f"Archivo traducido guardado en: {output_path}")
|
||||||
|
|
||||||
|
@ -362,12 +323,12 @@ if __name__ == "__main__":
|
||||||
batch_size = 20
|
batch_size = 20
|
||||||
translate_file = ".\\data\\2_master_export2translate.xlsx"
|
translate_file = ".\\data\\2_master_export2translate.xlsx"
|
||||||
|
|
||||||
mostrar_idiomas()
|
funciones_comunes.mostrar_idiomas()
|
||||||
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
|
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
|
||||||
if seleccion_idioma not in IDIOMAS:
|
if seleccion_idioma not in funciones_comunes.IDIOMAS:
|
||||||
print("Selección inválida.")
|
print("Selección inválida.")
|
||||||
else:
|
else:
|
||||||
target_lang, target_lang_code = IDIOMAS[seleccion_idioma]
|
target_lang, target_lang_code = funciones_comunes.IDIOMAS[seleccion_idioma]
|
||||||
traducir_todo = (
|
traducir_todo = (
|
||||||
input("¿Desea traducir todas las celdas (s/n)? ").strip().lower() == "s"
|
input("¿Desea traducir todas las celdas (s/n)? ").strip().lower() == "s"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
import funciones_comunes
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
from manejoArchivos import select_file
|
||||||
|
|
||||||
|
|
||||||
|
def configurar_logger(ruta_log):
|
||||||
|
os.makedirs(".\\data", exist_ok=True)
|
||||||
|
logger = logging.getLogger(".\\data\\importacion_logger")
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
fh = logging.FileHandler(ruta_log, encoding="utf-8")
|
||||||
|
fh.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter("%(asctime)s - %(message)s")
|
||||||
|
fh.setFormatter(formatter)
|
||||||
|
logger.addHandler(fh)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
|
def revertir_transformaciones(texto, digitos, secciones):
|
||||||
|
# Revertir <> a [[digits]]
|
||||||
|
for digito in digitos:
|
||||||
|
texto = texto.replace("<>", digito, 1)
|
||||||
|
# Revertir <#> a <...> usando las secciones originales
|
||||||
|
for seccion in secciones:
|
||||||
|
texto = texto.replace("<#>", f"<{seccion}>", 1)
|
||||||
|
return texto
|
||||||
|
|
||||||
|
|
||||||
|
def complete_emptys(archivo_maestro, target_lang_code, second_lang_code):
|
||||||
|
if not os.path.exists(archivo_maestro):
|
||||||
|
print("El archivo maestro no existe.")
|
||||||
|
return
|
||||||
|
|
||||||
|
master_col = target_lang_code
|
||||||
|
second_col = second_lang_code
|
||||||
|
|
||||||
|
df_maestro = pd.read_excel(archivo_maestro)
|
||||||
|
|
||||||
|
# Configurar el logger
|
||||||
|
directorio = os.path.dirname(archivo_maestro)
|
||||||
|
nombre_log = os.path.join(directorio, "importacion_traduccion.log")
|
||||||
|
logger = configurar_logger(nombre_log)
|
||||||
|
|
||||||
|
# Iterar sobre las filas del archivo de traducción para actualizar el maestro
|
||||||
|
for index, fila in df_maestro.iterrows():
|
||||||
|
clave = fila[df_maestro.columns[0]]
|
||||||
|
if fila[master_col] == "" or pd.isnull(fila[master_col]):
|
||||||
|
if pd.notnull(fila[second_col]) and fila[second_col] != "":
|
||||||
|
df_maestro.loc[
|
||||||
|
df_maestro[df_maestro.columns[0]] == clave, master_col
|
||||||
|
] = fila[second_col]
|
||||||
|
logger.info(
|
||||||
|
f'Fila {index}, Columna {master_col}: " actualizado a "{fila[second_col]}"'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
df_maestro.loc[
|
||||||
|
df_maestro[df_maestro.columns[0]] == clave, master_col
|
||||||
|
] = fila[df_maestro.columns[0]]
|
||||||
|
logger.info(
|
||||||
|
f'Fila {index}, Columna {master_col}: " actualizado a "{fila[df_maestro.columns[0]]}"'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Guardar el archivo maestro actualizado
|
||||||
|
funciones_comunes.save_dataframe_with_retries(
|
||||||
|
df_maestro, output_path=archivo_maestro
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Traducciones importadas y archivo maestro actualizado: {archivo_maestro}. Detalles de los cambios en {nombre_log}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
archivo_maestro = ".\\data\\1_hmi_master_translates.xlsx"
|
||||||
|
|
||||||
|
funciones_comunes.mostrar_idiomas()
|
||||||
|
seleccion_idioma = int(input("Introduce el número del idioma de destino: "))
|
||||||
|
if seleccion_idioma not in funciones_comunes.IDIOMAS:
|
||||||
|
print("Selección inválida.")
|
||||||
|
exit
|
||||||
|
seleccion_idioma_secundario = int(
|
||||||
|
input(
|
||||||
|
"Introduce el número del idioma de secundario para copiar desde en caso de vacios: "
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if seleccion_idioma_secundario not in funciones_comunes.IDIOMAS:
|
||||||
|
print("Selección inválida.")
|
||||||
|
exit
|
||||||
|
|
||||||
|
_, target_lang_code = funciones_comunes.IDIOMAS[seleccion_idioma]
|
||||||
|
_, second_lang_code = funciones_comunes.IDIOMAS[seleccion_idioma_secundario]
|
||||||
|
complete_emptys(archivo_maestro, target_lang_code, second_lang_code)
|
Loading…
Reference in New Issue