The challenges that are often encountered with multilingual solutions stem from the fact that business needs evolve over time. This could mean that an existing application needs to be altered to include additional content. Another common need that arises is that a new language may have to be added to an application.
Back in 2017, Anh-Thu Chang wrote a blog on Building multilingual apps in PowerApps. Some of the things discussed in this article relate to her blog post and build on the general concept.
Overview
The enterprise-wide solution proposed in this article will address key elements for creating an architecture that can support a number of languages across all PowerApps with an organization. These elements include:
- Language Determination
- Central Label Repository
- Central List Repository
- Performance
Language Determination
There are numerous ways to change languages in Office 365 as described in my previous article, Working in different languages in Office 365. For the solution described in this article, I'm using the Office 365 Account settings for the user. By doing so, I'm able to access a users preferred language in PowerApps using the Office 365 Users connector.
Language settings are made up of two components. The first two letters, representing the language, a hyphen, and then two more letters representing the locale. For example, English for Canada is represented as en-ca, while English for US is en-us. In my case, I only care about the language and not the locale.
If you choose to capture both, you can definitely do so. However, keep in mind that users within the same region may not pay attention to the locale and only pick the language. If that is the case, then they may not experience the PowerApp in the language that they expect to.
When the app is launched, the following expression is added to the OnStart() property for the app:
Language settings are made up of two components. The first two letters, representing the language, a hyphen, and then two more letters representing the locale. For example, English for Canada is represented as en-ca, while English for US is en-us. In my case, I only care about the language and not the locale.
If you choose to capture both, you can definitely do so. However, keep in mind that users within the same region may not pay attention to the locale and only pick the language. If that is the case, then they may not experience the PowerApp in the language that they expect to.
Set(preferredLanguage, Coalesce( Left(Office365Users.MyProfileV2().preferredLanguage, 2), "en"));
The expression gets the user's preferred language from their Office 365 account setting. It picks the two left-most characters and stores it in a global variable called preferredLanguage. I use the Coalesce expression to set the default to English (en) to avoid situations, where a user does not pick a language or other reasons that the preferredLanguage may be empty.
Central Label Repository
The Central Label Repository is used to store all the strings that are used across all the apps. For simplicity of management, I have chosen to use a SharePoint list to achieve this. If you go down this route, you need to make sure that all your users will have at least read access to this list.
There are four pieces of information that are needed for each label:
There are four pieces of information that are needed for each label:
- Title - a group for the label. For this, I typically use the App name
- Field Name - the name of the control that this label applies to.
- Label - what is the string that should actually appear
- Lang - the two-letter language code
Reuse of Labels
There are often labels that are commonly used across numerous forms, such as OK, Cancel, Yes, No, etc. Rather than defining them for each form, you can create a general group and put them in there. This will ensure consistency between the labels used across the various forms and reduce the overall SharePoint list size.Loading the labels
After the preferred language has been determined, each app needs to load the string labels into its memory. This is done after the preferredLanguage has been determined. The expression below loads the strings from the SharePoint list into a collection called StringLabels.
ClearCollect(StringLabels, GetStringLabels.Run("Update My Profile", preferredLanguage));
Loading of the strings from SharePoint into the app can be done by either loading the entire SharePoint list and then filtering the values during run-time or using a Flow to filter out the specific labels required and returning those to the PowerApp. When the list of items gets long, as in the case of defining labels for an entire organization, loading and filtering the entire list within the app may have an implication on performance. This is why I elected to go with the latter method. In the expression shown above, I have a Flow called Get String Labels to which I pass the name of the label group (e.g. Update My Profile) and the language. The Flow then filters the list on these two columns and returns all relevant items
Setting Control Labels
Once the labels have been loaded into a collection, you can now use them to set the text of your controls. For example, if I have a label called lblCity, then I set the Text property as follows:Coalesce(LookUp(StringLabels,FieldName = "lblCity",Label), "lblCity")
The Lookup expression searches for an item, where the FieldName is lblCity and returns the Label value. Coalesce is used to provide a default value in case the label has not been defined for the specific language. In my case, I make the default Coalesce value the same name of the label as it makes it easier to visually know what labels are missing in my SharePoint list.
Central List Repository
Similar to the central label repository for static labels, you can create a SharePoint list that will include related, such as in drop down lists, radio buttons, and other collection. The values captured for each list entry are a bit different from the labels:
- Title - a group for the list item
- Field Name - the name of the control that this list applies to
- Label - what is the string that should actually appear for the list entry
- Field Order - in what order should the labels appear in the app
- Lang - the two-letter language code
Loading the list items
Loading o the list items occurs in a way similar to the labels. However, each group of items is stored in its own collection. The expression below loads the options for rooms with curtain rods for a drop down list called drpCurtains.
ClearCollect(drpCurtains,GetListItems.Run("Account", "drpCurtains", preferredLanguage));
Here, I use a similar Flow that filters the list based on the app, list field, and preferred language and sorts the results based on the FieldOrder
Distinct(drpCurtain,Label)
The Distinct ensure that there are no duplicate fields in my list. Label indicates that from within the collection, the Label field values should be displayed in the list.
Setting List Items
Once the list items have been loaded loaded into a collection, all you need to do is make that collection the source of your list control. For my drpCurtain field, the :Distinct(drpCurtain,Label)
The Distinct ensure that there are no duplicate fields in my list. Label indicates that from within the collection, the Label field values should be displayed in the list.
Performance
I have implemented the architecture described above in an organization that uses around 40 different forms with over 2,000 labels and 15,000 list values successfully. There are, however opportunities to improve the performance. Labels and list items are elements that typically don't change too often. Therefore, rather than loading the values from a SharePoint list each time the app is opened, it would be better to first perform a query to see if values have changed. If there were changes, then the labels and list items should be loaded from SharePoint and also stored in the app's offline cache. If labels have not changed, then the labels and list items should be loaded from the app's cache.
One way to implement such a check is to keep a timestamp of the last update for the list and before loading the labels check if there were any additions or changes before that date.
One way to implement such a check is to keep a timestamp of the last update for the list and before loading the labels check if there were any additions or changes before that date.
Conclusion
The need for multilingual solutions is increasing as organizations are expanding. With the proliferation of business productivity solutions, the need to provide a localized user experience is also growing. I hope this article provided you with a good overview on making your enterprise PowerApps a multilingual success.
No comments:
Post a Comment