1/* 2ADOBE SYSTEMS INCORPORATED 3 Copyright 2008 Adobe Systems Incorporated 4 All Rights Reserved. 5 6NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the 7terms of the Adobe license agreement accompanying it. If you have received this file from a 8source other than Adobe, then your use, modification, or distribution of it requires the prior 9written permission of Adobe. 10*/ 11 12 13package com.adobe.utils 14{ 15 import flash.utils.Dictionary; 16 17 internal final class LocaleId 18 { 19 20 private var lang:String = ''; 21 private var script:String = ''; 22 private var region:String = ''; 23 private var extended_langs:Array = []; 24 private var variants:Array = []; 25 private var extensions:Object = {}; 26 private var privates:Array = []; 27 private var privateLangs:Boolean = false; 28 29 public function LocaleId() 30 { 31 } 32 33 34 public static function fromString(str:String):LocaleId{ 35 var localeId:LocaleId = new LocaleId(); 36 37 var state:int = LocaleParserState.PRIMARY_LANGUAGE; 38 var subtags:Array = str.replace(/-/g, '_').split('_'); 39 40 var last_extension:Array; 41 42 for(var i:int=0, l:int=subtags.length; i<l ;i++){ 43 var subtag:String = subtags[i].toLowerCase(); 44 45 if(state==LocaleParserState.PRIMARY_LANGUAGE){ 46 if(subtag=='x'){ 47 localeId.privateLangs = true; //not used in our implementation, but makes the tag private 48 }else if(subtag=='i'){ 49 localeId.lang += 'i-'; //and wait the next subtag to complete the language name 50 }else{ 51 localeId.lang += subtag; 52 state ++; 53 } 54 }else{ 55 //looging for an extended language - 3 chars 56 // a script - 4 chars 57 // a region - 2-3 chars 58 // a variant - alpha with at least 5 chars or numeric with at least 4 chars 59 // an extension/private singleton - 1 char 60 61 var subtag_length:int = subtag.length; //store it for faster use later 62 if(subtag_length==0) continue; //skip zero-lengthed subtags 63 var firstChar:String = subtag.charAt(0).toLowerCase(); 64 65 if(state<=LocaleParserState.EXTENDED_LANGUAGES && subtag_length==3){ 66 localeId.extended_langs.push(subtag); 67 if(localeId.extended_langs.length==3){ //allow a maximum of 3 extended langs 68 state = LocaleParserState.SCRIPT; 69 } 70 }else if ( state <= LocaleParserState.SCRIPT && subtag_length==4 ){ 71 localeId.script = subtag; 72 state = LocaleParserState.REGION; 73 }else if( state <= LocaleParserState.REGION && (subtag_length==2 || subtag_length==3) ){ 74 localeId.region = subtag; 75 state = LocaleParserState.VARIANTS; 76 }else if ( state <= LocaleParserState.VARIANTS && 77 ( 78 ( firstChar>='a' && firstChar<='z' && subtag_length>=5 ) 79 || 80 ( firstChar>='0' && firstChar<='9' && subtag_length>=4 ) 81 ) 82 ){ 83 //variant 84 localeId.variants.push(subtag); 85 state = LocaleParserState.VARIANTS; 86 }else if ( state < LocaleParserState.PRIVATES && subtag_length==1 ){ //singleton 87 if(subtag == 'x'){ 88 state = LocaleParserState.PRIVATES; 89 last_extension = localeId.privates; 90 } else { 91 state = LocaleParserState.EXTENSIONS; 92 last_extension = localeId.extensions[subtag] || []; 93 localeId.extensions[subtag] = last_extension; 94 } 95 }else if(state >= LocaleParserState.EXTENSIONS){ 96 last_extension.push(subtag); 97 } 98 } 99 } 100 localeId.canonicalize(); 101 return localeId; 102 } 103 104 public function canonicalize():void{ 105 for(var i:String in this.extensions){ 106 if(this.extensions.hasOwnProperty(i)){ 107 //also clear zero length extensions 108 if(this.extensions[i].length==0) delete this.extensions[i]; 109 else this.extensions[i] = this.extensions[i].sort(); 110 } 111 } 112 this.extended_langs = this.extended_langs.sort(); 113 this.variants = this.variants.sort(); 114 this.privates = this.privates.sort(); 115 if(this.script == ''){ 116 this.script = LocaleRegistry.getScriptByLang(this.lang); 117 } 118 //still no script, check the region 119 if(this.script == '' && this.region!=''){ 120 this.script = LocaleRegistry.getScriptByLangAndRegion(this.lang, this.region); 121 } 122 123 if(this.region=='' && this.script!=''){ 124 this.region = LocaleRegistry.getDefaultRegionForLangAndScript(this.lang, this.script); 125 } 126 } 127 128 public function toString():String{ 129 var stack:Array = [ this.lang ]; 130 appendElements(stack, this.extended_langs); 131 if(this.script!='') stack.push(this.script); 132 if(this.region!='') stack.push(this.region); 133 appendElements(stack, this.variants); 134 for(var i:String in this.extensions){ 135 if(this.extensions.hasOwnProperty(i)){ 136 stack.push(i); 137 appendElements(stack, this.extensions[i]); 138 } 139 } 140 if(this.privates.length>0){ 141 stack.push('x'); 142 appendElements(stack, this.privates); 143 } 144 return stack.join('_'); 145 } 146 147 public function equals(locale:LocaleId):Boolean{ 148 return this.toString() == locale.toString(); 149 } 150 151 public function isSiblingOf(other:LocaleId):Boolean{ 152 return (this.lang==other.lang&&this.script==other.script); 153 } 154 155 public function transformToParent():Boolean{ 156 if(this.privates.length>0){ 157 this.privates.splice(this.privates.length-1, 1); 158 return true; 159 } 160 161 var lastExtensionName:String = null; 162 for(var i:String in this.extensions){ 163 if(this.extensions.hasOwnProperty(i)){ 164 lastExtensionName = i; 165 } 166 } 167 if(lastExtensionName){ 168 var lastExtension:Array = this.extensions[lastExtensionName]; 169 if(lastExtension.length==1){ 170 delete this.extensions[ lastExtensionName ]; 171 return true; 172 } 173 lastExtension.splice(lastExtension.length-1, 1); 174 return true; 175 } 176 177 if(this.variants.length>0){ 178 this.variants.splice(this.variants.length-1, 1); 179 return true; 180 } 181 182 if(this.script!=''){ 183 //check if we can surpress the script 184 if(LocaleRegistry.getScriptByLang(this.lang)!=''){ 185 this.script=''; 186 return true; 187 }else if(this.region==''){ 188 //maybe the default region can surpress the script 189 var region:String = LocaleRegistry.getDefaultRegionForLangAndScript(this.lang, this.script); 190 if(region!=''){ 191 this.region = region; 192 this.script = ''; 193 return true; 194 } 195 } 196 } 197 198 if(this.region!=''){ 199 if(!(this.script=='' && LocaleRegistry.getScriptByLang(this.lang) == '')){ 200 this.region=''; 201 return true; 202 } 203 } 204 205 206 if(this.extended_langs.length>0){ 207 this.extended_langs.splice(this.extended_langs.length-1, 1); 208 return true; 209 } 210 211 return false; 212 } 213 214 /** 215 * @private 216 */ 217 private static function appendElements(dest:Array, src:Array):void 218 { 219 for (var i:uint=0, argc:uint=src.length; i < argc; i++) 220 dest.push(src[i]); 221 } 222 223 224 } 225}