Changing application's language at runtime.
运行过程中改变应用程序的语言
There're many examples that show how to write multi-language applications. The basic idea is getting the proper language at installation time, or through the use of optional packs. Sometimes, there's a need to change languages dynamically while the application is running. This may seem like a difficult task, but following some basic guidelines it'll prove to be very easy.
有很多例子介绍如何写支持多语言的应用程序。基本的思路是:在安装时获取合适的语言,或者通过使用可选包来改变程序语言。有时候,需要在应用程序运行时动态改变语言。这貌似是一个不容易的工作,但是如果你遵照下面的指导来进行,那么动态改变程序语言将变得非常容易。
First off, we'll need to separate the default resource file into two pieces. Depending on the way you choose to allow the user to toggle among languages, you'll provide the default resource file of the corresponding structures. For example purposes, I've chosen a listbox dialog, which is the first control shown upon execution. Depending on the language selected, the corresponding secondary resource file will be loaded. This second resource file will be the provider of the localized content.
So back to our example, the default resource file will look like:
首先,我们需要把默认的资源文件分成两部分。根据你选择的允许用户在多种语言之间进行切换的方式,你需要提供对应结构的默认资源文件。为举例说明,我选择了程序运行时第一个出现的控件-----列表对话框。依据选择的语言,加载相应的第二个资源文件。这第二个资源文件提供本地化内容。因此,回到我们的例子中来,默认的资源文件将会是这样:
NAME TEST
#include <eikon.rh>
#include <avkon.rsg>
#include <avkon.rh>
#include <avkon.mbg>
#include "Test.hrh"
#include "Test.loc"
RESOURCE RSS_SIGNATURE { }
RESOURCE TBUF { buf = qtn_app_caption_string; }
RESOURCE EIK_APP_INFO
{
cba = R_AVKON_SOFTKEYS_OPTIONS_BACK;
menubar = r_dummy_menubar;
}
RESOURCE MENU_BAR r_dummy_menubar
{
titles=
{
MENU_TITLE { menu_pane = r_dummy_menupane; txt=""; }
};
}
RESOURCE MENU_PANE r_dummy_menupane
{
items=
{
MENU_ITEM { command = EAknCmdExit; txt = qtn_cmd_exit; }
};
}
RESOURCE DIALOG r_list_dialog
{
flags = EAknDialogSelectionList | EEikDialogFlagWait;
buttons = R_AVKON_SOFTKEYS_SELECT_CANCEL;
items =
{
DLG_LINE
{
type = EAknCtSingleListBox;
id = ESelectionListControl;
control = LISTBOX
{
flags = EAknListBoxSelectionList;
};
}
};
}
First thing to note is the use of cba and menubar in the EIK_APP_INFO resource structure. This is a
convenience, as it delegates construction and layout of both CBA and menu bar to the application's UI.
Otherwise, we'd have to perform this action manually (which means calculating the screen area and
location for each of these controls, among other things) which is also specific to the UI used (Avkon,
Qikon, etc). The last resource structure defined corresponds to the dialog that will allow us to select the
language dynamically.
需要注意的第一件事是在EIK_APP_INFO 资源结构中使用命令按钮域(CBA:Command Button Area)和菜单栏。这样很方便,因为它指定了应用程序用户界面中的命令按钮域和菜单栏的创建和布局。否则,我们将不得不手动执行这些特定于所使用的用户接口(Avkon,Qikon,等等)的操作(这意味着我们需要在其他控件中计算出每一个这样的控件的屏幕区域和位置)。最后定义的资源结构,和允许我们动态选择语言的对话框是对应的。
Now we define a second resource file, which will contain the rest of the resources used by the
application. Most controls should be in this resource file:
现在我们定义第二个资源文件,它将包含应用程序使用的其他资源。大部分的控件应该包含在这个资源文件里面:
NAME EXTR
#include <eikon.rh>
#include <avkon.rsg>
#include <avkon.rh>
#include <avkon.mbg>
#include "Test.hrh"
#include "Test.loc"
RESOURCE RSS_SIGNATURE { }
RESOURCE CBA r_softkeys
{
buttons =
{
AVKON_CBA_BUTTON { id = EAknSoftkeyOptions; txt = qtn_softkey_options; },
AVKON_CBA_BUTTON { id = EAknSoftkeyExit; txt = qtn_softkey_exit; }
};
}
RESOURCE MENU_BAR r_menubar
{
titles=
{
MENU_TITLE { menu_pane = r_menupane; txt=""; }
};
}
RESOURCE MENU_PANE r_menupane
{
items=
{
MENU_ITEM { command = ECmdLang; txt = qtn_cmd_lang; },
MENU_ITEM { command = ECmdTest; txt = qtn_cmd_test; },
MENU_ITEM { command = EAknCmdExit; txt = qtn_cmd_exit; }
};
}
RESOURCE TBUF r_text_greeting
{
buf = qtn_text_greeting;
}
Also note we need to provide a NAME and RSS_SIGNATURE, otherwise we'd get a panic (internally,
CONE's AddResourceFileL() uses RResourceFile and RResourceFile::ConfirmSignatureL() to verify the
signature and initialize the offset)
另外注意,我们需要提供一个NAME和RSS_SIGNATURE,否则程序将发生异常
(在程序内部,CONE 的AddResourceFileL() 函数使
用RResourceFile和RResourceFile::ConfirmSignatureL() 来验证签名,并初始化偏
移量)。
And this is the function that will scan the available localized resource files. For simplicity, the list dialog
shows the corresponding file names. You may want to provide some mapping to more user-friendly
names. Also, for clarity's sake, only basic error handling is done.
这是一个扫描可用本地化资源文件的函数。为了简化起见,列表对话框显示了
相应的文件名称。你可能需要提供一些使其更加用户友好型的名字的映射。另
外,为了清楚起见,仅作了基本的错误处理。
void CTestAppUi::ChooseLanguageL()
{
HBufC* appName = Application()->AppFullName().AllocLC();
TParsePtrC parse(*appName);
// Construct search path
_LIT(KExtra, "Extra.r??");
TFileName file;
file.Copy(parse.DriveAndPath());
file.Append(KExtra);
RFs& fs = iCoeEnv->FsSession();
CDir* entries;
fs.GetDir(file, KEntryAttNormal, ESortByName, entries);
CleanupStack::PushL(entries);
CDesCArray* list = new(ELeave) CDesCArrayFlat(5);
CleanupStack::PushL(list);
// Fill up listbox
for (TInt i = 0; i < entries->Count(); ++i)
{
_LIT(KFormat, "/t%S");
file.Format(KFormat, &(*entries)[i].iName);
list->AppendL(file);
}
TInt index;
CAknSelectionListDialog* dialog = CAknSelectionListDialog::NewL(index, list, 0);
if (dialog->ExecuteLD(R_LIST_DIALOG))
{
file.Copy(parse.DriveAndPath());
file.Append((*entries)[index].iName);
// Replace resource file
if (iOffset)
iCoeEnv->DeleteResourceFile(iOffset);
iOffset = iCoeEnv->AddResourceFileL(file);
// Load cba, menu, etc as necessary
iEikonEnv->AppUiFactory()->Cba()->SetCommandSetL(R_SOFTKEYS);
iEikonEnv->AppUiFactory()->MenuBar()->SetMenuTitleResourceId(R_MENUBAR);
}
CleanupStack::PopAndDestroy(3, appName); // list, entries, appName
}
Here are some screenshots of the example project:
You may download the project here你可以在这里下载这个项目:
Source code 源码: DynLang.zip
Application 可执行应用程序: DynLang.SIS
Language pack 语言包: DynLang_Language_Pack.SIS
All emulator builds have been compiled & linked using Microsoft Visual C++ 6.0 compiler. In some cases, some small changes might be required to make it work with your toolchain. I'm not responsible for your use of the information contained in or linked from these web pages.
所有的基于模拟器的创建都已经通过Microsoft Visual C++ 6.0编译器编译和连接
。在有些情况下,为了能在你的程序中正常运行,你需要作一些小小的改动。
对于你使用这些网页包含的信息或者链接,我不负有任何责任。
注:本文由wave于2007年12月13日翻译,对于翻译中存在的任何问题,希望能够不吝赐教。 我的E-mai:wave_1102@126.com |