Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#1 2020-06-28 07:33:40

gomedia
Plugin Author
Registered: 2008-06-01
Posts: 1,242
Website

Textpacks in cached plugins

I’m looking at converting some plugins to the new Textpack system (TXP 4.7+).

Can someone confirm for plugins loaded from the plugin cache, that their textpacks are loaded in as well? Had a conversation about this a while ago.

I’m using zem_plugin_example to test this on TXP 4.8.1 but the language strings are not being loaded. On the admin panel for this plugin I see “zem_type_something” rather than “Type something:”.

Offline

#2 2020-06-28 09:40:00

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 9,468
Website

Re: Textpacks in cached plugins

They do indeed load, and switch multiple languages when the admin language changes.

Here’s an example for smd_at_work:

#@owner smd_at_work
#@language en, en-gb, en-us
#@admin-side
smd_at_work_admin_message => Website is in <a href="{url}">Maintenance Mode</a>
#@prefs
smd_at_work => Maintenance mode
smd_at_work_enabled => Maintenance mode enabled
smd_at_work_message => Maintenance message
#@language fr
#@admin-side
smd_at_work_admin_message => Le site est en <a href="{url}">mode de maintenance</a>
#@prefs
smd_at_work => Mode de maintenance
smd_at_work_enabled => Activer le mode de maintenance ?
smd_at_work_message => Message de maintenance

BUT there’s still a subtle bug – even in the upcoming 4.8.2 – (see issue) that means register_tab doesn’t have access to gTxt() content from cached plugins when the menu is drawn. This means that plugins such as smd_bio running from the cache don’t have their tab names localised, and thus have an untranslated string in the menu bar. If the plugin’s installed, it’s fine because the strings are in the database and are pulled in immediately. Searching for a solution.

All the remaining strings on the plugin’s panel are fine, though. If you post your Textpack here, and mention how the strings are being used, we might be able to figure out why things are not working for you.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#3 2020-06-28 11:02:30

gomedia
Plugin Author
Registered: 2008-06-01
Posts: 1,242
Website

Re: Textpacks in cached plugins

Hi Stef,

Thanks for replying. The example plugin has this embedded:

$plugin['textpack'] = <<< EOT
#@public
#@language en-gb
zem_greeting => Hello,
zem_default_name => Alice
#@language de-de
zem_greeting => Hallo,
zem_default_name => Elise
#@test
#@language en-gb
zem_type_something => Type something:
#@language de-de
zem_type_something => Schreibe etwas:
EOT;

And having looked at your example, I’ve found the problem. Changing the language statement from en-gb to en (to match the default admin language) fixes my problem. But obviously en, en-gb, en-us is the way to go.

Perhaps a tweak to zem_plugin_example.php, to make it work out of the box, might stop stupid people getting flustered!

As always, I am in your debt.

P.S. Did I read in some TXP code comments somewhere that owner is critically endangered?

Offline

#4 2020-06-28 12:38:07

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 9,468
Website

Re: Textpacks in cached plugins

Good catch on the example file. Sorry for the hassle, I’ll tweak that.

If there’s a comment somewhere about owner being killed off, it wasn’t me. I went to great lengths to have it supported in 4.7+ so you could collect together strings per plugin or even entire swathes of all strings for all plugins under adi if you prefer that approach. Use the field however you feel most comfortable.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#5 2020-06-28 22:02:05

gomedia
Plugin Author
Registered: 2008-06-01
Posts: 1,242
Website

Re: Textpacks in cached plugins

This is from Lang.php:

// For the time being, load any non-core (plugin) strings on every
// page too. Core strings have no owner. Plugins installed since 4.6+
// will have either the 'site' owner or their own plugin name.
// Longer term, when all plugins have caught up with the event
// naming convention, the owner clause can be removed.

… but perhaps I’m misunderstanding the meaning.

And just to abuse your hospitality a bit more. Short of using a crowbar, is there a subtle way of accessing language strings that are now hidden behind event walls? For example, install_textpack.

Last edited by gomedia (2020-06-28 22:02:17)

Offline

#6 2020-06-28 23:37:54

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 9,468
Website

Re: Textpacks in cached plugins

gomedia wrote #324079:

For the time being, load any non-core (plugin) strings on every page…

Yeah, that’s not the most descriptive comment ever. So here’s the thing. From 4.7 onwards there were several changes to the way strings were managed, brought about because of the fact loading strings was one of the highest consumers of RAM and time. A recap:

  • Language designators were shortened to be less opinionated about their country. Older lang codes such as fr-fr automatically fall back to fr.
  • en became the new default language rather then en-gb.
  • Strings were grouped better into their events so the number of strings per page could be reduced to only those strings that were needed on a particular panel.
  • A new [admin-side] group was introduced for any string that could be used on more than one panel. This includes all ‘tab’ menu items, plugin menu items, and the strings that we reuse.
  • Any string that could appear on both admin-side and public site is housed in [common].
  • Any strings that were exclusively for the public site or for public tags, now reside in [public].
  • All packs were served locally from the lang directory instead of via RPC.
  • Plugin Textpacks are stashed in their entirety in the txp_plugin table along with the code and help and so forth. This has the benefit that if someone subsequently installs a new language that your plugin has a translation for already, it gets automatically pulled from there into the txp_lang table. Previously, if you had five languages in your plugin Textpack, only the one that was currently being used at the time of plugin install would be put in the txp_lang table. If you then added languages later, you’d have to manually get the pack from the plugin file and install it yourself. No more such hoops!
  • For plugins running from cache, all strings are loaded on-the-fly from the plugin file and merged with those loaded from the lang table into RAM. On every page load, your strings are pulled in and merged. The caveat being that current bug with the ‘tab’ that doesn’t get loaded in time for the menu to be drawn.
  • The owner field can be used for your own purposes. If omitted, then all non-core strings will be labelled with owner = ‘site’. Core strings have no owner so they are easy to distinguish. As I alluded to above you can use the owner to collect together strings for a single plugin that may span multiple events (so it’s easier to remove them when a plugin is uninstalled, for example) or you can simply ‘brand’ all your strings with, say, your plugin prefix. Not quite as flexible if you want to clean up an individual plugin’s strings that may be in multiple event groups, but if you wanted to have a single “all my plugin strings” management plugin then this might be quite handy. P.S. see smd_babel.
  • We decided it was an unreasonable expectation to have all plugins with their Textpacks aligned/events grouped properly/language designators correct/owners set with the 4.7 changes above from day one. So what we currently do in the Lang class is widen the net so that all plugin strings are loaded on all panels at all times. In other words, not just the ones designated for particular events.

That last point is what the code comment is about. It’s a note-to-self that in some far-off distant future Textpattern version when the majority of admin plugins have caught up with the new designators and are nicely segregated into their events and have [admin-side] where necessary, yahde yahde, that we can remove the clause in our WHERE statement to only load the plugin strings on their nominated events. On that day, we’ll get a yummy RAM reduction on the admin side – with the amount of RAM reduced by the number of admin plugins a site has installed.

Does all that make sense?

Short of using a crowbar, is there a subtle way of accessing language strings that are now hidden behind event walls?

Certainly. The language class simply preps and loads into memory a single array (previously global $textarray though that’s still around for legacy reasons) of all strings in scope for the current panel (plus, currently, all plugin strings). You can get the current set:

$allLoadedStrings = Txp::get('\Textpattern\L10n\Lang')->getStrings();

If you want to overwrite or add strings to those that are available on this page run, simply prep an array of key => translation pairs and throw it at setPack():

Txp::get('\Textpattern\L10n\Lang')->setPack($myStrings, true);

The second argument there tells it to merge your strings with those there already. Otherwise, it blats the currently loaded string set entirely and replaces it with yours. It’s all temporary: no table or disk wrangling. Just memory.

Other things you can do now include calling Lang->getPack() to fetch a bunch of strings in the nominated language for a given list of events, but these can be in any language – not just from those installed. There’s a performance penalty here because it goes back to disk to fetch these but if you’re running on an SSD that point is largely moot.

Lang->installTextpack() is not really designed for custom use, but it could be. That’s what the Admin>Languages panel uses when you paste a pack into the textarea.

The rest of the methods in the class like extract(), load() and txt() etc, are mainly for core use to set up the environment. But you could use extract() for example to fetch a bunch of installed strings from a list of events for your own use. Maybe to merge into the current strings with setPack().

From 4.8.2 you’ll also be able to swap in other languages on a temporary basis, which might be handy for local overriding:

Txp::get('\Textpattern\L10n\Lang')->swapStrings('fr', 'admin, common, prefs, article');

That will:

  • Stash the current string set.
  • Go and fetch all strings from those four event groups in the nominated (installed) language.
  • Merge them with the current language pack.

You can then do your stuff with those new strings in place, render localised content, whatever. When you’re done, issue:

Txp::get('\Textpattern\L10n\Lang')->swapStrings(null);

which will swap the stashed strings back in. Interestingly – and pursuant to your question – it does a merge here, so if you’ve fetched any additional events they will still be there after the swap back.

Although this feature is designed for overriding the current language with another, there’s nothing to stop you abusing this to merge in events outside of the ones loaded in the same language as currently in use.

Lots of stuff you can do. It’s a lot more flexible than it used to be! Hope some of this splurge helps.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#7 2020-06-29 10:13:04

gomedia
Plugin Author
Registered: 2008-06-01
Posts: 1,242
Website

Re: Textpacks in cached plugins

Hi Stef,

As always your explanation are epic and comprehensive! Much appreciated.

Txp::get('\Textpattern\L10n\Lang')->setPack($myStrings, true);

- this is great! It means I can lose a function, a global var, the textarray gymnastics, as well as reverting back to using gTxt().

Shame it’s not possible to cherry-pick individual strings & translations though. As Lang->getPack() accesses the database as well as returning multiple translations (as does extract()), I’ll stick with my original crowbar (it does db reads as well) but can target individual translations.

All the best,

Adi

Offline

#8 2020-06-29 11:10:03

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 9,468
Website

Re: Textpacks in cached plugins

gomedia wrote #324086:

Shame it’s not possible to cherry-pick individual strings & translations though.

What’s your use case? Perhaps if I can get a handle on what it is you’re trying to do, we can tweak the Lang methods (or introduce new ones) that would help.

For example, if you wanted to cherry pick from the currently loaded strings then we could add a param to getStrings() that allowed you to filter out the strings you wanted to see.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

#9 2020-06-29 11:56:22

gomedia
Plugin Author
Registered: 2008-06-01
Posts: 1,242
Website

Re: Textpacks in cached plugins

The bottom line is: I would like to access any language string individually, regardless of event, and make it available to a plugin. This way I’m avoiding reinventing the translation wheel, if TXP already has useful phrases set up. Phrases which used to be free for everyone!

Let’s say, for the sake of argument, I need the phrase (in English) “No preferences available.”. However, gTxt('no_preferences') in a plugin will simply return the key back because it belongs to event prefs.

I know getPack() & extract() will pull in all strings for a particular event, but what they provide is not a simple key => translation array.

Perhaps a function update so the required key or keys could be supplied & the simple key => translation array returned. This could then be fed straight into my new favourite setPack() function. Not sure if an event would be required as well, but that wouldn’t be a problem.

At the moment I’m doing my own db rummaging through txp_lang to get what I’m after. No big deal at the end of the day however!

Offline

#10 2020-06-29 16:12:12

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 9,468
Website

Re: Textpacks in cached plugins

gomedia wrote #324088:

The bottom line is: I would like to access any language string individually, regardless of event, and make it available to a plugin. This way I’m avoiding reinventing the translation wheel, if TXP already has useful phrases set up. Phrases which used to be free for everyone!

Yes, this is actually an important consideration. I’ve just pushed a commit to 4.8.2 which permits an additional parameter to both getPack() and extract(). The third $filter param will return only the strings for the list/array of keys you supply.

I appreciate that getPack() returns a multi-dimensional array of stuff about each string, but extract() doesn’t. You just get key=>translation pairs back. So with these newfound powers you can:

  1. Use getPack() to pull out metadata and strings from any language we support (from files on disk), in any group(s) you want and to then optionally only grab a subset of those records.
  2. Use extract() to pull out key=>translation pairs from any installed language (from those in the database), in any group(s) you want and to then optionally only grab a subset of those strings.

The latter can be injected straight into setPack() to augment the available strings to ones in other ‘events’ that used to be available to all. I don’t see many plugins wanting to add strings from languages that aren’t installed, so the fact `getPack()` doesn’t return a nice simple array is not a deal breaker. If you really need this functionality, then iterating over the multi-dimensional array or using array_column() works:

$additionalStrings = array_column($stuffFromGetPack, 'data', 'name');

The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Online

Board footer

Powered by FluxBB