We manage a lot of content at Battlefy. Between our core platform, portals, registration flows, sub-apps and more, we have over 10,000 translated phrases (and plenty more that haven't been).
For most of Battlefy's history, we used gettext to inject localized phrases into our products. This involved many manual steps for developers:
gettext
call (or annotate parent with a directive if in angular.js land)This was painful for developers as even the most minor content changes required a developer chore. It was also painful for our localization team, because of the way we were using gettext
. Our implementation relied on a one-to-one connection between english source phrase and localized target phrase, so changing anything in the source phrase broke that connection. This was true even if changing some punctuation or fixing a spelling mistake, something that often wouldn't actually require re-localization. It also prevented interpolation within the source phrases, which meant phrases that require interpolation (for example, "You have ${X} new messages") required breaking the source phrase into multiple pieces, which denies context to the translation professional in the best case and in the worst case, creates two meaningless phrases that are untranslatable in isolation.
So we had alignment within the development team that this wasn't an ideal, or even acceptable, approach to content management. We even had a few people outside the development team that were also feeling the pain, but it wasn't enough to launch us with both feet into a full CMS solution.
With the end goal of a dream content management system in mind, we (the developers) nudged ourselves closer by implementing a new content injection pipeline that didn't use gettext
. Instead, we had a single source map of english content which was identified not by the phrase itself, but by a unique key that described the content's role on the page. For example:
We elected not to enforce a JSON file format, instead using plain JS, to encourage multi-line formatting so that future edits would be easier. This solved the problem of slight changes breaking localization, because the phrases in all languages are identified by a common key. It also solved the interpolation problem, as we could simply come up with some standardised format:
This keying approach also opened some other doors. At Battlefy, we have an internal micro-CMS we call Manual Data Kit (or MDK). This was designed as a simple, schemaful, row-based data storage mechanism with some real-time capabilities, as well as a few other bells and whistles specific to our needs. We were able to build a layer on top of MDK for managing portal FAQs. For the first time, we had truly operations-lead content updates. This went over well. As a bonus, the systems and practices would translate very well once we adopted a true CMS - we just have to switch out the source of the keyed phrases from the source code to the CMS.
What it did NOT solve, was the chore problem. This was as bad as ever, with the exact same steps require for localization. In fact, now that we had two places where content was managed (the source code and MDK), even more pain was creeping in. These multiple sources of content resulted in multiple sources of .po files, which quickly became messy and annoying to work with. However, there is another way to look at it - that the pain was actually creeping out into the open! It was simultaneously driving demand for dev-free content management as well as highlighting the pain points in our process. Now that more people who weren't developers were able to feel the pain the developers were feeling with content management, we finally had team-wide consensus, and we were handed a mandate - solve localization, for everyone, once and for all.
With this mandate, we set out to look for solutions. The first port of call? Our old friend Manual Data Kit. We already had a bunch of code, infrastructure and tribal knowledge around using it to handle localized content thanks to the FAQ sub-system. It had the right kind of features we wanted like staging env support and deploying to our primary CDN. It even had real-time updates so we could push content changes directly to customers as they were viewing the page! This seemed like an easy win - slap an extra UI on top, probably the Medium editor, and call it a day, right?
Those of you who have been down this road before are probably shaking your heads and tutting. It didn't take much research into the practicalities of this to realize it was not a sensible approach. Content management systems are extremely complex. Features like asset management, versioned releases, revision history, nested component schemas and content folders comprise the very tip of the CMS iceberg. This is how we relearned a critical golden rule for tech startups - if it's not your core competency, BUY IT!
Fry gets it
With just a little bit of nudging and some initiative, we were able to get alignment that a CMS was not only a good direction, it was a necessity that would be worth the learning curve.
There are many, many CMS options out there with different pros and cons. We looked into Contentful, Strapi and Kontent to name a few, but eventually settled on Storyblok thanks to their stellar options for internationalization, rich plugin options and appealing price-point. While it hasn't all been smooth sailing (though truth be told, it's debatable whether "smooth sailing" can exist in the CMS world), it does seem to be a good option for us right now. Our next mission was to lead the way in adoption and show the team how great this new solution was for everyone.
The lowest hanging fruit was right under both of our noses, dear reader - the very blog you are reading now! With just a little bit of automation wizardry, we were able to export all the blog posts we had so far into a format we could import into Storyblok. We then had a short checklist of features we wanted to get right (such as social unfurling and code formatting), and we were ready to go. This gave us hands-on, end-to-end experience with Storyblok. To make this work, we had to
All this has given us a good understanding of the platform's strengths and weaknesses. We've also been developing a dashboard app using Storyblok's plugin infrastructure that can be used to import and export entire folders worth of content to our translation service (OneSky for the curious), thereby fulfilling our mandate to fix localization.
And with that, we reach the present in Battlefy's content journey. If you recognize any of these problems and think you have better solutions, or you want to be part of a company where you're empowered to solve problems as long as you're willing to take the initiative, or even if you've ever just found yourself wondering how dog food tastes, Battlefy is hiring!