----
XUL::App - Jifty way of doing XUL
----
{{#x|XUL::App}} - {{#ci|Jifty}} way of doing {{#x|XUL}}
XUL::App - {{#ci|Jifty}} 风格的 XUL 开发
☺{{#author|Agent Zhang}}☺
{{#author|章亦春}}
{{#date|2007.11}}
----
{{#kw|☼}} Let's {{#x|start}} with
a {{#ci|hello world}} Firefox extension!
让我们从一个 {{#ci|hello world}}
Firefox 扩展开始!
----
{{#v|$}} {{#ci|xulapp}} {{#x|app}} {{#cm|--name}} HelloWorld
Creating new application HelloWorld
Creating directory lib/
Creating directory lib/HelloWorld/
Writing file {{#x|lib/HelloWorld/App.pm}}
Creating directory js/
Creating directory css/
Creating directory icons/
Creating directory icons/default/
Creating directory t/
Creating directory po/
Creating directory docs/
{{#v|$}}
----
{{#v|$}} {{#x|cd}} {{#cm|HelloWorld/}}
{{#v|$}} {{#x|ls}}
css docs icons js lib po t
----
{{#cm|☺}} Let's create a {{#ci|window view}}
named {{#x|HelloWin}}!
让我们来创建一个
名叫 {{#x|HelloWin}} 的{{#ci|窗口视图}}!
----
{{#v|$}} {{#ci|xulapp}} {{#x|view}} {{#cm|--name}} HelloWin {{#cm|--type}} window
Creating directory lib/HelloWorld/View/
Writing file {{#x|lib/HelloWorld/View/HelloWin.pm}}
{{#v|$}}
----
{{#v|$}} {{#ci|wc}} -l {{#t|lib/HelloWorld/View/HelloWin.pm}}
{{#x|26}} lib/HelloWorld/View/HelloWin.pm
{{#v|$}}
----
{{#cm|☺}} Now let's {{#ci|register}} our HelloWin {{#x|view}}
in our {{#x|HelloWorld::App}} module.
现在让我们在 HelloWorld::App 模块中
{{#ci|注册}}一下我们的 HelloWin 视图。
----
{{#v|$}} {{#ci|vim}} {{#t|lib/HelloWorld/App.pm}}
----
{{#cm|# File lib/HelloWorld/App.pm}}
{{#kw|package}} HelloWorld::App;
{{#kw|our}} {{#v|$$VERSION}} = '0.01';
{{#kw|use}} XUL::App::Schema;
{{#kw|use}} XUL::App schema {
xpifile 'helloworld.xpi' =>
name is 'HelloWorld',
id is 'helloworld@agentz.agentz-office', {{#cm|# FIXME}}
version is '0.0.1',
targets {
Firefox => ['2.0' => '3.0a5'], {{#cm|# FIXME}}
},
creator is 'The HelloWorld development team',
developers are ['agentz'],
contributors are [];
homepageURL is 'http://helloworld.agentz.org',
{{#v|...}}
};
1;
----
{{#cm|# File lib/HelloWorld/App.pm}}
{{#kw|package}} HelloWorld::App;
{{#kw|our}} {{#v|$$VERSION}} = '0.01';
{{#kw|use}} XUL::App::Schema;
{{#kw|use}} XUL::App schema {
{{#x|# Code that we added by hand:}}
{{#x|xulfile 'hellowin.xul' => }}
{{#x|generated from 'HelloWorld::View::HelloWin';}}
xpifile 'helloworld.xpi' =>
name is 'HelloWorld',
id is 'helloworld@agentz.agentz-office', {{#cm|# FIXME}}
version is '0.0.1',
targets {
Firefox => ['2.0' => '3.0a5'], {{#cm|# FIXME}}
},
creator is 'The HelloWorld development team',
{{#v|...}}
----
{{#cm|☺}} Now let's add some {{#ci|contents}} to
our HelloWin {{#x|view}} class.
现在让我们往 HelloWin {{#x|视图}}类中
添加一些{{#ci|内容}}。
----
{{#v|$}} {{#ci|vim}} {{#t|lib/HelloWorld/View/HelloWin.pm}}
----
{{#cm|# File lib/HelloWorld/View/HelloWin.pm}}
{{#kw|package}} HelloWorld::View::HelloWin;
{{#kw|use base}} 'XUL::App::View::Base';
{{#kw|use}} Template::Declare::Tags 'XUL';
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
window {
attr {
id => \"helloworld-hellowin\",
xmlns => {{#v|$::XUL_NAME_SPACE}},
title => 'HelloWorld',
{{#v|...}}
}
}
};
1;
----
{{#cm|# File lib/HelloWorld/View/HelloWin.pm}}
{{#kw|package}} HelloWorld::View::HelloWin;
{{#kw|use base}} 'XUL::App::View::Base';
{{#kw|use}} Template::Declare::Tags 'XUL';
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
window {
attr {
id => \"helloworld-hellowin\",
xmlns => {{#v|$::XUL_NAME_SPACE}},
title => 'HelloWorld',
{{#v|...}}
}
{{#x|# Code that we added by hand:}}
{{#x|label { "Hello, world!" } }}
}
{{#v|...}}
----
{{#tag|☆}} Hey, it {{#ci|runs}} now!
嘿,它现在已经能{{#x|跑}}起来了!
----
{{#cm|# Assuming the Firefox profile dev already exists:}}
{{#v|$}} {{#ci|xulapp}} {{#x|debug}} hellowin.xul {{#kw|--profile}} dev
Writing file hellowin.xul
Registering extension hellowin in profile dev
Setting configure variables in dev's prefs.js
MOZ_NO_REMOTE=1 && firefox -jsconsole -P dev -chrome \\
chrome://helloworld/content/hellowin.xul
----
{{img src="#" width="0" height="0"}}
{{img src="images/hellowin.png" width="427" height="178"}}
----
☺ If the {{#x|dev}} profile does {{#ci|not}} exist,
xulapp will automatically create one for you.
如果 dev 配置文件{{#ci|不存在}}的话,那么 xulapp 会
自动为你创建一个。
----
{{#cm|# Assuming the Firefox profile dev does NOT exist:}}
{{#v|$}} {{#ci|xulapp}} {{#x|debug}} hellowin.xul {{#kw|--profile}} dev
Writing file hellowin.xul
{{#x|Creating profile dev}}
{{#x|Success: created profile 'dev'}}
{{#x|Start Firefox temporarily to initialize the profile}}
Registering extension hellowin in profile dev
Setting configure variables in dev's prefs.js
MOZ_NO_REMOTE=1 && firefox -jsconsole -P dev -chrome \\
chrome://helloworld/content/hellowin.xul
----
{{img src="images/hellowin.png" width="427" height="178"}}
----
{{#cm|♡}} It's time to
{{#ci|bundle}} and {{#ci|distribute}} our toy!
到了{{#x|打包}}和{{#x|发布}}我们的玩具的时候了!
----
{{#v|$}} {{#ci|xulapp}} {{#x|bundle}} .
Writing file hellowin.xul
Writing bundle file {{#x|./helloworld.xpi}}
{{#v|$}}
----
Our {{#kw|helloworld.xpi}} bundle {{#tag|➥}}
+ {{#cm|✓}} contains {{#ci|0}} {{#x|Perl}}
+ {{#cm|✓}} has {{#ci|0}} {{#x|dependencies}}
(except Firefox itself)
+ {{#cm|✓}} runs happily {{#ci|everywhere}}
(Win32, Linux, Mac, and etc.)
----
{{#cm|☺}} Put {{#x|helloworld.xpi}} onto an {{#ci|HTTP server}}
and make sure the mime-type for .xpi is
{{#x|application/x-xpinstall}}.
将 helloworld.xpi 放到一个 HTTP 服务器上,
并确保 .xpi 的 mime 类型为
application/x-xpinstall.
----
On the {{#ci|end user}} side...
{{img src="images/install-xpi.png" width="835" height="580"}}
----
On the {{#ci|end user}} side...
{{img src="images/chrome-url.png" width="834" height="582"}}
----
{{#kw|☹}} But requiring the {{#ci|end user}} to enter
the {{#x|chrome URL}} to access our extension
is {{#ci|NOT}} professional.
但是要求最终用户靠输入 {{#ci|chrome URL}}
来访问我们的扩展
是很{{#x|不专业}}的。
----
{{#kw|☼}} Let's add a {{#x|button}} to
Firefox's {{#ci|Tools menu}} for our baby then!
那么就让我们来为我们的东东
向 Firefox 工具菜单添加一个按钮吧!
----
{{#cm|☺}} First of all, create an {{#ci|overlay view}}
named {{#x|Overlay}}!
让我们来创建一个
名叫 Overlay 的覆盖视图!
----
{{#v|$}} {{#ci|xulapp}} {{#x|view}} {{#cm|--name}} Overlay {{#cm|--type}} overlay
Writing file {{#x|lib/HelloWorld/View/Overlay.pm}}
----
{{#v|$}} {{#ci|wc}} -l {{#t|lib/HelloWorld/View/Overlay.pm}}
27 lib/HelloWorld/View/Overlay.pm
{{#v|$}}
----
{{#cm|☺}} Now let's {{#ci|register}} our Overlay {{#x|view}}
in our {{#x|HelloWorld::App}} module.
现在让我们在 HelloWorld::App 模块中
{{#ci|注册}}一下我们的 Overlay 视图。
----
{{#v|$}} {{#ci|vim}} {{#t|lib/HelloWorld/App.pm}}
----
{{#cm|# File lib/HelloWorld/App.pm}}
{{#kw|package}} HelloWorld::App;
{{#kw|our}} {{#v|$$VERSION}} = '0.01';
{{#kw|use}} XUL::App::Schema;
{{#kw|use}} XUL::App schema {
{{#cm|# Code that we added by hand:}}
xulfile 'hellowin.xul' =>
generated from 'HelloWorld::View::HelloWin';
xpifile 'helloworld.xpi' =>
name is 'HelloWorld',
id is 'helloworld@agentz.agentz-office',
version is '0.0.1',
{{#v|...}}
----
{{#cm|# File lib/HelloWorld/App.pm}}
{{#kw|package}} HelloWorld::App;
{{#kw|our}} {{#v|$$VERSION}} = '0.01';
{{#kw|use}} XUL::App::Schema;
{{#kw|use}} XUL::App schema {
{{#cm|# Code that we added by hand:}}
{{#x|xulfile 'overlay.xul' => }}
{{#x|generated from 'HelloWorld::View::Overlay',}}
{{#x|overlays 'chrome://browser/content/browser.xul';}}
xulfile 'hellowin.xul' =>
generated from 'HelloWorld::View::HelloWin';
xpifile 'helloworld.xpi' =>
name is 'HelloWorld',
{{#v|...}}
----
{{#cm|☺}} Now let's add some {{#ci|contents}} to
our {{#t|Overlay}} {{#x|view}} class.
现在让我们往 Overlay {{#x|视图}}类中
添加一些{{#ci|内容}}。
----
{{#cm|# File lib/HelloWorld/View/Overlay.pm}}
{{#v|...}}
{{#kw|package}} HelloWorld::View::Overlay;
{{#kw|use base}} 'XUL::App::View::Base';
{{#kw|use}} Template::Declare::Tags 'XUL';
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
overlay {
attr {
id => \"helloworld-overlay\",
xmlns => {{#v|$::XUL_NAME_SPACE}},
}
{{#cm|# Add your elements here...}}
}
};
1;
----
{{#cm|# File lib/HelloWorld/View/Overlay.pm}}
{{#v|...}}
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
overlay {
{{#v|...}}
{{#cm|# Add your elements here...}}
{{#x|menupopup {}}
{{#x|attr { id => "menu_ToolsPopup" } }}
{{#x|menuitem {}}
{{#x|attr {}}
{{#x|oncommand => "toOpenWindowByType(}}
{{#x|'helloworld',}}
{{#x|'chrome://helloworld/content/hellowin.xul')",}}
{{#x|insertafter => }} {{#x|"javascriptConsole,devToolsSeparator",}}
{{#x|label => "Hello World",}}
{{#x|}}}
{{#x|}}}
{{#x|}}}
{{#v|...}}
----
{{#tag|☆}} Job's {{#ci|done}}! Let's {{#x|test}} it!
工作{{#ci|完成}}了!让我们来{{#x|测试}}它!
----
{{#v|$}} {{#ci|xulapp}} {{#x|overlay}} {{#cm|--profile}} dev
Writing file {{#x|overlay.xul}}
Writing file hellowin.xul
Registering extension hellowin in profile dev
Setting configure variables in dev's prefs.js
firefox -jsconsole -P dev
----
{{img src="images/hw-overlay.gif" width="640" height="466"}}
----
{{#cm|♡}} {{#ci|rebundle}} it!
重新{{#x|打包}}!
----
{{#v|$}} {{#ci|xulapp}} {{#x|bundle}} .
Writing file overlay.xul
Writing file hellowin.xul
Writing bundle file {{#x|./helloworld.xpi}}
{{#v|$}}
----
{{#kw|☼}} \"Hey, I want to support {{#ci|multiple languages}},
my users come from {{#x|different}} countries.\"
嘿,我想要支持{{#ci|多国语言}},
我的用户来自{{#x|不同的}}国家.
----
{{#cm|☺}} {{#t|No problem,}}
it's {{#ci|easy}} to implement with {{#x|XUL::App}}!
{{#t|没问题,}}
使用 {{#x|XUL::App}} 来实现是{{#ci|很容易的}}!
----
{{#kw|☼}} Let's Add a {{#ci|zh-CN}} {{#x|locale}}
to our extension!
让我们为我们的扩展
添加一个简体中文的 locale!
----
{{#cm|Step 1}} Change every occurrence of
{{#ci|string literals}} {{#x|"..."}} in our view classes
to the form {{#x|_("...")}}
{{#cm|第一步}} 将我们的视图类中出现的
每一个字符串字面值 {{#x|"..."}}
都替换为 {{#x|_("...")}} 的形式。
----
{{#cm|# File lib/HelloWorld/View/HelloWin.pm}}
{{#kw|package}} HelloWorld::View::HelloWin;
{{#kw|use base}} 'XUL::App::View::Base';
{{#kw|use}} Template::Declare::Tags 'XUL';
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
window {
attr {
id => \"helloworld-hellowin\",
xmlns => {{#v|$::XUL_NAME_SPACE}},
title => 'HelloWorld',
{{#v|...}}
}
{{#cm|# Code that we added by hand:}}
label { \"Hello, world!\" }
}
{{#v|...}}
----
{{#cm|# File lib/HelloWorld/View/HelloWin.pm}}
{{#kw|package}} HelloWorld::View::HelloWin;
{{#kw|use base}} 'XUL::App::View::Base';
{{#kw|use}} Template::Declare::Tags 'XUL';
template main => {{#kw|sub}} {
show 'header'; {{#cm|# from XUL::App::View::Base}}
window {
attr {
id => \"helloworld-hellowin\",
xmlns => {{#v|$::XUL_NAME_SPACE}},
title => {{#x|_('HelloWorld')}},
{{#v|...}}
}
{{#cm|# Code that we added by hand:}}
label { {{#x|_("Hello, world!")}} }
}
{{#v|...}}
----
{{#cm|# File lib/HelloWorld/View/Overlay.pm}}
{{#v|...}}
{{#cm|# Add your elements here...}}
menupopup {
attr { id => \"menu_ToolsPopup\" }
menuitem {
attr {
oncommand => \"toOpenWindowByType(
'helloworld',
'chrome://helloworld/content/hellowin.xul')\",
insertafter => \"javascriptConsole,devToolsSeparator\",
label => \"Hello World\",
}
}
}
{{#v|...}}
----
{{#cm|# File lib/HelloWorld/View/Overlay.pm}}
{{#v|...}}
{{#cm|# Add your elements here...}}
menupopup {
attr { id => \"menu_ToolsPopup\" }
menuitem {
attr {
oncommand => \"toOpenWindowByType(
'helloworld',
'chrome://helloworld/content/hellowin.xul')\",
insertafter => \"javascriptConsole,devToolsSeparator\",
label => {{#x|_("Hello World")}},
}
}
}
{{#v|...}}
----
{{#cm|Step 2}} Generate the {{#ci|PO file}} for {{#x|zh-cn}}.
{{#cm|第二步}} 为我们的 {{#x|zh-cn}} 生成 {{#ci|PO 文件}}.
----
{{#v|$}} {{#ci|xulapp}} {{#x|po}} {{#cm|--lang}} zh-cn
Write {{#x|po/zh-cn.po}}
----
{{#v|$}} {{#ci|wc}} -l {{#t|po/zh-cn.po}}
{{#x|28}} po/zh-cn.po
----
{{#cm|Step 3}} Edit the {{#ci|PO file}} to
do the {{#t|actual}} {{#x|translation}}
{{#cm|第三步}} 编辑 {{#ci|PO 文件}}进行
实际的{{#x|翻译}}工作。
----
{{#v|$}} {{#ci|vim}} po/zh-cn.po
----
{{#v|...}}
\"MIME-Version: 1.0\\n\"
\"Content-Type: text/plain; charset=CHARSET\\n\"
\"Content-Transfer-Encoding: 8bit\\n\"
{{#cm|#: lib/HelloWorld/View/Overlay.pm:28}}
{{#kw|msgid}} \"Hello World\"
{{#kw|msgstr}} \"\"
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:23}}
{{#kw|msgid}} \"Hello, world!\"
{{#kw|msgstr}} \"\"
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:17}}
{{#kw|msgid}} \"HelloWorld\"
{{#kw|msgstr}} \"\"
----
{{#v|...}}
\"MIME-Version: 1.0\\n\"
\"Content-Type: text/plain; charset={{#x|UTF-8}}\\n\"
\"Content-Transfer-Encoding: 8bit\\n\"
{{#cm|#: lib/HelloWorld/View/Overlay.pm:28}}
{{#kw|msgid}} \"Hello World\"
{{#kw|msgstr}} {{#x|"你好 世界"}}
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:23}}
{{#kw|msgid}} \"Hello, world!\"
{{#kw|msgstr}} {{#x|"你好,世界"}}
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:17}}
{{#kw|msgid}} \"HelloWorld\"
{{#kw|msgstr}} {{#x|"你好世界"}}
----
{{#kw|☺}} {{#x|Done}} and {{#x|done}}; let's {{#ci|test}} it!
搞定了,搞定了;
让我们{{#ci|测试}}一下!
----
{{#v|$}} {{#ci|xulapp}} {{#x|overlay}} {{#cm|--profile}} dev {{#cm|--lang}} {{#x|zh-cn}}
Writing file {{#x|zh-CN.dtd}}
Writing file overlay.xul
Writing file hellowin.xul
Registering extension hellowin in profile dev
Setting configure variables in dev's prefs.js
LANG=\"{{#x|zh-CN}}.UTF-8\" LC_CTYPE=\"{{#x|zh-CN}}.UTF-8\" firefox -jsconsole -P dev
----
{{img src="images/hw-zh-cn.gif" width="634" height="474"}}
----
{{#v|♡}} Let's create an {{#x|en-US}} locale
as the {{#ci|fall back}}.
让我们创建一下 en-US 作为默认方式。
----
{{#v|$}} {{#ci|xulapp}} {{#x|po}} {{#cm|--lang}} {{#x|en-us}}
Write {{#x|po/en-us.po}}
----
{{#v|...}}
\"MIME-Version: 1.0\\n\"
\"Content-Type: text/plain; charset={{#x|UTF-8}}\\n\"
\"Content-Transfer-Encoding: 8bit\\n\"
{{#cm|#: lib/HelloWorld/View/Overlay.pm:28}}
{{#kw|msgid}} \"Hello World\"
{{#kw|msgstr}} {{#x|""}}
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:23}}
{{#kw|msgid}} \"Hello, world!\"
{{#kw|msgstr}} {{#x|""}}
{{#cm|#: lib/HelloWorld/View/HelloWin.pm:17}}
{{#kw|msgid}} \"HelloWorld\"
{{#kw|msgstr}} {{#x|""}}
----
{{#v|☺}} Strings that're {{#ci|not}} translated
are {{#x|kept intact}}.
没有被翻译的字符串会保持原样。
----
{{#cm|☺}} Let's {{#ci|test}} the {{#x|en-US}} locale now.
现在让我们测试一下 en-US 语言支持。
----
{{#v|$}} {{#ci|xulapp}} {{#x|overlay}} {{#cm|--profile}} dev {{#cm|--lang}} {{#x|en-us}}
Writing file {{#x|en-US.dtd}}
Writing file overlay.xul
Writing file hellowin.xul
Registering extension hellowin in profile dev
Setting configure variables in dev's prefs.js
LANG=\"{{#x|en-US}}.UTF-8\" LC_CTYPE=\"{{#x|en-US}}.UTF-8\" firefox -jsconsole -P dev
----
{{img src="images/hw-overlay.gif" width="640" height="466"}}
----
----
{{#cm|☺}} We can add as {{#ci|many}} {{#x|locales}} as we wish ;)
我们想加多少种语言支持,
就可以加多少 ;)
----
What if our {{#x|view}} classes' .pm files {{#ci|change}}?
Do we have to {{#ci|redo}} the whole translation?
如果我们{{#ci|改变}}了{{#x|视图类}}的 .pm 文件的话呢?
我们是否必须{{#ci|重做}}所有的翻译?
----
{{#v|$}} xulapp {{#x|po}}
{{#ci|Updated}} po/zh-en.po
{{#ci|Updated}} po/zh-cn.po
----
{{#cm|☺}} XUL::App will try its best to {{#ci|reuse}}
the {{#x|existing}} translation items in the .po files.
XUL::App 将会尽最大努力{{#ci|复用}}
.po 文件中{{#x|已有的}}翻译条目。
----
{{#cm|☺}} Now we can {{#ci|rebundle}} our baby
and make both {{#x|Chinese}} and {{#x|US}} users happy.
现在我们可以{{#ci|重新打包}}我们的孩子
来让{{#x|中国}}用户和{{#x|美国}}用户同时开心。
----
{{#v|$}} {{#ci|xulapp}} {{#x|bundle}} .
Writing file overlay.xul
Writing file hellowin.xul
Writing file en-US.dtd
Writing file zh-CN.dtd
Writing bundle file {{#x|./helloworld.xpi}}
{{#v|$}}
----
♡
----
➥
----
☺
----