[解決済み】ベストプラクティスの多言語ウェブサイト
質問内容
この質問にはもう何ヶ月も悩んでいるのですが、これまであらゆる選択肢を検討する必要がある状況にはありませんでした。今まさに、その可能性を知り、今後のプロジェクトで使用するための自分なりの好みを作る時だと感じています。
まず、私が求めている状況をスケッチしてみます。
私は、かなり長い間使用してきたコンテンツ管理システムをアップグレード/再開発しようとしています。しかし、このシステムには、多言語が大きな改善となると感じています。以前はフレームワークを使用していませんでしたが、今度のプロジェクトではLaraval4を使用するつもりです。Laravelは、PHPをよりきれいにコーディングするためのベストな選択だと思います。
Sidenote: Laraval4 should be no factor in your answer
. プラットフォームやフレームワークに依存しない、一般的な翻訳方法を探しています。
翻訳すべき内容
私が探しているシステムは、できるだけユーザーフレンドリーである必要があるため、翻訳を管理する方法はCMSの中にあるべきです。翻訳ファイルやhtml/phpパースされたテンプレートを修正するためにFTP接続を開始する必要はありません。
さらに、複数のデータベースのテーブルを、テーブルを追加することなく翻訳する最も簡単な方法を探しています。
自分で思いついたこと
もう自分でいろいろと検索したり、読んだり、試したりしているうちに 私が持っている選択肢はいくつかあります。しかし、自分が本当に求めているものに対するベストプラクティスの手法には、まだ到達していないように感じます。今、私が思いついたのはこの方法ですが、この方法には副作用もあります。
- PHPパース済みテンプレート : テンプレートシステムを PHP でパースする必要があります。そうすれば、テンプレートを開いて修正することなく、翻訳されたパラメータをHTMLに挿入することができます。さらに、PHPで解析されたテンプレートは、各言語のサブフォルダを持つ代わりに、ウェブサイト全体に対して1つのテンプレートを持つことができます(以前はそうしていました)。この目標を達成するための方法は、Smarty、TemplatePower、LaravelのBlade、または他のテンプレートパーサを使用することです。私が言ったように、これは書かれたソリューションとは独立したものであるべきです。
-
データベース駆動型
改めて説明するまでもないでしょう。しかし、このソリューションはデータベース駆動型であるべきです。CMSは、オブジェクト指向とMVCを目指しているので、文字列のための論理的なデータ構造を考える必要があります。私のテンプレートは、 templates/Controller/View.php という構造になっているので、おそらくこの構造が最も理にかなっていると思います。
Controller.View.parameter
. データベースのテーブルは、これらのフィールドを持つことになります。value
フィールドがあります。テンプレートの内部では、次のようなメソッドを使用できます。echo __('Controller.View.welcome', array('name', 'Joshua'))
で、パラメータにはWelcome, :name
. したがって、結果はWelcome, Joshua
. この方法は、:nameなどのパラメータがエディタで理解しやすいので、良い方法だと思われます。 -
データベースへの負荷が少ない
: もちろん、上記のシステムでは、これらの文字列が移動中に読み込まれる場合、データベースへの負荷が発生します。そのため、言語ファイルが管理環境で編集・保存されるとすぐに再レンダリングするようなキャッシュシステムが必要でしょう。ファイルが生成されるため、ファイルシステムのレイアウトも工夫が必要です。このような場合
languages/en_EN/Controller/View.php
や.iniなど、お好きな方をお選びください。おそらく.iniの方が最終的には早くパースされるでしょう。このフォールドにはformat parameter=value;
. レンダリングされる各ビューに独自の言語ファイルが存在する場合は、それを含めることができるので、これが最善の方法だと思います。言語パラメータは、パラメータ同士の上書きを防ぐために、グローバルスコープではなく、特定のビューにロードされる必要があります。 -
データベーステーブルの翻訳
実は、これが一番心配なんです。ニュース/ページ/などの翻訳をできるだけ早く作成する方法を探しています。各モジュールのための2つのテーブルを持つ(例えば
News
とNews_translations
) も選択肢の一つですが、良いシステムを手に入れるには手間がかかりすぎるように感じます。私が思いついたもののひとつはdata versioning
システムは、データベーステーブル名Translations
, このテーブルには、一意な組み合わせのlanguage
,tablename
とprimarykey
. 例えば、en_En / News / 1 (ID=1の英語版Newsを参照)といった具合です。しかし、この方法には2つの大きな欠点があります。まず、このテーブルはデータベース内の多くのデータでかなり長くなる傾向があり、次に、この設定を使ってテーブルを検索するのはとんでもない仕事になります。例えば、アイテムのSEOスラッグを検索すると、フルテキスト検索になり、かなり間抜けです。しかし、一方で:それはすべてのテーブルで非常に高速に翻訳可能なコンテンツを作成するための迅速な方法ですが、私はこのプロが短所を上回るとは思わない。 - フロントエンドワーク : また、フロントエンドも少し考える必要があります。もちろん、利用可能な言語をデータベースに保存し、必要なものをアクティブにします。そうすれば、スクリプトが言語を選択するためのドロップダウンを生成し、バックエンドがCMSを使ってどのような翻訳ができるかを自動的に決定することができます。選択された言語(例:en_EN)は、ビューの言語ファイルを取得するときや、ウェブサイトのコンテンツアイテムに適切な翻訳を取得するときに使用されるでしょう。
というわけで、こんな感じです。これまでのところ、私のアイデアです。日付などのローカライズオプションもまだ含まれていませんが、私のサーバーはPHP5.3.2以上をサポートしているので、ここで説明されているようにintl拡張を使用することが最良の選択です。 http://devzone.zend.com/1500/internationalization-in-php-53/ - しかし、これは後の開発段階でも役に立つでしょう。今のところ、主な問題は、ウェブサイト内のコンテンツの翻訳について、どのようにベストプラクティスを持つかです。
ここで説明したことのほかに、まだ決めかねていることがもうひとつあります。
URLの翻訳?やるべきなのか、やらないのか、どのような方法で?
だから...私はこのURLを持っている場合。
http://www.domain.com/about-us
で、英語は私のデフォルト言語です。このURLは次のように翻訳されるべきです
http://www.domain.com/over-ons
オランダ語を言語として選択した場合 それとも、簡単な方法で
/about
. 最後のものは、同じURLの複数のバージョンを生成するので、有効なオプションに見えません、このコンテンツのインデックスは、正しい方法で失敗します。
もう一つの選択肢は
http://www.domain.com/nl/about-us
の代わりに これにより、少なくとも各コンテンツに対して一意なURLが生成されます。また、これは他の言語に移動する際にも簡単です、例えば
http://www.domain.com/en/about-us
と提供されるURLは、Googleと人間の両方の訪問者にとって理解しやすくなっています。このオプションを使用すると、我々は、デフォルトの言語をどうするのですか?デフォルトの言語は、デフォルトで選択された言語を削除する必要がありますか?では、リダイレクトする
http://www.domain.com/en/about-us
から
http://www.domain.com/about-us
... なぜなら、CMSが1つの言語のためにセットアップされている場合、URLの中に言語識別を持つ必要がないからです。
そして3つ目の選択肢は、両方の選択肢を組み合わせたものです: "言語識別なし"-URL (
http://www.domain.com/about-us
) をメイン言語として使用します。そして、サブ言語には、翻訳されたSEOスラッグ付きのURLを使用します。
http://www.domain.com/nl/over-ons
&です。
http://www.domain.com/de/uber-uns
私の質問で皆さんの頭が割れることを願っています!確かに私も割られました。ここで質問として物事を解決することは、すでに私の助けになっています。以前使っていた方法と、今度作るCMSのためのアイデアを見直すことができました。
このような文章に時間を割いていただき、すでに感謝申し上げます。
// Edit #1
:
言い忘れましたが、__()関数は、与えられた文字列を翻訳するためのエイリアスです。このメソッド内には、翻訳がまだないときにデフォルトテキストが読み込まれる、ある種のフォールバックメソッドが明らかに存在するはずです。翻訳がない場合は、翻訳を挿入するか、翻訳ファイルを再生成する必要があります。
解決方法は?
トピックの前提
多言語サイトには3つの側面があります。
- インターフェース翻訳
- コンテンツ
- URLルーティング
これらはすべて異なる方法で相互接続していますが、CMSの観点からは、異なるUI要素を使用して管理され、異なる方法で保存されています。あなたは、最初の2つの実装と理解に自信があるようですね。質問は、後者の側面についてです。 URL変換はできますか?やるべきなのか、やらないのか、どのような方法で?
URLは何で作ることができますか?
とても大切なことは、「洒落たこと」をしないことです。 IDN . 代わりに 音訳 (転写とローマ字表記も)。一見すると、IDNは国際的なURLのための実行可能なオプションのように見えますが、実際には2つの理由で広告のようには機能しません。
-
のような非ASCII文字が、ブラウザによっては
'ч'
または'ž'
を'%D1%87'
と'%C5%BE'
- ユーザーがカスタムテーマを使用している場合、テーマのフォントにはこれらの文字に対応する記号がない可能性が非常に高いです。
私は数年前、YiiベースのプロジェクトでIDNアプローチを実際に試してみました(ひどいフレームワークですね、私見ですが)。その解決策を破棄する前に、上記の2つの問題に遭遇しました。また、私は、それが攻撃ベクトルであるかもしれないと疑っています。
利用可能なオプション......私が思うに。
基本的には2つの選択肢があり、それは次のように抽象化されます。
-
http://site.tld/[:query]
: ここで[:query]
は、言語とコンテンツの選択の両方を決定する -
http://site.tld/[:language]/[:query]
: ここで[:language]
の部分は、言語の選択を定義し[:query]
は、コンテンツを識別するためにのみ使用されます。
クエリーはΑとΩ ....
例えば
http://site.tld/[:query]
.
この場合、言語の主要な情報源は1つです。
[:query]
セグメントと、2つの追加ソースがあります。
まず、クエリを定義されたルーティングパターンの一つにマッチさせる必要があります(Laravelを選んだ場合 こちらをご覧ください ). パターンのマッチングに成功したら、次に言語を見つける必要があります。
パターンのすべてのセグメントを調べる必要があります。これらのセグメントすべてについて翻訳候補を探し、どの言語が使用されたかを判断します。2つの追加ソース(クッキーとヘッダー)は、ルーティングの競合が発生したときに("if"ではない)解決するために使用されます。
例えば、次のような場合です。
http://site.tld/blog/novinka
.
の音訳です。
"блог, новинка"
という意味で、英語ではおよそ
"blog", "latest"
.
すでにお気づきのように、ロシア語では "блог" は "blog" と訳されることになります。つまり、最初の部分の
[:query]
を選択した場合
ベストケース・シナリオ
で終わることになります。
['en', 'ru']
可能な言語のリスト。 そして、次のセグメント、"novinka" を取ります。このセグメントには、可能性のある言語が1つしか含まれていないかもしれません。
['ru']
.
リストに1つでも項目があれば、言語の検索に成功したことになります。
しかし、2つ(例:ロシア語とウクライナ語)以上の可能性がある場合、または0つの可能性がある場合、場合によっては、。クッキーやヘッダーを使って、正しい選択肢を見つける必要があります。
そして、他のすべてが失敗した場合、あなたはサイトのデフォルトの言語を選択します。
パラメータとしての言語
別の方法として、URLを使用することができます。
http://site.tld/[:language]/[:query]
. この場合、クエリを翻訳するときに、言語を推測する必要はありません。なぜなら、その時点ですでに、どの言語を使用すべきかがわかっているからです。
また、言語の二次的な情報源として、クッキーの値もあります。なぜなら、quot;コールドスタート(ユーザーが初めてカスタムクエリでサイトを開いたとき)の場合、可能性のある未知の言語の量を処理する必要がないからです。
その代わり、シンプルで優先順位の高い3つのオプションがあります。
-
もし
[:language]
セグメントが設定されている場合は、それを使用します。 -
もし
$_COOKIE['lang']
が設定されている場合は、それを使用します。 - デフォルトの言語を使用します。
言語がわかっている場合は、単純にクエリの翻訳を試み、翻訳に失敗した場合は、その特定のセグメントに対して(ルーティング結果に基づいて)"デフォルト値"を使用することになります。
第3の選択肢はないのですか?
はい、技術的には両方のアプローチを組み合わせることができますが、その場合、プロセスが複雑になるため、手動で
http://site.tld/en/news
から
http://site.tld/de/news
をクリックし、ニュースページがドイツ語に変わることを期待します。
しかし、このケースでさえ、クッキーの値(以前の言語選択に関する情報を含む)を使って軽減できる可能性があり、魔法や希望を少なくして実装することができます。
どの方法を使うか?
すでにご推察の通り、私がお勧めするのは
http://site.tld/[:language]/[:query]
の方がより賢明な選択です。
また、実際の言葉の状況では、URLの3番目の主要な部分である "title"を持つことになるでしょう。オンラインショップの商品名やニュースサイトの記事の見出しのようなものです。
例
http://site.tld/en/news/article/121415/EU-as-global-reserve-currency
この場合
'/news/article/121415'
がクエリになり
'EU-as-global-reserve-currency'
はタイトルです。純粋にSEOのためです。
Laravelでできるのか?
ちょっとだけですが、デフォルトではありません。
私はあまり詳しくないのですが、私が見たところ、Laravelはシンプルなパターンベースのルーティング機構を使用しています。多言語のURLを実装するには、おそらく コアクラスを拡張する なぜなら、多言語ルーティングは、異なる形式のストレージ(データベース、キャッシュ、設定ファイル)にアクセスする必要があるからです。
ルーティングされました。次はどうする?
現在の言語とクエリの翻訳セグメントです。これらの値は、結果を生成するクラスへのディスパッチに使用することができます。
基本的には、以下のようなURLです。
http://site.tld/ru/blog/novinka
(または
'/ru'
は次のようになります。
$parameters = [
'language' => 'ru',
'classname' => 'blog',
'method' => 'latest',
];
これはディスパッチに使うだけです。
$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );
... あるいは、特定の実装に依存した、そのバリエーション。
関連
-
[解決済み】空の配列要素を削除する
-
[解決済み】不明なMySQLサーバーのホスト
-
[解決済み】XAMPPのphpMyAdminで「設定にあるcontroluserの接続に失敗しました。
-
[解決済み] mysqli_fetch_assoc() は、パラメータ 1 が mysqli_result であることを期待し、boolean が与えられる [重複] 。
-
[解決済み】警告: file_get_contents(): https:// ラッパーがサーバー構成ですべて無効になっています。
-
[解決済み] MySQLです。大きなVARCHARとTEXTの比較?
-
[解決済み] デバイスの現在の言語を取得する
-
[解決済み】PHPパスワードのハッシュとソルトの安全性について
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
-
[解決済み】多言語データベースのためのスキーマ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】予期せぬ例外。SQLSTATE[HY000] [1045] Access denied for user ****@'localhost' (using password: YES)
-
[解決済み】PHP 7.2 - Warning: count(): パラメータは配列かCountableを実装したオブジェクトでなければならない [解決済み]
-
[解決済み】pdo - 非オブジェクトのメンバー関数prepare()への呼び出し【重複】。
-
[解決済み】Chrome net::ERR_INCOMPLETE_CHUNKED_ENCODING エラーが発生しました。
-
[解決済み】警告:mysql_fetch_array()はパラメータ1がリソースであることを期待、ブール値は[重複]で与えられる]
-
[解決済み] * vchiqインスタンスを開くのに失敗しました。
-
phpのAllowed memory size of 134217728 bytes枯渇問題の解決法
-
[解決済み】In_arrayが動作しない。
-
[解決済み】書き込みコンテキストでメソッドの戻り値を使用することができない
-
[解決済み】警告: file_get_contents(): https:// ラッパーがサーバー構成ですべて無効になっています。