From 550519dbf20063230dcd5044d0903df69ddbc01a Mon Sep 17 00:00:00 2001 From: Ignacio Fagian <nachofagian@gmail.com> Date: Tue, 20 Nov 2018 23:23:39 -0300 Subject: [PATCH] Se agrega i18n en el backend, y se acomoda la parametrizacion desde el frontend --- Frontend Angular 4/package.json | 2 +- .../src/app/login/login.component.html | 10 +- .../src/app/login/login.component.ts | 17 +- Frontend Angular 4/src/app/shared/config.ts | 6 +- .../shared/services/authentication.service.ts | 8 +- .../src/app/shared/services/ghci.service.ts | 9 +- Servidor JEE/pom.xml | 5 + .../java/edu/proygrado/ejb/CommandsBean.java | 44 +++-- .../main/java/edu/proygrado/ejb/I18nEJB.java | 153 ++++++++++++++++++ .../servicios/ghci/WebSocketEndpoint.java | 5 +- 10 files changed, 235 insertions(+), 24 deletions(-) create mode 100644 Servidor JEE/src/main/java/edu/proygrado/ejb/I18nEJB.java diff --git a/Frontend Angular 4/package.json b/Frontend Angular 4/package.json index 4c50554..8c1b796 100755 --- a/Frontend Angular 4/package.json +++ b/Frontend Angular 4/package.json @@ -1,6 +1,6 @@ { "name": "matefun", - "version": "2.0.1", + "version": "2.0.2", "license": "MIT", "scripts": { "ng": "ng", diff --git a/Frontend Angular 4/src/app/login/login.component.html b/Frontend Angular 4/src/app/login/login.component.html index 53a6d14..25c3e4c 100755 --- a/Frontend Angular 4/src/app/login/login.component.html +++ b/Frontend Angular 4/src/app/login/login.component.html @@ -11,7 +11,15 @@ <div class="form-group"> <input type="password" [(ngModel)]=model.password (keyup.enter)=login() name="password" class="form-control input-underline input-lg" placeholder="Contraseña"> </div> - + <div class="form-group" style="margin-bottom: 0px;"> + <div ngbDropdown class="d-inline-block"> + <button class="btn btn-outline-secondary" id="input-lang" ngbDropdownToggle>{{model.language.name}}</button> + <div class="dropdown-menu" aria-labelledby="input-lang"> + <button class="dropdown-item" *ngFor="let lang of languages" (click)="model.language = lang" >{{lang.name}}</button> + </div> + </div> + + </div> </div> <a class="btn rounded-btn" style="background: transparent;color: white;cursor: pointer;width: 159px;margin-right: 3px;" (click)=login()> Iniciar Sesión </a> diff --git a/Frontend Angular 4/src/app/login/login.component.ts b/Frontend Angular 4/src/app/login/login.component.ts index c2a01b4..82f555e 100755 --- a/Frontend Angular 4/src/app/login/login.component.ts +++ b/Frontend Angular 4/src/app/login/login.component.ts @@ -12,12 +12,21 @@ import { AuthenticationService } from '../shared/services/authentication.service }) export class LoginComponent implements OnInit { - model: any = {}; + languages = [ + {id: 0, name: "Ingles", code: 'en'}, + {id: 1, name: "Español", code: 'es'} + ]; + + model: any = { + language: this.languages[0] + }; + loading = false; error = false; errorText = ""; returnUrl: string; + constructor( private route: ActivatedRoute, private router: Router, @@ -38,7 +47,8 @@ export class LoginComponent implements OnInit { this.loading = true; var that = this; - this.authenticationService.login(this.model.cedula, this.model.password) + + this.authenticationService.login(this.model.cedula, this.model.password, this.model.language.code) .subscribe( data => { //resetSession = true; @@ -54,7 +64,8 @@ export class LoginComponent implements OnInit { invitado(){ this.loading = true; - this.authenticationService.login("invitado", "invitado") + + this.authenticationService.login("invitado", "invitado", this.model.language.code) .subscribe( data => { this.router.navigate([this.returnUrl]); diff --git a/Frontend Angular 4/src/app/shared/config.ts b/Frontend Angular 4/src/app/shared/config.ts index 839412f..ff7baec 100755 --- a/Frontend Angular 4/src/app/shared/config.ts +++ b/Frontend Angular 4/src/app/shared/config.ts @@ -12,8 +12,10 @@ // export const SERVER = window.location.protocol + '//' + window.location.host;//'http://localhost:9090'; // export const GHCI_URL = window.location.protocol == 'http:'? 'ws://'+window.location.host+'/endpoint': 'wss://'+window.location.host+'/endpoint'; -// Google cloud platform +// Linux Nacho +// export const SERVER = 'http://192.168.129.3:9090'; +// export const GHCI_URL = 'ws://192.168.129.3:9090/endpoint'; +// Google cloud platform export const SERVER = 'http://35.199.110.129:9090'; export const GHCI_URL = 'ws://35.199.110.129:9090/endpoint'; - diff --git a/Frontend Angular 4/src/app/shared/services/authentication.service.ts b/Frontend Angular 4/src/app/shared/services/authentication.service.ts index 972b246..0a8655e 100755 --- a/Frontend Angular 4/src/app/shared/services/authentication.service.ts +++ b/Frontend Angular 4/src/app/shared/services/authentication.service.ts @@ -10,12 +10,13 @@ import { SERVER } from '../config'; export class AuthenticationService { constructor(private http: Http) { } - login(cedula: string, password: string) { + login(cedula: string, password: string, language: string) { let headers = new Headers({ 'Content-Type': 'application/json' }); let options = new RequestOptions({ headers: headers }); return this.http.post(SERVER+'/servicios/login', JSON.stringify({ "cedula": cedula, "password": password }),options) .map((response: Response) => { let user = response.json(); + user.language = language; sessionStorage.setItem('currentUser', JSON.stringify(user)); }); } @@ -33,6 +34,11 @@ export class AuthenticationService { return currentUser? currentUser.token: undefined; } + getLanguage() { + var currentUser = JSON.parse(sessionStorage.getItem('currentUser')); + return currentUser? currentUser.language: undefined; + } + setUserConfig(config){ var user = JSON.parse(sessionStorage.getItem('currentUser')); user.configuracion = config; diff --git a/Frontend Angular 4/src/app/shared/services/ghci.service.ts b/Frontend Angular 4/src/app/shared/services/ghci.service.ts index 31d1dc2..2442c58 100755 --- a/Frontend Angular 4/src/app/shared/services/ghci.service.ts +++ b/Frontend Angular 4/src/app/shared/services/ghci.service.ts @@ -36,7 +36,7 @@ export class GHCIService { constructor(private authService:AuthenticationService,private router: Router){ console.log("contructor ghci"); - this.conectarWS(GHCI_URL, authService.getUser().cedula, authService.getToken()); + this.conectarWS(GHCI_URL, authService.getUser().cedula, authService.getToken(), authService.getLanguage()); setInterval( this.checkConnection.bind(this), 5000); setInterval( this.doPing.bind(this), 30000); } @@ -79,9 +79,9 @@ export class GHCIService { consoleRef:any; - conectarWS(wsUrl, cedula, token){ + conectarWS(wsUrl, cedula, token, language){ if(cedula && token && (!this.connection || this.connection.readyState == WebSocket.CLOSED)){ - this.connection = new WebSocket(wsUrl+"/"+cedula+"/"+token); + this.connection = new WebSocket(wsUrl+"/"+cedula+"/"+token+"/"+language); this.connection.onopen = function(){ console.log('Conexión con web socket exitosa'); @@ -323,8 +323,9 @@ export class GHCIService { checkConnection(){ var usuario = this.authService.getUser(); var token = this.authService.getToken(); + var language = this.authService.getLanguage(); if(usuario && token && (!this.connection || this.connection.readyState == WebSocket.CLOSED)){ - this.conectarWS(GHCI_URL, usuario.cedula, token); + this.conectarWS(GHCI_URL, usuario.cedula, token, language); } } diff --git a/Servidor JEE/pom.xml b/Servidor JEE/pom.xml index 97286c4..5d04865 100644 --- a/Servidor JEE/pom.xml +++ b/Servidor JEE/pom.xml @@ -46,6 +46,11 @@ <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.0</version> + </dependency> </dependencies> diff --git a/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java b/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java index d675807..a944abd 100644 --- a/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java +++ b/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java @@ -16,6 +16,7 @@ import java.util.regex.Pattern; import java.util.Map; import javax.annotation.PreDestroy; import javax.ejb.Stateful; +import javax.ejb.EJB; import javax.inject.Inject; import javax.json.Json; import javax.json.JsonArray; @@ -46,6 +47,9 @@ public class CommandsBean { @Inject LoginEJB loginEJB; + + @EJB + I18nEJB i18nEJB; @Inject private ServletContext context; @@ -58,6 +62,8 @@ public class CommandsBean { private Process proceso; private BufferedWriter p_stdin; private CountDownLatch latch; + + private Map<String, String> i18n = null; private String nombrePrompt = ""; @@ -91,7 +97,7 @@ public class CommandsBean { System.out.print("Web socket finalizado"); return; } - + if (comandoJson.containsKey("ping")) { // System.out.println(comandoJson.getString("ping")); } else if (comandoJson.containsKey("comando")) { @@ -155,7 +161,7 @@ public class CommandsBean { } else { archivo = archivos.getArchivo(fileId); } - this.p_stdin.write("!load " + corregirNombreArchivo(archivo.getNombre())); + this.p_stdin.write(String.format("!%s ",this.i18n.get("load")) + corregirNombreArchivo(archivo.getNombre())); this.p_stdin.newLine(); this.p_stdin.flush(); @@ -212,6 +218,16 @@ public class CommandsBean { p.waitFor(); ConfiguracionDTO config = usuarioEJB.getConfiguracion(this.cedula); + String userLang = "en"; + + if (session.getUserProperties().containsKey("lang")) { + userLang = (String)session.getUserProperties().get("lang"); + } + + if (this.i18n == null) { + this.i18n = this.i18nEJB.getLanguage(context.getRealPath("/WEB-INF/classes/edu/proygrado/binarios/i18n"), userLang); + } + if (config != null && config.isArgumentoI() && config.isArgumentoF()) { System.out.println("restart con parametros -i -f"); this.builder = new ProcessBuilder( @@ -233,7 +249,8 @@ public class CommandsBean { this.latch = new CountDownLatch(2); Map<String, String> envs = this.builder.environment(); - envs.put("LANGUAGE", "en"); + + envs.put("LANGUAGE", userLang); this.proceso = this.builder.start(); this.p_stdin = new BufferedWriter(new OutputStreamWriter(proceso.getOutputStream())); @@ -293,6 +310,8 @@ public class CommandsBean { } private Thread outputStandardConsoleThread() { + final Map<String, String> _i18n = this.i18n; + Thread inputThread = new Thread(new Runnable() { @Override public void run() { @@ -301,13 +320,18 @@ public class CommandsBean { try { Scanner s = new Scanner(proceso.getInputStream()); latch.countDown(); - Pattern p = Pattern.compile("OUTFigure:(Figure:)*\\[\\]"); - Pattern p3d = Pattern.compile("OUT3D Figure:(3D Figure:)*\\[\\]"); + Pattern p = Pattern.compile(String.format("OUT%1$s:(%1$s:)*\\[\\]", _i18n.get("Figure"))); + Pattern p3d = Pattern.compile(String.format("OUT%1$s:(%1$s:)*\\[\\]",_i18n.get("3D Figure"))); + + String i18n_OUTFigure = String.format("OUT%s", _i18n.get("Figure")); + String i18n_OUT3D_Figure = String.format("OUT%s", _i18n.get("3D Figure")); + String i18n_OUTGraph = String.format("OUT%s", _i18n.get("Graph")); + ArrayList<String> animacion = new ArrayList<>(); while (s.hasNextLine()) { String result = s.nextLine(); - //System.out.println(result); - //System.out.println("&&&/////"); + // System.out.println(result); + // System.out.println("&&&/////"); if (nombrePrompt != "" && result.contains(nombrePrompt + ">")) { if (nombrePrompt.length() > 10) { nombrePrompt = nombrePrompt.substring(0, 7) + "..."; @@ -328,12 +352,12 @@ public class CommandsBean { result = result.substring(index + 6); animacion.add(result); respuestaJson = null; - } else if (result.equals("OUTFigure")) { + } else if (result.equals(i18n_OUTFigure)) { respuestaJson = Json.createObjectBuilder().add("tipo", "canvas") .add("resultado", animacion.get(0)).build(); animacion.clear(); - } else if (result.equals("OUT3D Figure")) { + } else if (result.equals(i18n_OUT3D_Figure)) { respuestaJson = Json.createObjectBuilder().add("tipo", "canvas3D") .add("resultado", animacion.get(0)).build(); @@ -362,7 +386,7 @@ public class CommandsBean { result = result.substring(index + 6); respuestaJson = Json.createObjectBuilder().add("tipo", "graph").add("resultado", result) .build(); - } else if (result.contains("OUTGraph")) { + } else if (result.contains(i18n_OUTGraph)) { } else { respuestaJson = Json.createObjectBuilder().add("tipo", "salida") diff --git a/Servidor JEE/src/main/java/edu/proygrado/ejb/I18nEJB.java b/Servidor JEE/src/main/java/edu/proygrado/ejb/I18nEJB.java new file mode 100644 index 0000000..ba1d0b0 --- /dev/null +++ b/Servidor JEE/src/main/java/edu/proygrado/ejb/I18nEJB.java @@ -0,0 +1,153 @@ +package edu.proygrado.ejb; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.io.Reader; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.PostConstruct; +import javax.ejb.ConcurrencyManagement; +import javax.ejb.ConcurrencyManagementType; +import javax.ejb.Singleton; +import javax.ejb.Startup; +import javax.ejb.LockType; +import javax.ejb.Lock; +import javax.inject.Inject; + +import org.apache.commons.text.StringEscapeUtils; + +@Singleton +@Startup +@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) +public class I18nEJB { + + + private Map<String, Map<String, String>> languages; + + @PostConstruct + private void Initialize(){ + languages = new HashMap<String, Map<String, String>>(); + } + + @Lock(LockType.READ) + public Map<String, String> getLanguage(String path, String lang) { + if (!this.languages.containsKey(lang)) { + try { + String filePath = String.format("%s/%s.po", path, lang); + this.languages.put(lang, LoadPoFile(filePath)); + } catch (FileNotFoundException e) { + System.out.println("File not found exception getLanguage for " + lang + " force loading default: en"); + + if (!this.languages.containsKey("en")) { + try { + String filePath = String.format("%s/%s.po", path, "en"); + this.languages.put("en", LoadPoFile(filePath)); + + return this.languages.get("en"); + } catch (FileNotFoundException e2) { + System.out.println("File not found exception getLanguage for default"); + } + } + } + } + + return this.languages.get(lang); + } + + private Map<String, String> LoadPoFile(String path) throws FileNotFoundException { + + Pattern LINE_PATTERN = Pattern.compile("^([\\w_\\[\\]]*)\\s*\\\"(.*)\\\"$"); + + Map<String, String> resources = new HashMap<String, String>(); + File file = new File(path); + + LineNumberReader reader = new LineNumberReader(new FileReader(file)); + + if (reader != null) { + String line = null; + String key = null; + String value = null; + + try { + + while ((line = reader.readLine()) != null) { + + if (line.startsWith("#")) { + + // Parsing PO file, comment skipped + + } else if (line.trim().length() == 0) { + + // Parsing PO file, whitespace line skipped + + } else { + Matcher matcher = LINE_PATTERN.matcher(line); + + if (matcher.matches()) { + String type = matcher.group(1); + String str = matcher.group(2); + + if ("msgid".equals(type)) { + + if ( key != null && value != null ) { + // Parsing PO file, key,value pair found [" + key + " => " + value + "]"); + resources.put(StringEscapeUtils.unescapeJava(key), StringEscapeUtils.unescapeJava(value)); + key = null; + value = null; + } + + key = str; + // Parsing PO file, msgid found [" + key + "]"); + } + else if ("msgstr".equals(type)) { + value = str; + // Parsing PO file, msgstr found [" + value + "]"); + } + else if ( type == null || type.length()==0 ) { + if ( value == null ) { + // Parsing PO file, addition to msgid found + key += str; + } + else { + // Parsing PO file, addition to msgstr found + value += str; + } + } + } else { + + // Parsing PO file, invalid syntax + } + } + } + + if ( key != null && value != null ) { + // Parsing PO file, key,value pair found [" + key + " => " + value + "]"); + resources.put(StringEscapeUtils.unescapeJava(key), StringEscapeUtils.unescapeJava(value)); + key = null; + value = null; + } + + reader.close(); + } catch (IOException e) { + + } + } + + return resources; + + } + +} + + + \ No newline at end of file diff --git a/Servidor JEE/src/main/java/edu/proygrado/servicios/ghci/WebSocketEndpoint.java b/Servidor JEE/src/main/java/edu/proygrado/servicios/ghci/WebSocketEndpoint.java index b8055ef..c6b79e6 100644 --- a/Servidor JEE/src/main/java/edu/proygrado/servicios/ghci/WebSocketEndpoint.java +++ b/Servidor JEE/src/main/java/edu/proygrado/servicios/ghci/WebSocketEndpoint.java @@ -24,7 +24,7 @@ import edu.proygrado.ejb.CommandsBean; * * @author gonzalo */ -@ServerEndpoint("/endpoint/{cedula}/{token}") +@ServerEndpoint("/endpoint/{cedula}/{token}/{language}") @Stateful public class WebSocketEndpoint { @@ -40,9 +40,10 @@ public class WebSocketEndpoint { } @OnOpen - public void onOpen(@PathParam("cedula") String cedula, @PathParam("token") String token, Session session) { + public void onOpen(@PathParam("cedula") String cedula, @PathParam("token") String token, @PathParam("language") String language, Session session) { System.out.println("Nueva conexion cedula:"+cedula+" sessionHashCode:" + session.hashCode()); try { + session.getUserProperties().put("lang", language); commandsBean.restartProcess(cedula, token, session); } catch (InterruptedException e) { // TODO Auto-generated catch block -- GitLab