Howto: Setting up translations on Weblate

Crowdin has served us well, but the maintenance got out of hand a bit and everything is a bit dusty by now. So I investigated Weblate as an alternative and for a while we had basically decided to switch to that.

During the current Neos sprint (in November 2021) I got back to that topic, finally. This is a documentation on how to set up a project on Weblate.


  • A Project has just a name, website and translation instructions. The other settings are not relevant for us or are fine at their default. A project is then used to group multiple components.
  • Components hold translations and are referring to a single source file. So we have components for Main.xlf and ValidationErrors.xlf, among others. That component can be tied to a Git repository and then always relates to one specific branch.
  • Addons can automate things, like translating new strings automagically, discover components, cleanup translations, …
  • Checks are run automatically and detect common mistakes like mismatching punctuation between source and translation, duplicate words, …

How to set up a simple package for translation

For a package that has a single XLIFF file and where only one branch (main/master) is to be translated, the setup is rather straightforward.

Add the component

Configure the addons

Enable the following addons:

  • Cleanup translation files
  • Stale comment removal – 90 days is what I chose for our “velocity”
  • Add missing languages
  • Automatic translation – I decided to go with “Add as needing edit”

The Component discovery is somewhat special and might not be needed, but it can be used to automate the creation of more components from the files in Git. The addon can be added multiple times, even, as we do for the development collections of Flow and Neos.

The screenshot shows the settings for the Google Analytics component, the “template” settings are (adjust package name and branch):

  • Resources/Private/Translations/(?P<language>[^/]*)/(?P<component>.*)\.xlf
  • Neos.GoogleAnalytics - {{ component }} - master
  • Resources/Private/Translations/en/{{ component }}.xlf

This will create components for other XLIFF files that may be added later.

Automatically receiving changes from GitHub

Using webhooks Weblate can keep itself up to date when the source changes. It can be set up following Continuous localization — Weblate 4.9.1 documentation

For the Neos and Flowpack organizations the Weblate GitHub App has been enabled, so there is nothing to be done…

Set up branch handling

Since a component targets a single branch, you need to set up additional components for other branches you might want to work on when it comes to translations. For a lot of packages it could be enough to just work on the main branch, and have new or improved translations “in the next version.”

For longer-living branches being developed in parallel you need to set up all components you have for all branches you want to maintain. Luckily there is a way to create a new component using the “Additional branch” choice.

The example above shows a (hypothetical) setup for the 3.2 branch of the the Main.xlf file of Neos.GoogleAnalytics.

If doing that, just make sure to check the addons and add or re-configure things as needed in the new component!

Mono-repo handling (development collections)

Our development collections pose a special challenge, since they have just one repository holding multiple components. That is fine when using the main/master branch, but as soon as component from two packages should be managed in two branches, this does no longer “just work”. That’s because the first component will “use up” the branch, so you cannot select it a second time, when using “real repository URLs”.

The way I came up with for our development collections is based on component discovery. For the Flow development collection there are these components:

  • Neos.Flow - Main - master (manually created)
  • Neos.Flow - ValidationErrors - master (component discovery)
  • Neos.FluidAdaptor - Main - master (component discovery)

The latter two are discovered through two instances of component discovery in the “Neos.Flow - Main - master” component. In this case the discovery is configured like this for every “Main” component:

  • (?P<package>[^/]*)/Resources/Private/Translations/(?P<language>[^/]*)/(?P<component>.*)\.xlf
  • {{ package }} - {{ component }} - master (make sure to replace the master with the branch name)
  • {{ package }}/Resources/Private/Translations/en/{{ component }}.xlf

The named group package catches the package directory and it can be used in the other options.

Now this whole setup is multiplied by the supported branches, and we end up with:

For the Neos development collection we end up with a similar, but larger, setup.

1 Like