views:

61

answers:

1

Up until now, I have maintained a 'dictionary' table in my database, for example:

+-----------+---------------------------------------+-----------------------------------------------+--------+
| phrase    | en                                    | fr                                            | etc... |
+-----------+---------------------------------------+-----------------------------------------------+--------+
| generated | Generated in %1$01.2f seconds at %2$s | Créée en %1$01.2f secondes à %2$s aujourd'hui | ...    |
| submit    | Submit...                             | Envoyer...                                    | ...    |
+-----------+---------------------------------------+-----------------------------------------------+--------+

I'll then select all rows from the database for the column that matches the locale we're interested in (or read the cache from a file to speed db lookup) and dump the dictionary into an array called $lng.

Then I'll have HTML helper objects like this in my view:

$html->input(array('type' => 'submit', 'value' => $lng['submit'], etc...));
...
$html->div(array('value' => sprintf($lng['generated'], $generated, date('H:i')), etc...));

The translations can appear in PDF, XLS and AJAX responses too.

The problem with my approach so far is that I now have loads of global $lng; in every class where there is a function that spits out UI code..

How do other people get the translation into the object? Is it one scenario where globals aren't actually that bad? Would it be madness to create a class with accessors when the dictionary terms are all static?

Addendum

As I have an HTML class, a PDF class, a JSON class etc, all of which have the dictionary as a dependency, is this a situation whereby I could use dependency injection in a Lng class to make it easier to test different translations?

+2  A: 

As a quick and simple solution just make lng a function:

 $html->input(array('type' => 'submit', 'value' => lng('submit'), etc...));

Another thought: if you're using html helpers, why don't make them aware of i18n, so that you can just pass a string ID, like

 $html->input(array('type' => 'submit', 'value' => '@submit', etc...));

and in input() function replace '@xxx' with 'lng(xxx)'

Also gettext might be an option.

stereofrog
Much more beneficial than using `global`.
Anthony Forloney
If `lng` becomes a global function, then surely it has to either lookup the database on every request, or reference a **global** array from somewhere else... How would `lng()` be implemented if not?
boatingcow
@boatingcow - if a global is known and referred to in one single function, i see nothing wrong with it, but i'd use a static variable for this purpose.
stereofrog
@stereofrog - thanks for your comments - as soon as a question is up, there is the reply! I don't think I can use the `@symbol` syntax like in other frameworks since there are quite often dynamic values as in the sprintf case above. Although I haven't used it, getText would seem to be limited as I'm working from the database. I take it when you say static variable, you mean that I'd feed the array into the static variable on first use, then since it's already initialised, subsequent requests use the same result set? Are there any pitfalls in using `lng()` everywhere instead of `$lng`?
boatingcow
yes, lng() can look like this: `static $data = null; if(is_null($data)) $data=load(); return $data[$param]`. I don't see any pitfalls here, except that calling a function is slower than array access.
stereofrog