Better way to develop a multilingual application in Flex - apache-flex

I'm planning to create a multilingual app in Flex. My approach is kind of the following:
To have an XML with all the phrases in application...
<mx:Script>
<![CDATA[
public var selectedLanguage : String = "spanish";
public var language : xml =
<xml>
<message id="<<hashcode of the string in english>>" english="hello world" spanish="hola mundo" french="bonjour tout le monde"/>
<message id="<<hashcode of the string in english>>" english="good bye every body" spanish="adios a todos" french="tout le monde au revoir"/>
</xml>;
//Then a function to make the translation:
public function translate(msg:String):String{
//Maybe not a hashCodeFunction but some function to return an unique code for every string
var hashcode : int = hashCodeFunction(msg);
var translation : String = language.message.(#id==hashcode)[selectedLanguage];
if(translation==null) return msg;
return translation;
}
]]>
</mx:Script>
<mx:Button label="translate('hello world')"/>
Well, the xml could be structured in a different way but what I want is create all labels like "translate('some text')" because in this way I think is better at programmer time, and at the end of the development process just create a "pre processor" that is going to look for ALL strings in source code like "translate('some text')" and extract 'some text' then calculate the hash code and append it to xml, and when xml is ready all the application is going to be multilingual.
I want to know if someone has another approach to share.

Adobe implements Resource Bundles for localization and internationalization of text and images.
Compiler options may be specified to include locales:
-locale=en_US,ja_JP,fr_FR
Then, locale specific properties may be retrieved such as:
<s:Label text="{resourceManager.getString('bundleName', 'key')}" />
References:
Adobe Introduction to localization
Flex 4 Localization Quick Start
Introduction to Flex Resource Bundles
Localizing a Flex library with multiple languages in one .swc file

Related

CreateEnvelopeFromTemplates - Guid should contain 32 digits with 4 dashes

I am attempting to create a DocuSign envelope from a template document using the CreateEnvelopeFromTemplates method, available within their v3 SOAP API web service. This is being instantiated from a asp.NET v4.0 web site.
Upon calling the method armed with the required parameter objects being passed in. I am recieving an exception from the web service, basically telling me that the Template ID is not a valid GUID.
669393: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Line 14889:
Line 14890: public DocuSignDSAPI.EnvelopeStatus CreateEnvelopeFromTemplates(DocuSignDSAPI.TemplateReference[] TemplateReferences, DocuSignDSAPI.Recipient[] Recipients, DocuSignDSAPI.EnvelopeInformation EnvelopeInformation, bool ActivateEnvelope) {
Line 14891: return base.Channel.CreateEnvelopeFromTemplates(TemplateReferences, Recipients, EnvelopeInformation, ActivateEnvelope);
Line 14892: }
Line 14893:
The template reference, a guid. Must be specified as the "Template" string property against TemplateReference object. This is then added to a dynamic array of TemplateReferences, which is one of the input parameters of the CreateEnvelopeFromTemplates method.
Actual template GUID: f37b4d64-54e3-4723-a6f1-a4120f0e9695
I am building up my template reference object using the following function that i wrote to try and make the functionality reusable:
Private Function GetTemplateReference(ByVal TemplateID As String) As TemplateReference
Dim templateReference As New TemplateReference
Dim guidTemplateID As Guid
With TemplateReference
.TemplateLocation = TemplateLocationCode.Server
If Guid.TryParse(TemplateID, guidTemplateID) Then
.Template = guidTemplateID.ToString
End If
End With
Return TemplateReference
End Function
The TemplateID is being passed in from a appSetting configuration value at the time of the TemplateReferences array instantiation like so...
templateReferences = New TemplateReference() {GetTemplateReference(ConfigurationManager.AppSettings("DocuSignTemplate_Reference"))}
recipients = New Recipient() {AddRecipient("myself#work.email", "My Name")}
envelopeInformation = CreateEnvelopeInformation()
envelopeStatus = client.CreateEnvelopeFromTemplates(templateReferences, recipients, envelopeInformation, True)
As you can see from my GetTemplateReference function I am also parsing the GUID before setting it back as a string so i know its valid. The template is managed and stored at the DocuSign end, hence specifying the document location.
I am referring to their own documentation:
CreateEnvelopeFromTemplates
Why oh why is the method not liking my Template ID? I can successfully use their REST API to call the same method, using their own code samples. Worst case I can make use of this but would rather interact with the web service as I would need to construct all the relevent requests in either XML or JSON.
I would really appreciate if someone could perhaps shed some light on this problem.
Thanks for taking the time to read my question!
Andrew might be spot on with the AccountId mention - are you setting the AccountId in the envelope information object? Also, have you seen the DocuSign SOAP SDK up on Github? That has 5 sample SOAP projects including one MS.NET project. The .NET project is in C# not Visual Basic, but still I think it will be helpful to you. Check out the SOAP SDK here:
https://github.com/docusign/DocuSign-eSignature-SDK
For instance, here is the test function for the CreateEnvelopeFromTemplates() function:
public void CreateEnvelopeFromTemplatesTest()
{
// Construct all the recipient information
DocuSignWeb.Recipient[] recipients = HeartbeatTests.CreateOneSigner();
DocuSignWeb.TemplateReferenceRoleAssignment[] finalRoleAssignments = new DocuSignWeb.TemplateReferenceRoleAssignment[1];
finalRoleAssignments[0] = new DocuSignWeb.TemplateReferenceRoleAssignment();
finalRoleAssignments[0].RoleName = recipients[0].RoleName;
finalRoleAssignments[0].RecipientID = recipients[0].ID;
// Use a server-side template -- you could make more than one of these
DocuSignWeb.TemplateReference templateReference = new DocuSignWeb.TemplateReference();
templateReference.TemplateLocation = DocuSignWeb.TemplateLocationCode.Server;
// TODO: replace with template ID from your account
templateReference.Template = "server template ID";
templateReference.RoleAssignments = finalRoleAssignments;
// Construct the envelope information
DocuSignWeb.EnvelopeInformation envelopeInfo = new DocuSignWeb.EnvelopeInformation();
envelopeInfo.AccountId = _accountId;
envelopeInfo.Subject = "create envelope from templates test";
envelopeInfo.EmailBlurb = "testing docusign creation services";
// Create draft with all the template information
DocuSignWeb.EnvelopeStatus status = _apiClient.CreateEnvelopeFromTemplates(new DocuSignWeb.TemplateReference[] { templateReference },
recipients, envelopeInfo, false);
// Confirm that the envelope has been assigned an ID
Assert.IsNotNullOrEmpty(status.EnvelopeID);
Console.WriteLine("Status for envelope {0} is {1}", status.EnvelopeID, status.Status);
}
This code calls other sample functions in the SDK which I have not included, but hopefully this helps shed some light on what you're doing wrong...
This problem arises when you don't set up the field AccountId. This field can be retrieved from your account. In Docusign's console go to Preferences / API and look here
Where to find AccountID Guid in Docusign's Console
Use API Account ID (which is in GUID format) and you should be OK.

Passing request file into flex application with flashvar

I am trying to get a xml file with data into Flex application. There are a lot of examples online passing parameter into flex I found very helpful. However, it doesn't really work in my case.
here is my code in HTML:
var flashvars = {};
flashvars.storageStatsXML = "stats.xml";
var params = {};
swfobject.embedSWF("mySWF.swf", "mySWF", "1000", "500", "10.0.0", "js/expressInstall.swf", flashvars, params);
here is the code in mxml:
[Bindable]
public var storageStats:XML;
protected function start(event:FlexEvent):void
{
storageStats = Application.application.parameters.storageStatsXML;
}
And then the XML file got parsed in the application.
I think there is something not right about the code, any thoughts?
Thanks.
The Application.application.parameters.storageStatsXML property is not the XML data you are expecting, it is a String containing the text "stats.xml".
In the same way that the file path "c:\temp\info.txt" (or "/temp/info.txt") isn't the file itself, it just tells you how to find the file on disk.
You will need to use a URLRequest to load the XML file specified by the storageStatsXML property.
Have a look at the Actionscript documentation and here on StackOverflow for examples on how to load external data.

What is the recommend way to create a custom culture and associated resource files for a specific Client?

I have client that wants to specifiy their own version of localized content for a subset of my string resources.
For simplicity here is basic example:
Lets say I have 2 localized strings (showing english content)
PageTitle="Hello World"
PageDescription="This is a more wordy version of Hello World!"
I wish to localize these so I have resource files.
Strings.resx (contains my English
string)
Strings.fr-ca.resx
(contains my French-Canadian strings)
Strings.fr-ca-clientX.resx (contains
my strings for a Client whom is
French-Canadian and therfore very
picky;) - just joking)
Ideally "Strings.fr-ca-clientX" can specify only the strings they want to "override". In other words they may just wish to change the PageTitle and continue using the PageDescription from the "fr-ca" resource file.
So how do I go about this in .NET? Ideally I would just create the resx file and specify the culture in my "Web.config" and it should work...
<globalization uiCulture="fr-ca-clientX" culture="fr-ca-clientX" />
However, this does not work. "The tag contains an invalid value for the 'culture' attribute" is my first obsticle.
Thanks,
Justin
public void AddCustomCulture(string cultureName, string baseCulture)
{
var cultureBuilder = new CultureAndRegionInfoBuilder(cultureName, CultureAndRegionModifiers.None);
cultureBuilder.LoadDataFromCultureInfo(new CultureInfo(baseCulture));
var region = baseCulture.Substring(3, 2);
cultureBuilder.LoadDataFromRegionInfo(new RegionInfo(region));
cultureBuilder.Register();
}
You can create a new culture with the following code:
//Get culture info based on Great Britain
CultureInfo cultureInfo = new CultureInfo( "en-GB" );
RegionInfo regionInfo = new RegionInfo( cultureInfo.Name );
CultureAndRegionInfoBuilder cultureAndRegionInfoBuilder = new CultureAndRegionInfoBuilder( txtCultureName.Text, CultureAndRegionModifiers.None );
cultureAndRegionInfoBuilder.LoadDataFromCultureInfo( cultureInfo );
cultureAndRegionInfoBuilder.LoadDataFromRegionInfo( regionInfo );
// Custom Changes
cultureAndRegionInfoBuilder.CultureEnglishName = txtCultureName.Text;
cultureAndRegionInfoBuilder.CultureNativeName = txtNativeName.Text;
cultureAndRegionInfoBuilder.Register();
I have written a post on creating an app to do just that..
http://wraithnath.blogspot.com/search/label/Globalization
You probably need to create your own culture and register it. You'll find MSDN article on that topic here.
You don't need to alter culture attribute, it should stay at "fr-CA", as uiCulture attribute is responsible for loading strings from resources.

Call a Java Applet from Flex

I'm working on Flex application and I need to open a Java Applet from Flex (e.g. clicking a button). In particular I'd like to open imageJ, a particular imaging program that could work as application, applet or be integrated in a web page. Is there a way to call it from Flex? I've seen a couple of tutorials that explain how to call a single function in another Java file from Flex, but I'm not so sure that it is what I'm looking for.
Thanks for your answers,
cheers,
David
I don't know if there's a better way, but if I was doing it, I'd write a JavaScript function that would load the Java applet (could be as simple as document.write("<object …>")), then use Flex's ExternalInterface to call that JavaScript.
Expose a public method in your applet, which the flex would call. You could load the applet the following way. It is a sample program, to call java methods and get a value from java, you can do changes as per your need
<object
id = "MyApplet"
name = "Some name"
classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="0" height="0">
<PARAM NAME = "CODE" VALUE = "com.my.applet.MyApplet.class" >
<PARAM NAME = "CODEBASE" VALUE = "." >
<PARAM NAME = "ARCHIVE" VALUE = "applet-client.jar" >
<PARAM NAME = "cache_option" VALUE="No">
<PARAM NAME = "java_version" VALUE="1.6+">
<param name = "type" value = "application/x-java-applet;version=1.6">
<comment>
<embed
name = "MyApplet"
type = "application/x-java-applet;version=1.6" \
CODE = "com.my.applet.MyApplet.class" \
JAVA_CODEBASE = "." \
ARCHIVE = "applet-client.jar"
cache_option = "No"
scriptable = false
pluginspage = "http://java.sun.com/products/plugin/index.html#download"
width="0" height="0"
>
<noembed>
</noembed>
</embed>
</comment>
</object>
With the above in your html file( I am not explaining everything) , the applet will be downloaded and ready to use. Now on click of a button on your flex app, you should have something like below.
var returnedStringFrom java:String=ExternalInterface.call("document.MyApplet.functionInJava",stringParam);
Note : MyApplet is the name in the object declaration above, the functionInJava is a public function in the the java class com.my.applet.MyApplet. It takes a parameter and returns a string parameter. The Java program will look like below.
package com.my.applet;
public class MyApplet{
//other methods..
public String functionInJava(String stringpm){
// your implementation
return "SomeString";
}
}
Happy coding.

HTTP Basic Authentication with HTTPService Objects in Adobe Flex/AIR

I'm trying to request a HTTP resource that requires basic authorization headers from within an Adobe AIR application. I've tried manually adding the headers to the request, as well as using the setRemoteCredentials() method to set them, to no avail.
Here's the code:
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
private function authAndSend(service:HTTPService):void
{
service.setRemoteCredentials('someusername', 'somepassword');
service.send();
}
private function resultHandler(event:ResultEvent):void
{
apiResult.text = event.result.toString();
}
private function resultFailed(event:FaultEvent):void
{
apiResult.text = event.fault.toString();
}
]]>
</mx:Script>
<mx:HTTPService id="apiService"
url="https://mywebservice.com/someFileThatRequiresBasicAuth.xml"
resultFormat="text"
result="resultHandler(event)"
fault="resultFailed(event)" />
<mx:Button id="apiButton"
label="Test API Command"
click="authAndSend(apiService)" />
<mx:TextArea id="apiResult" />
However, a standard basic auth dialog box still pops up prompting the user for their username and password. I have a feeling I'm not doing this the right way, but all the info I could find (Flex docs, blogs, Google, etc.) either hasn't worked or was too vague to help.
Any black magic, oh Flex gurus? Thanks.
EDIT: Changing setRemoteCredentials() to setCredentials() yields the following ActionScript error:
[MessagingError message='Authentication not supported on DirectHTTPChannel (no proxy).']
EDIT: Problem solved, after some attention from Adobe. See the posts below for a full explanation. This code will work for HTTP Authentication headers of arbitrary length.
import mx.utils.Base64Encoder;
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false; // see below for why you need to do this
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Finally received some attention from Adobe and got an answer on this. The problem with long HTTP Authentication headers is that, by default, the Base64Encoder class will inject newline characters every 72 characters. Obviously that causes a chunk of the base-64 encoded string to be interpreted as a new header attribute, which causes the error.
You can fix this by setting (in the above example) encoder.insertNewLines = false; The default setting is true.
I've fixed the above code to work for arbitrarily long Authentication strings.
Ah. The pain, the suffering. The sheer misery.
While you've figured out how to add a header before making your call, the nasty truth is that somewhere deep down in the Flash/browser integration space your headers are being removed again.
From my blogpost last year at verveguy.blogspot.com
So I have unraveled the Truth. (I think)
It's more tortured than one would imagine
1/ All HTTP GET requests are stripped of headers. It's not in the Flex stack so it's probably the underlying Flash player runtime
2/ All HTTP GET requests that have content type other than application/x-www-form-urlencoded are turned into POST requests
3/ All HTTP POST requests that have no actual posted data are turned into GET requests. See 1/ and 2/
4/ All HTTP PUT and HTTP DELETE requests are turned into POST requests. This appears to be a browser limitation that the Flash player is stuck with. (?)
What this boils down to in practical terms is that if you want to pass headers in all requests, you should always use POST and you should find another way to communicate the semantics of the operation you "really wanted". The Rails community have settled on passing ?_method=PUT/DELETE as a work around for the browser problems underlying 4/
Since Flash adds the wonderful header stripping pain on GET, I'm also using ?_method=GET as a workaround for that. However, since this trips up on 3/,
I am passing a dummy object as the encoded POST data. Which means my service needs to ignore dummy posted data on a ?_method=GET request.
Crucial at this point to know about 2/. That wasted a bunch of my time.
I've built all of this handling into a new RESTService class with MXML markup support so it's possible to pretend this doesn't exist on the client side.
Hope this helps someone.
The setCredentials() & setRemoteCredentials() methods are intended for use with Flex/LiveCycle Data Services, so they probably don't apply in your case.
This ought to work for you. I was able to reproduce this behavior on my server, and this fix seems to have done the trick; it still seems a bit odd this isn't more API-user-friendly, considering how common a use case you'd think it were, but nonetheless, I've tested and verified this works, given a valid SSL cert:
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Hope it helps! And thanks for posting -- I'm sure I would've run into this one sooner or later myself. ;)
This really has helped me! Thanks!
I use Flex Builder 3
One note: WebService's property headers is read only.
So I tried to use httpHeaders. It works!
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("test:test");
sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};
I had the same problem while consuming HTTP Basic Authenticated Webservice. This is my solution; it works fine:
private function authAndSend(service:WebService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("user:password");
service.httpHeaders = { Authorization:"Basic " + encoder.ToString() };
service.initialize();
}
usage
authAndSend(WebService( aWebServiceWrapper.serviceControl));
Try using setCredentials rather than setRemoteCredentials and failing that, using Fiddler/Charles to find out what headers are being sent with the request.
Also, just so other people don't spend 10 minutes working out why the correct example doesn't quite work asis, you need to import the mx.utils.Base64Encoder package eg:
import mx.utils.Base64Encoder;
At the beginning or somewhere within the CDATA area. I'm new to flex so this wasn't quite obvious at first.
This is how its done.
import mx.utils.Base64Encoder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
var _oHttp:HTTPService = new HTTPService;
var sUsername:String = "theusername"
var sPassword:String = "thepassword";
var oEncoder:Base64Encoder = new Base64Encoder();
oEncoder.insertNewLines = false;
oEncoder.encode(sUsername + ":" + sPassword);
_oHttp.method = "POST";
_oHttp.headers = {Authorization:"Basic " + oEncoder.toString()};

Resources