Resource Management System
The Resource Management System is part of the tools support that happens when you build your app. It creates a file that is packaged with the app, and then is called upon by the Windows Runtime to resolve resources when the app runs in a user context.
Package Resource Index (PRI) file
Every app package should contain a binary index of the resources in the app. This file is created at build time and it is referred to as a Package Resource Index (PRI) file.
- The PRI file is packaged with the rest of the app and helps to resolve resources at run time.
- The PRI contains actual string resources, and an indexed set of file paths that refer to various files in the package.
- Packages typically contain a single PRI file per language named resources.pri.
- The resources.pri file from the root of each package is automatically loaded when the ResourceManager is instantiated.
- PRI files can be created and dumped with the tool MakePRI.exe.
- For typical app development you won't need MakePRI.exe because it's already integrated into the Visual Studio compile workflow, and Visual Studio supports editing PRI files in a dedicated UI. However, your localizers and the tools they use might rely upon MakePRI.exe.
- Each PRI file contains a named collection of resources, referred to as a resource map. When a PRI file from a package is loaded, the resource map name is verified to match the package identity name.
- PRI files are data-only and don't use the portable executable (PE) format. They are specifically designed to be data-only as the resource format for Windows. They replace resources contained within DLLs in the Win32 app model.
Windows Runtime APIs
Basic functionality (ResourceLoader)
Advanced functionality (ResourceManager)
The ResourceManager class ( in the Windows.ApplicationModel.Resources.Core namespace) provides additional info about resources, such as enumeration and inspection. This goes beyond what the ResourceLoader class can provide.
A NamedResource object represents an individual logical resource with multiple language or other qualified variants. It describes the logical view of the asset or resource, with a name such as
A ResourceCandidate object represents a single concrete resource value and its qualifiers, such as the string "Hello World" for English or "logo.scale-100.jpg" as a qualified image resource that's specific to the scale-100 resolution.
Resources available to an app are stored in hierarchical collections, which you can access with a ResourceMap object. The ResourceManager class provides access to the various top-level ResourceMap instances used by the app, which correspond to the various packages for the app. The MainResourceMap value corresponds to the resource map for the current app package, and excludes any referenced framework packages. Each ResourceMap is named after the package name that is specified in the package's manifest. Within a ResourceMap are ResourceMap subtrees (see ResourceMap.GetSubtree), which further contain NamedResource objects. The subtrees typically correspond to the resource files that contains the resource. For more info see "How to load string resources" (HTML or XAML). Here's an example:
var rcns = Windows.ApplicationModel.Resources.Core; var resMap = rcns.ResourceManager.current.mainResourceMap.getSubtree("Resources"); var resContext = rcns.ResourceContext.getForCurrentView(); var str = resMap.getValue("String1", resContext).valueAsString;
// using Windows.ApplicationModel.Resources.Core; ResourceMap resMap = ResourceManager.Current.MainResourceMap.GetSubtree("Resources"); ResourceContext resContext = ResourceContext.GetForCurrentView() String str = resMap.GetValue("String1", resContext).ValueAsString;
Note The resource identifier is treated as a Uniform Resource Identifier (URI) fragment, subject to URI semantics. For example, GetValue("Caption%20") is treated as GetValue("Caption "). Do not use "?" or "#" in resource identifiers, because they terminate the resource path evaluation. For example, "MyResource?3" is treated as "MyResource".
The ResourceManager not only supports access to an app's string resources, but it maintains the ability to enumerate and inspect the various file resources as well. In order to avoid collisions between files and other resources that originate from within a file, indexed file paths all reside within a reserved "Files" ResourceMap subtree. For example, the file images/logo.png corresponds to the resource name Files/images/Logo.png.
The StorageFile APIs transparently handle references to files as resources and are appropriate for typical usage scenarios. The ResourceManager should only be used for advanced scenarios, such as overridden context or enumeration of possible values.
Resource candidates are chosen based on a particular ResourceContext, which is a collection of resource qualifier values (language, scale, and so on). A default context uses the app's current configuration for each qualifier value, unless overridden. In general, resources can be qualified for scale, which can vary from one monitor to another, and hence from one application view to another. For this reason, each application view has a distinct default context. The default context for a given view can be obtained using ResourceContext.GetForCurrentView. Whenever a resource candidate is retrieved, a ResourceContext instance should be passed in to obtain the most appropriate value for a given view.
When a resource is requested, there may be several candidates that match the current resource context to some degree. The Resource Management System will analyze all of the candidates and determine the best candidate to return. This is done by taking all qualifiers into consideration to rank all of the candidates.
In this ranking process, the different qualifiers are given different priorities: language has the greatest impact on the overall ranking, followed by contrast, then scale, and so on. For each qualifier, candidate qualifiers are compared with the context qualifier value to determine a quality of match. How the comparison is done depends upon the qualifier.
For some qualifiers, such as scale and contrast, there is always some minimal degree of match. For example, a candidate qualified for scale-100 matches a context of scale-180 to some degree, albeit not as well as candidates qualified for scale-140 or (perfect match) scale-180.
For other qualifiers, however, such as language or home region, it is possible to have a non-match comparison (as well as degrees of matching). For example, a candidate qualified for language as "en-US" matches a context of "en-GB" to at least some degree, but a candidate qualified as "fr" does not match that context at all. Similarly, a candidate qualified for home region as "155" (Western Europe) matches a context for a user with a home region setting of "FR" somewhat well, but a candidate qualified as "US" does not match at all.
When a candidate is evaluated, if there is a non-match comparison for any qualifier, then that candidate will get an overall non-match ranking and will not be selected. In this way, the higher-priority qualifiers can have the greatest weight in selecting the best match, but even a low-priority qualifier can eliminate a candidate due to a non-match.
A candidate is neutral in relation to a qualifier if it is not marked for that qualifier at all. For any qualifier, a neutral candidate is always a match for the context qualifier value, but only with a lower quality of match than any candidate that was marked for that qualifier and has some degree of match (exact or partial). For example, if we have candidates qualified for "en-US", "en", "fr", and also a language-neutral candidate, then for a context with a language qualifier value of "en-GB", the candidates will be ranked in the following order: "en", "en-US", neutral, and "fr". In this case, "fr" does not match at all, while the other candidates match to some degree.
The overall ranking process begins by evaluating candidates in relation to the highest-priority qualifier, which is language. Non-matches are eliminated. The remaining candidates are ranked in relation to their quality of match for language. If there are any ties, then the next-highest-priority qualifier, contrast, is considered, using the quality of match for contrast to differentiate among tied candidates. After contrast, the scale qualifier is used to differentiate remaining ties, and so on through as many qualifiers as are needed to arrive at a well-ordered ranking.
If all candidates are removed from consideration due to qualifiers that don't match the context, the resource loader goes through a second pass looking for a default candidate to display. Default candidates are determined during creation of the PRI file and are required to ensure there is always some candidate to select for any runtime context (see Compiling resources (MakePRI.exe) for details). If a candidate has any qualifiers that don't match and aren't a default, that resource candidate is thrown permanently out of consideration.
For all the resource candidates still in consideration, the resource loader looks at the highest-priority context qualifier value and chooses the one that has the best match or best default score. Any actual match is considered better than a default score.
If there is a tie, the next-highest priority context qualifier value is inspected and the process continues, until a best match is found.
For examples, see Examples of how resources are chosen.
Compiling resources (MakePRI.exe)
MakePRI.exe is a command line tool used for creating and dumping PRI files. It is integrated as part of MSBuild within Microsoft Visual Studio, but can be useful for developers to create packages by hand or by custom build systems.
MakePRI.exe command options
MakePRI.exe has a set of command options: createconfig, new, versioned, resourcepack, and dump. For details of their use, see MakePRI.exe command options.
The PRI XML configuration file dictates how and what resources are indexed. The schema of the configuration XML is described in MakePRI.exe configuration.
MakePRI.exe is typically used with the new, versioned, or resourcepack options. In those cases it indexes source files to generate an index of resources. MakePRI.exe uses various individual indexers to read different source resource files or containers for resources. The simplest indexer is the folder indexer, which indexes the contents of a folder, such as .jpg or .png images.
The format-specific indexers are identified by
<indexer-config> elements within an
<index> element of the configuration file. The type attribute identifies the format-specific indexer that is used.
Resource containers encountered during indexing usually get their contents indexed rather than being added to the index themselves. For example, .resjson files that the folder indexer finds may be further indexed by a .resjson indexer, in which case the .resjson file itself does not appear in the index. (Note that an
<indexer-config> element for the indexer associated with that container must be included in the configuration file for this to happen.) Typically, qualifiers found on a containing entity, such as a folder or a .resjson file, are applied to all resources within it, such as the files within the folder, or the strings within the .resjson file.
See Format-specific indexers for the descriptions and schemas of the following indexer types.
Indexes the contents of a PRI file. It is typically used to index a resource contained in another assembly, DLL, or class library.
All resource names, qualifiers and values contained in the PRI file are directly maintained in the new PRI file. The top level resource map, however, is not maintained in the final PRI. Resource Maps are merged.
Indexes the contents of a detailed dump file. The dump file is produced by using the dump command from MakePri.exe, with the detailed dump type option. See the PRIINFO section of the Format-specific indexers topic.
MakePRI.exe warnings and error messages
Resources found for language(s) '<language(s)>' but no resources found for default language(s): '<language(s)>'. Change the default language or qualify resources with the default language.
is displayed when MakePRI.exe or MSBuild discovers files or string resources for a given named resource that appear to be marked with language qualifiers, but no candidate is found for a default language. The process for marking files is described in How to name resources using qualifiers. A file or folder may have a language name in it, but no resources are discovered that are qualified for the exact default language. For example, if a project uses "en-US" as the default language and has a file named "de/logo.png", but does not have any files that are marked with the default language "en-US", this warning will appear. In order to remove this warning, either file(s) or string resource(s) should be qualified with the default language, or the default language should be changed. You can change the default language in Windows Store app projects by opening package.appxmanifest in Visual Studio and editing "Default language" in the Application UI tab.
No default or neutral resource given for '<resource identifier>'. The application may throw an exception for certain user configurations when retrieving the resources.
is displayed when MakePRI.exe or MSBuild discovers files or resources that appear to be marked with language qualifiers for which the resources are unclear. There are qualifiers, but there is no guarantee that a particular resource candidate can be returned for that resource identifier at run time. If no resource candidate for a particular language, homeregion, or other qualifier can be found that is a default or will always match the context of a user, this warning will be displayed. At run time, for particular user configurations such as a user's language preferences or home location (PC Settings > Region & language), the APIs used to retrieve the resource may throw an unexpected exception. In order to remove this warning, default resources should be provided, such as a resource in the project's default language or global home region (homeregion-001).
Using MakePRI.exe in a build system
Build systems should use the MakePRI.exe "new", "versioned", or "resourcepack" commands, depending on the type of project being built. Build systems that create a fresh PRI file should use the "new" command. Build systems that must ensure compatibility of internal offsets through iterations can use the "versioned" command. Build systems that must create a PRI file that contains additional variants of resources, with validation to ensure that no new resources are added for that variant, should use the "resourcepack" command.
Build systems that require explicit control over source files that get indexed can use the ResFiles indexer instead of indexing a folder. Build systems can also use multiple index passes with different format-specific indexers to generate a single PRI file.
Build systems can also use the PRI format-specific indexer to add pre-built PRI files into the PRI for the package from other components, such as class libraries, assemblies, SDKs, and DLLs.
When PRI files are built for other components, class libraries, assemblies, DLLs, and SDKs, the initialPath configuration should be used to ensure component resources have their own sub resource maps that don't conflict with the app they're included in.