Releasing Njuškalo technology to Slovenian market

Authors

Antonio Pauletich, Damir Brekalo & Goran Kljaić

Recently we were presented with a challenge of releasing an existing Croatian project njuskalo.hr on a new market that is based in Slovenia (bolha.com). This implied the need to support new currency, language, payment options, some features like delivery from the original project turned off, and a new theme.

Since the original project was in active development for over 10 years, you might imagine the state of the codebase at the time: hardcoded static texts everywhere, hardcoded currency values, features that require a crystal ball to figure out how to turn them off on one market, etc. When we started digging in, the idea was to have a single code repository for both markets and manage the differences between markets like currency, language and switchable features through configuration files.

This approach would ensure easier future development and maintenance for both markets, turning features on or off as the business department requires and eventually easier transition to new markets.Here are some of the challenges we faced and how we solved them.

Translations

We had to go through all of the existing codebase of more than 20.000 source files, scan and replace all static Croatian text content with dynamic translation function calls. This was a huge effort lasting more than 5 months taken by a team of our junior developers.

A total of 18.000 translation entries were identified and extracted to .po files. GetText Portable Object (PO) files are the industry standard for multilingual websites in PHP. These files are written in a human-readable format so that they can be easily edited by programmers and translators who had to supply us with translations for Slovenian marketplace. Symfony translation component was used to translate content on the backend.

A subset of those 18.000 translations needed to be available to javascript in frontend code. Translation subset loader service was implemented on backend to supply frontend with only those translations that were needed on a given page type. Our internally developed translate-js module was used to render translations in our frontend modules based on Figura and Vue view components.

Route localization

We had to internationalize our routes for a new market. Since at the time we were on Symfony 3.4 which did not provide this feature, we had to look at alternatives. We found a couple of bundles made by the community, but as we knew that Symfony 4.1 got support for this feature (and we knew that the upgrade to Symfony 4.4 was on our roadmap), we decided to temporarily backport the internationalization support from Symfony 4 to our 3.4 project (instead of using a third party library for that purpose).

After upgrading to Symfony 4.4 this year we successfully just deleted that code and everything just kept working.Part of this effort to internationalize routes was also to move the route definitions and route URL generation from our in-house framework to Symfony so that we can have one central tool which would handle routes (Symfony).

Some of these new localized routes had to be pushed to the front end where client side routing was utilized using Vue router. We wanted to keep route definitions and localization in one technology stack – so route subset loader service was implemented on backend to supply frontend javascript code with a “on demand” subset of localized route patterns.

Theming and assets localization

We knew from the start that Bolha will have to have a different color scheme, graphics, and assets from Njuškalo. Therefore our technology had to be extended to allow for this customization.

We developed themes as a way to differentiate instance assets, visuals and general “look and feel” of the platform. Every CBT instance has one theme applied through instance configuration. When an asset is referenced in our backend or frontend code it goes through our theme asset lookup algorithm. When instance CSS is generated through the webpack / SASS pipeline theme aware variables and styles are injected into final output bundles. Theme aware asset resolution and CSS output customization are technical foundations of simple and powerful theming System.

Currency localization

Before the start of the project we had hardcoded Croatian currency (HRK) as a primary currency and Euro (EUR) as a secondary currency all over the codebase. Not only that but we had at least five different currency formatters in the codebase which were all formatting the currency in a different way before displaying it to the user.

This obviously had to change and we needed to agree with the business on an uniform way of formatting prices on the platform depending on the market. This was no easy feat as the financial department wanted it to be done one way, the user support department another etc. At the end we decided on one standard with some tiny variations depending on if the price is being displayed on the public part of the site or if it is displayed in the admin part of the site.

After we did the initial implementation our hosting provider bumped our PHP version from 7.2.15 to 7.2.16 and the output from the price formatter changed. Our investigation has shown that the PHP intl extension has now been bundled with a much newer libICU version (almost a ten major versions bump) which in turn had a much newer Unicode CLDR database bundled with it.

For this reason we had to improve our implementation and give it the ability to force some formattingoptions (like whitespaces, the position of the currency symbol and how a currency symbolshould look like for a currency – for example in the intl bump the currency symbol for the Croatian kuna changed from “kn” to “HRK”) in order to not make it dependent on the PHP intl / libICU versions that the application is running on.

Switchable features (flags) and instanceconfiguration

Through the joint effort of our back-end and front-end developers a system was built where backend configuration variables are transparently available to the frontend build pipeline. A subset of instance configuration parameters is compiled on the backend to a JSON file that is read by the frontend build process. CSS and Javascript output bundles are therefore customized and automagically optimized for each instance based on instance configuration and feature flags. On the backend the features can be switched on or off in the configuration which was achieved by using the Flagception bundle.