Chapter 17
Apps for Everyone: Accessibility, World-Readiness, and the Windows Store

The title of this chapter, “Apps for Everyone”—especially the “Everyone” part—has several shades of meaning. First is the vitally central role that the Windows Store plays in the whole Windows 8 experience. As first mentioned in Chapter 1, “The Life Story of a Windows Store App,” the Store is the place where you distribute apps to customers (outside of the enterprise and sharing with other developers). Everyone, in other words, gets their apps from the Store.

In this same way, everyone who does business with apps does business with the Store. To define your app’s relationship to the Store is in many ways to define your business itself, and that relationship affects all stages of the app lifecycle from planning and development to distribution and servicing. Thinking about the Store, then, is not something you want to do only when you’ve completed an app: you want to be thinking about it when you start thinking about the apps you’d like to build. You might have come here directly from Chapter 1, in fact, where I recommended reading the first section below even before starting your first coding experiments! Truly, the Windows Store is like a pair of bookends to the whole app development process: you think about the Store when planning the business of your app, and when all is said and done, you go to the Store’s developer portal itself to make your app available to others.

Those “others” are the context for the additional meanings of “everyone.” In general, when you set out to offer a product to customers, you want to broaden your reach to include as many potential customers as you can. There are, of course, cases where you might want to specifically limit your audience, but for most apps, being able to reach more customers is certainly an attractive opportunity. And if you don’t, your competitors will!

One way to broaden your reach is to cover your bases where accessibility is concerned. Though accessibility has its origins in serving people with serious disabilities, research has shown that a majority of people—nearly 60% —use accessibility features in some capacity, even though there’s no disability involved. For one, being able to accommodate limited input models—like keyboard only or mouse/pointer only—is inherent in dealing with touch-only devices. Resolution-scaling, similarly, serves the needs of the visually impaired alongside the desires of the financially unimpaired (that is, those customers who are willing to splurge for a high-DPI device just to get sharper graphics). An app that works well with a screen reader for the visually impaired can also work rather well for the mobile customer whose otherwise sound eyes need to be focused elsewhere—like the road they’re ostensibly driving on! And providing for high-contrast color schemes helps not only those whose eyes don’t do well with subtle colorations but also those who might be working with a mobile device in bright sunlight.

It therefore behooves app developers to take accessibility concerns seriously, especially as the Store will specifically mark fully accessible apps. As we will see, this primarily involves adding the appropriate aria-* attributes to your HTML markup, adapting your layout to different screen sizes, and making sure to provide image variations for different contrast settings.

The second way to extend your reach is to make your app world-ready—that is, to utilize localized resources within the app so that it adapts itself to each user’s language, regional conventions, date and time formats, currency formats, and so on. Fortunately, Windows 8 enables you to structure your resources—images and strings, primarily—so that the right variations show up automatically, just like they do for resolution scales and contrasts. The Windows Runtime also contains a number of APIs to help an app be world-ready, and the app itself can take additional steps to localize the web services from which it’s drawing data, how it works with live tiles and notifications, and so on. Furthermore, some additional tools such as the Multilingual App Toolkit are available to make it all the easier to translate your resources.

The reward for all this effort, of course, is that users who search in the Windows Store for apps in their regional language will see your app and not those that are available only in a single language like English. Those users will also be more likely to express their appreciation in your app’s reviews and ratings.

One of the great things about the Windows Store is the access it gives you to global markets from wherever you happen to be working. In the past, learning to do business in many countries around the world has been a tedious and expensive process, sometimes requiring that you understand local tax laws, manage currency conversions, and so forth. No longer—this is really what the Windows Store is doing on your behalf. Once the Store becomes available in a market, it means that Microsoft has done the work to embed local policies into the Store itself. Put another way, whatever small fee you pay to upload apps to the Store has made it possible for you to business in those markets with little or no effort! This is good. The Store also lets you vary your app pricing for regional markets—if you charge for the app or in-app purchases—because standards of living do vary widely around the world. This is also good.

In this chapter then, we’ll begin by looking at the relationship between your app and the business of your app as supported by the Store, regardless of whether you seek to monetize your app in any way. We’ll then take a tour of accessibility followed by another through the world of world-readiness. The last section—of this chapter and of this book!—will bring us full circle to where we started in Chapter 1: uploading your app to the Store and what you can expect there. Now that you’ve brought your app this far, let’s get it ready for everyone to enjoy!

Your App, Your Business

If you check in with your local psychologist of philosopher, they’d probably agree with the idea that just about all people, across all professions, cultures, and capabilities, are driven by a small number of fundamental motivations: fear, lust, power, love, service to others, and just plain ol’ joy. Indeed, the wisest among them will even say that the last one—the quest for joy or happiness—is actually the root of all the others.

Leaving all that aside, and assuming that you’re not programming under threat of death or working on apps that are going to be rejected from the Windows Store as a matter of policy, let’s take a simpler view and identify the few basic reasons why you might be interested in writing apps:

Fortune You want to make money.

Fame You want social recognition.

Philanthropy You want to contribute to a cause.

Fun You just want to enjoy yourself through coding—an activity that, alas, nonprogrammers just don’t understand!

Wherever you land in this list—and with whatever combination—your motivations essentially define your “business” as a developer. I use the term loosely here. In English, at least, there are about a dozen different definitions of this word, only a third of which relate to commercial activities, organizations, practices, and commerce. The other definitions have to do with concerns that are important to you, as when we say “It’s none of your business” or “I make it my business to know about such things.” In short, apps can reflect the nature of your “business,” whatever it is, and that nature is reflected in how you share apps with others. Again, with the exception of side loading (see the next section), sharing your app means distributing it through the Windows Store. For that reason, your app’s relationship to the Store effectively defines your business with that app, and that relationship spans the entire app lifecycle:

Planning Determining whether the app can actually be a Store app, meet Store certification requirements, and be suitably monetized (if desired).

Development Implementing Store-related features and using the APIs for trial versions, in-app purchases, etc.

Testing Using precertification tools prior to onboarding the app to the Store, and checking the app against certification requirements.

Availability Making the app available in various markets through the Store developer portal.

Marketing, sales, and support Promoting your app, increasing its visibility, working with your customers (responding to ratings and reviews), linking it to your website (if applicable), and using Store analytics through the developer portal.

Updates and growth Improving your app over time, or removing it from the market.

We’ll explore some of these topics in more detail shortly, especially those areas that affect planning and development. This includes the APIs that allow you to simulate Store interactions when debugging. We’ll also review the available monetization models—from completely free apps, ad-supported apps, and paid apps, to trial versions and those with in-app purchases, After all, your choices here are fundamental to how you’re going to fulfill your goals in writing applications, whatever your motivations.

The remaining topics we’ll return to in the last section of this chapter, as it’s appropriate to first discuss accessibility and localization.

Side Loading

A question that’s arisen with just about every mobile platform is the ability for developers to load and run apps without going through the associated store. Because store-only distribution is generally inconvenient for developers who want to experiment with a platform—especially with apps that don’t have the fit-and-finish needed for store certification—they end up hacking that platform to allow for some kind of side loading anyway.

Such is not an issue with Windows. First, as explained on Get a developer license, “A developer license for Windows 8 lets you install, develop, test, and evaluate Windows Store apps before the Windows Store tests and certifies them.” In addition to enabling some technical capabilities (like using local loopback, as we’ve seen in earlier chapters), a developer license means you can share app packages (.appx files) with other developers for whatever purposes you need, such as testing.

Second, enterprise administrators can allow side loading on machines running the Enterprise edition of Windows 8. This is typically useful for distributing line-of-business (LOB) apps within that organization, as such apps clearly have no need to be uploaded to the public Store. Details and requirements can be found on How to Add and Remove Apps (Microsoft TechNet) as well as Deploying Windows Store apps to business (Windows Store blog).

In both cases, the side loading process is the same. You first create the app package through the Store > Create App Packages command in Visual Studio and selecting the No radio button, as shown in Figure 17-1. You then provide some details for the package, as in Figure 17-2, and press the Create button.

Images

FIGURE 17-1 Creating an app package for side loading. The actual dialog box is much taller; I’ve compressed it to save space.

Images

FIGURE 17-2 The second step of creating an app package for side loading.

When the process is complete, Visual Studio will give you a link to the folder where the package was created. Going there you’ll see a file with the extension .appxupload, which is what you’d be using for the Store. For side loading, you want to look at the folder whose name ends with _Test. In that folder you’ll see the following:

• The app package (.appx file).

• A temporary certificate (.cer file).

• A Dependencies folder that contains any libraries that would normally be provided by the Store; WinJS is one such library.

• Most importantly, a PowerShell script named Add-AppDevPackage.ps1 (and a folder with associated resources) that will install the app on a side load–capable machine.

This process makes it easy to share your app with others without sharing your source code project. A good case for using this is if you hire others to thoroughly test your app. Running the PowerShell script installs the app very much like it would be from the Store, so if testers side-load on a machine where your app has not been installed before, it closely approximates a typical user’s environment. This way you can truly test the first-run experience of your app on a variety of devices.

Planning: Can the App Be a Windows Store App?

In a slight contradiction to this chapter’s title, the idea of “apps for everyone” doesn’t necessarily mean that every app can, in fact, be a Windows Store app. There are two sides to this: technical feasibility and meeting Store certification requirements.

Technically, as we covered in Chapter 3, “App Anatomy and Page Navigation” and a few other places, Window Store apps run under certain conditions and restrictions. Here’s a summary:

• Windows Store apps always run in the app container and have no access to APIs that can openly access the file system or any other sensitive resource.

• Sharing data between Windows Store apps always goes through the Share contract, the clipboard, or web services; local interprocess communication is not supported. (Local loopback is supported only on machines with developer licenses and will cause the app to be rejected from Store certification.)

• Windows Store apps can use only the WinRT APIs along with a subset of Win32 and .NET APIs; apps written in HTML and JavaScript can also use the intrinsic HTML and JavaScript APIs provided by the app host. Any third-party libraries you use in the app must also use only these APIs.

• Apps cannot install custom device drivers or anything else that affects the system, nor can apps customize their install process.

• Only certain apps can run in the background, and for specific purposes, as we’ve seen in Chapter 10, “Media,” and Chapter 13, “Live Tiles, Notifications, the Lock Screen, and Background Tasks.”

• Some UI interaction models aren’t appropriate for touch input, such as high precision CAD. Because Windows Store apps must support all forms of input, high precision apps either need to be redesigned for touch or should be implemented as a desktop app.

• Windows Store apps run in one of four view states and cannot utilize overlapping windows.

If any of these technical aspects would prevent you from writing the kind of app you want to write, then working with the Windows Store as your business location, if you will, is not really possible. For example, many development tools, network administration tools, file system utilities, antimalware utilities (that scan the whole hard drive), and database management systems must be implemented as desktop applications and distributed through the Internet or other retail channels.78

More generally, because Windows Store apps run full screen or with at most one other visible app, they are intended to be much more specifically focused on certain tasks. Apps that try to do too much—Swiss Army Knife apps, if you will—may end up feeling cumbersome or confusing. It’s good to hone the purpose of the app, as discussed in Planning Windows Store apps; otherwise you should probably implement a desktop app instead (for which there is still a very large market, mind you!).

When planning any app, be sure to review the Windows 8 app certification requirements to understand whether the app you’re thinking about will be summarily rejected during the onboarding process. Examples include apps that contain gratuitous violence, hate, adult content, solicitations, and so forth, as well as apps that consume an inordinate amount of battery power, attempt to just repackage a website as an app, or clearly don’t add value to the Store as a whole. So, if you’re thinking to submit the next great bodily-functions-sound-effects app, you might think again.

Also be aware that the Store policies can change over time, so be sure to check them anew before you start any new project.

A final consideration is whether the Windows Store is itself available in a target market when you plan to release your app—the Store will be rolled out to different markets over time. Unfortunately, there is not a published schedule for that rollout; you’ll need to watch for announcements. There might also be restrictions on whether you can submit an app to certain locales based on where you operate as a developer. This information is again best found on the Store developer portal.

Planning for Monetization (or Not)

Just as there are a number of reasons why you’re interested in creating apps in the first place, there are also a number of ways to fulfill your business goals. Will your app be completely free? Will it be free but supported by ads? Will it be paid, with or without a trial version? Will it involve in-app purchases? Each of these business models has its place, especially if you plan on releasing multiple apps. Furthermore, it’s likely that your business model or models will change over time as you improve your apps and respond to competition.

In this section, we’ll explore at these different models and better understand how they relate to one another.79 Remember in this whole context that licenses for apps and in-app purchases are granted to the user and will apply across up to five devices. This isn’t typically a concern for apps because the details are automatically handled by the Store—if the user attempts to install the app on a sixth device, Windows will instruct him or her to remove the app from a machine.

Free Apps

You don’t need to do anything special to create a free app so far as the Store is concerned. You write it, upload it to the Store, have it certified, and then get the word out.

Free apps can serve several purposes:

• Earn you praise and glory from users and possibly other developers.

• Give you experience producing apps (otherwise known as resumé items!).

• Provide a space for marketing your own products and/or services (as opposed to hosting third-party ads, as discussed in the next section).

The first purpose here is self-explanatory and doesn’t need any elaboration, I hope! If this is your motivation, I imagine you’re already doing daily or hourly web searches on your name and will be watching your app’s ratings and reviews like a floor trader watches stock tickers.

As for gaining experience, that’s a great exercise, of course, but be aware that every app you make available through the Store—along with its ratings and reviews—becomes a permanent part of your developer reputation. Because of this, uploading apps to the Store before they’re ready—or before you’re really ready as a developer—could backfire over the long term. You don’t want your reputation to be weighed down by early experiments when you finally have the idea that’s really going to take off!

To manage this risk, you could start by only sharing apps with other developers who can side-load whatever packages you make available through some means other than the Store. You might also consider creating a personal developer account just for your experimental work, keeping it separate from the account through which you’d want to post your real apps. This way, any negative reputation from your experiments doesn’t accrue to your serious work; neither does positive reputation, of course, but that’s a balance you have to find for yourself. Also, creating an extra account will require an additional annual fee, but that might be well worth it in the end.

As for marketing, what I mean here again differs greatly from ad-supported apps (see the next section). Here I’m specifically referring to promoting your own business or causes (such as a charity) through the functioning of the app where you have complete control over the content.

Be aware, however, that the Store certification requirements are somewhat strict where this sort of thing is concerned. Section 2.1 states, “Your app must not display only ads.” Section 2.3 says, “Your app must not use its tiles, notifications, app bar, or swipe-from-edge interactions to display ads.” That said, it’s recognized that the very purpose of some apps is to provide offers, for example, in which case it’s not really displaying ads, per se, but content for which the user has expressed interest through the act of installing the app. The policies are targeted more toward apps that pick up ads from an ad provider, such that the user would get random content showing up on their tiles and other key areas of the user interface.

The other point to these policies reflects Section 1.1 of the requirements: “Your app must offer customers unique, creative value or utility in all languages and markets that it supports.” What this means is that if you want to promote a cause or business through the app, do it in a way that delivers value to consumers. For example, an app for a nonprofit organization could help its users understand and be inspired by the organization’s activities, keep up to date on current projects, and be directed to a place where perhaps they can make a donation. There’s a fine line to walk here, because apps that simply ask for donations won’t be accepted to the store (no creative value). Their primary purpose must be to inform, educate, inspire, entertain, and so on, with links to websites for any kind of charitable transactions. (Making donations directly through the Windows Store is not presently supported, plus it would incur revenue sharing, which you’d want to avoid anyway.)

More generally, free apps can also provide some useful functions in themselves but otherwise be a demonstration of features of any number of other apps—something like a tour of your paid offerings (so long as there’s again real value in the app by itself). When related to only a single app, such a demo or “lite” version is different from a trial version of a full app. As we’ll see shortly, a trial version should look and operate as if you had acquired a license to a full version, but it would be hobbled in some key ways or time-limited to place a restriction on its use. A demo app, on the other hand, is meant more to showcase features rather than provide a complete experience.

For example, let’s say you have a game with five distinct “worlds” through which a player would normally progress in the app’s full version. A trial version would allow a player to start working through those worlds but would cease to operate completely after some short period of time, say 30 or 60 minutes. In that time, a player might not progress past the first few levels in the first world, so the experience of the overall game is incomplete. A free demo/lite version, on the other hand, could be played as much as one wished but would contain only one level from, say, three of the five worlds. This gives the user a broader taste of the app and, because it can be played many times, serves as a continual advertisement for the full experience without giving anything more away. In other words, a demo app is like a teaser trailer: enough to create but not satisfy a hunger. (And, yes, while there may be some people that only ever watch free trailers and never go see a full movie, those are a rare breed. The same is true with apps.)

Great free apps can also fit well into an overall business model without asking for anything: they can help build a great reputation for your business, thereby supporting other paid offerings. Each app in the store can include links to your website and support information, so each one is a doorway to the rest of your business. In this way, free apps are like the giveaways (or loss leaders) that many businesses offer to get you in the door so that you can look at their full line of products without distraction.

Ad-Supported Apps

Ad-supported apps, which are typically free but can also be paid, are those that deliver some clear value in themselves and use that value to sell advertising space to others. Such advertising, while hopefully well-directed to the user’s interests, typically isn’t integral to the app’s own function. Many free games, for instance, place interstitial (gap-filling) ads between levels or boards, ostensibly to keep you entertained while the next level is loading but in truth to take full advantage of your captured attention! The bottom line is that a user’s attention, focused on something of value, has real value to advertisers who are willing to pay you for a bit of that focus.

As a user of the web, you’re undoubtedly familiar with how ads can appear in an app’s overall layout: filling gaps in space rather than in time. Typically, an app will place a control in such a space, which is itself connected to an ad service and pretty much manages itself. The control will acquire ads to display and track click-throughs, which is typically how you get paid: clicking is a sign that the user actually did pay a little attention to the ad, so you receive the value for that attention; users who ignore ads and never click them don’t register.

Either way, many developers have found that selling ad space may be the most lucrative means of monetizing an app and building a business, but of course you have to understand your target audience and whether they’re the sorts who will care for advertising at all.

The advertising control you use depends on the ad provider. For Windows 8, you can use the Microsoft Advertising SDK, an extension that you incorporate into your app. For details on how this works, see the Developer Walkthrough – HTML 5 JavaScript documentation (part of the Microsoft Advertising SDK for Windows 8 documentation). I expect that other ad providers will make similar controls available in time.

Paid Apps and Trial Versions

Producing an app and charging for a license is certainly the one of the oldest means of monetizing, and it still works quite well. Value received for value delivered: that’s the simple equation on which many successful products are built. Generally speaking, paid apps are free of advertising and are not advertisements themselves (again enforced by policy), hence customers’ willingness to pay money for the apps in the first place. It could be, however, that we’ll gradually see some creative means of ad insertion even into paid apps: after all, you pay for issues of a magazine and yet that magazine contains ads (unless you pay for premium magazines that contain none). Think too how we once balked at the idea of advertising on cable television or in movie theaters, but all that’s just a matter-of-course now. The simple truth is that wherever there is a focus of customer attention, as already mentioned, there is a value to advertisers and to the businesses that can sell them access to that attention. You just have to be careful not to abuse those customers!

An important consideration for paid apps especially (but really for all apps) is the need for marketing. The existence of a place—the Windows Store—where customers can acquire your app doesn’t eliminate the need for finding your customers and making them aware of your product. With every such store, there is a brief window of time where the total number of apps is still relatively small, meaning that users have a good chance of finding the app through casual browsing. But as soon as the store contains more apps, and users tire of browsing as a primary means of discovery, either users have to find you in a search (assuming you even show up in the top of the results list) or you have to generate interest through other means. This is again one of the functions of other free apps or demo versions that you might produce: if one of your free apps gets featured in some category, every user who downloads that free app at least has an opportunity to learn about your other products. And then, of course, there are all the other means to market your product: the social web, your company website and SEO, advertising in traditional media, and so forth.

You should also strongly consider making a trial version of the paid app available. A trial is typically free and is subject to an expiration date. As noted before, a trial app looks, feels, and operates like the real thing but is simply time-limited or hobbled. For example, a picture editor might allow you to edit but not save your work, meaning that you get the full experience of using the product without the full benefits of owning a license. A video converter app, as another example, might place a logo or watermark (that is, an advertisement) on the output video, so the functionality is all there, but the result isn’t as useful. A trial version might also just disable in-app purchases, thereby limiting its extensibility until the full app is acquired.

Whether the trial is hobbled is your choice as a developer—if an app creates something and saves it in a particular format, such that you could not re-open those files without the same app (unlike pictures), there may be no reason to disable a save feature at all. In such cases, the strategy is to get the trial user heavily invested in continued use of the app, such that purchasing the full license is a better choice than letting go of that investment. Personal finance and contact management are good examples: in a 30-day trial period (or whatever period the app sets), users of such apps could amass quite a bit of useful data that they would not want to re-enter into another app. (Such a trial might also quietly disable any exporting features.)

A trial version is typically quite adept at reminding the user (that is, nagging them) about their trial status and that, hey, really, don’t you want to get the real thing? The APIs for working with the Windows Store are such that checking for trial status (and its pending expiration) is quite simple. APIs also exist to initiate a streamlined purchase flow through which the user can acquire a full license with minimal disruption, all within the context of the app itself. In short, trial versions are an important monetization model that are, fortunately, quite easy to implement in Windows 8.

A technical stipulation of a trial version is that all the bits of the full version are actually already present on the user’s machine: purchasing a full license from a trial version is simply an act of setting the license information in the Windows Store, and such a purchase will not initiate any new downloading. For a user, this means that to download and install a trial is to effectively download and install the full version, with the Store simply indicating that the user doesn’t have full rights. If such a full download would be an obstacle, however, such as when the app is large, it may be a better strategy to create a much smaller demo version that will take the user to the appropriate page in the Store to buy the full app.

All of this is really about creating a smooth and painless experience for users to try new software. One of the primarily motivations behind the Store (and the associated packaging technology) is to eliminate nearly all of the past risk of software acquisition: unknown or untrusted sources, potential malware, inconsistent install/uninstall procedures, and so forth. Microsoft wants Windows users to feel confident that they can experiment and try out new apps—your apps!—without corrupting their system, compromising their data, or in other ways being exposed to those sorts of problems.

The existence of the Windows Store and the fact that users cannot install an app except in the context of the Store provides a certain inherent level of piracy protection. Users are blocked from accessing the folders that contain installed appx packages, and even if they managed to extract and install one elsewhere, the Store would report that the app is unlicensed for that user and would thus refuse to run it.

Beyond that, any additional levels of protection are up to the app. It’s perfectly allowable for an app to ask the user to register with the publisher (because customer information isn’t shared from the Store) and to obtain a secondary license key. Windows does not block such procedures but doesn’t provide any such services itself. Do consider, however, that customers might be annoyed by such additional requirements. It’s best to exercise caution in such a decision.

In-App Purchases

In-app purchases are a primary means to monetize an application over time by selling incremental add-ons, options, periodicals, time-limited subscriptions/rentals, and so forth. By definition, the lack of any such options cannot interfere with the core operation of the app. In-app purchases cannot also be interdependent—that is, users cannot be required to purchase other options to use one they’re already bought. Know too that an app is limited to 100 such in-app purchases when they are managed through the Windows Store; if you use your own commerce engine, as described in the next section, there is no such limit.

Whether in-app purchases are the right choice for your app involves a number of considerations:

• Implementing them well can be difficult because they introduce complexities into an app’s architecture. (Note that Windows does maintain information for in-app purchases that can expire.)

• The app has full responsibility for correct delivery of the purchased item or feature, as opposed to the Store handling all the details.

• In-app purchases effectively create multiple variations of an app, which can increase user support and interaction.

• Overuse or inappropriate use of in-app purchases can generate the perception that you’re trying to get money from users at every possible opportunity. Users who don’t or won’t pay for in-app purchases can still leave bad reviews about their experience.

• At present, the Windows Store supports only “durable” products (that can be purchased only once until they expire); there is no support for “consumable” products that can be repeatedly purchased. Consumables are under consideration for future versions; at present they can be implemented by using a custom commerce engine.

• In-app purchases through the Windows Store do not trigger download of additional content; they only change the user’s license for that product. If needed, an app can initiate its own downloads once the product license has been acquired.

On the flip side, offering a new full version of an app with new features might generate better sales than offering the same features as in-app purchases. An app update is a real event in itself and can generate renewed interest in and energy around your product like the release of a new movie. In-app purchases, on the other hand, are by nature more prosaic, like the popcorn and drinks you buy in the theater—always there, and often considered essential for the whole experience, but not all that exciting outside that context. The best approach is probably to follow Hollywood’s example and do both!

So it’s worthwhile at even the earliest stages of design to think about what kinds of in-app purchases make sense for your product. You may not even at this time have anything you plan to offer, but you may want to add them later on. In short, keep the door open for expansion and creativity without necessarily having to revise the app. It’s equally important to also think about what makes sense for your customers. We emphasize this point because there have been stories of outright abuse in this area. Apps aimed at young children, for example, have been known to dangle lots of in-app purchases like candy, enticing those children to press a “buy” button when they have no sense of the transaction. For this reason, the Windows Store will prompt the user for authentication with each purchase. Parents, protect your passwords!

The key thing is that if you try to be sleazy, you probably won’t get far with your app. If you try to trick users out of their money, your app will certainly decline in ratings and reviews over time. And if you’re found to be truly abusive, Microsoft does reserve the right to kicked your app out of the Store altogether, if it even passes certification at the outset.

All in all, these are all just considerations that will eventually affect how you set prices in the Store. You’ll need to consider the tradeoffs involved between setting a higher price point with an initial-app purchase versus monetizing through multiple in-app purchases, and you’ll need to be sensitive to how willing your target customers might be to making one purchase versus making multiple purchases. Apps that constantly nag their users to make additional purchases will be on par with pushy street vendors who just won’t leave you alone.

Revenue Sharing and Custom Commerce for In-App Purchases

The subject of monetization is not complete without answering one of the most important questions: how much of the Store-related revenue stream do you, as the publisher of the app, get to keep? The basic answer is simple: 70% comes to you, 30% goes to the Store (you have to pay your rent). However, once an app achieves US$25,000 in sales (from both the app and in-app purchases), your share increases to 80%.

Revenue sharing is always in effect for paid apps. For in-app purchases, however, you have the option to bypass the Windows Store altogether and use a commerce platform of your own, which potentially allows you to realize a much higher percentage of the revenue. This is an especially great option if you already have arrangements with a transaction provider through your existing websites. Be aware that Sections 4.8 and 4.9 of the Store certification requirements apply here, where you need to ensure that the user enters credentials for each purchase and that each transaction meets the PCI Data Security Standards.

With this custom commerce option, you’re pretty much on your own where all the details are concerned, including UI—the Windows Store API itself doesn’t provide for extensibility of its own mechanisms. You might draw from The in-app purchase user experience for a customer topic in the documentation to understand the flow, and you may also be able to find a third-party solution that provides an app control along with the backend commerce services.

Note that although the Windows Store does not presently support consumable in-app purchases, you can certainly implement this with your own commerce scheme. Doing so will also avoid the 100-item limit imposed by the Windows Store mechanisms.

The Windows Store APIs

Now that you’ve likely decided on a course for your app, let’s see how you use the Windows Store APIs to accomplish those ends. These are found in the Windows.ApplicationModel.Store namespace; all objects referred to in this section are contained in this namespace unless noted.80

First, know that basic licensing and trial enforcement comes for free: the app doesn’t actually need to do anything at all! A user cannot acquire your app without going through the Store, and even if he did manage to, he’d have to have a developer license to install and run it. Furthermore, because the Store automatically tracks trial periods for apps, Windows will simply not launch an app once the trial is expired. Instead, Windows will redirect the user to the product’s page in the Store where the user can purchase a full license.

An app can also set the expiration time of a license—not just for trials but the full app. This could be useful for apps that aren’t valid or useful after a given date, such as event registration (conferences, meetings, etc.) or time-limited demos. Think about it, though: if the user has gone to the trouble of acquiring the app in the first place, do you really want to go and disable it? Far better, I imagine, is to maintain the usefulness of the app in some way. With event registration, for example, there are probably more events in the future that you could provide information about and perhaps open up registration at the appropriate time. Again, the user has the app already and must have had some intent in launching it even after it’s expired—so can you leverage that intent in some way? It’s a good question to ask.

As noted before, apps can enforce a secondary licensing scheme if desired. Here it would ask the user for a separate registration or a separately acquired license key of some sort. Again, Windows does not offer an API for this but will not block schemes of your own.

That said, WinRT provides for the following features:

• Retrieving app and product (in-app purchase) information from the Store, including price values formatted for the user’s current locale.

• Retrieving license information for the app, indicating trials, expirations, etc. The app can make any decisions it wants with these details.

• Prompting the user to purchase a full license during or after a trial period; this is especially useful when the app is running and the trial period expires.

• Handling in-app (product) purchases.

• Generating receipts.

• Testing all the app’s Store interactions prior to uploading to the store.

When an app runs for real—that is, after it has been uploaded to the Store and has made its way into the hands of customers—interaction with the API happens through the static CurrentApp object:

var currentApp = Windows.ApplicationModel.Store.CurrentApp;

whose methods and properties are as follows:

appId The GUID that uniquely identifies the app in the Store.

linkUri The URI (Windows.Foundation.Uri) to the app’s listing page in the Store. (If you recall from Chapter 12, “Contracts,” this is the value you want to store in the application-ListingUri property of a DataPackage used in the Share contract; doing so lets a user who receives the shared data easily find your app.)

licenseInformation A LicenseInformation object.

loadListingInformationAsync Retrieves the ListingInformation object for the app; through this you can retrieve information about the in-app products.

requestAppPurchaseAsync Invokes the Store UI to invite the user to purchase the app. This is used when the app is running and detects that a license has expired.

requestProductPurchaseAsync Invokes the Store UI to invite the user to do an in-app purchase.

getAppReceiptAsync Requests an XML string that contains receipts for the app and any in-app purchases.81

A ListingInformation object contains a number of properties that come pre-localized as appropriate: ageRating (a number, currently one of 3, 7, 12, and 16), currentMarket (a BCP-47 string indicating the user’s market that is used for transation), description (a string containing the app’s description from its Store page localized for the user’s current market), formattedPrice (a string containing the app’s purchase price formatted for the user’s current market and currency), name (a string with the app’s name in the current market), and productListings. The latter is an array of ProductListing objects, each of which contains just three properties: productId (a string containing the app-defined product identifier), formattedPrice (a localized string containing the product price), and a localized name (a string). You can see that this collection is exactly what you’ll use to present the user with a localized list of options they can purchase, where the productId could be used to retrieve additional content like images from your package or a web service.

The LicenseInformation object for its part contains simple properties of expirationDate (a Date), isActive (a Boolean), and isTrial (a Boolean). It has one event, licenseChanged, which you can use to detect any changes to these properties, such as the expiration of a license while the app is running, in which case you want to prompt for purchase. The remaining property, productLicenses, is a collection of ProductLicense objects. Each of these contains the appropriate productId, expirationDate, and isActive properties.

Tip For globalization purposes, never compare two dates with simple arithmetic operators like <, >, and =. Instead. Use the Windows.Globalization.Calendar.compareDateTime method, which will account for the specific needs of different calendar systems that might be in effect.

That’s really the extent of the Store APIs in a nutshell. You may notice, by the way, that the APIs don’t concern themselves with ad-supported apps, since ads don’t involve the Store itself.

But you might be asking yourself some very significant questions: how on earth can this API return any meaningful information while the app is under development and has yet to be uploaded to the Store in the first place? How can you get product information and test all your purchase features when there’s nothing yet available to purchase?

These are great questions, and the answer lies in the one other object in the Windows.ApplicationModel.Store namespace that is our next topic: the Windows Store app simulator.

The CurrentAppSimulator Object

To make it possible to test an app’s interactions with the Store before the app is actually onboarded, WinRT provides the static CurrentAppSimulator object that is identical to CurrentApp with two exceptions: the simulator object works against data from a local XML file rather than live data from the Store, and the object has an extra method, reloadSimulatorAsync, to reinitialize the simulator with such XML. During development, you’ll want to use this line of code to start your work with the API:

var currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator;

and then delete the Simulator suffix when you’re ready to send the app to the Store. (And if you forget, you’ll fail Store certification.)

When your app accesses CurrentAppSimulator, WinRT looks for a file called WindowsStore-Proxy.xml in your app data, specifically under %userprofile%\AppData\local\packages\<package name>\Microsoft\Windows Store\ApiData. If it exists, the simulator is initialized from that data; otherwise the file is created with the following defaults (slightly formatted to fit the page):

<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
    <ListingInformation>
        <App>
            <AppId>00000000-0000-0000-0000-000000000000</AppId>
            <LinkUri>
              http://apps.microsoft.com/webpdp/app/00000000-0000-0000-0000-000000000000
            </LinkUri>
            <CurrentMarket>en-US</CurrentMarket>
            <AgeRating>3</AgeRating>
            <MarketData xml:lang="en-us">
                <Name>AppName</Name>
                <Description>AppDescription</Description>
                <Price>1.00</Price>
                <CurrencySymbol>$</CurrencySymbol>
                <CurrencyCode>USD</CurrencyCode>
            </MarketData>
        </App>
        <Product ProductId="1" LicenseDuration="0">
            <MarketData xml:lang="en-us">
                <Name>Product1Name</Name>
                <Price>1.00</Price>
                <CurrencySymbol>$</CurrencySymbol>
                <CurrencyCode>USD</CurrencyCode>
            </MarketData>
        </Product>
    </ListingInformation>
    <LicenseInformation>
        <App>
            <IsActive>true</IsActive>
            <IsTrial>true</IsTrial>
        </App>
        <Product ProductId="1">
            <IsActive>true</IsActive>
        </Product>
    </LicenseInformation>
</CurrentApp>

The full XML schema for this can be found on the CurrentAppSimulator page, but it’s straightforward to see exactly where you’d modify the XML to test different scenarios:

• Create additional MarketData elements to specify app details for other locales. The CurrentMarket element indicates the default.

• Create additional Product elements (including their MarketData children) for each in-app purchase.

• In the App element under LicenseInformation, change the values of IsActive (that is, not expired) and IsTrial between true and false to test the variations: active/non-trial, active/trial, expired/non-trial, and expired/trial. You can also add an ExpirationDate element to indicate when the app expires (in UTC time), using the form of yyyy-mm-ddThh:mm:ss.ssZ (replacing yyyy:mm:dd with the date and mm:ss.ss with the time). For automated testing, additional elements allow you to hard-code result codes; see the CurrentAppSimulator page for details.

• For each product, add a Product element under LicenseInformation with the appropriate ProductId attribute. Supported child elements are IsActive and ExpirationDate, with the same meaning as the app license.

It’s important to note that using the methods in the simulator object that change license status, such as converting a trial app to a purchased app or acquiring in-app purchases, will not alter the contents of the WindowsStoreProxy.xml file. This means you can just restart the app to reset the state of the simulator object. But it also means you’d need to edit the XML and launch the app again to test how different variations are handled on startup. (Note also that the store simulator state is not persisted when the app is suspended and terminated.)

For this purpose, the simulator object’s reloadSimulatorAsync method takes a StorageFile containing the XML initialization data. This can very much simplify your testing procedures, and often you’ll have such files directly in your project folder such that you can refer to them with ms-appx:/// URIs. However, make sure that these files don’t end up in your app package when you upload to the Store. In Visual Studio, right-click the file in the Solution Explorer pane and select Properties. In the Property Pages dialog that appears, as shown in Figure 17-3, set Package Action to None.

Images

FIGURE 17-3 Make sure that XML configuration files for the simulator object don’t end up in your Store packages.

The Trial app and in-app purchase sample, which we’ll be drawing from in the sections ahead, use reloadSimulatorAsync to load a specific XML file for each of its scenarios. In Scenario 4, for example (js/api-listing-uri.js), it loads data/app-listing-uri.xml as follows:

var currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator;
var page = WinJS.UI.Pages.define("/html/app-listing-uri.html", {
    ready: function (element, options) {
        // ...
        loadAppListingUriProxyFile(); // Initialize the license proxy file
    },
    unload: function () {
        currentApp.licenseInformation.removeEventListener("licensechanged",
            appListingUriRefreshScenario);
    }
});

function loadAppListingUriProxyFile() {
    // We could also use folder.getFileFromPathAsync("ms-appx:///data/app-listing-ur.xml")
    // instead of the two-step process with getFileAsync as shown here.
    Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("data").done(
       function (folder) {
           folder.getFileAsync("app-listing-uri.xml").done(
               function (file) {
                   currentApp.licenseInformation.addEventListener("licensechanged",
                       appListingUriRefreshScenario);
                   Windows.ApplicationModel.Store.CurrentAppSimulator
                       .reloadSimulatorAsync(file).done();
               });
       });
}

Notice how this sample listens for the licensechanged event and makes sure to call remove-EventListener when the page is unloaded. (See the “WinRT Events and removeEventListener” section in Chapter 3.)

This same Scenario 4 shows the basic retrieval of app information from the Store. When you click the Show Uri button on that page, it goes to the handler below that simply outputs the app’s linkUri property:

function displayLink() {
    WinJS.log && WinJS.log(currentApp.linkUri.absoluteUri, "sample", "status");
}

Getting at the app’s other properties would look the same, just using currentApp.loadListingInformationAsync first to obtain that data. This is shown in Scenario 1 (js/trial-mode.js):

function trialModeRefreshScenario() {
    currentApp.loadListingInformationAsync().done(
    function (listing) {
        document.getElementById("purchasePrice").innerText =
            "You can buy the full app for: " + listing.formattedPrice + ".";
    });

    displayCurrentLicenseMode();
}

And on that note, let’s look at the rest of the sample more fully because it shows the other use scenarios of the Store API as a whole.

Trial Versions and App Purchase

Implementing a trial version that hopefully leads to an app purchase is demonstrated in Scenario 1 of the Trial app and in-app purchase sample. When you run this sample and select Scenario 1, as shown in Figure 17-4, the simulator object is initialized using data/trial-mode.xml where the app’s IsActive and IsTrial elements are both set to true, meaning that we have a valid trial license. The ExpirationDate for this license is set to January 1, 2014, but we’ll play around with that in a moment.

Images

FIGURE 17-4 Scenario 1 of the Trial apps and in-app purchases sample (cropped slightly).

The Trial Period button in this scenario just calculates the number of days remaining in the trial period, using basic arithmetic and the licenseInformation.expirationDate property. Again, let me point out that the proper way to do this is with the Windows.Globalization.Calendar class that we’ll see later in the “World Readiness and Localization” section and demonstrated in the Calendar details and math sample. Using the APIs designed for this purpose will insulate your app from regional variations.

The Trial Mode and Purchased buttons just output different messages based on the state of the isActive and isTrial properties. Both button click handlers start like this:

var licenseInformation = currentApp.licenseInformation;
if (licenseInformation.isActive) {
    if (licenseInformation.isTrial) {

What can make the output from these buttons more interesting is modifying the data/trail-mode.xml file with different initial values for IsActive and IsTrial. Also try setting the ExpirationDate to a time in the past (remembering that it’s UTC time, not local time), and you’ll see that IsActive automatically gets set to false. You can also try setting ExpirationDate about a minute in the future, set a breakpoint on the trailModeRefreshScenario function inside js/trial-mode.js, then run the sample again.

You won’t hit your breakpoint immediately after ExpirationDate has passed, however. For performance reasons, the licensechanged event is not triggered immediately—there could be hundreds of expiration dates to track throughout the system. The event will instead fire reasonably soon, within about 20 minutes, so you might start such a test before going out for lunch.

This sample, of course, merely changes some output messages according to the validity of the license. In a real app you would either disable certain features for an active trial license or let the user do nothing except purchase the app if the trial has expired. You’d want to make such checks both when the app is run and in the resuming event.

The latter case is handled by the Buy App button in this scenario, an option that you would almost always present to users of your trial version at appropriate times, regardless of expiration status. This button calls a function called doTrialConversion that makes use of the CurrentApp.requestAppPurchaseAsync method (sample output code has been replaced here with comments identifying the specific results):

var licenseInformation = currentApp.licenseInformation;
if (!licenseInformation.isActive || licenseInformation.isTrial) {
    currentApp.requestAppPurchaseAsync(false).done(
    function () {
        if (licenseInformation.isActive && !licenseInformation.isTrial) {
            // Purchase was fulfilled
        } else {
            // Purchase UI was shown, but the user canceled.
        }
    },
    function () {
        // There was an error in the transaction; purchase did not occur
    });

The one argument to requestAppPurchaseAsync indicates whether a receipt string is sent to your completed handler; see “Receipts” below. In any case, if the user makes a purchase, the license-changed event will fire as it does for trial expiration, so you can always consolidate your license handling there.

When running in the simulator and you invoke requestAppPurchaseAsync, you won’t see the actual Store UI. Instead you’ll get an ultra-prosaic dialog from the simulator object in which you can specify the exact return value (an HRESULT):

Images

Sending back S_OK indicates that the purchase was made. The isTrial flag should change to false and isActive set to true. Returning any of the other errors will invoke the error handler for requestAppPurchaseAsync. Pressing Cancel, on the other hand, will call your completed handler but the values of isTrial and isActive will remain unchanged.

In the real world, of course, consumers will not be fiddling around with simulated Store conditions. Instead, if your app is marked to offer a trial version (something you set while uploading to the Store), they’ll see a Try button on the app’s listing page like this:

Images

Tapping Try will install the app and set both isActive and isTrial to true. At the point when the app calls requestAppPurchaseAsync, Windows will launch the Store and take the user to the app’s listing page where they can tap the Buy button if they choose.

Tip When writing this book, I looked at a number of apps that were available in the Windows Store and found that while many offered trials, few of them gave me any indication about why and how to purchase a full version. I was presented with such an option only when the (unknown) trial period had passed. If you want to convert trials into paid licenses, it’s better, even as the sample demonstrates, to inform the user that she’s running a trial and give her reminders and opportunities to convert!

Although the app’s expiration date is often used in conjunction with a trial license, there’s no limitation that it must be so: a free or paid app can also expire. If you don’t indicate a trial version when uploading the app to the Store yet indicate an expiration, the isActive flag will change to false at that date and time. A licensechanged event will also fire, allowing a running app to take appropriate action. The app can also check the active status and/or expiration date on startup and in the resuming event and display an appropriate message. Such an option is possibly useful for apps that truly have a limited lifespan, say an app that provides news and other information about a certain candidate’s political campaign. It might not expire immediately after election day, of course—maybe the app is still good for another few months, at which point it could be taken down from the Store altogether. Yet, as noted before, if the user has gone to all the trouble of acquiring an app in the first place, why not make it useful even after its primary purpose has been fulfilled? Updates to the app can also add fresh content and capabilities later.

Listing and Purchasing In-App Products

There are two aspects of working with your in-app purchases, or products as the API calls them. The first is letting the user appropriately know that those products are available through your own UI. The second is then completing the purchase and activating the product’s license.

If you’re using a custom commerce engine, the app will use its own services to retrieve the necessary product information and handle all the UI and license management for a transaction—the Store API will not play any role here. If the products are handled through the Store, on the other hand, the ListingInformation.productListings collection supplies localized product details and the CurrentApp.requestProductPurchaseAsync method handles the transaction, including the UI. This section focuses on these APIs.

As noted before, in-app purchases can have expiration dates, after which time the user needs to repurchase the product to continue its use. This is appropriate for subscriptions or rentals where the user was fully aware at the time of purchase that the product would eventually expire. In general, you should always make it clear if a product purchase will expire. Don’t surprise the user or the user will likely surprise you with a less than favorable review in the Store!

In-app purchases are demonstrated in Scenario 2 of the sample we’ve been using. In this case, the CurrentAppSimulator is initialized with data/in-app-purchase.xml, which defines two products (prosaically named Product 1 and Product 2), the first of which has an active license and the second of which is inactive. When you switch to this scenario (js/in-app-purchase.js), the sample loads the app’s ListingInformation, retrieves the product details from the productListings collection, and then displays those options (as shown in Figure 17-5):

currentApp.loadListingInformationAsync().done(
    function (listing) {
        var product1 = listing.productListings.lookup("product1");
        var product2 = listing.productListings.lookup("product2");
        document.getElementById("product1SellMessage").innerText =
            "You can buy " + product1.name + " for: " + product1.formattedPrice + ".";
        document.getElementById("product2SellMessage").innerText =
            "You can buy " + product2.name + " for: " + product2.formattedPrice + ".";
    });

Images

FIGURE 17-5 Scenario 2 of the Trial apps and in-app purchases sample (cropped); product information obtained from the Store is displayed in blue text (circled here in red).

Note that the productListings collection is an IMapView object and not an array; you can retrieve a specific item in the collection by using its lookup method, as in the code above, or by using a key-based array lookup:

var product1 = listing.productListings["product1"];

Iterating through the IMapView takes a little more work; it does not support index-based lookup nor the foreach method. You instead use an IIterator obtained through the first method, as shown here:

var iterator = listing.productListings.first()
var product;

while (iterator.hasCurrent) {
    product = iterator.current.value;
    document.getElementById(product.productId + "SellMessage").innerText =
        "You can buy " + product.name + " for: " + product.formattedPrice + ".";
    iterator.moveNext();
};

This code is completely equivalent to the previous snippet and relies on the fact that the product ID just so happens to match the first part of the appropriate element ID in the HTML. In any case, this is the sort of code you would use to present a variable list of options to the user.

In doing so, you’ll likely want to filter out those products that have already been purchased. In that case, you’d look up the product license within the CurrentApp.licenseInformation.productLicenses collection, which is another IMapView of ProductLicense objects, using the product’s ID as the key. Here’s how we’d modify the code above to perform this additional step:

var iterator = listing.productListings.first()
var licenses = currentApp.licenseInformation.productLicenses;
var product, message;

while (iterator.hasCurrent) {
    product = iterator.current.value;

    if (licenses[product.productId].isActive) {
        message = "You own " + product.name + ".";
    } else {
        message = "You can buy " + product.name + " for: " + product.formattedPrice + ".";
    }

    document.getElementById(product.productId + "SellMessage").innerText = message;
    iterator.moveNext();
};

If you use this code in Scenario 2 of the sample (which is provided in the modified sample in this chapter’s companion content), you’ll see the message “You own Product 1” when you first switch to that scenario. You could also add a further refinement to check the expirationDate property of each product license and display its remaining time.

You might have noticed that a ProductListing (from the app’s productListings collection) only contains a name and not a description. This really means that the name is the description and you should use it as such, rather than using it as another type of identifier, for which you already have productId. In other words, a product that provides 20 extra levels for a game should be named something like “Twenty extra levels with new challenges” rather than “extra_levels” because that name will appear in UI.

As you dangle all your product options in front of the user, the user will (I’m being very affirmative here!) at some point want to purchase one or more of them. When the user taps the appropriate button, like the Buy Product buttons in the sample (see Figure 17-5 again), the app just needs to call requestProductPurchaseAsync with the product ID and a Boolean indicating whether the method should provide a receipt:

currentApp.requestProductPurchaseAsync("product1", false).done(
    function () {
        if (licenseInformation.productLicenses.lookup("product1").isActive) {
            // Purchase was fulfilled; UI is not shown if the user already owns the product.
        } else {
            // Purchase UI was shown, but the user canceled.
        }
    },
    function () {
        // There was an error in the transaction; purchase did not occur
    });

If the product already has an active license, requestProductPurchaseAsync will simply call your completed handler without showing any UI, as none is needed. Otherwise the user will see a series of prompts to confirm the purchase, including confirmation of their credentials. For the whole flow, see The in-app purchase user experience for a customer. A typical confirmation message is shown below:

Images

Note that the warning here, which exists to meet regulations in some countries, is not entirely true: you can also cancel entering your credentials in the next dialog.

When using the CurrentAppSimulator, of course, you won’t see the Store prompts but only another simple dialog to control the result:

Images

As with the app purchase, any changes in product license status will trigger the licensechanged event; your handler for that event makes a great place to update your app status and initiate any downloads related to the purchase. The same event will be fired if a time-limited product license expires, which is your signal to make the purchase available again. It’s likely that you might also want to alert the user to that status, perhaps with a toast notification or with inline messages when the user tries to access that feature.

Receipts

Both the requestAppPurchaseAsync and requestProductPurchaseAsync methods of CurrentApp have an option, as we saw earlier, to provide a receipt string to the completed handler of the async operation. Its getAppReceiptAsync method also provides an all-up receipt (app and products) at any time. Generally speaking, receipts are most useful when a service needs to validate that an app is authorized to use certain functionality. The app acquires the receipt and sends it to the service, which can then do whatever validation it requires.

In all cases, the receipt is an XML string that contains information such as the app or product id, the dates when the purchase was made and when the receipt was issued, and a digital signature. The details of the XML schema can be found on the reference page linked above.

As an example, here’s the receipt string provided from requestProductPurchaseAsync when purchasing Product 2 in Scenario 2 of the sample:

<?xml version=\"1.0\" encoding=\"utf-8\"?><Receipt Version=\"1.0\" ReceiptDate=\"2012-09-11T17:35:55Z\"
CertificateId=\"\" ReceiptDeviceId=\"7a61447d-c8f4-457a-8310-363cbdffd21c\"><ProductReceipt
Id=\"e729be49-8299-4122-b6fb-a95bcfac6a7c\" AppId=\"Microsoft.SDKSamples.Store.JS_8wekyb3d8bbwe\"
ProductId=\"product2\" PurchaseDate=\"2012-09-11T17:35:55Z\" ProductType=\"Durable\" /></Receipt>

Here’s what Scenario 5 of the same sample receives from getAppReceiptAsync:

<?xml version=\"1.0\" encoding=\"utf-8\"?><Receipt Version=\"1.0\" ReceiptDate=\"2012-09-11T17:39:39Z\"
CertificateId=\"\" ReceiptDeviceId=\"50b4267d-437d-429e-a4b8-88da96da9e52\"><AppReceipt
Id=\"1550eb89-31ae-4559-b516-267afe47ae19\" AppId=\"Microsoft.SDKSamples.Store.JS_8wekyb3d8bbwe\"
PurchaseDate=\"2012-09-11T17:39:12Z\" LicenseType=\"Full\" /><ProductReceipt
Id=\"e2a62d42-dbca-43d2-b779-66eb916d9df4\" AppId=\"Microsoft.SDKSamples.Store.JS_8wekyb3d8bbwe\"
ProductId=\"product2\" PurchaseDate=\"2012-09-11T17:39:12Z\" ProductType=\"Durable\"
ExpirationDate=\"2014-01-01T00:00:00Z\" /><ProductReceipt Id=\"21967f50-ac55-4b41-acd9-f1e86ad6c7b9\"
AppId=\"Microsoft.SDKSamples.Store.JS_8wekyb3d8bbwe\" ProductId=\"product1\"
PurchaseDate=\"2012-09-11T17:39:12Z\" ProductType=\"Durable\" /></Receipt>

If you want to consume a receipt as an XML document instead of a string (for display or print), it’s a simple matter to create such an object like we did with tile and notification XML in Chapter 13:

var receiptDOM = new Windows.Data.Xml.Dom.XmlDocument();
receiptDOM.loadXml(receipt);

Accessibility

As I mentioned in this chapter’s introduction, nearly 60% of users employ accessibility features in some capacity—sometimes because of a real disability, sometimes due to personal preference, and sometimes just to make the device easier to use within certain environments. In many countries, accessibility is actually a legal requirement, so it will be necessary if you plan to make an app available in those regions. In short, supporting accessibility is something that every app should do and do well, and fortunately this isn’t the onerous task you might think it to be. (For reference, see Making your app accessible and Introduction to Web Accessibility; the latter is written for web apps but is very applicable to Windows Store apps. Also see Guidelines and checklist for Accessibility, Practices to avoid for accessible apps, and Implementing accessibility for particular content types.)

Accessibility might feel like a lot of work because developers are relatively unfamiliar with what it means. To remedy this, take a few minutes to give yourself some direct experience. But before you do anything else:

Go to PC Settings > Sync Your Settings and turn off the options for Desktop Personalization and Ease of Access. Otherwise the effects of your tinkering will roam to other devices you might have. I learned this the hard way when I was playing around with contrast settings on my main laptop after which a game my son wanted to play on a tablet came up mostly black! Clearly, that app didn’t handle high contrast well, but it also took me a while to figure out what was going on!

Now that we’ve taken care of that detail, try the following:

• Press Left Shift+Alt+Print Screen or go to PC Settings > Ease of Access and toggle high contrast mode (see image below). How does the app respond? Are all of the critical elements visible? A mode like this is important for users who have difficulty distinguishing subtle colors.

Images

• You can also select a particular high contrast theme through Control Panel > Appearance and Personalization > Personalization, where you have a choice between three black background themes and one white-background theme; the latter is the same one that’s activated through PC Settings or Left Shift + Alt + Print Screen:

Images

• In PC Settings > Ease of Access, tap Make Everything on the Screen Bigger. If your display is large enough, this will effectively scale everything by 140%. How does the app respond to the new screen dimensions? As discussed in Chapter 6, turning this on will activate the 140% resolution scaling, even though you’re not using a high pixel density device.

• Press Win+Ctrl+U to start (and stop) the built-in screen reader called Narrator. Win+Enter also starts it, and you can press Win+U to go to Control Panel > Ease of Access Center and tap Start Narrator. (Note that Narrator is a desktop application that starts minimized; you need to close that application to stop Narrator.) Now turn off the monitor. Can you still use the app? What happens when you navigate around with the keyboard? Do you hear an audible indication of where the focus is? This is clearly important for users who are blind or visually impaired.

• If you have a mouse, disconnect it and try keyboard-only navigation (you can open your eyes now). This is important for users with mobility issues and those who rely on speech recognition.

• With your mouse connected, go to Control Panel > Ease of Access Center and tap Start On-Screen Keyboard to try mouse/touch-only navigation. This special on-screen keyboard is different from the one activated for touch with input fields (as we saw in Chapter 9, “Input and Sensors”) because it always remains visible.

Through this experience I hope you’ve gained some understanding of what accessibility means. Simply said, there are four key scenarios for accessibility support: screen readers, keyboard-only or mouse-only input, high contrast, and resolution scaling.

The latter two we’ve already covered. In Chapter 6, “Layout,” we saw how to work with different resolution scales, how to handle varying screen sizes (which can occur as a result of scaling), and how to provide raster graphics for different scales so that they always look their best. For a quick review, you might want to revisit the Scaling according to DPI sample.

Input considerations were also covered in Chapter 9, and I’ll remind you again that the Store certification policy (section 3.5) requires that apps support all forms of input. Typically, this isn’t an issue for mouse and touch; the real work to be done is making sure that your app can be used with nothing but a keyboard. As noted in Chapter 9, see Implementing keyboard accessibility for full details. Testing your app with Narrator turned on will also reveal whether you’ve paid any attention to keyboard navigation, because no matter how well your elements are labeled for that purpose, those labels don’t do any good if the user can never set the focus to them!

It’s also worth mentioning that including closed captions in video will assist users who are hearing impaired. Doing so, however, is a detail for the video data itself or can be implemented via text overlays on a video element. See the HTML5 and Accessibility in MSDN Magazine for more on video accessibility.

Let’s now look at how we support screen readers and contrast variations.

The Windows SDK includes two tools to help you verify your implementation of accessibility. The first is called Inspect, a UI automation tool that checks through the accessibility information you’ve made available to screen readers and lets you know what you’ve missed. The second is called AccChecker, which runs a series of verifications on the rest of the app. You’ll find these tools in the Windows SDK install folder, typically c:\Program Files (x86)\Windows Kits\8.0\bin\x86. You might also be interested in the Accessible Event Watcher and the UI Automation Verify tools. For usage details on all of these, see Automation Testing Tools in the documentation as well as Testing your app for accessibility. Of course, for the most complete kind of testing, find yourself a few users who regularly work with assistive technologies, set them up with a developer license (so that you can share your app package), and let them put your app through its paces!

When making your app navigable by keyboard, be careful not to overuse tabindex attributes on elements that don’t need them, thinking that this will help Narrator for noninteractive elements. It actually doesn’t. Narrator has its own keyboard commands (like CapsLock+arrows) and its own navigation modes that skilled users employ to read anything on a page, irrespective of tabindex. For this reason, setting tabindex properties on static elements decreases Narrator’s usability; you should set the property only on interactive elements. In other words, understand that using an app through keyboard and using it through Narrator are different processes, and think only of tabindex in the context of keyboard navigation.

Screen Readers and Aria Attributes

Screen readers like the built-in Narrator can work only if the app provides some kind of information that tells the screen reader about the elements in the UI. For Windows Store apps written in HTML, CSS, and JavaScript, this is achieved through aria-* attributes on your UI elements.

Tip If you need separate text to speech capabilities, the Bing Translator API, for example includes a Speak method available through AJAX, SOAP, and HTTP interfaces that generates a WAV or MP3 stream for text in a given language. Other web services also exist for this purpose, and third-party libraries might be available.

ARIA stands for Accessible Rich Internet Applications, a standard that’s spelled out in the WAI-ARIA specifications. WIA itself stands for the W3C Web Accessibility Initiative. Two other W3C documents of interest are the WAI-ARIA Primer and WAI-ARIA Authoring Practices.

What it really boils down to is that assistive technologies like Narrator are first able to automatically derive what they need from certain elements, like header element, paragraphs, the title attribute, label elements associated with focusable elements (using the label’s for attribute), button text, input elements, the caption attribute of a table, and the alt attribute of img elements. The role attribute also comes into play here.

For everything else, as for div elements (including custom controls) whose role cannot be inferred, the specs define a number of attributes, starting with aria-, to indicate the role that a particular element plays in the app. Full details can of course be found in the specifications linked above, along with the ARIA reference on the Windows Developer Center. Another good reference topic is also Exposing basic information about UI elements in the documentation, that shows examples of a number of the core aria-* attributes. That page makes a special note about the canvas element. Because a canvas is just a pixel bucket, it generally doesn’t have content that is accessible to screen readers, even though it might appear as text. Make a special effort, then, to give a canvas appropriate attributes as you would with other custom elements (again see the HTML5 and Accessibility article for more on canvas).

All of the controls in WinJS are fully stocked with ARIA attributes and other bits that work with assistive technologies, so by using them you get lots of accessibility for free. (An exception is the SemanticZoom control that specifically does not have an aria-label itself because it’s a container for other controls that should have such labels themselves.) That said, it’s still necessary for you to properly adorn other elements, including HTML controls like progress. Here’s a summary of the core aria-* attributes:

aria-label Directly provides text for screen readers.

aria-labelledby (Note the spelling with two l’s.) Specifies the identifier of another element that contains the appropriate label for an element. The specifications state that aria-labelledby should be used instead of aria-label if that text is already on the screen.

aria-describedby Similar to aria-labelledby, identifies an element that contains fuller description instead of just label text. Narrator reads that text when the user presses the Win+Alt+F key on the element with this attribute. This is a good option to use with a canvas that contains drawn text: if you also store that text in another element linked with this attribute, even a hidden element, then the user has a way to hear that content.

aria-valuemin, aria-valuemax, and aria-valuenow For div elements whose role is set to slider, progressbar, or spinbutton, these indicate the values within the control. aria-valuetext can also provide text that corresponds to the value of aria-valuenow.

aria-selected, aria-checked, aria-disabled and aria-hidden Indicate the state of an element.

aria-live Needed for content that changes dynamically, such as master-detail views, chat, RSS feeds, fragment loading, and so forth.

Back in Chapter 4, “Controls, Control Styling, and Data Binding,” we saw that a special syntax was necessary to do data-binding on attributes of target elements where there are no associated JavaScript properties. The aria-* attributes are the primary example of this, because of their hyphenated names, for which we use this[ ] along with special WinJS initializers in data-win-bind:

<div data-win-bind="this['aria-label']: title WinJS.Binding.setAttribute"></div>
<div data-win-bind="this['aria-label']: title WinJS.Binding.setAttributeOneTime"></div>

It’s probably more typical, though, that you’ll provide localized ARIA labels in your app’s resources, and for this there is a different declarative syntax that we’ll see later on in “World Readiness and Localization.”

The ARIA Sample

To see the various aria-* attributes and Narrator in action, the best place to turn is a unique sample in the Windows SDK, the ARIA sample. One of its unique characteristics is that is doesn’t at all look like an SDK sample, as you can see in Figure 17-6. This was done to intentionally represent the content of a typical app, without all the other chrome that normally decorates the samples. In this case the sample emulates a simple chat app with a kind of master-detail view on the left side.

Images

FIGURE 17-6 The ARIA sample’s main page.

When you run this sample, be sure to turn on Narrator to hear what it has to say. (I highly recommend doing this in the Visual Studio simulator because then Narrator is only running in that session and not for your entire machine!) You’ll find that it’s accurately reflecting what’s happening on the screen, especially as you Tab or Shift+Tab between controls, press Enter or the spacebar to select items, and enter chat text. Again, turn off your monitor, close your eyes, get a blindfold, or have your five-year-old come up behind you and cover your eyes to get the full experience.

Pressing Enter on an item in the left-hand list will update the contacts shown in the middle. Selecting one of those contacts and pressing enter will then open another page containing a table—a contrived table, certainly, but one that shows the aria-* attributes that apply there. The page, shown in Figure 17-7, also provides an opportunity to experience page navigation through the keyboard and Narrator.

Images

FIGURE 17-7 The ARIA sample’s secondary page (cropped a bit).

Apart from the small bits of code in pages/chat/chat.js to work the chat window, the really interesting parts of this sample are all contained in the markup, specifically pages/chat/chat.html (the main page) and pages/table/table.html (the secondary page). In the first we can see aria-label on most of the controls (with the text you hear as you tab around) and much more extensive roster of attributes for the chat output div near the bottom:

<div class="chatpage fragment">
    <header aria-label="Header content" role="banner">
        <button class="win-backbutton" aria-label="Back" disabled></button>
        <h1 class="titlearea win-type-ellipsis">
           <span class="pagetitle">Aria Sample</span>
        </h1>
    </header>
    <section aria-label="Main content" role="main">
        <div class="chat">
           <div class="groupslist" aria-label="List of groups"
               data-win-control="WinJS.UI.ListView"
               data-win-options="{ selectionMode: 'none'}"></div>
           <div class="contactslist" aria-label="List of contacts"
               data-win-control="WinJS.UI.ListView"
               data-win-options="{ selectionMode: 'none' }"></div>
           <div class="chatTextContainer">
               <div class="chatTextEchoContainer" aria-label="Chat text area"
                   aria-live="assertive" aria-multiline="true" aria-readonly="true"
                   aria-relevant="additions" role="log"
                   tabindex="0"></div>
               <input class="chatTextInput" accesskey="i"
                   aria-label="Chat input area" type="text"
                   value="Type here..."/>
            </div>
        </div>
    </section>
</div>

That div, with the chatTextEchoContainer class, is updated at run time to contain child div elements for each text entry. For this reason it has the aria-live attribute, whose values are described as a “politeness level” in the W3C spec. The value of assertive says “communicate the change right away,” which is appropriate for chat but should be used carefully. The other value, polite (the default for role="log" elements), indicates a lower priority such that Narrator won’t interrupt the current task. The aria-relevant="additions" attribute is related to this, indicating what kind of changes are relevant to the live area. Its values are additions, removals, text, and all. With additions, if we happened to add an image to the chat window with an alt attribute, that would be communicated; if we set this to text, only text elements would be read.

The aria-multiline attribute indicates that the chat window is a mutliline textbox such that the Enter key is taken as text input rather than as a button press that would submit a form (as with the single-line textbox). The aria-readonly attribute then indicates that this control cannot be edited, to distinguish it from those marked with aria-disabled.

If you play with the sample, you’ll notice that when you tab to the chat window, Narrator reads the entire contents. When you enter a line of in the single line control, on the other hand, Narrator only reads the new element that’s been added. This is due to a default value of false for the aria-atomic attribute (not present in the markup). When used on an aria-live element, this tells the screen reader to read only the changed node in that element. If you set aria-atomic to true, a change to any child element is considered a change to the whole element such that all the contents will be read. This can apply on multiple levels, mind you, so that if you add a child element that is atomic and add grandchild elements within it, only that atomic child element would be read if the parent element is not atomic.

As for the markup in pages/table/table.html, this gives us an example of aria-describedby. Here’s the relevant section, omitting the table contents:

<div class="detail">
    <h2 id="title" role="heading" aria-level="2">Sample table</h2>
    <p id="subtitle" role="note">This table shows sample data.</p>
    <p class="generaltext">...</p>
    <table class="tabledetail" aria-describedby="subtitle"
        aria-labelledby="title" border="1">
        <!-- Contents omitted -->
    </table>
</div>

When you set the focus to the table in the running sample (you have to use the mouse for this unless you add a tabindex to the table), you’ll initially hear “Sample table” according to the aria-labelledby attribute. Then press Win+Alt+F, and you’ll hear “Item described by…” followed by the aria-describedby text. (And yes, go ahead and change it so that Narrator says some silly things. You know you want to!)

Note, finally, that it’s essential that the title and subtitle elements also have some aria-related attributes, such as role. Otherwise aria-labelledby and aria-describedby won’t work.

Handling Contrast Variations

Working with high contrast modes is primarily one of accommodating changes to the Windows color theme and making sure that you apply graphics that meet high contrast requirements. Technically speaking, high contrast is defined by the W3C as a minimum luminosity ratio of 4.5 to 1. A full explanation including how to measure this ratio can be found on http://www.w3.org/TR/WCAG20-TECHS/G18.html. A Contrast Analyzer (from the Paciello Group) is also available to check your images (some of mine in Here My Am! failed the test). Do note, however, that creating high contrast graphics isn’t required for non-informational content such as logos and decorative graphics. At the same time, full-color graphics might look out of place in a high contrast mode, so be sure to evaluate your entire end-to-end user experience under such conditions.

An app handles high contrast through four means. The first is to use built-in controls (both HTML and WinJS) and let the system do the work! To see what happens, run a few of the controls samples, such as the HTML essential controls sample and HTML essential controls sample and the HTML Rating control sample, and switch between the different high contrast themes in the Personalization section of Control Panel.

Of course, an app will almost always have some layout of its own, such as div elements with custom color schemes and such defined in CSS. You’ll want to make sure you have appropriate style rules for high contrast settings, for which we have the -ms-high-contrast media feature for media queries, similar to -ms-view-state as we saw in Chapter 6. This feature can have the values of active (to apply its rules to all high contrast themes), black-on-white (the white background theme), white-on-black (a black background theme), and none. Clearly, none is implied when you don’t use -ms-high-contrast to group any rules; active is also implied if you use -ms-high-contrast without a value. We’ll take a closer look at all this in the next section.

As with view states, you can use media query listeners and matchMedia to pick up contrast themes in code. This is useful for updating canvas elements, as we’ll see shortly. There is also the -ms-high-contrast-adjust CSS style that indicates whether to allow the element’s normal CSS properties to be overridden for high contrast. The default value, auto, allows this; the value of none will prevent this behavior. Again, we’ll see more shortly.

Next, WinRT surfaces the current contrast settings through the Windows.UI.ViewManagement.-AccessibilitySettings class. This has two properties: highContrast, a Boolean indicating if high contrast is on), and highContrastTheme, a string with the name of the high contrast color scheme. For the black on white theme this will be “High Contrast White”; for the other three themes in Control Panel > Personalization the strings will be “High Contrast #1”, “High Contrast #2”, and “High Contrast Black” (going from left to right). You can see these results through Scenario 2 of the UI contrast and settings sample, where the code is very simple:

var accessibilitySettings = new Windows.UI.ViewManagement.AccessibilitySettings();
id("highContrast").innerHTML = accessibilitySettings.highContrast;
id("highContrastScheme").innerHTML = accessibilitySettings.highContrast ?
    accessibilitySettings.highContrastScheme : "undefined";

WinRT also provides detailed color information through the Windows.UI.ViewManagement.-UISettings.uIElementColor method. (Note the odd casing on uIElementColor, an artifact of WinRT names projecting into JavaScript.) This returns a Windows.UI.Color object for an element identified with a UIElementType. Scenario 1 of the UI contrast and settings sample shows all these possibilities with a piece of instructive but otherwise uninspiring code that I won’t duplicate here!

The AccessibilitySettings object also supports one event, highcontrastchanged, that lets you know when high contrast is turned on or off; its eventArgs.target is the updated AccessbilitySettings object. You can use this event to trigger any programmatic updates you need to make in your UI, such as redrawing a canvas with high contrast colors if you’re not using a media query listener for that purpose.

Finally, with both raster and vector images, there are file naming conventions that you use in conjunction with the .scale-100, .scale-140, and .scale-180 suffixes for pixel density. For contrast, the appropriate suffixes are .contrast-standard, .contrast-high, .contrast-black (black-on-white), and .contrast-white (white on black). We’ll see this in action in the second section below, “High Contrast Resources,” and see how to combine both the scaling and contrast suffixes in the third section, “Scale + Contrast = Resource Qualifiers.”

CSS Styling for High Contrast

The CSS styling for high contrast mode sample provides a valuable look at dealing with high contrast modes where media queries and image files are concerned. As you might expect, most of these features are demonstrated declaratively in CSS and the app’s resources; only one scenario actually has any JavaScript code at all!

Scenario 1 shows the difference between elements that are and are not aware of contrast. With a normal color scheme in effect, its three buttons appear as follows, where the first two are div elements and the third a true button:

Images

When high contrast is turned on (Left Shift + Alt + Print Screen is very handy to toggle the setting for this sample), they appear like so:

Images

The first control, lacking contrast awareness, is still using white for its border, which of course disappears against a white background. The second button, on the other hand, has styles that use system-defined colors associated with a high contrast media query, so the button works well with any theme (css/scenario1.css):

@media (-ms-high-contrast) {
   .s1-hc {
       background-color: ButtonFace;
       color: ButtonText;
       border: 1px solid ButtonText;
   }
   /* ... */
}

Tip If you just stick with system colors entirely, both in CSS and in SVGs, then you won’t need to use media queries or different SVG files at all, because those colors will be adjusted for high contrast modes automatically. See User-defined system colors for a reference. You can also use the current-Color value in SVGs for fill, stroke, stop-color, flood-color, and lighting-color properties to reflect contrast settings.

Scenario 2 shows similar effects with button elements that use SVGs for their background images. With normal settings, those buttons appear as follows:

Images

With high contrast turned on, they appear like this:

Images

All that’s happening here is that we’re using a media query to use a high contrast background image for the button when necessary:

.s2-button-hc-bg-svg {
    background-image: url(../button-not-aware.svg);
    background-size: 100% 100%;
    width: 200px;
    height: 200px;
}

@media (-ms-high-contrast) {
    .s2-button-hc-bg-svg {
        background-image: url(../button.contrast-high.svg);
        background-repeat: no-repeat;
        background-size: cover;
    }
}

If you look in button-not-aware.svg, you’ll see that its gradient colors have many different values; in button.contrast-high.svg, on the other hand, those colors are generally set to black or ButtonFace, the latter reflecting the system color setting as is appropriate. (It would probably be better, in fact, to replace black with ButtonText, to use a system color that will automatically adjust to contrast settings.)

What’s going on with the first and second buttons? If you look in the CSS (css/scenario2.css), you’ll see that the only difference is that the style class for the first button, .s2-button, lacks a rule within the high contrast media query, whereas the second, .s2-button-hc, has a rule there that just specifies the exact same background image. So what’s the deal? What’s happening is that because the first button lacks any applicable style rule within the media query, its styles are automatically overridden with high contrast values. As described in Introduction to Web Accessibility, turning on high contrast overrides most color styles as well as background-image, in the latter case simply removing those images. This is why the first button shows up blank. The second button has a rule to define a background-image within the media query, so that image appears.

This brings us to the purpose of the -ms-high-contrast-adjust style. By default this is set to auto, allowing CSS properties to be overridden. If we set this to none within a style rule, we prevent those styles from being overridden or adjusted. Thus, if you add -ms-high-contrast-adjust: none; to the .s2-button rule in css/scenario2.css, you’ll see that the first and second buttons behave exactly the same. You can see this change in the copy of the sample included with this chapter’s companion content.

Moving now to Scenario 3, it normally draws the Internet Explorer logo on a canvas in color (below left), whereas in high contrast mode it draws the logo in black and white (below right):

Images

In this case, high contrast is picked up in JavaScript (js/scenario3.js) using a media query listener; no CSS is involved (this code is simplified for clarity; the actual sample also detects high contrast on startup):

var fillStyleOuterColor = "rgb(9, 126, 196)";
var fillStyleInnerColor = "rgb(255, 255, 255)";

var mql = matchMedia("(-ms-high-contrast)");
mql.addListener(updateColorValues);

function updateColorValues(listener) {
    if (listener.matches) {
        fillStyleOuterColor = "ButtonText";
        fillStyleInnerColor = "ButtonFace";
        draw();
    }
    else {
        fillStyleOuterColor = "rgb(9, 126, 196)";
        fillStyleInnerColor = "rgb(255, 255, 255)";
        draw();
    }

Note that the AccessibilitySettings.onhighcontrastchanged event could be used here instead of the media query listener.

Canvas a better choice? To this point in the Here My Am! app, I’ve been using images to provide messages in img elements when a photograph or the map isn’t available. When considering the needs for contrast and localized variations of those images, it’s easier to take localized string resources, as we’ll work with later on, and just generate the images on the fly with a canvas. This eliminates the need for many different image files and make the app package smaller, while still fully addressing both accessibility and localization needs. The version of Here My Am! in this chapter now works this way.

High Contrast Resources

In the previous section with the CSS styling for high contrast mode sample we saw a bit of the filename conventions that the Windows resource loader uses for high contrast: button.contrast-high.svg, for example. Scenario 4 of that sample shows how this lookup can happen automatically. In the project there is a file named button.svg alongside one named button.contrast-high.svg, with an img element declared in html/scenario4.html as follows:

<img src="../button.svg" />

If the system is running with normal contrast, the resource loader resolves the URI here to button.svg. (The ../ is because the scenario page is one level down in the HTML folder.) When high contrast is in effect, the resource loader instead looks for that same filename but with .contrast-high inserted before the extension.

Note If you’re using custom app bar icons, as discussed in the “Custom Icons” section of Chapter 7, “Commanding UI,” remember to include high contrast variants of your source images using this naming scheme.

If you like having more parallel filenames, you can also name the normal contrast file with .contrast-standard, as in button.contrast-standard.svg. If you do this in the sample project, leaving the HTML as is, you’ll see no difference in the output. At the same time, because of behavior nuances with contrast handling, it’s only recommended to use .contrast-standard if you also supply .contrast-white and .contrast-black variants.

As noted before, these variants are applied automatically for black-on-white (white background) and white-on-black (black background) themes, respectively. To see this, make a copy of button.contrast-high.svg and name it button.contrast-white.svg, and then make a second copy names button.contrast-black.svg. In that second copy, modify the gradient colors in the CDATA block by exchanging black with ButtonFace. When you then switch on a black background theme, you’ll see a button that’s white on black, as it should be.

All these changes can be found in the copy of the sample included with this chapter’s companion content.

The one caveat with the img element in Scenario 4 is that it won’t be updated when contrast is changed while the app is running, as happens with media queries in Scenarios 1–3. That is, the app host will not re-render the img element in response to a contrast switch. To change this behavior, we basically have to trick the app host into thinking that the source URI has changed by appending some dummy URI parameters. We can do this inside AccessibilitySettings.onhighcontrastchanged with eventArgs.target.highContrastScheme providing a decent variable for the URI (see js/scenario4.js in the modified sample):

var page = WinJS.UI.Pages.define("/html/scenario4.html", {
    ready: function (element, options) {
        var accSet = new Windows.UI.ViewManagement.AccessibilitySettings();

        accSet.addEventListener("highcontrastchanged", function (e) {
            var image = document.getElementById("buttonImage");

            //Use the scheme name (sans whitespace) as the dummy URI parameter
            var params = e.target.highContrast ?
                "?" + e.target.highContrastScheme.replace(/\s*/g, "") : "";
            image.src = "../button.svg" + params;
        });
    }
});

One significant advantage to highcontrastchanged over media query listeners is that the latter will be fired very soon after the change happens, at which point the resource loader might not have picked up the change by the time you set the img.src attribute. This results in the wrong image being displayed. highcontrastchanged is fired much later, so the code above generally works. That said, my experiments along these lines (with the sample running in snap view and the desktop control panel in filled view) show that it’s still not 100% reliable: changing contrasts is an expensive operation that triggers many events throughout the system, and there’s no guarantee when the resource loader will get reset. For this reason you can consider just bypassing the whole matter and explicitly setting the src attribute to a known file with a specific name. The modified sample actually runs with code like this (commenting out the code above). Or you can just use media queries!

Scale + Contrast = Resource Qualifiers

Because the graphics we worked with in the previous section are SVGs, there is no need to supply separate files for different pixel densities. But what if we have raster graphics? How do we combine scaling and contrast? This will also come up when we look at localization in the next section, because we might also need to include language variants.

This brings us to the matter of resource qualifiers, a topic that’s discussed in its fullest extent on How to name resources using qualifiers. Qualifiers include scale and contrast as we’ve seen, along with language, layout direction, home region, and a few other obscure variants.

To combine qualifiers within a single filename, append them together with underscores. The general form is filename.qualifiername-value_qualifiername-value.ext. So, a graphic named logo.png can have variants like logo.contrast-high_scale-180.png and logo.scale-100_contrast-white.png (the order of qualifiers doesn’t matter). Clearly, with the full set of three or four scales (accounting for the few scale-80 cases) and four possible contrasts, you might have as many as 16 distinct graphics files for that one resource. For a few examples of this, load the Application resources and localization sample into Visual Studio and look in the images folder. (Although the sample shows only contrast+100% scale examples, be sure to provide at 140% and 180% scales as well in your own app; Here My Am! for this chapter does so with its splash screen, tile, and other logo graphics.)

As we get into the topic of world readiness, we’ll find that localized image resources will require a set of scale and contrast variants for each language. As you can guess, the file naming conventions here could get really messy as the file count increases! Fortunately, the resource loader also allows qualifiers in folder names, so localized resources are typically placed within language-specific folders. We’ll see more of this later on in the section entitled “Part 2: Structuring Resources for the Default Language.” We’ll also avoid this complexity entirely in Here My Am! by using a canvas instead of discrete images for those graphics that contain text messages (the logos aren’t localized).

High Contrast Tile and Toast Images

Like any other images in your app, tile images in your manifest, images sent to the tile through updates, and images used in toast notifications all respect contrast settings. (Badges are not an issue as they are already monochromatic and adapt automatically.) In the manifest, naming images with resource qualifiers work for both scale and contrast, as well as language as we’ll see later.

XML payloads for tiles and toasts can refer to local images using ms-appx:/// URIs, and the resource loader will look for the appropriately qualified file. This does not apply to ms-appdata:/// URIs, however, so if you’re working with downloaded or dynamically generated images, you’ll need to identify a specific file yourself.

For XML payloads that refer to remote images, setting the addImageQuery option in the payload to true, as discussed in the “Using Local and Web Images” section of Chapter 13, will append query strings to the remote URIs that indicate scale, contrast, and language:

?ms-scale=<scale>&ms-contrast=<contrast>&ms-lang=<language>

These details are described on Globalization and accessibility for tile and toast notifications, along with how to localize strings in the XML payload. We’ll see these details for ourselves later on.

World Readiness and Localization

Over the years I’ve heard a number of words used to describe the process of making an app ready for different regional markets, and I imagine you have too: localization, localizability, internationalization, globalization, and world readiness. To be honest, the differences between these terms have confused me for some time, but I finally found a good explanation in an older book for desktop apps called Developing International Software by Dr. International (Microsoft Press, 2003). The same ideas are also expressed on Globalization Step-by-Step. Let me begin this section then by offering a simple summary of that view.

The goal with Windows Store apps is to make them available in many markets around the world, as provided for so conveniently by the Store itself. To do this, an app needs to be written such that it can adapt itself to just about any language and culture it might encounter. In some situations you may need to produce specific versions of the app, but hopefully you can have one app with localized resources that works for most markets. Truly, the days of monolingual apps are over.

To reach this goal you must first make your app world-ready. World readiness means that even though the app initially supports only one language and culture (most likely your own), it doesn’t actually make any assumptions about those specifics anywhere within its HTML, CSS, and JavaScript (and any WinRT components). That is, the core app is language-, culture-, and market-neutral, taking all these factors into account:

• Each and every string that might be shown in the app’s user interface, including element attributes like aria-label and img.alt, has been separated out into a resource file such that different resources can be loaded for different languages. (Using Unicode text is pretty much a given nowadays, so displaying text in many languages isn’t an issue, but be sure to keep this in mind if you’re migrating older software or using web services that might work otherwise).

• Each and every localized image (those that contain text or culture-specific content) has been organized into language-specific folders, appropriately named so that the resource loader can find them automatically.

• Any formatting and manipulation of dates, times, and currencies use APIs that automatically apply regional settings.

• Any sorting or collation of data takes the user’s language into account, using APIs for this purpose.

• No assumptions are made about how strings are concatenated; format strings with appropriate placeholders are instead included in language-specific resource strings so that they can be localized.

• The web services an app uses might vary from location to location, because of the need for local information or regional legal requirements.

• Text might be laid out left to right or right to left. Vertical is also possible but might be implemented in a separate version of an app because of its unique layout needs.

• Text input just works for all languages, whether from a keyboard or an Input Method Editor (IME), which implies that you should avoid hard-coding font names that don’t have full Unicode support. It’s good to stick with the typography in the WinJS stylesheets—they have built-in support for at least 109 languages.

• The user might switch languages at run time, and the app responds accordingly.

A world-ready app, in short, is both globalized—using APIs that isolate regional specifics—and is readily localizable such that adding support for another language requires no code changes, just the addition of new string and image resources. This is mostly a matter of how you structure those resources and how you reference them within the app’s markup and source code.

The process of localization, then, is one of generating or acquiring those language- and culture-specific resources, for which some very helpful tools are available to streamline translation work.

In the following sections we’ll look first at matters of globalization, explore how to structure resources to be localizable, and then see how to go about obtaining localized resources. After that, we’ll be ready to look at the last step in the long journey of an app’s creation: uploading to the Store.

Globalization

Besides language, the things that vary around the world are the representation of dates and times (including calendars); the representation of numbers, measures (units), phone numbers, and addresses; currencies; paper sizes (already discussed in Chapter 15, “Devices and Printing”); how text is sorted (collation); the direction of text; and the fonts used for text along with the input method.

To globalize an app means to make no assumptions about how any of this is accomplished, instead using the WinRT APIs that will do the right thing according to the current user’s settings. Working with those APIs is what globalization is mostly about.

Beyond using the APIs, look at the content of the app itself, checking for words, phrases, or expressions that might be very hard to translate (or potentially politically offensive), especially colloquialisms, vernacular, slang, metaphors, jargon, and the like. Use images that travel well, and aren’t likely to be misinterpreted elsewhere in the world (imagine wearing a T-shirt with such imagery in a country where you intend to market the app!). And exercise caution with maps because there is disagreement among different nations about where, exactly, their borders should be drawn. Be sure also to refer to “country/region” rather than just “country,” because disputed territories might not be recognized specifically as a country.

Also be aware of your regional export laws regarding encryption algorithms, because you might not be allowed to make the app available in certain markets. See Staying within export restrictions on cryptography. In addition, if you’re writing a game, be mindful of regional game rating requirements that might create more work for you than it’s worth. See Windows game publishing requirements.

If you use web services, make sure you also use services that are appropriate to the user’s locale. This might be required by law in some parts of the world (especially for financial transactions and maps) and often ensures that the user gets regionally relevant information from that service, unless they’ve specifically configured the app otherwise. You also want to be able to communicate the user’s locale and language to those services so that they can return content that’s already localized. It’s also helpful for the app’s overall performance to use servers that are relatively close to the user rather than on the other side of the world!

The first step in any of this, however, is to know where your app is actually running and the user’s language and cultural preferences, so let’s see how that is accomplished.

User Language and Other Settings

When a user first acquires a Windows 8 device or installs Windows 8 on a machine, it will likely be configured for their country of residence. However, many users speak multiple languages irrespective of where they live and might want to work with Windows in a particular language that has nothing to do with their location. For this reason, you always want to think about the user’s preferences separately from the actual location of the device, applying the user’s preferences to how your app displays information but using the physical location to control the services you use and other more functional aspects.

Languages and other preferences are configured through Control Panel > Clock, Language, and Region. Here you can add languages and select your primary one (see Figure 17-8), change input methods, specifically set your location (a country or territory), and set date, time, number, and currency formats (see Figure 17-9).

Images

FIGURE 17-8 Managing and selecting a language in Control Panel.

It’s a good thing there are globalization APIs, because dealing with all the variations here would be quite a chore otherwise! (Note that changes to the formats in Figure 17-9 will affect only those Windows Store apps that are running in the language you’re configuring; each set of custom formats is particular to a language.)

The basic details of the user’s settings are available through the Windows.System.UserProfile.-GlobalizationPreferences object and the classes in the Windows.Globalization namespace. GlobalizationPreferences just provides a handful of properties. Four of these, calendars, clocks, currencies, and languages are each an array of strings (an IVectorView to be precise) with the user’s preferred settings in order of preference. In the case of languages, it contains a list of BCP-47 language tags.

Images

FIGURE 17-9 Control panel dialogs for formatting and region.

It also contains a string property called homeGeographicRegion, which is the abbreviation for the selected value in Control Panel’s Location tab of Figure 17-9, and a property called weekStartsOn, which is a DayOfWeek value. Scenario 1 of the Globalization preferences sample will retrieve and display these values, except that you’ll want to add a line for currencies, which is missing from the sample. Having made that change and added a number of languages to my system, I see this output:

Images

Generally speaking, these values are exactly what you’ll typically need to communicate to a web service if it will be providing localized data to the app. However, the user’s language preference is best obtained in a slightly different manner, as we’ll see shortly.

Oftentimes you’ll need more detail for all of these settings, for which we can turn to the classes in Windows.Globalization. Some of these are static classes that are just there in the API to provide you with all the string identifiers that you would use to make comparisons in code without writing out the strings explicitly. ClockIdentifiers, for instance, just contains two string properties, twelveHour and twentyFourHour, whose values match those returned from Globalization-Preferences.clocks. Similarly, CalendarIdentifiers contains string properties for gregorian, hebrew, hijri, japanese, julian, korean, taiwan, thai, and umAlQura. So, if you wanted to compare the user’s preferred calendar to a specific one, you’d write code like this:

var userCalendar = Windows.System.UserProfile.GlobalizationPreferences.calendars[0];
if (userCalendar == Windows.Globalization.CalendarIdentifiers.julian) {
    // ...
}

This way you’re fully honoring the key principle of globalization by not making any assumptions about what those calendar strings are.

The other globalization classes are somewhat richer in scope and function. The Language class, which you typically instantiate with a specific BCP-47 tag, provides details like the displayName, nativeName, languageTag, and script. Scenario 2 of the aforementioned sample demonstrates this. The Language class also has two static members. One is the isWellFormed method that will tell you if a string contains a valid BCP-47 tag. The other is the currentInputMethodLanguageTag property that contains the BCP-47 tag for the user’s preferred input, which can be customized in Control Panel to be something other than the language’s default. (See the Options links on the right side of Figure 17-8; this is also demonstrated in Scenario 4 of the sample.)

Then we have the GeographicRegion class, which, if instantiated with no arguments, provides details on the user’s home region. You can also instantiate it with a specific location string. Either way, it then provides you with a displayName, a nativeName, a variety of code formats for the region (code, codeThreeDigit, codeThreeLetter, and codeTwoLetter), and currenciesInUse (an array of ISO 4217 three-letter codes). Scenario 3 of the sample shows these values for your configuration, such as:

Images

The ApplicationLanguages class, for its part, contains just a few things. manifestLanguages is an array of languages as defined by the app’s manifest; you’ll set these when you localize an app. languages contains a combination of the GlobalizationPreferences.languages array and those from manifestLanguages. The first item in this list is the best value to use for the user’s preferred language in your app, so this will be the one to send to web services for localization purposes.

Lastly, there’s primaryLanguageOverride, a property (BCP-47 tag) for apps that allow the user to select an app-specific language preference (and add it to the mix of languages). Setting this tells the system what language the app is using so that it can configure its own UI, and the setting is persistent across sessions. As it’s a relatively expensive operation, avoid using primaryLanguageOverride for transient purposes, such as rendering a few elements in a different language. For that, create a new language context and use that explicitly; see Windows.ApplicationModel.Resources.Code.-ResourceContext and scenario 13 of the Application resources and localization sample.

The last class, Calendar, is quite extensive and contains too many members to list here, many of which work with formatting as well performing calendar math. Before stepping into that arena, however, let’s look more broadly at the question of formatting data.

Formatting Culture-Specific Data and Calendar Math

If you clicked around within Control Panel’s formatting and region dialogs (refer back to Figure 17-9), you’ll find that the possible permutations for formatting something as simple as a number is quite mind boggling, let alone dates, times, and currencies!

Fortunately, “formatter” classes in WinRT take care of all the details such that you can take a value from new Date(), for example, and get back a string that completely reflects the user’s preferences. The APIs also provide parsing services that work in the opposite direction.

In Windows.Globalization.NumberFormatting we have CurrencyFormatter, DecimalFormatter, PercentFormatter, and PermilleFormatter, which you should always use these when converting data values into UI display strings. All of these classes are demonstrated in the Number formatting and parsing sample, where the basic process is to instantiate the formatter with or without specific codes or languages, set any necessary properties for the formatter (such as the number of digits and using separators), ahd then call its format method to obtain a string or, alternately, one of its parse* methods to turn a string into a number.

For example, to format a currency value, instantiate a CurrencyFormatter with a currency identifier (or a currency identifier plus a language list and a geographic region), set up any options, and then call format (js/CurrencyFormatting.js):

var userCurrency = Windows.System.UserProfile.GlobalizationPreferences.currencies;
var wholeNumber = 12345;
var fractionalNumber = 12345.67;

// Apply user defaults
var userCurrencyFormat =
    new Windows.Globalization.NumberFormatting.CurrencyFormatter(userCurrency);
var currencyDefault = userCurrencyFormat.format(fractionalNumber);

// Apply a specific currency
var currencyFormatUSD = new Windows.Globalization.NumberFormatting.CurrencyFormatter("USD");
var currencyUSD = currencyFormatUSD.format(fractionalNumber);

// Apply a specific currency, language, and region (France, then Ireland)
var currencyFormatEuroFR =
    new Windows.Globalization.NumberFormatting.CurrencyFormatter("EUR",
    ["fr-FR"], "ZZ");
var currencyEuroFR = currencyFormatEuroFR.format(fractionalNumber);

var currencyFormatEuroIE =
    new Windows.Globalization.NumberFormatting.CurrencyFormatter("EUR",
    ["gd-IE"], "IE");
var currencyEuroIE = currencyFormatEuroIE.format(fractionalNumber);

// Include fractions with a whole number
var currencyFormatUSD1 =
    new Windows.Globalization.NumberFormatting.CurrencyFormatter("USD");
currencyFormatUSD1.fractionDigits = 2;
var currencyUSD1 = currencyFormatUSD1.format(wholeNumber); 
// Group integers
var currencyFormatUSD2 =
    new Windows.Globalization.NumberFormatting.CurrencyFormatter("USD");
currencyFormatUSD2.isGrouped = 1;
var currencyUSD2 = currencyFormatUSD2.format(fractionalNumber);

The output of this code is as follows:

Images

The other number formatters all work like this, so I’ll leave it to you to check out the details in the documentation and the sample.

To format dates and time, we can turn to the Windows.Globalization.DateTimeFormatting namespace where we find the DateTimeFormatter class along with many enumerations for the different ways to formats seconds, minutes, hours, days, months, and years. To use the API, you instantiate a formatter object specifying the desired formats and applicable languages. (There are no less than eight separate constructors here!) You then set options like the clock, geographicRegion, and so forth and call its format method with the Date value you need to format. You can even apply custom formats if desired. Many such variations are demonstrated in the Date and time formatting sample; I trust a simple snippet of its code will suffice here (from Scenario 2, js/stringtemplate.js);

var mydatefmt1 = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
    "month day");
var mytimefmt1 = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
    "hour minute ");
var dateToFormat = new Date();
var mydate1 = mydatefmt1.format(dateToFormat);
var mytime1 = mytimefmt1.format(dateToFormat);

The other bit of code from the SDK that’s relevant here is the Calendar details and math sample. As mentioned earlier in this chapter when I described expiration times for app trials and in-app purchases, a world-ready app must not make assumptions about how time periods are computed or compared because this can vary depending on regional calendars. This is why the extensive Windows.-Globalization.Calendar class contains ten distinct add* methods that range from addNanoseconds to addEras, along with its compare and compareDateTime methods (and a bunch to get all the little bits of calendar-related text). In other words, drill it into your mind now to never, ever use arithmetic operators on date and time values because they won’t work properly in every locale. Even in the United States you’ll end up getting wrong answers at times because you won’t be taking things like daylight savings time into account, where the number of hours in two days of every year will not actually be 24!

Sorting and Grouping

Just as a world-ready app cannot make assumptions about comparing date and time values, it cannot make assumptions about how strings are sorted. Simply said, every language has its own way of sorting that doesn’t necessarily have anything to do with the values of the character codes involved. The bottom line here is that you should never sort by such values; always use a language-aware API instead.

For Windows Store apps written in HTML and JavaScript, you can use the localeCompare method that’s already built into strings (even for individual characters). This performs the comparison based on the user’s current language. You can also use a string’s tolocaleLowerCase and toLocaleUpper-Case methods. In Chapter 5, “Collections and Collection Controls,” specifically in the section “Quickstart #2b: The ListView Grouping Sample,“ we also saw how to use the Windows.Globalization.-Collation.CharacterGroupings API to create proper groupings by the first character of item titles. You can compare the original SDK sample and the modified sample in Chapter 5’s companion content to see how such code was globalized.

Fonts and Text Layout

Thanks to Unicode and the ability of HTML directly handle text in different languages, there’s little you need to do to make such text appear properly within your layout. For example, if you look at the Language font mapping sample, pages like html/scenario2.html that contain this markup:

<div id="scenario2Document">
    <h2 lang="hi" id="scenario2Heading" contenteditable="true">
        Images
    <p lang="hi" contenteditable="true">
        Images
</div>

just show up like you expect they would (and if you read Hindi, you’ll see that this is just jibberish):

Images

What this particular sample is actually meant to demonstrate is the Windows.Globalization.-Font.LanguageFontGroup object, which provides specific font recommendations for different parts of the UI. Once created using a specific BCP-47 tag, the object contains a number of properties, each of type LanguageFont, such as uITextFont and uIHeadingFont (notice the odd casing again). Each LanguageFont object then contains properties of fontFamily, fontStretch, fontStyle, fontWeight, and scaleFactor. Through a couple of helper functions in js/langfont.js, which are deceivingly added to the WinJS.UI namespace without being part of WinJS itself, these recommen-dations are applied to elements in the DOM simply by setting the appropriate styles for those elements.

Be clear that these font recommendations are really refinements and not necessary for basic function. As Scenario 4 of the sample demonstrates, a basic English font (with Unicode characters, of course) applied to mixed English/Japanese text will still render the Japanese but perhaps not optimally. Applying the recommended font will make that refinement.

The other aspect to working with different fonts and languages is how these affect your overall layout, something we didn’t go into in Chapter 6, “Layout.” This is discussed in the documentation on How to adjust layout for RTL languages and localize fonts, but let me summarize that material and add a bit more.

First of all, a world-ready app leaves extra space for various bits of content like headings and labels because the words and phrases will be longer in some languages and shorter in others. The general guidelines are to leave at least 30% more room over what’s needed in English for typical strings and as much as 300% for really short strings or single words. As a simple example, the English word “wrench” translates into German as “Schraubenschlüssel”; the word “click” (if I’m to trust Bing Translator), translates into Greek as “Κάντε κλικ στο κουμπί.” You may need to enable word wrapping in some cases.

For all such purposes you can and should use the :lang()/:-ms-lang() pseudo-class selector in CSS to adjust styles like width as needed for specific languages. Just be sure to test your app with those languages, or test thoroughly with the pseudo-language (see “Testing with the Pseudo Language” later on).

Secondly, different languages flow text in directions other than the left to right (then top to bottom), like English and many Indo-European languages. Arabic and Hebrew, for instance, read right to left (RTL) instead of left to right; a few will flow top to bottom first, then right to left.

When making your app world-ready for RTL languages (considering that such markets are significant), you’ll want to support what is called mirroring in your layout. It really means reversing your layout, including images, the direction of the back button, the direction of animations, panning directions, and so forth.

Fortunately, HTML and CSS layout automatically accommodate this, and the WinJS stylesheets, ui-light.css and ui-dark.css, set the CSS direction style appropriately as follows (something you should use on the element level for RTL languages rather than align):

html:-ms-lang(ar, dv, fa, he, ku-Arab, pa-Arab, prs, ps, sd-Arab, syr, ug, ur, qps-plocm) {
    direction: rtl;
}

In fact, look around in the WinJS stylesheets and you’ll find many adjustments made for RTL languages with :-ms-lang, specifically with margins and padding. So by using HTML, CSS< and WinJS—including built-in controls—much of the mirroring is taken care of automatically; Here My Am!, for instance, just works in Hebrew.

With images, you can reverse them when needed by applying a transform: scaleX(-1) style to the necessary elements. If, however, you have images that really need to be replaced (as when some parts would be mirrored by other parts would not), you can use layoutdir-RTL in the image filename in the same way we’ve seen for pixel densities and contrast. In fact, there are many qualifiers for use with resources that are described on How to name resources using qualifiers, something we’ll be looking at more closely in the next section.

Sometimes you’ll need to reverse a certain portion of text, as when mixing languages in the same paragraph. For this you can apply the unicode-bidi style in conjunction with direction. (Do note that numbers are generally direction-neutral so that they take on the directionality of their containing element, so you might need to set direction separately.) Along similar lines, you can also use the -ms-writing-mode style to flow text in just about any other direction, something you might use for an app that presents classical Chinese, Japanese, or Korean poetry.

Preparing for Localization

Once your app has been made world-ready such that it can handle just about any language and regional settings you want to throw at it, the next step is to make sure that language-specific resources in the app are cleanly separated from your HTML, CSS, and JavaScript and placed in your resources where the Windows resource loader (also referred to as the Resource Management System) can find them.

Before going further, there’s an excellent topic in the documentation on this subject, How to prepare for localization, which provides suggestions for translation and other details. It’s not productive to repeat all of that here, of course, so I want instead to break that guidance down into a couple of steps that you can apply to an app and its default language before adding support for additional languages.

Note The resource loader supports sparse localization for dealing with slight variations between similar. It means that with languages like American English (en-US) and British English (en-GB), most of the app’s resources can be assigned to en-US with en-GB resources for only those bits that vary, like “color” vs. “colour” and “favorite” vs. “favourite,” or vice-versa. Because each resource is resolved individually according to the user’s preferences, an app running in an en-GB context will find those specific bits first, if they exist, otherwise the loader will look in the en-US resources. There is also support for dealing with specific language exceptions through the use of resources marked with the undertermined tag und. See How to manage language and region, step 4 (toward the end) for details along with Language Matching.

Part 1: Separating String Resources

The first step in preparing for localization is to move language- or region-specific strings from source files into a string resource file and inserting references to that file where necessary. In the next section (Part 2), we’ll then set up the folder structure for this file and image resources that will then accommodate localized versions.

To create your first string resource file, right-click your project in Visual Studio’s solution explorer, select Add > New Item, and then select Resources File (.resjson). Although you can change the filename, just leave it set to the default resources.resjson for now. Press Add, and the file will be created in your project root, where we’ll also leave it until Part 2.

Omitting a comment at the top, the contents of this file appear as follows:

{
   "greeting"          : "Hello World!",
   "_greeting.comment"  : "This is a comment to the localizer"
}

As you can see, the file is just plain JSON where each property has a string identifier and a string value; any resjson file can have as many properties as you want.

Clearly, too, there is a relationship between the two entries above. The first entry of the form <identifier> : <value>, is a real string resource that maps an valid JSON identifier (no whitespace) to a string value. This is what the resource loader will use to replace references to the identifier with the string value.

Any entry of that begins with an underscore, such as the conventional <_identifier.comment> : <value> is ignored by the resource loader. Such entries provide notes for a translator so that they can fully understand how the string is used and specific parts that shouldn’t be translated. A second optional entry, <_identifier.source> : <value>, provides the original string in the default language, which is very helpful for reference.

If you want to see some more extensive resjson files, open the Application resources and localization sample and look in the strings folder under a particular language. In the ja/resources.resjson file, for example, you’ll see the string resources along with both comment and source entries:

{
  "displayName"          : Images,
  "_displayName.source"   : "Application Resources JS SDK Sample",
  "_displayName.comment"  : "Don't change 'SDK'",

  "description"          : Images,
  "_description.source"   : "Application Resources JS SDK Sample",
  "_description.comment"  : "Don't change 'SDK'",
}

Turning back to your own app with the new resources.resjson file in hand, we’re now ready to go on a search and replace mission throughout the app project, looking for localizable strings, extracting them into the resource file, and replacing them in the source files with an appropriate reference. The three primary places we need to look at are your HTML files, JavaScript files, and the app manifest. To demonstrate, I’ll show what I did with the Here My Am! example that we’ve been working with in this book (to which I’ve added a resources.resjson file).

Note CSS files can contain string literals in the content and quotes styles; however, resource lookup from CSS is not supported for Windows Store apps in Windows 8. Localization must be done in CSS with the :lang and :-ms-lang pseudo-selectors.

JavaScript: Let’s start with JavaScript, where you need to scrub your code for string literals, including any you are drawing to a canvas. In Here My Am! I found only a couple localizable strings, namely a folder name used in the Pictures library and the title and description used when formatting text for the Share contract and our live tiles (pages/home/home.js):

var folderName = "HereMyAm";
data.properties.title = "Here My Am!";
return "At latitude " + lat + ", longitude " + long;
return "At (" + lat + ", " + long + ")";

and the Settings commands in js/default.js:

app.onsettings = function (e) {
    e.detail.applicationcommands =
        {

           "about":   { title: "About", href: "/html/about.html" },
           "help":    { title: "Help", href: "/html/help.html" },
           "privacy": { title: "Privacy Statement", href: "/html/privacy.html" }
        };
    WinJS.UI.SettingsFlyout.populateSettings(e);
};

Note that in home.js English strings are used for exceptions, but because they’re only for debugging purposes they don’t need to be localized.

Extracting the other strings into resources.resjson, then, that file appears as follows where I’m using regular comments to identify where the strings are used. Notice that I’m now using a format string to create a descriptive location for Share and tiles instead of hard-coding its construction (see the formatLocation function in js/home.js for how these are used):

{

    // pages/home/home.js
    "foldername" : "HereMyAm",
    "share_title" : "Here My Am!",
    "location_formatShort"         : "At (%s, %s)",
    "_location_formatShort_comment" : "Used to format a short location as in 'At (120, 45)",
    "location_formatLong"          : "At latitude %s, longitude %s",
    "_location_formatLong_comment"  :
                         "Used to format a long location, 'At latitude 120, longitude 45",

    // default.js
    // Settings panel commands
    "about_command"  : "About",
    "help_command"   : "Help",
    "privacy_command" : "Privacy Statement",
}

I highly recommend that you organize your entries by source file like this, and you can also use multiple resource files if you like, as explained in the next section. Also be careful about how you reuse the same string that occurs in multiple places. If it’s for the same kind of UI with the same intent, that’s fine, but if the usage context is different it’s better to duplicate the string as they might translate differently in other languages. In the resources above, notice how I also included a comment for location_formatShort because the word “At” by itself probably needs more context to translate properly.

With the strings separated as resources, we can now use the resource loader to obtain those strings at run time. This can be done in two ways. First is with the WinRT APIs directly, namely Windows.ApplicationModel.Resources.ResourceLoader.getString:

var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
var text = loader.getString('location_formatShort');

or, more simply, with the WinJS.Resources.getString wrapper:

var text = WinJS.Resources.getString('location_formatShort').value;

that also happens to work in the web context where WinRT isn’t defined (see Scenario 12 of the Application resources and localization sample.) Note that getString returns an object that includes a value property with the string along with lang and an empty flag indicating if the resource wasn’t found.

The WinJS method, being one line, is clearly helpful in cases like our settings commands because we can call it inline. Thus, in our code we just replace the string literals with the WinJS call, such as the following in pages/home/home.js:

data.properties.title = WinJS.Resources.getString('about_command').value;

and the following inside the object for the Settings commands:

"about": { title: WinJS.Resources.getString('about_command').value,
    href: "/html/about.html" },

Note that WinJS, being optimized for common scenarios, supports loading strings in the user’s default language only. The WinRT ResourceLoader class, on the other hand, is much more flexible and can load a string for any specific language. You’ll need to use that API when your requirements exceed what WinJS provides.

And that’s really it for JavaScript. If you’ve made these changes to your app, now is a good time to use the Build > Build Solution command in Visual Studio. This will compile the resources.resjson file into a more efficient binary format called resources.pri, ignoring entries that begin with an underscore. Doing an occasional build (without string the app) is a good practice when working with resources so that you can clean up any problems in your files, such as duplicate entries or syntax errors. Then you can run the app to see the resource loader in action—mostly by seeing no difference from the app as it was before! Be sure to test all the code paths that were affected, however, to ensure that all the strings are being loaded properly.

Manifest: Let’s turn now to the manifest, where the story is even simpler because there’s no code involved. The textual pieces here that might need localization are

• The display name, description, and short name (for tiles) on the Application UI tab.

• Any text descriptions for specific entries on the Declarations tab.

• The package display name on the Packaging tab. (You would change the package name only if you were going to submit the app to the Store under a different name in certain markets, in which case it’s a different app package entirely.)

• Possibly some URIs on the Content URIs tab.

While we’re looking at the manifest, note the Default Language setting on the Application UI tab. This is what defines the app’s default or fallback language if the user runs the app with a language that isn’t provided for in your resources. We’ll also come back to images in the manifest in the next section.

Looking at all the strings in the manifest, extract these to your resources.resjson file, giving them appropriate identifiers. Again, if you have some strings in the manifest that match those elsewhere in the app, carefully evaluate them to determine if they can all use the same resource. When in doubt, keep them separate as the overhead is quite small. In the case of Here My Am!, the app’s display name and the string used for the header on the main page are the same and have the same usage, so they can refer to the same resource.

To refer to those resources in the manifest, then, use ms-resource:<identifier>. For example, I moved the Application UI > Display Name value into the resource file and called it app_title, so in that field of the manifest editor I simply write ms-resource:app_title. I did the same for the description and the package display name.

Once you’ve made these changes, run the app and make sure text on your tile, if you’re using it, shows up properly. You might temporarily set the Application UI > Show Name to “All Logos” as a check, but be sure to change it back before you forget!

As described on Globalization and accessibility for tile and toast notifications, XML payloads for tile and toast notifications use the ms-resource: syntax to identify string resources in text elements. This will trigger the resource loader’s lookup mechanism when the tile is rendered, and this works regardless of whether the notification was issued locally, obtained from a web service, or received as a push notification. The web services just need to be sure they use the app’s particular resource identifiers.

A web service can also issue localized tile updates directly. In this case, an app will generally append query strings to the service URI to communicate the desired language, updating those parameters as necessary when the language changes (see “Localization Wrap-Up” for details). An app can also combine this with using regional web services that help localize the update content.

HTML: The final place we need to look for strings is our HTML, which I’ve saved for last because it’s the most involved. In HTML, really scrub, scrub, scrub your markup for any hard-coded text that will become visible in the UI. Check the body content of elements like p, h1, span, div, button, option, and so on, as well as the value of attributes like title, alt, aria-label, etc. Also look inside WinJS controls like AppBar and Flyout, and look for any embedded URIs that you’ll want to localize, including those of services you employ and content you show in an iframe. Note, though, that title elements in a page head are not shown and do not need localization.

In Here My Am! I found lots of strings in pages/html/home.html, which I’ve highlighted below:

<header id="header" aria-label="Header content" role="banner">
<section id="section" aria-label="Main content" role="main">
<div id="photoSection" class="subsection" aria-label="Photo section">
<h1 class="titlearea win-type-ellipsis"><span class="pagetitle">Here My Am! (8)</span></h1>
<h2 class="group-title" role="heading">Photo</h2>
<img id="photo" class="graphic" src="/images/taphere.png"
    alt="Tap to capture image from camera" role="img" />
<div id="locationSection" class="subsection" aria-label="Location section">
<h2 class="group-title" role="heading">Location</h2>
<div id="floatingError" class="win-type-x-large">Unable to obtain geolocation; check
<br />permissions and use the app bar to try again.</div>
<div id="retryFlyout" data-win-control="WinJS.UI.Flyout" aria-label="Trying geolocation"
    data-win-options="{anchor: 'mapDiv', placement: 'bottom', alignment: 'center'}">
    <div class="win-type-large">Attempting to obtain geolocation...</div>
</div>

where I also made a note that I’ll need to localize the taphere.png image, as it contains text, but this is for the next section. In default.html, I also found labels and tooltips in the data-win-options attributes of the appbar commands (and I’m omitting some of the other markup for brevity):

<div id="appbar" data-win-control="WinJS.UI.AppBar" data-win-options="">
    <button data-win-options="{id:'cmdPickFile', label:'Load picture', icon:'browsephotos',
        section:'global', tooltip:'Load a picture through the file picker'}">
    </button>
    <button data-win-options="{id:'cmdRecentPictures', label:'Recent pictures',
        icon:'pictures',
        section:'global', tooltip:'Browse recent pictures taken in the app'}">
    </button>
    <button data-win-options="{id:'cmdRefreshLocation', label:'Refresh location',
        icon:'globe',
        section:'global', tooltip:'Refresh your location'}">
    </button>
</div>

Tip When preparing for localization, consider whether your appbar icons have a universal meaning. If not, they’ll also need to be localized. Fortunately, the icon values are strings and can be localized as such, in which case you can treat them like the labels and tooltips.

Other affected files in this app include all of those in the HTML folder that are used for Settings commands. With such commands, be especially careful to note the short header labels that might be in a div like the one below amongst a bunch of other markup. Leave nothing behind!

Once you’ve located your strings, copy them as before to resources.resjson. This will likely be an extensive workout with copy and paste, so grab some refreshments and go for it. It’s also fine to have HTML in these strings—they’ll just be inserted into the markup and will render as such if you attach them to a property like innerHTML, but don’t include the surrounding tag (we’ll need it shortly). For example, in html/about.html I have a number of p elements with text, such as:

<p>Here My Am!<br />Version 1.0.0.0<br /></p>

for which I make the following string in the resources (no p tag):

"about1" : "Here My Am!<br />Version 1.0.0.0<br />",

Now for the fun part: how to we reference the string resources in markup? If you think about it a little bit, we have to run some piece of code to go through and replace whatever references we make with the appropriate string from the resource file. Hmmm. Haven’t we seen something like this before? Indeed we have. With controls, we added data-win-control attributes to the markup and used WinJS.UI.processAll or WinJS.UI.process to run the code to instantiate the control. We have a similar setup for resources: a data-win-res attribute and WinJS.Resources.processAll, the latter of which should be called in each page’s ready method or wherever else HTML content like the appbar is loaded, such as in the app’s activated handler after WinJS.UI.processAll (so the controls are instantiated).82 Here’s what you do in markup:

• Replace attributes and their string values with data-win-res="{<attribute> : '<identifier>'}" where <attribute> is the original attribute name and <identifier> matches the desired string in the resource file, contained in single quotes.

• Where there are multiple attributes in the same element, you can separate each <attribute> : '<identifier>' pair with a comma.

• When the string is directly inside a tag, we use data-win-res with the equivalent attribute name, such as textContent for a div, p, or span. If the string contains markup, use innerHTML instead, but only when necessary because textContent is much faster.

• For hyphenated attributes like aria-label, use the syntax {attributes: {'<attribute>' : '<identifier>'}} in the data-win-res value, using single quotes around <attribute>. This is how you combine localization and accessibility together.

• For properties of WinJS controls that would normally appear within data-win-options, place those in data-win-res with the syntax {winControl: {<property> : '<identifier>'}}. Multiple properties are again separated with a comma within the inner { }’s.

Here are some examples as modified from the earlier markup:

Images

When WinJS.Resources.processAll goes through the DOM, it actually doesn’t remove any of the data-win-res attributes; it just processes those values and adds other attributes to the element that contain the string resource. The advantage of this is that a later call to processAll will go through the DOM and refresh all those strings. That means that if you handle the WinJS.Resources.-oncontextchanged event, which tells you when the language changes, you can call processAll again and your UI appears in that new language! We’ll add this little piece of code later on once we’ve added a few more languages to Here My Am!.

It also means that if you want to perform WinJS data binding in conjunction with a string that originates in your resources, simply include data-win-bind attributes inside those strings, assign that string to an element’s innerHTML property within data-win-res, and then be sure to call WinJS.Resources.processAll before calling WinJS.Binding.processAll. This is demonstrated in Scenario 8 of the Application resources and localization sample (html/scenario8.html and js/scenario8.js):

HTML: <p id="messageCount" data-win-res="{innerHTML: 'scenario8MessageCount'}">
Resources: "scenario8MessageCount" : "You have <span
           data-win-bind=\"innerText:count\"></span> message(s)",

And with that (except for the following sidebar that I’ve cleverly inserted), we’re ready for the next step that will take care of our image resources and set us up to localize all this content we’ve extracted.

Sidebar: String Resources in Settings Flyouts

In all of this, one of the more challenging pieces of markup to work with were the HTML pages for settings flyouts, namely the about.html, help.html, and privacy.html in the project’s HTML folder. These pages are not loaded until the settings command is invoked, and because that’s happening all within WinJS we have to use the flyout’s beforeshow event to call WinJS.Resources.processAll for the flyout’s markup. To catch that event, I added onbeforeshow : beforeShow in each flyout’s data-win-options string and then this piece of code within a script tag at the end of the body element:

function beforeShow() {
    WinJS.Resources.processAll();
}
beforeShow.supportedForProcessing = true;

where the last line is necessary because WinJS will be calling WinJS.UI.processAll when the page is loaded. In any case, this works just great for patching up the string resources, with one exception. In privacy.html, if you remember from Chapter 8, “State, Settings, Files, and Documents,” I’m using an iframe to load a remote page with a privacy statement. Because this should be localized, I placed the URI itself into the string resources and attempted to load it up like other strings:

<!-- This won't work -->
<iframe data-win-res="{src : 'privacy_URI'}" height="600"></iframe>

However, this caused an exception within WinJS.Resources.processAll that complained about something not being marked with supportedForProcessing. Say what? The only such function I clearly had marked, and I couldn’t think of what that has to do with an iframe. It turns out that iframe elements are specifically blocked from the WinJS processAll methods just like unmarked functions. As a result, you simply can’t use data-win-res with an iframe!

Fortunately, the simple solution was to give the iframe an id (privacyFrame), load the string manually in the beforeshow handler, and then set the iframe.src attribute:

document.getElementById("privacyFrame").src = WinJS.Resources.getString('privacy_URI').value;

Now you’ll have to excuse me for a moment while I file a bug to make sure this fact gets documented!

Part 2: Structuring Resources for the Default Language

In the previous section we created only a single resources.resjson file in the root folder of the project and we deferred any work on images. The next step is to introduce a little more structure into the project that will allow us to add localized resources for additional languages, including our images.

Starting with strings, do the following steps:

1. Create a strings folder in the root of your app project.

2. Within that folder, create a subfolder that matches the BCP-47 language tag specified as the default language in the manifest (for example, en-US, fr-FR, ja-JP, or just the base language like en or ru).

3. Move your resources.resjson file into that folder.

If you run your app again at this point, you should see that everything still works. If you go back to the How to name resources using qualifiers topic we mentioned earlier, you’ll see that the resource loader is perfectly happy when you use qualifiers like a BCP-47 name as a folder name. It basically parses entire folder names looking for qualifiers, so you can create deep hierarchies to sort your resources however you like. That is, you can sort by contrast or scale first, if desired, and include language suffixes in the filename (where the format is lang-<BCP-47 tag>). What’s more, you can create secondary .resjson files in these folders as well and play some other tricks. See “Sidebar: Secondary String Resource Files” for details.

Anyway, what you’ve just done by moving your resources into a folder for your default language is set your fallback language resources—this is what the resource loader will turn to if it cannot find a more specific match for the user’s current language. Finding a match is actually a sophisticated process wherein the resource loader measures a kind of “distance” between the user’s preferences and the available resources and chooses whichever is closest. This makes it possible to select en-GB as a closer match to en-AU than en-US, for example. Generally, though, it means that the resource loaded will search for a specific match like de-DE (German) first, then the next closest language using the base qualifier de, and then eventually fall back to your default language (if there are no resources for the user’s other languages). The short of it is that you should always make sure the language identified in your manifest is fully populated with your full set of resources! Then even if you don’t happen to localize some of those resources (say, for exact cultural alignment with images), one will still be found. For the complete story on this subject, refer to Language Matching in the documentation.

Both WinRT and WinJS are able to work with secondary string resource (.resjson) files, allowing you to organize your strings in multiple files, if desired. For example, it’s common to separate error strings into a file called errors.resjson. When referencing a string identifier in one of these secondary files, all that’s needed is that you use the syntax /<file>/<identifier> instead of just <identifier>. This syntax works in HTML, JavaScript, and the app manifest. See Scenario 5 of the Application resources and localization sample for an example.

Something else you can do with .resjson files is name them with other qualifiers for contrast, scale, home region, and so forth and even organize those files under any old folder. This is demonstrated in Scenario 13 of the same sample, where it has many different .resjson files underneath strings/scenario13, each of which is named as scenario13.<qualifiers>.resjson. Because the folder name itself doesn’t use a standard qualifier, you have to do a little more work to get at everything, using the Windows.ApplicationModel.Resources.Core.-ResourceManager API, but it can be done if you’re a serious resource junkie!

With images, we’ve already seen that if you have something like an images folder and place files like logo.contrast-high_scale-140.png therein, you can just refer to that file with a nonqualified relative URI like /images/logo.png and the resource loader will find them.

Tip The potential multiplicity of images with (scale variants * contrast variants * language variants) and potentially others (like direction) is an important consideration for your app package: more images will make the package size larger. A large package in the Store might deter some users from downloading your app, especially those running on metered networks. So it’s worth carefully evaluating exactly which images really need to vary with these different factors, especially the larger ones, and to optimize the degree of compression for all of your images to minimize the package size. Ask especially whether your splash screen image—typically one of the largest, especially at the 180% scale—needs to be localized at all, and even test whether the 180% image will look good when scaled down to 140%, 100%. If your splash screen, in other words, is just imagery with a sufficient contrast ratio and you have used a universally acceptable app name, one file might work everywhere.

Note also that you don’t want to provide an unqualified resource if you provide any other specific variants, because a scale variant will always be matched before the unqualified one. As a result, the unqualified resource will just take up space in the app package but will never be used.

To prepare for localization, we need only move those images into a folder for our default language, as we did with strings. Because you’re already using relative URIs to refer to your images (with or without ms-appx:///), you can use whatever folder path you want as your image root. There, create a folder with the appropriate BCP-47 tag and move all your default language images into that one. In Here My Am!, for example, images live in the images folder, so all I need to do is create an en-US folder under there, move all the images, and all my references such as /images/tile.png will still work. And because they now live in a folder that corresponds to the app’s default language, they become the fallback images.

I will mention that I did have one image, maperror.png, that was located in pages/home alongside the home.html file that referenced it. I moved this to images/en-US and updated URI references accordingly (but later eliminated it and taphere.png in favor of drawing a canvas dynamically). You can, of course, place images in as many folders as you like, provided that they each have language-specific folders therein. It’s probably most convenient, however, to use a single root folder, or just a few; with Here My Am!, at the end of this step I had just two language folders in the project:

Images

In your own app, then, look for app image references throughout your project. In HTML, look especially for img elements. In CSS, look especially for background-image styles. In the manifest, look at the Application UI tab (logos and badges), the Declarations tab (more logos), and the Packaging tab (the store logo). In JavaScript, finally, check any URIs you might be assigning to element properties or CSS styles, as well as any you might be referring to in the XML for tiles, badges, and toasts.

After that, evaluate each graphic to determine whether it will require localization, including those that need to be reversed generally for right to left languages (for these you can use single copies for all RTL languages, named with the layoutdir qualifier; refer back to How to name resources using qualifiers). For images that don’t require localization (perhaps your tile and other logos, along with plain graphic elements you use in your layout), keep them in your fallback language folder. These will be used if no other match to the current set of qualifiers is found (language, scale, contrast, etc.) Depend on the fallbacks only if you have no other variants.

With that, we’re now ready to localize!

The Application resources and localization sample shows many different scenarios for managing and referring to localized resources. It’s worth spending some time with this sample because it will reinforce much of what we’ve discussed here: image resources (Scenario 1); string resources in HTML, JavaScript, and the manifest (Scenarios 2–4); using secondary resource files (Scenario 5); sending language info to web services (Scenario 7); combining resources and data binding (Scenario 8); using resources with hyphenated attributes (Scenario 9); triggering and detecting language changes (Scenarios 10 and 6); overriding the default language context (Scenario 11); using WinJS for resource lookup in the web context (Scenario 12); and multidimensional fallback (Scenario 13).

Creating Localized Resources: The Multilingual App Toolkit

Congratulations! With all the work you’ve done in the previous sections, you should have an app that’s completely ready to be localized. The process here is really just one of acquiring translated versions of your .resjson files (for strings, taking sparse localization into account) and translated copies of any necessary images.

Tip If you have images that contain text, make sure that you have strings in your resources that match the image content, as you’d typically use for img alt attributes. In doing so, you’ll obtain the necessary translations for the graphics in the process of localizing the strings.

If you like, you can just send your .resjson files, along with the text inside images, to an appropriate translator or translation agency and have them do the work. When you get them back, simply create additional BCP-47 folders in your strings and images, drop in those files, and away you go. You’ll see such structures in the Application resources and localization sample, as we’ve referred to before.

Such manual translation can take a long time, however, and can become expensive. This is partly because professional translators don’t necessarily have tools to work with resjson files other than a text editor. What they do have—sophisticated tools that help them track the status of translation jobs and much more—work with an industry-standard XML format known as XLIFF (XML Language Files). So it behooves us (and our checkbooks!) to make life as easy as we can for translators, even reducing their job to reviewing suggested translations rather than generating everything from scratch.

To assist in this, Microsoft offers the free Multilingual App Toolkit for Visual Studio 2012. Once you’ve downloaded and installed the Toolkit, load your project into Visual Studio and select the Tools > Enable Multilingual App Toolkit menu item. You have to do this for each project separately, because what happens from here on is that the Toolkit will be generating multilingual resources for your app—in the resources.pri file—without you having to actually add any more .resjson files.

Once you’ve enabled the Toolkit, a command appears on the Project menu called Add Translation Languages. This brings up the Translation Languages dialog, as in Figure 17-10, in which you select desired target languages. At the very top of the list, the Pseudo Language option (qps-ploc) will be automatically checked; we’ll be using it in the next section to test localization. This is something you typically want to do before doing specific localizations. Also note that many languages sport a “Microsoft Translator” logo, which means they can be mostly translated automatically, saving paid translators much time and you, much money.

Videos! For a video series on the Toolkit from the team who created it, see the following:

Introduction to the Multilingual App Toolkit (3m 50s)

Build Multi-language apps using the Multilingual App Toolkit (9m 01s), covers creating string resources as we’ve already discussed.

Test Multi-language apps using the Multilingual App Toolkit (5m 36s), covers what we’ll talk about in “Testing with the Pseudo Language” later on.

Localize Multi-language apps using the Multilingual App Toolkit (6m 40s) demonstrates the Multilingual App Toolkit Editor as we’ll see shortly.

Submitting your localized app to the Store (9m, 05s) highlights considerations for getting your app to the right markets.

Once you’ve made your selections (you can add more later), press OK and the Toolkit will create a folder in your project called MultilingualResources stocked with a bunch of XLF files (the ones the translators like). At first these will be mostly empty, but now here’s why it was worth the effort to build up your default resources.resjson file. Right-click your project in Solution Explorer and select Build or Rebuild, or use the Build > [Re]build Solution menu item. This will go through your string resources (including any localized variants you might have created already) and populate all the XLF files with all your strings. The process will also draw in references to nonlogo images (that is, tiles and splash screens are omitted) that might also need translation.

Now for the real fun: double-click an XLF file to launch the Multilingual App Toolkit Editor shown in Figure 17-11. Here you can manage which resources can or should be translated along with the state of the translation. If the language is also supported by Microsoft Translator, the Translate button at the top will be enabled to translate a single entry as well as to Translate All. Select the latter and sit back to enjoy the show. In a few moments you’ll see that the tool has translated all your strings, marking each with the state of Review, as shown in Figure 17-12.

Images

FIGURE 17-10 The first dialog of the Multilingual App Toolkit’s language selection feature. At left we see the option for Pseudo Language, an artificial language with lots of funky characters that represents the needs of most other languages.

Images

FIGURE 17-11 The Multilingual App Toolkit Editor, an XLF editor with machine translation built in.

Images

FIGURE 17-12 The string resources of Here My Am! after being machine-translated into Hindi.

Once the translation is complete, save the file and close the editor if you want. Go to Control Panel > Control Clock, Language, and Region > Language and make sure the target language is added and is placed at the top of the list. Then return to Visual Studio and launch the app—and there is your first-pass localization, as shown in Figure 17-13 for Here My Am! (Notice that I elected to not translate the title, something that my translators suggested I keep in English because of its unique grammar.)

Images

FIGURE 17-13 Here My Am! running in Hindi using machine translation output, which should still be checked by a native speaker, of course. As you can see, I’m checking if Yogananda has any advice apropos to the language.

If you like living on the edge and don’t mind shipping an app that people in other markets might laugh at or otherwise criticize for your carelessness, there’s nothing stopping you from making your app available to those markets in the Windows Store with such machine translations. If you like good positive ratings and reviews, on the other hand, it’s a good idea to at least find some native speaker who can validate and correct what the automatic translation process suggested. You can have this helpful person use the Toolkit editor to review your XLF files, in fact. When those files are reviewed and returned to you, import them back into your project by right-clicking the existing XLF file in Visual Studio and selecting Import Translation. The new translations will then be included in your next build.

When working with professional translators, you can also select specific XLIFF Translation file formats by right-clicking the XLF file in Visual Studio and selecting Send for Translation.

Three other notes about this process. First, there may be some strings or parts of strings that don’t require translation. In the Toolkit editor you can set the Translatable option to No for whole strings to prevent the machine translation from changing that string. For parts of a string, those will be translated but you can edit them back to their original and make a note in the Comments area for your translators.

Second, the Toolkit will detect if you’ve already made translations in an XLF file such that running a Build/Rebuild will not overwrite those strings. At the same time it will import any new strings you’ve added to your resource file in the meantime and remove any that have been deleted. A change in a resource identifier, however, is treated as a delete+add, meaning that the translation will be lost.

Lastly, if you want to remove a language just right-click the XLF file and select Exclude From Project. This will keep the language out of the build while preserving the file (and its translations) in your project folder.

Testing with the Pseudo Language

As much fun as it is to produce many translations for your app, there is still the matter of testing it well, a task that is clearly overwhelming if you’re targeting many languages! To reduce this burden, the best approach is to test your app using the Pseudo Language, a step that’s ideally done before incurring the cost of specific translations. It helps you validate that your app can handle a variety of languages, because the fictitious Psuedo Language contains some of the most problematic characteristics of localized text.

As noted in the previous section, this language is automatically added to your project through the Multilingual App Toolkit’s language selection dialog. This creates a Pseudo Language (pseudo).xlf file in your MultilingualResources folder, alongside the real translations. Next, right-click that file and select the Generate Pseudo Translations command. This will populate the XLF file with translations of your default resources where basic characters are often converted to extended characters and strings are generally expanded with extra !!!’s tacked on. So, a string like “Recent pictures” gets translated to “[62BD8][!!_Ŗęćęйť þîćťµŗêš_!!!!]” where the hexadecimal stuff in the first [ ]’s is a resource identifier that helps testers identify the exact resource that’s being used. (Note that this process will “translate” every string whether you will ultimately translate those strings for real, because it’s helpful for testing.)

To run the app with this translation, you need to make Pseudo Language the system default. In Control Panel > Clock, Language, and Region > Language, click Add a Language, and then enter qps-ploc in the search box. This is the only way to make the Pseudo Language option appear:

Images

Select that language, click Add, and then move it to the top of the list:

Images

When you run you app now, you should see it appear in Pseudo Language:

Images

With your app running in Pseudo Language, be sure to exercise every feature and option. Check every page in each view state; check all your app bar commands; check all of your settings; check any error messages, flyouts, and message dialogs that might only appear under specific circumstances like changes in network connectivity; and test your app with all its activation paths according to the contracts you support. As you do so, look for any strings that don’t appear in Pseudo Language, a clear indication that you missed pulling that string from your markup or code. Also check for truncated text, unintended word wrapping, and so forth, which reveals where your layout isn’t accommodating longer translated strings.

This is the time to be as thorough as possible, because once you upload to the Store, issuing another update will take at least one or two weeks, during which time your customers might find those problems and ding your ratings accordingly. It’s always something to keep in mind, especially if you’ve been accustomed to instantly fixing bugs on websites: apps simply take longer, so you want to invest in testing ahead of time.

Localization Wrap-Up

Well, we’re almost done with the app and ready to go to the Store! There are just a few more things to mention about localization:

• Testing with the Pseudo Language does not cover RTL language considerations; you’ll need to run with those languages separately. I’m happy to say that when I ran Here My Am! under such conditions (such as Hebrew), the layout automatically mirrored thanks to the direction style set in the WinJS stylesheets.

• Be sure to test any and all interactions with online services, including periodic tile/badge updates and those that arrive through push notifications.

• If you want to dynamically update your app when the user changes languages (instead of having to restart the app), listen for the WinJS.Resources.oncontextchanged event and call WinJS.Resources.processAll. This code is in Here My Am! as well as Scenario 6 of the Application resources and localization sample:

    WinJS.Resources.addEventListener("contextchanged", function () {
        WinJS.Resources.processAll();
    });

• The above code will refresh string resources but neither image resources nor content obtained from online sources. You’ll want to do those other updates with additional code, such as giving Windows a new URI for periodic tile updates or indicating that language to a service that issues push notifications. For the app’s overall UI, try using document.location = document.location + "?reload", picking up that URI parameter in your activated handler to take additional steps. This essentially mimics relaunching your app.

• If you like, you can allow the user to select the language for the app independent of the system settings. This is done by setting the Windows.Globalization.ApplicationLanguages.-primaryLanguageOverride property, as demonstrated in Scenario 10 the Application resources and localization sample. Scenario 11 also shows loading specific language resources rather than the default.

• In Visual Studio, open your manifest in the XML code editor (right-click and select View Code) and check if you see this line within the Resources element: <Resource Language="x-generate" />. If so, replace that line with individual entries like <Resource Language="en-US" />, where the first is your default language, and you must have localized resources for all the rest. In addition, you must have at least one “certification language,” as described on Building your app package, or the app will fail Store certification.

• For translation on the fly, you can use various web services such as Bing Translator.

Releasing Your App to the World

We have arrived at the last section of this chapter and the last section of this book, coming full circle to the exact point where we started in Chapter 1: onboarding our world-ready app to the Windows Store and making it available to that world.

Because the onboarding process is well documented already in the Selling apps topic, I’m not going to spend our time here together giving you a bunch of screen shots from the Store Dashboard, where all of this action takes place. I’ll point you to specific pages in those docs when appropriate, but it’s definitely a section of the documentation that you should review. After all, the Windows Store is the retail channel for your app, so you want to understand that channel as best you can. The Store dashboard is also designed to lead you through the process directly.

What we’ll focus on here specifically are those aspects of the process that aren’t always so obvious, based on the real-world experience that I and my teammates in the Windows Ecosystem Team have gained through working with the first partners to submit apps to the Store. Through this I hope to raise your awareness of issues that you’ll likely face so that you’re more prepared to address them. We’ll then conclude with a look at app updates and increasing discoverability of your app through linkage with your website.

When you create your app package to upload to the Store, be mindful that you set your project’s configuration to Release instead of Debug, otherwise it will fail certification. When choosing the target platform, set this to “Any CPU” unless you specifically have WinRT components written in C++. That is, JavaScript and .NET languages (C#/VisualBasic) are architecture-neutral; anything written in C++, on the other hand, must target x86, x64, and ARM specifically. More often you’ll need to create three builds for these architectures that you’ll upload to the Store individually.

Promotional Screenshots, Store Graphics, and Text Copy

Before you do anything else with your app and the Store, review the topic How customers see your app in the Windows Store and its four subsidiary topics: App listing info, app listing overview, app listing details, and app images. Also review the Pre-development checklist, which provides a blend of pre-development and pre-onboarding topics, especially Naming your app and Describing your app.

The reason why I specifically call out these topics is because you’ve invested or you’re going to invest a lot of time and energy developing your app (and testing it, as we’ll discuss in the next section), and so you should make a comparable effort to make it look great in the Store. All of the content described by the links above—your app’s name and description, its details, and its promotional images—constitute your customers’ first experience of your app.

Let me say that again: all of this information is what potential customers will use to evaluate your app before they tap any button to acquire it. It is marketing material, plain and simple, so make it shine! Spend time writing really good copy for your app description—even to the point of having it professionally edited or hiring a professional writer. If you feel your app is fun and engaging, communicate that experience through your description and imagery. Truly, you want customers’ first impression of your app—just from a quick glance at your app’s page in the Store—to be WOW! And this content is all that determines that response.

The other reason I emphasize this so strongly is that you won’t otherwise know you need any of this information until you begin the onboarding process, at which point the Store will ask you to paste in text and upload images. If you haven’t prepared those materials already, then, and you’re trying to get the app into the Store as quickly as possible, you’ll end up cutting some serious corners. As a result, your app’s first impression will be nowhere near as good as it could be.

Game Rating Certificate When uploading a game to the Windows Store, you’ll also be required to provide a game rating certificate in the form of a GDF file. For details, see Windows game publishing requirements.

Testing and Pre-Certification Tools

Unless you’re a born tester, app testing is an activity that has little glory and thrill compared to development, yet it can make a huge difference in the success of your app.

Indeed, for many developers—especially those who have been primarily focused on the web, as I expect many readers are—rigorous testing is not one of their skill sets. I think this is because the nature of web development, where you can upload a fix to a site and have it take effect immediately, has not demanded much testing discipline. How often have you seen one of your favorite websites just blow up one day, hobble around for a few hours, and then come back to life? It’s probably because some developer introduced a nasty bug which was discovered and purged during those hours of awkwardness. For some sites, that downtime can be disastrous, but for many others the impact is small to negligible.

Put another way, the costliness of bugs in web apps is generally quite small because the update time is also very small. But this is not a reality with apps. The time from when you submit an app to the Windows Store to when it’s made available is at least a week, if not longer, depending on the Store’s backlog. This means that each submission is far more significant.

Just look at it in terms of turnaround time. Let’s say it takes five minutes to upload a fix to a web app. Compare that to the number of minutes in a week, which is 10080. The ratio? 1 to 2016. In other words, it’s at least 2000 times more expensive in terms of time and effort to update an app in the Store. Practically speaking, this means that you might need to spend orders of magnitude more effort testing apps than testing websites. That’s significant! (And don’t make the argument that because you spend zero time testing web apps the multiple still comes out zero.)

If you don’t have some testing methodology in place, then, start building one, even from the basics. For example, be sure to always test your app on a clean install of Windows 8 on a machine without a developer license, as well as on low-end machines whose performance is similar to many ARM devices. One developer I worked with had an app rejected by the Store because it came up blank on first run—he never saw this happen because of all the cached data on his development machine!

You also want to develop a solid checklist of how to poke and prod your app to exercise all its code paths. This should include subjecting it to all the conditions that come from outside your app: changing view states and device orientations; invocation of the different charms; changes in network connectivity; running on slow networks; varying screen sizes and pixel densities; input from different sources; having your temp files cleaned out with the Disk Cleanup tool; signing on with different credentials; suspending, resuming, and restarting after termination; running with high contrast modes and other accessibility features; and running under different languages. The better your app behaves under all these circumstances, the more solid it will look and feel to the customers who will be writing ratings and reviews. I cover these topics in a two-part video called “Beyond Just Beautiful” that you can find on the Concepts and architecture page of the Developer Center.

Beyond that there are some great topics in the documentation to help you take the next steps:

Debugging and Testing Windows Store apps

Analyzing the code quality of Windows Store apps with Visual Studio code analysis

Creating and running unit tests on a Windows Store app

Analyzing the performance of Windows Store apps

The other very important part of testing is running your app through the Windows App Certification Kit, otherwise known as the WACK. This tool subjects your app to all the automated tests that will happen when you onboard to the Store, thereby letting you correct any problems it finds beforehand. Passing the tests in the WACK is no guarantee that your app will be accepted, but it will certainly save you a great deal of time waiting for onboarding results and having to resubmit over and over. You should, in fact, run the WACK just about every day during development. You won’t necessarily fix everything it brings up right away, but the ongoing data will be very valuable.

For complete details on the tool and what it does, see Testing your app with the Windows App Certification Kit and Windows App Certification Kit tests.

Tip If you find the WACK coming up blank (showing no apps to test), try uninstalling SDK samples that you might have run from Visual Studio. It seems the tool can get overloaded sometimes.

Onboarding and Working through Rejection

When you’re really ready to upload your app to the Store, you can use the Visual Studio’s Store menu options. Create App Package will let you create a Store-ready package (and run the WACK); the Upload App Package command will take you to the Store dashboard to complete the process. And just in case you’re interested, the maximum size of an app page for upload is 2GB (see Building the app package).

When onboarding your app, you’ll be asked for all the promotional details discussed earlier, as well as URIs where support and privacy information can be found. You’ll also select target markets, set pricing, enter details for in-app purchases, set trials and expiration dates, set a release date, and provide notes to the Store testers. (For an overview, see the App submission checklist.) The last item is essential if there are any details that will be necessary for a real person to test your app as part of the process, such as credentials for a test account. And yes, a real human being will look at your app (and read your notes, so be courteous)! Automated tests can only accomplish so much—in the end, someone needs to run the app and make sure it does what it says.

If you’ve done the work to make your app accessible, by the way, there’s a special place to say so. See Declaring your app as accessible.

Once your app has completed the testing process, it will either be accepted or rejected. Acceptance is really a nonissue—that’s what you’re looking for! If your app is rejected, on the other hand, the Store will tell you why, specifically citing violations of the Windows 8 app certification requirements. Indeed, these policies contain the only reasons that an app can be rejected, so any rejection must necessarily indicate the particular requirement that isn’t being met. The Store also provides some information about failures, such as where an app crashed (a violation of requirement 1.2).

By and large, most of the policies are straightforward such that if you fail on them, it’s pretty clear why. A few, however, seem to be more confusing or subjective, and in the early days of Windows 8 previews they were downright mysterious. Now, fortunately, there is an extensive list of reasons why an app might fail a number of requirements on Resolving certification errors, many of which come from our experience with real apps submitted to the Store. The Store testers can also provide direct feedback regarding specific failures, like where and when an app might have crashed which certainly caused them to reject it.

App Updates

One thing that apps and books share in common is that the moment you release them, you’ll find errors, bugs, typos, and a hundred other things you wish you could change. Fortunately, updating apps is easier than updating books (even though fixing app bugs is often far more difficult than correcting a typo).

You might want to issue an update for many reasons besides the obvious problems you see yourself and the features that didn’t make it into your current version. You might want to respond to user reviews and requests, add more in-app purchase options, or add features to pursue new opportunities. For nearly all of these purposes, the Reports and data that come from the Windows Store will be highly valuable. You’ll want to review this as soon as your app is in the Store and make a plan for monitoring those reports that are most interesting to you. Some suggestions for this are found on Updating your Windows Store app. In fact, schedule some time in the future right now to check in with these reports, lest you forget they exist. Truly, these reports are your best link to real customers!83

All such data will surely feed back into your planning and development processes, ultimately bringing you to the point of one again uploading your app with new promotional materials and more features. When you’re ready to upload a new package, be sure to increment the version number in the manifest so that you can keep track of things. (This is available at run time from Windows.ApplicationModel.Package.current.id.version.) Onboarding is then the same as for any other app—no matter how little you might have changed, the app goes through the whole certification process again. For this reason, don’t think to make whimsical updates—make each one count (fixing a single critical bug certainly counts!). Also, be aware that the certification requirements can change over time, so just because an app was accepted once doesn’t mean it will be accepted again. Make it a point to periodically review the requirements.

In your updated app, be prepared to migrate any state that might already exist on the machine, if there have been changes. We talked about this in Chapter 8 in “Versioning App State,” where we distinguished between the version of an app and the version of its state; many app versions can use the same state version. However, if the app now uses a new state version, the old state must be migrated. Remember too that you can use the servicingComplete background task for this purpose, as mentioned in Chapter 13 in “Tasks for System Triggers (Non-Lock Screen).” Finally, once you introduce new versions of your state, roaming data will roam between apps of the same version only—you’ll be able to migrate old state when the new app is run, but once the version is increased, that data will no longer roam to devices with older versions of the app.

The last point to mention about updates is that although your new app package might be fairly large, existing customers will not have to download the whole thing again. If you go way, way back in this book to Figure 1-1 in Chapter 1, we talked about the package’s blockmap. To summarize, an app package is segmented into 64K blocks, and only those blocks that have actually changed between versions are necessary to download for the update. In practical terms, this means that you shouldn’t worry about making a critical update to your app: if it affects only a small part of the code, your existing customers might end up downloading only one or two 64K blocks total! To help this along, try to have more small files in your project than a few large ones, and it’s better to make changes at the ends of files than at the beginning or the middle.

Getting Known: Marketing, Discoverability, and the Web

As Gandalf the White says to Frodo, Sam, Merry, and Pippin at the conclusion of the Lord of the Rings movies, “Here at least, on the shores of the sea, comes the end of our fellowship.” And, my friends, it has been a delight to share the journey with you! In this last section, then, I wanted to leave you with one technical matter—that of linking your app to your website—before sharing a few final thoughts.

Connecting Your Website

If you have an app, you’ll almost certainly have a site that provides additional information and support. (Requirement 6.3 deals with support specifically.) What, then, if potential customers come to your site first? Surely you’ll want to provide an easy way for them to acquire your app if they’re running on Windows 8.

For this you can simply link to a special URI for the Windows Store that starts with ms-windows-store, as described on Creating links with the Windows Store protocol. You can also use the form ms-windows-store:REVIEW? to link directly to your app’s ratings and reviews. And also remember that you can include a link to your app’s page in the Store with data packages you provide to the Share contract, as covered in Chapter 12, “Contracts.”

With Internet Explorer, a little bit of metadata in your web page’s <head> will enable a feature that makes it simple for a customer to acquire your app and even run it if the app is installed. For example:

<meta name="msApplication-ID" content="ProgrammingWin8-JS-CH17-HereMyAm17"/>
<meta name="msApplication-PackageFamilyName"
    content="ProgrammingWin8-JS-CH17-HereMyAm17_5xchamk3agtd6"/>

where the two content values come from the Package Name and Package Family Name fields in your manifest’s Packaging tab. Again, if the user doesn’t have your app, this makes the acquisition process easy. If the user does have your app, he’ll have the opportunity to launch it in which case the app will be activated with the launch kind of protocol.

For more, see Linking to your apps on the web on the Windows Store developer blog and Connect your Web Site to Your Windows 8 App on the Internet Explorer blog. And for a working example, visit the site of Inrix Traffic, one of the earliest app partners who implemented these features.

One other possibility comes to mind here as you make the effort to promote your app: you might be approached by an OEM to include the app preinstalled on their devices. If this happens—it’s quite a prize!—the OEM will share with you some special instructions about how to onboard and maintain an app specifically for their customers.

Final Thoughts: Qualities of a Rock Star App

It almost goes without saying that the Windows Store will at some point become crowded, so differentiating your app and yourself as a developer will become increasingly important. Again, there’s plenty to do with marketing and gaining awareness for your app, as well as being responsive to customers. Beyond that, though, what does it really mean to make an app that’s truly special?

Early on, long before Microsoft landed on the term “Windows Store apps,” we referred to them as “tailored apps.” To play with that older term, think of what tailoring means in the context of clothes: well-tailored clothes are very distinctive. They make you look really good. They make you feel great. That’s how you want the users of your app to feel when they’re immersed in your experience. Indeed, just as joy and happiness are the undercurrent behind your own app-building efforts, so also do they live in the hearts of your customers. If you can deliver joy to them through your app, then I think you’ll have a winner!

Another meaning of “tailored” implies that the kinds of apps we’ve been building in this book—apps that run full screen and deeply immerse a user in an experience—lend themselves well to being very specific to both the device and the user’s context. As we saw in Chapter 9, sensors give you the ability to know the device’s relationship to the physical world, which is an extension of the user who is holding that device. Ask then, “What can I do with that information? How can the app really light up when it has a deeper understanding of where the user is and how the user is moving about in this world of ours? Is there something more the app can do to say, ‘Aren’t you glad you brought me along?’”

To differentiate your app, think through how a consumer might use various form factors in different situations and have the app present itself differently in those contexts. This kind of tailoring means that the app surfaces the most relevant features or content for the most likely or appropriate use cases. As shown in the last figure of Chapter 1 within “Sidebar: The Opportunity of Per-User Licensing and Data Roaming,” I like to think of there being one app across many devices and that the user has a much stronger relationship to the app than to the devices it’s running on. The app and its underlying state becomes the consistent element across the whole experience, with the devices just being the vehicles. The more you can deliver an app that understands and support this (and obviously roaming data is important here!), the more I think the app will stand out from others that, sure, run in the new environment of Windows, but otherwise offer the same experience as we’ve had for many years.

So, what about being a rock star? Let’s be honest here. You’re in this game for name and fame, right? And for the big money that could come with it? What kind of app will get you there?

In what is now the very last paragraph of this book (apart from the end-of-chapter summary), I can’t really give you a bunch of specific ideas. (Otherwise I’d be writing those apps instead of writing books, but someone has to do this dirty work….) But ponder this: what makes a rock star in the music industry? Well, it’s not typically about the philosophical depth of the lyrics or the virtuosity of the musicians, it’s about performance, personality, and sheer entertainment value. It’s about delivering a joyful experience that turns everyday customers into raving lunatic fans who can’t wait to be your greatest champions. In a very real way, the experience is one that truly lets people escape their everyday realities and become part of something larger for a time, or even just part of a fantasy. And like great music or movies, the app experience is one that people want to repeat many times over and not just check the box as another “been there, done that.” Although there are certainly aspects of timing and sheer luck, all rock stars—along with great athletes, Oscar-winning movies like Lord of the Rings, and so on—strive for and achieve one thing above all: excellence. Commit yourself to that. Commit yourself to excellence in everything you do—not just in your apps, but in all parts of your life. Such striving, certainly, will eventually bring many rewards!

What We’ve Just Learned

• An app’s relationship to the Windows Store is very closely related to your business as a developer, because it supports a range of options from free apps, ad-supported apps, limited-time trials, paid apps, and in-app purchases (using a custom commerce engine for the latter if desired).

• Side loading of app packages is supported for developers (on a machine with a developer license) and for enterprises. Otherwise all apps come from the Windows Store.

• The Windows Store APIs provide for managing app licenses, licenses for in-app purchases, and receipts. During development, the app uses a simulator object where data is obtained from a local XML file instead of the live Store, which allows for testing different types of transactions and license conditions.

• Accessibility features are a concern for the majority of users, even those without disabilities who find those features useful at different times. Apps support accessibility through ARIA attributes (for screen readers), implementing keyboard interaction, resolution scaling, and responding to high contrast modes.

• Globalization is the process of removing language and cultural assumptions from an app, using globalization APIs to properly handle user language, varying, calendars, formatting of numbers, dates, times, and currencies, sort orders, how strings are combined, varying text input methods, and which web services are used from which regions.

• To prepare for localization, an app needs to be scrubbed for text and image content that will be subject to translation, separating strings into resources files and inserting references in their place, and then structuring those resources in folders and files that employ resource qualifiers.

• For efficient localization, the Multilingual App Toolkit for Visual Studio generates and translates an app’s default resources into any number of other languages, using the file formats employed by professional translators who can verify the results. It also produces a Pseudo Language translation for localization testing.

• Getting an app in the store starts with testing the app both manually and through the Windows App Certification Kit and being prepared for possible rejection during the onboarding process.

• App updates can be submitted to the Store at a later time, with improvements based on feedback and telemetry, and the updated code needs to be ready to migrate state.

• Being in the Windows Store does not reduce the need for marketing; getting found will become increasingly difficult as more apps appear in the Store. Cross-linking your app and website can thus very much help discoverability.