diff --git a/CUSTOMIZE.md b/CUSTOMIZE.md index 3b50a8703..bc9205ccf 100644 --- a/CUSTOMIZE.md +++ b/CUSTOMIZE.md @@ -29,6 +29,19 @@ In that file, you can customize much of the user-facing text on the website. Most of the text should be ready to go, but there is one specific setting you should customize: the [location](https://github.com/codeforamerica/ohana-web-search/blob/master/config/locales/en.yml#L28) value under `branding`. +## Language Translation Services +The application uses Google Translate for free language translation of the site. The Google Website Translator Gadget appears in the footer of the site and provides free translation of the site into dozens of languages. By default, six major language translation links are provided (in their native script) on the upper-right of the homepage. A number of aspects related to translation can be customized: + +- **Homepage language links**. The language translation links on the homepage can be added, removed, and edited in `config/settings.yml`. + +- **Support for saving custom translations**. If you want to make edits to the Google provided translations of a live site you can add a `GOOGLE_TRANSLATE_CUSTOMIZATION_CODE` in `config/application.yml`. Follow the directions in that file for obtaining the proper code for your site. + +- **Support for non-English keyword searches**. If you want your users to be able to enter a keyword search in a language other than English, you can enable language detection by adding a `GOOGLE_TRANSLATE_API_TOKEN` in `config/application.yml`. Follow the directions in that file for obtaining an API token. +**NOTE: GOOGLE CHARGES FOR THIS FEATURE.** + +- **Change the gadget layout**. If you want to change the Google Website Translator Gadget's layout, two of the layouts provided by Google are supported: InlineLayout.VERTICAL and InlineLayout.HORIZONTAL. One or the other +can be set in `assets/javascripts/application.js`. + ## Pagination The pagination of search results is handled by the [Kaminari](https://github.com/amatsuda/kaminari) gem. To configure the functionality, make changes in [kaminari_config.rb](https://github.com/codeforamerica/ohana-web-search/blob/master/config/initializers/kaminari_config.rb). diff --git a/app/assets/javascripts/app/app-init.js b/app/assets/javascripts/app/app-init.js index 3275dab46..22f4f4540 100644 --- a/app/assets/javascripts/app/app-init.js +++ b/app/assets/javascripts/app/app-init.js @@ -3,16 +3,12 @@ // and search details pages. It is not called by // the about page, because that page does not have popups to manage. require([ - 'app/google-translate-manager', 'app/popup-manager', 'app/alert-manager' ], -function (gt, pm, alert) { +function (pm, alert) { 'use strict'; - // Initialize the google translate manager. - gt.init(); - // If box-shadow CSS is supported, initialize the popups. if (Modernizr.boxshadow) pm.init(); diff --git a/app/assets/javascripts/app/google-translate-manager.js b/app/assets/javascripts/app/google-translate-manager.js deleted file mode 100644 index 41c0d7ed7..000000000 --- a/app/assets/javascripts/app/google-translate-manager.js +++ /dev/null @@ -1,61 +0,0 @@ -// Manages behavior of google translate drop-down. -define([ - 'util/util' -], -function (util) { - 'use strict'; - - var _languages; - var _timeoutCount = 0; - - function init() { - _deleteTranslateCookies(); - _checkForGoogleInitialization(); - } - - // Removes the google translate cookies by setting their expiration date - // into the past. - function _deleteTranslateCookies() { - var cookies = document.cookie.split(';'); - - for (var i = 0, len = cookies.length; i < len; i++) { - var cookie = cookies[i]; - var eqPos = cookie.indexOf('='); - var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - if (name === 'googtrans') - document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; - } - } - - // Polling check for Google Translate drop-down to be initialized. - function _checkForGoogleInitialization() { - // Timeout check set to 20 seconds. - if (_timeoutCount++ < 20) { - setTimeout( function () { - var query = '#google-translate-element select'; - _languages = document.querySelector(query); - if (!_languages) _checkForGoogleInitialization(); - else _hookDropDown(); - }, 1000); - } else { - console.log('Timeout while initializing Google Translate drop-down!'); - } - } - - // Hook in a change event to the language drop-down menu so the page reloads - // and is appended a translate query string when the drop-down menu changes. - function _hookDropDown() { - _languages.addEventListener('change', _langUpdated, false); - } - - function _langUpdated() { - var options = { - 'translate': _languages.options[_languages.selectedIndex].value - }; - document.location.search = util.queryString(options); - } - - return { - init:init - }; -}); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 98d767f85..e9ac1a359 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -69,8 +69,19 @@ // app/assets/javascripts/routes/. // require([ + 'util/translation/google-translate-manager', 'domReady!' ], -function () { +function (googleTranslate) { 'use strict'; + + // The Google translate manager handles loading of the + // Google Website Translator Gadget at the bottom of the page's body. + // The layout settings passed in as an argument to the initialization + // method can be set to: + // InlineLayout.VERTICAL, InlineLayout.HORIZONTAL, + // which correspond to the 'inline' display modes available through Google. + // The 'tabbed' and 'auto' display modes are not supported. + // The 'inline' InlineLayout.SIMPLE layout is also not supported. + googleTranslate.init(googleTranslate.InlineLayout.VERTICAL); }); diff --git a/app/assets/javascripts/result/result-map-manager.js b/app/assets/javascripts/result/result-map-manager.js index 11625a80f..1d66539d9 100644 --- a/app/assets/javascripts/result/result-map-manager.js +++ b/app/assets/javascripts/result/result-map-manager.js @@ -1,11 +1,11 @@ // Manages search results view Google Map. define([ - 'util/bitmask', + 'util/BitMask', 'util/map/marker-manager', 'domReady!', 'async!https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false!callback' ], -function (bitmask, markerManager) { +function (BitMask, markerManager) { 'use strict'; // The
element that the Google map loads into. @@ -75,7 +75,7 @@ function (bitmask, markerManager) { var _infoBoxContent; function init() { - _infoBoxState = bitmask.create(); + _infoBoxState = BitMask.create(); // Turn off assumption that touch is being used initially, this is turned // on if a touch event is registered. diff --git a/app/assets/javascripts/routes/about/index.js b/app/assets/javascripts/routes/about/index.js index 34922510c..22996eda4 100644 --- a/app/assets/javascripts/routes/about/index.js +++ b/app/assets/javascripts/routes/about/index.js @@ -1,15 +1,11 @@ // Manages initialization of scripts for the About page. require([ - 'app/google-translate-manager', 'app/feedback-form-manager', 'application' ], function (gt, feedback) { 'use strict'; - // Initialize the Google Translate manager. - gt.init(); - // Initialize the feedback form. feedback.init(); }); diff --git a/app/assets/javascripts/util/bitmask.js b/app/assets/javascripts/util/BitMask.js similarity index 100% rename from app/assets/javascripts/util/bitmask.js rename to app/assets/javascripts/util/BitMask.js diff --git a/app/assets/javascripts/util/map/marker-manager.js.erb b/app/assets/javascripts/util/map/marker-manager.js.erb index 8a62363f9..aef2bd14e 100644 --- a/app/assets/javascripts/util/map/marker-manager.js.erb +++ b/app/assets/javascripts/util/map/marker-manager.js.erb @@ -5,9 +5,9 @@ // Used for managing which map marker should be shown. define([ - 'util/bitmask' + 'util/BitMask' ], -function (bitmask) { +function (BitMask) { 'use strict'; // 'Constants' for the kind labels returned by the Ohana API. @@ -34,7 +34,7 @@ function (bitmask) { var UNSPIDERFIED_ICON = 8; // A bitmask instance for tracking the four states of the icon appearance. - var _iconState = bitmask.create(); + var _iconState = BitMask.create(); _iconState.turnOn(SMALL_ICON | UNSPIDERFIED_ICON); // The kind set on this marker. diff --git a/app/assets/javascripts/util/translation/google-translate-manager.js b/app/assets/javascripts/util/translation/google-translate-manager.js new file mode 100644 index 000000000..9abe098c0 --- /dev/null +++ b/app/assets/javascripts/util/translation/google-translate-manager.js @@ -0,0 +1,90 @@ +// Manages behavior of the Google Website Translator Gadget. +define([ + 'util/translation/layout/DropDownLayout' +], +function (DropDownLayout) { + 'use strict'; + + // The layout object in use. + var _layout; + + // The current layout that is set. Determined by the + // 'layout' setting in the Google Translate provided script + // in the footer. + var _layoutType; + + // Same 'constants' as google.translate.TranslateElement.InlineLayout + // for tracking which layout is in use. + var VERTICAL = 0; + var HORIZONTAL = 1; + var InlineLayout = { VERTICAL:VERTICAL, HORIZONTAL:HORIZONTAL }; + + // The id of the element on the page that will contain + // the Google Website Translator Gadget. + var GOOGLE_TRANSLATE_ELEMENT_ID = 'google-translate-container'; + + function init(layoutType) { + _layoutType = layoutType; + + _deleteTranslateCookies(); + + _layout = DropDownLayout.create(); + _layout.init(GOOGLE_TRANSLATE_ELEMENT_ID); + + // Add Google Translate script call by appending script element. + var scriptElm = document.createElement('script'); + var scriptUrl = '//translate.google.com/translate_a/element.js?cb='; + var scriptCallback = 'GoogleTranslate.googleTranslateElementInit'; + scriptElm.setAttribute('src', scriptUrl+scriptCallback); + document.body.appendChild(scriptElm); + + // Add the callback function for the Google Translate script. + var GoogleTranslate = { + googleTranslateElementInit:_googleTranslateElementInit + }; + window.GoogleTranslate = GoogleTranslate; + } + + // Initialize the Google Website Translator Gadget. + function _googleTranslateElementInit() { + var opts = { + pageLanguage: 'en', + layout: _getGoogleLayout(), + autoDisplay: false + }; + + new google.translate.TranslateElement( opts, GOOGLE_TRANSLATE_ELEMENT_ID ); + + // Activate hooks to manipulate Google Website Translator Gadget through + // the URL 'translate' parameter. + _layout.activate(); + } + + // @return [Object] Return the inline Google Website Translator Gadget + // layouts supplied by Google. + function _getGoogleLayout() { + if (_layoutType === VERTICAL) + return google.translate.TranslateElement.InlineLayout.VERTICAL; + else if (_layoutType === HORIZONTAL) + return google.translate.TranslateElement.InlineLayout.HORIZONTAL; + } + + // Removes the Google Website Translator cookies by setting their expiration + // date into the past. + function _deleteTranslateCookies() { + var cookies, cookie, eqPos, name; + cookies = document.cookie.split('; '); + for (var i = 0, len = cookies.length; i < len; i++) { + cookie = cookies[i]; + eqPos = cookie.indexOf('='); + name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + if (name === 'googtrans') + document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + } + } + + return { + init:init, + InlineLayout:InlineLayout + }; +}); diff --git a/app/assets/javascripts/util/translation/layout/DropDownLayout.js b/app/assets/javascripts/util/translation/layout/DropDownLayout.js new file mode 100644 index 000000000..7e337d41c --- /dev/null +++ b/app/assets/javascripts/util/translation/layout/DropDownLayout.js @@ -0,0 +1,64 @@ +// Manages behavior of posting changes to the URL for +// inlinelayout.VERTICAL and inlinelayout.HORIZONTAL +// Google Translate Widget layouts. +define([ + 'util/util' +], +function (util) { + 'use strict'; + + function create() { + return new DropDownLayout(); + } + + function DropDownLayout() { + + // The HTML element that contain the language options. + var _languages; + + // The ID of the Google Translate widget HTML container. + var _googleTranslateElmID; + + function init(id) { + _googleTranslateElmID = id; + } + + function activate() { + _languages = _getGoogleLayoutElement(); + _hookDropDown(); + } + + // @return [Object] The HTML element that contains the Google Translate + // languages. + function _getGoogleLayoutElement() { + var query = '#'+_googleTranslateElmID + ' select'; + var elm = document.querySelector(query); + if (!elm) + throw new Error('Google Translate Widget HTML container not found!'); + return elm + } + + // Hook in a change event to the language drop-down menu so the page reloads + // and is appended a translate query string when the drop-down menu changes. + function _hookDropDown() { + _languages.addEventListener('change', _languageDropDownChanged, false); + } + + // Update the URL with the selected language. + function _languageDropDownChanged() { + var options = { + 'translate': _languages.options[_languages.selectedIndex].value + }; + document.location.search = util.queryString(options); + } + + return { + init:init, + activate:activate + }; + } + + return { + create:create + }; +}); diff --git a/app/assets/stylesheets/_base.scss b/app/assets/stylesheets/_base.scss index dfdc2f712..4b1249980 100644 --- a/app/assets/stylesheets/_base.scss +++ b/app/assets/stylesheets/_base.scss @@ -636,17 +636,42 @@ sup } //================================================================================= -// language box styles on homepage -#language-box +// Google Translate widget styles. + +// The container for the Google Translate widget. +#google-translate-container +{ + padding-bottom: 20px; +} + +// Hides the Google Translate translation banner at the top of the page. +.goog-te-banner-frame.skiptranslate { display: none !important; } +body { top: 0px !important; } + +//================================================================================= +// Area above the search box, which holds the language translation links box. +.home .search-utilities { - // background: $primary; // IE fallback - // background: rgba($primary,0.9); background: $search-bg; // IE fallback - background: rgba($search-bg,0.9); + background: rgba($search-bg, 0.9); + min-height: 40px; padding: 10px; padding-right: 25px; - padding-bottom: 20px; text-align: right; +} + +// Area below the search box, which could hold settings, but doesn't currently. +.home #search-bottom-utilities +{ + border-bottom: 2px solid $main-border-color; +} + + +//================================================================================= +// Language translation links on the upper-right homepage. +.home #language-box +{ + padding-bottom: 10px; ul { @@ -661,27 +686,6 @@ sup } } -#google-translate-element -{ - padding-bottom: 20px; -} - -.goog-te-banner-frame.skiptranslate {display: none !important;} -body { top: 0px !important; } - -//================================================================================= -// Help box styles on homepage. -#help-box -{ - background: $search-bg; // IE fallback - background: rgba($search-bg, .9); - border-bottom: 2px solid $main-border-color; - padding: 10px; - padding-right: 25px; - text-align: right; - min-height: 40px; -} - //================================================================================= // Search options. .home #search-container diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index 0b5de0611..f887efae3 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -1,4 +1,5 @@ class AboutController < ApplicationController + include GoogleTranslator respond_to :html, :json def index diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index 606ff028b..d07b6b5ee 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -1,4 +1,5 @@ class LocationsController < ApplicationController + include GoogleTranslator include CurrentLanguage include Cacheable diff --git a/app/helpers/language_links_helper.rb b/app/helpers/language_links_helper.rb index 1aee4ece5..a8c70a03c 100644 --- a/app/helpers/language_links_helper.rb +++ b/app/helpers/language_links_helper.rb @@ -1,7 +1,7 @@ module LanguageLinksHelper def language_link_tag(language_plus_code) language = language_plus_code.split(':').first - code = language_plus_code.split(':').second + code = language_plus_code.split(':').second.strip! link_to_unless(@current_lang == code, language, "?translate=#{code}", lang: code, class: 'notranslate button-small') do |language_text| content_tag(:a, language_text, lang: code, class: 'translate-active button-small') diff --git a/app/views/component/search/_languages.html.haml b/app/views/component/search/_languages.html.haml index cd3baafef..d06c14ee5 100644 --- a/app/views/component/search/_languages.html.haml +++ b/app/views/component/search/_languages.html.haml @@ -1,5 +1,6 @@ -%section#language-box - %ul - - SETTINGS[:language_links].each do |language_plus_code| - %li - = language_link_tag language_plus_code +- if SETTINGS[:language_links].present? + %section#language-box + %ul + - SETTINGS[:language_links].each do |language_plus_code| + %li + = language_link_tag language_plus_code diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 96fc2d2f6..30f60a53e 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -1,6 +1,7 @@ - title '' %section#search-container - = render 'component/search/languages' + %section#search-top-utilities.search-utilities + = render 'component/search/languages' = render 'component/search/box' - %section#help-box + %section#search-bottom-utilities.search-utilities = render 'homepage_links' \ No newline at end of file diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 9085c116e..b57a732c4 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -18,15 +18,4 @@ -# This line needs to go ABOVE the Google Translate code, or it can take too long to load (see issue #462) = requirejs_include_tag("routes/#{controller_name}/#{action_name}").gsub("/assets/routes/#{controller_name}/#{action_name}", "routes/#{controller_name}/#{action_name}").html_safe - #google-translate-element - :javascript - function googleTranslateElementInit() { - new google.translate.TranslateElement( - { - pageLanguage: 'en', - autoDisplay: false - }, - 'google-translate-element' - ); - } - %script{ type: 'text/javascript', src: '//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit' } + #google-translate-container diff --git a/config/application.example.yml b/config/application.example.yml index 083b53601..a08695c58 100644 --- a/config/application.example.yml +++ b/config/application.example.yml @@ -58,8 +58,8 @@ DOMAIN_NAME: lvh.me # # # This code is generated by adding your site to your Google Account -# via the Google Website Translator Widget Wizard at -# https://translate.google.com/manager/website/suggestions +# via the Google Website Translator Gadget Wizard at +# https://translate.google.com/manager/website/ # and clicking "Get Code" when prompted. # GOOGLE_TRANSLATE_CUSTOMIZATION_CODE: Your_Website_Code_from_Google diff --git a/config/settings.example.yml b/config/settings.example.yml index 5833374a4..1686bbd7e 100644 --- a/config/settings.example.yml +++ b/config/settings.example.yml @@ -211,26 +211,27 @@ info_box_terms: ################################################################### # -# LANGUAGE LINKS SETTINGS +# LANGUAGE TRANSLATION LINKS SETTINGS # ################################################################### -# This represents the 6 most common languages in your community. +# This represents the most common languages in your community. # The languages will appear at the top of the home page, and # clicking on each language will translate the text on the entire # site into that language using Google Translate. -# The format should be 'Language:code', as shown below. +# The format should be 'Language: code', as shown below. # To see a list of all supported languages and codes, read the # "Language reference" section in the Google Translate documentation: -# https://developers.google.com/translate/v2/using_rest - +# https://developers.google.com/translate/v2/using_rest#language-params +# If you do not wish to include any language translation links, +# comment out or delete all of the language settings shown. language_links: - - 'English:en' - - 'Español:es' - - 'Tagalog:tl' - - '中文:zh-CN' - - 'العربية:ar' - - 'Русский:ru' + - 'English: en' + - 'Español: es' + - 'Tagalog: tl' + - '中文: zh-CN' + - 'العربية: ar' + - 'Русский: ru' ###################### # @@ -306,11 +307,11 @@ test: custom: component/info_box/example_custom_template language_links: - - 'English:en' - - 'Español:es' - - 'Tagalog:tl' - - '中文:zh-CN' - - 'العربية:ar' - - 'Русский:ru' + - 'English: en' + - 'Español: es' + - 'Tagalog: tl' + - '中文: zh-CN' + - 'العربية: ar' + - 'Русский: ru' site_title: Ohana Web Search diff --git a/config/settings.yml b/config/settings.yml index 5833374a4..1686bbd7e 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -211,26 +211,27 @@ info_box_terms: ################################################################### # -# LANGUAGE LINKS SETTINGS +# LANGUAGE TRANSLATION LINKS SETTINGS # ################################################################### -# This represents the 6 most common languages in your community. +# This represents the most common languages in your community. # The languages will appear at the top of the home page, and # clicking on each language will translate the text on the entire # site into that language using Google Translate. -# The format should be 'Language:code', as shown below. +# The format should be 'Language: code', as shown below. # To see a list of all supported languages and codes, read the # "Language reference" section in the Google Translate documentation: -# https://developers.google.com/translate/v2/using_rest - +# https://developers.google.com/translate/v2/using_rest#language-params +# If you do not wish to include any language translation links, +# comment out or delete all of the language settings shown. language_links: - - 'English:en' - - 'Español:es' - - 'Tagalog:tl' - - '中文:zh-CN' - - 'العربية:ar' - - 'Русский:ru' + - 'English: en' + - 'Español: es' + - 'Tagalog: tl' + - '中文: zh-CN' + - 'العربية: ar' + - 'Русский: ru' ###################### # @@ -306,11 +307,11 @@ test: custom: component/info_box/example_custom_template language_links: - - 'English:en' - - 'Español:es' - - 'Tagalog:tl' - - '中文:zh-CN' - - 'العربية:ar' - - 'Русский:ru' + - 'English: en' + - 'Español: es' + - 'Tagalog: tl' + - '中文: zh-CN' + - 'العربية: ar' + - 'Русский: ru' site_title: Ohana Web Search