Flex开发的一些经验总结——本地化(多语言)实现

2011-04-08 9:48 by hackerzhou

良好的本地化一直是一个成熟的软件系统必备的,一般需要在若干语言properties文件中切换,先做出一份模板的语言文件(比如en_US),然后交给翻译团队翻译成各种语言文件。本文讲述如何配置Flex,使得能编译多语言版本的swf,以及如何进行自定义的ResourceManager封装。

简单配置步骤

1.新建一个名为resource的文件夹,并在其下建立locale文件夹,在locale文件夹下建立zh_CN.properties和en_US.properties以及别的你想支持的语言。

2.配置项目的源代码目录,增加resources/locale/{locale},这样就能让编译器找到语言文件。

3.配置项目属性中的编译命令,增加-locale zh_CN en_US,让编译器在编译的时候编译进swf。

如果还有不清楚的地方可以查阅我的UI项目:ReflectProxyServerUI

ResourceManager的封装

对于Flex来说,由于有绑定的支持,完成这些事情变得非常容易。 Flex有ResourceManager提供这类的支持,这个类用来管理Flex代码中用到的资源(字符串,图片等)。唯一一点不方便的地方是,每次使用的时候都传入一个bundle_name,让我觉得有点不方便,因此考虑封装下,提供类似getString(resName:String, para:Array = null)的接口。而且切换语言的时候可以做到即时把界面上的字符串全都替换成目标语言。不过对于大型系统来说这样做会导致界面卡住,因为Bindable本身就是用事件来实现的,一旦切换语言,所有绑定的字符串都会重新执行一遍绑定函数,比较低效。

package me.hackerzhou.reflectproxy.ui.util
{
	import flash.events.Event;
	import flash.events.EventDispatcher;

	public class ResourceUtil extends EventDispatcher
	{
		import mx.resources.IResourceManager;
		import mx.resources.ResourceManager;
		import mx.controls.Alert;

		private static const BUNDLE_NAME:String = "Main";
		[Bindable]
		public static var resourceManager:IResourceManager = null;
		private static var instance:ResourceUtil = null;
		private static var currentLanguage:String = "zh_CN";

		public static function getInstance():ResourceUtil {
			if(instance == null) {
				instance = new ResourceUtil();
				resourceManager = ResourceManager.getInstance();
				resourceManager.initializeLocaleChain([currentLanguage]);
			}
			return instance;
		}

		public function changeLanguage(languageName:String):void {
			resourceManager.localeChain.localeChain = [languageName];
			currentLanguage = languageName;
			dispatchChange();
		}

		[Bindable("change")]
		public function getImage(resName:String):Class {
			var result:Class = resourceManager.getClass(BUNDLE_NAME, resName
                            , currentLanguage);
			return result;
		}

		[Bindable("change")]
		public function getString(resName:String, para:Array = null):String {
			var result:String = resourceManager.getString(BUNDLE_NAME, resName, para
                            , currentLanguage);
			return result;
		}

		private function dispatchChange():void
		{
			dispatchEvent(new Event("change"));
		}
	}
}

从上述代码可以看到,因为无法Bindable到一个静态的函数上进行切换语言,我使用了单例模式,而且本身ResourceManager在系统中就是单例的。需要修改语言时,只需要dispatch一个change的事件,所有绑定到getString的字符串都将会被重新执行getString操作,因此就能获得到最新的语言对应的字符串。

而在外部进行调用的时候,只需要把值绑定到ResourceUitl.getInstance().getString(…)就可以了,当然如果想在ActionScript中而不是MXML中执行绑定,则需要用BindUtil.bindProperty(…)。

当然,有了这套机制,图片等页面元素也可以根据语言的切换而进行修改。需要注意的是,properties文件的key=value中的value要变成类似Embed(“url”)的样子,其中的url是相对于当前properties语言文件的,使用ResourceManager.getClass(…)就可以获取图片以及媒体资源。

效果见下图:

切换语言成英文后:

本文基于 署名 2.5 中国大陆 许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 hackerzhou 并包含 原文链接
发表评论

本文有 1 条评论

  1. jinghu
    2012-08-28 10:07

    你好,请问多语言就只能这么办吗

发表评论