GitHub user mike-jumper opened a pull request:
https://github.com/apache/guacamole-client/pull/356
GUACAMOLE-699: Add helper script for verifying translations.
This change adds a utility script, `guacamole/util/check-translation.py`,
which performs automated comparisons between the JSON files that define
Guacamole's translated strings.
By default, strings which are present in English but absent in the
translation will be listed (these will need to be added), as well as strings
which are present in the translation but not in English (these are likely
incorrect and should be removed). These checks can be disabled with command
line options, if desired.
An additional duplicate string check can be enabled to test whether strings
were incorrectly copied verbatim from English without being translated at all.
This check includes some obvious exclusions (empty strings, simple numbers,
protocol names, "Apache Guacamole"), but will likely produce false positives.
It is disabled by default unless requested on the command line.
Usage
-----
```
usage: check-translation.py [-h] [--no-missing] [--no-unused]
[--check-copied]
[ORIGINAL] TRANSLATED
Compares two JSON translation files, as used by the Apache Guacamole web
application, listing the strings which appear to be missing or incorrect.
positional arguments:
ORIGINAL The JSON file which should be used as the basis for
comparison. This should be JSON which can be expected to
contain every string used by the web application and no
others. Typically, this will be the primary, original
language of the web application. In the case of Apache
Guacamole, this should be English. If omitted, the file
"en.json" within the same directory as TRANSLATED will be
used by default.
TRANSLATED The JSON file which should be compared against ORIGINAL.
This should be the JSON which has been translated from
ORIGINAL, and thus should contain the same set of strings
if
the translation is complete.
optional arguments:
-h, --help show this help message and exit
--no-missing Disables checking for strings which are present in
ORIGINAL
but are missing from TRANSLATED. Assuming ORIGINAL
represents the set of strings actually used by the web
application, these strings are those which are missing and
need to be defined for the translation to be complete. By
default, the comparison will check for missing
translations.
--no-unused Disables checking for strings which are present in
TRANSLATED but not in ORIGINAL. Assuming ORIGINAL
represents
the set of strings actually used by the web application,
these strings are those which are defined by the
translation
but unused. By default, the comparison will check for
unused
translations.
--check-copied Enables checking for strings defined in TRANSLATED which
are
identical to the corresponding strings in ORIGINAL. Such
strings may have been incorrectly copied verbatim from the
original without being translated at all. It is also
possible that both languages simply use the same text for
that string, and the string is correct. As this test can
produce false positives, it is disabled by default.
```
Example output
-------------
```
[mjumper@dev-mjumper guacamole]$ ./util/check-translation.py --check-copied
src/main/webapp/translations/de.json
Original language: en (English)
Translation language: de (Deutsch)
The following strings are missing from the translation and should be added:
APP.ACTION_DOWNLOAD
APP.ACTION_MANAGE_USER_GROUPS
APP.ACTION_SHARE
APP.ERROR_PAGE_UNAVAILABLE
APP.TEXT_ANONYMOUS_USER
CLIENT.ACTION_SHARE
CLIENT.ERROR_CLIENT_207
CLIENT.ERROR_CLIENT_208
CLIENT.ERROR_CLIENT_209
CLIENT.ERROR_CLIENT_20A
CLIENT.ERROR_CLIENT_20B
CLIENT.ERROR_TUNNEL_207
CLIENT.ERROR_TUNNEL_208
CLIENT.HELP_SHARE_LINK
CLIENT.INFO_CONNECTION_SHARED
CLIENT.TEXT_CLIENT_STATUS_UNSTABLE
LIST.TEXT_ANONYMOUS_USER
MANAGE_CONNECTION.TABLE_HEADER_HISTORY_REMOTEHOST
MANAGE_CONNECTION_GROUP.ACTION_CLONE
MANAGE_SHARING_PROFILE.DIALOG_HEADER_CONFIRM_DELETE
MANAGE_SHARING_PROFILE.FIELD_HEADER_PRIMARY_CONNECTION
MANAGE_SHARING_PROFILE.SECTION_HEADER_EDIT_SHARING_PROFILE
MANAGE_SHARING_PROFILE.TEXT_CONFIRM_DELETE
MANAGE_USER.FIELD_HEADER_CREATE_NEW_SHARING_PROFILES
MANAGE_USER.FIELD_HEADER_CREATE_NEW_USER_GROUPS
MANAGE_USER.HELP_NO_USER_GROUPS
MANAGE_USER.INFO_NO_USER_GROUPS_AVAILABLE
MANAGE_USER.SECTION_HEADER_ALL_CONNECTIONS
MANAGE_USER.SECTION_HEADER_CURRENT_CONNECTIONS
MANAGE_USER.SECTION_HEADER_USER_GROUPS
MANAGE_USER_GROUP.ACTION_ACKNOWLEDGE
MANAGE_USER_GROUP.ACTION_CANCEL
MANAGE_USER_GROUP.ACTION_CLONE
MANAGE_USER_GROUP.ACTION_DELETE
MANAGE_USER_GROUP.ACTION_SAVE
MANAGE_USER_GROUP.DIALOG_HEADER_CONFIRM_DELETE
MANAGE_USER_GROUP.DIALOG_HEADER_ERROR
MANAGE_USER_GROUP.FIELD_HEADER_ADMINISTER_SYSTEM
MANAGE_USER_GROUP.FIELD_HEADER_CHANGE_OWN_PASSWORD
MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_CONNECTIONS
MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_CONNECTION_GROUPS
MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_SHARING_PROFILES
MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_USERS
MANAGE_USER_GROUP.FIELD_HEADER_CREATE_NEW_USER_GROUPS
MANAGE_USER_GROUP.FIELD_HEADER_USER_GROUP_NAME
MANAGE_USER_GROUP.FIELD_PLACEHOLDER_FILTER
MANAGE_USER_GROUP.HELP_NO_MEMBER_USERS
MANAGE_USER_GROUP.HELP_NO_MEMBER_USER_GROUPS
MANAGE_USER_GROUP.HELP_NO_USER_GROUPS
MANAGE_USER_GROUP.INFO_NO_USERS_AVAILABLE
MANAGE_USER_GROUP.INFO_NO_USER_GROUPS_AVAILABLE
MANAGE_USER_GROUP.INFO_READ_ONLY
MANAGE_USER_GROUP.SECTION_HEADER_ALL_CONNECTIONS
MANAGE_USER_GROUP.SECTION_HEADER_CONNECTIONS
MANAGE_USER_GROUP.SECTION_HEADER_CURRENT_CONNECTIONS
MANAGE_USER_GROUP.SECTION_HEADER_EDIT_USER_GROUP
MANAGE_USER_GROUP.SECTION_HEADER_MEMBER_USERS
MANAGE_USER_GROUP.SECTION_HEADER_MEMBER_USER_GROUPS
MANAGE_USER_GROUP.SECTION_HEADER_PERMISSIONS
MANAGE_USER_GROUP.SECTION_HEADER_USER_GROUPS
MANAGE_USER_GROUP.TEXT_CONFIRM_DELETE
PROTOCOL_RDP.FIELD_HEADER_CREATE_RECORDING_PATH
PROTOCOL_RDP.FIELD_HEADER_DISABLE_BITMAP_CACHING
PROTOCOL_RDP.FIELD_HEADER_DISABLE_GLYPH_CACHING
PROTOCOL_RDP.FIELD_HEADER_DISABLE_OFFSCREEN_CACHING
PROTOCOL_RDP.FIELD_HEADER_DRIVE_NAME
PROTOCOL_RDP.FIELD_HEADER_ENABLE_AUDIO_INPUT
PROTOCOL_RDP.FIELD_HEADER_LOAD_BALANCE_INFO
PROTOCOL_RDP.FIELD_HEADER_PRECONNECTION_BLOB
PROTOCOL_RDP.FIELD_HEADER_PRECONNECTION_ID
PROTOCOL_RDP.FIELD_HEADER_PRINTER_NAME
PROTOCOL_RDP.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
PROTOCOL_RDP.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
PROTOCOL_RDP.FIELD_HEADER_RECORDING_INCLUDE_KEYS
PROTOCOL_RDP.FIELD_HEADER_RECORDING_NAME
PROTOCOL_RDP.FIELD_HEADER_RECORDING_PATH
PROTOCOL_RDP.FIELD_HEADER_RESIZE_METHOD
PROTOCOL_RDP.FIELD_HEADER_SFTP_HOST_KEY
PROTOCOL_RDP.FIELD_HEADER_SFTP_ROOT_DIRECTORY
PROTOCOL_RDP.FIELD_HEADER_SFTP_SERVER_ALIVE_INTERVAL
PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_DISPLAY_UPDATE
PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_EMPTY
PROTOCOL_RDP.FIELD_OPTION_RESIZE_METHOD_RECONNECT
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_EN_GB_QWERTY
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_ES_ES_QWERTY
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_FR_CH_QWERTZ
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_JA_JP_QWERTY
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_PT_BR_QWERTY
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_TR_TR_QWERTY
PROTOCOL_RDP.SECTION_HEADER_GATEWAY
PROTOCOL_RDP.SECTION_HEADER_LOAD_BALANCING
PROTOCOL_RDP.SECTION_HEADER_PRECONNECTION_PDU
PROTOCOL_RDP.SECTION_HEADER_RECORDING
PROTOCOL_SSH.FIELD_HEADER_BACKSPACE
PROTOCOL_SSH.FIELD_HEADER_CREATE_RECORDING_PATH
PROTOCOL_SSH.FIELD_HEADER_CREATE_TYPESCRIPT_PATH
PROTOCOL_SSH.FIELD_HEADER_HOST_KEY
PROTOCOL_SSH.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
PROTOCOL_SSH.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
PROTOCOL_SSH.FIELD_HEADER_RECORDING_INCLUDE_KEYS
PROTOCOL_SSH.FIELD_HEADER_RECORDING_NAME
PROTOCOL_SSH.FIELD_HEADER_RECORDING_PATH
PROTOCOL_SSH.FIELD_HEADER_SERVER_ALIVE_INTERVAL
PROTOCOL_SSH.FIELD_HEADER_SFTP_ROOT_DIRECTORY
PROTOCOL_SSH.FIELD_HEADER_TERMINAL_TYPE
PROTOCOL_SSH.FIELD_HEADER_TYPESCRIPT_NAME
PROTOCOL_SSH.FIELD_HEADER_TYPESCRIPT_PATH
PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_127
PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_8
PROTOCOL_SSH.FIELD_OPTION_BACKSPACE_EMPTY
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_ANSI
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_EMPTY
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_LINUX
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_VT100
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_VT220
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_XTERM
PROTOCOL_SSH.FIELD_OPTION_TERMINAL_TYPE_XTERM_256COLOR
PROTOCOL_SSH.SECTION_HEADER_BEHAVIOR
PROTOCOL_SSH.SECTION_HEADER_RECORDING
PROTOCOL_SSH.SECTION_HEADER_TYPESCRIPT
PROTOCOL_TELNET.FIELD_HEADER_BACKSPACE
PROTOCOL_TELNET.FIELD_HEADER_CREATE_RECORDING_PATH
PROTOCOL_TELNET.FIELD_HEADER_CREATE_TYPESCRIPT_PATH
PROTOCOL_TELNET.FIELD_HEADER_LOGIN_FAILURE_REGEX
PROTOCOL_TELNET.FIELD_HEADER_LOGIN_SUCCESS_REGEX
PROTOCOL_TELNET.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
PROTOCOL_TELNET.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
PROTOCOL_TELNET.FIELD_HEADER_RECORDING_INCLUDE_KEYS
PROTOCOL_TELNET.FIELD_HEADER_RECORDING_NAME
PROTOCOL_TELNET.FIELD_HEADER_RECORDING_PATH
PROTOCOL_TELNET.FIELD_HEADER_TERMINAL_TYPE
PROTOCOL_TELNET.FIELD_HEADER_TYPESCRIPT_NAME
PROTOCOL_TELNET.FIELD_HEADER_TYPESCRIPT_PATH
PROTOCOL_TELNET.FIELD_HEADER_USERNAME_REGEX
PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_127
PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_8
PROTOCOL_TELNET.FIELD_OPTION_BACKSPACE_EMPTY
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_ANSI
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_EMPTY
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_LINUX
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_VT100
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_VT220
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_XTERM
PROTOCOL_TELNET.FIELD_OPTION_TERMINAL_TYPE_XTERM_256COLOR
PROTOCOL_TELNET.SECTION_HEADER_BEHAVIOR
PROTOCOL_TELNET.SECTION_HEADER_RECORDING
PROTOCOL_TELNET.SECTION_HEADER_TYPESCRIPT
PROTOCOL_VNC.FIELD_HEADER_CREATE_RECORDING_PATH
PROTOCOL_VNC.FIELD_HEADER_RECORDING_EXCLUDE_MOUSE
PROTOCOL_VNC.FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT
PROTOCOL_VNC.FIELD_HEADER_RECORDING_INCLUDE_KEYS
PROTOCOL_VNC.FIELD_HEADER_RECORDING_NAME
PROTOCOL_VNC.FIELD_HEADER_RECORDING_PATH
PROTOCOL_VNC.FIELD_HEADER_SFTP_HOST_KEY
PROTOCOL_VNC.FIELD_HEADER_SFTP_ROOT_DIRECTORY
PROTOCOL_VNC.FIELD_HEADER_SFTP_SERVER_ALIVE_INTERVAL
PROTOCOL_VNC.SECTION_HEADER_RECORDING
SETTINGS_CONNECTIONS.ACTION_NEW_SHARING_PROFILE
SETTINGS_CONNECTION_HISTORY.ACTION_DOWNLOAD
SETTINGS_CONNECTION_HISTORY.FILENAME_HISTORY_CSV
SETTINGS_CONNECTION_HISTORY.TABLE_HEADER_SESSION_REMOTEHOST
SETTINGS_USERS.TABLE_HEADER_FULL_NAME
SETTINGS_USERS.TABLE_HEADER_LAST_ACTIVE
SETTINGS_USERS.TABLE_HEADER_ORGANIZATION
SETTINGS_USER_GROUPS.ACTION_ACKNOWLEDGE
SETTINGS_USER_GROUPS.ACTION_NEW_USER_GROUP
SETTINGS_USER_GROUPS.DIALOG_HEADER_ERROR
SETTINGS_USER_GROUPS.FIELD_PLACEHOLDER_FILTER
SETTINGS_USER_GROUPS.FORMAT_DATE
SETTINGS_USER_GROUPS.HELP_USER_GROUPS
SETTINGS_USER_GROUPS.SECTION_HEADER_USER_GROUPS
SETTINGS_USER_GROUPS.TABLE_HEADER_USER_GROUP_NAME
USER_ATTRIBUTES.FIELD_HEADER_GUAC_EMAIL_ADDRESS
USER_ATTRIBUTES.FIELD_HEADER_GUAC_FULL_NAME
USER_ATTRIBUTES.FIELD_HEADER_GUAC_ORGANIZATION
USER_ATTRIBUTES.FIELD_HEADER_GUAC_ORGANIZATIONAL_ROLE
USER_MENU.ACTION_MANAGE_USER_GROUPS
USER_MENU.ACTION_VIEW_HISTORY
The following strings are either NOT defined for the original language or
are
expected to be inherited from the original language and should be removed:
CLIENT.ERROR_CLIENT_205
The following strings are identical to the original language and MIGHT be
untranslated:
APP.ACTION_ACKNOWLEDGE
APP.FIELD_PLACEHOLDER_FILTER
CLIENT.NAME_KEY_ALT
CLIENT.NAME_KEY_ESC
CLIENT.NAME_KEY_TAB
CLIENT.NAME_MOUSE_MODE_ABSOLUTE
CLIENT.NAME_MOUSE_MODE_RELATIVE
CLIENT.TEXT_FILE_TRANSFER_PROGRESS
FORM.FIELD_PLACEHOLDER_DATE
FORM.FIELD_PLACEHOLDER_TIME
MANAGE_CONNECTION.FIELD_HEADER_NAME
MANAGE_CONNECTION.INFO_CONNECTION_DURATION_UNKNOWN
MANAGE_CONNECTION_GROUP.FIELD_HEADER_NAME
MANAGE_CONNECTION_GROUP.NAME_TYPE_BALANCING
MANAGE_SHARING_PROFILE.FIELD_HEADER_NAME
PROTOCOL_RDP.FIELD_HEADER_GATEWAY_HOSTNAME
PROTOCOL_RDP.FIELD_HEADER_GATEWAY_PORT
PROTOCOL_RDP.FIELD_HEADER_HOSTNAME
PROTOCOL_RDP.FIELD_HEADER_PORT
PROTOCOL_RDP.FIELD_HEADER_SFTP_HOSTNAME
PROTOCOL_RDP.FIELD_HEADER_SFTP_PASSPHRASE
PROTOCOL_RDP.FIELD_HEADER_SFTP_PORT
PROTOCOL_RDP.FIELD_OPTION_SERVER_LAYOUT_FAILSAFE
PROTOCOL_SSH.FIELD_HEADER_HOSTNAME
PROTOCOL_SSH.FIELD_HEADER_PASSPHRASE
PROTOCOL_SSH.FIELD_HEADER_PORT
PROTOCOL_TELNET.FIELD_HEADER_HOSTNAME
PROTOCOL_TELNET.FIELD_HEADER_PORT
PROTOCOL_VNC.FIELD_HEADER_CURSOR
PROTOCOL_VNC.FIELD_HEADER_HOSTNAME
PROTOCOL_VNC.FIELD_HEADER_PORT
PROTOCOL_VNC.FIELD_HEADER_SFTP_HOSTNAME
PROTOCOL_VNC.FIELD_HEADER_SFTP_PASSPHRASE
PROTOCOL_VNC.FIELD_HEADER_SFTP_PORT
PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_CP1252
PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_ISO8859_1
PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_UTF_16
PROTOCOL_VNC.FIELD_OPTION_CLIPBOARD_ENCODING_UTF_8
PROTOCOL_VNC.SECTION_HEADER_AUDIO
PROTOCOL_VNC.SECTION_HEADER_REPEATER
SETTINGS_CONNECTION_HISTORY.INFO_CONNECTION_DURATION_UNKNOWN
220 error(s) total.
[mjumper@dev-mjumper guacamole]$
```
You can merge this pull request into a Git repository by running:
$ git pull https://github.com/mike-jumper/guacamole-client translator-utils
Alternatively you can review and apply these changes as the patch at:
https://github.com/apache/guacamole-client/pull/356.patch
To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:
This closes #356
----
commit 28d5a4603d0786ce88e591218ee800f5ebc3480d
Author: Michael Jumper <mjumper@...>
Date: 2019-01-12T09:09:28Z
GUACAMOLE-699: Add helper script for verifying translations.
----
---