This is an example I have in the pipe for a long time but I think it still might be helpful to post it.
I had the use case to build a Flex UI where elements are visible/invisible depending on the user who is logged in. The combination of the properties includeInLayout and visible does the trick.
includeInLayout docs:
“Specifies whether this component is included in the layout of the parent container. If
true, the object is included in its parent container’s layout. Iffalse, the object is positioned by its parent container as per its layout rules, but it is ignored for the purpose of computing the position of the next child.”
So when for instance a Button has includeInLayout and visible set to false the control is hidden and does not effect the layout and is not accessible. Now how can we bind this to the roles of a user who is logged into the application?
I thought of this:
<Button label="delete" includeInLayout="{user.hasRole(UserRole.DELETE)}" visible="{user.hasRole(UserRole.DELETE)}" />The User class:
package { import flash.events.Event; import flash.events.EventDispatcher; public class User extends EventDispatcher { private static const ROLES_CHANGED:String = "rolesChanged"; [Bindable] public var username:String; public var password:String; private var _roles:Array; public function get roles():Array { return _roles; } public function set roles(a:Array):void { _roles = a; dispatchEvent(new Event(ROLES_CHANGED)); } public function User(username:String = "", password:String = "") { this.username = username; this.password = password; } [Bindable(event=ROLES_CHANGED)] public function hasRole(userRole:UserRole):Boolean { if(roles != null) { for each(var role:UserRole in roles) { if(role.equals(userRole)) { return true; } } return false; } return false; } } }
The key is the hasRole method which is bindable and can be used for MXML bindings to the includeInLayout and visible property. All bindings will refresh every time the roles setter is called as the ROLES_CHANGED event is dispatched within. And this event is the custom binding event for the hasRole method.
The UserRole class:
package { public class UserRole { public static const DO_A:UserRole = new UserRole("DO_A"); public static const DO_B:UserRole = new UserRole("DO_B"); public static const DO_C:UserRole = new UserRole("DO_C"); public static const VIEW_A:UserRole = new UserRole("VIEW_A"); public static const VIEW_B:UserRole = new UserRole("VIEW_B"); public static const VIEW_C:UserRole = new UserRole("VIEW_C"); private var name:String; public function UserRole(name:String) { this.name = name; } public function equals(userRole:UserRole):Boolean { if(userRole != null) { return this.name == userRole.name; } return false; } } }
The UserRole class specifies all available Roles as constants so they can be passed as parameters to the hasRole method of the User class.
I build a little example application which you can try here and view the source here.
I wanted to continue to play with a little fun project which I localized for three languages but my compiler showed me the error:
unable to open ‘/Applications/Adobe Flex Builder 3 Plug-in/sdks/3.0.2.2113/frameworks/locale/de_DE’
Hmm, this formerly worked so what changed? I changed the SDK to 3.0.2.2113 to upgrade to AIR 1.1 and all framework resources except default en_US are not part of the SDK and have to be created.
So here a little step by step tutorial how to enable localization from scratch with a new SDK. My reference for Flex localization is the article on Adobe Labs written by Gordon Smith which covers all necessary informations and is written in a funny style which I like a lot.
Create Framework Resources
- Open a console/terminal and change to the Flex SDK directory. In my case /Applications/Adobe Flex Builder 3 Plug-in/skds/3.0.2.2113
- Execute this command ./bin/copylocale en_US de_DE where you can replace de_DE with the locale you want to have in your app. After executing the command you see a lot of output on the console which gives you an overview what happens behind the scenes. Repeat this step for each locale you want to add.
- When you look into SKD_DIR/locale/de_DE you should now see the three new files airframework_rb.swc, framework_rb.swc and rpc_rb.swc where “rb” is short for resource bundle.
Setup Flex Project
- Open Flex Builder and create a new Flex project
- Create the directory locale as a project subdirectory
- Create the directories en_US and de_DE
- Create the file myResources.properties in locale/en_US and locale/de_DE
- Add this line to the english property file: Hello=Hello
- Add this line to the german (de_DE) property file: Hello=Hallo (Note in german it is different with “a”)
- Change the project compiler settings (right-click Project->Properties->Flex Compiler) and change the additional compiler settings to -locale en_US de_DE -source-path+=../locale/{locale}
Code with resource bundles in MXML or ActionScript Class
- Open the main MXML src/YourProjectName.mxml
Now you have got two ways to include the localized string:
-
<mx:Label text="@Resource(bundle='myResources', key='Hello')" />
-
<mx:Label text="{resourceManager.getString('myResources', 'Hello')}" />
The first option uses the compiler directive @Resource and runs out of the box. The second option does not give a compiler error but when you test the application you see no text appearing. This is because data binding is used which only evaluates at runtime. To tell the compiler upfront that we need the resource bundle myResources we have to add a Metadata tag and declare the resource bundle:
<mx:Metadata
[ResourceBundle("myResources")]
</mx:Metadata>
You can also declare this in an ActionScript class like this:
[ResourceBundle("myResources")
public class YourClass{...}
You can also use the resource metadata brackets in ActionScript classes:
[Resource(bundle="myResources", key="Hello")]
or use the ResourceManager singleton:
ResourceManager.getInstance().getString("myResources", "Hello");
Using Placeholders in Strings
Often you have to locate strings where parts have to be replaced by variables. Placeholder can be defined like this:
Welcome=Hello {0}!
As you want to replace the {0} with a variable this only works at runtime so you have to use data binding:
<mx:Label text="{resourceManager.getString('myResources', 'Welcome', [userObject.username])}" />
The third argument of getString is an Array of parameters where each index corresponds to the placeholder index so you could have a string like Foo=Hello {0}! The time is {1} and you have {2} new emails.
Multiline Strings and Comments
You can define multiline strings with “\” (backslash on OS X is alt+shift+7). Comments in a property file start with a #:
# this is a comment MyText=Here is a text written in two lines
HTML
There is also nothing to say against using HTML:
MyHTMLText=Here is <b>bold text</b>.
<mx:Label htmlText="{resourceManager.getString('myResources', 'MyHTMLText')}" />
Switch Locale and Fallback
Switching the locale depends on whether you have use the compiler directive @Resource or data binding. The easier thing is data binding because you can switch with one line of code:
resourceManager.localeChain = ["de_DE"];
As you see localeChain is an Array so you can define it like this:
resourceManager.localeChain = ["de_DE", "en_US"];
In this case first de_DE is looked up and when the key is not found the fallback is english so you show at least something up.
When it comes to the static implementation with @Resource the switch is a bit more difficult and also explained in the wiki article. There you have to compile the resource bundles via console to SWF and load them at runtime.
Use Resource Bundles for Code/Content Separation
I recommend to use resource bundles also if you do not localize your application. The separation of code and content will at least be beneficial when for instance someone has to review all text and you simply have to hand over property files instead of several MXML classes …
Links
- Feature Introduction Runtime Localization
- Building multilingual Flex Application on Adobe AIR
- as3localelib
- Wikipedia Locale
So far! These are the most basics for localization I hope. For more detailed information check the first link to Adobe Labs which covers all in detail. But there is much more possible which I did not cover like not using strings but to localize images or even classes but enough for now.
A couple of weeks ago TechCrunch posted about Xoopit and I got an early invitation. Xoopit indexes all images, videos and attachments in your Gmail account and makes them available on the Xoopit homepage but also within the Gmail user interface as you see below:

The service works pretty slick. The only thing I had to do was going to the Xoopit site and login with my Gmail credentials. That’s it. I got the message that have to wait a bit until all my mails are indexed and Xoopit will inform me by email when it’s done. When you click one of your images in the top bar you also got the option to share it by email, Facebook or to blog it directly.
One of the weakness of Flash was the fact that search engines did not index SWF very well. This “missing link” was that indexing SWF was not easily possible. In the past only static textand links were indexed but to be honest - no serious Flash application works with static content. The problem was how to access the dynamic content because all Flash apps are coded differently and use trillions of different techniques to load external data. So the only one who can access all parts of a SWF is the Flash Player itself. For that reason Adobe developed a special headless version which runs on the server.
Mark Anders describes it like this:
“So what we’ve done is to enable the search engines to actually run the app just as an end user would. They can not only run it and see the information that’s displayed, including data dynamically loaded from the network, but can interact with it as well, pressing on buttons and links to interact with the app and explore all of is content.
To enable this we have created a special version of the Flash player that is designed to run on the server as part of the indexing process. As the code executes, there are special API that notify the search engine when something changes and that allow inspection of the textual and other data that would be displayed to the user.
There are other API that enumerate links and allow the indexer to instruct the player to simulate a “click” on various objects that are displayed. In this way, the indexer can navigate the running app.”
This new technology was developed together search industry leaders Google and Yahoo! and Google is rolling out this today! The nice thing is that SWFs do not have to be changed so all existing SWFs are ready to be indexed.
“All of this is going on now! Google is already in progress with spidering SWF content through the new system. Over the next weeks and months, you should see some pretty significant impact on the indicies as SWF content is made a first-class citizen for searchability”
More links:
- Adobe announcement
- SWF searchability FAQ
- Google Webmaster Central Blog
- TechCrunch
- Doug McCune comes with a scientific graphical explanation







