Writing MLP-Ready Plugins.
Localised strings
If you want to allow users to edit your plugins’ strings using the string editing features of the new MLP Pack then you need to take a few extra steps to get your plugins into shape for the task.
Don’t worry, this will not make your plugins dependent upon the MLP Pack being present in an installation in order for it to work—it will work just fine without the MLP Pack.
Here are the steps…
- Have an internal array of named strings.
- Register a callback routine.
- Write your callback routine—copy the example routine from the code that follows changing details as needed. This will pass your array of strings to the MLP pack and register them as owned by your plugin.
- Write, or modify the example, plugin-specific gTxt() function that…
- tries to get the string from the $textarray and if that fails,
- tries to get the string from it’s private array and if that fails,
- returns the name of the string you were trying to access.
- does any variale substitutions that are needed
- Use the specific gTxt() function consistently throughout your pluign.
Here is an example you can use for study…
| # | Code |
|---|---|
| 0001 | /*------------------------- PART 1: Define the strings -----------------------*/ |
| 0002 | |
| 0003 | # |
| 0004 | # Define the string that will get prefixed to your strings when they are |
| 0005 | # injected into the txp_lang table. |
| 0006 | # |
| 0007 | # Keep it less than 10 chars. |
| 0008 | # Change both parts of the define for your plugins. |
| 0009 | # |
| 0010 | define( 'SED_EXAMPLE_PREFIX' , 'sed_xmpl' ); |
| 0011 | |
| 0012 | |
| 0013 | # |
| 0014 | # Define the array of strings. |
| 0015 | # |
| 0016 | # Change the name and content of the array for your plugin. |
| 0017 | # Variable substitutions will be done in your gTxt() routine, not here. |
| 0018 | # |
| 0019 | $sed_example_strings = array( |
| 0020 | 'string1' => 'Welcome {name}!', |
| 0021 | 'string2' => 'See you again {time}.', |
| 0022 | ); |
| 0023 | |
| 0024 | |
| 0025 | |
| 0026 | /*------------------------ PART 2: Register A Callback -----------------------*/ |
| 0027 | |
| 0028 | # |
| 0029 | # Register the callback for the enumerate string event. |
| 0030 | # If the MLP pack is not present and active this will NOT get called. |
| 0031 | # |
| 0032 | register_callback( 'sed_example_enumerate_strings' , 'l10n.enumerate_strings' ); |
| 0033 | |
| 0034 | |
| 0035 | /*---------------------- PART 3: Registration Callback -----------------------*/ |
| 0036 | |
| 0037 | # |
| 0038 | # Here's a callback routine used to register the above strings with |
| 0039 | # the MLP Pack (if installed). |
| 0040 | # |
| 0041 | function sed_example_enumerate_strings($event , $step='' , $pre=0) |
| 0042 | { |
| 0043 | global $sed_example_strings; |
| 0044 | $r = array ( |
| 0045 | 'owner' => 'sed_example_plugin_name', # Change to your plugin's name |
| 0046 | 'prefix' => SED_EXAMPLE_PREFIX, # Its unique string prefix |
| 0047 | 'lang' => 'en-gb', # The language of the initial strings. |
| 0048 | 'event' => 'public', # public/admin/common = which interface the strings will be loaded into |
| 0049 | 'strings' => $sed_example_strings, # The strings themselves. |
| 0050 | ); |
| 0051 | return $r; |
| 0052 | } |
| 0053 | |
| 0054 | /*--------------------- PART 4: Plugin Specific gTxt() -----------------------*/ |
| 0055 | |
| 0056 | function sed_example_gTxt( $what , $args = array() ) |
| 0057 | { |
| 0058 | global $textarray; |
| 0059 | global $sed_example_strings; |
| 0060 | |
| 0061 | # |
| 0062 | # Prepare the prefixed key for use... |
| 0063 | # |
| 0064 | $key = SED_EXAMPLE_PREFIX . '-' . $what; |
| 0065 | $key = strtolower($key); |
| 0066 | |
| 0067 | # |
| 0068 | # Grab from the global textarray (possibly edited by MLP) if we can... |
| 0069 | # |
| 0070 | if(isset($textarray[$key])) |
| 0071 | { |
| 0072 | $str = $textarray[$key]; |
| 0073 | } |
| 0074 | else |
| 0075 | { |
| 0076 | # |
| 0077 | # The string isn't in the localised $textarray so fallback to using |
| 0078 | # the string array in the plugin (which is not prefixed.) |
| 0079 | # |
| 0080 | $key = strtolower($what); |
| 0081 | |
| 0082 | if( isset( $sed_example_strings[$key] ) ) |
| 0083 | $str = $sed_example_strings[$key]; |
| 0084 | else |
| 0085 | # |
| 0086 | # Fallback to returning the key if the string is not present... |
| 0087 | # |
| 0088 | $str = $what; |
| 0089 | } |
| 0090 | |
| 0091 | # |
| 0092 | # If needed, perform substitutions... |
| 0093 | # |
| 0094 | if( !empty($args) ) |
| 0095 | $str = strtr( $str , $args ); |
| 0096 | |
| 0097 | return $str; |
| 0098 | } |
| 0099 |
Gettng Localised Data
The MLP Pack creates tables with localised content in them from the master textpattern table. The pack then uses a table-name remapping on the public interface to serve language specific content to plugins through the DB layer.
This remapping is not done on the admin side.
Although a language-specific temporary textpattern table could have been created to hide the original textpattern table for each client connection this would put a continuous un-needed load on the server so the MLP pack maintains a set of copies of the textpattern table—one table per site language— and then relies on a simple function to remap any queries against the ‘textpattern’ table to the copy with content in that language.
If your plugin uses any of the safe_blah() functions (except safe_query) or the fetch() routine; then this will happen without your needing to do anything special.
However, if your plugin accesses the textpattern table via a call to safe_query() or any of the other routines in txplib_db.php then it will work, but will potentially retreive rows for languages that the site visitor is not using.
To get around this you can make a few simple adjustments…
a) use the built-in DB access functions found in textpattern/lib/txplib_db.php rather than going to the DB via PHP’s MySQL access routines.
b) Don’t use the PFX constant.
Huh? Yes, if your plugin is meant for TxP 4.0.4 or above then this is easy as you can simply switch all PFX prefixing over to the safe_pfx() or safe_pfx_j() routines. The MLP Pack currently uses these to do some crafty table name changing to give access to localised content.
For plugins that need to work in TxP versions prior to 4.0.4 and you use the PFX constant then you can use the following routine to prefix your tables (and redirect to localised tables if the MLP Pack is present)...
| # | Code |
|---|---|
| 0001 | /*============================================================================== |
| 0002 | EXAMPLE CODE |
| 0003 | |
| 0004 | Here is an example skeleton that meets the above requirements. |
| 0005 | |
| 0006 | I am using the prefix sed_example_ here for my routines but you *must* change |
| 0007 | that for your own plugins. |
| 0008 | ==============================================================================*/ |
| 0009 | |
| 0010 | function sed_example_pfx( $table ) |
| 0011 | { |
| 0012 | if( is_callable( 'safe_pfx' ) ) |
| 0013 | $table = safe_pfx( $table ); |
| 0014 | else |
| 0015 | $table = PFX.$table; |
| 0016 | |
| 0017 | return $table; |
| 0018 | } |
| 0019 | |
| 0020 | (Remember to rename the function according to your plugin's naming convention). |
| 0021 |
Now use this call whenever you need to construct the name of a table for a call to safe_query().
Or…
c) Try not to use the safe_query() routine but rather use the specific routines for the operations you are trying to perform (this is not possible for all queries)
For example, instead of doing…
safe_query( "select * from ".PFX."textpattern where `ID`='$my_id'" );
either use your prefix routine…
$table = sed_example_pfx( 'textpattern' );
safe_query( "select * from $table where `ID`='$my_id'" );
or use a more specfic access routine…
safe_row( '*', 'textpattern', "`ID`='$my_id'" );