kayでの国際化対応について

29 views
Skip to first unread message

Yosuke Suzuki

unread,
Jan 16, 2013, 8:08:51 AM1/16/13
to kay-us...@googlegroups.com
スズキと申します。

kay-frameworkを便利に使わせてもらっています。

さて、kayをベースにCMSを作りたいと思っていますが、
その際の国際化対応に関連してアドバイスをいただけないでしょうか。

ウェブページ上に表示する各種メニューについては
ビルトインされているi18n機能を使って多言語対応可能だと思います。

一方で、CMSで管理するコンテンツ自体については、
どのようにdatastoreで管理すれば多言語対応できるのか悩んでいます。

ベースとなるモデルを以下のように定義した場合、
class Article(db.Model):
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

別の翻訳コンテンツを入れるためのモデルを作ってkey_nameの工夫などで
連携させるのが、一手だと思います。

class ArticleTrans(db.Model):
    lang = db.StringProperty(verbose_name=_('Language'),required=True)
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

もう一つ考えてみたのは、Expandoモデルを定義した上で
class Article(db.Expando):
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

title_enやcontent_enのように対応する言語の分だけ、
プロパティを動的に追加するのもあるのかなと思いました。
この場合は、対応する言語が増えた場合は破綻しそうですが。

よろしくお願いします。

--
--------------------------
Yosuke Suzuki

Takashi Matsuo

unread,
Jan 16, 2013, 9:45:29 AM1/16/13
to kay-us...@googlegroups.com

スズキさん

2013年1月16日 5:08 Yosuke Suzuki <yosuke...@gmail.com>:

スズキと申します。

kay-frameworkを便利に使わせてもらっています。

さて、kayをベースにCMSを作りたいと思っていますが、
その際の国際化対応に関連してアドバイスをいただけないでしょうか。

これ、悩みますよね。
 

ウェブページ上に表示する各種メニューについては
ビルトインされているi18n機能を使って多言語対応可能だと思います。

一方で、CMSで管理するコンテンツ自体については、
どのようにdatastoreで管理すれば多言語対応できるのか悩んでいます。

ベースとなるモデルを以下のように定義した場合、
class Article(db.Model):
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

別の翻訳コンテンツを入れるためのモデルを作ってkey_nameの工夫などで
連携させるのが、一手だと思います。

class ArticleTrans(db.Model):
    lang = db.StringProperty(verbose_name=_('Language'),required=True)
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

僕は基本的にこちらの方が良いとおもいます。

ただ、まだ色々考えることがありそうです。
* ArticleTrans と Article を別クラスにする必要ありますか?同じでも動きそう。
* 両方の class とも draft フラグのようなものがあったほうが良さそう
* 元のコンテンツにも lang があったほうが良さそう
* 元のコンテンツが変更した場合にはそれを検知して
  * 検知はどのように行うか
    * Article の更新時に、翻訳全てに stale フラグを付ける - これが簡単で良さそう
    * update を比較する - あまりおすすめしません
    * entity group の version を使う - ちょっと難しそう
  * 検知した場合どうするか
    * 翻訳と一緒に「古い」旨と元のコンテンツへのリンクも表示する
    * or 元のコンテンツを表示する

下記はコストもかかるのであくまで nice-to-have ですが
* 元のコンテンツを翻訳した時のバージョンと、最新版の差分がわかると嬉しい

key_name の工夫というと、翻訳コンテンツの parent に元コンテンツを指定するということでしょうかね。
これはとても良いとおもいます。

一点だけ懸念があるとすれば、
翻訳 UI の仕様や、元コンテンツの人気度などによっては Entity Group への書き込みが多すぎて破綻する可能性もありそうです。
例えば、もし翻訳 UI の方で Auto Save 機能があり、複数の翻訳者が同時に作業していると書き込みが増えます。
といっても、Auto Save 機能を Datastore に直接書き込むのもどうかと思うので、気にしなくても良さそうです。
 

もう一つ考えてみたのは、Expandoモデルを定義した上で
class Article(db.Expando):
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

title_enやcontent_enのように対応する言語の分だけ、
プロパティを動的に追加するのもあるのかなと思いました。
この場合は、対応する言語が増えた場合は破綻しそうですが。

そうですね。おっしゃるとおり、これはあまりおすすめしません。

-- 
Takashi Matsuo
matsuo....@gmail.com
Kay's daddy
 

よろしくお願いします。

--
--------------------------
Yosuke Suzuki

--
このメールは Google グループのグループ「kay-users-ja」の登録者に送られています。
このグループに投稿するには、kay-us...@googlegroups.com にメールを送信してください。
このグループから退会するには、kay-users-ja...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/kay-users-ja?hl=ja からこのグループにアクセスしてください。

Yosuke Suzuki

unread,
Jan 16, 2013, 5:48:23 PM1/16/13
to kay-us...@googlegroups.com
返信ありがとうございます。
ベースとなるモデルを以下のように定義した場合、
class Article(db.Model):
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

別の翻訳コンテンツを入れるためのモデルを作ってkey_nameの工夫などで
連携させるのが、一手だと思います。

class ArticleTrans(db.Model):
    lang = db.StringProperty(verbose_name=_('Language'),required=True)
    title = db.StringProperty(verbose_name=_('Title'),required=True,indexed=False)
    content = db.TextProperty(verbose_name=_('Content'),required=True)
    update = db.DateTimeProperty(verbose_name=_('Update'),auto_now=True)
    created = db.DateTimeProperty(verbose_name=_('Created'),auto_now_add=True)

僕は基本的にこちらの方が良いとおもいます。

ただ、まだ色々考えることがありそうです。
* ArticleTrans と Article を別クラスにする必要ありますか?同じでも動きそう。
* 両方の class とも draft フラグのようなものがあったほうが良さそう
そうですね。モデルは同じものでも良さそうです。
draftフラグ的なものは考えていたのですが、マニュアル操作での並び順など
制御用のプロパティがもっと増えた場合は、それらをベースのモデルで管理して
おくのかなと思っていました。
ただ正規化するよりも冗長にして、パフォーマンス&スケールアウトを優先した方がGAEっぽいですかね。
  
* 元のコンテンツにも lang があったほうが良さそう
* 元のコンテンツが変更した場合にはそれを検知して
  * 検知はどのように行うか
    * Article の更新時に、翻訳全てに stale フラグを付ける - これが簡単で良さそう
    * update を比較する - あまりおすすめしません
    * entity group の version を使う - ちょっと難しそう
  * 検知した場合どうするか
    * 翻訳と一緒に「古い」旨と元のコンテンツへのリンクも表示する
    * or 元のコンテンツを表示する
更新については検討できてなかったので、
参考にさせていただきます。
 
下記はコストもかかるのであくまで nice-to-have ですが
* 元のコンテンツを翻訳した時のバージョンと、最新版の差分がわかると嬉しい

key_name の工夫というと、翻訳コンテンツの parent に元コンテンツを指定するということでしょうかね。
これはとても良いとおもいます。
たしかにparentを指定したほうが良さそうですね。

考えていたのは、Article のentityのkey_nameをarticle1 とした場合、
デフォルトに設定していない、言語のコンテンツのkey_nameをarticle1_enなどとして、
以下のようにクエリ&get

lang = 'en' #現在の表示言語
article_results = Article.all().order('-update')
trans_results = ArticleTrans.get_by_key_name([ar.key().name()+_+lang for ar in article_results.fetch(20,0)])

上の2つの結果を組み合わせてArticle一覧ページを表示できるかなと思っていました。
一覧を表示して、その後に遷移する個別のArticleのページ自体は以下のように。
article_entity = Article.get_by_key_name('article1')
trans_entity = ArticleTrans.get_by_key_name('article1_en')

parentを指定してかつ同じArticle場合は、Article一覧ページのクエリは
以下のような感じでしょうか?

results = Article.all().filter(u'lang =',lang).order('-update')

個別のページについてはancestorクエリを使う感じでしょうか?
article_entity = Article.get_by_key_name('article1')
if article_entity.lang != lang:
   article_results = Article.all.ancestor(article_entity)
   for ar in article_results:
       if ar.lang == lang:
            article_entity = ar

parentとchildの関係はほとんど扱ったことがないので、、、 

一点だけ懸念があるとすれば、
翻訳 UI の仕様や、元コンテンツの人気度などによっては Entity Group への書き込みが多すぎて破綻する可能性もありそうです。
例えば、もし翻訳 UI の方で Auto Save 機能があり、複数の翻訳者が同時に作業していると書き込みが増えます。
といっても、Auto Save 機能を Datastore に直接書き込むのもどうかと思うので、気にしなくても良さそうです。
ここもまったく検討していなかった部分です。
書き込みのパフォーマンスについて検討しておきたいと思います。



--
--------------------------
Yosuke Suzuki
Reply all
Reply to author
Forward
0 new messages