Browser Add-ons, Google Chrome, Interpr.it, Mozilla, Mozilla Firefox

Interpr.it Will Be Shutting Down

Interpr.it is a platform for translating browser extensions that I launched five years ago; it will be shutting down on September 1, 2017.  I no longer have the time to maintain it, and since I stopped writing Firefox extensions, I don’t have any skin in the game either.

I’ve notified everyone that uploaded an extension so that they have ample time to download any translations (333 days). It was not a large Bcc list; although nearly six thousand users created an account during the last five years, only about two dozen of those users uploaded an extension. Eight hundred of those six thousand contributed a translation of at least one string.

For anyone interested in improving the browser extension translation process, I’d suggest writing a GlotPress plugin to add support for Firefox and Chrome-style locale files. It’s been on my todo list for so long that I’m sure I will never get to it.

Standard
Browser, Google Chrome, Ideas, Internet Explorer, Life, Mozilla, Programming, Safari

An API for Browser Screenshots

What do the following screenshots all have in common?

From Amazon’s Cloud Reader Installation:

From the University of Virigina’s guide to setting proxy settings in Firefox:

From HootSuite’s TwitterBar acquisition announcement:

From Tecca’s Guide to Internet Explorer:

That’s right: they all include portions of browser chrome. (Chrome 13, Firefox 3, Firefox 4 for Windows, and Internet Explorer 9, I believe.)

What else do these screenshots have in common? They will all one day be out of date (if they aren’t already). As soon as Google modifies their extension installation dialog, or Mozilla changes their proxy settings tab, or the Firefox address bar gets a new background color, these screenshots will no longer accurately represent the interaction through which they’re meant to guide the user.

A Modest Proposal

I propose that this problem of stale browser screenshots could be alleviated by the creation of a Web service that exists solely to serve semi-dynamic screenshots of browser chrome. Allow me to explain with examples.

The Amazon screenshot above could be replaced with a call like this:

<img src="http://browsers.foo/addons/installation?highlight=confirm&w=460&h=60" />

Or the TwitterBar image could use this URL instead:

<img src="http://browsers.foo/toolbar/?include=url-bar,icon&icon=http://foo.com/hoot.png&highlight=icon" />

(Note the idea of being able to merge existing images into the screenshots.)

The IE add-ons dialog screenshot could just as easily call this URL:

<img src="http://browsers.foo/addons/tracking-protection?browser=ie&version=9&highlight=easy-list" />

The API would automatically use the user’s user-agent to determine what browser, version, and platform to show in the screenshot (although these could also be specified manually, as seen in the IE example). If images from the exact current version aren’t available, the most recent version could be used instead.

I think that with a couple dozen high-resolution, high-quality screenshots of the various windows and dialogs in each major browser version on each major platform combined with metadata defining the position of key elements in those screenshots (e.g., the home button, the address bar, the History menu), 90%+ of the browser-specific screenshots on the Web could be replaced by calls to this service.

What do you think?

Is this a solution in search of a problem, or is it a legitimately useful idea? I think it would be worth its development costs just for organizations like Mozilla or Google to use in order to populate their help documents with screenshots that would always be up to date. Tell me what you think in the comments below.

Standard
Browser Add-ons, Google Chrome, Mozilla, Mozilla Firefox, Programming

Using Google Chrome locale files in Firefox extensions, updated

After I posted my latest revision to some code for using Google Chrome locale files in Firefox extensions, Wladimir Palant pointed out some shortcomings with the code; I’ve made some changes to address these issues, and the new code is shown below.

View the code at GitHub.

Usage

The new usage rules are as follows:

  • Replace MY_EXTENSION_NAMESPACE with the namespace of your extension’s files. e.g., if your files are at chrome://abcdefg/content/, then replace MY_EXTENSION_NAMESPACE with abcdefg.
  • Rename MY_EXTENSION_STRINGS to something that won’t interfere with another extension.
  • The _locales directory from your Chrome extension should be in the chrome/content/ directory of your Firefox extension (or update my code to point to wherever you put it).

Advantages

This code has four advantages over the previous versions:

  1. It’s a single code block that works with all recent versions of Firefox.
  2. You don’t need to include an additional library for file I/O.
  3. It fixes a bug in retrieving the proper locale code in Firefox on Linux.
  4. You don’t have to specify <em:unpack>true</em:unpack> in your install.rdf in Firefox 4.

Thanks Wladimir for your input; this version is undoubtedly better than both previous versions. I can’t ensure that it’s the best possible solution, but it’s the best one that I’ve found so far.

Standard
Browser Add-ons, Google Chrome, Mozilla, Mozilla Firefox, Programming

How to use Google Chrome extension locales in Firefox 4 extensions

Update: Don’t use this code. Use this new version.

A few months ago, I posted a snippet of code that provides an API for using locale files from Google Chrome extensions in extensions for Firefox 3.6 and older. I’ve now added support for Firefox 4, and the updated code is shown below:

View the code at GitHub.

The same usage rules still apply:

  • Replace “MY_EXTENSION_ID” with the ID of your extension.
  • Rename “MY_EXTENSION_STRINGS” to something that won’t interfere with another extension.
  • The _locales directory from your Chrome extension should be in the chrome/content/ directory of your Firefox extension (or update my code to point to wherever you put it).
  • Include the excellent io.js library in your extension.
  • NEW: For Firefox 4, you’ll need to specify <em:unpack>true</em:unpack> in your install.rdf.

I’ve been using this solution in ScribeFire in Firefox 3.5, 3.6, and 4.0 (and 5 and 6) for a while now with no complaints. Let me know if you implement this in your extension, and I’d love any feedback you have on the code or its performance.

Standard
Browser Add-ons, Comment Snob, Google Chrome, JavaScript, Mozilla, Mozilla Firefox, Programming, Software, Technology, YouTube Comment Snob

Announcing Typo.js: Client-side JavaScript Spellchecking

When I first ported YouTube Comment Snob to Chrome, Chrome’s lack of a spellchecking API for extensions meant that I would be unable to implement Comment Snob’s most popular and distinguishing feature: the ability to filter out comments based on spelling mistakes. That, my friend, is about to change.

I’ve finished work on the first version of a client-side spellchecker written entirely in JavaScript, and I’m calling it Typo.js. Its express purpose is to allow Chrome extensions to perform spellchecking, although there’s no reason it wouldn’t work in other JavaScript environments. (Don’t use it for Firefox extensions though; use Firefox’s native spellchecking API.)

How does it work?

Typo.js uses Hunspell-style dictionaries – the same ones used in the spellcheckers of OpenOffice.org and Firefox. (Typo.js ships with the latest American English dictionary, but you could add any number of other dictionary files to it yourself.) You initialize a Typo.js instance in one of two ways:

Method #1

var dictionary = new Typo("en_US");

This tells Typo.js to load the dictionary represented by two files in the dictionaries/en_US/ directory: en_US.aff and en_US.dic. The .aff file is an affix file: a list of rules for creating multiple forms of a word by adding prefixes and suffixes. The .dic file is the dictionary file: a list of root words and the affix rules that apply to them. Typo parses these files and generates a complete dictionary by applying the applicable affix rules to the list of root words.

Method #2

var dictionary = new Typo("en_US", affData, dicData);

With this initialization method, you supply the data from the affix and dictionary files. This method is preferable if you wish to change the location of the affix and dictionary files or if you are using Typo.js in an environment other than a Chrome extension, such as in a webpage or in a server-side JavaScript environment.

Once you’ve initialized a Typo instance, you can use it to check whether a word is misspelled:

var is_correct_spelling = dictionary.check("mispelled");

Customization

Depending on your needs, you can configure Typo.js to perform word lookups in one of two ways:

  1. hash: Stores the dictionary words as the keys of a hash and does a key existence check to determine whether a word is spelled correctly. Lookups are very fast, but this method uses more memory.
  2. binary search: Concatenates dictionary words of identical length into sets of long strings and uses binary search in these strings to check whether a word exists in the dictionary. It uses less memory than the hash implementation, but lookups are slower. This method was abandoned as it became impractical to implement for some features.

See this blog post by John Resig for a more detailed exploration of possible dictionary representations in JavaScript.

Practice vs. Theory

Typo.js is already in use in my Comment Snob extension. You can install it today to experience Typo.js in action, filtering comments on YouTube based on the number of spelling mistakes in each one.

What’s next for Typo.js?

The next step is adding support for returning spelling suggestions; right now, all Typo.js can do is tell you whether a word is spelled correctly or not. It also needs to support Hunspell’s compound word rules. These are the rules that a spellchecker uses to determine whether words like “100th”, “101st”, “102th” are correct spellings (yes, yes, and no, for those of you keeping track) since it would be impossible to precompute a list of all possible words of these forms.

The Typo.js code is available on GitHub. I welcome any and all suggestions or code contributions.

Standard
Browser Add-ons, Comment Snob, Google Chrome, Programming, Yahoo!, YouTube, YouTube Comment Snob

YouTube Comment Snob is now Comment Snob

In 2007, I wrote a Firefox add-on called YouTube Comment Snob. Its main function was to filter out the inanity from YouTube comment threads, and it worked (and still works) very well, but the comment I heard most frequently from people who tried it out was “Can you make this for the entire Web?” Until now, my answer has been, “No, not yet.” But now, my answer is “Very yes.”

Announcing Comment Snob

Comment Snob is an extension for Google Chrome that filters out undesirable comments from comment threads all over the Web.

Before: After:
YouTube (before Comment Snob) YouTube (after Comment Snob)

You can install it here. It still comes with support for YouTube built in, but you can add support for many other sites by installing Comment Snob rules.

What are Comment Snob Rules?

Comment Snob rules are JSON objects that dictate how Comment Snob finds and filters comments on different websites. Here’s the rule for YouTube that ships with Comment Snob:

{
	"id": "youtube@chrisfinke.com",
	"label": "YouTube",
	"url": "^http://www\\.youtube\\.com/.*$",
	"allCommentsSelector": "#comments-view",
	"commentContainerSelector": "li.comment",
	"commentTextSelector": "div.comment-text",
	"commentHideSelector": "> div",
	"statusElementTag": "div",
	"statusElementAttributes": {
		"class": "content",
		"style": "color: #666;"
	},
	"ajaxInitiatorSelector": ".comments-pagination button, .comments-pagination a, .comments-pagination button > span",
	"updateURL": "/comment-snob/rules/youtube.snob"
}

If you know HTML and understand how to use jQuery, you can write rules for Comment Snob. (Full instructions for writing rules are available here.)

For each rule that you install, you can choose a unique set of filtering rules:

Where Can I Install Rules?

I’ve written eight rules myself and made them available on this page (scroll down to “Featured Comment Snob Rules”); as other people write rules, I’ll link to them from that page as well. Eventually, I’ll have a proper site put together for showcasing the most popular rules.

Where Can I Install It?

Install it from the Google Chrome Extensions Gallery. It’s not available for Firefox yet, but I’ll most likely be releasing the next version for Chrome and Firefox simultaneously.

What’s Next?

This version of Comment Snob is just a shell of what my final vision is for comment filtering on the Web; right now, it’s all very manual, and the chances of false positives are too high for my taste. Adding a proper spellcheck filter will help that somewhat (Chrome doesn’t yet have a spellcheck API like Firefox does), but imagine a future where all comments on all websites could be filtered automatically based on their content, grammar, and keyword frequency, without having to account for personality differences between different websites. (e.g., The expected quality of a YouTube comment is much lower than the expected quality of a Hacker News comment, so Hacker News comments should be judged more stringently.) That starts to get close to what I want Comment Snob to be.

Standard
Browser Add-ons, Google Chrome, Interpr.it, Launch Announcement, Mozilla, Mozilla Firefox, Programming

Improving the browser extension localization process

Executive summary: I’ve developed a new site to help extension authors and translators collaborate; it’s called Interpr.it.

My least favorite aspect of developing browser extensions is localization. Writing the actual code to internationalize an extension isn’t so bad, but keeping the translation files up to date has always been a chore. (Localization is the process of translating software into different languages; internationalization is writing software that can be easily localized.)

The preeminent site in the extension localization space is Babelzilla. Babelzilla has been around since 2006, and it is the only site that I know of for pairing extension developers with translators. It works, but I’ve never felt that it works especially well, and when you can’t release an update to your extension because Babelzilla is down or buggy (preventing you from retrieving the latest locale files), it’s very frustrating.

Localizing Google Chrome Extensions

When I started developing browser extensions for Google Chrome, I was surprised to find that no Babelzilla equivalent exists, even though Chrome has very full-featured internationalization support for extensions – apparently, extension developers in this ecosystem are expected to come up with their own ad hoc solutions for managing their extension translations. “Ad hoc” is not a term I enjoy applying to solutions, so I decided to see what I could do to improve upon the Babelzilla experience for Chrome extension developers.

Centralizing Extension Internationalization

In developing a translation site for Chrome extensions, I had two goals:

  1. A full-featured API that allows developers to interact with the site without visiting it.
  2. A clean and simple interface for translators that reduces the barrier to entry as close to zero as possible.

With these two goals in mind, I developed Interpr.it. On Interpr.it, developers upload their extensions, translators localize them into their native language, and then developers can download the new locale files to use in their next extension update.

Interpr.it for Developers

Developer interaction is limited to the upload and download of locale files. In fact, developers can interact with Interpr.it completely from the command line via the /api/upload and /api/download API methods. (There are also API methods for translating messages and retrieving the translation history of a message.)

Interpr.it for Translators

Once an extension has been uploaded to Interpr.it, a status page is generated that shows the progress made on all of the locales supported by Chrome for extensions. Here’s an example screenshot of that page:

Each locale code links to a translation page, which is a listing of all of the messages (or “phrases” or “strings”) used in the extension. Here’s what one of those messages looks like:

There are 4 aspects to the UI for translating a single message:

  1. The original un-translated message.
  2. A description of the message from the developer, which adds context to the message.
  3. The placeholders in the message, used to insert information which can’t or shouldn’t be translated.
  4. The history of the message’s translation, which shows previous revisions and allows a developer or translator to revert changes.

(Not every message will have a description, placeholders, and a translation history.) The translator types the translated phrase in the box, and as soon as they hit the tab key (or click outside of the box), the message is automatically saved without a page reload.

Additional Interpr.it Features

Sign in/out is tied to your Google account, so you don’t have to create another username and password; it seemed like a natural fit for a site focused on Google Chrome extensions.

The Interpr.it site itself is localized using itself. (Interpr.it obviously isn’t a browser extension, but it does use Google Chrome-style JSON locale files, so it’s compatible with Interpr.it’s translation system.) To access a localized version of Interpr.it, select a locale code from the menu in top-right corner of the website, or manually type a URL like es.interpr.it.

Interpr.it will also automatically fill in any translations that have been previously completed for other extensions. For example, if a translator has already translated ‘Thank you’ into French for another extension, and a different developer’s extension uses the phrase ‘Thank you,’ Interpr.it will automatically transfer that translation. (There’s been some discussion as to whether this will backfire, but I have been unable to come up with identical English phrases that would result in different translated phrases. If you can come up with some, I’d love to hear them.)

Open for Business

If you’re a Chrome extension developer, you can upload your extension to Interpr.it right now. I’m already using it to manage localization for the Interpr.it website and two of my Chrome extensions, and so far, thirteen different translators have translated a total of 1087 messages.

After I have some more time to collect feedback from developers and translators, I plan on either adding support for Mozilla browser extensions or possibly donating code to the Babelzilla project to improve their experience for developers (if they’re interested).

Feedback

If you’ve read this far, I want your feedback. Even if you’re not involved in the development or translation of browser extensions, I want to know what you think – were you not aware of the process at all? Does it sound like a problem worth solving? If you are familiar with the problems faced by developers and translators, do you think that Interpr.it is an improvement upon the Babelzilla experience? Or am I wasting my time reimplementing something that already (kind of) exists? What features would you like to see? What localization/internationalization issues do you find irritating? Leave your thoughts in the comments.

Standard
Browser Add-ons, Google Chrome, Mozilla, Mozilla Firefox, Programming, ScribeFire

Using Google Chrome-style locales in Firefox extensions

Update: Don’t use this code. Use this new version.

If you’ve ever developed the same extension for both Google Chrome and Firefox, you’ve probably noticed that there is no easy way to reuse internationalization efforts between the two. Firefox uses a mix of Java-style properties files and DTD files to store translated strings, while Chrome uses JSON “messages” files. This was especially frustrating to me because 95% of the code in ScribeFire is shared between the Chrome and Firefox (and Safari) versions.

To eliminate this annoyance, I came up with a method to parse and query the locales from the Chrome version in the Firefox version. If you want to use this method in your Firefox extension, you need to take the following steps:

  • Replace “MY_EXTENSION_ID” with the ID of your extension.
  • Rename “MY_EXTENSION_STRINGS” to something that won’t interfere with another extension.
  • The _locales directory from your Chrome extension should be in the chrome/content/ directory of your Firefox extension.
  • Include the excellent io.js library in your extension.

View the code at GitHub.

After running this function, you can call MY_EXTENSION_STRINGS.get(key, substitutions); anywhere that you would have called chrome.i18n.getMessage(key, substitutions);. (It doesn’t work in Firefox 4 (yet) due to the extension manager changes, but I’ll post a follow-up when I have a Firefox 4-compatible version.)

What are your thoughts? Is there a better way? Would it be better to write a script to convert Firefox-style locales for use in Chrome?

Standard