From: Bruno Haible Date: Mon, 10 Sep 2007 00:27:34 +0000 (+0000) Subject: Add support for Qt 4 format strings. X-Git-Tag: v0.17~256 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5bb62c8d4d5d0ce2791e3bf9dd2a36a1d104e0e5;p=thirdparty%2Fgettext.git Add support for Qt 4 format strings. --- diff --git a/NEWS b/NEWS index ff3fdcdae..5728582a4 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,8 @@ Version 0.16.2 - January 2007 be updated all together. * Programming languages support: - Contexts (msgctxt) are now also supported for Java and C#. + - Contexts (msgctxt) are now also supported for Java and C#. + - C# with Qt: The support for Qt format strings has been updated for Qt 4. * Documentation: The "Users" chapter has been completely rewritten. diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog index d45547fc0..e6e940e45 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog @@ -1,3 +1,14 @@ +2007-09-09 Bruno Haible + + Add support for Qt 4 format strings. + * format-qt.c (struct spec): Increase args_used field size to 100. + Add 'simple' field. + (format_parse): Update for Qt 4 syntax. Remove error message when the + same format argument is used more than once. + (format_check): Add check: If the msgid is simple, the msgstr must be + simple as well. + Reported by Chusslove Illich . + 2007-09-02 Bruno Haible Correct handling of different libexpat ABIs. diff --git a/gettext-tools/src/format-qt.c b/gettext-tools/src/format-qt.c index 75407ed64..49abf1a77 100644 --- a/gettext-tools/src/format-qt.c +++ b/gettext-tools/src/format-qt.c @@ -31,22 +31,37 @@ #define _(str) gettext (str) /* Qt format strings are processed by QString::arg and are documented in - qt-3.0.5/doc/html/qstring.html. - A directive starts with '%' and is followed by a digit ('0' to '9'). - Each %n must occur only once in the given string. + qt-4.3.0/doc/html/qstring.html. + A directive + - starts with '%', + - is optionally followed by 'L' (indicates locale-dependent processing), + - is followed by one or two digits ('0' to '9'). %0n is equivalent to %n. + An unterminated directive ('%' or '%L' not followed by a digit or at the + end) is not an error. The first .arg() invocation replaces the %n with the lowest numbered n, the next .arg() invocation then replaces the %n with the second-lowest numbered n, and so on. - (This is inherently buggy because a '%' in the first replacement confuses - the second .arg() invocation.) + This is inherently buggy because a '%' in the first replacement confuses + the second .arg() invocation. + To reduce this problem and introduce another one, there are also .arg() + methods that take up to 9 strings and perform the replacements in one swoop. + But this method works only on strings that contain no 'L' flags and only + single-digit argument designators. Although %0 is supported, usually %1 denotes the first argument, %2 the second argument etc. */ struct spec { + /* Number of format directives. */ unsigned int directives; + + /* True if the string supports the multi-argument .arg() methods, i.e. if it + contains no 'L' flags and only single-digit argument designators. */ + bool simple; + + /* Booleans telling which %nn was seen. */ unsigned int arg_count; - bool args_used[10]; + bool args_used[100]; }; @@ -59,42 +74,51 @@ format_parse (const char *format, bool translated, char *fdi, struct spec *result; spec.directives = 0; + spec.simple = true; spec.arg_count = 0; for (; *format != '\0';) if (*format++ == '%') - if (*format >= '0' && *format <= '9') - { - /* A directive. */ - unsigned int number; - - FDI_SET (format - 1, FMTDIR_START); - spec.directives++; - - number = *format - '0'; - - while (spec.arg_count <= number) - spec.args_used[spec.arg_count++] = false; - if (spec.args_used[number]) - { - *invalid_reason = - xasprintf (_("Multiple references to %%%c."), *format); - FDI_SET (format, FMTDIR_ERROR); - goto bad_format; - } - spec.args_used[number] = true; - - FDI_SET (format, FMTDIR_END); - - format++; - } + { + const char *dir_start = format - 1; + bool locale_flag = false; + + if (*format == 'L') + { + locale_flag = true; + format++; + } + if (*format >= '0' && *format <= '9') + { + /* A directive. */ + unsigned int number; + + FDI_SET (dir_start, FMTDIR_START); + spec.directives++; + if (locale_flag) + spec.simple = false; + + number = *format - '0'; + if (format[1] >= '0' && format[1] <= '9') + { + number = 10 * number + (format[1] - '0'); + spec.simple = false; + format++; + } + + while (spec.arg_count <= number) + spec.args_used[spec.arg_count++] = false; + spec.args_used[number] = true; + + FDI_SET (format, FMTDIR_END); + + format++; + } + } result = XMALLOC (struct spec); *result = spec; return result; - - bad_format: - return NULL; } static void @@ -123,25 +147,34 @@ format_check (void *msgid_descr, void *msgstr_descr, bool equality, bool err = false; unsigned int i; - for (i = 0; i < spec1->arg_count || i < spec2->arg_count; i++) + if (spec1->simple && !spec2->simple) { - bool arg_used1 = (i < spec1->arg_count && spec1->args_used[i]); - bool arg_used2 = (i < spec2->arg_count && spec2->args_used[i]); - - /* The translator cannot omit a %n from the msgstr because that would - yield a "Argument missing" warning at runtime. */ - if (arg_used1 != arg_used2) - { - if (error_logger) - error_logger (arg_used1 - ? _("a format specification for argument %u doesn't exist in '%s'") - : _("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"), - i, pretty_msgstr); - err = true; - break; - } + if (error_logger) + error_logger (_("'msgid' is a simple format string, but '%s' is not: it contains an 'L' flag or a double-digit argument number"), + pretty_msgstr); + err = true; } + if (!err) + for (i = 0; i < spec1->arg_count || i < spec2->arg_count; i++) + { + bool arg_used1 = (i < spec1->arg_count && spec1->args_used[i]); + bool arg_used2 = (i < spec2->arg_count && spec2->args_used[i]); + + /* The translator cannot omit a %n from the msgstr because that would + yield a "Argument missing" warning at runtime. */ + if (arg_used1 != arg_used2) + { + if (error_logger) + error_logger (arg_used1 + ? _("a format specification for argument %u doesn't exist in '%s'") + : _("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"), + i, pretty_msgstr); + err = true; + break; + } + } + return err; } diff --git a/gettext-tools/tests/ChangeLog b/gettext-tools/tests/ChangeLog index c4e908551..5f2161aae 100644 --- a/gettext-tools/tests/ChangeLog +++ b/gettext-tools/tests/ChangeLog @@ -1,3 +1,10 @@ +2007-09-09 Bruno Haible + + Add support for Qt 4 format strings. + * format-qt-1: Update for Qt 4 syntax. + * format-qt-2: Likewise. + Based on input by by Chusslove Illich . + 2007-09-02 Bruno Haible Implement msgctxt for C# ResourceManagers. diff --git a/gettext-tools/tests/format-qt-1 b/gettext-tools/tests/format-qt-1 index 74df988a1..e2207bc32 100755 --- a/gettext-tools/tests/format-qt-1 +++ b/gettext-tools/tests/format-qt-1 @@ -13,16 +13,28 @@ cat <<\EOF > f-qt-1.data "abc%1def" # Valid: one argument "abc%9def" +# Valid: one argument specified by two digits +"abc%09def" +# Valid: one argument specified by two digits +"abc%99def" # Valid: unterminated "abc%1def%" +# Valid: unterminated +"abc%1def%L" # Valid: non-digit "abc%1def%x" # Valid: zero "abc%1def%0" +# Valid: zero specified by two digits +"abc%1def%00" # Valid: permutation "abc%2def%1" -# Invalid: multiple uses of same argument +# Valid: multiple uses of same argument "abc%2def%1ghi%2" +# Valid: an argument with locale-dependency flag +"abc%L1def" +# Valid: an argument with locale-dependency flag and two digits +"abc%L12def" EOF : ${XGETTEXT=xgettext} diff --git a/gettext-tools/tests/format-qt-2 b/gettext-tools/tests/format-qt-2 index e0118679b..0f8005e2c 100755 --- a/gettext-tools/tests/format-qt-2 +++ b/gettext-tools/tests/format-qt-2 @@ -10,12 +10,27 @@ cat <<\EOF > f-qt-2.data # Valid: %% doesn't count msgid "abc%%def" msgstr "xyz" -# Invalid: invalid msgstr -msgid "abc%1def" -msgstr "xyz%1%1" # Valid: same arguments msgid "abc%2def" msgstr "xyz%2" +# Valid: same arguments, msgstr may be simpler than msgid +msgid "abc%L2def" +msgstr "xyz%2" +# Valid: same arguments, msgstr may be simpler than msgid +msgid "abc%02def" +msgstr "xyz%2" +# Invalid: msgid is simple but msgstr is not +msgid "abc%2def" +msgstr "xyz%L2" +# Invalid: msgid is simple but msgstr is not +msgid "abc%2def" +msgstr "xyz%02" +# Valid: repetition of an argument in the translation +msgid "abc%2def" +msgstr "xyz%2uvw%2" +# Valid: removing repeated argument in the translation +msgid "abc%2def%2" +msgstr "xyz%2uvw" # Valid: permutation msgid "abc%3%1%2def" msgstr "xyz%2%1%3"