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, Mozilla, Mozilla Add-ons, Mozilla Firefox, Slashdot, Slashdotter

Discontinuing Slashdotter

Slashdotter is an extension I wrote in 2006 in order to customize the Slashdot experience. It was covered on Slashdot and was received favorably by the Slashdot audience, but I don’t have the time anymore to update it every time Slashdot changes their UI or HTML.

If you’d like to take over development, let me know, and I’ll transfer the Slashdotter add-on to you on AMO; if nobody volunteers, I’ll be removing the add-on from AMO in a couple of weeks. (Like all of my browser extensions, Slashdotter’s source code is open source, so you could still develop your own version if you want.)

Standard
Browser Add-ons, HootBar, HootSuite, Mozilla, Mozilla Firefox, Twitter, TwitterBar

TwitterBar is now HootBar

Update: TwitterBar for Firefox was sold to HootSuite and renamed HootBar in March of 2011. TwitterBar for Chrome was discontinued in October of 2012.

My Firefox add-on TwitterBar, the world’s most popular Twitter client for Firefox’s URL bar, has been acquired by HootSuite and has been renamed “HootBar.”

HootBar users now have access to great HootSuite features like the Hootlet: instead of typing “–post” at the end of your tweet, if you type “–hoot”, you can schedule your tweet for later, send your message to networks besides Twitter (like Facebook or LinkedIn), and track stats for link clicks.

The rebranded version of TwitterBar is still awaiting approval by Mozilla, but you can install it manually here. More information on the TwitterBar-to-HootBar change is available at HootSuite’s “TwitterBar to HootBar” transition page.

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, Mozilla, Mozilla Add-ons, Mozilla Fennec, Mozilla Firefox for Mobile, Programming, Tapsure

Tapsure: Better password input on mobile devices

Typing passwords on mobile devices sucks. If you have even a reasonably strong password (one that includes letters, numbers, and special characters), it can take more than a few seconds to type it out on a phone’s keypad or on-screen keyboard. In this day and age, that’s time you just don’t have!

Tapsure is an extension for Firefox for Mobile that alleviates this problem by allowing you to input passwords on websites by tapping a rhythm on your touchscreen rather than hunting through the device’s keyboard.

How does it work?

Install Tapsure here, and after restarting Firefox for Mobile, log into one of your online accounts as usual. After you log in, you’ll see a notification from Tapsure:

Choose “Yes,” and you’ll see this dialog:

(If you choose “No,” Tapsure will never ask about that specific password again. If you just close the notification, Tapsure will ask the next time you use the password.)

Here comes the fun part: think of a song, a pattern, a rhythm, or even some Morse code that you want to use to log in to sites that use this password – it can be anything, as long as it doesn’t have more than a full second between taps. Got it? Ok, now tap that song/pattern/rhythm/Morse code on the screen. Tapsure will save it and close the dialog.

Now, the next time you’re logging into a site that uses that password, instead of slowly typing out your super-secure 20-character password, just hold your finger down on the password field until you see this:

Now tap out your pattern from the previous step, and Tapsure will automatically fill in your password for you. (If you tap the pattern incorrectly, Tapsure will shake it off and give you another chance.)

You can repeat these steps for as many passwords as you like – Tapsure will remember them all.

Tapsure Settings

In the add-on options panel, you can reset all of the patterns you’ve saved with Tapsure to start over. (This will also clear the list of passwords that Tapsure won’t ask you to save a pattern for.)

Is this secure?

Yes, Tapsure saves your patterns and passwords using Firefox’s built-in password manager, so it just as secure as having Firefox remember your passwords. Tapsure also has the benefit that someone could closely watch you log in to a website without knowing your password, because it’s harder to discern and remember a tapped pattern than it is to watch the keys that you press.

Couldn’t I just tell Firefox to remember the password?

You could… but if you use the same password on more than one site (which I estimate that 99.9% of people do), you’d have to type it out with excruciating care on every single site that you use it on.

Miscellaneous

Try and use a semi-unique pattern – don’t choose Happy Birthday. It’s like using the password “password.”

Tapsure probably works better on capacitive touchscreens than resistive touch screens, simply due to the fact that it’s easier to tap a quick pattern when you don’t have to press down firmly on each tap.

Tapsure was entered in the Firefox Mobile Add-ons Cup. If you want to see it win, please write to your senators and representatives.

Where can I install it again?

Or, you can search for “Tapsure” in the “Get Add-ons” portion of Firefox for Mobile.

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