[PATCH V6 0/3] add a make check-local command to verify the i18n string formatting

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> V5 -> V6: use ZhengSheng's expression pattern. V4 -> V5: improve the regular expression pattern. remove glob V3 -> V4: use python script to check the i18n string formatting For discuss with ZhengSheng, we should extend the check. We should check the string are obsolete or they are statement but not define in i18n.py V2 -> V3: improve the regular expression pattern. V1 -> V2: move the check to top makefile. check all i18n.py improve the checking information. ShaoHe Feng (3): add a make check-local command to verify the i18n string formatting remove obsolete i18n strings which are no longer in use add a method to check the i18n strings are obsolete Makefile.am | 5 +++ contrib/check_i18n.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ plugins/sample/i18n.py | 1 - src/kimchi/i18n.py | 4 --- 4 files changed, 87 insertions(+), 5 deletions(-) create mode 100755 contrib/check_i18n.py -- 1.8.5.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> When I do i18n translation, I find some string formattings are wrong. So I add a check-local command to help the developer to check their string formatting. Every developers please run this command before submit your patch. After you run this command, it may report some invalid string formattings as follow. $ make check-local Checking for invalid i18n string... bad i18n string formatting: KCHAPI0005E: Create is not allowed for %(resource). make: *** [check-local] Error 1 You should check %(resource) is what you want. Ref: https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- Makefile.am | 5 +++++ contrib/check_i18n.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100755 contrib/check_i18n.py diff --git a/Makefile.am b/Makefile.am index 6831b5d..ca5623d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -76,7 +76,12 @@ PEP8_WHITELIST = \ SKIP_PYFLAKES_ERR = "\./src/kimchi/websocket\.py" +I18N_FILES = plugins/*/i18n.py \ + src/kimchi/i18n.py \ + $(NULL) + check-local: + contrib/check_i18n.py $(I18N_FILES) find . -path './.git' -prune -type f -o \ -name '*.py' -o -name '*.py.in' | xargs $(PYFLAKES) | \ grep -w -v $(SKIP_PYFLAKES_ERR) | \ diff --git a/contrib/check_i18n.py b/contrib/check_i18n.py new file mode 100755 index 0000000..d5220d9 --- /dev/null +++ b/contrib/check_i18n.py @@ -0,0 +1,62 @@ +#!/usr/bin/python +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import imp +import os +import re +import sys + + +# Match all conversion specifier with mapping key +PATTERN = re.compile(r'''%\([^)]+\) # Mapping key + [#0\-+]? # Conversion flags (optional) + (\d+|\*)? # Minimum field width (optional) + (\.(\d+|\*))? # Precision (optional) + [lLh]? # Length modifier (optional) + [cdeEfFgGioursxX%] # Conversion type''', + re.VERBOSE) +BAD_PATTERN = re.compile(r"%\([^)]*?\)") + + +def load_i18n_module(i18nfile): + path = os.path.dirname(i18nfile) + mname = i18nfile.replace("/", "_").rstrip(".py") + mobj = imp.find_module("i18n", [path]) + return imp.load_module(mname, *mobj) + + +def check_string_formatting(messages): + for k, v in messages.iteritems(): + if BAD_PATTERN.findall(PATTERN.sub(" ", v)): + print "bad i18n string formatting:" + print " %s: %s" % (k, v) + exit(1) + + +def main(): + print "Checking for invalid i18n string..." + for f in sys.argv[1:]: + messages = load_i18n_module(f).messages + check_string_formatting(messages) + print "Checking for invalid i18n string successfully" + + +if __name__ == '__main__': + main() -- 1.8.5.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> These strings are no longer in use, but they still remain in i18n.py Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- plugins/sample/i18n.py | 1 - src/kimchi/i18n.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py index 8957e11..72d9783 100644 --- a/plugins/sample/i18n.py +++ b/plugins/sample/i18n.py @@ -26,7 +26,6 @@ messages = { "SPAPI0001E": _("Unkown parameter specified %(value)s"), "SPAPI0002E": _("The specified value %(value)s is not a positive number"), - "SPCIRC0001E": _("Circle %(name)s already exists"), "SPCIRC0002E": _("Circle %(name)s does not exist"), "SPCIRC0003E": _("Specify name and radius to create a Circle"), "SPCIRC0004E": _("Circle name must be a string"), diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index ae8d24e..2062227 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -37,7 +37,6 @@ messages = { "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), "KCHAUTH0002E": _("You are not authorized to access Kimchi"), "KCHAUTH0003E": _("Specify %(item)s to login into Kimchi"), - "KCHAUTH0004E": _("This operation is not allowed as you have restricted access to Kimchi."), "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), @@ -113,7 +112,6 @@ messages = { "KCHPOOL0001E": _("Storage pool %(name)s already exists"), "KCHPOOL0002E": _("Storage pool %(name)s does not exist"), - "KCHPOOL0003E": _("Autostart flag must be true or false"), "KCHPOOL0004E": _("Specify %(item)s in order to create the storage pool %(name)s"), "KCHPOOL0005E": _("Unable to delete active storage pool %(name)s"), "KCHPOOL0006E": _("Unable to list storage pools. Details: %(err)s"), @@ -178,7 +176,6 @@ messages = { "KCHNET0007E": _("Interface should be bare NIC, bonding or bridge device."), "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), - "KCHNET0010E": _("Unable to create VLAN tagged bridge using interface %(iface)s. Details: %(err)s"), "KCHNET0011E": _("Network name must be a string"), "KCHNET0012E": _("Supported network types are isolated, NAT and bridge"), "KCHNET0013E": _("Network subnet must be a string with IP address and prefix or netmask"), @@ -224,7 +221,6 @@ messages = { "KCHCDROM0002E": _("Invalid storage type. Types supported: 'cdrom'"), "KCHCDROM0003E": _("The path '%(value)s' is not valid local/remote path for the device"), "KCHCDROM0004E": _("Device name %(dev_name)s already exists in vm %(vm_name)s"), - "KCHCDROM0006E": _("Can't specify a directory for a CDROM device path"), "KCHCDROM0007E": _("The storage device %(dev_name)s does not exist in the guest %(vm_name)s"), "KCHCDROM0008E": _("Error while creating new storage device: %(error)s"), "KCHCDROM0009E": _("Error while updating storage device: %(error)s"), -- 1.8.5.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> There are some i18n strings are no longer in use in source code. But they are still remain in i18n.py. We should add a mechanism to check the obsolete i18n strings. Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- contrib/check_i18n.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/contrib/check_i18n.py b/contrib/check_i18n.py index d5220d9..c542e0b 100755 --- a/contrib/check_i18n.py +++ b/contrib/check_i18n.py @@ -50,11 +50,31 @@ def check_string_formatting(messages): exit(1) +def check_obsolete_messages(path, messages): + def find_message_key(path, k): + for root, dirs, files in os.walk(path): + for f in files: + fname = os.path.join(root, f) + if (not fname.endswith("i18n.py") and fname.endswith(".py") + or fname.endswith(".json")): + with open(fname) as f: + string = "".join(f.readlines()) + if k in string: + return True + return False + + for k in messages.iterkeys(): + if not find_message_key(path, k): + print " %s is obsolete, it is no longer in use" % k + exit(1) + + def main(): print "Checking for invalid i18n string..." for f in sys.argv[1:]: messages = load_i18n_module(f).messages check_string_formatting(messages) + check_obsolete_messages(os.path.dirname(f), messages) print "Checking for invalid i18n string successfully" -- 1.8.5.3
participants (2)
-
Aline Manera
-
shaohef@linux.vnet.ibm.com