14

I have some calls to t() in *.tpl.php files. For the sake of example, let's say I'm talking about products and product.tpl.php file.

Strings in templates are not recognized until the first time they are actually used. There was a thread on Drupal.org about that and I found it to be accurate. Sadly, if I go to, let's say, http://example.com/pl/product/200, then that string will be saved in {locales_source} table with location field set to /pl/product/200.

I need my users to be able to translate using Localization client module's on-site translation tool, so they can actually see what they are translating, having it in proper context. With source location set to /pl/product/200, the product with ID 200 is the only one on which the string is shown to be translated. And far worse, if I may be able to force users to translate on that particular product, I need them also to be able to translate to russian, and there is no product with location set to /ru/product/PID.

Is there a way to re-format location string in database, to make all strings visible on all products, all languages in l10n_client tool?

I tried setting it to:

  • ; sites/default/themes/mytheme/product.tpl.php,
  • sites/default/themes/mytheme/product.tpl.php,
  • sites/default/modules/mymodule/mymodule.module (module that generates themed data)

But it only made them invisible for the translation tool.

I'm pretty sure it's not a bug in Localization client, it shows the string where it's told this string occurred. And it seems it's "just the way it works" for Drupal 7 translation system, too - was discussed and reported already, and nothing changed. So this isn't a bug report, I just ask how to work with what we have to work with.


I'm talking about texts that have nothing to do with the data module operates on. I don't want to translate products, just template strings that have nothing to do with product itself, like Previous - Next on product image gallery template.

For example, module returns 15 thumbnails, and it is a theme's job to show 5 a time. And previous / next links needs alt and title attributes. Translated. But my module does not know that. And never should need to.

8
  • I'm not sure if I've fully understood what you want, but would crawling the site in all languages be enough? You could use eg. xmlsitemap to generate the links in multiple languages and then use wget or whatever. Hackish, but you did say that was allowed (:
    – Andy
    Jul 10, 2014 at 12:13
  • @Andy Localization Client allows users to open a bar on the bottom of a page and translate texts that appear on that page directly, when they see them. I can export all texts all right, but that's not exactly the point.
    – Mołot
    Jul 10, 2014 at 12:26
  • 1
    I remember from drupal_set_message() and dpm(), that these messages will be queued up for the next request, if called e.g. from page.tpl.php. This is because templates are usually processed quite late in a request, after messages are processed. Something similar could be the case with t() and localization client.
    – donquixote
    Jul 11, 2014 at 0:08
  • Nice question. Nice problem. Jul 11, 2014 at 21:31
  • Just a suggestion... if you wish your users to be able to translate your tpl t() strings at anytime in any language, you may extract these strings with Translation template extractor (drupal.org/project/potx) and give them the original .po , that they could translate with a tool such as Poedit ? (poedit.net). As you present these strings as a few static ones, the job would be done at one time by each translator...
    – Kojo
    Jul 15, 2014 at 18:37

4 Answers 4

5
+500

Your requirement:
In order for my site to work in multiple languages
as a authenticated user
I need to be able to translate at once any and all translation calls found in my site's codebase that were done with the t() function.

Is that requirement description even close to what you're asking for?


Crawlers

Like someone said - a crawler could theoretically go through the entire site to force the registration of all t() calls. But 1) the crawler does not know which pages to crawl; 2) we are not looking to maintain a list of pages to crawl, therefore; 3) we don't want to use a crawler, period. Eww. Just, eww. Right?


The problem

  1. We don't have a list of all translation strings.
  2. Drupal/PHP is a dynamic language unlike C which is compiled. So we cannot go and say for example: compile this entire codebase, then find me all instances of this function t(), then register those instances in the database, then translate all those registered instances of t() in one go. I don't think is an option we have on our table.
  3. A static code analysis tool would be helpless for the same reason a crawler would be helpless. I found this t() in this file. Great! What URL is it used in? What's the context?

Attacking the problem with the current tools (Drupal, and some contrib modules), and with the current constraints (relying on real-time theme calls -> template files -> t() calls), looks like a no-exit alleyway here. We might need to think a little bit out of the box.


What we need

  1. We need a data source, a model, that tells me which current translation strings we have, and what is their context -
  2. Proactive data model. The current data model is reactive (the model gets updated whenever a call to t() happens). We need a proactive data model - one in which the application takes care of looking for t() instances before they actually get executed by the customer.
  3. We need context. t() alone does not cut it - because - we do not know we are translating 'foo', but the target language we are translating to depends on the URL of where the t() occurs on. Even if we could hardcode the target language into the t() call, say, using a wrapper call, it would not work for your purposes.

I have identified some of the tools that - if we had them - would help our problem. With these tools we could go into the data model and say: give me all the strings wrapped in t() that have not been populated yet. Now insert these translations. Thank you.

And the next time the customer comes, the translations are there in place.

How would we...build these tools?


Constraints

  1. The target language cannot be on the template, that is decided by the URL. Assuming the string must support any language.
  2. The translated string cannot be on the template. The translation will reside in a database.

Now that I've given the problem more thought, and identified some challenges and constraints, I can think about looking at any solutions available out there, or at making any custom solutions.

Solution brainstorm

I need something that ties "everything" together. What about...an entity?

  • An entity can hold the product that needs to be translated.
  • Entities can provide the relation - the glue - between the product that needs to be translated, and it's context.
  • The entity can specify say, in a field, the default URL location of the product.
  • Tokens can be used to specify alternative locations (languages?) that the product will appear on.
  • Entities provide us with the proactive data model that we need, and it's context. Which in turn allows us to do thing such as: go into the database, grab all the product entities, and if the do not have a translation string for fields X, Y, and Z, create those translation strings.

When the customer then grabs /pl/product/200, you take a trip to the db, look up product 200, and grab the already existing pl translation. You have a title and caption field for that product as well? The translations should be there also.

Note that I'm being very vague and generic here in terms of what translation module you're using. You could very well end up using your own translation module - most likely this is the case. All the translations models I've seen in Drupal so far (as of D7, haven't looked at D8 yet) are reactive, not proactive.

In a nutshell

In theory, the tools to build what you need are there, entities being the key component that would tie everything together: - data (translation string), - target languages. Don't have to be on the Entity itself, preferably a taxonomy vocabulary, say for product languages. or maybe a generic taxonomy for other entities as well. - Context. The URL that the entity appears on. The URL would contain a token, and the token in turn would reference the target language taxonomy.

With those three ingredients you can say: Grab all the product entities, go to the URL alias field, get the taxonomy token, cycle through all possible term combinations, present all combinations to the current user using either a very large ugly form - or, AJAX - and multi-step forms (something like that), and as the currently logged in user translates the various languages for product 200, save those somewhere into the database

Somewhere in the database could be a Field API field in the entity, the settings field belonging to each entity (not exactly Field API, but it can still hold data), or a separate table that you use for this. I think saving the data into the Entity would keep both the code and data tidier and easier.


Building It: Possible solutions

  • D8MI (Drupal 8 Multilingual Initiative)
  • Custom code: "index" translations made available in templates by t() by programmatically querying and rendering available bundles and their related theme hook implementations.

Pseudocode

Foreach entity (of type x),
Find all languages (taxonomy or core language associated with product),
Render the entity,
- in order to detect it’s t() translation strings
- render calls theme(), which handles the multilingual presentation layer of the product, not the product data model itself.

Result:
- First call to render entity template in each language returns the default language implementation for each call.
- The t() parameters on the template are now cached in Drupal and ready for translation (for each language instance, not each product instance).
- User with “translator” role can now go to translation interface and translate all available t() parameters, for each language.
- Site owner does not need to wait for customers to visit each product page, or visit each product page manually, as this was done programmatically for him.

Open questions:
- What is the context? If I do a programatic call to theme() for each “product” entity bundle, does it record the location from which the call was made? Does it record the URL of the node? Can the “context” be altered? Where is the context recorded? What happens when you have "dynamic" templates - i.e., when you have more than one template per product and how you go about detecting those variations?

As always, theorizing and pseudocode is only good for brainstorming. But in development we'll hardly know what we're really up against until we start prototyping. So having drawn up a couple of constraints, possible solutions, and possible problems or questions - I can now proceed to implement a proof of concept or working prototype. Some of the open questions above can only be answered this way, and the earliest we prototype (regardless of success or failure), we can start answering some of those questions - or change the approach altogether. Stay tuned ~

2
  • 1
    Even without reading the whole post, that kind of answer deserves an upvote Jul 12, 2014 at 9:51
  • The point is - tool that claims it is doing just what I need for Drupal 7 exists already. It's just a problem with Drupal saving these strings with bad metadata. But I can change said metadata in db once strings are collected, no problem. I just need to know what to set them to, so the tool could see it. Or at least I believed it is what I need. And most important: I don't want to translate products, just template strings that have nothing to do with product itself, like Previous - Next on product image gallery template.
    – Mołot
    Jul 14, 2014 at 13:19
2

Ok, Spent some more time with Localization client & entity translation module to reproduce the same scenario. Since this answer is totally differnt from my previous one, adding as separate comment:

  1. The translation added for a language in one/first node is available for all nodes.

    Here is an example:

    • If I add new product of same type as nid 200 and visit the pl translation the new node(say pl/product/204), I would see the same translation string in pl/product/200.

    • Only difference is it doesn't appear in Localization client. We can ask for this feature in the module's issue queue, however it would introduce more confusion as the translation is not specific to current page and would affect all pages (i.e. both pl/product/200 & pl/product/204).

    • If the two nodes created by two different persons, and the later one wants to change the translation, then they have to use the interface translation.

  2. The string is available in Localization client for the first language you visit for the same node

    Here is an example:

    • If I add new product nid 199 and create translation for 'pl' language (nid 200) and translation for 'rs' language (nid 201), you can see the string only on 'pl' page, not on 'rs' page. Again, this looks like a restriction in the Localization client module.
1

Your approach to add the translation string on template or module file level may work for interface translation UI, but not Localization client.

Obviously when you have Russian version of the product 200, it will be a new node, say for example /ru/product/201 where you can translate using Localization client.

Just a thought: Look for a string that can be translated for all languages in interface translation UI and ask customer to translate product level when it is really necessary. Here is an example:

"This is product foo of category bar"

and if we are sure that other than 'foo' & 'bar' can be common, the we can add

$vars['product_title'] = t('This is product @product of category @category')

in preprocess.

and the .tpl.php file will be

<?php t($product_title, array('@product' => t('foo'),  '@category' => t('bar')); ?>
3
  • It's more about title texts for arrows in image rotator. My module does not care how theme will display 15 images. And theme displays 5 at a time, with "prev" and "next" arrows that needs alt and title, and needs them translated. Altering module each and every time my front-end will change is possible, but certainly should not be needed. These strings have nothing to do with module itself. Last but not least, I may be simply unaware strings in theme changed. Or not available to migrate them into module.
    – Mołot
    Jul 10, 2014 at 12:24
  • IMHO, this case should be handled in interface translation UI instead of Localization client.
    – vijaycs85
    Jul 10, 2014 at 13:06
  • Localization client aims to allow to "fix translations on your site as you see the issues." - why it shouldn't apply to template files? Strings in tpl are even more sensitive to context they appear, if anything.
    – Mołot
    Jul 10, 2014 at 13:10
1

AFAIK with the Translation template extractor you can extract the string within all your calls to the t() function.

The Translation template extractor provides a web based and a command line Gettext translation template extractor interface for Drupal as well as a reusable API to look for translatable strings and translatability errors. This tool is used under the hood at http://localize.drupal.org/ as well to serve as a parsing machine for Drupal.org project releases.

Read this How to Translate a module?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.