スレッドに非常に遅れていますが、私が以前に使用した手法(Angularより前)は、JSONとJSの柔軟性を利用して動的にコレクションキーを参照し、環境の不可解な事実(ホストサーバー名、現在のブラウザー言語)を使用することですなど)。JSONデータ構造内の接尾辞付きのキー名を選択的に区別/優先するための入力として。
これにより、(OPごとに)単に展開環境コンテキストが提供されるだけでなく、i18nまたは(理想的には)単一の構成マニフェスト内で重複する必要のない、同時に必要なi18nまたはその他の差異を提供するための任意のコンテキスト(言語など)が提供されます。
10ラインについてVANILLA JS
単純化しすぎたが古典的な例:ホストサーバーも(ナッチ)が異なる環境ごとに異なる、JSON形式のプロパティファイル内のAPIエンドポイントベースURL:
...
'svcs': {
'VER': '2.3',
'API@localhost': 'http://localhost:9090/',
'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
},
...
識別機能の鍵となるのは、リクエスト内のサーバーのホスト名だけです。
これは当然、ユーザーの言語設定に基づいて追加のキーと組み合わせることができます。
...
'app': {
'NAME': 'Ferry Reservations',
'NAME@fr': 'Réservations de ferry',
'NAME@de': 'Fähren Reservierungen'
},
...
識別/設定の範囲は、(上記のように)個々のキーに限定できます。「ベース」キーは、関数への入力に対応するキー+サフィックス、または構造全体、およびその構造自体がある場合にのみ上書きされます一致する識別/優先サフィックスについて再帰的に解析されます:
'help': {
'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
'PHONE': '808-867-5309',
'EMAIL': 'coder.jen@lostnumber.com'
},
'help@www.productionwebsite.com': {
'BLURB': 'Please contact Customer Service Center',
'BLURB@fr': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
'BLURB@de': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
したがって、本番Webサイトにアクセスするユーザーがドイツ語(de)言語設定を持っている場合、上記の構成は次のように折りたたまれます。
'help': {
'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
そのような不思議な設定/識別JSON書き換え関数はどのように見えますか?あまりない:
// prefer(object,suffix|[suffixes]) by/par/durch storsoc
// prefer({ a: 'apple', a@env: 'banana', b: 'carrot' },'env') -> { a: 'banana', b: 'carrot' }
function prefer(o,sufs) {
for (var key in o) {
if (!o.hasOwnProperty(key)) continue; // skip non-instance props
if(key.split('@')[1]) { // suffixed!
// replace root prop with the suffixed prop if among prefs
if(o[key] && sufs.indexOf(key.split('@')[1]) > -1) o[key.split('@')[0]] = JSON.parse(JSON.stringify(o[key]));
// and nuke the suffixed prop to tidy up
delete o[key];
// continue with root key ...
key = key.split('@')[0];
}
// ... in case it's a collection itself, recurse it!
if(o[key] && typeof o[key] === 'object') prefer(o[key],sufs);
};
};
AngularおよびPre-Angular Webサイトを含む私たちの実装では、prefer()関数を含む自己実行JSクロージャ内にJSONを配置し、ホスト名と言語コード(必要に応じて追加の任意のサフィックスを受け入れます):
(function(prefs){ var props = {
'svcs': {
'VER': '2.3',
'API@localhost': 'http://localhost:9090/',
'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
},
...
/* yadda yadda moar JSON und bisque */
function prefer(o,sufs) {
// body of prefer function, broken for e.g.
};
// convert string and comma-separated-string to array .. and process it
prefs = [].concat( ( prefs.split ? prefs.split(',') : prefs ) || []);
prefer(props,prefs);
window.app_props = JSON.parse(JSON.stringify(props));
})([location.hostname, ((window.navigator.userLanguage || window.navigator.language).split('-')[0]) ] );
Angularより前のサイトには、参照するために折りたたまれた(@サフィックスの付いたキーがない)window.app_propsがあります。
Angularサイトは、ブートストラップ/初期化ステップとして、デッドドロップされたpropsオブジェクトを$ rootScopeにコピーし、(オプションで)グローバル/ウィンドウスコープから破棄します
app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );
続いてコントローラーに注入する:
app.controller('CtrlApp',function($log,props){ ... } );
またはビューのバインディングから参照されます:
<span>{{ props.help.blurb }} {{ props.help.email }}</span>
警告?@文字は有効なJS / JSON変数/キーの命名ではありませんが、これまでのところ受け入れられています。それが取引ブレーカーである場合は、それに固執する限り、「__」(ダブルアンダースコア)などの任意の規約に置き換えてください。
この手法はサーバー側に適用することも、JavaまたはC#に移植することもできますが、効率/コンパクトさは異なる場合があります。
代わりに、関数/規約をフロントエンドのコンパイルスクリプトの一部にすることもできるため、完全な残酷な全環境/全言語のJSONがネットワーク経由で送信されることはありません。
更新
この手法の使用法を進化させて、キーに複数のサフィックスを使用できるようにし、コレクションの使用を強制されないようにして(必要に応じてさらに深く)、優先されるサフィックスの順序を尊重できるようにしました。
例(動作しているjsFiddleも参照):
var o = { 'a':'apple', 'a@dev':'apple-dev', 'a@fr':'pomme',
'b':'banana', 'b@fr':'banane', 'b@dev&fr':'banane-dev',
'c':{ 'o':'c-dot-oh', 'o@fr':'c-point-oh' }, 'c@dev': { 'o':'c-dot-oh-dev', 'o@fr':'c-point-oh-dev' } };
/*1*/ prefer(o,'dev'); // { a:'apple-dev', b:'banana', c:{o:'c-dot-oh-dev'} }
/*2*/ prefer(o,'fr'); // { a:'pomme', b:'banane', c:{o:'c-point-oh'} }
/*3*/ prefer(o,'dev,fr'); // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o); // { a:'apple', b:'banana', c:{o:'c-dot-oh'} }
1/2(基本的な使用法)は「@dev」キーを優先し、他のすべての接尾辞付きキーを破棄します
3は「@dev」を「@fr」よりも優先し、「@ dev&fr」を他のすべてよりも優先します
4(3と同じですが、「@ dev」よりも「@fr」を優先します)
5優先サフィックスなし、すべてのサフィックスプロパティを削除
これは、各サフィックスプロパティをスコアリングし、プロパティを反復処理してスコアの高いサフィックスを見つけるときに、サフィックスプロパティの値を非サフィックスプロパティに昇格させることで実現します。
このバージョンでは、JSONへの依存を削除してディープコピーすることや、スコアリングラウンドの深度で生き残ったオブジェクトにのみ再帰することなど、いくつかの効率性があります。
function prefer(obj,suf) {
function pr(o,s) {
for (var p in o) {
if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1] ) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
var b = p.split('@')[0]; // base prop name
if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
var ps = p.split('@')[1].split('&'); // array of property suffixes
var sc = 0; var v = 0; // reset (running)score and value
while(ps.length) {
// suffix value: index(of found suffix in prefs)^10
v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
sc += v;
}
if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
delete o[p];
}
for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
}
if( typeof obj !== 'object' ) return; // validate
suf = ( (suf || suf === 0 ) && ( suf.length || suf === parseFloat(suf) ) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
pr(obj,suf.reverse());
}
'ngconstant:development'
ではなく'serve'
-ウォッチの設定に'gruntfile'
as で置く場合、gruntfileの開発変数を更新するときtasks: ['ngconstant:development']
に再起動grunt serve
する必要はありません。