-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add fallback code for unsupported locales #168
Changes from 17 commits
6b3afea
4d952e8
46af76e
5cedb00
91bba84
a7e10aa
e46bea7
167f7c2
2f40ceb
46a02f0
9580c37
9a19e1e
fb33367
86c0761
6fcd345
f69f3c3
2550759
72ea895
1cfe155
5237e12
e4d58a1
e605e82
d5b6331
3684ed3
d32fbc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,7 @@ module.exports = function(version, _options) { | |
getWayName: function(language, step, options) { | ||
var classes = options ? options.classes || [] : []; | ||
if (typeof step !== 'object') throw new Error('step must be an Object'); | ||
if (!language) throw new Error('No language code provided'); | ||
if (!Array.isArray(classes)) throw new Error('classes must be an Array or undefined'); | ||
|
||
var wayName; | ||
|
@@ -206,6 +207,7 @@ module.exports = function(version, _options) { | |
return this.tokenize(language, instruction, replaceTokens); | ||
}, | ||
grammarize: function(language, name, grammar) { | ||
if (!language) throw new Error('No language code provided'); | ||
// Process way/rotary name with applying grammar rules if any | ||
if (name && grammar && grammars && grammars[language] && grammars[language][version]) { | ||
var rules = grammars[language][version][grammar]; | ||
|
@@ -225,6 +227,7 @@ module.exports = function(version, _options) { | |
return name; | ||
}, | ||
tokenize: function(language, instruction, tokens) { | ||
if (!language) throw new Error('No language code provided'); | ||
// Keep this function context to use in inline function below (no arrow functions in ES4) | ||
var that = this; | ||
var output = instruction.replace(/\{(\w+):?(\w+)?\}/g, function(token, tag, grammar) { | ||
|
@@ -243,6 +246,49 @@ module.exports = function(version, _options) { | |
} | ||
|
||
return output; | ||
}, | ||
getBestMatchingLanguage: function(language) { | ||
if (languages.instructions[language]) return language; | ||
|
||
var codes = languages.parseLanguageIntoCodes(language); | ||
var languageCode = codes.languageCode; | ||
var scriptCode = codes.scriptCode; | ||
var countryCode = codes.countryCode; | ||
|
||
var supportedLanguageCodes = languages.supportedCodes.map(function(language) { | ||
return language.toLowerCase().split('-')[0]; | ||
}); | ||
|
||
// Same language code and script code (lng-Scpt) | ||
if (languages.instructions[languageCode + '-' + scriptCode]) { | ||
return languageCode + '-' + scriptCode; | ||
// Same language code and country code (lng-CC) | ||
} else if (languages.instructions[languageCode + '-' + countryCode]) { | ||
return languageCode + '-' + countryCode; | ||
// Same language code (lng) | ||
} else if (supportedLanguageCodes[languageCode]) { | ||
return languageCode; | ||
// Same language code and any script code (lng-Scpx) and the found language contains a script | ||
} else if (languages.parsedSupportedCodes.find(function (language) { | ||
return language.language === languageCode && language.scriptCode; | ||
})) { | ||
return languages.parsedSupportedCodes.find(function (language) { | ||
return language.languageCode === languageCode && language.scriptCode; | ||
}).locale; | ||
// Same language code and any country code (lng-CX) | ||
} else if (supportedLanguageCodes.indexOf(languageCode) > -1 && countryCode) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the passed-in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return languages.supportedCodes[supportedLanguageCodes.indexOf(languageCode)]; | ||
// Only language code provided, but we on support this language code | ||
// with either script/country code. | ||
} else if (languages.parsedSupportedCodes.find(function (language) { | ||
return language.languageCode === languageCode; | ||
})) { | ||
return (languages.parsedSupportedCodes.find(function (language) { | ||
return language.languageCode === languageCode; | ||
})).locale; | ||
} else { | ||
return 'en'; | ||
} | ||
} | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,8 +49,49 @@ var grammars = { | |
'ru': grammarRu | ||
}; | ||
|
||
function parseLanguageIntoCodes (language) { | ||
// If the language is not found, try a little harder | ||
var splitLocale = language.toLowerCase().split('-'); | ||
var languageCode = splitLocale[0]; | ||
var scriptCode = false; | ||
var countryCode = false; | ||
|
||
/** | ||
Documentation on how the language tag is being split: https://en.wikipedia.org/wiki/IETF_language_tag#Syntax_of_language_tags | ||
|
||
Example: zh-Hant-TW | ||
language code: zh | ||
script code: Hant | ||
country code: TW | ||
|
||
Example: en-US | ||
language code: en | ||
country code: US | ||
*/ | ||
|
||
if (splitLocale.length === 2 && splitLocale[1].length === 4) { | ||
scriptCode = splitLocale[1]; | ||
} else if (splitLocale.length === 2 && splitLocale[1].length === 2) { | ||
countryCode = splitLocale[1]; | ||
} else if (splitLocale.length === 3) { | ||
scriptCode = splitLocale[1]; | ||
countryCode = splitLocale[2]; | ||
} | ||
|
||
return { | ||
locale: language, | ||
languageCode: languageCode, | ||
scriptCode: scriptCode, | ||
countryCode: countryCode | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It’s a bit redundant to say “code” in each of these keys. |
||
}; | ||
} | ||
|
||
module.exports = { | ||
supportedCodes: Object.keys(instructions), | ||
parsedSupportedCodes: Object.keys(instructions).map(function(language) { | ||
return parseLanguageIntoCodes(language); | ||
}), | ||
instructions: instructions, | ||
grammars: grammars | ||
grammars: grammars, | ||
parseLanguageIntoCodes: parseLanguageIntoCodes | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -190,12 +190,116 @@ tape.test('v5 compile', function(t) { | |
|
||
assert.throws(function() { | ||
v5Compiler.compile('foo'); | ||
}, /language code foo not loaded/ | ||
); | ||
}, /language code foo not loaded/); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('en-US fallback to en', function(assert) { | ||
var v5Compiler = compiler('v5'); | ||
var language = v5Compiler.getBestMatchingLanguage('en-us'); | ||
|
||
assert.equal(v5Compiler.compile(language, { | ||
maneuver: { | ||
type: 'turn', | ||
modifier: 'left' | ||
}, | ||
name: 'Way Name' | ||
}), 'Turn left onto Way Name'); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('zh-CN fallback to zh-Hans', function(assert) { | ||
var v5Compiler = compiler('v5'); | ||
var language = v5Compiler.getBestMatchingLanguage('zh-CN'); | ||
|
||
assert.equal(v5Compiler.compile(language, { | ||
maneuver: { | ||
type: 'turn', | ||
modifier: 'left' | ||
}, | ||
name: 'Way Name' | ||
}), '左转,上Way Name'); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('zh-Hant fallback to zh-Hanz', function(assert) { | ||
var v5Compiler = compiler('v5'); | ||
var language = v5Compiler.getBestMatchingLanguage('zh-Hant'); | ||
|
||
assert.equal(v5Compiler.compile(language, { | ||
maneuver: { | ||
type: 'turn', | ||
modifier: 'left' | ||
}, | ||
name: 'Way Name' | ||
}), '左转,上Way Name'); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('zh-Hant-TW fallback to zh-Hant', function(assert) { | ||
var v5Compiler = compiler('v5'); | ||
var language = v5Compiler.getBestMatchingLanguage('zh-Hant-TW'); | ||
|
||
assert.equal(v5Compiler.compile(language, { | ||
maneuver: { | ||
type: 'turn', | ||
modifier: 'left' | ||
}, | ||
name: 'Way Name' | ||
}), '左转,上Way Name'); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('es-MX fallback to es', function(assert) { | ||
var v5Compiler = compiler('v5'); | ||
var language = v5Compiler.getBestMatchingLanguage('es-MX'); | ||
|
||
assert.equal(v5Compiler.compile(language, { | ||
maneuver: { | ||
type: 'turn', | ||
modifier: 'straight' | ||
}, | ||
name: 'Way Name' | ||
}), 'Ve recto en Way Name'); | ||
|
||
assert.end(); | ||
}); | ||
|
||
t.test('getBestMatchingLanguage', function(t) { | ||
t.equal(compiler('v5').getBestMatchingLanguage('foo'), 'en'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('en-US'), 'en'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('zh-CN'), 'zh-Hans'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('zh-Hant'), 'zh-Hans'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('zh-Hant-TW'), 'zh-Hans'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('zh'), 'zh-Hans'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('es-MX'), 'es'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('es-ES'), 'es-ES'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('pt-PT'), 'pt-BR'); | ||
t.equal(compiler('v5').getBestMatchingLanguage('pt'), 'pt-BR'); | ||
t.end(); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let’s add some tests of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
/* eslint-disable */ | ||
t.test('parseLanguageIntoCodes', function(t) { | ||
t.deepEqual(languages.parseLanguageIntoCodes('foo'), { countryCode: false, languageCode: 'foo', locale: 'foo', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('en-US'), { countryCode: 'us', languageCode: 'en', locale: 'en-US', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('zh-CN'), { countryCode: 'cn', languageCode: 'zh', locale: 'zh-CN', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('zh-Hant'), { countryCode: false, languageCode: 'zh', locale: 'zh-Hant', scriptCode: 'hant' }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('zh-Hant-TW'), { countryCode: 'tw', languageCode: 'zh', locale: 'zh-Hant-TW', scriptCode: 'hant' }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('zh'), { countryCode: false, languageCode: 'zh', locale: 'zh', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('es-MX'), { countryCode: 'mx', languageCode: 'es', locale: 'es-MX', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('es-ES'), { countryCode: 'es', languageCode: 'es', locale: 'es-ES', scriptCode: false }); | ||
t.deepEqual(languages.parseLanguageIntoCodes('pt-PT'), { countryCode: 'pt', languageCode: 'pt', locale: 'pt-PT', scriptCode: false }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Directions API currently allows a |
||
t.deepEqual(languages.parseLanguageIntoCodes('pt'), { countryCode: false, languageCode: 'pt', locale: 'pt', scriptCode: false }); | ||
t.end(); | ||
}); | ||
/* eslint-enable */ | ||
|
||
t.test('respects options.instructionStringHook', function(assert) { | ||
var v5Compiler = compiler('v5', { | ||
hooks: { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of repeating the
find()
call, store the result of the first find. It’d be a lot easier to store things in local variables if you replace all theelse if
s withif
s – after all, we’re returning early in each case.