Upload
xiaprojectsteam
View
322
Download
1
Embed Size (px)
DESCRIPTION
Tiyla is an infrastructure that enables management of software internationalization.- Multiplatform Libraries- Public Api- Support for multiple translation Crews- Support for Crowdsourcing- Community database of translations.. and more :]
Citation preview
Mobile Translation Systemin Crowdsourcing
Stefano ZingariniLuca Figoli
Our Projects
3
About Us
4
Chi siamoDal 1998 sviluppiamo so/ware per ges4one da4 su interfaccia Web Nel 2004 realizzata prima versione piaAaforma RAD e BPM -‐Dal 2009 introdoAa estensione Mobile Mul4piaAaforma ( , , , , )Reparto R&D con 20 dipenden4 tecnici ([email protected])
Il Prodo.o e le SoluzioniAAraverso gli strumen4 RAD e BPM offer4 dalla nostra piaAaforma possiamo realizzare velocemente applicazioni Mobile Mul4piaAaforma in grado di ges4re, da4, contenu4 e processi
Chi ha scelto al nostra tecnologia
About Us
5
ERP/Web
Enterprise/SaaS Apps
Intro: Roundup
6
La soluzione Tiyla: Goals & Examples
Internazionalizzazione del software oggi
Interazione Software / Utente
Software & i18n
7
Problematica non nuova ma attualissima
Internazionalizzazione
Localizzazione
“Progettazione per mercati diversi da quello di origine in cui si sviluppa”
“Le azioni volte a rendere il software fruibile per tali mercati”
Why i18n is a chance
8
Affinità culturali trasversali alle lingue
Raggiungere nuovi mercati / paesi non in crisi
11 persone su 12 nel mondo non conoscono l’Inglese
Psicologicamente rassicurantepagare per un’App da poter usare nella
propria lingua
Markets For All
9
Markets Mobile & Desktop
Multi-language and Multi Country Billing Support
With great opportunities... few problems
10
• Supporto nativo i18n diverso per ogni dispositivo•Gestione “script automatici” traduzioni attraverso un sw specifico: integrazione?•Distribuzione delle traduzioni in diversi formati (crossplatform)
Sviluppo
With great opportunities... few problems
11
• A chi rivolgersi per le traduzioni• Come gestire le collaborazioni• Come gestire la validazione della traduzione• Tenere sotto controllo il processo per più
lingue e più fornitori
Gestione
With great opportunities... few problems
12
• Ri-Pubblicazione dell’applicativo quando è disponibile una nuova lingua• Diversi store / versioni• Tempi di attesa• Possibilità di reject (per qualsiasi fantasioso
motivo)
Pubblicazione
Our Solution: Tiyla
13
Crossplatform
Process Control
Libraries
Api
Crowdsourcing
Collaboration
Tiyla Components
14
•Community•Applicazione•Crowdsourcing
Database
Api LibsGui Libs
Admin Manager
Crossplatform
API
AS
15
Tiyla Components Interaction
3 core of Tiyla solution
16
Trasparenza
Flessibilità
Crowdsourcing
Tiyla & Trasparenza
17
Esigenza di Traduzioni “Trasparenti”con Tiyla nel Backend
(es Software Enterprise)
• Supporto alla crew di traduzione aziendale o ai Partner in outsourcing tramite Tiyla
• Offerta traduzioni Tiyla Crew dai nostri partner• Disponibilità delle traduzioni di default “Community”• Generazione dei file per i18n multipiattaforma da
includere offline
Tiyla & Trasparenza
18
Le traduzioni sono generate all’atto della compilazione del progetto.
• Il sistema Tiyla è completamente nascosto all’utente finale
• L’azienda rimane proprietaria delle proprie traduzioni seguendone workflow & deploy
Plugin Ambiente di sviluppo
Tiyla Desktop
Tiyla & Trasparenza
19
Workflow “Standard”
• Registrazione App• Abilitazione Crew
20
Pannello di controllo Developer (OSx)
Tiyla & Trasparenza
21
Workflow “Standard”
• Registrazione App• Abilitazione Crew
• Traduzione• Da Partner• Da Community• Da Tiyla Crew
22
Pannello di controllo Traduzione (Win)
Tiyla & Trasparenza
23
Workflow “Standard”
• Registrazione App• Abilitazione Crew
• Traduzione• Da Partner• Da Community• Da Tiyla Crew
• File i18n generato da Plugin in IDE
• File i18n generato da Desktop Client da includere al progeOo
• Build
SELL
Tiyla & Flessibilità
• Inclusione di un set base di lingue• Update remoto (via Api) di nuove lingue per l’app
quando queste vengono validate• Possibilità di contribuire / usufruire del db
Community delle traduzioni
24
Si abilita l’update dell’i18n App Remoto
Tiyla & Flessibilità
• Possibilità di pubblicare l’applicazione partendo da una lingua base (abbattere i tempi di debutto sul mercato)
• Arricchire l’app “on the fly” senza bisogno di ripubblicarla
• Correggere le traduzioni al volo
25
Vantaggi: Tempo = Denaro
Tiyla & Flessibilità
26
Workflow Tiyla On The FLy
• Registrazione App• Abilitazione Crew
• Traduzione• Da Partner• Da Commuinity• Da Tiyla Crew
• File i18n generato da Plugin in IDE
• File i18n generato da Desktop Client da includere al progeOo
• Build
SELL• Correzioni• Nuove Lingue
Tiyla & Crowdsourcing
27
Perchè fa Fico?
Tiyla & Crowdsourcing
28
Innumerevoli casi di successo...
...anche nell’ambito delle traduzioni sw
Tiyla & Crowdsourcing
29
Tiyla & Crowdsourcing
30
Infrastruttura:
• Gestione di base Utenti • Traduzione degli utenti a partire da una lingua
certificata• Rating delle traduzioni• Conteggio attività dell’utente in Crowd Tiyla
– Rating degli utenti (individuare best & worst)– Possibilità di indire contest
VALUE
VALUE
VALUE
31
Into the Code
&
Tiyla & iOS (1/5)
32
Tiyla & iOS (2/5)
33
Tiyla & iOS (3/5)
34
Tiyla & iOS (4/5)
35
Tiyla & iOS (5/5)
36
iOS + MacOS: Supporto Nativo
37
• Prevede un file “Localizzato” aggiunto al bundle del progetto
• Automatico in base alla lingua impostata nel dispositivo
• API da utilizzare• Traduce anche i contenuti XIB Disegnati usando il
Designer
iOS + MacOS: Supporto Nativo
38
iOS + MacOS: Supporto Nativo
39
Aggiungo la lingua a Localizable.strings
Completo le traduzioni
iOS + MacOS: Supporto Nativo
40
NSLocalizedString(@”Hello World”,@”Label Description”);
iOS + MacOS: Supporto Nativo
41
• Richiede la ricompilazione: File (*) da mettere nel bundle
• Aggiungere un file per ogni nuova lingua da tradurre• Modificare tutti i file se cambia la lingua del
“programmatore”
Tiyla & iOS: .h
42
//! Profile management//! create new profile, or if exist and password match return TRUE-(BOOL)registerProfile:(NSString *)email password:(NSString *)password;//! verify your password-(BOOL)loginProfile:(NSString *)email password:(NSString *)password;//! remove profile-(BOOL)dropProfile:(NSString *)email password:(NSString *)password;//! return data for profile, if password is empty you will receive public informations-(NSDictionary *)getProfile:(NSString *)email password:(NSString *)password;//! Developer API://! create new Application, if application exists does do nothing-(NSString *)registerApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password;//! set KeyPairs App info to db-(BOOL)setApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password data:(NSDictionary *)data;//! Crew manage-(BOOL)linkCrew:(NSString *)emailCrew toApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password;-(BOOL)unlinkCrew:(NSString *)emailCrew toApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password;//! Translations Update Crew-(BOOL)setTApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password language:(NSString *)language data:(NSDictionary *)data;//! Translations Update Developer-(BOOL)setTRankApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password language:(NSString *)language data:(NSDictionary *)data;//! Translations Client-(NSDictionary *)getApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password data:(NSDictionary *)data;//! get Translation * work with shots *-(NSDictionary *)getTApp:(NSString *)bundleId email:(NSString *)email password:(NSString *)password language:(NSString *)language data:(NSDictionary *)data;
Tiyla & iOS: RAPI
43
+(NSMutableDictionary *)rapi:(NSURL *)url data:(NSDictionary *)data{ //! Data Variables NSString *jsonStringEncodedData=nil;! NSData *dataFromJson=nil;! NSData *dataCompressedFromJson=nil; NSMutableURLRequest *urlRequest =nil; NSData *replyFromServer=nil; NSString *replyFromServerString=nil; NSMutableDictionary *returnResponse=nil; //! JSON Engine SBJsonWriter *jsonWriter=[[SBJsonWriter alloc] init]; SBJsonParser *jsonParser=[[SBJsonParser alloc] init]; //! Some casts jsonStringEncodedData=[jsonWriter stringWithObject:data];! dataFromJson=[jsonStringEncodedData dataUsingEncoding:NSUTF8StringEncoding]; dataCompressedFromJson=[self gzipData:dataFromJson];!! //! Prepare Remote API! urlRequest =[NSMutableURLRequest requestWithURL:url];! [urlRequest setHTTPMethod:@"POST"]; [urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];! [urlRequest setHTTPBody:dataCompressedFromJson];! //! Reply RAPI! replyFromServer=[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];! replyFromServerString=[[NSString alloc] initWithData:replyFromServer encoding:NSASCIIStringEncoding];
//! JSON Return returnResponse=[jsonParser objectWithString:replyFromServerString]; return returnResponse;!}
Tiyla & iOS: GZIP
44
/** * GZip Compression helper for NSData */+(NSData *)gzipData:(NSData *)pUncompressedData { z_stream zlibStreamStruct; // ... int initError = deflateInit2(&zlibStreamStruct, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY); // ... NSMutableData *compressedData = [NSMutableData dataWithLength:[pUncompressedData length] * 1.01 + 12]; // ... do { // ... deflateStatus = deflate(&zlibStreamStruct, Z_FINISH); // ...! ! } while ( deflateStatus == Z_OK ); // ... deflateEnd(&zlibStreamStruct); // ... [compressedData setLength: zlibStreamStruct.total_out]; // ... return compressedData; }
Tiyla: Server IO GZIP
45
<?php// Imposto il Xpo di ritornoheader ("content-‐type: applicaXon/json");// Imposto il fuso orario (il server è in USA)date_default_Xmezone_set('UTC');// DEBUG: Memorizzo l'ora di partenza per calcolare il "peso" in fondo$start_Xme=microXme(TRUE);// ATTENZIONE: lo stream in ingresso POST deve essere compresso$fp=gzopen("php://input","r");// POST: leggo in input tuOo il JSON inviato dai client$data = gzread($fp,1024000); // 1MB in upload (decompresso...)// chiudo il descriOorefclose($fp);$fp=0;// genero un array associaXvo dal POST$data=json_decode($data,true);
?>
Tiyla & iOS: Libreria (1/5)
46
Tiyla & iOS: Libreria (2/5)
47
Tiyla & iOS: Libreria (3/5)
48
Tiyla & iOS: Libreria (4/5)
49
Tiyla & iOS: Libreria (5/5)
50
Tiyla & MacOS: Desktop Client
51
Tiyla & MacOS: Desktop Client
52
53
Into the Code
&
Android: Supporto Nativo
54
• Sistema di localizzazione integrato basato su file xml, presenti in diverse folder con suffisso differente a seconda della lingua (values, values-it, values-fr)
• Il file chiamato strings.xml è semplicemente un elenco di righe chiave – valore dove il valore è appunto la stringa tradotta.
• Da codice per recuperare la stringa corrente getString(R.string.key)
• Se si vuole modificare o aggiungere una nuova lingua bisogna ricompilare il programma producendo il nuovo apk e pubblicare l’aggiornamento sul market
Tiyla & Android: Presentazione
55
Tiyla & Android: API
56
//! Profile management//! create new profile, or if exist and password match return TRUEsta7c public boolean registerProfile(String email, String password)//! verify your passwordsta7c public boolean loginProfile(String email, String password)//! remove profilesta7c public boolean dropProfile(String email, String password)//! return data for profile, if password is empty you will receive public informaXonssta7c public JSONObject getProfile(String email, String password)//! Developer API://! create new ApplicaXon, if applicaXon exists does do nothingsta7c public String registerApp(String bundleId, String email, String password)//! set KeyPairs App info to dbsta7c public boolean setApp(String bundleId, String email, String password, JSONObject data)//! Crew managesta7c public boolean linkCrew(String emailCrew, String bundleId, String email, String password)sta7c public boolean unlinkCrew(String emailCrew, String bundleId, String email, String password)//! TranslaXons Update Crewsta7c public boolean setTApp(String bundleId, String email, String password, String language, JSONObject data)//! TranslaXons Update Developersta7c public boolean setTRankApp(String bundleId, String email, String password, String language, JSONObject data)//! TranslaXons Clientsta7c public JSONObject getApp(String bundleId, String email, String password, JSONObject data)//! get TranslaXon * work with shots *sta7c public JSONObject getTApp(String bundleId, String email, String password, String language, JSONObject data);
Tiyla & Android: RAPI
57
//Inizialmente comprimo i daX in formato gzip uXlizzando //l'oggeOo GZIPOutputStreambyte[] compressedData = Library.compressData(dataS.getBytes());
//-‐-‐-‐//Apro una HOpURLConnecXon verso il serverconnecXon = (HOpURLConnecXon) new URL(url).openConnec8on();//-‐-‐//Imposto il parametro "Accept-‐Encoding" "deflate" per ricevere i daX in formato compresso connecXon.addRequestProperty("Accept-‐Encoding", "deflate");connecXon.setRequestProperty("Content-‐Type","applicaXon/json");
//Invio i daXconnecXon.getOutputStream().write(compressedData);
//Ricevo i daX dal serverInputStream input = connecXon.getInputStream();String contentEncoding = connecXon.getContentEncoding(); BufferedInputStream inputB = new BufferedInputStream(input, 10000);
//-‐-‐-‐while ((nRead = inputB.read(data, 0, data.length)) != -‐1) {byteAOSB.write(data, 0, nRead);}
//-‐-‐ //ScompaOo i daX dal serverreceived_result = new String(Library.decompressData(received_result.getBytes()));//-‐-‐
Tiyla & BlackBerry
58
•Java•Eclipse Sdk
Tiyla & Nokia
59
QT
60
Into the Code
&
Windows & WP7: Supporto Nativo
61
• Sistema di localizzazione integrato basato su file di risorse (resx), con nomi organizzati gerarchicamente a partire dal file della lingua di default. Ad esempio myRes.resx contiene le informazioni in lingua di default, mentre una eventuale traduzione in francese standard si ottiene aggiungendo il file myRes.fr.resx al progetto
• Un file di risorse è composto da una serie di coppie chiave-valore. Tutti i file dovrebbero avere le stesse chiavi a cui corrispondono le versioni in lingua degli stessi testi
• Le interfacce utente invocano le stringhe contenute nei file di risorse tramite la loro chiave, usando l’operatore binding
• Se si vuole modificare o aggiungere una nuova lingua bisogna ricompilare il programma producendo il nuovo xap e pubblicare l’aggiornamento sul market
Tiyla & WP7: Presentazione
62
Windows & WP7: Supporto Nativo
63
• Le chiamate al server in WP7 sono gestite in modo asincrono.
• La libreria mette a disposizione una serie di eventi che vengono generati quando la chiamata è stata completata.
Tiyla & WP7: Metodi (1/3)
64
public delegate void OperationCompletedDelegate (String result, Exception error); public event OperationCompletedDelegate OperationCompleted; /// <summary> /// Profile management /// create new profile, or if exist and password match return TRUE /// </summary> public void registerProfile(String email, String password); public OperationCompletedDelegate registerProfile_Completed;
/// <summary> /// verify your password /// </summary> public void loginProfile(String email, String password); public OperationCompletedDelegate loginProfile_Completed;
/// <summary> /// remove profile /// </summary> public void dropProfile(String email, String password); public OperationCompletedDelegate dropProfile_Completed;
/// <summary> /// return data for profile, if password is empty you will receive informations /// </summary> public void getProfileString(String email, String password); public OperationCompletedDelegate getProfileString_Completed;
/// <summary> /// create new Application, if application exists does do nothing /// </summary> public void registerApp(String bundleId, String email, String password); public OperationCompletedDelegate registerApp_Completed;
Tiyla & WP7: Metodi (2/3)
65
/// <summary> /// set KeyPairs App info to db /// </summary> public void setApp(String bundleId, String email, String password, Dictionary<string, string> data); public OperationCompletedDelegate setApp_Completed;
/// <summary> /// Crew manage /// </summary> public void linkCrew(String emailCrew, String bundleId, String email, String password); public OperationCompletedDelegate linkCrew_Completed; /// <summary> /// Crew manage /// </summary> public void unlinkCrew(String emailCrew, String bundleId, String email, String password); public OperationCompletedDelegate unlinkCrew_Completed;
/// <summary> /// Translations Update Crew /// </summary> public void setTApp(String bundleId, String email, String password, String language, Dictionary<string, string> data); public OperationCompletedDelegate setTApp_Completed;
/// <summary> /// Translations Update Developer /// </summary> public bool setTRankApp(String bundleId, String email, String password, String language, Dictionary<string, string> data); public OperationCompletedDelegate setTRankApp_Completed;
/// <summary> /// Translations Client /// </summary> public void getApp(String bundleId, String email, String password, Dictionary<string, string> data); public OperationCompletedDelegate getApp_Completed;
Tiyla & WP7: Metodi (3/3)
66
/// <summary>/// get Translation * work with shots */// </summary> public void getTApp(String bundleId, String email, String password, String language, Dictionary<string, string> data);public OperationCompletedDelegate getTApp_Completed;
/// <summary> /// get Translation * work with shots * /// </summary> public void getTApp(String bundleId, String email, String password, String language, Dictionary<string, string> data); public OperationCompletedDelegate getTApp_Completed;
Tiyla & WP7: RAPI (1/3)
67
• Per implementare alcune funzionalità sono state usate librerie open source pubblicate da CODEPLEX:
• JSON.NET - http://json.codeplex.com/releases/view/64935
• Silverlight SharpZipLib - http://slsharpziplib.codeplex.com/releases/view/50561
Tiyla & WP7: RAPI (2/3)
68
private void registerProfile(String email, String password, string method = "GET") { var sender = new TyilaUtils(); sender.MyDownLoadCompletedEvent += onDownloadCompleted; switch (method) { case "POST": string postData = JsonConvert.SerializeObject(new command3pars() { func = "registerProfile", email = email, password = password }); sender.executeCommandWithPost("http://tiyla.xiaprojects.com/core/echo.php", postData); break; case "GET": default: var theUrlAndGetData = String.Format("func={0}&email={1}&password={2}", "registerProfile", HttpUtility.UrlEncode(email), HttpUtility.UrlEncode(password)); theUrlAndGetData = "http://tiyla.xiaprojects.com/core/echo.php?" + theUrlAndGetData; sender.executeCommandWithGet(theUrlAndGetData); break; } } private void onDownloadCompleted(TyilaUtils sender, String content, Exception ex) { sender.MyDownLoadCompletedEvent -‐= onDownloadCompleted; if (ex != null) { MessageBox.Show(ex.Message); } else { MessageBox.Show(content); } }
Tiyla & WP7: RAPI (3/3)
69
public void executeCommandWithGet(String theUrl) { var client = new WebClient(); client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); client.DownloadStringAsync(new Uri(theUrl)); }
private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { if (MyDownLoadCompletedEvent != null) MyDownLoadCompletedEvent(this, e.Result, e.Error); }
Contact us
70
xiaprojects.com & @xiateam
Xyla.com & @Xylatweets