I work on a web application that allows users to upload files. Files with certain formats (e.g. PDF, DOC, XLS, etc.) are scraped using PHPOffice libraries like PHPWord. Recently a user uploaded a DOCX file that lead to an error:
Uncaught InvalidArgumentException: und is not a valid language code in C:\Atlas\vendor\phpoffice\phpword\src\PhpWord\Style\Language.php:252
I considered posting an issue on the PHPWord github repository but wanted to know more about what was causing the error.
I renamed the DOCX file as a zip and opened it up. Within the zip at path word/styles.xml I found the XML that contains "und":
<w:style w:type="paragraph" w:styleId="Header">
<w:name w:val="Header"/>
<w:basedOn w:val="Normal"/>
<w:next w:val="Header"/>
<w:autoRedefine w:val="0"/>
<w:hidden w:val="0"/>
<w:qFormat w:val="1"/>
<w:pPr>
<w:tabs>
<w:tab w:val="center" w:leader="none" w:pos="4153"/>
<w:tab w:val="right" w:leader="none" w:pos="8306"/>
</w:tabs>
<w:suppressAutoHyphens w:val="1"/>
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
<w:ind w:leftChars="-1" w:rightChars="0" w:firstLineChars="-1"/>
<w:textDirection w:val="btLr"/>
<w:textAlignment w:val="top"/>
<w:outlineLvl w:val="0"/>
</w:pPr>
<w:rPr>
<w:w w:val="100"/>
<w:position w:val="-1"/>
<w:sz w:val="20"/>
<w:szCs w:val="20"/>
<w:effect w:val="none"/>
<w:vertAlign w:val="baseline"/>
<w:cs w:val="0"/>
<w:em w:val="none"/>
<w:lang w:bidi="ar-SA" w:eastAsia="en-US" w:val="und"/>
</w:rPr>
</w:style>
Notice towards the end is this element:
<w:lang w:bidi="ar-SA" w:eastAsia="en-US" w:val="und"/>
It appears that w:style element corresponds to the header and there is a similar element for the footer that also contains a child element w:lang with attribute w:val="und".
Does that attribute correspond to the value being undefined or something else? Can it be changed within MS Word?
Update Jan 20, 2023
I've logged an issue on the GH repo
Running the command I¥ command returns:
2 AA1579X 16SEP 5 DFWORD HF1 0625 0846 /DCBA*SDAZXT /E
I have successfully sent a request using GetReservationRQ. Asking for the remarks sections but I am getting the result above which I would expect. (I assumed this is the right section and have tried Itinerary too, see below)
<GetReservationRQ version="1.1.0" xmlns="http://services.sabre.com/sp/updatereservation/v1_1">
<Profile>
<UniqueID id="......."/>
</Profile>
<SubjectAreas>
<SubjectArea>REMARKS</SubjectArea>
</SubjectAreas>
<ReturnOptions>
<ViewName>Default</ViewName>
<ResponseFormat>STL</ResponseFormat>
</ReturnOptions>
</GetReservationRQ>
Which returns 2 remarks as part of the response:
<Remarks>
<Remark id="44" index="1" type="HS">
<RemarkLines>
<RemarkLine>
<Text>POSSIBLE DUPE BOOKING. SEE PNR JZXWEI JBVFYC HUSTLM</Text>
</RemarkLine>
</RemarkLines>
</Remark>
<Remark id="45" index="2" type="HS">
<RemarkLines>
<RemarkLine>
<Text>POSSIBLE DUPE BOOKING. SEE PNR KDCFKD KQLLXF</Text>
</RemarkLine>
</RemarkLines>
</Remark>
</Remarks>
However as you can see they are not the same remark as when I run the command I¥. What am I doing wrong?
Here are links to the sabre documentation:
https://developer.sabre.com/docs/soap_apis/management/itinerary/Retrieve_Itinerary/help_doc?page=get-reservation-request-and-response-structure
Which says:
REMARKS Allows to display remark information (supported types: REG, HD, HS, CLIADR, DELADR, INVOICE, ITINERARY, INTERFACE, CODED_A, PRTONTKT, CORPORATE, FOP, QQ, FILLER, ITINSEGASSOC)
Is there a way to use http sources for data in Qt's scxml implementation?
In other implementations this works, but not in my Qt Version 5.15.3
When using a simple state machine, with it's data src pointing to my running flask script I get the following error:
qrc:/main.qml:15:5: QML StateMachineLoader: :/http.scxml:5:59: error: src attribute resolves to non existing file (:/http://localhost:8080/) qrc:/main.qml: 15
Can't I define remote sources for data?
The statemachine:
<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early"
xmlns:qt="http://www.qt.io/2015/02/scxml-ext" datamodel="ecmascript" name="http_test" initial="test">
<datamodel>
<data id="http_data" src="http://localhost:8080/"/>
</datamodel>
<state id="test">
<onentry>
<send event="entried" delay="2s">
<param name="eventbody" location="http_data"/>
</send>
</onentry>
</state>
</scxml>
qml:
import QtScxml 5.15
id:theId
property StateMachine stateMachine: scxmlLoader.stateMachine
StateMachineLoader {
id: scxmlLoader
source: "http.scxml"
}
EventConnection {
events: ["entried"]
stateMachine: theId.stateMachine
onOccurred: {
var d=event.data
console.debug(d.eventbody)
}
}
Qt SCXML works only with local files
<?xml version="1.0" encoding="UTF-8"?><dsn>
<station
name="gdscc"
friendlyName="Goldstone"
timeUTC="1415478847476"
timeZoneOffset="-28800000" />
<dish
name="DSS25"
azimuthAngle="187.97"
elevationAngle="37.30"
windSpeed="9.27"
isMSPA="false"
isArray="false"
isDDOR="false"
created="2014-11-08T17:50:08.220Z"
updated="2014-11-08T17:50:44.263Z">
<downSignal
signalType="data"
signalTypeDebug="IN LOCK OFF 1 MCD3"
dataRate="22119.933594"
frequency="8429852703.323329"
power="-153.442429"
spacecraft="CAS"
spacecraftId="82"/>
<upSignal
signalType="none"
signalTypeDebug="OFF 0 "
power="0.000000"
frequency="7152"
dataRate=""
spacecraft="CAS"
spacecraftId="82"/>
<target name="CAS" id="82" uplegRange="1.634442012999E9" downlegRange="1.634454516607E9" rtlt="10903.761527"/>
</dish>
so what is DSS25 tracking??
I have this information from wire shark and am confused on what exactly it's "tracking."
I just have to answer some questions on the specific parts such as the windspeed but in all what is this specific dish tracking?
It's tracking spacecraft n. -82, which is Cassini, all official NASA codes are here:
https://ssd.jpl.nasa.gov/horizons_batch.cgi?batch=1&COMMAND=%27*%27
I have a small app that uses a Qt Quick MessageDialog. I created translations files with command
lupdate-qt5 ../myapp.pro .
In myapp.pro I indicated:
lupdate_only {
SOURCES += $$PWD/ui/*.qml
}
and
TRANSLATIONS += \
translations/i18n_nl.ts translations/i18n_fr.ts translations/i18n_en.ts
All translations are generated correctly. But I have no idea how to generate translations for the standard buttons that MessageDialog provides. In the following example the translations for "Warning" and "Please select Yes or No" are generated. But I can't get them generated for "Yes" and "No" (which is the text value of the StandardButtons property)
MessageDialog {
title: qsTr("Warning")
text: qsTr("Please select Yes or No")
icon: StandardIcon.Warning
standardButtons: StandardButton.Yes | StandardButton.No
//.....
}
I have checked the source code and it indicates that they should be translated:
Button {
id: yesButton
text: qsTr("Yes")
onClicked: root.click(StandardButton.Yes)
visible: root.standardButtons & StandardButton.Yes
}
I've also tried manually adding an entry Yes and No but that doesn't seem to help.
I've found an issue on stackoverflow that talks about adding the qml file to the .pro file to make it work, and that is something I already do. I though about adding the built-in MessageDialog, but I have no idea how to do this.
As a final note: I know that in Qt 5.3 the qsTr's weren't in MessageDialog. But starting from Qt 5.4 they are. I am currently on Qt 5.5
Any help is greatly appreciated.
EDIT
After posting this I kept looking and found an interesting post of someone who has had the same issue. Unfortunately, no answer there.
EDIT 2
Thank you tynn for the response. I have tried both suggestions but no succes. I did try something else as well. I added a qDebug in my code to see if it would translate. I was hoping the same translation would then be used for the MessageDialog, but unfortunatly that doesn't seem to be the case.
qDebug() << "Translate yes :" << tr("Yes"); //translates correctly, dialog doesn't
I have also tried to build a dialog from scratch that does the same as the built-in messagedialog, but at the moment my knowledge of qml is too limited to get this working.
Well, it may be a bit tricky.
First of all, localized strings for Qt widgets may be in Qt's .qm files. Remember that in general you will need all Qt's .qm files for locales you translate into. That's because Qt may, for example, use native MessageDialogs on platforms where they are available, and related code in this case will be located in qtbase, so you will need not only qtquickcontrols_XX.qm files, but also qtbase_XX.qm files for selected locales. And so on.
However, there may be cases when the above does not help. Required strings may simply be missing in the Qt's localization files for your locale (it's a quite common), so you will need to make .ts and .qm files for these strings by yourself. In this case you will need to study Qt sources in order to understand internals of those widgets you are interested in.
Please note that the following example depends on implementation details which may change in future Qt versions.
For example, Qt implementation of QML MessageDialog for Android and iOS uses QPlatformTheme that may be further subclassed to work with different platforms. In QPlatformTheme texts for button labels are returned by defaultStandardButtonText() method which looks like this:
QString QPlatformTheme::defaultStandardButtonText(int button)
{
switch (button) {
case QPlatformDialogHelper::Ok:
return QCoreApplication::translate("QPlatformTheme", "OK");
case QPlatformDialogHelper::Save:
return QCoreApplication::translate("QPlatformTheme", "Save");
case QPlatformDialogHelper::SaveAll:
return QCoreApplication::translate("QPlatformTheme", "Save All");
case QPlatformDialogHelper::Open:
return QCoreApplication::translate("QPlatformTheme", "Open");
case QPlatformDialogHelper::Yes:
return QCoreApplication::translate("QPlatformTheme", "&Yes");
case QPlatformDialogHelper::YesToAll:
return QCoreApplication::translate("QPlatformTheme", "Yes to &All");
case QPlatformDialogHelper::No:
return QCoreApplication::translate("QPlatformTheme", "&No");
case QPlatformDialogHelper::NoToAll:
return QCoreApplication::translate("QPlatformTheme", "N&o to All");
case QPlatformDialogHelper::Abort:
return QCoreApplication::translate("QPlatformTheme", "Abort");
case QPlatformDialogHelper::Retry:
return QCoreApplication::translate("QPlatformTheme", "Retry");
case QPlatformDialogHelper::Ignore:
return QCoreApplication::translate("QPlatformTheme", "Ignore");
case QPlatformDialogHelper::Close:
return QCoreApplication::translate("QPlatformTheme", "Close");
case QPlatformDialogHelper::Cancel:
return QCoreApplication::translate("QPlatformTheme", "Cancel");
case QPlatformDialogHelper::Discard:
return QCoreApplication::translate("QPlatformTheme", "Discard");
case QPlatformDialogHelper::Help:
return QCoreApplication::translate("QPlatformTheme", "Help");
case QPlatformDialogHelper::Apply:
return QCoreApplication::translate("QPlatformTheme", "Apply");
case QPlatformDialogHelper::Reset:
return QCoreApplication::translate("QPlatformTheme", "Reset");
case QPlatformDialogHelper::RestoreDefaults:
return QCoreApplication::translate("QPlatformTheme", "Restore Defaults");
default:
break;
}
return QString();
}
So, in order to localize Yes/No buttons, you will need to add in your .ts file the following:
<context>
<name>QPlatformTheme</name>
<message>
<source>&Yes</source>
<translation>[...]</translation>
</message>
<message>
<source>&No</source>
<translation>[...]</translation>
</message>
</context>
Android have its own subclassed platform theme (QAndroidPlatformTheme) with overriden defaultStandardButtonText(), so for Android you will need to add the following:
<context>
<name>QAndroidPlatformTheme</name>
<message>
<source>Yes</source>
<translation>[...]</translation>
</message>
<message>
<source>No</source>
<translation>[...]</translation>
</message>
</context>
iOS does not override this method in its own QPlatformTheme subclass, so no additional action is needed for it.
You can take a look on one of my projects which use the technique described above for QML MessageBox localization on Android and iOS.
The translations you need should be found inside a qtquickcontrols_*.qm file. Deploying Translations states concerning this
Usually, there are .qm files for the application, and, if a version of Qt is used that is not installed on the system, Qt's .qm files need to be deployed as well.
However your application might just fail to find a suitable translation file. If you only need the translations for Yes and No, you could as well add these to your translation files with a context of DefaultMessageDialog
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>DefaultMessageDialog</name>
<message>
<source>Yes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
Adding the built-in MessageDialog would work as well. Or if you'd like to, you could just use a dummy file DefaultMessageDialog.qml
Rectangle {
Button {
id: yesButton
text: qsTr("Yes")
}
Button {
id: noButton
text: qsTr("No")
}
}
and add this one instead.
On Desktop platforms, such as Windows, macOS and Linux, most Dialog components from QtQuick.Dialogs uses C++ widget components. Their source translations are covered in qtbase_{lang}.ts files and their compiled translations are covered in qtbase_{lang}.qmfiles.
In Qt5.13.1:
refer to C:\Qt\Qt5.13.1\5.13.1\Src\qttranslations\translations for source translations
refer to C:\Qt\Qt5.13.1\5.13.1\mingw83_64\translations for the compiled translations
If you find the sizes of qtbase to be too large for your liking, you can deploy a minified version of the translation files. The following Windows Batch file creates French, German and Japanese subsets of the qtbase files:
setlocal
set QTDIR=C:\Qt\Qt5.13.1\5.13.1\msvc2017_64\
set QTSRC=C:\Qt\Qt5.13.1\5.13.1\Src
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qmessagebox.cpp > %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qfiledialog.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qcolordialog.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qfontdialog.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qinputdialog.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qprogressdialog.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\widgets\dialogs\qwizard.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\gui\kernel\qplatformtheme.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\plugins\platforms\android\qandroidplatformtheme.cpp >> %TEMP%\qtbase_min.lst
ECHO %QTSRC%\qtbase\src\platformsupport\themes\genericunix\qgenericunixthemes.cpp >> %TEMP%\qtbase_min.lst
for /d %%F in (fr de ja en) do copy %QTSRC%\qttranslations\translations\qtbase_%%F.ts qtbase_min_%%F.ts
%QTDIR%\bin\lupdate #%TEMP%/qtbase_min.lst -pluralonly -locations none -ts qtbase_min_en.ts
for /d %%F in (fr de ja en) do if "%%F" neq "en" %QTDIR%\bin\lupdate.exe #%TEMP%/qtbase_min.lst -no-obsolete -locations none -ts qtbase_min_%%F.ts
for /d %%F in (fr de ja en) do %QTDIR%\bin\lrelease qtbase_min_%%F.ts
On mobile platforms, such as iOS and Android, Dialog the MessageDialog component the translatable text are still covered in the qtbase_{lang}.ts files. For the other components, such as ColorDialog, FontDialog, they are implemented in QML as QtQuick components. The translations will be found in the qtquickcontrols_{lang}.ts and qtquickcontrols_{lang}.qm files.
The following demonstrates how to create minified versions of the qtquickcontrols_{lang}.ts and qtquickcontrols_{lang}.qm files for French, German and Japanese:
setlocal
set QTDIR=C:\Qt\Qt5.13.1\5.13.1\msvc2017_64\
set QTSRC=C:\Qt\Qt5.13.1\5.13.1\Src
ECHO %QTSRC%\qtquickcontrols\src\dialogs\DefaultMessageDialog.qml > %TEMP%\qtquickcontrols_min.lst
ECHO %QTSRC%\qtquickcontrols\src\dialogs\DefaultColorDialog.qml >> %TEMP%\qtquickcontrols_min.lst
ECHO %QTSRC%\qtquickcontrols\src\dialogs\DefaultFileDialog.qml >> %TEMP%\qtquickcontrols_min.lst
ECHO %QTSRC%\qtquickcontrols\src\dialogs\DefaultFontDialog.qml >> %TEMP%\qtquickcontrols_min.lst
ECHO %QTSRC%\qtquickcontrols\src\dialogs\DefaultDialogWrapper.qml >> %TEMP%\qtquickcontrols_min.lst
for /d %%F in (fr de ja en) do copy %QTSRC%\qttranslations\translations\qtquickcontrols_%%F.ts qtquickcontrols_min_%%F.ts
%QTDIR%\bin\lupdate #%TEMP%/qtquickcontrols_min.lst -pluralonly -locations none -ts qtquickcontrols_min_en.ts
for /d %%F in (fr de ja en) do if "%%F" neq "en" %QTDIR%\bin\lupdate.exe #%TEMP%/qtquickcontrols_min.lst -no-obsolete -locations none -ts qtquickcontrols_min_%%F.ts
for /d %%F in (fr de ja en) do %QTDIR%\bin\lrelease qtquickcontrols_min_%%F.ts
Presently, at Qt5.13.1, there are 22 languages (including English). If your desired language is not covered in this list (e.g. Indonesian, Vietnamese), then, you can still use the above scripts to create placeholder minified version of qtbase/qtquickcontrols but you will have to populate the qtbase_min_{lang}.ts files yourself.