Multilingual FileMaker solutions — DDRparser + ACF-plugin: the ultimate combo
With ACF-plugin 1.7.6.2 we’ve introduced new functions for fast, clean translations. Paired with DDRparser 1.2.0, you can scan a solution for translatable strings, generate a POT file, translate it with Poedit (or any PO platform/AI), and load the resulting .po back into your FileMaker app from a container field or a file path. That’s it — translations live!
The DDRparser GUI tool shipped with v1.2.0 also doubles as a demo of this technique.
Note: We have lifted the license requirements for the translation lookup functions «_(some text)» in version 1.7.6.1+, for users running demo mode it should not break application functioning when demo window expires.
Here is the manual page for the new functions: https://horneks.no/manuals/ACF/translationfunctions.html
Why not the traditional approaches?
Developers have tried many patterns for multi-language in FileMaker. They work, but they don’t scale well:
- A table full of global fields (one per string) — becomes impossible to navigate as strings grow.
- Global variables rendered in layouts — hard to discover/maintain; clutters the Data Viewer.
- Duplicate layouts per language — reliable, but a maintenance burden (every change × languages).
- Lookup by key in a translations table — workable, but still more plumbing and upkeep.
The new flow (simple and professional)
1) Author strings inline
Use short, readable calls where the text lives:
_("My orders")
_("Overwrite file “%1”?" ; Packages::FileName)
_n("%1 item" ; "%1 items" ; Items::Count ; Items::Count)
%1,%2, … are placeholders (substituted at runtime)._npicks singular/plural based oncount(simple rule today; PO plural rules later).
2) Extract strings into a POT
Run DDRparser 1.2.0 to scan for _("…")/_n("…") calls and write TranslationFiles/messages.pot.
3) Translate with PO tools
Open the POT in Poedit (or any PO platform) and create one .po per language. Translate only msgstr — placeholders stay intact.
4) Load the translation at runtime
In your FileMaker app, load a .po from a container or disk:
ACF_Load_TranslationPO( Languages::POContainer )- or
ACF_Load_TranslationPO( Get ( DocumentsPath ) & "i18n/en.po" )
If a string is missing, the original text is shown (safe fallback). You can also call ACF_UpdatePOT ( pathTo/messages.pot ) to append any runtime “misses” to the POT.
Built-in demo
The DDRparser GUI tool shipped with v1.2.0 demonstrates the full loop. It can also install/update the correct ACF-plugin if needed.
Layout text is now easy (FileMaker 20+)
Under the Text toolbar, choose Layout Calculation and just write:
_("My orders")
No more hunting through fields or variables — the string is right where it’s used.
What makes this better?
- Readable source — text is inline:
_("…"). - Automatic extraction — DDRparser creates a clean POT.
- Professional workflow — standard PO format; use Poedit, Weblate, POEditor, etc.
- Instant runtime — hash-map lookups keep translations equally fast, no matter how many strings you have.
- Effortless iteration — new strings appear in the base language; update POT, translate, reload.
Quick start in your app
- Create a Languages table with:
Name(text)PO(container)
- Script switchLanguage:
ACF_Clear_TranslationACF_Load_TranslationPO ( Languages::PO )
- Add a dropdown of available languages on your main layout, add a script trigger to call
switchLanguage— watch text update instantly.
Notes & tips
- Prefer placeholders over string concatenation (e.g.,
“%1”for filenames). - Keep msgids tidy (no stray spaces; fix typos early).
- Locale headers:
Language: nb,Language: ja, etc. AddPlural-Forms(e.g.,nb: nplurals=2; plural=(n != 1);,ja: nplurals=1; plural=0;). - For collaboration, PO is universal — Poedit, Weblate, POEditor, Crowdin, Lokalise all work.
Performance metrix
Tested on a Mac-Mini Intel Core i7, 3.2GHz, 32GB RAM. All strings have english original and norwegian translation. The .mo file is compiled .po file (in Poedit) – dropped the .mo file into the po-container instead. Way faster load time.
| Number of Strings in container | Load (po-container) – One time | Load .mo file in po-container – instead | String lookup |
|---|---|---|---|
| 100 | 0.60 ms | 0.43 ms | 0.12 ms |
| 1,000 | 2.37 ms | 1.43 ms | 0.15 ms |
| 10,000 | 13.1 ms | 5 ms | 0.155 ms |
| 100,000 | 141 ms | 71 ms | 0.16 ms |
| 500,000 | 615 ms | 234 ms | 0.15 ms |
Takeaway: load time scales linearly with catalog size, while lookup stays flat (~0.12–0.16 ms) regardless of size.
For a layout containing 50 translateable strings: average of 7.5 ms to translate the strings. Hardly noticable for the user.
Download & try
Grab DDRparser 1.2.0, run an extraction, translate with Poedit, and load the .po via the ACF-plugin 1.7.6.0. You’ll have a multilingual solution up and running in minutes — with a workflow that scales.
