Skip to content

Enhance add Gui Translations#1334

Closed
SlySven wants to merge 13 commits intoMudlet:developmentfrom
SlySven:Enhance_addGuiTranslations
Closed

Enhance add Gui Translations#1334
SlySven wants to merge 13 commits intoMudlet:developmentfrom
SlySven:Enhance_addGuiTranslations

Conversation

@SlySven
Copy link
Copy Markdown
Member

@SlySven SlySven commented Oct 14, 2017

Right this steaming pile of code represents my reworking of https://github.com/SlySven/Mudlet/tree/enhance_refactorForI18n (that was left to fester in a dark place a couple of years ago) and this should go pretty far towards the framework needed to use languages other than English (American) for the User Interface, it includes partial translation files (both source ./src/mudlet_xx_YY.ts and binary ./src/mudlet_xx_YY.qm) for:

  • en_US (American English)
  • en_GB (British English)
  • fr_FR (France French)
  • de_DE (German German)
  • ru_RU (Russian Russian)
  • zn_CN (Simplified Chinese)

screenshot_20171012_045042

At present the .qm files need to appear to be in the same directory as the mudlet executable for Linux and Windows builds - I left some macOs defines in place which will not help. Currently, if no suitable files are found on start-up the control to switch on translation/change language will be disabled:
screenshot_20171012_051809

During development I have found it is enough to set up some symbolic links to the ./src/mudlet_xx_YY.qm files from the "build" directory where the mudlet executable is built then you will get:
screenshot_20171012_052251

For demonstration purposes the most obvious (and "complete"; although that complete is only in terms of the %-age of entries - the translation quality is probably 💩 !) language to try is French. Note that that control is filled with entries in the language of the particular language itself as nothing else makes sense from a UI point of view; as a help for this the tool-tip for that control is a special one in that it is NOT translated but instead contains a series of texts all saying the same thing but in a range of languages...
screenshot_20171012_053317

There are a couple of External commands that are included in the Qt Creator IDE by default that seem to be to do with:

  • extracting the QStrings that need to be translated from various locations in the source code {lupdate - produces/updates .ts files which are XML files}
  • convert the translation data in .ts files into the binary .qm files that are needed by the application at runtime to provide the data needed in a particular language

however as provided the first one reads the TRANSLATIONS variable in the qmake project file and processes all the languages to produce what are full translation files with every QString in - for the English (American) language, as the source code is already in that language it produces a much larger file than is needed, and by running the lupdate command with an existing mudlet_en_US.ts file it can be made much simpler with the additional -pluralonly option that only picks out the cases where the %n parameter is used to specify a (usually integer but it need not be) 3rd argument to the QObject::tr() method which enables the handling of all the different plural forms for those many languages where adding an s if there is more (or less) than one article is just plain wrong!

also, the second command has a useful option - that is not used by the default configuration in Qt Creator - that will mark a case where there is not a "finished" translation in place for the particular QString instance, which, when debugging a translation, or where the source code string has been modified (which invalidates the translations based on it) can be prefixed in the application to flag it as something that needs attention.

Anyhow, I have included in this PR a couple of simple *nix shell scripts which can be added to the Qt Creator "External" tool list, the first one is unix_lupdate.sh and you can set it up like this:
screenshot_20171014_041748

It takes one argument - the location of the current Qt library version's bin directory so it knows which version of lupdate to run - and it will cycle through all the mudlet_xx.ts and mudlet_xx_YY.ts files, updating them (whether mentioned in the qmake project file or NOT) in the mudlet /src directory and pick out the mudlet_en_US.ts for the special plurals only treatment.

The other script unix_lrelease.sh also takes the same path to wanted binaries argument and if run like that it will regenerate all the mudlet_xx.qm and mudlet_xx_YY.qm binaries but by default it will include a # prefix on all the unfinished translations - as does QLinguist when it is previewing a form/dialogue. However you can change this with an optional second argument, I have been using ~ to use a different marker, to suppress any prefix supply an empty string "" as a second argument.

The work flow when C++ coding is:

  • write/modify source which changes a QObject::tr(...) or other translatable QString
  • run lupdate or my unix_lupdate.sh script - by default they will not "throw away" obsolete translations i.e. ones where the source string in the tr(...) command is changed so it will not dump already worked out translations (there is a command line option to do so, but it is an all-or-nothing action though it is possible to hand edit EVERY .ts file if it is vital that a really wrong (accidentally obscene source text word :devil:) thing has to be purged, but that is not a thing to be undertaken lightly!
  • run QtLinguist and enter a translation for the languages you are invested in/investigating, if happy with it, mark the translation as "finished" (will have a green or yellow tick)
  • run lrelease or my unix_lrelease.sh script
  • run mudlet and select the language (if it is not already the one that was stored as being set)

We will probably have to discipline ourselves in making commits to the .qm files stored in the repository - it may be useful to hash out a system where developers can keep a local "working" copy of a set of .ts/.qm files if they are working on GUI stuff that will hit translated QStrings

In passing I would note that I have addressed the "other licences" issue #1273 herein.

This is a big one - please ask questions if something doesn't make sense - I regret that the main commit message is a bit of a mess as the code evolved over time and I lost some stuff and had to retrieve it from the equivalent to the git rubbish bin.

ToDo list:

  • - insert "debugger option" to specify/override where to look for mudlet_xx_YY.qm files at runtime {and improve handling of different Os wanting them in different places at the same time; needed for macOs based developers...}
  • - do a working 3.4+ version of (release 30)bug fix get splitter working properly on editor right side #436 and merge it in , as having reformatted the help messages for (completely) empty types items in the editor the fixed size widget at the top of the screen is no longer big enough to display the, now arranged into an HTML list, set of instructions for some types.
  • - add a command line argument to set/change the language from the command line, to provide a get-out if the user really cannot navigate to the setting from the start (or after installation) and they have fouled it up and need to adjust the setting.

Adds a control to the preferences dialog that allows a different
translation (*.qm) file to be loaded for the main application - and the
Qt libraries themselves - to change language.

Also inserts some initial translation source and compiled files that I have
been using to test GUI language change features for British-English and
French-French they are not complete but do show the effects of changing
language - in the interests of supporting other Mudlet developers with
their own language interests there are also even less well populated
Russian, German and Simplified Chinese but it is fairly painless to add
others - there are some notes in the mudlet.pro project file and the
dlgProfilePreferences constructor.

Also inserts code into some other classes to respond to
QEvent::LanguageChange:
* TConsole
* dlgIRC

In passing found that there is no need for a separate "enable spellchecking"
checkBox in the same tab of the options/preferences dialog as the GUI
language change option is placed as the same effect can be achieved by
the intrinsic checkbox that all groupBoxes have if it is enabled. This
saves a small amount of space on that tab of the dialogue!

=== IMPORTANT ===
If using the Qt Creator IDE ensure that in the:
"Options" dialog -> "C++" item -> "Qt Class Generation" tab the:
"Support for changing language at runtime" option is CHECKED.

This will ensure that the files produced by the forms compiler include the
retranslateUi(QWidget *) method which needs to be called on Language
Change to tell the generated forms (dialogues) to repaint their
textual content in a (new) language.  The source of that method is the
(hidden) "ui_FORM_NAME.h" include file that our classes that work with
the generated form code (made from the "src/ui/FORM_NAME.ui" form
definition (XML) files that the Qt Designer plug-in/stand-alone utility
creates) uses. For the record those header files are also the source
of the "setupUi(QWidget *)" methods that can be seen near the top of
the constructors for some of the Mudlet classes that use forms...
=================

Also as part of a BugFix for Mudlet#1273 there is a partially complete update
to show more non-GPL code licences in the "About" dialog's third tab.

This and other forms/dialogues have been refactored to bring HTML code
into the C++ core from the Form file ui/*.ui files to make it easier to
(re)-translate such texts.

Also added missing licence boiler-plate to 3rdparty/lua_yajl/lua_yajl.c
to properly attribute it to its creator.

Also narrowed the licence used for
3rdpaty/communi/src/3rdparty/mozilla/rdf_utils.c to GPL 2+ from the triplet
which included that option in the original file as the text there says we
may - so that the code has the same licence as we use for the main part of
our code.

Made ircmessageformatter correct for lua(not-translatable) / other use

This means NOT using tr(...) for cases where the boolean isForLua is set
in the various methods in this class and also not using HTML/Rich Text.

It also means using something other than any raw string literals which has
been enforced with the inclusion of the #define QT_NO_CAST_FROM_ASCII and
QT_NO_CAST_TO_ASCII which will cause compilation to fail in any case where
such literals ARE used.  Typically a QString will instead be wrapped with
a QLatin1String(...) wrapper should it be a true constant and destined for
a method/function call that has a QLatin1String form or a
QStringLiteral(...) form should it require positional argument replacements
(as QString::arg(...)) in the same way that the tr(...) form does - but not
as something that is subject to translation.

Also fixes a few argument number errors in QString::arg(...) codes in:
* (QString) IrcMessageFormatter::formatTopicMessage(IrcTopicMessage*, bool)
* (QString) IrcMessageFormatter::formatInviteMessage(IrcInviteMessage*,
                                                                      bool)

Made dlgTriggerEditor support run-time language changing

It also means adding support for language changing to related classes:
* dlgActionMainArea
* dlgAliasMainArea
* dlgKeysMainArea
* dlgScriptsMainArea
* dlgTimersMainArea
* dlgTriggersMainArea
* dlgVarsMainArea

Make T2DMap better suited to translation

For many texts that are subject to translation we use Rich/HTML text and
in the past I have hidden the open and closing HTML paragraph tags in the
none translatable part of the strings.  However should the content extend
to be more than one paragraph the translator would have to remember to
close the first paragraph with a </p> and then open a one with <p>.

By not including the outer pair of tags it is less clear to translators,
IMHO what might be going on so they have been restored to the texts that
translators would see.

This commit also moves various entries - manly tooltips and mainly HTML,
from the form definitions into the C++ source which makes it possible to
de-obfuscate the HTML that later versions of the Qt Designer plugin/utility
insist on making more complex even though a long standing QTBUG means that
Qt Linguist is unable to display HTML markup in a way that makes it
editable by translators!

Also wrap some raw strings in QStringLiteral/QLatin1String wrappers to hide
them from translation system and others into it.

Made dlgComposer more amenable to GUI translation

Added sysGuiLanguageChange & getGuiLanguageCode() for Lua subsystem

This causes a sysGuiLangageChange event to be sent to all loaded profiles
when the user changes the setting in the preferences.  Two additional
arguments are passed being the "XX" or "XX-yy" {XX is language;
yy is Country} codes for the new followed by the old translation codes.

Additionally a script/package can query the current setting with the
getGuiLanguageCode() which returns the same type of code which could, in
theory, allow package creators to tailor their scripts for more than one
language - of course for API simplicity the Mudlet Lua implementation is
not translated.

Made TConsole more amiable to translation

Convert 4 error messages that are bound for the Lua subsystem from tr(...)
to QStringLiteral(...) so they are not subject to translation process.

Correct/fixup some messages in TAlias

One of the emended lines raised a parsing issue with lupdate {the:
R"(in: ")" line, then 263 causes a "Excess closing parenthesis in C++ code
(or abuse of the C++ preprocessor)" warning} I rewrote it and also
arranged for it and a couple of related messages to be translatable when
they may not have been before - and they are sent to the Central Debug
Console and the Error display label in the top of the Editor Dialog so do
constitute GUI elements IMHO.

Make dlgPackageExporter class work for subDirs & translatable

It was found that the form used for this dialog was not configured in a
manner consistent with the Qt IDE:
"Tools" -> "Options" -> "C++" -> "Qt Class Generation"
  -> "Embedding of the UI Class"
setting of "Multiple Inheritance" that has been used for (most ?) other
forms/dialog - so this commit includes switching some code over to that
form.  This revealed that the class member "filePath" was masking/shadowing
a dialog member (a QLineEdit) of the same name.  I renamed the latter to
lineEdit_filePath and then found that the class member was largely
redundant as the textual content of the lineEdit contains the wanted
detail.

I also renamed a couple of other items in the form:
* (QLabel *) textLabel1 ==> textLabel_exportLocation
* (QLabel *) textLabel1_2 ==> textLabel_informationText
to be a bit better named.

It became clear that it would be possible and might be useful to show the
lineEdit contents (in readOnly mode) once it was populated.

There was an issue with the creation of temporary files/directories in
that they were assembled in a sub-directory:
"mudlet home dir"/profiles/"profile name"/tmp/"package-name"
folder that was not cleared after the creation of a module and so would
not be a "temporary" one and would still be around should another instance
of the same package/module be assembled.  This commit changes that to
have the option to properly use an OS-dependent temporary location and
which is removed now after the package is created (unless a debugging line
is un-commented) or which (in the linux case "/tmp") has a well-known
(to the OS) as being likely to be subject to temporary file clean-up.

More fundamentally it became clear that the existing code DID NOT WORK to
produce modules if there were any sub-directories and in the absence of any
error reporting it was not clear why. This commit changes the way that the
user created files and sub-directories are scanned to pick up on
sub-directories and to make the needed but missing entries in the archive
for them.  It also arranges for the "config.lua" file to be stored as the
first "file" in the archive and the Mudlet items in the
"'package-name'.xml" file to be the last (so that all the other contained
files are loaded in before it is used in any way.

The form/dialog has been simplified a little with a more informative text
(which has been brought into the C++ code to make it easier for translators
to work with {some of the fixed HTML has been hidden from them}) and it
now persists for around 10 seconds after the "Export" button has been hit
so that the "results label" which is now populated with a
"success / fail + reason" message is at least briefly readable.  In the
past only a success message was shown and as the form was being hidden as
part of the "close()" method called immediately after it was put up it was
never seen...!

Differences between the form object name and the ".ui" file that contains
their definition was causing confusion in Qt Linguist as it was not clear
of the context for some entries.  However renaming the object meant that
where they were inherited in various Mudlet class header files needed
emending to match...

Names changed:
color_trigger_dlg ==> color_trigger
profile_dialog ==> connection_profiles
irc_dlg ==> irc
keys_main_area ==> keybindings_main_area
NotesEditor ==> notes_editor
roomExits ==> room_exits
MainWindow ==> main_window

Some forms also referred to the old mudlet_alpha.qrc resource file instead
of the correct mudlet.qrc one.

As it has been a while since some forms were edited in any way, a small
change in the format (removal of an unneeded space character between the
last attribute in XML entity and the closing '>') has also modified some
form (.ui) files edited in some other way...

Also fixed a spelling mistake (overide ==> override) in my source code.

I did lose a set of changes that I accidently deleted and recovered
by delving in the ./.git/lost-found/other area for blobs of
changed files - hopefully I managed to rescue all the bits
needed...

Some versions of Qt's lupdate seems to have issues parsing modern C++11(?)
string literals and get confused when there are an odd number of, possibly
escaped/embedded double quotations (or that is what I found) however
reverting to the prior form involving back-slashes '\' seems to work.

The default scripts/commands built-in to Qt Creator do not:
* produce a reduced "plurals only" en_US which is all that we need for
  American English
* mark untranslated strings - Qt Linguist does with a '#'
* compress the binary files to save space

I enclose a couple of shell scripts unix_lupdate.sh and unix_lrelease.sh
that should be executable from within the QtCreator environment
(or included in qmake/cmake project files) that should automate updating
translation source files and producing binary translation output files
that can be used now. They should be executed from the ./src/
sub-directory.

At present the translation binary files are expected to be in the same
directory as the Mudlet executable - but this is not be satisfactory for
all situations and will need further revision.  In the mean time for (unix)
developers it is useful to include symbolic links from the "build" shadow
directory to the ./src/ one so that a development executable sees the
translation binaries as they are updated.

Only the en_US; en_GB and fr_FR files included significant translation
work at present, the first two are largely usable and the French one
includes many prototype translations in order to test various features,
I would like to think that it is a basis for future work but a native
French speaker would probably think it is absolute "merde"...

On the other hand as an British speaker the middle one does help to remove
the stress I get that is centred around not seeing colour!

Revised I18n "[ XXXX ] - aaa bbb ccc." cTelnet::postMessage(...) system

This needed revision to allow for message tags to have different lengths in
different languages.  May still not be good enough to work with texts
containing combining diacriticals or non-BMP plane characters...

Tidied up mudlet class items, move some permanents into class

For dynamic GUI language changes we will need to change the texts and
tool-tips assigned to many parts of the main window but until now the
QActions concerned have not explicitly been members of this class - so
retrieving them later for amendment is awkward.  This commit moves the
following into the class (and renames them accordingly):
actionConnect         ==> mpActionConnect
actionTriggers        ==> mpActionTriggers
actionAlias           ==> mpActionAlias
actionTimers          ==> mpActionTimers
actionButtons         ==> mpActionButtons
actionScripts         ==> mpActionScripts
actionKeys            ==> mpActionKeys
actionVars            ==> mpActionVars
actionIRC             ==> mpActionIRC
actionMapper          ==> mpActionMapper
actionHelp            ==> mpActionHelp
actionOptions         ==> mpActionHelp
actionNotes           ==> mpActionNotes
actionPackageM        ==> mpActionPackageM
actionModuleM         ==> mpActionModuleM
actionReplay          ==> mpActionReplay
actionMultiView       ==> mpActionMultiView
actionStopAllTriggers ==> mpActionStopAllTriggers
actionAbout           ==> mpActionAbout
The following is only used in some circumstances, it is set to a null
pointer when not (and I corrected a spelling mistake!):
actionFullScreeniew   ==> mpActionFullScreenView
The following were already members of the class but it was not obvious from
their previous names:
actionReconnect       ==> mpActionReconnect
actionReplaySpeedDown ==> mpActionReplaySpeedDown
actionReplaySpeedUp   ==> mpActionReplaySpeedUp
actionSpeedDisplay    ==> mpActionSpeedDisplay
actionReplayTime      ==> mpActionReplayTime
Also:
(QToolBar *)replayToolBar      ==> mpToolBarReplay
(QLabel *)replaySpeedDisplay   ==> mpLabelReplaySpeedDisplay
(QLabel *)replayTime           ==> mpLabelReplayTime
(QTimer *)replayTimer          ==> mpTimerReplay

Many of the edited items had tooltips (though a few had status tips
instead) as the items are generated by the Mudlet application rather than
from a Qt Designer form they will not get modified if there is a change
in the translation file(s) during an application runtime; code that sets
those items up/changes them has been placed in a new private method:
(void) mudlet::guiLanguageChange(void) to be called when needed.

There were also many "dead" QActions (mainly with an 'm' prefix that were
declared but never used in a meaningful way, they have been deleted:
mactionConnect, mactionTriggers, mactionTriggers, mactionTriggers,
mactionButtons, mactionButtons, mactionKeys, mactionKeys, mactionHelp,
mactionOptions, mactionMultiView, mactionAbout & mactionCloseProfile.

Make class member pointers in TConsole to bottom toolbar buttons so that
they can be found after the end of the constructor so that their tool-tips
can be revised if the GUI language changes.  As we now have those pointers
we can also arrange for the tool-tips to relate to the toolbar button
current state.  Whilst "wiring this up" I spotted that there was a useless
function call from:
(void) TTextEdit::slot_copySelectionToClipboard()
to:
(void) TTextEdit::copySelectionToClipboard()
and from:
(void) TTextEdit::slot_copySelectionToClipboardHTML()
to:
(void) TTextEdit::copySelectionToClipboardHTML()
where the functions wthout the "slot_" prefix could be renamed to have it
and be called directly.  Also I could changed
(void) TTextEdit::slot_toggleTimeStamps()
to
(bool) TTextEdit::toggleTimeStamps()
so that it isn't a SLOT and then get it to return the state of the variable
that determines whether time-stamps are showing - this is so the slot
function can be in the TConsole class so that it can modify the time-stamp
control button's tooltip to match the state of the control.

Whilst debugging the changes herein I found that
* (QToolButton *) mudlet::mpActionFullScreenView
needed to be initialised in the constructors initialiser list and spotted
a couple of other variables that were NOT being initialised:
* (bool) mudlet::mIsLoadingLayout
* (bool) mudlet::mHasSavedLayout

I found an issue where, when the same "source" text is used in different
places, then QtLinguist only displays ONE source which can cause issues if one
source text is modified but another is not - however by adding additional
developer diambigution strings each instance is separately displayed - where
this has been done there will be such comments with an identical comment
except for an (X of Y) indication - this may help to ensure that changes
are carried through to all places in the source code when needed. One example
of this is the texts to use for the Server Encoding type ComboBox on the
preferences dialog when one set of translations are use on initialisation but
a different set is used when the GUI Language is changed...

Whilst going through the main window menu bar I noticed it badly needed a
clean-up to remove cruft.  I have taken the liberty of:
* reorganising some items
* adding the same icon where possible as is used on the main toolbar
* adding a quit option to the games menu - as I find when I run the application
  in full screen mode I do NOT have a title-bar with a close button on it and
  there is nothing to click on directly to close Mudlet down without doing
  an un-fullscreen first.
* adding the Qt provided "About Qt" action to the "Help" menu where other Qt
  applications often have it.
* change "Settings" to "Preferences" and "Replay" to "Load Replay"
  so that menu items are identical to toolbar items...

Do not populate or mark as translatable the doubleclick_ignore_lineedit
"text" field in the profile_preferences.ui dialog so that it does not get
"retranslated" should a GUI language change be invoked elsewhere in the
same dialog as that will overwrite any existing contents that were set up
in the dlgProfilePreferences constructor which will be the current profile
settings.

Enjoy

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Storing a QString as the line style for any exit with a custom line does
not work so well when the language used to display the option has to be
changed to accommodate a different language.  This commit changes the
TRoom class to store the Qt:PenStyle enum value directly instead of a
representation of the name of the style.

This did show up a slightly tricky issue when serialising the enum as at
some point in the Qt 5.x history it seems to have gotten harder to access
the underlying integer value.  This is solved by a pair of QDataStream
handling "friends":
* (QDataStream) &operator<<(QDataStream&, const Qt::PenStyle&) {writing}
* (QDataStream) &operator>>(QDataStream& ds, Qt::PenStyle& value) {reading}
they have been included at the top of the TMap and TRoom classes
respectively and which are used "behind" the scenes when a Qt::PenStyle is
serialised.  NOTE: the absence of the function in TRoom will throw up a
slew of compilation errors about "no match for 'operator>>' (operand types
are 'QDataStream' and 'QMap<QString, Qt::PenStyle>::mapped_type {aka
Qt::PenStyle}') in "qdatastream.h" as line 284 but it will be unclear
otherwise what on earth has gone wrong.  More insidiously the absence of
a matching function in the TMap write to file process will silently
seem to work but write out a different number of bytes (several rather than
one or two) such that any data afterwards in the file produced will be
corrupted...!!!

When I tried to work out what texts to use for other languages for the
different line styles I realised I could not be certain of the Google
translations so I ran up a set of icons to use as well - they are a bit
skimpy at the moment so may need a bit of tweaking to look better.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
@SlySven SlySven requested a review from a team as a code owner October 14, 2017 03:55
@SlySven SlySven requested a review from a team October 14, 2017 03:55
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 14, 2017

Hi Stephen! Thanks for doing this massive amount of effort, it is awesome to see thie PR finally come to life :)

What do you think about adding the translation files into the Qt Resource file - that's how we've already been solving the runtime detection issue for files already.

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 14, 2017

Let's leave #436 for later - it addresses a totally different problem and has many issues itself that'll slow down this PR from making it in. If we do this step by step, it'll be easier.

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 14, 2017

On blast got an ENOCOFFEE with a couple of:

#if Q_OS_WIN32

instead of:

#if defined(Q_OS_WIN32)

causing fails on Apveyor and it turns out I use zip_file_add(...) and zip_dir_add(...) in an included fix for the buggy module/package exporter that silently breaks if there is a sub-directory in the package being made but those are libzip 1.x functions that replace the declared obsolete 0.1x zip_add(...) ones but get which version is used on trusty on Travis... 😒 🔨

Copy link
Copy Markdown
Member

@vadi2 vadi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not finished reviewing everything yet, just what I got done so far...

src/KeyUnit.cpp Outdated
mKeys[0x01020006] = QString("Zoom");
mKeys[0x01020001] = QString("Cancel");
// This WAS called setupKeyNames but it actually represents all that needs
// doing for this class when the language changes...! 8-)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to have this comment in code - we can have it in the Github review if need be. Otherwise leaving behind cruft in things will rename will lead us to comments all over the place ten years down the road saying "this used to be called this and that" and it'll be like "okay... this is adding no useful information"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☑️ This comment removed.

mKeys[0x0f7] = tr("division");
mKeys[0x0ff] = tr("ydiaeresis");

mKeys[0x01000000] = tr("Escape");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keyboards don't translate this stuff - it needs to stay as-is in English.

Copy link
Copy Markdown
Member Author

@SlySven SlySven Oct 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily - a French Key board is not going to have a "BackSpace" key and the "Shift" keys are not labelled "Shift" e.g. see Wikipedia's AZERTY Keyboard layout article...

This is about the name that is displayed to the user - it has no programmatical significance fortunately...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay


p.save();
p.setPen(Qt::yellow);
p.fillRect(0, 0, width(), height(), Qt::darkRed);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look like it's related to i18n.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigh yeah it is a little off-topic - but as I was marking the "No map..." message I remembered being bugged by the layout and colour of the message in the past - and as there are no guarantees about the size (or shape) of the translated message it seemed sensible to use the layout system to centre it properly and allow it to be wrapped if the map was very small rather than specify a start point of half-way across the screen {neglecting the fact the message has a length}...

} else {
customLinePen.setStyle(Qt::DashDotDotLine);
}
customLinePen.setStyle(pR->customLinesStyle.value(itk.key(), Qt::SolidLine));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement!

}
}

// TODO: Hide this information in release version?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

* This should really be called "dlgModuleExporter" - "Packages" should be
* reserved for a single node (plus sub-nodes) from one type of Mudlet item that
* is "Exported" from the "Editor" whereas "Modules" are collections of possibly
* more than one type of Mudlet item and which can include additional reasources
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not correct - packages are not reserved for single-node items, they can be multi-node packages just like modules.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How, the "Export" option in the Editor only allows one item to be selected IIRC...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a crappy export option...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So? That is how it is isn't it, and it does have its uses to get a straight forward XML file. I guess this might be a bit of a simplistic division between the two terms but actually there is some merit in distinguishing between a simple XML "extract of one leaf/branch of one tree" in the Editor compared to a more complex "collection of multiple branches from multiple trees together with other file based resources all zipped up in an archive file"...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree but this isn't the right place to have this discussion, nor is this the i18n PR the right place to sneak remarks into the source code about completely unrelated things 😉

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☑️ Reworded to note the difference between what this class does/produces and the "Export" option in the Editor (dlgTriggerEditor class) - the latter only exports one "branch" of one "tree" (widget) of Mudlet items in an .xml file whereas this manages a whole "forest" (and external files besides) as a .mpackage (renamed .zip) archive file; but there is no mention of anything about packages vs. modules... 😉

}
fileEntries.remove(QStringLiteral("config.lua"));
} else {
qWarning() << "dlgPackageExporter::slot_exportPackage() - ERROR: failed to add package detail file config.lua to archive, the package/module may not work!";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll work just fine without it, the name will just be assumed from the zip file instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... but it is a warning that the config.lua file has been clobbered...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but the text is incorrect.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would:

qWarning() << "dlgPackageExporter::slot_exportPackage() - WARNING: failed to add package detail file config.lua to archive!"

be acceptable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☑️ Done

***************************************************************************/

/*
* THIS FILE CONTAINS UTF-8 UNICODE ENCODED CHARACTER STRINGS THAT ARE (OR
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what is the takeaway message I'm supposed to get here, could you explain?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tool-tips in the constructor MUST remain as QStringLiterals(...) and NOT be converted to tr(...) but I could word it as that now - when I started on this I was not quite sure how it would all work out... 🙂

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay - can we just say that, without the shouting?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YES err, yes!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☑️ Done

QStringList tooltipLanguageEntries;

// This covers the default en_US as well as en_GB:
tooltipLanguageEntries.append(QStringLiteral("Choose the language for Mudlet to use..."));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be Choose the language for Mudlet to use:

elipsis is used to indicate that there is more following in another menu in UI design.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I meant the ellipsis to mean if you select this control it carries out this action...

Grammatically I might not be entirely correct, but I suspect that a colon : is definitely not right here.

// Handle case when no map is present:
if (pHost->mpMap && pHost->mpMap->mpRoomDB && pHost->mpMap->mpRoomDB->size() > 0 ) {
label_mapFileSaveFormatVersion->setEnabled(true);
Q_ASSERT_X((pHost->mpMap->mMaxVersion >= pHost->mpMap->mDefaultVersion
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a static_assert() would work well here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment about the same Qt Macro elsewhere

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 14, 2017

I've resolved the merge conflicts that occured, but the PR still has the initial outstanding issues it had in compiling!

Repairs a stupid mistake in #ifdef-ing a couple of Windows specific chunks
of code I made before.

I didn't realise it but I am using a (locally compiled) version 1.x of
libzip but some Debian versions and the Trusty Ubuntu Travis Platform only
comes with an 0.1x version by default (that may not encode UTF-8 paths)
correctly - I am not sure of the exact details) although the source for
libzip {https://nih.at/libzip/libzip.html} has declared the functions that
we were using {zip_add(...) and zip_add_dir(...)} OBSOLETE - however that
is all that is available for those cases so I have added #ifdefs that will
use the later functions {zip_file_add(...) and zip_dir_add(...)} if they
are available.  Whilst this hits two places in the previous part of the PR
there is one more instance in the code base that I have also fixed up in
this way.

As it happens both of these issues have arisen as a result of a reworking
of the package/module handling code which, prior to this PR will silently
FAIL to make packages/modules if there are any files placed in the staging
area in a sub-directory.  That staging area was described as a "temporary"
one but in fact persists beyond the production of a package/module. As part
of the reworking it has been made to have the option (NOT ENABLED BY
DEFAULT) to clean up the temporary area afterwards but if a package/module
is being developed then it is likely that the other resources are likely
wanted to be kept for producing later, updated/revised, ones...

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
... but this should be correct.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
Forgot to convert the entered value back from a QString to a UF-8 encoded
const char * should the value be duff!

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 14, 2017

Could we move the translations file to a separate top-level /translations/ to keep things clean?

Fixed a spurious open C type multi-line comment at start of:
3rdpart/communi/3rparty/mozilla/rdf_utils.c where I had chosen the GPL
only licence and rewritten the header in a manner consistant with the
Mozilla terms provided therein.

With the addition of Q_OBJECT macro into KeyUnit and Host classes
(to allow them to use Qt SIGNALs/SLOTs) it also seems to be necessary
to #include <Q_OBJECT> for some build platforms even though it must be
inherited from one of the other #include s...

Not being totally familiar with the methodology in adding overloaded
helpers for data items to QDataStream::operator<< and
QDataStream::operator>> friend type helpers I did not realise I had to
return the (first) argument reference for the two argument methods.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 14, 2017

Could we move the translations file to a separate top-level /translations/ to keep things clean?

In the source tree for development (followed by installation placement in, say, a shared, read only location such as /usr/[local/]share/mudlet/translations for *nix platform builds) ? That seems like a good idea - 💡 in conjunction with a "Preferences" => "Special Options" QLineEdit to override it for development/testing work .

With the inclusion of `Host` and `KeyUnit` classes into the list of those
that use the `Q_OBJECT` macro it means that their header files need to be
moved from the `mudlet_HDRS` variable to the `mudlet_MOC_HDRS` one so that
they get run through the `moc`.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 14, 2017

🎉 Finally - it passed CI - ye-ha!

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 14, 2017

Awesome work!

@SlySven SlySven mentioned this pull request Oct 14, 2017
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 16, 2017

What do you think about adding the translation files into the Qt Resource file - that's how we've already been solving the runtime detection issue for files already.

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 16, 2017

That has some promise - though I think we'd want to enable the -compress option to lrelease as uncompressed I think I was seeing files of size of a couple of hundreds of kilobytes for the binary translation files as they were...

Note that some platforms would not want that though, Linux distributions such as Debian or Ubuntu expect those shareable, read-only files to be located elsewhere in the file-system and I expect @csmall would patch the source to strip them out of the mudlet binary, probably to /usr/share/mudlet/translations/ and trim the mudlet_ off the name...

A QLineEdit on the special options does seem to be the way to go on this - with a :/transations/ default value... which packagers can patch to say /usr/share/mudlet/translations/ instead but still allow modifications for developers/translators to test locally generated ones in a different (or even ./src/ location).

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 17, 2017

Who are we gonna share Mudlet translations with exactly?

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 17, 2017

To make it easier to see which comments of mine are actually requesting changes, I've went through and made a list - hope it helps:

#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment)
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️
#1334 (comment) ☑️

Updated by SlySven as he made changes to his local copy to keep track... 😀

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 17, 2017

Who are we gonna share Mudlet translations with exactly?

Do you mean, why place them in a /usr/share/ or /usr/local/share/ directory? If so it means other users of the same *nix PC who also want to play MUDs - though this is not usually simultaneously with multi-seat configurations this is becoming increasingly do-able. The same also applies I suppose in an "install for all users" Windoze installation, though with a centralised Program Files location it is likely that the translations can be kept in the same section of the file-system anyhow.

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 18, 2017

I think it'll be a lot easier to just embed them into a resource file. If someone asks us to split it out and gives pretty good reasoning, we can do that... but otherwise this is additional file loading complication that I'd rather not deal with. This complicates setup instructions, makes it a lot harder for Windows, adds more room for error and frustration, all for no real benefit to us. It seems like a nice idea but really the costs of it are high.

@SlySven SlySven self-assigned this Oct 29, 2017
@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Oct 29, 2017

Nice, thanks for addressing the feedback! I'm also keen on #1334 (comment).

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Oct 31, 2017

⏱ I'm looking at the outstanding thing about using a resource file...

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 19, 2017

however as provided the first one reads the TRANSLATIONS variable in the qmake project file and processes all the languages to produce what are full translation files with every QString in - for the English (American) language, as the source code is already in that language it produces a much larger file than is needed, and by running the lupdate command with an existing mudlet_en_US.ts file it can be made much simpler with the additional -pluralonly option that only picks out the cases where the %n parameter is used to specify a (usually integer but it need not be) 3rd argument to the QObject::tr() method which enables the handling of all the different plural forms for those many languages where adding an s if there is more (or less) than one article is just plain wrong!

I've read and re-read this parasentence and I'm having difficulty making sense of it. Why do you suggest we exclude singular form of the messages? 🤔

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 19, 2017

 vadi   Enhance_addGuiTranslations  ⋯  Mudlet  mudlet  src  ./unix_lupdate.sh
Usage: unix_lupdate.sh /path/to/QtBin/lupdate
    /path/to/QtBin/lupdate  a path to the particular Qt lupdate executable to
 vadi   Enhance_addGuiTranslations  ⋯  Mudlet  mudlet  src  1  ./unix_lupdate.sh `which lupdate`
Error: /home/vadi/Programs/Qt/5.9/gcc_64/bin/lupdate/ does not appear to be a path to a Qt lupdate executable

I'd like to see it just work with the lupdate I've got in the $PATH. If I want a different binary, I'll just change it like I do for everything else - or at least make it $PATH default and have it an option that you can change it.

Copy link
Copy Markdown
Member

@vadi2 vadi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had another look at this. I'd love to see this in! I love how it changes the language realtime in selection - super cool.

mpMainToolBar->addAction(mpActionReplay);
mpMainToolBar->widgetForAction(mpActionReplay)->setObjectName(mpActionReplay->objectName());

mpActionDisconnect = new QAction(this);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey we've had the discussion about scoping PRs more than once. A new disconnect button can't go in the PR that adds translations.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to go through that area and clean out a load of cruft relating to unused QActions and reorganise what was left - I got the impression that as this appeared on the menu bar and is also present as a lua command that it was something that had been missed out.

I did refrain from including another one! 👼 I wanted to put a "Close" profile button mudlet_door_48px that if used returned the application to the initial pre-first profile connection state (with the menu/toolbar buttons disabled - which links into the state things would be at when the changes that #1388 handles):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this PR. Let's have it be a sub-button of Reconnect if that's going to be added, we have way too many buttons already as it is.

#if defined( Q_OS_MAC )
return QStringLiteral("%1/../Resources/").arg(QCoreApplication::applicationDirPath());
#else
return QStringLiteral("%1/").arg(QCoreApplication::applicationDirPath());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to embed this inside resource path so we don't have to deal with the complexity of find where the translation files are hiding.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whilst including them in the resource file is one way of doing it and one I am keen to do, I am trying to code my way around something that allows this to be made optional as a resource file method is not amiable to allowing interested parties to create their own language translations and developing them on the fly.

I am still hacking away at this but the implementation as it stands is flawed in that loading up all the translations at start-up is wasteful (keeping all the non-used ones around in memory) and not flexible (changing the source requires restarting the application). There is a better way of doing it and it includes taking into account the language settings that the user has already told the system to use - but given them the chance to change it if they insist {your tale of changing your resident country and then getting everything in the wrong language suggests something changed automatically - or that you hadn't specified your language settings...! 🙁 }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well:

so we don't have to deal with the complexity of find where the translation files are hiding.

Adding both methods is gonna defeat the point here as we'll have even more complicated code to do it both ways! 😄 So nevermind - let's have it be just one way, but at least let's add some search paths for the translations then so we aren't forcing people to make symlinks from whatever folder the Mudlet binary ends up at to the translations.

const QString languageCode(mudlet::self()->getGuiLanguage());

if (languageCode.isEmpty()) {
lua_pushstring(L, "none");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to change - "none" is not a language people speak! Let's make this for humans, not engineers 😉

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Nov 19, 2017

a long and rambling sentance

I've read and re-read this parasentence and I'm having difficulty making sense of it. Why do you suggest we exclude singular form of the messages?

Briefly: the Qt provide external tool lupdate script produces an en_US translation source file (mudlet_en_US.ts) that is is a full-size one with every translatable string included for translation and then needing to be "approved" - even though that apart from plurals (and possible "Britishism" coming from me 😊 ) a translation is NOT required. My script processes that locale specially to make it a plurals only one with something less than twenty texts to approve. Also, the Qt Script only (I think) considers translations included in the TRANSLATIONS variable in the qmake project file - my script works through all the files matching the mudlet_*.ts globbing pattern.

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Nov 19, 2017

Some mojibake which looks as though it is the "usage" output from one of my scripts

I'd like to see it just work with the lupdate I've got in the $PATH. If I want a different binary, I'll just change it like I do for everything else - or at least make it $PATH default and have it an option that you can change it.

I needed to do it like that so that I could ensure with the multiple Qt library versions/kits I have got installed/setup that the right one was used to match the current version selected:
screenshot_20171119_211607

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Nov 20, 2017

Alright. What about the Windows and macOS versions of the scripts? Perhaps we won't need them because the web translation service will be automatically pulling the strings anyway so translators don't have to mess around with this complicated stuff.

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Dec 4, 2017

@SlySven let's work on getting this PR finished out. What is outstanding? The disconnect button has to go as it is offtopic, "none" as a language needs to go, and need to add search paths for loading translations I think is all that is left.

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Dec 4, 2017

I have a revised (by merging in some recent changes) edition that does work for translations included as a (separate) resource file (so the inclusion can be made build environment dependent) which defaults to auto-locale selection (using the user's own or system settings) but which can be changed to a specific one on demand - this is via a comboBox on the first profile preferences ("General") tab - it is then also possible to override the location of the translation's file and specify a manual location (which can be the local source tree) in a QLineEdit but which has the same default location (visible as a placeholder text) as the compiled in setting. This seems to work well to me - and I have retained the "none" option but it is right at the end of the options listed (the "auto", default locale/language one is right at the start).

However given the textual changes elsewhere and the other things like module code that this current includes but which I developed further/better in #1355 - I would like to get that one in and then redo this one with less in it based upon the current development branch. Basically I think in merging in things I may have broken other PRs and want to try again now I have something that operates as I would like... hopefully for Mudlet 3.7 . I have had to juggle some things on the profile preferences (added another tab for "Profile and Server preferences") and with all the other changes that have happened there it will need careful going over again to get this in:

(For testing purposes I set up another user on my Box stephane who has a locale setting of "fr;en_GB") on there the current code does select things to be French - once I remember to have the translations where they should be:

screenshot_20171204_172921

There is a bit of a mix up that I have to check - but the default location for this build should have been in :/translations which is a resource file within the application, which hitting the clear button should have shown:
screenshot_20171204_173054

This has to use a non-native file dialog so that the directory search will show only the mudlet_*.qm files that are wanted:

screenshot_20171204_173456

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Dec 11, 2017

OK, thank you, great progress. I've got feedback on this but as you suggest let's process #1355 first.

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Jan 2, 2018

OK, once #1355 and #1446 finally get in I can get back to bringing this Frankensteinian monster to life again. Those other two have things that interact with this one (I touched the package/module handling stuff in this one but it was only completed in the first one so that need merging in correctly and the font optional font handling stuff which has been done by moving the fonts to a second, optional, resource file has shown me how to place the translations into the resource system - for some platforms and how to access them afterwards).

🎉 All in all, I have good hopes for progressing Mudlet in 2018...! 🎆

@SlySven
Copy link
Copy Markdown
Member Author

SlySven commented Jan 3, 2018

Aaaarrggh! :hurtrealbad: As a test I have tried to merge the development branch into this on my local working code - and, I cannot do it - there are just too many other changes to keep track of. I am going to try and go through the changes racked up here bit-by- bit and cherry-pick them onto a fresh copy of development with, I think, 1355 and 1446 merged in first...

Yes, I wish I had KISSed it...

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented May 24, 2018

I'll close the PR, the PR itself is too different now to be merged. It's code will still live on SlySven:Enhance_addGuiTranslations and I suspect you'll be more interested in pulling the bits out into separate, smaller PRs :)

@vadi2 vadi2 closed this May 24, 2018
vadi2 added a commit to vadi2/Mudlet that referenced this pull request Jul 21, 2018
vadi2 added a commit that referenced this pull request Jul 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants