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
- We don't have a list of all translation strings.
- 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.
- 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
- We need a data source, a model, that tells me which current translation strings we have, and what is their context -
- 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.
- 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
- The target language cannot be on the template, that is decided by the URL. Assuming the string must support any language.
- 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 ~
wget
or whatever. Hackish, but you did say that was allowed (: