Hooray, I have built my first Chrome extension! Why and how? Annoyed by the automated translation of Microsoft Docs, I decided to do something about it. You can read all the details in this post and lean how easy it is to get started on your first Chrome extension.
As you might have noticed by now, all the Microsoft documentation has been shifted to docs.microsoft.com. And to be fair; I like it! The docs are well written, indexed so I can find everything very fast and like everything at Microsoft these days: the docs are open-source. This means you can even contribute yourself.
There is one thing I don't like that much, and that is the automated translations. If you're not from an English native country like me, Docs tries to serve you a localized version of the page you want to reach. If there isn't a human-translated one, they will translate it with the power of Azure and show you that.
While this seems like a good idea in theory, in practice it doesn't work that great. Technical content is very hard to translate in an automated matter, mostly because there are so much technical terms that you just want to keep English and translates sometimes quite hilarious. Because of this, reading becomes harder and you get distracted of what is trying to be explained.
The worst thing is: you can't override this behavior from Docs. Per page you have a toggle in the top right which lets you show the original version, but just for that page. The is no way to persist it and just say; hey Microsoft! I always want the English content!
So, there I was. Laptop open, ready to go, but no clue how to start. I did notice the "developer mode" toggle in the extensions page before and decide to have a play with it. It gave me a couple of extra buttons, but no clue on how to get started, you can see this depicted in the image underneath. I turned to my best friend Google and simply searched for "developing Chrome extension". I quickly got to this page: https://developer.chrome.com/extensions/getstarted
The manifest.json file is basically the entry of your extension. Here you declare what files your extension consists of, what permissions it needs, add some nice icons and specify other metadata. The manifest.json is, as far as I know at this point, the only file that has to have a specific filename. All other files are referenced from there and can be in folders or subfolders.
Below you can see the manifest.json file that I ended up with.
To be fair, I didn't deep-dive into all of the specifics of building a Chrome extension, but I think the keys in the above file is pretty much the least you need to have in there
There are some obvious keys in there. You will have to give your extension a name, description and version. Also, you have to specify the manifest_version. At this time, simply set it to 2. This specifies which version of the manifest you are using, so the Chrome extension parsing knows what keys to look for. At the time of writing, though, version 1 is no longer supported and there is no version 3, so 2 it is!
With the options_page key, you specify the HTML page that is opened whenever a user navigates to the settings of your extension. All extensions will have a button in the Chrome toolbar, if you press it you can go to the settings, here is where you specify what that settings page is.
The page_action key will define what is shown whenever a user hits a certain page. This is also something that is explained in more detail in the next section.
Lastly, there is a couple of icon keys in there. Just make sure you have a nice icon and supply it in a number of different formats.
To read up in detail on all the different keys in here, refer to the Google documentation at https://developer.chrome.com/apps/manifest.
Different Extension Types
As far as I can tell there are roughly two types of extensions you can build: either user triggered or background
The thing I wanted to do is take the URL the user might be navigating to, check if it contains the Microsoft Docs URL and then swap out the localization code if needed. Since this is something that should happen automatically, this would be a background plugin.
You can also choose to build an extension that acts whenever the user interacts with it. Regardless of if an extension is a background extension or not, it will always have an icon in the toolbar. From that icon, you can spawn a pop-up, which is just an HTML page where you can have your user interact and from there trigger any logic that you want. The difference here is if you implement it as a page action or a browser action
With both you can do the exact same thing, the difference is when your toolbar icon is activated. Your popup will only show whenever the button is activated. As the name already implies: a page action only activated whenever the user lands on a certain page, and a browser action is available to every page. The guideline Google prescribes for this is:
- Do use page actions for features that make sense for only a few pages.
- Don't use page actions for features that make sense for most pages. Use browser actions instead.
- Don't constantly animate your icon. That's just annoying.
In my case, I went for a page action. Since the extension is very specific for just one website, or at least one base address, I decided to go for page action. You don't even have to include a page action if you don't want to, but it will look a bit nicer, in my opinion, to let the user know your plugin is active on this page. When you do not include browser action or page action, your extension icon - which is always there - will always look disabled. With a browser action, it will always look enabled, since it is relevant to the browser and all pages. If you use the page action, it will only become active on the page(s) that you define. To define on which page your icon should be active, you use this piece of code in your background JS file:
This code adds a rule and checks if the host is equal to, in this case, docs.microsoft.com. Whenever it is, the icon lights up and when the user clicks it, your popup will come up. If the icon is disabled and the user clicks it, it will show a default context menu.
By defining the default_popup, you set a page that will pop-up whenever your extension icon is active and the user clicks on it. In my extension, I have given it an HTML page that allows you to configure the plugin. What it really does is the same thing as my full-blown settings page. As I said; it doesn't add that much value, it's more like a minor UX improvement. As I mentioned earlier, you just store your settings in the local storage of your plugin, so you can access that from your popup, the settings page or the scripts that are associated to your extension.
There are a whole number of events that you can hook into and act upon to implement the functionality you desire with your extension. Note that you will have to look
The debugging experience was quite good! Because it all runs in Chrome and it's all web languages, you can , debug everything with the Chrome Developer Tools that are already available to you in the browser. There is, however, a difference between unpacked and packed debugging. Ask me how I know...
Unpacked is the name they gave to just a folder which contains all your files. You can simply point to that folder from the extensions screen in developer mode, and it will load the extension like it would normally. The extra thing you get is that you can debug through it.
Depending on what kind of extension you are building you can just go into the developer tools as you normally would, set breakpoints and trigger them. However, if you're building a background extension like me, you will have to open the developer console from the extensions page. If you go there, you will notice that the words "background page" are blue, indicating that it is a link. When you click on it, you will get the same developer console as you would normally open yourself on a page.
A packed extension is actually the release version. The important thing you should know here is that when using an unpacked extension, you seem to have less limitations. So, what happened was; I thought I was done, packed up my extension (note: it with the pack button, but simply zip it) and took it to the extension store. After it was published I decided to uninstall my development version and download it from the store to see if the behavior was the same. As it turned out, it wasn't.
At first I was a bit confused on how I should then test my extension when the unpacked version worked properly. After a little search engine action, I found out that you can bypass the store by packing your extension with the designated button in the extension screen and then drag the packed extension back into your Chrome instance. That way, your extension is installed the same way as it would through the store. There is a field there for a signing key, as far as I can tell it's not important since it's just used for local debugging. One might expect that this is also the package that you need for distribution, but it is not as we will learn a little bit later on.
Release and Distribution
After little more than an hour, I had the first version of my extension ready, pretty fast, right? Thinking to myself I couldn't be the only one being annoyed by the Microsoft Docs translation fairy, I decided to put this in the extension store. So, the next step would be to find out how to publish it there.
Although I already have an Android developer account, this is apparently not a global Google developer account. I had to crest a separate account for the Chrome extension. Don't worry though, the process is pretty simple and can be completed within a matter of minutes. If you're already a Google user, that is
All I needed to do was click on the developer console in the options and enter some details. The funny thing is, is that I had to pay a small amount of 5 dollars (once) to be able to publish to the store. For your 5
Anyway, after going through these hoops I was taken to the developer dashboard, which looks horrific by the way, and I could start creating my extension entry. To create the entry, you have to enter some simple data like a description and some images. Then to add your actual extension, you simply bump up the version number in your manifest.json file, zip the folder and upload that to the developer portal.
By the way, if you look closely at the old developer portal, there is an alert that tells you the new developer portal is in preview and you could try it. You should! It's much, much better and if you, by any chance, know the Android developer portal, it looks pretty much the same.
So, as I mentioned earlier, my extension showed some weird behavior in production. It would work for a second or two, but then it stopped! At first I couldn't figure out what was going on, until I noticed this key in my manifest file:
This seemed odd, and I quickly took it out to see what was happening, According to this page, you should not persist your background scripts, unless you are using the chrome.webRequest object. And guess what I was using... So after that little quirk, everything was up and running!
Creating a Chrome extension isn't that hard, but can solve some issues that you might have with certain web applications or really add value. For instance, I have an extension for ages that lets me pick a color from the page that I am on. And now, for this hassle I encountered myself, I have created a small piece of code, that I learned from, and I won't be bothered with poor Dutch translations any longer.
If you want to use the extension, you can get it from here: https://chrome.google.com/webstore/detail/microsoft-docs-langyfier/gkneebafjlcpcgahjdlmdoejhjnfleha. If you like it, please rate and/or share it!
I hope you got a great start of this write-up and please let me know if you have created any cool extensions of your own, or if you are using mine. Everything described here is open-source on GitHub: https://github.com/jfversluis/Microsoft-Docs-Langyfier and I will gladly look at any issues or accept any improvements through pull requests.