Très tard dans le fil, mais une technique que j'ai utilisée, pré-angulaire, est de tirer parti de JSON et de la flexibilité de JS pour référencer dynamiquement les clés de collection et utiliser des faits inaliénables de l'environnement (nom du serveur hôte, langue actuelle du navigateur , etc.) comme entrées pour discriminer / préférer sélectivement les noms de clés suffixés dans une structure de données JSON.
Cela fournit non seulement un contexte d'environnement de déploiement (par OP), mais tout contexte arbitraire (tel que le langage) pour fournir i18n ou tout autre écart requis simultanément, et (idéalement) dans un manifeste de configuration unique, sans duplication et clairement visible.
EN ENVIRON 10 LIGNES VANILLE JS
Exemple trop simplifié mais classique: une URL de base de point de terminaison API dans un fichier de propriétés au format JSON qui varie selon l'environnement où (natch) le serveur hôte variera également:
...
'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/'
},
...
Une clé de la fonction de discrimination est simplement le nom d'hôte du serveur dans la demande.
Ceci, naturellement, peut être combiné avec une clé supplémentaire basée sur les paramètres de langue de l'utilisateur:
...
'app': {
'NAME': 'Ferry Reservations',
'NAME@fr': 'Réservations de ferry',
'NAME@de': 'Fähren Reservierungen'
},
...
L'étendue de la discrimination / préférence peut être limitée à des clés individuelles (comme ci-dessus) où la clé "de base" n'est écrasée que s'il y a une clé correspondante + suffixe pour les entrées de la fonction - ou une structure entière, et cette structure elle-même récursivement analysé pour faire correspondre les suffixes de discrimination / préférence:
'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'
},
Donc, si un utilisateur visitant le site Web de production a un paramètre de préférence de langue allemande ( de ), la configuration ci-dessus se réduirait à:
'help': {
'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
À quoi ressemble une telle fonction de réécriture JSON de préférence / discrimination magique? Pas tant:
// 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);
};
};
Dans nos implémentations, qui incluent les sites Web angulaires et pré-angulaires, nous démarrons simplement la configuration bien avant les autres appels de ressources en plaçant le JSON dans une fermeture JS auto-exécutable, y compris la fonction prefer (), et en alimentant les propriétés de base du nom d'hôte et code de langue (et accepte tous les suffixes arbitraires supplémentaires dont vous pourriez avoir besoin):
(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]) ] );
Un site pré-angulaire aurait maintenant une fenêtre.app_props réduite (pas de clés suffixées @) à laquelle faire référence.
Un site angulaire, en tant qu'étape bootstrap / init, copie simplement l'objet props perdu dans $ rootScope et (éventuellement) le détruit de la portée globale / fenêtre
app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );
à injecter ensuite dans les contrôleurs:
app.controller('CtrlApp',function($log,props){ ... } );
ou référencé à partir des liaisons dans les vues:
<span>{{ props.help.blurb }} {{ props.help.email }}</span>
Des mises en garde? Le caractère @ n'est pas un nom de variable / clé JS / JSON valide, mais jusqu'à présent accepté. Si c'est une rupture, remplacez toute convention que vous aimez, comme "__" (double soulignement) tant que vous y tenez.
La technique pourrait être appliquée côté serveur, portée sur Java ou C # mais votre efficacité / compacité peut varier.
Alternativement, la fonction / convention pourrait faire partie de votre script de compilation frontal, de sorte que le JSON complet, tout environnement / tout langage, n'est jamais transmis sur le câble.
METTRE À JOUR
Nous avons développé l'utilisation de cette technique pour autoriser plusieurs suffixes à une clé, pour éviter d'être obligé d'utiliser des collections (vous pouvez toujours, aussi profondément que vous le souhaitez), ainsi que pour respecter l'ordre des suffixes préférés.
Exemple (voir aussi jsFiddle de travail ):
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 (utilisation de base) préfère les clés '@dev', supprime toutes les autres clés suffixées
3 préfère '@dev' à '@fr', préfère '@ dev & fr' à tous les autres
4 (identique à 3 mais préfère '@fr' à '@dev')
5 pas de suffixes préférés, supprime TOUTES les propriétés suffixées
Il accomplit cela en notant chaque propriété suffixée et en promouvant la valeur d'une propriété suffixée à la propriété non suffixée lors de l'itération sur les propriétés et de la recherche d'un suffixe ayant un score plus élevé.
Quelques efficacités dans cette version, y compris la suppression de la dépendance à JSON pour la copie en profondeur, et la récurrence uniquement dans les objets qui survivent à la ronde de notation à leur profondeur:
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'
en'serve'
- si vous le mettre dans la configuration de la montre sous'gruntfile'
quetasks: ['ngconstant:development']
- vous ne devez redémarrergrunt serve
lorsque vous mettez à jour les variables de développement dans le gruntfile.