Hmm; is it really so clear? I’ve developed localizable applications,
localized apps myself (translating English into Spanish), and worked on
adding translation systems to a large existing product. My experience is
that (a) it is notable effort to develop this way and (b) it is easy to
add later, and easier to add when you are actually ready for it than
just speculatively. Let me describe.
(This is just from the technical side, in addition to what @panchomiguel
has already written.)
Placeholders
Your examples hint at one problem that makes this not trivial:
"grain_accounts": "${Grain} Accounts",
Here, you’ve included a placeholder in the string. That means that our
UI code has to perform interpolation. Previously, we would write:
<span>{currencyName} Accounts</span>
…but now we must write:
<span>{uiStrings["grain_accounts"].replace("${Grain}", currencyName)}</span>
Of course, you don’t do the interpolation manually every time. You have
a framework to do it (pofiles, etc.)… so now we need to set that up, and
everyone has to learn to use it.
This goes beyond simple substitutions. Our code now needs to be generic
over different languages’ grammatical structures. In English, we often
write:
<span>{userCount} {userCount === 1 ? "user" : "users"}</span>
But other languages have different singular/plural forms, so this
doesn’t suffice anymore. Likewise for dates, currencies, decimal places.
Readability, navigability
Translated strings also make it harder to read and navigate the code.
When looking at the code, you can’t directly visualize the UI. And when
looking at the UI, you can’t directly find what part of the code that
maps to. You can usually do it through one or two layers of indirection,
which is fine if you’re only looking up one thing. But when you’re
trying to get your bearings in a GUI module that is littered with
Messages.getString
s or whatever, it’s notably harder to get an idea of
what’s going on. Some approaches use gettext directives around natural
language, like _("My account balance")
, but this makes updates harder…
Updates
Once you have a translated app, changing it becomes a whole process. If
you change the structure of the strings that need to be localized, then
you lose existing translations. Without mitigation, this results in
localized UIs that are always half in the target language and half in
English, as translations keep regressing. Users often report this as
more frustrating than if the UI were just in English, since they have to
keep context-switching and they can’t just learn the interface. There
are different ways to handle this, but they usually involve some form of
(a) minimum time delay before new code makes it into production and (b)
an expected turnaround time for translators to submit updated strings.
When?
The thing is, when we decide that the time is right and we do want to
invest in this infrastructure, retrofitting it onto existing strings is
pretty straightforward. There are linter plugins to help catch
untranslated strings in UIs. You can define mechanically generated
locales with extra-long text to suss out fixed-width UI elements, or with
extra-tall diacritic stacks to suss out bad Unicode or font handling.
You can actually try out uncommon substitution patterns on real data.
What we can do now
All that said, I do agree that keeping localization in mind from the
beginning is helpful, and there are things that we can do now. Use
Unicode and UTF-8 extensively. Distinguish byte strings and text strings
correctly. Avoid baking critical text into images (should be trying to
do this anyway for accessibility). Don’t assume that people have “first
names” or “last names”. Don’t rely on strings fitting into really small
areas (like, a 20px wide button labeled “Go!”). These are good practices
now, and they’ll also pay off later.
tl;dr: Localization is important; localization reduces development
velocity; it doesn’t make sense to pay the real costs of localization
before reaping its benefits. Ship a half-baked product to English
speakers and then a polished product to everyone.