Entities in XUL work the same way as they do in any other XML application. They are used to reference data that was abstracted from the content. This process encourages reuse of data, but in the context of Mozilla's XPFE, it is used to extract visible text in interface widgets. This extraction ensures that the content can remain untouched during the localization process.
Example 11-1 shows how to put DTD entities into your XUL code by using attribute values for the text of a menu item (label) and the keyboard access shortcuts (accesskey). The syntax requires that an entity be placed in quotes as the value of the attribute. This is a useful example because it highlights the localization of a widget label, which is common to many widgets, and a supplementary attribute, which, in this case, is an accesskey.
Example 11-1. XUL menu with entity references for text and accesskeys
<menu label="&menuFile.label;" accesskey="&menuFile.accesskey;"> <menupopup> <menuitem accesskey="&menuNew.accesskey;" label="&menuNew.label;" oncommand="doNew( );"/> <menuitem accesskey="&menuOpen.accesskey;" label="&menuOpen.label;" oncommand="doOpen( );"/> <menuseparator /> <menuitem accesskey="&menuClose.accesskey;" label="&menuClose.label;" oncommand="doClose( );"/> <menuitem accesskey="&menuSave.accesskey;" label="&menuSave.label;" oncommand="doSave( )"/> <menuitem accesskey="&menuSaveAs.accesskey;" label="&menuSaveAs.label;" oncommand="doSaveAs"/> <menuseparator /> <menuitem accesskey="&menuPrint.accesskey;" label="&menuPrint.label;" oncommand="doPrint( );"/> <menuseparator /> <menuitem accesskey="&menuExit.accesskey;" label="&menuExit.label;" </menupopup> </menu>
Note that each entity in Example 11-1 has a text value associated with it in the DTD entities declarations. The entity that appears on the menu is &menuFile.label;. Note that this entity mirrors the correct syntax for referencing a value, which is: &get.text;.
The entity reference (or name, in this context) must be preceded by an ampersand (&) and end with a semicolon (;). The period is optional, but conventional. Typically, the period separates the entity's element or target (menuFile) from the type of entity (label). Refer to theSection 11.4 section later in this chapter for more information on naming conventions.
For some widgets, including <description> and <label>, the entity can be placed inside the element tags, as opposed to being values of attributes.
Table 11-1 represents the DTD files that accompany the XUL content in Example 11-1. Two languages, English and Spanish, are separated into different files. These files have the same name as the DTD file referenced in the XUL file that contains the entities. However, each file for every different language exists in a separate locale folder. Each entry, or entity, in the DTD file has a name that matches the name referenced in the XUL and a value to be filled in for that entity. The value is enclosed in quotes. When generating these files, you will need to create the file only once and copy it to a different directory where you can replace the values in the entities. A good tool would carry out this process for you. Refer to the Localization Tools sidebar later in the chapter for more information.
Table 11-1. Entity definitions for the XUL menu
<!ENTITY menuFile.label "File"> <!ENTITY menuNew.label "New"> <!ENTITY menuOpen.label "Open..."> <!ENTITY menuClose.label "Close"> <!ENTITY menuSave.label "Save"> <!ENTITY menuSaveAs.label "Save As..."> <!ENTITY menuPrint.label "Print..."> <!ENTITY menuExit.label "Exit"> <!ENTITY menuFile.accesskey "f"> <!ENTITY menuNew.accesskey "n"> <!ENTITY menuOpen.accesskey "o"> <!ENTITY menuClose.accesskey "c"> <!ENTITY menuSave.accesskey "s"> <!ENTITY menuSaveAs.accesskey "a"> <!ENTITY menuPrint.accesskey "p"> <!ENTITY menuExit.accesskey "x">
<!ENTITY menuFile.label "Archivo"> <!ENTITY menuNew.label "Nuevo"> <!ENTITY menuOpen.label "Abrir Archivo..."> <!ENTITY menuClose.label "Cerrar"> <!ENTITY menuSave.label "Salvar"> <!ENTITY menuSaveAs.label "Salvar Como..."> <!ENTITY menuPrint.label "Imprimir..."> <!ENTITY menuExit.label "Salir"> <!ENTITY menuFile.accesskey "a"> <!ENTITY menuNew.accesskey "n"> <!ENTITY menuOpen.accesskey "o"> <!ENTITY menuClose.accesskey "c"> <!ENTITY menuSave.accesskey "s"> <!ENTITY menuSaveAs.accesskey "a"> <!ENTITY menuPrint.accesskey "i"> <!ENTITY menuExit.accesskey "r">
Figure 11-1 shows the resulting XUL menus. There can only be one value for each entity and only one language taking precedence, or appearing in the UI, at a time.
This example presents only two languages, but theoretically, you can have as many languages as you require. The locale-switching mechanism and the chrome registry must determine which one should be used, which is explained later in the section "The Chrome Registry and Locale."
You may ask, how are the entities accessed? You can associate the DTD with your XUL file in two ways. The first is internally, which involves wrapping the strings in a DTD data type enclosure by using the DOCTYPE declaration.
<!DOCTYPE window [ <!ENTITY windowTitle.label "Greetings"> <!ENTITY fileMenu.label "File"> ]>
The second is an external DTD file, which is associated with your XUL that also uses the DOCTYPE declaration, and a reference pointing to the file:
<!DOCTYPE window SYSTEM "chrome://xfly/locale/xfly.dtd">
The node referenced in the DOCTYPE declaration is usually followed by the XUL document's root node. In this case, it is window, but can be other elements like page or dialog (however, it is not actually validated so it can be any value).
If you have a small application, the DTD files can reside in the same folder as your XUL files, but putting them into their own locale directory within your chrome structure is good practice.
Consider the main Editor window in Mozilla. Its declaration in Example 11-2 is flexible enough to associate multiple DTD files with your content.
Example 11-2. The Editor's Doctype definitions
<!DOCTYPE window [ <!ENTITY % editorDTD SYSTEM "chrome://editor/locale/editor.dtd" > %editorDTD; <!ENTITY % editorOverlayDTD SYSTEM "chrome://editor/locale/editorOverlay.dtd" > %editorOverlayDTD; <!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd" > %brandDTD; ]>
The declaration first stores the document associated with the chrome URL in an associated parameter entity. It then simply uses it. XML does not have a one-step way of storing and using the entity as in other languages. In other words, the declaration is the equivalent of the import foo in Python, or #include "foo.h" in C.
Certain localizable resources lend themselves to reuse. It makes sense to use the same strings across different content, which explains the inclusion of a DTD file in more than one XUL document. In Mozilla, this includes brand information, build ID numbers, and help resources.
Which is more appropriate to use: internal or external entities? Using the external approach is preferable because the content (XUL) does not have to be touched during the translation process. If someone opts to create a tool to extract and/or insert strings, their job would be much easier if they had to parse one less file type. This may remove context somewhat, but it can be overcome by actively commenting the DTD file.