[gtranslator] Translation memory from plugins to src



commit ec1e6417d4dca188559a9038dfcea7c321330886
Author: Daniel García Moreno <danigm wadobo com>
Date:   Fri Sep 7 14:03:21 2018 +0200

    Translation memory from plugins to src

 build-aux/flatpak/org.gnome.Gtranslator.json       |  54 +-
 meson.build                                        |   2 +
 src/gtr-context.c                                  |  30 +
 src/gtr-context.ui                                 |  16 +-
 src/gtr-tab.ui                                     |   2 +
 src/meson.build                                    |   2 +
 src/translation-memory/gda/gda-utils.c             | 152 ++++
 src/translation-memory/gda/gda-utils.h             |  31 +
 src/translation-memory/gda/gtr-gda.c               | 999 +++++++++++++++++++++
 src/translation-memory/gda/gtr-gda.h               |  58 ++
 src/translation-memory/gda/meson.build             |   4 +
 .../gtr-translation-memory-dialog.c                | 375 ++++++++
 .../gtr-translation-memory-dialog.h                |  56 ++
 .../gtr-translation-memory-dialog.ui               | 322 +++++++
 src/translation-memory/gtr-translation-memory-ui.c | 495 ++++++++++
 src/translation-memory/gtr-translation-memory-ui.h |  62 ++
 .../gtr-translation-memory-utils.c                 |  96 ++
 .../gtr-translation-memory-utils.h                 |  33 +
 src/translation-memory/gtr-translation-memory.c    | 208 +++++
 .../gtr-translation-memory.gresource.xml           |   6 +
 src/translation-memory/gtr-translation-memory.h    |  80 ++
 src/translation-memory/meson.build                 |  36 +
 ...lator.plugins.translation-memory.gschema.xml.in |  43 +
 23 files changed, 3133 insertions(+), 29 deletions(-)
---
diff --git a/build-aux/flatpak/org.gnome.Gtranslator.json b/build-aux/flatpak/org.gnome.Gtranslator.json
index 8574a5d2..87e15584 100644
--- a/build-aux/flatpak/org.gnome.Gtranslator.json
+++ b/build-aux/flatpak/org.gnome.Gtranslator.json
@@ -52,32 +52,32 @@
             ]
         },
         {
-            "name" : "gdl",
-            "sources" : [
-                {
-                    "type" : "git",
-                    "url" : "https://gitlab.gnome.org/GNOME/gdl.git";
-                }
-            ]
-        },
-        {
-            "name" : "libgda",
-            "buildsystem" : "meson",
-            "sources" : [
-                {
-                    "type" : "git",
-                    "url" : "https://gitlab.gnome.org/GNOME/libgda.git";
-                }
-            ]
-        },
-        {
-            "name" : "libpeas",
-            "sources" : [
-                {
-                    "type" : "git",
-                    "url" : "https://gitlab.gnome.org/GNOME/libpeas.git";
-                }
-            ]
+          "name": "libgda",
+          "config-opts": [
+            "--enable-json=yes",
+            "--enable-system-sqlite=yes",
+            /* FIXME */
+            "--enable-introspection=no"
+          ],
+          "sources": [
+            {
+              "type": "archive",
+              "url": "http://ftp.gnome.org/pub/GNOME/sources/libgda/5.2/libgda-5.2.4.tar.xz";,
+              "sha256": "2cee38dd583ccbaa5bdf6c01ca5f88cc08758b9b144938a51a478eb2684b765e"
+            }
+          ],
+          "cleanup": [
+            "/include",
+            "/lib/*.a",
+            "/lib/*.la",
+            "/lib/pkgconfig",
+            "/man",
+            "/share/aclocal",
+            "/share/doc",
+            "/share/gtk-doc",
+            "/share/man",
+            "/share/pkgconfig"
+          ]
         },
         {
             "name" : "gettext",
@@ -103,4 +103,4 @@
             ]
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/meson.build b/meson.build
index 81f2ad39..b2df339f 100644
--- a/meson.build
+++ b/meson.build
@@ -113,12 +113,14 @@ add_project_arguments(common_flags, language: 'c')
 
 gtk_dep = dependency('gtk+-3.0', version: '>= 3.22.20')
 glib_dep = dependency('glib-2.0', version: '>=2.36.0')
+gda_dep = dependency('libgda-5.0')
 
 gtranslator_deps = [
   iso_codes_dep,
   po_dep,
   gtk_dep,
   glib_dep,
+  gda_dep,
   dependency('libxml-2.0', version: '>=2.4.12'),
   dependency('gthread-2.0', version: '>=2.13.0'),
   dependency('gio-2.0', version: '>=2.36.0'),
diff --git a/src/gtr-context.c b/src/gtr-context.c
index 2b953ac1..519621c6 100644
--- a/src/gtr-context.c
+++ b/src/gtr-context.c
@@ -22,6 +22,9 @@
 #include "gtr-context.h"
 #include "gtr-tab.h"
 #include "gtr-debug.h"
+#include "translation-memory/gtr-translation-memory.h"
+#include "translation-memory/gtr-translation-memory-ui.h"
+#include "translation-memory/gda/gtr-gda.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -34,6 +37,7 @@ typedef struct
   GtkWidget *context;
   GtkWidget *button_box;
   GtkWidget *button;
+  GtkWidget *translation_memory_box;
 
   GdkCursor *hand_cursor;
   GdkCursor *regular_cursor;
@@ -41,6 +45,11 @@ typedef struct
 
   GtrTab *tab;
   GtrMsg *current_msg;
+
+  // translation memory
+  GSettings *tm_settings;
+  GtrTranslationMemory *translation_memory;
+  GtkWidget *translation_memory_ui;
 } GtrContextPanelPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtrContextPanel, gtr_context_panel, GTK_TYPE_BOX)
@@ -378,6 +387,24 @@ gtr_context_panel_init (GtrContextPanel *panel)
 
   g_signal_connect (priv->button, "clicked",
                     G_CALLBACK (on_done_button_clicked), panel);
+
+  priv->tm_settings = g_settings_new ("org.gnome.gtranslator.plugins.translation-memory");
+  priv->translation_memory = GTR_TRANSLATION_MEMORY (gtr_gda_new());
+  gtr_translation_memory_set_max_omits (priv->translation_memory,
+                                        g_settings_get_int (priv->tm_settings,
+                                                            "max-missing-words"));
+  gtr_translation_memory_set_max_delta (priv->translation_memory,
+                                        g_settings_get_int (priv->tm_settings,
+                                                            "max-length-diff"));
+  gtr_translation_memory_set_max_items (priv->translation_memory, 10);
+
+  priv->translation_memory_ui = gtr_translation_memory_ui_new (GTK_WIDGET (priv->tab),
+                                                               priv->translation_memory);
+  gtk_widget_show (priv->translation_memory_ui);
+  gtk_widget_set_size_request (priv->translation_memory_ui, 300, 400);
+  gtk_box_pack_start (GTK_BOX (priv->translation_memory_box),
+                      priv->translation_memory_ui,
+                      FALSE, FALSE, 0);
 }
 
 static void
@@ -455,6 +482,8 @@ gtr_context_panel_dispose (GObject *object)
 
   g_clear_object (&priv->hand_cursor);
   g_clear_object (&priv->regular_cursor);
+  g_clear_object (&priv->translation_memory);
+  g_clear_object (&priv->tm_settings);
 
   G_OBJECT_CLASS (gtr_context_panel_parent_class)->dispose (object);
 }
@@ -497,6 +526,7 @@ gtr_context_panel_class_init (GtrContextPanelClass * klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, context);
   gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, button_box);
   gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, button);
+  gtk_widget_class_bind_template_child_private (widget_class, GtrContextPanel, translation_memory_box);
 }
 
 /**
diff --git a/src/gtr-context.ui b/src/gtr-context.ui
index 3e1dfdfe..f11fb69e 100644
--- a/src/gtr-context.ui
+++ b/src/gtr-context.ui
@@ -7,6 +7,18 @@
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="translation_memory_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
     <child>
       <object class="GtkScrolledWindow" id="sw">
         <property name="visible">True</property>
@@ -25,7 +37,7 @@
       <packing>
         <property name="expand">True</property>
         <property name="fill">True</property>
-        <property name="position">0</property>
+        <property name="position">1</property>
       </packing>
     </child>
     <child>
@@ -51,7 +63,7 @@
       <packing>
         <property name="expand">False</property>
         <property name="fill">False</property>
-        <property name="position">1</property>
+        <property name="position">2</property>
       </packing>
     </child>
   </template>
diff --git a/src/gtr-tab.ui b/src/gtr-tab.ui
index ca2f81a9..98b989d7 100644
--- a/src/gtr-tab.ui
+++ b/src/gtr-tab.ui
@@ -137,6 +137,7 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="tab">GtrTab</property>
+            <property name="width_request">400</property>
           </object>
           <packing>
             <property name="expand">False</property>
@@ -154,3 +155,4 @@
   </template>
 </interface>
 
+
diff --git a/src/meson.build b/src/meson.build
index 97f3a345..ed7d7a1c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -115,9 +115,11 @@ sources += gnome.compile_resources(
 incs = [
   top_inc,
   include_directories('toolbareditor'),
+  include_directories('translation-memory'),
 ]
 
 subdir('toolbareditor')
+subdir('translation-memory')
 
 
 ###############
diff --git a/src/translation-memory/gda/gda-utils.c b/src/translation-memory/gda/gda-utils.c
new file mode 100644
index 00000000..57fd124c
--- /dev/null
+++ b/src/translation-memory/gda/gda-utils.c
@@ -0,0 +1,152 @@
+/*
+ * (C) 2001     Fatih Demir <kabalak kabalak net>
+ *     2012    Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or   
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ *   Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gda-utils.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+static const gchar *badwords[] = {
+  "a",
+  //"all",
+  "an",
+  //"are",
+  //"can",
+  //"for",
+  //"from",
+  "have",
+  //"it",
+  //"may",
+  //"not",
+  "of",
+  //"that",
+  "the",
+  //"this",
+  //"was",
+  "will",
+  //"with",
+  //"you",
+  //"your",
+  NULL
+};
+
+static gboolean
+check_good_word (const gchar * word, gchar ** badwords)
+{
+  gboolean check = TRUE;
+  gchar *lower = g_utf8_strdown (word, -1);
+  gint i = 0;
+
+  while (badwords[i] != NULL)
+    {
+      gchar *lower_collate = g_utf8_collate_key (lower, -1);
+
+      if (strcmp (lower_collate, badwords[i]) == 0)
+        {
+          check = FALSE;
+          g_free (lower_collate);
+          break;
+        }
+      i++;
+      g_free (lower_collate);
+    }
+  return check;
+}
+
+
+/**
+ * gtr_gda_utils_split_string_in_words:
+ * @string: the text to process
+ *
+ * Process a text and split it in words using pango.
+ * 
+ * Returns: an array of words of the processed text
+ */
+gchar **
+gtr_gda_utils_split_string_in_words (const gchar * string)
+{
+  PangoLanguage *lang = pango_language_from_string ("en");
+  PangoLogAttr *attrs;
+  GPtrArray *array;
+  gint char_len;
+  gint i = 0;
+  gchar *s;
+  gchar *start = NULL;
+  static gchar **badwords_collate = NULL;
+
+  if (badwords_collate == NULL)
+    {
+      gint words_size = g_strv_length ((gchar **) badwords);
+      gint x = 0;
+
+      badwords_collate = g_new0 (gchar *, words_size + 1);
+
+      while (badwords[x] != NULL)
+        {
+          badwords_collate[x] = g_utf8_collate_key (badwords[x], -1);
+          x++;
+        }
+      badwords_collate[x] = NULL;
+    }
+
+  char_len = g_utf8_strlen (string, -1);
+  attrs = g_new (PangoLogAttr, char_len + 1);
+
+  pango_get_log_attrs (string,
+                       strlen (string), -1, lang, attrs, char_len + 1);
+
+  array = g_ptr_array_new ();
+
+  s = (gchar *) string;
+  while (i <= char_len)
+    {
+      gchar *end;
+
+      if (attrs[i].is_word_start)
+        start = s;
+      if (attrs[i].is_word_end)
+        {
+          gchar *word;
+
+          end = s;
+          word = g_strndup (start, end - start);
+
+          if (check_good_word (word, badwords_collate))
+            g_ptr_array_add (array, word);
+        }
+
+      i++;
+      s = g_utf8_next_char (s);
+    }
+
+  g_free (attrs);
+  g_ptr_array_add (array, NULL);
+
+  return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
diff --git a/src/translation-memory/gda/gda-utils.h b/src/translation-memory/gda/gda-utils.h
new file mode 100644
index 00000000..7036e7e6
--- /dev/null
+++ b/src/translation-memory/gda/gda-utils.h
@@ -0,0 +1,31 @@
+/*
+ * (C) 2001     Fatih Demir <kabalak kabalak net>
+ *     2012     Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or   
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ *   Fatih Demir <kabalak kabalak net>
+ *   Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifndef GDA_UTILS_H
+#define GDA_UTILS_H 1
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+gchar **gtr_gda_utils_split_string_in_words (const gchar *string);
+
+#endif
diff --git a/src/translation-memory/gda/gtr-gda.c b/src/translation-memory/gda/gtr-gda.c
new file mode 100644
index 00000000..0c140e07
--- /dev/null
+++ b/src/translation-memory/gda/gtr-gda.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright (C) 2010  Andrey Kutejko <andy128k gmail com>
+ *
+ *     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 <libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include "gtr-gda.h"
+#include "gtr-translation-memory.h"
+#include "gtr-dirs.h"
+#include "gda-utils.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <string.h>
+
+#define GTR_GDA_GET_PRIVATE(object)                                     \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((object),                               \
+                                GTR_TYPE_GDA,                           \
+                                GtrGdaPrivate))
+
+static void
+gtr_translation_memory_iface_init (GtrTranslationMemoryInterface * iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtrGda,
+                         gtr_gda,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GTR_TYPE_TRANSLATION_MEMORY,
+                                                gtr_translation_memory_iface_init))
+
+struct _GtrGdaPrivate
+{
+  GdaConnection *db;
+
+  GdaSqlParser *parser;
+
+  /* prepared statements */
+  GdaStatement *stmt_find_orig;
+  GdaStatement *stmt_select_trans;
+  GdaStatement *stmt_select_word;
+  GdaStatement *stmt_find_trans;
+
+  GdaStatement *stmt_insert_orig;
+  GdaStatement *stmt_insert_word;
+  GdaStatement *stmt_insert_link;
+  GdaStatement *stmt_insert_trans;
+
+  GdaStatement *stmt_delete_trans;
+
+  guint max_omits;
+  guint max_delta;
+  gint max_items;
+
+  GHashTable *lookup_query_cache;
+};
+
+static gint
+select_integer (GdaConnection *db,
+                GdaStatement *stmt,
+                GdaSet *params,
+                GError **error)
+{
+  GdaDataModel *model;
+  GError *inner_error;
+  gint result = 0;
+
+  inner_error = NULL;
+  model = gda_connection_statement_execute_select (db, stmt, params,
+                                                   &inner_error);
+  g_object_unref (params);
+
+  if (!model)
+    {
+      g_propagate_error (error, inner_error);
+      return 0;
+    }
+
+  if (gda_data_model_get_n_rows (model) > 0)
+    {
+      const GValue * val;
+
+      inner_error = NULL;
+      val = gda_data_model_get_typed_value_at (model,
+                                               0, 0,
+                                               G_TYPE_INT,
+                                               FALSE,
+                                               &inner_error);
+      if (val)
+        result = g_value_get_int (val);
+      else
+        g_propagate_error (error, inner_error);
+    }
+
+  g_object_unref (model);
+
+  return result;
+}
+
+static gint
+insert_row (GdaConnection *db,
+            GdaStatement *stmt,
+            GdaSet *params,
+            GError **error)
+{
+  GdaSet *last_row;
+  GError *inner_error;
+  const GValue * val;
+  gint result = 0;
+
+  inner_error = NULL;
+  if (-1 == gda_connection_statement_execute_non_select (db,
+                                                         stmt,
+                                                         params,
+                                                         &last_row,
+                                                         &inner_error))
+    {
+      g_object_unref (params);
+      g_propagate_error (error, inner_error);
+      return 0;
+    }
+  g_object_unref (params);
+
+  g_return_val_if_fail (last_row != NULL, 0);
+
+  val = gda_set_get_holder_value (last_row, "+0");
+  if (val)
+    result = g_value_get_int (val);
+
+  g_object_unref (last_row);
+
+  return result;
+}
+
+static int
+string_comparator (const void *s1, const void *s2)
+{
+  return strcmp (*(const gchar **) s1, *(const gchar **) s2);
+}
+
+static gchar **
+gtr_gda_split_string_in_words (const gchar *phrase)
+{
+  gchar **words = gtr_gda_utils_split_string_in_words (phrase);
+  gsize count = g_strv_length (words);
+  gint w;
+  gint r;
+
+  if (count <= 1)
+    return words;
+
+  qsort (words, count, sizeof (gchar *), string_comparator);
+
+  w = 1;
+  r = 1;
+  for (; r < count; ++r)
+    {
+      if (0 == strcmp (words[r], words[w-1]))
+        {
+          g_free (words[r]);
+        }
+      else
+        {
+          words[w] = words[r];
+          ++w;
+        }
+    }
+  words[w] = NULL;
+
+  return words;
+}
+
+static void
+gtr_gda_words_append (GtrGda *self,
+                      const gchar * word,
+                      gint orig_id,
+                      GError **error)
+{
+  GError *inner_error;
+  gint word_id = 0;
+
+  /* look for word */
+  {
+    inner_error = NULL;
+    word_id = select_integer (self->priv->db,
+                              self->priv->stmt_select_word,
+                              gda_set_new_inline (1,
+                                                  "value", G_TYPE_STRING,
+                                                  word),
+                              &inner_error);
+    if (inner_error)
+      {
+        g_propagate_error (error, inner_error);
+        return;
+      }
+  }
+
+  if (word_id == 0)
+    {
+      inner_error = NULL;
+      word_id = insert_row (self->priv->db,
+                            self->priv->stmt_insert_word,
+                            gda_set_new_inline (1,
+                                                "value", G_TYPE_STRING, word),
+                            &inner_error);
+      if (inner_error)
+        {
+          g_propagate_error (error, inner_error);
+          return;
+        }
+    }
+
+  /* insert link */
+  {
+    GdaSet *params;
+
+    params = gda_set_new_inline (2,
+                                 "word_id", G_TYPE_INT, word_id,
+                                 "orig_id", G_TYPE_INT, orig_id);
+
+    inner_error = NULL;
+    if (-1 == gda_connection_statement_execute_non_select (self->priv->db,
+                                                           self->priv->stmt_insert_link,
+                                                           params,
+                                                           NULL,
+                                                           &inner_error))
+      g_propagate_error (error, inner_error);
+
+    g_object_unref (params);
+  }
+}
+
+static gboolean
+gtr_gda_store_impl (GtrGda *self,
+                    const gchar * original,
+                    const gchar * translation,
+                    GError **error)
+{
+  gint orig_id;
+  gboolean found_translation = FALSE;
+  gchar **words = NULL;
+  GError *inner_error;
+
+  inner_error = NULL;
+  orig_id = select_integer (self->priv->db,
+                            self->priv->stmt_find_orig,
+                            gda_set_new_inline (1,
+                                                "original", G_TYPE_STRING,
+                                                original),
+                            &inner_error);
+  if (inner_error)
+    {
+      g_propagate_error (error, inner_error);
+      return FALSE;
+    }
+
+  if (orig_id == 0)
+    {
+      gsize sz, i;
+
+      words = gtr_gda_split_string_in_words (original);
+      sz = g_strv_length (words);
+
+      inner_error = NULL;
+      orig_id = insert_row (self->priv->db,
+                            self->priv->stmt_insert_orig,
+                            gda_set_new_inline (2,
+                                                "original", G_TYPE_STRING,
+                                                original,
+                                                "sentence_size", G_TYPE_INT,
+                                                (gint) sz),
+                            &inner_error);
+      if (inner_error)
+        goto error;
+
+      /* insert words */
+      for (i = 0; i < sz; i++)
+        {
+          inner_error = NULL;
+          gtr_gda_words_append (self, words[i], orig_id, &inner_error);
+          if (inner_error)
+            goto error;
+        }
+
+      g_strfreev (words);
+    }
+  else
+    {
+      inner_error = NULL;
+      found_translation = select_integer (self->priv->db,
+                                          self->priv->stmt_find_trans,
+                                          gda_set_new_inline (2,
+                                                              "orig_id",
+                                                              G_TYPE_INT,
+                                                              orig_id,
+                                                              "value",
+                                                              G_TYPE_STRING,
+                                                              translation),
+                                          &inner_error);
+      if (inner_error)
+        goto error;
+    }
+
+  if (!found_translation)
+    {
+      inner_error = NULL;
+      insert_row (self->priv->db,
+                  self->priv->stmt_insert_trans,
+                  gda_set_new_inline (2,
+                                      "orig_id", G_TYPE_INT,
+                                      orig_id,
+                                      "value", G_TYPE_STRING,
+                                      translation),
+                  &inner_error);
+      if (inner_error)
+        goto error;
+    }
+
+  return TRUE;
+
+ error:
+  g_strfreev (words);
+  g_propagate_error (error, inner_error);
+  return FALSE;
+}
+
+static gboolean
+gtr_gda_store (GtrTranslationMemory * tm, GtrMsg * msg)
+{
+  GtrGda *self = GTR_GDA (tm);
+  gboolean result;
+  GError *error;
+
+  g_return_val_if_fail (GTR_IS_GDA (self), FALSE);
+
+  error = NULL;
+  if (!gda_connection_begin_transaction (self->priv->db,
+                                         NULL,
+                                         GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+                                         &error))
+    {
+      g_warning ("starting transaction failed: %s", error->message);
+      g_error_free (error);
+      return FALSE;
+    }
+
+  error = NULL;
+  result = gtr_gda_store_impl (self,
+                               gtr_msg_get_msgid (msg),
+                               gtr_msg_get_msgstr (msg),
+                               &error);
+
+  if (error)
+    {
+      g_warning ("storing message failed: %s", error->message);
+      g_error_free (error);
+    }
+
+  if (result)
+    gda_connection_commit_transaction (self->priv->db, NULL, NULL);
+  else
+    gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+  return result;
+}
+
+static gboolean
+gtr_gda_store_list (GtrTranslationMemory * tm, GList * msgs)
+{
+  GtrGda *self = GTR_GDA (tm);
+  gboolean result = TRUE;
+  GList *l;
+  GError *error;
+
+  g_return_val_if_fail (GTR_IS_GDA (self), FALSE);
+
+  error = NULL;
+  if (!gda_connection_begin_transaction (self->priv->db,
+                                         NULL,
+                                         GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+                                         &error))
+    {
+      g_warning ("starting transaction failed: %s", error->message);
+      g_error_free (error);
+      return FALSE;
+    }
+
+  for (l = msgs; l; l = g_list_next (l))
+    {
+      GtrMsg *msg = GTR_MSG (l->data);
+
+      if (!gtr_msg_is_translated (msg) || gtr_msg_is_fuzzy (msg))
+        continue;
+
+      error = NULL;
+      result = gtr_gda_store_impl (self,
+                                   gtr_msg_get_msgid (msg),
+                                   gtr_msg_get_msgstr (msg),
+                                   &error);
+      if (!result)
+        {
+          g_warning ("storing message failed: %s", error->message);
+          g_error_free (error);
+          break;
+        }
+    }
+
+  if (result)
+    gda_connection_commit_transaction (self->priv->db, NULL, NULL);
+  else
+    gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+  return result;
+}
+
+static void
+gtr_gda_remove (GtrTranslationMemory *tm,
+                gint translation_id)
+{
+  GtrGda *self = GTR_GDA (tm);
+  GdaSet *params;
+  GError *error;
+
+  params = gda_set_new_inline (1,
+                               "id_trans",
+                               G_TYPE_INT,
+                               translation_id);
+
+  error = NULL;
+  gda_connection_statement_execute_non_select (self->priv->db,
+                                               self->priv->stmt_delete_trans,
+                                               params,
+                                               NULL,
+                                               &error);
+  if (error)
+    {
+      g_warning ("removing translation failed: %s", error->message);
+      g_error_free (error);
+    }
+
+  g_object_unref (params);
+}
+
+static void
+free_match (gpointer data)
+{
+  GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) data;
+
+  g_free (match->match);
+  g_slice_free (GtrTranslationMemoryMatch, match);
+}
+
+static gchar*
+build_lookup_query (GtrGda *self, guint word_count)
+{
+  GString * query = g_string_sized_new (1024);
+  guint i;
+
+  g_string_append_printf (query,
+                          "select "
+                          "    TRANS.VALUE, "
+                          "    100 SCORE, "
+                         "    TRANS.ID "
+                          "from "
+                          "     TRANS, ORIG "
+                          "where ORIG.ID = TRANS.ORIG_ID "
+                          "  and ORIG.VALUE = ##phrase::string "
+                          "union "
+                          "select "
+                          "    TRANS.VALUE, "
+                          "    SC SCORE, "
+                          "    TRANS.ID "
+                          "from TRANS, "
+                          "     (select "
+                          "          ORIG.ID ORID, "
+                          "          cast(count(1) * count(1) * 100 "
+                          "               / (%d * ORIG.SENTENCE_SIZE + 1) "
+                          "            as integer) SC "
+                          "      from "
+                          "          WORD, WORD_ORIG_LINK, ORIG "
+                          "      where WORD.ID = WORD_ORIG_LINK.WORD_ID "
+                          "        and ORIG.ID = WORD_ORIG_LINK.ORIG_ID "
+                          "        and ORIG.VALUE <> ##phrase::string "
+                          "        and ORIG.SENTENCE_SIZE between %u and %u "
+                          "        and WORD.VALUE in (",
+                          word_count,
+                          word_count,
+                          word_count + self->priv->max_delta);
+
+  for (i = 0; i < word_count; ++i)
+    {
+      g_string_append_printf (query, "##word%d::string", i);
+      if (i != word_count - 1)
+        g_string_append (query, ", ");
+    }
+
+  g_string_append_printf (query,
+                          ") "
+                          "     group by ORIG.ID "
+                          "     having count(1) >= %d) "
+                          "where ORID = TRANS.ORIG_ID "
+                          "order by SCORE desc "
+                          "limit %d",
+                          word_count - self->priv->max_omits,
+                          self->priv->max_items);
+
+  return g_string_free (query, FALSE);
+}
+
+static GdaStatement *
+gtr_gda_get_lookup_statement (GtrGda *self, guint word_count, GError **error)
+{
+  GdaStatement *stmt;
+  gchar *query;
+
+  stmt = GDA_STATEMENT (g_hash_table_lookup (self->priv->lookup_query_cache,
+                                             GUINT_TO_POINTER (word_count)));
+
+  if (stmt)
+    return stmt;
+
+  query = build_lookup_query (self, word_count);
+  stmt = gda_sql_parser_parse_string (self->priv->parser,
+                                      query,
+                                      NULL,
+                                      error);
+  g_free (query);
+
+  g_hash_table_insert (self->priv->lookup_query_cache,
+                       GUINT_TO_POINTER (word_count),
+                       stmt);
+
+  return stmt;
+}
+
+static GList *
+gtr_gda_lookup (GtrTranslationMemory * tm, const gchar * phrase)
+{
+  GtrGda *self = GTR_GDA (tm);
+  gchar **words = NULL;
+  guint cnt = 0;
+  GList *matches = NULL;
+  GError *inner_error;
+  GdaStatement *stmt = NULL;
+  GdaSet *params = NULL;
+  GdaDataModel *model = NULL;
+  gint i;
+
+  g_return_val_if_fail (GTR_IS_GDA (self), NULL);
+
+  if (!gda_connection_begin_transaction (self->priv->db,
+                                         NULL,
+                                         GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
+                                         NULL))
+    return NULL;
+
+  words = gtr_gda_split_string_in_words (phrase);
+  cnt = g_strv_length (words);
+
+  inner_error = NULL;
+  stmt = gtr_gda_get_lookup_statement (self, cnt, &inner_error);
+  if (inner_error)
+    goto end;
+
+  inner_error = NULL;
+  if (!gda_statement_get_parameters (stmt, &params, &inner_error))
+    goto end;
+
+  inner_error = NULL;
+  gda_set_set_holder_value (params,
+                            &inner_error,
+                            "phrase", phrase);
+  if (inner_error)
+    goto end;
+
+  {
+    gchar word_id[25];
+    for (i = 0; i < cnt; i++)
+      {
+        sprintf (word_id, "word%d", i);
+
+        inner_error = NULL;
+        gda_set_set_holder_value (params,
+                                  &inner_error,
+                                  word_id, words[i]);
+        if (inner_error)
+          goto end;
+      }
+  }
+
+  inner_error = NULL;
+  model = gda_connection_statement_execute_select (self->priv->db,
+                                                   stmt,
+                                                   params,
+                                                   &inner_error);
+  if (!model)
+    goto end;
+
+  {
+    gint count = gda_data_model_get_n_rows (model);
+    for (i = 0; i < count; ++i)
+      {
+        const GValue * val;
+        gchar *suggestion;
+        gint score;
+        gint id;
+        GtrTranslationMemoryMatch *match;
+
+        inner_error = NULL;
+        val = gda_data_model_get_typed_value_at (model,
+                                                 0, i,
+                                                 G_TYPE_STRING,
+                                                 FALSE,
+                                                 &inner_error);
+        if (!val)
+          goto end;
+
+        suggestion = g_value_dup_string (val);
+
+        inner_error = NULL;
+        val = gda_data_model_get_typed_value_at (model,
+                                                 1, i,
+                                                 G_TYPE_INT,
+                                                 FALSE,
+                                                 &inner_error);
+        if (!val)
+          {
+            g_free (suggestion);
+            goto end;
+          }
+
+        score = g_value_get_int (val);
+
+        inner_error = NULL;
+        val = gda_data_model_get_typed_value_at (model,
+                                                 2, i,
+                                                 G_TYPE_INT,
+                                                 FALSE,
+                                                 &inner_error);
+        if (!val)
+          {
+            g_free (suggestion);
+            goto end;
+          }
+
+        id = g_value_get_int (val);
+
+        match = g_slice_new (GtrTranslationMemoryMatch);
+        match->match = suggestion;
+        match->level = score;
+        match->id = id;
+
+        matches = g_list_prepend (matches, match);
+      }
+  }
+
+ end:
+
+  if (model)
+    g_object_unref (model);
+  if (params)
+    g_object_unref (params);
+
+  gda_connection_rollback_transaction (self->priv->db, NULL, NULL);
+
+  if (inner_error)
+    {
+      g_list_free_full (matches, free_match);
+
+      g_warning ("%s\n", inner_error->message);
+
+      g_error_free (inner_error);
+
+      return NULL;
+    }
+
+  matches = g_list_reverse (matches);
+  return matches;
+}
+
+static void
+gtr_gda_set_max_omits (GtrTranslationMemory * tm, gsize omits)
+{
+  GtrGda *self = GTR_GDA (tm);
+
+  self->priv->max_omits = omits;
+  g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_gda_set_max_delta (GtrTranslationMemory * tm, gsize delta)
+{
+  GtrGda *self = GTR_GDA (tm);
+
+  self->priv->max_delta = delta;
+  g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_gda_set_max_items (GtrTranslationMemory * tm, gint items)
+{
+  GtrGda *self = GTR_GDA (tm);
+
+  self->priv->max_items = items;
+  g_hash_table_remove_all (self->priv->lookup_query_cache);
+}
+
+static void
+gtr_translation_memory_iface_init (GtrTranslationMemoryInterface * iface)
+{
+  iface->store = gtr_gda_store;
+  iface->store_list = gtr_gda_store_list;
+  iface->remove = gtr_gda_remove;
+  iface->lookup = gtr_gda_lookup;
+  iface->set_max_omits = gtr_gda_set_max_omits;
+  iface->set_max_delta = gtr_gda_set_max_delta;
+  iface->set_max_items = gtr_gda_set_max_items;
+}
+
+static GdaStatement *
+prepare_statement(GdaSqlParser *parser, const gchar *query)
+{
+  GError *error = NULL;
+  GdaStatement *statement = gda_sql_parser_parse_string (parser,
+                                                         query,
+                                                         NULL,
+                                                         &error);
+
+  if (error)
+    {
+      g_error ("gtr-gda.c: prepare_statement: "
+               "gda_sql_parser_parse_string failed.\n"
+               "query: %s\n"
+               "error message: %s\n",
+               query,
+               error->message);
+    }
+  return statement;
+}
+
+static void
+gtr_gda_init (GtrGda * self)
+{
+  gchar *connection_string;
+  GError *error = NULL;
+
+  self->priv = GTR_GDA_GET_PRIVATE (self);
+
+  gda_init ();
+
+  {
+    const gchar *config_dir;
+    gchar *encoded_config_dir;
+
+    config_dir = gtr_dirs_get_user_config_dir ();
+    encoded_config_dir = gda_rfc1738_encode (config_dir);
+
+    connection_string = g_strdup_printf ("DB_DIR=%s;"
+                                         "DB_NAME=translation-memory",
+                                         encoded_config_dir);
+
+    g_free (encoded_config_dir);
+  }
+
+  self->priv->db = gda_connection_open_from_string ("Sqlite",
+                                                    connection_string,
+                                                    NULL,
+                                                    GDA_CONNECTION_OPTIONS_NONE,
+                                                    &error);
+  if (error)
+    {
+      g_warning ("Error creating database: %s", error->message);
+      g_error_free (error);
+    }
+
+  gda_connection_execute_non_select_command (self->priv->db,
+                                             "create table WORD ("
+                                             "ID integer primary key autoincrement,"
+                                             "VALUE text unique)",
+                                             NULL);
+
+  gda_connection_execute_non_select_command (self->priv->db,
+                                             "create table WORD_ORIG_LINK ("
+                                             "WORD_ID integer,"
+                                             "ORIG_ID integer,"
+                                             "primary key (WORD_ID, ORIG_ID))",
+                                             NULL);
+
+  gda_connection_execute_non_select_command (self->priv->db,
+                                             "create table ORIG ("
+                                             "ID integer primary key autoincrement,"
+                                             "VALUE text unique,"
+                                             "SENTENCE_SIZE integer)",
+                                             NULL);
+
+  gda_connection_execute_non_select_command (self->priv->db,
+                                             "create table TRANS ("
+                                             "ID integer primary key autoincrement,"
+                                             "ORIG_ID integer,"
+                                             "VALUE text)",
+                                             NULL);
+
+  gda_connection_execute_non_select_command (self->priv->db,
+                                             "create index "
+                                             "if not exists IDX_TRANS_ORIG_ID "
+                                             "on TRANS (ORIG_ID)",
+                                             NULL);
+
+  /* prepare statements */
+
+  self->priv->parser = gda_connection_create_parser (self->priv->db);
+  if (self->priv->parser == NULL)
+    self->priv->parser = gda_sql_parser_new ();
+
+  self->priv->stmt_find_orig =
+    prepare_statement (self->priv->parser,
+                       "select ID from ORIG "
+                       "where VALUE=##original::string");
+
+  self->priv->stmt_select_word =
+    prepare_statement (self->priv->parser,
+                       "select ID from WORD "
+                       "where VALUE=##value::string");
+
+  self->priv->stmt_select_trans =
+    prepare_statement (self->priv->parser,
+                       "select VALUE from TRANS "
+                       "where ORIG_ID=##orig_id::int");
+
+  self->priv->stmt_find_trans =
+    prepare_statement (self->priv->parser,
+                       "select ID from TRANS "
+                       "where ORIG_ID=##orig_id::int "
+                       "and VALUE=##value::string");
+
+  self->priv->stmt_insert_orig =
+    prepare_statement (self->priv->parser,
+                       "insert into "
+                       "ORIG (VALUE, SENTENCE_SIZE) "
+                       "values "
+                       "(##original::string, ##sentence_size::int)");
+
+  self->priv->stmt_insert_word =
+    prepare_statement (self->priv->parser,
+                       "insert into "
+                       "WORD (VALUE) "
+                       "values "
+                       "(##value::string)");
+
+  self->priv->stmt_insert_link =
+    prepare_statement (self->priv->parser,
+                       "insert into "
+                       "WORD_ORIG_LINK (WORD_ID, ORIG_ID) "
+                       "values "
+                       "(##word_id::int, ##orig_id::int)");
+
+  self->priv->stmt_insert_trans =
+    prepare_statement (self->priv->parser,
+                       "insert into "
+                       "TRANS (ORIG_ID, VALUE) "
+                       "values "
+                       "(##orig_id::int, ##value::string)");
+
+  self->priv->stmt_delete_trans =
+    prepare_statement (self->priv->parser,
+                       "delete from TRANS "
+                       "where id = ##id_trans::int");
+
+  self->priv->max_omits = 0;
+  self->priv->max_delta = 0;
+  self->priv->max_items = 0;
+
+  self->priv->lookup_query_cache = g_hash_table_new_full (g_direct_hash,
+                                                          g_direct_equal,
+                                                          NULL,
+                                                          g_object_unref);
+}
+
+static void
+gtr_gda_dispose (GObject * object)
+{
+  GtrGda *self = GTR_GDA (object);
+
+  if (self->priv->stmt_find_orig != NULL)
+    {
+      g_object_unref (self->priv->stmt_find_orig);
+      self->priv->stmt_find_orig = NULL;
+    }
+
+  if (self->priv->stmt_select_trans != NULL)
+    {
+      g_object_unref (self->priv->stmt_select_trans);
+      self->priv->stmt_select_trans = NULL;
+    }
+
+  if (self->priv->stmt_find_trans != NULL)
+    {
+      g_object_unref (self->priv->stmt_find_trans);
+      self->priv->stmt_find_trans = NULL;
+    }
+
+  if (self->priv->stmt_select_word != NULL)
+    {
+      g_object_unref (self->priv->stmt_select_word);
+      self->priv->stmt_select_word = NULL;
+    }
+
+  if (self->priv->stmt_insert_orig != NULL)
+    {
+      g_object_unref (self->priv->stmt_insert_orig);
+      self->priv->stmt_insert_orig = NULL;
+    }
+
+  if (self->priv->stmt_insert_word != NULL)
+    {
+      g_object_unref (self->priv->stmt_insert_word);
+      self->priv->stmt_insert_word = NULL;
+    }
+
+  if (self->priv->stmt_insert_link != NULL)
+    {
+      g_object_unref (self->priv->stmt_insert_link);
+      self->priv->stmt_insert_link = NULL;
+    }
+
+  if (self->priv->stmt_insert_trans != NULL)
+    {
+      g_object_unref (self->priv->stmt_insert_trans);
+      self->priv->stmt_insert_trans = NULL;
+    }
+
+  if (self->priv->stmt_delete_trans != NULL)
+    {
+      g_object_unref (self->priv->stmt_delete_trans);
+      self->priv->stmt_delete_trans = NULL;
+    }
+
+  if (self->priv->parser != NULL)
+    {
+      g_object_unref (self->priv->parser);
+      self->priv->parser = NULL;
+    }
+
+  if (self->priv->db != NULL)
+    {
+      g_object_unref (self->priv->db);
+      self->priv->db = NULL;
+    }
+
+  if (self->priv->lookup_query_cache != NULL)
+    {
+      g_hash_table_unref (self->priv->lookup_query_cache);
+      self->priv->lookup_query_cache = NULL;
+    }
+
+  G_OBJECT_CLASS (gtr_gda_parent_class)->dispose (object);
+}
+
+static void
+gtr_gda_class_init (GtrGdaClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GtrGdaPrivate));
+  object_class->dispose = gtr_gda_dispose;
+}
+
+/**
+ * gtr_gda_new:
+ *
+ * Creates a new #GtrGda object.
+ *
+ * Returns: a new #GtrGda object
+ */
+GtrGda *
+gtr_gda_new ()
+{
+  GtrGda *gda;
+
+  gda = g_object_new (GTR_TYPE_GDA, NULL);
+
+  return gda;
+}
+
diff --git a/src/translation-memory/gda/gtr-gda.h b/src/translation-memory/gda/gtr-gda.h
new file mode 100644
index 00000000..a2f0e91b
--- /dev/null
+++ b/src/translation-memory/gda/gtr-gda.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010  Andrey Kutejko <andy128k gmail com>
+ *
+ *     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/>.
+ */
+
+#ifndef __GDA_BACKEND_H__
+#define __GDA_BACKEND_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_GDA           (gtr_gda_get_type ())
+#define GTR_GDA(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_GDA, GtrGda))
+#define GTR_GDA_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_GDA, GtrGdaClass))
+#define GTR_IS_GDA(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_GDA))
+#define GTR_IS_GDA_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_GDA))
+#define GTR_GDA_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_GDA, GtrGdaClass))
+
+typedef struct _GtrGdaPrivate GtrGdaPrivate;
+typedef struct _GtrGda        GtrGda;
+typedef struct _GtrGdaClass   GtrGdaClass;
+
+struct _GtrGda
+{
+  GObject parent_instance;
+
+  /*< private > */
+  GtrGdaPrivate *priv;
+};
+
+struct _GtrGdaClass
+{
+  GObjectClass parent_class;
+};
+
+GType                   gtr_gda_get_type                (void) G_GNUC_CONST;
+
+GType                   gtr_gda_register_type           (GTypeModule *module);
+
+GtrGda                 *gtr_gda_new                     (void);
+
+G_END_DECLS
+#endif /* __GDA_BACKEND_H__ */
diff --git a/src/translation-memory/gda/meson.build b/src/translation-memory/gda/meson.build
new file mode 100644
index 00000000..c44d486e
--- /dev/null
+++ b/src/translation-memory/gda/meson.build
@@ -0,0 +1,4 @@
+sources += files(
+  'gda-utils.c',
+  'gtr-gda.c',
+)
diff --git a/src/translation-memory/gtr-translation-memory-dialog.c 
b/src/translation-memory/gtr-translation-memory-dialog.c
new file mode 100644
index 00000000..26edca70
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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 "gtr-translation-memory-dialog.h"
+#include "gtr-profile-manager.h"
+#include "gtr-translation-memory-utils.h"
+#include "gtr-po.h"
+
+#include <glib/gi18n.h>
+
+
+#define GTR_TRANSLATION_MEMORY_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogPrivate))
+
+struct _GtrTranslationMemoryDialogPrivate
+{
+  GSettings *tm_settings;
+
+  GtkWidget *directory_entry;
+  GtkWidget *search_button;
+  GtkWidget *add_database_button;
+  GtkWidget *add_database_progressbar;
+  GtkWidget *tm_lang_entry;
+  GtkWidget *use_lang_profile_in_tm;
+
+  GtrTranslationMemory *translation_memory;
+};
+
+G_DEFINE_TYPE (GtrTranslationMemoryDialog, gtr_translation_memory_dialog, GTK_TYPE_DIALOG)
+
+static void
+gtr_translation_memory_dialog_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gtr_translation_memory_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtr_translation_memory_dialog_dispose (GObject *object)
+{
+  GtrTranslationMemoryDialogPrivate *priv = GTR_TRANSLATION_MEMORY_DIALOG (object)->priv;
+
+  g_clear_object (&priv->tm_settings);
+
+  G_OBJECT_CLASS (gtr_translation_memory_dialog_parent_class)->dispose (object);
+}
+
+static void
+gtr_translation_memory_dialog_class_init (GtrTranslationMemoryDialogClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtr_translation_memory_dialog_finalize;
+  object_class->dispose = gtr_translation_memory_dialog_dispose;
+
+  g_type_class_add_private (object_class, sizeof (GtrTranslationMemoryDialogPrivate));
+}
+
+/***************Translation Memory pages****************/
+static void
+response_filechooser_cb (GtkDialog                  *dialog,
+                         gint                        response_id,
+                         GtrTranslationMemoryDialog *dlg)
+{
+  if (response_id == GTK_RESPONSE_YES)
+    {
+      gchar *filename;
+
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+      gtk_entry_set_text (GTK_ENTRY (dlg->priv->directory_entry),
+                          filename);
+      g_settings_set_string (dlg->priv->tm_settings,
+                             "po-directory",
+                             filename);
+      g_free (filename);
+    }
+
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+on_search_button_clicked (GtkButton                  *button,
+                          GtrTranslationMemoryDialog *dlg)
+{
+  GtkWidget *filechooser;
+
+  filechooser = gtk_file_chooser_dialog_new ("Select PO directory",
+                                             GTK_WINDOW (dlg),
+                                             GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                             GTK_STOCK_CANCEL,
+                                             GTK_RESPONSE_CANCEL,
+                                             GTK_STOCK_OK,
+                                             GTK_RESPONSE_YES, NULL);
+
+  g_signal_connect (GTK_DIALOG (filechooser), "response",
+                    G_CALLBACK (response_filechooser_cb), dlg);
+
+  gtk_widget_show (filechooser);
+}
+
+typedef struct _IdleData
+{
+  GSList *list;
+  GtkProgressBar *progress;
+  GtrTranslationMemory *tm;
+  GtkWindow *parent;
+} IdleData;
+
+static gboolean
+add_to_database (gpointer data_pointer)
+{
+  IdleData *data = (IdleData *) data_pointer;
+  static GSList *l = NULL;
+  gdouble percentage;
+
+  if (l == NULL)
+    l = data->list;
+  else
+    l = g_slist_next (l);
+
+  if (l)
+    {
+      GList *msg_list = NULL;
+      GFile *location;
+      GError *error = NULL;
+      GtrPo *po;
+
+      po = gtr_po_new ();
+      location = (GFile *) l->data;
+
+      gtr_po_parse (po, location, &error);
+      if (error)
+        return TRUE;
+
+      msg_list = gtr_po_get_messages (po);
+
+      gtr_translation_memory_store_list (data->tm, msg_list);
+
+      g_object_unref (po);
+    }
+  else
+    {
+      GtkWidget *dialog;
+      gchar *markup;
+
+      gtk_progress_bar_set_fraction (data->progress, 1.0);
+
+      dialog = gtk_message_dialog_new (data->parent,
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, NULL);
+
+      markup =
+        g_strdup_printf("<span weight=\"bold\" size=\"large\">%s</span>",
+                        _("Strings added to database"));
+      gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
+      g_free(markup);
+
+      g_signal_connect (dialog, "response",
+                        G_CALLBACK (gtk_widget_destroy), NULL);
+      gtk_widget_show (dialog);
+
+      return FALSE;
+    }
+
+  percentage =
+    (gdouble) g_slist_position (data->list,
+                                l) / (gdouble) g_slist_length (data->list);
+
+  /*
+   * Set the progress only if the values are reasonable.
+   */
+  if (percentage > 0.0 && percentage < 1.0)
+    {
+      /* Set the progressbar status. */
+      gtk_progress_bar_set_fraction (data->progress, percentage);
+    }
+
+  return TRUE;
+}
+
+static void
+destroy_idle_data (gpointer data)
+{
+  IdleData *d = (IdleData *) data;
+
+  gtk_widget_hide (GTK_WIDGET (d->progress));
+
+  g_slist_free_full (d->list, g_object_unref);
+  g_free (d);
+}
+
+static void
+on_add_database_button_clicked (GtkButton                  *button,
+                                GtrTranslationMemoryDialog *dlg)
+{
+  GFile *dir;
+  gchar *dir_name;
+  IdleData *data;
+
+  dir_name = g_settings_get_string (dlg->priv->tm_settings,
+                                    "po-directory");
+
+  /* If dir name is empty, show a warning message */
+  if (*dir_name == '\0')
+    {
+      GtkWidget *dialog;
+      dialog = gtk_message_dialog_new (GTK_WINDOW (dlg),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_WARNING,
+                                       GTK_BUTTONS_CLOSE,
+                                       _("Please specify a valid path to build the translation memory"));
+
+      gtk_widget_show (dialog);
+      g_signal_connect (dialog, "response",
+                        G_CALLBACK (gtk_widget_destroy), NULL);
+      g_free (dir_name);
+      return;
+    }
+
+  dir = g_file_new_for_path (dir_name);
+  g_free (dir_name);
+
+  data = g_new0 (IdleData, 1);
+  data->list = NULL;
+
+  if (g_settings_get_boolean (dlg->priv->tm_settings,
+                              "restrict-to-filename"))
+    {
+      gchar *restriction;
+
+      restriction = g_settings_get_string (dlg->priv->tm_settings,
+                                           "filename-restriction");
+      gtr_scan_dir (dir, &data->list, restriction);
+      g_free (restriction);
+    }
+  else
+    gtr_scan_dir (dir, &data->list, NULL);
+
+  data->tm = dlg->priv->translation_memory;
+  data->progress = GTK_PROGRESS_BAR (dlg->priv->add_database_progressbar);
+  data->parent = GTK_WINDOW (dlg);
+
+  gtk_widget_show (dlg->priv->add_database_progressbar);
+  g_idle_add_full (G_PRIORITY_HIGH_IDLE + 30,
+                   (GSourceFunc) add_to_database,
+                   data, (GDestroyNotify) destroy_idle_data);
+
+  g_object_unref (dir);
+}
+
+static void
+gtr_translation_memory_dialog_init (GtrTranslationMemoryDialog *dlg)
+{
+  GtrTranslationMemoryDialogPrivate *priv;
+  GtkWidget *action_area;
+  GtkWidget *content_area;
+  GtkBuilder *builder;
+  GtkWidget *content;
+  GtrProfileManager *prof_manager;
+  GtrProfile *profile;
+  const gchar *language_code;
+  gchar *filename = NULL;
+  gchar *root_objects[] = {
+    "translation-memory-box",
+    NULL
+  };
+
+  dlg->priv = GTR_TRANSLATION_MEMORY_DIALOG_GET_PRIVATE (dlg);
+  priv = dlg->priv;
+
+  priv->tm_settings = g_settings_new ("org.gnome.gtranslator.plugins.translation-memory");
+
+  gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+                          GTK_STOCK_CLOSE,
+                          GTK_RESPONSE_CLOSE,
+                          NULL);
+
+  gtk_window_set_title (GTK_WINDOW (dlg), _("Gtranslator Translation Memory Manager"));
+  gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
+  gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+
+  action_area = gtk_dialog_get_action_area (GTK_DIALOG (dlg));
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
+
+  /* HIG defaults */
+  gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+  gtk_box_set_spacing (GTK_BOX (content_area), 2);    /* 2 * 5 + 2 = 12 */
+  gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
+  gtk_box_set_spacing (GTK_BOX (action_area), 4);
+
+  g_signal_connect (dlg, "response",
+                    G_CALLBACK (gtk_widget_destroy), NULL);
+
+  builder = gtk_builder_new ();
+  gtk_builder_add_objects_from_resource (builder, 
"/org/gnome/gtranslator/plugins/translation-memory/ui/gtr-translation-memory-dialog.ui", root_objects, NULL);
+  content = GTK_WIDGET (gtk_builder_get_object (builder, "translation-memory-box"));
+  g_object_ref (content);
+  priv->directory_entry = GTK_WIDGET (gtk_builder_get_object (builder, "directory-entry"));
+  priv->search_button = GTK_WIDGET (gtk_builder_get_object (builder, "search-button"));
+  priv->add_database_button = GTK_WIDGET (gtk_builder_get_object (builder, "add-database-button"));
+  priv->add_database_progressbar = GTK_WIDGET (gtk_builder_get_object (builder, "add-database-progressbar"));
+  priv->use_lang_profile_in_tm = GTK_WIDGET (gtk_builder_get_object (builder, "use-lang-profile-in-tm"));
+  priv->tm_lang_entry = GTK_WIDGET (gtk_builder_get_object (builder, "tm-lang-entry"));
+  g_object_unref (builder);
+
+  gtk_box_pack_start (GTK_BOX (content_area), content, TRUE, TRUE, 0);
+  g_object_unref (content);
+
+  prof_manager = gtr_profile_manager_get_default ();
+  profile = gtr_profile_manager_get_active_profile (prof_manager);
+
+  if (profile != NULL)
+    {
+      language_code = gtr_profile_get_language_code (profile);
+      filename = g_strconcat (language_code, ".po", NULL);
+
+      gtk_entry_set_text (GTK_ENTRY (priv->tm_lang_entry), filename);
+    }
+  g_object_unref (prof_manager);
+
+  if (filename != NULL)
+    g_settings_set_string (priv->tm_settings,
+                           "filename-restriction",
+                           filename);
+
+  g_free (filename);
+
+  g_settings_bind (priv->tm_settings,
+                   "restrict-to-filename",
+                   priv->use_lang_profile_in_tm,
+                   "active",
+                   G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+  g_settings_bind (priv->tm_settings,
+                   "po-directory",
+                   priv->directory_entry,
+                   "text",
+                   G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+  g_settings_bind (priv->tm_settings,
+                   "filename-restriction",
+                   priv->tm_lang_entry,
+                   "text",
+                   G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+
+  g_signal_connect (GTK_BUTTON (priv->search_button), "clicked",
+                    G_CALLBACK (on_search_button_clicked), dlg);
+
+  g_signal_connect (GTK_BUTTON (priv->add_database_button), "clicked",
+                    G_CALLBACK (on_add_database_button_clicked), dlg);
+}
+
+GtkWidget *
+gtr_translation_memory_dialog_new (GtrTranslationMemory *translation_memory)
+{
+  GtrTranslationMemoryDialog *dlg;
+
+  dlg = GTR_TRANSLATION_MEMORY_DIALOG (g_object_new (GTR_TYPE_TRANSLATION_MEMORY_DIALOG, NULL));
+
+  /* FIXME: use a property */
+  dlg->priv->translation_memory = translation_memory;
+
+  return GTK_WIDGET (dlg);
+}
diff --git a/src/translation-memory/gtr-translation-memory-dialog.h 
b/src/translation-memory/gtr-translation-memory-dialog.h
new file mode 100644
index 00000000..7a6ed2d2
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * 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/>.
+ */
+
+#ifndef __GTR_TRANSLATION_MEMORY_DIALOG_H__
+#define __GTR_TRANSLATION_MEMORY_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "gtr-translation-memory.h"
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_TRANSLATION_MEMORY_DIALOG             (gtr_translation_memory_dialog_get_type ())
+#define GTR_TRANSLATION_MEMORY_DIALOG(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialog))
+#define GTR_TRANSLATION_MEMORY_DIALOG_CONST(obj)       (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialog const))
+#define GTR_TRANSLATION_MEMORY_DIALOG_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogClass))
+#define GTR_IS_TRANSLATION_MEMORY_DIALOG(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG))
+#define GTR_IS_TRANSLATION_MEMORY_DIALOG_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG))
+#define GTR_TRANSLATION_MEMORY_DIALOG_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTR_TYPE_TRANSLATION_MEMORY_DIALOG, GtrTranslationMemoryDialogClass))
+
+typedef struct _GtrTranslationMemoryDialog         GtrTranslationMemoryDialog;
+typedef struct _GtrTranslationMemoryDialogClass    GtrTranslationMemoryDialogClass;
+typedef struct _GtrTranslationMemoryDialogPrivate  GtrTranslationMemoryDialogPrivate;
+
+struct _GtrTranslationMemoryDialog
+{
+  GtkDialog parent;
+
+  GtrTranslationMemoryDialogPrivate *priv;
+};
+
+struct _GtrTranslationMemoryDialogClass
+{
+  GtkDialogClass parent_class;
+};
+
+GType            gtr_translation_memory_dialog_get_type     (void) G_GNUC_CONST;
+
+GtkWidget       *gtr_translation_memory_dialog_new          (GtrTranslationMemory *translation_memory);
+
+G_END_DECLS
+
+#endif /* __GTR_TRANSLATION_MEMORY_DIALOG_H__ */
diff --git a/src/translation-memory/gtr-translation-memory-dialog.ui 
b/src/translation-memory/gtr-translation-memory-dialog.ui
new file mode 100644
index 00000000..f77e5292
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-dialog.ui
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="translation-memory-dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="translation-memory-box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">12</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">18</property>
+            <child>
+              <object class="GtkBox" id="vbox9">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label20">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Database:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="right_padding">12</property>
+                    <child>
+                      <object class="GtkBox" id="hbox8">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">18</property>
+                        <child>
+                          <object class="GtkLabel" id="label25">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox" id="vbox11">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkLabel" id="label26">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Select the directory which 
contains PO files:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkBox" id="hbox9">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkEntry" id="directory-entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="xalign">0.0099999997764825821</property>
+                                    <property name="invisible_char_set">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkButton" id="search-button">
+                                    <property name="label">gtk-find</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="use_stock">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="add-database-button">
+                                <property name="label" translatable="yes">Add to Database</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_action_appearance">False</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkProgressBar" id="add-database-progressbar">
+                                <property name="can_focus">False</property>
+                                <property name="no_show_all">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">3</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="vbox10">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label21">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Configuration:</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="right_padding">12</property>
+                    <child>
+                      <object class="GtkBox" id="hbox7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">18</property>
+                        <child>
+                          <object class="GtkLabel" id="label22">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox" id="box1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkBox" id="box2">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkCheckButton" id="use-lang-profile-in-tm">
+                                    <property name="label" translatable="yes">Use only files with this 
name:</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="tm-lang-entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button1</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/src/translation-memory/gtr-translation-memory-ui.c 
b/src/translation-memory/gtr-translation-memory-ui.c
new file mode 100644
index 00000000..db107175
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-ui.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2008 Igalia
+ *
+ * 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/>.
+ *
+ * Authors:
+ *   Pablo Sanxiao <psanxiao gmail com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtr-application.h"
+#include "gtr-po.h"
+#include "gtr-translation-memory.h"
+#include "gtr-translation-memory-ui.h"
+#include "gtr-tab.h"
+#include "gtr-utils.h"
+#include "gtr-window.h"
+#include "gtr-debug.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#define MAX_ELEMENTS 9
+
+#define GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE(object)           \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((object),                       \
+                                GTR_TYPE_TRANSLATION_MEMORY_UI, \
+                                GtrTranslationMemoryUiPrivate))
+
+G_DEFINE_TYPE (GtrTranslationMemoryUi, gtr_translation_memory_ui, GTK_TYPE_SCROLLED_WINDOW)
+
+struct _GtrTranslationMemoryUiPrivate
+{
+  GtrTranslationMemory *translation_memory;
+  GtkWidget *tree_view;
+  GtrTab *tab;
+
+  gchar **tm_list;
+  gint *tm_list_id;
+
+  GtkWidget *popup_menu;
+  GtrMsg *msg;
+};
+
+enum
+{
+  SHORTCUT_COLUMN,
+  LEVEL_COLUMN,
+  STRING_COLUMN,
+  N_COLUMNS
+};
+
+static void
+tree_view_size_cb (GtkWidget * widget,
+                   GtkAllocation * allocation,
+                   gpointer user_data);
+
+static void
+choose_translation (GtrTranslationMemoryUi *tm_ui, const gchar *translation)
+{
+  GtrView *view;
+  GtkTextBuffer *buffer;
+  GtrPo *po;
+  GList *current_msg = NULL;
+  GtrMsg *msg;
+
+  view = gtr_tab_get_active_view (tm_ui->priv->tab);
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+  po = gtr_tab_get_po (tm_ui->priv->tab);
+  current_msg = gtr_po_get_current_message (po);
+
+  msg = GTR_MSG (current_msg->data);
+
+  gtr_msg_set_msgstr (msg, translation);
+
+  gtk_text_buffer_begin_user_action (buffer);
+  gtk_text_buffer_set_text (buffer, translation, -1);
+  gtk_text_buffer_end_user_action (buffer);
+
+  gtr_po_set_state (po, GTR_PO_STATE_MODIFIED);
+}
+
+static void
+on_activate_item_cb (GtkMenuItem            *menuitem,
+                     GtrTranslationMemoryUi *tm_ui)
+{
+  gint index;
+
+  /* Possible this hack is not going to work with all languages neither, we
+     are supposing the integer at the end of the string */
+  index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), "option"));
+
+  choose_translation (tm_ui, tm_ui->priv->tm_list[index]);
+}
+
+static void
+free_match (gpointer data)
+{
+  GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) data;
+
+  g_free (match->match);
+  g_slice_free (GtrTranslationMemoryMatch, match);
+}
+
+static void
+showed_message_cb (GtrTab *tab, GtrMsg *msg, GtrTranslationMemoryUi *tm_ui)
+{
+  GtkListStore *model;
+  GtkTreeIter iter;
+  GtkTreeViewColumn *level_column;
+  const gchar *msgid;
+  gint i;
+  gint j;
+  GList *tm_list = NULL;
+  GList *l = NULL;
+  GList *renderers_list = NULL;
+  GtkWidget *tm_item;
+  GtkWidget *tm_menu;
+  GtkWidget *items_menu;
+  GtkWidget *window;
+  gchar *item_name;
+
+  model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tm_ui->priv->tree_view)));
+
+  window = gtk_widget_get_toplevel (GTK_WIDGET (tm_ui));
+
+  g_signal_connect (tm_ui->priv->tree_view,
+                    "size_allocate",
+                    G_CALLBACK (tree_view_size_cb), tm_ui->priv->tree_view);
+
+  if (tm_ui->priv->msg)
+    g_object_unref (tm_ui->priv->msg);
+  tm_ui->priv->msg = g_object_ref (msg);
+
+  msgid = gtr_msg_get_msgid (msg);
+
+  tm_list = gtr_translation_memory_lookup (tm_ui->priv->translation_memory, msgid);
+  g_strfreev (tm_ui->priv->tm_list);
+
+  gtk_list_store_clear (model);
+  tm_ui->priv->tm_list = g_new (gchar *, MAX_ELEMENTS + 1);
+  tm_ui->priv->tm_list_id = g_new (gint, MAX_ELEMENTS + 1);
+
+  i = 0;
+  for (l = tm_list; l && i < MAX_ELEMENTS; l = l->next)
+    {
+      GtrTranslationMemoryMatch *match = (GtrTranslationMemoryMatch *) l->data;
+
+      tm_ui->priv->tm_list_id[i] = match->id;
+      tm_ui->priv->tm_list[i] = g_strdup (match->match);
+      level_column = gtk_tree_view_get_column (GTK_TREE_VIEW (tm_ui->priv->tree_view), 0);
+      renderers_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (level_column));
+
+      g_object_set (renderers_list->data,
+                    "accel-mods", GDK_CONTROL_MASK, NULL);
+      g_list_free (renderers_list);
+
+      gtk_list_store_append (model, &iter);
+      gtk_list_store_set (model, &iter,
+                          SHORTCUT_COLUMN, GDK_KEY_1 + i,
+                          STRING_COLUMN, match->match,
+                          LEVEL_COLUMN, match->level,
+                          -1);
+      i++;
+    }
+
+  /* Ensure last element is NULL */
+  tm_ui->priv->tm_list[i] = NULL;
+
+  g_list_free_full (tm_list, free_match);
+}
+
+static void
+tree_view_row_activated (GtkTreeView *tree_view,
+                         GtkTreePath *path,
+                         GtkTreeViewColumn *column,
+                         GtrTranslationMemoryUi *tm_ui)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gchar *translation;
+
+  model = gtk_tree_view_get_model (tree_view);
+
+  if (!gtk_tree_model_get_iter (model, &iter, path))
+    return;
+
+  gtk_tree_model_get (model, &iter,
+                      STRING_COLUMN, &translation,
+                      -1);
+
+  choose_translation (tm_ui, translation);
+
+  g_free (translation);
+}
+
+static void
+popup_menu_translation_activate (GtkMenuItem *menuitem,
+                                 GtrTranslationMemoryUi *tm_ui)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gchar *translation;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tm_ui->priv->tree_view));
+  if (!selection || !gtk_tree_selection_get_selected (selection, &model, &iter))
+    return;
+
+  gtk_tree_model_get (model, &iter,
+                      STRING_COLUMN, &translation,
+                      -1);
+
+  choose_translation (tm_ui, translation);
+
+  g_free (translation);
+}
+
+static void
+popup_menu_remove_from_memory (GtkMenuItem *menuitem,
+                               GtrTranslationMemoryUi *tm_ui)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint i;
+  gchar *translation;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tm_ui->priv->tree_view));
+  if (!selection || !gtk_tree_selection_get_selected (selection, &model, &iter))
+    return;
+
+  gtk_tree_model_get (model, &iter,
+                      STRING_COLUMN, &translation,
+                      -1);
+
+  for (i = 0; tm_ui->priv->tm_list[i]; i++)
+    if (!strcmp (tm_ui->priv->tm_list[i], translation))
+      break;
+
+  gtr_translation_memory_remove (tm_ui->priv->translation_memory, tm_ui->priv->tm_list_id[i]);
+
+  g_free (translation);
+
+  /* update list */
+  showed_message_cb (tm_ui->priv->tab, tm_ui->priv->msg, tm_ui);
+}
+
+static GtkWidget *
+create_tree_popup_menu (GtrTranslationMemoryUi *self)
+{
+  GtkTreeSelection *selection;
+  GtkWidget *menu;
+  GtkWidget *item;
+  GtkWidget *image;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->tree_view));
+
+  menu = gtk_menu_new ();
+
+  item = gtk_menu_item_new_with_mnemonic (_("_Use this translation"));
+  g_signal_connect (item, "activate",
+                    G_CALLBACK (popup_menu_translation_activate), self);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Remove"));
+  image = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+  g_signal_connect (item, "activate",
+                    G_CALLBACK (popup_menu_remove_from_memory), self);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_set_sensitive (item, TRUE);
+
+  gtk_widget_show_all (menu);
+
+  return menu;
+}
+
+static void
+tree_popup_menu_detach (GtrTranslationMemoryUi *self, GtkMenu * menu)
+{
+  self->priv->popup_menu = NULL;
+}
+
+static void
+gtr_translation_memory_ui_show_menu (GtrTranslationMemoryUi *self,
+                                     GdkEventButton * event)
+{
+  if (self->priv->popup_menu)
+    gtk_widget_destroy (self->priv->popup_menu);
+
+  self->priv->popup_menu = create_tree_popup_menu (self);
+
+  gtk_menu_attach_to_widget (GTK_MENU (self->priv->popup_menu),
+                             GTK_WIDGET (self),
+                             (GtkMenuDetachFunc) tree_popup_menu_detach);
+
+  if (event != NULL)
+    gtk_menu_popup (GTK_MENU (self->priv->popup_menu), NULL, NULL,
+                    NULL, NULL,
+                    event->button, event->time);
+  else
+    gtk_menu_popup (GTK_MENU (self->priv->popup_menu), NULL, NULL,
+                    gtr_utils_menu_position_under_tree_view,
+                    self->priv->tree_view,
+                    0, gtk_get_current_event_time ());
+}
+
+static void
+tree_view_size_cb (GtkWidget * widget,
+                   GtkAllocation * allocation,
+                   gpointer user_data)
+{
+  GtkTreeView *treeview;
+  GtkTreeViewColumn *column;
+  GList *renderers_list = NULL;
+  gint size;
+
+  treeview = GTK_TREE_VIEW (user_data);
+
+  column = gtk_tree_view_get_column (treeview, 2);
+  renderers_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+
+  size = gtk_tree_view_column_get_width (column);
+
+  g_object_set (renderers_list->data, "wrap-width", MAX(1, size - 10), NULL);
+
+  g_list_free (renderers_list);
+}
+
+static gboolean
+tree_view_button_press_event (GtkTreeView *tree,
+                              GdkEventButton *event,
+                              GtrTranslationMemoryUi *tm_ui)
+{
+  GtkTreePath *path;
+
+  if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
+    return FALSE;
+
+  if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y,
+                                      &path, NULL, NULL, NULL))
+    return FALSE;
+
+  gtk_widget_grab_focus (GTK_WIDGET (tree));
+  gtk_tree_view_set_cursor (tree, path, NULL, FALSE);
+
+  gtr_translation_memory_ui_show_menu (tm_ui, event);
+  return TRUE;
+}
+
+static gboolean
+tree_view_popup_menu (GtkTreeView *tree, GtrTranslationMemoryUi *tm_ui)
+{
+  gtr_translation_memory_ui_show_menu (tm_ui, NULL);
+  return TRUE;
+}
+
+static void
+gtr_translation_memory_ui_init (GtrTranslationMemoryUi * tm_ui)
+{
+  GtrTranslationMemoryUiPrivate *priv;
+  GtkListStore *model;
+  GtkCellRenderer *level_renderer, *string_renderer, *shortcut_renderer;
+  GtkTreeViewColumn *shortcut, *string, *level;
+
+  tm_ui->priv = GTR_TRANSLATION_MEMORY_UI_GET_PRIVATE (tm_ui);
+  priv = tm_ui->priv;
+  tm_ui->priv->tm_list = NULL;
+  tm_ui->priv->popup_menu = NULL;
+  tm_ui->priv->msg = NULL;
+
+  priv->tree_view = gtk_tree_view_new ();
+  gtk_widget_show (priv->tree_view);
+
+  model = gtk_list_store_new (N_COLUMNS, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view),
+                           GTK_TREE_MODEL (model));
+
+  shortcut_renderer = gtk_cell_renderer_accel_new ();
+  shortcut = gtk_tree_view_column_new_with_attributes (_("Shortcut"),
+                                                       shortcut_renderer,
+                                                       "accel-key",
+                                                       SHORTCUT_COLUMN, NULL);
+  g_object_set (shortcut_renderer, "width", 80, NULL);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), shortcut);
+
+  level_renderer = gtk_cell_renderer_progress_new ();
+  level = gtk_tree_view_column_new_with_attributes (_("Level"),
+                                                    level_renderer,
+                                                    "value", LEVEL_COLUMN,
+                                                    NULL);
+  g_object_set (level_renderer, "width", 80, NULL);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), level);
+
+  string_renderer = gtk_cell_renderer_text_new ();
+  string = gtk_tree_view_column_new_with_attributes (_("String"),
+                                                     string_renderer,
+                                                     "text", STRING_COLUMN,
+                                                     NULL);
+  gtk_tree_view_column_set_sizing (string, GTK_TREE_VIEW_COLUMN_FIXED);
+
+  g_object_set (string_renderer,
+                "ypad", 0,
+                "xpad", 5,
+                "yalign", 0.0,
+                "wrap-mode", PANGO_WRAP_WORD_CHAR,
+                NULL);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), string);
+
+  g_signal_connect (priv->tree_view, "button-press-event",
+                    G_CALLBACK (tree_view_button_press_event), tm_ui);
+
+  g_signal_connect (priv->tree_view, "popup-menu",
+                    G_CALLBACK (tree_view_popup_menu), tm_ui);
+
+  g_signal_connect (priv->tree_view, "row-activated",
+                    G_CALLBACK (tree_view_row_activated), tm_ui);
+}
+
+static void
+gtr_translation_memory_ui_dispose (GObject * object)
+{
+  GtrTranslationMemoryUi *tm_ui = GTR_TRANSLATION_MEMORY_UI (object);
+
+  DEBUG_PRINT ("Dispose translation memory ui");
+
+  g_clear_object (&tm_ui->priv->msg);
+
+  G_OBJECT_CLASS (gtr_translation_memory_ui_parent_class)->dispose (object);
+}
+
+static void
+gtr_translation_memory_ui_finalize (GObject * object)
+{
+  GtrTranslationMemoryUi *tm_ui = GTR_TRANSLATION_MEMORY_UI (object);
+
+  DEBUG_PRINT ("Finalize translation memory ui");
+
+  g_strfreev (tm_ui->priv->tm_list);
+
+  G_OBJECT_CLASS (gtr_translation_memory_ui_parent_class)->finalize (object);
+}
+
+static void
+gtr_translation_memory_ui_class_init (GtrTranslationMemoryUiClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GtrTranslationMemoryUiPrivate));
+
+  object_class->dispose = gtr_translation_memory_ui_dispose;
+  object_class->finalize = gtr_translation_memory_ui_finalize;
+}
+
+GtkWidget *
+gtr_translation_memory_ui_new (GtkWidget *tab,
+                               GtrTranslationMemory *translation_memory)
+{
+  GtrTranslationMemoryUi *tm_ui;
+  tm_ui = g_object_new (GTR_TYPE_TRANSLATION_MEMORY_UI, NULL);
+
+  tm_ui->priv->tab = GTR_TAB (tab);
+  tm_ui->priv->translation_memory = translation_memory;
+
+  g_signal_connect (tab,
+                    "showed-message", G_CALLBACK (showed_message_cb), tm_ui);
+
+  /* Scrolledwindow needs to be realized to add a widget */
+  gtk_container_add (GTK_CONTAINER (tm_ui), tm_ui->priv->tree_view);
+
+  return GTK_WIDGET (tm_ui);
+}
diff --git a/src/translation-memory/gtr-translation-memory-ui.h 
b/src/translation-memory/gtr-translation-memory-ui.h
new file mode 100644
index 00000000..536cfc9f
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-ui.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Igalia  
+ * 
+ * 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/>.
+ *
+ * Authors:
+ *   Pablo Sanxiao <psanxiao gmail com>
+ */
+
+#ifndef __TRANSLATION_MEMORY_UI_H__
+#define __TRANSLATION_MEMORY_UI_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_TRANSLATION_MEMORY_UI          (gtr_translation_memory_ui_get_type ())
+#define GTR_TRANSLATION_MEMORY_UI(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUi))
+#define GTR_TRANSLATION_MEMORY_UI_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), 
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUiClass))
+#define GTR_IS_TRANSLATION_MEMORY_UI(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GTR_TYPE_TRANSLATION_MEMORY_UI))
+#define GTR_IS_TRANSLATION_MEMORY_UI_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE ((k), 
GTR_TYPE_TRANSLATION_MEMORY_UI))
+#define GTR_TRANSLATION_MEMORY_UI_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), 
GTR_TYPE_TRANSLATION_MEMORY_UI, GtrTranslationMemoryUiClass))
+
+typedef struct _GtrTranslationMemoryUi        GtrTranslationMemoryUi;
+typedef struct _GtrTranslationMemoryUiClass   GtrTranslationMemoryUiClass;
+typedef struct _GtrTranslationMemoryUiPrivate GtrTranslationMemoryUiPrivate;
+
+struct _GtrTranslationMemoryUi
+{
+  GtkScrolledWindow parent_instance;
+
+  /*< private > */
+  GtrTranslationMemoryUiPrivate *priv;
+};
+
+struct _GtrTranslationMemoryUiClass
+{
+  GtkScrolledWindowClass parent_class;
+};
+
+GType            gtr_translation_memory_ui_get_type             (void) G_GNUC_CONST;
+
+GType            gtr_translation_memory_ui_register_type        (GTypeModule            *module);
+
+GtkWidget       *gtr_translation_memory_ui_new                  (GtkWidget              *tab,
+                                                                 GtrTranslationMemory   *translation_memory);
+
+G_END_DECLS
+#endif /* __TRANSLATION_MEMORY_UI_H__ */
diff --git a/src/translation-memory/gtr-translation-memory-utils.c 
b/src/translation-memory/gtr-translation-memory-utils.c
new file mode 100644
index 00000000..9c5580ad
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-utils.c
@@ -0,0 +1,96 @@
+/*
+ * (C) 2001     Fatih Demir <kabalak kabalak net>
+ *     2012    Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or   
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ *   Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtr-translation-memory-utils.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+
+/**
+ * gtr_scan_dir:
+ * @dir: the dir to parse
+ * @list: the list where to store the GFiles
+ * @po_name: the name of the specific po file to search or NULL.
+ *
+ * Scans the directory and subdirectories of @dir looking for filenames remained
+ * with .po or files that matches @po_name. @list must be freed with
+ * g_slist_free_full (list, g_object_unref).
+ */
+void
+gtr_scan_dir (GFile * dir, GSList ** list, const gchar * po_name)
+{
+  GFileInfo *info;
+  GError *error;
+  GFile *file;
+  GFileEnumerator *enumerator;
+
+  error = NULL;
+  enumerator = g_file_enumerate_children (dir,
+                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
+                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                          NULL, &error);
+  if (enumerator)
+    {
+      error = NULL;
+
+      while ((info =
+              g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
+        {
+          const gchar *name;
+          gchar *filename;
+
+          name = g_file_info_get_name (info);
+          file = g_file_get_child (dir, name);
+
+          if (po_name != NULL)
+            {
+              if (g_str_has_suffix (po_name, ".po"))
+                filename = g_strdup (po_name);
+              else
+                filename = g_strconcat (po_name, ".po", NULL);
+            }
+          else
+            filename = g_strdup (".po");
+
+          if (g_str_has_suffix (name, filename))
+            *list = g_slist_prepend (*list, file);
+          g_free (filename);
+
+          gtr_scan_dir (file, list, po_name);
+          g_object_unref (info);
+        }
+      g_file_enumerator_close (enumerator, NULL, NULL);
+      g_object_unref (enumerator);
+
+      if (error)
+        {
+          g_warning ("%s", error->message);
+        }
+    }
+}
+
diff --git a/src/translation-memory/gtr-translation-memory-utils.h 
b/src/translation-memory/gtr-translation-memory-utils.h
new file mode 100644
index 00000000..07660a54
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory-utils.h
@@ -0,0 +1,33 @@
+/*
+ * (C) 2001     Fatih Demir <kabalak kabalak net>
+ *     2012     Ignacio Casal Quinteiro <icq gnome org>
+ *
+ * gtranslator 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 2 of the License, or   
+ * (at your option) any later version.
+ *
+ * gtranslator 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/>.
+ *
+ * Authors:
+ *   Fatih Demir <kabalak kabalak net>
+ *   Ignacio Casal Quinteiro <icq gnome org>
+ */
+
+#ifndef GTR_TRANSLATION_MEMORY_UTILS_H
+#define GTR_TRANSLATION_MEMORY_UTILS_H
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+void    gtr_scan_dir    (GFile         *dir,
+                         GSList       **list,
+                         const gchar   *po_name);
+
+#endif
diff --git a/src/translation-memory/gtr-translation-memory.c b/src/translation-memory/gtr-translation-memory.c
new file mode 100644
index 00000000..95b7c6fc
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ *
+ * 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 "gtr-translation-memory.h"
+
+G_DEFINE_INTERFACE (GtrTranslationMemory, gtr_translation_memory, G_TYPE_OBJECT)
+
+/**
+ * gtr_translation_memory_store:
+ * @obj: a #GtrTranslationMemory
+ * @msg: message
+ *
+ * Stores the @msg in the database.
+ */
+gboolean
+gtr_translation_memory_store (GtrTranslationMemory * obj, GtrMsg * msg)
+{
+  g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), FALSE);
+  return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->store (obj, msg);
+}
+
+/* Default implementation */
+static gboolean
+gtr_translation_memory_store_default (GtrTranslationMemory * obj, GtrMsg * msg)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+/**
+ * gtr_translation_memory_store_list:
+ * @obj: a #GtrTranslationMemory
+ * @msgs: list of messages (#GtrMsg)
+ *
+ * Stores the messages from @msgs in the database.
+ */
+gboolean
+gtr_translation_memory_store_list (GtrTranslationMemory * obj, GList * msgs)
+{
+  g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), FALSE);
+  return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->store_list (obj, msgs);
+}
+
+/* Default implementation */
+static gboolean
+gtr_translation_memory_store_list_default (GtrTranslationMemory * obj,
+                                           GList * msgs)
+{
+  GList * l;
+
+  for (l = msgs; l; l = g_list_next (l))
+    {
+      GtrMsg *msg = GTR_MSG (l->data);
+      gboolean result;
+
+      if (!gtr_msg_is_translated (msg))
+        continue;
+
+      result = gtr_translation_memory_store (obj, msg);
+      if (!result)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * gtr_translation_memory_remove:
+ * @obj: a #GtrTranslationMemory
+ * @original: the original message.
+ * @translation: the translation to remove.
+ *
+ * Removes @translation of @original from translation memory.
+ */
+void
+gtr_translation_memory_remove (GtrTranslationMemory * obj,
+                                                gint  translation_id)
+{
+  g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+  return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->remove (obj,
+                                                        translation_id);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_remove_default (GtrTranslationMemory * obj,
+                                                        gint translation_id)
+{
+}
+
+/**
+ * gtr_translation_memory_lookup:
+ * @obj: a #GtrTranslationMemory
+ * @phrase: the unstranslated text to search for translations.
+ *
+ * Looks for the @phrase in the database and gets a list of the #GtrTranslationMemoryMatch.
+ *
+ * Returns: a list of #GtrTranslationMemoryMatch.
+ */
+GList *
+gtr_translation_memory_lookup (GtrTranslationMemory * obj,
+                               const gchar * phrase)
+{
+  g_return_val_if_fail (GTR_IS_TRANSLATION_MEMORY (obj), 0);
+  return GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->lookup (obj, phrase);
+}
+
+/* Default implementation */
+static GList *
+gtr_translation_memory_lookup_default (GtrTranslationMemory *obj,
+                                       const gchar * phrase)
+{
+  g_return_val_if_reached (0);
+}
+
+/**
+ * gtr_translation_memory_set_max_omits:
+ * @omits: the number of omits
+ *
+ * Sets the number of omits used in the search.
+ */
+void
+gtr_translation_memory_set_max_omits (GtrTranslationMemory * obj, gsize omits)
+{
+  g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+  GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_omits (obj, omits);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_set_max_omits_default (GtrTranslationMemory * obj,
+                                              gsize omits)
+{
+  g_return_if_reached ();
+}
+
+/**
+ * gtr_translation_memory_set_max_delta:
+ * @delta: the difference in the length of strings
+ *
+ * Sets the difference in the length of string for searching in the database.
+ */
+void
+gtr_translation_memory_set_max_delta (GtrTranslationMemory * obj, gsize delta)
+{
+  g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+  GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_delta (obj, delta);
+}
+
+/* Default implementation */
+static void
+  gtr_translation_memory_set_max_delta_default
+  (GtrTranslationMemory * obj, gsize omits)
+{
+  g_return_if_reached ();
+}
+
+/**
+ * gtr_translation_memory_set_max_items:
+ * @items: the max item to return in lookup
+ *
+ * Sets the number of item to return in gtr_translation_memory_lookup().
+ */
+void
+gtr_translation_memory_set_max_items (GtrTranslationMemory * obj, gint items)
+{
+  g_return_if_fail (GTR_IS_TRANSLATION_MEMORY (obj));
+  GTR_TRANSLATION_MEMORY_GET_IFACE (obj)->set_max_items (obj, items);
+}
+
+/* Default implementation */
+static void
+gtr_translation_memory_set_max_items_default (GtrTranslationMemory * obj, gint items)
+{
+  g_return_if_reached ();
+}
+
+static void
+gtr_translation_memory_default_init (GtrTranslationMemoryInterface *iface)
+{
+  static gboolean initialized = FALSE;
+
+  iface->store = gtr_translation_memory_store_default;
+  iface->store_list = gtr_translation_memory_store_list_default;
+  iface->remove = gtr_translation_memory_remove_default;
+  iface->lookup = gtr_translation_memory_lookup_default;
+  iface->set_max_omits = gtr_translation_memory_set_max_omits_default;
+  iface->set_max_delta = gtr_translation_memory_set_max_delta_default;
+  iface->set_max_items = gtr_translation_memory_set_max_items_default;
+
+  if (!initialized)
+    initialized = TRUE;
+}
+
+
diff --git a/src/translation-memory/gtr-translation-memory.gresource.xml 
b/src/translation-memory/gtr-translation-memory.gresource.xml
new file mode 100644
index 00000000..17f797cd
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/gtranslator/plugins/translation-memory/ui">
+    <file preprocess="xml-stripblanks">gtr-translation-memory-dialog.ui</file>
+  </gresource>
+</gresources>
diff --git a/src/translation-memory/gtr-translation-memory.h b/src/translation-memory/gtr-translation-memory.h
new file mode 100644
index 00000000..a3f29abf
--- /dev/null
+++ b/src/translation-memory/gtr-translation-memory.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ *
+ * 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/>.
+ */
+
+#ifndef _GTR_TRANSLATION_MEMORY_H_
+#define _GTR_TRANSLATION_MEMORY_H_
+
+#include <glib-object.h>
+#include "gtr-msg.h"
+
+G_BEGIN_DECLS
+#define GTR_TYPE_TRANSLATION_MEMORY (gtr_translation_memory_get_type ())
+#define GTR_TRANSLATION_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTR_TYPE_TRANSLATION_MEMORY, 
GtrTranslationMemory))
+#define GTR_IS_TRANSLATION_MEMORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTR_TYPE_TRANSLATION_MEMORY))
+#define GTR_TRANSLATION_MEMORY_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), 
GTR_TYPE_TRANSLATION_MEMORY, GtrTranslationMemoryInterface))
+
+typedef struct _GtrTranslationMemory GtrTranslationMemory;
+typedef struct _GtrTranslationMemoryInterface GtrTranslationMemoryInterface;
+
+struct _GtrTranslationMemoryInterface
+{
+  GTypeInterface g_iface;
+
+  gboolean (*store) (GtrTranslationMemory * obj, GtrMsg * msg);
+  gboolean (*store_list) (GtrTranslationMemory * obj, GList * msgs);
+  void (*remove) (GtrTranslationMemory *obj,
+                  gint                 translation_id);
+
+  GList *(*lookup) (GtrTranslationMemory * obj, const gchar * phrase);
+  void (*set_max_omits) (GtrTranslationMemory * obj, gsize omits);
+  void (*set_max_delta) (GtrTranslationMemory * obj, gsize delta);
+  void (*set_max_items) (GtrTranslationMemory * obj, gint items);
+};
+
+typedef struct _GtrTranslationMemoryMatch GtrTranslationMemoryMatch;
+struct _GtrTranslationMemoryMatch
+{
+  gchar *match;
+  gint level;
+  gint id;
+};
+
+GType           gtr_translation_memory_get_type         (void);
+
+gboolean        gtr_translation_memory_store            (GtrTranslationMemory   *obj,
+                                                         GtrMsg                 *msg);
+
+gboolean        gtr_translation_memory_store_list       (GtrTranslationMemory   *obj,
+                                                         GList                  *msg);
+
+void            gtr_translation_memory_remove           (GtrTranslationMemory   *obj,
+                                                         gint                  translation_id);
+
+GList          *gtr_translation_memory_lookup           (GtrTranslationMemory   *obj,
+                                                         const gchar            *phrase);
+
+void            gtr_translation_memory_set_max_omits    (GtrTranslationMemory   *obj,
+                                                         gsize                   omits);
+
+void            gtr_translation_memory_set_max_delta    (GtrTranslationMemory   *obj,
+                                                         gsize                   delta);
+
+void            gtr_translation_memory_set_max_items    (GtrTranslationMemory   *obj,
+                                                         gint                    items);
+
+G_END_DECLS
+#endif
diff --git a/src/translation-memory/meson.build b/src/translation-memory/meson.build
new file mode 100644
index 00000000..2ed682da
--- /dev/null
+++ b/src/translation-memory/meson.build
@@ -0,0 +1,36 @@
+memory_resource_data = files(
+    'gtr-translation-memory-dialog.ui',
+)
+
+memory_resource = files('gtr-translation-memory.gresource.xml')
+
+sources += gnome.compile_resources(
+  'gtr-translation-memory-resources', memory_resource,
+        source_dir: src_dir,
+      dependencies: memory_resource_data,
+            export: true
+)
+
+sources += files(
+  'gtr-translation-memory.c',
+  'gtr-translation-memory-dialog.c',
+  'gtr-translation-memory-ui.c',
+  'gtr-translation-memory-utils.c',
+)
+
+subdir('gda')
+
+# GSettings schema
+memory_schema_conf = configuration_data()
+memory_schema_conf.set('GETTEXT_PACKAGE', meson.project_name())
+
+memory_schema = 'org.gnome.gtranslator.plugins.translation-memory.gschema.xml'
+
+schema_xml = configure_file(
+  input: memory_schema + '.in',
+  output: memory_schema,
+  install: true,
+  install_dir: gtranslator_schemadir,
+  configuration: memory_schema_conf
+)
+
diff --git a/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in 
b/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in
new file mode 100644
index 00000000..8bfdae84
--- /dev/null
+++ b/src/translation-memory/org.gnome.gtranslator.plugins.translation-memory.gschema.xml.in
@@ -0,0 +1,43 @@
+<schemalist>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.gtranslator.plugins.translation-memory" 
path="/org/gnome/gtranslator/plugins/translation-memory/">
+    <key name="po-directory" type="s">
+      <default>''</default>
+      <summary>PO directory</summary>
+      <description>
+        Directory containing PO files to add to the translation memory.
+      </description>
+    </key>
+    <key name="restrict-to-filename" type="b">
+      <default>false</default>
+      <summary>Restrict search by filename</summary>
+      <description>
+        If true, only include files with a specified filename when searching 
+        the translation memory.
+      </description>
+    </key>
+    <key name="filename-restriction" type="s">
+      <default>''</default>
+      <summary>Filename to restrict search to</summary>
+      <description>
+        Filename to which searching of the translation memory should be 
+        restricted.
+      </description>
+    </key>
+    <key name="max-missing-words" type="i">
+      <default>2</default>
+      <summary>Maximum number of missing words</summary>
+      <description>
+        Maximum number of words that can be missing from a message displayed as 
+        a match by the translation memory.
+      </description>
+    </key>
+    <key name="max-length-diff" type="i">
+      <default>2</default>
+      <summary>Maximum difference in message length</summary>
+      <description>
+        Maximum difference in length between messages displayed as matches by 
+        the translation memory.
+      </description>
+    </key>
+  </schema>
+</schemalist>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]