OSS maintenance by Michael, github.com/theluckystrike, works in writing
Your translated app is showing customers broken text
I check every locale file in your app against the source language, then send one PR that fixes every objective bug. $400 fixed, one repo, written report in 3 business days.
Start now See the sample report
Translations break quietly. Few teams can read most of their own locales, tests run in English, and the bug only shows up on a customer's screen. In 6 open-source apps that companies ship to their own customers, I found these this week.
- White-label customers saw the vendor's name. In ToolJet, 46 strings in 8 languages lost the white-label name, and 44 of them printed "ToolJet" instead on the login, sign-up, Slack and Google Sheets screens.
- A price rule with no numbers. Medusa's Spanish admin summarized a shipping price rule as "Rango" (range), without the attribute or the bounds.
- Whole screens falling back to English. In Strapi, 40 of the 68 strings I fixed made the message formatter throw, so the admin showed English instead.
- Emails that never got translated. OpenAEV's lessons learned email went out in English in all 8 translated languages, because the key in the language files did not match the one the code asks for.
- Raw markup on a login screen. Infisical's Korean and Brazilian Portuguese users saw
<email>{{email}}</email><wrapper>above the verification code field. - Placeholders mangled by machine translation. OpenMetadata's Spanish domain change warning read "moverá _ 0 _ activos) del dominio actual a _1 __."
PR states are read live from GitHub each time this page is built. Last built 5 Oct 2026, 01:33 UTC. The full sample report is further down.
What the audit checks
Every string in every locale, compared with the same key in your source language.
- Placeholders that were dropped, renamed, translated or added:
{{name}},{name},%{name},%s,${name}. - ICU messages: plural and select keywords that got translated, braces that don't balance, and whether each message parses and formats with the values your code passes.
- Rich text and Trans tags like
<0>,<b>and<a>that were lost, left unclosed or shown as raw text. - Brand names typed into a translation where your code passes a variable. That's the white-label leak.
- Keys your code asks for that the locale files don't match, and findings on keys no code uses any more. Those dead keys are listed, not fixed blindly.
The string checks run by script on every locale. Each finding is then checked by hand against the code that calls it, so the PR only changes what users actually see.
What you get
- A written report. Every finding with locale, key, the current text, the fixed text and what the user sees today.
- One PR that fixes every objective bug: placeholders, syntax, tags and brand leaks. Wording only changes where a value has to fit into the sentence.
- Checked with your repo's own tooling (lint, translation validator, JSON parse) and a render test that formats every changed string with real values before and after.
- If your translations live in a TMS like Crowdin, Lokalise, Lingo.dev or Tolgee, you get the fixes as a file to import there instead of a PR, since edits to the repo would be overwritten.
Price and terms
i18n audit and fix
$400 fixed price, one repo- One app's locale files in one repo, up to 40 locales.
- Report and PR within 3 business days after I can read the repo.
- A public repo needs only the link. A private one needs a read invite on GitHub. No production access, deploy rights or secrets.
- Everything happens in writing, by email and in the PR. I don't do calls.
- Paid in USD, by card payment link or bank transfer invoice.
Not included: native-speaker review, translating keys that are missing entirely, and new languages. Keeping locales filled after every release is the $750 a month locale upkeep on the main page.
For agencies
If you build Medusa, Strapi or similar stores and admin apps for clients, I can run this audit on a client's repo as white-label capacity. The report can go out under your agency's name, and the PR goes to the client repo for your team to review. Framework upgrades and ongoing locale work are on the main page.
Start now
i18n audit and fix, $400 fixed
Pilot month $400, locale upkeep $750 a month, or maintenance $1,500 a month
Pay now opens a Stripe checkout. The seller name shown there is BeLikeNative, the name of my Stripe account.
Or email lipmichal@gmail.com. Use email for a private repo or anything you'd rather not post in public, since the form opens a public GitHub issue.
What happens next
- I reply in writing within 24 hours to confirm the scope. If you have not paid yet, the reply has the payment link.
- Work starts when the payment arrives.
- You get the written report and the first PR within 3 business days.
No calls. Every step happens in writing, in the issue or by email.
Sample report
The same audit, run on 6 public apps on 3 Oct 2026. "Broken strings found" counts one string in one locale. Every before and after below is quoted from the PR diff.
Medusa
Open, waiting for reviewAdmin dashboard, i18next. medusajs/medusa#17118
- 14 placeholder dropped
- 11 rich text tags lost
- 9 plural form drops {{count}}
- 2 placeholder the source does not have
- 1 wrong placeholder syntax
ar 15, el 11, fr 6, es 4, ptPT 1. The other 29 locales were clean. 5 Arabic singular forms left as they are on purpose, because they spell out "one" in words, which is natural Arabic. The repo's own i18n-validation-admin-dashboard CI check passed on the PR.
es Shipping price rule summary
BeforeRango
AfterSi <0>{{attribute}}</0> está entre <1>{{gte}}</1> y <2>{{lte}}</2>
The Spanish admin showed only "Rango" (range). It never said which attribute the rule checks or what the bounds are.
fr Type to confirm prompt
BeforeVeuillez entrer {{val}} pour confirmer :
AfterVeuillez entrer {val} pour confirmer :
The code fills {val}. With double braces the French prompt never showed the value the user has to type.
ptPT Delete variant warning
BeforeTens a certeza que queres eliminar esta variante?
AfterEstás prestes a eliminar a variante {{title}}. Esta ação não pode ser anulada.
The warning now names the variant that is about to be deleted, like the English one does.
Strapi
Open, waiting for reviewAdmin panel and plugins, react-intl (ICU). strapi/strapi#27908
- 168 placeholder dropped
- 93 placeholder renamed or translated
- 58 ICU message does not parse
- 6 mixed placeholder syntax
- 1 placeholder the source does not have
Across the admin, content manager, upload, i18n and users-permissions packages. 134 findings left out because other open PRs already edit those keys, and 124 sit on keys no code uses any more. Of the 68 old strings, 40 made intl-messageformat throw with the values the code passes, so the admin fell back to English. Another 26 rendered without the value.
hi Delete component label
Before{नाम} हटाएं
After{name} हटाएं
The argument name itself was translated into Hindi, so the code's {name} value had nowhere to go.
eu Settings page title
BeforeKonfigurazioa - {name}}
AfterKonfigurazioa - {name}
One stray closing brace and the whole message stops parsing.
pl i18n plugin, delete locale action
BeforeUsuń
AfterUsuń język {name}
The Polish action label said only "Delete". It now says which locale gets deleted.
OpenMetadata
Open, waiting for reviewWeb UI, i18next. open-metadata/OpenMetadata#34584
- 123 placeholder dropped
- 39 placeholder the source does not have
- 10 placeholder renamed or translated
- 1 ICU message does not parse
- 1 mixed placeholder syntax
Every translated UI locale had at least one. 22 left out because two other open PRs (#34084, #33416) edit the same keys. The project's CI only runs after a maintainer adds the safe to test label, so most checks show as failed until then.
es-es Change domain warning
BeforeCambiar el dominio moverá _ 0 _ activos) del dominio actual a _1 __.¿Quieres continuar?
AfterCambiar el dominio moverá {{count}} activo(s) del dominio actual a {{domain}}. ¿Quieres continuar?
Machine translation mangled both placeholders. Spanish users were asked to confirm a move without seeing how many assets or which domain.
es-es Copy action
BeforeCopiar URL
AfterCopiar {{item}}
The button said "Copy URL" whatever it was copying.
ar-sa Uninstall app message
Beforeستؤدي إزالة تثبيت تطبيق {{app}} هذا إلى إزالته من OpenMetaData
Afterستؤدي إزالة تثبيت تطبيق {{app}} هذا إلى إزالته من {{brandName}}
The product name was typed in by hand where the code passes {{brandName}}, so this string ignores the brand setting.
ToolJet
Open, waiting for reviewFrontend, i18next, white-label support. ToolJet/ToolJet#18211
- 57 placeholder dropped
de, es, fr, id, it, ru, uk, zh. 46 of the 57 dropped {{whiteLabelText}}, and 44 of those printed "ToolJet" instead, on the login, sign-up, verification, Slack and Google Sheets screens. The other 11 dropped {{appName}}, {{version}} or {{componentName}}.
es Sign-up page
Before¿Nuevo en ToolJet?
After¿Nuevo en {{whiteLabelText}}?
A white-label customer's Spanish users saw the vendor's brand instead of the customer's.
de Slack connection help
BeforeToolJet kann eine Verbindung zu Slack herstellen und Benutzer auflisten, Nachrichten senden, usw. Bitte wählen Sie entsprechende Berechtigungsbereiche.
After{{whiteLabelText}} kann eine Verbindung zu Slack herstellen und Benutzer auflisten, Nachrichten senden, usw. Bitte wählen Sie entsprechende Berechtigungsbereiche.
Same brand leak, in German, on a setup screen.
de Delete app confirmation
BeforeDie App und die zugehörigen Daten werden endgültig gelöscht. Möchten Sie fortfahren?
AfterDie App {{appName}} und die zugehörigen Daten werden endgültig gelöscht. Möchten Sie fortfahren?
A permanent delete prompt that did not say which app.
OpenAEV
Open, waiting for reviewFrontend, react-intl (ICU). OpenAEV-Platform/openaev#8258
- 1 placeholder dropped
- 1 placeholder renamed or translated
- 1 ICU message does not parse
- 1 placeholder the source does not have
ja, ko and zh. Separately, one key mismatch kept the lessons learned email in English in all 8 translated languages. 13 lines in 9 language files: the 4 placeholder bugs, the email key in every file, and an unclosed <a/> tag in it and ja. Commits are signed, as the repo requires.
zh Launch atomic testing dialog
Before你想启动这个原子测试吗: {truc}?
After你想启动这个原子测试吗: {title}?
"truc" is French for "thing". The Chinese dialog showed an empty value where the test title belongs.
ko Getting started, test more scenarios
Before에서 더 많은 시나리오를 테스트하세요 !
After{xtmHubLink}에서 더 많은 시나리오를 테스트하세요 !
The link to XTM Hub was gone, so the sentence started with a dangling particle.
all 9 Lessons learned email key
Before<a href='${lessons_uri}'>
After<a href="${lessons_uri}">
The code asks for the key with double quotes, the language files stored it with single quotes. The lookup never matched, so the email went out in English in every language.
Infisical
Open, waiting for reviewFrontend, i18next. Infisical/infisical#8419
- 4 raw markup shown to users
ko and pt-BR. The other 3 translated locales were clean. Checked by calling t() in i18next before and after. Only the ko and pt-BR output changed.
ko Email verification and MFA step
Before<email>{{email}}</email><wrapper>로 인증 메일을 전송하였습니다</wrapper><email>{{email}}</email>
After다음 주소로 인증 메일을 전송하였습니다
Korean users saw raw tags and an unfilled {{email}} above the code field, at sign-up and at every email MFA login.
pt-BR Email verification and MFA step
Before<wrapper>Enviamos um e-mail de verificação para</wrapper><email>{{email}}</email>
AfterEnviamos um e-mail de verificação para
Same leftover markup from an older layout, in Brazilian Portuguese.
Audited without a PR, because translations come from a TMS
These 5 repos had 317 broken strings between them. Their translations are synced from a translation management system, so a repo edit would be overwritten. A client in this situation gets the fix file for the TMS instead.
| Repo | TMS | Found | Locales | Note |
|---|---|---|---|---|
| calcom/cal.diy | Lingo.dev | 213 | 39 | Fix branch with 30 fixes is pushed. The PR is not open yet, because the account has 5 other open PRs there. |
| formbricks/formbricks | Lingo.dev | 45 | 13 | The repo's AGENTS.md says not to edit non en-US locales by hand. |
| RocketChat/Rocket.Chat | LingoHub | 44 | 33 | Mostly %s and __x__ placeholders. |
| twentyhq/twenty | Crowdin | 11 | 6 | Includes an Italian ICU quote that makes {x} render literally. |
| baptisteArno/typebot.io | Tolgee | 4 | 2 |
To be clear
None of these projects paid for this work or asked for it. The PRs were opened as normal public contributions, and listing them here doesn't mean their maintainers endorse this offer. 6 of the 6 PRs are still open, and 0 are merged so far. I have no paying audit clients yet, so there are no testimonials. The PRs above are the evidence.