Please integrate support for language packs into the plugin.
This would allow plugin/ theme developers to host translations also on GitHub/ Bitbucket/ GitLab and offer automatic updates for them, independent from plugin/ theme releases.
For requested integration I would see two alternatives to make it happen:
There are pros and cons for either alternative -- and maybe there are even more ways of doing it.
However, integrating support for language packs would make it lot easier to host plugins/ themes fully on services like GitHub when also translations could be updated fully automatically without always doing a new plugin release.
I would really hope for such a support sometime soon or at least for a fruitful discussion here. Thanks in advance!
Hey David!
Unfortunately this has been around for a while #50
There are several issues, at least that I can see.
A couple of months ago I created a branch, since deleted, on trying to split out language updating. I thought about just keeping the translations in a plugin by themselves, like https://github.com/afragen/github-updater-translations
This was fine but once the file updated what to do with the translations. After I stopped working on it I had a thought about loading the textdomain for the main plugin from within the translations plugin. I haven't had an opportunity to test this theory, but if it works we might be able to do the following.
Keep a plugin that contains only the translations and code to load the translations in the main plugin's textdomain. Update the translations plugin just like any other plugin when new translations exist. If this works we could have a working system where a plugin with it's translations were 2 separately installed plugins that could easily be updated independently.
Clearly this isn't really working similarly to the Plugin/Theme Directories but it may work. Previously I was working on some code that would copy the translation files into the wp-content/languages/plugin-slug folder but ran into problems.
I would love to get this working in any fashion we can.
Thoughts?
@deckerweb let me know what you think.
Here's what I did. In the develop branch of afragen/github-updater-translations I moved all the mo/po files into /languages and added a load_plugin_textdomain() command from the main plugin file.
The main plugin file has the same textdomain and domain path as github-updater.php, though I'm not sure this is necessary
When the load_plugin_textdomain command is commented out in github-updater.php and github-updater-translations.php is activated. I can see that languages files are loaded properly. I can see this in Query Monitor.
It would seem that this would be an ideal method of decoupling language files from the primary plugin, though it would require 2 plugins be present and active if translations are used.
What do you think?
@grappler pinging you on this too.
In testing yesterday I didn't need to call load_plugin_textdomain from a hook, for some reason today I need to. Also, needed to adjust the source location.
Current develop branch of github-updater-translations seems to load correctly for me both locally and on server.
We need to data to formatted in the following format
{
"translations": [
{
"language": "de_DE",
"version": "2.5.17",
"updated": "2016-05-06 02:16:51",
"english_name": "German",
"native_name": "Deutsch",
"package": "https:\/\/downloads.wordpress.org\/translation\/plugin\/easy-digital-downloads\/2.5.17\/de_DE.zip",
"iso": {
"1": "de"
}
}
]
}
https://api.wordpress.org/translations/plugins/1.0/?slug=easy-digital-downloads
To give the information to WordPress we would need to add
$translations = array(
'translations' => array(
'language' => '',
'version' => '',
'updated' => '',
'english_name' => '',
'native_name' => '',
'package' => '',
'iso' => array(
'1' => 'de'
)
)
);
$transient->translations[] = $translations;
to https://github.com/afragen/github-updater/blob/develop/src/GitHub_Updater/Theme.php#L695
I hope this makes sense. I do not have the knowledge how we can manipulate GitHub to give the info.
@grappler thanks for the input. Isn't the idea to decouple the translation files from the plugin/theme?
The example above seems to be just about passing info about a single translation file to core.
I thought we were looking for a way to selectively add and update the entirety of a plugin/theme translation files?
In my example, this works. The translation files in the main plugin aren't referenced, instead the translation files that exist in the _Language Pack plugin_ are referenced and loaded depending upon the user's locale.
How do language packs currently exist outside of core? How are they installed/used?
Isn't the idea to decouple the translation files from the plugin/theme?
Yes
The example above seems to be just about passing info about a single translation file to core. How are they installed/used?
Yes, once core has the information about possible translations then it will install the languages that it needs when you click the button "Install translations". We just need to tell core where the zip file for the translations are.
How do language packs currently exist outside of core?
They need to exist as a zip file with a po and mo file in it.
Is there a way to get the list of files from using the GitHub API and the date it was updated? Once we get the information we can create a foreach loop and process the zip files and pass the list of translations to core.
There may be a way to scrape all the file contents of a repo and/or it's directories. But to get the individual file meta to check the last updated values will be very, very API intensive. This would require a wp_remote_get for every API query.
Even if possible it would take an excessive amount of time to complete. Given this I don't really think this is feasible. Possible maybe, but no where near performant.
This method clearly works well for the WP DIrectory but it would seem we would be better simply having a plugin specific language pack plugin. This would be loaded and updated separately.
The language pack plugin can be automatically installed as a plugin dependency using my wp_dependency_installer framework.
After running through the solution most closely matching core and my method I wonder whether it's worthwhile to pursue this.
Any more ideas?
I had a thought, if we put the properly zipped up files in an additional plugin we could get all this information without having to query the GitHub API, but the translation files would still exist in a separate plugin that would need to be activated. Seems like overkill. If your adding and activating another plugin there's less overhead to just using load_plugin_textdomain from there.
Is there any prior art for doing this outside of the official directories?
I suppose to get it to work you would need a different source then GitHub. One could have a basic PHP system which reads the zip files like Release Belt or create a plugin to have an API with the zip file and related meta data.
It may be best to close this issue as it is not really possible to do it with GitHub. May be an idea to create a SASS to support this.
Maybe we could add support so that the theme or plugin only needs to define the source of the API via a filter.
Let's not give up yet. I just had a thought about adding a JSON file to the language repo that contains the all the info required. It would mean some sort of pre-processing locally before a release.
But then we could just get the contents of the JSON file and use that to populate the translations in the update transient.
Thoughts?
That would work. Seems like a good idea.
@grappler in your example above, is the version info the the plugin/theme's version or the language file's version?
I see this as a 2 part project.
Is the translations update transient an array of every translation array above?
$translations = array(
[0] = array( 'translations' => array( 'language' => ... ),
[1] = array( 'translations' => array( 'language' => ... ),
);
$transient->translations = $translations;
I'll need some more info, but I've been thinking this shouldn't be as difficult as I originally anticipated.
is the version info the the plugin/theme's version or the language file's version?
It is the plugin version. you can see the whole json here https://api.wordpress.org/translations/plugins/1.0/?slug=easy-digital-downloads
Creating a library to zip up mo/po files and create the JSON. Is this what the zip file contains?
Yes the zip only contains the po and mo for that language.
This is how the whole data looks like that is saved in the transients for plugins.
stdClass Object
(
[last_checked] => 1473344858
[checked] => Array
(
[akismet/akismet.php] => 3.1.11
)
[response] => Array
(
[akismet/akismet.php] => stdClass Object
(
[id] => 15
[slug] => akismet
[plugin] => akismet/akismet.php
[new_version] => 3.2
[url] => https://wordpress.org/plugins/akismet/
[package] => https://downloads.wordpress.org/plugin/akismet.3.2.zip
[tested] => 4.6.1
[compatibility] => stdClass Object
(
[scalar] => stdClass Object
(
[scalar] =>
)
)
)
)
[translations] => Array
(
[0] => Array
(
[type] => plugin
[slug] => akismet
[language] => de_CH
[version] => 3.1.11
[updated] => 2016-05-12 18:04:38
[package] => https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/de_CH.zip
[autoupdate] => 1
)
[1] => Array
(
[type] => plugin
[slug] => akismet
[language] => fr_FR
[version] => 3.1.11
[updated] => 2016-08-31 16:41:16
[package] => https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/fr_FR.zip
[autoupdate] => 1
)
)
[no_update] => Array
(
[hello.php] => stdClass Object
(
[id] => 3564
[slug] => hello-dolly
[plugin] => hello.php
[new_version] => 1.6
[url] => https://wordpress.org/plugins/hello-dolly/
[package] => https://downloads.wordpress.org/plugin/hello-dolly.1.6.zip
)
)
)
Hi there!
I have to say sorry for the delay on my behalf, as the one who opened the "topic" here...! (Was sick and busy work stuff... ya know)
Thanks a lot @afragen and @grappler for your thoughts and input!
This looks really promising already!
Let's give more input on what I originally dreamed of when posting the request here, I am sorry if I was not detailed enough:
1) I mean GitHub Updater should support updating language packs for other plugins/ themes:
Example: I have some plugins here on GitHub (and many more to come!) and I want to offer my own German translations as well as other community translations of these plugins.
And just for that task I want to leverage the genius GitHub Updater plugin, and "only" host the translation files (being in a .zip or also as .mo files I don't care...) on GitHub, give GitHub Updater some notice (how, this is what we should discuss here...) and the updater plugin does all the heavy lifting then.
2) It could be done!
WooCommerce had from 2014 until end of Summer 2015 such a translations updater class built-in which used Core language pack mechanism
Also, there is an extension for EDD (I believe somewhere here on Github) that uses custom language packs within EDD's Software Licensing Add-On to offer language packs/ translations to license holders.
So really, it must be possible for GitHub Updater to somehow fetch .zip or .mo files from "somewhere" and then let the updates happen.
Of course, this could and should also be used by GitHub Updater itself for its own plugin translations! ;-)
So I hope it's much clearer for you now what I am trying to achieve.
It's a bit hard for me to express in a foreign language sometimes... :)
I have to go through all your code and examples above in more detail to figure more out of it.
Thanks, Dave :)
Hi there!
I have to say sorry for the delay on my behalf, as the one who opened the "topic" here...! (Was sick and busy work stuff... ya know)
Feel better!
Thanks a lot @afragen and @grappler for your thoughts and input!
This looks really promising already!Let's give more input on what I originally dreamed of when posting the request here, I am sorry if I was not detailed enough:
1) I mean GitHub Updater should support updating language packs for other plugins/ themes:
Example: I have some plugins here on GitHub (and many more to come!) and I want to offer my own German translations as well as other community translations of these plugins.
And just for that task I want to leverage the genius GitHub Updater plugin, and "only" host the translation files (being in a .zip or also as .mo files I don't care...) on GitHub, give GitHub Updater some notice (how, this is what we should discuss here...) and the updater plugin does all the heavy lifting then.
I believe that's what we're working towards. It would ultimately require a couple a headers in the plugins that would register the plugins with GitHub Updater for both updating and for language packs.
I see this as a 2 part process where the translation files live in their own repo and GHU parses the language repo JSON and adds the appropriate content to the update transient.
I'll also work on a PHP class to create a folder of zip files suitable for inclusion (possibly via composer) and the language pack JSON. Running this would be a local process for the maintainer of the language repo but I'll try to make it simple.
2) It could be done!
WooCommerce had from 2014 until end of Summer 2015 such a translations updater class built-in which used Core language pack mechanismAlso, there is an extension for EDD (I believe somewhere here on Github) that uses custom language packs within EDD's Software Licensing Add-On to offer language packs/ translations to license holders.
So really, it must be possible for GitHub Updater to somehow fetch .zip or .mo files from "somewhere" and then let the updates happen.
Yes, once I start work on this I'll share the branch here. I don't think GitHub Updater needs to fetch the .zip or .mo files, I think we just need to add the appropriate info to the update transient.
Of course, this could and should also be used by GitHub Updater itself for its own plugin translations! ;-)
I'm just using GitHub Updater's language files as an example.
So I hope it's much clearer for you now what I am trying to achieve.
It's a bit hard for me to express in a foreign language sometimes... :)
We've waited a long time for this, we can work our way through our own potential misunderstandings. 馃槈
I have to go through all your code and examples above in more detail to figure more out of it.
Thanks, Dave :)
You're welcome.
@grappler it seems that the EDD JSON has a different format than the Akismet array?
"translations": [
{
"language": "de_CH_informal",
"version": "2.5.17",
"updated": "2016-04-28 19:38:54",
"english_name": "(Switzerland, Informal)",
"native_name": "Deutsch (Schweiz, Du)",
"package": "https://downloads.wordpress.org/translation/plugin/easy-digital-downloads/2.5.17/de_CH_informal.zip",
"iso": {
"1": "de"
}
},
{
"language": "de_DE",
"version": "2.5.17",
"updated": "2016-05-06 02:16:51",
"english_name": "German",
"native_name": "Deutsch",
"package": "https://downloads.wordpress.org/translation/plugin/easy-digital-downloads/2.5.17/de_DE.zip",
"iso": {
"1": "de"
}
},
[translations] => Array
(
[0] => Array
(
[type] => plugin
[slug] => akismet
[language] => de_CH
[version] => 3.1.11
[updated] => 2016-05-12 18:04:38
[package] => https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/de_CH.zip
[autoupdate] => 1
)
[1] => Array
(
[type] => plugin
[slug] => akismet
[language] => fr_FR
[version] => 3.1.11
[updated] => 2016-08-31 16:41:16
[package] => https://downloads.wordpress.org/translation/plugin/akismet/3.1.11/fr_FR.zip
[autoupdate] => 1
)
)
Which format should we use?
@deckerweb
Also, there is an extension for EDD (I believe somewhere here on Github) that uses custom language packs within EDD's Software Licensing Add-On to offer language packs/ translations to license holders.
Yes, and I think you are thinking of the one that I wrote.
@afragen The JSON file for a single plugin should be same as EDD JSON as it contains all of the translations for the single plugin.
Then after the processing the multiple JSON files from different plugin you create a single array of translations for the language that the site is in of all of the plugins. Sorry my example must have been confusing with Akismet translations in two languages. I had set my to two languages that is why WordPress wanted to download the translations in two languages.
I hope this makes sense.
@grappler, if the Akismet example is is actually from the update transient how is what goes in from the EDD JSON get converted?
Another question. So only the translation files corresponding to to get_locale() should be the only ones added to the update transient?
I'm still needing to grok exactly what's going on.
The way I see this working is that as GitHub Updater parses each plugin/theme. It will get the data from the language pack repo and add the appropriate scheme into the update transient, if there's an update available.
What I don't quite understand is if the schema is to be entered like the EDD JSON, how does it end up getting converted to the $transient->translations? Where does this conversion happen? Since we normally directly modify the update transient why wouldn't we do the same thing here?
if the Akismet example is is actually from the update transient how is what goes in from the EDD JSON get converted?
What I don't quite understand is if the schema is to be entered like the EDD JSON, how does it end up getting converted to the $transient->translations? Where does this conversion happen?
We would need to manually convert it. It seems the WordPress gets all of the information in a single API request. We could possibly just have the JSON in the format that we need.
So only the translation files corresponding to to get_locale() should be the only ones added to the update transient?
Yes, you can see how it works in wp_update_plugins(). The API request includes the locals that are installed.
Since we normally directly modify the update transient why wouldn't we do the same thing here?
We would update the transient here too.
So really the schema for our _language-pack.json_ ( or whatever we call it ) will be closer to the Aksimet example, where most of the info, is created from our _class Language_Pack_Creator_ and the version number is added from GitHub Updater and then the relevant translations are added into the transient.
Is updated the mod date of one of the mo/po files or the zip of the files?
I still have to test whether a zip file inside of a repo can be downloaded from a URL. Otherwise we may have to individually add the generated zip file as release assets.
Is updated the mod date of one of the mo/po files or the zip of the files?
I suppose from both. You will only create a new zip file if there are changes to the po/mo files.
Do I need to update po/mo files if the line numbers for the strings change? That's what I have been doing.
I'm at #WCLAX this weekend, but I definitely will be thinking about the best way to implement this.
Do I need to update po/mo files if the line numbers for the strings change?
No, that is only inline documentation. The mo file does not contain that information. Like PHP code works with documentation too.
Wow, I've been doing a lot of extra work.
@grappler @deckerweb I've gotten a class Language_Pack_Maker completed and in the vendor directory. It's in preparation for loading as a composer asset. I will likely need some help to correctly create the composer.json so a PR would be good.
In order to use the library, you install it into your language pack repo. In localhost load the page at http://localhost/{language-pack-repo}/vendor/github-updater-language-pack-maker
You will need to have your .mo/.po files in a /languages directory in the repo root directory. Loading the index.php page will create the zip files in a /packages directory and create a language-pack.json in the repo root.
You should then push these changes up to GitHub.
The next part, the integration, I still have to code. More here once that's done, but you should be able to see where I'm going.
I still have to clean-up the library and add docblocks, etc.
What do you think?
This should work as your composer.json. @Rarst Can you check this? It is for this code. https://github.com/afragen/github-updater-translations/tree/develop/vendor/github-updater-language-pack-maker
{
"package": {
"name" : "afragen/github-updater-language-pack-maker",
"description" : "",
"license" : "MIT",
"authors": [
{
"name" : "Andy Fragen",
"email" : "[email protected]",
"homepage" : "http://thefragens.com",
"role" : "Developer"
},
],
"support": {
"issues": "https://github.com/afragen/github-updater-language-pack-maker/issues"
},
"autoload": {
"psr-4": {
"Fragen\\GitHub_Updater\\": "/"
}
}
}
}
I did not look at the code but the language.json. I don't think it is nessary to have the plugin name and langauge in the key. We can always change that after the integration is complete.
Looks fine-ish from quick look (don't want to go through this pretty long thread for context).
Thanks, the long post is not really related to that.
I did not look at the code but the language.json. I don't think it is nessary to have the plugin name and langauge in the key. We can always change that after the integration is complete.
You may be correct that it would be safer to add the plugin name during the integration.
Isn't the language necessary in the key? It's much easier to add it here and I'm not sure there's any way to add it after this step.
The integration will involve adding a header, GitHub Languages, and GitHub Updater would parse that and create the package download links, grab the version number, and declare the type. It would then add this array to the update transient.
At least that' how I see it working.
So I've finished the Language Pack Maker and submitted it to Packagist.
Add it to your language pack repos via composer require afragen/github-updater-language-pack-maker
As an example, see GitHub Updater translations. The vendor file has not been uploaded.
Next up the integration in this plugin.
@deckerweb @grappler if you can test for me I think I have it set up for GitHub only right now. Use the branch switcher to change to branch translations.
GitHub Languages: https://github.com/path_to_translation_repo to the plugin/theme repo.language-pack.jsonIn my testing, I saw a translation update but the it said download failed, even though when put in a browser window, the download succeeds. This may be because of the way I was testing.
Let me know if you have questions or problems.
Update - I just reworked the download link and it installed the language files appropriately. 馃挴
Odd, in testing, the translations only update from update-core.php. They update automatically if the plugin/theme with the translations is updated or if the translations are updated before the plugin/theme is updated.
It doesn't appear that translations update along with the plugin/theme when using shiny updates ( from themes.php or plugins.php ). I've only tested with themes.
@deckerweb @grappler has anyone been able to test?
Any feedback?
Any help needed?
Sorry, I have not been able to test it yet. I don't really have a project I can test it on. Switched to composer now! 馃槃
I will test your plugin in the morning.
Also let me know if the instructions are clear or if the process could be made simpler.
I also added a .gitignore that hides the vendordirectory in my language pack repo. It just looks cleaner and doesn't seem needed upstream.
Hi again!
Thanks for the heads up, I will test it this week definitely!
Anyone able to test? Thoughts?
@afragen Sorry for the delay. It was not working for me and I wanted to find the bug. At the moment the the language updates only work if there is plugin update if there is no update then the translation do not get added to the transient. This is caused by can_update() in pre_set_site_transient_update_plugins(). The language pack code/updates need to separate from the plugin/theme updates.
Ok, I'll need to rewrite some code to bring the language packs transients into its own function. This will likely happen in class Language_Pack.
I will need to add a theme/plugin designation in the Language Pack Maker as this would then be independent from the plugins/themes.
We will need some way to determine a newer language pack is available. Any thoughts?
What's not working? Can you point to the repo?
We can require a package.json file in the translation repo that contains the "type": "theme" or "type": "plugin" and even the slug.
The real problem I see is how to designate when an update in needed.
At the moment the the language updates only work if there is plugin update if there is no update then the translation do not get added to the transient. This is caused by can_update() in pre_set_site_transient_update_plugins(). The language pack code/updates need to separate from the plugin/theme updates.
I can change this by moving the code to add the translations outside of the can_update() but then the language update will always show.
How would we tell when a translation file is up to date or not?
@grappler I re-worked how/where translations are added to the update transient. https://github.com/afragen/github-updater/commit/3e4b759c1ad4c14cfda8a01fe7606cabc8494282
Downside is that translations will always show as needing update.
Update use branch switcher to update translations branch.
How would we tell when a translation file is up to date or not?
You can use wp_get_installed_translations() like core does. This should return the modified date of the po file and then you can compare it with the date that you have in the JSON file.
I checked locally and the mod date of the translation.mo file is the date of install. Given that I'm not sure it'll work, but I'll see.
wp_get_installed_translations() gets the modified date from the po headers.
@grappler I think that's the key. I've updated the translations branch and I've updated the Language Pack Maker.
To test you will need to composer update your language pack repo and do a branch switch update to the translations branch.
Let me know how it works for you.
I got the PHP notice: Notice: Undefined index: github-updater in github-updater/src/GitHub_Updater/Language_Pack.php on line 98
The latest commit did not seem to fix it. I think you also want to use $locales = array_values( get_available_languages() ); to get the locales as currently the system would not work on multilingual sites.
P.S Why is there a en_US translation?
The latest commit allows the plugin to work correctly.
I didn't think about multilingual sites. So get_locale switched for array_values( get_available_languages() )
I didn't see a PHP notice but I'll see about fixing it.
There's an en_US translation just so I could actually see something loading.
Now I need to start working on Bitbucket and GitLab. 馃槀
Just to confirm, you're still getting a PHP notice on line 98.
I think you also want to use $locales = array_values( get_available_languages() ); to get the locales as currently the system would not work on multilingual sites.
This returns an empty array for me with en_US. Can you give an example of what it should produce?
Is there a reason for using array_values()?
From source it appears the return value of get_available_languages() is either an empty array or an unordered array.
Isn't array_values() then repetitive?
I think you also want to use $locales = array_values( get_available_languages() ); to get the locales as currently the system would not work on multilingual sites.
See if https://github.com/afragen/github-updater/commit/7458b875d205014dd1a117746b10f263af8ed2cb doesn't work for multilingual sites.
There's an en_US translation just so I could actually see something loading.
Ok, I suppose you could understand en_GB 馃槃
All of the needed languages are being downloaded on the multilingual site. 馃帀
I am only getting these two errors at the moment.
Notice: Undefined property: stdClass::$en_GB in /plugins/github-updater/src/GitHub_Updater/Language_Pack.php on line 99
Notice: Trying to get property of non-object in /plugins/github-updater/src/GitHub_Updater/Language_Pack.php on line 99
Notice: Undefined property: stdClass::$en_GB in /plugins/github-updater/src/GitHub_Updater/Language_Pack.php on line 99
Notice: Trying to get property of non-object in /plugins/github-updater/src/GitHub_Updater/Language_Pack.php on line 99
https://github.com/afragen/github-updater/commit/569a30e87046dcb28b131392044521d6d61f1d82 should fix this error.
I did delete a couple of my errant comments about this PHP notice.
There's an en_US translation just so I could actually see something loading.
Ok, I suppose you could understand en_GB 馃槃
But I don't have a translation in afragen/github-updater-translations for en_GB 馃槣
Is anything left broken?
And it works perfectly! Just need to test a theme for this just to be sure. Do you know of a theme that we could help set up with this so to be able to test a proper theme?
ping @fxbenard
All you would have to do is take an existing theme and create a language pack repo similar to afragen/github-updater-translations. There's functionally no difference between a theme language pack and a plugin language pack. The code will differentiate between them. 馃憤
Let me know, I'd like to test too. Now I guess I'll have to get working on the Bitbucket and GitLab code. Though once tested I'll release this as just GitHub only.
I would rather that the time spent setting up the language pack repo will be of use to someone instead of just doing it to test the code. I don't have any plugins or themes that use GitHub Updater 馃槥
I would rather that the time spent setting up the language pack repo will be of use to someone instead of just doing it to test the code. I don't have any plugins or themes that use GitHub Updater 馃槥
I agree and no time like the present to make one. 馃槃
Bitbucket Language Packs now working. https://github.com/afragen/github-updater/commit/d06834abfc07802255948c05b3a67ac16d4e60e0 馃憤
GitLab Language Packs should now work. https://github.com/afragen/github-updater/commit/fa87b7318e2a477a1cd2e987f80d51d2fba97e2a 馃憤
Time for 馃挙
Read this thread from top to bottom. Thanks @afragen for all your hardwork.
Merged into develop. If you update translations it will automatically switch you back to the develop branch. 馃憤 https://github.com/afragen/github-updater/commit/6bfd20001bbf5738c4e8f5b00a7803cb48a86984
The develop branch is now dogfooding this.
Merged into v6.0.0
Most helpful comment
wp_get_installed_translations()gets the modified date from the po headers.