├── .dockerignore ├── .github └── FUNDING.yml ├── .gitignore ├── Dockerfile ├── Makefile ├── assets └── AppAsset.php ├── composer.json ├── composer.lock ├── config ├── .gitignore ├── csrf_key.php.example └── web.php ├── controllers └── SiteController.php ├── docker-compose.dev.yml ├── docker-compose.prod.yml ├── models ├── NormalizedPluralRule.php ├── NumberFormatterInfo.php └── ResourceInfo.php ├── public ├── assets │ └── .gitignore ├── css │ └── site.css ├── favicon.ico ├── index.php └── robots.txt ├── readme.md ├── runtime └── .gitignore └── views ├── layouts └── main.php └── site ├── _icuData.php ├── _locale.php ├── about.php ├── currency-data.php ├── error.php ├── index.php ├── language-data.php ├── message.php ├── number.php ├── region-data.php ├── unit-data.php └── zone-data.php /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .idea 4 | .gitignore 5 | .dockerignore 6 | /Dockerfile 7 | /docker-compose.* 8 | /Makefile 9 | /README.md 10 | /readme.md 11 | /composer.json 12 | /composer.lock 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: samdark 4 | patreon: samdark 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # phpstorm project files 2 | .idea 3 | 4 | # netbeans project files 5 | nbproject 6 | 7 | # zend studio for eclipse project files 8 | .buildpath 9 | .project 10 | .settings 11 | 12 | # windows thumbnail cache 13 | Thumbs.db 14 | 15 | # composer vendor dir 16 | /vendor 17 | 18 | # composer itself is not needed 19 | composer.phar 20 | 21 | # Mac DS_Store Files 22 | .DS_Store 23 | 24 | # phpunit itself is not needed 25 | phpunit.phar 26 | # local phpunit config 27 | /phpunit.xml 28 | 29 | /logs -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/shyim/wolfi-php/frankenphp:8.3 AS base 2 | RUN apk add --no-cache \ 3 | php-frankenphp-8.3-opcache \ 4 | php-frankenphp-8.3-mbstring \ 5 | php-frankenphp-8.3-intl 6 | 7 | FROM base AS prod 8 | COPY . . 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # HELP 2 | # This will output the help for each task 3 | # thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 4 | .PHONY: help 5 | 6 | help: ## This help. 7 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 8 | 9 | # run silent 10 | MAKEFLAGS += --silent 11 | 12 | build: ## Build an image 13 | docker build --target prod --pull -t git.rmcreative.ru/web/intl.rmcreative.ru:latest . 14 | 15 | push: ## Push image to repository 16 | docker push git.rmcreative.ru/web/intl.rmcreative.ru:latest 17 | 18 | up: ## Up the dev environment 19 | docker compose -f docker-compose.dev.yml up -d 20 | 21 | down: ## Down the dev environment 22 | docker compose -f docker-compose.dev.yml down 23 | 24 | deploy: ## Deploy to production 25 | docker -H ssh://docker-web stack deploy --with-registry-auth -d -c docker-compose.prod.yml intl -------------------------------------------------------------------------------- /assets/AppAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class AppAsset extends AssetBundle 17 | { 18 | public $basePath = '@webroot'; 19 | public $baseUrl = '@web'; 20 | public $css = [ 21 | 'css/site.css', 22 | ]; 23 | public $js = [ 24 | ]; 25 | public $depends = [ 26 | 'yii\web\YiiAsset', 27 | 'yii\bootstrap\BootstrapAsset', 28 | ]; 29 | } 30 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samdark/intl-icu-data-tables", 3 | "description": "PHP intl extension, ICU data tables", 4 | "keywords": ["php", "intl"], 5 | "type": "project", 6 | "license": "BSD-3-Clause", 7 | "require": { 8 | "php": ">=5.4.0", 9 | "yiisoft/yii2": "~2.0.7", 10 | "yiisoft/yii2-bootstrap": "~2.0.5", 11 | "yiisoft/yii2-jui": "~2.0.4", 12 | "ext-intl": "*" 13 | }, 14 | "require-dev": { 15 | "yiisoft/yii2-debug": "~2.1.0", 16 | "yiisoft/yii2-gii": "~2.1.0" 17 | }, 18 | "config": { 19 | "process-timeout": 1800, 20 | "fxp-asset": { 21 | "enabled": false 22 | }, 23 | "allow-plugins": { 24 | "yiisoft/yii2-composer": true 25 | } 26 | }, 27 | "repositories": [ 28 | { 29 | "type": "composer", 30 | "url": "https://asset-packagist.org" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "6dce91ba96604962f31bb417c234f3ad", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/bootstrap", 11 | "version": "v3.4.1", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/twbs/bootstrap.git", 15 | "reference": "68b0d231a13201eb14acd3dc84e51543d16e5f7e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/twbs/bootstrap/zipball/68b0d231a13201eb14acd3dc84e51543d16e5f7e", 20 | "reference": "68b0d231a13201eb14acd3dc84e51543d16e5f7e" 21 | }, 22 | "require": { 23 | "bower-asset/jquery": ">=1.9.1,<4.0" 24 | }, 25 | "type": "bower-asset", 26 | "license": [ 27 | "MIT" 28 | ] 29 | }, 30 | { 31 | "name": "bower-asset/inputmask", 32 | "version": "5.0.9", 33 | "source": { 34 | "type": "git", 35 | "url": "https://github.com/RobinHerbots/Inputmask.git", 36 | "reference": "310a33557e2944daf86d5946a5e8c82b9118f8f7" 37 | }, 38 | "dist": { 39 | "type": "zip", 40 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/310a33557e2944daf86d5946a5e8c82b9118f8f7", 41 | "reference": "310a33557e2944daf86d5946a5e8c82b9118f8f7" 42 | }, 43 | "require": { 44 | "bower-asset/jquery": ">=1.7" 45 | }, 46 | "type": "bower-asset", 47 | "license": [ 48 | "http://opensource.org/licenses/mit-license.php" 49 | ] 50 | }, 51 | { 52 | "name": "bower-asset/jquery", 53 | "version": "3.7.1", 54 | "source": { 55 | "type": "git", 56 | "url": "https://github.com/jquery/jquery-dist.git", 57 | "reference": "fde1f76e2799dd877c176abde0ec836553246991" 58 | }, 59 | "dist": { 60 | "type": "zip", 61 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/fde1f76e2799dd877c176abde0ec836553246991", 62 | "reference": "fde1f76e2799dd877c176abde0ec836553246991" 63 | }, 64 | "type": "bower-asset", 65 | "license": [ 66 | "MIT" 67 | ] 68 | }, 69 | { 70 | "name": "bower-asset/jquery-ui", 71 | "version": "1.12.1", 72 | "source": { 73 | "type": "git", 74 | "url": "git@github.com:components/jqueryui.git", 75 | "reference": "44ecf3794cc56b65954cc19737234a3119d036cc" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/components/jqueryui/zipball/44ecf3794cc56b65954cc19737234a3119d036cc", 80 | "reference": "44ecf3794cc56b65954cc19737234a3119d036cc" 81 | }, 82 | "require": { 83 | "bower-asset/jquery": ">=1.6" 84 | }, 85 | "type": "bower-asset", 86 | "license": [ 87 | "MIT" 88 | ] 89 | }, 90 | { 91 | "name": "bower-asset/punycode", 92 | "version": "v2.3.1", 93 | "source": { 94 | "type": "git", 95 | "url": "https://github.com/mathiasbynens/punycode.js.git", 96 | "reference": "9e1b2cda98d215d3a73fcbfe93c62e021f4ba768" 97 | }, 98 | "dist": { 99 | "type": "zip", 100 | "url": "https://api.github.com/repos/mathiasbynens/punycode.js/zipball/9e1b2cda98d215d3a73fcbfe93c62e021f4ba768", 101 | "reference": "9e1b2cda98d215d3a73fcbfe93c62e021f4ba768" 102 | }, 103 | "type": "bower-asset" 104 | }, 105 | { 106 | "name": "bower-asset/yii2-pjax", 107 | "version": "2.0.8", 108 | "source": { 109 | "type": "git", 110 | "url": "git@github.com:yiisoft/jquery-pjax.git", 111 | "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" 112 | }, 113 | "dist": { 114 | "type": "zip", 115 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/a9298d57da63d14a950f1b94366a864bc62264fb", 116 | "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" 117 | }, 118 | "require": { 119 | "bower-asset/jquery": ">=1.8" 120 | }, 121 | "type": "bower-asset", 122 | "license": [ 123 | "MIT" 124 | ] 125 | }, 126 | { 127 | "name": "cebe/markdown", 128 | "version": "1.2.1", 129 | "source": { 130 | "type": "git", 131 | "url": "https://github.com/cebe/markdown.git", 132 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" 133 | }, 134 | "dist": { 135 | "type": "zip", 136 | "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", 137 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", 138 | "shasum": "" 139 | }, 140 | "require": { 141 | "lib-pcre": "*", 142 | "php": ">=5.4.0" 143 | }, 144 | "require-dev": { 145 | "cebe/indent": "*", 146 | "facebook/xhprof": "*@dev", 147 | "phpunit/phpunit": "4.1.*" 148 | }, 149 | "bin": [ 150 | "bin/markdown" 151 | ], 152 | "type": "library", 153 | "extra": { 154 | "branch-alias": { 155 | "dev-master": "1.2.x-dev" 156 | } 157 | }, 158 | "autoload": { 159 | "psr-4": { 160 | "cebe\\markdown\\": "" 161 | } 162 | }, 163 | "notification-url": "https://packagist.org/downloads/", 164 | "license": [ 165 | "MIT" 166 | ], 167 | "authors": [ 168 | { 169 | "name": "Carsten Brandt", 170 | "email": "mail@cebe.cc", 171 | "homepage": "http://cebe.cc/", 172 | "role": "Creator" 173 | } 174 | ], 175 | "description": "A super fast, highly extensible markdown parser for PHP", 176 | "homepage": "https://github.com/cebe/markdown#readme", 177 | "keywords": [ 178 | "extensible", 179 | "fast", 180 | "gfm", 181 | "markdown", 182 | "markdown-extra" 183 | ], 184 | "support": { 185 | "issues": "https://github.com/cebe/markdown/issues", 186 | "source": "https://github.com/cebe/markdown" 187 | }, 188 | "time": "2018-03-26T11:24:36+00:00" 189 | }, 190 | { 191 | "name": "ezyang/htmlpurifier", 192 | "version": "v4.17.0", 193 | "source": { 194 | "type": "git", 195 | "url": "https://github.com/ezyang/htmlpurifier.git", 196 | "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" 197 | }, 198 | "dist": { 199 | "type": "zip", 200 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", 201 | "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", 202 | "shasum": "" 203 | }, 204 | "require": { 205 | "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" 206 | }, 207 | "require-dev": { 208 | "cerdic/css-tidy": "^1.7 || ^2.0", 209 | "simpletest/simpletest": "dev-master" 210 | }, 211 | "suggest": { 212 | "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", 213 | "ext-bcmath": "Used for unit conversion and imagecrash protection", 214 | "ext-iconv": "Converts text to and from non-UTF-8 encodings", 215 | "ext-tidy": "Used for pretty-printing HTML" 216 | }, 217 | "type": "library", 218 | "autoload": { 219 | "files": [ 220 | "library/HTMLPurifier.composer.php" 221 | ], 222 | "psr-0": { 223 | "HTMLPurifier": "library/" 224 | }, 225 | "exclude-from-classmap": [ 226 | "/library/HTMLPurifier/Language/" 227 | ] 228 | }, 229 | "notification-url": "https://packagist.org/downloads/", 230 | "license": [ 231 | "LGPL-2.1-or-later" 232 | ], 233 | "authors": [ 234 | { 235 | "name": "Edward Z. Yang", 236 | "email": "admin@htmlpurifier.org", 237 | "homepage": "http://ezyang.com" 238 | } 239 | ], 240 | "description": "Standards compliant HTML filter written in PHP", 241 | "homepage": "http://htmlpurifier.org/", 242 | "keywords": [ 243 | "html" 244 | ], 245 | "support": { 246 | "issues": "https://github.com/ezyang/htmlpurifier/issues", 247 | "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" 248 | }, 249 | "time": "2023-11-17T15:01:25+00:00" 250 | }, 251 | { 252 | "name": "paragonie/random_compat", 253 | "version": "v9.99.100", 254 | "source": { 255 | "type": "git", 256 | "url": "https://github.com/paragonie/random_compat.git", 257 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" 258 | }, 259 | "dist": { 260 | "type": "zip", 261 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", 262 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", 263 | "shasum": "" 264 | }, 265 | "require": { 266 | "php": ">= 7" 267 | }, 268 | "require-dev": { 269 | "phpunit/phpunit": "4.*|5.*", 270 | "vimeo/psalm": "^1" 271 | }, 272 | "suggest": { 273 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 274 | }, 275 | "type": "library", 276 | "notification-url": "https://packagist.org/downloads/", 277 | "license": [ 278 | "MIT" 279 | ], 280 | "authors": [ 281 | { 282 | "name": "Paragon Initiative Enterprises", 283 | "email": "security@paragonie.com", 284 | "homepage": "https://paragonie.com" 285 | } 286 | ], 287 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 288 | "keywords": [ 289 | "csprng", 290 | "polyfill", 291 | "pseudorandom", 292 | "random" 293 | ], 294 | "support": { 295 | "email": "info@paragonie.com", 296 | "issues": "https://github.com/paragonie/random_compat/issues", 297 | "source": "https://github.com/paragonie/random_compat" 298 | }, 299 | "time": "2020-10-15T08:29:30+00:00" 300 | }, 301 | { 302 | "name": "yiisoft/yii2", 303 | "version": "2.0.51", 304 | "source": { 305 | "type": "git", 306 | "url": "https://github.com/yiisoft/yii2-framework.git", 307 | "reference": "ea1f112f4dc9a9824e77b788019e2d53325d823c" 308 | }, 309 | "dist": { 310 | "type": "zip", 311 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ea1f112f4dc9a9824e77b788019e2d53325d823c", 312 | "reference": "ea1f112f4dc9a9824e77b788019e2d53325d823c", 313 | "shasum": "" 314 | }, 315 | "require": { 316 | "bower-asset/inputmask": "^5.0.8 ", 317 | "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 318 | "bower-asset/punycode": "^2.2", 319 | "bower-asset/yii2-pjax": "~2.0.1", 320 | "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0", 321 | "ext-ctype": "*", 322 | "ext-mbstring": "*", 323 | "ezyang/htmlpurifier": "^4.17", 324 | "lib-pcre": "*", 325 | "paragonie/random_compat": ">=1", 326 | "php": ">=7.3.0", 327 | "yiisoft/yii2-composer": "~2.0.4" 328 | }, 329 | "bin": [ 330 | "yii" 331 | ], 332 | "type": "library", 333 | "extra": { 334 | "branch-alias": { 335 | "dev-master": "2.0.x-dev" 336 | } 337 | }, 338 | "autoload": { 339 | "psr-4": { 340 | "yii\\": "" 341 | } 342 | }, 343 | "notification-url": "https://packagist.org/downloads/", 344 | "license": [ 345 | "BSD-3-Clause" 346 | ], 347 | "authors": [ 348 | { 349 | "name": "Qiang Xue", 350 | "email": "qiang.xue@gmail.com", 351 | "homepage": "https://www.yiiframework.com/", 352 | "role": "Founder and project lead" 353 | }, 354 | { 355 | "name": "Alexander Makarov", 356 | "email": "sam@rmcreative.ru", 357 | "homepage": "https://rmcreative.ru/", 358 | "role": "Core framework development" 359 | }, 360 | { 361 | "name": "Maurizio Domba", 362 | "homepage": "http://mdomba.info/", 363 | "role": "Core framework development" 364 | }, 365 | { 366 | "name": "Carsten Brandt", 367 | "email": "mail@cebe.cc", 368 | "homepage": "https://www.cebe.cc/", 369 | "role": "Core framework development" 370 | }, 371 | { 372 | "name": "Timur Ruziev", 373 | "email": "resurtm@gmail.com", 374 | "homepage": "http://resurtm.com/", 375 | "role": "Core framework development" 376 | }, 377 | { 378 | "name": "Paul Klimov", 379 | "email": "klimov.paul@gmail.com", 380 | "role": "Core framework development" 381 | }, 382 | { 383 | "name": "Dmitry Naumenko", 384 | "email": "d.naumenko.a@gmail.com", 385 | "role": "Core framework development" 386 | }, 387 | { 388 | "name": "Boudewijn Vahrmeijer", 389 | "email": "info@dynasource.eu", 390 | "homepage": "http://dynasource.eu", 391 | "role": "Core framework development" 392 | } 393 | ], 394 | "description": "Yii PHP Framework Version 2", 395 | "homepage": "https://www.yiiframework.com/", 396 | "keywords": [ 397 | "framework", 398 | "yii2" 399 | ], 400 | "support": { 401 | "forum": "https://forum.yiiframework.com/", 402 | "irc": "ircs://irc.libera.chat:6697/yii", 403 | "issues": "https://github.com/yiisoft/yii2/issues?state=open", 404 | "source": "https://github.com/yiisoft/yii2", 405 | "wiki": "https://www.yiiframework.com/wiki" 406 | }, 407 | "funding": [ 408 | { 409 | "url": "https://github.com/yiisoft", 410 | "type": "github" 411 | }, 412 | { 413 | "url": "https://opencollective.com/yiisoft", 414 | "type": "open_collective" 415 | }, 416 | { 417 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2", 418 | "type": "tidelift" 419 | } 420 | ], 421 | "time": "2024-07-18T19:50:00+00:00" 422 | }, 423 | { 424 | "name": "yiisoft/yii2-bootstrap", 425 | "version": "2.0.11", 426 | "source": { 427 | "type": "git", 428 | "url": "https://github.com/yiisoft/yii2-bootstrap.git", 429 | "reference": "83d144f4089adaa7064ad60dc4c1436daa2eb30e" 430 | }, 431 | "dist": { 432 | "type": "zip", 433 | "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/83d144f4089adaa7064ad60dc4c1436daa2eb30e", 434 | "reference": "83d144f4089adaa7064ad60dc4c1436daa2eb30e", 435 | "shasum": "" 436 | }, 437 | "require": { 438 | "bower-asset/bootstrap": "3.4.* | 3.3.* | 3.2.* | 3.1.*", 439 | "yiisoft/yii2": "~2.0.6" 440 | }, 441 | "require-dev": { 442 | "cweagans/composer-patches": "^1.7", 443 | "phpunit/phpunit": "4.8.34" 444 | }, 445 | "type": "yii2-extension", 446 | "extra": { 447 | "branch-alias": { 448 | "dev-master": "2.0.x-dev" 449 | }, 450 | "patches": { 451 | "phpunit/phpunit-mock-objects": { 452 | "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" 453 | }, 454 | "phpunit/phpunit": { 455 | "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", 456 | "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch" 457 | } 458 | } 459 | }, 460 | "autoload": { 461 | "psr-4": { 462 | "yii\\bootstrap\\": "src" 463 | } 464 | }, 465 | "notification-url": "https://packagist.org/downloads/", 466 | "license": [ 467 | "BSD-3-Clause" 468 | ], 469 | "authors": [ 470 | { 471 | "name": "Qiang Xue", 472 | "email": "qiang.xue@gmail.com", 473 | "homepage": "http://www.yiiframework.com/" 474 | }, 475 | { 476 | "name": "Alexander Makarov", 477 | "email": "sam@rmcreative.ru", 478 | "homepage": "http://rmcreative.ru/" 479 | }, 480 | { 481 | "name": "Antonio Ramirez", 482 | "email": "amigo.cobos@gmail.com" 483 | }, 484 | { 485 | "name": "Paul Klimov", 486 | "email": "klimov.paul@gmail.com" 487 | } 488 | ], 489 | "description": "The Twitter Bootstrap extension for the Yii framework", 490 | "keywords": [ 491 | "bootstrap", 492 | "yii2" 493 | ], 494 | "support": { 495 | "forum": "http://www.yiiframework.com/forum/", 496 | "irc": "irc://irc.freenode.net/yii", 497 | "issues": "https://github.com/yiisoft/yii2-bootstrap/issues", 498 | "source": "https://github.com/yiisoft/yii2-bootstrap", 499 | "wiki": "http://www.yiiframework.com/wiki/" 500 | }, 501 | "funding": [ 502 | { 503 | "url": "https://github.com/yiisoft", 504 | "type": "github" 505 | }, 506 | { 507 | "url": "https://opencollective.com/yiisoft", 508 | "type": "open_collective" 509 | }, 510 | { 511 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-bootstrap", 512 | "type": "tidelift" 513 | } 514 | ], 515 | "time": "2021-08-09T20:54:06+00:00" 516 | }, 517 | { 518 | "name": "yiisoft/yii2-composer", 519 | "version": "2.0.10", 520 | "source": { 521 | "type": "git", 522 | "url": "https://github.com/yiisoft/yii2-composer.git", 523 | "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510" 524 | }, 525 | "dist": { 526 | "type": "zip", 527 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/94bb3f66e779e2774f8776d6e1bdeab402940510", 528 | "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510", 529 | "shasum": "" 530 | }, 531 | "require": { 532 | "composer-plugin-api": "^1.0 | ^2.0" 533 | }, 534 | "require-dev": { 535 | "composer/composer": "^1.0 | ^2.0@dev", 536 | "phpunit/phpunit": "<7" 537 | }, 538 | "type": "composer-plugin", 539 | "extra": { 540 | "class": "yii\\composer\\Plugin", 541 | "branch-alias": { 542 | "dev-master": "2.0.x-dev" 543 | } 544 | }, 545 | "autoload": { 546 | "psr-4": { 547 | "yii\\composer\\": "" 548 | } 549 | }, 550 | "notification-url": "https://packagist.org/downloads/", 551 | "license": [ 552 | "BSD-3-Clause" 553 | ], 554 | "authors": [ 555 | { 556 | "name": "Qiang Xue", 557 | "email": "qiang.xue@gmail.com" 558 | }, 559 | { 560 | "name": "Carsten Brandt", 561 | "email": "mail@cebe.cc" 562 | } 563 | ], 564 | "description": "The composer plugin for Yii extension installer", 565 | "keywords": [ 566 | "composer", 567 | "extension installer", 568 | "yii2" 569 | ], 570 | "support": { 571 | "forum": "http://www.yiiframework.com/forum/", 572 | "irc": "irc://irc.freenode.net/yii", 573 | "issues": "https://github.com/yiisoft/yii2-composer/issues", 574 | "source": "https://github.com/yiisoft/yii2-composer", 575 | "wiki": "http://www.yiiframework.com/wiki/" 576 | }, 577 | "funding": [ 578 | { 579 | "url": "https://github.com/yiisoft", 580 | "type": "github" 581 | }, 582 | { 583 | "url": "https://opencollective.com/yiisoft", 584 | "type": "open_collective" 585 | }, 586 | { 587 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-composer", 588 | "type": "tidelift" 589 | } 590 | ], 591 | "time": "2020-06-24T00:04:01+00:00" 592 | }, 593 | { 594 | "name": "yiisoft/yii2-jui", 595 | "version": "2.0.7", 596 | "source": { 597 | "type": "git", 598 | "url": "https://github.com/yiisoft/yii2-jui.git", 599 | "reference": "ce45c16d4fbbe7d1c516d8d0e8311e07f6138eed" 600 | }, 601 | "dist": { 602 | "type": "zip", 603 | "url": "https://api.github.com/repos/yiisoft/yii2-jui/zipball/ce45c16d4fbbe7d1c516d8d0e8311e07f6138eed", 604 | "reference": "ce45c16d4fbbe7d1c516d8d0e8311e07f6138eed", 605 | "shasum": "" 606 | }, 607 | "require": { 608 | "bower-asset/jquery-ui": "~1.12.1", 609 | "yiisoft/yii2": "~2.0.4" 610 | }, 611 | "type": "yii2-extension", 612 | "extra": { 613 | "branch-alias": { 614 | "dev-master": "2.0.x-dev" 615 | } 616 | }, 617 | "autoload": { 618 | "psr-4": { 619 | "yii\\jui\\": "" 620 | } 621 | }, 622 | "notification-url": "https://packagist.org/downloads/", 623 | "license": [ 624 | "BSD-3-Clause" 625 | ], 626 | "authors": [ 627 | { 628 | "name": "Qiang Xue", 629 | "email": "qiang.xue@gmail.com" 630 | } 631 | ], 632 | "description": "The Jquery UI extension for the Yii framework", 633 | "keywords": [ 634 | "jQuery UI", 635 | "yii2" 636 | ], 637 | "support": { 638 | "forum": "http://www.yiiframework.com/forum/", 639 | "irc": "irc://irc.freenode.net/yii", 640 | "issues": "https://github.com/yiisoft/yii2-jui/issues", 641 | "source": "https://github.com/yiisoft/yii2-jui", 642 | "wiki": "http://www.yiiframework.com/wiki/" 643 | }, 644 | "time": "2017-11-25T15:32:29+00:00" 645 | } 646 | ], 647 | "packages-dev": [ 648 | { 649 | "name": "phpspec/php-diff", 650 | "version": "v1.1.3", 651 | "source": { 652 | "type": "git", 653 | "url": "https://github.com/phpspec/php-diff.git", 654 | "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9" 655 | }, 656 | "dist": { 657 | "type": "zip", 658 | "url": "https://api.github.com/repos/phpspec/php-diff/zipball/fc1156187f9f6c8395886fe85ed88a0a245d72e9", 659 | "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9", 660 | "shasum": "" 661 | }, 662 | "type": "library", 663 | "extra": { 664 | "branch-alias": { 665 | "dev-master": "1.0.x-dev" 666 | } 667 | }, 668 | "autoload": { 669 | "psr-0": { 670 | "Diff": "lib/" 671 | } 672 | }, 673 | "notification-url": "https://packagist.org/downloads/", 674 | "license": [ 675 | "BSD-3-Clause" 676 | ], 677 | "authors": [ 678 | { 679 | "name": "Chris Boulton", 680 | "homepage": "http://github.com/chrisboulton" 681 | } 682 | ], 683 | "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", 684 | "support": { 685 | "source": "https://github.com/phpspec/php-diff/tree/v1.1.3" 686 | }, 687 | "time": "2020-09-18T13:47:07+00:00" 688 | }, 689 | { 690 | "name": "yiisoft/yii2-debug", 691 | "version": "2.1.25", 692 | "source": { 693 | "type": "git", 694 | "url": "https://github.com/yiisoft/yii2-debug.git", 695 | "reference": "4d011b9bfc83bde71cde43c9f6837f5a74685ea7" 696 | }, 697 | "dist": { 698 | "type": "zip", 699 | "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/4d011b9bfc83bde71cde43c9f6837f5a74685ea7", 700 | "reference": "4d011b9bfc83bde71cde43c9f6837f5a74685ea7", 701 | "shasum": "" 702 | }, 703 | "require": { 704 | "ext-mbstring": "*", 705 | "php": ">=5.4", 706 | "yiisoft/yii2": "~2.0.13" 707 | }, 708 | "require-dev": { 709 | "cweagans/composer-patches": "^1.7", 710 | "phpunit/phpunit": "4.8.34", 711 | "yiisoft/yii2-coding-standards": "~2.0", 712 | "yiisoft/yii2-swiftmailer": "*" 713 | }, 714 | "type": "yii2-extension", 715 | "extra": { 716 | "branch-alias": { 717 | "dev-master": "2.0.x-dev" 718 | }, 719 | "composer-exit-on-patch-failure": true, 720 | "patches": { 721 | "phpunit/phpunit-mock-objects": { 722 | "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" 723 | }, 724 | "phpunit/phpunit": { 725 | "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", 726 | "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch", 727 | "Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php81.patch" 728 | } 729 | } 730 | }, 731 | "autoload": { 732 | "psr-4": { 733 | "yii\\debug\\": "src" 734 | } 735 | }, 736 | "notification-url": "https://packagist.org/downloads/", 737 | "license": [ 738 | "BSD-3-Clause" 739 | ], 740 | "authors": [ 741 | { 742 | "name": "Qiang Xue", 743 | "email": "qiang.xue@gmail.com" 744 | }, 745 | { 746 | "name": "Simon Karlen", 747 | "email": "simi.albi@outlook.com" 748 | } 749 | ], 750 | "description": "The debugger extension for the Yii framework", 751 | "keywords": [ 752 | "debug", 753 | "debugger", 754 | "yii2" 755 | ], 756 | "support": { 757 | "forum": "http://www.yiiframework.com/forum/", 758 | "irc": "irc://irc.freenode.net/yii", 759 | "issues": "https://github.com/yiisoft/yii2-debug/issues", 760 | "source": "https://github.com/yiisoft/yii2-debug", 761 | "wiki": "http://www.yiiframework.com/wiki/" 762 | }, 763 | "funding": [ 764 | { 765 | "url": "https://github.com/yiisoft", 766 | "type": "github" 767 | }, 768 | { 769 | "url": "https://opencollective.com/yiisoft", 770 | "type": "open_collective" 771 | }, 772 | { 773 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-debug", 774 | "type": "tidelift" 775 | } 776 | ], 777 | "time": "2023-09-26T15:50:00+00:00" 778 | }, 779 | { 780 | "name": "yiisoft/yii2-gii", 781 | "version": "2.1.4", 782 | "source": { 783 | "type": "git", 784 | "url": "https://github.com/yiisoft/yii2-gii.git", 785 | "reference": "d879cb186361fbc6f71a2d994d580b5a071a5642" 786 | }, 787 | "dist": { 788 | "type": "zip", 789 | "url": "https://api.github.com/repos/yiisoft/yii2-gii/zipball/d879cb186361fbc6f71a2d994d580b5a071a5642", 790 | "reference": "d879cb186361fbc6f71a2d994d580b5a071a5642", 791 | "shasum": "" 792 | }, 793 | "require": { 794 | "phpspec/php-diff": "^1.1.0", 795 | "yiisoft/yii2": "~2.0.14" 796 | }, 797 | "require-dev": { 798 | "phpunit/phpunit": "<7", 799 | "yiisoft/yii2-coding-standards": "~2.0" 800 | }, 801 | "type": "yii2-extension", 802 | "extra": { 803 | "branch-alias": { 804 | "dev-master": "2.0.x-dev" 805 | } 806 | }, 807 | "autoload": { 808 | "psr-4": { 809 | "yii\\gii\\": "src" 810 | } 811 | }, 812 | "notification-url": "https://packagist.org/downloads/", 813 | "license": [ 814 | "BSD-3-Clause" 815 | ], 816 | "authors": [ 817 | { 818 | "name": "Qiang Xue", 819 | "email": "qiang.xue@gmail.com" 820 | } 821 | ], 822 | "description": "The Gii extension for the Yii framework", 823 | "keywords": [ 824 | "code generator", 825 | "gii", 826 | "yii2" 827 | ], 828 | "support": { 829 | "forum": "http://www.yiiframework.com/forum/", 830 | "irc": "irc://irc.freenode.net/yii", 831 | "issues": "https://github.com/yiisoft/yii2-gii/issues", 832 | "source": "https://github.com/yiisoft/yii2-gii", 833 | "wiki": "http://www.yiiframework.com/wiki/" 834 | }, 835 | "time": "2020-01-17T13:33:30+00:00" 836 | } 837 | ], 838 | "aliases": [], 839 | "minimum-stability": "stable", 840 | "stability-flags": {}, 841 | "prefer-stable": false, 842 | "prefer-lowest": false, 843 | "platform": { 844 | "php": ">=5.4.0", 845 | "ext-intl": "*" 846 | }, 847 | "platform-dev": {}, 848 | "plugin-api-version": "2.6.0" 849 | } 850 | -------------------------------------------------------------------------------- /config/.gitignore: -------------------------------------------------------------------------------- 1 | /csrf_key.php 2 | -------------------------------------------------------------------------------- /config/csrf_key.php.example: -------------------------------------------------------------------------------- 1 | 'basic', 5 | 'basePath' => dirname(__DIR__), 6 | 'bootstrap' => ['log'], 7 | 'aliases' => [ 8 | '@bower' => '@vendor/bower-asset', 9 | '@npm' => '@vendor/npm-asset', 10 | ], 11 | 'components' => [ 12 | 'request' => [ 13 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 14 | 'cookieValidationKey' => require 'csrf_key.php', 15 | ], 16 | 'cache' => [ 17 | 'class' => 'yii\caching\FileCache', 18 | ], 19 | 'user' => [ 20 | 'identityClass' => 'app\models\User', 21 | 'enableAutoLogin' => true, 22 | ], 23 | 'errorHandler' => [ 24 | 'errorAction' => 'site/error', 25 | ], 26 | 'log' => [ 27 | 'traceLevel' => YII_DEBUG ? 3 : 0, 28 | 'targets' => [ 29 | [ 30 | 'class' => 'yii\log\FileTarget', 31 | 'levels' => ['error', 'warning'], 32 | ], 33 | ], 34 | ], 35 | 'urlManager' => [ 36 | 'enablePrettyUrl' => true, 37 | 'showScriptName' => false, 38 | 'rules' => [ 39 | // compatibility with old URLs 40 | 'tables' => 'site/message-formatting', 41 | 42 | 'general/' => 'site/index', 43 | 'general' => 'site/index', 44 | 45 | '/' => 'site/', 46 | '' => 'site/', 47 | 48 | 'suggestLocale' => 'site/suggest-locale', 49 | ], 50 | ], 51 | ], 52 | ]; 53 | 54 | if (YII_ENV_DEV) { 55 | // configuration adjustments for 'dev' environment 56 | $config['bootstrap'][] = 'debug'; 57 | $config['modules']['debug'] = [ 58 | 'class' => 'yii\debug\Module', 59 | ]; 60 | 61 | $config['bootstrap'][] = 'gii'; 62 | $config['modules']['gii'] = [ 63 | 'class' => 'yii\gii\Module', 64 | ]; 65 | } 66 | 67 | return $config; 68 | -------------------------------------------------------------------------------- /controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | [ 20 | 'class' => 'yii\web\ErrorAction', 21 | ], 22 | ]; 23 | } 24 | 25 | public function actionIndex($locale = '') 26 | { 27 | if ($locale) { 28 | $locale = \Locale::canonicalize($locale); 29 | } 30 | 31 | return $this->render('index', [ 32 | 'locale' => $locale, 33 | ]); 34 | } 35 | 36 | public function actionMessageFormatting($locale = '') 37 | { 38 | if ($locale) { 39 | $locale = \Locale::canonicalize($locale); 40 | } 41 | 42 | if (!$this->localeExists($locale)) { 43 | throw new NotFoundHttpException("Locale $locale was not found."); 44 | } 45 | 46 | return $this->render('message', [ 47 | 'locale' => $locale, 48 | 'spelloutRules' => $this->getRules($locale, \NumberFormatter::SPELLOUT), 49 | 'ordinalRules' => $this->getRules($locale, \NumberFormatter::ORDINAL), 50 | 'durationRules' => $this->getRules($locale, \NumberFormatter::DURATION), 51 | 'pluralCardinalRules' => $this->getPluralCardinalRules($locale), 52 | 'pluralCardinalExample' => $this->getPluralCardinalExample($locale), 53 | 'pluralOrdinalRules' => $this->getPluralOrdinalRules($locale), 54 | 'pluralOrdinalExample' => $this->getPluralOrdinalExample($locale), 55 | ]); 56 | } 57 | 58 | public function actionNumberFormatting($locale = '') 59 | { 60 | if ($locale) { 61 | $locale = \Locale::canonicalize($locale); 62 | } 63 | 64 | return $this->render('number', [ 65 | 'locale' => $locale, 66 | ]); 67 | } 68 | 69 | public function actionCurrencyData($locale = '') 70 | { 71 | if ($locale) { 72 | $locale = \Locale::canonicalize($locale); 73 | } 74 | 75 | return $this->render('currency-data', [ 76 | 'locale' => $locale, 77 | ]); 78 | } 79 | 80 | public function actionLanguageData($locale = '') 81 | { 82 | if ($locale) { 83 | $locale = \Locale::canonicalize($locale); 84 | } 85 | 86 | return $this->render('language-data', [ 87 | 'locale' => $locale, 88 | ]); 89 | } 90 | 91 | public function actionRegionData($locale = '') 92 | { 93 | if ($locale) { 94 | $locale = \Locale::canonicalize($locale); 95 | } 96 | 97 | return $this->render('region-data', [ 98 | 'locale' => $locale, 99 | ]); 100 | } 101 | 102 | public function actionUnitData($locale = '') 103 | { 104 | if ($locale) { 105 | $locale = \Locale::canonicalize($locale); 106 | } 107 | 108 | return $this->render('unit-data', [ 109 | 'locale' => $locale, 110 | ]); 111 | } 112 | 113 | public function actionZoneData($locale = '') 114 | { 115 | if ($locale) { 116 | $locale = \Locale::canonicalize($locale); 117 | } 118 | 119 | return $this->render('zone-data', [ 120 | 'locale' => $locale, 121 | ]); 122 | } 123 | 124 | 125 | private function getRules($locale, $type) 126 | { 127 | $formatter = new \NumberFormatter($locale, $type); 128 | 129 | $rules = []; 130 | $rawRules = explode(';', trim($formatter->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS), ';')); 131 | $default = $formatter->getTextAttribute(\NumberFormatter::DEFAULT_RULESET); 132 | 133 | foreach ($rawRules as $rule) { 134 | $rules[$rule] = ($rule === $default); 135 | } 136 | 137 | return $rules; 138 | } 139 | 140 | private function getLanguage($locale) 141 | { 142 | $parts = \Locale::parseLocale($locale); 143 | return $parts['language']; 144 | } 145 | 146 | private function getNumberThatSatisfiesCondition($condition) 147 | { 148 | $n = 0; 149 | while ($n < 10000) { 150 | try { 151 | if (@eval('return ' . $condition . ';')) { 152 | return $n; 153 | } 154 | } catch (\ParseError $error) { 155 | // ignore 156 | } 157 | 158 | $n++; 159 | } 160 | return []; 161 | } 162 | 163 | private function getPluralCardinalRules($locale, $forPHP = false) 164 | { 165 | return $this->getPluralRules($locale, 'locales', $forPHP); 166 | } 167 | 168 | private function getPluralCardinalExample($locale) 169 | { 170 | $rules = $this->getPluralCardinalRules($locale, true); 171 | 172 | if ($rules === null) { 173 | return null; 174 | } 175 | 176 | $examples = []; 177 | 178 | $ruleStrings = []; 179 | foreach ($rules as $category => $rule) { 180 | $ruleStrings[] = "$category{# $category}"; 181 | $examples[] = $this->getNumberThatSatisfiesCondition($rule); 182 | } 183 | 184 | return [ 185 | '{n, plural, ' . implode(' ', $ruleStrings) . ' other{# other}}', 186 | $examples 187 | ]; 188 | } 189 | 190 | private function getPluralOrdinalRules($locale, $forPHP = false) 191 | { 192 | return $this->getPluralRules($locale, 'locales_ordinals', $forPHP); 193 | } 194 | 195 | private function getPluralOrdinalExample($locale) 196 | { 197 | $rules = $this->getPluralOrdinalRules($locale, true); 198 | 199 | if ($rules === null) { 200 | return null; 201 | } 202 | 203 | $examples = []; 204 | 205 | $ruleStrings = []; 206 | foreach ($rules as $category => $rule) { 207 | $ruleStrings[] = $category . '{#-' . $category . '}'; 208 | $examples[] = $this->getNumberThatSatisfiesCondition($rule); 209 | } 210 | 211 | return [ 212 | '{n, selectordinal, ' . implode(' ', $ruleStrings) . ' other{#-other}}', 213 | $examples 214 | ]; 215 | } 216 | 217 | private function getPluralRules($locale, $type, $forPHP = false) 218 | { 219 | $language = $this->getLanguage($locale); 220 | $bundle = new \ResourceBundle('plurals', null); 221 | $key = $bundle[$type][$language]; 222 | $data = $this->resourceBundleToArray($bundle['rules'][$key]); 223 | 224 | if ($data) { 225 | unset($data['other']); 226 | foreach ($data as $category => $rules) { 227 | $normalizedRule = new NormalizedPluralRule($rules); 228 | if ($forPHP) { 229 | $data[$category] = $normalizedRule->getPhp(); 230 | } else { 231 | $data[$category] = $normalizedRule->getDisplayString(); 232 | } 233 | } 234 | } 235 | 236 | if ($data !== null) { 237 | $order = ['one', 'two', 'few', 'many']; 238 | foreach ($order as $k => $v) { 239 | if (!array_key_exists($v, $data)) { 240 | unset($order[$k]); 241 | } 242 | } 243 | 244 | $data = array_replace(array_flip($order), $data); 245 | } 246 | 247 | return $data; 248 | } 249 | 250 | private function resourceBundleToArray($bundle, $depth = 0) 251 | { 252 | if ($bundle === null) { 253 | return null; 254 | } 255 | 256 | if (is_scalar($bundle)) { 257 | return $bundle; 258 | } 259 | 260 | $result = []; 261 | foreach ($bundle as $key => $value) { 262 | $result[$key] = $this->resourceBundleToArray($value); 263 | } 264 | return $result; 265 | } 266 | 267 | public function actionAbout() 268 | { 269 | return $this->render('about'); 270 | } 271 | 272 | public function actionSuggestLocale($term) 273 | { 274 | $result = []; 275 | $locales = \ResourceBundle::getLocales(''); 276 | 277 | foreach ($locales as $locale) { 278 | if ($term !== '' && strncasecmp($term, $locale, min(strlen($term), strlen($locale))) === 0) { 279 | $result[] = $locale; 280 | } 281 | } 282 | 283 | Yii::$app->response->format = Response::FORMAT_JSON; 284 | return $result; 285 | } 286 | 287 | private function localeExists($term) 288 | { 289 | $locales = \ResourceBundle::getLocales(''); 290 | 291 | foreach ($locales as $locale) { 292 | if (strcasecmp($term, $locale) === 0) { 293 | return true; 294 | } 295 | } 296 | 297 | return false; 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | services: 2 | webserver: 3 | build: 4 | context: . 5 | target: base 6 | restart: unless-stopped 7 | ports: 8 | - "80:80" 9 | - "443:443" 10 | volumes: 11 | - ./:/app 12 | - caddy_data:/data 13 | - caddy_config:/config 14 | - runtime:/app/runtime 15 | tty: true 16 | 17 | volumes: 18 | caddy_data: 19 | caddy_config: 20 | runtime: 21 | -------------------------------------------------------------------------------- /docker-compose.prod.yml: -------------------------------------------------------------------------------- 1 | services: 2 | webserver: 3 | image: git.rmcreative.ru/web/intl.rmcreative.ru:latest 4 | networks: 5 | - caddy_public 6 | volumes: 7 | - caddy_data:/data 8 | - caddy_config:/config 9 | - runtime:/app/app/runtime 10 | environment: 11 | SERVER_NAME: ":80" 12 | deploy: 13 | restart_policy: 14 | condition: on-failure 15 | delay: 5s 16 | max_attempts: 3 17 | window: 120s 18 | labels: 19 | caddy: intl.rmcreative.ru 20 | caddy.reverse_proxy: "{{upstreams 80}}" 21 | 22 | volumes: 23 | caddy_data: 24 | caddy_config: 25 | runtime: 26 | 27 | networks: 28 | caddy_public: 29 | external: true 30 | -------------------------------------------------------------------------------- /models/NormalizedPluralRule.php: -------------------------------------------------------------------------------- 1 | removeSamples($rule); 18 | $rule = $this->removeVisibleFractionDigitsRule($rule); 19 | $this->_rule = $rule; 20 | } 21 | 22 | public function getDisplayString() 23 | { 24 | $rule = strtr($this->_rule, ['mod' => '%', 'not in' => '!=', 'is not' => '!=', 'is' => '=', 'within' => '=', 'in' => '=']); 25 | return trim($rule); 26 | } 27 | 28 | public function getPhp() 29 | { 30 | $rule = $this->_rule; 31 | $rule = $this->replaceAndOrWithPHP($rule); 32 | $rule = $this->replaceRangesWithPHP($rule); 33 | 34 | $replace = [ 35 | '~ = ~' => ' == ', 36 | '~( |^|\()(?:n|i)( |$|\))~' => '\1 $n \2', 37 | '~mod~' => '%', 38 | '~is not~' => '!=', 39 | '~is~' => '==', 40 | ]; 41 | 42 | $rule = preg_replace(array_keys($replace), array_values($replace), $rule); 43 | return trim($rule); 44 | } 45 | 46 | private function replaceRangesWithPHP($rules) 47 | { 48 | return preg_replace_callback('~([^&|!]+)\s*(!?=|in|not in|within)\s*(\d+)\.\.(\d+)~', function($matches) { 49 | list(, $value, $operator, $rangeStart, $rangeEnd) = $matches; 50 | 51 | $out = ' '; 52 | 53 | if (in_array($operator, ['!=', 'not in'], true)) { 54 | $out .= '!'; 55 | } 56 | 57 | $out .= "in_array({$value}, range({$rangeStart}, {$rangeEnd}))"; 58 | return $out; 59 | }, $rules); 60 | } 61 | 62 | private function replaceAndOrWithPHP($rules) 63 | { 64 | return strtr($rules, ['and' => '&&', 'or' => '||']); 65 | } 66 | 67 | private function removeSamples($rules) 68 | { 69 | return preg_replace('~\s*@(integer|decimal).*~', '', $rules); 70 | } 71 | 72 | private function removeVisibleFractionDigitsRule($rules) 73 | { 74 | $replace = [ 75 | '~v = 0 and ~' => '', 76 | '~ and v = 0~' => '', 77 | '~ or v = 0~' => '', 78 | '~v = 0 or ~' => '', 79 | '~v = 0~' => '', 80 | ]; 81 | 82 | return preg_replace(array_keys($replace), array_values($replace), $rules); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /models/NumberFormatterInfo.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class NumberFormatterInfo extends BaseObject 13 | { 14 | /** 15 | * @var array 16 | * @see http://php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants 17 | */ 18 | public static $types = [ 19 | // NumberFormatter::PATTERN_DECIMAL => ['PATTERN_DECIMAL', 'Decimal format defined by pattern.'], 20 | // NumberFormatter::PATTERN_RULEBASED => ['PATTERN_RULEBASED', 'Rule-based format defined by pattern.'], 21 | NumberFormatter::DECIMAL => ['DECIMAL', 'Decimal format.'], 22 | NumberFormatter::CURRENCY => ['CURRENCY', 'Currency format.'], 23 | NumberFormatter::PERCENT => ['PERCENT', 'Percent format.'], 24 | NumberFormatter::SCIENTIFIC => ['SCIENTIFIC', 'Scientific format.'], 25 | NumberFormatter::SPELLOUT => ['SPELLOUT', 'Spellout rule-based format.'], 26 | NumberFormatter::ORDINAL => ['ORDINAL', 'Ordinal rule-based format.'], 27 | NumberFormatter::DURATION => ['DURATION', 'Duration rule-based format.'], 28 | NumberFormatter::DEFAULT_STYLE => ['DEFAULT_STYLE', 'Default format for the locale.'], 29 | // NumberFormatter::IGNORE => ['IGNORE', 'Alias for PATTERN_DECIMAL.'], 30 | ]; 31 | 32 | public static $formats = [ 33 | NumberFormatter::TYPE_DEFAULT => ['TYPE_DEFAULT', 'Derive the type from variable type.'], 34 | NumberFormatter::TYPE_INT32 => ['TYPE_INT32', 'Format/parse as 32-bit integer.'], 35 | NumberFormatter::TYPE_INT64 => ['TYPE_INT64', 'Format/parse as 64-bit integer.'], 36 | NumberFormatter::TYPE_DOUBLE => ['TYPE_INT64', 'Format/parse as floating point value.'], 37 | NumberFormatter::TYPE_CURRENCY => ['TYPE_CURRENCY', 'Format/parse as currency value.'], 38 | ]; 39 | 40 | public static $attributes = [ 41 | NumberFormatter::PARSE_INT_ONLY => ['PARSE_INT_ONLY', 'Parse integers only.'], 42 | NumberFormatter::GROUPING_USED => ['GROUPING_USED', 'Use grouping separator.'], 43 | NumberFormatter::DECIMAL_ALWAYS_SHOWN => ['DECIMAL_ALWAYS_SHOWN', 'Always show decimal point.'], 44 | NumberFormatter::MAX_INTEGER_DIGITS => ['MAX_INTEGER_DIGITS', 'Maximum integer digits.'], 45 | NumberFormatter::MIN_INTEGER_DIGITS => ['MIN_INTEGER_DIGITS', 'Minimum integer digits.'], 46 | NumberFormatter::INTEGER_DIGITS => ['INTEGER_DIGITS', 'Integer digits.'], 47 | NumberFormatter::MAX_FRACTION_DIGITS => ['MAX_FRACTION_DIGITS', 'Maximum fraction digits.'], 48 | NumberFormatter::MIN_FRACTION_DIGITS => ['MIN_FRACTION_DIGITS', 'Minimum fraction digits.'], 49 | NumberFormatter::FRACTION_DIGITS => ['FRACTION_DIGITS', 'Fraction digits.'], 50 | NumberFormatter::MULTIPLIER => ['MULTIPLIER', 'Multiplier.'], 51 | NumberFormatter::GROUPING_SIZE => ['GROUPING_SIZE', 'Grouping size.'], 52 | NumberFormatter::ROUNDING_MODE => ['ROUNDING_MODE', 'Rounding Mode.'], 53 | NumberFormatter::ROUNDING_INCREMENT => ['ROUNDING_INCREMENT', 'Rounding increment.'], 54 | NumberFormatter::FORMAT_WIDTH => ['FORMAT_WIDTH', 'The width to which the output of format() is padded.'], 55 | NumberFormatter::PADDING_POSITION => ['PADDING_POSITION', 'The position at which padding will take place.'], 56 | NumberFormatter::SECONDARY_GROUPING_SIZE => ['SECONDARY_GROUPING_SIZE', 'Secondary grouping size.'], 57 | NumberFormatter::SIGNIFICANT_DIGITS_USED => ['SIGNIFICANT_DIGITS_USED', 'Use significant digits.'], 58 | NumberFormatter::MIN_SIGNIFICANT_DIGITS => ['MIN_SIGNIFICANT_DIGITS', 'Minimum significant digits.'], 59 | NumberFormatter::MAX_SIGNIFICANT_DIGITS => ['MAX_SIGNIFICANT_DIGITS', 'Maximum significant digits.'], 60 | NumberFormatter::LENIENT_PARSE => ['LENIENT_PARSE', 'Lenient parse mode used by rule-based formats.'], 61 | ]; 62 | 63 | public static $textAttributes = [ 64 | NumberFormatter::POSITIVE_PREFIX => ['POSITIVE_PREFIX', 'Positive suffix.'], 65 | NumberFormatter::NEGATIVE_PREFIX => ['NEGATIVE_PREFIX', 'Negative prefix.'], 66 | NumberFormatter::NEGATIVE_SUFFIX => ['NEGATIVE_SUFFIX', 'Negative suffix.'], 67 | NumberFormatter::PADDING_CHARACTER => ['PADDING_CHARACTER', 'The character used to pad to the format width.'], 68 | NumberFormatter::CURRENCY_CODE => ['CURRENCY_CODE', 'The ISO currency code.'], 69 | NumberFormatter::DEFAULT_RULESET => [ 70 | 'DEFAULT_RULESET', 71 | 'The default rule set. This is only available with rule-based formatters.' 72 | ], 73 | NumberFormatter::PUBLIC_RULESETS => [ 74 | 'PUBLIC_RULESETS', 75 | 'The public rule sets.This is only available with rule-based formatters. This is a read-only attribute. The public rulesets are returned as a single string, with each ruleset name delimited by \';\' (semicolon).' 76 | ], 77 | ]; 78 | 79 | public static $symbols = [ 80 | NumberFormatter::DECIMAL_SEPARATOR_SYMBOL => ['DECIMAL_SEPARATOR_SYMBOL', 'The decimal separator.'], 81 | NumberFormatter::GROUPING_SEPARATOR_SYMBOL => ['GROUPING_SEPARATOR_SYMBOL', 'The grouping separator.'], 82 | NumberFormatter::PATTERN_SEPARATOR_SYMBOL => ['PATTERN_SEPARATOR_SYMBOL', 'The pattern separator.'], 83 | NumberFormatter::PERCENT_SYMBOL => ['PERCENT_SYMBOL', 'The percent sign.'], 84 | NumberFormatter::ZERO_DIGIT_SYMBOL => ['ZERO_DIGIT_SYMBOL', 'Zero.'], 85 | NumberFormatter::DIGIT_SYMBOL => ['DIGIT_SYMBOL', 'Character representing a digit in the pattern.'], 86 | NumberFormatter::MINUS_SIGN_SYMBOL => ['MINUS_SIGN_SYMBOL', 'The minus sign.'], 87 | NumberFormatter::PLUS_SIGN_SYMBOL => ['PLUS_SIGN_SYMBOL', 'The plus sign.'], 88 | NumberFormatter::CURRENCY_SYMBOL => ['CURRENCY_SYMBOL', 'The currency symbol.'], 89 | NumberFormatter::INTL_CURRENCY_SYMBOL => ['INTL_CURRENCY_SYMBOL', 'The international currency symbol.'], 90 | NumberFormatter::MONETARY_SEPARATOR_SYMBOL => ['MONETARY_SEPARATOR_SYMBOL', 'The monetary separator.'], 91 | NumberFormatter::EXPONENTIAL_SYMBOL => ['EXPONENTIAL_SYMBOL', 'The exponential symbol.'], 92 | NumberFormatter::PERMILL_SYMBOL => ['PERMILL_SYMBOL', 'Per mill symbol.'], 93 | NumberFormatter::PAD_ESCAPE_SYMBOL => ['PAD_ESCAPE_SYMBOL', 'Escape padding character.'], 94 | NumberFormatter::INFINITY_SYMBOL => ['INFINITY_SYMBOL', 'Infinity symbol.'], 95 | NumberFormatter::NAN_SYMBOL => ['NAN_SYMBOL', 'Not-a-number symbol.'], 96 | NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL => ['SIGNIFICANT_DIGIT_SYMBOL', 'Significant digit symbol.'], 97 | NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL => [ 98 | 'MONETARY_GROUPING_SEPARATOR_SYMBOL', 99 | 'The monetary grouping separator. ' 100 | ], 101 | ]; 102 | 103 | public static function getSymbolTable($locale) 104 | { 105 | $result = []; 106 | foreach (static::$types as $type => $typeDetails) { 107 | $nf = new NumberFormatter($locale, $type); 108 | foreach (static::$symbols as $symbol => $symbolDetails) { 109 | $result[$symbol][$type] = $nf->getSymbol($symbol); 110 | } 111 | } 112 | return $result; 113 | } 114 | 115 | public static function getPatternTable($locale) 116 | { 117 | $result = []; 118 | foreach (static::$types as $type => $typeDetails) { 119 | $nf = new NumberFormatter($locale, $type); 120 | $result[$type] = $nf->getPattern(); 121 | } 122 | return $result; 123 | } 124 | 125 | public static function getDefaultCurrency($locale) 126 | { 127 | $nf = new NumberFormatter($locale, NumberFormatter::CURRENCY); 128 | return $nf->getSymbol(NumberFormatter::INTL_CURRENCY_SYMBOL); 129 | } 130 | 131 | public static function getDefaultCurrencySymbol($locale) 132 | { 133 | $nf = new NumberFormatter($locale, NumberFormatter::CURRENCY); 134 | return $nf->getSymbol(NumberFormatter::CURRENCY_SYMBOL); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /models/ResourceInfo.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ResourceInfo extends BaseObject 12 | { 13 | public static function defaultData($locale) 14 | { 15 | $r = ResourceBundle::create($locale, null); 16 | return self::dumpIntlResource($r); 17 | } 18 | 19 | public static function currencyData($locale) 20 | { 21 | $r = ResourceBundle::create($locale, 'ICUDATA-curr'); 22 | return self::dumpIntlResource($r); 23 | } 24 | 25 | public static function languageData($locale) 26 | { 27 | $r = ResourceBundle::create($locale, 'ICUDATA-lang'); 28 | return self::dumpIntlResource($r); 29 | } 30 | 31 | public static function regionData($locale) 32 | { 33 | $r = ResourceBundle::create($locale, 'ICUDATA-region'); 34 | return self::dumpIntlResource($r); 35 | } 36 | 37 | public static function unitData($locale) 38 | { 39 | $r = ResourceBundle::create($locale, 'ICUDATA-unit'); 40 | return self::dumpIntlResource($r); 41 | } 42 | 43 | public static function zoneData($locale) 44 | { 45 | $r = ResourceBundle::create($locale, 'ICUDATA-zone'); 46 | return self::dumpIntlResource($r); 47 | } 48 | 49 | private static function dumpIntlResource($resourceBundle) 50 | { 51 | return self::recursiveIteratorToArray($resourceBundle); 52 | } 53 | 54 | private static function recursiveIteratorToArray($iterator) 55 | { 56 | if ($iterator === null) { 57 | return []; 58 | } 59 | 60 | return array_map(function ($item) { 61 | return $item instanceof \ResourceBundle ? self::recursiveIteratorToArray($item) : $item; 62 | }, iterator_to_array($iterator)); 63 | } 64 | 65 | public static function getCurrencyName($iso, $locale) 66 | { 67 | $currencyInfo = ResourceBundle::create($locale, 'ICUDATA-curr')->get('Currencies')->get($iso); 68 | if ($currencyInfo === null) { 69 | return '-'; 70 | } 71 | return $currencyInfo[1]; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /public/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/css/site.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | .wrap { 7 | min-height: 100%; 8 | height: auto; 9 | margin: 0 auto -60px; 10 | padding: 0 0 60px; 11 | } 12 | 13 | .wrap > .container { 14 | padding: 70px 15px 20px; 15 | } 16 | 17 | .footer { 18 | height: 60px; 19 | background-color: #f5f5f5; 20 | border-top: 1px solid #ddd; 21 | padding-top: 20px; 22 | } 23 | 24 | .jumbotron { 25 | text-align: center; 26 | background-color: transparent; 27 | } 28 | 29 | .jumbotron .btn { 30 | font-size: 21px; 31 | padding: 14px 24px; 32 | } 33 | 34 | .not-set { 35 | color: #c55; 36 | font-style: italic; 37 | } 38 | 39 | /* add sorting icons to gridview sort links */ 40 | a.asc:after, a.desc:after { 41 | position: relative; 42 | top: 1px; 43 | display: inline-block; 44 | font-family: 'Glyphicons Halflings'; 45 | font-style: normal; 46 | font-weight: normal; 47 | line-height: 1; 48 | padding-left: 5px; 49 | } 50 | 51 | a.asc:after { 52 | content: /*"\e113"*/ "\e151"; 53 | } 54 | 55 | a.desc:after { 56 | content: /*"\e114"*/ "\e152"; 57 | } 58 | 59 | .sort-numerical a.asc:after { 60 | content: "\e153"; 61 | } 62 | 63 | .sort-numerical a.desc:after { 64 | content: "\e154"; 65 | } 66 | 67 | .sort-ordinal a.asc:after { 68 | content: "\e155"; 69 | } 70 | 71 | .sort-ordinal a.desc:after { 72 | content: "\e156"; 73 | } 74 | 75 | .grid-view th { 76 | white-space: nowrap; 77 | } 78 | 79 | .hint-block { 80 | display: block; 81 | margin-top: 5px; 82 | color: #999; 83 | } 84 | 85 | .error-summary { 86 | color: #a94442; 87 | background: #fdf7f7; 88 | border-left: 3px solid #eed3d7; 89 | padding: 10px 20px; 90 | margin: 0 0 15px 0; 91 | } 92 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samdark/intl-icu-data-tables/b58bc78efa000e51c9d3fedd4cfd9c5dd008e7a5/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | run(); 13 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # PHP intl extension, ICU data tables 2 | 3 | Live version is available at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/). 4 | 5 | The project was created to simplify checking out various PHP intl / ICU / CLDR data which is mainly used in translation 6 | strings without the need to check different websites and search huge data tables for locale you need. 7 | 8 | Instead, you can enter locale code and get all the info for just that locale right away. 9 | 10 | ## What's currently displayed 11 | 12 | - General locale info. 13 | - Plural rules. Also [available via CLDR website](http://www.unicode.org/cldr/charts/27/supplemental/language_plural_rules.html). 14 | - Numbering schemas. Not available anywhere but ICU resource sources which aren't too user-friendly to read. 15 | - Number formatting rules and data. 16 | - Currency data. 17 | - Language data. 18 | - Region data. 19 | - Zone data. 20 | - Unit data. 21 | 22 | ## Are examples broken? 23 | 24 | There are [known issues](https://bugs.php.net/bug.php?id=70484) with PHP intl extension regarding usage of named 25 | parameters such as `{n}`. The Severity of issues depends on PHP and intl versions used. 26 | The primary goal of the project is to serve as an info source for using with 27 | [Yii 2.0 framework](http://www.yiiframework.com/) which provides wrapper around intl allowing usage of named parameters in all possible cases. 28 | 29 | If you're not using Yii, try positional placeholders such as `{0}` instead. 30 | 31 | # Directory structure 32 | 33 | assets/ contains assets definition 34 | config/ contains application configurations 35 | controllers/ contains Web controller classes 36 | runtime/ contains files generated during runtime 37 | vendor/ contains dependent 3rd-party packages 38 | views/ contains view files for the Web application 39 | public/ contains the entry script and Web resources 40 | 41 | # Requirements 42 | 43 | The minimum requirement by this project that your Web server supports PHP 5.4.0 with mbstring and intl extensions. 44 | 45 | # Using Docker 46 | 47 | Copy `/config/csrf_key.php.example` to `/config/csrf_key.php`. Paste validation key there. 48 | 49 | ## Run a dev instance 50 | 51 | ```sh 52 | make up 53 | ``` 54 | 55 | Access it at [http://localhost/](http://localhost/). 56 | 57 | ## Build production image and push it 58 | 59 | ```sh 60 | make build 61 | make push 62 | ``` 63 | 64 | ## Deploy to production 65 | 66 | ```sh 67 | make deploy 68 | ``` 69 | 70 | # Local installation 71 | 72 | 1. Download zip. 73 | 2. Copy `/config/csrf_key.php.example` to `/config/csrf_key.php`. Paste validation key there. 74 | 3. Run `composer global require "fxp/composer-asset-plugin:~1.1.0" && composer install`. 75 | 4. Configure your webserver to point to `/web`. 76 | -------------------------------------------------------------------------------- /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 14 | beginPage() ?> 15 | 16 | 17 | 18 | 19 | 20 | 21 | <?= Html::encode($this->title) ?> 22 | head() ?> 23 | 24 | 25 | beginBody() ?> 26 | 27 |
28 | 'PHP intl extension, ICU data tables', 31 | 'brandUrl' => Yii::$app->homeUrl, 32 | 'options' => [ 33 | 'class' => 'navbar-inverse navbar-fixed-top', 34 | ], 35 | ]); 36 | echo Nav::widget([ 37 | 'options' => ['class' => 'navbar-nav navbar-right'], 38 | 'items' => [ 39 | ['label' => 'About', 'url' => ['/site/about']], 40 | ], 41 | ]); 42 | NavBar::end(); 43 | ?> 44 | 45 |
46 | isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], 48 | ]) ?> 49 | 50 |
51 |
52 | 53 | 60 | 61 | endBody() ?> 62 | 63 | 64 | endPage() ?> 65 | -------------------------------------------------------------------------------- /views/site/_icuData.php: -------------------------------------------------------------------------------- 1 | Parent Locale: ' . Html::a(Html::encode($icuData['%%Parent']), ['', 'locale' => $icuData['%%Parent']]) . '

'; 12 | unset($icuData['%%Parent']); 13 | } 14 | 15 | foreach($icuData as $key => $data) { 16 | $id = 'icu-data-' . Inflector::slug($key); 17 | echo "

" . Html::encode($key) . " #

"; 18 | echo '
';
19 |     VarDumper::dump($data, 10, true);
20 |     echo '
'; 21 | } 22 | -------------------------------------------------------------------------------- /views/site/_locale.php: -------------------------------------------------------------------------------- 1 | title = ''; 12 | if ($locale) { 13 | $this->title = \Locale::getDisplayName($locale, Yii::$app->language) . ', '. Html::encode($locale) . ' - '; 14 | } 15 | if ($title) { 16 | $this->title .= Html::encode($title) . ' - '; 17 | } 18 | $this->title .= 'PHP intl extension, ICU data tables'; 19 | ?> 20 | 21 | 'form-horizontal']) ?> 22 |
23 | 'locale', 25 | 'value' => $locale, 26 | 'options' => ['class' => 'form-control', 'placeholder' => 'Enter locale code such as "en" or "en_US"', 'autofocus' => true], 27 | 'clientOptions' => [ 28 | 'source' => Url::toRoute(['site/suggest-locale']), 29 | ], 30 | ]) ?> 31 | 32 | 'btn btn-primary']) ?> 33 | 34 |
35 | 36 | 37 | 38 | 39 |

language)) ?>

40 | Based on PHP intl data: ICU . Data . 41 | 42 | [ 44 | ['label' => 'General', 'url' => ['site/index', 'locale' => $locale], 'active' => $this->context->action->id === 'index'], 45 | ['label' => 'Message Formatting', 'url' => ['site/message-formatting', 'locale' => $locale], 'active' => $this->context->action->id === 'message-formatting'], 46 | ['label' => 'Number Formatting', 'url' => ['site/number-formatting', 'locale' => $locale], 'active' => $this->context->action->id === 'number-formatting'], 47 | ['label' => 'ICU Currency Data', 'url' => ['site/currency-data', 'locale' => $locale], 'active' => $this->context->action->id === 'currency-data'], 48 | ['label' => 'ICU Language Data', 'url' => ['site/language-data', 'locale' => $locale], 'active' => $this->context->action->id === 'language-data'], 49 | ['label' => 'ICU Region Data', 'url' => ['site/region-data', 'locale' => $locale], 'active' => $this->context->action->id === 'region-data'], 50 | ['label' => 'ICU Zone Data', 'url' => ['site/zone-data', 'locale' => $locale], 'active' => $this->context->action->id === 'zone-data'], 51 | ['label' => 'ICU Unit Data', 'url' => ['site/unit-data', 'locale' => $locale], 'active' => $this->context->action->id === 'unit-data'], 52 | ] 53 | ]) ?> 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /views/site/about.php: -------------------------------------------------------------------------------- 1 | title = 'About the project - PHP intl extension, ICU data tables'; 3 | ?> 4 | 5 |

About the project

6 | 7 |

The project was created by Alexander Makarov to simplify checking out 8 | various PHP intl / ICU / CLDR data which is mainly used in translation strings without the need to check different 9 | websites and search huge data tables for locale you need.

10 | 11 |

Instead you can enter locale code and get all the info for just that locale right away.

12 | 13 |

It was then improved by Carsten Brandt to display more ICU data.

14 | 15 |

What's currently displayed:

16 | 17 |
    18 |
  • General locale info.
  • 19 |
  • Plural rules. Also available via CLDR website.
  • 20 |
  • Numbering schemas. Not available anywhere but ICU resource sources which aren't too user friendly to read.
  • 21 |
  • Number formatting rules and data.
  • 22 |
  • Currency data.
  • 23 |
  • Language data.
  • 24 |
  • Region data.
  • 25 |
  • Zone data.
  • 26 |
  • Unit data.
  • 27 |
28 | 29 |

Are examples broken?

30 | 31 |

There are known issues with PHP intl extension regarding usage of named 32 | parameters such as {n}. Severity of issues depends on PHP and intl versions used. The primary goal of the project 33 | is to serve as info source for using with Yii 2.0 framework which provides 34 | wrapper around intl allowing usage of named parameters in all possible cases.

35 | 36 |

If you're not using Yii, try positional placeholders such as {0} instead.

37 | 38 |

Source code, issue and pull requests

39 | 40 |

Source code is available at GitHub. Feel free to submit issues 41 | and pull requests.

-------------------------------------------------------------------------------- /views/site/currency-data.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => 'ICU Currency Data']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

ICU Currency Data #

17 | 18 |

In PHP you may retrieve this data using the following code:

19 |
20 | 
21 | 
22 | $data = ResourceBundle::create('', 'ICUDATA-curr');
23 | foreach($data as $name => $value) {
24 |     echo "$name: " . print_r($value, true);
25 | }
26 | 
27 | 28 | render('_icuData', ['icuData' => ResourceInfo::currencyData($locale)]) ?> 29 | 30 | -------------------------------------------------------------------------------- /views/site/error.php: -------------------------------------------------------------------------------- 1 | title = $name; 11 | ?> 12 |
13 | 14 |

title) ?>

15 | 16 |
17 | 18 |
19 | 20 |

21 | The above error occurred while the Web server was processing your request. 22 |

23 |

24 | Please contact us if you think this is a server error. Thank you. 25 |

26 | 27 |
28 | -------------------------------------------------------------------------------- /views/site/index.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => '']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

General Information #

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
CodeName (language) ?>)Name ()
Languagenone' ?>language) ?: 'none' ?>none' ?>
Regionnone' ?>language) ?: 'none' ?>none' ?>
Scriptnone' ?>language) ?: 'none' ?>none' ?>
Default Currencynone' ?>language) : 'none' ?>none' ?>
51 | 52 | 53 |

ICU Data #

54 | 55 | render('_icuData', ['icuData' => ResourceInfo::defaultData($locale)]) ?> 56 | 57 | -------------------------------------------------------------------------------- /views/site/language-data.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => 'ICU Language Data']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

ICU Language Data #

17 | 18 |

In PHP you may retrieve this data using the following code:

19 |
20 | 
21 | 
22 | $data = ResourceBundle::create('', 'ICUDATA-lang');
23 | foreach($data as $name => $value) {
24 |     echo "$name: " . print_r($value, true);
25 | }
26 | 
27 | 28 | render('_icuData', ['icuData' => ResourceInfo::languageData($locale)]) ?> 29 | 30 | -------------------------------------------------------------------------------- /views/site/message.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => '']); 18 | 19 | if ($locale): 20 | ?> 21 | 22 |

Plural Rules #

23 | 24 |

Cardinal plural #

25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | $rules): ?> 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
CategoryRules
otherEverything else
43 | 44 |
45 | 46 |
    47 | 48 |
  • i18n->format($pluralCardinalExample[0], ['n' => $n], $locale) ?>
  • 49 | 50 |
  • i18n->format($pluralCardinalExample[0], ['n' => 0.12], $locale) ?>
  • 51 |
52 | 53 | Not supported. 54 | 55 | 56 |

Ordinal selectordinal #

57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | $rules): ?> 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
CategoryRules
otherEverything else
75 | 76 |
77 | 78 |
    79 | 80 |
  • i18n->format($pluralOrdinalExample[0], ['n' => $n], $locale) ?>
  • 81 | 82 |
  • i18n->format($pluralOrdinalExample[0], ['n' => 0.12], $locale) ?>
  • 83 |
84 | 85 | Not supported. 86 | 87 | 88 |

Numbering schemas #

89 | 90 |

Spellout #

91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | $isDefault): ?> 99 | 100 | 107 | 110 | 113 | 114 | 115 |
SchemaExampleResult
101 | 102 | (default) 103 | 104 | 105 | 106 | 108 |
{n, spellout,}
109 |
111 | i18n->format('{n, spellout,' . $rule . '}', ['n' => 471], $locale) ?> 112 |
116 | 117 |

Ordinal #

118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | $isDefault): ?> 126 | 127 | 134 | 137 | 140 | 141 | 142 |
SchemaExampleResult
128 | 129 | (default) 130 | 131 | 132 | 133 | 135 |
{n, ordinal,}
136 |
138 | i18n->format('{n, ordinal,' . $rule . '}', ['n' => 471], $locale) ?> 139 |
143 | 144 |

Duration #

145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | $isDefault): ?> 153 | 154 | 161 | 164 | 167 | 168 | 169 |
SchemaExampleResult
155 | 156 | (default) 157 | 158 | 159 | 160 | 162 |
{n, duration,}
163 |
165 | i18n->format('{n, duration,' . $rule . '}', ['n' => 471227], $locale) ?> 166 |
170 | 171 | -------------------------------------------------------------------------------- /views/site/number.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => '']); 11 | 12 | if ($locale): 13 | ?> 14 | 15 |

NumberFormatter Symbols #

16 | 17 | 18 | 19 | 20 | $typeDetails): ?> 21 | 22 | 23 | 24 | $symbols): ?> 25 | 26 | 27 | $symbol): ?> 28 | 29 | 30 | 31 | 32 |
 

33 | 34 |

NumberFormatter Patterns #

35 | 36 | 37 | 38 | 39 | 40 | 41 | $pattern): ?> 42 | 43 | 44 | 45 | 46 | 47 |
Formatter TypePattern

', $pattern) ?>
48 | 49 | -------------------------------------------------------------------------------- /views/site/region-data.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => 'ICU Region Data']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

ICU Region Data #

17 | 18 |

In PHP you may retrieve this data using the following code:

19 |
20 | 
21 | 
22 | $data = ResourceBundle::create('', 'ICUDATA-region');
23 | foreach($data as $name => $value) {
24 |     echo "$name: " . print_r($value, true);
25 | }
26 | 
27 | 28 | render('_icuData', ['icuData' => ResourceInfo::regionData($locale)]) ?> 29 | 30 | -------------------------------------------------------------------------------- /views/site/unit-data.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => 'ICU Unit Data']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

ICU Unit Data #

17 | 18 |

In PHP you may retrieve this data using the following code:

19 |
20 | 
21 | 
22 | $data = ResourceBundle::create('', 'ICUDATA-unit');
23 | foreach($data as $name => $value) {
24 |     echo "$name: " . print_r($value, true);
25 | }
26 | 
27 | 28 | render('_icuData', ['icuData' => ResourceInfo::unitData($locale)]) ?> 29 | 30 | -------------------------------------------------------------------------------- /views/site/zone-data.php: -------------------------------------------------------------------------------- 1 | render('_locale', ['locale' => $locale, 'title' => 'ICU Zone Data']); 12 | 13 | if ($locale): 14 | ?> 15 | 16 |

ICU Zone Data #

17 | 18 |

In PHP you may retrieve this data using the following code:

19 |
20 | 
21 | 
22 | $data = ResourceBundle::create('', 'ICUDATA-zone');
23 | foreach($data as $name => $value) {
24 |     echo "$name: " . print_r($value, true);
25 | }
26 | 
27 | 28 | render('_icuData', ['icuData' => ResourceInfo::zoneData($locale)]) ?> 29 | 30 | --------------------------------------------------------------------------------