template variable. * * File-based i18n-translations always have a "locale" (e.g. 'en_US'). * Common language names (e.g. 'en') are mainly used in {Translatable} for * database-entities. * * Features a "textcollector-mode" that parses all files with a certain extension * (currently *.php and *.ss) for new translatable strings. Textcollector will write * updated string-tables to their respective folders inside the module, and automatically * namespace entities to the classes/templates they are found in (e.g. $lang['en_US']['AssetAdmin']['UPLOADFILES']). * * Caution: Does not apply any character-set conversion, it is assumed that all content * is stored and represented in UTF-8 (Unicode). Please make sure your files are created with the correct * character-set, and your HTML-templates render UTF-8. * * Please see the {Translatable} DataObjectDecorator for managing translations of database-content. * * @author Bernat Foj Capell */ class i18n extends Controller { /** * This static variable is used to store the current defined locale. */ protected static $current_locale = ''; /** * This is the locale in which generated language files are (we assume US English) * * @var string */ protected static $default_locale = 'en_US'; /** * An exhaustive list of possible locales (code => language and country) * * @var array */ public static $all_locales = array( 'aa_DJ' => 'Afar (Djibouti)', 'ab_GE' => 'Abkhazian (Georgia)', 'abr_GH' => 'Abron (Ghana)', 'ace_ID' => 'Achinese (Indonesia)', 'ady_RU' => 'Adyghe (Russia)', 'af_ZA' => 'Afrikaans (South Africa)', 'ak_GH' => 'Akan (Ghana)', 'am_ET' => 'Amharic (Ethiopia)', 'ar_AE' => 'Arabic (United Arab Emirates)', 'ar_BH' => 'Arabic (Bahrain)', 'ar_DZ' => 'Arabic (Algeria)', 'ar_EG' => 'Arabic (Egypt)', 'ar_EH' => 'Arabic (Western Sahara)', 'ar_IQ' => 'Arabic (Iraq)', 'ar_JO' => 'Arabic (Jordan)', 'ar_KW' => 'Arabic (Kuwait)', 'ar_LB' => 'Arabic (Lebanon)', 'ar_LY' => 'Arabic (Libya)', 'ar_MA' => 'Arabic (Morocco)', 'ar_MR' => 'Arabic (Mauritania)', 'ar_OM' => 'Arabic (Oman)', 'ar_PS' => 'Arabic (Palestinian Territory)', 'ar_QA' => 'Arabic (Qatar)', 'ar_SA' => 'Arabic (Saudi Arabia)', 'ar_SD' => 'Arabic (Sudan)', 'ar_SY' => 'Arabic (Syria)', 'ar_TD' => 'Arabic (Chad)', 'ar_TN' => 'Arabic (Tunisia)', 'ar_YE' => 'Arabic (Yemen)', 'as_IN' => 'Assamese (India)', 'auv_FR' => 'Auvergnat (France)', 'av_RU' => 'Avaric (Russia)', 'awa_IN' => 'Awadhi (India)', 'ay_BO' => 'Aymara (Bolivia)', 'ay_PE' => 'Aymara (Peru)', 'az_AZ' => 'Azerbaijani (Azerbaijan)', 'az_IR' => 'Azerbaijani (Iran)', 'ba_RU' => 'Bashkir (Russia)', 'ban_ID' => 'Balinese (Indonesia)', 'be_BY' => 'Belarusian (Belarus)', 'bew_ID' => 'Betawi (Indonesia)', 'bg_BG' => 'Bulgarian (Bulgaria)', 'bgc_IN' => 'Haryanvi (India)', 'bcc_PK' => 'Balochi, Southern (Pakistan)', 'bgn_PK' => 'Balochi, Western (Pakistan)', 'bgp_PK' => 'Balochi, Easter (Pakistan)', 'bhb_IN' => 'Bhili (India)', 'bhi_IN' => 'Bhilali (India)', 'bcl_PH' => 'Bicolano, Central (Philippines)', 'bhk_PH' => 'Bicolano, Albay (Philippines)', 'bho_IN' => 'Bhojpuri (India)', 'bho_MU' => 'Bhojpuri (Mauritius)', 'bho_NP' => 'Bhojpuri (Nepal)', 'bi_VU' => 'Bislama (Vanuatu)', 'bjj_IN' => 'Kanauji (India)', 'bjn_ID' => 'Banjar (Indonesia)', 'bm_ML' => 'Bambara (Mali)', 'bn_BD' => 'Bengali (Bangladesh)', 'bn_IN' => 'Bengali (India)', 'bo_CN' => 'Tibetan (China)', 'bqi_IR' => 'Bakhtiari (Iran)', 'brh_PK' => 'Brahui (Pakistan)', 'bs_BA' => 'Bosnian (Bosnia and Herzegovina)', 'btk_ID' => 'Batak (Indonesia)', 'buc_YT' => 'Bushi (Mayotte)', 'bug_ID' => 'Buginese (Indonesia)', 'ca_AD' => 'Catalan (Andorra)', 'ca_ES' => 'Catalan (Spain)', 'ce_RU' => 'Chechen (Russia)', 'ceb_PH' => 'Cebuano (Philippines)', 'cgg_UG' => 'Chiga (Uganda)', 'ch_GU' => 'Chamorro (Guam)', 'chk_FM' => 'Chuukese (Micronesia)', 'crk_CA' => 'Cree, Plains (Canada)', 'cwd_CA' => 'Cree, Woods (Canada)', 'cs_CZ' => 'Czech (Czech Republic)', 'cy_GB' => 'Welsh (United Kingdom)', 'da_DK' => 'Danish (Denmark)', 'da_GL' => 'Danish (Greenland)', 'dcc_IN' => 'Deccan (India)', 'de_AT' => 'German (Austria)', 'de_BE' => 'German (Belgium)', 'de_CH' => 'German (Switzerland)', 'de_DE' => 'German (Germany)', 'de_LI' => 'German (Liechtenstein)', 'de_LU' => 'German (Luxembourg)', 'dgo_IN' => 'Dogri (India)', 'dhd_IN' => 'Dhundari (India)', 'diq_TR' => 'Dimli (Turkey)', 'dje_NE' => 'Zarma (Niger)', 'dv_MV' => 'Divehi (Maldives)', 'dz_BT' => 'Dzongkha (Bhutan)', 'ee_GH' => 'Ewe (Ghana)', 'el_CY' => 'Greek (Cyprus)', 'el_GR' => 'Greek (Greece)', 'en_AS' => 'English (American Samoa)', 'en_AU' => 'English (Australia)', 'en_BM' => 'English (Bermuda)', 'en_BS' => 'English (Bahamas)', 'en_CA' => 'English (Canada)', 'en_GB' => 'English (United Kingdom)', 'en_HK' => 'English (Hong Kong SAR China)', 'en_IE' => 'English (Ireland)', 'en_IN' => 'English (India)', 'en_JM' => 'English (Jamaica)', 'en_KE' => 'English (Kenya)', 'en_LR' => 'English (Liberia)', 'en_MM' => 'English (Myanmar)', 'en_MW' => 'English (Malawi)', 'en_MY' => 'English (Malaysia)', 'en_NZ' => 'English (New Zealand)', 'en_PH' => 'English (Philippines)', 'en_SG' => 'English (Singapore)', 'en_TT' => 'English (Trinidad and Tobago)', 'en_US' => 'English (United States)', 'en_ZA' => 'English (South Africa)', 'en_DE' => 'English (Germany)', 'en_ES' => 'English (Spain)', 'en_FR' => 'English (France)', 'en_IT' => 'English (Italy)', 'en_NL' => 'English (Netherlands)', 'es_419' => 'Spanish (Latin America)', 'es_AR' => 'Spanish (Argentina)', 'es_BO' => 'Spanish (Bolivia)', 'es_CL' => 'Spanish (Chile)', 'es_CO' => 'Spanish (Colombia)', 'es_CR' => 'Spanish (Costa Rica)', 'es_CU' => 'Spanish (Cuba)', 'es_DO' => 'Spanish (Dominican Republic)', 'es_EC' => 'Spanish (Ecuador)', 'es_ES' => 'Spanish (Spain)', 'es_GQ' => 'Spanish (Equatorial Guinea)', 'es_GT' => 'Spanish (Guatemala)', 'es_HN' => 'Spanish (Honduras)', 'es_MX' => 'Spanish (Mexico)', 'es_NI' => 'Spanish (Nicaragua)', 'es_PA' => 'Spanish (Panama)', 'es_PE' => 'Spanish (Peru)', 'es_PH' => 'Spanish (Philippines)', 'es_PR' => 'Spanish (Puerto Rico)', 'es_PY' => 'Spanish (Paraguay)', 'es_SV' => 'Spanish (El Salvador)', 'es_US' => 'Spanish (United States)', 'es_UY' => 'Spanish (Uruguay)', 'es_VE' => 'Spanish (Venezuela)', 'et_EE' => 'Estonian (Estonia)', 'eu_ES' => 'Basque (Spain)', 'fa_AF' => 'Persian (Afghanistan)', 'fa_IR' => 'Persian (Iran)', 'fa_PK' => 'Persian (Pakistan)', 'fan_GQ' => 'Fang (Equatorial Guinea)', 'fi_FI' => 'Finnish (Finland)', 'fi_SE' => 'Finnish (Sweden)', 'fil_PH' => 'Filipino (Philippines)', 'fj_FJ' => 'Fijian (Fiji)', 'fo_FO' => 'Faroese (Faroe Islands)', 'fon_BJ' => 'Fon (Benin)', 'fr_002' => 'French (Africa)', 'fr_BE' => 'French (Belgium)', 'fr_CA' => 'French (Canada)', 'fr_CH' => 'French (Switzerland)', 'fr_DZ' => 'French (Algeria)', 'fr_FR' => 'French (France)', 'fr_GF' => 'French (French Guiana)', 'fr_GP' => 'French (Guadeloupe)', 'fr_HT' => 'French (Haiti)', 'fr_KM' => 'French (Comoros)', 'fr_MA' => 'French (Morocco)', 'fr_MQ' => 'French (Martinique)', 'fr_MU' => 'French (Mauritius)', 'fr_NC' => 'French (New Caledonia)', 'fr_PF' => 'French (French Polynesia)', 'fr_PM' => 'French (Saint Pierre and Miquelon)', 'fr_RE' => 'French (Reunion)', 'fr_SC' => 'French (Seychelles)', 'fr_SN' => 'French (Senegal)', 'fr_US' => 'French (United States)', 'fuv_NG' => 'Fulfulde (Nigeria)', 'ga_IE' => 'Irish (Ireland)', 'ga_GB' => 'Irish (United Kingdom)', 'gaa_GH' => 'Ga (Ghana)', 'gbm_IN' => 'Garhwali (India)', 'gcr_GF' => 'Guianese Creole French (French Guiana)', 'gd_GB' => 'Scottish Gaelic (United Kingdom)', 'gil_KI' => 'Gilbertese (Kiribati)', 'gl_ES' => 'Galician (Spain)', 'glk_IR' => 'Gilaki (Iran)', 'gn_PY' => 'Guarani (Paraguay)', 'gno_IN' => 'Gondi, Northern (India)', 'gsw_CH' => 'Swiss German (Switzerland)', 'gsw_LI' => 'Swiss German (Liechtenstein)', 'gu_IN' => 'Gujarati (India)', 'guz_KE' => 'Gusii (Kenya)', 'ha_NG' => 'Hausa (Nigeria)', 'ha_NE' => 'Hausa (Niger)', 'haw_US' => 'Hawaiian (United States)', 'haz_AF' => 'Hazaragi (Afghanistan)', 'he_IL' => 'Hebrew (Israel)', 'hi_IN' => 'Hindi (India)', 'hil_PH' => 'Hiligaynon (Philippines)', 'hne_IN' => 'Chhattisgarhi (India)', 'hno_PK' => 'Hindko, Northern (Pakistan)', 'hoc_IN' => 'Ho (India)', 'hr_BA' => 'Croatian (Bosnia and Herzegovina)', 'hr_HR' => 'Croatian (Croatia)', 'hr_AT' => 'Croatian (Austria)', 'ht_HT' => 'Haitian (Haiti)', 'hu_HU' => 'Hungarian (Hungary)', 'hu_AT' => 'Hungarian (Austria)', 'hu_RO' => 'Hungarian (Romania)', 'hu_RS' => 'Hungarian (Serbia)', 'hy_AM' => 'Armenian (Armenia)', 'id_ID' => 'Indonesian (Indonesia)', 'ig_NG' => 'Igbo (Nigeria)', 'ilo_PH' => 'Iloko (Philippines)', 'inh_RU' => 'Ingush (Russia)', 'is_IS' => 'Icelandic (Iceland)', 'it_CH' => 'Italian (Switzerland)', 'it_IT' => 'Italian (Italy)', 'it_SM' => 'Italian (San Marino)', 'it_FR' => 'Italian (France)', 'it_HR' => 'Italian (Croatia)', 'it_US' => 'Italian (United States)', 'iu_CA' => 'Inuktitut (Canada)', 'ja_JP' => 'Japanese (Japan)', 'jv_ID' => 'Javanese (Indonesia)', 'ka_GE' => 'Georgian (Georgia)', 'kam_KE' => 'Kamba (Kenya)', 'kbd_RU' => 'Kabardian (Russia)', 'kfy_IN' => 'Kumauni (India)', 'kha_IN' => 'Khasi (India)', 'khn_IN' => 'Khandesi (India)', 'ki_KE' => 'Kikuyu (Kenya)', 'kj_NA' => 'Kuanyama (Namibia)', 'kk_KZ' => 'Kazakh (Kazakhstan)', 'kk_CN' => 'Kazakh (China)', 'kl_GL' => 'Kalaallisut (Greenland)', 'kl_DK' => 'Kalaallisut (Denmark)', 'kln_KE' => 'Kalenjin (Kenya)', 'km_KH' => 'Khmer (Cambodia)', 'kn_IN' => 'Kannada (India)', 'ko_KR' => 'Korean (Korea)', 'koi_RU' => 'Komi-Permyak (Russia)', 'kok_IN' => 'Konkani (India)', 'kos_FM' => 'Kosraean (Micronesia)', 'kpv_RU' => 'Komi-Zyrian (Russia)', 'krc_RU' => 'Karachay-Balkar (Russia)', 'kru_IN' => 'Kurukh (India)', 'ks_IN' => 'Kashmiri (India)', 'ku_IQ' => 'Kurdish (Iraq)', 'ku_IR' => 'Kurdish (Iran)', 'ku_SY' => 'Kurdish (Syria)', 'ku_TR' => 'Kurdish (Turkey)', 'kum_RU' => 'Kumyk (Russia)', 'kxm_TH' => 'Khmer, Northern (Thailand)', 'ky_KG' => 'Kirghiz (Kyrgyzstan)', 'la_VA' => 'Latin (Vatican)', 'lah_PK' => 'Lahnda (Pakistan)', 'lb_LU' => 'Luxembourgish (Luxembourg)', 'lbe_RU' => 'Lak (Russia)', 'lez_RU' => 'Lezghian (Russia)', 'lg_UG' => 'Ganda (Uganda)', 'lij_IT' => 'Ligurian (Italy)', 'lij_MC' => 'Ligurian (Monaco)', 'ljp_ID' => 'Lampung (Indonesia)', 'lmn_IN' => 'Lambadi (India)', 'ln_CD' => 'Lingala (Congo - Kinshasa)', 'ln_CG' => 'Lingala (Congo - Brazzaville)', 'lo_LA' => 'Lao (Laos)', 'lrc_IR' => 'Luri, Northern (Iran)', 'lt_LT' => 'Lithuanian (Lithuania)', 'luo_KE' => 'Luo (Kenya)', 'luy_KE' => 'Luyia (Kenya)', 'lv_LV' => 'Latvian (Latvia)', 'mad_ID' => 'Madurese (Indonesia)', 'mai_IN' => 'Maithili (India)', 'mai_NP' => 'Maithili (Nepal)', 'mak_ID' => 'Makasar (Indonesia)', 'mdf_RU' => 'Moksha (Russia)', 'mdh_PH' => 'Maguindanao (Philippines)', 'mer_KE' => 'Meru (Kenya)', 'mfa_TH' => 'Malay, Pattani (Thailand)', 'mfe_MU' => 'Morisyen (Mauritius)', 'mg_MG' => 'Malagasy (Madagascar)', 'mh_MH' => 'Marshallese (Marshall Islands)', 'mi_NZ' => 'Maori (New Zealand)', 'min_ID' => 'Minangkabau (Indonesia)', 'mk_MK' => 'Macedonian (Macedonia)', 'ml_IN' => 'Malayalam (India)', 'mn_MN' => 'Mongolian (Mongolia)', 'mn_CN' => 'Mongolian (China)', 'mni_IN' => 'Manipuri (India)', 'mr_IN' => 'Marathi (India)', 'ms_BN' => 'Malay (Brunei)', 'ms_MY' => 'Malay (Malaysia)', 'ms_SG' => 'Malay (Singapore)', 'ms_CC' => 'Malay (Cocos Islands)', 'ms_ID' => 'Malay (Indonesia)', 'mt_MT' => 'Maltese (Malta)', 'mtr_IN' => 'Mewari (India)', 'mup_IN' => 'Malvi (India)', 'muw_IN' => 'Mundari (India)', 'my_MM' => 'Burmese (Myanmar)', 'myv_RU' => 'Erzya (Russia)', 'na_NR' => 'Nauru (Nauru)', 'nb_NO' => 'Norwegian Bokmål (Norway)', 'nb_SJ' => 'Norwegian Bokmål (Svalbard and Jan Mayen)', 'nd_ZW' => 'North Ndebele (Zimbabwe)', 'ndc_MZ' => 'Ndau (Mozambique)', 'ne_NP' => 'Nepali (Nepal)', 'ne_IN' => 'Nepali (India)', 'ng_NA' => 'Ndonga (Namibia)', 'ngl_MZ' => 'Lomwe (Mozambique)', 'niu_NU' => 'Niuean (Niue)', 'nl_AN' => 'Dutch (Netherlands Antilles)', 'nl_AW' => 'Dutch (Aruba)', 'nl_BE' => 'Dutch (Belgium)', 'nl_NL' => 'Dutch (Netherlands)', 'nl_SR' => 'Dutch (Suriname)', 'nn_NO' => 'Norwegian Nynorsk (Norway)', 'nod_TH' => 'Thai, Northern (Thailand)', 'noe_IN' => 'Nimadi (India)', 'nso_ZA' => 'Northern Sotho (South Africa)', 'ny_MW' => 'Nyanja (Malawi)', 'ny_ZM' => 'Nyanja (Zambia)', 'nyn_UG' => 'Nyankole (Uganda)', 'om_ET' => 'Oromo (Ethiopia)', 'or_IN' => 'Oriya (India)', 'pa_IN' => 'Punjabi (India)', 'pag_PH' => 'Pangasinan (Philippines)', 'pap_AN' => 'Papiamento (Netherlands Antilles)', 'pap_AW' => 'Papiamento (Aruba)', 'pau_PW' => 'Palauan (Palau)', 'pl_PL' => 'Polish (Poland)', 'pl_UA' => 'Polish (Ukraine)', 'pon_FM' => 'Pohnpeian (Micronesia)', 'ps_AF' => 'Pashto (Afghanistan)', 'ps_PK' => 'Pashto (Pakistan)', 'pt_AO' => 'Portuguese (Angola)', 'pt_BR' => 'Portuguese (Brazil)', 'pt_CV' => 'Portuguese (Cape Verde)', 'pt_GW' => 'Portuguese (Guinea-Bissau)', 'pt_MZ' => 'Portuguese (Mozambique)', 'pt_PT' => 'Portuguese (Portugal)', 'pt_ST' => 'Portuguese (Sao Tome and Principe)', 'pt_TL' => 'Portuguese (East Timor)', 'qu_BO' => 'Quechua (Bolivia)', 'qu_PE' => 'Quechua (Peru)', 'rcf_RE' => 'Réunion Creole French (Reunion)', 'rej_ID' => 'Rejang (Indonesia)', 'rif_MA' => 'Tarifit (Morocco)', 'rjb_IN' => 'Rajbanshi (India)', 'rm_CH' => 'Rhaeto-Romance (Switzerland)', 'rmt_IR' => 'Domari (Iran)', 'rn_BI' => 'Rundi (Burundi)', 'ro_MD' => 'Romanian (Moldova)', 'ro_RO' => 'Romanian (Romania)', 'ro_RS' => 'Romanian (Serbia)', 'ru_BY' => 'Russian (Belarus)', 'ru_KG' => 'Russian (Kyrgyzstan)', 'ru_KZ' => 'Russian (Kazakhstan)', 'ru_RU' => 'Russian (Russia)', 'ru_SJ' => 'Russian (Svalbard and Jan Mayen)', 'ru_UA' => 'Russian (Ukraine)', 'rw_RW' => 'Kinyarwanda (Rwanda)', 'sa_IN' => 'Sanskrit (India)', 'sah_RU' => 'Yakut (Russia)', 'sas_ID' => 'Sasak (Indonesia)', 'sat_IN' => 'Santali (India)', 'sck_IN' => 'Sadri (India)', 'sco_GB' => 'Scots (United Kingdom)', 'sd_IN' => 'Sindhi (India)', 'sd_PK' => 'Sindhi (Pakistan)', 'se_NO' => 'Northern Sami (Norway)', 'sg_CF' => 'Sango (Central African Republic)', 'si_LK' => 'Sinhalese (Sri Lanka)', 'sid_ET' => 'Sidamo (Ethiopia)', 'sk_SK' => 'Slovak (Slovakia)', 'sk_RS' => 'Slovak (Serbia)', 'sl_SI' => 'Slovenian (Slovenia)', 'sl_AT' => 'Slovenian (Austria)', 'sm_AS' => 'Samoan (American Samoa)', 'sm_WS' => 'Samoan (Samoa)', 'sn_ZW' => 'Shona (Zimbabwe)', 'so_SO' => 'Somali (Somalia)', 'so_DJ' => 'Somali (Djibouti)', 'so_ET' => 'Somali (Ethiopia)', 'sou_TH' => 'Thai, Southern (Thailand)', 'sq_AL' => 'Albanian (Albania)', 'sr_BA' => 'Serbian (Bosnia and Herzegovina)', 'sr_ME' => 'Serbian (Montenegro)', 'sr_RS' => 'Serbian (Serbia)', 'ss_SZ' => 'Swati (Swaziland)', 'ss_ZA' => 'Swati (South Africa)', 'st_LS' => 'Southern Sotho (Lesotho)', 'st_ZA' => 'Southern Sotho (South Africa)', 'su_ID' => 'Sundanese (Indonesia)', 'sv_AX' => 'Swedish (Aland Islands)', 'sv_FI' => 'Swedish (Finland)', 'sv_SE' => 'Swedish (Sweden)', 'sw_KE' => 'Swahili (Kenya)', 'sw_TZ' => 'Swahili (Tanzania)', 'sw_UG' => 'Swahili (Uganda)', 'sw_SO' => 'Swahili (Somalia)', 'swb_KM' => 'Comorian (Comoros)', 'swb_YT' => 'Comorian (Mayotte)', 'swv_IN' => 'Shekhawati (India)', 'ta_IN' => 'Tamil (India)', 'ta_LK' => 'Tamil (Sri Lanka)', 'ta_SG' => 'Tamil (Singapore)', 'ta_MY' => 'Tamil (Malaysia)', 'tcy_IN' => 'Tulu (India)', 'te_IN' => 'Telugu (India)', 'tet_TL' => 'Tetum (East Timor)', 'tg_TJ' => 'Tajik (Tajikistan)', 'th_TH' => 'Thai (Thailand)', 'ti_ER' => 'Tigrinya (Eritrea)', 'ti_ET' => 'Tigrinya (Ethiopia)', 'tk_TM' => 'Turkmen (Turkmenistan)', 'tk_IR' => 'Turkmen (Iran)', 'tkl_TK' => 'Tokelau (Tokelau)', 'tl_PH' => 'Tagalog (Philippines)', 'tl_US' => 'Tagalog (United States)', 'tn_BW' => 'Tswana (Botswana)', 'tn_ZA' => 'Tswana (South Africa)', 'to_TO' => 'Tonga (Tonga)', 'tr_CY' => 'Turkish (Cyprus)', 'tr_TR' => 'Turkish (Turkey)', 'tr_DE' => 'Turkish (Germany)', 'tr_MK' => 'Turkish (Macedonia)', 'ts_ZA' => 'Tsonga (South Africa)', 'ts_MZ' => 'Tsonga (Mozambique)', 'tsg_PH' => 'Tausug (Philippines)', 'tt_RU' => 'Tatar (Russia)', 'tts_TH' => 'Thai, Northeastern (Thailand)', 'tvl_TV' => 'Tuvalu (Tuvalu)', 'tw_GH' => 'Twi (Ghana)', 'ty_PF' => 'Tahitian (French Polynesia)', 'tyv_RU' => 'Tuvinian (Russia)', 'tzm_MA' => 'Tamazight, Central Atlas (Morocco)', 'udm_RU' => 'Udmurt (Russia)', 'ug_CN' => 'Uighur (China)', 'uk_UA' => 'Ukrainian (Ukraine)', 'uli_FM' => 'Ulithian (Micronesia)', 'ur_IN' => 'Urdu (India)', 'ur_PK' => 'Urdu (Pakistan)', 'uz_UZ' => 'Uzbek (Uzbekistan)', 'uz_AF' => 'Uzbek (Afghanistan)', 've_ZA' => 'Venda (South Africa)', 'vi_VN' => 'Vietnamese (Vietnam)', 'vi_US' => 'Vietnamese (United States)', 'vmw_MZ' => 'Waddar (Mozambique)', 'wal_ET' => 'Walamo (Ethiopia)', 'war_PH' => 'Waray (Philippines)', 'wbq_IN' => 'Waddar (India)', 'wbr_IN' => 'Wagdi (India)', 'wo_MR' => 'Wolof (Mauritania)', 'wo_SN' => 'Wolof (Senegal)', 'wtm_IN' => 'Mewati (India)', 'xh_ZA' => 'Xhosa (South Africa)', 'xnr_IN' => 'Kangri (India)', 'xog_UG' => 'Soga (Uganda)', 'yap_FM' => 'Yapese (Micronesia)', 'yo_NG' => 'Yoruba (Nigeria)', 'za_CN' => 'Zhuang (China)', 'zh_CN' => 'Chinese (China)', 'zh_HK' => 'Chinese (Hong Kong SAR China)', 'zh_MO' => 'Chinese (Macao SAR China)', 'zh_SG' => 'Chinese (Singapore)', 'zh_TW' => 'Chinese (Taiwan)', 'zh_US' => 'Chinese (United States)', 'zu_ZA' => 'Zulu (South Africa)', ); /** * A list of commonly used languages, in the form * langcode => array( EnglishName, NativeName) */ public static $common_languages = array( 'af' => array('Afrikaans', 'Afrikaans'), 'sq' => array('Albanian', 'shqip'), 'ar' => array('Arabic', 'العربية'), 'eu' => array('Basque', 'euskera'), 'be' => array('Belarusian', 'Беларуская мова'), 'bn' => array('Bengali', 'বাংলা'), 'bg' => array('Bulgarian', 'български'), 'ca' => array('Catalan', 'català'), 'zh-yue' => array('Chinese (Cantonese)', '廣東話 [广东话]'), 'zh-cmn' => array('Chinese (Mandarin)', '普通話 [普通话]'), 'zh-min-nan' => array('Chinese (Min Nan)', '台語'), 'hr' => array('Croatian', 'Hrvatski'), 'cs' => array('Czech', 'čeština'), 'da' => array('Danish', 'dansk'), 'nl' => array('Dutch', 'Nederlands'), 'en' => array('English', 'English'), 'eo' => array('Esperanto', 'Esperanto'), 'et' => array('Estonian', 'eesti keel'), 'fo' => array('Faroese', 'Føroyska'), 'fi' => array('Finnish', 'suomi'), 'fr' => array('French', 'français'), 'gd' => array('Gaelic', 'Gaeilge'), 'gl' => array('Galician', 'Galego'), 'de' => array('German', 'Deutsch'), 'el' => array('Greek', 'ελληνικά'), 'gu' => array('Gujarati', 'ગુજરાતી'), 'ha' => array('Hausa', 'حَوْسَ'), 'he' => array('Hebrew', 'עברית'), 'hi' => array('Hindi', 'हिन्दी'), 'hu' => array('Hungarian', 'magyar'), 'is' => array('Icelandic', 'Íslenska'), 'io' => array('Ido', 'Ido'), 'id' => array('Indonesian', 'Bahasa Indonesia'), 'ga' => array('Irish', 'Irish'), 'it' => array('Italian', 'italiano'), 'ja' => array('Japanese', '日本語'), 'jv' => array('Javanese', 'basa Jawa'), 'ko' => array('Korean', '한국어 [韓國語]'), 'ku' => array('Kurdish', 'Kurdí'), 'lv' => array('Latvian', 'latviešu'), 'lt' => array('Lithuanian', 'lietuviškai'), 'lmo' => array('Lombard', 'Lombardo'), 'mk' => array('Macedonian', 'македонски'), 'ms' => array('Malay', 'Bahasa melayu'), 'mt' => array('Maltese', 'Malti'), 'mr' => array('Marathi', 'मराठी'), 'ne' => array('Nepali', 'नेपाली'), 'no' => array('Norwegian', 'Norsk'), 'om' => array('Oromo', 'Afaan Oromo'), 'fa' => array('Persian', 'فارسى'), 'pl' => array('Polish', 'polski'), 'pt-PT' => array('Portuguese (Portugal)', 'português (Portugal)'), 'pt-BR' => array('Portuguese (Brazil)', 'português (Brazil)'), 'pa' => array('Punjabi', 'ਪੰਜਾਬੀ'), 'qu' => array('Quechua', 'Quechua'), 'rm' => array('Romansh', 'rumantsch'), 'ro' => array('Romanian', 'român'), 'ru' => array('Russian', 'Русский'), 'sco' => array('Scots', 'Scoats leid, Lallans'), 'sr' => array('Serbian', 'српски'), 'sk' => array('Slovak', 'slovenčina'), 'sl' => array('Slovenian', 'slovenščina'), 'es' => array('Spanish', 'español'), 'sv' => array('Swedish', 'Svenska'), 'tl' => array('Tagalog', 'Tagalog'), 'ta' => array('Tamil', 'தமிழ்'), 'te' => array('Telugu', 'తెలుగు'), 'to' => array('Tonga', 'chiTonga'), 'ts' => array('Tsonga', 'xiTshonga'), 'tn' => array('Tswana', 'seTswana'), 'tr' => array('Turkish', 'Türkçe'), 'tk' => array('Turkmen', 'түркmенче'), 'tw' => array('Twi', 'twi'), 'uk' => array('Ukrainian', 'Українська'), 'ur' => array('Urdu', 'اردو'), 'uz' => array('Uzbek', 'ўзбек'), 've' => array('Venda', 'tshiVenḓa'), 'vi' => array('Vietnamese', 'tiếng việt'), 'wa' => array('Walloon', 'walon'), 'wo' => array('Wolof', 'Wollof'), 'xh' => array('Xhosa', 'isiXhosa'), 'yi' => array('Yiddish', 'ײִדיש'), 'zu' => array('Zulu', 'isiZulu') ); static $tinymce_lang = array( 'ca_AD' => 'ca', 'ca_ES' => 'ca', 'cs_CZ' => 'cs', 'cy_GB' => 'cy', 'da_DK' => 'da', 'da_GL' => 'da', 'de_AT' => 'de', 'de_BE' => 'de', 'de_CH' => 'de', 'de_DE' => 'de', 'de_LI' => 'de', 'de_LU' => 'de', 'de_BR' => 'de', 'de_US' => 'de', 'el_CY' => 'el', 'el_GR' => 'el', 'es_AR' => 'es', 'es_BO' => 'es', 'es_CL' => 'es', 'es_CO' => 'es', 'es_CR' => 'es', 'es_CU' => 'es', 'es_DO' => 'es', 'es_EC' => 'es', 'es_ES' => 'es', 'es_GQ' => 'es', 'es_GT' => 'es', 'es_HN' => 'es', 'es_MX' => 'es', 'es_NI' => 'es', 'es_PA' => 'es', 'es_PE' => 'es', 'es_PH' => 'es', 'es_PR' => 'es', 'es_PY' => 'es', 'es_SV' => 'es', 'es_UY' => 'es', 'es_VE' => 'es', 'es_AD' => 'es', 'es_BZ' => 'es', 'es_US' => 'es', 'fa_AF' => 'fa', 'fa_IR' => 'fa', 'fa_PK' => 'fa', 'fi_FI' => 'fi', 'fi_SE' => 'fi', 'fr_BE' => 'fr', 'fr_BF' => 'fr', 'fr_BI' => 'fr', 'fr_BJ' => 'fr', 'fr_CA' => 'fr_ca', 'fr_CF' => 'fr', 'fr_CG' => 'fr', 'fr_CH' => 'fr', 'fr_CI' => 'fr', 'fr_CM' => 'fr', 'fr_DJ' => 'fr', 'fr_DZ' => 'fr', 'fr_FR' => 'fr', 'fr_GA' => 'fr', 'fr_GF' => 'fr', 'fr_GN' => 'fr', 'fr_GP' => 'fr', 'fr_HT' => 'fr', 'fr_KM' => 'fr', 'fr_LU' => 'fr', 'fr_MA' => 'fr', 'fr_MC' => 'fr', 'fr_MG' => 'fr', 'fr_ML' => 'fr', 'fr_MQ' => 'fr', 'fr_MU' => 'fr', 'fr_NC' => 'fr', 'fr_NE' => 'fr', 'fr_PF' => 'fr', 'fr_PM' => 'fr', 'fr_RE' => 'fr', 'fr_RW' => 'fr', 'fr_SC' => 'fr', 'fr_SN' => 'fr', 'fr_SY' => 'fr', 'fr_TD' => 'fr', 'fr_TG' => 'fr', 'fr_TN' => 'fr', 'fr_VU' => 'fr', 'fr_WF' => 'fr', 'fr_YT' => 'fr', 'fr_GB' => 'fr', 'fr_US' => 'fr', 'he_IL' => 'he', 'hu_HU' => 'hu', 'hu_AT' => 'hu', 'hu_RO' => 'hu', 'hu_RS' => 'hu', 'is_IS' => 'is', 'it_CH' => 'it', 'it_IT' => 'it', 'it_SM' => 'it', 'it_FR' => 'it', 'it_HR' => 'it', 'it_US' => 'it', 'it_VA' => 'it', 'ja_JP' => 'ja', 'ko_KP' => 'ko', 'ko_KR' => 'ko', 'ko_CN' => 'ko', 'nb_NO' => 'nb', 'nb_SJ' => 'nb', 'nl_AN' => 'nl', 'nl_AW' => 'nl', 'nl_BE' => 'nl', 'nl_NL' => 'nl', 'nl_SR' => 'nl', 'nn_NO' => 'nn', 'pl_PL' => 'pl', 'pl_UA' => 'pl', 'pt_AO' => 'pt_br', 'pt_BR' => 'pt_br', 'pt_CV' => 'pt_br', 'pt_GW' => 'pt_br', 'pt_MZ' => 'pt_br', 'pt_PT' => 'pt_br', 'pt_ST' => 'pt_br', 'pt_TL' => 'pt_br', 'ro_MD' => 'ro', 'ro_RO' => 'ro', 'ro_RS' => 'ro', 'ru_BY' => 'ru', 'ru_KG' => 'ru', 'ru_KZ' => 'ru', 'ru_RU' => 'ru', 'ru_SJ' => 'ru', 'ru_UA' => 'ru', 'si_LK' => 'si', 'sk_SK' => 'sk', 'sk_RS' => 'sk', 'sq_AL' => 'sq', 'sr_BA' => 'sr', 'sr_ME' => 'sr', 'sr_RS' => 'sr', 'sv_FI' => 'sv', 'sv_SE' => 'sv', 'tr_CY' => 'tr', 'tr_TR' => 'tr', 'tr_DE' => 'tr', 'tr_MK' => 'tr', 'uk_UA' => 'uk', 'vi_VN' => 'vi', 'vi_US' => 'vi', 'zh_CN' => 'zh_cn', 'zh_HK' => 'zh_cn', 'zh_MO' => 'zh_cn', 'zh_SG' => 'zh_cn', 'zh_TW' => 'zh_tw', 'zh_ID' => 'zh_cn', 'zh_MY' => 'zh_cn', 'zh_TH' => 'zh_cn', 'zh_US' => 'zn_cn', ); /** * Get a list of commonly used languages * * @param boolean $native Use native names for languages instead of English ones * @return list of languages in the form 'code' => 'name' */ static function get_common_languages($native = false) { $languages = array(); foreach (self::$common_languages as $code => $name) { $languages[$code] = ($native ? $name[1] : $name[0]); } return $languages; } /** * Get a list of locales (code => language and country) * * @return list of languages in the form 'code' => 'name' */ static function get_locale_list() { return self::$all_locales; } /** * Get a list of languages with at least one element translated in (including the default language) * * @param string $className Look for languages in elements of this class * @return array Map of languages in the form langCode => langName */ static function get_existing_content_languages($className = 'SiteTree', $where = '') { if(!Translatable::is_enabled()) return false; $query = new SQLQuery('Lang',$className.'_lang',$where,"",'Lang'); $dbLangs = $query->execute()->column(); $langlist = array_merge((array)Translatable::default_lang(), (array)$dbLangs); $returnMap = array(); $allCodes = array_merge(self::$all_locales, self::$common_languages); foreach ($langlist as $langCode) { $returnMap[$langCode] = (is_array($allCodes[$langCode]) ? $allCodes[$langCode][0] : $allCodes[$langCode]); } return $returnMap; } /** * Searches the root-directory for module-directories * (identified by having a _config.php on their first directory-level). * Returns all found locales. * * @return array */ static function get_existing_translations() { $locales = array(); $baseDir = Director::baseFolder(); $modules = scandir($baseDir); foreach($modules as $module) { $moduleDir = $baseDir . DIRECTORY_SEPARATOR . $module; $langDir = $moduleDir . DIRECTORY_SEPARATOR . "lang"; if(is_dir($moduleDir) && is_file($moduleDir . DIRECTORY_SEPARATOR . "_config.php") && is_dir($langDir)) { $moduleLocales = scandir($langDir); foreach($moduleLocales as $moduleLocale) { if(preg_match('/(.*)\.php$/',$moduleLocale, $matches)) { $locales[$matches[1]] = self::$all_locales[$matches[1]]; } } } } return $locales; } /** * Get a name from a language code * * @param mixed $code Language code * @param boolean $native If true, the native name will be returned * @return Name of the language */ static function get_language_name($code, $native = false) { $langs = self::$common_languages; return ($native ? $langs[$code][1] : $langs[$code][0]); } /** * Get a name from a locale code (xx_YY) * * @param mixed $code locale code * @return Name of the locale */ static function get_locale_name($code) { $langs = self::get_locale_list(); return isset($langs[$code]) ? $langs[$code] : false; } /** * Get a code from an English language name * * @param mixed $name Name of the language * @return Language code (if the name is not found, it'll return the passed name) */ static function get_language_code($name) { $code = array_search($name,self::get_common_languages()); return ($code ? $code : $name); } /** * Get the current tinyMCE language * * @return Language */ static function get_tinymce_lang() { if(isset(self::$tinymce_lang[self::get_locale()])) { return self::$tinymce_lang[self::get_locale()]; } return 'en'; } /** * Searches the root-directory for module-directories * (identified by having a _config.php on their first directory-level * and a language-file with the default locale in the /lang-subdirectory). * * @return array */ static function get_translatable_modules() { $translatableModules = array(); $baseDir = Director::baseFolder(); $modules = scandir($baseDir); foreach($modules as $module) { $moduleDir = $baseDir . DIRECTORY_SEPARATOR . $module; if( is_dir($moduleDir) && is_file($moduleDir . DIRECTORY_SEPARATOR . "_config.php") && is_file($moduleDir . DIRECTORY_SEPARATOR . "lang" . DIRECTORY_SEPARATOR . self::$default_locale . ".php") ) { $translatableModules[] = $module; } } return $translatableModules; } /** * Given a file name (a php class name, without the .php ext, or a template name, including the .ss extension) * this helper function determines the module where this file is located * * @param string $name php class name or template file name * @return string Module where the file is located */ protected static function get_owner_module($name) { if (substr($name,-3) == '.ss') { global $_TEMPLATE_MANIFEST; $path = current($_TEMPLATE_MANIFEST[substr($name,0,-3)]); ereg('.*/([^/]+)/templates/',$path,$module); } else { global $_CLASS_MANIFEST; $path = $_CLASS_MANIFEST[$name]; ereg('.*/([^/]+)/code/',$path,$module); } return $module[1]; } /** * Build the module's master string table * * @param string $baseDir Silverstripe's base directory * @param string $module Module's name * @return string Generated master string table */ protected static function process_module($baseDir, $module) { // Only search for calls in folder with a _config.php file (which means they are modules) if(is_dir("$baseDir/$module") && is_file("$baseDir/$module/_config.php") && substr($module,0,1) != '.') { $mst = ''; // Search for calls in code files if these exists if(is_dir("$baseDir/$module/code")) { $fileList = array(); self::get_files_rec("$baseDir/$module/code", $fileList); foreach($fileList as $file) { $mst .= self::report_calls_code($file); } } else if('sapphire' == $module) { // sapphire doesn't have the usual module structure, so we'll scan all subfolders $fileList = array(); self::get_files_rec("$baseDir/$module", $fileList); foreach($fileList as $file) { if('.ss' != substr($file,-3)) $mst .= self::report_calls_code($file); } } // Search for calls in template files if these exists if(is_dir("$baseDir/$module/templates")) { $fileList = array(); $includedtpl[$module] = array(); self::get_files_rec("$baseDir/$module/templates", $fileList); foreach($fileList as $index => $file) { $mst .= self::report_calls_tpl($index, $file, $includedtpl[$module]); } } return $mst; } else return false; } /** * Write the master string table of every processed module * * @param string $baseDir Silverstripe's base directory * @param array $allmst Module's master string tables * @param array $includedtpl Templates included by other templates */ protected static function write_mst($baseDir, $allmst, $includedtpl) { // Evaluate the constructed mst foreach($allmst as $mst) eval($mst); // Resolve template dependencies foreach($includedtpl as $tplmodule => $includers) { // Variable initialization $stringsCode = ''; $moduleCode = ''; $modulestoinclude = array(); foreach($includers as $includertpl => $allincluded) foreach($allincluded as $included) // we will only add code if the included template has localizable strings if(isset($lang['en_US']["$included.ss"])) { $module = self::get_owner_module("$included.ss"); /* if the module of the included template is not the same as the includer's one * we will need to load the first one in order to have these included strings in memory */ if ($module != $tplmodule) $modulestoinclude[$module] = $included; // Give the includer name to the included strings in order to be used from the includer template $stringsCode .= "\$lang['en_US']['$includertpl'] = " . "array_merge(\$lang['en_US']['$includertpl'], \$lang['en_US']['$included.ss']);\n"; } // Include a template for every needed module (the module language file will then be autoloaded) foreach($modulestoinclude as $tpltoinclude) $moduleCode .= "self::include_by_class('$tpltoinclude.ss');\n"; // Add the extra code to the existing module mst if ($stringsCode) $allmst[$tplmodule] .= "\n$moduleCode$stringsCode"; } // Write each module language file foreach($allmst as $module => $mst) { // Create folder for lang files $langFolder = $baseDir . '/' . $module . '/lang'; if(!file_exists($baseDir. '/' . $module . '/lang')) { mkdir($langFolder, 02775); touch($baseDir. '/' . $module . '/lang/_manifest_exclude'); } // Open the English file and write the Master String Table if($fh = fopen($langFolder . '/en_US.php', "w")) { fwrite($fh, ""); fclose($fh); echo "Created file: $langFolder/en_US.php
"; } else { user_error("Cannot write language file! Please check permissions of $langFolder/en_US.php", E_USER_ERROR); } } } /** * Helper function that searches for potential files to be parsed * * @param string $folder base directory to scan (will scan recursively) * @param array $fileList Array where potential files will be added to */ protected static function get_files_rec($folder, &$fileList) { $items = scandir($folder); if($items) foreach($items as $item) { if(substr($item,0,1) == '.') continue; if(substr($item,-4) == '.php') $fileList[substr($item,0,-4)] = "$folder/$item"; else if(substr($item,-3) == '.ss') $fileList[$item] = "$folder/$item"; else if(is_dir("$folder/$item")) self::get_files_rec("$folder/$item", $fileList); } } /** * Look for calls to the underscore function in php files and build our MST * * @param string $file Path to the file to be parsed * @return string Built Master String Table from this file */ protected static function report_calls_code($file) { static $callMap; $content = file_get_contents($file); $mst = ''; while (ereg('_t[[:space:]]*\([[:space:]]*("[^"]*"|\\\'[^\']*\\\')[[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,[[:space:]]*[^,)]*)?([[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\'))?[[:space:]]*\)', $content, $regs)) { $entityParts = explode('.',substr($regs[1],1,-1)); $entity = array_pop($entityParts); $class = implode('.',$entityParts); if (isset($callMap["$class--$entity"])) echo "Warning! Redeclaring entity $entity in file $file (previously declared in {$callMap["$class--$entity"]})
"; if (substr($regs[2],0,1) == '"') $regs[2] = addcslashes($regs[2],'\''); $mst .= '$lang[\'en_US\'][\'' . $class . '\'][\'' . $entity . '\'] = '; if ($regs[5]) { $mst .= "array(\n\t'" . substr($regs[2],1,-1) . "',\n\t" . substr($regs[5],1); if ($regs[7]) { if (substr($regs[7],0,1) == '"') $regs[7] = addcslashes($regs[7],'\''); $mst .= ",\n\t'" . substr($regs[7],1,-1) . '\''; } $mst .= "\n);"; } else $mst .= '\'' . substr($regs[2],1,-1) . '\';'; $mst .= "\n"; $content = str_replace($regs[0],"",$content); $callMap["$class--$entity"] = $file; } return $mst; } /** * Look for calls to the underscore function in template files and build our MST * Template version - no "class" argument * * @param string $index Index used to namespace strings * @param string $file Path to the file to be parsed * @param string $included List of explicitly included templates * @return string Built Master String Table from this file */ protected static function report_calls_tpl($index, $file, &$included) { static $callMap; $content = file_get_contents($file); // Search for included templates preg_match_all('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', $content, $inc, PREG_SET_ORDER); foreach ($inc as $template) { if (!isset($included[$index])) $included[$index] = array(); array_push($included[$index], $template[1]); } $mst = ''; while (ereg('_t[[:space:]]*\([[:space:]]*("[^"]*"|\\\'[^\']*\\\')[[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,[[:space:]]*[^,)]*)?([[:space:]]*,[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\'))?[[:space:]]*\)',$content,$regs)) { $entityParts = explode('.',substr($regs[1],1,-1)); $entity = array_pop($entityParts); // Entity redeclaration check if (isset($callMap["$index--$entity"])) echo "Warning! Redeclaring entity $entity in file $file (previously declared in {$callMap["$class--$entity"]})
"; if (substr($regs[2],0,1) == '"') $regs[2] = addcslashes($regs[2],'\''); $mst .= '$lang[\'en_US\'][\'' . $index . '\'][\'' . $entity . '\'] = '; if ($regs[5]) { $mst .= "array(\n\t'" . substr($regs[2],1,-1) . "',\n\t" . substr($regs[5],1); if ($regs[7]) { if (substr($regs[7],0,1) == '"') $regs[7] = addcslashes($regs[7],'\'\\'); $mst .= ",\n\t'" . substr($regs[7],1,-1) . '\''; } $mst .= "\n);"; } else $mst .= '\'' . substr($regs[2],1,-1) . '\';'; $mst .= "\n"; $content = str_replace($regs[0],"",$content); $callMap["$index--$entity"] = $file; } return $mst; } /** * Set the current locale * See http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html for a list of possible locales * * @param string $locale Locale to be set */ static function set_locale($locale) { if ($locale) self::$current_locale = $locale; } /** * Get the current locale * * @return string Current locale in the system */ static function get_locale() { return (!empty(self::$current_locale)) ? self::$current_locale : self::$default_locale; } /** * Set default language (proxy for Translatable::set_default_lang()) * * @param $lang String */ static function set_default_lang($lang) { Translatable::set_default_lang($lang); } /** * Get default language (proxy for Translatable::default_lang()) * * @return String */ static function default_lang() { return Translatable::default_lang(); } /** * Include a locale file determined by module name and locale * * @param string $module Module that contains the locale file * @param string $locale Locale to be loaded */ static function include_locale_file($module, $locale) { if (file_exists($file = Director::getAbsFile("$module/lang/$locale.php"))) include_once($file); } /** * Includes all available language files for a certain defined locale * * @param string $locale All resources from any module in locale $locale will be loaded */ static function include_by_locale($locale) { $topLevel = scandir(Director::baseFolder()); foreach($topLevel as $module) { if (file_exists(Director::getAbsFile("$module/_config.php")) && file_exists($file = Director::getAbsFile("$module/lang/$locale.php"))) { include_once($file); } } } /** * Given a class name (a "locale namespace"), will search for its module and, if available, * will load the resources for the currently defined locale. * If not available, the original English resource will be loaded instead (to avoid blanks) * * @param string $class Resources for this class will be included, according to the set locale. */ static function include_by_class($class) { $module = self::get_owner_module($class); if (file_exists($file = Director::getAbsFile("$module/lang/". self::get_locale() . '.php'))) { include_once($file); } else if (self::get_locale() != 'en_US') { self::set_locale('en_US'); self::include_by_class($class); } else { user_error("Locale file $file should exist", E_USER_WARNING); } } //-----------------------------------------------------------------------------------------------// /** * This method will delete every SiteTree instance in the given language */ public function removelang() { if (!Permission::check("ADMIN")) user_error("You must be an admin to remove a language", E_USER_ERROR); $translatedToDelete = Translatable::get_by_lang('SiteTree',$this->urlParams['ID']); foreach ($translatedToDelete as $object) { $object->delete(); } echo "Language {$this->urlParams['ID']} successfully removed"; } /** * This is the main method to build the master string tables with the original strings. * It will search for existent modules that use the i18n feature, parse the _t() calls * and write the resultant files in the lang folder of each module. */ public function textcollector() { if (!Permission::check("ADMIN")) user_error("You must be an admin to enable text collector mode", E_USER_ERROR); echo "Collecting text...

"; //Calculate base directory $baseDir = Director::baseFolder(); // A master string tables array (one mst per module) $mst = array(); // A list of included templates dependencies $includedtpl = array(); //Search for and process existent modules, or use the passed one instead if (!isset($_GET['module'])) { $topLevel = scandir($baseDir); foreach($topLevel as $module) { // we store the master string tables $processed = self::process_module($baseDir, $module, $includedtpl); if ($processed) $mst[$module] = $processed; } } else { $processed = self::process_module($baseDir, $_GET['module'], $includedtpl); if ($processed) $mst[$module] = $processed; } // Write the generated master string tables self::write_mst($baseDir, $mst, $includedtpl); echo "Done!"; } } ?>