A Grav-Native Translation Portal

Replacing Crowdin with a self-hosted, AI-bootstrapped, GitHub-integrated workflow built on Grav 2.0

10 mins

Back in late 2015, we announced that Grav's translation workflow was moving to Crowdin. At the time it was a huge step forward. Instead of forking a plugin repo, hand-editing YAML in your editor, and submitting a pull request for every typo, contributors could log into a polished web UI, translate strings in context, and let Crowdin manage the round-trip back to GitHub. For a community that was just starting to grow internationally, it was the right call.

A decade later, the picture has changed. The Admin plugin became Admin2 with its own SvelteKit5 SPA. The plugin ecosystem expanded well past what a single Crowdin project was comfortable indexing. AI translation went from "interesting demo" to "genuinely usable", and our own ecosystem now ships a first-party API plugin and Admin Next that make it trivial to build the kind of integrated tooling that used to require a whole separate platform.

Translations Portal

So we built one. Today I'm thrilled to announce the Grav Translations Portal, live at translations.getgrav.org, and the new home for translating Grav plugins and themes going forward.

Why Move Off Crowdin

Crowdin served us well for ten years, and I want to be fair about that. None of what follows is a knock on the platform. It's just that the gap between what Crowdin is (a general-purpose localization platform) and what the Grav community needs has widened, and a tailored tool can do things a generic one can't.

A few things stopped fitting:

  • Round-trip latency. Strings translated on Crowdin had to be exported, merged, and PR'd back into each plugin repo. That process was manual enough that translations would sit "complete" on Crowdin while the actual plugin shipping to GPM was still missing them. Contributors lost the thread, and so did we.
  • One project per plugin. Each new plugin or theme needed its own Crowdin project, its own contributor invites, its own configuration. Grav has a lot of plugins. Scaling that by hand was never going to keep up.
  • No Grav-specific validation. Crowdin doesn't know what an ICU placeholder looks like in a Grav YAML file. It doesn't know that PLUGIN_ADMIN.* keys are shared vocabulary and shouldn't drift. It doesn't validate that the HTML in a help: field is well-formed. We had to bolt all of that on after the fact, in audit scripts that ran outside the platform.
  • Crowdin doesn't know about Grav. Reviewers had no way to preview a translated string inside the actual admin where it would be rendered. The platform showed you the YAML key and a text box, and you trusted that the result would look right.
  • AI was a paid afterthought. Crowdin's AI features exist, but they're priced and structured for enterprise localization teams, not a volunteer-driven open-source community.

The fix wasn't to find a better third-party platform. It was to build the workflow we actually want, on the stack we now have.

The Vision

The vision for the Translations Portal is simple to state and a lot more interesting to deliver: make translation contributions painless to get into a Grav plugin, and painless to get back out. Everything else follows from that.

Concretely, that means:

  1. A new language for a plugin should go from "doesn't exist" to "complete first draft" without a human writing a single string.
  2. A human reviewer for that language should be able to log in, scan the AI draft, accept the good parts, fix the bad parts, and submit the result, all without leaving the browser.
  3. The submitted translation should arrive back at the plugin repository as a clean pull request, with the same key ordering, same comments, and same structure as the source en.yaml.
  4. The plugin maintainer should be able to merge that PR with confidence that the result is valid YAML, the ICU placeholders are preserved, the HTML in help text is well-formed, and the key set matches the source.
  5. None of this should require a separate account on a third-party platform. You sign in with GitHub. That's it.

The portal exists to make every one of those steps trivial.

How It Works

The portal is itself a Grav 2.0 site, running the new Admin2 plugin, with all the translation-specific functionality shipped in a dedicated Translation Service plugin. It's the same stack we're recommending to everyone else: file-based, API-first, with Admin Next as the chrome. Dogfooding all the way down.

The high-level flow looks like this:

Repository Sync

Each registered plugin or theme is pulled in via a GitHub App that has read access to the source languages/en.yaml (and theme equivalents). When a maintainer pushes a change to that file, a webhook fires and the portal re-indexes the keys. New strings show up immediately as "untranslated" across every language already in flight.

AI Bootstrap

When a contributor adds a new language to a plugin, the portal generates a complete <lang>.yaml from the source English file in one pass. Claude Haiku handles the bulk translation, Claude Sonnet runs a self-review pass over the result, and the entire output gets fed through our existing audit pipeline before it lands in the database. That means ICU placeholders preserved, HTML in help text well-formed, and the key set exactly matching the source. The audit is the same one we run in CI on the live plugins, so the AI output is held to the same standard as a human-submitted translation.

Community Review

This is where humans take over. Each language has one or more community reviewers with permission to approve translations for that language. They see every string in context, in an interface built specifically for the job: source on one side, current translation on the other, a status pill that tells you whether it's AI-drafted, human-reviewed, or untouched. They can edit, approve, or flag strings as needing more work. Everything is API-backed, so the UI is fast, and the review state lives in a real database rather than a YAML file.

Round-Trip via Pull Request

When a reviewer is ready to ship, the portal generates a clean PR back to the plugin's source repo, preserving the key order and structure of the original English file. The maintainer reviews and merges. The translation is now live in the plugin, and the portal records the SHA it was published in so we know exactly what's shipped and what's still pending.

The whole loop happens inside the browser, on a single sign-in, with no platform-specific accounts to manage.

Why This Beats Crowdin for the Grav Community

A few things are genuinely better here, not just "different":

  • Grav-aware validation. The portal knows what a Grav lang file looks like. ICU placeholders, the PLUGIN_ADMIN vs PLUGIN_<NAME> namespace split, HTML in help: fields, key alignment between source and translation: all of it is checked automatically, on every save. We can't accidentally ship a translation that breaks the admin.
  • AI as a first-class citizen. New languages don't need a contributor to grind through 800 strings before there's anything to review. The AI bootstrap puts a complete draft on the table, and the humans focus on the part where humans actually add value: tone, idiom, technical correctness, and cultural nuance.
  • GitHub-native round-trip. No export step, no manual merging, no "wait, which Crowdin project is this string in?". The portal pulls from GitHub, the portal pushes back to GitHub, and the plugin repo stays the single source of truth.
  • One platform, every plugin. Every Grav plugin or theme that wants to be translated registers once. Contributors browse one list, log in once, and pick whatever they want to work on. No per-project setup overhead.
  • Built on the stack we ship. The portal is a Grav 2.0 site. The UI is Admin Next. The data layer is the API plugin. If you've used Grav 2.0, you already know how to use this. And if you're a plugin developer, the portal itself is an existence proof that the new platform can carry real production workloads.
  • Self-hosted, by us, for us. No external dependencies, no platform pricing tiers, no risk of a service we don't control changing its terms or its API.

Starting with Admin2

We're rolling this out incrementally, and we're starting where the demand is heaviest: the Admin2 plugin itself. Admin2 has by far the largest translation surface of anything in the Grav ecosystem, it's the one plugin every user installs, and it's the one where a missing or broken translation is the most visible. So that's project one in the portal.

Admin2 is already loaded into the portal, the English source is being tracked, and the existing translations from the Admin Classic plugin have been imported as the starting point. AI bootstraps are available for any language that isn't already present. If you've previously contributed translations through the old Crowdin workflow, the migration carries your work forward.

From there, we'll add the other heavily-translated plugins (Form, Login, Email, etc.), then the rest of the official plugin set, and finally open the portal up to third-party plugin and theme maintainers who want to register their own projects. The infrastructure is built to scale to the whole ecosystem from day one. We just want to land Admin2 cleanly first so the rough edges show up where we can find them quickly.

How to Get Involved

If you've translated for Grav before, or you've ever wanted to, this is the easiest moment in the project's history to jump in.

  1. Head over to translations.getgrav.org
  2. Sign in with your GitHub account (no separate signup, no email confirmations)
  3. Pick a language you're fluent in, browse the Admin2 project, and start reviewing the AI-drafted strings
  4. If your language doesn't exist yet, kick off a new AI bootstrap and you'll have a complete draft in a few minutes ready for review

If you want to become a community reviewer for a specific language (with permission to promote translations to live and trigger PRs back to the source repos), reach out in Discord and we'll get you set up. We're actively looking for reviewers across every language Admin2 has historically supported, and we'd love to grow that list.

What's Next

The portal is live, the Admin2 project is open, and the round-trip back to GitHub is wired up end to end. A few things are still on the immediate roadmap:

  • Multiple in-flight proposals per string. Today the model is "one active translation per string with full history", which is the right call for small teams. We've already sketched the design for a Crowdin-style "N candidates with voting and reviewer promotion" model, and we'll layer that in once the basic workflow has settled.
  • Self-service plugin registration. Right now the team adds new plugins by hand. We want third-party maintainers to be able to register their own plugin or theme repo through the portal directly.
  • In-context preview. Showing each string rendered inside the actual Admin2 panel it'll appear in, so reviewers can sanity-check tone and length against the real UI rather than imagining it.
  • Translation memory across plugins. When the same English string appears in multiple plugins (and it does, often), the portal will start suggesting the existing translation rather than asking the AI from scratch.

This is the beginning of a much longer effort to make Grav genuinely first-class in every language its community speaks. Crowdin got us through the last ten years. The Translations Portal is what gets us through the next ten.

A huge thanks to everyone who has contributed translations to Grav over the past decade, both on Crowdin and through direct PRs. None of this work is wasted. It's all carried forward into the new portal, and you're the reason we're in a position to build something better.

Enjoy!

Andy

Grav Premium
Turbo-charge your Grav site - from the creators of Grav