User translations
User translations provides the user of a Microbizz solution to provide own translations to own data, such as custom field names, task status'es, info boxes etc.
See Translation.
Type of languages
System language
The system language can be understood as the language which the system talks, and therefore must be one of the languages that Microbizz is translated into.it
Base language
The base language is the language in which the users start their texts, and will usually match the system language, except if the user uses a language which isn't available as a system language. The base language must be one of the language that Microbizz is translated into. All data entered into Microbizz such as custom field names, are considered to be entered using the base language.
Other languages
A number of other languages can be defined, which is languages that the data will be translated into, so everything is translated from the base language to one or more other languages. Other languages must be selected from the languages Microbizz is translated into.dit
Which language to display ?
When logging in a user (or person, if on xnet) should be able to select between all languages (system, base and other).
If the user selects the base language, then phrases should be chosen in the following order:
The phrase in the base language as stored in the translation system.
The phrase as typed directly in Microbizz.
If the user selects another language than the base language:
The translation as stored in the translation system.
The phrase in the base language as stored in the translation system.
The phrase as typed directly in Microbizz.
Translateable objects
The following types of objects may be translated:
type | objectcode | objectid | subid | subsubid |
---|---|---|---|---|
Question form name | “question_form_name” | ID of the q.form | not used | not used |
Question form question | “question_form” | ID of the q.form | The 'hardid' of the question | 0 for the actual question |
Question form question option (A) | “question_form” | ID of the q.form | The 'hardid' of the question | 1..N : The index of the option |
Custom field name | “customfields” | ID of the field | 0 for the field name | not used |
Custom field option (B) | “customfields” | ID of the field | 1..N for the index of the option | |
“Types” (C) | <tablename> | ID of the type | not used | |
Headline of infoboxes (on startpage) | “infobox_name” | ID of the box | not used | not used |
Help text for infoboxes | “infobox_helptext” | ID of the box | not used | not used |
Extranet (D) | “xnet_menu” | ID of the xnet page | ||
Extranet | <fieldname> | ID of the xnet page |
(A) For the question types “dropdown”, “radio” and “select multiple”.
(B) For the field types “One of many” or “Multi check” etc
(C) Person types, work areas, customer types, equipment types, task status etc. The modcode should be set to types
and the objectcode should be set to the name of the table holding the types. TODO what if each type includes multiple translateable phrases ?
(D) There are other extranet texts that should be translateable, like the login page, and the frontpage.
Translation structure
A translation is structured as follows:
modcode | Module in which the base phrase occurs. |
---|---|
objectcode | A unique string naming the object where the base phrase occurs, ie. “customfield”. |
objectid | A unique ID identifying the specific object where the base phrase occurs ie. “49”. |
subid | An optional sub-ID identifying a subpart of the specific object where the base phrase occurs. |
subsubid | Used in case each sub-ID may refer to multiple phrases. |
basephrase | The base phrase in the base language. |
translations | The translations of the base phrase. |
translation_statuses | The status of each translation. See later. |
changedate | The date of last editing |
changetime | The time of last editing |
The translation structures for a custom field named: “Antenna position” with the following options: “On roof”, “On ground” could look like this:
modcode | objectcode | objectid | subid | basephrase | translations | translation_statuses |
---|---|---|---|---|---|---|
todo | customfields | 49 | 0 | Antenna position | DA:Antenneposition SE:Antenneposition | DA:1 SE:1 |
todo | customfields | 49 | 1 | On roof | DA:På taget SE:På taket | DA:1 SE:1 |
todo | customfields | 49 | 2 | On ground | DA: På jorden SE:På marken | DA:1 SE:1 |
If the same field is editable in a question form, the translation structure for the question could look like this:
modcode | objectcode | objectid | subid | subsubid | basephrase | translations | translation_statuses |
---|---|---|---|---|---|---|---|
todo | question_form | 32 | 2 | 0 | Antenna position | DA:Antenneposition SE:Antenneposition | DA:1 SE:1 |
todo | question_form | 32 | 2 | 1 | On roof | DA:På taget SE:På taket | DA:1 SE:1 |
todo | question_form | 32 | 2 | 2 | On ground | DA: På jorden SE:På marken | DA:1 SE:1 |
Translation status
Each translation keeps a status, as follows:
0 | Missing. The translation is missing. |
---|---|
1 | OK. The translation is entered and considered correct. |
2 | Tainted. The translation is entered, but is not necessarily correct. |
When a base phrase is added, then all translations are considered missing, but as they are entered they will become OK. If the base phrase at some point is changed from the original all existing translations becomes tainted, to indicate that they most likely doesn't represent a valid translation anymore.
If a tainted translation is edited and saved, it is automatically considered OK again.
Adding and removing phrases
Some phrases are added and removed on the fly as data is created in the system, while other very basic phrases such as yes and no are added to the system by default.
Updating an object
Things like task state is sent to the app in text form, So if the translation of a task state changes then all tasks in that state need be marked so that they will be resend to the app.
Changing base language
If the base language is changed and translations are present, the following takes place:
The old base language becomes another language and all base phrases are copied to the appropriate translations for that language.
If the new base language earlier was another language with translations present, these translations are copied into the base language. In the case where a translation isn't available, the former text is kept (even though it is in a wrong language).
Using the translations
The various classes should register/unregister phrases as necessary, based on the fields that may be translatable, and should subsequently call Translation::getPhrase()
or trt()
when a translatable field is displayed, typically in gvd()
.
Types
“Types” classes like Workarea, PersonType, TodoState etc should use Translation::getPhrase()
or trt()
when gvd()
is called for the object title.
The classes should also set “registertranslations” in the Record2 definition in Record2::getClasses()
- this will allow Record2 to handle the registering of phrases whenever an object is saved.
When editing a “type” object the input field for the object title should be an FTextTranslate, eg. for equipment types:
$trans = new Translation('tools', 'tools_group', $obj->toolgroupid); $form->addField(new FTextTranslate(l('Type name'), 'groupname', true, array('width' => 250, 'trans' => $trans)));
When the form is submitted, Record2 will update the base language translation and taint the other translations for the other languages.
Extranet
Each XnetPagexxx class should include a list of the fields that can be translated:
public $translation_fields = array('pagehtml', 'disclaimer');
Thanks to the way HTML editable fields are handled by Xnet you will have to specify pagehtml
instead of pagetext
for the pagetext
field.
Retrieving the translated phrase is done using trt()
:
$text = trt('xnet', 'pagetext', $this->pageid, $this->pagetext);
Input fields
The field FTextTranslate can be used instead of FText for text that should be translatable.
The FTextarea field provides a function makeTranslatable()
which makes it translatable. I
$trans = new Translation($modcode, $objectcode, $objectid, $subid); $field = new FTextTranslate(l('Name'), 'name', false, array('trans' => $trans)); $field = new FTextarea(l('Description'), 'desc', false); $field->makeTranslatable($trans);
If a <textarea>
use the HTML editor (puny_mce) then it is necessary for Javascript to call
translation_adjust_textareaHTML($('textarea'), false);
This will adjust the onscreen position of the translation icons for the <textarea>
.
javascript
The javascript for editing translation should be initialized by calling translation_init()
when the editing form has been loaded.
Javascript generates events when the 'globe' icon is clicked for editing, and when the translations are about to be saved.
If the page allows editing of multiple objects with different modcodes or object codes or object IDs etc then it is necessary to update the translation ID when an object is selected for editing/translation. This is done using e.g. translation_set_objectid(objid)
or translation_set_subid(subid)
. These may only be called from the translation_xxx
events.
You may use translation_set_future_objectid(objid)
at any time; the next time the translation dialog is opened the object ID is then set.
Record2
The class definitions in Record2::getClasses()
may include a field registertranslations
which (when present) allows Record2 to automatically register translatable phrases when an object is saved, and unregister them when the object is removed.
registertranslations
may either be a bool (true
to enable auto.reg., false
to disable), or a string (will be used as the objectcode for the translation, instead of the DB table name), or an array (in case there are multiple translatable fields in the class, see UserSkill for an example).
App / API
Some API calls include the textual name of eg. a task status. Thus the information in the app may be incorrect if the translation of the task status changed. The function Translation::changed()
time-stamps the tasks (or whatever) when the translation changes, so that they will be resent to the app.