R
R
Roman Krylov2015-06-05 10:46:30
ruby
Roman Krylov, 2015-06-05 10:46:30

PostgreSQL how to implement I18n using hstore?

I want to write a website with multilingual support. I use Ruby and Sequel.
I decided to store all translations of the model in one table, where the multilingual property will be in the HStore format.
---
id : PK
title : {"ru"=>"Russian title", "en"=>"English title"}
info : {"ru"=>"Russian description", "en"=> "Description in English"}
---
The simplest move is, of course, to query all property keys and select the appropriate one based on the current locale and the default locale.
In theory, there were no problems until I thought about the number of queries to the database.
Does anyone have ready-made SQL functions or other solutions in this regard?
For example, it would not be bad to have a function on the database server side, to which we pass an array of locales ["ru", "en", "de"] in order of their priority, and it returns a suitable value to us.

Update 1 ================

Here's what I coded. So far, only SQL.
Suppose we have such a sign

CREATE TABLE countries
(
  id serial NOT NULL,
  name hstore NOT NULL,
  capital hstore NOT NULL,
  locale character varying(2) NOT NULL,
  CONSTRAINT countries_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE countries
  OWNER TO distrozine;

CREATE INDEX countries_name_capital_idx
  ON countries
  USING gin
  (name, capital);

Where name and capital are multilingual properties, and locale defines the native locale for the object.
Here is the contents of this table
879d83e64e6c47dabd50855476eeb8ae.png
And with such a request we pull out the data, taking into account multilingualism
SELECT
  id,
  (array_remove(name -> ARRAY['ru','en', locale], NULL))[1] AS name,
  (array_remove(capital -> ARRAY['ru','en', locale], NULL))[1] AS capital,
  locale
  FROM countries;

after executing, we get this
52a9ed654d7d4fbcbf57d52ab4c5c34a.png
ARRAY['ru','en', locale] in the request indicates the locales we need, set by priority, while at the end we indicate that if there is not a single locale suitable for us, then we take the one that is specified native for the object .
For example, in the case of the example, it is assumed that 'ru' is the current locale, and 'en' is the default locale

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman Krylov, 2015-06-06
@xtsidx

Understood the problem myself.
Here is a simple plugin that does what I need.

module Sequel
  module Plugins
    module I18nModel

      def self.apply(model, opts={})
        model.instance_eval do
          @i18n_columns = opts[:i18n_columns]
        end
      end
      
      module ClassMethods
      
        def i18n(options = {})
          locales = options[:locales].clone
          locales << :locale
          locales = locales.pg_array
          ds = select
          @i18n_columns.each do|c|
            ds = ds.select_append(Sequel.lit("(array_remove(? -> ?, NULL))[1]", c, locales).as(c))
          end
          return ds
        end
      
      end
      
    end
  end
end

For the model, you will need to call the i18n method, in the locale parameter, pass an array of locales by priority. All in one request.

E
Eugene Burmakin, 2015-06-05
@Freika

https://github.com/bithavoc/multilang-hstore won't work? Truth there activerecord is used like.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question