Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

HTML Setup: Enable translation in mythbackend and setup menu.

Load the mythfrontend .ts file in mythbackend to enable translation
in mythbackend's HTML server.  This uses the mythfrontend .ts files
because that is what mythtv-setup uses and the primary reason for
enabling translation in the backend is to translate the backend
setup webpages being developed.  The backend normally serves only
data, not presentation, so the backend should not normally be
executing tr() to translate messages for the user.  The HTML setup
pages are different.  We want the backend to automatically translate
.qsp and .qjs files before they are presented to the user.

This patch enables translation of the menu.qsp main menu in the HTML
setup webpages.  To enable translation in other .qsp and .qjs files,
the translatable text should be wrapped in <i18n> and </i18n> opening
and closing tags.  Only .qsp and .qjs are processed for translations,
so all .html and .js files needing translation must be renamed to
.qsp and .qjs respectively.

To rebuild the htmlstrings.h file, change to the mythtv/html directory
and run ./buildhtmlstrings.sh.  Once htmlstrings.h has been
regenerated, change to the mythtv/i18n directory and run the normal
lupdate command to pull in the strings from htmlstrings.h and allow
their translation.

Since mythtv-setup is already using the mythfrontend *.ts files for
translations, there should be no new requirements for files to be
installed on a backend server via packagers because the mythfrontend
*.ts files should already be installed on both frontends and backends.

The *.ts files have not been updated as part of this commit.  There
are some strings in htmlstrings.h which are already translated in the
existing *.ts files.  This commit can be tested by changing your
Language setting, restarting mythbackend, and looking in the HTML setup
menu at options like 'General' and 'Job Queue' which already exist in
the existing *.ts files.
  • Loading branch information...
commit ae4a014c90065e6afa02381bcc6c6a3dd0b61898 1 parent 504189d
Chris Pinkham cpinkham authored
27 mythtv/html/buildhtmlstrings.sh
View
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+BASEDIR="."
+OUTFILE="${BASEDIR}/htmlstrings.h"
+
+echo "/*********************************************************/" > ${OUTFILE}
+echo "/* This file is automatically generated by running the */" >> ${OUTFILE}
+echo "/* buildhtmlstrings.sh script which parses translatable */" >> ${OUTFILE}
+echo "/* strings from .qsp and .qjs files under the html */" >> ${OUTFILE}
+echo "/* subdirectory using getTransStringsFromFile.pl. This */" >> ${OUTFILE}
+echo "/* file should be regenerated before running lupdate in */" >> ${OUTFILE}
+echo "/* the i18n directory to regenerate the i18n/*.ts files. */" >> ${OUTFILE}
+echo "/*********************************************************/" >> ${OUTFILE}
+echo >> ${OUTFILE}
+echo "void html_strings_null() {" >> ${OUTFILE}
+
+find ${BASEDIR}/ -type f | egrep "\.(qsp|qjs)$" | while read FILE
+do
+ echo "Checking: ${FILE}"
+ ${BASEDIR}/getTransStringsFromFile.pl ${BASEDIR}/${FILE} ${FILE} >> ${OUTFILE}
+done
+
+echo " QString()" >> ${OUTFILE}
+echo "}" >> ${OUTFILE}
+
+echo "================================================================="
+cat ${OUTFILE}
47 mythtv/html/getTransStringsFromFile.pl
View
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+
+if (!defined($ARGV[0])) {
+ print "ERROR: Usage: getTransStringsFromFile.pl FILENAME\n";
+ exit -1;
+}
+
+my $inFile = $ARGV[0];
+my $baseFile = defined($ARGV[1]) ? $ARGV[1] : $inFile;
+my %strings;
+my $contents = "";
+open( IN, "< $inFile" ) || die "Can not open $inFile: $!";
+while( my $line = <IN> ) {
+ chomp($line);
+
+ $line =~ s/^\s*//;
+ $line =~ s/\s*$//;
+
+ $contents .= " ";
+ $contents .= $line;
+}
+close( IN );
+
+my @lines = split('>', $contents);
+foreach my $line ( @lines ) {
+ if ($line =~ /<\/i18n$/i) {
+ $line =~ s/<\/i18n$//;
+ $line =~ s/"/\\"/g;
+ $strings{$line} = 1;
+ }
+}
+
+@lines = split('\)', $contents);
+foreach my $line ( @lines ) {
+ if ($line =~ /qsTr\(/i) {
+ $line =~ s/.*qsTr\(\s*["']//i;
+ $line =~ s/['"]$//;
+ $strings{$line} = 1;
+ }
+}
+
+if (scalar(keys %strings)) {
+ print " /* $baseFile */\n";
+ foreach my $string ( sort keys %strings ) {
+ print " QObject::tr(\"" . $string . "\"),\n";
+ }
+}
44 mythtv/html/htmlstrings.h
View
@@ -0,0 +1,44 @@
+/*********************************************************/
+/* This file is automatically generated by running the */
+/* buildhtmlstrings.sh script which parses translatable */
+/* strings from .qsp and .qjs files under the html */
+/* subdirectory using getTransStringsFromFile.pl. This */
+/* file should be regenerated before running lupdate in */
+/* the i18n directory to regenerate the i18n/*.ts files. */
+/*********************************************************/
+
+void html_strings_null() {
+ /* ./menu.qsp */
+ QObject::tr("API"),
+ QObject::tr("Advanced Setup"),
+ QObject::tr("Backend Status"),
+ QObject::tr("Change Password"),
+ QObject::tr("Channel Editor"),
+ QObject::tr("Channel Service"),
+ QObject::tr("Content Service"),
+ QObject::tr("DVR Service"),
+ QObject::tr("Database"),
+ QObject::tr("Database Tools"),
+ QObject::tr("Expert/Dev Setup"),
+ QObject::tr("General"),
+ QObject::tr("GetRecorded() Example"),
+ QObject::tr("GetStorageGroups()"),
+ QObject::tr("Guide Data"),
+ QObject::tr("Guide Data Sources"),
+ QObject::tr("Guide Service"),
+ QObject::tr("Hardware Profile"),
+ QObject::tr("Information"),
+ QObject::tr("Job Queue"),
+ QObject::tr("Myth Service"),
+ QObject::tr("Overview"),
+ QObject::tr("Recording Devices"),
+ QObject::tr("Send a Message"),
+ QObject::tr("Server Side Scripting"),
+ QObject::tr("Setup"),
+ QObject::tr("Setup Wizard"),
+ QObject::tr("Storage Groups"),
+ QObject::tr("System Events"),
+ QObject::tr("Utilities"),
+ QObject::tr("WSDL Links"),
+ QString()
+}
62 mythtv/html/menu.qsp
View
@@ -3,23 +3,23 @@
</div>
<div id="menu">
<ul class="menu collapsible">
- <li><a href='#'>Setup</a>
+ <li><a href='#'><i18n>Setup</i18n></a>
<ul class="acitem collapsible">
- <li><a href='#' onClick="javascript:clearContent(); loadEditWindow('/setup/wizard.html', '/setup/js/wizard.js')">Setup Wizard</a></li>
- <li><a href='#'>Advanced Setup</a>
+ <li><a href='#' onClick="javascript:clearContent(); loadEditWindow('/setup/wizard.html', '/setup/js/wizard.js')"><i18n>Setup Wizard</i18n></a></li>
+ <li><a href='#'><i18n>Advanced Setup</i18n></a>
<ul class="acitem collapsible">
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('database')">Database</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('general')">General</a></li>
- <li class="indent1"><a href='#'>Guide Data</a>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('database')"><i18n>Database</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('general')"><i18n>General</i18n></a></li>
+ <li class="indent1"><a href='#'><i18n>Guide Data</i18n></a>
<ul class="acitem collapsible">
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('guidedatasources')">Guide Data Sources</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('channeleditor')">Channel Editor</a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('guidedatasources')"><i18n>Guide Data Sources</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('channeleditor')"><i18n>Channel Editor</i18n></a></li>
</ul>
</li>
- <li class="indent1"><a href='#' onClick="javascript:loadContent('/misc/placeholder.html')">Recording Devices</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('storagegroups')">Storage Groups</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('jobqueue')">Job Queue</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('systemevents')">System Events</a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadContent('/misc/placeholder.html')"><i18n>Recording Devices</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('storagegroups')"><i18n>Storage Groups</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('jobqueue')"><i18n>Job Queue</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadSetupPage('systemevents')"><i18n>System Events</i18n></a></li>
</ul>
</li>
<%
@@ -32,44 +32,44 @@
if (devMode)
{
- os.write("<li><a href='#' onClick=\"javascript:loadSetupContent('/setup/expert.html')\">Expert/Dev Setup</a></li>");
+ os.write("<li><a href='#' onClick=\"javascript:loadSetupContent('/setup/expert.html')\"><i18n>Expert/Dev Setup</i18n></a></li>");
}
%>
- <li><a href='#' onClick="javascript:loadSetupPage('password')">Change Password</a></li>
+ <li><a href='#' onClick="javascript:loadSetupPage('password')"><i18n>Change Password</i18n></a></li>
</ul>
</li>
- <li><a href='#'>Information</a>
+ <li><a href='#'><i18n>Information</i18n></a>
<ul class="acitem collapsible">
- <li><a class='menuitem' href='#' onClick="javascript:loadContent('/Status/GetStatusHTML')">Backend Status</a></li>
+ <li><a class='menuitem' href='#' onClick="javascript:loadContent('/Status/GetStatusHTML')"><i18n>Backend Status</i18n></a></li>
</ul>
</li>
- <li><a href='#'>Utilities</a>
+ <li><a href='#'><i18n>Utilities</i18n></a>
<ul class="acitem collapsible">
- <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('messagetab')">Send a Message</a></li>
- <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('databasetabs')">Database Tools</a></li>
- <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('hardwareprofile')">Hardware Profile</a></li>
+ <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('messagetab')"><i18n>Send a Message</i18n></a></li>
+ <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('databasetabs')"><i18n>Database Tools</i18n></a></li>
+ <li><a class='menuitem' href='#' onClick="javascript:loadMiscPage('hardwareprofile')"><i18n>Hardware Profile</i18n></a></li>
</ul>
</li>
<li><hr></li>
- <li><a href='#'>API</a>
+ <li><a href='#'><i18n>API</i18n></a>
<ul class="acitem collapsible">
- <li><a href='#'>WSDL Links</a>
+ <li><a href='#'><i18n>WSDL Links</i18n></a>
<ul class="acitem">
- <li class="indent1"><a href='/Myth/wsdl'>Myth Service</a></li>
- <li class="indent1"><a href='/Guide/wsdl'>Guide Service</a></li>
- <li class="indent1"><a href='/Dvr/wsdl'>DVR Service</a></li>
- <li class="indent1"><a href='/Content/wsdl'>Content Service</a></li>
- <li class="indent1"><a href='/Channel/wsdl'>Channel Service</a></li>
+ <li class="indent1"><a href='/Myth/wsdl'><i18n>Myth Service</i18n></a></li>
+ <li class="indent1"><a href='/Guide/wsdl'><i18n>Guide Service</i18n></a></li>
+ <li class="indent1"><a href='/Dvr/wsdl'><i18n>DVR Service</i18n></a></li>
+ <li class="indent1"><a href='/Content/wsdl'><i18n>Content Service</i18n></a></li>
+ <li class="indent1"><a href='/Channel/wsdl'><i18n>Channel Service</i18n></a></li>
</ul>
</li>
- <li><a href='#'>Server Side Scripting</a>
+ <li><a href='#'><i18n>Server Side Scripting</i18n></a>
<ul class="acitem">
- <li class="indent1"><a href='#' onClick="javascript:loadContent('/samples/serverside.qsp', '/samples/js/samples.js')">Overview</a></li>
- <li class="indent1"><a href='#' onClick="javascript:loadContent('/samples/recorded.qsp', '/samples/js/samples.js')">GetRecorded() Example</a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadContent('/samples/serverside.qsp', '/samples/js/samples.js')"><i18n>Overview</i18n></a></li>
+ <li class="indent1"><a href='#' onClick="javascript:loadContent('/samples/recorded.qsp', '/samples/js/samples.js')"><i18n>GetRecorded() Example</i18n></a></li>
<%
if (devMode)
{
- os.write("<li class='indent1'><a href='#' onClick=\"javascript:loadContent('/samples/storagegroups.qsp', '/samples/js/samples.js')\">GetStorageGroups()</a></li>");
+ os.write("<li class='indent1'><a href='#' onClick=\"javascript:loadContent('/samples/storagegroups.qsp', '/samples/js/samples.js')\"><i18n>GetStorageGroups()</i18n></a></li>");
}
%>
</ul>
1  mythtv/i18n/translate.pro
View
@@ -23,6 +23,7 @@ SOURCES += ../programs/mythshutdown/*.cpp
SOURCES += ../programs/mythjobqueue/*.cpp
SOURCES += ../programs/mythtvosd/*.cpp
SOURCES += ../themes/themestrings.h
+SOURCES += ../html/htmlstrings.h
TRANSLATIONS = mythfrontend_bg.ts
TRANSLATIONS += mythfrontend_ca.ts
3  mythtv/programs/mythbackend/main_helpers.cpp
View
@@ -51,6 +51,7 @@
#include "mythsystemevent.h"
#include "main_helpers.h"
#include "backendcontext.h"
+#include "mythtranslation.h"
#include "mediaserver.h"
#include "httpstatus.h"
@@ -672,6 +673,8 @@ int run_backend(const MythCommandLineParser &cmdline)
return GENERIC_EXIT_DB_OUTOFDATE;
}
+ MythTranslation::load("mythfrontend");
+
if (!ismaster)
{
int ret = connect_to_master();
Please sign in to comment.
Something went wrong with that request. Please try again.