Sidebar

Using iTop

Creating your iTop

iTop Customization

"How to" examples
DataModel

User Interface

Automation & Ticket management

Portal Customization

How to translate

Principles

In iTop and iTop modules, a language is identified by two things:

  • The ISO 639-1 language code. Example: pt for Portuguese.
  • The ISO country code. Example: br for Brazil.

Localization relies on dictionary files, which names are prefixed with the language code in lowercase, like : pt_br.dictionary.itop.core.php. Those files are part of the datamodel, so a compilation is needed after each modification (run the setup again or use the toolkit).

In iTop, the embedded dictionnaries are located in :

  • <itop-root>/dictionaries/
  • <itop-root>/datamodels/2.x/<module>/dictionaries

In modules, thoses files are located in the module's root directory.

Since iTop 3.0.0 (N°2969), module dictionarie files can be located either in the module root folder, or in a dictionaries subfolder.
For compatibility reasons, modules distributed as extensions kept their dictionary files in their root folder, but iTop core modules (datamodels/2.x) were modified.

Dictionary file format

A dictionary is in fact a PHP file. It must be encoded in the utf-8 character set (this is a MUST). We recommend that the PHP closing tag be omitted as in the example given below.

<?php
/**
 * Localized data
 *
 * @copyright   Copyright (C) 2015 John Foo Ltd
 * @author      John Foo (john@foo.com)
 * @license     http://opensource.org/licenses/AGPL-3.0
 */

Dict::Add('PT BR', 'Brazilian', 'Portuguese', array(
        'Menu:ChangeManagement' => 'Gerenciamento Mudanças',
        'Menu:Change:Overview' => 'Visão geral',
        'Menu:NewChange' => 'New Change~~',
));

Notes:

  • The first parameter of the function call is the language code in uppercase.
  • The second parameter of the function call is the language name in english.
  • The third parameter of the function call is the language name in the target language.
  • The line Dict::Add must be the same amongst all the dictionnary files for the same language (yes, there are redundant information here).
  • Notice the ~~ at the end of some strings. This suffix is not displayed to the end-user. It is added by Combodo when releasing a new version, revealing which new strings requires a translation.

Some generic rules

  • Keep consistency : Re-use already translated terms (form example “manager” is a word used in many keys)
  • You can keep english terms if they are more understandable in the context
  • Try not to use formulations that are too familiar : iTop is a product used both by companies and its clients
  • Do not hardcode the “iTop” name, use constants instead (they are defined in core/config.class.inc.php) :
    • ITOP_APPLICATION : The complete name of the application package, for example “iTop Community” or “iTop Professional”
    • ITOP_APPLICATION_SHORT : Just the name of the application, for example “iTop”
  • Use camel case for class names
  • There are standards for datamodel items : Class:<classname>, Class:<classname>/Attribute:<fieldname>. For example : Class:Ticket, Class:Ticket/Attribute:ref, Class:UserRequest/Attribute:status/Value:new
  • If you want to translate a field label, do it for the class where the field is defined, and not in child classes. Example : ok for Class:Ticket/Attribute:ref but not Class:Change/Attribute:ref. If you need the later, then just add it to your iTop instance using a customization module.
  • Try not to mention classes in action labels for generic users. This can be done for admin users though. If using a class label, capitalize it : eg Notification instead of notification.
  • A special entry Class:<classname>/Attribute:friendlyname displayed as “Full name” in english if not translated, which do not correspond to a particular class field but to the magic attribute used as the object label on external key, objects list and object details.
Key syntax Purpose Example
Class:<classname> Translating the name of a class Class:Ticket
Class:<classname>/Attribute:<fieldname> Translating a field label Class:Ticket/Attribute:ref
Class:<classname>/Attribute:<fieldname>/Value:<value> Translating a value of a Enum attribute Class:UserRequest/Attribute:status/Value:new
Class:<classname>/Attribute Formating the friendlyname value. (see example below) 'Class:Person/Name' ⇒ '%2$s %1$s'

Friendlyname syntax: In this example

'Class:Person/Name' => '%2$s, %1$s',  /* example: "Christie, Agatha" */ 
  • %1$s correspond to the first field in the naming XML tag of the Person class, so first_name
  • %2$s correspond to the second field in the naming XML tag of the Person class, so name

This allow to specify a different order and even some other characters, separators.

friendlyname
<classes>
  <class id="Person">
     <properties>
        <naming>
          <attributes>
            <attribute id="first_name"/> <!-- mapped to %1$s -->
            <attribute id="name"/>       <!-- mapped to %2$s -->
          </attributes>
        </naming>

Dictionary key naming convention

A new entry should be named after its domain and purpose, starting with the less specific information.

The most commonly used separator is ':' but '/' and '-' could also be found.

'Core:BulkExport:TextFormat' => 'Text fields containing some HTML markup',
'UI:CSVImport:TextQualifierCharacter' => 'Text qualifier character',
'DayOfWeek-Sunday-Min' => 'Su',

Use suffixes to define variations of the same label :

  • '+' means a short description (to be shown in a tooltip most of the time)
  • '?' means help / explanations (could fit on several lines)
'Core:SynchroAtt:update' => 'Update ?',
'Core:SynchroAtt:update+' => 'Used to update the object',
 
'UI:CSVImport:AdvancedMode' => 'Advanced mode',
'UI:CSVImport:AdvancedMode+' => 
  'In advanced mode the "id" (primary key) of the objects can be used to update and rename objects.'
  .'However the column "id" (if present) can only be used as a search criteria'
  .' and can not be combined with any other search criteria.',

When a naming convention is established, then the identifiers should be specified as <name>:<value>, like in the following example:

'Class:Event/Attribute:date' => 'Date',
'Class:Event/Attribute:date+' => 'date and time at which the changes have been recorded',

Note that, in this case, the separator should be '/'.

Enumeration values

Values of an enumeration or enumset, uses its own syntax:

  'Class:Action/Attribute:status/Value:test'      => 'Being tested',
        'Class:Action/Attribute:status/Value:test+'     => 'Action has maybe a different behavior than when in production',
        'Class:Action/Attribute:status/Value:enabled'   => 'In production',
        'Class:Action/Attribute:status/Value:enabled+'  => '',
        'Class:Action/Attribute:status/Value:disabled' => 'Inactive',
        'Class:Action/Attribute:status/Value:disabled+' => 'Action is not effective',

Entry overwrite

A subclass can overwrite the label/tooltips of an attribute (or value), even if the attribute has been defined in one of its parent classes

  'Class:ActionEmail/Attribute:status/Value:test+'       => 'Only the Test recipient is notified',
        'Class:ActionEmail/Attribute:status/Value:enabled+'    => 'All To, Cc and Bcc emails are notified',
        'Class:ActionEmail/Attribute:status/Value:disabled+'   => 'The email notification will not be sent',
        'Class:ActionEmail/Attribute:test_recipient'           => 'Test recipient',

Relationships

There are default Links related action/icon tooltip, pop-up window title and confirmation message, which are listed below.
They can be customized and even specialized per class/linkedset attribute (see below)

1:n relationship

Generic dictionary entry code Usage EN FR
UI:Links:Create:Button+ Tooltip of the plus icon at top-right of the list Create a %4$s Créer un(e) %4$s
UI:Links:Create:Modal:Title Title of the sub-object creation pop-up window Create a %4$s in %2$s Ajouter un(e) %4$s à %2$s
UI:Links:ModifyObject:Button+ Tooltip of the pen icon at the right end of rows Modify this object Modifier cet objet
UI:Links:ModifyObject:Modal:Title Title of the sub-object modification pop-up window Modify %5$s Modifier %5$s
UI:Links:Remove:Button+ Tooltip of the minus icon at the right end of rows Remove this %4$s Retirer cet(te) %4$s
UI:Links:Remove:Modal:Title Title of the sub-object removal from its host pop-up Remove a %4$s from its %1$s Retirer un(e) %4$s de son/sa %1$s
UI:Links:Remove:Modal:Message Confirmation message for the sub-object removal from its host Do you really want to remove %5$s from %2$s? Voulez vous vraiment retirer %5$s de %2$s ?
UI:Links:Delete:Button+ Tooltip of the trash icon at the right end of rows Delete this %4$s Supprimer cet(te) %4$s
UI:Links:Delete:Modal:Title Title of the sub-object deletion pop-up window Delete a %4$s Supprimer un(e) %4$s
UI:Links:Delete:Modal:Message Confirmation message of the sub-object deletion Do you really want to delete %5$s? Voulez vous vraiment supprimer %5$s ?

n:n relationship

Generic dictionary entry code Usage EN FR
UI:Links:Add:Button+ Tooltip of the plus icon at top-right corner of the list Add a %4$s Ajouter un %4$s
UI:Links:Add:Modal:Title Title of the link creation pop-up window Add a %4$s to %2$s Ajouter un %4$s à %2$s
UI:Links:ModifyLink:Button+ Tooltip of the pen icon at the right end of rows Modify this link Modifier cette relation
UI:Links:ModifyLink:Modal:Title Title of the link modification pop-up window Modify the link between %2$s and  %5$s Modifier la relation entre %2$s et %5$s
UI:Links:Remove:Button+ Tooltip of the minus icon at the right end of rows Remove this %4$s Retirer ce %4$s
UI:Links:Remove:Modal:Title Title of the link deletion pop-up window Remove a %4$s Retirer un %4$s
UI:Links:Remove:Modal:Message Confirmation message of the link deletion Do you really want to remove $%5s from $%2s? Voulez vous vraiment retirer %5$s de %2$s ?

Placeholders

  • $%1s: host object class name (localized)
  • $%2s: host object friendlyname
  • $%3s: current tab label within the host object (localized)
  • $%4s: remote object class name (localized)
  • $%5s: remote object friendlyname cautious this placeholder is not available in all usage, check!

Specialized

The above generic entry codes are used unless a more specific entry is defined for a particular LinkedSet (or LinkedSetIndirect) attribute of a given class.

Examples of overwrite logic to take into account the class gender in french:

Dict::Add('FR FR', 'French', 'Français', array(
        'Class:Person/Attribute:team_list/UI:Links:Add:Button+'         => 'Ajouter une %4$s',
        'Class:Person/Attribute:team_list/UI:Links:Add:Modal:Title'     => 'Ajouter une %4$s à %2$s',
        'Class:Person/Attribute:team_list/UI:Links:Remove:Button+'      => 'Retirer cette %4$s',
        'Class:Person/Attribute:team_list/UI:Links:Remove:Modal:Title'  => 'Retirer une %4$s',
        'Class:Team/Attribute:persons_list/UI:Links:Add:Button+'        => 'Ajouter une %4$s',
        'Class:Team/Attribute:persons_list/UI:Links:Add:Modal:Title'    => 'Ajouter une %4$s à %2$s',
        'Class:Team/Attribute:persons_list/UI:Links:Remove:Button+'     => 'Retirer cette %4$s',
        'Class:Team/Attribute:persons_list/UI:Links:Remove:Modal:Title' => 'Retirer une %4$s'
));

End-users portals

If you add a new end-users portal, you might want to create a dict. entry so it has a real label, to do so follow this synthax:

// Default portal
'portal:itop-portal' => 'Standard portal',
'portal:<YOUR_PORTAIL_ID>' => 'Your new portal label',

UI themes

If you create a new theme for the backoffice, you might want to create a dict. entry so it has a nice label when users will select it from the preferences page.to do so follow this synthax:

// Default theme
'theme:fullmoon' => 'Full Moon 🌕',
'theme:<YOUR_THEME_ID>' => 'Your new theme label',

How to contribute to improve an existing language

You'll have to create a fork from iTop main repository or the corresponding module repository, then do your modifications and propose them using a pull request : see the CONTRIBUTING.md file in the repo you're modifying for details.

A detailed procedure on pull request model is available in the GitHub help pages : Creating a pull request from a fork.

To add translations to an existing language : look for (grep) the ~~ and translate them in place.

Here is a quick Linux command line to find all dictionary entries (of the German (=de) language) with the ~~ tag:
find -name "de*dict*.php" | grep -v "env-" | xargs grep "~~"

Simply change de* in the command above by the language code you want to process (fr, it, sp…) and launch this command from the directory where you installed iTop.

To add translations for a new language : find out your language code and country code. Copy the english files (either dictionary.*.php or en.dict.*.php) into their respective directory, with the relevant prefix (like in pt_br.dict…). Translate them.

Do not forget to change the parameters of the Dict::Add function calls. Failing to do so will overwrite (at runtime) the english texts with yours.

The pull request will then be analyzed by Combodo maintainers, and eventually merged into the original repository.

latest/customization/translation.txt · Last modified: 2024/09/10 10:25 (external edit)
Back to top
Contact us