To localize a UWP app, a developer needs to do a few things:
- create Resources folder in the solution;
- add a subfolder with the name of the app default locale, for example en-US;
- set default locale in AppManifest;
- add Resources.resw to the created subfolder;
- utilize x:Uid directive in XAML to apply a resource value.
After the main functionality is ready, the same steps can be applied for locales you want to support in the app. You also might need to create a service to load and access the resources. But intent of this article is to take a deeper look at the internal structure of localized resources in a package, when an app is ready to be published to the store.
With Universal Windows Platform, a new way of an app distribution was introduced. Microsoft suggests to create a bundle when your app is ready for submission to the store. Appxbundle is an archive file, which contains app packages for: x86, x64 and ARM. What is also interesting about app bundle is that allows to manage resources included into a package. Usually, an app has string resources or images with different resolutions for different locales. And for sure, when a user installs an app, he doesn’t need everything at his device. That’s exactly what app bundle helps to solve. All resources in an app bundle are packed in some way and when a user downloads an app, he gets localized resources, related to his device language settings. Thus, users from USA won’t get German resources, because they don’t need them.
This image can give you some insights about internal structure of a bundle:
Apart of the files related to the locales, there is also AppManifest file which contains metadata about the resources.
When a user installs a package distributed as not a bundle, he gets all localized resources used in the app. And that’s the main difference between a bundle distribution and the distribution used for Windows 8.1 apps.
If localized resources are downloaded respectively with a device language settings, how then programmatically apply different locales for UI? What if users want to set a different language? A language which is not the same as in device settings? That’s a tricky part of appxbundle. Even, you might not notice any issue with that when developing your app. But when try to change a language when the app is installed from a bundle, you will see that not every locale is applied properly. That’s because end device doesn’t have all files with localized resources.
The described issue can be handled in different ways. One possible solution is implemented in Bing News app. When the user chooses the app language, it asks to add chosen language to the device settings and set it as display language. Afterwards, an update will be installed by Windows. I suspect that Windows also will update the app with required resources file from the store.
The second solution is to implement custom localization and apply a resource value with bindings instead of x:Uid directive.
The third solution is to publish your app in the old way, with a package per configuration. As I mentioned before, if create a package but not a bundle, all localized resource will be included to that package. Thus, this approach gives more flexibility while can significantly increase the size of downloaded package for final users.
Once you started to distribute an app as a bundle, it won’t be possible to switch to a package per configuration. Dev center forbids an update with separated packages above appxbundle.
Actually, that’s not always forbidden. Our team had a bad experience with that. We published an update as a bundle for existing Windows 8.1 app. In other words, new Windows 10 app as an update for Windows 8.1 app. Afterwards, we figured out that localization doesn’t work as we expected. We decided to switch to a package per configuration distribution. We did that update and when submitting, it was allowed to upload three separated packages. As soon as the update became available, the users started complain about a crash when the app was launching.
That was really painful. It took significant amount of time to figured out the reason. When an update is being installed, all localized resources are being merged. Thus, the system tried to merge the resources from the installed bundle with the resources included to a new package. Such merge is not possible. And it wasn’t easy to catch the reason.
The main lesson – don’t switch from a bundle to the old way of distribution. It’s very possible that you will get some issues with that. But migrating to a bundle from the old way of distribution works well.