| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.locale.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Locale</classname> is the Frameworks answer to the question, "How can the same application be used around
- the whole world?" Most people will say, "That's easy. Let's translate all our output to several languages."
- However, using simple translation tables to map phrases from one language to another is not sufficient.
- Different regions will have different conventions for first names, surnames, salutory titles, formatting of
- numbers, dates, times, currencies, etc.
- </para>
- <para>
- We need
- <ulink url="http://en.wikipedia.org/wiki/L10n">Localization</ulink>
- and complementary
- <ulink url="http://en.wikipedia.org/wiki/L10n">Internationalization</ulink>
- . Both are often abbreviated to <code>L10n</code> and <code>I18n</code>. Internationalization refers more to
- support for use of systems, regardless of special needs unique to groups of users related by language, region,
- number format conventions, financial conventions, time and date conventions, etc. Localization involves adding
- explicit support to systems for special needs of these unique groups, such as language translation, and support
- for local customs or conventions for communicating plurals, dates, times, currencies, names, symbols, sorting
- and ordering, etc. <code>L10n</code> and <code>I18n</code> compliment each other. Zend Framework provides
- support for these through a combination of components, including <classname>Zend_Locale</classname>, <classname>Zend_Date</classname>, <classname>Zend_Measure</classname>,
- <classname>Zend_Translate</classname>, <classname>Zend_Currency</classname>, and <classname>Zend_TimeSync</classname>.
- </para>
- <tip>
- <title>Zend_Locale and setLocale()</title>
- <para>
- <ulink url="http://php.net/setlocale">PHP's documentation</ulink> states that <code>setlocale()</code>
- is not threadsave because it is maintained per process and not per thread. This means that, in
- multithreaded environments, you can have the problem that the locale changes while the script
- never has changed the locale itself. This can lead to unexpected behaviour when you use
- <code>setlocale()</code> in your scripts.
- </para>
- <para>
- When you are using <classname>Zend_Locale</classname> you will not have this limitations, because
- <classname>Zend_Locale</classname> is not related to or coupled with PHP's <code>setlocale()</code>.
- </para>
- </tip>
- <sect2 id="zend.locale.whatislocalization">
- <title>What is Localization</title>
- <para>
- Localization means that an application (or homepage) can be used from different users which speak different
- languages. But as you already have expected Localization means more than only translating strings. It
- includes
- </para>
- <itemizedlist mark='opencircle'>
- <listitem>
- <para>
- <classname>Zend_Locale</classname> - Backend support of locales available for localization support within
- other ZF components.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Translate</classname> - Translating of strings.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Date</classname> - Localization of dates, times.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Calendar</classname> - Localization of calendars (support for non-Gregorian calendar systems)
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Currency</classname> - Localization of currencies.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Locale_Format</classname> - Parsing and generating localized numbers.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Locale_Data</classname> - Retrieve localized standard strings as country names, language names
- and
- <ulink url="http://unicode.org/cldr/">more from the CLDR</ulink>
- .
- </para>
- </listitem>
- <listitem>
- <para>
- <code>TODO</code> - Localization of collations
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.locale.whatis">
- <title>What is a Locale?</title>
- <para>
- Each computer user makes use of Locales, even when they don't know it. Applications lacking localization
- support, normally have implicit support for one particular locale (the locale of the author). When a class
- or function makes use of localization, we say it is <code>locale-aware</code>. How does the code know which
- localization the user is expecting?
- </para>
- <para>
- A locale string or object identifying a supported locale gives <classname>Zend_Locale</classname> and its subclasses
- access to information about the language and region expected by the user. Correct formatting, normalization,
- and conversions are made based on this information.
- </para>
- </sect2>
- <sect2 id="zend.locale.representation">
- <title>How are Locales Represented?</title>
- <para>
- Locale identifiers consist of information about the user's language and preferred/primary geographic region
- (e.g. state or province of home or workplace). The locale identifier strings used in Zend Framework are
- internationally defined standard abbreviations of language and region, written as
- <code>language_REGION</code>. Both the language and region parts are abbreviated to alphabetic, ASCII
- characters.
- </para>
- <note>
- <para>
- Be aware that there exist not only locales with 2 characters as most people think. Also there
- are languages and regions which are not only abbreviated with 2 characters. Therefor you should
- NOT strip the region and language yourself, but use <classname>Zend_Locale</classname> when you want to strip language
- or region from a locale string. Otherwise you could have unexpected behaviour within your code
- when you do this yourself.
- </para>
- </note>
- <para>
- A user from USA would expect the language <code>English</code> and the region <code>USA</code>, yielding the
- locale identifier "en_US". A user in Germany would expect the language <code>German</code> and the region
- <code>Germany</code>, yielding the locale identifier "de_DE". See the
- <ulink url="http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html">list of pre-defined locale and region combinations</ulink>, if you need to select a specific locale within Zend Framework.
- </para>
- <example id="zend.locale.representation.example-1">
- <title>Choosing a specific locale</title>
- <programlisting language="php"><![CDATA[
- $locale = new Zend_Locale('de_DE'); // German language _ Germany
- ]]></programlisting>
- </example>
- <para>
- A German user in America might expect the language <code>German</code> and the region <code>USA</code>, but
- these non-standard mixes are not supported directly as recognized "locales". Instead, if an invalid
- combination is used, then it will automatically be truncated by dropping the region code. For example,
- "de_IS" would be truncated to "de", and "xh_RU" would be truncated to "xh", because neither of these
- combinations are valid. Additionally, if the base language code is not supported (e.g. "zz_US") or does not
- exist, then a default "root" locale will be used. The "root" locale has default definitions for
- internationally recognized representations of dates, times, numbers, currencies, etc. The truncation process
- depends on the requested information, since some combinations of language and region might be valid for one
- type of data (e.g. dates), but not for another (e.g. currency format).
- </para>
- <para>
- Beware of historical changes, as ZF components do not know about or attempt to track the numerous timezone
- changes made over many years by many regions. For example,
- <ulink url="http://www.statoids.com/tus.html">we can see a historical list</ulink>
- showing dozens of changes made by governments to when and if a particular region observes Daylight Savings
- Time, and even which timezone a particular geographic area belongs. Thus, when performing date math, the
- math performed by ZF components will not adjust for these changes, but instead will give the correct time
- for the timezone using current, modern rules for DST and timezone assignment for geographic regions.
- </para>
- </sect2>
- <sect2 id="zend.locale.selection">
- <title>Selecting the Right Locale</title>
- <para>
- For most situations, <code>new Zend_Locale()</code> will automatically select the correct locale, with
- preference given to information provided by the user's web browser. However, if <code>new
- Zend_Locale(Zend_Locale::ENVIRONMENT)</code> is used, then preference will be given to using the host
- server's environment configuration, as described below.
- </para>
- <example id="zend.locale.selection.example-1">
- <title>Automatically selecting a locale</title>
- <programlisting language="php"><![CDATA[
- $locale = new Zend_Locale();
- // default behavior, same as above
- $locale1 = new Zend_Locale(Zend_Locale::BROWSER);
- // prefer settings on host server
- $locale2 = new Zend_Locale(Zend_Locale::ENVIRONMENT);
- // perfer framework app default settings
- $locale3 = new Zend_Locale(Zend_Locale::FRAMEWORK);
- ]]></programlisting>
- </example>
- <para>
- The search algorithm used by <classname>Zend_Locale</classname> for automatic selection of a locale uses three sources
- of information:
- <orderedlist>
- <listitem>
- <para>
- const <classname>Zend_Locale::BROWSER</classname> - The user's Web browser provides information with each
- request, which is published by PHP in the global variable <code>HTTP_ACCEPT_LANGUAGE</code>. If
- no matching locale can be found, then preference is given to <code>ENVIRONMENT</code> and lastly
- <code>FRAMEWORK</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- const <classname>Zend_Locale::ENVIRONMENT</classname> - PHP publishes the host server's locale via the PHP
- internal function <code>setlocale()</code>. If no matching locale can be found, then preference
- is given to <code>FRAMEWORK</code> and lastly <code>BROWSER</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- const <classname>Zend_Locale::FRAMEWORK</classname> - When Zend Framework has a standardized way of
- specifying component defaults (planned, but not yet available), then using this constant during
- instantiation will give preference to choosing a locale based on these defaults. If no matching
- locale can be found, then preference is given to <code>ENVIRONMENT</code> and lastly
- <code>BROWSER</code>.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect2>
- <sect2 id="zend.locale.selection.automatic">
- <title>Usage of automatic Locales</title>
- <para>
- <classname>Zend_Locale</classname> provides three additionally locales. These locales do not belong to
- any language or region. They are "automatic" locales which means that they have the same effect
- as the method <code>getDefault()</code> but without the negative effects like creating an instance.
- These "automatic" locales can be used anywhere, where also a standard locale and also the
- definition of a locale, its string representation, can be used. This offers simplicity for
- situations like working with locales which are provided by a browser.
- </para>
- <para>
- There are three locales which have a slightly different behaviour:
- <orderedlist>
- <listitem>
- <para>
- <code>'browser'</code> - <classname>Zend_Locale</classname> should work with the information
- which is provided by the user's Web browser. It is published by PHP in the global
- variable <code>HTTP_ACCEPT_LANGUAGE</code>.
- </para>
- <para>
- If a user provides more than one locale within his browser, <classname>Zend_Locale</classname>
- will use the first found locale. If the user does not provide a locale or the script is
- being called from the command line the automatic locale <code>'environment'</code>
- will automatically be used and returned.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>'environment'</code> - <classname>Zend_Locale</classname> should work with the information
- which is provided by the host server. It is published by PHP via the internal function
- <code>setlocale()</code>.
- </para>
- <para>
- If a environment provides more than one locale, <classname>Zend_Locale</classname> will use the
- first found locale. If the host does not provide a locale the automatic locale
- <code>'browser'</code> will automatically be used and returned.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>'auto'</code> - <classname>Zend_Locale</classname> should automatically detect any locale
- which can be worked with. It will first search for a users locale and then, if not
- successful, search for the host locale.
- </para>
- <para>
- If no locale can be detected, it will throw an exception and tell you that the
- automatic detection has been failed.
- </para>
- </listitem>
- </orderedlist>
- </para>
- <example id="zend.locale.selection.automatic.example-1">
- <title>Using automatic locales</title>
- <programlisting language="php"><![CDATA[
- // without automatic detection
- //$locale = new Zend_Locale(Zend_Locale::BROWSER);
- //$date = new Zend_Date($locale);
- // with automatic detection
- $date = new Zend_Date('auto');
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.locale.defaultlocale">
- <title>Using a default Locale</title>
- <para>
- In some environments it is not possible to detect a locale automatically. You can expect this
- behaviour when you get an request from command line or the requesting browser has no language tag
- set and additionally your server has the default locale 'C' set or another proprietary locale.
- </para>
- <para>
- In such cases <classname>Zend_Locale</classname> will normally throw an exception with a message that
- the automatic detection of any locale was not successful. You have two options to handle such
- a situation. Either through setting a new locale per hand, or defining a default locale.
- </para>
- <example id="zend.locale.defaultlocale.example-1">
- <title>Handling locale exceptions</title>
- <programlisting language="php"><![CDATA[
- // within the bootstrap file
- try {
- $locale = new Zend_Locale('auto');
- } catch (Zend_Locale_Exception $e) {
- $locale = new Zend_Locale('de');
- }
- // within your model/controller
- $date = new Zend_Date($locale);
- ]]></programlisting>
- </example>
- <para>
- But this has one big negative effect. You will have to set your locale object within
- every class using <classname>Zend_Locale</classname>. This could become very unhandy if you are using
- multiple classes.
- </para>
- <para>
- Since Zend Framework Release 1.5 there is a much better way to handle this. You can set a
- default locale which the static <code>setDefault()</code> method. Of course, every unknown
- or not full qualified locale will also throw an exception. <code>setDefault()</code> should
- be the first call before you initiate any class using <classname>Zend_Locale</classname>. See the
- following example for details:
- </para>
- <example id="zend.locale.defaultlocale.example-2">
- <title>Setting a default locale</title>
- <programlisting language="php"><![CDATA[
- // within the bootstrap file
- Zend_Locale::setDefault('de');
- // within your model/controller
- $date = new Zend_Date();
- ]]></programlisting>
- </example>
- <para>
- In the case that no locale can be detected, automatically the locale
- <emphasis>de</emphasis> will be used. Otherwise, the detected locale will be used.
- </para>
- </sect2>
- <sect2 id="zend.locale.interoperate">
- <title>ZF Locale-Aware Classes</title>
- <para>
- In the ZF, locale-aware classes rely on <classname>Zend_Locale</classname> to automatically select a locale, as
- explained above. For example, in a ZF web application, constructing a date using <classname>Zend_Date</classname>
- without specifying a locale results in an object with a locale based on information provided by the current
- user's web browser.
- </para>
- <example id="zend.locale.interoperate.example-1">
- <title>Dates default to correct locale of web users</title>
- <programlisting language="php"><![CDATA[
- $date = new Zend_Date('2006',Zend_Date::YEAR);
- ]]></programlisting>
- </example>
- <para>
- To override this default behavior, and force locale-aware ZF components to use specific locales, regardless
- of the origin of your website visitors, explicitly specify a locale as the third argument to the
- constructor.
- </para>
- <example id="zend.locale.interoperate.example-2">
- <title>Overriding default locale selection</title>
- <programlisting language="php"><![CDATA[
- $usLocale = new Zend_Locale('en_US');
- $date = new Zend_Date('2006', Zend_Date::YEAR, $usLocale);
- $temp = new Zend_Measure_Temperature('100,10',
- Zend_Measure::TEMPERATURE,
- $usLocale);
- ]]></programlisting>
- </example>
- <para>
- If you know many objects should all use the same default locale, explicitly specify the default locale to
- avoid the overhead of each object determining the default locale.
- </para>
- <example id="zend.locale.interoperate.example-3">
- <title>Performance optimization when using a default locale</title>
- <programlisting language="php"><![CDATA[
- $locale = new Zend_Locale();
- $date = new Zend_Date('2006', Zend_Date::YEAR, $locale);
- $temp = new Zend_Measure_Temperature('100,10',
- Zend_Measure::TEMPERATURE,
- $locale);
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.locale.frameworkwidelocale">
- <title>Application wide locale</title>
- <para>
- Zend Framework allows the usage of an application wide locale. You simply set an instance of
- <classname>Zend_Locale</classname> to the registry with the key 'Zend_Locale'. Then this instance will
- be used within all locale aware classes of Zend Framework. This way you set one locale within
- your registry and then you can forget about setting it again. It will automatically be used
- in all other classes. See the below example for the right usage:
- </para>
- <example id="zend.locale.frameworkwidelocale.example">
- <title>Usage of an application wide locale</title>
- <programlisting language="php"><![CDATA[
- // within your bootstrap
- $locale = new Zend_Locale('de_AT');
- Zend_Registry::set('Zend_Locale', $locale);
- // within your model or controller
- $date = new Zend_Date();
- // print $date->getLocale();
- echo $date->getDate();
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.locale.formatoptions">
- <title>Zend_Locale_Format::setOptions(array $options)</title>
- <para>
- The 'precision' option of a value is used to truncate or stretch extra digits. A value of '-1' disables
- modification of the number of digits in the fractional part of the value. The 'locale' option helps when
- parsing numbers and dates using separators and month names. The date format 'format_type' option selects between
- CLDR/ISO date format specifier tokens and PHP's date() tokens. The 'fix_date' option enables or disables
- heuristics that attempt to correct invalid dates. The 'number_format' option specifies a default number
- format for use with <code>toNumber()</code> (see
- <xref
- linkend= "zend.locale.number.localize"/>
- ).
- </para>
- <para>
- The 'date_format' option can be used to specify a default date format string, but beware of using getDate(),
- checkdateFormat() and getTime() after using setOptions() with a 'date_format'. To use these four methods
- with the default date format for a locale, use array('date_format' => null, 'locale' => $locale) for their
- options.
- </para>
- <example id="zend.locale.formatoptions.example-1">
- <title>Dates default to correct locale of web users</title>
- <programlisting language="php"><![CDATA[
- Zend_Locale_Format::setOptions(array('locale' => 'en_US',
- 'fix_date' => true,
- 'format_type' => 'php'));
- ]]></programlisting>
- </example>
- <para>
- For working with the standard definitions of a locale the option <classname>Zend_Locale_Format::STANDARD</classname> can be used.
- Setting the option <classname>Zend_Locale_Format::STANDARD</classname> for <code>date_format</code> uses the standard definitions from the actual
- set locale. Setting it for number_format uses the standard number format for this locale.
- And setting it for locale uses the standard locale for this environment or browser.
- </para>
- <example id="zend.locale.formatoptions.example-2">
- <title>Using STANDARD definitions for setOptions()</title>
- <programlisting language="php"><![CDATA[
- Zend_Locale_Format::setOptions(array('locale' => 'en_US',
- 'date_format' => 'dd.MMMM.YYYY'));
- // overriding the global set date format
- $date = Zend_Locale_Format::getDate('2007-04-20',
- array('date_format' =>
- Zend_Locale_Format::STANDARD);
- // global setting of the standard locale
- Zend_Locale_Format::setOptions(array('locale' => Zend_Locale_Format::STANDARD,
- 'date_format' => 'dd.MMMM.YYYY'));
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.locale.cache">
- <title>Speed up Zend_Locale and its subclasses</title>
- <para>
- <classname>Zend_Locale</classname> and its subclasses can be speed up by the usage of
- <classname>Zend_Cache</classname>. Use the static method
- <classname>Zend_Locale::setCache($cache)</classname> if you are using
- <classname>Zend_Locale</classname>. <classname>Zend_Locale_Format</classname> can be
- speed up the using the option <code>cache</code> within
- <classname>Zend_Locale_Format::setOptions(array('cache' => $adapter));</classname>.
- If you are using both classes you should only set the cache for
- <classname>Zend_Locale</classname>, otherwise the last set cache will overwrite the
- previous set cache. For convenience there are also the static methods
- <methodname>getCache()</methodname>, <methodname>hasCache()</methodname>,
- <methodname>clearCache()</methodname> and <methodname>removeCache()</methodname>.
- </para>
- <para>
- When no cache is set, then <classname>Zend_Locale</classname> will automatically set a
- cache itself. Sometimes it is wished to prevent that a cache is set, even if this
- degrades performance. In this case the static
- <methodname>disableCache(true)</methodname> method should be used. It does not only
- disable the actual set cache, without erasing it, but also prevents that a cache is
- automatically generated when no cache is set.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|