In some cases there's a strong use case to have fallbacks when fetching translations.

Say you've got fr-CA and fr (Canadian French and French) on your site. A user is viewing the site in fr-CA. Lots of elements translatable through i18nstrings (taxonomy terms, block titles, whatever) have been translated into fr, but only a few have been translated into fr-CA. It would be useful to be able to say: show the fr-CA translation, if one exists. If not, use the generic fr one.

Over in the country_code module, which we at CivicActions are currently building, we've got a similar use case. We're tracking the country a user is viewing the site from separately from the global language. In this case, we want a user viewing the site in fr from Canada to see any fr-CA translations first, but use the current language (fr) as the fallback.

Language fallbacks are probably in themselves beyond the scope of i18nstrings. But could a hook invocation make it possible to implement i18nstrings fallbacks in other languages?

To try to see, I've coded up a module that would implement such a hook and attached it as language_hierarchy. This module adds a 'parent' field to the language edit form. Selecting a parent creates a hierarchy, much like a taxonomy tree.

Then we implement a drupal_alter style hook to instruct i18nstrings to look for parent languages after looking for a given language's translation. Here's the hook implementation:


/**
 * Implementation of hook_i18nstrings_languages_alter().
 *
 * Instruct i18nstrings to look for translations in parent languages if the given one
 * isn't available.
 */
function language_hierarchy_i18strings_languages_alter(&$languages, $langcode) {
  $tree = language_hierarchy_get_tree();
  if (isset($tree[$langcode]) && $parents = array_filter($tree[$langcode]['parents'])) {
    $languages = array_merge($languages, $parents);
  }
}

So far so good. But the harder part is seeing just where and how to modify i18nstrings to invoke such a hook.

Attached patch is my first guess. In i18nstrings_get_string() we call drupal_alter(), feeding in the single langcode that's being requested and iterate through the resulting array. If nothing was added, we get no changed functionality. If other languages are added to the array, each is tested in turn, with a NULL or FALSE returned only if we're testing the last array element and it too comes up empty.

Some questions and difficulties:

1. Do we every use the return value or its cached version to determine the existing translation for editing purposes? If so, we'll get the wrong value (the value for another language).

2. In tt() we promptly return if the $langcode is the default while in the came case in ts() we go straight for the source translation. Both of these will prevent any fallback.

3. What to do if we're loading a bunch of translations through i18nstrings_prefetch()? Do we need a separate implementation with its own drupal_alter() call here?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nedjo’s picture

On reconsidering this, I don't think it makes sense, mainly because a fallback here but not in core would be confusing and not all that useful. And I have to conclude after looking at the relevant code that adding this to core would be messy.

But the idea may be worth revisiting at the translation import stage. That is, e.g.:

* Site has fr-CA language enabled.
* Site admin enables module examplex.
* If there is a fr-CA translation available it is imported. But if not, a fr one is used if present.

Jose Reyero’s picture

Status: Active » Postponed

I agree this may be an interesting feature, implementing it may be a major mess though. Also you cannot assume 'fr-CA' will default to 'fr', it may be the other way too so this needs specific configuration.

An intermediate approach may be creating a page on which you can populate missing string translations, similar to the i18nstrings synchronization page, something like:
Select:
- Language to populate missing translations
- Language to get strings from
- Textgroup (or all)

nedjo’s picture

Jose Reyero’s picture

Component: Code » Blocks
Status: Postponed » Closed (won't fix)

No new features for 6.x