Skip to content

Content localization Proposal

geloescht edited this page Apr 18, 2016 · 4 revisions

How to configure:

var Article = new keystone.List('Article', {
	autokey: { from: 'name', path: 'key', unique: true },
    translation: true //to use built-in service
    translation: require('custom-translation-service') //to inject a different service
});

Article.add({`
    name: { type: String, required: true, translatable: true },
    description: { type: String, translatable: true },
    href: { type: String, translatable: false}`
});

How to use:

There does not seem to be a way to implicitly set language on models in an opaque way, because keystone cannot determine from which request a model is accessed.

  1. Set language explicitly
  • + Maximum backwards compatibility

  • - Transparent to developers, requires documentation

      router.get('some-article', function(req, res)
      {
        context.list('Article').model.findOne({href: 'http://some.website/some/page'}).localize(req.language).exec(function(err, article)
        {
          res.end(article.name);
        });
      }
    
  1. Wrap keystone features in "context" objects
  • + Clean

  • + Provides solution to other poblems as well, such as determining current user model for the request

  • - Might require restructuring of internals

  • - Transparent to developers, requires documentation

      router.get('some-article', function(req, res)
      {
        var context = keystone.context(req);
        
        context.list('Article').model.findOne({href: 'http://some.website/some/page'}).exec(function(err, article)
        {
          res.end(article.name);
        });
        
        // context should probably be chainable and be usable in different places
        var listContext = keystone.list('Article').context(req);
        var modelContext = keystone.list('Article').model.context(req);
        // keystone should provide a global context retrieving all language fields or a fallback language by default
        var globalContext = keystone;
        //context can also be contructed from manually supplied parameters
        var customContext = keystone.context({language: 'it'});
      }
    

DB structure possibilities:

  1. Put all localized fields into one main document
  • + no reference traversal
  • + might be easily implemented with virtuals
  • - big documents
  • - growing documents
  • ? impact on indexing
  1. store an embedded document per field with sub-fields per language (keyed by language code)
1. **language-code keys**
  
  - **+** dead simple
  - **-** bloat through many keys (on the good side, language codes are very short and compress well)
  - **-** many projection criteria (one per translated field) when retrieving localised document

  article_links:
  
      {
        _id: 'fhdsjfs',
        href: 'http://some.website/some/page',
        name:
        {
          en: 'Great Article',
          de: 'Toller Artikel'
        },
        description:
        {
          en: 'This is the best article I've ever read!',
          de: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
        }
      }

2. **index-based language coding**

  - **+** no key bloat
  - **-** change in translated languages might require big database update
  - **-** many projection criteria (one per translated field) if retrieving localized fields
  - **?** impact on indexing 
  
  l10n:
  
      {
        languages: [ 'en', 'de' ]
      }
  
  article_links:
  
      {
        _id: 'fhdsjfs',
        href: 'http://some.website/some/page',
        name: [ 'Great Article', 'Toller Artikel' ],
        description:[ 'This is the best article I've ever read!', 'Das ist der beste Artikel, den ich jemals gelesen habe!' ]
      }
  1. store an embedded document per language with sub-fields per translatable field
- **+** quite simple
- **-** bloat through many keys (field keys can be any length, but compress well)

  1. **language-code keys**

    - **-** many projection criteria (one per translated field) if retrieving localized fields

    article_links:

        {
          _id: 'fhdsjfs',
          href: 'http://some.website/some/page',
          l10n:
          {
            en:
            {
              name: 'Great Article',
              description: 'This is the best article I've ever read!'
            },
            de:
            {
              name: 'Toller Artikel',
              description: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
            }
          }
        }

  1. **array with language tag**

    - **+** simple projection criterion using $elemMatch

    article_links:

        {
          _id: 'fhdsjfs',
          href: 'http://some.website/some/page',
          l10n:
          [
            {
              language: 'en',
              name: 'Great Article',
              description: 'This is the best article I've ever read!'
            },
            {
              language: 'de',
              name: 'Toller Artikel',
              description: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
            }
          ]
        }
  1. Store different documents for each language (inside one or more extra collections)
  • + no growing documents
  • - additional overhead through referencing (when indexing on anything but the main _id)
  • ? impact on indexing
  • ? harder to implement
  1. one collection for translations and shared fields, indexed by group id
article_links:

    {
      group_id: 'fhdsjfs',
      language: '',
      href: 'http://some.website/some/page'
    }

    {
      group_id: 'fhdsjfs',
      language: 'en',
      name: 'Great Article',
      description: 'This is the best article I've ever read!'
    }

    {
      group_id: 'fhdsjfs',
      language: 'de',
      name: 'Toller Artikel',
      description: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
    }
  1. one collection for translations containing one document per language and main document
article_links:
  
    {
      _id: 'fhdsjfs',
      href: 'http://some.website/some/page'
    }

article_links_l10n:

    {
      article_links_id: 'fhdsjfs',
      language: 'en',
      name: 'Great Article',
      description: 'This is the best article I've ever read!'
    }

    {
      article_links_id: 'fhdsjfs',
      language: 'de',
      name: 'Toller Artikel',
      description: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
    }
  1. one collection per language containing one document per main document
- **-** many collections

article_links:
  
    {
      _id: 'fhdsjfs',
      href: 'http://some.website/some/page'
    }

article_links_en:
  
    {
      article_links_id: 'fhdsjfs',
      name: 'Great Article',
      description: 'This is the best article I've ever read!'
    }

article_links_de:

    {`
      article_links_id: 'fhdsjfs',
      name: 'Toller Artikel',
      description: 'Das ist der beste Artikel, den ich jemals gelesen habe!'
    }