From 4cd233af3b8916c74c301d90a3fd1d831dd13bb8 Mon Sep 17 00:00:00 2001
From: Philip Withnall <philip.withnall@collabora.co.uk>
Date: Thu, 25 Aug 2016 18:46:03 +0100
Subject: [PATCH] xgettext: Add support for ClutterScript
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

ClutterScript is a UI definition language for the Clutter toolkit, based
on JSON. It allows marking translatable strings by adding a
‘translatable’ attribute to an object, and putting the string to be
translated in a ‘string’ attribute. Translations are looked up by
Clutter at runtime, rather than being merged back into the ClutterScript
file.

https://developer.gnome.org/clutter/stable/ClutterScript.html

This adds an extractor for ClutterScript files, which uses json-c to
parse the JSON. The dependency is optional, and can be disabled by
compiling gettext with --without-json-c.

A couple of new test cases are included, which will be skipped if
ClutterScript support is compiled out.
---
 gettext-tools/configure.ac                   |  14 ++
 gettext-tools/doc/gettext.texi               |  18 ++-
 gettext-tools/doc/xgettext.texi              |   4 +-
 gettext-tools/src/FILES                      |   3 +
 gettext-tools/src/Makefile.am                |  10 +-
 gettext-tools/src/x-clutterscript.c          | 234 +++++++++++++++++++++++++++
 gettext-tools/src/x-clutterscript.h          |  43 +++++
 gettext-tools/src/xgettext.c                 |   9 +-
 gettext-tools/tests/Makefile.am              |   1 +
 gettext-tools/tests/xgettext-clutterscript-1 |  97 +++++++++++
 gettext-tools/tests/xgettext-clutterscript-2 |  27 ++++
 11 files changed, 450 insertions(+), 10 deletions(-)
 create mode 100644 gettext-tools/src/x-clutterscript.c
 create mode 100644 gettext-tools/src/x-clutterscript.h
 create mode 100644 gettext-tools/tests/xgettext-clutterscript-1
 create mode 100644 gettext-tools/tests/xgettext-clutterscript-2

diff --git a/gettext-tools/configure.ac b/gettext-tools/configure.ac
index 3b132ed..89c1201 100644
--- a/gettext-tools/configure.ac
+++ b/gettext-tools/configure.ac
@@ -87,6 +87,20 @@ gl_EARLY
 grgl_EARLY
 gtpo_EARLY
 
+dnl JSON parser for ClutterScript files (optional)
+AC_ARG_WITH([json-c],[
+  AS_HELP_STRING([--with-json-c],[Build with json-c for ClutterScript support])
+],[],[with_json_c=maybe])
+
+AS_IF([test "$with_json_c" != "no"],[
+  PKG_CHECK_MODULES([JSON_C],[json-c],[have_json_c=yes],[have_json_c=no])
+])
+
+AS_IF([test "$with_json_c" != "no" && test "$have_json_c" = "yes"],
+      [AC_DEFINE([HAVE_JSON_C],[1],[Define when json-c is available.])],
+      [test "$with_json_c" = "yes" && test "$have_json_c" != "yes"],
+      [AC_MSG_ERROR([json-c dependency requested but json-c.pc not found.])])
+
 dnl Check for build configuration.
 
 gl_WOE32_DLL
diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi
index 1e332be..488ceb3 100644
--- a/gettext-tools/doc/gettext.texi
+++ b/gettext-tools/doc/gettext.texi
@@ -468,6 +468,7 @@ Internationalizable Data
 * POT::                         POT - Portable Object Template
 * RST::                         Resource String Table
 * Glade::                       Glade - GNOME user interface description
+* ClutterScript::               ClutterScript - Clutter user interface description
 * GSettings::                   GSettings - GNOME user configuration schema
 * AppData::                     AppData - freedesktop.org application description
 * Preparing ITS Rules::         Preparing Rules for XML Internationalization
@@ -12154,6 +12155,7 @@ using GNU gettext.
 * POT::                         POT - Portable Object Template
 * RST::                         Resource String Table
 * Glade::                       Glade - GNOME user interface description
+* ClutterScript::               ClutterScript - Clutter user interface description
 * GSettings::                   GSettings - GNOME user configuration schema
 * AppData::                     AppData - freedesktop.org application description
 * Preparing ITS Rules::  Preparing Rules for XML Internationalization
@@ -12202,7 +12204,21 @@ glade, libglade, glade2, libglade2, intltool
 @code{xgettext}, @code{libglade-xgettext}, @code{xml-i18n-extract}, @code{intltool-extract}
 @end table
 
-@node GSettings, AppData, Glade, List of Data Formats
+@node ClutterScript, GSettings, Glade, List of Data Formats
+@subsection ClutterScript - Clutter user interface description
+
+@table @asis
+@item RPMs
+clutter, clutter-gtk
+
+@item File extension
+@code{json}
+
+@item Extractor
+@code{xgettext}
+@end table
+
+@node GSettings, AppData, ClutterScript, List of Data Formats
 @subsection GSettings - GNOME user configuration schema
 
 @table @asis
diff --git a/gettext-tools/doc/xgettext.texi b/gettext-tools/doc/xgettext.texi
index e2700d9..c26e4d0 100644
--- a/gettext-tools/doc/xgettext.texi
+++ b/gettext-tools/doc/xgettext.texi
@@ -74,7 +74,7 @@ are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, @code{Shell},
 @code{Smalltalk}, @code{Java}, @code{JavaProperties}, @code{C#}, @code{awk},
 @code{YCP}, @code{Tcl}, @code{Perl}, @code{PHP}, @code{GCC-source},
 @code{NXStringTable}, @code{RST}, @code{Glade}, @code{Lua}, @code{JavaScript},
-@code{Vala}, @code{GSettings}, @code{Desktop}.
+@code{Vala}, @code{GSettings}, @code{Desktop}, @code{ClutterScript}.
 
 @item -C
 @itemx --c++
@@ -214,7 +214,7 @@ Extract all strings.
 
 This option has an effect with most languages, namely C, C++, ObjectiveC,
 Shell, Python, Lisp, EmacsLisp, librep, Java, C#, awk, Tcl, Perl, PHP,
-GCC-source, Glade, Lua, JavaScript, Vala, GSettings.
+GCC-source, Glade, Lua, JavaScript, Vala, GSettings, ClutterScript.
 
 @item -k[@var{keywordspec}]
 @itemx --keyword[=@var{keywordspec}]
diff --git a/gettext-tools/src/FILES b/gettext-tools/src/FILES
index b647a84..da8f0c8 100644
--- a/gettext-tools/src/FILES
+++ b/gettext-tools/src/FILES
@@ -360,6 +360,9 @@ msgl-check.c
 | x-appdata.h
 | x-appdata.c
 |               String extractor for AppData files.
+| x-clutterscript.h
+| x-clutterscript.c
+|               String extractor for ClutterScript files; Clutter GUI descriptions.
 | xgettext.c
 |               Main source for the 'xgettext' program.
 |
diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am
index 0538d1e..2b39524 100644
--- a/gettext-tools/src/Makefile.am
+++ b/gettext-tools/src/Makefile.am
@@ -55,7 +55,7 @@ po-time.h plural-table.h lang-table.h format.h filters.h \
 xgettext.h x-c.h x-po.h x-sh.h x-python.h x-lisp.h x-elisp.h x-librep.h \
 x-scheme.h x-smalltalk.h x-java.h x-properties.h x-csharp.h x-awk.h x-ycp.h \
 x-tcl.h x-perl.h x-php.h x-stringtable.h x-rst.h x-glade.h x-lua.h \
-x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h
+x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h x-clutterscript.h
 
 EXTRA_DIST += FILES project-id
 
@@ -70,7 +70,8 @@ AM_CPPFLAGS = \
   -I.. -I$(top_srcdir) \
   -I$(top_srcdir)/libgrep \
   -I../gnulib-lib -I$(top_srcdir)/gnulib-lib \
-  -I../intl -I$(top_srcdir)/../gettext-runtime/intl
+  -I../intl -I$(top_srcdir)/../gettext-runtime/intl \
+  $(JSON_C_CFLAGS)
 DEFS = \
   -DLOCALEDIR=\"$(localedir)\" -DBISON_LOCALEDIR=\"$(BISON_LOCALEDIR)\" \
   -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \
@@ -184,7 +185,8 @@ xgettext_SOURCES += \
   x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \
   x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \
   x-rst.c x-lua.c x-javascript.c x-vala.c \
-  x-desktop.c
+  x-desktop.c x-clutterscript.c
+
 if !WOE32DLL
 msgattrib_SOURCES = msgattrib.c
 else
@@ -289,7 +291,7 @@ msgcmp_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD
 msgfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD)
 msgmerge_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD) $(OPENMP_CFLAGS)
 msgunfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD)
-xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBICONV@ $(WOE32_LDADD)
+xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBICONV@ $(WOE32_LDADD) $(JSON_C_LIBS)
 msgattrib_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD)
 msgcat_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD)
 msgcomm_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD)
diff --git a/gettext-tools/src/x-clutterscript.c b/gettext-tools/src/x-clutterscript.c
new file mode 100644
index 0000000..97149a5
--- /dev/null
+++ b/gettext-tools/src/x-clutterscript.c
@@ -0,0 +1,234 @@
+/* xgettext ClutterScript backend.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file was written by Philip Withnall <philip.withnall@collabora.co.uk>, 2016.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "x-clutterscript.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#ifdef HAVE_JSON_C
+#include <json.h>
+#endif
+
+#include "gettext.h"
+#include "message.h"
+#include "xgettext.h"
+#include "po-charset.h"
+#include "pos.h"
+#include "xalloc.h"
+#include "xvasprintf.h"
+
+#define _(str) gettext (str)
+
+/* ClutterScript is defined here:
+   https://developer.gnome.org/clutter/stable/ClutterScript.html
+
+   Basically, any string can be replaced with an object with two mandatory
+   properties:
+    - translatable: bool
+    - string: string
+   and two optional properties:
+    - domain: string
+    - context: string
+
+   For example:
+     {
+       "translatable": true,
+       "string": "Translate me!",
+       "context": "Button text"
+     }
+ */
+
+#ifdef HAVE_JSON_C
+
+static void extract_from_object (json_object       *object,
+                                 msgdomain_list_ty *mdlp,
+                                 const char        *logical_filename);
+static void extract_from_array (json_object        *array,
+                                msgdomain_list_ty  *mdlp,
+                                const char         *logical_filename);
+
+void
+extract_clutterscript (FILE *f,
+                       const char *real_filename, const char *logical_filename,
+                       flag_context_list_table_ty *flag_table,
+                       msgdomain_list_ty *mdlp)
+{
+  json_object *jobj = NULL;
+  json_tokener *tokener = NULL;
+  uint8_t buf[1024];
+  size_t n_read;
+
+  /* JSON strings are always in UTF-8. */
+  xgettext_current_source_encoding = po_charset_utf8;
+
+  tokener = json_tokener_new ();
+
+  while (!feof (f) && !ferror (f))
+    {
+      n_read = fread (buf, sizeof (*buf), sizeof (buf), f);
+      jobj = json_tokener_parse_ex (tokener, (const char *) buf, n_read);
+
+      if (json_tokener_get_error (tokener) != json_tokener_continue)
+        break;
+    }
+
+  if (json_tokener_get_error (tokener) != json_tokener_success)
+    {
+      const char *error_message;
+
+      /* Bail! */
+      if (json_tokener_get_error (tokener) == json_tokener_continue)
+        error_message = _("File ended unexpectedly before JSON finished.");
+      else
+        error_message = json_tokener_error_desc (json_tokener_get_error (tokener));
+
+      multiline_error (xstrdup (""),
+                       xasprintf (_("Error parsing JSON file ‘%s’:\n%s\n"),
+                                  logical_filename, error_message));
+      json_tokener_free (tokener);
+
+      exit (EXIT_FAILURE);
+    }
+
+  assert (jobj != NULL);
+
+  /* Traverse the JSON tree and find any objects which have a `translatable`
+   * and a `string` property. */
+  extract_from_object (jobj, mdlp, logical_filename);
+
+  json_object_put (jobj);
+  json_tokener_free (tokener);
+}
+
+static void
+extract_from_node (json_object       *jobj,
+                   msgdomain_list_ty *mdlp,
+                   const char        *logical_filename)
+{
+  switch (json_object_get_type (jobj))
+    {
+    case json_type_null:
+    case json_type_boolean:
+    case json_type_double:
+    case json_type_int:
+    case json_type_string:
+      /* Nothing to extract here. */
+      return;
+    case json_type_object:
+      extract_from_object (jobj, mdlp, logical_filename);
+      return;
+    case json_type_array:
+      extract_from_array (jobj, mdlp, logical_filename);
+      break;
+    default:
+      /* This should never be reached. */
+      assert (false);
+    }
+}
+
+static void
+extract_from_object (json_object       *object,
+                     msgdomain_list_ty *mdlp,
+                     const char        *logical_filename)
+{
+  json_object *translatable = NULL, *string = NULL;
+  json_object *domain = NULL, *context = NULL;
+
+  /* Is this a translatable string? */
+  json_object_object_get_ex (object, "translatable", &translatable);
+  json_object_object_get_ex (object, "string", &string);
+
+  if (translatable != NULL && string != NULL &&
+      json_object_is_type (translatable, json_type_boolean) &&
+      json_object_get_boolean (translatable) &&
+      json_object_is_type (string, json_type_string))
+    {
+      char *context_string = NULL, *domain_string = NULL;
+      lex_pos_ty pos;
+      message_list_ty *mlp;
+
+      /* It is a translatable string: extract and remember it. */
+      json_object_object_get_ex (object, "domain", &domain);
+      json_object_object_get_ex (object, "context", &context);
+
+      if (domain != NULL &&
+          json_object_is_type (domain, json_type_string))
+        domain_string = xstrdup (json_object_get_string (domain));
+
+      if (context != NULL &&
+          json_object_is_type (context, json_type_string))
+        context_string = xstrdup (json_object_get_string (context));
+
+      /* ClutterScript supports multiple domains — make sure we append to the
+       * correct one. */
+      if (domain_string != NULL && *domain_string != '\0')
+        {
+          mlp = msgdomain_list_sublist (mdlp, domain_string, TRUE);
+        }
+      else
+        {
+          mlp = mdlp->item[0]->messages;
+          free (domain_string);
+        }
+
+      pos.file_name = (char *) logical_filename;
+      pos.line_number = 0;  /* no way to get line numbers from json-c */
+
+      remember_a_message (mlp, context_string,
+                          xstrdup (json_object_get_string (string)),
+                          null_context, &pos, NULL, NULL);
+    }
+
+  /* Recurse through the object’s properties. */
+  json_object_object_foreach (object, key, child)
+    extract_from_node (child, mdlp, logical_filename);
+}
+
+static void
+extract_from_array (json_object       *array,
+                    msgdomain_list_ty *mdlp,
+                    const char        *logical_filename)
+{
+  int i;
+
+  for (i = 0; i < json_object_array_length (array); i++)
+    extract_from_node (json_object_array_get_idx (array, i),
+                       mdlp, logical_filename);
+}
+
+#else /* if !HAVE_JSON_C */
+
+void
+extract_clutterscript (FILE *f,
+                       const char *real_filename, const char *logical_filename,
+                       flag_context_list_table_ty *flag_table,
+                       msgdomain_list_ty *mdlp)
+{
+  multiline_error (xstrdup (""),
+                   xasprintf (_("Parsing JSON is not supported by this "
+                                "version of xgettext.\n")));
+
+  exit (EXIT_FAILURE);
+}
+
+#endif /* !HAVE_JSON_C */
diff --git a/gettext-tools/src/x-clutterscript.h b/gettext-tools/src/x-clutterscript.h
new file mode 100644
index 0000000..058e189
--- /dev/null
+++ b/gettext-tools/src/x-clutterscript.h
@@ -0,0 +1,43 @@
+/* xgettext ClutterScript backend.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Written by Philip Withnall <philip.withnall@collabora.co.uk>, 2016.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include <stdio.h>
+
+#include "message.h"
+#include "xgettext.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EXTENSIONS_CLUTTERSCRIPT \
+  { "json", "ClutterScript" }, \
+
+#define SCANNERS_CLUTTERSCRIPT \
+  { "ClutterScript", extract_clutterscript, NULL, NULL, NULL, NULL }, \
+
+/* Scan a ClutterScript file and add its translatable strings to mdlp. */
+extern void extract_clutterscript (FILE *fp, const char *real_filename,
+                                   const char *logical_filename,
+                                   flag_context_list_table_ty *flag_table,
+                                   msgdomain_list_ty *mdlp);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c
index f848d76..ec80003 100644
--- a/gettext-tools/src/xgettext.c
+++ b/gettext-tools/src/xgettext.c
@@ -106,6 +106,7 @@
 #include "x-vala.h"
 #include "x-gsettings.h"
 #include "x-desktop.h"
+#include "x-clutterscript.h"
 
 
 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
@@ -1077,7 +1078,7 @@ Choice of input file language:\n"));
                                 EmacsLisp, librep, Scheme, Smalltalk, Java,\n\
                                 JavaProperties, C#, awk, YCP, Tcl, Perl, PHP,\n\
                                 GCC-source, NXStringTable, RST, Glade, Lua,\n\
-                                JavaScript, Vala, Desktop)\n"));
+                                JavaScript, Vala, Desktop, ClutterScript)\n"));
       printf (_("\
   -C, --c++                   shorthand for --language=C++\n"));
       printf (_("\
@@ -1087,7 +1088,7 @@ By default the language is guessed depending on the input file name extension.\n
 Input file interpretation:\n"));
       printf (_("\
       --from-code=NAME        encoding of input files\n\
-                                (except for Python, Tcl, Glade)\n"));
+                                (except for Python, Tcl, Glade, ClutterScript)\n"));
       printf (_("\
 By default the input files are assumed to be in ASCII.\n"));
       printf ("\n");
@@ -1119,7 +1120,7 @@ Language specific options:\n"));
                                 (only languages C, C++, ObjectiveC, Shell,\n\
                                 Python, Lisp, EmacsLisp, librep, Scheme, Java,\n\
                                 C#, awk, Tcl, Perl, PHP, GCC-source, Glade,\n\
-                                Lua, JavaScript, Vala)\n"));
+                                Lua, JavaScript, Vala, ClutterScript)\n"));
       printf (_("\
   -kWORD, --keyword=WORD      look for WORD as an additional keyword\n\
   -k, --keyword               do not to use default keywords\n"));
@@ -3901,6 +3902,7 @@ language_to_extractor (const char *name)
     SCANNERS_GSETTINGS
     SCANNERS_DESKTOP
     SCANNERS_APPDATA
+    SCANNERS_CLUTTERSCRIPT
     /* Here may follow more languages and their scanners: pike, etc...
        Make sure new scanners honor the --exclude-file option.  */
   };
@@ -3992,6 +3994,7 @@ extension_to_language (const char *extension)
     EXTENSIONS_GSETTINGS
     EXTENSIONS_DESKTOP
     EXTENSIONS_APPDATA
+    EXTENSIONS_CLUTTERSCRIPT
     /* Here may follow more file extensions... */
   };
 
diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am
index 23b09b1..84e617e 100644
--- a/gettext-tools/tests/Makefile.am
+++ b/gettext-tools/tests/Makefile.am
@@ -81,6 +81,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
 	xgettext-c-11 xgettext-c-12 xgettext-c-13 xgettext-c-14 xgettext-c-15 \
 	xgettext-c-16 xgettext-c-17 xgettext-c-18 xgettext-c-19 xgettext-c-20 \
 	xgettext-c-21 \
+	xgettext-clutterscript-1 xgettext-clutterscript-2 \
 	xgettext-csharp-1 xgettext-csharp-2 xgettext-csharp-3 \
 	xgettext-csharp-4 xgettext-csharp-5 xgettext-csharp-6 \
 	xgettext-csharp-7 xgettext-csharp-8 \
diff --git a/gettext-tools/tests/xgettext-clutterscript-1 b/gettext-tools/tests/xgettext-clutterscript-1
new file mode 100644
index 0000000..b8d91bb
--- /dev/null
+++ b/gettext-tools/tests/xgettext-clutterscript-1
@@ -0,0 +1,97 @@
+#!/bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test of ClutterScript support.
+
+cat <<EOF > xg-clutterscript-1-empty.json
+{}
+EOF
+
+: ${XGETTEXT=xgettext}
+${XGETTEXT} -o xg-clutterscript-1.pot xg-clutterscript-1-empty.json 2>/dev/null
+test $? = 0 || {
+  echo "Skipping test: xgettext was built without ClutterScript support"
+  exit 77
+}
+
+cat <<EOF > xg-clutterscript-1.json
+{
+  "id" : "label",
+  "type" : "ClutterText",
+  "str1" : {
+    "translatable" : true,
+    "string" : "Clutter Script",
+    "context" : "Message Context"
+  },
+  "str2" : {
+    "translatable" : true,
+    "string" : "Has translatable strings"
+  },
+  "str3" : {
+    "translatable" : false,
+    "string" : "And non-translatable strings"
+  },
+  "str4" : {
+    "translatable" : true,
+    "string" : "In another domain",
+    "domain" : "other"
+  },
+  "array" : [
+    { "translatable" : true, "string" : "test1" },
+    { "translatable" : false, "string" : "test2" },
+    { "translatable" : true, "string" : "test3" }
+  ]
+}
+EOF
+
+: ${XGETTEXT=xgettext}
+${XGETTEXT} -o - xg-clutterscript-1.json | grep -v 'POT-Creation-Date' > xg-clutterscript-1.pot || exit 1
+
+cat <<EOF > xg-clutterscript-1.ok
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: xg-clutterscript-1.json:0
+msgctxt "Message Context"
+msgid "Clutter Script"
+msgstr ""
+
+#: xg-clutterscript-1.json:0
+msgid "Has translatable strings"
+msgstr ""
+
+#: xg-clutterscript-1.json:0
+msgid "test1"
+msgstr ""
+
+#: xg-clutterscript-1.json:0
+msgid "test3"
+msgstr ""
+
+domain "other"
+
+#: xg-clutterscript-1.json:0
+msgid "In another domain"
+msgstr ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-clutterscript-1.ok xg-clutterscript-1.pot
+result=$?
+
+exit $result
diff --git a/gettext-tools/tests/xgettext-clutterscript-2 b/gettext-tools/tests/xgettext-clutterscript-2
new file mode 100644
index 0000000..81381aa
--- /dev/null
+++ b/gettext-tools/tests/xgettext-clutterscript-2
@@ -0,0 +1,27 @@
+#!/bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test of ClutterScript support.
+
+cat <<EOF > xg-clutterscript-2-empty.json
+{}
+EOF
+
+: ${XGETTEXT=xgettext}
+${XGETTEXT} -o xg-clutterscript-2.pot xg-clutterscript-2-empty.json 2>/dev/null
+test $? = 0 || {
+  echo "Skipping test: xgettext was built without ClutterScript support"
+  Exit 77
+}
+
+cat <<EOF > xg-clutterscript-2.json
+{
+  this is not valid JSON
+}
+EOF
+
+# xgettext should fail, as the JSON is invalid
+: ${XGETTEXT=xgettext}
+${XGETTEXT} -o - xg-clutterscript-2.json > xg-clutterscript-2.pot && exit 1
+
+exit 0
-- 
2.7.4

