Warning: This page has not been updated in over over a year and may be outdated or deprecated.
videos:i18n
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revisionLast revisionBoth sides next revision | ||
videos:i18n [2021/10/22 14:39] – created demiankatz | videos:i18n [2021/10/22 19:00] – [Transcript] demiankatz | ||
---|---|---|---|
Line 3: | Line 3: | ||
The fourteenth VuFind® instructional video discusses VuFind®' | The fourteenth VuFind® instructional video discusses VuFind®' | ||
- | Video is available as an [[https:// | + | Video is available as an [[https:// |
===== Related Resources ===== | ===== Related Resources ===== | ||
Line 13: | Line 13: | ||
// This is a raw machine-generated transcript; it will be cleaned up as time permits. // | // This is a raw machine-generated transcript; it will be cleaned up as time permits. // | ||
- | :!: Coming soon. | + | for this month' |
+ | taking a deep dive into viewfinder' | ||
+ | internationalization system | ||
+ | we're going to start at the surface | ||
+ | talking about what it does and how you | ||
+ | can configure it | ||
+ | uh when we'll go a little bit deeper to | ||
+ | talk about how you can add additional | ||
+ | languages to the software | ||
+ | and then even deeper uh to talk about | ||
+ | how internationalization can be used uh | ||
+ | when you're developing on the software | ||
+ | adding new features or building local | ||
+ | customizations | ||
+ | i've tried to organize this content in | ||
+ | order by complexity so you can leave the | ||
+ | video whenever you think you've had | ||
+ | enough but you can keep going to get | ||
+ | deeper and deeper into the system | ||
+ | so viewfind is a piece of software | ||
+ | that's used throughout the world and of | ||
+ | course in different parts of the world | ||
+ | people speak different languages | ||
+ | so viewfinder needs a way to | ||
+ | present its interface in multiple | ||
+ | languages and that's where | ||
+ | internationalization comes into play | ||
+ | if you have a default viewfinder | ||
+ | installation you'll have this language | ||
+ | control at the top right as you can see | ||
+ | which shows many different languages | ||
+ | all rendered using their native | ||
+ | representations so people who speak the | ||
+ | language can instantly pick out | ||
+ | their native preference | ||
+ | and if you choose one of these | ||
+ | the whole interface | ||
+ | draws itself uh in the new language | ||
+ | all of this like everything else in | ||
+ | viewfind uh is highly configurable so | ||
+ | we're going to go into some of that | ||
+ | today | ||
+ | it also is useful even if you' | ||
+ | presenting your viewfinder in only one | ||
+ | language | ||
+ | because the internationalization system | ||
+ | provides a way to override a lot of the | ||
+ | text that viewfind uses | ||
+ | so if you need to customize specific | ||
+ | language in the interface you can often | ||
+ | do it uh just by changing one line of | ||
+ | text | ||
+ | making it a really easy way to customize | ||
+ | your viewfind experience we'll talk | ||
+ | about that too | ||
+ | so let's start by taking a look at some | ||
+ | configuration files i'm just bringing up | ||
+ | visual studio which is pointed at my | ||
+ | viewfinder home directory so i can | ||
+ | quickly navigate through the files | ||
+ | so if we look | ||
+ | at the config.ini | ||
+ | main configuration | ||
+ | there are a few settings that are of | ||
+ | interest | ||
+ | first of all fairly near the top | ||
+ | there are a few language related | ||
+ | settings there' | ||
+ | which by default is turned on at true | ||
+ | and this means that viewfind will try to | ||
+ | read | ||
+ | http headers sent by your web browser | ||
+ | to determine your native language and if | ||
+ | that language is supported by viewfind | ||
+ | it will turn it on by default | ||
+ | so if you have a viewfinder instance | ||
+ | that's used by many people speaking many | ||
+ | different languages | ||
+ | having this setting on just ensures that | ||
+ | they won't be inconvenienced by having | ||
+ | to switch the language manually | ||
+ | right below the detect language setting | ||
+ | is just language where you can set the | ||
+ | default language of your viewfind | ||
+ | installation | ||
+ | so this is the language that will be | ||
+ | turned on | ||
+ | uh if you either turn off the detect | ||
+ | language setting or if a user's browser | ||
+ | specifies a language that viewfind isn' | ||
+ | currently configured to support | ||
+ | so | ||
+ | you aren't necessarily forcing this | ||
+ | language but this is the one that will | ||
+ | be used | ||
+ | if nothing more specific is identified | ||
+ | i should also note that right under | ||
+ | language is the locale setting | ||
+ | and this indicates where your viewfind | ||
+ | instance is located and this is | ||
+ | completely independent of the language | ||
+ | setting | ||
+ | this is mainly used for things like | ||
+ | determining what type of currency is uh | ||
+ | displayed when | ||
+ | users look at their fines and so forth | ||
+ | so you want to set this to where you are | ||
+ | or where your library is | ||
+ | and it's independent of the language | ||
+ | setting because the language is | ||
+ | controlled by the end user | ||
+ | in any case there' | ||
+ | config.ini we should look at which is | ||
+ | further down | ||
+ | and this is just a section called | ||
+ | languages and this is a list of language | ||
+ | codes mapped to those language names in | ||
+ | english and we use english language | ||
+ | names in the configuration here | ||
+ | just for consistent readability | ||
+ | they get translated into their native | ||
+ | forms elsewhere and i'll show you that | ||
+ | later | ||
+ | but | ||
+ | the point is | ||
+ | this lists | ||
+ | all of the languages that viewfind | ||
+ | currently supports and they are all | ||
+ | turned on by default | ||
+ | the order of this list | ||
+ | also | ||
+ | controls the order of the language drop | ||
+ | down in the viewfind interface | ||
+ | so if your community is more likely to | ||
+ | speak a certain set of languages you | ||
+ | might want to move them to the top of | ||
+ | this list | ||
+ | and if there are languages here that are | ||
+ | very narrowly used and don't apply to | ||
+ | your audience you might want to turn | ||
+ | them off just to simplify the interface | ||
+ | you'll also notice that there are some | ||
+ | languages that are turned off by default | ||
+ | and these are regional variations so for | ||
+ | example uh you could switch english to | ||
+ | use british rather than american | ||
+ | spellings or you can turn on both | ||
+ | versions if you wanted to uh similarly | ||
+ | uh there' | ||
+ | dutch but that's turned off by by | ||
+ | default | ||
+ | we do offer both | ||
+ | portuguese and brazilian portuguese by | ||
+ | default so this is something you might | ||
+ | even want to consider turning off if | ||
+ | that's not relevant to your users | ||
+ | while we're in the configuration files | ||
+ | uh there' | ||
+ | would like to show you which is uh in | ||
+ | facets.ini the facet configuration | ||
+ | uh in the advanced section | ||
+ | the advanced settings more specifically | ||
+ | uh there' | ||
+ | facets | ||
+ | and this tells viewfind when it's | ||
+ | displaying facet lists | ||
+ | uh which facet fields should be run | ||
+ | through the translation system and | ||
+ | potentially translated | ||
+ | as you can see by default we're only | ||
+ | translating the format names uh and the | ||
+ | high level library of congress call | ||
+ | numbers | ||
+ | uh in the future we may add more | ||
+ | translated fields but of course it's a | ||
+ | lot of work to translate all possible | ||
+ | values in a facet | ||
+ | so we only add those as time permits | ||
+ | that work to be done | ||
+ | and this is certainly something members | ||
+ | of the community could contribute back | ||
+ | if it's important to them | ||
+ | for example there' | ||
+ | project to translate language names into | ||
+ | all supported languages | ||
+ | which i'd love to see completed but it | ||
+ | just hasn't been done yet because it's a | ||
+ | lot of work but it is certainly | ||
+ | technically possible within this system | ||
+ | uh one little detail i will highlight | ||
+ | is that when translating a facet | ||
+ | you can specify | ||
+ | either that it comes from the main | ||
+ | language file by | ||
+ | specifying the name of the field by | ||
+ | itself | ||
+ | or you can follow the field name with a | ||
+ | colon and a name of a text domain | ||
+ | containing relevant translations | ||
+ | text domains are a way of organizing our | ||
+ | translations and i will show these to | ||
+ | you in more detail in just a moment | ||
+ | so now that i've showed you how to | ||
+ | configure internationalization both in | ||
+ | terms of what languages are provided and | ||
+ | also in terms of what facet fields can | ||
+ | get translated | ||
+ | let me show you how the translations are | ||
+ | actually organized within viewfind | ||
+ | uh inside your viewfinder home directory | ||
+ | you'll find a languages subdirectory | ||
+ | that contains many many uh any files | ||
+ | and as you can see | ||
+ | most of these use the two letter or two | ||
+ | letter and regional subdivision codes | ||
+ | the same ones that are found in the | ||
+ | config.ini file | ||
+ | this is of course how we organize each | ||
+ | language' | ||
+ | file | ||
+ | there' | ||
+ | native.ini file | ||
+ | and as i mentioned this is | ||
+ | how we translate the english language | ||
+ | names from the configuration file into | ||
+ | their | ||
+ | native forms for display in the drop | ||
+ | down it's the one special exception | ||
+ | within this directory where otherwise | ||
+ | every file name corresponds to a code | ||
+ | so let's look at one of the | ||
+ | actual language files en.ini where all | ||
+ | of the english | ||
+ | codes are found | ||
+ | the any files containing viewfinds | ||
+ | language | ||
+ | translations use a subset of the broader | ||
+ | any file standard | ||
+ | they support semicolons for comments | ||
+ | um and beyond that everything is in the | ||
+ | format of a translation key an equal | ||
+ | sign and then the translation | ||
+ | in double quotes | ||
+ | viewfinds language files are | ||
+ | standardized to always use this format | ||
+ | every string is always in double quotes | ||
+ | and the keys are always sorted | ||
+ | alphabetically | ||
+ | just for consistency and to make it | ||
+ | easier to find things | ||
+ | if you scroll through you'll notice that | ||
+ | some of the translation strings include | ||
+ | placeholder values | ||
+ | of the format percent percent some name | ||
+ | percent percent | ||
+ | these placeholder tokens are used uh in | ||
+ | cases where a translation needs to have | ||
+ | a value inserted into it at a particular | ||
+ | position | ||
+ | and using these tokens is really | ||
+ | important for translation because if | ||
+ | you're assembling a sentence | ||
+ | different languages have different | ||
+ | grammars and so the word order may be | ||
+ | different | ||
+ | so by using a token | ||
+ | this makes it possible for translators | ||
+ | to always put the changeable parts of a | ||
+ | phrase in the correct position | ||
+ | while it's being translated | ||
+ | you'll also notice that some of the | ||
+ | translation keys end | ||
+ | in underscore html | ||
+ | uh this indicates that | ||
+ | the | ||
+ | translation string itself | ||
+ | may include some html | ||
+ | and when it is being displayed in the | ||
+ | viewfind interface it should not be | ||
+ | escaped | ||
+ | because we want to actually render the | ||
+ | html for the end user rather than | ||
+ | display the literal less than em greater | ||
+ | than in this particular example | ||
+ | uh most of the other keys that do not | ||
+ | have the html suffix on them are going | ||
+ | to be assumed to be plain text with no | ||
+ | html | ||
+ | and when they get rendered they will | ||
+ | have any special characters escaped to | ||
+ | ensure that they display | ||
+ | to the end user exactly as they are | ||
+ | written in the translation file with no | ||
+ | characters being interpreted as html | ||
+ | you'll also notice that there' | ||
+ | a mix in here of actual uh english | ||
+ | phrases being used as keys | ||
+ | and more abstract tokens being used as | ||
+ | keys | ||
+ | this is sort of a side effect of | ||
+ | viewfinder | ||
+ | code evolving over time when viewfind | ||
+ | was first written | ||
+ | everything was just an english key | ||
+ | but | ||
+ | it pretty quickly became apparent that | ||
+ | it was sometimes more useful to use a | ||
+ | more abstract name for a translation | ||
+ | this is particularly critical when the | ||
+ | same english word | ||
+ | might have | ||
+ | different words | ||
+ | for different meanings in another | ||
+ | language | ||
+ | so we started using keys that | ||
+ | offer more context about how the | ||
+ | translation is used so that even if the | ||
+ | text is identical for two different | ||
+ | things in english | ||
+ | it's possible for a translation to use | ||
+ | different phrases for each context in | ||
+ | which the words are used | ||
+ | if that happens to be necessary | ||
+ | you'll also notice that there are some | ||
+ | subdirectories under the languages | ||
+ | directory | ||
+ | uh and these contain more any files | ||
+ | these are the text domains that i | ||
+ | mentioned earlier | ||
+ | um | ||
+ | if you have a specific set of related | ||
+ | translations | ||
+ | rather than putting them in the top | ||
+ | level language file which is already | ||
+ | very long and contains a lot of | ||
+ | different things | ||
+ | you could instead decide that they | ||
+ | belong in a text domain which is just in | ||
+ | any file in a named subdirectory so for | ||
+ | example when i showed you the facet | ||
+ | translations earlier | ||
+ | i showed that | ||
+ | the call number first field had its own | ||
+ | text domain | ||
+ | so if we look uh in these files you' | ||
+ | see that all of the top level library of | ||
+ | congress | ||
+ | classifications | ||
+ | are translated in these files | ||
+ | in some cases complete translations | ||
+ | haven' | ||
+ | but the point is | ||
+ | uh this way we can | ||
+ | sort out | ||
+ | our translations into a more logical | ||
+ | arrangement it becomes easier to find | ||
+ | things and easier to read things | ||
+ | again there are still many things in the | ||
+ | top level translation | ||
+ | files that would probably better belong | ||
+ | in a separate text domain | ||
+ | but because text domains were introduced | ||
+ | to viewfind later in its development | ||
+ | not everything has been refactored yet | ||
+ | so over time you may start to see more | ||
+ | text domains and shorter top level | ||
+ | language files | ||
+ | but for now | ||
+ | we are just | ||
+ | refactoring as time permits and | ||
+ | circumstances allow | ||
+ | the language files are really useful for | ||
+ | translating short phrases and words | ||
+ | to build larger interfaces | ||
+ | but there are also some other | ||
+ | translation facilities in viewfind for | ||
+ | situations where you have a huge block | ||
+ | of text that perhaps would not be | ||
+ | appropriate to include as a line in a | ||
+ | language file | ||
+ | one of the most obvious examples of this | ||
+ | is view finds help pages | ||
+ | if i | ||
+ | go over here | ||
+ | there are a few different search screens | ||
+ | in viewfind like the search tips page | ||
+ | which pops up here | ||
+ | that have a whole lot of text in them | ||
+ | but which we want to be able to provide | ||
+ | to users in multiple languages | ||
+ | so you know for example here if i | ||
+ | uh | ||
+ | switch this to spanish | ||
+ | and pop open the search tips i get that | ||
+ | whole page | ||
+ | in spanish | ||
+ | but if i had to break that down into a | ||
+ | separate translation for every sentence | ||
+ | in the file that would be uh | ||
+ | unreasonably tedious so instead for help | ||
+ | screens we have a template based system | ||
+ | if you go into the themes you will find | ||
+ | in the root theme where our widely | ||
+ | shared content lives | ||
+ | under the templates directory | ||
+ | there is a help translations folder | ||
+ | and in here as you can see there are | ||
+ | folders that correspond to language | ||
+ | codes | ||
+ | and not every help screen has been | ||
+ | translated into every language yet | ||
+ | but where they have been you'll find | ||
+ | that there are templates | ||
+ | with parallel names so for example | ||
+ | you know here in english is search phtml | ||
+ | which has the html | ||
+ | template for search tips | ||
+ | and under es | ||
+ | for espanol | ||
+ | we have the spanish version of the same | ||
+ | file | ||
+ | so for help screens uh viewfind just has | ||
+ | some code that looks at the user' | ||
+ | current language | ||
+ | checks to see | ||
+ | if | ||
+ | a help template exists in that language | ||
+ | uh and displays it if it's available | ||
+ | if a translation is not available the | ||
+ | help system will just display the | ||
+ | english template with a warning message | ||
+ | apologizing that a translation is not | ||
+ | available | ||
+ | this is another area of course where | ||
+ | members of the community could | ||
+ | contribute by translating more of the | ||
+ | help screens into more languages | ||
+ | one final thing which i will briefly | ||
+ | mention and we'll show in more detail in | ||
+ | a future video when we talk about | ||
+ | managing static content in viewfind | ||
+ | there are a few different ways that | ||
+ | viewfind can display static pages of | ||
+ | content | ||
+ | if you want to use it as a lightweight | ||
+ | content management system for example if | ||
+ | you want to build | ||
+ | local pages with frequently asked | ||
+ | questions or information about your | ||
+ | library | ||
+ | all of these also have template-based | ||
+ | mechanisms for providing translations | ||
+ | just as a | ||
+ | quick example | ||
+ | let me switch into the bootstrap three | ||
+ | theme | ||
+ | go into templates | ||
+ | and in here there is a folder called | ||
+ | content | ||
+ | and as you can see uh there are a few | ||
+ | different uh example | ||
+ | content templates here | ||
+ | all of these are really designed to be | ||
+ | overridden locally so you know for | ||
+ | example the frequently asked questions | ||
+ | page is very short | ||
+ | um | ||
+ | the ask a librarian page just says | ||
+ | this is the default page | ||
+ | this isn't meant to be used in | ||
+ | production | ||
+ | but what i want to show here uh relating | ||
+ | to internationalization is that | ||
+ | all of these content pages have a fixed | ||
+ | name | ||
+ | but if you put an underscore and | ||
+ | language code after that you can create | ||
+ | an english specific version of the page | ||
+ | that will be used when that language is | ||
+ | selected | ||
+ | so for example | ||
+ | you know you can see ask a librarian has | ||
+ | a default page and an english page | ||
+ | so if i go | ||
+ | back to english | ||
+ | and click on ask a librarian to view | ||
+ | this | ||
+ | it says this is the english ask a | ||
+ | librarian page | ||
+ | so now that i've showed you | ||
+ | where all of the language files are | ||
+ | located uh and how they work | ||
+ | let me do a quick demo of how you can | ||
+ | easily override some language strings to | ||
+ | customize something uh in your your | ||
+ | local instance of viewfinder | ||
+ | so suppose | ||
+ | i don't like the message that is | ||
+ | displayed | ||
+ | when i perform a search and don't get | ||
+ | any results so right now it says your | ||
+ | search | ||
+ | no results did not match any resources | ||
+ | but say i want to change that language | ||
+ | the first thing i need to do is figure | ||
+ | out what language string | ||
+ | is actually causing this message to | ||
+ | appear the easiest way to do that is to | ||
+ | go into the main language file and | ||
+ | search for uh a phrase | ||
+ | that matches this the string i want to | ||
+ | change and of course if i don't find it | ||
+ | in the main file i can search in all of | ||
+ | the text domains as well but most things | ||
+ | you see in the viewfind interface are | ||
+ | going to come from the main translation | ||
+ | file | ||
+ | so | ||
+ | let me go back to | ||
+ | visual studio here | ||
+ | and look in the english language file | ||
+ | i'm just going to search for any | ||
+ | resources because | ||
+ | that's a fairly distinctive part of the | ||
+ | string i want to override | ||
+ | and sure enough i find that | ||
+ | there is a string here called | ||
+ | no hit look for html | ||
+ | so this is the string i can customize if | ||
+ | i want to change | ||
+ | this particular message in the user | ||
+ | interface | ||
+ | like many things in viewfind | ||
+ | uh you can create files in your local | ||
+ | settings directory to override uh | ||
+ | settings from the core | ||
+ | languages are no exception so | ||
+ | if i go to my local directory | ||
+ | and i create a folder called languages | ||
+ | and inside that folder i create a file | ||
+ | called | ||
+ | en.ini | ||
+ | i can customize english language strings | ||
+ | here | ||
+ | and override the defaults | ||
+ | a nice thing about the language file | ||
+ | overwriting is that you don't have to | ||
+ | copy the whole language | ||
+ | file from the core you can override only | ||
+ | the strings that you want to change here | ||
+ | and they' | ||
+ | with the defaults from the core | ||
+ | so | ||
+ | suppose i want this to instead say | ||
+ | sorry we could not find any matches for | ||
+ | your search | ||
+ | i just edit the string here in my local | ||
+ | language file | ||
+ | but there' | ||
+ | we need to remember | ||
+ | and this is | ||
+ | uh because the the language translations | ||
+ | are distributed across a number of files | ||
+ | a viewfinder maintains a cache of | ||
+ | language strings | ||
+ | so that it doesn' | ||
+ | of time gathering things together every | ||
+ | time it renders a page so if you change | ||
+ | a language file | ||
+ | you also need to remember to empty out | ||
+ | the language cache so that your changes | ||
+ | will immediately take effect | ||
+ | i can do this by going to my view find | ||
+ | home directory | ||
+ | and then simply running sudo rm minus rf | ||
+ | local slash cache languages | ||
+ | and that will clean out my cache and now | ||
+ | uh if i refresh | ||
+ | my page | ||
+ | over here | ||
+ | sure enough my custom translation has | ||
+ | kicked in and it says sorry we could not | ||
+ | find any matches for no results | ||
+ | so customizing any piece of text in | ||
+ | viewfind is that easy | ||
+ | and of course if you need to customize | ||
+ | the text in multiple languages you just | ||
+ | need to create multiple language files | ||
+ | uh inside your local languages directory | ||
+ | so now that we've talked about how to | ||
+ | use the language system and how to | ||
+ | customize uh what is displayed let's go | ||
+ | a little bit deeper and talk about how | ||
+ | you can add additional languages | ||
+ | uh to viewfind | ||
+ | you can probably guess that it's really | ||
+ | just a matter of creating some new files | ||
+ | um | ||
+ | you just need to figure out | ||
+ | what the language code is for your new | ||
+ | language | ||
+ | uh then you can take one of the existing | ||
+ | language files uh rename it to match the | ||
+ | code of the new language and translate | ||
+ | all the strings within it | ||
+ | you of course have to repeat that | ||
+ | process for all of the text domains if | ||
+ | you want your | ||
+ | translation to be comprehensive | ||
+ | uh you also need to add the new language | ||
+ | to config.ini in the languages section | ||
+ | so that it's | ||
+ | included in the list of available | ||
+ | languages | ||
+ | and you want to uh make sure that | ||
+ | there' | ||
+ | so that we can represent the language | ||
+ | name in english in config.ini for | ||
+ | consistency with the language within | ||
+ | that file but we can also represent the | ||
+ | language uh in its native form uh in the | ||
+ | user interface | ||
+ | so | ||
+ | it's really just | ||
+ | those few steps the hard part of course | ||
+ | is doing the actual translation work and | ||
+ | of course if anybody does want to add a | ||
+ | new language to viewfinder has any | ||
+ | questions about the context of | ||
+ | particular strings or needs any help | ||
+ | please feel free to reach out to me or | ||
+ | to the community at large | ||
+ | and you'll get some assistance | ||
+ | because we're always pleased to expand | ||
+ | the reach of ufind by adding more | ||
+ | languages | ||
+ | but outside of that | ||
+ | general process for creating languages i | ||
+ | also wanted to highlight | ||
+ | one useful tool that viewfind includes | ||
+ | that's helpful while managing languages | ||
+ | which i use every time a new viewfinder | ||
+ | release is being planned and we need to | ||
+ | update | ||
+ | all of the translations | ||
+ | viewfind actually includes several tools | ||
+ | within it that are geared toward | ||
+ | developers | ||
+ | and as such these tools are only | ||
+ | available when viewfinder is switched | ||
+ | into development mode | ||
+ | i showed this in a past video but just | ||
+ | as a reminder | ||
+ | if you go to your apache configuration | ||
+ | in the local directory httpd | ||
+ | viewfinder.conf | ||
+ | there is a line in there | ||
+ | which sets development mode and right | ||
+ | now in the demo instance i'm teaching | ||
+ | with | ||
+ | development mode is already turned on | ||
+ | but if this were not already turned on | ||
+ | you would have to make sure that any | ||
+ | comment marker in front of it was | ||
+ | removed | ||
+ | and after making that change you would | ||
+ | need to restart apache uh to make the | ||
+ | change take effect | ||
+ | uh if | ||
+ | this were setting were not in place you | ||
+ | would not be able to see the developers | ||
+ | tools | ||
+ | but since in my case it is already | ||
+ | turned on i can just go ahead and show | ||
+ | you | ||
+ | that if you go to | ||
+ | viewfind slash devtools | ||
+ | you will see a page | ||
+ | summarizing the available development | ||
+ | tools and one of these is language | ||
+ | details | ||
+ | if you look at the language details page | ||
+ | you will see a list | ||
+ | of all of the languages currently | ||
+ | supported by vuefind | ||
+ | and all of these are getting compared | ||
+ | against the english | ||
+ | language file | ||
+ | to show you where there are gaps | ||
+ | because while we try to keep all of our | ||
+ | translations up to date | ||
+ | not all of our volunteer translators are | ||
+ | always available | ||
+ | so some languages have more complete | ||
+ | translations than others | ||
+ | and this tool allows you to find out | ||
+ | what strings are missing so for example | ||
+ | uh if i wanted to see | ||
+ | uh which lines still need to be | ||
+ | translated into welsh i could click show | ||
+ | here | ||
+ | and i get a pop-up summarizing all of | ||
+ | the english lines that still need | ||
+ | translation | ||
+ | if you click on this it automatically | ||
+ | highlights the whole thing for you so | ||
+ | it's easy to copy and paste | ||
+ | and this is the process i follow when i | ||
+ | request new translations for every | ||
+ | release i go through here copy and paste | ||
+ | all the lists of missing lines and email | ||
+ | them to the volunteer translators who | ||
+ | then send them back to me for | ||
+ | incorporation into the project | ||
+ | this extra lines | ||
+ | column is also useful because if you | ||
+ | accidentally create a translation in | ||
+ | another language file that doesn' | ||
+ | in english | ||
+ | it will be highlighted here | ||
+ | and sometimes this can catch minor | ||
+ | typographical errors or formatting | ||
+ | problems because they' | ||
+ | be interpreted as | ||
+ | inappropriate lines in the file this | ||
+ | will help you track them down and fix | ||
+ | them | ||
+ | you can also see this extra help files | ||
+ | column | ||
+ | gives you a count of how many files | ||
+ | exist uh in that help template directory | ||
+ | i showed you for each language | ||
+ | so as you can see there are some | ||
+ | opportunities to fill gaps here | ||
+ | if anybody cares to do so | ||
+ | also note that there' | ||
+ | recent work to improve the look and feel | ||
+ | of this screen so by the time you' | ||
+ | watching this video uh it may actually | ||
+ | look a little bit different | ||
+ | but the functionality will remain the | ||
+ | same | ||
+ | uh now that i've showed you | ||
+ | where to create files to add a new | ||
+ | language and how to manage languages | ||
+ | through this development tool i'd also | ||
+ | like to highlight a few useful command | ||
+ | line tools that you can use for managing | ||
+ | the language files | ||
+ | and these are mainly used during | ||
+ | development of the core project they' | ||
+ | less useful for local customizations so | ||
+ | you would find yourself using these uh | ||
+ | primarily if you're adding new features | ||
+ | to the viewfinder core and those | ||
+ | features introduce | ||
+ | new language strings | ||
+ | so i'm going to pop to the command line | ||
+ | here | ||
+ | and just a reminder you can always get a | ||
+ | summary of all of viewfind' | ||
+ | line capabilities by just running the | ||
+ | index.php file in the public directory | ||
+ | through php | ||
+ | so | ||
+ | this gives me a summary of many commands | ||
+ | and you'll notice that there are a few | ||
+ | language specific ones | ||
+ | whose names all start with language | ||
+ | so there is language add using template | ||
+ | this uh provides a mechanism for | ||
+ | creating new language strings by | ||
+ | combining existing ones | ||
+ | and i will actually do a demo of this | ||
+ | a little bit later so it will become | ||
+ | more clear then | ||
+ | there is a copy string | ||
+ | command which simply copies one string | ||
+ | in all of the language files to another | ||
+ | string | ||
+ | this could be useful uh if you want to | ||
+ | differentiate something so | ||
+ | suppose you have a text string that' | ||
+ | being used in two places | ||
+ | but you decide that maybe you want to | ||
+ | refine the language in one of those two | ||
+ | places to be more specific | ||
+ | you could use copy string to create two | ||
+ | different identical strings in all of | ||
+ | the language files | ||
+ | and then you could customize them where | ||
+ | appropriate | ||
+ | this way you can add a new string | ||
+ | without creating gaps in the translation | ||
+ | but you still provide the opportunity to | ||
+ | customize more specifically as needed | ||
+ | there' | ||
+ | fairly self-explanatory it removes a | ||
+ | particular translation key from all of | ||
+ | the language files uh this can be useful | ||
+ | uh if something becomes obsolete | ||
+ | again i'll demonstrate this for you in a | ||
+ | moment | ||
+ | and finally there is language normalize | ||
+ | the language file normalizer | ||
+ | for this one | ||
+ | you give it the name of a directory | ||
+ | containing any files and it will format | ||
+ | all of them to meet a viewfind' | ||
+ | language file standards as i mentioned | ||
+ | earlier | ||
+ | it alphabetizes everything by key and it | ||
+ | puts all of the text | ||
+ | to the right of the equal sign into | ||
+ | double quotes | ||
+ | it's just a nice way to be sure that | ||
+ | everything is neatly formatted | ||
+ | and if you're submitting new language | ||
+ | strings to viewfind | ||
+ | our continuous integration process which | ||
+ | looks at submissions and checks their | ||
+ | validity will double check that all of | ||
+ | your language files are normalized | ||
+ | correctly so running this tool can just | ||
+ | help prevent some bumps during the | ||
+ | contribution process | ||
+ | so with | ||
+ | all of that introduced let's uh | ||
+ | dive into a hands-on example of using | ||
+ | these command line tools | ||
+ | and i'm actually going to use this to | ||
+ | create a real change to the viewfind | ||
+ | code that i think will be useful | ||
+ | which i'll submit as a pull request | ||
+ | following this call | ||
+ | so if i go to | ||
+ | the home page of view find | ||
+ | by default i see all of these browse by | ||
+ | headings | ||
+ | for the the different facets that we | ||
+ | display on the home page | ||
+ | and i happen to notice | ||
+ | that this isn' | ||
+ | formatted in the best possible way | ||
+ | let me show you what i mean | ||
+ | if i go into the english language file | ||
+ | and i search for | ||
+ | browse by | ||
+ | i have this uh | ||
+ | home browse key which just translates to | ||
+ | browse by so what this means and | ||
+ | actually i can show you this in a moment | ||
+ | is that we are just concatenating a | ||
+ | facet name onto a translation to create | ||
+ | those headings | ||
+ | and as i mentioned that may not be | ||
+ | appropriate in every language because | ||
+ | perhaps in some other language the | ||
+ | grammar specifies that the facet name | ||
+ | should be before the string or even in | ||
+ | the middle of the string | ||
+ | this is a situation where we really | ||
+ | should be using a placeholder token | ||
+ | instead of combining strings together | ||
+ | and i'm sure the reason this is the way | ||
+ | it is is that this browse by string was | ||
+ | added to viewfind in its early days | ||
+ | before we improved our practices | ||
+ | so this seems like a perfect opportunity | ||
+ | to improve that little detail | ||
+ | and demonstrate | ||
+ | uh all of the processes around it | ||
+ | along the way | ||
+ | so if we're going to change a string in | ||
+ | the language files the first thing we | ||
+ | need to do | ||
+ | is figure out where it is being used | ||
+ | uh i like to use the grep command to do | ||
+ | this it's a | ||
+ | standard unix command line tool for | ||
+ | finding things in files | ||
+ | so let me just do that i'll go to the | ||
+ | command line | ||
+ | i'm going to go into the themes | ||
+ | directory because i think in this | ||
+ | instance it's safe to assume that this | ||
+ | text is only being used in templates | ||
+ | it's probably not found in any of our | ||
+ | controller or service logic | ||
+ | and then i'm just going to say grep | ||
+ | minus r home browse star | ||
+ | so | ||
+ | grep minus r | ||
+ | means recursively search through all the | ||
+ | subdirectories of the current directory | ||
+ | look for the phrase home browse and star | ||
+ | just means look in every file | ||
+ | so | ||
+ | grep is telling us here that home browse | ||
+ | is only found in one file | ||
+ | but within that file | ||
+ | it's actually used in three places so | ||
+ | let me open up this file templates | ||
+ | content block facet list | ||
+ | html | ||
+ | content block | ||
+ | facetlist.phtml | ||
+ | so there are a few different conditions | ||
+ | in this file that cause the headings to | ||
+ | be generated | ||
+ | in different contexts but | ||
+ | in all three uh situations it's doing | ||
+ | exactly the same thing and as i said | ||
+ | before it's first translating the home | ||
+ | browse text then it's adding a space to | ||
+ | it | ||
+ | and then | ||
+ | uh it is displaying the label | ||
+ | but this is not as flexible as we would | ||
+ | like | ||
+ | so let's change this | ||
+ | so that uh it instead | ||
+ | uses a token in the appropriate position | ||
+ | and this is a perfect use case | ||
+ | for | ||
+ | the add using template command line tool | ||
+ | for | ||
+ | managing language files | ||
+ | so i'm moving back to my viewfind home | ||
+ | directory and then i'm just going to | ||
+ | show you | ||
+ | you can run php public slash index.php | ||
+ | add using template minus minus help to | ||
+ | get help on uh how to use this | ||
+ | particular command | ||
+ | in this instance | ||
+ | the help screen shows us that the first | ||
+ | parameter is the name of the new | ||
+ | key that we want to create | ||
+ | and the second is a template showing it | ||
+ | how to build that string | ||
+ | and this uses | ||
+ | a double piped placeholders to embed | ||
+ | existing translation strings | ||
+ | so this will become more clear as i show | ||
+ | the example | ||
+ | so right now | ||
+ | we have an existing translation string | ||
+ | called home | ||
+ | and | ||
+ | we need to create a new one | ||
+ | because this tool creates a new key it | ||
+ | doesn' | ||
+ | but let's take this opportunity to use a | ||
+ | more specific | ||
+ | key name anyway | ||
+ | so let' | ||
+ | call this | ||
+ | home browse by facet | ||
+ | and then we're going to create the | ||
+ | template | ||
+ | to match the current behavior | ||
+ | so i'm going to use double quotes to | ||
+ | surround my template because it will | ||
+ | have spaces in it | ||
+ | and i want it to be treated as a single | ||
+ | piece of text when it gets passed in | ||
+ | as a command line parameter to my tool | ||
+ | so i'm going to double pipe home browse | ||
+ | so this is going to take the existing | ||
+ | translation of the home browse key and | ||
+ | put it into my new home browse by facet | ||
+ | key | ||
+ | then i'm going to add a space | ||
+ | and i'm just going to create a token | ||
+ | called percent percent facet percent | ||
+ | percent and then i'm going to end | ||
+ | my double quoted phrase for the template | ||
+ | so what this is going to do is it's | ||
+ | going to go through every single | ||
+ | language file | ||
+ | it's going to create a new home browse | ||
+ | by facet translation which will be | ||
+ | the existing home browse translation | ||
+ | followed by a space and followed by this | ||
+ | percent percent facet percent percent | ||
+ | token | ||
+ | of course this may not be optimal in | ||
+ | every language but this is going to | ||
+ | match the current behavior uh and it's | ||
+ | at least going to give us the | ||
+ | possibility of improving this in the | ||
+ | future whereas as currently implemented | ||
+ | there' | ||
+ | order of this display | ||
+ | so when i run it it runs through all of | ||
+ | my language files | ||
+ | you'll notice that it skips a couple of | ||
+ | files because they don't contain a home | ||
+ | browse key and thus | ||
+ | uh cannot | ||
+ | translate it | ||
+ | and these files that got skipped are the | ||
+ | regional translations | ||
+ | so the | ||
+ | the british english and the flemish | ||
+ | dutch | ||
+ | and these don't contain this particular | ||
+ | key | ||
+ | because they only contain text that | ||
+ | provides a regional variation and in | ||
+ | both of these instances there' | ||
+ | difference between regions for this | ||
+ | particular piece of text | ||
+ | in any case i've now edited a whole | ||
+ | bunch of files | ||
+ | so if i do a git diff | ||
+ | it will show me uh what has been added | ||
+ | and as you can see it's just | ||
+ | taken the existing home browse | ||
+ | translation and added | ||
+ | uh facet on the end of it | ||
+ | which is exactly what we wanted | ||
+ | uh but now um | ||
+ | our intent is to replace the home browse | ||
+ | with home browse by facet so this is an | ||
+ | opportunity to also use | ||
+ | the language delete command | ||
+ | now that we've moved home browse we can | ||
+ | get rid of it | ||
+ | and so that works just the same we say | ||
+ | you know php public index language | ||
+ | delete the name of the key to delete | ||
+ | it runs through all the files and | ||
+ | deletes it it reports | ||
+ | files that don't contain the key | ||
+ | so if i do a git diff now | ||
+ | we can see that it has removed home | ||
+ | browse but it's still adding home browse | ||
+ | by facet | ||
+ | so now that we've created the home | ||
+ | browse by facet | ||
+ | we need to actually use it | ||
+ | this is a great opportunity to | ||
+ | demonstrate | ||
+ | uh | ||
+ | viewfinds | ||
+ | translation view helpers | ||
+ | which are used throughout | ||
+ | the | ||
+ | uh | ||
+ | language fi uh throughout the themes in | ||
+ | the templates | ||
+ | there are two of them | ||
+ | uh one is called this translate and one | ||
+ | is called this transesque | ||
+ | and they both work exactly the same way | ||
+ | except trans-esque | ||
+ | html escapes the translation when it's | ||
+ | done running whereas translate leaves | ||
+ | the text raw | ||
+ | so | ||
+ | the the escaping helper is used in most | ||
+ | places but the translate helper is used | ||
+ | if we need to render html which is why | ||
+ | we have that html suffix to indicate uh | ||
+ | templates that contain html | ||
+ | or it's used in context where we're not | ||
+ | generating html for example if we' | ||
+ | building the body of a text email | ||
+ | so let' | ||
+ | refactor this code a little bit to make | ||
+ | it easier to modify so since we have | ||
+ | identical logic in three different | ||
+ | places i think it will be cleaner | ||
+ | if we just uh | ||
+ | take this whole bit of logic and we | ||
+ | create a variable | ||
+ | called | ||
+ | label heading | ||
+ | so then we can do the calculation in one | ||
+ | place in the code | ||
+ | and display it | ||
+ | three times over | ||
+ | so i'm just going to put some php logic | ||
+ | right here | ||
+ | that says uh | ||
+ | sorry label heading | ||
+ | equals | ||
+ | and that's the current logic which we | ||
+ | will change in a moment | ||
+ | i'm just going to uh | ||
+ | finish refactoring this everywhere | ||
+ | i know there are three of these where' | ||
+ | the third one | ||
+ | two three okay | ||
+ | so now we have one piece of code that' | ||
+ | generating the label heading | ||
+ | and we're using that value in three | ||
+ | different places but we now have a token | ||
+ | so | ||
+ | instead of concatenating this stuff | ||
+ | together | ||
+ | uh and just to refresh memory on that | ||
+ | what we used to be doing was translating | ||
+ | the home browse key then adding a space | ||
+ | then translating the name of the facet | ||
+ | field being displayed | ||
+ | let's be smarter about this | ||
+ | and instead | ||
+ | let's translate | ||
+ | home | ||
+ | browse by facet | ||
+ | and the | ||
+ | both of the translate view helpers | ||
+ | accept a second parameter which is | ||
+ | optional | ||
+ | and contains an array | ||
+ | of tokens | ||
+ | to | ||
+ | values so in this case we created a | ||
+ | token called a percent percent facet | ||
+ | and we want that | ||
+ | to instead | ||
+ | [Music] | ||
+ | be the name of that facet | ||
+ | so | ||
+ | i'm going to take away | ||
+ | the concatenation and instead | ||
+ | plug this value right into this array | ||
+ | but there' | ||
+ | this instance | ||
+ | which is that here we're translating and | ||
+ | escaping the label | ||
+ | but | ||
+ | we're also | ||
+ | translating and escaping this whole | ||
+ | thing | ||
+ | we don't want to escape the value twice | ||
+ | because if we do that we might end up | ||
+ | causing some html entities to be | ||
+ | rendered to the end user and that would | ||
+ | be confusing so | ||
+ | when generating the list of tokens here | ||
+ | we'll just do a flat out translate | ||
+ | and then | ||
+ | i will escape it at the end after we' | ||
+ | combined all the parts together | ||
+ | so that completes my refactoring | ||
+ | but you will recall that i mentioned | ||
+ | that the language cache | ||
+ | needs to be cleared in order for uh | ||
+ | changes to the language files to take | ||
+ | effect and let me just demonstrate that | ||
+ | uh to prove that what i've done has | ||
+ | actually had an effect if i refresh the | ||
+ | page now | ||
+ | all of my headings just changed to home | ||
+ | browse by facet because i created a new | ||
+ | string but that string isn't in the | ||
+ | cache yet so now if i go down to the | ||
+ | terminal | ||
+ | and i | ||
+ | remove local cache languages again to | ||
+ | clear out that part of the cache | ||
+ | and then i refresh my page again | ||
+ | now we're back to having appropriate | ||
+ | headings on all of our columns but now | ||
+ | we're using a more uh appropriate | ||
+ | tokenized version of the language string | ||
+ | that will be easier to customize in the | ||
+ | future | ||
+ | so uh we've just about run out of time | ||
+ | here | ||
+ | but | ||
+ | the last thing i wanted to very quickly | ||
+ | highlight is i've showed you uh how | ||
+ | translation works | ||
+ | in the template files | ||
+ | you can also occasionally need to do | ||
+ | translations deeper in the code when | ||
+ | you're writing controllers | ||
+ | or building services | ||
+ | and viewfind provides a couple of useful | ||
+ | mechanisms to help you with that | ||
+ | if you look inside the core viewfinder | ||
+ | module code | ||
+ | under | ||
+ | viewfind | ||
+ | i18n | ||
+ | translator | ||
+ | there' | ||
+ | aware interface and something called the | ||
+ | translator aware trait | ||
+ | and | ||
+ | to make a a long story short | ||
+ | if you implement | ||
+ | the translator aware interface on a | ||
+ | service or controller | ||
+ | many of viewfind service managers will | ||
+ | automatically call its set translator | ||
+ | method and pass in | ||
+ | the laminas class that | ||
+ | actually does the work of translating | ||
+ | things | ||
+ | uh and even if it doesn' | ||
+ | auto-injected this makes it easy to | ||
+ | inject through a factory so depending on | ||
+ | context the point is anything that has a | ||
+ | translator aware interface | ||
+ | can receive a translator and use it to | ||
+ | translate strings | ||
+ | the translator aware trait is a trait | ||
+ | that can be mixed into any of your | ||
+ | classes | ||
+ | uh it gives you the set translator | ||
+ | method | ||
+ | to match the translator aware interface | ||
+ | and it provides some useful utility | ||
+ | methods that you might find helpful it | ||
+ | has this get translator locale | ||
+ | method which | ||
+ | will find out what user language is | ||
+ | currently active | ||
+ | so if you need to find out what user | ||
+ | language code has been selected this | ||
+ | will tell you | ||
+ | and it has the translate method | ||
+ | which | ||
+ | we showed in the view helper earlier | ||
+ | that takes a string to translate an | ||
+ | array of tokens | ||
+ | and also a third parameter a default | ||
+ | value that can be used if no translation | ||
+ | is found at all | ||
+ | so this is used throughout the viewfind | ||
+ | code it can be useful in your custom | ||
+ | code | ||
+ | i don't have time today to go much | ||
+ | deeper into it but just wanted to make | ||
+ | you aware that this is available uh | ||
+ | should you need it | ||
+ | and that's all we have time for so i | ||
+ | hope this has been a useful introduction | ||
+ | to internationalization uh and that it | ||
+ | will help you customize | ||
+ | your local interface and perhaps inspire | ||
+ | you to contribute some more languages to | ||
+ | viewfind | ||
+ | thank you as always for your time and | ||
+ | see you next time | ||
---- struct data ---- | ---- struct data ---- | ||
---- | ---- | ||
videos/i18n.txt · Last modified: 2023/05/09 18:17 by crhallberg