XUL 覆盖、stringbundleset、getString 不是函数的问题,但 createBundle 方法有效

Trouble with XUL overlay, stringbundleset, getString is not a function, but createBundle method works

所以我正在处理一个旧的 XUL 覆盖附加组件并遇到了这个问题,并将其简化为一个最小的附加组件。想知道如果我做错了什么,如果我误解了什么,或者如何让它按预期工作,是否有人可以向我解释。完整代码如下。在 FF 29.0b1 和 49.0a1 中测试,结果相同。

在主 XUL 文件中,我定义了一个 stringbundleset 和一个 stringbundle,它们都具有(很可能)唯一的 ID。在 JavaScript 文件中,我只想通过元素 ID 获取包(而不是集合),并使用 getString(或 getFormattedString)方法。在主 JavaScript 文件中,我有一个事件侦听器调用一个加载函数,它可以调用其他函数,包括一个 init 函数,我在其中放置了字符串抓取代码。所有字符串变量都使用 var 全局定义(在 init 函数之外)。问题是,我得到 getString is not a function。此外,console.log() 甚至在函数中的任何地方都不起作用,所以我什至无法检查应该保存返回字符串包的变量的值。

在我的插件中,我在 Options 和 About XUL 文件中使用了完全相同的模式,并且它有效,正如 MDN 文档所说的那样。所以我从示例代码中排除了这个。

如果尝试构建和测试,请注意在示例 JavaScript 代码中,我有尝试使用 XUL stringbundle 并失败的损坏块,以及工作纯 javascript-only使用 createBundle() 的技术被注释掉了。这很容易用 //* code /**/ 注释模式修改,只需删除第一个 / 并在另一个块上添加一个 / 并重建 xpi。

这是工作代码应创建的示例屏幕截图。该附加组件依赖于旧的状态栏。我使用了 "The Addon Bar (Restored)" 附加组件。请注意状态栏上的 "TSBS"。右击"TSBS",弹出菜单,顶部为Options。这些标签是从 .dtd 文件中提取的。 Menu 是一个子菜单,其标签由 tsbs.js 脚本设置,从 .properties 文件中提取值。该示例显示它们是从仅限 JS 的方法中提取的。我正在尝试通过 XUL/DOM 方法让它工作。

我意识到 XUL 附加组件无论如何都会很快消失。我意识到我不应该仅仅依赖状态栏。我意识到我应该只使用 JS-only 方法,因为它看起来更可靠。但我问这个是因为我注意到它并想从中学习。知道如何更正或改进代码模式,或者这是一个已知问题或常见陷阱吗?

Directory tree:

test_string_bundle_set-1.0.0-fx
  +-- chrome
  |     +-- content
  |     |     +-- tsbs.js
  |     |     +-- tsbs.xul
  |     +-- locale
  |     |     +-- en-US
  |     |           +-- contents.rdf
  |     |           +-- tsbs.dtd
  |     |           +-- tsbs.properties
  +-- chrome.manifest
  +-- install.rdf

chrome.manifest:

overlay chrome://browser/content/browser.xul chrome://{00735700-7357-7357-7357-073570073570}/content/tsbs.xul

content {00735700-7357-7357-7357-073570073570} chrome/content/

locale {00735700-7357-7357-7357-073570073570} en-US chrome/locale/en-US/

install.rdf:

<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
        <em:id>{00735700-7357-7357-7357-073570073570}</em:id>
        <em:version>1.0.0</em:version>
        <em:type>2</em:type>

        <em:name>Test String Bundle Sets</em:name>
        <em:description>Test String Bundle Sets</em:description>
        <em:creator>Quite A. Character</em:creator>

        <!--Firefox-->
        <em:targetApplication>
            <Description>
                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
                <em:minVersion>29.0</em:minVersion>
                <em:maxVersion>49.*</em:maxVersion>
            </Description>
        </em:targetApplication>
    </Description>  
</RDF>

chrome/content/tsbs.js:

var tsbs_strings;

var tsbs_string_4;
var tsbs_string_5;
var tsbs_string_6;

function tsbs_load( ) {
    tsbs_init( );
    return true;
}

function tsbs_close( ) {
    return true;
}

window.addEventListener( 'load', tsbs_load, false );
window.addEventListener( 'close', tsbs_close, false );

function tsbs_init( ) {
    //* XUL/DOM method
    tsbs_strings    = document.getElementById( 'tsbs-strings' );

    console.log( 'TSBS->tsbs_init()->tsbs_strings: ' + typeof tsbs_strings );

    tsbs_string_4   = tsbs_strings.getString( 'tsbs.properties.string.4' );
    tsbs_string_5   = tsbs_strings.getString( 'tsbs.properties.string.5' );
    tsbs_string_6   = tsbs_strings.getString( 'tsbs.properties.string.6' );
    /**/
    /* JS-only method
    tsbs_strings    = Services.strings.createBundle( 'chrome://{00735700-7357-7357-7357-073570073570}/locale/tsbs.properties' );

    console.log( 'TSBS->tsbs_init()->tsbs_strings: ' + typeof tsbs_strings );

    tsbs_string_4   = tsbs_strings.GetStringFromName( 'tsbs.properties.string.4' );
    tsbs_string_5   = tsbs_strings.GetStringFromName( 'tsbs.properties.string.5' );
    tsbs_string_6   = tsbs_strings.GetStringFromName( 'tsbs.properties.string.6' );
    /**/

    document.getElementById( 'tsbs-item-4' ).label = tsbs_string_4;
    document.getElementById( 'tsbs-item-5' ).label = tsbs_string_5;
    document.getElementById( 'tsbs-item-6' ).label = tsbs_string_6;
}

chrome/content/tsbs.xul:

<?xml version="1.0" encoding="UTF-8"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<!DOCTYPE overlay SYSTEM "chrome://{00735700-7357-7357-7357-073570073570}/locale/tsbs.dtd">

<overlay id="tsbs-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

    <script type="application/javascript" src="chrome://{00735700-7357-7357-7357-073570073570}/content/tsbs.js"/>

    <stringbundleset id="tsbs-stringset">
        <stringbundle id="tsbs-strings" src="chrome://{00735700-7357-7357-7357-073570073570}/locale/tsbs.properties"/>
    </stringbundleset>

    <statusbar id="status-bar">
        <statusbarpanel
            id="tsbs-display"
            label="&tsbs.dtd.statusbarpanel.display;"
            pack="end"
            context="tsbs-contextmenu"
        />
    </statusbar>

    <window id="main-window">
        <vbox id="tsbs-notifier">
            <popupset id="mainPopupSet">
                <menupopup id="tsbs-contextmenu" position="before_end">
                    <menuitem id="tsbs-options" label="&tsbs.dtd.options;"/>
                    <menuitem label="&tsbs.dtd.string.1;"/>
                    <menuitem label="&tsbs.dtd.string.2;"/>
                    <menuitem label="&tsbs.dtd.string.3;"/>
                    <menu id="tsbs-menu" label="&tsbs.dtd.menu;">
                        <menupopup id="tsbs-submenu">
                            <menuitem id="tsbs-item-4"/>
                            <menuitem id="tsbs-item-5"/>
                            <menuitem id="tsbs-item-6"/>
                        </menupopup>
                    </menu>
                </menupopup>
            </popupset>
        </vbox>
    </window>

</overlay>

chrome/locale/en-US/contents.rdf:

<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
    <Seq about="urn:mozilla:locale:root">
        <li resource="urn:mozilla:locale:en-US"/>
    </Seq>
    <Description about="urn:mozilla:locale:en-US">
        <chrome:packages>
            <Seq about="urn:mozilla:locale:en-US:packages">
                <li resource="urn:mozilla:locale:en-US:{00735700-7357-7357-7357-073570073570}"/>
            </Seq>
        </chrome:packages>
    </Description>
</RDF>

chrome/locale/en-US/tsbs.dtd:

<!ENTITY tsbs.dtd.statusbarpanel.display    "TSBS"      >
<!ENTITY tsbs.dtd.options                   "Options"   >
<!ENTITY tsbs.dtd.menu                      "Menu"      >
<!ENTITY tsbs.dtd.string.1                  "One"       >
<!ENTITY tsbs.dtd.string.2                  "Two"       >
<!ENTITY tsbs.dtd.string.3                  "Three"     >

chrome/locale/en-US/tsbs.properties:

extensions.{00735700-7357-7357-7357-073570073570}.description=Test String Bundle Sets
tsbs.properties.string.4=four
tsbs.properties.string.5=five
tsbs.properties.string.6=six

我相信这是你的问题:

<stringbundleset id="tsbs-stringset">

在 XUL 覆盖中,如果 <overlay> 的直接子元素具有 ID,则它应该与基本文档中的元素相匹配。 If it does, its contents is inserted under the matching element. If it doesn't this part of an overlay is ignored.

browser.xul can be matched using 中现有的 stringbundleset:

<stringbundleset id="stringbundleset">

另外,我不认为有 'close' 事件(使用 'unload'),并且自 Firefox 2 左右以来您不需要 contents.rdf。关于 console.log() 不工作 - 你检查了 Browser Console,而不是 Web 控制台,对吧?