System and methods for translating software into localized versions5678039Abstract A Software Translation Kit (STK) system having a shell, TShell, coupled to an Export/Import module and various Editors is described. The Export/Import module itself includes a parsing engine to extract strings and translatable information from application programs. It functions as a front end parser to "translatable" sources, providing data conversion as needed. The STK system provides a standard interface and set of tools which can be used to localize graphic user interface products. By employing a datacentric approach, the system provides a standard platform which allows translators to act independently of the product they are translating. Claims What is claimed is: Description COPYRIGHT NOTICE
______________________________________
CreateWindow
( button, // window class name
"&Yes", // window caption
WS.sub.-- CHILD .linevert split.
// window style
WS.sub.-- VISIBLE .linevert split.
WS.sub.-- TABSTOP,
24/cxChar*4,
// initial x position
35/cyChar*8,
// initial y position
24/cxChar*4,
// initial x size
14/cyChar*8,
// initial y size
hDlg, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL // creation parameters
);
______________________________________
At runtime, each CreateWindow call API may be trapped for determining each screen object which is about to be created. System Operation A. Windows "Notepad" example The methods of the present invention for translating an application will now be illustrated using a well-known application--Microsoft Windows Notepad. In particular, a dialog from Microsoft Windows Notepad program will be translated using the tools of the system. In this manner, the reader may focus on the teachings of the present invention without distraction from a complex application. The resource composition of Notepad is as follows. The interface for the Notepad application is shown in FIG. 5A. The interface includes a main or application window 500 having a caption bar 501, a menu bar 520, and a client area 540. Menu bar 520, in turn, invokes a plurality of submenus, such as submenu 530. As shown in FIG. 5B, the menu bar 520 and its submenus may be decomposed into a resource file 570. Menu resource file 570 includes "popup" sections defining the submenus which are attached to the menu bar 520. Submenu 530, for instance, is defined by popup section 575. Thus as shown, the menu bar 520 and its submenus may be decomposed for tracking its individual elements. The decomposition into a resource file may be accomplished either by reading resource data from the EXE file (static method), or by executing the EXE file and inquiring about menu information (from the running application during runtime). Using the latter method provides an added advantage since it can extract dynamic menu attributes (grayed, checked, and the like) from the application. These attributes are generally not available in the resource file. When the user invokes a File.vertline.Open command (e.g., by selecting "Open" from the submenu 530), the Notepad application 500 displays the Open dialog 550, shown in FIG. 5C. The dialog 550 includes a plurality of screen objects. The dialog 550 includes a window with caption bar and includes static text fields, an edit text field, list boxes, combo boxes, and push buttons. Such a dialog is defined by the following resource information:
__________________________________________________________________________
1536 DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
STYLE DS.sub.-- MODALFRAME .linevert split. WS.sub.-- POPUP .linevert
split. WS.sub.-- CAPTION .linevert split. WS.sub.-- SYSMENU
CAPTION "Open"
FONT 8, "Helv"
LTEXT "File &Name:", 1090, 6, 6, 76, 9
EDITTEXT 1152, 6, 16, 90, 12, ES.sub.-- AUTOHSCROLL .linevert split.
ES.sub.-- OEMCONVERT .linevert split.
WS.sub.-- BORDER .linevert split. WS.sub.-- TABSTOP
LISTBOX 1120, 6, 32, 90, 68, LBS.sub.-- STANDARD .linevert split. NOT
LBS.sub.-- NOTIFY .linevert split.
LBS.sub.-- OWNERDRAWFIXED .linevert split.LBS.sub.-- HASSTRINGS
.linevert split. LBS.sub.-- DISABLENOSCROLL .linevert split.
NOT WS.sub.-- BORDER .linevert split. WS.sub.-- TABSTOP
LTEXT "&Directories:", -1, 110, 6, 92, 9
LTEXT "", 1088, 110, 18, 92, 9, SS.sub.-- NOPREFIX .linevert split.
WS.sub.-- GROUP
LISTBOX 1121, 110, 32, 92, 6B, LBS.sub.-- STANDARD .linevert split. NOT
LBS.sub.-- NOTIFY .linevert split.
LBS.sub.-- OWNERDRAWFIXED .linevert split. LBS.sub.-- HASSTRINGS
.linevert split. LBS.sub.-- DISABLENOSCROLL .linevert split.
NOT WS.sub.-- BORDER .linevert split. WS.sub.-- TABSTOP
LTEXT "List Files of &Type:", 1089, 6, 104, 90, 9
COMBOBOX 1136, 6, 114, 90, 36, CBS.sub.-- DROPDOWNLIST .linevert split.
CBS.sub.-- AUTOHSCROLL .linevert split.
WS.sub.-- BORDER .linevert split. WS.sub.-- VSCROLL .linevert split.
WS.sub.-- TABSTOP
LTEXT "Dri&ves:", 1091, 110, 104, 92, 9
COMBOBOX 1137, 110, 114, 92, 63, CBS.sub.-- DROPDOWNLIST .linevert
split.
CBS.sub.-- OWNERDRAWFIXED .linevert split. CBS.sub.-- AUTOHSCROLL
.linevert split. CBS.sub.-- SORT .linevert split.
CBS.sub.-- HASSTRINGS .linevert split. WS.sub.-- BORDER .linevert
split. WS.sub.-- VSCROLL .linevert split. WS.sub.-- TABSTOP
DEFPUSHBUTTON "OK", 1, 208, 6, 50, 14, BS.sub.-- DEFPUSHBUTTON .linevert
split.
WS.sub.-- GROUP .linevert split. WS.sub.-- TABSTOP
PUSHBUTTON "Cancel", 2, 208, 24, 50, 14, WS.sub.-- GROUP .linevert
split. WS.sub.-- TABSTOP
PUSHBUTTON "&Help", 1038, 208, 46, 50, 14, WS.sub.-- GROUP .linevert
split. WS.sub.-- TABSTOP
CRECKBOX "&Read Only", 1040, 208, 68, 50, 12, BS.sub.-- AUTOCHECKBOX
.linevert split.
WS.sub.-- GROUP .linevert split. WS.sub.-- TABSTOP
}
__________________________________________________________________________
B. User operation 1. Configuration As shown in FIG. 6A, the software translation system is generally operated by the user through a graphical user interface, such as workspace 600, shown in the figure. As shown at 601, the TShell module is configurable by the user via a TSHELL.INI config file. For instance, the configuration file includes an "Editors" section for specifying the various editors which TShell may launch. Similarly, the configuration file includes a "Tables" section for specifying the source language (e.g., U.S. English). 2. Underlying data structure Also shown in FIG. 6A is Translation Table 610, which stores information parsed from the resources of the program to be translated (in this instance, Windows Notepad). Shown in greater detail in FIG. 6B, the Translation Table 610 includes fields for storing for each resource its Resource Identifier, String value, Dimension, and Type. For each resource the table stores information about the owner or "Father" of the resource. A dialog, being a top-level resource, has a father of zero (i.e., no father). The dialog, in turn, is a father for the resources it contains. Thus, these resources store in their "Father" fields a handle or ID referring back to the dialog. In FIG. 6B, for instance, the static text resources for the "about box" of Notepad are shown at 620. The father for these resources is the "About" dialog itself which, as shown in the table, has an identifier of 66. Also shown, the Translation Table 610 includes a Translated field which indicates whether a particular resource is a translatable item. Unlike prior art systems, the software translation system of the present invention treats the dimension of each resource as a translatable item and carries that information forward. As will be illustrated below, this allows the end user to adjust dimensions on the fly, during translation. 3. TShell At this point, the system is properly configured and now ready to begin translating the target program, Windows Notepad. The user initiates the translation session by loading TShell (e.g., by selecting it from screen button 615, or by running it from the command line). FIG. 7 illustrates a TShell dialog interface 700. The dialog includes a module list 701, status box 705, editor buttons 707, status information 709, close button 711, and help button 713. The modules list 701 lists all active modules which have been loaded for translation. Since this example focuses on Windows Notepad, the word "notepad" appears in the list, as shown. Status box 705 lists how much of the product has been translated. Since no translation has occurred yet, the box displays "zero percent." Editor buttons 707 display screen buttons for launching the various editors which are used for translating the target program. Status box 709 displays current status information, such as how many total records have been created by parsing the resources for the target program. Finally, the close button 711 is used to close the dialog 700, and the help button 713 is used to invoke context-sensitive help for the interface. Next, use of the various editors will be described. 4. Editors Since the majority of time spent by a user translating a product will be spent in use of the editors, editors should be easy to use and consistent from one project to another. Although the following discussion focuses on editors embodied in a Microsoft Windows implementation (i.e., one using Windows .RC resource files), it should be noted that these editors function entirely independent of the particular implementation. In particular, since the editors draw information from and store information back into the Translation Table 340, the editors themselves are independent from the underlying implementation (which may have particular proprietary formats for storing its resources). (a) String Editor Generally, end user translators first work with the string editor to carry out bulk (i.e., large scale) translation of strings. Upon the user selecting the "string" button from editor buttons 707, the system displays String Editor 800, shown in FIG. 8A. The string editor displays the original string in a grey box above a white edit field where the translation is entered. The original string is displayed with a white background to make whitespace discernible. Strings are displayed sorted according to the current Windows country setting, and ignoring leading whitespace and &s (the Windows hotkey character), although these are displayed as a part of the string. The String Editor 800 displays all the translatable strings, as well as context information, for the product to be translated. In particular, for each translatable resource having a string, the editor includes fields for displaying and editing an Identifier 801, Type 803, (original) String 805, New String 807, Comment 809, and FileName 811. The Identifier, Type, and String information are read in directly from the Translation Table. FileName information 811, which is also read in from the translation table, displays information about the particular resource file (e.g., file name and line number) from which the resource originated. Using field selector 813 and standard cursor positioning technique, the end user translator may easily enter new text strings into field 807, for the various resources having translatable strings. All standard Windows-editor functions are supported (Cut, Paste, Undo, and the like) available from their standard CUA hot keys or by use of a popup menu which appears with a right-mouse click on the editor window. A "Find next untranslated option" is also available through the menu or the accelerator Control-N. This moves the cursor position to the next blank input line. Search on both the original and translated fields and search and replace on the translated fields are also available. Options can be set for case-sensitivity and for the support of regular expressions using GREP-like wildcards. Since the translator should be provided with as much information as possible about these potentially obscure strings, the editors in the system of the present invention provide information about the location where the message appears, its maximum length, its context information, and other such information which assists the user with translating the message. In the String Editor, for instance, the end-user translator can enter various comments into the comment field 809, for explaining a particular translation (or even explaining why a particular item should not be translated). Upon completing bulk translation of strings, the end user translator closes the string editor 800. This new information provided by the user is written back to the Translation Table 340. (b) Menu editor Ideally, a Menu Editor provides a user with a context translation. In other words, the translator is able to see how the item will appear on the final product as the translation is done. One problem in translating menus, for instance, are "pick letters"--"hotkey" letters which allow "short cut" selections from a menu. Since the translator must ensure that all "pick letters" are unique, he or she must also be able to change "short cut" selections. Thus, a menu editor should emulate the real menu, as well as warn the user of any pick-letter conflicts. While the string editor provides bulk translation of strings, the menu editor (as well as the dialog editor, described below) provide "in situ" or "live" translation of the target resource. Specifically, since the translation table also maintains other "translatable items" (such as dimension information), the system of the present invention can create the look and feel of a particular resource on screen while the end user translator is carrying out the translation. The Menu Editor 830 shown in FIG. 8B displays a String Editing Window 820 in the lower part of the screen, and two smaller windows 835, 837 on its upper part. The String Editing Window 820 comprises an editing work surface having Identifier 821, String 823, New String 825, and File Name 827 fields. The menu window 835 on the left hand side displays a representation of the original menu; this menu is constructed directly from the menu resource information stored in the translation table. The menu window 837 on the right displays a representation of the translated menu. As the end user translator moves the field selector 829 (e.g., using cursor positioning technique) the corresponding visual representation of the resource is selected as well. For instance, selecting an "Open" string in Editing Window 820 causes the File.vertline.Open menu item to be selected from the source menu 835. Selection of a popup menu in either the original menu window or the translated menu window results in the string associated with that menu being displayed at the current cursor position in the string editor. Selecting a non-popup menu item in either menu displays window results in that item being displayed at the current cursor position in the string editor, and the string editor is given the input focus. Changes to the translated menu are made as soon as the changed string in the string editor loses the input focus. Upon the user typing in a new text string in the field 825, for instance, the translated menu 837 illustrates the result. In this fashion, the end user translator performs a translation on a "live" interface and is thus able to immediately see the results as he or she performs the translation. (c) Dialog editor Dialogs present an additional complication. Not only must text strings be translated but also dimensions of the underlying dialogs need to be translated as well. Specifically, as a string gets translated its control in the dialog box might not be large enough to contain the new string (or may be too large, and thus can occupy unnecessary space). Accordingly, the dimensions associated with a text control need to be monitored and modified when necessary. As dimensions are typically not as easily translatable by the translator as strings, a dialog box editor should provide a mechanism for either visually resizing of the UI element (e.g., through emulation), or automatically resizing. This aspect can be particularly challenging as dynamically-generated dialog boxes might not be statically presentable. A dialog box editor should include safeguards to not allow a translator to change other aspects of the dialog. For instance, the translator should not be able to alter the styles or classes of either the dialog itself or the controls (i.e., screen buttons) in the dialog; nor should the translator be allowed to alter the "tab order" (i.e., the internal representation of the order of the controls kept by the dialog box). The Dialog Editor is illustrated in FIGS. 9A-B. The Dialog Editor displays a String Editing Window 925 in the lower half of the screen, and two dialog boxes 910, 920 on the upper half. The Source Dialog 910 on the left represents the original dialog box (i.e., Windows Notepad's "Now printing text" dialog, for the instant example); the Target Dialog 920 on the right represents the translated dialog box. The Dialog 910 contains the following resources (i.e., resources for which it is the father): Static Text Resource 911, Static Text Resource 912, and Button Resource 913. The system displays in the Dialog 920 the following corresponding resources: Static Text Resource 921, Static Text Resource 922, and Button Resource 923. Initially, Resources 921, 922, 923 are devoid of any text string, and all dimensions in the translated dialog box are the same as those in the original dialog box. As in the case with the Menu Editor, the Dialog Editor 900 displays "live" images of both source and target. The String Editing Window 925 displays the following fields: Identifier 901, Type 902, String 903, New String 904, Dimension 905, New.sub.-- Dimension 906, and FileName 907. The Identifier, Type, String, New String, and FileName fields function in a manner similar to those previously described for the String Editor. Note, however, that the dimension of a resource is treated as a translatable item. Therefore, the Dialog Editor 900 includes the Dimension Field 905 which displays the various dimensions for a resource (using diagonal x,y coordinate) and the New Dimension Field 906, which may receive new values from the end-user translator. The end-user translator may then proceed to select each resource desired to be translated and type in a New String. As shown in FIG. 9A, for instance, the user may select the New String Field 909 for the "cancel" button and type in a New String, as shown at 909. Simultaneous with the end-user's entry of a New String, the corresponding control (i.e., Button Control 923) is updated to display the New Text String. The translated dialog box has editable controls, which can be moved and resized as necessary. Left-mouse-clicking on a control makes that control active and highlighted by a black box. The active control can then be moved or re-sized. Pressing SHIFT and left-selecting multiple controls makes those controls active and highlighted by a black box. These controls can then be moved as a group, or be aligned/sized according to the align and size dialog boxes. Moving a control or group involves pressing the left mouse button while the cursor is inside the black selection box (the cursor will assume a cross-hair shape) or using the arrow cursor keys. Resizing a control manually involves pressing the left mouse button on either: (1) the bottom of the highlighted control (the cursor will be an up-down double-headed arrow) for vertical resizing; or (2) the right side of the highlighted control (the cursor will be a left-right double-headed arrow) for horizontal resizing; or (3) of the bottom-right corner of the control (the cursor will be a diagonal double-headed arrow) for both horizontal and vertical resizing. Modifying the display properties (e.g., automatic re-sizing) of the translated resource is accomplished as shown in FIG. 9B. The end-user translator may request property inspection of the control 923 (e.g., by "right-clicking" on it), where upon the system displays Object Popup Menu 930. The popup menu includes the following options: Align . . . : Selecting this option produces a dialog box with options for aligning controls and groups of controls. Size . . . : Produces a dialog box with options for resizing controls and groups of controls. Grow selected controls to text: Automatically resizes selected control(s) to fit the translated text. Grow all controls to text: Automatically resizes all controls to their text strings. Hide selected controls: Temporarily hides control(s) from view (to simplify editing of other objects). Show all controls: Restores hidden control(s). Default dimensions: Restores a control to its default dimensions. Repaint: Forces a repaint of the dialog in case any information had been corrupted. Save: Forces a write of any changed dimensions to disk. Undo <operation>: Will undo the last <operation>. <operation>is the last action performed on the dialog box--selection, resize, move, and the like. Selecting the Align or Size items produces a dialog box with options to align or size the selected control or controls horizontally or vertically. Certain options only apply to multiple selections. For resizing the control, for instance, the end-user translator selects the "Size" menu item 931. Upon the user selecting this option, the system displays a "Size Controls" dialog (not shown). The Size Controls dialog is where the starting point, the height, and the width of controls are specified in the dialog box. It includes two columns of buttons: Horizontal Size radio buttons and Vertical Size radio buttons. Horizontal Size radio buttons are selected to size the width of the selected controls; Vertical Size radio buttons size the height of the selected controls. Exemplary options include: No Change: The No Change radio button is selected if the user does not wish the controls to change size horizontally. Grow To Largest: The Grow To Largest radio button resizes controls horizontally so that they are as wide as the widest control in the selected group. Width Of Size Box: The Width Of Size radio button resizes controls so that they are as wide as the sizing frame. Width Of Dialog: The Width Of Dialog radio button controls so that they are as wide as the dialog box. No Change: The No Change radio button may be used if the user does not wish the controls to change size vertically. Shrink To Smallest: The Shrink To Smallest radio button resizes controls vertically so that they are only as tall as the shortest control in the selected group. Grow To Largest: The Grow To Largest radio button resizes controls vertically so that they are as tall as the tallest control in the selected group. Height Of Size Box: Turn on the Height Of Size radio button to resize controls so that they are as tall as the sizing frame. Height Of Dialog: Turn on the Height Of Dialog radio button to resize controls so that they are as tall as the dialog box. Changes to the strings in the Dialog Editor are preferably saved as soon as the input item loses focus; this change is immediately reflected in the translated dialog on the screen. Changes to dimensions of any of the controls are saved when the Save menu option is selected. As shown at 935, the "New Dimension" field is updated for receiving the new dimensions for the re-sized control; the original dimensions continue to be displayed in the "Dimension" field, shown at 933. If the dialog is closed after modifications are made but before the changes have been saved, a dialog box asking if the changes should be saved appears. (d) Bitmap and icon editor Any bitmap that appears in a product should ideally be international. Specifically, such bitmaps and icons should not contain country-specific information (e.g., such as a baseball hat representing a coach). Literal strings should also be avoided in bitmaps and icons. A commercial bitmap editor (not shown), such as Borland's Resource Workshop, may be employed in the system for editing icons and bitmaps, as desired. Such an editor may easily be added to the system through the TShell configuration file. 5. Exemplary translation of resource FIG. 10A illustrates the Page Setup Dialog 1010 from the Windows Notepad Application 1000. Use of the system of the present invention for translating this dialog from English to German will now be illustrated. FIG. 10B illustrates the Dialog Editor 1020, with the "Page Setup" dialog loaded. In particular, Editor 1020 displays Source Dialog 1021 and Target Dialog 1031. The original, English strings for the dialog are shown in the String field 1025. At this point in the example, no new strings have been entered and, therefore, the new string field 1027 appears empty. Similarly, the New Dimension field 1028 stores the same dimension (coordinate values) as the Dimension field 1029. After the end-user translator has interactively translated the various resources, the Dialog Editor (now 1020') appears as shown in FIG. 10C. Note, for this example, that new values have been entered into the New String field and the New Dimension field. In conjunction with these changes, the Target Dialog has been updated to display the new (translated) strings. Similarly, the underlying Translation Table, Table 1050 shown in FIG. 10D, has been updated with the New String and Dimension information. The Translation Table may then be used, in turn, to write out a new resource file, such as the resource file in FIG. 10E (shown compared with the original file). The translated resource file may itself be used, in turn, to build a new translated product. FIG. 10F shows the translated dialog of the final product. Internal operation A. Overview The Export/Import module includes a parsing engine to extract strings and translatable information from application programs. In a windows environment, for instance, the module includes a generic parser for processing Windows .RC files. Thus, it functions as a front end parser to "translatable" sources, providing data conversion as needed. Preferably, it provides upgrade functionality as follows. When as new set of files are parsed, instead of extracting to another table, the module updates any existing translation table with the new strings found in the new files. B. Data container Information extracted by the Export/Import module is stored in the Translation Table database which comprises a table having three major field types: token, English/source, and translation. The token field is a field or collection of fields that makes a given record unique. This is provided to insure that a given record is uniquely represented so that it can be used in data manipulation, merges back to sources, upgrades between versions, and the like. The English/source field stores strings, dialog coordinates, accelerators, and the like found in the sources of the starting language (e.g., English). These entries represent the elements that will differ between the "source language" base product and the "translated" product. Translation fields are fields where the translator enters strings, coordinates, and the like which should replace the ones in the "English" field. Data entry can occur either directly at the database, or by using a translation front end ("Editor"). Other field types include context information, sequential, comments, and user interface. The context information field stores information about the classification of a given string, such as whether it belongs to a menu or dialog. The sequential field is used to determine the context in which other strings are a part. The comment field stores comments which are extracted from the source, so that explanation or limitations to a given string are available to the translator. The specific internal layout of the Translation Table employed in a preferred embodiment is illustrated by the block diagram in FIG. 11. Its particular fields are as follows. The Father field stores the record number of the father of this control; a dialog control, since it has no father, stores zero in this field. The Type field indicates the type of control, such as Dialog (Type equal "D"), String Table (Type equal "S"), Menu (Type equal "M"), and the like. The Translatable field indicates whether an item is translatable (from one language to another). This is determined on the fly (as described by the methods below), based on the Type of the control. The Identifier field stores the resource identifier which is present in the original resource file. Similarly, the Dimension field and the String field store the original dimension and string, respectively, as they appear in the original resource file. The Number field stores a count value, which is used for internal tracking of the records by the system. The Class field stores the resource class, as it appears in the original resource file. The Used field stores a flag for indicating whether this item (record) is used in the translation. When a resource is first imported, Used is set to "Y"es. Then during an update operation (described below), Used is set to "N"o. When a record is located during the update operation (i.e., a pre-existing record is found), Used is then again set equal to "Y"es. If Used is set equal to "I"gnore (which is usually set by the person charged with localizing the software), the record is ignored during update operations. The FileName field stores the file name and line number where the resource can be found in the original resource file. The Comment field stores any comments embedded by the programmer in the original Resource file. Although not shown, a second Comment field may be provided for storing the translator's comments separately. C. Preferred implementation The following description of the Software Translation system of the present invention will focus on the presently preferred embodiment which includes components implemented in an event-driven Windows architecture with the C++ programming language. In particular, an object-oriented model is adopted whereby new objects (e.g., "Dialog" objects) may be derived from existing base classes (e.g., "Item" base class). The general features of C++, including data encapsulation, inheritance, and polymorphism, as well as C++ techniques for implementing class hierarchies and class methods are known; see e.g., Ellis, M. and Stroustrup, B., The Annotated C++ Reference Manual, Addison-Wesley, 1990. Additional information about object-oriented programming and C++ in particular can be found in Borland.RTM. C++: 1) User's Guide, 2) Programmer's Guide, and 3) Library Reference, all available from Borland International of Scotts Valley, Calif. The disclosures of each of the foregoing are hereby incorporated by reference 1. "Item" C++ base class The Export/Import module is implemented as a C++ base class. Each object instantiated from the "Item" class corresponds to a record stored in the Translation Table (as well as a resource read in from a resource file). In an exemplary embodiment, a class of "Item" may be defined as follows:
______________________________________
// Item class definition
// Base class for all translatable resources
class Item {
protected:
char concatLines; // remember the initial value of
//WordFlux::concatlines
ItemRecord *Fields;
// Contains all
//information
Item *Father;
PreprocessedFlux *Flux;
ItemTable *Table;
PreprocessedFlux *GetFlux()
{
if (Father) return Father->GetFlux();
return Flux;
}
ItemTable *GetTable();
// RECORDNUMBER is a define from pxengine.h (avail. from
Borland)
RECORDNUMBER GetRecordNumber();
RECORDNUMBER GetFatherRecordNumber();
virtual void FillFields()=0;
// pure virtual functions overwritten by all the subclasses
// that actually do the work
virtual void UpdateFile()=0;
virtual void CreateChilds()=0;
public:
Item(ItemTable *T,PreprocessedFlux *F);
Item(Item *I);
virtual .about.Item();
ItemRecord *GetFields()
{
return Fields;
}
static DATE Today;
// Paradox date structure
static int NumberProcessed;
// Housekeeping variables
static int NumberTranslated;
static int NumberTranslatable;
static int NumberAdded;
static char WindowRC;
// 1 == windows, 0 == os/2
static char DisplayIdentifiers;
// Display resource identifiers
static char ParseIDs;
// store numeric values of identifiers
static char JapaneseConversion;
// character set conversion routines
static char TaiwanConversion;
static char FontTranslate;
virtual void Build();
// routine to call FillFields, UpdateFile and CreateChilds
};
______________________________________
ConcatLines is a data member used for concatenating lines of text. Fields is a pointer of type ItemRecord, which points to a record storing all the information for this item (i.e., self). Father is a pointer of type Item which points to the owner for this record (item). If this item is a parent itself, then the Father pointer is set to null. A dialog box is one example of a resource which is a parent. If, on the other hand, the resource is a child, then the pointer points to the Father for the resource. Flux is a pointer of type PreprocessedFlux; it is employed for file processing. Table is a pointer of type ItemTable; this points to the underlying translation table itself. GetFlux, GetTable, GetRecordNumber, and GetFatherRecordNumber are methods for processing the records. Their functionality is self explanatory (e.g., GetRecordNumber returns the record number for this item). Next are three virtual methods: FillFields, UpdateFile, and CreateChilds. Each is a pure virtual function, meaning that it will be overwritten by a subclass which, in turn, does the actual work. For instance, a Dialog is derived from the Item class, as will be illustrated below. The Dialog class declares a FillFields method (overwriting the virtual definition), which includes steps specific for filling fields of a dialog-type resource. The UpdateFile method is employed for updating a resource file with the translated strings (which the enduser translator has typed into the new string fields). Since this is specific for each resource type, the method is defined as a pure virtual function in the item class. The method is overwritten (in the subclasses) as needed for servicing each resource type. The method CreateChilds is, like the above two functions, a pure virtual function. It serves to identify children of a resource, by scanning for particular identifiers in a given input stream. As with the other virtual functions, its particular implementation is resource-specific. Accordingly, it is defined in the Item class to be a pure virtual function, with each different subclass (resource type) providing a resource-specific implementation for the method. For a dialog input stream, for example, the identifier "Control" signals a child for the dialog. In a similar manner, for a menu input stream, the corresponding method would look for a "popup" identifier. Continuing with the description of the Item class definition, next are the public methods and data members. The Item class includes constructors and a destructor for initialization and cleanup, respectively. GetFields, the next public method, simply returns a pointer to Fields, which is a protected data member of type ItemRecord. Following these public methods are public data members whose functionality is largely self-explanatory. Today is a data member of type DATE (a Paradox data type), for tracking the current date. NumberProcessed, NumberTranslated, NumberTranslatable, and NumberAdded are housekeeping variables whose functionality is self-evident (e.g., NumberTranslated tracks the number of records translated). WindowRC is a flag for tracking whether the target platform is Microsoft Windows or IBM OS/2. DisplayIdentifiers is a flag for indicating that the system is to display resource identifiers as resources are read. ParseIDs stores numeric values of identifiers (for storage into another field of the table). JapaneseConversion and TaiwanConversion are flags for indicating that a double byte character set (and related conversion routines) is employed, for appropriate treatment for those locales. FontTranslate is a flag for indicating that the font (statement in the resource file) is treated as a translatable item as well. Finally, the class definition concludes with a Build virtual method which is used by the various subclasses to call the above-described FillFields, UpdateFile, and CreateChilds. 2. DoExpimp (main) method FIG. 12A illustrates an Export/Import (DoExpimp) method 1200 of the present invention, which serves to import resources into and export resources from the translation table. At step 1201, the method scans the current input stream, PreprocessedFlux, looking for resources. The method scans the string looking for words it recognizes. As soon as a word is recognized (e.g., "MENU"), the function proceeds to create an "Item" of that type. Specifically, the next resource is identified at step 1202 and an object is instantiated from the "Item" class (for the identified resource) at step 1203. At step 1204, the method builds a translated item. The step represents invocation of a "Build" method for each object of class item created. The Build method in turn, invokes FillFields, UpdateFile, and CreateChilds methods for that resource. At step 1205, the "Item" object is deleted. At step 1206, the translated "Item" is written to file. At step 1207, the method loops back to step 1202 if additional resources remain to be processed. Otherwise, the method has completed. Exemplary implementations for the Build, FillFields, UpdateFile, and CreateChilds methods are described in further detail below. In an exemplary embodiment, an Export/Import (DoExpimp) method may be constructed, as follows (shown in annotated C++ listings):
______________________________________
// Reads the input stream one word at a time looking for the control
// types we are interested in
void DoExpimp(PreprocessedFlux *W)
char PreviousWord›MaxWordLength!;
while (|W->eof ())
{
strcpy(PreviousWord,W->GetCurrentWord());
if (W->GetNextWord())
{
char *currentWord = strdup(W->GetCurrentWord());
{
//...
strupr(currentWord);
if (|strcmp(currentWord, "MENU"))
{
Item *I;
if (|Item::WindowRC)
{
I= (Item *) new Menu(Table,W);
}
else
{
I= (Item *) new Menu (Table,W,PreviousWord);
}
I->Build();
delete I;
}
else
if (|strcmp(currentWord, "STRINGTABLE"))
{
Item *I = (Item *) new StringTable (Table, W);
I->Build()
delete I;
}
//...
else
if ( |strcmp(currentWord, "DIALOG") .linevert split..linevert split.
|strcmp(currentWord, "DLGTEMPLATE") .linevert split..linevert
split.
|strcmp(currentWord, "WINDOWTEMPLATE") )
{
if (|Item::WindowRC)
{
// If we are parsing a Windows RC file,
// Get the Identifier
strcpy (PreviousWord, W->GetNextWord());
}
Item ** = (Item *) new Dialog(Table,W,PreviousWord);
I->Build();
delete I;
}
W->Flush(); // Write translated item to file
}
//...
delete ›! currentWord;
}
}
}
______________________________________
3. Build method FIG. 12B illustrates the Build method 1220 (which corresponds to step 1204 of FIG. 12A). The method, which is a public method of the "Item" C++ class, functions as follows. At step 1221, the method fills the fields of the translation table, for this resource. In a preferred embodiment, step 1221 is implemented as a FillFields pure virtual method, so that each resource may implement its own particular steps according to its type. At step 1222, the method updates the file (Translation Table). Again, this is implemented as a pure virtual method in a preferred embodiment, so that each resource may implement a particular UpdateFile method for its particular type. At step 1223, the method processes any child controls for the current resource. A dialog box, for instance, may include child controls consisting of screen buttons, edit controls, and the like. Again, in a preferred embodiment, the step is implemented as a pure virtual method, CreateChilds, so that each resource may implement appropriate steps for its type. Resource-specific implementations of the above pure virtual methods will now be described. 4. Dialog and Control Fill Fields methods FIG. 12C illustrates implementation of Dialog::FillFields--the FillFields method for a dialog resource. A dialog resource is treated essentially as a container for other resources (e.g., such as buttons, edit fields, and text). Even style information for a dialog resource (e.g., caption, font, and the like) is stored as various children, rather than in the record for the dialog. As a result, the information left for the dialog which is to be stored in the record is simple--the Dialog::FillFields method 1210 is implemented in just two steps. At step 1211, the method sets the Type to "D" ialog. Next, at step 1212, the method sets Translatable to "Y" es. At the conclusion of the step, the method 1210 returns. In an exemplary embodiment, a Dialog Fill Fields method may be constructed, as follows (shown in annotated C++ listings):
______________________________________
// Dialog fillfields
void Dialog::FillFields()
// Identifier is stored in the constructor
// This is verysimple since most of the work is done in
// CreateChilds
strcpy(Fields->Type, "D");
strcpy(Fields->Translatable, "Y");
}
______________________________________
FIG. 12D illustrates Control::FillFields--a FillFields method implemented for controls. Control FillFields method 1220, which provides support for each control which may be placed inside a dialog resource, proceeds as follows. At step 1221, the Type is set to "Control". Depending on how the control is specified in the resource file (e.g., as "Control", "Edit text", "LText", and the like), however, the method must look in different places for pieces of information. Thus at step 1222, a flag (IsControlled) is set for indicating whether the control is specified in generic "CONTROL" style. At step 1223, the control is bound to its Father, by storing the record number for the Father in the "Father" field for this control. At step 1224, the "Translatable" field is set equal to "Y"es, by default. At step 1225, if the control is not a ListBox, ScrollBar, ComboBox, or EditText, then the method proceeds to step 1226 to determine if the control is an icon. Otherwise, the method will proceed from step 1225 to step 1229. For the instance where the resource is an icon (Yes at step 1226), the method proceeds to step 1227 to set Translatable to "N"o. At step 1228, the method has determined that the resource is not an icon but, instead, a resource having a translatable string; the translatable string is stored in the table at this step. At step 1229 the method skips past any comma characters (","), as these may be treated as whitespace characters. At step 1230, the current position in the input string is at the identifier for this resource; the identifier is stored in the table at this step. At step 1231, the method skips past any comma character, if the resource is an icon control. At step 1232, the method parses the identifier and stores its numeric value in the "ID.sub.-- Value" field of the table. At step 1233, the method determines the coordinates (dimension) for the resource and stores them in the table. At step 1234, any control styles (e.g., WS.sub.-- VISIBLE) are stored in the table. Finally at step 1235, any comments (embedded by the programmer) associated with the resource are stored in the translation table. As sources are typically continually upgraded, it is desirable to provide this facility to allow the original developer (i.e., the one who knows the message and its context the best) to document the original message with comments in the source code. The extractions tools, in turn, store these comments in the database. After step 1235, the method returns. In an exemplary embodiment, a Control Fill Fields method may be constructed, as follows (shown in annotated C++ listings):
______________________________________
// Control fillfields
void Control::FillFields( )
// Change to preprocessor state
char ExpandMacros = PreprocessedFlux::ExpandMacros;
PreprocessedFlux::ExpandMacros=0;
// Type == Control
strcpy( Fields.fwdarw.Type, "C");
// Special processing is needed for icons
// and generic "CONTROL" styles
int isIcon = 0;
int IsControl = |strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),
"CONTROL");
// Depending on CONTROL, EDITEXT etc. . fill the class field
strcpy(Fields.fwdarw.Class,GetClass(GetFlux( ).fwdarw.GetCurrentWord(
)));
// bounds the father record number
Fields.fwdarw.Father=GetFatherRecordNumber( );
// it's translatable by default
strcpy( Fields.fwdarw.Translatable, "Y");
// for everything but listbox, scrollbar and editext there is
// a string to grab
if (strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"LISTBOX") &&
strcmpi(GetFlux( ).fwdarw.currentWord( ),"SCROLLBAR") &&
strcmpi(GetFlux( ).fwdarw.currentWord( ),"COMBOBOX") &&
strcmpi(GetFlux( ).fwdarw.currentWord( ),"EDITTEXT") )
{
PreprocessedFlux::DefineActivated=0;
// ICON has a (usually blank) string
if (|strcmpi (GetFlux( ).fwdarw.GetCurrerntWord( ), "ICON"))
// for an icon we want a blank string entry.
{
isIcon = 1;
// Icon is not translatable
strcpy( Fields.fwdarw.Translatable, "N");
GetFlux( ) .fwdarw. GetNextWord( );
}
else
{
getFlux( ).fwdarw.GetNextWord( );
// can have a , after the class name|
while (*GetFlux( ).fwdarw.GetCurrentWord( ) == `,`)
{
GetFlux( ).fwdarw.GetNextWord( );
}
//Store translatable string into fields
strncpy(Fields.fwdarw.String, GetFlux( ).fwdarw.GetCurrentWord( ),
sizeof(Fields.fwdarw.String));
while (*GetFlux( ) .fwdarw. GetNextWord( ) == `"`)
{
Fields.fwdarw.String›strlen(Fields.fwdarw.String) - 1! = 0;
strcat(Fields.fwdarw.String, GetFlux( ) .fwdarw.
GetCurrentWord( ) + 1);
}
}
if (*GetFlux( ) .fwdarw. GetCurrentWord( ) == `,`)
{
while (*GetFlux( ) .fwdarw. GetNextWord( ) == `,`);
}
}
else
{
PreprocessedFlux::DefineActivated=0;
while (*GetFlux( ) .fwdarw. GetNextWord( ) == `,`)
;
}
// All end up at the indentifier field
strcpy ( Fields.fwdarw.Identifier, GetFlux( ).fwdarw.GetCurrentWord( ));
while (strchr("+-*", *GetFlux( ).fwdarw.GetNextWord( )))
{ // Identifiers can be seperated by operators
strcat( Fields.fwdarw.Identifier,GetFlux( ).fwdarw.GetCurrentWord( ));
strcat( Fields.fwdarw.Identifier,GetFlux( ).fwdarw.GetNextWord( ));
}
if (isIcon)
{
GetFlux( ).fwdarw.GetNextWord( );
while (*GetFlux( ) .fwdarw. GetNextWord( ) == `,`)
;
}
if (ParseIDs)
Fields.fwdarw.ID.sub.-- Value = parseString(Fields.fwdarw.Identifier);
PreprocessedFlux::DefineActivated=1;
if ( (WindowRC) && (IsControl) )
// Similar logic for generic "CONTROL" style
{
//. . .
}
if (*GetFlux( ).fwdarw.GetCurrentWord( )==`,`) GetFlux( ).fwdarw.
GetNextWord( );
PreprocessedFlux::DefineActivated=0;
// Now read dimensions into coordinates field
((Dialog*) Father).fwdarw.GetCoordinate(Fields.fwdarw.Dimension);
if (*GetFlux( ).fwdarw.GetNextWord( )==`,`) GetFlux( ).fwdarw.
GetNextWord( );
strcat( Fields.fwdarw.Dimension, ","); // ,
((Dialog*) Father).fwdarw.GetCoordinate(Fields.fwdarw.Dimension);
if (*GetFlux( ).fwdarw.GetNextWord( )==`,`) GetFlux( ).fwdarw.
GetNextWord( );
strcat( Fields.fwdarw.Dimension,","); // ,
((Dialog*) Father).fwdarw.GetCoordinate(Fields.fwdarw.Dimension);
if (*GetFlux( ).fwdarw.GetNextWord( )==`,`) GetFlux( ).fwdarw.
GetNextWord( );
strcat( Fields.fwdarw.Dimension, ","); // ,
((Dialog*) Father).fwdarw.GetCoordinate(Fields.fwdarw.Dimension);
// Parse control styles
// Fill the Style Text Global
( (Dialog*) Father ) .fwdarw. GotoNextControl( );
if ( (WindowRC) && (|IsControl) )
// Variable.
ControlStyle .vertline.= GlobalStyle;
Fields.fwdarw.Style = ControlStyle;
// look for comments
char *comment = GetFlux( ) .fwdarw. GetComment( );
if (comment)
{
strncpy( Fields.fwdarw.Comment, comment, (sizeof(Fields.fwdarw.
Comment)-1));
}
PreprocessedFlux::ExpandMacros=ExpandMacros;
}
______________________________________
5. Update file method FIG. 12D illustrates an Update File (UpdateFile) method 1240 of the present invention which is responsible for writing the contents of the Fields (which are stored in memory as a record buffer at this point) into the Translation Table, which resides on a persistent storage device (e.g., hard disk). In general, the routine proceeds by adding a new record for the item if one does not already exist, or modifying the record if one already exists for the item. The method is also responsible for exporting translated strings into new resources, when the EXPIMP module is exporting. Referring now to FIG. 12E, the steps of the UpdateFile method 1240 are as follows. At step 1241, the method determines if a record for this item already exists. If yes at step 1241, the method proceeds to step 1242 to determine whether the record has been marked as "I"gnore (e.g., by the end-user translator). If the record is not to be ignored, then at step 1243 the record is updated. This is done by filling in the previous translations (if any) and previous values. The Filename/Line Number is updated and the "Used" field is set to "Y"es. Finally, the updated record buffer is then posted back to the table. If at step 1241, a record does not already exist, the method will then proceed to add a new record as follows. At step 1244, the method fills in values in the record buffer, in a manner similar to that described for step 1243. This record buffer is then written to the table as a new record. At step 1245, internal housekeeping variables (e.g., NumberAdded) are set (e.g., incremented), as needed. Note that the test for "I"gnore at step 1242 only applies if a record already exists--one cannot "ignore" a record which has not even been posted yet. Therefore, a "No" at step 1242 causes the method to proceed to step 1244 for posting a new record. The remaining steps of the update file method 1240 handle the exporting of resources to a translated resource file. As noted above, while the Translation Table is being updated with new information, it is convenient to also write that information out to an output stream. At step 1246, if export is requested and the string is one which may be exported, then the method proceeds to step 1247. Otherwise (no at the step), no exporting is required and the method may return. In a preferred embodiment, the test for determining whether an item may be exported includes testing whether there exists original and new strings, whether the item is "translatable", and whether the item is "used". If these conditions hold, then the method proceeds to step 1247 to do character set conversions for the string to export. At step 1248, the method replaces the string in the buffer (output stream) with the new string. At step 1249, the method makes the determination whether the dimensions are to be exported. Exportable dimensions occur when there exists original and new dimensions and the item is either "translatable" or a number. If these conditions hold, then the method proceeds to step 1250 to replace the original coordinates with those specified by the new dimension. At the conclusion of step 1250, the method returns. In an exemplary embodiment, an Update File method may be constructed, as follows (shown in annotated C++ listings):
______________________________________
// Update file
// Routine to find the record if it already exists,
// add a new record if new.
// Also responsible for replacing translated strings if we are exporting
void Item2Table::UpdateFile( )
ItemRecord R;
RECORDNUMBER RecordNumber;
//. . .
{
char fName›80!;
if ((RecordNumber=GetTable( ).fwdarw.Exist(Fields))|=0)
{
// record already exists
GetTable( ).fwdarw.GetRecord(RecordNumber,&R);
if (R.Used›0!|=`I`) // I == `ignore`
{
// Fill in previous translations
strcpy( Fields.fwdarw.NewDimension,R.NewDimension);
if (strlen(R.NewString))
{
strcpy( Fields.fwdarw.NewString,R.NewString);
NumberTranslated++;
}
// Fill in previous values
Fields.fwdarw.Number=R.Number;
Fields.fwdarw.Date=R.Date;
R.ID.sub.-- Value = Fields.fwdarw.ID.sub.-- Value;
// Update file name/line number
sprintf(fName, "%s %5d", GetFlux( ).fwdarw.
GetFileName( ),
GetFlux( ) .fwdarw. GetLineNumber( ));
strncpy(Fields.fwdarw.FileName,fName,sizeof(Fields.fwdarw.
FileName)-1);
// Set used field
strcpy(Fields.fwdarw.Used, "Y");
// . . and update table
GetTable( ).fwdarw.UpdateRecord(RecordNumber,Fields);
}
}
else
{
// New record
//. . .
// Fill in values
sprintf(fName, "%s %5d", GetFlux( ).fwdarw.GetFileName( ),
GetFlux( ) .fwdarw. GetLineNumber( ));
strncpy(Fields.fwdarw.FileName,fName,sizeof(Fields.fwdarw.
FileName)-1);
/* Patch to Inport and Convert ansto850(Fields.fwdarw.String); */
strcpy(Fields.fwdarw.Used, "Y");
// Update table
RecordNumber=GetTable( ).fwdarw.AddRecord(Fields);
// Keep track of housekeeping statistics
NumberAdded++;
}
// More housekeeping
if (Fields.fwdarw.Used›0! == `Y` && *Fields.fwdarw.Translatable==
`Y` &&
strlen(Fields .fwdarw. String) > 2)
{
NumberTranslatable++;
}
}
// Everything after here applies only to exporting
// Export strings
if ( (GetFlux( ).fwdarw.Export( )) && (Fields.fwdarw.NewString›0!)
&& (Fields.fwdarw.String›0!)
&& (*Fields.fwdarw.Translatable==`Y`) && (*Fields.fwdarw.Used==
`Y`))
{
// Do any necessary character set conversions
if (ANSIOEMConversion)
{
oemtoans(Fields.fwdarw.NewString);
}
if (JapaneseConversion)
{
JapanConvert(Fields.fwdarw.NewString);
}
if (TaiwanConversion)
{
TaiwanConvert(Fields.fwdarw.NewString);
}
// Replace the string in the buffer
if (|((ExportFlux*)GetFlux( )).fwdarw.Replace(Field.fwdarw.String,
Fields.fwdarw.NewString))
{
GetFlux( ).fwdarw.FluxError("Cannot replace string in",
Fields.fwdarw.Identifier);
}
}
//Export dimensions
if ((GetFlux( ).fwdarw.Export( )) && (Fields.fwdarw.Dimension›0!)
&& (Fields.fwdarw.NewDimension›0!)
&& ((*Fields.fwdarw.Translatable==`Y`) .vertline..vertline. (*Fields.fwdar
w.Type == `N`))
&& (*Fields.fwdarw.Type |= `O`) && (*Fields.fwdarw.Type |= `D`)
&& (*Fields.fwdarw.Type |= `S`))
{
if (| ((ExportFlux*)GetFlux( )).fwdarw.ReplaceCoords(
Fields.fwdarw.Dimension,Fields.fwdarw.NewDimension,
Fields .fwdarw. Identifier ))
{
GetFlux( ).fwdarw.FluxError("Cannot replace dimension in",
Fields.fwdarw.Identifier);
}
}
// . . .
}
______________________________________
6. Create Childs method Referring now to FIG. 12F, the Create Childs method 1260 for a dialog is illustrated. In general, the method operates by processing each control (i.e., building an "Item" for placement in the Translation Table) that may be contained within the dialog. At step 1261, the Dimension for the dialog is retrieved from the resource file and an "Item" is built for that Dimension. In other words, even though Dimension is not a child control per se, in a preferred embodiment it is treated as such. At step 1262, optional dialog fields (e.g., Caption, Font, Class, and Menu) are retrieved from the resource file and used to build corresponding Items. Thus, these optional fields are also treated as children, although they are not child controls per se. Steps 1263-1265 process the "true" controls of the dialog. In particular, at step 1263, the next control is retrieved from the resource file, and at step 1264 an "Item" object is built with that control. At the end of step 1264, the control has been registered with the Translation Table and the in-memory "Item" object is destroyed. At step 1265, if further controls remain for the dialog, the method loops back to step 1263 to continue processing. Otherwise ("No" at step 1265), the method has completed and may return. In an exemplary embodiment, a Create Childs method may be constructed, as follows (shown in annotated C++ listings):
______________________________________
// CreateChilds
void Dialog::CreateChilds( )
//. . .
// All optional parts of the dialog (STYLE, CAPTION, etc.
// are stored as children of the dialog)
{
// There is always a dimension and it should be next from
// the preprocessor
Item *I = (Item *) new DialogDimension(this);
I.fwdarw.Build( );
delete I;
// Look for begin and parse optional fields
while ((strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"BEGIN"))
&& (*GetFlux( ).fwdarw.GetCurrentWord( ) |= `{`)
&& (strcmpi(GetFlux( ).fwdarw.GetNextWord( ),"BEGIN"))
&& (*GetFlux( ).fwdarw.GetCurrentWord( ) |= `{`))
{
if (|strcmpi(GetFlex( ).fwdarw.GetCurrentWord( ),"STYLE"))
{
GetFlux( ).fwdarw.GetNextWord( );
char style›1024!;
// GetNextToken returns a compound statement
GetFlux( ) .fwdarw. GetNextToken(style);
// Style is stored as a numeric value,
// so evaluate the text string
Fields .fwdarw. Style = parseString(style);
}
// NB GetNextToken leaves the currentword after the
// end of the style.
// so GetCurrentWord is the one we are interested in
if (|strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"CAPTION"))
{
Item *I = (Item *) new Caption(this);
I.fwdarw.Build( );
delete I;
}
else
if (|strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"FONT"))
{
Item *I = (Item *) new Font(this);
I.fwdarw.Build( );
delete I;
}
else
if (|strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"CLASS"))
{
Item *I = (Item *) new DialogClass(this);
I.fwdarw.Build( );
delete I;
}
else
if (|strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"MENU"))
{
Item *I = (Item *) new DialogMenu(this);
I.fwdarw.Build( );
delete I;
}
}
}
//. . .
// tell the preprocessor to evaluate defines
PreprocessedFlux::DefineActivated=1;
// Reads stream until next CONTROL, EDITTEXT, etc
GotoNextControl( );
// should be on CONTROL etc. . . or END
while (strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"END") &&
(*GetFlux( ).fwdarw.GetCurrentWord( )|=`}`) &&
|(GetFlux( ).fwdarw.eof( )))
{
if (|strcmpi(GetFlux( ).fwdarw.GetCurrentWord( ),"CTLDATA"))
{
if (|strcmpi(GetFlux( ).fwdarw.GetNextWord( ),"BEGIN")
.vertline..vertline. *GetFlux( ).fwdarw.GetCurrentWord( ) ==
`{`)
{
GetFlux( ) .fwdarw. GotoNext("END","}");
}
else
if (*GetFlux( ).fwdarw.GetCurrentWord( ) |= `.backslash.`')
{
GetFlux( ) .fwdarw. FluxError("Unrecognized CTLDATA
format",
GetFlux( ).fwdarw.GetCurrentWord( ));
}
GetFlux( ).fwdarw.GetNextWord( );
}
else
{
// Create child control item
Item *I = (Item *) new Control(this);
I.fwdarw.Build( );
delete I;
}
}
PreprocessedFlux::DefinedActivated=0;
// Check for the closing END
if (GetFlux( ).fwdarw.eof( ))
GetFlux( ).fwdarw.FluxError("END or } expected in Dialog",
Fields.fwdarw.Identifier);
}
______________________________________
D. Extensibility As translatable data comes from different types of "source files," different parsing engines can be employed to address the different needs of the various sources. For instance, a parser written to extract translatable strings from a C/C++ source file might be different from one written to extract data from ASM files or Windows resource (.RC) style files. Despite the fact that data are extracted from different types and formats of files, the Translation Table can store all translatable items. Thus, it is a container which serves as a lowest common denominator for storing translatable items from a variety of sources. The parsing engines include the ability to upgrade information. As a new version of a source file is parsed, information which has been previously translated (i.e., from a prior version) is preserved. New items are related to items that they supersede, especially in instances where the new item contains a translation which may apply to the new item. The parsing engine also includes the ability to construct "hybrid builds." During the translation of a "live" product (i.e., a product still under development), the UI continues to be in a state of flux, with translations of new strings not readily available. Nevertheless, there continues to be a need to have access to the product. In such instances, the parsing engine can build a product which is a hybrid. The hybrid consists of a build which employs existing translations in the localized language together with English or machine-generated pseudo language for any new items which have yet to be translated. Advantages By maintaining resource information in a platform-independent Translation Table, the system of the present invention provides a set of tools which may be employed across a variety of platforms for translating programs. The extraction or parsing tools are highly generic, so that new objects may be readily accommodated. Likewise, the editors are highly generic, thus allowing them to be used across diverse platforms and modules. For instance, a menu or dialog box editor employed for Microsoft Windows should also be capable of handling OS/2 style menus and dialog boxes. As long as resource information can be parsed and read into the Translation Table 340, the various tools of the system may be used in a platform-independent fashion. Upon the user inputting a new text string in an editor, the translated resource on-screen illustrates the result. In this fashion, the end user translator can perform a translation on a "live" interface and is thus able to immediately see the results as he or she performs the translation. This approach of the present invention allows developers to see the results of translating as the translation is being done, instead of having to first rebuild the product with translated sources. While the invention is described in some detail with specific reference to a single preferred embodiment and certain alternatives, there is no intent to limit the invention to that particular embodiment or those specific alternatives. For example, the foregoing description of the Item base class and derived classes (e.g., Dialog and Control) has focused on the Microsoft Windows environment; those skilled in the art will appreciate, however, that the system may be adapted for other platforms, including, for example, OS/2, NeXTStep, X-Windows, and the like. Moreover, since the Item class employs pure virtual methods, the adaptation is fairly straightforward. Thus, the true scope of the present invention is not limited to any one of the foregoing exemplary embodiments but is instead defined by the appended claims.
|
Same subclass Same class Consider this |
||||||||||
