Preferred Languages - Version 1.4.0

Version Description

  • New: Keyboard navigation improvements.
  • New: Tooltips now show the available keyboard shortcuts.
  • New: Missing translations are now downloaded even when no changes were made.
  • New: A warning is shown when some of the preferred languages aren't installed.
  • New: Settings form is now hidden when JavaScript is disabled.
  • Fixed: Improved setting the current locale.
  • Fixed: CSS is no longer enqueued on the front end.
Download this release

Release Info

Developer swissspidy
Plugin Icon Preferred Languages
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.0 to 1.4.0

CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
  # Changelog
2
 
 
 
 
 
 
 
 
 
 
 
3
  ## 1.3.0
4
 
5
  * New: Users can now choose English (United States) again as a preferred locale.
1
  # Changelog
2
 
3
+ ## 1.4.0
4
+
5
+ * New: Keyboard navigation improvements.
6
+ * New: Tooltips now show the available keyboard shortcuts.
7
+ * New: Missing translations are now downloaded even when no changes were made.
8
+ * New: A warning is shown when some of the preferred languages aren't installed.
9
+ * New: Settings form is now hidden when JavaScript is disabled.
10
+ * Fixed: Improved setting the current locale.
11
+ * Fixed: CSS is no longer enqueued on the front end.
12
+
13
  ## 1.3.0
14
 
15
  * New: Users can now choose English (United States) again as a preferred locale.
css/preferred-languages-rtl.css CHANGED
@@ -1 +1 @@
1
- .active-locales{margin:1em 0}.active-locales-list,.inactive-locales-list{width:25em;margin:0 0 1em 1em;clear:both;float:right}.active-locales-controls{clear:both}.active-locales-controls .button,.active-locales-controls ul{margin:0}@media screen and (min-width:510px){.active-locales-controls{clear:none}}.active-locales-list{height:98px;overflow-y:scroll;margin-top:0;background:#fff;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);border:1px solid #ddd;color:#32373c;box-sizing:border-box}.active-locales-list.empty-list{background:hsla(0,0%,100%,.5);border-color:hsla(0,0%,87%,.75);box-shadow:inset 0 1px 2px rgba(0,0,0,.04);display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.active-locales-list li{box-sizing:border-box;width:100%;height:28px;line-height:28px;margin:0;padding:0 8px 0 0;cursor:pointer}.active-locales-list li:hover{background:rgba(0,0,0,.07)}.active-locales-list li[aria-selected=true]{background:rgba(0,0,0,.15)}#active-locales-empty-message{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;position:relative;text-align:center;width:25em;height:98px;margin-bottom:-98px;box-sizing:border-box;color:rgba(51,51,51,.5)}#active-locales-empty-message.hidden{display:none}.inactive-locales{clear:both}.inactive-locales select{width:100%}
1
+ .active-locales{margin:1em 0}.active-locales-list,.inactive-locales-list{width:25em;margin:0 0 1em 1em;clear:both;float:right}.active-locales-controls{clear:both}.active-locales-controls .button,.active-locales-controls ul{margin:0}@media screen and (min-width:510px){.active-locales-controls{clear:none}}.active-locales-list{height:98px;overflow-y:scroll;margin-top:0;background:#fff;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);border:1px solid #ddd;color:#32373c;box-sizing:border-box}.active-locales-list.empty-list{background:hsla(0,0%,100%,.5);border-color:hsla(0,0%,87%,.75);box-shadow:inset 0 1px 2px rgba(0,0,0,.04);display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.active-locales-list li{box-sizing:border-box;width:100%;height:28px;line-height:28px;margin:0;padding:0 8px 0 0;cursor:pointer}.active-locales-list li:hover{background:rgba(0,0,0,.07)}.active-locales-list li[aria-selected=true]{background:rgba(0,0,0,.15)}#active-locales-empty-message{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;position:relative;text-align:center;width:25em;height:98px;margin-bottom:-98px;box-sizing:border-box;color:rgba(51,51,51,.5)}#active-locales-empty-message.hidden{display:none}.inactive-locales{clear:both}.inactive-locales select{width:100%}.preferred-languages .notice{display:inline-block}.no-js #preferred-languages-label,.no-js .preferred-languages,.no-js .user-preferred-languages-wrap{display:none}@-webkit-keyframes tooltip-appear{0%{opacity:0}to{opacity:1}}@keyframes tooltip-appear{0%{opacity:0}to{opacity:1}}.tooltipped{position:relative}.tooltipped:active:after,.tooltipped:active:before,.tooltipped:focus:after,.tooltipped:focus:before,.tooltipped:hover:after,.tooltipped:hover:before{opacity:1;display:inline-block;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:.4s;animation-delay:.4s}.tooltipped:before{z-index:1000001;width:0;height:0;color:#191e23;content:"";border:6px solid transparent;top:-7px;left:50%;bottom:auto;margin-left:-6px;border-top-color:#191e23}.tooltipped:after,.tooltipped:before{position:absolute;display:none;pointer-events:none;opacity:0}.tooltipped:after{z-index:1000000;padding:.5em .75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;-webkit-font-smoothing:subpixel-antialiased;color:#fff;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-wrap:break-word;white-space:pre;content:attr(data-tooltip);background:#191e23;border-radius:3px;left:auto;right:50%;margin-right:-16px;bottom:100%;margin-bottom:6px}
css/preferred-languages.css CHANGED
@@ -1 +1 @@
1
- .active-locales{margin:1em 0}.active-locales-list,.inactive-locales-list{width:25em;margin:0 1em 1em 0;clear:both;float:left}.active-locales-controls{clear:both}.active-locales-controls .button,.active-locales-controls ul{margin:0}@media screen and (min-width:510px){.active-locales-controls{clear:none}}.active-locales-list{height:98px;overflow-y:scroll;margin-top:0;background:#fff;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);border:1px solid #ddd;color:#32373c;box-sizing:border-box}.active-locales-list.empty-list{background:hsla(0,0%,100%,.5);border-color:hsla(0,0%,87%,.75);box-shadow:inset 0 1px 2px rgba(0,0,0,.04);display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.active-locales-list li{box-sizing:border-box;width:100%;height:28px;line-height:28px;margin:0;padding:0 0 0 8px;cursor:pointer}.active-locales-list li:hover{background:rgba(0,0,0,.07)}.active-locales-list li[aria-selected=true]{background:rgba(0,0,0,.15)}#active-locales-empty-message{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;position:relative;text-align:center;width:25em;height:98px;margin-bottom:-98px;box-sizing:border-box;color:rgba(51,51,51,.5)}#active-locales-empty-message.hidden{display:none}.inactive-locales{clear:both}.inactive-locales select{width:100%}
1
+ .active-locales{margin:1em 0}.active-locales-list,.inactive-locales-list{width:25em;margin:0 1em 1em 0;clear:both;float:left}.active-locales-controls{clear:both}.active-locales-controls .button,.active-locales-controls ul{margin:0}@media screen and (min-width:510px){.active-locales-controls{clear:none}}.active-locales-list{height:98px;overflow-y:scroll;margin-top:0;background:#fff;box-shadow:inset 0 1px 2px rgba(0,0,0,.07);border:1px solid #ddd;color:#32373c;box-sizing:border-box}.active-locales-list.empty-list{background:hsla(0,0%,100%,.5);border-color:hsla(0,0%,87%,.75);box-shadow:inset 0 1px 2px rgba(0,0,0,.04);display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.active-locales-list li{box-sizing:border-box;width:100%;height:28px;line-height:28px;margin:0;padding:0 0 0 8px;cursor:pointer}.active-locales-list li:hover{background:rgba(0,0,0,.07)}.active-locales-list li[aria-selected=true]{background:rgba(0,0,0,.15)}#active-locales-empty-message{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;position:relative;text-align:center;width:25em;height:98px;margin-bottom:-98px;box-sizing:border-box;color:rgba(51,51,51,.5)}#active-locales-empty-message.hidden{display:none}.inactive-locales{clear:both}.inactive-locales select{width:100%}.preferred-languages .notice{display:inline-block}.no-js #preferred-languages-label,.no-js .preferred-languages,.no-js .user-preferred-languages-wrap{display:none}@-webkit-keyframes tooltip-appear{0%{opacity:0}to{opacity:1}}@keyframes tooltip-appear{0%{opacity:0}to{opacity:1}}.tooltipped{position:relative}.tooltipped:active:after,.tooltipped:active:before,.tooltipped:focus:after,.tooltipped:focus:before,.tooltipped:hover:after,.tooltipped:hover:before{opacity:1;display:inline-block;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:.4s;animation-delay:.4s}.tooltipped:before{z-index:1000001;width:0;height:0;color:#191e23;content:"";border:6px solid transparent;top:-7px;right:50%;bottom:auto;margin-right:-6px;border-top-color:#191e23}.tooltipped:after,.tooltipped:before{position:absolute;display:none;pointer-events:none;opacity:0}.tooltipped:after{z-index:1000000;padding:.5em .75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;-webkit-font-smoothing:subpixel-antialiased;color:#fff;text-align:center;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-wrap:break-word;white-space:pre;content:attr(data-tooltip);background:#191e23;border-radius:3px;right:auto;left:50%;margin-left:-16px;bottom:100%;margin-bottom:6px}
inc/class-preferred-languages-textdomain-registry.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Locale API: WP_Textdomain_Registry class
4
  *
5
  * @package WordPress
6
  * @subpackage i18n
1
  <?php
2
  /**
3
+ * Locale API: Preferred_Languages_Textdomain_Registry class
4
  *
5
  * @package WordPress
6
  * @subpackage i18n
inc/default-filters.php CHANGED
@@ -13,14 +13,18 @@ add_action( 'init', 'preferred_languages_register_setting' );
13
  add_action( 'init', 'preferred_languages_register_meta' );
14
  add_action( 'init', 'preferred_languages_register_scripts' );
15
 
 
 
16
  add_action( 'admin_init', 'preferred_languages_settings_field' );
17
 
18
  add_action( 'personal_options', 'preferred_languages_personal_options' );
19
  add_action( 'personal_options_update', 'preferred_languages_update_user_option' );
20
  add_action( 'edit_user_profile_update', 'preferred_languages_update_user_option' );
21
 
 
22
  add_filter( 'update_option_preferred_languages', 'preferred_languages_update_option', 10, 2 );
 
23
  add_filter( 'update_user_meta', 'preferred_languages_update_user_meta', 10, 4 );
24
  add_filter( 'get_user_metadata', 'preferred_languages_filter_user_locale', 10, 3 );
25
- add_filter( 'locale', 'preferred_languages_filter_locale' );
26
  add_filter( 'load_textdomain_mofile', 'preferred_languages_load_textdomain_mofile', 10 );
13
  add_action( 'init', 'preferred_languages_register_meta' );
14
  add_action( 'init', 'preferred_languages_register_scripts' );
15
 
16
+ add_action( 'admin_enqueue_scripts', 'preferred_languages_enqueue_scripts' );
17
+
18
  add_action( 'admin_init', 'preferred_languages_settings_field' );
19
 
20
  add_action( 'personal_options', 'preferred_languages_personal_options' );
21
  add_action( 'personal_options_update', 'preferred_languages_update_user_option' );
22
  add_action( 'edit_user_profile_update', 'preferred_languages_update_user_option' );
23
 
24
+ add_filter( 'pre_update_option', 'preferred_languages_pre_update_option', 10, 3 );
25
  add_filter( 'update_option_preferred_languages', 'preferred_languages_update_option', 10, 2 );
26
+ add_filter( 'update_user_metadata', 'preferred_languages_pre_update_user_meta', 10, 5 );
27
  add_filter( 'update_user_meta', 'preferred_languages_update_user_meta', 10, 4 );
28
  add_filter( 'get_user_metadata', 'preferred_languages_filter_user_locale', 10, 3 );
29
+ add_filter( 'locale', 'preferred_languages_filter_locale', 5 ); // Before WP_Locale_Switcher.
30
  add_filter( 'load_textdomain_mofile', 'preferred_languages_load_textdomain_mofile', 10 );
inc/functions.php CHANGED
@@ -86,7 +86,7 @@ function preferred_languages_get_user_list( $user_id = 0 ) {
86
  *
87
  * @since 1.3.0
88
  *
89
- * @return array|false Preferred languages.
90
  */
91
  function preferred_languages_get_site_list() {
92
  $preferred_languages = get_option( 'preferred_languages', '' );
@@ -118,6 +118,35 @@ function preferred_languages_get_list() {
118
  return preferred_languages_get_site_list();
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  /**
122
  * Downloads language pack when updating user meta.
123
  *
@@ -148,6 +177,27 @@ function preferred_languages_update_user_meta( $meta_id, $object_id, $meta_key,
148
  load_default_textdomain( reset( $preferred_languages_list ) );
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  /**
152
  * Downloads language packs upon updating the site option.
153
  *
@@ -225,7 +275,7 @@ function preferred_languages_sanitize_list( $preferred_languages ) {
225
  * @return string
226
  */
227
  function preferred_languages_filter_locale( $locale ) {
228
- $preferred_languages = preferred_languages_get_list();
229
 
230
  if ( empty( $preferred_languages ) ) {
231
  return $locale;
@@ -309,7 +359,7 @@ function preferred_languages_register_scripts() {
309
  'jquery-ui-sortable',
310
  'wp-a11y',
311
  ),
312
- '20180708',
313
  true
314
  );
315
 
@@ -326,15 +376,24 @@ function preferred_languages_register_scripts() {
326
  )
327
  );
328
 
329
- $rtl_suffix = is_rtl() ? '-rtl' : '';
330
-
331
- wp_enqueue_style(
332
  'preferred-languages',
333
- plugin_dir_url( dirname( __FILE__ ) ) . 'css/preferred-languages' . $rtl_suffix . '.css',
334
  array(),
335
- '20180708',
336
  'screen'
337
  );
 
 
 
 
 
 
 
 
 
 
 
338
  }
339
 
340
  /**
@@ -439,11 +498,23 @@ function preferred_languages_display_form( $args = array() ) {
439
  }
440
  }
441
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  ?>
443
  <div class="preferred-languages">
444
  <input type="hidden" name="preferred_languages" value="<?php echo esc_attr( implode( ',', $args['selected'] ) ); ?>"/>
445
  <p><?php _e( 'Choose languages for displaying WordPress in, in order of preference.', 'preferred-languages' ); ?></p>
446
- <div class="active-locales">
447
  <?php
448
  /* translators: %s: English (United States) */
449
  $screen_reader_text = sprintf( __( 'No languages selected. Falling back to %s.', 'preferred-languages' ), 'English (United States)' );
@@ -486,52 +557,87 @@ function preferred_languages_display_form( $args = array() ) {
486
  <li>
487
  <button
488
  aria-keyshortcuts="Alt+ArrowUp"
 
489
  aria-disabled="false"
 
490
  type="button"
491
- class="button locales-move-up">
492
  <?php _e( 'Move Up', 'preferred-languages' ); ?>
493
  </button>
494
  </li>
495
  <li>
496
  <button
497
  aria-keyshortcuts="Alt+ArrowDown"
 
498
  aria-disabled="false"
 
499
  type="button"
500
- class="button locales-move-down">
501
  <?php _e( 'Move Down', 'preferred-languages' ); ?>
502
  </button>
503
  </li>
504
  <li>
505
  <button
506
  aria-keyshortcuts="Alt+Delete"
 
507
  aria-disabled="false"
 
508
  type="button"
509
- class="button locales-remove">
510
  <?php _e( 'Remove', 'preferred-languages' ); ?>
511
  </button>
512
  </li>
513
  </ul>
514
  </div>
515
  </div>
516
- </div>
517
- <div class="inactive-locales">
518
- <label class="screen-reader-text" for="preferred-languages-inactive-locales"><?php _e( 'Inactive Locales', 'preferred-languages' ); ?></label>
519
- <div class="inactive-locales-list" data-show-en_US="<?php echo $args['show_option_en_US'] ? 'true' : 'false'; ?>">
520
- <?php
521
- wp_dropdown_languages(
522
- array(
523
- 'id' => 'preferred-languages-inactive-locales',
524
- 'name' => 'preferred-languages-inactive-locales',
525
- 'languages' => $languages,
526
- 'translations' => $translations,
527
- 'show_available_translations' => $args['show_available_translations'],
528
- )
529
- );
530
- ?>
531
- </div>
532
- <div class="inactive-locales-controls">
533
- <button type="button" class="button locales-add" data-action="add"><?php _e( 'Add', 'preferred-languages' ); ?></button>
 
 
 
 
 
 
 
 
 
534
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
  </div>
536
  <?php
537
  }
@@ -542,9 +648,9 @@ function preferred_languages_display_form( $args = array() ) {
542
  * @since 1.1.0
543
  */
544
  function preferred_languages_init_registry() {
545
- global $textdomain_registry;
546
 
547
- $textdomain_registry = new Preferred_Languages_Textdomain_Registry();
548
  }
549
 
550
  /**
@@ -566,20 +672,20 @@ function preferred_languages_filter_gettext( $translation, $text, $domain ) {
566
  $translations = get_translations_for_domain( $domain );
567
 
568
  if ( $translations instanceof NOOP_Translations ) {
569
- /* @var Preferred_Languages_Textdomain_Registry $textdomain_registry */
570
- global $textdomain_registry;
571
 
572
- if ( ! $textdomain_registry instanceof Preferred_Languages_Textdomain_Registry ) {
573
  preferred_languages_init_registry();
574
  }
575
 
576
- $path = $textdomain_registry->get( $domain );
577
 
578
  if ( ! $path ) {
579
- $textdomain_registry->get_translation_from_lang_dir( $domain );
580
  }
581
 
582
- $path = $textdomain_registry->get( $domain );
583
 
584
  if ( ! $path ) {
585
  return $translation;
@@ -592,8 +698,7 @@ function preferred_languages_filter_gettext( $translation, $text, $domain ) {
592
 
593
  if ( load_textdomain( $domain, $mofile ) ) {
594
  $translations = get_translations_for_domain( $domain );
595
- // phpcs:ignore WordPress.WP.I18n
596
- $translation = $translations->translate( $text );
597
 
598
  break;
599
  }
86
  *
87
  * @since 1.3.0
88
  *
89
+ * @return array Preferred languages.
90
  */
91
  function preferred_languages_get_site_list() {
92
  $preferred_languages = get_option( 'preferred_languages', '' );
118
  return preferred_languages_get_site_list();
119
  }
120
 
121
+ /**
122
+ * Downloads language packs when saving user meta without any changes.
123
+ *
124
+ * Makes sure the translations are downloaded when it didn't work the first time around.
125
+ *
126
+ * @since 1.4.0
127
+ *
128
+ * @param null|bool $check Whether to allow updating metadata for the given type.
129
+ * @param int $user_id User ID.
130
+ * @param string $meta_key Meta key.
131
+ * @param mixed $value Meta value.
132
+ * @param mixed $old_value The previous meta value.
133
+ * @return mixed
134
+ */
135
+ function preferred_languages_pre_update_user_meta( $check, $user_id, $meta_key, $value, $old_value ) {
136
+ if ( 'preferred_languages' === $meta_key ) {
137
+ if ( empty( $old_value ) ) {
138
+ $old_value = get_user_meta( $user_id, $meta_key, true );
139
+ }
140
+
141
+ if ( $value === $old_value ) {
142
+ $locales = array_filter( explode( ',', $value ) );
143
+ preferred_languages_download_language_packs( $locales );
144
+ }
145
+ }
146
+
147
+ return $check;
148
+ }
149
+
150
  /**
151
  * Downloads language pack when updating user meta.
152
  *
177
  load_default_textdomain( reset( $preferred_languages_list ) );
178
  }
179
 
180
+ /**
181
+ * Downloads language packs when saving the site option without any changes.
182
+ *
183
+ * Makes sure the translations are downloaded when it didn't work the first time around.
184
+ *
185
+ * @since 1.4.0
186
+ *
187
+ * @param mixed $value The new, unserialized option value.
188
+ * @param string $option Name of the option.
189
+ * @param mixed $old_value The old option value.
190
+ * @return mixed
191
+ */
192
+ function preferred_languages_pre_update_option( $value, $option, $old_value ) {
193
+ if ( 'preferred_languages' === $option && $value === $old_value ) {
194
+ $locales = array_filter( explode( ',', $value ) );
195
+ preferred_languages_download_language_packs( $locales );
196
+ }
197
+
198
+ return $value;
199
+ }
200
+
201
  /**
202
  * Downloads language packs upon updating the site option.
203
  *
275
  * @return string
276
  */
277
  function preferred_languages_filter_locale( $locale ) {
278
+ $preferred_languages = preferred_languages_get_site_list();
279
 
280
  if ( empty( $preferred_languages ) ) {
281
  return $locale;
359
  'jquery-ui-sortable',
360
  'wp-a11y',
361
  ),
362
+ '20180727',
363
  true
364
  );
365
 
376
  )
377
  );
378
 
379
+ wp_register_style(
 
 
380
  'preferred-languages',
381
+ plugin_dir_url( dirname( __FILE__ ) ) . 'css/preferred-languages.css',
382
  array(),
383
+ '20180727',
384
  'screen'
385
  );
386
+
387
+ wp_styles()->add_data( 'preferred-languages', 'rtl', true );
388
+ }
389
+
390
+ /**
391
+ * Enqueues the stylesheet in the admin.
392
+ *
393
+ * @since 1.4.0
394
+ */
395
+ function preferred_languages_enqueue_scripts() {
396
+ wp_enqueue_style( 'preferred-languages' );
397
  }
398
 
399
  /**
498
  }
499
  }
500
 
501
+ /* translators: accessibility text */
502
+ $label_up = __( 'Move up (Alt+Up)', 'preferred-languages' );
503
+
504
+ /* translators: accessibility text */
505
+ $label_down = __( 'Move down (Alt+Down)', 'preferred-languages' );
506
+
507
+ /* translators: accessibility text */
508
+ $label_remove = __( 'Remove from list (Alt+Delete)', 'preferred-languages' );
509
+
510
+ /* translators: accessibility text */
511
+ $label_add = __( 'Add to list (Alt+A)', 'preferred-languages' );
512
+
513
  ?>
514
  <div class="preferred-languages">
515
  <input type="hidden" name="preferred_languages" value="<?php echo esc_attr( implode( ',', $args['selected'] ) ); ?>"/>
516
  <p><?php _e( 'Choose languages for displaying WordPress in, in order of preference.', 'preferred-languages' ); ?></p>
517
+ <div class="active-locales wp-clearfix">
518
  <?php
519
  /* translators: %s: English (United States) */
520
  $screen_reader_text = sprintf( __( 'No languages selected. Falling back to %s.', 'preferred-languages' ), 'English (United States)' );
557
  <li>
558
  <button
559
  aria-keyshortcuts="Alt+ArrowUp"
560
+ aria-label="<?php esc_attr( $label_up ); ?>"
561
  aria-disabled="false"
562
+ data-tooltip="Alt+Up"
563
  type="button"
564
+ class="button locales-move-up tooltipped">
565
  <?php _e( 'Move Up', 'preferred-languages' ); ?>
566
  </button>
567
  </li>
568
  <li>
569
  <button
570
  aria-keyshortcuts="Alt+ArrowDown"
571
+ aria-label="<?php esc_attr( $label_down ); ?>"
572
  aria-disabled="false"
573
+ data-tooltip="Alt+Down"
574
  type="button"
575
+ class="button locales-move-down tooltipped">
576
  <?php _e( 'Move Down', 'preferred-languages' ); ?>
577
  </button>
578
  </li>
579
  <li>
580
  <button
581
  aria-keyshortcuts="Alt+Delete"
582
+ aria-label="<?php esc_attr( $label_remove ); ?>"
583
  aria-disabled="false"
584
+ data-tooltip="Alt+Delete"
585
  type="button"
586
+ class="button locales-remove tooltipped">
587
  <?php _e( 'Remove', 'preferred-languages' ); ?>
588
  </button>
589
  </li>
590
  </ul>
591
  </div>
592
  </div>
593
+ <div class="inactive-locales wp-clearfix">
594
+ <label class="screen-reader-text" for="preferred-languages-inactive-locales"><?php _e( 'Inactive Locales', 'preferred-languages' ); ?></label>
595
+ <div class="inactive-locales-list" data-show-en_US="<?php echo $args['show_option_en_US'] ? 'true' : 'false'; ?>">
596
+ <?php
597
+ wp_dropdown_languages(
598
+ array(
599
+ 'id' => 'preferred-languages-inactive-locales',
600
+ 'name' => 'preferred-languages-inactive-locales',
601
+ 'languages' => $languages,
602
+ 'translations' => $translations,
603
+ 'show_available_translations' => $args['show_available_translations'],
604
+ )
605
+ );
606
+ ?>
607
+ </div>
608
+ <div class="inactive-locales-controls">
609
+ <button
610
+ aria-keyshortcuts="Alt+A"
611
+ aria-label="<?php esc_attr( $label_add ); ?>"
612
+ aria-disabled="false"
613
+ data-tooltip="Alt+A"
614
+ type="button"
615
+ class="button locales-add tooltipped"
616
+ >
617
+ <?php _e( 'Add', 'preferred-languages' ); ?>
618
+ </button>
619
+ </div>
620
  </div>
621
+ <?php
622
+ if ( current_user_can( 'install_languages' ) ) {
623
+ foreach ( $preferred_languages as $language ) {
624
+ if ( 'en_US' === $language['language'] ) {
625
+ continue;
626
+ }
627
+
628
+ if ( ! in_array( $language['language'], get_available_languages(), true ) ) {
629
+ ?>
630
+ <div class="notice notice-warning inline">
631
+ <p>
632
+ <?php _e( 'Some of the languages are not installed. Re-save changes to download translations.', 'preferred-languages' ); ?>
633
+ </p>
634
+ </div>
635
+ <?php
636
+ break;
637
+ }
638
+ }
639
+ }
640
+ ?>
641
  </div>
642
  <?php
643
  }
648
  * @since 1.1.0
649
  */
650
  function preferred_languages_init_registry() {
651
+ global $preferred_languages_textdomain_registry;
652
 
653
+ $preferred_languages_textdomain_registry = new Preferred_Languages_Textdomain_Registry();
654
  }
655
 
656
  /**
672
  $translations = get_translations_for_domain( $domain );
673
 
674
  if ( $translations instanceof NOOP_Translations ) {
675
+ /* @var Preferred_Languages_Textdomain_Registry $preferred_languages_textdomain_registry */
676
+ global $preferred_languages_textdomain_registry;
677
 
678
+ if ( ! $preferred_languages_textdomain_registry instanceof Preferred_Languages_Textdomain_Registry ) {
679
  preferred_languages_init_registry();
680
  }
681
 
682
+ $path = $preferred_languages_textdomain_registry->get( $domain );
683
 
684
  if ( ! $path ) {
685
+ $preferred_languages_textdomain_registry->get_translation_from_lang_dir( $domain );
686
  }
687
 
688
+ $path = $preferred_languages_textdomain_registry->get( $domain );
689
 
690
  if ( ! $path ) {
691
  return $translation;
698
 
699
  if ( load_textdomain( $domain, $mofile ) ) {
700
  $translations = get_translations_for_domain( $domain );
701
+ $translation = $translations->translate( $text );
 
702
 
703
  break;
704
  }
js/preferred-languages.js CHANGED
@@ -1,14 +1,19 @@
1
  'use strict';
2
 
3
  (function (wp, settings, $) {
 
4
  var $activeLocales = $('.active-locales-list');
5
  var $activeLocalesControls = $('.active-locales-controls');
6
  var $emptyMessage = $('#active-locales-empty-message');
7
  var $inactiveLocalesWrap = $('.inactive-locales-list');
8
  var $inactiveLocales = $inactiveLocalesWrap.find('select');
9
  var $inactiveLocalesControls = $('.inactive-locales-controls');
10
- var $selectedLocale = $activeLocales.find('li[aria-selected="true"]');
11
  var $inputField = $('input[name="preferred_languages"]');
 
 
 
 
 
12
 
13
  /**
14
  * Changes the move button states.
@@ -20,9 +25,9 @@
20
  function changeButtonState(activeLocale) {
21
  var activeLocalesList = $activeLocales.find('.active-locale');
22
 
23
- $activeLocalesControls.find('.locales-move-up').attr('disabled', $activeLocales.hasClass('empty-list') || activeLocalesList.first().is(activeLocale) || !$selectedLocale.length);
24
- $activeLocalesControls.find('.locales-move-down').attr('disabled', $activeLocales.hasClass('empty-list') || activeLocalesList.last().is(activeLocale) || !$selectedLocale.length);
25
- $activeLocalesControls.find('.locales-remove').attr('disabled', $activeLocales.hasClass('empty-list') || !$selectedLocale.length);
26
  $inactiveLocalesControls.find('.locales-add').attr('disabled', 'disabled' === $inactiveLocales.attr('disabled'));
27
  }
28
 
@@ -39,17 +44,10 @@
39
 
40
  // It's already the current locale, so nothing to do here.
41
  if ('true' === selected) {
42
- $locale.attr('aria-selected', false);
43
- $selectedLocale = [];
44
-
45
- changeButtonState($locale);
46
-
47
  return;
48
  }
49
 
50
- if ($selectedLocale.length) {
51
- $selectedLocale.attr('aria-selected', false);
52
- }
53
 
54
  $locale.attr('aria-selected', newState);
55
 
@@ -270,39 +268,37 @@
270
  });
271
 
272
  // Active locales keyboard shortcuts.
273
- $activeLocales.on('keydown', function (e) {
274
-
275
- // Up.
276
- if (38 === e.which) {
277
- if (e.altKey) {
278
- moveLocaleUp();
279
- } else {
280
- $selectedLocale.prev().length && toggleLocale($selectedLocale.prev());
281
- }
282
-
283
- e.preventDefault();
284
- }
285
-
286
- // Down.
287
- if (40 === e.which) {
288
- if (e.altKey) {
289
- moveLocaleDown();
290
- } else {
291
- $selectedLocale.next().length && toggleLocale($selectedLocale.next());
292
- }
293
-
294
- e.preventDefault();
295
- }
296
-
297
- // Backspace.
298
- if (8 === e.which) {
299
- makeLocaleInactive();
300
- e.preventDefault();
301
  }
302
  });
303
 
304
  // Inactive Locales keyboard shortcuts.
305
- $inactiveLocales.on('keydown', function (e) {
306
 
307
  // Letter "A".
308
  if (65 === e.which) {
1
  'use strict';
2
 
3
  (function (wp, settings, $) {
4
+ var $document = $(document);
5
  var $activeLocales = $('.active-locales-list');
6
  var $activeLocalesControls = $('.active-locales-controls');
7
  var $emptyMessage = $('#active-locales-empty-message');
8
  var $inactiveLocalesWrap = $('.inactive-locales-list');
9
  var $inactiveLocales = $inactiveLocalesWrap.find('select');
10
  var $inactiveLocalesControls = $('.inactive-locales-controls');
 
11
  var $inputField = $('input[name="preferred_languages"]');
12
+ var $selectedLocale = $activeLocales.find('li[aria-selected="true"]');
13
+
14
+ var KEY_UP = 38;
15
+ var KEY_DOWN = 40;
16
+ var KEY_BACKSPACE = 8;
17
 
18
  /**
19
  * Changes the move button states.
25
  function changeButtonState(activeLocale) {
26
  var activeLocalesList = $activeLocales.find('.active-locale');
27
 
28
+ $activeLocalesControls.find('.locales-move-up').attr('disabled', $activeLocales.hasClass('empty-list') || activeLocalesList.first().is(activeLocale));
29
+ $activeLocalesControls.find('.locales-move-down').attr('disabled', $activeLocales.hasClass('empty-list') || activeLocalesList.last().is(activeLocale));
30
+ $activeLocalesControls.find('.locales-remove').attr('disabled', $activeLocales.hasClass('empty-list'));
31
  $inactiveLocalesControls.find('.locales-add').attr('disabled', 'disabled' === $inactiveLocales.attr('disabled'));
32
  }
33
 
44
 
45
  // It's already the current locale, so nothing to do here.
46
  if ('true' === selected) {
 
 
 
 
 
47
  return;
48
  }
49
 
50
+ $selectedLocale.attr('aria-selected', false);
 
 
51
 
52
  $locale.attr('aria-selected', newState);
53
 
268
  });
269
 
270
  // Active locales keyboard shortcuts.
271
+ $document.on('keydown', $activeLocales, function (e) {
272
+ switch (e.which) {
273
+ case KEY_UP:
274
+ if (e.altKey) {
275
+ moveLocaleUp();
276
+ } else {
277
+ $selectedLocale.prev().length && toggleLocale($selectedLocale.prev());
278
+ }
279
+
280
+ e.preventDefault();
281
+ break;
282
+
283
+ case KEY_DOWN:
284
+ if (e.altKey) {
285
+ moveLocaleDown();
286
+ } else {
287
+ $selectedLocale.next().length && toggleLocale($selectedLocale.next());
288
+ }
289
+
290
+ e.preventDefault();
291
+ break;
292
+
293
+ case KEY_BACKSPACE:
294
+ makeLocaleInactive();
295
+ e.preventDefault();
296
+ break;
 
 
297
  }
298
  });
299
 
300
  // Inactive Locales keyboard shortcuts.
301
+ $document.on('keydown', $inactiveLocales, function (e) {
302
 
303
  // Letter "A".
304
  if (65 === e.which) {
js/preferred-languages.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";(function(wp,settings,$){var $activeLocales=$(".active-locales-list");var $activeLocalesControls=$(".active-locales-controls");var $emptyMessage=$("#active-locales-empty-message");var $inactiveLocalesWrap=$(".inactive-locales-list");var $inactiveLocales=$inactiveLocalesWrap.find("select");var $inactiveLocalesControls=$(".inactive-locales-controls");var $selectedLocale=$activeLocales.find('li[aria-selected="true"]');var $inputField=$('input[name="preferred_languages"]');function changeButtonState(activeLocale){var activeLocalesList=$activeLocales.find(".active-locale");$activeLocalesControls.find(".locales-move-up").attr("disabled",$activeLocales.hasClass("empty-list")||activeLocalesList.first().is(activeLocale)||!$selectedLocale.length);$activeLocalesControls.find(".locales-move-down").attr("disabled",$activeLocales.hasClass("empty-list")||activeLocalesList.last().is(activeLocale)||!$selectedLocale.length);$activeLocalesControls.find(".locales-remove").attr("disabled",$activeLocales.hasClass("empty-list")||!$selectedLocale.length);$inactiveLocalesControls.find(".locales-add").attr("disabled","disabled"===$inactiveLocales.attr("disabled"))}function toggleLocale($locale){var selected=$locale.attr("aria-selected");var newState="true"!==selected;if("true"===selected){$locale.attr("aria-selected",false);$selectedLocale=[];changeButtonState($locale);return}if($selectedLocale.length){$selectedLocale.attr("aria-selected",false)}$locale.attr("aria-selected",newState);if(true===newState){$selectedLocale=$locale;$activeLocales.attr("aria-activedescendant",$selectedLocale.attr("id"))}changeButtonState($locale)}function updateHiddenInput(){var locales=[];$activeLocales.children(".active-locale").each(function(index,el){locales.push($(el).attr("id"))});$inputField.val(locales.join(","))}function moveLocaleUp(){$selectedLocale.insertBefore($selectedLocale.prev());updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.movedUp)}function moveLocaleDown(){$selectedLocale.insertAfter($selectedLocale.next());updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.movedDown)}function toggleEmptyListMessage(){if($activeLocales.hasClass("empty-list")){$activeLocales.removeClass("empty-list");$emptyMessage.addClass("hidden")}else{$activeLocales.addClass("empty-list");$activeLocales.attr("aria-activedescendant","");$emptyMessage.removeClass("hidden");wp.a11y.speak($emptyMessage.data("a11y-message"))}}function makeLocaleInactive(){var locale=$selectedLocale.attr("id");var $successor=void 0;$successor=$selectedLocale.prevAll(":first");if(0===$successor.length){$successor=$selectedLocale.nextAll(":first")}$selectedLocale.remove();if($successor.length){toggleLocale($successor)}else{toggleEmptyListMessage()}$inactiveLocales.find('option[value="'+locale+'"]').removeClass("hidden");$inactiveLocales.attr("disabled",false);updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.localeRemoved)}function makeLocaleActive(option){var locale=option.val()||"en_US";var $newLocale=$("<li/>",{text:option.text(),role:"option","aria-selected":false,id:locale,class:"active-locale"});var $successor=void 0;option.removeAttr("selected").addClass("hidden");$successor=option.prevAll(":not(.hidden):first");if(!$successor.length){$successor=option.nextAll(":not(.hidden):first")}if(!$successor.length){$successor=$inactiveLocales.find("option:not(.hidden):first")}if(!$successor.length){$inactiveLocales.attr("disabled",true)}$successor.attr("selected",true);$inactiveLocalesControls.val($successor.val());if($activeLocales.find("#"+locale).length){return}if($activeLocales.hasClass("empty-list")){toggleEmptyListMessage()}$activeLocales.append($newLocale);toggleLocale($newLocale);$activeLocales.animate({scrollTop:$newLocale.offset().top-$activeLocales.offset().top+$activeLocales.scrollTop()});updateHiddenInput();wp.a11y.speak(settings.l10n.localeAdded)}$(".user-language-wrap").remove();$("#WPLANG").parent().parent().remove();$inactiveLocalesWrap.filter('[data-show-en_US="false"]').find('[lang="en"][value=""]').remove();changeButtonState($selectedLocale);if($inputField.val().length){$.each($inputField.val().split(","),function(index,value){value="en_US"===value?"":value;var $option=$inactiveLocales.find('[value="'+value+'"]');$option.removeAttr("selected").addClass("hidden")});var $firstInactiveLocale=$inactiveLocales.find("option:not(.hidden):first");$firstInactiveLocale.attr("selected",true);$inactiveLocalesControls.val($firstInactiveLocale.val())}$activeLocales.sortable({axis:"y",cursor:"move",items:":not(#active-locales-list-empty-message)"});$activeLocales.on("keydown",function(e){if(38===e.which){if(e.altKey){moveLocaleUp()}else{$selectedLocale.prev().length&&toggleLocale($selectedLocale.prev())}e.preventDefault()}if(40===e.which){if(e.altKey){moveLocaleDown()}else{$selectedLocale.next().length&&toggleLocale($selectedLocale.next())}e.preventDefault()}if(8===e.which){makeLocaleInactive();e.preventDefault()}});$inactiveLocales.on("keydown",function(e){if(65===e.which){if(e.altKey){makeLocaleActive($inactiveLocales.find("option:selected"))}e.preventDefault()}});$inactiveLocalesControls.find(".locales-add").on("click",function(){makeLocaleActive($inactiveLocales.find("option:selected"))});$activeLocales.on("click",".active-locale",function(e){toggleLocale($(e.currentTarget))});$activeLocalesControls.find(".locales-move-up").on("click",moveLocaleUp);$activeLocalesControls.find(".locales-move-down").on("click",moveLocaleDown);$activeLocalesControls.find(".locales-remove").on("click",makeLocaleInactive)})(wp,preferredLanguages,jQuery);
1
+ "use strict";(function(wp,settings,$){var $document=$(document);var $activeLocales=$(".active-locales-list");var $activeLocalesControls=$(".active-locales-controls");var $emptyMessage=$("#active-locales-empty-message");var $inactiveLocalesWrap=$(".inactive-locales-list");var $inactiveLocales=$inactiveLocalesWrap.find("select");var $inactiveLocalesControls=$(".inactive-locales-controls");var $inputField=$('input[name="preferred_languages"]');var $selectedLocale=$activeLocales.find('li[aria-selected="true"]');var KEY_UP=38;var KEY_DOWN=40;var KEY_BACKSPACE=8;function changeButtonState(activeLocale){var activeLocalesList=$activeLocales.find(".active-locale");$activeLocalesControls.find(".locales-move-up").attr("disabled",$activeLocales.hasClass("empty-list")||activeLocalesList.first().is(activeLocale));$activeLocalesControls.find(".locales-move-down").attr("disabled",$activeLocales.hasClass("empty-list")||activeLocalesList.last().is(activeLocale));$activeLocalesControls.find(".locales-remove").attr("disabled",$activeLocales.hasClass("empty-list"));$inactiveLocalesControls.find(".locales-add").attr("disabled","disabled"===$inactiveLocales.attr("disabled"))}function toggleLocale($locale){var selected=$locale.attr("aria-selected");var newState="true"!==selected;if("true"===selected){return}$selectedLocale.attr("aria-selected",false);$locale.attr("aria-selected",newState);if(true===newState){$selectedLocale=$locale;$activeLocales.attr("aria-activedescendant",$selectedLocale.attr("id"))}changeButtonState($locale)}function updateHiddenInput(){var locales=[];$activeLocales.children(".active-locale").each(function(index,el){locales.push($(el).attr("id"))});$inputField.val(locales.join(","))}function moveLocaleUp(){$selectedLocale.insertBefore($selectedLocale.prev());updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.movedUp)}function moveLocaleDown(){$selectedLocale.insertAfter($selectedLocale.next());updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.movedDown)}function toggleEmptyListMessage(){if($activeLocales.hasClass("empty-list")){$activeLocales.removeClass("empty-list");$emptyMessage.addClass("hidden")}else{$activeLocales.addClass("empty-list");$activeLocales.attr("aria-activedescendant","");$emptyMessage.removeClass("hidden");wp.a11y.speak($emptyMessage.data("a11y-message"))}}function makeLocaleInactive(){var locale=$selectedLocale.attr("id");var $successor=void 0;$successor=$selectedLocale.prevAll(":first");if(0===$successor.length){$successor=$selectedLocale.nextAll(":first")}$selectedLocale.remove();if($successor.length){toggleLocale($successor)}else{toggleEmptyListMessage()}$inactiveLocales.find('option[value="'+locale+'"]').removeClass("hidden");$inactiveLocales.attr("disabled",false);updateHiddenInput();changeButtonState($selectedLocale);wp.a11y.speak(settings.l10n.localeRemoved)}function makeLocaleActive(option){var locale=option.val()||"en_US";var $newLocale=$("<li/>",{text:option.text(),role:"option","aria-selected":false,id:locale,class:"active-locale"});var $successor=void 0;option.removeAttr("selected").addClass("hidden");$successor=option.prevAll(":not(.hidden):first");if(!$successor.length){$successor=option.nextAll(":not(.hidden):first")}if(!$successor.length){$successor=$inactiveLocales.find("option:not(.hidden):first")}if(!$successor.length){$inactiveLocales.attr("disabled",true)}$successor.attr("selected",true);$inactiveLocalesControls.val($successor.val());if($activeLocales.find("#"+locale).length){return}if($activeLocales.hasClass("empty-list")){toggleEmptyListMessage()}$activeLocales.append($newLocale);toggleLocale($newLocale);$activeLocales.animate({scrollTop:$newLocale.offset().top-$activeLocales.offset().top+$activeLocales.scrollTop()});updateHiddenInput();wp.a11y.speak(settings.l10n.localeAdded)}$(".user-language-wrap").remove();$("#WPLANG").parent().parent().remove();$inactiveLocalesWrap.filter('[data-show-en_US="false"]').find('[lang="en"][value=""]').remove();changeButtonState($selectedLocale);if($inputField.val().length){$.each($inputField.val().split(","),function(index,value){value="en_US"===value?"":value;var $option=$inactiveLocales.find('[value="'+value+'"]');$option.removeAttr("selected").addClass("hidden")});var $firstInactiveLocale=$inactiveLocales.find("option:not(.hidden):first");$firstInactiveLocale.attr("selected",true);$inactiveLocalesControls.val($firstInactiveLocale.val())}$activeLocales.sortable({axis:"y",cursor:"move",items:":not(#active-locales-list-empty-message)"});$document.on("keydown",$activeLocales,function(e){switch(e.which){case KEY_UP:if(e.altKey){moveLocaleUp()}else{$selectedLocale.prev().length&&toggleLocale($selectedLocale.prev())}e.preventDefault();break;case KEY_DOWN:if(e.altKey){moveLocaleDown()}else{$selectedLocale.next().length&&toggleLocale($selectedLocale.next())}e.preventDefault();break;case KEY_BACKSPACE:makeLocaleInactive();e.preventDefault();break}});$document.on("keydown",$inactiveLocales,function(e){if(65===e.which){if(e.altKey){makeLocaleActive($inactiveLocales.find("option:selected"))}e.preventDefault()}});$inactiveLocalesControls.find(".locales-add").on("click",function(){makeLocaleActive($inactiveLocales.find("option:selected"))});$activeLocales.on("click",".active-locale",function(e){toggleLocale($(e.currentTarget))});$activeLocalesControls.find(".locales-move-up").on("click",moveLocaleUp);$activeLocalesControls.find(".locales-move-down").on("click",moveLocaleDown);$activeLocalesControls.find(".locales-remove").on("click",makeLocaleInactive)})(wp,preferredLanguages,jQuery);
preferred-languages.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Preferred Languages
4
  * Plugin URI: https://github.com/swissspidy/preferred-languages/
5
  * Description: Choose languages for displaying WordPress in, in order of preference.
6
- * Version: 1.3.0
7
  * Author: Pascal Birchler
8
  * Author URI: https://pascalbirchler.com
9
  * License: GPL-2.0+
3
  * Plugin Name: Preferred Languages
4
  * Plugin URI: https://github.com/swissspidy/preferred-languages/
5
  * Description: Choose languages for displaying WordPress in, in order of preference.
6
+ * Version: 1.4.0
7
  * Author: Pascal Birchler
8
  * Author URI: https://pascalbirchler.com
9
  * License: GPL-2.0+
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: internationalization, i18n, localization, l10n, language, locale, translat
4
  Requires at least: 4.9
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
- Stable tag: 1.3.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -31,6 +31,16 @@ If you want to get involved, check out [open issues](https://github.com/swissspi
31
 
32
  == Changelog ==
33
 
 
 
 
 
 
 
 
 
 
 
34
  = 1.3.0 =
35
 
36
  * New: Users can now choose English (United States) again as a preferred locale.
@@ -59,6 +69,10 @@ If you want to get involved, check out [open issues](https://github.com/swissspi
59
 
60
  == Upgrade Notice ==
61
 
 
 
 
 
62
  = 1.3.0 =
63
 
64
  Users can now install new languages from their user profile. Also, English (US) can be chosen as a preferred user language.
4
  Requires at least: 4.9
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
+ Stable tag: 1.4.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
31
 
32
  == Changelog ==
33
 
34
+ = 1.4.0 =
35
+
36
+ * New: Keyboard navigation improvements.
37
+ * New: Tooltips now show the available keyboard shortcuts.
38
+ * New: Missing translations are now downloaded even when no changes were made.
39
+ * New: A warning is shown when some of the preferred languages aren't installed.
40
+ * New: Settings form is now hidden when JavaScript is disabled.
41
+ * Fixed: Improved setting the current locale.
42
+ * Fixed: CSS is no longer enqueued on the front end.
43
+
44
  = 1.3.0 =
45
 
46
  * New: Users can now choose English (United States) again as a preferred locale.
69
 
70
  == Upgrade Notice ==
71
 
72
+ = 1.4.0 =
73
+
74
+ This release contains improvements regarding translation downloads upon saving.
75
+
76
  = 1.3.0 =
77
 
78
  Users can now install new languages from their user profile. Also, English (US) can be chosen as a preferred user language.