Snipe.Net Geeky, sweary things.

Project Localization Without the Pain


I run a few open source projects, one of which is Snipe-IT, a free IT asset management system. While the app is in English by default (since that’s my most fluent language), giving my end users the ability to use the app in their own language has always been important to me, so from pretty early on, I started to swap out hard-coded English strings with language localization strings.

Localization when you’re only dealing with one language is pretty easy. Tedious, but easy. Most popular web frameworks even give you that for free, supporting language files and having a convention to easily invoke language strings within your app. Laravel, for example, has that built right in.

In Laravel (and many other frameworks), the language translation files are kept in a simple array.
[code language=”php”]return array(
‘address’ => ‘Address’,
‘admin’ => ‘Admin’,[/code]

And so on…

In other apps, you may use .po files.


The challenge with localization is rarely the actual initial technical implementation, but rather with the workflow that allows you to have multiple people contributing to your code (therefore creating new language strings in your language files), and magically having all of your additional language translations pick up those new strings.

For example, if you only speak english and submit a pull request for a feature you built out, you’ll obviously provide the new strings in an updated lang/en/whatever.php file in your pull request – which is great. But what about the other 50 language files? As the maintainer, I now need to go through all 50+ files and add those strings into the corresponding translations.

Ugh. In a project with lots of contributors, or even just lots of updates being pushed through, you could spend all day just managing, diffing and syncing language translation files.

Another challenge is that sometimes, the folks who are willing to help you translate aren’t so good with code. In my case, Snipe-IT is aimed at IT Managers, which while technical, often don’t know much about coding or web servers, and instead focus on desktop support and networking. While asking them to open up a text editor and go through PHP arrays without being too terrified and without shitting all over the (very limited) PHP syntax within isn’t asking that much, it’s intimidating for some folks, which can discourage them from helping.

And yet another challenge is that asking people to translate something without providing any context for what the words mean can definitely cause unexpected problems, like “Command number” instead of “Order number”. Context absolutely matters in language.

These problems had been haunting me for a while, and it was part of the reason I wasn’t aggressively trying to ask people to translate my app, since it would create hassle for my volunteer translators – and even more hassle for me to upkeep once I had more languages to look after.

That is, until I ran across a wonderful service called CrowdIn, which makes all of these issues mostly moot. I do not work for CrowdIn, I do not know anyone who works for CrowdIn, and they are not paying me to write this. (Because it’s really about ethics in game journalism, right? Sorry. Couldn’t resist. Sigh.)

A Solution

There’s a lot more to CrowdIn than first meets the eye. At its most basic, it’s a way for web and mobile app developers to crowdsource their translations through a user-friendly and fast interface that requires zero code knowledge or technical skill, which in and of itself is pretty awesome.

To get started, I simply uploaded my source files, which in this case were my app/lang/en Laravel files through a simple web interface, making sure to select the “Auto approve imported” checkbox.

Screen Shot 2014-10-30 at 1.20.20 AM

You can select which languages you want to support (or quickly pick the top 30 they suggest), including pirate, LOLCAT and Klingon, because priorities, people!

Once you’ve built your project (by clicking on the “build project” button), you can download all of the language files generated in one zip. The ones that haven’t been translated yet will simply have your source language strings in them, which is helpful for the devs who do actually want to just translate via the PHP files.

You can then point people to your translation URL and ask them to translate as much as they can. (Mine is here, btw. Hint, hint.) You’ll see the progress of how many strings have been submitted, how many have been approved, and how many remain untranslated.



They also offer suggestions via Microsoft’s translation tools and by tapping into their entire database of previous translations, so if you’re 99% there on a language and want to get it to 100% without knowing the language (and are okay with the possible hilarity of a botched translation), you can add them yourself and hope for the best.

PLUS, if you have a membership to some of the popular machine translation services, you can attempt to automagically translate the whole thing via machine translation in one go. (I generally don’t recommend this, because again, context matters, but it may be useful to some.)

That’s already super helpful, but what about when new strings are added? They’ve got that figured out, too. You can either simply manually upload the changed files in your source language, or use their command line integration to automagically push and pull to CrowdIn. With some githook love, you could achieve continuous localization. Holy crap.

When new strings are added and haven’t been translated yet, you’ll see the percentage complete is no longer 100% in your dashboard. (It would be nice if there was an option to get an email notification or daily report of new strings translated, or new strings that have been added and need translation, but I don’t see that option.)

If you end up with a ton of translators, you’ll also appreciate another feature, which is the ability for your users to vote on the best translation for any particular string. I don’t have tons of translators, but I am friendly with tons of trolls who could easily sneak a naughty or silly phrase in a translation I don’t know. Crowdsourcing the validity and appropriateness of a translation string will definitely be useful.

The final super-crazy awesome thing that I appreciate about CrowdIn is the ability to provide context for what users are translating. You upload screenshots of your app, and then select the words in the screenshot using a marquee tool. CrowdIn then does a live OCR conversion, translating that hotspot into actual text, looks it up in your strings, and lets you match that particular usage of the words to the exact translation string in the translation interface, allowing users to see the phrase exactly as its used in the app:

Screen Shot 2014-10-30 at 1.36.04 AM

Once you dig even deeper, you realize they provide for things like in-context translations live on your own app (which would be clumsy for me, since it’s an OSS app and I wouldn’t want to ship that code with the product, but could work great for people maintaining a regular product.) It’s implemented using just a small chunk of javascript dropped into your site.


Their prices are quite reasonable, and they do offer free open source plans (YAY!). They approved my application within an hour of submitting it, and I was able to get started right away.

Even if you’re not a dev, and you just want to help out, you can find projects needing translators to lend a hand with.

In completely unrelated news, check out my newest gift to the internet, It’s good for a laugh or two, I’m sure. 🙂

Also be sure to check out my awesome startup, Mass Mosaic. Seriously, do it now. Create an account. Post a tile. It’s free!

About the author


I’m a tech geek/dev/infosec-nerd/scuba diver/blacksmith/sword-fighter/crime fighter/ENTP/warcrafter/activist. I run Grokability, Inc, and run several open source projects, including Snipe-IT Asset Management. Tweet at me @snipeyhead or read more...

  • Sergey Dmytryshyn

    Disclaimer: I work at Crowdin 🙂

    Thank you for sharing the feedback. This is really awesome.

    We were thinking about email digest that will keep you updated on what’s going on but decided to do not work on that in favor of the new report that is approaching (you can expect to have it on production in two weeks or so).

    Concerning the Crowdin In-Context, I strongly recommend to use that tool. It’s not necessary to ship your code with that integration. Just do the publically available installation of your web app and deploy it with the code integrated. Just do not commit the integration to the repo.

    Please ping us via Support, we will help with the integration.

    • Hi Sergey,

      If I included the code in the public app but not the repo, any new deployments would blow out the code and I’d have to re-add it every time.

      • Sergey Dmytryshyn

        Yes. Understandable.

        Any chance to have some kind of patch when deploying to the translation environment?

        Usually it’s one line of code, include our JS in the head.

        • Of course, but only so many hours in a day, you know? 🙂 I run a start-up, and my FOSS project (and too many other things), so it’s always a matter of managing priorities.

          Plus I’d need to confirm that the js include doesn’t mess with things like datatable javascripts, etc. Actually executing a javascript injection wouldn’t be difficult, but it takes time to confirm that it’s even something that wouldn’t cause other conflicts on the pages.

  • Niels Buus

    To me it looks a lot like the PhraseApp service, just pricier.

    • They are certainly similar but I found more options with respect to string translations and suggestions, machine translations, etc. it might just be a difference in UI, but UI really matters when you’re translating thousands of strings.

By snipe
Snipe.Net Geeky, sweary things.

About Me

I’m a tech geek/dev/infosec-nerd/scuba diver/blacksmith/sword-fighter/crime fighter/ENTP/warcrafter/activist. I run Grokability, Inc, and run several open source projects, including Snipe-IT Asset Management. Tweet at me @snipeyhead or read more...

Get in Touch