diff --git a/docs/guides/languages.md b/docs/guides/languages.md
index 94de374957..61f00542b9 100644
--- a/docs/guides/languages.md
+++ b/docs/guides/languages.md
@@ -37,7 +37,7 @@ Video.js uses key/value object dictionaries in JSON form. A sample dictionary fo
```
Notes:
-
+
- The file name should always be in the format `XX.json`, where `XX` is the two letter value of the language reported to the browser (for options see the bottom of this document).
- For automatic inclusion at build time, add your language file to the `/lang` directory (see 'Adding Languages to Video.js below').
@@ -45,7 +45,7 @@ Adding Languages to Video.js
----------------------------
Additional language support can be added to Video.js in multiple ways.
-1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script.
+1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script.
NOTE: These need to be added after the core Video.js script.
@@ -122,6 +122,24 @@ During a Video.js player instantiation you can force it to localize to a specifi
```
+Determining Player Language
+---------------------------
+
+The player language is set to one of the following in descending priority
+
+* The language set in setup options as above
+* The document language (`lang` attribute of the `html` element)
+* Browser language preference
+* 'en'
+
+That can be overridden after instantiation with `language('fr')`.
+
+Language selection
+------------------
+
+* Language codes are considered case-insensitively (`en-US` == `en-us`).
+* If there is no match for a language code with a subcode (`en-us`), a match for the primary code (`en`) is used if available.
+
Localization in Plugins
-----------------------
@@ -133,7 +151,7 @@ var details = '
' + player.localize('Technical de
Language Codes
--------------
-The following is a list of official language codes.
+The following is a list of official language codes.
**NOTE:** For supported language translations, please see the [Languages Folder (/lang)](../../lang) folder located in the project root.
@@ -180,10 +198,10 @@ The following is a list of official language codes.
fj | | Fiji |
fi | | Finnish |
---|
-
+
-
+
fr | | French |
fy | | Frisian |
@@ -223,10 +241,10 @@ The following is a list of official language codes.
lo | | Laothian |
la | | Latin |
-
+
|
-
+
lv | | Latvian (Lettish) |
li | | Limburgish ( Limburger) |
@@ -266,10 +284,10 @@ The following is a list of official language codes.
ii | | Sichuan Yi |
sd | | Sindhi |
-
+
|
-
+
si | | Sinhalese |
ss | | Siswati |
@@ -307,7 +325,7 @@ The following is a list of official language codes.
yo | | Yoruba |
zu | | Zulu |
-
+
|
diff --git a/src/js/component.js b/src/js/component.js
index 52b8d149cd..21e8140740 100644
--- a/src/js/component.js
+++ b/src/js/component.js
@@ -216,13 +216,21 @@ class Component {
}
localize(string) {
- let lang = this.player_.language();
+ let lang = ('' + this.player_.language()).toLowerCase();
+ let primaryCode = lang.split('-')[0];
let languages = this.player_.languages();
- if (languages && languages[lang] && languages[lang][string]) {
+ if (!languages) {
+ return string;
+ }
+ if (languages[lang] && languages[lang][string]) {
return languages[lang][string];
}
-
+ if (primaryCode !== lang &&
+ languages[primaryCode] &&
+ languages[primaryCode][string]) {
+ return languages[primaryCode][string];
+ }
return string;
}
diff --git a/src/js/player.js b/src/js/player.js
index 2cd47b12e3..7523924df4 100644
--- a/src/js/player.js
+++ b/src/js/player.js
@@ -104,7 +104,17 @@ class Player extends Component {
this.language_ = options['language'] || Options['language'];
// Update Supported Languages
- this.languages_ = options['languages'] || Options['languages'];
+ if (options['languages']) {
+ // Normalise player option languages to lowercase
+ let languagesToLower = {};
+
+ Object.getOwnPropertyNames(options['languages']).forEach(function(name) {
+ languagesToLower[name.toLowerCase()] = options['languages'][name];
+ });
+ this.languages_ = languagesToLower;
+ } else {
+ this.languages_ = Options['languages'];
+ }
// Cache for video property values.
this.cache_ = {};
@@ -2105,9 +2115,11 @@ class Player extends Component {
/**
* Get the player's language dictionary
+ * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time
+ * Languages specified directly in the player options have precedence
*/
languages() {
- return this.languages_;
+ return mergeOptions(Options['languages'], this.languages_);
}
toJSON() {
diff --git a/src/js/video.js b/src/js/video.js
index 563eb858c3..67f4a34537 100644
--- a/src/js/video.js
+++ b/src/js/video.js
@@ -142,7 +142,8 @@ videojs.plugin = plugin;
* @return {Object} The resulting global languages dictionary object
*/
videojs.addLanguage = function(code, data){
- if(Options['languages'][code] !== undefined) {
+ code = ('' + code).toLowerCase();
+ if(typeof Options['languages'][code] !== 'undefined') {
Options['languages'][code] = mergeOptions(Options['languages'][code], data);
} else {
Options['languages'][code] = data;
diff --git a/test/unit/player.test.js b/test/unit/player.test.js
index a7e00c1e5b..b1ede564ac 100644
--- a/test/unit/player.test.js
+++ b/test/unit/player.test.js
@@ -791,3 +791,25 @@ test('should have a sensible toJSON that is equivalent to player.options', funct
deepEqual(player2.toJSON(), popts, 'no circular references');
});
+
+test('should ignore case in language codes and try primary code', function() {
+expect(3);
+
+ var player = TestHelpers.makePlayer({
+ 'languages': {
+ 'en-gb': {
+ 'Good': 'Brilliant'
+ },
+ 'EN': {
+ 'Good': 'Awesome',
+ 'Error': 'Problem'
+ }
+ }
+ });
+
+ player.language('en-gb');
+ strictEqual(player.localize('Good'), 'Brilliant', 'Used subcode specific localisation');
+ strictEqual(player.localize('Error'), 'Problem', 'Used primary code localisation');
+ player.language('en-GB');
+ strictEqual(player.localize('Good'), 'Brilliant', 'Ignored case');
+});
diff --git a/test/unit/video.test.js b/test/unit/video.test.js
index 59e105c84b..e4f6447f4d 100644
--- a/test/unit/video.test.js
+++ b/test/unit/video.test.js
@@ -46,6 +46,17 @@ test('should add the value to the languages object', function() {
deepEqual(result[code], Options['languages'][code], 'should also match');
});
+test('should add the value to the languages object with lower case lang code', function() {
+ var code, data, result;
+
+ code = 'DE';
+ data = {'Hello': 'Guten Tag'};
+ result = videojs.addLanguage(code, data);
+
+ ok(Options['languages'][code.toLowerCase()], 'should exist');
+ equal(Options['languages'][code.toLowerCase()], data, 'should match');
+ deepEqual(result[code.toLowerCase()], Options['languages'][code.toLowerCase()], 'should also match');
+});
test('should expose plugin registry function', function() {
var pluginName, pluginFunction, player;