Servicely Configuration
Localisation
34 min
servicely supports multiple locales and localisation of messages into multiple languages, dynamic translation of fields and the ability to install language packs (a kind of specialised application) that contain localizedmessage records for a specific language all of this is configurable using application properties firstly, note that servicely refers to locales using language regions it also refers to languages using the locale name of the primary region rather than the language name itself, so for example the english language is referred to as en us, rather than as en , in script environments and platform code it is important to note at the outset that a locale is not the same as a language a locale is rather a set of standards for a region for items such as presentation of dates, times and numbers, names of days of the week, whether the week starts on sunday or monday, whether time is presented in the 12 or 24 hour clock and so on a language (and by extension a language pack) is a set of localisations of the messages of the application into a target language some locales share the same language for convenience and only differ in the other standards for example united states english ( en us ) and australian english ( en au ) are different locales that share the same language (also known as en us ) so there is only one localisation for each message one can still provide specific localisations for either locale, for example the message key " trash bin name ” could be localised as trash in en us and rubbish bin in en au but the base product doesn’t include them by default the default locale for servicely is en us and the default language is en us localizedmessage records for en us are stored directly in the applications themselves other languages should have their localizedmessage records in a language pack (a kind of application) which is not installed by default locales servicely now supports the unicode cldr standard https //cldr unicode org/ https //cldr unicode org/ for all locale information and use of the localesettings table has been discontinued a new localecustomization table has been added to allow custom definitions for date and time formats in cldr format if the default ones are not suitable supported locales with the introduction of release 1 8 servicely support a number of locales in the base product a number of them share the same language as detailed in the following table locale name default language af za afrikaans af za de de german de de en au english (australia) en us en gb english (united kingdom) en us en us english (united states) en us en za english (south africa) en us es cl spanish (chile) es es es es spanish (spain) es es fr fr french (france) fr fr hy am armenian (armenia) hy am id id indonesian (indonesia) id id lo la laotian (laos) lo la nl nl dutch (netherlands) nl nl pt br portuguese (brazil) pt br pt pt portuguese (portugal) pt pt ru ru russian (russia) ru ru th th thai (thailand) th th tr tr turkish (türkiye) tr tr uk uk ukrainian (ukraine) uk uk zh cn chinese (china) zh cn cldr information for each locale is included in the ui, along with localisations for many third party ui components new locales can only be added as part of a new release of the base platform an installation of servicely can determine whether that want to support multilingual capabilities and for which languages and locales by setting application properties appropriately a list of properties and their meaning is in the following table property default value meaning system multilingual false whether to enable multiple language support in the ui including the language switcher and localised message fields certain tables system supported locales en us, en au, en gb, en za, fr fr, de de, nl nl, es es, es cl, pt br, pt pt, af za, id id, ru ru, hy am, uk ua, th th, lo la, tr tr, zh cn locales to display in the language switcher and the preferredlanguage field on a user record system supported languages en us, fr fr, de de, nl nl, es es, pt br, pt pt, af za, id id, ru ru, hy am, uk ua, th th, lo la, tr tr, zh cn languages that are displayed in ui tools for localised message generation note that a multilingual installation is still possible even if system multilingual is set to false this is because a role of language editor is available which enables it for users with that role they can generate localisations, edit localised fields and switch languages but for users without that role they will see a monolingual installation but with the localisations determined by their preferredlangage setting (which will be read only) a installation should determine what locales and languages it wants to support by editing the application properties the default locale and language en us is supported even if the properties are empty or missing locale switching if system multilingual is true then a locale switcher component is available in the menu bar it displays the list of locales that are configured in the installation, in the language of the current locale by choosing a locale off the list the current users preferredlanguage is changed to the selection and the page reloaded a flag is displayed in the menu bar to indicate the current locale in this sequence of images the locale is changed from united states english to french localisation fields some tables were developed before their localisation needs were apparent these tables have been enhanced with additional localised message fields as a complement to the existing monolingual fields, and all display templates have been modified to use the localised message fields (if they have a value) before using the monolingual fields the localised message fields are hidden if system multilingual is false so as to not cause confusion the localised message field names are based on the monolingual field names with the word localized as a prefix, so the complementary field for description is localizeddescription on a form they have the word display as a prefix in the title and immediately follow the monolingual field as in this example of a catalogitem the localised message fields visible are display name , display summary and display button text the tables affected by this are table localised message fields child tables templatereport localizednamelocalizeddescription questionitem localizednamelocalizeddescriptionlocalizedsummarylocalizedbuttontext catalogitemriskassessmentitem report localizednamelocalizeddescriptionlocalizedtitle dashboard localizednamelocalizeddescription reportdashboardportalpage question localizedsectiontitle catalogcategory localizednamelocalizedsummary locale customisations prior to release 1 8 servicely used the localesettings table to store the definitions of locale properties, such as date and time formats and some number formats with the introduction of the cldr this table is no longer necessary and is no longer used some existing installations did use it though for customising the date and time formats from the servicely defaults to support those customers a new table localecustomization has been introduced that only contains date and time customisation fields in cldr format the cldr has the concept of skeleton and custom formats a skeleton format is a name like short or long that is an abstraction that can be applied in any locale and reduces the need to explicitly specify in detail what the format contains a custom format contains the full detail including placement of the various elements of a date or time and other indictors such as am/pm the servicely default formats are type format is skeleton notes short date short y long date ymmmed y short time short y long time medium y short date time short y commonly replaced by short date + “ “ + short time long date time medium y commonly replaced by long date + “ “ + long time the localecustomization table allows the override of any of these values for a locale and allows either skeleton or custom formats if you want to use a 24 hour format, you can update the short and long time format to be hh\ mm\ ss , which will be 23 50 30 for example, and if you add an a, such as hh\ mm\ ss a, it will also include pm/am localisation packs localisation packs for all supported languages are available as special applications listed in the application languages section they only contain localizedmessage records if they are installed using the standard procedure then those messages are available when a locale using that language is selected using the locale switcher currently only the french ( translations fr fr ) and german ( translations de de ) localisation packs are populated with messages by servicely for out of the box use we will be continually improving the translations in the packs to make them more accurate the translations language pack is empty but deployed and is used when experimenting with localisation generation in order to not modify the default ones there is no english localisation pack because those localisations are directly included in the default installation if a customer is generating localisations for a specific language in bulk then it is recommended that the appropriate language pack be installed and the messages generated into there this allows management of the localisations to be easier installation of a localisation pack is a short procedure and usually takes less than a minute they take effect immediately localisation servicely provides a number of mechanisms for localisation entry points, i e places where a localised message can be substituted for a base message, or for a localisation message key some of the mechanisms are based on the internationalisation tools that are part of the angular web framework because the majority of the servicely ui is angular, including catalog, portal and modal components localisation in angular angular provides the means to localise messages in the html template and the typescript code of a component servicely uses the html template approach as is, but provides a variation on the standard typescript approach that provides more flexibility and allows for development of components without needing to initially create localizedmessage records the official documentation can be found at https //angular io/guide/i18n overview https //angular io/guide/i18n overview localisation in an angular template an angular template can indicate localisation points by using custom html tags the i18n tag indicates that the element contents will be replaced with the localised message, while the i18n xxx tag indicates that the xxx attribute will be replaced with the localised message this is useful for replacing text such as the href of an anchor tag angular message keys have a marker prefix of “@@” but those characters are not used in the localizedmessage table, for example the message key "@@ng aaa bbb" is what would be used in the template while "ng aaa bbb" would be the message key for the record here is an example of markup from a template \<a i18n href="@@ng 0a00000a72811a1181728242dbb22f81 portalcomponent template demo href" href="http //default place com"> \<span i18n="@@ng 0a00000a72811a1181728242dbb22f81 portalcomponent template demo label"> the default place is {{place}} \</span> \</a> the body of the span and the href of the anchor will both be replaced by a localised message if one exists note that it is necessary to supply a default value for anything that is to be localised otherwise the substitution will not be made the default value is also used to derive the structure of the message format itself in the localizedmessage table note that the default message is the default place is {{place}} which has an embedded angular expression {{place}} this indicates that a variable is to be substituted in that part of the string usually a member variable of the component itself because it has a substitution point the messages in the localizedmessage table should also have a substitution point, and they will look like the default place is {0} , or le lieu par défaut est {0} this allows messages to be built up using the natural order of the localisation, for example one could imagine a language where the natural order would be xxx {0} yyy zzz, and the substitution of ‘place’ will still be at the {0} position messages can have an arbitrary number of substitution points indicated by {0}, {1} etc message formats in general also support named substitution points and number and plural substitution points but servicely does not at the moment the message key is designed to allow support for automated tooling to extract messages, which will be developed in a future release the format of the key is as follows, where name suffix can be anything you like but without spaces ng id tablename fieldname name suffix these can be generated easily inside a servicely code editor using the context menu or the key sequence central f12 (or cmd f12 on macos) if there is no localisation for the current locale (i e the users preferredlanguage) then the default message value is used instead this allows components to be built without having to add the en us message immediately localisation in an angular component in component code we can use the $translate function to perform localisation on template literals a template literal is a string wrapped in backticks ( ` ) that can have substitution points in a similar fashion to a default message in an angular template $translate is a function that operates on template literals and knows how to localise them, or how to construct the default message if there is no localisation available an example of such a function call would be let msg = $translate('ng 0a00000a719518168171966aa7a50a19 portalcomponent template approve error')`error approving ${response responsetext}`; $translate takes a parameter which is the message key and returns a function that can operate on the string `error approving ${response responsetext}` which is a template literal with one substitution point an equivalent localizedmessage would be erreur d'approbation {0} the return value of the $translate function call will be the localised message the default message is constructed from the parts of the template literal and the substituted strings if it is necessary to use that instead it is also possible to just supply a key in which case the call would be let msg = $translatekey('ng 0a00000a719518168171966aa7a50a19 portalcomponent template approve error'); localisation in server scripts server scripts (and script libraries) can use $translate and $translatekey in a similar fashion to an angular component it is also possible to use an older form like this let msg = i18n message("message key"); generating localised messages using a translation service it is possible to generate localised messages using a cloud translation service if the appropriate system properties are set and an access key is supplied as a bearer token servicely supports two translation services for release 1 8 google translate or openai configuration the relevant application properties are property default value meaning system translation service google whether to use google translate ('google') or openai ('openai') for generated translations ai openai token name openai name of the bearer token used to access openai ai openai organization id id of the organisation that supplies the bearer token ai openai model id gpt 4 openai model used to generate translations release 1 8 uses gpt 4 system translation openai prompt varies depending on customer… prompt sent to openai to fine tune translations for the servicely application there should be at least one systemapioutboundtoken record containing the bearer token for the translation service that is being used name type meaning google api translation key bearer bearer token for google translate openai bearer bearer token for openai generation localised messages can be generated using a server script they are currently done manually on the standard server script page, e g https // servicely ai/#/view/serverscript the common approach is to generate missing localised messages for a target locale relative to a source locale, usually en us the messages are generated into the localisation packs mentioned above so that they are all contained in one place for ease of management in this way the entire application can be localised in a short period of time note that if more components are developed then their messages can be generated in the same way (i e only doing the missing ones) without affecting already generated ones all the commands are part of the translation server script library translate a message note that this does not create a localizedmessage record, it is for testing the integration with a translation service if a fromlocale is not supplied the translation service will assume en us translation translate(tolocale string, text string) string? translation translate(fromlocale string, tolocale string, text string) string? translation translate(fromlocale string, tolocale string, text list\<string>) list\<string?> translation translate("fr fr", "i am an elk"); // will return "je suis un élan" list missing translations this will list all the messages that are in fromlocale but not in tolocale for the application identified by applicationnameorid if fromlocale is not supplied then en us is assumed if applicationnameorid is " " then all messages for all applications are listed translation listmissingtranslations(tolocale string, applicationnameorid string) list\<localizedmessagerec> translation listmissingtranslations(fromlocale string, tolocale string, applicationnameorid string) list\<localizedmessagerec> let missing = translation listmissingtranslations("fr fr", " "); // will return about 7500 records for a locale that has not had any messages translated generate missing translations this will generate all the missing messages using the translation service generally takes about two minutes to do a complete set of 7500 messages if fromlocale is not supplied then en us is assumed if fromapplicationnameorid is " " then all messages for all applications are checked the target application is toapplicationnameorid and should be one of the localisation packs translation generatemissingtranslations(tolocale string, fromapplicationnameorid string, toapplicationnameorid string) list\<localizedmessagerec?> translation generatemissingtranslations(fromlocale string, tolocale string, fromapplicationnameorid string, toapplicationnameorid string) list\<localizedmessagerec?> translation generatemissingtranslations("th th", " ", "translations th th"); // will generate about 7500 records into the thai localisation pack generate localised message generate localised messages for the supplied keys if fromlocale is not supplied then en us is assumed translation generatelocalizedmessage(tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key string) localizedmessagerec? translation generatelocalizedmessage(fromlocale string, tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key string) localizedmessagerec? translation generatelocalizedmessage(fromlocale string, tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key list\<string>) list\<localizedmessagerec?> translation generatelocalizedmessage("nl nl", "platform", "translations nl nl", "common button create"); // makes a single dutch localised message in the correct localisation pack replace localised message replaces an existing message with a better translation translation replacelocalizedmessage(locale string, applicationnameorid string, text string, replacement string) list\<localizedmessagerec> translation replacelocalizedmessage("fr fr", "translations fr fr", "non", "non"); // sometimes google translate make words all uppercase patch localised message replace a substring of a message with a better substring translation patchlocalizedmessage(locale string, applicationnameorid string, text string, replacement string) list\<localizedmessagerec> translation patchlocalizedmessage("fr fr", "translations fr fr", "jacques", "pierre"); // renames all the people copy localised message copy messages from one locale to another this is used when the translations have be the same in both locales and you don’t want them picked up by the missing translation detector if fromlocale is not supplied then en us is assumed translation copylocalizedmessage(fromlocale string, tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key string) localizedmessagerec? translation copylocalizedmessage(locale string, fromapplicationnameorid string, toapplicationnameorid string, key string) localizedmessagerec? translation copylocalizedmessage(fromlocale string, tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key list\<string>) list\<localizedmessagerec?> translation copylocalizedmessage(tolocale string, fromapplicationnameorid string, toapplicationnameorid string, key list\<string>) list\<localizedmessagerec?> translation copylocalizedmessage("es es", "itsm", "translations es es", "table incident name"); // we want the incident table in spanish to also be called incident delete translation deletion one or more translations translation deletetranslation(locale string, applicationnameorid string, key string) list\<string?> translation deletetranslation(locale string, applicationnameorid string, key list\<string>) list\<string?> translation deletetranslation(locale string, applicationnameorid string) list\<string?> translation deletetranslation(locale string) list\<string?> translation deletetranslation("th th"); // delete all thai localised messages dynamic translation if you have a translation service set up with an access key it is possible to mark specific fields as supporting dynamic translation an application property needs to be enabled first property default value meaning system dynamic translation false whether to enable dynamic translation by setting the field level renderer property “ dynamic translation " to true a translate button will appear against that field when clicked it will place the translation alongside or below the field itself translations are also possible for standard journal entries (but not for audit history entries) note that the renderer property is at the field level not the view definition level and is accessed from the context menu on the field the translate button is a small multilingual icon when clicked a translation into the current locale is performed using the cloud translation service the same applies for journal entries refreshing the form will clear the translations being displayed