Language switcher without plugin
Language switcher code for multilingual resource. This code can be inserted on any individual page, or on all pages of the site, in any convenient place.
Self-written code compares favorably with a plugin in that it does not contain the additional load that all plugins are overloaded with, since they are created for the versatile needs of users.
Some need a small switch, others need a large one, and still others need an auto-translator with an editor, an admin panel, and libraries, so the developers put everything in one box, and to a heap they also need an advertisement and a couple of links, etc., and so on, but free.
. blok text-align : center ;
width : 89px ;
>
. blok a text-decoration : none ;
display : block ;
transition : .5s linear ;
>
. blok ul list-style : none ;
margin : 0 ;
padding : 0 ;
>
. topmenu > li display : block ;
position : relative ;
top : 0 ;
left : 0 ;
margin-bottom : 2px ;
>
. submenu position : absolute ;
left : 0 ;
top : 0 ;
z-index : 5 ;
width : 89px ;
visibility : hidden ;
opacity : 0 ;
transform : translateY(10px) ;
transition : .5s ease-in-out ;
>
. submenu li position : relative ;
top : 0 ;
left : 0 ;
>
. submenu .submenu position : absolute ;
top : 0 ;
left : calc(100% — 1px) ;
left : -webkit-calc(100% — 1px) ;
>
. blok li:hover > .submenu visibility : visible ;
opacity : 1 ;
transform : translateY(0px) ;
>
As you can see — pure html + css.
In CMS themes, properties for lists are usually set (tags li, ul, ol), therefore, it may be necessary to enter classes in the li tags and set their positioning properties to these classes.
Pictures can, and even better, be cut in Paint right from here. You won’t find anything better in image services.
I wish you all fruitful work.
Creating an accessible language picker
In this article, we’ll go through the steps of creating a custom language picker and keeping it accessible.
By Claudia Romano Follow author on Twitter
We recently published the Language Picker component. It’s a common widget to find on a website but you need to keep a few things in mind during development if you want it to be accessible.
Let’s do this! #
The component we build in this tutorial is based on the CodyHouse framework.
👋 First time you hear about the CodyHouse Framework?
Let’s go through the steps of creating our custom language picker.
1. Initial HTML structure #
Our starting point will be a (with the list of all possible languages) and its element:
This is what users with JavaScript disabled will see; the form submission can be used to handle the language selection.
Note that each element has a lang attribute (that specifies the language of the text) and that we used the labels in their original language (for example, I’m Italian so I’m expecting to find ‘Italiano’ as an option, rather than ‘Italian’).
2. Custom Structure #
Using JavaScript, we can replace the default with a new structure. We’ll need:
- a which will be used as a trigger to open the language list;
- a dropdown element with the list of all available languages.
First, lets’ start by defining the HTML structure that we want to use for these elements.
For the element, we’ll have:
Let’s analyze the aria attributes we have added to this element:
- aria-label : this is a string that labels our button and it’s announced when the element is selected. It is composed of the selected language (e.g., ‘English’) and the text of the element (e.g., ‘Select your language’). You need this attribute as the may not have a visible text (for example, you just want to show a flag icon inside it).
- aria-expanded : by default, it is set to false (it tells you the language list is not expanded), but it will be changed to true when the language dropdown is visible.
- aria-controls : this attribute links the to the element it controls (language list). It is set equal to the id of the dropdown.
The element inside the button is used to create the flag icon and has an aria-hidden=»true» (it does not provide any additional info so we don’t want it to be announced by Screen Readers).
Let’s now take a look at the language list final HTML:
We have a .language-picker__dropdown element with an id equal to the aria-controls value of our .
We have added an aria-describedby equal to the id of the
element inside it. This will provide a description for the dropdown that will be announced by SR when the element is selected.
The
element inside the .language-picker__dropdown has a class of sr-only : this class (defined inside the Codyhouse Framework) can be used to visually hide an element, leaving it accessible to SR. You can read more about that on the accessibility global documentation page.
Inside the .language-picker__dropdown , we have an unordered list of languages with a role of listbox (this is a list of options which users can choose).
One important thing to add here is the lang attribute (defined for each element in the original HTML structure); this way SR will know how to pronounce the language label.
Finally, we have added an aria-selected=»true» to the selected language link.
Now that we have the final HTML structure, we can implement the JS code that will handle its creation.
First, we can define a LanguagePicker object:
var LanguagePicker = function(element) < this.element = element; this.select = this.element.getElementsByTagName('select')[0]; this.options = this.select.getElementsByTagName('option'); this.pickerId = this.select.getAttribute('id'); // .. initLanguagePicker(this); >; //initialize the LanguagePicker objects var languagePicker = document.getElementsByClassName('js-language-picker'); if( languagePicker.length > 0 ) < for( var i = 0; i < languagePicker.length; i++) < new LanguagePicker(languagePicker[i]); >>
The initLanguagePicker function can take care of creating the custom structure:
Now that the HTML structure is in place, we can style it:
.js .language-picker__form < // if JavaScript is enabled, hide the default form element display: none; >.language-picker__dropdown < position: absolute; left: 0; top: 100%; width: 200px; background-color: var(--color-bg); box-shadow: var(--shadow-sm); padding: var(--space-xxs) 0; border-radius: 0.25em; z-index: var(--zindex-popover); // hide the language list by default visibility: hidden; opacity: 0; transition: .2s ease-out; >.language-picker__button[aria-expanded="true"] + .language-picker__dropdown < // show the language list when the aria-expanded attribute of the button element is true visibility: visible; opacity: 1; transform: translateY(4px); >
3. Handling Events #
We still need to handle the click on the element that will toggle the dropdown visibility.
// click events picker.trigger.addEventListener('click', function()< toggleLanguagePicker(picker); >); function toggleLanguagePicker(picker, bool) < var ariaExpanded; if(bool) < ariaExpanded = bool; >else < ariaExpanded = picker.trigger.getAttribute('aria-expanded') == 'true' ? 'false' : 'true'; >picker.trigger.setAttribute('aria-expanded', ariaExpanded); if(ariaExpanded == 'true') < picker.dropdown.addEventListener('transitionend', function cb()< // once the dropdown is visible ->move focus from trigger to the first language in the list picker.firstLanguage.focus(); picker.dropdown.removeEventListener('transitionend', cb); >); > >;
When the button is clicked, we change the aria-expanded attribute of the (from false to true and vice-versa); this will update the dropdown visibility (check the CSS code at the end of step 2 for more info about the style).
When the dropdown is open (aria-expanded == true), we also move the focus from the to the first language in the list.
That’s pretty much all we had to do in JavaScript!
One last improvement (for keyboard navigation) would be to close the language list when pressing ‘Esc’:
// listen for key events window.addEventListener('keyup', function(event)< if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) < // close language picker on 'Esc' pickerArray.forEach(function(element)< moveFocusToTrigger(element); // if focus is still within the dropdown, move it to dropdown trigger toggleLanguagePicker(element, 'false'); // close dropdown >); > >);
Before using the toggleLanguagePicker function (that closes the dropdown), we use the moveFocusToTrigger function; this function checks if the focus is still within the dropdown element and, if it is, it moves it back to the button trigger:
function moveFocusToTrigger(picker) < if(picker.trigger.getAttribute('aria-expanded') == 'false') return; if(document.activeElement.closest('.language-picker__dropdown') == picker.dropdown) picker.trigger.focus(); >;
That’s it! You can find a preview (and the full code) on the Language Picker component demo page.
Cookie Compliance
We use cookies to give you the best possible website experience. By using CodyHouse, you agree to our Privacy Policy.
Локализация html-страницы средствами CSS
Люди по-разному относятся к CSS. Кто-то ворчит, что раньше и таблицы были зеленее, кто-то горячится, мол, дайте мне ваши таблицы, уж я их озеленю. Лично я довольно давно воспринимаю CSS-файлы как совего рода конфиги для внешнего вида веб-страницы. По сути ведь так и есть. У хорошего верстальщика HTML используется для того, чтобы создать структуру документа, у которой затем с помощью CSS настраивается внешнее отображение.
Обычно под внешним отображением понимаются всякие красоты вроде изображений, круглых уголков, градиентиков и прочей вебдванольности. Однако основным средством передачи информации в Интернете до сих пор является их величество текст. Текст применяется везде: и в навигации по сайту, и в основной информации.
Сейчас, когда космические сайты бороздят просторы мировой паутины, все чаще возникает потребность делать их многоязычными. Способов существует много. Под разные платформы, фреймворки и шаблонизаторы. Способ, который хочу предложить я, использует в качестве основы CSS.
Идея проста. Все верстальщики, работающие с CSS знают о таком свойстве как content:;, которое применяется к псевдоэлементам :after и :before. Чаще всего с помощью «волшебного» сочетания :after и content:; реализуют clear для «плавающих» блоков. Но вообще в content:; можно писать абсолютно любой текст. Без тегов, правда, но это разумное ограничение.
Как это можно использовать? Нужно создать два CSS-файла. Допустим, «en.css» и «ru.css». Основные стили блоков (цвета и прочие красивости) пусть определяются в файле «main.css».
/* Содержание файла «main.css» *//**/ .b-menu:after < content: ''; display: block; clear: both; >.b-menu__item
/* Содержание файла «en.css» *//**/ .b-menu__item_name_main .b-menu__curr:after, .b-menu__item_name_main .b-menu__link:after < content: 'Main Page'; >.b-menu__item_name_portfolio .b-menu__curr:after, .b-menu__item_name_portfolio .b-menu__link:after < content: 'Portfolio'; >.b-menu__item_name_team .b-menu__curr:after, .b-menu__item_name_team .b-menu__link:after < content: 'Team'; >.b-menu__item_name_contacts .b-menu__curr:after, .b-menu__item_name_contacts .b-menu__link:after
/* Содержание файла «ru.css» *//**/ .b-menu__item_name_main .b-menu__curr:after, .b-menu__item_name_main .b-menu__link:after < content: 'На главную'; >.b-menu__item_name_portfolio .b-menu__curr:after, .b-menu__item_name_portfolio .b-menu__link:after < content: 'Портфолио'; >.b-menu__item_name_team .b-menu__curr:after, .b-menu__item_name_team .b-menu__link:after < content: 'Команда'; >.b-menu__item_name_contacts .b-menu__curr:after, .b-menu__item_name_contacts .b-menu__link:after
Дальше нужно просто подключить файлы в таком порядке: main.css, en.css, ru.css. Ну, или сначала ru.css, а en.css — потом. В зависимости от того, какой язык является основным. В принципе, ничто не мешает CSS-свойства по умолчанию запихнуть в main.css, а подключать только файл языка, выбранного пользователем. Я разбил на два файла исключительно для наглядности.
+ Данный способ поддерживается всеми современными браузерами, включая IE восьмой и девятой версии, в том числе мобильными браузерами под iPhone и Android;
+ CSS-файл кешируется браузером, а это значит, что будучи скачанным однажды, он будет храниться у пользователя локально довольно долго (фактически пока с сервера не придет заголовок, сигнализирующий о необходимости обновить кеш);
+ Не нужно перегружать страницу, чтобы применить требуюемую локаль. Достаточно просто яваскриптом изменить href у тега . Или создать новый тег с нужным href.
Минусы (их, к сожалению, больше):
– ИЕ до восьмой версии не понимает свойство content:;, как и некоторые мобильные браузеры;
– Поисковые движки вряд ли проиндексируют тексты, записанные таким образом;
– Есть ряд ограничений к содержимого CSS-свойства content;
– Чтобы упорядочить названия классов для плейсхолдеров при более-менее сложном лэйауте, придется делать их довольно длинными (даже если не использовать BEM-названия);
– Невозможность сохранять длинные тексты с форматированием и изображениями.
На новизну идеи совершенно не претендую.